mirror of
https://github.com/btcsuite/btcd.git
synced 2024-11-19 01:40:07 +01:00
rpcserver+mempool: implement gettxspendingprevout
for btcd
This commit adds the RPC method `gettxspendingprevout` for btcd.
This commit is contained in:
parent
dd31767617
commit
72bbdd55a6
@ -117,5 +117,9 @@ func (m *MockTxMempool) CheckMempoolAcceptance(
|
||||
func (m *MockTxMempool) CheckSpend(op wire.OutPoint) *btcutil.Tx {
|
||||
args := m.Called(op)
|
||||
|
||||
if args.Get(0) == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return args.Get(0).(*btcutil.Tx)
|
||||
}
|
||||
|
44
rpcserver.go
44
rpcserver.go
@ -185,6 +185,7 @@ var rpcHandlersBeforeInit = map[string]commandHandler{
|
||||
"verifymessage": handleVerifyMessage,
|
||||
"version": handleVersion,
|
||||
"testmempoolaccept": handleTestMempoolAccept,
|
||||
"gettxspendingprevout": handleGetTxSpendingPrevOut,
|
||||
}
|
||||
|
||||
// list of commands that we recognize, but for which btcd has no support because
|
||||
@ -3906,6 +3907,49 @@ func handleTestMempoolAccept(s *rpcServer, cmd interface{},
|
||||
return results, nil
|
||||
}
|
||||
|
||||
// handleGetTxSpendingPrevOut implements the gettxspendingprevout command.
|
||||
func handleGetTxSpendingPrevOut(s *rpcServer, cmd interface{},
|
||||
closeChan <-chan struct{}) (interface{}, error) {
|
||||
|
||||
c := cmd.(*btcjson.GetTxSpendingPrevOutCmd)
|
||||
|
||||
// Convert the outpoints.
|
||||
ops := make([]wire.OutPoint, 0, len(c.Outputs))
|
||||
for _, o := range c.Outputs {
|
||||
hash, err := chainhash.NewHashFromStr(o.Txid)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ops = append(ops, wire.OutPoint{
|
||||
Hash: *hash,
|
||||
Index: o.Vout,
|
||||
})
|
||||
}
|
||||
|
||||
// Check mempool spend for all the outpoints.
|
||||
results := make([]*btcjson.GetTxSpendingPrevOutResult, 0, len(ops))
|
||||
for _, op := range ops {
|
||||
// Create a result entry.
|
||||
result := &btcjson.GetTxSpendingPrevOutResult{
|
||||
Txid: op.Hash.String(),
|
||||
Vout: op.Index,
|
||||
}
|
||||
|
||||
// Check the mempool spend.
|
||||
spendingTx := s.cfg.TxMemPool.CheckSpend(op)
|
||||
|
||||
// Set the spending txid if found.
|
||||
if spendingTx != nil {
|
||||
result.SpendingTxid = spendingTx.Hash().String()
|
||||
}
|
||||
|
||||
results = append(results, result)
|
||||
}
|
||||
|
||||
return results, nil
|
||||
}
|
||||
|
||||
// validateFeeRate checks that the fee rate used by transaction doesn't exceed
|
||||
// the max fee rate specified.
|
||||
func validateFeeRate(feeSats btcutil.Amount, txSize int64,
|
||||
|
@ -9,6 +9,7 @@ import (
|
||||
"github.com/btcsuite/btcd/btcutil"
|
||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
||||
"github.com/btcsuite/btcd/mempool"
|
||||
"github.com/btcsuite/btcd/wire"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
@ -411,3 +412,86 @@ func TestHandleTestMempoolAcceptFees(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestGetTxSpendingPrevOut checks that handleGetTxSpendingPrevOut handles the
|
||||
// cmd as expected.
|
||||
func TestGetTxSpendingPrevOut(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
require := require.New(t)
|
||||
|
||||
// Create a mock mempool.
|
||||
mm := &mempool.MockTxMempool{}
|
||||
defer mm.AssertExpectations(t)
|
||||
|
||||
// Create a testing server with the mock mempool.
|
||||
s := &rpcServer{cfg: rpcserverConfig{
|
||||
TxMemPool: mm,
|
||||
}}
|
||||
|
||||
// First, check the error case.
|
||||
//
|
||||
// Create a request that will cause an error.
|
||||
cmd := &btcjson.GetTxSpendingPrevOutCmd{
|
||||
Outputs: []*btcjson.GetTxSpendingPrevOutCmdOutput{
|
||||
{Txid: "invalid"},
|
||||
},
|
||||
}
|
||||
|
||||
// Call the method handler and assert the error is returned.
|
||||
closeChan := make(chan struct{})
|
||||
results, err := handleGetTxSpendingPrevOut(s, cmd, closeChan)
|
||||
require.Error(err)
|
||||
require.Nil(results)
|
||||
|
||||
// We now check the normal case. Two outputs will be tested - one found
|
||||
// in mempool and other not.
|
||||
//
|
||||
// Decode the hex so we can assert the mock mempool is called with it.
|
||||
tx := decodeTxHex(t, txHex1)
|
||||
|
||||
// Create testing outpoints.
|
||||
opInMempool := wire.OutPoint{Hash: chainhash.Hash{1}, Index: 1}
|
||||
opNotInMempool := wire.OutPoint{Hash: chainhash.Hash{2}, Index: 1}
|
||||
|
||||
// We only expect to see one output being found as spent in mempool.
|
||||
expectedResults := []*btcjson.GetTxSpendingPrevOutResult{
|
||||
{
|
||||
Txid: opInMempool.Hash.String(),
|
||||
Vout: opInMempool.Index,
|
||||
SpendingTxid: tx.Hash().String(),
|
||||
},
|
||||
{
|
||||
Txid: opNotInMempool.Hash.String(),
|
||||
Vout: opNotInMempool.Index,
|
||||
},
|
||||
}
|
||||
|
||||
// We mock the first call to `CheckSpend` to return a result saying the
|
||||
// output is found.
|
||||
mm.On("CheckSpend", opInMempool).Return(tx).Once()
|
||||
|
||||
// We mock the second call to `CheckSpend` to return a result saying the
|
||||
// output is NOT found.
|
||||
mm.On("CheckSpend", opNotInMempool).Return(nil).Once()
|
||||
|
||||
// Create a request with the above outputs.
|
||||
cmd = &btcjson.GetTxSpendingPrevOutCmd{
|
||||
Outputs: []*btcjson.GetTxSpendingPrevOutCmdOutput{
|
||||
{
|
||||
Txid: opInMempool.Hash.String(),
|
||||
Vout: opInMempool.Index,
|
||||
},
|
||||
{
|
||||
Txid: opNotInMempool.Hash.String(),
|
||||
Vout: opNotInMempool.Index,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
// Call the method handler and assert the expected result is returned.
|
||||
closeChan = make(chan struct{})
|
||||
results, err = handleGetTxSpendingPrevOut(s, cmd, closeChan)
|
||||
require.NoError(err)
|
||||
require.Equal(expectedResults, results)
|
||||
}
|
||||
|
@ -734,6 +734,17 @@ var helpDescsEnUS = map[string]string{
|
||||
"testmempoolacceptfees-base": "Transaction fees (only present if 'allowed' is true).",
|
||||
"testmempoolacceptfees-effective-feerate": "The effective feerate in BTC per KvB.",
|
||||
"testmempoolacceptfees-effective-includes": "Transactions whose fees and vsizes are included in effective-feerate. Each item is a transaction wtxid in hex.",
|
||||
|
||||
// GetTxSpendingPrevOutCmd help.
|
||||
"gettxspendingprevout--synopsis": "Scans the mempool to find transactions spending any of the given outputs",
|
||||
"gettxspendingprevout-outputs": "The transaction outputs that we want to check, and within each, the txid (string) vout (numeric).",
|
||||
"gettxspendingprevout-txid": "The transaction id",
|
||||
"gettxspendingprevout-vout": "The output number",
|
||||
|
||||
// GetTxSpendingPrevOutCmd result help.
|
||||
"gettxspendingprevoutresult-txid": "The transaction hash in hex.",
|
||||
"gettxspendingprevoutresult-vout": "The output index.",
|
||||
"gettxspendingprevoutresult-spendingtxid": "The hash of the transaction that spends the output.",
|
||||
}
|
||||
|
||||
// rpcResultTypes specifies the result types that each RPC command can return.
|
||||
@ -790,6 +801,7 @@ var rpcResultTypes = map[string][]interface{}{
|
||||
"verifymessage": {(*bool)(nil)},
|
||||
"version": {(*map[string]btcjson.VersionResult)(nil)},
|
||||
"testmempoolaccept": {(*[]btcjson.TestMempoolAcceptResult)(nil)},
|
||||
"gettxspendingprevout": {(*[]btcjson.GetTxSpendingPrevOutResult)(nil)},
|
||||
|
||||
// Websocket commands.
|
||||
"loadtxfilter": nil,
|
||||
|
Loading…
Reference in New Issue
Block a user