blockbook/bchain/coins/qtum/qtumparser.go

156 lines
3.4 KiB
Go

package qtum
import (
"bytes"
"encoding/json"
"io"
"github.com/martinboehm/btcd/wire"
"github.com/martinboehm/btcutil/chaincfg"
"spacecruft.org/spacecruft/blockbook/bchain"
"spacecruft.org/spacecruft/blockbook/bchain/coins/btc"
"spacecruft.org/spacecruft/blockbook/bchain/coins/utils"
)
// magic numbers
const (
MainnetMagic wire.BitcoinNet = 0xf1cfa6d3
TestnetMagic wire.BitcoinNet = 0x0d221506
)
// chain parameters
var (
MainNetParams chaincfg.Params
TestNetParams chaincfg.Params
)
func init() {
MainNetParams = chaincfg.MainNetParams
MainNetParams.Net = MainnetMagic
MainNetParams.PubKeyHashAddrID = []byte{58}
MainNetParams.ScriptHashAddrID = []byte{50}
MainNetParams.Bech32HRPSegwit = "qc"
TestNetParams = chaincfg.TestNet3Params
TestNetParams.Net = TestnetMagic
TestNetParams.PubKeyHashAddrID = []byte{120}
TestNetParams.ScriptHashAddrID = []byte{110}
TestNetParams.Bech32HRPSegwit = "tq"
}
// QtumParser handle
type QtumParser struct {
*btc.BitcoinParser
}
// NewQtumParser returns new DashParser instance
func NewQtumParser(params *chaincfg.Params, c *btc.Configuration) *QtumParser {
return &QtumParser{
BitcoinParser: btc.NewBitcoinParser(params, c),
}
}
// GetChainParams contains network parameters for the main Qtum network,
// the regression test Qtum network, the test Qtum network and
// the simulation test Qtum network, in this order
func GetChainParams(chain string) *chaincfg.Params {
if !chaincfg.IsRegistered(&MainNetParams) {
err := chaincfg.Register(&MainNetParams)
if err == nil {
err = chaincfg.Register(&TestNetParams)
}
if err != nil {
panic(err)
}
}
switch chain {
case "test":
return &TestNetParams
default:
return &MainNetParams
}
}
func parseBlockHeader(r io.Reader) (*wire.BlockHeader, error) {
h := &wire.BlockHeader{}
err := h.Deserialize(r)
if err != nil {
return nil, err
}
// hash_state_root 32
// hash_utxo_root 32
// hash_prevout_stake 32
// hash_prevout_n 4
buf := make([]byte, 100)
_, err = io.ReadFull(r, buf)
if err != nil {
return nil, err
}
sigLength, err := wire.ReadVarInt(r, 0)
if err != nil {
return nil, err
}
sigBuf := make([]byte, sigLength)
_, err = io.ReadFull(r, sigBuf)
if err != nil {
return nil, err
}
return h, err
}
func (p *QtumParser) ParseBlock(b []byte) (*bchain.Block, error) {
r := bytes.NewReader(b)
w := wire.MsgBlock{}
h, err := parseBlockHeader(r)
if err != nil {
return nil, err
}
err = utils.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{
BlockHeader: bchain.BlockHeader{
Size: len(b),
Time: h.Timestamp.Unix(),
},
Txs: txs,
}, nil
}
// ParseTxFromJson parses JSON message containing transaction and returns Tx struct
func (p *QtumParser) ParseTxFromJson(msg json.RawMessage) (*bchain.Tx, error) {
var tx bchain.Tx
err := json.Unmarshal(msg, &tx)
if err != nil {
return nil, err
}
for i := range tx.Vout {
vout := &tx.Vout[i]
// convert vout.JsonValue to big.Int and clear it, it is only temporary value used for unmarshal
vout.ValueSat, err = p.AmountToBigInt(vout.JsonValue)
if err != nil {
return nil, err
}
vout.JsonValue = ""
if vout.ScriptPubKey.Addresses == nil {
vout.ScriptPubKey.Addresses = []string{}
}
}
return &tx, nil
}