diff --git a/lastgersync/e2e_test.go b/lastgersync/e2e_test.go index 20170090..386be88c 100644 --- a/lastgersync/e2e_test.go +++ b/lastgersync/e2e_test.go @@ -2,86 +2,71 @@ package lastgersync_test import ( "context" - "errors" + "fmt" "math/big" + "strconv" "testing" "time" - gerContractL1 "github.com/0xPolygon/cdk-contracts-tooling/contracts/manual/globalexitrootnopush0" - gerContractEVMChain "github.com/0xPolygon/cdk-contracts-tooling/contracts/manual/pessimisticglobalexitrootnopush0" - "github.com/0xPolygon/cdk/aggoracle" - "github.com/0xPolygon/cdk/etherman" + "github.com/0xPolygon/cdk/lastgersync" + "github.com/0xPolygon/cdk/test/helpers" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/ethclient/simulated" + "github.com/ethereum/go-ethereum/rpc" "github.com/stretchr/testify/require" ) func TestE2E(t *testing.T) { - // 1. AggOracle ctx := context.Background() - l1Client, syncer, gerL1Contract, authL1 := CommonSetup(t) - sender := aggoracle.EVMSetup(t) - oracle, err := aggoracle.New(sender, l1Client.Client(), syncer, etherman.LatestBlock, time.Millisecond) + env := helpers.SetupAggoracleWithEVMChain(t) + dbPathSyncer := t.TempDir() + syncer, err := lastgersync.New( + ctx, + dbPathSyncer, + env.ReorgDetector, + env.L2Client.Client(), + env.GERL2Addr, + env.L1InfoTreeSync, + 0, + 0, + big.NewInt(int64(rpc.LatestBlockNumber)), + time.Millisecond*30, + 10, + ) require.NoError(t, err) - go oracle.Start(ctx) + go syncer.Start(ctx) - // 2. lastgersync - // 3. update GER - // 4. lastgersync has the updates -} - -func newSimulatedL1(auth *bind.TransactOpts) ( - client *simulated.Backend, - gerAddr common.Address, - gerContract *gerContractL1.Globalexitrootnopush0, - err error, -) { - balance, _ := new(big.Int).SetString("10000000000000000000000000", 10) //nolint:gomnd - address := auth.From - genesisAlloc := map[common.Address]types.Account{ - address: { - Balance: balance, - }, - } - blockGasLimit := uint64(999999999999999999) //nolint:gomnd - client = simulated.NewBackend(genesisAlloc, simulated.WithBlockGasLimit(blockGasLimit)) + for i := 0; i < 10; i++ { + // Update GER on L1 + _, err := env.GERL1Contract.UpdateExitRoot(env.AuthL1, common.HexToHash(strconv.Itoa(i))) + require.NoError(t, err) + env.L1Client.Commit() + time.Sleep(time.Millisecond * 50) + expectedGER, err := env.GERL1Contract.GetLastGlobalExitRoot(&bind.CallOpts{Pending: false}) + require.NoError(t, err) + isInjected, err := env.AggOracleSender.IsGERAlreadyInjected(expectedGER) + require.NoError(t, err) + require.True(t, isInjected, fmt.Sprintf("iteration %d, GER: %s", i, common.Bytes2Hex(expectedGER[:]))) - gerAddr, _, gerContract, err = gerContractL1.DeployGlobalexitrootnopush0(auth, client.Client(), auth.From, auth.From) - - client.Commit() - return -} - -func newSimulatedEVMAggSovereignChain(auth *bind.TransactOpts) ( - client *simulated.Backend, - gerAddr common.Address, - gerContract *gerContractEVMChain.Pessimisticglobalexitrootnopush0, - err error, -) { - balance, _ := new(big.Int).SetString("10000000000000000000000000", 10) //nolint:gomnd - address := auth.From - genesisAlloc := map[common.Address]types.Account{ - address: { - Balance: balance, - }, - } - blockGasLimit := uint64(999999999999999999) //nolint:gomnd - client = simulated.NewBackend(genesisAlloc, simulated.WithBlockGasLimit(blockGasLimit)) - - gerAddr, _, gerContract, err = gerContractEVMChain.DeployPessimisticglobalexitrootnopush0(auth, client.Client(), auth.From) - if err != nil { - return - } - client.Commit() + // Wait for syncer to catch up + syncerUpToDate := false + var errMsg string + for i := 0; i < 10; i++ { + lpb, err := syncer.GetLastProcessedBlock(ctx) + require.NoError(t, err) + lb, err := env.L2Client.Client().BlockNumber(ctx) + require.NoError(t, err) + if lpb == lb { + syncerUpToDate = true + break + } + time.Sleep(time.Millisecond * 10) + errMsg = fmt.Sprintf("last block from client: %d, last block from syncer: %d", lb, lpb) + } + require.True(t, syncerUpToDate, errMsg) - _GLOBAL_EXIT_ROOT_SETTER_ROLE := common.HexToHash("0x7b95520991dfda409891be0afa2635b63540f92ee996fda0bf695a166e5c5176") - _, err = gerContract.GrantRole(auth, _GLOBAL_EXIT_ROOT_SETTER_ROLE, auth.From) - client.Commit() - hasRole, _ := gerContract.HasRole(&bind.CallOpts{Pending: false}, _GLOBAL_EXIT_ROOT_SETTER_ROLE, auth.From) - if !hasRole { - err = errors.New("failed to set role") + actualGER, err := syncer.GetFirstGERAfterL1InfoTreeIndex(ctx, uint32(i)) + require.NoError(t, err) + require.Equal(t, common.Hash(expectedGER), actualGER) } - return } diff --git a/lastgersync/evmdownloader.go b/lastgersync/evmdownloader.go index c2e09ca3..5c1fde54 100644 --- a/lastgersync/evmdownloader.go +++ b/lastgersync/evmdownloader.go @@ -2,6 +2,7 @@ package lastgersync import ( "context" + "fmt" "math/big" "time" @@ -9,6 +10,7 @@ import ( "github.com/0xPolygon/cdk/l1infotreesync" "github.com/0xPolygon/cdk/log" "github.com/0xPolygon/cdk/sync" + "github.com/0xPolygon/cdk/tree" "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" @@ -63,7 +65,9 @@ func (d *downloader) Download(ctx context.Context, fromBlock uint64, downloadedC ) for { lastIndex, err = d.processor.getLastIndex(ctx) - if err != nil { + if err == ErrNotFound { + lastIndex = 0 + } else if err != nil { log.Errorf("error getting last indes: %v", err) attempts++ d.rh.Handle("getLastIndex", attempts) @@ -115,15 +119,18 @@ func (d *downloader) Download(ctx context.Context, fromBlock uint64, downloadedC func (d *downloader) getGERsFromIndex(ctx context.Context, fromL1InfoTreeIndex uint32) ([]Event, error) { lastIndex, _, err := d.l1InfoTreesync.GetLastL1InfoTreeRootAndIndex(ctx) + if err == tree.ErrNotFound { + return nil, nil + } if err != nil { - return nil, err + return nil, fmt.Errorf("error calling GetLastL1InfoTreeRootAndIndex: %v", err) } gers := []Event{} for i := fromL1InfoTreeIndex; i <= lastIndex; i++ { info, err := d.l1InfoTreesync.GetInfoByIndex(ctx, i) if err != nil { - return nil, err + return nil, fmt.Errorf("error calling GetInfoByIndex: %v", err) } gers = append(gers, Event{ L1InfoTreeIndex: i, diff --git a/lastgersync/lastgersync.go b/lastgersync/lastgersync.go index a8d0f923..2e6434eb 100644 --- a/lastgersync/lastgersync.go +++ b/lastgersync/lastgersync.go @@ -26,7 +26,8 @@ func New( l2Client EthClienter, globalExitRootL2 common.Address, l1InfoTreesync *l1infotreesync.L1InfoTreeSync, - rh *sync.RetryHandler, + retryAfterErrorPeriod time.Duration, + maxRetryAttemptsAfterError int, blockFinality *big.Int, waitForNewBlocksPeriod time.Duration, downloadBufferSize int, @@ -36,6 +37,10 @@ func New( return nil, err } + rh := &sync.RetryHandler{ + RetryAfterErrorPeriod: retryAfterErrorPeriod, + MaxRetryAttemptsAfterError: maxRetryAttemptsAfterError, + } downloader, err := newDownloader( l2Client, globalExitRootL2, @@ -59,3 +64,15 @@ func New( processor: processor, }, nil } + +func (s *LastGERSync) Start(ctx context.Context) { + s.driver.Sync(ctx) +} + +func (s *LastGERSync) GetFirstGERAfterL1InfoTreeIndex(ctx context.Context, l1InfoTreeIndex uint32) (common.Hash, error) { + return s.processor.GetFirstGERAfterL1InfoTreeIndex(ctx, l1InfoTreeIndex) +} + +func (s *LastGERSync) GetLastProcessedBlock(ctx context.Context) (uint64, error) { + return s.processor.GetLastProcessedBlock(ctx) +} diff --git a/test/helpers/aggoracle_e2e.go b/test/helpers/aggoracle_e2e.go index b1cbc3f7..27c3027b 100644 --- a/test/helpers/aggoracle_e2e.go +++ b/test/helpers/aggoracle_e2e.go @@ -38,11 +38,12 @@ type AggoracleWithEVMChainEnv struct { AuthL2 *bind.TransactOpts AggOracle *aggoracle.AggOracle AggOracleSender aggoracle.ChainSender + ReorgDetector *reorgdetector.ReorgDetector } func SetupAggoracleWithEVMChain(t *testing.T) *AggoracleWithEVMChainEnv { ctx := context.Background() - l1Client, syncer, gerL1Contract, gerL1Addr, authL1 := CommonSetup(t) + l1Client, syncer, gerL1Contract, gerL1Addr, authL1, rd := CommonSetup(t) sender, l2Client, gerL2Contract, gerL2Addr, authL2 := EVMSetup(t) oracle, err := aggoracle.New(sender, l1Client.Client(), syncer, etherman.LatestBlock, time.Millisecond) require.NoError(t, err) @@ -60,6 +61,7 @@ func SetupAggoracleWithEVMChain(t *testing.T) *AggoracleWithEVMChainEnv { AuthL2: authL2, AggOracle: oracle, AggOracleSender: sender, + ReorgDetector: rd, } } @@ -69,6 +71,7 @@ func CommonSetup(t *testing.T) ( *gerContractL1.Globalexitrootnopush0, common.Address, *bind.TransactOpts, + *reorgdetector.ReorgDetector, ) { // Config and spin up ctx := context.Background() @@ -89,7 +92,7 @@ func CommonSetup(t *testing.T) ( require.NoError(t, err) go syncer.Start(ctx) - return l1Client, syncer, gerL1Contract, gerL1Addr, authL1 + return l1Client, syncer, gerL1Contract, gerL1Addr, authL1, reorg } func EVMSetup(t *testing.T) (