Browse Source

rpc: /tx allows height+hash

pull/412/head
Ethan Buchman 7 years ago
parent
commit
6e065affe5
4 changed files with 60 additions and 23 deletions
  1. +38
    -12
      rpc/core/tx.go
  2. +5
    -5
      rpc/core/types/responses.go
  3. +7
    -6
      rpc/test/client_test.go
  4. +10
    -0
      types/tx.go

+ 38
- 12
rpc/core/tx.go View File

@ -5,16 +5,30 @@ import (
abci "github.com/tendermint/abci/types"
ctypes "github.com/tendermint/tendermint/rpc/core/types"
"github.com/tendermint/tendermint/state/tx/indexer"
"github.com/tendermint/tendermint/types"
)
func Tx(hash []byte, height, index int, prove bool) (*ctypes.ResultTx, error) {
var deliverTx abci.ResponseDeliverTx
if len(hash) > 0 {
if height != 0 || index != 0 {
return nil, fmt.Errorf("Invalid args. If hash is provided, height and index should not be")
}
// if index is disabled, we need a height
_, indexerDisabled := txIndexer.(*indexer.Null)
if indexerDisabled && height == 0 {
return nil, fmt.Errorf("TxIndexer is disabled. Please specify a height to search for the tx by hash or index")
}
// hash and index must not be passed together
if len(hash) > 0 && index != 0 {
return nil, fmt.Errorf("Invalid args. Only one of hash and index may be provided")
}
// results
var txResult abci.ResponseDeliverTx
var tx types.Tx
// if indexer is enabled and we have a hash,
// fetch the tx result and set the height and index
if !indexerDisabled && len(hash) > 0 {
r, err := txIndexer.Tx(hash)
if err != nil {
return nil, err
@ -26,19 +40,31 @@ func Tx(hash []byte, height, index int, prove bool) (*ctypes.ResultTx, error) {
height = int(r.Height) // XXX
index = int(r.Index)
deliverTx = r.DeliverTx
txResult = r.DeliverTx
}
// height must be valid
if height <= 0 || height > blockStore.Height() {
return nil, fmt.Errorf("Invalid height (%d) for blockStore at height %d", height, blockStore.Height())
}
block := blockStore.LoadBlock(height)
// index must be valid
if index < 0 || index >= len(block.Data.Txs) {
return nil, fmt.Errorf("Index (%d) is out of range for block (%d) with %d txs", index, height, len(block.Data.Txs))
}
tx := block.Data.Txs[index]
// if indexer is disabled and we have a hash,
// search for it in the list of txs
if indexerDisabled && len(hash) > 0 {
index = block.Data.Txs.IndexByHash(hash)
if index < 0 {
return nil, fmt.Errorf("Tx hash %X not found in block %d", hash, height)
}
}
tx = block.Data.Txs[index]
var proof types.TxProof
if prove {
@ -46,10 +72,10 @@ func Tx(hash []byte, height, index int, prove bool) (*ctypes.ResultTx, error) {
}
return &ctypes.ResultTx{
Height: height,
Index: index,
DeliverTx: deliverTx,
Tx: tx,
Proof: proof,
Height: height,
Index: index,
TxResult: txResult,
Tx: tx,
Proof: proof,
}, nil
}

+ 5
- 5
rpc/core/types/responses.go View File

@ -94,11 +94,11 @@ type ResultBroadcastTxCommit struct {
}
type ResultTx struct {
Height int `json:"height"`
Index int `json:"index"`
DeliverTx abci.ResponseDeliverTx `json:"deliver_tx"`
Tx types.Tx `json:"tx"`
Proof types.TxProof `json:"proof,omitempty"`
Height int `json:"height"`
Index int `json:"index"`
TxResult abci.ResponseDeliverTx `json:"tx_result"`
Tx types.Tx `json:"tx"`
Proof types.TxProof `json:"proof,omitempty"`
}
type ResultUnconfirmedTxs struct {


+ 7
- 6
rpc/test/client_test.go View File

@ -165,8 +165,9 @@ func testTx(t *testing.T, client rpc.HTTPClient) {
// first we broadcast a tx
tmResult := new(ctypes.TMResult)
tx := types.Tx(randBytes(t))
_, err := client.Call("broadcast_tx_commit", map[string]interface{}{"tx": tx}, tmResult)
txBytes := randBytes(t)
tx := types.Tx(txBytes)
_, err := client.Call("broadcast_tx_commit", map[string]interface{}{"tx": txBytes}, tmResult)
require.Nil(err)
res := (*tmResult).(*ctypes.ResultBroadcastTxCommit)
@ -195,10 +196,10 @@ func testTx(t *testing.T, client rpc.HTTPClient) {
// on proper hash match
{true, 0, 0, tx.Hash(), false},
{true, 0, 0, tx.Hash(), true},
{false, res.Height, 0, tx.Hash(), false}, // TODO: or shall we allow this????
{false, res.Height, 0, tx.Hash(), true}, // TODO: or shall we allow this????
{true, res.Height, 0, tx.Hash(), false},
{true, res.Height, 0, tx.Hash(), true},
{true, 100, 0, tx.Hash(), false}, // with indexer disabled, height is overwritten
// with extra data is an error
{false, 10, 0, tx.Hash(), false},
{false, 0, 2, tx.Hash(), true},
{false, 0, 0, []byte("jkh8y0fw"), false},
{false, 0, 0, nil, true},
@ -229,7 +230,7 @@ func testTx(t *testing.T, client rpc.HTTPClient) {
assert.Equal(tx, res2.Tx, idx)
assert.Equal(res.Height, res2.Height, idx)
assert.Equal(0, res2.Index, idx)
assert.Equal(abci.CodeType_OK, res2.DeliverTx.Code, idx)
assert.Equal(abci.CodeType_OK, res2.TxResult.Code, idx)
// time to verify the proof
proof := res2.Proof
if tc.prove && assert.Equal(tx, proof.Data, idx) {


+ 10
- 0
types/tx.go View File

@ -45,6 +45,16 @@ func (txs Txs) Index(tx Tx) int {
return -1
}
// Index returns the index of this transaction hash in the list, or -1 if not found
func (txs Txs) IndexByHash(hash []byte) int {
for i := range txs {
if bytes.Equal(txs[i].Hash(), hash) {
return i
}
}
return -1
}
// Proof returns a simple merkle proof for this node.
//
// Panics if i < 0 or i >= len(txs)


Loading…
Cancel
Save