Handle error tx not found #94

This commit is contained in:
Martin Boehm 2019-01-10 16:39:36 +01:00
parent 8c4fcf4441
commit 3ca593aff1
11 changed files with 39 additions and 29 deletions

View File

@ -107,7 +107,10 @@ func (w *Worker) GetSpendingTxid(txid string, n int) (string, error) {
func (w *Worker) GetTransaction(txid string, spendingTxs bool, specificJSON bool) (*Tx, error) {
bchainTx, height, err := w.txCache.GetTransaction(txid)
if err != nil {
return nil, NewAPIError(fmt.Sprintf("Tx not found, %v", err), true)
if err == bchain.ErrTxNotFound {
return nil, NewAPIError(fmt.Sprintf("Transaction '%v' not found", txid), true)
}
return nil, NewAPIError(fmt.Sprintf("Transaction '%v' not found (%v)", txid, err), true)
}
return w.GetTransactionFromBchainTx(bchainTx, height, spendingTxs, specificJSON)
}
@ -158,6 +161,11 @@ func (w *Worker) GetTransactionFromBchainTx(bchainTx *bchain.Tx, height uint32,
// try to load from backend
otx, _, err := w.txCache.GetTransaction(bchainVin.Txid)
if err != nil {
if err == bchain.ErrTxNotFound {
// try to get AddrDesc using coin specific handling and continue processing the tx
vin.AddrDesc = w.chainParser.GetAddrDescForUnknownInput(bchainTx, i)
continue
}
return nil, errors.Annotatef(err, "txCache.GetTransaction %v", bchainVin.Txid)
}
if len(otx.Vout) > int(vin.Vout) {

View File

@ -28,12 +28,12 @@ func (p *BaseParser) ParseTx(b []byte) (*Tx, error) {
}
// GetAddrDescForUnknownInput returns nil AddressDescriptor
func (p *BaseParser) GetAddrDescForUnknownInput(block *Block, tx *Tx, input int) AddressDescriptor {
func (p *BaseParser) GetAddrDescForUnknownInput(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)
glog.Warningf("tx %v, input tx %v not found in txAddresses", tx.Txid, iTxid)
return nil
}

View File

@ -154,6 +154,7 @@ func (p *BitcoinParser) outputScriptToAddresses(script []byte) ([]string, bool,
return rv, s, nil
}
// TxFromMsgTx converts bitcoin wire Tx to bchain.Tx
func (p *BitcoinParser) TxFromMsgTx(t *wire.MsgTx, parseAddresses bool) bchain.Tx {
vin := make([]bchain.Vin, len(t.TxIn))
for i, in := range t.TxIn {

View File

@ -633,6 +633,13 @@ func (b *BitcoinRPC) GetMempool() ([]string, error) {
return res.Result, nil
}
func isMissingTx(err *bchain.RPCError) bool {
if err.Code == -5 { // "No such mempool or blockchain transaction"
return true
}
return false
}
// GetTransactionForMempool returns a transaction by the transaction ID
// It could be optimized for mempool, i.e. without block time and confirmations
func (b *BitcoinRPC) GetTransactionForMempool(txid string) (*bchain.Tx, error) {
@ -647,6 +654,9 @@ func (b *BitcoinRPC) GetTransactionForMempool(txid string) (*bchain.Tx, error) {
return nil, errors.Annotatef(err, "txid %v", txid)
}
if res.Error != nil {
if isMissingTx(res.Error) {
return nil, bchain.ErrTxNotFound
}
return nil, errors.Annotatef(res.Error, "txid %v", txid)
}
data, err := hex.DecodeString(res.Result)
@ -696,6 +706,9 @@ func (b *BitcoinRPC) getRawTransaction(txid string) (json.RawMessage, error) {
return nil, errors.Annotatef(err, "txid %v", txid)
}
if res.Error != nil {
if isMissingTx(res.Error) {
return nil, bchain.ErrTxNotFound
}
return nil, errors.Annotatef(res.Error, "txid %v", txid)
}
return res.Result, nil

View File

@ -520,7 +520,7 @@ func (b *EthereumRPC) GetBlockInfo(hash string) (*bchain.BlockInfo, error) {
func (b *EthereumRPC) GetTransactionForMempool(txid string) (*bchain.Tx, error) {
tx, err := b.GetTransaction(txid)
// it there is an error getting the tx or the tx is confirmed, remove it from pending transactions
if err != nil || (tx != nil && tx.Confirmations > 0) {
if err == bchain.ErrTxNotFound || (tx != nil && tx.Confirmations > 0) {
b.pendingTransactionsLock.Lock()
delete(b.pendingTransactions, txid)
b.pendingTransactionsLock.Unlock()
@ -538,7 +538,7 @@ func (b *EthereumRPC) GetTransaction(txid string) (*bchain.Tx, error) {
if err != nil {
return nil, err
} else if tx == nil {
return nil, ethereum.NotFound
return nil, bchain.ErrTxNotFound
}
var btx *bchain.Tx
if tx.BlockNumber == "" {

View File

@ -74,7 +74,7 @@ func (p *LiquidParser) UnpackTx(buf []byte) (*bchain.Tx, uint32, error) {
// 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 {
func (p *LiquidParser) GetAddrDescForUnknownInput(tx *bchain.Tx, input int) bchain.AddressDescriptor {
var iTxid string
s := make([]byte, 0, 40)
if len(tx.Vin) > input {
@ -88,7 +88,7 @@ func (p *LiquidParser) GetAddrDescForUnknownInput(block *bchain.Block, tx *bchai
s = append(s, buf[:l]...)
}
}
glog.Info("height ", block.Height, ", tx ", tx.Txid, ", encountered Bitcoin tx ", iTxid)
glog.Info("tx ", tx.Txid, ", encountered Bitcoin tx ", iTxid)
return s
}

View File

@ -31,6 +31,8 @@ var (
// ErrTxidMissing is returned if txid is not specified
// for example coinbase transactions in Bitcoin
ErrTxidMissing = errors.New("Txid missing")
// ErrTxNotFound is returned if transaction was not found
ErrTxNotFound = errors.New("Tx not found")
)
// Outpoint is txid together with output (or input) index
@ -256,7 +258,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
GetAddrDescForUnknownInput(tx *Tx, input int) AddressDescriptor
// blocks
PackBlockHash(hash string) ([]byte, error)
UnpackBlockHash(buf []byte) (string, error)

View File

@ -491,7 +491,7 @@ func (d *RocksDB) processAddressesBitcoinType(block *bchain.Block, addresses add
}
if ita == nil {
// 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)
tai.AddrDesc = d.chainParser.GetAddrDescForUnknownInput(tx, i)
continue
}
txAddressesMap[stxID] = ita

View File

@ -19,7 +19,7 @@ import (
"github.com/golang/glog"
"github.com/martinboehm/btcutil/chaincfg"
"github.com/martinboehm/golang-socketio"
gosocketio "github.com/martinboehm/golang-socketio"
"github.com/martinboehm/golang-socketio/transport"
)
@ -388,7 +388,7 @@ func httpTests_BitcoinType(t *testing.T, ts *httptest.Server) {
status: http.StatusBadRequest,
contentType: "application/json; charset=utf-8",
body: []string{
`{"error":"Tx not found, Not found"}`,
`{"error":"Transaction '1232e48aeabdd9b75def7b48d756ba304713c2aba7b522bf9dbc893fc4231b07' not found"}`,
},
},
{
@ -406,7 +406,7 @@ func httpTests_BitcoinType(t *testing.T, ts *httptest.Server) {
status: http.StatusBadRequest,
contentType: "application/json; charset=utf-8",
body: []string{
`{"error":"Tx not found, Not found"}`,
`{"error":"Transaction '1232e48aeabdd9b75def7b48d756ba304713c2aba7b522bf9dbc893fc4231b07' not found"}`,
},
},
{

View File

@ -138,7 +138,7 @@ func (c *fakeBlockChain) GetTransaction(txid string) (v *bchain.Tx, err error) {
if v != nil {
return v, nil
}
return nil, errors.New("Not found")
return nil, bchain.ErrTxNotFound
}
func (c *fakeBlockChain) GetTransactionSpecific(tx *bchain.Tx) (v json.RawMessage, err error) {

View File

@ -11,7 +11,7 @@ import (
"testing"
"time"
"github.com/deckarep/golang-set"
mapset "github.com/deckarep/golang-set"
"github.com/juju/errors"
)
@ -351,7 +351,7 @@ func getTxid2addrs(t *testing.T, h *TestHandler, txs []string) map[string][]stri
for i := range txs {
tx, err := h.Chain.GetTransactionForMempool(txs[i])
if err != nil {
if isMissingTx(err) {
if err == bchain.ErrTxNotFound {
continue
}
t.Fatal(err)
@ -370,20 +370,6 @@ func getTxid2addrs(t *testing.T, h *TestHandler, txs []string) map[string][]stri
return txid2addrs
}
func isMissingTx(err error) bool {
switch e1 := err.(type) {
case *errors.Err:
switch e2 := e1.Cause().(type) {
case *bchain.RPCError:
if e2.Code == -5 { // "No such mempool or blockchain transaction"
return true
}
}
}
return false
}
func intersect(a, b []string) []string {
setA := mapset.NewSet()
for _, v := range a {