blockbook/bchain/coins/divi/diviparser.go
Martin Boehm eae9b6b613 Handle Bitcoin vout addresses after upgrade to bitcoind 22.0.0
It was necessary to split the composition chain in other coins
from BitcoinParser to BitcoinLikeParser to keep backwards compatibility
2021-09-21 23:59:20 +02:00

228 lines
5.8 KiB
Go
Executable File

package divi
import (
"bytes"
"encoding/hex"
"encoding/json"
"io"
"math/big"
"github.com/juju/errors"
"github.com/martinboehm/btcd/wire"
"github.com/martinboehm/btcutil/chaincfg"
"github.com/trezor/blockbook/bchain"
"github.com/trezor/blockbook/bchain/coins/btc"
"github.com/trezor/blockbook/bchain/coins/utils"
)
const (
// MainnetMagic = "network messages so the messages can be identified to belong to a specific coin"
// Source https://github.com/DiviProject/Divi/blob/master0/divi/src/chainparams.cpp#L128-L136
MainnetMagic wire.BitcoinNet = 0x8f8da0df
)
var (
// MainNetParams = ???
MainNetParams chaincfg.Params
)
func init() {
// DIVI mainnet Address encoding magics
MainNetParams = chaincfg.MainNetParams
MainNetParams.Net = MainnetMagic
MainNetParams.PubKeyHashAddrID = []byte{30} // starting with 'D'
MainNetParams.ScriptHashAddrID = []byte{13}
MainNetParams.PrivateKeyID = []byte{212}
}
// DivicoinParser handle
type DivicoinParser struct {
*btc.BitcoinLikeParser
baseparser *bchain.BaseParser
BitcoinOutputScriptToAddressesFunc btc.OutputScriptToAddressesFunc
}
// NewDiviParser returns new DivicoinParser instance
func NewDiviParser(params *chaincfg.Params, c *btc.Configuration) *DivicoinParser {
p := &DivicoinParser{
BitcoinLikeParser: btc.NewBitcoinLikeParser(params, c),
baseparser: &bchain.BaseParser{},
}
p.BitcoinOutputScriptToAddressesFunc = p.OutputScriptToAddressesFunc
p.OutputScriptToAddressesFunc = p.outputScriptToAddresses
return p
}
// GetChainParams contains network parameters for the main Divi network
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
//}
}
// ParseBlock parses raw block to our Block struct
func (p *DivicoinParser) ParseBlock(b []byte) (*bchain.Block, error) {
r := bytes.NewReader(b)
w := wire.MsgBlock{}
h := wire.BlockHeader{}
err := h.Deserialize(r)
if err != nil {
return nil, errors.Annotatef(err, "Deserialize")
}
if h.Version > 3 {
// Skip past AccumulatorCheckpoint which was added in pivx block version 4
r.Seek(32, io.SeekCurrent)
}
err = utils.DecodeTransactions(r, 0, wire.WitnessEncoding, &w)
if err != nil {
return nil, errors.Annotatef(err, "DecodeTransactions")
}
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
}
// PackTx packs transaction to byte array using protobuf
func (p *DivicoinParser) PackTx(tx *bchain.Tx, height uint32, blockTime int64) ([]byte, error) {
return p.baseparser.PackTx(tx, height, blockTime)
}
// UnpackTx unpacks transaction from protobuf byte array
func (p *DivicoinParser) UnpackTx(buf []byte) (*bchain.Tx, uint32, error) {
return p.baseparser.UnpackTx(buf)
}
// ParseTx parses byte array containing transaction and returns Tx struct
func (p *DivicoinParser) ParseTx(b []byte) (*bchain.Tx, error) {
t := wire.MsgTx{}
r := bytes.NewReader(b)
if err := t.Deserialize(r); err != nil {
return nil, err
}
tx := p.TxFromMsgTx(&t, true)
tx.Hex = hex.EncodeToString(b)
return &tx, nil
}
// TxFromMsgTx parses tx and adds handling for OP_ZEROCOINSPEND inputs
func (p *DivicoinParser) TxFromMsgTx(t *wire.MsgTx, parseAddresses bool) bchain.Tx {
vin := make([]bchain.Vin, len(t.TxIn))
for i, in := range t.TxIn {
s := bchain.ScriptSig{
Hex: hex.EncodeToString(in.SignatureScript),
// missing: Asm,
}
txid := in.PreviousOutPoint.Hash.String()
vin[i] = bchain.Vin{
Txid: txid,
Vout: in.PreviousOutPoint.Index,
Sequence: in.Sequence,
ScriptSig: s,
}
}
vout := make([]bchain.Vout, len(t.TxOut))
for i, out := range t.TxOut {
addrs := []string{}
if parseAddresses {
addrs, _, _ = p.OutputScriptToAddressesFunc(out.PkScript)
}
s := bchain.ScriptPubKey{
Hex: hex.EncodeToString(out.PkScript),
Addresses: addrs,
// missing: Asm,
// missing: Type,
}
var vs big.Int
vs.SetInt64(out.Value)
vout[i] = bchain.Vout{
ValueSat: vs,
N: uint32(i),
ScriptPubKey: s,
}
}
tx := bchain.Tx{
Txid: t.TxHash().String(),
Version: t.Version,
LockTime: t.LockTime,
Vin: vin,
Vout: vout,
// skip: BlockHash,
// skip: Confirmations,
// skip: Time,
// skip: Blocktime,
}
return tx
}
// ParseTxFromJSON parses JSON message containing transaction and returns Tx struct
func (p *DivicoinParser) 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
}
// outputScriptToAddresses converts ScriptPubKey to bitcoin addresses
func (p *DivicoinParser) outputScriptToAddresses(script []byte) ([]string, bool, error) {
rv, s, _ := p.BitcoinOutputScriptToAddressesFunc(script)
return rv, s, nil
}
// GetAddrDescForUnknownInput = ???
func (p *DivicoinParser) GetAddrDescForUnknownInput(tx *bchain.Tx, input int) bchain.AddressDescriptor {
if len(tx.Vin) > input {
scriptHex := tx.Vin[input].ScriptSig.Hex
if scriptHex != "" {
script, _ := hex.DecodeString(scriptHex)
return script
}
}
s := make([]byte, 10)
return s
}