From 96f2f7bf16d90c3eabbe33ea90bcf5efb459bcce Mon Sep 17 00:00:00 2001 From: Francisco Moura Date: Mon, 29 Jul 2024 16:08:40 -0300 Subject: [PATCH 1/4] feat(evm-reader): Add max input fetch size --- cmd/cartesi-rollups-evm-reader/main.go | 1 + docs/config.md | 7 + internal/evmreader/evmreader.go | 96 ++++--- internal/evmreader/evmreader_test.go | 272 ++++++++++++++++++ .../evmreader/service/evmreader_service.go | 4 + internal/evmreader/testdata/header_3.json | 14 + .../testdata/input_added_event_4.json | 20 ++ .../testdata/input_added_event_5.json | 20 ++ internal/node/config/config.go | 2 + internal/node/config/generate/Config.toml | 6 + internal/node/config/generate/code.go | 7 + internal/node/config/generated.go | 21 ++ internal/node/services.go | 1 + 13 files changed, 431 insertions(+), 40 deletions(-) create mode 100644 internal/evmreader/testdata/header_3.json create mode 100644 internal/evmreader/testdata/input_added_event_4.json create mode 100644 internal/evmreader/testdata/input_added_event_5.json diff --git a/cmd/cartesi-rollups-evm-reader/main.go b/cmd/cartesi-rollups-evm-reader/main.go index b4667c185..6a05976a0 100644 --- a/cmd/cartesi-rollups-evm-reader/main.go +++ b/cmd/cartesi-rollups-evm-reader/main.go @@ -158,6 +158,7 @@ func run(cmd *cobra.Command, args []string) { database, c.EvmReaderRetryPolicyMaxRetries, c.EvmReaderRetryPolicyMaxDelay, + c.EvmReaderMaxFetchSize, ) // logs startup time diff --git a/docs/config.md b/docs/config.md index a76309d0d..e71a8ce62 100644 --- a/docs/config.md +++ b/docs/config.md @@ -231,6 +231,13 @@ At the end of each epoch, the node will send claims to the blockchain. * **Type:** `uint64` * **Default:** `"7200"` +## `CARTESI_EVM_READER_MAX_FETCH_SIZE` + +Maximum number of blocks that can be read on each input fetch request. + +* **Type:** `uint` +* **Default:** `"10"` + ## `CARTESI_EVM_READER_RETRY_POLICY_MAX_DELAY` How seconds the retry policy will wait between retries. diff --git a/internal/evmreader/evmreader.go b/internal/evmreader/evmreader.go index e7f4d22fa..5a6af9bbd 100644 --- a/internal/evmreader/evmreader.go +++ b/internal/evmreader/evmreader.go @@ -86,11 +86,12 @@ func (e *SubscriptionError) Error() string { // EvmReader reads inputs from the blockchain type EvmReader struct { - client EthClient - wsClient EthWsClient - inputSource InputSource - repository EvmReaderRepository - config NodePersistentConfig + client EthClient + wsClient EthWsClient + inputSource InputSource + repository EvmReaderRepository + config NodePersistentConfig + maxFetchSize uint } func (r *EvmReader) String() string { @@ -104,13 +105,15 @@ func NewEvmReader( inputSource InputSource, repository EvmReaderRepository, config NodePersistentConfig, + maxFetchSize uint, ) EvmReader { return EvmReader{ - client: client, - wsClient: wsClient, - inputSource: inputSource, - repository: repository, - config: config, + client: client, + wsClient: wsClient, + inputSource: inputSource, + repository: repository, + config: config, + maxFetchSize: maxFetchSize, } } @@ -177,6 +180,22 @@ func (r *EvmReader) checkForNewInputs(ctx Context) error { groupedApps := r.classifyApplicationsByLastProcessedInput(apps) + step := uint64(r.maxFetchSize) + + mostRecentHeader, err := r.fetchMostRecentHeader( + ctx, + r.config.DefaultBlock, + ) + if err != nil { + // slog.Error("Error fetching most recent block", + // "last default block", + // r.config.DefaultBlock, + // "error", + // err) + return err + } + mostRecentBlockNumber := mostRecentHeader.Number.Uint64() + for lastProcessedBlock, apps := range groupedApps { // Safeguard: Only check blocks starting from the block where the InputBox @@ -185,42 +204,39 @@ func (r *EvmReader) checkForNewInputs(ctx Context) error { lastProcessedBlock = r.config.InputBoxDeploymentBlock - 1 } - currentMostRecentFinalizedHeader, err := r.fetchMostRecentHeader( - ctx, - r.config.DefaultBlock, - ) - if err != nil { - slog.Error("Error fetching most recent block", - "last default block", - r.config.DefaultBlock, - "error", - err) - continue - } - currentMostRecentFinalizedBlockNumber := currentMostRecentFinalizedHeader.Number.Uint64() + if mostRecentBlockNumber > lastProcessedBlock { - if currentMostRecentFinalizedBlockNumber > lastProcessedBlock { + // Check block range and split requests + start := lastProcessedBlock + 1 + end := uint64(0) + for ; start <= mostRecentBlockNumber; start = start + step { - err = r.readInputs(ctx, - lastProcessedBlock+1, - currentMostRecentFinalizedBlockNumber, - apps, - ) - if err != nil { - slog.Error("Error reading inputs", - "start", - lastProcessedBlock+1, - "end", - currentMostRecentFinalizedBlockNumber, - "error", - err) - continue + end = start + step - 1 + + if end > mostRecentBlockNumber { + end = mostRecentBlockNumber + } + err = r.readInputs(ctx, + start, + end, + apps, + ) + if err != nil { + slog.Error("Error reading inputs", + "start", + start, + "end", + end, + "error", + err) + break + } } - } else if lastProcessedBlock < currentMostRecentFinalizedBlockNumber { + } else if lastProcessedBlock < mostRecentBlockNumber { slog.Warn( "current most recent block is lower than the last processed one", "most recent block", - currentMostRecentFinalizedBlockNumber, + mostRecentBlockNumber, "last processed", lastProcessedBlock, ) diff --git a/internal/evmreader/evmreader_test.go b/internal/evmreader/evmreader_test.go index eb15e01f7..105109eda 100644 --- a/internal/evmreader/evmreader_test.go +++ b/internal/evmreader/evmreader_test.go @@ -38,6 +38,12 @@ var inputAddedEvent2JsonBytes []byte //go:embed testdata/input_added_event_3.json var inputAddedEvent3JsonBytes []byte +//go:embed testdata/input_added_event_4.json +var inputAddedEvent4JsonBytes []byte + +//go:embed testdata/input_added_event_5.json +var inputAddedEvent5JsonBytes []byte + //go:embed testdata/header_0.json var header0JsonBytes []byte @@ -47,10 +53,14 @@ var header1JsonBytes []byte //go:embed testdata/header_2.json var header2JsonBytes []byte +//go:embed testdata/header_3.json +var header3JsonBytes []byte + var ( header0 = types.Header{} header1 = types.Header{} header2 = types.Header{} + header3 = types.Header{} block0 = types.Block{} @@ -58,6 +68,8 @@ var ( inputAddedEvent1 = inputbox.InputBoxInputAdded{} inputAddedEvent2 = inputbox.InputBoxInputAdded{} inputAddedEvent3 = inputbox.InputBoxInputAdded{} + inputAddedEvent4 = inputbox.InputBoxInputAdded{} + inputAddedEvent5 = inputbox.InputBoxInputAdded{} subscription0 = newMockSubscription() ) @@ -86,6 +98,8 @@ func (s *EvmReaderSuite) SetupSuite() { s.Require().Nil(err) err = json.Unmarshal(header2JsonBytes, &header2) s.Require().Nil(err) + err = json.Unmarshal(header3JsonBytes, &header3) + s.Require().Nil(err) block0 = *types.NewBlockWithHeader(&header0) @@ -97,6 +111,10 @@ func (s *EvmReaderSuite) SetupSuite() { s.Require().Nil(err) err = json.Unmarshal(inputAddedEvent3JsonBytes, &inputAddedEvent3) s.Require().Nil(err) + err = json.Unmarshal(inputAddedEvent4JsonBytes, &inputAddedEvent4) + s.Require().Nil(err) + err = json.Unmarshal(inputAddedEvent5JsonBytes, &inputAddedEvent5) + s.Require().Nil(err) } func (s *EvmReaderSuite) TearDownSuite() { @@ -118,6 +136,7 @@ func (s *EvmReaderSuite) SetupTest() { DefaultBlock: model.DefaultBlockStatusLatest, InputBoxDeploymentBlock: 0, }, + 10, ) s.evmReader = &inputReader } @@ -180,6 +199,7 @@ func (s *EvmReaderSuite) TestItReadsInputsFromNewBlocks() { InputBoxDeploymentBlock: 0x10, DefaultBlock: model.DefaultBlockStatusLatest, }, + 10, ) // Prepare repository @@ -288,6 +308,7 @@ func (s *EvmReaderSuite) TestItUpdatesLastProcessedBlockWhenThereIsNoInputs() { InputBoxDeploymentBlock: 0x10, DefaultBlock: model.DefaultBlockStatusLatest, }, + 10, ) // Prepare repository @@ -396,6 +417,7 @@ func (s *EvmReaderSuite) TestItReadsMultipleInputsFromSingleNewBlock() { InputBoxDeploymentBlock: 0x10, DefaultBlock: model.DefaultBlockStatusLatest, }, + 10, ) // Prepare Client @@ -486,6 +508,7 @@ func (s *EvmReaderSuite) TestItStartsWhenLasProcessedBlockIsTheMostRecentBlock() InputBoxDeploymentBlock: 0x10, DefaultBlock: model.DefaultBlockStatusLatest, }, + 10, ) // Prepare Client @@ -532,6 +555,255 @@ func (s *EvmReaderSuite) TestItStartsWhenLasProcessedBlockIsTheMostRecentBlock() ) } +func (s *EvmReaderSuite) TestItReadsInputsInSmallerBatches() { + + waitGroup := sync.WaitGroup{} + wsClient := FakeWSEhtClient{} + wsClient.NewHeaders = []*Header{&header2} + wsClient.WaitGroup = &waitGroup + inputReader := NewEvmReader( + s.client, + &wsClient, + s.inputBox, + s.repository, + model.NodePersistentConfig{ + InputBoxDeploymentBlock: 0x10, + DefaultBlock: model.DefaultBlockStatusLatest, + }, + 2, + ) + + // Prepare Client + s.client.Unset("HeaderByNumber") + s.client.On( + "HeaderByNumber", + mock.Anything, + mock.Anything, + ).Return(&header3, nil).Once() + + // Prepare sequence of inputs + // Batch 0x11 - 0x12 + s.inputBox.Unset("RetrieveInputs") + events_0 := []inputbox.InputBoxInputAdded{inputAddedEvent0, inputAddedEvent1} + currentMostRecentFinalizedBlockNumber_0 := uint64(0x12) + retrieveInputsOpts_0 := bind.FilterOpts{ + Context: s.ctx, + Start: 0x11, + End: ¤tMostRecentFinalizedBlockNumber_0, + } + s.inputBox.On( + "RetrieveInputs", + &retrieveInputsOpts_0, + mock.Anything, + mock.Anything, + ).Return(events_0, nil) + + // Batch 0x13 - 0x14 + events_1 := []inputbox.InputBoxInputAdded{inputAddedEvent2, inputAddedEvent3} + currentMostRecentFinalizedBlockNumber_1 := uint64(0x14) + retrieveInputsOpts_1 := bind.FilterOpts{ + Context: s.ctx, + Start: 0x13, + End: ¤tMostRecentFinalizedBlockNumber_1, + } + s.inputBox.On( + "RetrieveInputs", + &retrieveInputsOpts_1, + mock.Anything, + mock.Anything, + ).Return(events_1, nil) + + // Batch 0x15 - 0x16 + events_2 := []inputbox.InputBoxInputAdded{inputAddedEvent2, inputAddedEvent3} + currentMostRecentFinalizedBlockNumber_2 := uint64(0x16) + retrieveInputsOpts_2 := bind.FilterOpts{ + Context: s.ctx, + Start: 0x15, + End: ¤tMostRecentFinalizedBlockNumber_2, + } + s.inputBox.On( + "RetrieveInputs", + &retrieveInputsOpts_2, + mock.Anything, + mock.Anything, + ).Return(events_2, nil) + + // Prepare Repo + s.repository.Unset("GetAllRunningApplications") + s.repository.On( + "GetAllRunningApplications", + mock.Anything, + ).Return([]Application{{ + ContractAddress: common.HexToAddress("0x2E663fe9aE92275242406A185AA4fC8174339D3E"), + LastProcessedBlock: 0x10, + }}, nil).Once() + + // Start service + ready := make(chan struct{}, 1) + errChannel := make(chan error, 1) + + waitGroup.Add(1) + go func() { + errChannel <- inputReader.Run(s.ctx, ready) + }() + + select { + case <-ready: + break + case err := <-errChannel: + s.FailNow("unexpected error signal", err) + } + + waitGroup.Wait() + + s.inputBox.AssertNumberOfCalls(s.T(), "RetrieveInputs", 3) + s.repository.AssertNumberOfCalls( + s.T(), + "InsertInputsAndUpdateLastProcessedBlock", + 3, + ) +} + +func (s *EvmReaderSuite) TestItReadsInputsInSmallerBatchesWithError() { + + waitGroup := sync.WaitGroup{} + wsClient := FakeWSEhtClient{} + wsClient.NewHeaders = []*Header{&header2} + wsClient.WaitGroup = &waitGroup + inputReader := NewEvmReader( + s.client, + &wsClient, + s.inputBox, + s.repository, + model.NodePersistentConfig{ + InputBoxDeploymentBlock: 0x10, + DefaultBlock: model.DefaultBlockStatusLatest, + }, + 2, + ) + + // Prepare Client + s.client.Unset("HeaderByNumber") + s.client.On( + "HeaderByNumber", + mock.Anything, + mock.Anything, + ).Return(&header3, nil).Once() + + // Prepare sequence of inputs + // Batch 0x11 - 0x12 for application 0x2E663fe9aE92275242406A185AA4fC8174339D3E + s.inputBox.Unset("RetrieveInputs") + events_0 := []inputbox.InputBoxInputAdded{inputAddedEvent0, inputAddedEvent1} + currentMostRecentFinalizedBlockNumber_0 := uint64(0x12) + retrieveInputsOpts_0 := bind.FilterOpts{ + Context: s.ctx, + Start: 0x11, + End: ¤tMostRecentFinalizedBlockNumber_0, + } + s.inputBox.On( + "RetrieveInputs", + &retrieveInputsOpts_0, + []common.Address{common.HexToAddress("0x2E663fe9aE92275242406A185AA4fC8174339D3E")}, + mock.Anything, + ).Return(events_0, nil) + + // Batch 0x13 - 0x14 for application 0x2E663fe9aE92275242406A185AA4fC8174339D3E with error + currentMostRecentFinalizedBlockNumber_1 := uint64(0x14) + retrieveInputsOpts_1 := bind.FilterOpts{ + Context: s.ctx, + Start: 0x13, + End: ¤tMostRecentFinalizedBlockNumber_1, + } + s.inputBox.On( + "RetrieveInputs", + &retrieveInputsOpts_1, + []common.Address{common.HexToAddress("0x2E663fe9aE92275242406A185AA4fC8174339D3E")}, + mock.Anything, + ).Return([]inputbox.InputBoxInputAdded{}, fmt.Errorf("An error")) + + // Batch 0x12 - 0x13 for application 0xFFFF3fe9aE92275242406A185AA4fC817433EEEE" + currentMostRecentFinalizedBlockNumber_2 := uint64(0x13) + retrieveInputsOpts_2 := bind.FilterOpts{ + Context: s.ctx, + Start: 0x12, + End: ¤tMostRecentFinalizedBlockNumber_2, + } + s.inputBox.On( + "RetrieveInputs", + &retrieveInputsOpts_2, + []common.Address{common.HexToAddress("0xFFFF3fe9aE92275242406A185AA4fC817433EEEE")}, + mock.Anything, + ).Return([]inputbox.InputBoxInputAdded{}, nil) + + // Batch 0x14 - 0x15 for application 0xFFFF3fe9aE92275242406A185AA4fC817433EEEE" + currentMostRecentFinalizedBlockNumber_3 := uint64(0x15) + retrieveInputsOpts_3 := bind.FilterOpts{ + Context: s.ctx, + Start: 0x14, + End: ¤tMostRecentFinalizedBlockNumber_3, + } + s.inputBox.On( + "RetrieveInputs", + &retrieveInputsOpts_3, + []common.Address{common.HexToAddress("0xFFFF3fe9aE92275242406A185AA4fC817433EEEE")}, + mock.Anything, + ).Return([]inputbox.InputBoxInputAdded{}, nil) + + // Batch 0x16 - 0x17 for application 0xFFFF3fe9aE92275242406A185AA4fC817433EEEE" + currentMostRecentFinalizedBlockNumber_4 := uint64(0x16) + retrieveInputsOpts_4 := bind.FilterOpts{ + Context: s.ctx, + Start: 0x16, + End: ¤tMostRecentFinalizedBlockNumber_4, + } + s.inputBox.On( + "RetrieveInputs", + &retrieveInputsOpts_4, + []common.Address{common.HexToAddress("0xFFFF3fe9aE92275242406A185AA4fC817433EEEE")}, + mock.Anything, + ).Return([]inputbox.InputBoxInputAdded{}, nil) + + // Prepare Repo + s.repository.Unset("GetAllRunningApplications") + s.repository.On( + "GetAllRunningApplications", + mock.Anything, + ).Return([]Application{ + { + ContractAddress: common.HexToAddress("0x2E663fe9aE92275242406A185AA4fC8174339D3E"), + LastProcessedBlock: 0x10, + }, + { + ContractAddress: common.HexToAddress("0xFFFF3fe9aE92275242406A185AA4fC817433EEEE"), + LastProcessedBlock: 0x11, + }}, nil).Once() + + // Start service + ready := make(chan struct{}, 1) + errChannel := make(chan error, 1) + + waitGroup.Add(1) + go func() { + errChannel <- inputReader.Run(s.ctx, ready) + }() + + select { + case <-ready: + break + case err := <-errChannel: + s.FailNow("unexpected error signal", err) + } + + waitGroup.Wait() + + s.inputBox.AssertNumberOfCalls(s.T(), "RetrieveInputs", 5) + s.repository.AssertNumberOfCalls( + s.T(), + "InsertInputsAndUpdateLastProcessedBlock", + 4, + ) +} + // Mock EthClient type MockEthClient struct { mock.Mock diff --git a/internal/evmreader/service/evmreader_service.go b/internal/evmreader/service/evmreader_service.go index e71af9e18..aa70ca8ec 100644 --- a/internal/evmreader/service/evmreader_service.go +++ b/internal/evmreader/service/evmreader_service.go @@ -26,6 +26,7 @@ type EvmReaderService struct { database *repository.Database maxRetries uint64 maxDelay time.Duration + maxFetchSize uint } func NewEvmReaderService( @@ -34,6 +35,7 @@ func NewEvmReaderService( database *repository.Database, maxRetries uint64, maxDelay time.Duration, + maxFetchSize uint, ) EvmReaderService { return EvmReaderService{ blockchainHttpEndpoint: blockchainHttpEndpoint, @@ -41,6 +43,7 @@ func NewEvmReaderService( database: database, maxRetries: maxRetries, maxDelay: maxDelay, + maxFetchSize: maxFetchSize, } } @@ -77,6 +80,7 @@ func (s EvmReaderService) Start( retrypolicy.NewInputSourceWithRetryPolicy(inputSource, s.maxRetries, s.maxDelay), s.database, *config, + s.maxFetchSize, ) return reader.Run(ctx, ready) diff --git a/internal/evmreader/testdata/header_3.json b/internal/evmreader/testdata/header_3.json new file mode 100644 index 000000000..a07f15464 --- /dev/null +++ b/internal/evmreader/testdata/header_3.json @@ -0,0 +1,14 @@ +{ + "number": "0x16", + "gasUsed": "0x11ddc", + "gasLimit": "0x1c9c380", + "extraData": "0x", + "timestamp": "0x6653e99c", + "difficulty": "0x0", + "parentHash":"0x0000000000000000000000000000000000000000000000000000000000000000", + "sha3Uncles":"0x0000000000000000000000000000000000000000000000000000000000000000", + "stateRoot":"0x0000000000000000000000000000000000000000000000000000000000000000", + "transactionsRoot":"0x0000000000000000000000000000000000000000000000000000000000000000", + "receiptsRoot":"0x0000000000000000000000000000000000000000000000000000000000000000", + "logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" +} diff --git a/internal/evmreader/testdata/input_added_event_4.json b/internal/evmreader/testdata/input_added_event_4.json new file mode 100644 index 000000000..bac8d51e9 --- /dev/null +++ b/internal/evmreader/testdata/input_added_event_4.json @@ -0,0 +1,20 @@ +{ + "AppContract": "0x2e663fe9ae92275242406a185aa4fc8174339d3e", + "Index": 4, + "Input": "zH3uHwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHppAAAAAAAAAAAAAAAALmY/6a6SJ1JCQGoYWqT8gXQznT4AAAAAAAAAAAAAAADzn9blGq2I9vTOariCcnnP/7kiZgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAATAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGZx6R8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAT+rb7vAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==", + "Raw": { + "address": "0xa1b8eb1f13d8d5db976a653bbdf8972cfd14691c", + "topics": [ + "0xc05d337121a6e8605c6ec0b72aa29c4210ffe6e5b9cefdd6a7058188a8f66f98", + "0x0000000000000000000000002e663fe9ae92275242406a185aa4fc8174339d3e", + "0x0000000000000000000000000000000000000000000000000000000000000004" + ], + "data": "0x00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000124cc7dee1f0000000000000000000000000000000000000000000000000000000000007a690000000000000000000000002e663fe9ae92275242406a185aa4fc8174339d3e000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb922660000000000000000000000000000000000000000000000000000000000000013000000000000000000000000000000000000000000000000000000006671e91f000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000004feadbeef0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "blockNumber": "0x15", + "transactionHash": "0xd2c73d400ea0b4531ca8ca774a1cdfa9cc146b6fae63eafd3d664a00f800173a", + "transactionIndex": "0x0", + "blockHash": "0xdf76e699e009f868c6f893487cc7d6368c5d48c5e49115a288353f202670fa37", + "logIndex": "0x0", + "removed": false + } +} diff --git a/internal/evmreader/testdata/input_added_event_5.json b/internal/evmreader/testdata/input_added_event_5.json new file mode 100644 index 000000000..8980f1c17 --- /dev/null +++ b/internal/evmreader/testdata/input_added_event_5.json @@ -0,0 +1,20 @@ +{ + "AppContract": "0x2e663fe9ae92275242406a185aa4fc8174339d3e", + "Index": 4, + "Input": "zH3uHwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHppAAAAAAAAAAAAAAAALmY/6a6SJ1JCQGoYWqT8gXQznT4AAAAAAAAAAAAAAADzn9blGq2I9vTOariCcnnP/7kiZgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAATAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGZx6R8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAT+rb7vAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==", + "Raw": { + "address": "0xa1b8eb1f13d8d5db976a653bbdf8972cfd14691c", + "topics": [ + "0xc05d337121a6e8605c6ec0b72aa29c4210ffe6e5b9cefdd6a7058188a8f66f98", + "0x0000000000000000000000002e663fe9ae92275242406a185aa4fc8174339d3e", + "0x0000000000000000000000000000000000000000000000000000000000000005" + ], + "data": "0x00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000124cc7dee1f0000000000000000000000000000000000000000000000000000000000007a690000000000000000000000002e663fe9ae92275242406a185aa4fc8174339d3e000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb922660000000000000000000000000000000000000000000000000000000000000013000000000000000000000000000000000000000000000000000000006671e91f000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000004feadbeef0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "blockNumber": "0x16", + "transactionHash": "0xd25040a2becee77022cec08be1411cabc3ea47d4e1701be8ddd5bb5cd3921f72", + "transactionIndex": "0x0", + "blockHash": "0xd965fcb4c783cc9eb77557e8097e407b0bf7964d95fd363778f6c2713f6684bb", + "logIndex": "0x0", + "removed": false + } +} diff --git a/internal/node/config/config.go b/internal/node/config/config.go index 9f75939ef..7b4e3df5d 100644 --- a/internal/node/config/config.go +++ b/internal/node/config/config.go @@ -24,6 +24,7 @@ type NodeConfig struct { EvmReaderDefaultBlock DefaultBlock EvmReaderRetryPolicyMaxRetries uint64 EvmReaderRetryPolicyMaxDelay Duration + EvmReaderMaxFetchSize uint BlockchainBlockTimeout int ContractsApplicationAddress string ContractsIConsensusAddress string @@ -84,6 +85,7 @@ func FromEnv() NodeConfig { config.EvmReaderDefaultBlock = getEvmReaderDefaultBlock() config.EvmReaderRetryPolicyMaxRetries = getEvmReaderRetryPolicyMaxRetries() config.EvmReaderRetryPolicyMaxDelay = getEvmReaderRetryPolicyMaxDelay() + config.EvmReaderMaxFetchSize = getEvmReaderMaxFetchSize() config.BlockchainBlockTimeout = getBlockchainBlockTimeout() config.ContractsApplicationAddress = getContractsApplicationAddress() config.ContractsIConsensusAddress = getContractsIconsensusAddress() diff --git a/internal/node/config/generate/Config.toml b/internal/node/config/generate/Config.toml index 19d1ae7bf..c250bac41 100644 --- a/internal/node/config/generate/Config.toml +++ b/internal/node/config/generate/Config.toml @@ -56,6 +56,12 @@ go-type = "Duration" description = """ How seconds the retry policy will wait between retries.""" +[rollups.CARTESI_EVM_READER_MAX_FETCH_SIZE] +default = "10" +go-type = "uint" +description = """ +Maximum number of blocks that can be read on each input fetch request.""" + # # Blockchain # diff --git a/internal/node/config/generate/code.go b/internal/node/config/generate/code.go index 33f30e900..f9996da20 100644 --- a/internal/node/config/generate/code.go +++ b/internal/node/config/generate/code.go @@ -96,6 +96,12 @@ const ( // Parsing functions // ------------------------------------------------------------------------------------------------ +func ToUintFromString(s string) (uint, error) { + value,err := strconv.ParseUint(s, 10, 0) + if err != nil { return 0,err } + return uint(value),nil +} + func ToInt64FromString(s string) (int64, error) { return strconv.ParseInt(s, 10, 64) } @@ -163,6 +169,7 @@ func ToAuthKindFromString(s string) (AuthKind, error) { var ( toBool = strconv.ParseBool toInt = strconv.Atoi + toUint = ToUintFromString toInt64 = ToInt64FromString toUint64 = ToUint64FromString toString = ToStringFromString diff --git a/internal/node/config/generated.go b/internal/node/config/generated.go index bb2f24c84..da31dddbb 100644 --- a/internal/node/config/generated.go +++ b/internal/node/config/generated.go @@ -40,6 +40,14 @@ const ( // Parsing functions // ------------------------------------------------------------------------------------------------ +func ToUintFromString(s string) (uint, error) { + value, err := strconv.ParseUint(s, 10, 0) + if err != nil { + return 0, err + } + return uint(value), nil +} + func ToInt64FromString(s string) (int64, error) { return strconv.ParseInt(s, 10, 64) } @@ -107,6 +115,7 @@ func ToAuthKindFromString(s string) (AuthKind, error) { var ( toBool = strconv.ParseBool toInt = strconv.Atoi + toUint = ToUintFromString toInt64 = ToInt64FromString toUint64 = ToUint64FromString toString = ToStringFromString @@ -480,6 +489,18 @@ func getEpochLength() uint64 { return val } +func getEvmReaderMaxFetchSize() uint { + s, ok := os.LookupEnv("CARTESI_EVM_READER_MAX_FETCH_SIZE") + if !ok { + s = "10" + } + val, err := toUint(s) + if err != nil { + panic(fmt.Sprintf("failed to parse CARTESI_EVM_READER_MAX_FETCH_SIZE: %v", err)) + } + return val +} + func getEvmReaderRetryPolicyMaxDelay() Duration { s, ok := os.LookupEnv("CARTESI_EVM_READER_RETRY_POLICY_MAX_DELAY") if !ok { diff --git a/internal/node/services.go b/internal/node/services.go index 7c52e9c51..45dd364be 100644 --- a/internal/node/services.go +++ b/internal/node/services.go @@ -180,5 +180,6 @@ func newEvmReaderService(c config.NodeConfig, database *repository.Database) ser database, c.EvmReaderRetryPolicyMaxRetries, c.EvmReaderRetryPolicyMaxDelay, + c.EvmReaderMaxFetchSize, ) } From 7dc537a5eb2706952d8903002a43110e55dea6cd Mon Sep 17 00:00:00 2001 From: Francisco Moura Date: Mon, 29 Jul 2024 16:09:35 -0300 Subject: [PATCH 2/4] chore(evm-reader): Remove dead code --- cmd/cartesi-rollups-evm-reader/main.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/cmd/cartesi-rollups-evm-reader/main.go b/cmd/cartesi-rollups-evm-reader/main.go index 6a05976a0..e32a3bfbe 100644 --- a/cmd/cartesi-rollups-evm-reader/main.go +++ b/cmd/cartesi-rollups-evm-reader/main.go @@ -26,8 +26,7 @@ var ( ) const ( - CMD_NAME = "evm-reader" - devnetInputBoxDeploymentBlockNumber = uint64(16) + CMD_NAME = "evm-reader" ) var Cmd = &cobra.Command{ From a9297b40381c5776c426b834c85425fc0d0c6e95 Mon Sep 17 00:00:00 2001 From: Francisco Moura Date: Mon, 29 Jul 2024 16:10:11 -0300 Subject: [PATCH 3/4] chore(ethutil): Improve debug logs --- pkg/ethutil/ethutil.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/pkg/ethutil/ethutil.go b/pkg/ethutil/ethutil.go index 86d1561a9..959ccfe9d 100644 --- a/pkg/ethutil/ethutil.go +++ b/pkg/ethutil/ethutil.go @@ -8,6 +8,7 @@ package ethutil import ( "context" "fmt" + "log/slog" "math/big" "github.com/cartesi/rollups-node/pkg/addresses" @@ -104,6 +105,9 @@ func getInputIndex( if err != nil { return 0, fmt.Errorf("failed to parse input added event: %v", err) } + + slog.Debug("Input added event", "event", inputAdded) + // We assume that int will fit all dapp inputs inputIndex := int(inputAdded.Index.Int64()) return inputIndex, nil From 3c534c824aa71662a5776352a0981f199ebb946c Mon Sep 17 00:00:00 2001 From: Francisco Moura Date: Fri, 2 Aug 2024 11:39:26 -0300 Subject: [PATCH 4/4] fixup! feat(evm-reader): Add max input fetch size --- internal/evmreader/evmreader.go | 5 ----- 1 file changed, 5 deletions(-) diff --git a/internal/evmreader/evmreader.go b/internal/evmreader/evmreader.go index 5a6af9bbd..ea283aedf 100644 --- a/internal/evmreader/evmreader.go +++ b/internal/evmreader/evmreader.go @@ -187,11 +187,6 @@ func (r *EvmReader) checkForNewInputs(ctx Context) error { r.config.DefaultBlock, ) if err != nil { - // slog.Error("Error fetching most recent block", - // "last default block", - // r.config.DefaultBlock, - // "error", - // err) return err } mostRecentBlockNumber := mostRecentHeader.Number.Uint64()