Implement gettxout rpc.

Use new error type defined in Roasbeef/btcjson@4dc9db809
This commit is contained in:
Olaoluwa Osuntokun 2014-07-04 17:42:45 -07:00 committed by Dave Collins
parent 8a7b73e62b
commit 293d71e9c3

View File

@ -144,7 +144,7 @@ var rpcHandlersBeforeInit = map[string]commandHandler{
"getpeerinfo": handleGetPeerInfo, "getpeerinfo": handleGetPeerInfo,
"getrawmempool": handleGetRawMempool, "getrawmempool": handleGetRawMempool,
"getrawtransaction": handleGetRawTransaction, "getrawtransaction": handleGetRawTransaction,
"gettxout": handleUnimplemented, "gettxout": handleGetTxOut,
"getwork": handleGetWork, "getwork": handleGetWork,
"help": handleHelp, "help": handleHelp,
"ping": handlePing, "ping": handlePing,
@ -2434,6 +2434,97 @@ func reverseUint32Array(b []byte) {
} }
} }
// handleGetTxOut handles gettxout commands.
func handleGetTxOut(s *rpcServer, cmd btcjson.Cmd, closeChan <-chan struct{}) (interface{}, error) {
c := cmd.(*btcjson.GetTxOutCmd)
// Convert the provided transaction hash hex to a ShaHash.
txSha, err := btcwire.NewShaHashFromStr(c.Txid)
if err != nil {
return nil, btcjson.Error{
Code: btcjson.ErrInvalidParameter.Code,
Message: fmt.Sprintf("argument must be hexadecimal "+
"string (not %q)", c.Txid),
}
}
// If requested and the tx is available in the mempool try to fetch it from
// there, otherwise attempt to fetch from the block database.
var mtx *btcwire.MsgTx
var bestBlockSha string
var confirmations int64
if c.IncludeMempool && s.server.txMemPool.HaveTransaction(txSha) {
tx, err := s.server.txMemPool.FetchTransaction(txSha)
if err != nil {
rpcsLog.Errorf("Error fetching tx: %v", err)
return nil, btcjson.ErrNoTxInfo
}
mtx = tx.MsgTx()
confirmations = 0
bestBlockSha = ""
} else {
txList, err := s.server.db.FetchTxBySha(txSha)
if err != nil || len(txList) == 0 {
return nil, btcjson.ErrNoTxInfo
}
lastTx := len(txList) - 1
mtx = txList[lastTx].Tx
blksha := txList[lastTx].BlkSha
txHeight := txList[lastTx].Height
_, bestHeight, err := s.server.db.NewestSha()
if err != nil {
rpcsLog.Errorf("Cannot get newest sha: %v", err)
return nil, btcjson.ErrBlockNotFound
}
confirmations = 1 + bestHeight - txHeight
bestBlockSha = blksha.String()
}
if c.Output < 0 || c.Output > len(mtx.TxOut)-1 {
return nil, btcjson.ErrInvalidTxVout
}
if mtx.TxOut[c.Output] == nil {
rpcsLog.Errorf("Output index: %d, for txid: %s does not exist.", c.Output, c.Txid)
return nil, btcjson.ErrInternal
}
// Disassemble script into single line printable format.
// The disassembled string will contain [error] inline if the script
// doesn't fully parse, so ignore the error here.
script := mtx.TxOut[c.Output].PkScript
disbuf, _ := btcscript.DisasmString(script)
// Get further info about the script.
// Ignore the error here since an error means the script couldn't parse
// and there is no additional information about it anyways.
net := s.server.netParams
scriptClass, addrs, reqSigs, _ := btcscript.ExtractPkScriptAddrs(script, net)
addresses := make([]string, len(addrs))
for i, addr := range addrs {
addresses[i] = addr.EncodeAddress()
}
txOutReply := &btcjson.GetTxOutResult{
BestBlock: bestBlockSha,
Confirmations: confirmations,
Value: btcutil.Amount(mtx.TxOut[c.Output].Value).ToUnit(btcutil.AmountBTC),
Version: mtx.Version,
ScriptPubKey: btcjson.ScriptPubKeyResult{
Asm: disbuf,
Hex: hex.EncodeToString(script),
ReqSigs: int32(reqSigs),
Type: scriptClass.String(),
Addresses: addresses,
},
Coinbase: btcchain.IsCoinBase(btcutil.NewTx(mtx)),
}
return txOutReply, nil
}
// handleGetWorkRequest is a helper for handleGetWork which deals with // handleGetWorkRequest is a helper for handleGetWork which deals with
// generating and returning work to the caller. // generating and returning work to the caller.
// //