From 341bf331c107f894cb771f5c2d925a7f090595a6 Mon Sep 17 00:00:00 2001 From: Martin Boehm Date: Wed, 9 Jan 2019 23:24:25 +0100 Subject: [PATCH] Add custom handling of unknown input txs during BitcoinType block import --- bchain/baseparser.go | 11 +++++++ bchain/coins/liquid/liquidparser.go | 46 +++++++++++++++++++++++++++-- bchain/types.go | 1 + db/rocksdb.go | 5 ++-- 4 files changed, 59 insertions(+), 4 deletions(-) diff --git a/bchain/baseparser.go b/bchain/baseparser.go index 3060b3c2..10cd7096 100644 --- a/bchain/baseparser.go +++ b/bchain/baseparser.go @@ -7,6 +7,7 @@ import ( "strings" "github.com/gogo/protobuf/proto" + "github.com/golang/glog" "github.com/juju/errors" ) @@ -26,6 +27,16 @@ func (p *BaseParser) ParseTx(b []byte) (*Tx, error) { return nil, errors.New("ParseTx: not implemented") } +// GetAddrDescForUnknownInput returns nil AddressDescriptor +func (p *BaseParser) GetAddrDescForUnknownInput(block *Block, tx *Tx, input int) AddressDescriptor { + var iTxid string + if len(tx.Vin) > input { + iTxid = tx.Vin[input].Txid + } + glog.Warningf("height %d, tx %v, input tx %v not found in txAddresses", block.Height, tx.Txid, iTxid) + return nil +} + const zeros = "0000000000000000000000000000000000000000" // AmountToBigInt converts amount in json.Number (string) to big.Int diff --git a/bchain/coins/liquid/liquidparser.go b/bchain/coins/liquid/liquidparser.go index c21e7653..f6758895 100644 --- a/bchain/coins/liquid/liquidparser.go +++ b/bchain/coins/liquid/liquidparser.go @@ -3,7 +3,12 @@ package liquid import ( "blockbook/bchain" "blockbook/bchain/coins/btc" + "strconv" + vlq "github.com/bsm/go-vlq" + "github.com/golang/glog" + + "github.com/martinboehm/btcd/txscript" "github.com/martinboehm/btcd/wire" "github.com/martinboehm/btcutil/chaincfg" ) @@ -27,15 +32,19 @@ func init() { // LiquidParser handle type LiquidParser struct { *btc.BitcoinParser - baseparser *bchain.BaseParser + baseparser *bchain.BaseParser + origOutputScriptToAddressesFunc btc.OutputScriptToAddressesFunc } // NewLiquidParser returns new LiquidParser instance func NewLiquidParser(params *chaincfg.Params, c *btc.Configuration) *LiquidParser { - return &LiquidParser{ + p := &LiquidParser{ BitcoinParser: btc.NewBitcoinParser(params, c), baseparser: &bchain.BaseParser{}, } + p.origOutputScriptToAddressesFunc = p.OutputScriptToAddressesFunc + p.OutputScriptToAddressesFunc = p.outputScriptToAddresses + return p } // GetChainParams contains network parameters for the main GameCredits network, @@ -62,3 +71,36 @@ func (p *LiquidParser) PackTx(tx *bchain.Tx, height uint32, blockTime int64) ([] func (p *LiquidParser) UnpackTx(buf []byte) (*bchain.Tx, uint32, error) { return p.baseparser.UnpackTx(buf) } + +// GetAddrDescForUnknownInput processes inputs that were not found in txAddresses - they are bitcoin transactions +// create a special script for the input in the form OP_INVALIDOPCODE +func (p *LiquidParser) GetAddrDescForUnknownInput(block *bchain.Block, tx *bchain.Tx, input int) bchain.AddressDescriptor { + var iTxid string + s := make([]byte, 0, 40) + if len(tx.Vin) > input { + iTxid = tx.Vin[input].Txid + btxID, err := p.PackTxid(iTxid) + if err == nil { + buf := make([]byte, vlq.MaxLen64) + l := vlq.PutInt(buf, int64(tx.Vin[input].Vout)) + s = append(s, txscript.OP_INVALIDOPCODE) + s = append(s, btxID...) + s = append(s, buf[:l]...) + } + } + glog.Info("height ", block.Height, ", tx ", tx.Txid, ", encountered Bitcoin tx ", iTxid) + return s +} + +// outputScriptToAddresses converts ScriptPubKey to bitcoin addresses +func (p *LiquidParser) outputScriptToAddresses(script []byte) ([]string, bool, error) { + // minimum length of the special script OP_INVALIDOPCODE is 34 bytes (1 byte opcode, 32 bytes tx, 1 byte vout) + if len(script) > 33 && script[0] == txscript.OP_INVALIDOPCODE { + txid, _ := p.UnpackTxid(script[1:33]) + vout, _ := vlq.Int(script[33:]) + return []string{ + "Bitcoin tx " + txid + ":" + strconv.Itoa(int(vout)), + }, false, nil + } + return p.origOutputScriptToAddressesFunc(script) +} diff --git a/bchain/types.go b/bchain/types.go index 293d4e58..e65bada3 100644 --- a/bchain/types.go +++ b/bchain/types.go @@ -256,6 +256,7 @@ type BlockChainParser interface { ParseTxFromJson(json.RawMessage) (*Tx, error) PackTx(tx *Tx, height uint32, blockTime int64) ([]byte, error) UnpackTx(buf []byte) (*Tx, uint32, error) + GetAddrDescForUnknownInput(block *Block, tx *Tx, input int) AddressDescriptor // blocks PackBlockHash(hash string) ([]byte, error) UnpackBlockHash(buf []byte) (string, error) diff --git a/db/rocksdb.go b/db/rocksdb.go index 73c4ad7a..94437caa 100644 --- a/db/rocksdb.go +++ b/db/rocksdb.go @@ -13,7 +13,7 @@ import ( "strconv" "time" - "github.com/bsm/go-vlq" + vlq "github.com/bsm/go-vlq" "github.com/golang/glog" "github.com/juju/errors" "github.com/tecbot/gorocksdb" @@ -490,7 +490,8 @@ func (d *RocksDB) processAddressesBitcoinType(block *bchain.Block, addresses add return err } if ita == nil { - glog.Warningf("rocksdb: height %d, tx %v, input tx %v not found in txAddresses", block.Height, tx.Txid, input.Txid) + // allow parser to process unknown input, some coins may implement special handling, default is to log warning + tai.AddrDesc = d.chainParser.GetAddrDescForUnknownInput(block, tx, i) continue } txAddressesMap[stxID] = ita