mirror of
https://github.com/fluencelabs/tendermint
synced 2025-06-26 19:21:44 +00:00
rpc: /tx allows height+hash
This commit is contained in:
@ -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 {
|
||||
@ -48,7 +74,7 @@ func Tx(hash []byte, height, index int, prove bool) (*ctypes.ResultTx, error) {
|
||||
return &ctypes.ResultTx{
|
||||
Height: height,
|
||||
Index: index,
|
||||
DeliverTx: deliverTx,
|
||||
TxResult: txResult,
|
||||
Tx: tx,
|
||||
Proof: proof,
|
||||
}, nil
|
||||
|
@ -96,7 +96,7 @@ type ResultBroadcastTxCommit struct {
|
||||
type ResultTx struct {
|
||||
Height int `json:"height"`
|
||||
Index int `json:"index"`
|
||||
DeliverTx abci.ResponseDeliverTx `json:"deliver_tx"`
|
||||
TxResult abci.ResponseDeliverTx `json:"tx_result"`
|
||||
Tx types.Tx `json:"tx"`
|
||||
Proof types.TxProof `json:"proof,omitempty"`
|
||||
}
|
||||
|
@ -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
types/tx.go
10
types/tx.go
@ -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)
|
||||
|
Reference in New Issue
Block a user