77 "context"
88 "errors"
99 "fmt"
10+ "math/big"
1011
1112 . "github.com/cartesi/rollups-node/internal/model"
1213 "github.com/ethereum/go-ethereum/accounts/abi/bind"
@@ -25,6 +26,50 @@ func (r *Service) checkForNewInputs(
2526
2627 r .Logger .Debug ("Checking for new inputs" )
2728
29+ mostRecentBlockNumberCallOpts := & bind.CallOpts {
30+ BlockNumber : new (big.Int ).SetUint64 (mostRecentBlockNumber ),
31+ }
32+
33+ findFirstInputBlock := func (app * appContracts ) uint64 {
34+ var noiBig * big.Int
35+ var err error
36+
37+ // application has never received an input
38+ noiBig , err = app .inputSource .GetNumberOfInputs (
39+ mostRecentBlockNumberCallOpts ,
40+ app .application .IApplicationAddress ,
41+ )
42+ if err != nil {
43+ return app .application .LastInputCheckBlock
44+ }
45+ if noiBig .Uint64 () == 0 {
46+ return mostRecentBlockNumber
47+ }
48+
49+ // application has not received an input since its deployment
50+ // but find its deployment block number first
51+ deploymentBlockNumberBig , err := app .applicationContract .GetDeploymentBlockNumber (mostRecentBlockNumberCallOpts )
52+ if err != nil {
53+ return app .application .LastInputCheckBlock
54+ }
55+
56+ noiBig , err = app .inputSource .GetNumberOfInputs (& bind.CallOpts {
57+ BlockNumber : deploymentBlockNumberBig ,
58+ },
59+ app .application .IApplicationAddress ,
60+ )
61+ if err != nil {
62+ return app .application .LastInputCheckBlock
63+ }
64+ if noiBig .Uint64 () == 0 {
65+ return deploymentBlockNumberBig .Uint64 ()
66+ }
67+
68+ // TODO(mpolitzer): use GetNumberOfInputs to binary search the
69+ // block of the first input
70+ return app .application .IInputBoxBlock
71+ }
72+
2873 appsByInputBox := map [common.Address ][]appContracts {}
2974 for _ , app := range applications {
3075 if ! app .application .HasDataAvailabilitySelector (DataAvailability_InputBox ) {
@@ -39,18 +84,24 @@ func (r *Service) checkForNewInputs(
3984 "inputbox_address" , inputBoxAddress ,
4085 "most recent block" , mostRecentBlockNumber ,
4186 )
42- appsByLastInputCheckBlock := indexApps (byLastInputCheckBlock , inputBoxApps )
87+
88+ appsByLastInputCheckBlock := make (map [uint64 ][]appContracts )
89+ for _ , app := range inputBoxApps {
90+ i := app .application .LastInputCheckBlock
91+ if i == 0 { // fast sync applications with no inputs
92+ i = findFirstInputBlock (& app )- 1
93+ r .Logger .Info ("Fast sync application inputs" ,
94+ "application" , app .application .Name ,
95+ "start_block" , i ,
96+ )
97+ app .application .LastInputCheckBlock = i
98+ }
99+ appsByLastInputCheckBlock [i ] = append (appsByLastInputCheckBlock [i ], app )
100+ }
43101
44102 for lastProcessedBlock , apps := range appsByLastInputCheckBlock {
45103 appAddresses := appsToAddresses (apps )
46104
47- // Only check blocks starting from the block where the InputBox
48- // contract was deployed as Inputs can be added to that same block
49- inputBoxDeploymentBlock := apps [0 ].application .IInputBoxBlock
50- if lastProcessedBlock < inputBoxDeploymentBlock {
51- lastProcessedBlock = inputBoxDeploymentBlock - 1
52- }
53-
54105 if mostRecentBlockNumber > lastProcessedBlock {
55106
56107 r .Logger .Debug ("Checking inputs for applications" ,
0 commit comments