Correct getrawtransaction RPC handling and cleanup.

The getrawtransaction RPC call should return a hex-encoded string of the
transaction when verbose is false instead of a TxRawResult object with the
Hex field set to be compatible with the Sathoshi client.  This commit,
along with a recent commit to btcjson corrects this.

Also, while here, do a bit of cleanup, finish a TODO to check for an
invalid hash, and optimize the handling of non-verbose slightly.
This commit is contained in:
Dave Collins 2013-12-26 23:22:41 -06:00
parent af3609d861
commit e0fab228a4

View file

@ -802,9 +802,11 @@ func handleGetBlock(s *rpcServer, cmd btcjson.Cmd, walletNotification chan []byt
txSha := tx.Sha().String() txSha := tx.Sha().String()
mtx := tx.MsgTx() mtx := tx.MsgTx()
rawTxn, err := createTxRawResult(s.server.btcnet, txSha, mtx, blk, maxidx, sha, true) rawTxn, err := createTxRawResult(s.server.btcnet, txSha,
mtx, blk, maxidx, sha)
if err != nil { if err != nil {
rpcsLog.Errorf("Cannot create TxRawResult for txSha=%s: %v", txSha, err) rpcsLog.Errorf("Cannot create TxRawResult for "+
"transaction %s: %v", txSha, err)
return nil, err return nil, err
} }
rawTxns[i] = *rawTxn rawTxns[i] = *rawTxn
@ -946,9 +948,18 @@ func handleGetRawMempool(s *rpcServer, cmd btcjson.Cmd, walletNotification chan
func handleGetRawTransaction(s *rpcServer, cmd btcjson.Cmd, walletNotification chan []byte) (interface{}, error) { func handleGetRawTransaction(s *rpcServer, cmd btcjson.Cmd, walletNotification chan []byte) (interface{}, error) {
c := cmd.(*btcjson.GetRawTransactionCmd) c := cmd.(*btcjson.GetRawTransactionCmd)
// TODO: check error code. tx is not checked before // Convert the provided transaction hash hex to a ShaHash.
// this point. txSha, err := btcwire.NewShaHashFromStr(c.Txid)
txSha, _ := btcwire.NewShaHashFromStr(c.Txid) if err != nil {
rpcsLog.Errorf("Error generating sha: %v", err)
return nil, btcjson.Error{
Code: btcjson.ErrBlockNotFound.Code,
Message: "Parameter 1 must be a hexaecimal string",
}
}
// Try to fetch the transaction from the memory pool and if that fails,
// try the block database.
var mtx *btcwire.MsgTx var mtx *btcwire.MsgTx
var blksha *btcwire.ShaHash var blksha *btcwire.ShaHash
tx, err := s.server.txMemPool.FetchTransaction(txSha) tx, err := s.server.txMemPool.FetchTransaction(txSha)
@ -967,9 +978,18 @@ func handleGetRawTransaction(s *rpcServer, cmd btcjson.Cmd, walletNotification c
mtx = tx.MsgTx() mtx = tx.MsgTx()
} }
// When the verbose flag isn't set, simply return the network-serialized
// transaction as a hex-encoded string.
if !c.Verbose {
mtxHex, err := messageToHex(mtx)
if err != nil {
return nil, err
}
return mtxHex, nil
}
var blk *btcutil.Block var blk *btcutil.Block
var maxidx int64 var maxidx int64
if blksha != nil { if blksha != nil {
blk, err = s.server.db.FetchBlockBySha(blksha) blk, err = s.server.db.FetchBlockBySha(blksha)
if err != nil { if err != nil {
@ -984,7 +1004,7 @@ func handleGetRawTransaction(s *rpcServer, cmd btcjson.Cmd, walletNotification c
} }
} }
rawTxn, jsonErr := createTxRawResult(s.server.btcnet, c.Txid, mtx, blk, maxidx, blksha, c.Verbose) rawTxn, jsonErr := createTxRawResult(s.server.btcnet, c.Txid, mtx, blk, maxidx, blksha)
if err != nil { if err != nil {
rpcsLog.Errorf("Cannot create TxRawResult for txSha=%s: %v", txSha, err) rpcsLog.Errorf("Cannot create TxRawResult for txSha=%s: %v", txSha, err)
return nil, *jsonErr return nil, *jsonErr
@ -992,25 +1012,17 @@ func handleGetRawTransaction(s *rpcServer, cmd btcjson.Cmd, walletNotification c
return *rawTxn, nil return *rawTxn, nil
} }
// createTxRawResult // createTxRawResult converts the passed transaction and associated parameters
func createTxRawResult(net btcwire.BitcoinNet, txSha string, mtx *btcwire.MsgTx, blk *btcutil.Block, maxidx int64, blksha *btcwire.ShaHash, verbose bool) (*btcjson.TxRawResult, *btcjson.Error) { // to a raw transaction JSON object.
func createTxRawResult(net btcwire.BitcoinNet, txSha string, mtx *btcwire.MsgTx, blk *btcutil.Block, maxidx int64, blksha *btcwire.ShaHash) (*btcjson.TxRawResult, *btcjson.Error) {
tx := btcutil.NewTx(mtx) tx := btcutil.NewTx(mtx)
mtxHex, err := messageToHex(mtx) mtxHex, err := messageToHex(mtx)
if err != nil { if err != nil {
return nil, err return nil, err
} }
if !verbose { vinList := make([]btcjson.Vin, len(mtx.TxIn))
return &btcjson.TxRawResult{Hex: mtxHex}, nil for i, v := range mtx.TxIn {
}
txOutList := mtx.TxOut
voutList := make([]btcjson.Vout, len(txOutList))
txInList := mtx.TxIn
vinList := make([]btcjson.Vin, len(txInList))
for i, v := range txInList {
if btcchain.IsCoinBase(tx) { if btcchain.IsCoinBase(tx) {
vinList[i].Coinbase = hex.EncodeToString(v.SignatureScript) vinList[i].Coinbase = hex.EncodeToString(v.SignatureScript)
} else { } else {
@ -1024,7 +1036,8 @@ func createTxRawResult(net btcwire.BitcoinNet, txSha string, mtx *btcwire.MsgTx,
vinList[i].Sequence = float64(v.Sequence) vinList[i].Sequence = float64(v.Sequence)
} }
for i, v := range txOutList { voutList := make([]btcjson.Vout, len(mtx.TxOut))
for i, v := range mtx.TxOut {
voutList[i].N = i voutList[i].N = i
voutList[i].Value = float64(v.Value) / float64(btcutil.SatoshiPerBitcoin) voutList[i].Value = float64(v.Value) / float64(btcutil.SatoshiPerBitcoin)
@ -1060,8 +1073,7 @@ func createTxRawResult(net btcwire.BitcoinNet, txSha string, mtx *btcwire.MsgTx,
blockHeader := &blk.MsgBlock().Header blockHeader := &blk.MsgBlock().Header
idx := blk.Height() idx := blk.Height()
// This is not a typo, they are identical in // This is not a typo, they are identical in bitcoind as well.
// bitcoind as well.
txReply.Time = blockHeader.Timestamp.Unix() txReply.Time = blockHeader.Timestamp.Unix()
txReply.Blocktime = blockHeader.Timestamp.Unix() txReply.Blocktime = blockHeader.Timestamp.Unix()
txReply.BlockHash = blksha.String() txReply.BlockHash = blksha.String()