Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(tm2): store tx results and add endpoint to query them #1546

Merged
merged 12 commits into from
Apr 17, 2024
10 changes: 10 additions & 0 deletions gno.land/pkg/gnoclient/mock_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ type (
mockStatus func() (*ctypes.ResultStatus, error)
mockUnconfirmedTxs func(limit int) (*ctypes.ResultUnconfirmedTxs, error)
mockNumUnconfirmedTxs func() (*ctypes.ResultUnconfirmedTxs, error)
mockTx func(hash []byte) (*ctypes.ResultTx, error)
)

type mockRPCClient struct {
Expand All @@ -141,6 +142,7 @@ type mockRPCClient struct {
status mockStatus
unconfirmedTxs mockUnconfirmedTxs
numUnconfirmedTxs mockNumUnconfirmedTxs
tx mockTx
}

func (m *mockRPCClient) BroadcastTxCommit(tx types.Tx) (*ctypes.ResultBroadcastTxCommit, error) {
Expand Down Expand Up @@ -282,3 +284,11 @@ func (m *mockRPCClient) NumUnconfirmedTxs() (*ctypes.ResultUnconfirmedTxs, error
}
return nil, nil
}

func (m *mockRPCClient) Tx(hash []byte) (*ctypes.ResultTx, error) {
if m.tx != nil {
return m.tx(hash)
}

return nil, nil
}
20 changes: 2 additions & 18 deletions tm2/pkg/bft/rpc/client/httpclient.go
Original file line number Diff line number Diff line change
Expand Up @@ -307,11 +307,10 @@ func (c *baseRPCClient) Commit(height *int64) (*ctypes.ResultCommit, error) {
return result, nil
}

func (c *baseRPCClient) Tx(hash []byte, prove bool) (*ctypes.ResultTx, error) {
func (c *baseRPCClient) Tx(hash []byte) (*ctypes.ResultTx, error) {
result := new(ctypes.ResultTx)
params := map[string]interface{}{
"hash": hash,
"prove": prove,
"hash": hash,
}
_, err := c.caller.Call("tx", params, result)
if err != nil {
Expand All @@ -320,21 +319,6 @@ func (c *baseRPCClient) Tx(hash []byte, prove bool) (*ctypes.ResultTx, error) {
return result, nil
}

func (c *baseRPCClient) TxSearch(query string, prove bool, page, perPage int) (*ctypes.ResultTxSearch, error) {
result := new(ctypes.ResultTxSearch)
params := map[string]interface{}{
"query": query,
"prove": prove,
"page": page,
"per_page": perPage,
}
_, err := c.caller.Call("tx_search", params, result)
if err != nil {
return nil, errors.Wrap(err, "TxSearch")
}
return result, nil
}

func (c *baseRPCClient) Validators(height *int64) (*ctypes.ResultValidators, error) {
result := new(ctypes.ResultValidators)
params := map[string]interface{}{}
Expand Down
6 changes: 5 additions & 1 deletion tm2/pkg/bft/rpc/client/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,13 @@ import (
// first synchronously consumes the events from the node's synchronous event
// switch, or reads logged events from the filesystem.
type Client interface {
// service.Service
ABCIClient
HistoryClient
NetworkClient
SignClient
StatusClient
MempoolClient
TxClient
}

// ABCIClient groups together the functionality that principally affects the
Expand Down Expand Up @@ -94,3 +94,7 @@ type MempoolClient interface {
UnconfirmedTxs(limit int) (*ctypes.ResultUnconfirmedTxs, error)
NumUnconfirmedTxs() (*ctypes.ResultUnconfirmedTxs, error)
}

type TxClient interface {
Tx(hash []byte) (*ctypes.ResultTx, error)
}
10 changes: 2 additions & 8 deletions tm2/pkg/bft/rpc/client/localclient.go
Original file line number Diff line number Diff line change
Expand Up @@ -138,12 +138,6 @@ func (c *Local) Validators(height *int64) (*ctypes.ResultValidators, error) {
return core.Validators(c.ctx, height)
}

/*
func (c *Local) Tx(hash []byte, prove bool) (*ctypes.ResultTx, error) {
return core.Tx(c.ctx, hash, prove)
func (c *Local) Tx(hash []byte) (*ctypes.ResultTx, error) {
return core.Tx(c.ctx, hash)
}

func (c *Local) TxSearch(query string, prove bool, page, perPage int) (*ctypes.ResultTxSearch, error) {
return core.TxSearch(c.ctx, query, prove, page, perPage)
}
*/
1 change: 1 addition & 0 deletions tm2/pkg/bft/rpc/client/mock/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ type Client struct {
client.HistoryClient
client.StatusClient
client.MempoolClient
client.TxClient
service.Service
}

Expand Down
136 changes: 34 additions & 102 deletions tm2/pkg/bft/rpc/client/rpc_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -365,130 +365,62 @@ func TestNumUnconfirmedTxs(t *testing.T) {
mempool.Flush()
}

/*
func TestTx(t *testing.T) {
t.Parallel()

// first we broadcast a tx
// Prepare the transaction
// by broadcasting it to the chain
c := getHTTPClient()
_, _, tx := MakeTxKV()
bres, err := c.BroadcastTxCommit(tx)
require.Nil(t, err, "%+v", err)

txHeight := bres.Height
txHash := bres.Hash
response, err := c.BroadcastTxCommit(tx)
require.NoError(t, err)
require.NotNil(t, response)

anotherTxHash := types.Tx("a different tx").Hash()
var (
txHeight = response.Height
txHash = response.Hash
)

cases := []struct {
name string
valid bool
hash []byte
prove bool
}{
// only valid if correct hash provided
{true, txHash, false},
{true, txHash, true},
{false, anotherTxHash, false},
{false, anotherTxHash, true},
{false, nil, false},
{false, nil, true},
{
"tx result found",
true,
txHash,
},
{
"tx result not found",
false,
types.Tx("a different tx").Hash(),
},
}

for i, c := range GetClients() {
for j, tc := range cases {
t.Logf("client %d, case %d", i, j)
for _, c := range GetClients() {
for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
// now we query for the tx.
// since there's only one tx, we know index=0.
ptx, err := c.Tx(tc.hash)

if !tc.valid {
require.Error(t, err)

return
}

// now we query for the tx.
// since there's only one tx, we know index=0.
ptx, err := c.Tx(tc.hash, tc.prove)
require.NoError(t, err)

if !tc.valid {
require.NotNil(t, err)
} else {
require.Nil(t, err, "%+v", err)
assert.EqualValues(t, txHeight, ptx.Height)
assert.EqualValues(t, tx, ptx.Tx)
assert.Zero(t, ptx.Index)
assert.True(t, ptx.TxResult.IsOK())
assert.EqualValues(t, txHash, ptx.Hash)

// time to verify the proof
proof := ptx.Proof
if tc.prove && assert.EqualValues(t, tx, proof.Data) {
assert.NoError(t, proof.Proof.Verify(proof.RootHash, txHash))
}
}
}
}
}

func TestTxSearch(t *testing.T) {
t.Parallel()

// first we broadcast a tx
c := getHTTPClient()
_, _, tx := MakeTxKV()
bres, err := c.BroadcastTxCommit(tx)
require.Nil(t, err, "%+v", err)

txHeight := bres.Height
txHash := bres.Hash

anotherTxHash := types.Tx("a different tx").Hash()

for i, c := range GetClients() {
t.Logf("client %d", i)

// now we query for the tx.
// since there's only one tx, we know index=0.
result, err := c.TxSearch(fmt.Sprintf("tx.hash='%v'", txHash), true, 1, 30)
require.Nil(t, err, "%+v", err)
require.Len(t, result.Txs, 1)

ptx := result.Txs[0]
assert.EqualValues(t, txHeight, ptx.Height)
assert.EqualValues(t, tx, ptx.Tx)
assert.Zero(t, ptx.Index)
assert.True(t, ptx.TxResult.IsOK())
assert.EqualValues(t, txHash, ptx.Hash)

// time to verify the proof
proof := ptx.Proof
if assert.EqualValues(t, tx, proof.Data) {
assert.NoError(t, proof.Proof.Verify(proof.RootHash, txHash))
}

// query by height
result, err = c.TxSearch(fmt.Sprintf("tx.height=%d", txHeight), true, 1, 30)
require.Nil(t, err, "%+v", err)
require.Len(t, result.Txs, 1)

// query for non existing tx
result, err = c.TxSearch(fmt.Sprintf("tx.hash='%X'", anotherTxHash), false, 1, 30)
require.Nil(t, err, "%+v", err)
require.Len(t, result.Txs, 0)

// query using a tag (see kvstore application)
result, err = c.TxSearch("app.creator='Cosmoshi Netowoko'", false, 1, 30)
require.Nil(t, err, "%+v", err)
if len(result.Txs) == 0 {
t.Fatal("expected a lot of transactions")
})
}

// query using a tag (see kvstore application) and height
result, err = c.TxSearch("app.creator='Cosmoshi Netowoko' AND tx.height<10000", true, 1, 30)
require.Nil(t, err, "%+v", err)
if len(result.Txs) == 0 {
t.Fatal("expected a lot of transactions")
}

// query a non existing tx with page 1 and txsPerPage 1
result, err = c.TxSearch("app.creator='Cosmoshi Neetowoko'", true, 1, 1)
require.Nil(t, err, "%+v", err)
require.Len(t, result.Txs, 0)
}
}
*/

func TestBatchedJSONRPCCalls(t *testing.T) {
c := getHTTPClient()
Expand Down
78 changes: 78 additions & 0 deletions tm2/pkg/bft/rpc/core/mock_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
package core

import "github.com/gnolang/gno/tm2/pkg/bft/types"

type (
heightDelegate func() int64
loadBlockMetaDelegate func(int64) *types.BlockMeta
loadBlockDelegate func(int64) *types.Block
loadBlockPartDelegate func(int64, int) *types.Part
loadBlockCommitDelegate func(int64) *types.Commit
loadSeenCommitDelegate func(int64) *types.Commit

saveBlockDelegate func(*types.Block, *types.PartSet, *types.Commit)
)

type mockBlockStore struct {
heightFn heightDelegate
loadBlockMetaFn loadBlockMetaDelegate
loadBlockFn loadBlockDelegate
loadBlockPartFn loadBlockPartDelegate
loadBlockCommitFn loadBlockCommitDelegate
loadSeenCommitFn loadSeenCommitDelegate
saveBlockFn saveBlockDelegate
}

func (m *mockBlockStore) Height() int64 {
if m.heightFn != nil {
return m.heightFn()
}

return 0
}

func (m *mockBlockStore) LoadBlockMeta(height int64) *types.BlockMeta {
if m.loadBlockMetaFn != nil {
return m.loadBlockMetaFn(height)
}

return nil
}

func (m *mockBlockStore) LoadBlock(height int64) *types.Block {
if m.loadBlockFn != nil {
return m.loadBlockFn(height)
}

return nil
}

func (m *mockBlockStore) LoadBlockPart(height int64, index int) *types.Part {
if m.loadBlockPartFn != nil {
return m.loadBlockPartFn(height, index)
}

return nil
}

func (m *mockBlockStore) LoadBlockCommit(height int64) *types.Commit {
if m.loadBlockCommitFn != nil {
return m.loadBlockCommitFn(height)
}

return nil
}

func (m *mockBlockStore) LoadSeenCommit(height int64) *types.Commit {
if m.loadSeenCommitFn != nil {
return m.loadSeenCommitFn(height)
}

return nil
}

func (m *mockBlockStore) SaveBlock(block *types.Block, blockParts *types.PartSet, seenCommit *types.Commit) {
if m.saveBlockFn != nil {
m.saveBlockFn(block, blockParts, seenCommit)
}
}
19 changes: 9 additions & 10 deletions tm2/pkg/bft/rpc/core/routes.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,15 @@ import (
// NOTE: Amino is registered in rpc/core/types/codec.go.
var Routes = map[string]*rpc.RPCFunc{
// info API
"health": rpc.NewRPCFunc(Health, ""),
"status": rpc.NewRPCFunc(Status, ""),
"net_info": rpc.NewRPCFunc(NetInfo, ""),
"blockchain": rpc.NewRPCFunc(BlockchainInfo, "minHeight,maxHeight"),
"genesis": rpc.NewRPCFunc(Genesis, ""),
"block": rpc.NewRPCFunc(Block, "height"),
"block_results": rpc.NewRPCFunc(BlockResults, "height"),
"commit": rpc.NewRPCFunc(Commit, "height"),
//"tx": rpc.NewRPCFunc(Tx, "hash,prove"),
//"tx_search": rpc.NewRPCFunc(TxSearch, "query,prove,page,per_page"),
thehowl marked this conversation as resolved.
Show resolved Hide resolved
"health": rpc.NewRPCFunc(Health, ""),
"status": rpc.NewRPCFunc(Status, ""),
"net_info": rpc.NewRPCFunc(NetInfo, ""),
"blockchain": rpc.NewRPCFunc(BlockchainInfo, "minHeight,maxHeight"),
"genesis": rpc.NewRPCFunc(Genesis, ""),
"block": rpc.NewRPCFunc(Block, "height"),
"block_results": rpc.NewRPCFunc(BlockResults, "height"),
"commit": rpc.NewRPCFunc(Commit, "height"),
"tx": rpc.NewRPCFunc(Tx, "hash"),
"validators": rpc.NewRPCFunc(Validators, "height"),
"dump_consensus_state": rpc.NewRPCFunc(DumpConsensusState, ""),
"consensus_state": rpc.NewRPCFunc(ConsensusState, ""),
Expand Down
Loading
Loading