Fixed block and address parsing
parent
2d0c56c442
commit
400194a9aa
|
@ -85,7 +85,7 @@ func outputScriptToAddresses(script []byte, params *chaincfg.Params) ([]string,
|
||||||
return rv, nil
|
return rv, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *BitcoinParser) txFromMsgTx(t *wire.MsgTx, parseAddresses bool) bchain.Tx {
|
func (p *BitcoinParser) TxFromMsgTx(t *wire.MsgTx, parseAddresses bool) bchain.Tx {
|
||||||
vin := make([]bchain.Vin, len(t.TxIn))
|
vin := make([]bchain.Vin, len(t.TxIn))
|
||||||
for i, in := range t.TxIn {
|
for i, in := range t.TxIn {
|
||||||
if blockchain.IsCoinBaseTx(t) {
|
if blockchain.IsCoinBaseTx(t) {
|
||||||
|
@ -145,7 +145,7 @@ func (p *BitcoinParser) ParseTx(b []byte) (*bchain.Tx, error) {
|
||||||
if err := t.Deserialize(r); err != nil {
|
if err := t.Deserialize(r); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
tx := p.txFromMsgTx(&t, true)
|
tx := p.TxFromMsgTx(&t, true)
|
||||||
tx.Hex = hex.EncodeToString(b)
|
tx.Hex = hex.EncodeToString(b)
|
||||||
|
|
||||||
for i, vout := range tx.Vout {
|
for i, vout := range tx.Vout {
|
||||||
|
@ -172,7 +172,7 @@ func (p *BitcoinParser) ParseBlock(b []byte) (*bchain.Block, error) {
|
||||||
|
|
||||||
txs := make([]bchain.Tx, len(w.Transactions))
|
txs := make([]bchain.Tx, len(w.Transactions))
|
||||||
for ti, t := range w.Transactions {
|
for ti, t := range w.Transactions {
|
||||||
txs[ti] = p.txFromMsgTx(t, false)
|
txs[ti] = p.TxFromMsgTx(t, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
return &bchain.Block{Txs: txs}, nil
|
return &bchain.Block{Txs: txs}, nil
|
||||||
|
|
|
@ -1,23 +1,54 @@
|
||||||
package bch
|
package btg
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"blockbook/bchain"
|
"blockbook/bchain"
|
||||||
"blockbook/bchain/coins/btc"
|
"blockbook/bchain/coins/btc"
|
||||||
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
|
|
||||||
"github.com/btcsuite/btcd/chaincfg"
|
"github.com/btcsuite/btcd/chaincfg"
|
||||||
"github.com/btcsuite/btcd/txscript"
|
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
||||||
"github.com/btcsuite/btcutil"
|
"github.com/btcsuite/btcd/wire"
|
||||||
"github.com/cpacia/bchutil"
|
"github.com/golang/glog"
|
||||||
"github.com/schancel/cashaddr-converter/address"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
MainnetMagic wire.BitcoinNet = 0x446d47e1
|
MainnetMagic wire.BitcoinNet = 0x446d47e1
|
||||||
TestnetMagic wire.BitcoinNet = 0x456e48e2
|
TestnetMagic wire.BitcoinNet = 0x456e48e2
|
||||||
RegtestMagic wire.BitcoinNet = 0xdab5bffa
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
MainNetParams chaincfg.Params
|
||||||
|
TestNetParams chaincfg.Params
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
MainNetParams = chaincfg.MainNetParams
|
||||||
|
MainNetParams.Net = MainnetMagic
|
||||||
|
|
||||||
|
// Address encoding magics
|
||||||
|
MainNetParams.PubKeyHashAddrID = 38 // base58 prefix: G
|
||||||
|
MainNetParams.ScriptHashAddrID = 23 // base58 prefix: A
|
||||||
|
|
||||||
|
TestNetParams = chaincfg.TestNet3Params
|
||||||
|
TestNetParams.Net = TestnetMagic
|
||||||
|
|
||||||
|
// Human-readable part for Bech32 encoded segwit addresses, as defined in
|
||||||
|
// BIP 173.
|
||||||
|
// see https://github.com/satoshilabs/slips/blob/master/slip-0173.md
|
||||||
|
MainNetParams.Bech32HRPSegwit = "btg"
|
||||||
|
TestNetParams.Bech32HRPSegwit = "tbtg"
|
||||||
|
|
||||||
|
err := chaincfg.Register(&MainNetParams)
|
||||||
|
if err == nil {
|
||||||
|
err = chaincfg.Register(&TestNetParams)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// BGoldParser handle
|
// BGoldParser handle
|
||||||
type BGoldParser struct {
|
type BGoldParser struct {
|
||||||
*btc.BitcoinParser
|
*btc.BitcoinParser
|
||||||
|
@ -25,25 +56,110 @@ type BGoldParser struct {
|
||||||
|
|
||||||
// NewBCashParser returns new BGoldParser instance
|
// NewBCashParser returns new BGoldParser instance
|
||||||
func NewBGoldParser(params *chaincfg.Params, c *btc.Configuration) *BGoldParser {
|
func NewBGoldParser(params *chaincfg.Params, c *btc.Configuration) *BGoldParser {
|
||||||
return BGoldParser{BitcoinParser: btc.NewBitcoinParser(params, c)}
|
return &BGoldParser{BitcoinParser: btc.NewBitcoinParser(params, c)}
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetChainParams contains network parameters for the main Bitcoin Cash network,
|
// GetChainParams contains network parameters for the main Bitcoin Cash network,
|
||||||
// the regression test Bitcoin Cash network, the test Bitcoin Cash network and
|
// the regression test Bitcoin Cash network, the test Bitcoin Cash network and
|
||||||
// the simulation test Bitcoin Cash network, in this order
|
// the simulation test Bitcoin Cash network, in this order
|
||||||
func GetChainParams(chain string) *chaincfg.Params {
|
func GetChainParams(chain string) *chaincfg.Params {
|
||||||
var params *chaincfg.Params
|
|
||||||
switch chain {
|
switch chain {
|
||||||
case "test":
|
case "test":
|
||||||
params = &chaincfg.TestNet3Params
|
return &TestNetParams
|
||||||
params.Net = TestnetMagic
|
|
||||||
case "regtest":
|
case "regtest":
|
||||||
params = &chaincfg.RegressionNetParams
|
return &chaincfg.RegressionNetParams
|
||||||
params.Net = Regtestmagic
|
|
||||||
default:
|
default:
|
||||||
params = &chaincfg.MainNetParams
|
return &MainNetParams
|
||||||
params.Net = MainnetMagic
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// minTxPayload is the minimum payload size for a transaction. Note
|
||||||
|
// that any realistically usable transaction must have at least one
|
||||||
|
// input or output, but that is a rule enforced at a higher layer, so
|
||||||
|
// it is intentionally not included here.
|
||||||
|
// Version 4 bytes + Varint number of transaction inputs 1 byte + Varint
|
||||||
|
// number of transaction outputs 1 byte + LockTime 4 bytes + min input
|
||||||
|
// payload + min output payload.
|
||||||
|
const minTxPayload = 10
|
||||||
|
|
||||||
|
// maxTxPerBlock is the maximum number of transactions that could
|
||||||
|
// possibly fit into a block.
|
||||||
|
const maxTxPerBlock = (wire.MaxBlockPayload / minTxPayload) + 1
|
||||||
|
|
||||||
|
const headerConstLength = 44 + (chainhash.HashSize * 3)
|
||||||
|
|
||||||
|
// ParseBlock parses raw block to our Block struct
|
||||||
|
func (p *BGoldParser) ParseBlock(b []byte) (*bchain.Block, error) {
|
||||||
|
r := bytes.NewReader(b)
|
||||||
|
err := skipHeader(r, 0)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return params
|
if glog.V(1) {
|
||||||
|
off, _ := r.Seek(0, io.SeekCurrent)
|
||||||
|
glog.Infof("parseblock: skipped %d bytes", off)
|
||||||
|
}
|
||||||
|
|
||||||
|
w := wire.MsgBlock{}
|
||||||
|
err = decodeTransactions(r, 0, wire.WitnessEncoding, &w)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
glog.V(1).Infof("parseblock: got %d transactions", len(w.Transactions))
|
||||||
|
|
||||||
|
txs := make([]bchain.Tx, len(w.Transactions))
|
||||||
|
for ti, t := range w.Transactions {
|
||||||
|
txs[ti] = p.TxFromMsgTx(t, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &bchain.Block{Txs: txs}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func skipHeader(r io.ReadSeeker, pver uint32) error {
|
||||||
|
_, err := r.Seek(headerConstLength, io.SeekStart)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
size, err := wire.ReadVarInt(r, pver)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = r.Seek(int64(size), io.SeekCurrent)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func decodeTransactions(r io.Reader, pver uint32, enc wire.MessageEncoding, blk *wire.MsgBlock) error {
|
||||||
|
txCount, err := wire.ReadVarInt(r, pver)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prevent more transactions than could possibly fit into a block.
|
||||||
|
// It would be possible to cause memory exhaustion and panics without
|
||||||
|
// a sane upper bound on this count.
|
||||||
|
if txCount > maxTxPerBlock {
|
||||||
|
str := fmt.Sprintf("too many transactions to fit into a block "+
|
||||||
|
"[count %d, max %d]", txCount, maxTxPerBlock)
|
||||||
|
return &wire.MessageError{Func: "btg.decodeTransactions", Description: str}
|
||||||
|
}
|
||||||
|
|
||||||
|
blk.Transactions = make([]*wire.MsgTx, 0, txCount)
|
||||||
|
for i := uint64(0); i < txCount; i++ {
|
||||||
|
tx := wire.MsgTx{}
|
||||||
|
err := tx.BtcDecode(r, pver, enc)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
blk.Transactions = append(blk.Transactions, &tx)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package bch
|
package btg
|
||||||
|
|
||||||
// import (
|
// import (
|
||||||
// "blockbook/bchain"
|
// "blockbook/bchain"
|
||||||
|
|
|
@ -1,14 +1,11 @@
|
||||||
package bch
|
package btg
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"blockbook/bchain"
|
"blockbook/bchain"
|
||||||
"blockbook/bchain/coins/btc"
|
"blockbook/bchain/coins/btc"
|
||||||
"encoding/hex"
|
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
|
||||||
"github.com/cpacia/bchutil"
|
|
||||||
"github.com/golang/glog"
|
"github.com/golang/glog"
|
||||||
"github.com/juju/errors"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// BGoldRPC is an interface to JSON-RPC bitcoind service.
|
// BGoldRPC is an interface to JSON-RPC bitcoind service.
|
||||||
|
@ -40,11 +37,7 @@ func (b *BGoldRPC) Initialize() error {
|
||||||
params := GetChainParams(chainName)
|
params := GetChainParams(chainName)
|
||||||
|
|
||||||
// always create parser
|
// always create parser
|
||||||
b.Parser, err = NewBGoldParser(params, b.ChainConfig)
|
b.Parser = NewBGoldParser(params, b.ChainConfig)
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// parameters for getInfo request
|
// parameters for getInfo request
|
||||||
if params.Net == MainnetMagic {
|
if params.Net == MainnetMagic {
|
||||||
|
@ -59,117 +52,3 @@ func (b *BGoldRPC) Initialize() error {
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
|
||||||
// // getblock
|
|
||||||
//
|
|
||||||
// type cmdGetBlock struct {
|
|
||||||
// Method string `json:"method"`
|
|
||||||
// Params struct {
|
|
||||||
// BlockHash string `json:"blockhash"`
|
|
||||||
// Verbose bool `json:"verbose"`
|
|
||||||
// } `json:"params"`
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// type resGetBlockRaw struct {
|
|
||||||
// Error *bchain.RPCError `json:"error"`
|
|
||||||
// Result string `json:"result"`
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// type resGetBlockThin struct {
|
|
||||||
// Error *bchain.RPCError `json:"error"`
|
|
||||||
// Result bchain.ThinBlock `json:"result"`
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// // estimatesmartfee
|
|
||||||
//
|
|
||||||
// type cmdEstimateSmartFee struct {
|
|
||||||
// Method string `json:"method"`
|
|
||||||
// Params struct {
|
|
||||||
// Blocks int `json:"nblocks"`
|
|
||||||
// } `json:"params"`
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// type resEstimateSmartFee struct {
|
|
||||||
// Error *bchain.RPCError `json:"error"`
|
|
||||||
// Result struct {
|
|
||||||
// Feerate float64 `json:"feerate"`
|
|
||||||
// Blocks int `json:"blocks"`
|
|
||||||
// } `json:"result"`
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// // GetBlock returns block with given hash.
|
|
||||||
// func (b *BGoldRPC) GetBlock(hash string, height uint32) (*bchain.Block, error) {
|
|
||||||
// var err error
|
|
||||||
// if hash == "" && height > 0 {
|
|
||||||
// hash, err = b.GetBlockHash(height)
|
|
||||||
// if err != nil {
|
|
||||||
// return nil, err
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// header, err := b.GetBlockHeader(hash)
|
|
||||||
// if err != nil {
|
|
||||||
// return nil, err
|
|
||||||
// }
|
|
||||||
// data, err := b.GetBlockRaw(hash)
|
|
||||||
// if err != nil {
|
|
||||||
// return nil, err
|
|
||||||
// }
|
|
||||||
// block, err := b.Parser.ParseBlock(data)
|
|
||||||
// if err != nil {
|
|
||||||
// return nil, errors.Annotatef(err, "hash %v", hash)
|
|
||||||
// }
|
|
||||||
// block.BlockHeader = *header
|
|
||||||
// return block, nil
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// // GetBlockRaw returns block with given hash as bytes.
|
|
||||||
// func (b *BGoldRPC) GetBlockRaw(hash string) ([]byte, error) {
|
|
||||||
// glog.V(1).Info("rpc: getblock (verbose=0) ", hash)
|
|
||||||
//
|
|
||||||
// res := resGetBlockRaw{}
|
|
||||||
// req := cmdGetBlock{Method: "getblock"}
|
|
||||||
// req.Params.BlockHash = hash
|
|
||||||
// req.Params.Verbose = false
|
|
||||||
// err := b.Call(&req, &res)
|
|
||||||
//
|
|
||||||
// if err != nil {
|
|
||||||
// return nil, errors.Annotatef(err, "hash %v", hash)
|
|
||||||
// }
|
|
||||||
// if res.Error != nil {
|
|
||||||
// if isErrBlockNotFound(res.Error) {
|
|
||||||
// return nil, bchain.ErrBlockNotFound
|
|
||||||
// }
|
|
||||||
// return nil, errors.Annotatef(res.Error, "hash %v", hash)
|
|
||||||
// }
|
|
||||||
// return hex.DecodeString(res.Result)
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// // GetBlockFull returns block with given hash.
|
|
||||||
// func (b *BGoldRPC) GetBlockFull(hash string) (*bchain.Block, error) {
|
|
||||||
// return nil, errors.New("Not implemented")
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// // EstimateSmartFee returns fee estimation.
|
|
||||||
// func (b *BGoldRPC) EstimateSmartFee(blocks int, conservative bool) (float64, error) {
|
|
||||||
// glog.V(1).Info("rpc: estimatesmartfee ", blocks)
|
|
||||||
//
|
|
||||||
// res := resEstimateSmartFee{}
|
|
||||||
// req := cmdEstimateSmartFee{Method: "estimatesmartfee"}
|
|
||||||
// req.Params.Blocks = blocks
|
|
||||||
// // conservative param is omitted
|
|
||||||
// err := b.Call(&req, &res)
|
|
||||||
//
|
|
||||||
// if err != nil {
|
|
||||||
// return 0, err
|
|
||||||
// }
|
|
||||||
// if res.Error != nil {
|
|
||||||
// return 0, res.Error
|
|
||||||
// }
|
|
||||||
// return res.Result.Feerate, nil
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// func isErrBlockNotFound(err *bchain.RPCError) bool {
|
|
||||||
// return err.Message == "Block not found" ||
|
|
||||||
// err.Message == "Block height out of range"
|
|
||||||
// }
|
|
||||||
|
|
Loading…
Reference in New Issue