github.com/trezor/blockbook@v0.4.1-0.20240328132726-e9a08582ee2c/bchain/coins/btg/bgoldparser.go (about)

     1  package btg
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/binary"
     6  	"io"
     7  
     8  	"github.com/martinboehm/btcd/chaincfg/chainhash"
     9  	"github.com/martinboehm/btcd/wire"
    10  	"github.com/martinboehm/btcutil/chaincfg"
    11  	"github.com/trezor/blockbook/bchain"
    12  	"github.com/trezor/blockbook/bchain/coins/btc"
    13  	"github.com/trezor/blockbook/bchain/coins/utils"
    14  )
    15  
    16  const (
    17  	// MainnetMagic is mainnet network constant
    18  	MainnetMagic wire.BitcoinNet = 0x446d47e1
    19  	// TestnetMagic is testnet network constant
    20  	TestnetMagic wire.BitcoinNet = 0x456e48e2
    21  )
    22  
    23  var (
    24  	// MainNetParams are parser parameters for mainnet
    25  	MainNetParams chaincfg.Params
    26  	// TestNetParams are parser parameters for testnet
    27  	TestNetParams chaincfg.Params
    28  )
    29  
    30  func init() {
    31  	MainNetParams = chaincfg.MainNetParams
    32  	MainNetParams.Net = MainnetMagic
    33  
    34  	// Address encoding magics
    35  	MainNetParams.PubKeyHashAddrID = []byte{38} // base58 prefix: G
    36  	MainNetParams.ScriptHashAddrID = []byte{23} // base58 prefix: A
    37  
    38  	TestNetParams = chaincfg.TestNet3Params
    39  	TestNetParams.Net = TestnetMagic
    40  
    41  	// Human-readable part for Bech32 encoded segwit addresses, as defined in
    42  	// BIP 173.
    43  	// see https://github.com/satoshilabs/slips/blob/master/slip-0173.md
    44  	MainNetParams.Bech32HRPSegwit = "btg"
    45  	TestNetParams.Bech32HRPSegwit = "tbtg"
    46  }
    47  
    48  // BGoldParser handle
    49  type BGoldParser struct {
    50  	*btc.BitcoinLikeParser
    51  }
    52  
    53  // NewBGoldParser returns new BGoldParser instance
    54  func NewBGoldParser(params *chaincfg.Params, c *btc.Configuration) *BGoldParser {
    55  	p := &BGoldParser{BitcoinLikeParser: btc.NewBitcoinLikeParser(params, c)}
    56  	p.VSizeSupport = true
    57  	return p
    58  }
    59  
    60  // GetChainParams contains network parameters for the main Bitcoin Cash network,
    61  // the regression test Bitcoin Cash network, the test Bitcoin Cash network and
    62  // the simulation test Bitcoin Cash network, in this order
    63  func GetChainParams(chain string) *chaincfg.Params {
    64  	if !chaincfg.IsRegistered(&MainNetParams) {
    65  		err := chaincfg.Register(&MainNetParams)
    66  		if err == nil {
    67  			err = chaincfg.Register(&TestNetParams)
    68  		}
    69  		if err != nil {
    70  			panic(err)
    71  		}
    72  	}
    73  	switch chain {
    74  	case "test":
    75  		return &TestNetParams
    76  	case "regtest":
    77  		return &chaincfg.RegressionNetParams
    78  	default:
    79  		return &MainNetParams
    80  	}
    81  }
    82  
    83  // headerFixedLength is the length of fixed fields of a block (i.e. without solution)
    84  // see https://github.com/BTCGPU/BTCGPU/wiki/Technical-Spec#block-header
    85  const headerFixedLength = 44 + (chainhash.HashSize * 3)
    86  const timestampOffset = 100
    87  const timestampLength = 4
    88  
    89  // ParseBlock parses raw block to our Block struct
    90  func (p *BGoldParser) ParseBlock(b []byte) (*bchain.Block, error) {
    91  	r := bytes.NewReader(b)
    92  	time, err := getTimestampAndSkipHeader(r, 0)
    93  	if err != nil {
    94  		return nil, err
    95  	}
    96  
    97  	w := wire.MsgBlock{}
    98  	err = utils.DecodeTransactions(r, 0, wire.WitnessEncoding, &w)
    99  	if err != nil {
   100  		return nil, err
   101  	}
   102  
   103  	txs := make([]bchain.Tx, len(w.Transactions))
   104  	for ti, t := range w.Transactions {
   105  		txs[ti] = p.TxFromMsgTx(t, false)
   106  	}
   107  
   108  	return &bchain.Block{
   109  		BlockHeader: bchain.BlockHeader{
   110  			Size: len(b),
   111  			Time: time,
   112  		},
   113  		Txs: txs,
   114  	}, nil
   115  }
   116  
   117  func getTimestampAndSkipHeader(r io.ReadSeeker, pver uint32) (int64, error) {
   118  	_, err := r.Seek(timestampOffset, io.SeekStart)
   119  	if err != nil {
   120  		return 0, err
   121  	}
   122  
   123  	buf := make([]byte, timestampLength)
   124  	if _, err = io.ReadFull(r, buf); err != nil {
   125  		return 0, err
   126  	}
   127  	time := binary.LittleEndian.Uint32(buf)
   128  
   129  	_, err = r.Seek(headerFixedLength-timestampOffset-timestampLength, io.SeekCurrent)
   130  	if err != nil {
   131  		return 0, err
   132  	}
   133  
   134  	size, err := wire.ReadVarInt(r, pver)
   135  	if err != nil {
   136  		return 0, err
   137  	}
   138  
   139  	_, err = r.Seek(int64(size), io.SeekCurrent)
   140  	if err != nil {
   141  		return 0, err
   142  	}
   143  
   144  	return int64(time), nil
   145  }