chainntnfs: include transaction in confirmation details

This commit is contained in:
Wilmer Paulino 2018-12-10 18:24:04 -08:00
parent 5ab30cf7ea
commit 50650d054e
No known key found for this signature in database
GPG Key ID: 6DF57B9F9514972F
6 changed files with 83 additions and 31 deletions

@ -1,6 +1,8 @@
package bitcoindnotify package bitcoindnotify
import ( import (
"bytes"
"encoding/hex"
"errors" "errors"
"fmt" "fmt"
"strings" "strings"
@ -462,7 +464,7 @@ func (b *BitcoindNotifier) confDetailsFromTxIndex(txid *chainhash.Hash,
// If the transaction has some or all of its confirmations required, // If the transaction has some or all of its confirmations required,
// then we may be able to dispatch it immediately. // then we may be able to dispatch it immediately.
tx, err := b.chainConn.GetRawTransactionVerbose(txid) rawTxRes, err := b.chainConn.GetRawTransactionVerbose(txid)
if err != nil { if err != nil {
// If the transaction lookup was successful, but it wasn't found // If the transaction lookup was successful, but it wasn't found
// within the index itself, then we can exit early. We'll also // within the index itself, then we can exit early. We'll also
@ -483,18 +485,18 @@ func (b *BitcoindNotifier) confDetailsFromTxIndex(txid *chainhash.Hash,
// Make sure we actually retrieved a transaction that is included in a // Make sure we actually retrieved a transaction that is included in a
// block. If not, the transaction must be unconfirmed (in the mempool), // block. If not, the transaction must be unconfirmed (in the mempool),
// and we'll return TxFoundMempool together with a nil TxConfirmation. // and we'll return TxFoundMempool together with a nil TxConfirmation.
if tx.BlockHash == "" { if rawTxRes.BlockHash == "" {
return nil, chainntnfs.TxFoundMempool, nil return nil, chainntnfs.TxFoundMempool, nil
} }
// As we need to fully populate the returned TxConfirmation struct, // As we need to fully populate the returned TxConfirmation struct,
// grab the block in which the transaction was confirmed so we can // grab the block in which the transaction was confirmed so we can
// locate its exact index within the block. // locate its exact index within the block.
blockHash, err := chainhash.NewHashFromStr(tx.BlockHash) blockHash, err := chainhash.NewHashFromStr(rawTxRes.BlockHash)
if err != nil { if err != nil {
return nil, chainntnfs.TxNotFoundIndex, return nil, chainntnfs.TxNotFoundIndex,
fmt.Errorf("unable to get block hash %v for "+ fmt.Errorf("unable to get block hash %v for "+
"historical dispatch: %v", tx.BlockHash, err) "historical dispatch: %v", rawTxRes.BlockHash, err)
} }
block, err := b.chainConn.GetBlockVerbose(blockHash) block, err := b.chainConn.GetBlockVerbose(blockHash)
@ -506,23 +508,39 @@ func (b *BitcoindNotifier) confDetailsFromTxIndex(txid *chainhash.Hash,
// If the block was obtained, locate the transaction's index within the // If the block was obtained, locate the transaction's index within the
// block so we can give the subscriber full confirmation details. // block so we can give the subscriber full confirmation details.
targetTxidStr := txid.String() txidStr := txid.String()
for txIndex, txHash := range block.Tx { for txIndex, txHash := range block.Tx {
if txHash == targetTxidStr { if txHash != txidStr {
details := &chainntnfs.TxConfirmation{ continue
BlockHash: blockHash,
BlockHeight: uint32(block.Height),
TxIndex: uint32(txIndex),
}
return details, chainntnfs.TxFoundIndex, nil
} }
// Deserialize the hex-encoded transaction to include it in the
// confirmation details.
rawTx, err := hex.DecodeString(rawTxRes.Hex)
if err != nil {
return nil, chainntnfs.TxFoundIndex,
fmt.Errorf("unable to deserialize tx %v: %v",
txHash, err)
}
var tx wire.MsgTx
if err := tx.Deserialize(bytes.NewReader(rawTx)); err != nil {
return nil, chainntnfs.TxFoundIndex,
fmt.Errorf("unable to deserialize tx %v: %v",
txHash, err)
}
return &chainntnfs.TxConfirmation{
Tx: &tx,
BlockHash: blockHash,
BlockHeight: uint32(block.Height),
TxIndex: uint32(txIndex),
}, chainntnfs.TxFoundIndex, nil
} }
// We return an error because we should have found the transaction // We return an error because we should have found the transaction
// within the block, but didn't. // within the block, but didn't.
return nil, chainntnfs.TxNotFoundIndex, return nil, chainntnfs.TxNotFoundIndex, fmt.Errorf("unable to locate "+
fmt.Errorf("unable to locate tx %v in block %v", txid, "tx %v in block %v", txid, blockHash)
blockHash)
} }
// confDetailsManually looks up whether a transaction/output script has already // confDetailsManually looks up whether a transaction/output script has already
@ -568,6 +586,7 @@ func (b *BitcoindNotifier) confDetailsManually(confRequest chainntnfs.ConfReques
} }
return &chainntnfs.TxConfirmation{ return &chainntnfs.TxConfirmation{
Tx: tx,
BlockHash: blockHash, BlockHash: blockHash,
BlockHeight: height, BlockHeight: height,
TxIndex: uint32(txIndex), TxIndex: uint32(txIndex),

@ -1,6 +1,8 @@
package btcdnotify package btcdnotify
import ( import (
"bytes"
"encoding/hex"
"errors" "errors"
"fmt" "fmt"
"strings" "strings"
@ -514,7 +516,7 @@ func (b *BtcdNotifier) confDetailsFromTxIndex(txid *chainhash.Hash,
// If the transaction has some or all of its confirmations required, // If the transaction has some or all of its confirmations required,
// then we may be able to dispatch it immediately. // then we may be able to dispatch it immediately.
tx, err := b.chainConn.GetRawTransactionVerbose(txid) rawTxRes, err := b.chainConn.GetRawTransactionVerbose(txid)
if err != nil { if err != nil {
// If the transaction lookup was successful, but it wasn't found // If the transaction lookup was successful, but it wasn't found
// within the index itself, then we can exit early. We'll also // within the index itself, then we can exit early. We'll also
@ -535,20 +537,19 @@ func (b *BtcdNotifier) confDetailsFromTxIndex(txid *chainhash.Hash,
// Make sure we actually retrieved a transaction that is included in a // Make sure we actually retrieved a transaction that is included in a
// block. If not, the transaction must be unconfirmed (in the mempool), // block. If not, the transaction must be unconfirmed (in the mempool),
// and we'll return TxFoundMempool together with a nil TxConfirmation. // and we'll return TxFoundMempool together with a nil TxConfirmation.
if tx.BlockHash == "" { if rawTxRes.BlockHash == "" {
return nil, chainntnfs.TxFoundMempool, nil return nil, chainntnfs.TxFoundMempool, nil
} }
// As we need to fully populate the returned TxConfirmation struct, // As we need to fully populate the returned TxConfirmation struct,
// grab the block in which the transaction was confirmed so we can // grab the block in which the transaction was confirmed so we can
// locate its exact index within the block. // locate its exact index within the block.
blockHash, err := chainhash.NewHashFromStr(tx.BlockHash) blockHash, err := chainhash.NewHashFromStr(rawTxRes.BlockHash)
if err != nil { if err != nil {
return nil, chainntnfs.TxNotFoundIndex, return nil, chainntnfs.TxNotFoundIndex,
fmt.Errorf("unable to get block hash %v for "+ fmt.Errorf("unable to get block hash %v for "+
"historical dispatch: %v", tx.BlockHash, err) "historical dispatch: %v", rawTxRes.BlockHash, err)
} }
block, err := b.chainConn.GetBlockVerbose(blockHash) block, err := b.chainConn.GetBlockVerbose(blockHash)
if err != nil { if err != nil {
return nil, chainntnfs.TxNotFoundIndex, return nil, chainntnfs.TxNotFoundIndex,
@ -558,23 +559,39 @@ func (b *BtcdNotifier) confDetailsFromTxIndex(txid *chainhash.Hash,
// If the block was obtained, locate the transaction's index within the // If the block was obtained, locate the transaction's index within the
// block so we can give the subscriber full confirmation details. // block so we can give the subscriber full confirmation details.
targetTxidStr := txid.String() txidStr := txid.String()
for txIndex, txHash := range block.Tx { for txIndex, txHash := range block.Tx {
if txHash == targetTxidStr { if txHash != txidStr {
details := &chainntnfs.TxConfirmation{ continue
BlockHash: blockHash,
BlockHeight: uint32(block.Height),
TxIndex: uint32(txIndex),
}
return details, chainntnfs.TxFoundIndex, nil
} }
// Deserialize the hex-encoded transaction to include it in the
// confirmation details.
rawTx, err := hex.DecodeString(rawTxRes.Hex)
if err != nil {
return nil, chainntnfs.TxFoundIndex,
fmt.Errorf("unable to deserialize tx %v: %v",
txHash, err)
}
var tx wire.MsgTx
if err := tx.Deserialize(bytes.NewReader(rawTx)); err != nil {
return nil, chainntnfs.TxFoundIndex,
fmt.Errorf("unable to deserialize tx %v: %v",
txHash, err)
}
return &chainntnfs.TxConfirmation{
Tx: &tx,
BlockHash: blockHash,
BlockHeight: uint32(block.Height),
TxIndex: uint32(txIndex),
}, chainntnfs.TxFoundIndex, nil
} }
// We return an error because we should have found the transaction // We return an error because we should have found the transaction
// within the block, but didn't. // within the block, but didn't.
return nil, chainntnfs.TxNotFoundIndex, return nil, chainntnfs.TxNotFoundIndex, fmt.Errorf("unable to locate "+
fmt.Errorf("unable to locate tx %v in block %v", txid, "tx %v in block %v", txid, blockHash)
blockHash)
} }
// confDetailsManually looks up whether a transaction/output script has already // confDetailsManually looks up whether a transaction/output script has already
@ -621,6 +638,7 @@ func (b *BtcdNotifier) confDetailsManually(confRequest chainntnfs.ConfRequest,
} }
return &chainntnfs.TxConfirmation{ return &chainntnfs.TxConfirmation{
Tx: tx,
BlockHash: blockHash, BlockHash: blockHash,
BlockHeight: height, BlockHeight: height,
TxIndex: uint32(txIndex), TxIndex: uint32(txIndex),

@ -150,6 +150,9 @@ type TxConfirmation struct {
// TxIndex is the index within the block of the ultimate confirmed // TxIndex is the index within the block of the ultimate confirmed
// transaction. // transaction.
TxIndex uint32 TxIndex uint32
// Tx is the transaction for which the notification was requested for.
Tx *wire.MsgTx
} }
// ConfirmationEvent encapsulates a confirmation notification. With this struct, // ConfirmationEvent encapsulates a confirmation notification. With this struct,

@ -563,6 +563,7 @@ func (n *NeutrinoNotifier) historicalConfDetails(confRequest chainntnfs.ConfRequ
} }
return &chainntnfs.TxConfirmation{ return &chainntnfs.TxConfirmation{
Tx: tx.MsgTx(),
BlockHash: blockHash, BlockHash: blockHash,
BlockHeight: scanHeight, BlockHeight: scanHeight,
TxIndex: uint32(i), TxIndex: uint32(i),

@ -1226,6 +1226,7 @@ func (n *TxNotifier) filterTx(tx *btcutil.Tx, blockHash *chainhash.Hash,
blockHeight, blockHash) blockHeight, blockHash)
details := &TxConfirmation{ details := &TxConfirmation{
Tx: tx.MsgTx(),
BlockHash: blockHash, BlockHash: blockHash,
BlockHeight: blockHeight, BlockHeight: blockHeight,
TxIndex: uint32(tx.Index()), TxIndex: uint32(tx.Index()),

@ -256,6 +256,7 @@ func TestTxNotifierFutureConfDispatch(t *testing.T) {
BlockHash: block1.Hash(), BlockHash: block1.Hash(),
BlockHeight: 11, BlockHeight: 11,
TxIndex: 0, TxIndex: 0,
Tx: &tx1,
} }
assertConfDetails(t, txConf, &expectedConf) assertConfDetails(t, txConf, &expectedConf)
default: default:
@ -327,6 +328,7 @@ func TestTxNotifierFutureConfDispatch(t *testing.T) {
BlockHash: block1.Hash(), BlockHash: block1.Hash(),
BlockHeight: 11, BlockHeight: 11,
TxIndex: 1, TxIndex: 1,
Tx: &tx2,
} }
assertConfDetails(t, txConf, &expectedConf) assertConfDetails(t, txConf, &expectedConf)
default: default:
@ -386,6 +388,7 @@ func TestTxNotifierHistoricalConfDispatch(t *testing.T) {
BlockHash: &chainntnfs.ZeroHash, BlockHash: &chainntnfs.ZeroHash,
BlockHeight: 9, BlockHeight: 9,
TxIndex: 1, TxIndex: 1,
Tx: &tx1,
} }
err := n.UpdateConfDetails(ntfn1.ConfRequest, &txConf1) err := n.UpdateConfDetails(ntfn1.ConfRequest, &txConf1)
if err != nil { if err != nil {
@ -419,6 +422,7 @@ func TestTxNotifierHistoricalConfDispatch(t *testing.T) {
BlockHash: &chainntnfs.ZeroHash, BlockHash: &chainntnfs.ZeroHash,
BlockHeight: 9, BlockHeight: 9,
TxIndex: 2, TxIndex: 2,
Tx: &tx2,
} }
err = n.UpdateConfDetails(ntfn2.ConfRequest, &txConf2) err = n.UpdateConfDetails(ntfn2.ConfRequest, &txConf2)
if err != nil { if err != nil {
@ -1344,6 +1348,7 @@ func TestTxNotifierConfReorg(t *testing.T) {
BlockHash: block3.Hash(), BlockHash: block3.Hash(),
BlockHeight: 12, BlockHeight: 12,
TxIndex: 0, TxIndex: 0,
Tx: &tx2,
} }
assertConfDetails(t, txConf, &expectedConf) assertConfDetails(t, txConf, &expectedConf)
default: default:
@ -1374,6 +1379,7 @@ func TestTxNotifierConfReorg(t *testing.T) {
BlockHash: block3.Hash(), BlockHash: block3.Hash(),
BlockHeight: 12, BlockHeight: 12,
TxIndex: 1, TxIndex: 1,
Tx: &tx3,
} }
assertConfDetails(t, txConf, &expectedConf) assertConfDetails(t, txConf, &expectedConf)
default: default:
@ -2106,6 +2112,10 @@ func assertConfDetails(t *testing.T, result, expected *chainntnfs.TxConfirmation
t.Fatalf("Incorrect tx index in confirmation details: "+ t.Fatalf("Incorrect tx index in confirmation details: "+
"expected %d, got %d", expected.TxIndex, result.TxIndex) "expected %d, got %d", expected.TxIndex, result.TxIndex)
} }
if result.Tx.TxHash() != expected.Tx.TxHash() {
t.Fatalf("expected tx hash %v, got %v", expected.Tx.TxHash(),
result.Tx.TxHash())
}
} }
func assertSpendDetails(t *testing.T, result, expected *chainntnfs.SpendDetail) { func assertSpendDetails(t *testing.T, result, expected *chainntnfs.SpendDetail) {