adds optional prevOut section to vin for searchrawtransactions api. See https://github.com/btcsuite/btcd/issues/485
This commit is contained in:
parent
2441120b55
commit
43774fe6bb
10 changed files with 294 additions and 53 deletions
|
@ -300,7 +300,7 @@ func (b *BlockChain) fetchInputTransactions(node *blockNode, block *btcutil.Bloc
|
|||
// passed transaction from the point of view of the end of the main chain. It
|
||||
// also attempts to fetch the transaction itself so the returned TxStore can be
|
||||
// examined for duplicate transactions.
|
||||
func (b *BlockChain) FetchTransactionStore(tx *btcutil.Tx) (TxStore, error) {
|
||||
func (b *BlockChain) FetchTransactionStore(tx *btcutil.Tx, includeSpent bool) (TxStore, error) {
|
||||
// Create a set of needed transactions from the transactions referenced
|
||||
// by the inputs of the passed transaction. Also, add the passed
|
||||
// transaction itself as a way for the caller to detect duplicates.
|
||||
|
@ -311,9 +311,8 @@ func (b *BlockChain) FetchTransactionStore(tx *btcutil.Tx) (TxStore, error) {
|
|||
}
|
||||
|
||||
// Request the input transactions from the point of view of the end of
|
||||
// the main chain without including fully spent trasactions in the
|
||||
// results. Fully spent transactions are only needed for chain
|
||||
// reorganization which does not apply here.
|
||||
txStore := fetchTxStoreMain(b.db, txNeededSet, false)
|
||||
// the main chain with or without without including fully spent transactions
|
||||
// in the results.
|
||||
txStore := fetchTxStoreMain(b.db, txNeededSet, includeSpent)
|
||||
return txStore, nil
|
||||
}
|
||||
|
|
|
@ -1119,7 +1119,7 @@ out:
|
|||
}
|
||||
|
||||
case fetchTransactionStoreMsg:
|
||||
txStore, err := b.blockChain.FetchTransactionStore(msg.tx)
|
||||
txStore, err := b.blockChain.FetchTransactionStore(msg.tx, false)
|
||||
msg.reply <- fetchTransactionStoreResponse{
|
||||
TxStore: txStore,
|
||||
err: err,
|
||||
|
|
|
@ -545,10 +545,11 @@ func NewReconsiderBlockCmd(blockHash string) *ReconsiderBlockCmd {
|
|||
|
||||
// SearchRawTransactionsCmd defines the searchrawtransactions JSON-RPC command.
|
||||
type SearchRawTransactionsCmd struct {
|
||||
Address string
|
||||
Verbose *int `jsonrpcdefault:"1"`
|
||||
Skip *int `jsonrpcdefault:"0"`
|
||||
Count *int `jsonrpcdefault:"100"`
|
||||
Address string
|
||||
Verbose *int `jsonrpcdefault:"1"`
|
||||
Skip *int `jsonrpcdefault:"0"`
|
||||
Count *int `jsonrpcdefault:"100"`
|
||||
VinExtra *int `jsonrpcdefault:"0"`
|
||||
}
|
||||
|
||||
// NewSearchRawTransactionsCmd returns a new instance which can be used to issue a
|
||||
|
@ -556,12 +557,13 @@ type SearchRawTransactionsCmd struct {
|
|||
//
|
||||
// The parameters which are pointers indicate they are optional. Passing nil
|
||||
// for optional parameters will use the default value.
|
||||
func NewSearchRawTransactionsCmd(address string, verbose, skip, count *int) *SearchRawTransactionsCmd {
|
||||
func NewSearchRawTransactionsCmd(address string, verbose, skip, count *int, vinExtra *int) *SearchRawTransactionsCmd {
|
||||
return &SearchRawTransactionsCmd{
|
||||
Address: address,
|
||||
Verbose: verbose,
|
||||
Skip: skip,
|
||||
Count: count,
|
||||
Address: address,
|
||||
Verbose: verbose,
|
||||
Skip: skip,
|
||||
Count: count,
|
||||
VinExtra: vinExtra,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -679,14 +679,15 @@ func TestChainSvrCmds(t *testing.T) {
|
|||
return btcjson.NewCmd("searchrawtransactions", "1Address")
|
||||
},
|
||||
staticCmd: func() interface{} {
|
||||
return btcjson.NewSearchRawTransactionsCmd("1Address", nil, nil, nil)
|
||||
return btcjson.NewSearchRawTransactionsCmd("1Address", nil, nil, nil, nil)
|
||||
},
|
||||
marshalled: `{"jsonrpc":"1.0","method":"searchrawtransactions","params":["1Address"],"id":1}`,
|
||||
unmarshalled: &btcjson.SearchRawTransactionsCmd{
|
||||
Address: "1Address",
|
||||
Verbose: btcjson.Int(1),
|
||||
Skip: btcjson.Int(0),
|
||||
Count: btcjson.Int(100),
|
||||
Address: "1Address",
|
||||
Verbose: btcjson.Int(1),
|
||||
Skip: btcjson.Int(0),
|
||||
Count: btcjson.Int(100),
|
||||
VinExtra: btcjson.Int(0),
|
||||
},
|
||||
},
|
||||
{
|
||||
|
@ -696,14 +697,15 @@ func TestChainSvrCmds(t *testing.T) {
|
|||
},
|
||||
staticCmd: func() interface{} {
|
||||
return btcjson.NewSearchRawTransactionsCmd("1Address",
|
||||
btcjson.Int(0), nil, nil)
|
||||
btcjson.Int(0), nil, nil, nil)
|
||||
},
|
||||
marshalled: `{"jsonrpc":"1.0","method":"searchrawtransactions","params":["1Address",0],"id":1}`,
|
||||
unmarshalled: &btcjson.SearchRawTransactionsCmd{
|
||||
Address: "1Address",
|
||||
Verbose: btcjson.Int(0),
|
||||
Skip: btcjson.Int(0),
|
||||
Count: btcjson.Int(100),
|
||||
Address: "1Address",
|
||||
Verbose: btcjson.Int(0),
|
||||
Skip: btcjson.Int(0),
|
||||
Count: btcjson.Int(100),
|
||||
VinExtra: btcjson.Int(0),
|
||||
},
|
||||
},
|
||||
{
|
||||
|
@ -713,14 +715,15 @@ func TestChainSvrCmds(t *testing.T) {
|
|||
},
|
||||
staticCmd: func() interface{} {
|
||||
return btcjson.NewSearchRawTransactionsCmd("1Address",
|
||||
btcjson.Int(0), btcjson.Int(5), nil)
|
||||
btcjson.Int(0), btcjson.Int(5), nil, nil)
|
||||
},
|
||||
marshalled: `{"jsonrpc":"1.0","method":"searchrawtransactions","params":["1Address",0,5],"id":1}`,
|
||||
unmarshalled: &btcjson.SearchRawTransactionsCmd{
|
||||
Address: "1Address",
|
||||
Verbose: btcjson.Int(0),
|
||||
Skip: btcjson.Int(5),
|
||||
Count: btcjson.Int(100),
|
||||
Address: "1Address",
|
||||
Verbose: btcjson.Int(0),
|
||||
Skip: btcjson.Int(5),
|
||||
Count: btcjson.Int(100),
|
||||
VinExtra: btcjson.Int(0),
|
||||
},
|
||||
},
|
||||
{
|
||||
|
@ -730,14 +733,33 @@ func TestChainSvrCmds(t *testing.T) {
|
|||
},
|
||||
staticCmd: func() interface{} {
|
||||
return btcjson.NewSearchRawTransactionsCmd("1Address",
|
||||
btcjson.Int(0), btcjson.Int(5), btcjson.Int(10))
|
||||
btcjson.Int(0), btcjson.Int(5), btcjson.Int(10), nil)
|
||||
},
|
||||
marshalled: `{"jsonrpc":"1.0","method":"searchrawtransactions","params":["1Address",0,5,10],"id":1}`,
|
||||
unmarshalled: &btcjson.SearchRawTransactionsCmd{
|
||||
Address: "1Address",
|
||||
Verbose: btcjson.Int(0),
|
||||
Skip: btcjson.Int(5),
|
||||
Count: btcjson.Int(10),
|
||||
Address: "1Address",
|
||||
Verbose: btcjson.Int(0),
|
||||
Skip: btcjson.Int(5),
|
||||
Count: btcjson.Int(10),
|
||||
VinExtra: btcjson.Int(0),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "searchrawtransactions",
|
||||
newCmd: func() (interface{}, error) {
|
||||
return btcjson.NewCmd("searchrawtransactions", "1Address", 0, 5, 10, 1)
|
||||
},
|
||||
staticCmd: func() interface{} {
|
||||
return btcjson.NewSearchRawTransactionsCmd("1Address",
|
||||
btcjson.Int(0), btcjson.Int(5), btcjson.Int(10), btcjson.Int(1))
|
||||
},
|
||||
marshalled: `{"jsonrpc":"1.0","method":"searchrawtransactions","params":["1Address",0,5,10,1],"id":1}`,
|
||||
unmarshalled: &btcjson.SearchRawTransactionsCmd{
|
||||
Address: "1Address",
|
||||
Verbose: btcjson.Int(0),
|
||||
Skip: btcjson.Int(5),
|
||||
Count: btcjson.Int(10),
|
||||
VinExtra: btcjson.Int(1),
|
||||
},
|
||||
},
|
||||
{
|
||||
|
|
|
@ -272,6 +272,56 @@ func (v *Vin) MarshalJSON() ([]byte, error) {
|
|||
return json.Marshal(txStruct)
|
||||
}
|
||||
|
||||
// PrevOut represents previous output for an input Vin.
|
||||
type PrevOut struct {
|
||||
Addresses []string `json:"addresses,omitempty"`
|
||||
Value float64 `json:"value"`
|
||||
}
|
||||
|
||||
// VinPrevOut is like Vin except it includes PrevOut. It is used by searchrawtransaction
|
||||
type VinPrevOut struct {
|
||||
Coinbase string `json:"coinbase"`
|
||||
Txid string `json:"txid"`
|
||||
Vout uint32 `json:"vout"`
|
||||
ScriptSig *ScriptSig `json:"scriptSig"`
|
||||
PrevOut *PrevOut `json:"prevOut"`
|
||||
Sequence uint32 `json:"sequence"`
|
||||
}
|
||||
|
||||
// IsCoinBase returns a bool to show if a Vin is a Coinbase one or not.
|
||||
func (v *VinPrevOut) IsCoinBase() bool {
|
||||
return len(v.Coinbase) > 0
|
||||
}
|
||||
|
||||
// MarshalJSON provides a custom Marshal method for VinPrevOut.
|
||||
func (v *VinPrevOut) MarshalJSON() ([]byte, error) {
|
||||
if v.IsCoinBase() {
|
||||
coinbaseStruct := struct {
|
||||
Coinbase string `json:"coinbase"`
|
||||
Sequence uint32 `json:"sequence"`
|
||||
}{
|
||||
Coinbase: v.Coinbase,
|
||||
Sequence: v.Sequence,
|
||||
}
|
||||
return json.Marshal(coinbaseStruct)
|
||||
}
|
||||
|
||||
txStruct := struct {
|
||||
Txid string `json:"txid"`
|
||||
Vout uint32 `json:"vout"`
|
||||
ScriptSig *ScriptSig `json:"scriptSig"`
|
||||
PrevOut *PrevOut `json:"prevOut,omitempty"`
|
||||
Sequence uint32 `json:"sequence"`
|
||||
}{
|
||||
Txid: v.Txid,
|
||||
Vout: v.Vout,
|
||||
ScriptSig: v.ScriptSig,
|
||||
PrevOut: v.PrevOut,
|
||||
Sequence: v.Sequence,
|
||||
}
|
||||
return json.Marshal(txStruct)
|
||||
}
|
||||
|
||||
// Vout models parts of the tx data. It is defined seperately since both
|
||||
// getrawtransaction and decoderawtransaction use the same structure.
|
||||
type Vout struct {
|
||||
|
@ -332,8 +382,7 @@ type NetworksResult struct {
|
|||
Proxy string `json:"proxy"`
|
||||
}
|
||||
|
||||
// TxRawResult models the data from the getrawtransaction and
|
||||
// searchrawtransaction commands.
|
||||
// TxRawResult models the data from the getrawtransaction command.
|
||||
type TxRawResult struct {
|
||||
Hex string `json:"hex"`
|
||||
Txid string `json:"txid"`
|
||||
|
@ -347,6 +396,21 @@ type TxRawResult struct {
|
|||
Blocktime int64 `json:"blocktime,omitempty"`
|
||||
}
|
||||
|
||||
// SearchRawTransactionsResult models the data from the searchrawtransaction
|
||||
// command.
|
||||
type SearchRawTransactionsResult struct {
|
||||
Hex string `json:"hex"`
|
||||
Txid string `json:"txid"`
|
||||
Version int32 `json:"version"`
|
||||
LockTime uint32 `json:"locktime"`
|
||||
Vin []VinPrevOut `json:"vin"`
|
||||
Vout []Vout `json:"vout"`
|
||||
BlockHash string `json:"blockhash,omitempty"`
|
||||
Confirmations uint64 `json:"confirmations,omitempty"`
|
||||
Time int64 `json:"time,omitempty"`
|
||||
Blocktime int64 `json:"blocktime,omitempty"`
|
||||
}
|
||||
|
||||
// TxRawDecodeResult models the data from the decoderawtransaction command.
|
||||
type TxRawDecodeResult struct {
|
||||
Txid string `json:"txid"`
|
||||
|
|
|
@ -43,6 +43,31 @@ func TestChainSvrCustomResults(t *testing.T) {
|
|||
},
|
||||
expected: `{"txid":"123","vout":1,"scriptSig":{"asm":"0","hex":"00"},"sequence":4294967295}`,
|
||||
},
|
||||
{
|
||||
name: "custom vinprevout marshal with coinbase",
|
||||
result: &btcjson.VinPrevOut{
|
||||
Coinbase: "021234",
|
||||
Sequence: 4294967295,
|
||||
},
|
||||
expected: `{"coinbase":"021234","sequence":4294967295}`,
|
||||
},
|
||||
{
|
||||
name: "custom vinprevout marshal without coinbase",
|
||||
result: &btcjson.VinPrevOut{
|
||||
Txid: "123",
|
||||
Vout: 1,
|
||||
ScriptSig: &btcjson.ScriptSig{
|
||||
Asm: "0",
|
||||
Hex: "00",
|
||||
},
|
||||
PrevOut: &btcjson.PrevOut{
|
||||
Addresses: []string{"addr1"},
|
||||
Value: 0,
|
||||
},
|
||||
Sequence: 4294967295,
|
||||
},
|
||||
expected: `{"txid":"123","vout":1,"scriptSig":{"asm":"0","hex":"00"},"prevOut":{"addresses":["addr1"],"value":0},"sequence":4294967295}`,
|
||||
},
|
||||
}
|
||||
|
||||
t.Logf("Running %d tests", len(tests))
|
||||
|
|
|
@ -214,7 +214,7 @@ the method name for further details such as parameter and return information.
|
|||
|Method|decoderawtransaction|
|
||||
|Parameters|1. data (string, required) - serialized, hex-encoded transaction|
|
||||
|Description|Returns a JSON object representing the provided serialized, hex-encoded transaction.|
|
||||
|Returns|`{ (json object)`<br /> `"txid": "hash", (string) the hash of the transaction`<br /> `"version": n, (numeric) the transaction version`<br /> `"locktime": n, (numeric) the transaction lock time`<br /> `"vin": [ (array of json objects) the transaction inputs as json objects`<br /> <font color="orange">For coinbase transactions:</font><br /> `{ (json object)`<br /> `"coinbase": "data", (string) the hex-dencoded bytes of the signature script`<br /> `"sequence": n, (numeric) the script sequence number`<br /> `}`<br /> <font color="orange">For non-coinbase transactions:</font><br /> `{ (json object)`<br /> `"txid": "hash", (string) the hash of the origin transaction`<br /> `"vout": n, (numeric) the index of the output being redeemed from the origin transaction`<br /> `"scriptSig": { (json object) the signature script used to redeem the origin transaction`<br /> `"asm": "asm", (string) disassembly of the script`<br /> `"hex": "data", (string) hex-encoded bytes of the script`<br /> `}`<br /> `"sequence": n, (numeric) the script sequence number`<br /> `}, ...`<br /> `]`<br /> `"vout": [ (array of json objects) the transaction outputs as json objects`<br /> `{ (json object)`<br /> `"value": n, (numeric) the value in BTC`<br /> `"n": n, (numeric) the index of this transaction output`<br /> `"scriptPubKey": { (json object) the public key script used to pay coins`<br /> `"asm": "asm", (string) disassembly of the script`<br /> `"hex": "data", (string) hex-encoded bytes of the script`<br /> `"reqSigs": n, (numeric) the number of required signatures`<br /> `"type": "scripttype" (string) the type of the script (e.g. 'pubkeyhash')`<br /> `"addresses": [ (json array of string) the bitcoin addresses associated with this output`<br /> `"bitcoinaddress", (string) the bitcoin address`<br /> `...`<br /> `]`<br /> `}`<br /> `}, ...`<br /> `]`<br />`}`|
|
||||
|Returns|`{ (json object)`<br /> `"txid": "hash", (string) the hash of the transaction`<br /> `"version": n, (numeric) the transaction version`<br /> `"locktime": n, (numeric) the transaction lock time`<br /> `"vin": [ (array of json objects) the transaction inputs as json objects`<br /> <font color="orange">For coinbase transactions:</font><br /> `{ (json object)`<br /> `"coinbase": "data", (string) the hex-encoded bytes of the signature script`<br /> `"sequence": n, (numeric) the script sequence number`<br /> `}`<br /> <font color="orange">For non-coinbase transactions:</font><br /> `{ (json object)`<br /> `"txid": "hash", (string) the hash of the origin transaction`<br /> `"vout": n, (numeric) the index of the output being redeemed from the origin transaction`<br /> `"scriptSig": { (json object) the signature script used to redeem the origin transaction`<br /> `"asm": "asm", (string) disassembly of the script`<br /> `"hex": "data", (string) hex-encoded bytes of the script`<br /> `}`<br /> `"sequence": n, (numeric) the script sequence number`<br /> `}, ...`<br /> `]`<br /> `"vout": [ (array of json objects) the transaction outputs as json objects`<br /> `{ (json object)`<br /> `"value": n, (numeric) the value in BTC`<br /> `"n": n, (numeric) the index of this transaction output`<br /> `"scriptPubKey": { (json object) the public key script used to pay coins`<br /> `"asm": "asm", (string) disassembly of the script`<br /> `"hex": "data", (string) hex-encoded bytes of the script`<br /> `"reqSigs": n, (numeric) the number of required signatures`<br /> `"type": "scripttype" (string) the type of the script (e.g. 'pubkeyhash')`<br /> `"addresses": [ (json array of string) the bitcoin addresses associated with this output`<br /> `"bitcoinaddress", (string) the bitcoin address`<br /> `...`<br /> `]`<br /> `}`<br /> `}, ...`<br /> `]`<br />`}`|
|
||||
|Example Return|`{`<br /> `"txid": "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b",`<br /> `"version": 1,`<br /> `"locktime": 0,`<br /> `"vin": [`<br /> <font color="orange">For coinbase transactions:</font><br /> `{ (json object)`<br /> `"coinbase": "04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6...",`<br /> `"sequence": 4294967295,`<br /> `}`<br /> <font color="orange">For non-coinbase transactions:</font><br /> `{`<br /> `"txid": "60ac4b057247b3d0b9a8173de56b5e1be8c1d1da970511c626ef53706c66be04",`<br /> `"vout": 0,`<br /> `"scriptSig": {`<br /> `"asm": "3046022100cb42f8df44eca83dd0a727988dcde9384953e830b1f8004d57485e2ede1b9c8f0...",`<br /> `"hex": "493046022100cb42f8df44eca83dd0a727988dcde9384953e830b1f8004d57485e2ede1b9c8...",`<br /> `}`<br /> `"sequence": 4294967295,`<br /> `}`<br /> `]`<br /> `"vout": [`<br /> `{`<br /> `"value": 50,`<br /> `"n": 0,`<br /> `"scriptPubKey": {`<br /> `"asm": "04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4ce...",`<br /> `"hex": "4104678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4...",`<br /> `"reqSigs": 1,`<br /> `"type": "pubkey"`<br /> `"addresses": [`<br /> `"1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa",`<br /> `]`<br /> `}`<br /> `}`<br /> `]`<br />`}`|
|
||||
[Return to Overview](#MethodOverview)<br />
|
||||
|
||||
|
@ -437,7 +437,7 @@ Example Return|`{`<br /> `"bytes": 310768,`<br /> `"size":
|
|||
|Parameters|1. transaction hash (string, required) - the hash of the transaction<br />2. verbose (int, optional, default=0) - specifies the transaction is returned as a JSON object instead of hex-encoded string|
|
||||
|Description|Returns information about a transaction given its hash.|
|
||||
|Returns (verbose=0)|`"data" (string) hex-encoded bytes of the serialized transaction`|
|
||||
|Returns (verbose=1)|`{ (json object)`<br /> `"hex": "data", (string) hex-encoded transaction`<br /> `"txid": "hash", (string) the hash of the transaction`<br /> `"version": n, (numeric) the transaction version`<br /> `"locktime": n, (numeric) the transaction lock time`<br /> `"vin": [ (array of json objects) the transaction inputs as json objects`<br /> <font color="orange">For coinbase transactions:</font><br /> `{ (json object)`<br /> `"coinbase": "data", (string) the hex-dencoded bytes of the signature script`<br /> `"sequence": n, (numeric) the script sequence number`<br /> `}`<br /> <font color="orange">For non-coinbase transactions:</font><br /> `{ (json object)`<br /> `"txid": "hash", (string) the hash of the origin transaction`<br /> `"vout": n, (numeric) the index of the output being redeemed from the origin transaction`<br /> `"scriptSig": { (json object) the signature script used to redeem the origin transaction`<br /> `"asm": "asm", (string) disassembly of the script`<br /> `"hex": "data", (string) hex-encoded bytes of the script`<br /> `}`<br /> `"sequence": n, (numeric) the script sequence number`<br /> `}, ...`<br /> `]`<br /> `"vout": [ (array of json objects) the transaction outputs as json objects`<br /> `{ (json object)`<br /> `"value": n, (numeric) the value in BTC`<br /> `"n": n, (numeric) the index of this transaction output`<br /> `"scriptPubKey": { (json object) the public key script used to pay coins`<br /> `"asm": "asm", (string) disassembly of the script`<br /> `"hex": "data", (string) hex-encoded bytes of the script`<br /> `"reqSigs": n, (numeric) the number of required signatures`<br /> `"type": "scripttype" (string) the type of the script (e.g. 'pubkeyhash')`<br /> `"addresses": [ (json array of string) the bitcoin addresses associated with this output`<br /> `"bitcoinaddress", (string) the bitcoin address`<br /> `...`<br /> `]`<br /> `}`<br /> `}, ...`<br /> `]`<br />`}`|
|
||||
|Returns (verbose=1)|`{ (json object)`<br /> `"hex": "data", (string) hex-encoded transaction`<br /> `"txid": "hash", (string) the hash of the transaction`<br /> `"version": n, (numeric) the transaction version`<br /> `"locktime": n, (numeric) the transaction lock time`<br /> `"vin": [ (array of json objects) the transaction inputs as json objects`<br /> <font color="orange">For coinbase transactions:</font><br /> `{ (json object)`<br /> `"coinbase": "data", (string) the hex-encoded bytes of the signature script`<br /> `"sequence": n, (numeric) the script sequence number`<br /> `}`<br /> <font color="orange">For non-coinbase transactions:</font><br /> `{ (json object)`<br /> `"txid": "hash", (string) the hash of the origin transaction`<br /> `"vout": n, (numeric) the index of the output being redeemed from the origin transaction`<br /> `"scriptSig": { (json object) the signature script used to redeem the origin transaction`<br /> `"asm": "asm", (string) disassembly of the script`<br /> `"hex": "data", (string) hex-encoded bytes of the script`<br /> `}`<br /> `"sequence": n, (numeric) the script sequence number`<br /> `}, ...`<br /> `]`<br /> `"vout": [ (array of json objects) the transaction outputs as json objects`<br /> `{ (json object)`<br /> `"value": n, (numeric) the value in BTC`<br /> `"n": n, (numeric) the index of this transaction output`<br /> `"scriptPubKey": { (json object) the public key script used to pay coins`<br /> `"asm": "asm", (string) disassembly of the script`<br /> `"hex": "data", (string) hex-encoded bytes of the script`<br /> `"reqSigs": n, (numeric) the number of required signatures`<br /> `"type": "scripttype" (string) the type of the script (e.g. 'pubkeyhash')`<br /> `"addresses": [ (json array of string) the bitcoin addresses associated with this output`<br /> `"bitcoinaddress", (string) the bitcoin address`<br /> `...`<br /> `]`<br /> `}`<br /> `}, ...`<br /> `]`<br />`}`|
|
||||
|Example Return (verbose=0)|`"010000000104be666c7053ef26c6110597dad1c1e81b5e6be53d17a8b9d0b34772054bac60000000`<br />`008c493046022100cb42f8df44eca83dd0a727988dcde9384953e830b1f8004d57485e2ede1b9c8f`<br />`022100fbce8d84fcf2839127605818ac6c3e7a1531ebc69277c504599289fb1e9058df0141045a33`<br />`76eeb85e494330b03c1791619d53327441002832f4bd618fd9efa9e644d242d5e1145cb9c2f71965`<br />`656e276633d4ff1a6db5e7153a0a9042745178ebe0f5ffffffff0280841e00000000001976a91406`<br />`f1b6703d3f56427bfcfd372f952d50d04b64bd88ac4dd52700000000001976a9146b63f291c295ee`<br />`abd9aee6be193ab2d019e7ea7088ac00000000`<br /><font color="orange">**Newlines added for display purposes. The actual return does not contain newlines.**</font>|
|
||||
|Example Return (verbose=1)|`{`<br /> `"hex": "01000000010000000000000000000000000000000000000000000000000000000000000000f...",`<br /> `"txid": "90743aad855880e517270550d2a881627d84db5265142fd1e7fb7add38b08be9",`<br /> `"version": 1,`<br /> `"locktime": 0,`<br /> `"vin": [`<br /> <font color="orange">For coinbase transactions:</font><br /> `{ (json object)`<br /> `"coinbase": "03708203062f503253482f04066d605108f800080100000ea2122f6f7a636f696e4065757374726174756d2f",`<br /> `"sequence": 0,`<br /> `}`<br /> <font color="orange">For non-coinbase transactions:</font><br /> `{`<br /> `"txid": "60ac4b057247b3d0b9a8173de56b5e1be8c1d1da970511c626ef53706c66be04",`<br /> `"vout": 0,`<br /> `"scriptSig": {`<br /> `"asm": "3046022100cb42f8df44eca83dd0a727988dcde9384953e830b1f8004d57485e2ede1b9c8f0...",`<br /> `"hex": "493046022100cb42f8df44eca83dd0a727988dcde9384953e830b1f8004d57485e2ede1b9c8...",`<br /> `}`<br /> `"sequence": 4294967295,`<br /> `}`<br /> `]`<br /> `"vout": [`<br /> `{`<br /> `"value": 25.1394,`<br /> `"n": 0,`<br /> `"scriptPubKey": {`<br /> `"asm": "OP_DUP OP_HASH160 ea132286328cfc819457b9dec386c4b5c84faa5c OP_EQUALVERIFY OP_CHECKSIG",`<br /> `"hex": "76a914ea132286328cfc819457b9dec386c4b5c84faa5c88ac",`<br /> `"reqSigs": 1,`<br /> `"type": "pubkeyhash"`<br /> `"addresses": [`<br /> `"1NLg3QJMsMQGM5KEUaEu5ADDmKQSLHwmyh",`<br /> `]`<br /> `}`<br /> `}`<br /> `]`<br />`}`|
|
||||
[Return to Overview](#MethodOverview)<br />
|
||||
|
@ -632,10 +632,10 @@ The following is an overview of the RPC methods which are implemented by btcd, b
|
|||
| | |
|
||||
|---|---|
|
||||
|Method|searchrawtransactions|
|
||||
|Parameters|1. address (string, required) - bitcoin address <br /> 2. verbose (int, optional, default=true) - specifies the transaction is returned as a JSON object instead of hex-encoded string <br />3. skip (int, optional, default=0) - the number of leading transactions to leave out of the final response <br /> 4. count (int, optional, default=100) - the maximum number of transactions to return|
|
||||
|Parameters|1. address (string, required) - bitcoin address <br /> 2. verbose (int, optional, default=true) - specifies the transaction is returned as a JSON object instead of hex-encoded string <br />3. skip (int, optional, default=0) - the number of leading transactions to leave out of the final response <br /> 4. count (int, optional, default=100) - the maximum number of transactions to return <br /> 5. (vinextra int, optional, default=0) - Specify that extra data from previous output will be returned in vin|
|
||||
|Description|Returns raw data for transactions involving the passed address. Returned transactions are pulled from both the database, and transactions currently in the mempool. Transactions pulled from the mempool will have the `"confirmations"` field set to 0. Usage of this RPC requires the optional `--addrindex` flag to be activated, otherwise all responses will simply return with an error stating the address index has not yet been built up. Similarly, until the address index has caught up with the current best height, all requests will return an error response in order to avoid serving stale data.|
|
||||
|Returns (verbose=0)|`[ (json array of strings)` <br/> `"serializedtx", ... hex-encoded bytes of the serialized transaction` <br/>`]` |
|
||||
|Returns (verbose=1)|`[ (array of json objects)` <br/> `{ (json object)`<br /> `"hex": "data", (string) hex-encoded transaction`<br /> `"txid": "hash", (string) the hash of the transaction`<br /> `"version": n, (numeric) the transaction version`<br /> `"locktime": n, (numeric) the transaction lock time`<br /> `"vin": [ (array of json objects) the transaction inputs as json objects`<br /> <font color="orange">For coinbase transactions:</font><br /> `{ (json object)`<br /> `"coinbase": "data", (string) the hex-dencoded bytes of the signature script`<br /> `"sequence": n, (numeric) the script sequence number`<br /> `}`<br /> <font color="orange">For non-coinbase transactions:</font><br /> `{ (json object)`<br /> `"txid": "hash", (string) the hash of the origin transaction`<br /> `"vout": n, (numeric) the index of the output being redeemed from the origin transaction`<br /> `"scriptSig": { (json object) the signature script used to redeem the origin transaction`<br /> `"asm": "asm", (string) disassembly of the script`<br /> `"hex": "data", (string) hex-encoded bytes of the script`<br /> `}`<br /> `"sequence": n, (numeric) the script sequence number`<br /> `}, ...`<br /> `]`<br /> `"vout": [ (array of json objects) the transaction outputs as json objects`<br /> `{ (json object)`<br /> `"value": n, (numeric) the value in BTC`<br /> `"n": n, (numeric) the index of this transaction output`<br /> `"scriptPubKey": { (json object) the public key script used to pay coins`<br /> `"asm": "asm", (string) disassembly of the script`<br /> `"hex": "data", (string) hex-encoded bytes of the script`<br /> `"reqSigs": n, (numeric) the number of required signatures`<br /> `"type": "scripttype" (string) the type of the script (e.g. 'pubkeyhash')`<br /> `"addresses": [ (json array of string) the bitcoin addresses associated with this output`<br /> `"address", (string) the bitcoin address`<br /> `...`<br /> `]`<br /> `}`<br /> `}, ...`<br /> `]`<br /> `"blockhash":"hash" Hash of the block the transaction is part of.` <br /> `"confirmations":n, Number of numeric confirmations of block.` <br /> `"time":t, Transaction time in seconds since the epoch.` <br /> `"blocktime":t, Block time in seconds since the epoch.`<br />`},...`<br/> `]`|
|
||||
|Returns (verbose=1)|`[ (array of json objects)` <br/> `{ (json object)`<br /> `"hex": "data", (string) hex-encoded transaction`<br /> `"txid": "hash", (string) the hash of the transaction`<br /> `"version": n, (numeric) the transaction version`<br /> `"locktime": n, (numeric) the transaction lock time`<br /> `"vin": [ (array of json objects) the transaction inputs as json objects`<br /> <font color="orange">For coinbase transactions:</font><br /> `{ (json object)`<br /> `"coinbase": "data", (string) the hex-encoded bytes of the signature script`<br /> `"sequence": n, (numeric) the script sequence number`<br /> `}`<br /> <font color="orange">For non-coinbase transactions:</font><br /> `{ (json object)`<br /> `"txid": "hash", (string) the hash of the origin transaction`<br /> `"vout": n, (numeric) the index of the output being redeemed from the origin transaction`<br /> `"scriptSig": { (json object) the signature script used to redeem the origin transaction`<br /> `"asm": "asm", (string) disassembly of the script`<br /> `"hex": "data", (string) hex-encoded bytes of the script`<br /> `}`<br /> `"prevOut": { (json object) Data from the origin transaction output with index vout.`<br /> `"addresses": ["value",...], (array of string) previous output addresses`<br /> `"value": n.nnn, (numeric) previous output value`<br /> `}`<br /> `"sequence": n, (numeric) the script sequence number`<br /> `}, ...`<br /> `]`<br /> `"vout": [ (array of json objects) the transaction outputs as json objects`<br /> `{ (json object)`<br /> `"value": n, (numeric) the value in BTC`<br /> `"n": n, (numeric) the index of this transaction output`<br /> `"scriptPubKey": { (json object) the public key script used to pay coins`<br /> `"asm": "asm", (string) disassembly of the script`<br /> `"hex": "data", (string) hex-encoded bytes of the script`<br /> `"reqSigs": n, (numeric) the number of required signatures`<br /> `"type": "scripttype" (string) the type of the script (e.g. 'pubkeyhash')`<br /> `"addresses": [ (json array of string) the bitcoin addresses associated with this output`<br /> `"address", (string) the bitcoin address`<br /> `...`<br /> `]`<br /> `}`<br /> `}, ...`<br /> `]`<br /> `"blockhash":"hash" Hash of the block the transaction is part of.` <br /> `"confirmations":n, Number of numeric confirmations of block.` <br /> `"time":t, Transaction time in seconds since the epoch.` <br /> `"blocktime":t, Block time in seconds since the epoch.`<br />`},...`<br/> `]`|
|
||||
[Return to Overview](#ExtMethodOverview)<br />
|
||||
|
||||
***
|
||||
|
|
|
@ -749,7 +749,7 @@ func (mp *txMemPool) addTransactionToAddrIndex(tx *btcutil.Tx) error {
|
|||
//
|
||||
// This function MUST be called with the mempool lock held (for reads).
|
||||
func (mp *txMemPool) fetchReferencedOutputScripts(tx *btcutil.Tx) ([][]byte, error) {
|
||||
txStore, err := mp.fetchInputTransactions(tx)
|
||||
txStore, err := mp.fetchInputTransactions(tx, false)
|
||||
if err != nil || len(txStore) == 0 {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -919,8 +919,8 @@ func (mp *txMemPool) checkPoolDoubleSpend(tx *btcutil.Tx) error {
|
|||
// fetch any missing inputs from the transaction pool.
|
||||
//
|
||||
// This function MUST be called with the mempool lock held (for reads).
|
||||
func (mp *txMemPool) fetchInputTransactions(tx *btcutil.Tx) (blockchain.TxStore, error) {
|
||||
txStore, err := mp.server.blockManager.blockChain.FetchTransactionStore(tx)
|
||||
func (mp *txMemPool) fetchInputTransactions(tx *btcutil.Tx, includeSpent bool) (blockchain.TxStore, error) {
|
||||
txStore, err := mp.server.blockManager.blockChain.FetchTransactionStore(tx, includeSpent)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -1069,7 +1069,7 @@ func (mp *txMemPool) maybeAcceptTransaction(tx *btcutil.Tx, isNew, rateLimit boo
|
|||
// transaction. This function also attempts to fetch the transaction
|
||||
// itself to be used for detecting a duplicate transaction without
|
||||
// needing to do a separate lookup.
|
||||
txStore, err := mp.fetchInputTransactions(tx)
|
||||
txStore, err := mp.fetchInputTransactions(tx, false)
|
||||
if err != nil {
|
||||
if cerr, ok := err.(blockchain.RuleError); ok {
|
||||
return nil, chainRuleError(cerr)
|
||||
|
|
112
rpcserver.go
112
rpcserver.go
|
@ -637,6 +637,79 @@ func createVinList(mtx *wire.MsgTx) []btcjson.Vin {
|
|||
return vinList
|
||||
}
|
||||
|
||||
// createVinList returns a slice of JSON objects for the inputs of the passed
|
||||
// transaction.
|
||||
func createVinListPrevOut(s *rpcServer, mtx *wire.MsgTx, chainParams *chaincfg.Params, vinExtra int) []btcjson.VinPrevOut {
|
||||
|
||||
// Coinbase transactions only have a single txin by definition.
|
||||
vinList := make([]btcjson.VinPrevOut, len(mtx.TxIn))
|
||||
if blockchain.IsCoinBaseTx(mtx) {
|
||||
txIn := mtx.TxIn[0]
|
||||
vinList[0].Coinbase = hex.EncodeToString(txIn.SignatureScript)
|
||||
vinList[0].Sequence = txIn.Sequence
|
||||
return vinList
|
||||
}
|
||||
|
||||
// Lookup all of the referenced transactions needed to populate the
|
||||
// previous output information if requested.
|
||||
var txStore blockchain.TxStore
|
||||
if vinExtra != 0 {
|
||||
tx := btcutil.NewTx(mtx)
|
||||
txStoreNew, err := s.server.txMemPool.fetchInputTransactions(tx, true)
|
||||
if err == nil {
|
||||
txStore = txStoreNew
|
||||
}
|
||||
}
|
||||
|
||||
for i, txIn := range mtx.TxIn {
|
||||
// The disassembled string will contain [error] inline
|
||||
// if the script doesn't fully parse, so ignore the
|
||||
// error here.
|
||||
disbuf, _ := txscript.DisasmString(txIn.SignatureScript)
|
||||
|
||||
vinEntry := &vinList[i]
|
||||
vinEntry.Txid = txIn.PreviousOutPoint.Hash.String()
|
||||
vinEntry.Vout = txIn.PreviousOutPoint.Index
|
||||
vinEntry.Sequence = txIn.Sequence
|
||||
vinEntry.ScriptSig = &btcjson.ScriptSig{
|
||||
Asm: disbuf,
|
||||
Hex: hex.EncodeToString(txIn.SignatureScript),
|
||||
}
|
||||
|
||||
// Only populate previous output information if requested and
|
||||
// available.
|
||||
if vinExtra == 0 || len(txStore) == 0 {
|
||||
continue
|
||||
}
|
||||
txData := txStore[txIn.PreviousOutPoint.Hash]
|
||||
if txData == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
originTxOut := txData.Tx.MsgTx().TxOut[txIn.PreviousOutPoint.Index]
|
||||
|
||||
// Ignore the error here since an error means the script
|
||||
// couldn't parse and there is no additional information about
|
||||
// it anyways.
|
||||
var strAddrs []string
|
||||
_, addrs, _, _ := txscript.ExtractPkScriptAddrs(
|
||||
originTxOut.PkScript, chainParams)
|
||||
if addrs != nil {
|
||||
strAddrs = make([]string, len(addrs))
|
||||
for j, addr := range addrs {
|
||||
strAddrs[j] = addr.EncodeAddress()
|
||||
}
|
||||
}
|
||||
|
||||
vinEntry.PrevOut = &btcjson.PrevOut{
|
||||
Addresses: strAddrs,
|
||||
Value: btcutil.Amount(originTxOut.Value).ToBTC(),
|
||||
}
|
||||
}
|
||||
|
||||
return vinList
|
||||
}
|
||||
|
||||
// createVoutList returns a slice of JSON objects for the outputs of the passed
|
||||
// transaction.
|
||||
func createVoutList(mtx *wire.MsgTx, chainParams *chaincfg.Params) []btcjson.Vout {
|
||||
|
@ -672,6 +745,37 @@ func createVoutList(mtx *wire.MsgTx, chainParams *chaincfg.Params) []btcjson.Vou
|
|||
return voutList
|
||||
}
|
||||
|
||||
// createSearchRawTransactionsResult converts the passed transaction and associated parameters
|
||||
// to a raw transaction JSON object, possibly with vin.PrevOut section.
|
||||
func createSearchRawTransactionsResult(s *rpcServer, chainParams *chaincfg.Params, mtx *wire.MsgTx,
|
||||
txHash string, blkHeader *wire.BlockHeader, blkHash string,
|
||||
blkHeight int32, chainHeight int32, vinExtra int) (*btcjson.SearchRawTransactionsResult, error) {
|
||||
|
||||
mtxHex, err := messageToHex(mtx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
txReply := &btcjson.SearchRawTransactionsResult{
|
||||
Hex: mtxHex,
|
||||
Txid: txHash,
|
||||
Vout: createVoutList(mtx, chainParams),
|
||||
Vin: createVinListPrevOut(s, mtx, chainParams, vinExtra),
|
||||
Version: mtx.Version,
|
||||
LockTime: mtx.LockTime,
|
||||
}
|
||||
|
||||
if blkHeader != nil {
|
||||
// This is not a typo, they are identical in bitcoind as well.
|
||||
txReply.Time = blkHeader.Timestamp.Unix()
|
||||
txReply.Blocktime = blkHeader.Timestamp.Unix()
|
||||
txReply.BlockHash = blkHash
|
||||
txReply.Confirmations = uint64(1 + chainHeight - blkHeight)
|
||||
}
|
||||
|
||||
return txReply, nil
|
||||
}
|
||||
|
||||
// createTxRawResult converts the passed transaction and associated parameters
|
||||
// to a raw transaction JSON object.
|
||||
func createTxRawResult(chainParams *chaincfg.Params, mtx *wire.MsgTx,
|
||||
|
@ -2198,7 +2302,7 @@ func handleGetRawMempool(s *rpcServer, cmd interface{}, closeChan <-chan struct{
|
|||
// the tx's inputs. Use zeros if one or more of the
|
||||
// input transactions can't be found for some reason.
|
||||
var startingPriority, currentPriority float64
|
||||
inputTxs, err := mp.fetchInputTransactions(desc.Tx)
|
||||
inputTxs, err := mp.fetchInputTransactions(desc.Tx, false)
|
||||
if err == nil {
|
||||
startingPriority = desc.StartingPriority(inputTxs)
|
||||
currentPriority = desc.CurrentPriority(inputTxs,
|
||||
|
@ -2935,7 +3039,7 @@ func handleSearchRawTransactions(s *rpcServer, cmd interface{}, closeChan <-chan
|
|||
return nil, internalRPCError(err.Error(), context)
|
||||
}
|
||||
|
||||
rawTxns := make([]btcjson.TxRawResult, len(addressTxs), len(addressTxs))
|
||||
rawTxns := make([]btcjson.SearchRawTransactionsResult, len(addressTxs), len(addressTxs))
|
||||
for i, txReply := range addressTxs {
|
||||
txHash := txReply.Sha.String()
|
||||
mtx := txReply.Tx
|
||||
|
@ -2960,8 +3064,8 @@ func handleSearchRawTransactions(s *rpcServer, cmd interface{}, closeChan <-chan
|
|||
blkHeight = txReply.Height
|
||||
}
|
||||
|
||||
rawTxn, err := createTxRawResult(s.server.chainParams, mtx,
|
||||
txHash, blkHeader, blkHashStr, blkHeight, maxIdx)
|
||||
rawTxn, err := createSearchRawTransactionsResult(s, s.server.chainParams, mtx,
|
||||
txHash, blkHeader, blkHashStr, blkHeight, maxIdx, *c.VinExtra)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -58,6 +58,18 @@ var helpDescsEnUS = map[string]string{
|
|||
"scriptsig-asm": "Disassembly of the script",
|
||||
"scriptsig-hex": "Hex-encoded bytes of the script",
|
||||
|
||||
// PrevOut help.
|
||||
"prevout-addresses": "previous output addresses",
|
||||
"prevout-value": "previous output value",
|
||||
|
||||
// VinPrevOut help.
|
||||
"vinprevout-coinbase": "The hex-encoded bytes of the signature script (coinbase txns only)",
|
||||
"vinprevout-txid": "The hash of the origin transaction (non-coinbase txns only)",
|
||||
"vinprevout-vout": "The index of the output being redeemed from the origin transaction (non-coinbase txns only)",
|
||||
"vinprevout-scriptSig": "The signature script used to redeem the origin transaction as a JSON object (non-coinbase txns only)",
|
||||
"vinprevout-prevOut": "Data from the origin transaction output with index vout.",
|
||||
"vinprevout-sequence": "The script sequence number",
|
||||
|
||||
// Vin help.
|
||||
"vin-coinbase": "The hex-encoded bytes of the signature script (coinbase txns only)",
|
||||
"vin-txid": "The hash of the origin transaction (non-coinbase txns only)",
|
||||
|
@ -155,6 +167,18 @@ var helpDescsEnUS = map[string]string{
|
|||
"txrawresult-time": "Transaction time in seconds since 1 Jan 1970 GMT",
|
||||
"txrawresult-blocktime": "Block time in seconds since the 1 Jan 1970 GMT",
|
||||
|
||||
// SearchRawTransactionsResult help.
|
||||
"searchrawtransactionsresult-hex": "Hex-encoded transaction",
|
||||
"searchrawtransactionsresult-txid": "The hash of the transaction",
|
||||
"searchrawtransactionsresult-version": "The transaction version",
|
||||
"searchrawtransactionsresult-locktime": "The transaction lock time",
|
||||
"searchrawtransactionsresult-vin": "The transaction inputs as JSON objects",
|
||||
"searchrawtransactionsresult-vout": "The transaction outputs as JSON objects",
|
||||
"searchrawtransactionsresult-blockhash": "Hash of the block the transaction is part of",
|
||||
"searchrawtransactionsresult-confirmations": "Number of confirmations of the block",
|
||||
"searchrawtransactionsresult-time": "Transaction time in seconds since 1 Jan 1970 GMT",
|
||||
"searchrawtransactionsresult-blocktime": "Block time in seconds since the 1 Jan 1970 GMT",
|
||||
|
||||
// GetBlockVerboseResult help.
|
||||
"getblockverboseresult-hash": "The hash of the block (same as provided)",
|
||||
"getblockverboseresult-confirmations": "The number of confirmations",
|
||||
|
@ -441,10 +465,11 @@ var helpDescsEnUS = map[string]string{
|
|||
"Similarly, until the address index has caught up with the current best height, all requests will return an error response in order to avoid serving stale data.",
|
||||
"searchrawtransactions-address": "The Bitcoin address to search for",
|
||||
"searchrawtransactions-verbose": "Specifies the transaction is returned as a JSON object instead of hex-encoded string",
|
||||
"searchrawtransactions-skip": "The number of leading transactions to leave out of the final response",
|
||||
"searchrawtransactions-count": "The maximum number of transactions to return",
|
||||
"searchrawtransactions--condition0": "verbose=0",
|
||||
"searchrawtransactions--condition1": "verbose=1",
|
||||
"searchrawtransactions-skip": "The number of leading transactions to leave out of the final response",
|
||||
"searchrawtransactions-count": "The maximum number of transactions to return",
|
||||
"searchrawtransactions-vinextra": "Specify that extra data from previous output will be returned in vin",
|
||||
"searchrawtransactions--result0": "Hex-encoded serialized transaction",
|
||||
|
||||
// SendRawTransactionCmd help.
|
||||
|
@ -581,7 +606,7 @@ var rpcResultTypes = map[string][]interface{}{
|
|||
"node": nil,
|
||||
"help": []interface{}{(*string)(nil), (*string)(nil)},
|
||||
"ping": nil,
|
||||
"searchrawtransactions": []interface{}{(*string)(nil), (*[]btcjson.TxRawResult)(nil)},
|
||||
"searchrawtransactions": []interface{}{(*string)(nil), (*[]btcjson.SearchRawTransactionsResult)(nil)},
|
||||
"sendrawtransaction": []interface{}{(*string)(nil)},
|
||||
"setgenerate": nil,
|
||||
"stop": []interface{}{(*string)(nil)},
|
||||
|
|
Loading…
Reference in a new issue