diff --git a/btcjson/chainsvrcmds.go b/btcjson/chainsvrcmds.go index 58fa8cd1..956b4db6 100644 --- a/btcjson/chainsvrcmds.go +++ b/btcjson/chainsvrcmds.go @@ -1064,6 +1064,38 @@ func NewTestMempoolAcceptCmd(rawTxns []string, } } +// GetTxSpendingPrevOutCmd defines the gettxspendingprevout JSON-RPC command. +type GetTxSpendingPrevOutCmd struct { + // Outputs is a list of transaction outputs to query. + Outputs []*GetTxSpendingPrevOutCmdOutput +} + +// GetTxSpendingPrevOutCmdOutput defines the output to query for the +// gettxspendingprevout JSON-RPC command. +type GetTxSpendingPrevOutCmdOutput struct { + Txid string `json:"txid"` + Vout uint32 `json:"vout"` +} + +// NewGetTxSpendingPrevOutCmd returns a new instance which can be used to issue +// a gettxspendingprevout JSON-RPC command. +func NewGetTxSpendingPrevOutCmd( + outpoints []wire.OutPoint) *GetTxSpendingPrevOutCmd { + + outputs := make([]*GetTxSpendingPrevOutCmdOutput, 0, len(outpoints)) + + for _, op := range outpoints { + outputs = append(outputs, &GetTxSpendingPrevOutCmdOutput{ + Txid: op.Hash.String(), + Vout: op.Index, + }) + } + + return &GetTxSpendingPrevOutCmd{ + Outputs: outputs, + } +} + func init() { // No special flags for commands in this file. flags := UsageFlag(0) @@ -1125,4 +1157,5 @@ func init() { MustRegisterCmd("verifymessage", (*VerifyMessageCmd)(nil), flags) MustRegisterCmd("verifytxoutproof", (*VerifyTxOutProofCmd)(nil), flags) MustRegisterCmd("testmempoolaccept", (*TestMempoolAcceptCmd)(nil), flags) + MustRegisterCmd("gettxspendingprevout", (*GetTxSpendingPrevOutCmd)(nil), flags) } diff --git a/btcjson/chainsvrcmds_test.go b/btcjson/chainsvrcmds_test.go index eddfb037..d3143a52 100644 --- a/btcjson/chainsvrcmds_test.go +++ b/btcjson/chainsvrcmds_test.go @@ -13,6 +13,7 @@ import ( "testing" "github.com/btcsuite/btcd/btcjson" + "github.com/btcsuite/btcd/chaincfg/chainhash" "github.com/btcsuite/btcd/wire" ) @@ -1500,6 +1501,29 @@ func TestChainSvrCmds(t *testing.T) { MaxFeeRate: 0.01, }, }, + { + name: "gettxspendingprevout", + newCmd: func() (interface{}, error) { + return btcjson.NewCmd( + "gettxspendingprevout", + []*btcjson.GetTxSpendingPrevOutCmdOutput{ + {Txid: "0000000000000000000000000000000000000000000000000000000000000001", Vout: 0}, + }) + }, + staticCmd: func() interface{} { + outputs := []wire.OutPoint{ + {Hash: chainhash.Hash{1}, Index: 0}, + } + return btcjson.NewGetTxSpendingPrevOutCmd(outputs) + }, + marshalled: `{"jsonrpc":"1.0","method":"gettxspendingprevout","params":[[{"txid":"0000000000000000000000000000000000000000000000000000000000000001","vout":0}]],"id":1}`, + unmarshalled: &btcjson.GetTxSpendingPrevOutCmd{ + Outputs: []*btcjson.GetTxSpendingPrevOutCmdOutput{{ + Txid: "0000000000000000000000000000000000000000000000000000000000000001", + Vout: 0, + }}, + }, + }, } t.Logf("Running %d tests", len(tests)) diff --git a/btcjson/chainsvrresults.go b/btcjson/chainsvrresults.go index 8f59f776..11c0483d 100644 --- a/btcjson/chainsvrresults.go +++ b/btcjson/chainsvrresults.go @@ -911,3 +911,17 @@ type TestMempoolAcceptFees struct { // NOTE: this field only exists in bitcoind v25.0 and above. EffectiveIncludes []string `json:"effective-includes"` } + +// GetTxSpendingPrevOutResult defines a single item returned from the +// gettxspendingprevout command. +type GetTxSpendingPrevOutResult struct { + // Txid is the transaction id of the checked output. + Txid string `json:"txid"` + + // Vout is the vout value of the checked output. + Vout uint32 `json:"vout"` + + // SpendingTxid is the transaction id of the mempool transaction + // spending this output (omitted if unspent). + SpendingTxid string `json:"spendingtxid,omitempty"` +}