Return nil for some spent gettxout outputs.

This change modifies the behavior of the gettxout RPC to match the
behavior of the reference client.  If a transaction output is spent by
a mined transaction, the handler will now return nil (JSON null).

While here, avoid indexing some slices multiple times, by creating a
local variable instead.
This commit is contained in:
Josh Rickmar 2014-07-23 17:08:25 -05:00
parent 764893c400
commit 790a4f5a6e

View file

@ -2453,6 +2453,7 @@ func handleGetTxOut(s *rpcServer, cmd btcjson.Cmd, closeChan <-chan struct{}) (i
var mtx *btcwire.MsgTx var mtx *btcwire.MsgTx
var bestBlockSha string var bestBlockSha string
var confirmations int64 var confirmations int64
var dbSpentInfo []bool
if c.IncludeMempool && s.server.txMemPool.HaveTransaction(txSha) { if c.IncludeMempool && s.server.txMemPool.HaveTransaction(txSha) {
tx, err := s.server.txMemPool.FetchTransaction(txSha) tx, err := s.server.txMemPool.FetchTransaction(txSha)
if err != nil { if err != nil {
@ -2468,10 +2469,11 @@ func handleGetTxOut(s *rpcServer, cmd btcjson.Cmd, closeChan <-chan struct{}) (i
return nil, btcjson.ErrNoTxInfo return nil, btcjson.ErrNoTxInfo
} }
lastTx := len(txList) - 1 lastTx := txList[len(txList)-1]
mtx = txList[lastTx].Tx mtx = lastTx.Tx
blksha := txList[lastTx].BlkSha blksha := lastTx.BlkSha
txHeight := txList[lastTx].Height txHeight := lastTx.Height
dbSpentInfo = lastTx.TxSpent
_, bestHeight, err := s.server.db.NewestSha() _, bestHeight, err := s.server.db.NewestSha()
if err != nil { if err != nil {
@ -2487,15 +2489,25 @@ func handleGetTxOut(s *rpcServer, cmd btcjson.Cmd, closeChan <-chan struct{}) (i
return nil, btcjson.ErrInvalidTxVout return nil, btcjson.ErrInvalidTxVout
} }
if mtx.TxOut[c.Output] == nil { txOut := mtx.TxOut[c.Output]
if txOut == nil {
rpcsLog.Errorf("Output index: %d, for txid: %s does not exist.", c.Output, c.Txid) rpcsLog.Errorf("Output index: %d, for txid: %s does not exist.", c.Output, c.Txid)
return nil, btcjson.ErrInternal return nil, btcjson.ErrInternal
} }
// To match the behavior of the reference client, this handler returns
// nil (JSON null) if the transaction output is spent by another
// transaction already in the database. Unspent transaction outputs
// from transactions in mempool, as well as mined transactions that are
// spent by a mempool transaction, are not affected by this.
if dbSpentInfo != nil && dbSpentInfo[c.Output] {
return nil, nil
}
// Disassemble script into single line printable format. // Disassemble script into single line printable format.
// The disassembled string will contain [error] inline if the script // The disassembled string will contain [error] inline if the script
// doesn't fully parse, so ignore the error here. // doesn't fully parse, so ignore the error here.
script := mtx.TxOut[c.Output].PkScript script := txOut.PkScript
disbuf, _ := btcscript.DisasmString(script) disbuf, _ := btcscript.DisasmString(script)
// Get further info about the script. // Get further info about the script.
@ -2511,7 +2523,7 @@ func handleGetTxOut(s *rpcServer, cmd btcjson.Cmd, closeChan <-chan struct{}) (i
txOutReply := &btcjson.GetTxOutResult{ txOutReply := &btcjson.GetTxOutResult{
BestBlock: bestBlockSha, BestBlock: bestBlockSha,
Confirmations: confirmations, Confirmations: confirmations,
Value: btcutil.Amount(mtx.TxOut[c.Output].Value).ToUnit(btcutil.AmountBTC), Value: btcutil.Amount(txOut.Value).ToUnit(btcutil.AmountBTC),
Version: mtx.Version, Version: mtx.Version,
ScriptPubKey: btcjson.ScriptPubKeyResult{ ScriptPubKey: btcjson.ScriptPubKeyResult{
Asm: disbuf, Asm: disbuf,