Skip to content

Commit

Permalink
Merge pull request #23 from m-Peter/eth-get-logs-endpoint
Browse files Browse the repository at this point in the history
Implement the `eth_getLogs` JSON-RPC endpoint
  • Loading branch information
franklywatson authored Jan 25, 2024
2 parents 8881c00 + 66abba9 commit 96a9e6e
Show file tree
Hide file tree
Showing 6 changed files with 137 additions and 49 deletions.
18 changes: 8 additions & 10 deletions api/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -456,18 +456,16 @@ func (s *BlockChainAPI) GetLogs(
if len(criteria.Topics) > maxTopics {
return nil, errExceedMaxTopics
}
log := &types.Log{
Index: 1,
BlockNumber: 436,
BlockHash: common.HexToHash("0x8216c5785ac562ff41e2dcfdf5785ac562ff41e2dcfdf829c5a142f1fccd7d"),
TxHash: common.HexToHash("0xdf829c5a142f1fccd7d8216c5785ac562ff41e2dcfdf5785ac562ff41e2dcf"),
TxIndex: 0,
Address: common.HexToAddress("0x16c5785ac562ff41e2dcfdf829c5a142f1fccd7d"),
Data: []byte{0, 0, 0},
Topics: []common.Hash{common.HexToHash("0x59ebeb90bc63057b6515673c3ecf9438e5058bca0f92585014eced636878c9a5")},

logs := []*types.Log{}
for _, topicList := range criteria.Topics {
for _, topic := range topicList {
matchingLogs := s.Store.LogsByTopic(topic.Hex())
logs = append(logs, matchingLogs...)
}
}

return []*types.Log{log}, nil
return logs, nil
}

// eth_newFilter
Expand Down
129 changes: 92 additions & 37 deletions api/api_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -178,38 +178,20 @@ func TestBlockChainAPI(t *testing.T) {
nonce := uint64(0)
assert.Equal(t, txCount, (*hexutil.Uint64)(&nonce))

evt := cadence.Event{
EventType: cadence.NewEventType(
stdlib.FlowLocation{},
"evm.TransactionExecuted",
[]cadence.Field{
cadence.NewField("blockHeight", cadence.UInt64Type{}),
cadence.NewField("transactionHash", cadence.StringType{}),
cadence.NewField("transaction", cadence.StringType{}),
cadence.NewField("failed", cadence.BoolType{}),
cadence.NewField("transactionType", cadence.UInt8Type{}),
cadence.NewField("gasConsumed", cadence.UInt64Type{}),
cadence.NewField("deployedContractAddress", cadence.StringType{}),
cadence.NewField("returnedValue", cadence.StringType{}),
cadence.NewField("logs", cadence.StringType{}),
},
nil,
),
Fields: []cadence.Value{
cadence.NewUInt64(3),
cadence.String("0xb47d74ea64221eb941490bdc0c9a404dacd0a8573379a45c992ac60ee3e83c3c"),
cadence.String("b88c02f88982029a01808083124f809499466ed2e37b892a2ee3e9cd55a98b68f5735db280a4c6888fa10000000000000000000000000000000000000000000000000000000000000006c001a0f84168f821b427dc158c4d8083bdc4b43e178cf0977a2c5eefbcbedcc4e351b0a066a747a38c6c266b9dc2136523cef04395918de37773db63d574aabde59c12eb"),
cadence.NewBool(false),
cadence.NewUInt8(2),
cadence.NewUInt64(22514),
cadence.String("0000000000000000000000000000000000000000"),
cadence.String("000000000000000000000000000000000000000000000000000000000000002a"),
cadence.String("f85af8589499466ed2e37b892a2ee3e9cd55a98b68f5735db2e1a024abdb5865df5079dcc5ac590ff6f01d5c16edbc5fab4e195d9febd1114503daa0000000000000000000000000000000000000000000000000000000000000002a"),
},
}
event := transactionExecutedEvent(
3,
"0xb47d74ea64221eb941490bdc0c9a404dacd0a8573379a45c992ac60ee3e83c3c",
"b88c02f88982029a01808083124f809499466ed2e37b892a2ee3e9cd55a98b68f5735db280a4c6888fa10000000000000000000000000000000000000000000000000000000000000006c001a0f84168f821b427dc158c4d8083bdc4b43e178cf0977a2c5eefbcbedcc4e351b0a066a747a38c6c266b9dc2136523cef04395918de37773db63d574aabde59c12eb",
false,
2,
22514,
"0000000000000000000000000000000000000000",
"000000000000000000000000000000000000000000000000000000000000002a",
"f85af8589499466ed2e37b892a2ee3e9cd55a98b68f5735db2e1a024abdb5865df5079dcc5ac590ff6f01d5c16edbc5fab4e195d9febd1114503daa0000000000000000000000000000000000000000000000000000000000000002a",
)

store := blockchainAPI.Store
store.UpdateAccountNonce(context.Background(), evt)
store.UpdateAccountNonce(context.Background(), event)

txCount, err = blockchainAPI.GetTransactionCount(
context.Background(),
Expand Down Expand Up @@ -477,15 +459,46 @@ func TestBlockChainAPI(t *testing.T) {
)
require.NoError(t, err)

assert.Equal(t, []*types.Log{}, logs)

event := transactionExecutedEvent(
3,
"0xb47d74ea64221eb941490bdc0c9a404dacd0a8573379a45c992ac60ee3e83c3c",
"b88c02f88982029a01808083124f809499466ed2e37b892a2ee3e9cd55a98b68f5735db280a4c6888fa10000000000000000000000000000000000000000000000000000000000000006c001a0f84168f821b427dc158c4d8083bdc4b43e178cf0977a2c5eefbcbedcc4e351b0a066a747a38c6c266b9dc2136523cef04395918de37773db63d574aabde59c12eb",
false,
2,
22514,
"0000000000000000000000000000000000000000",
"000000000000000000000000000000000000000000000000000000000000002a",
"f85af8589499466ed2e37b892a2ee3e9cd55a98b68f5735db2e1a024abdb5865df5079dcc5ac590ff6f01d5c16edbc5fab4e195d9febd1114503daa0000000000000000000000000000000000000000000000000000000000000002a",
)

store := blockchainAPI.Store
store.StoreLog(context.Background(), event)

logs, err = blockchainAPI.GetLogs(
context.Background(),
filters.FilterCriteria{
Topics: [][]common.Hash{
{
common.HexToHash("0x24abdb5865df5079dcc5ac590ff6f01d5c16edbc5fab4e195d9febd1114503da"),
},
},
},
)
require.NoError(t, err)

data, err := hex.DecodeString("000000000000000000000000000000000000000000000000000000000000002a")
require.NoError(t, err)
log := &types.Log{
Index: 1,
BlockNumber: 436,
BlockHash: common.HexToHash("0x8216c5785ac562ff41e2dcfdf5785ac562ff41e2dcfdf829c5a142f1fccd7d"),
TxHash: common.HexToHash("0xdf829c5a142f1fccd7d8216c5785ac562ff41e2dcfdf5785ac562ff41e2dcf"),
Index: 0,
BlockNumber: 0,
BlockHash: common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000000"),
TxHash: common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000000"),
TxIndex: 0,
Address: common.HexToAddress("0x16c5785ac562ff41e2dcfdf829c5a142f1fccd7d"),
Data: []byte{0, 0, 0},
Topics: []common.Hash{common.HexToHash("0x59ebeb90bc63057b6515673c3ecf9438e5058bca0f92585014eced636878c9a5")},
Address: common.HexToAddress("0x99466ed2e37b892a2ee3e9cd55a98b68f5735db2"),
Data: data,
Topics: []common.Hash{common.HexToHash("0x24abdb5865df5079dcc5ac590ff6f01d5c16edbc5fab4e195d9febd1114503da")},
}

assert.Equal(t, []*types.Log{log}, logs)
Expand Down Expand Up @@ -747,3 +760,45 @@ func TestBlockChainAPI(t *testing.T) {
)
})
}

func transactionExecutedEvent(
blockHeight uint64,
transactionHash string,
transaction string,
failed bool,
transactionType uint8,
gasConsumed uint64,
deployedContractAddress string,
returnedValue string,
logs string,
) cadence.Event {
return cadence.Event{
EventType: cadence.NewEventType(
stdlib.FlowLocation{},
"evm.TransactionExecuted",
[]cadence.Field{
cadence.NewField("blockHeight", cadence.UInt64Type{}),
cadence.NewField("transactionHash", cadence.StringType{}),
cadence.NewField("transaction", cadence.StringType{}),
cadence.NewField("failed", cadence.BoolType{}),
cadence.NewField("transactionType", cadence.UInt8Type{}),
cadence.NewField("gasConsumed", cadence.UInt64Type{}),
cadence.NewField("deployedContractAddress", cadence.StringType{}),
cadence.NewField("returnedValue", cadence.StringType{}),
cadence.NewField("logs", cadence.StringType{}),
},
nil,
),
Fields: []cadence.Value{
cadence.NewUInt64(blockHeight),
cadence.String(transactionHash),
cadence.String(transaction),
cadence.NewBool(failed),
cadence.NewUInt8(transactionType),
cadence.NewUInt64(gasConsumed),
cadence.String(deployedContractAddress),
cadence.String(returnedValue),
cadence.String(logs),
},
}
}
2 changes: 1 addition & 1 deletion api/fixtures/eth_json_rpc_requests.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
{"jsonrpc":"2.0","id":1,"method":"eth_getBlockTransactionCountByNumber","params":["0xe8"]}
{"jsonrpc":"2.0","id":1,"method":"eth_getUncleCountByBlockHash","params":["0xb903239f8543d04b5dc1ba6579132b143087c68db1b2168786408fcbce568238"]}
{"jsonrpc":"2.0","id":1,"method":"eth_getUncleCountByBlockNumber","params":["0xe8"]}
{"jsonrpc":"2.0","id":1,"method":"eth_getLogs","params":[{"topics":["0x000000000000000000000000a94f5374fce5edbc8e2a8697c15331677e6ebf0b"]}]}
{"jsonrpc":"2.0","id":1,"method":"eth_getLogs","params":[{"topics":[]}]}
{"jsonrpc":"2.0","id":1,"method":"eth_newFilter","params":[{"topics":["0x000000000000000000000000a94f5374fce5edbc8e2a8697c15331677e6ebf0b"]}]}
{"jsonrpc":"2.0","id":1,"method":"eth_uninstallFilter","params":["0xb"]}
{"jsonrpc":"2.0","id":1,"method":"eth_getFilterLogs","params":["0x16"]}
Expand Down
2 changes: 1 addition & 1 deletion api/fixtures/eth_json_rpc_responses.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
{"jsonrpc":"2.0","id":1,"result":"0x20a"}
{"jsonrpc":"2.0","id":1,"result":"0x0"}
{"jsonrpc":"2.0","id":1,"result":"0x0"}
{"jsonrpc":"2.0","id":1,"result":[{"address":"0x16c5785ac562ff41e2dcfdf829c5a142f1fccd7d","topics":["0x59ebeb90bc63057b6515673c3ecf9438e5058bca0f92585014eced636878c9a5"],"data":"0x000000","blockNumber":"0x1b4","transactionHash":"0x00df829c5a142f1fccd7d8216c5785ac562ff41e2dcfdf5785ac562ff41e2dcf","transactionIndex":"0x0","blockHash":"0x008216c5785ac562ff41e2dcfdf5785ac562ff41e2dcfdf829c5a142f1fccd7d","logIndex":"0x1","removed":false}]}
{"jsonrpc":"2.0","id":1,"result":[]}
{"jsonrpc":"2.0","id":1,"result":"filter0"}
{"jsonrpc":"2.0","id":1,"result":true}
{"jsonrpc":"2.0","id":1,"result":[{"address":"0x16c5785ac562ff41e2dcfdf829c5a142f1fccd7d","topics":["0x59ebeb90bc63057b6515673c3ecf9438e5058bca0f92585014eced636878c9a5"],"data":"0x000000","blockNumber":"0x1b4","transactionHash":"0x00df829c5a142f1fccd7d8216c5785ac562ff41e2dcfdf5785ac562ff41e2dcf","transactionIndex":"0x0","blockHash":"0x008216c5785ac562ff41e2dcfdf5785ac562ff41e2dcfdf829c5a142f1fccd7d","logIndex":"0x1","removed":false}]}
Expand Down
1 change: 1 addition & 0 deletions cmd/server/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ func runIndexer(ctx context.Context, store *storage.Store, logger zerolog.Logger
logger.Info().Msgf(" %s", event.Value)
if event.Type == "flow.evm.TransactionExecuted" {
store.UpdateAccountNonce(ctx, event.Value)
store.StoreLog(ctx, event.Value)
}
}

Expand Down
34 changes: 34 additions & 0 deletions storage/store.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (

type Store struct {
mu sync.RWMutex
logsByTopic map[string][]*types.Log
latestHeight uint64
accountNonce map[common.Address]uint64
}
Expand All @@ -26,6 +27,7 @@ type Store struct {
func NewStore() *Store {
return &Store{
accountNonce: make(map[common.Address]uint64),
logsByTopic: make(map[string][]*types.Log),
}
}

Expand Down Expand Up @@ -90,6 +92,38 @@ func (s *Store) UpdateAccountNonce(ctx context.Context, event cadence.Event) {
s.accountNonce[from] = s.accountNonce[from] + 1
}

func (s *Store) StoreLog(ctx context.Context, event cadence.Event) {
s.mu.Lock()
defer s.mu.Unlock()

logValue := event.GetFieldValues()[8]
logC, ok := logValue.(cadence.String)
if !ok {
return
}
logS := logC.ToGoValue().(string)
if len(logS) == 0 {
return
}
bt, err := hex.DecodeString(logS)
if err != nil {
panic(err)
}
logs := []*types.Log{}
err = rlp.Decode(bytes.NewReader(bt), &logs)
if err != nil {
panic(err)
}
for _, log := range logs {
topic := log.Topics[0].Hex()
s.logsByTopic[topic] = append(s.logsByTopic[topic], logs...)
}
}

func (s *Store) LogsByTopic(topic string) []*types.Log {
return s.logsByTopic[topic]
}

func (s *Store) StoreBlockHeight(ctx context.Context, blockHeight uint64) error {
s.mu.Lock()
defer s.mu.Unlock()
Expand Down

0 comments on commit 96a9e6e

Please sign in to comment.