Add custom handling of unknown input txs during BitcoinType block import

pull/105/head
Martin Boehm 2019-01-09 23:24:25 +01:00
parent d77fb35bb5
commit 341bf331c1
4 changed files with 59 additions and 4 deletions

View File

@ -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

View File

@ -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 <txid> <vout varint>
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 <txid> <index varint> 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)
}

View File

@ -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)

View File

@ -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