From 6b022bb9c5a6a89629d04a8eefa459a41d633fd9 Mon Sep 17 00:00:00 2001 From: Dante <35383529+srdante@users.noreply.github.com> Date: Fri, 7 Jul 2023 15:36:28 -0300 Subject: [PATCH] Fix PIVX parser after update v5.0 (#946) --- bchain/coins/pivx/pivxparser.go | 94 ++++++++++++++++++++++++++++++++- 1 file changed, 92 insertions(+), 2 deletions(-) diff --git a/bchain/coins/pivx/pivxparser.go b/bchain/coins/pivx/pivxparser.go index 4dc92943..bd0c2800 100644 --- a/bchain/coins/pivx/pivxparser.go +++ b/bchain/coins/pivx/pivxparser.go @@ -2,8 +2,10 @@ package pivx import ( "bytes" + "encoding/binary" "encoding/hex" "encoding/json" + "fmt" "io" "math/big" @@ -13,7 +15,6 @@ import ( "github.com/martinboehm/btcutil/chaincfg" "github.com/trezor/blockbook/bchain" "github.com/trezor/blockbook/bchain/coins/btc" - "github.com/trezor/blockbook/bchain/coins/utils" ) // magic numbers @@ -100,7 +101,12 @@ func (p *PivXParser) ParseBlock(b []byte) (*bchain.Block, error) { r.Seek(32, io.SeekCurrent) } - err = utils.DecodeTransactions(r, 0, wire.WitnessEncoding, &w) + if h.Version > 7 { + // Skip new hashFinalSaplingRoot (block version 8 or newer) + r.Seek(32, io.SeekCurrent) + } + + err = p.PivxDecodeTransactions(r, 0, &w) if err != nil { return nil, errors.Annotatef(err, "DecodeTransactions") } @@ -255,6 +261,90 @@ func (p *PivXParser) GetAddrDescForUnknownInput(tx *bchain.Tx, input int) bchain return s } +func (p *PivXParser) PivxDecodeTransactions(r *bytes.Reader, pver uint32, blk *wire.MsgBlock) error { + maxTxPerBlock := uint64((wire.MaxBlockPayload / 10) + 1) + + 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: "utils.decodeTransactions", Description: str} + } + + blk.Transactions = make([]*wire.MsgTx, 0, txCount) + for i := uint64(0); i < txCount; i++ { + tx := wire.MsgTx{} + + // read version & seek back to original state + var version uint32 = 0 + if err = binary.Read(r, binary.LittleEndian, &version); err != nil { + return err + } + if _, err = r.Seek(-4, io.SeekCurrent); err != nil { + return err + } + + txVersion := version & 0xffff + enc := wire.WitnessEncoding + + // shielded transactions + if txVersion >= 3 { + enc = wire.BaseEncoding + } + + err := p.PivxDecode(&tx, r, pver, enc) + if err != nil { + return err + } + blk.Transactions = append(blk.Transactions, &tx) + } + + return nil +} + +func (p *PivXParser) PivxDecode(MsgTx *wire.MsgTx, r *bytes.Reader, pver uint32, enc wire.MessageEncoding) error { + if err := MsgTx.BtcDecode(r, pver, enc); err != nil { + return err + } + + // extra + version := uint32(MsgTx.Version) + txVersion := version & 0xffff + + if txVersion >= 3 { + // valueBalance + r.Seek(9, io.SeekCurrent) + + vShieldedSpend, err := wire.ReadVarInt(r, 0) + if err != nil { + return err + } + if vShieldedSpend > 0 { + r.Seek(int64(vShieldedSpend*384), io.SeekCurrent) + } + + vShieldOutput, err := wire.ReadVarInt(r, 0) + if err != nil { + return err + } + if vShieldOutput > 0 { + r.Seek(int64(vShieldOutput*948), io.SeekCurrent) + } + + // bindingSig + r.Seek(64, io.SeekCurrent) + } + + return nil +} + // Checks if script is OP_ZEROCOINMINT func isZeroCoinMintScript(signatureScript []byte) bool { return len(signatureScript) > 1 && signatureScript[0] == OP_ZEROCOINMINT