2018-06-06 03:34:50 -06:00
|
|
|
package btg
|
2018-05-31 06:17:34 -06:00
|
|
|
|
|
|
|
import (
|
|
|
|
"blockbook/bchain"
|
|
|
|
"blockbook/bchain/coins/btc"
|
2018-06-06 03:34:50 -06:00
|
|
|
"bytes"
|
2018-05-31 06:17:34 -06:00
|
|
|
"fmt"
|
2018-06-06 03:34:50 -06:00
|
|
|
"io"
|
2018-05-31 06:17:34 -06:00
|
|
|
|
|
|
|
"github.com/btcsuite/btcd/chaincfg"
|
2018-06-06 03:34:50 -06:00
|
|
|
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
|
|
|
"github.com/btcsuite/btcd/wire"
|
2018-05-31 06:17:34 -06:00
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
|
|
|
MainnetMagic wire.BitcoinNet = 0x446d47e1
|
|
|
|
TestnetMagic wire.BitcoinNet = 0x456e48e2
|
|
|
|
)
|
|
|
|
|
2018-06-06 03:34:50 -06:00
|
|
|
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)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-05-31 06:17:34 -06:00
|
|
|
// BGoldParser handle
|
|
|
|
type BGoldParser struct {
|
|
|
|
*btc.BitcoinParser
|
|
|
|
}
|
|
|
|
|
2018-06-08 07:11:35 -06:00
|
|
|
// NewBGoldParser returns new BGoldParser instance
|
2018-05-31 06:17:34 -06:00
|
|
|
func NewBGoldParser(params *chaincfg.Params, c *btc.Configuration) *BGoldParser {
|
2018-06-06 03:34:50 -06:00
|
|
|
return &BGoldParser{BitcoinParser: btc.NewBitcoinParser(params, c)}
|
2018-05-31 06:17:34 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
// GetChainParams contains network parameters for the main Bitcoin Cash network,
|
|
|
|
// the regression test Bitcoin Cash network, the test Bitcoin Cash network and
|
|
|
|
// the simulation test Bitcoin Cash network, in this order
|
|
|
|
func GetChainParams(chain string) *chaincfg.Params {
|
|
|
|
switch chain {
|
|
|
|
case "test":
|
2018-06-06 03:34:50 -06:00
|
|
|
return &TestNetParams
|
2018-05-31 06:17:34 -06:00
|
|
|
case "regtest":
|
2018-06-06 03:34:50 -06:00
|
|
|
return &chaincfg.RegressionNetParams
|
2018-05-31 06:17:34 -06:00
|
|
|
default:
|
2018-06-06 03:34:50 -06:00
|
|
|
return &MainNetParams
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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
|
|
|
|
|
2018-06-06 06:50:30 -06:00
|
|
|
// headerFixedLength is the length of fixed fields of a block (i.e. without solution)
|
|
|
|
// see https://github.com/BTCGPU/BTCGPU/wiki/Technical-Spec#block-header
|
|
|
|
const headerFixedLength = 44 + (chainhash.HashSize * 3)
|
2018-06-06 03:34:50 -06:00
|
|
|
|
|
|
|
// 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
|
|
|
|
}
|
|
|
|
|
|
|
|
w := wire.MsgBlock{}
|
|
|
|
err = decodeTransactions(r, 0, wire.WitnessEncoding, &w)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
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 {
|
2018-06-06 06:50:30 -06:00
|
|
|
_, err := r.Seek(headerFixedLength, io.SeekStart)
|
2018-06-06 03:34:50 -06:00
|
|
|
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)
|
2018-05-31 06:17:34 -06:00
|
|
|
}
|
|
|
|
|
2018-06-06 03:34:50 -06:00
|
|
|
return nil
|
2018-05-31 06:17:34 -06:00
|
|
|
}
|