From c555e6435cf9a90963cfe10f788fac764cbd79ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20Negovanovi=C4=87?= Date: Wed, 25 Dec 2024 16:47:51 +0100 Subject: [PATCH 1/3] remove aggoracle component --- aggoracle/chaingersender/evm.go | 155 --------------- aggoracle/chaingersender/evm_test.go | 168 ----------------- aggoracle/config.go | 25 --- aggoracle/e2e_test.go | 33 ---- aggoracle/mocks/mock_ethtxmanager.go | 270 --------------------------- aggoracle/mocks/mock_l2germanager.go | 97 ---------- aggoracle/oracle.go | 138 -------------- claimsponsor/e2e_test.go | 7 +- cmd/main.go | 3 +- cmd/run.go | 72 +------ common/components.go | 2 - config/config.go | 11 +- config/default.go | 32 ---- docs/SUMMARY.md | 1 - docs/aggoracle.md | 123 ------------ lastgersync/e2e_test.go | 8 +- test/helpers/e2e.go | 28 +-- test/helpers/ethtxmanmock_e2e.go | 6 +- 18 files changed, 34 insertions(+), 1145 deletions(-) delete mode 100644 aggoracle/chaingersender/evm.go delete mode 100644 aggoracle/chaingersender/evm_test.go delete mode 100644 aggoracle/config.go delete mode 100644 aggoracle/e2e_test.go delete mode 100644 aggoracle/mocks/mock_ethtxmanager.go delete mode 100644 aggoracle/mocks/mock_l2germanager.go delete mode 100644 aggoracle/oracle.go delete mode 100644 docs/aggoracle.md diff --git a/aggoracle/chaingersender/evm.go b/aggoracle/chaingersender/evm.go deleted file mode 100644 index adfb19504..000000000 --- a/aggoracle/chaingersender/evm.go +++ /dev/null @@ -1,155 +0,0 @@ -package chaingersender - -import ( - "context" - "fmt" - "math/big" - "time" - - "github.com/0xPolygon/cdk-contracts-tooling/contracts/l2-sovereign-chain/globalexitrootmanagerl2sovereignchain" - cdkcommon "github.com/0xPolygon/cdk/common" - cfgtypes "github.com/0xPolygon/cdk/config/types" - "github.com/0xPolygon/cdk/log" - "github.com/0xPolygon/zkevm-ethtx-manager/ethtxmanager" - ethtxtypes "github.com/0xPolygon/zkevm-ethtx-manager/types" - "github.com/ethereum/go-ethereum" - "github.com/ethereum/go-ethereum/accounts/abi" - "github.com/ethereum/go-ethereum/accounts/abi/bind" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/types" -) - -const insertGERFuncName = "insertGlobalExitRoot" - -type EthClienter interface { - ethereum.LogFilterer - ethereum.BlockNumberReader - ethereum.ChainReader - bind.ContractBackend -} - -type EthTxManager interface { - Remove(ctx context.Context, id common.Hash) error - ResultsByStatus(ctx context.Context, - statuses []ethtxtypes.MonitoredTxStatus, - ) ([]ethtxtypes.MonitoredTxResult, error) - Result(ctx context.Context, id common.Hash) (ethtxtypes.MonitoredTxResult, error) - Add(ctx context.Context, - to *common.Address, - value *big.Int, - data []byte, - gasOffset uint64, - sidecar *types.BlobTxSidecar, - ) (common.Hash, error) -} - -type L2GERManager interface { - GlobalExitRootMap(opts *bind.CallOpts, ger [common.HashLength]byte) (*big.Int, error) -} - -type EVMConfig struct { - GlobalExitRootL2Addr common.Address `mapstructure:"GlobalExitRootL2"` - URLRPCL2 string `mapstructure:"URLRPCL2"` - ChainIDL2 uint64 `mapstructure:"ChainIDL2"` - GasOffset uint64 `mapstructure:"GasOffset"` - WaitPeriodMonitorTx cfgtypes.Duration `mapstructure:"WaitPeriodMonitorTx"` - EthTxManager ethtxmanager.Config `mapstructure:"EthTxManager"` -} - -type EVMChainGERSender struct { - logger *log.Logger - - l2GERManager L2GERManager - l2GERManagerAddr common.Address - l2GERManagerAbi *abi.ABI - - ethTxMan EthTxManager - gasOffset uint64 - waitPeriodMonitorTx time.Duration -} - -func NewEVMChainGERSender( - logger *log.Logger, - l2GERManagerAddr common.Address, - l2Client EthClienter, - ethTxMan EthTxManager, - gasOffset uint64, - waitPeriodMonitorTx time.Duration, -) (*EVMChainGERSender, error) { - l2GERManager, err := globalexitrootmanagerl2sovereignchain.NewGlobalexitrootmanagerl2sovereignchain( - l2GERManagerAddr, l2Client) - if err != nil { - return nil, err - } - - l2GERAbi, err := globalexitrootmanagerl2sovereignchain.Globalexitrootmanagerl2sovereignchainMetaData.GetAbi() - if err != nil { - return nil, err - } - - return &EVMChainGERSender{ - logger: logger, - l2GERManager: l2GERManager, - l2GERManagerAddr: l2GERManagerAddr, - l2GERManagerAbi: l2GERAbi, - ethTxMan: ethTxMan, - gasOffset: gasOffset, - waitPeriodMonitorTx: waitPeriodMonitorTx, - }, nil -} - -func (c *EVMChainGERSender) IsGERInjected(ger common.Hash) (bool, error) { - blockHashBigInt, err := c.l2GERManager.GlobalExitRootMap(&bind.CallOpts{Pending: false}, ger) - if err != nil { - return false, fmt.Errorf("failed to check if global exit root is injected %s: %w", ger, err) - } - - return common.BigToHash(blockHashBigInt) != cdkcommon.ZeroHash, nil -} - -func (c *EVMChainGERSender) InjectGER(ctx context.Context, ger common.Hash) error { - ticker := time.NewTicker(c.waitPeriodMonitorTx) - defer ticker.Stop() - - updateGERTxInput, err := c.l2GERManagerAbi.Pack(insertGERFuncName, ger) - if err != nil { - return err - } - - id, err := c.ethTxMan.Add(ctx, &c.l2GERManagerAddr, common.Big0, updateGERTxInput, c.gasOffset, nil) - if err != nil { - return err - } - - for { - select { - case <-ctx.Done(): - c.logger.Infof("context cancelled") - return nil - - case <-ticker.C: - c.logger.Debugf("waiting for tx %s to be mined", id.Hex()) - res, err := c.ethTxMan.Result(ctx, id) - if err != nil { - c.logger.Errorf("failed to check the transaction %s status: %s", id.Hex(), err) - return err - } - - switch res.Status { - case ethtxtypes.MonitoredTxStatusCreated, - ethtxtypes.MonitoredTxStatusSent: - continue - case ethtxtypes.MonitoredTxStatusFailed: - return fmt.Errorf("inject GER tx %s failed", id.Hex()) - case ethtxtypes.MonitoredTxStatusMined, - ethtxtypes.MonitoredTxStatusSafe, - ethtxtypes.MonitoredTxStatusFinalized: - c.logger.Debugf("inject GER tx %s was successfully mined at block %d", id.Hex(), res.MinedAtBlockNumber) - - return nil - default: - c.logger.Error("unexpected tx status:", res.Status) - } - } - } -} diff --git a/aggoracle/chaingersender/evm_test.go b/aggoracle/chaingersender/evm_test.go deleted file mode 100644 index ad1cb5af0..000000000 --- a/aggoracle/chaingersender/evm_test.go +++ /dev/null @@ -1,168 +0,0 @@ -package chaingersender - -import ( - "context" - "errors" - "math/big" - "strings" - "testing" - "time" - - "github.com/0xPolygon/cdk/aggoracle/mocks" - "github.com/0xPolygon/cdk/log" - "github.com/0xPolygon/zkevm-ethtx-manager/types" - "github.com/ethereum/go-ethereum/accounts/abi" - "github.com/ethereum/go-ethereum/common" - "github.com/stretchr/testify/mock" - "github.com/stretchr/testify/require" -) - -func TestEVMChainGERSender_InjectGER(t *testing.T) { - insertGERFuncABI := `[{ - "inputs": [ - { - "internalType": "bytes32", - "name": "_newRoot", - "type": "bytes32" - } - ], - "name": "insertGlobalExitRoot", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }]` - l2GERManagerAddr := common.HexToAddress("0x123") - l2GERManagerAbi, err := abi.JSON(strings.NewReader(insertGERFuncABI)) - require.NoError(t, err) - - ger := common.HexToHash("0x456") - txID := common.HexToHash("0x789") - - tests := []struct { - name string - addReturnTxID common.Hash - addReturnErr error - resultReturn types.MonitoredTxResult - resultReturnErr error - expectedErr string - }{ - { - name: "successful injection", - addReturnTxID: txID, - addReturnErr: nil, - resultReturn: types.MonitoredTxResult{Status: types.MonitoredTxStatusMined, MinedAtBlockNumber: big.NewInt(123)}, - resultReturnErr: nil, - expectedErr: "", - }, - { - name: "injection fails due to transaction failure", - addReturnTxID: txID, - addReturnErr: nil, - resultReturn: types.MonitoredTxResult{Status: types.MonitoredTxStatusFailed}, - resultReturnErr: nil, - expectedErr: "inject GER tx", - }, - { - name: "injection fails due to Add method error", - addReturnTxID: common.Hash{}, - addReturnErr: errors.New("add error"), - resultReturn: types.MonitoredTxResult{}, - resultReturnErr: nil, - expectedErr: "add error", - }, - { - name: "injection fails due to Result method error", - addReturnTxID: txID, - addReturnErr: nil, - resultReturn: types.MonitoredTxResult{}, - resultReturnErr: errors.New("result error"), - expectedErr: "result error", - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - ctx, cancelFn := context.WithTimeout(context.Background(), time.Millisecond*500) - defer cancelFn() - - ethTxMan := new(mocks.EthTxManagerMock) - ethTxMan. - On("Add", ctx, &l2GERManagerAddr, common.Big0, mock.Anything, mock.Anything, mock.Anything). - Return(tt.addReturnTxID, tt.addReturnErr) - ethTxMan. - On("Result", ctx, tt.addReturnTxID). - Return(tt.resultReturn, tt.resultReturnErr) - - sender := &EVMChainGERSender{ - logger: log.GetDefaultLogger(), - l2GERManagerAddr: l2GERManagerAddr, - l2GERManagerAbi: &l2GERManagerAbi, - ethTxMan: ethTxMan, - waitPeriodMonitorTx: time.Millisecond * 10, - } - - err := sender.InjectGER(ctx, ger) - if tt.expectedErr == "" { - require.NoError(t, err) - } else { - require.Error(t, err) - require.Contains(t, err.Error(), tt.expectedErr) - } - }) - } -} - -func TestEVMChainGERSender_IsGERInjected(t *testing.T) { - tests := []struct { - name string - mockReturn *big.Int - mockError error - expectedResult bool - expectedErrMsg string - }{ - { - name: "GER is injected", - mockReturn: big.NewInt(1), - mockError: nil, - expectedResult: true, - expectedErrMsg: "", - }, - { - name: "GER is not injected", - mockReturn: big.NewInt(0), - mockError: nil, - expectedResult: false, - expectedErrMsg: "", - }, - { - name: "Error checking GER injection", - mockReturn: nil, - mockError: errors.New("some error"), - expectedResult: false, - expectedErrMsg: "failed to check if global exit root is injected", - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - mockL2GERManager := new(mocks.L2GERManagerMock) - mockL2GERManager.On("GlobalExitRootMap", mock.Anything, mock.Anything). - Return(tt.mockReturn, tt.mockError) - - evmChainGERSender := &EVMChainGERSender{ - l2GERManager: mockL2GERManager, - } - - ger := common.HexToHash("0x12345") - result, err := evmChainGERSender.IsGERInjected(ger) - if tt.expectedErrMsg != "" { - require.ErrorContains(t, err, tt.expectedErrMsg) - } else { - require.NoError(t, err) - } - require.Equal(t, tt.expectedResult, result) - - mockL2GERManager.AssertExpectations(t) - }) - } -} diff --git a/aggoracle/config.go b/aggoracle/config.go deleted file mode 100644 index 8559ddb61..000000000 --- a/aggoracle/config.go +++ /dev/null @@ -1,25 +0,0 @@ -package aggoracle - -import ( - "github.com/0xPolygon/cdk/aggoracle/chaingersender" - "github.com/0xPolygon/cdk/config/types" -) - -type TargetChainType string - -const ( - EVMChain TargetChainType = "EVM" -) - -var ( - SupportedChainTypes = []TargetChainType{EVMChain} -) - -type Config struct { - TargetChainType TargetChainType `mapstructure:"TargetChainType"` - URLRPCL1 string `mapstructure:"URLRPCL1"` - // BlockFinality indicates the status of the blocks that will be queried in order to sync - BlockFinality string `jsonschema:"enum=LatestBlock, enum=SafeBlock, enum=PendingBlock, enum=FinalizedBlock, enum=EarliestBlock" mapstructure:"BlockFinality"` //nolint:lll - WaitPeriodNextGER types.Duration `mapstructure:"WaitPeriodNextGER"` - EVMSender chaingersender.EVMConfig `mapstructure:"EVMSender"` -} diff --git a/aggoracle/e2e_test.go b/aggoracle/e2e_test.go deleted file mode 100644 index 648791ebb..000000000 --- a/aggoracle/e2e_test.go +++ /dev/null @@ -1,33 +0,0 @@ -package aggoracle_test - -import ( - "fmt" - "strconv" - "testing" - "time" - - "github.com/0xPolygon/cdk/test/helpers" - "github.com/ethereum/go-ethereum/accounts/abi/bind" - "github.com/ethereum/go-ethereum/common" - "github.com/stretchr/testify/require" -) - -func TestEVM(t *testing.T) { - setup := helpers.NewE2EEnvWithEVML2(t) - - for i := 0; i < 10; i++ { - _, err := setup.L1Environment.GERContract.UpdateExitRoot(setup.L1Environment.Auth, common.HexToHash(strconv.Itoa(i))) - require.NoError(t, err) - setup.L1Environment.SimBackend.Commit() - - // wait for the GER to be processed by the InfoTree syncer - time.Sleep(time.Millisecond * 100) - expectedGER, err := setup.L1Environment.GERContract.GetLastGlobalExitRoot(&bind.CallOpts{Pending: false}) - require.NoError(t, err) - - isInjected, err := setup.L2Environment.AggoracleSender.IsGERInjected(expectedGER) - require.NoError(t, err) - - require.True(t, isInjected, fmt.Sprintf("iteration %d, GER: %s", i, common.Bytes2Hex(expectedGER[:]))) - } -} diff --git a/aggoracle/mocks/mock_ethtxmanager.go b/aggoracle/mocks/mock_ethtxmanager.go deleted file mode 100644 index b011f5682..000000000 --- a/aggoracle/mocks/mock_ethtxmanager.go +++ /dev/null @@ -1,270 +0,0 @@ -// Code generated by mockery. DO NOT EDIT. - -package mocks - -import ( - big "math/big" - - common "github.com/ethereum/go-ethereum/common" - - context "context" - - mock "github.com/stretchr/testify/mock" - - types "github.com/ethereum/go-ethereum/core/types" - - zkevm_ethtx_managertypes "github.com/0xPolygon/zkevm-ethtx-manager/types" -) - -// EthTxManagerMock is an autogenerated mock type for the EthTxManager type -type EthTxManagerMock struct { - mock.Mock -} - -type EthTxManagerMock_Expecter struct { - mock *mock.Mock -} - -func (_m *EthTxManagerMock) EXPECT() *EthTxManagerMock_Expecter { - return &EthTxManagerMock_Expecter{mock: &_m.Mock} -} - -// Add provides a mock function with given fields: ctx, to, value, data, gasOffset, sidecar -func (_m *EthTxManagerMock) Add(ctx context.Context, to *common.Address, value *big.Int, data []byte, gasOffset uint64, sidecar *types.BlobTxSidecar) (common.Hash, error) { - ret := _m.Called(ctx, to, value, data, gasOffset, sidecar) - - if len(ret) == 0 { - panic("no return value specified for Add") - } - - var r0 common.Hash - var r1 error - if rf, ok := ret.Get(0).(func(context.Context, *common.Address, *big.Int, []byte, uint64, *types.BlobTxSidecar) (common.Hash, error)); ok { - return rf(ctx, to, value, data, gasOffset, sidecar) - } - if rf, ok := ret.Get(0).(func(context.Context, *common.Address, *big.Int, []byte, uint64, *types.BlobTxSidecar) common.Hash); ok { - r0 = rf(ctx, to, value, data, gasOffset, sidecar) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(common.Hash) - } - } - - if rf, ok := ret.Get(1).(func(context.Context, *common.Address, *big.Int, []byte, uint64, *types.BlobTxSidecar) error); ok { - r1 = rf(ctx, to, value, data, gasOffset, sidecar) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// EthTxManagerMock_Add_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Add' -type EthTxManagerMock_Add_Call struct { - *mock.Call -} - -// Add is a helper method to define mock.On call -// - ctx context.Context -// - to *common.Address -// - value *big.Int -// - data []byte -// - gasOffset uint64 -// - sidecar *types.BlobTxSidecar -func (_e *EthTxManagerMock_Expecter) Add(ctx interface{}, to interface{}, value interface{}, data interface{}, gasOffset interface{}, sidecar interface{}) *EthTxManagerMock_Add_Call { - return &EthTxManagerMock_Add_Call{Call: _e.mock.On("Add", ctx, to, value, data, gasOffset, sidecar)} -} - -func (_c *EthTxManagerMock_Add_Call) Run(run func(ctx context.Context, to *common.Address, value *big.Int, data []byte, gasOffset uint64, sidecar *types.BlobTxSidecar)) *EthTxManagerMock_Add_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].(*common.Address), args[2].(*big.Int), args[3].([]byte), args[4].(uint64), args[5].(*types.BlobTxSidecar)) - }) - return _c -} - -func (_c *EthTxManagerMock_Add_Call) Return(_a0 common.Hash, _a1 error) *EthTxManagerMock_Add_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *EthTxManagerMock_Add_Call) RunAndReturn(run func(context.Context, *common.Address, *big.Int, []byte, uint64, *types.BlobTxSidecar) (common.Hash, error)) *EthTxManagerMock_Add_Call { - _c.Call.Return(run) - return _c -} - -// Remove provides a mock function with given fields: ctx, id -func (_m *EthTxManagerMock) Remove(ctx context.Context, id common.Hash) error { - ret := _m.Called(ctx, id) - - if len(ret) == 0 { - panic("no return value specified for Remove") - } - - var r0 error - if rf, ok := ret.Get(0).(func(context.Context, common.Hash) error); ok { - r0 = rf(ctx, id) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// EthTxManagerMock_Remove_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Remove' -type EthTxManagerMock_Remove_Call struct { - *mock.Call -} - -// Remove is a helper method to define mock.On call -// - ctx context.Context -// - id common.Hash -func (_e *EthTxManagerMock_Expecter) Remove(ctx interface{}, id interface{}) *EthTxManagerMock_Remove_Call { - return &EthTxManagerMock_Remove_Call{Call: _e.mock.On("Remove", ctx, id)} -} - -func (_c *EthTxManagerMock_Remove_Call) Run(run func(ctx context.Context, id common.Hash)) *EthTxManagerMock_Remove_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].(common.Hash)) - }) - return _c -} - -func (_c *EthTxManagerMock_Remove_Call) Return(_a0 error) *EthTxManagerMock_Remove_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *EthTxManagerMock_Remove_Call) RunAndReturn(run func(context.Context, common.Hash) error) *EthTxManagerMock_Remove_Call { - _c.Call.Return(run) - return _c -} - -// Result provides a mock function with given fields: ctx, id -func (_m *EthTxManagerMock) Result(ctx context.Context, id common.Hash) (zkevm_ethtx_managertypes.MonitoredTxResult, error) { - ret := _m.Called(ctx, id) - - if len(ret) == 0 { - panic("no return value specified for Result") - } - - var r0 zkevm_ethtx_managertypes.MonitoredTxResult - var r1 error - if rf, ok := ret.Get(0).(func(context.Context, common.Hash) (zkevm_ethtx_managertypes.MonitoredTxResult, error)); ok { - return rf(ctx, id) - } - if rf, ok := ret.Get(0).(func(context.Context, common.Hash) zkevm_ethtx_managertypes.MonitoredTxResult); ok { - r0 = rf(ctx, id) - } else { - r0 = ret.Get(0).(zkevm_ethtx_managertypes.MonitoredTxResult) - } - - if rf, ok := ret.Get(1).(func(context.Context, common.Hash) error); ok { - r1 = rf(ctx, id) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// EthTxManagerMock_Result_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Result' -type EthTxManagerMock_Result_Call struct { - *mock.Call -} - -// Result is a helper method to define mock.On call -// - ctx context.Context -// - id common.Hash -func (_e *EthTxManagerMock_Expecter) Result(ctx interface{}, id interface{}) *EthTxManagerMock_Result_Call { - return &EthTxManagerMock_Result_Call{Call: _e.mock.On("Result", ctx, id)} -} - -func (_c *EthTxManagerMock_Result_Call) Run(run func(ctx context.Context, id common.Hash)) *EthTxManagerMock_Result_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].(common.Hash)) - }) - return _c -} - -func (_c *EthTxManagerMock_Result_Call) Return(_a0 zkevm_ethtx_managertypes.MonitoredTxResult, _a1 error) *EthTxManagerMock_Result_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *EthTxManagerMock_Result_Call) RunAndReturn(run func(context.Context, common.Hash) (zkevm_ethtx_managertypes.MonitoredTxResult, error)) *EthTxManagerMock_Result_Call { - _c.Call.Return(run) - return _c -} - -// ResultsByStatus provides a mock function with given fields: ctx, statuses -func (_m *EthTxManagerMock) ResultsByStatus(ctx context.Context, statuses []zkevm_ethtx_managertypes.MonitoredTxStatus) ([]zkevm_ethtx_managertypes.MonitoredTxResult, error) { - ret := _m.Called(ctx, statuses) - - if len(ret) == 0 { - panic("no return value specified for ResultsByStatus") - } - - var r0 []zkevm_ethtx_managertypes.MonitoredTxResult - var r1 error - if rf, ok := ret.Get(0).(func(context.Context, []zkevm_ethtx_managertypes.MonitoredTxStatus) ([]zkevm_ethtx_managertypes.MonitoredTxResult, error)); ok { - return rf(ctx, statuses) - } - if rf, ok := ret.Get(0).(func(context.Context, []zkevm_ethtx_managertypes.MonitoredTxStatus) []zkevm_ethtx_managertypes.MonitoredTxResult); ok { - r0 = rf(ctx, statuses) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).([]zkevm_ethtx_managertypes.MonitoredTxResult) - } - } - - if rf, ok := ret.Get(1).(func(context.Context, []zkevm_ethtx_managertypes.MonitoredTxStatus) error); ok { - r1 = rf(ctx, statuses) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// EthTxManagerMock_ResultsByStatus_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ResultsByStatus' -type EthTxManagerMock_ResultsByStatus_Call struct { - *mock.Call -} - -// ResultsByStatus is a helper method to define mock.On call -// - ctx context.Context -// - statuses []zkevm_ethtx_managertypes.MonitoredTxStatus -func (_e *EthTxManagerMock_Expecter) ResultsByStatus(ctx interface{}, statuses interface{}) *EthTxManagerMock_ResultsByStatus_Call { - return &EthTxManagerMock_ResultsByStatus_Call{Call: _e.mock.On("ResultsByStatus", ctx, statuses)} -} - -func (_c *EthTxManagerMock_ResultsByStatus_Call) Run(run func(ctx context.Context, statuses []zkevm_ethtx_managertypes.MonitoredTxStatus)) *EthTxManagerMock_ResultsByStatus_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].([]zkevm_ethtx_managertypes.MonitoredTxStatus)) - }) - return _c -} - -func (_c *EthTxManagerMock_ResultsByStatus_Call) Return(_a0 []zkevm_ethtx_managertypes.MonitoredTxResult, _a1 error) *EthTxManagerMock_ResultsByStatus_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *EthTxManagerMock_ResultsByStatus_Call) RunAndReturn(run func(context.Context, []zkevm_ethtx_managertypes.MonitoredTxStatus) ([]zkevm_ethtx_managertypes.MonitoredTxResult, error)) *EthTxManagerMock_ResultsByStatus_Call { - _c.Call.Return(run) - return _c -} - -// NewEthTxManagerMock creates a new instance of EthTxManagerMock. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -// The first argument is typically a *testing.T value. -func NewEthTxManagerMock(t interface { - mock.TestingT - Cleanup(func()) -}) *EthTxManagerMock { - mock := &EthTxManagerMock{} - mock.Mock.Test(t) - - t.Cleanup(func() { mock.AssertExpectations(t) }) - - return mock -} diff --git a/aggoracle/mocks/mock_l2germanager.go b/aggoracle/mocks/mock_l2germanager.go deleted file mode 100644 index a7ec0296f..000000000 --- a/aggoracle/mocks/mock_l2germanager.go +++ /dev/null @@ -1,97 +0,0 @@ -// Code generated by mockery. DO NOT EDIT. - -package mocks - -import ( - big "math/big" - - bind "github.com/ethereum/go-ethereum/accounts/abi/bind" - - mock "github.com/stretchr/testify/mock" -) - -// L2GERManagerMock is an autogenerated mock type for the L2GERManager type -type L2GERManagerMock struct { - mock.Mock -} - -type L2GERManagerMock_Expecter struct { - mock *mock.Mock -} - -func (_m *L2GERManagerMock) EXPECT() *L2GERManagerMock_Expecter { - return &L2GERManagerMock_Expecter{mock: &_m.Mock} -} - -// GlobalExitRootMap provides a mock function with given fields: opts, ger -func (_m *L2GERManagerMock) GlobalExitRootMap(opts *bind.CallOpts, ger [32]byte) (*big.Int, error) { - ret := _m.Called(opts, ger) - - if len(ret) == 0 { - panic("no return value specified for GlobalExitRootMap") - } - - var r0 *big.Int - var r1 error - if rf, ok := ret.Get(0).(func(*bind.CallOpts, [32]byte) (*big.Int, error)); ok { - return rf(opts, ger) - } - if rf, ok := ret.Get(0).(func(*bind.CallOpts, [32]byte) *big.Int); ok { - r0 = rf(opts, ger) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*big.Int) - } - } - - if rf, ok := ret.Get(1).(func(*bind.CallOpts, [32]byte) error); ok { - r1 = rf(opts, ger) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// L2GERManagerMock_GlobalExitRootMap_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GlobalExitRootMap' -type L2GERManagerMock_GlobalExitRootMap_Call struct { - *mock.Call -} - -// GlobalExitRootMap is a helper method to define mock.On call -// - opts *bind.CallOpts -// - ger [32]byte -func (_e *L2GERManagerMock_Expecter) GlobalExitRootMap(opts interface{}, ger interface{}) *L2GERManagerMock_GlobalExitRootMap_Call { - return &L2GERManagerMock_GlobalExitRootMap_Call{Call: _e.mock.On("GlobalExitRootMap", opts, ger)} -} - -func (_c *L2GERManagerMock_GlobalExitRootMap_Call) Run(run func(opts *bind.CallOpts, ger [32]byte)) *L2GERManagerMock_GlobalExitRootMap_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(*bind.CallOpts), args[1].([32]byte)) - }) - return _c -} - -func (_c *L2GERManagerMock_GlobalExitRootMap_Call) Return(_a0 *big.Int, _a1 error) *L2GERManagerMock_GlobalExitRootMap_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *L2GERManagerMock_GlobalExitRootMap_Call) RunAndReturn(run func(*bind.CallOpts, [32]byte) (*big.Int, error)) *L2GERManagerMock_GlobalExitRootMap_Call { - _c.Call.Return(run) - return _c -} - -// NewL2GERManagerMock creates a new instance of L2GERManagerMock. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -// The first argument is typically a *testing.T value. -func NewL2GERManagerMock(t interface { - mock.TestingT - Cleanup(func()) -}) *L2GERManagerMock { - mock := &L2GERManagerMock{} - mock.Mock.Test(t) - - t.Cleanup(func() { mock.AssertExpectations(t) }) - - return mock -} diff --git a/aggoracle/oracle.go b/aggoracle/oracle.go deleted file mode 100644 index 2bdc469f8..000000000 --- a/aggoracle/oracle.go +++ /dev/null @@ -1,138 +0,0 @@ -package aggoracle - -import ( - "context" - "errors" - "fmt" - "math/big" - "time" - - "github.com/0xPolygon/cdk/etherman" - "github.com/0xPolygon/cdk/l1infotreesync" - "github.com/0xPolygon/cdk/log" - "github.com/ethereum/go-ethereum" - "github.com/ethereum/go-ethereum/common" -) - -type L1InfoTreer interface { - GetLatestInfoUntilBlock(ctx context.Context, blockNum uint64) (*l1infotreesync.L1InfoTreeLeaf, error) -} - -type ChainSender interface { - IsGERInjected(ger common.Hash) (bool, error) - InjectGER(ctx context.Context, ger common.Hash) error -} - -type AggOracle struct { - logger *log.Logger - waitPeriodNextGER time.Duration - l1Client ethereum.ChainReader - l1Info L1InfoTreer - chainSender ChainSender - blockFinality *big.Int -} - -func New( - logger *log.Logger, - chainSender ChainSender, - l1Client ethereum.ChainReader, - l1InfoTreeSyncer L1InfoTreer, - blockFinalityType etherman.BlockNumberFinality, - waitPeriodNextGER time.Duration, -) (*AggOracle, error) { - finality, err := blockFinalityType.ToBlockNum() - if err != nil { - return nil, err - } - - return &AggOracle{ - logger: logger, - chainSender: chainSender, - l1Client: l1Client, - l1Info: l1InfoTreeSyncer, - blockFinality: finality, - waitPeriodNextGER: waitPeriodNextGER, - }, nil -} - -func (a *AggOracle) Start(ctx context.Context) { - ticker := time.NewTicker(a.waitPeriodNextGER) - defer ticker.Stop() - - var blockNumToFetch uint64 - - for { - select { - case <-ticker.C: - if err := a.processLatestGER(ctx, &blockNumToFetch); err != nil { - a.handleGERProcessingError(err, blockNumToFetch) - } - - case <-ctx.Done(): - return - } - } -} - -// processLatestGER fetches the latest finalized GER, checks if it is already injected and injects it if not -func (a *AggOracle) processLatestGER(ctx context.Context, blockNumToFetch *uint64) error { - // Fetch the latest GER - blockNum, gerToInject, err := a.getLastFinalizedGER(ctx, *blockNumToFetch) - if err != nil { - return err - } - - // Update the block number for the next iteration - *blockNumToFetch = blockNum - - isGERInjected, err := a.chainSender.IsGERInjected(gerToInject) - if err != nil { - return fmt.Errorf("error checking if GER is already injected: %w", err) - } - - if isGERInjected { - a.logger.Debugf("GER %s is already injected", gerToInject.Hex()) - return nil - } - - a.logger.Infof("injecting new GER: %s", gerToInject.Hex()) - if err := a.chainSender.InjectGER(ctx, gerToInject); err != nil { - return fmt.Errorf("error injecting GER %s: %w", gerToInject.Hex(), err) - } - - a.logger.Infof("GER %s is injected successfully", gerToInject.Hex()) - return nil -} - -// handleGERProcessingError handles global exit root processing error -func (a *AggOracle) handleGERProcessingError(err error, blockNumToFetch uint64) { - switch { - case errors.Is(err, l1infotreesync.ErrBlockNotProcessed): - a.logger.Debugf("syncer is not ready for the block %d", blockNumToFetch) - case errors.Is(err, l1infotreesync.ErrNotFound): - a.logger.Debugf("syncer has not found any GER until block %d", blockNumToFetch) - default: - a.logger.Error("unexpected error processing GER: ", err) - } -} - -// getLastFinalizedGER tries to return a finalised GER: -// If targetBlockNum != 0: it will try to fetch it until the given block -// Else it will ask the L1 client for the latest finalised block and use that. -// If it fails to get the GER from the syncer, it will return the block number that used to query -func (a *AggOracle) getLastFinalizedGER(ctx context.Context, targetBlockNum uint64) (uint64, common.Hash, error) { - if targetBlockNum == 0 { - header, err := a.l1Client.HeaderByNumber(ctx, a.blockFinality) - if err != nil { - return 0, common.Hash{}, err - } - targetBlockNum = header.Number.Uint64() - } - - info, err := a.l1Info.GetLatestInfoUntilBlock(ctx, targetBlockNum) - if err != nil { - return targetBlockNum, common.Hash{}, err - } - - return 0, info.GlobalExitRoot, nil -} diff --git a/claimsponsor/e2e_test.go b/claimsponsor/e2e_test.go index 5ad332c0f..d62568aca 100644 --- a/claimsponsor/e2e_test.go +++ b/claimsponsor/e2e_test.go @@ -51,9 +51,12 @@ func TestE2EL1toEVML2(t *testing.T) { expectedGER, err := setup.L1Environment.GERContract.GetLastGlobalExitRoot(&bind.CallOpts{Pending: false}) require.NoError(t, err) - isInjected, err := setup.L2Environment.AggoracleSender.IsGERInjected(expectedGER) + _, err = setup.L2Environment.GERContract.InsertGlobalExitRoot(setup.L2Environment.Auth, expectedGER) require.NoError(t, err) - require.True(t, isInjected, fmt.Sprintf("iteration %d, GER: %s", i, common.Bytes2Hex(expectedGER[:]))) + setup.L2Environment.SimBackend.Commit() + gerIndex, err := setup.L2Environment.GERContract.GlobalExitRootMap(nil, expectedGER) + require.NoError(t, err) + require.Equal(t, big.NewInt(int64(i)+1), gerIndex, fmt.Sprintf("iteration %d, GER: %s is not updated on L2", i, common.Bytes2Hex(expectedGER[:]))) // Build MP using bridgeSyncL1 & env.InfoTreeSync info, err := setup.L1Environment.InfoTreeSync.GetInfoByIndex(ctx, i) diff --git a/cmd/main.go b/cmd/main.go index 3fdb6a8f4..5cd86b261 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -41,8 +41,7 @@ var ( Aliases: []string{"co"}, Usage: "List of components to run", Required: false, - Value: cli.NewStringSlice(common.SEQUENCE_SENDER, common.AGGREGATOR, - common.AGGORACLE, common.BRIDGE, common.AGGSENDER), + Value: cli.NewStringSlice(common.SEQUENCE_SENDER, common.AGGREGATOR, common.BRIDGE, common.AGGSENDER), } saveConfigFlag = cli.StringFlag{ Name: config.FlagSaveConfigPath, diff --git a/cmd/run.go b/cmd/run.go index cca10b60e..e088c740a 100644 --- a/cmd/run.go +++ b/cmd/run.go @@ -13,8 +13,6 @@ import ( dataCommitteeClient "github.com/0xPolygon/cdk-data-availability/client" jRPC "github.com/0xPolygon/cdk-rpc/rpc" "github.com/0xPolygon/cdk/agglayer" - "github.com/0xPolygon/cdk/aggoracle" - "github.com/0xPolygon/cdk/aggoracle/chaingersender" "github.com/0xPolygon/cdk/aggregator" "github.com/0xPolygon/cdk/aggregator/db" "github.com/0xPolygon/cdk/aggsender" @@ -38,7 +36,6 @@ import ( ethtxman "github.com/0xPolygon/zkevm-ethtx-manager/etherman" "github.com/0xPolygon/zkevm-ethtx-manager/etherman/etherscan" "github.com/0xPolygon/zkevm-ethtx-manager/ethtxmanager" - ethtxlog "github.com/0xPolygon/zkevm-ethtx-manager/log" "github.com/ethereum/go-ethereum/ethclient" "github.com/urfave/cli/v2" ) @@ -103,9 +100,7 @@ func start(cliCtx *cli.Context) error { log.Fatal(err) } }() - case cdkcommon.AGGORACLE: - aggOracle := createAggoracle(*cfg, l1Client, l2Client, l1InfoTreeSync) - go aggOracle.Start(cliCtx.Context) + case cdkcommon.BRIDGE: rpcBridge := createBridgeRPC( cfg.RPC, @@ -325,58 +320,6 @@ func newTxBuilder( return txBuilder, err } -func createAggoracle( - cfg config.Config, - l1Client, - l2Client *ethclient.Client, - syncer *l1infotreesync.L1InfoTreeSync, -) *aggoracle.AggOracle { - logger := log.WithFields("module", cdkcommon.AGGORACLE) - var sender aggoracle.ChainSender - switch cfg.AggOracle.TargetChainType { - case aggoracle.EVMChain: - cfg.AggOracle.EVMSender.EthTxManager.Log = ethtxlog.Config{ - Environment: ethtxlog.LogEnvironment(cfg.Log.Environment), - Level: cfg.Log.Level, - Outputs: cfg.Log.Outputs, - } - ethTxManager, err := ethtxmanager.New(cfg.AggOracle.EVMSender.EthTxManager) - if err != nil { - log.Fatal(err) - } - go ethTxManager.Start() - sender, err = chaingersender.NewEVMChainGERSender( - logger, - cfg.AggOracle.EVMSender.GlobalExitRootL2Addr, - l2Client, - ethTxManager, - cfg.AggOracle.EVMSender.GasOffset, - cfg.AggOracle.EVMSender.WaitPeriodMonitorTx.Duration, - ) - if err != nil { - log.Fatal(err) - } - default: - log.Fatalf( - "Unsupported chaintype %s. Supported values: %v", - cfg.AggOracle.TargetChainType, aggoracle.SupportedChainTypes, - ) - } - aggOracle, err := aggoracle.New( - logger, - sender, - l1Client, - syncer, - etherman.BlockNumberFinality(cfg.AggOracle.BlockFinality), - cfg.AggOracle.WaitPeriodNextGER.Duration, - ) - if err != nil { - logger.Fatal(err) - } - - return aggOracle -} - func newDataAvailability(c config.Config, etherman *etherman.Client) (*dataavailability.DataAvailability, error) { if !c.Common.IsValidiumMode { return nil, nil @@ -508,7 +451,7 @@ func runL1InfoTreeSyncerIfNeeded( l1Client *ethclient.Client, reorgDetector *reorgdetector.ReorgDetector, ) *l1infotreesync.L1InfoTreeSync { - if !isNeeded([]string{cdkcommon.AGGORACLE, cdkcommon.BRIDGE, + if !isNeeded([]string{cdkcommon.BRIDGE, cdkcommon.SEQUENCE_SENDER, cdkcommon.AGGSENDER, cdkcommon.L1INFOTREESYNC}, components) { return nil } @@ -538,8 +481,7 @@ func runL1InfoTreeSyncerIfNeeded( func runL1ClientIfNeeded(components []string, urlRPCL1 string) *ethclient.Client { if !isNeeded([]string{ cdkcommon.SEQUENCE_SENDER, cdkcommon.AGGREGATOR, - cdkcommon.AGGORACLE, cdkcommon.BRIDGE, - cdkcommon.AGGSENDER, + cdkcommon.BRIDGE, cdkcommon.AGGSENDER, cdkcommon.L1INFOTREESYNC, }, components) { return nil @@ -568,7 +510,7 @@ func getRollUpIDIfNeeded(components []string, networkConfig ethermanconfig.L1Con } func runL2ClientIfNeeded(components []string, urlRPCL2 string) *ethclient.Client { - if !isNeeded([]string{cdkcommon.AGGORACLE, cdkcommon.BRIDGE, cdkcommon.AGGSENDER}, components) { + if !isNeeded([]string{cdkcommon.BRIDGE, cdkcommon.AGGSENDER}, components) { return nil } @@ -589,7 +531,7 @@ func runReorgDetectorL1IfNeeded( ) (*reorgdetector.ReorgDetector, chan error) { if !isNeeded([]string{ cdkcommon.SEQUENCE_SENDER, cdkcommon.AGGREGATOR, - cdkcommon.AGGORACLE, cdkcommon.BRIDGE, cdkcommon.AGGSENDER, + cdkcommon.BRIDGE, cdkcommon.AGGSENDER, cdkcommon.L1INFOTREESYNC}, components) { return nil, nil @@ -613,7 +555,7 @@ func runReorgDetectorL2IfNeeded( l2Client *ethclient.Client, cfg *reorgdetector.Config, ) (*reorgdetector.ReorgDetector, chan error) { - if !isNeeded([]string{cdkcommon.AGGORACLE, cdkcommon.BRIDGE, cdkcommon.AGGSENDER}, components) { + if !isNeeded([]string{cdkcommon.BRIDGE, cdkcommon.AGGSENDER}, components) { return nil, nil } rd := newReorgDetector(cfg, l2Client) @@ -810,5 +752,5 @@ func getL2RPCUrl(c *config.Config) string { return c.AggSender.URLRPCL2 } - return c.AggOracle.EVMSender.URLRPCL2 + return "" } diff --git a/common/components.go b/common/components.go index 2b562cff7..f1398ae9a 100644 --- a/common/components.go +++ b/common/components.go @@ -5,8 +5,6 @@ const ( SEQUENCE_SENDER = "sequence-sender" //nolint:stylecheck // AGGREGATOR name to identify the aggregator component AGGREGATOR = "aggregator" - // AGGORACLE name to identify the aggoracle component - AGGORACLE = "aggoracle" // BRIDGE name to identify the bridge component (have RPC) BRIDGE = "bridge" // CLAIM_SPONSOR name to identify the claim sponsor component diff --git a/config/config.go b/config/config.go index 9363b93b7..7665dc41d 100644 --- a/config/config.go +++ b/config/config.go @@ -8,7 +8,6 @@ import ( "strings" jRPC "github.com/0xPolygon/cdk-rpc/rpc" - "github.com/0xPolygon/cdk/aggoracle" "github.com/0xPolygon/cdk/aggregator" "github.com/0xPolygon/cdk/aggsender" "github.com/0xPolygon/cdk/bridgesync" @@ -128,22 +127,28 @@ The file is [TOML format] type Config struct { // Configuration of the etherman (client for access L1) Etherman ethermanconfig.Config + // Configuration of the aggregator Aggregator aggregator.Config + // Configure Log level for all the services, allow also to store the logs in a file Log log.Config + // Configuration of the genesis of the network. This is used to known the initial state of the network NetworkConfig NetworkConfig + // Configuration of the sequence sender service SequenceSender sequencesender.Config + // Common Config that affects all the services Common common.Config + // Configuration of the reorg detector service to be used for the L1 ReorgDetectorL1 reorgdetector.Config + // Configuration of the reorg detector service to be used for the L2 ReorgDetectorL2 reorgdetector.Config - // Configuration of the aggOracle service - AggOracle aggoracle.Config + // Configuration of the L1 Info Treee Sync service L1InfoTreeSync l1infotreesync.Config diff --git a/config/default.go b/config/default.go index e53a929a6..0c78a2ce9 100644 --- a/config/default.go +++ b/config/default.go @@ -217,38 +217,6 @@ InitialBlock={{genesisBlockNumber}} RetryAfterErrorPeriod="1s" MaxRetryAttemptsAfterError=-1 -[AggOracle] -TargetChainType="EVM" -URLRPCL1="{{L1URL}}" -BlockFinality="FinalizedBlock" -WaitPeriodNextGER="100ms" - [AggOracle.EVMSender] - GlobalExitRootL2="{{L2Config.GlobalExitRootAddr}}" - URLRPCL2="{{L2URL}}" - ChainIDL2=1337 - GasOffset=0 - WaitPeriodMonitorTx="100ms" - [AggOracle.EVMSender.EthTxManager] - FrequencyToMonitorTxs = "1s" - WaitTxToBeMined = "2s" - GetReceiptMaxTime = "250ms" - GetReceiptWaitInterval = "1s" - PrivateKeys = [ - {Path = "/app/keystore/aggoracle.keystore", Password = "testonly"}, - ] - ForcedGas = 0 - GasPriceMarginFactor = 1 - MaxGasPriceLimit = 0 - StoragePath = "{{PathRWData}}/ethtxmanager-sequencesender.sqlite" - ReadPendingL1Txs = false - SafeStatusL1NumberOfBlocks = 5 - FinalizedStatusL1NumberOfBlocks = 10 - [AggOracle.EVMSender.EthTxManager.Etherman] - URL = "{{L2URL}}" - MultiGasProvider = false - L1ChainID = {{NetworkConfig.L1.L1ChainID}} - HTTPHeaders = [] - [RPC] Host = "0.0.0.0" Port = 5576 diff --git a/docs/SUMMARY.md b/docs/SUMMARY.md index d9d8cddfb..3bc963188 100644 --- a/docs/SUMMARY.md +++ b/docs/SUMMARY.md @@ -4,4 +4,3 @@ - [Local Debug](./local_debug.md) - [DA Integration](./da_integration.md) - [Non-EVM integrations](./non_evm_integration.md) -- [AggOracle](./aggoracle.md) diff --git a/docs/aggoracle.md b/docs/aggoracle.md deleted file mode 100644 index b67675753..000000000 --- a/docs/aggoracle.md +++ /dev/null @@ -1,123 +0,0 @@ -# AggOracle Component - Developer Documentation - -## Overview - -The **AggOracle** component ensures the **Global Exit Root (GER)** is propagated from L1 to the L2 sovereign chain smart contract. This is critical for enabling asset and message bridging between chains. - -The GER is picked up from the smart contract by **LastGERSyncer** for local storage. - -### Key Components: - -- **ChainSender**: Interface for submitting GERs to the smart contract. -- **EVMChainGERSender**: An implementation of `ChainSender`. - ---- - -## Workflow - -### What is Global Exit Root (GER)? - -The **Global Exit Root** consolidates: - -- **Mainnet Exit Root (MER)**: Updated during bridge transactions from L1. -- **Rollup Exit Root (RER)**: Updated when verified rollup batches are submitted via ZKP. - - GER = hash(MER, RER) - -### Process - -1. **Fetch Finalized GER**: - - AggOracle retrieves the latest GER finalized on L1. -2. **Check GER Injection**: - - Confirms whether the GER is already stored in the smart contract. -3. **Inject GER**: - - If missing, AggOracle submits the GER via the `insertGlobalExitRoot` function. -4. **Sync Locally**: - - LastGERSyncer fetches and stores the GER locally for downstream use. - -The sequence diagram below depicts the interaction in the AggOracle. - -```mermaid -sequenceDiagram - participant AggOracle - participant ChainSender - participant L1InfoTreer - participant L1Client - - AggOracle->>AggOracle: start - loop trigger on preconfigured frequency - AggOracle->>AggOracle: process latest GER - AggOracle->>L1InfoTreer: get last finalized GER - alt targetBlockNum == 0 - AggOracle->>L1Client: get (latest) header by number - L1Client-->>AggOracle: the latest header - AggOracle->>L1InfoTreer: get latest L1 info tree until provided header - L1InfoTreer-->>AggOracle: global exit root (from L1 info tree) - else - AggOracle->>L1InfoTreer: get latest L1 info tree until provided header - L1InfoTreer-->>AggOracle: global exit root (from L1 info tree) - end - AggOracle->>ChainSender: check is GER injected - ChainSender-->>AggOracle: isGERInjected result - alt is GER injected - AggOracle->>AggOracle: log GER already injected - else - AggOracle->>ChainSender: inject GER - ChainSender-->>AggOracle: GER injection result - end - end - AggOracle->>AggOracle: handle GER processing error -``` - ---- - -## Key Components - -### 1. AggOracle - -The `AggOracle` fetches the finalized GER and ensures its injection into the L2 smart contract. - -### Functions: - -- **`Start`**: Periodically processes GER updates using a ticker. -- **`processLatestGER`**: Checks if the GER exists and injects it if necessary. -- **`getLastFinalizedGER`**: Retrieves the latest finalized GER based on block finality. - ---- - -### 2. ChainSender Interface - -Defines the interface for submitting GERs. - -``` -IsGERInjected(ger common.Hash) (bool, error) -InjectGER(ctx context.Context, ger common.Hash) error -``` - ---- - -### 3. EVMChainGERSender - -Implements `ChainSender` using Ethereum clients and transaction management. - -### Functions: - -- **`IsGERInjected`**: Verifies GER presence in the smart contract. -- **`InjectGER`**: Submits the GER using the `insertGlobalExitRoot` method and monitors transaction status. - ---- - -## Smart Contract Integration - -- **Contract**: `GlobalExitRootManagerL2SovereignChain.sol` -- **Function**: `insertGlobalExitRoot` - - [Source Code](https://github.com/0xPolygonHermez/zkevm-contracts/blob/feature/audit-remediations/contracts/v2/sovereignChains/GlobalExitRootManagerL2SovereignChain.sol#L89-L103) -- **Bindings**: Available in [cdk-contracts-tooling](https://github.com/0xPolygon/cdk-contracts-tooling/tree/main/contracts/l2-sovereign-chain). - ---- - -## Summary - -The **AggOracle** component automates the propagation of GERs from L1 to L2, enabling bridging across networks. - -Refer to the EVM implementation in [evm.go](https://github.com/0xPolygon/cdk/blob/main/aggoracle/chaingersender/evm.go) for guidance on building new chain senders. diff --git a/lastgersync/e2e_test.go b/lastgersync/e2e_test.go index b0782538a..88036ee84 100644 --- a/lastgersync/e2e_test.go +++ b/lastgersync/e2e_test.go @@ -3,6 +3,7 @@ package lastgersync_test import ( "context" "fmt" + "math/big" "path" "strconv" "testing" @@ -44,9 +45,12 @@ func TestE2E(t *testing.T) { time.Sleep(time.Millisecond * 150) expectedGER, err := setup.L1Environment.GERContract.GetLastGlobalExitRoot(&bind.CallOpts{Pending: false}) require.NoError(t, err) - isInjected, err := setup.AggoracleSender.IsGERInjected(expectedGER) + _, err = setup.L2Environment.GERContract.InsertGlobalExitRoot(setup.L2Environment.Auth, expectedGER) require.NoError(t, err) - require.True(t, isInjected, fmt.Sprintf("iteration %d, GER: %s", i, common.Bytes2Hex(expectedGER[:]))) + setup.L2Environment.SimBackend.Commit() + gerIndex, err := setup.L2Environment.GERContract.GlobalExitRootMap(nil, expectedGER) + require.NoError(t, err) + require.Equal(t, big.NewInt(int64(i+1)), gerIndex, fmt.Sprintf("iteration %d, GER: %s is not updated on L2", i, common.Bytes2Hex(expectedGER[:]))) // Wait for syncer to catch up lb, err := setup.L2Environment.SimBackend.Client().BlockNumber(ctx) diff --git a/test/helpers/e2e.go b/test/helpers/e2e.go index c7fb908e1..42d81463d 100644 --- a/test/helpers/e2e.go +++ b/test/helpers/e2e.go @@ -10,12 +10,9 @@ import ( "github.com/0xPolygon/cdk-contracts-tooling/contracts/l2-sovereign-chain/globalexitrootmanagerl2sovereignchain" "github.com/0xPolygon/cdk-contracts-tooling/contracts/l2-sovereign-chain/polygonzkevmbridgev2" "github.com/0xPolygon/cdk-contracts-tooling/contracts/l2-sovereign-chain/polygonzkevmglobalexitrootv2" - "github.com/0xPolygon/cdk/aggoracle" - "github.com/0xPolygon/cdk/aggoracle/chaingersender" "github.com/0xPolygon/cdk/bridgesync" "github.com/0xPolygon/cdk/etherman" "github.com/0xPolygon/cdk/l1infotreesync" - "github.com/0xPolygon/cdk/log" "github.com/0xPolygon/cdk/reorgdetector" "github.com/0xPolygon/cdk/test/contracts/transparentupgradableproxy" "github.com/ethereum/go-ethereum/accounts/abi/bind" @@ -36,7 +33,6 @@ const ( type AggoracleWithEVMChain struct { L1Environment L2Environment - AggOracle *aggoracle.AggOracle NetworkIDL2 uint32 } @@ -58,11 +54,10 @@ type L1Environment struct { InfoTreeSync *l1infotreesync.L1InfoTreeSync } -// L2Environment contains setup results for L1 network. +// L2Environment contains setup results for L2 network. type L2Environment struct { CommonEnvironment GERContract *globalexitrootmanagerl2sovereignchain.Globalexitrootmanagerl2sovereignchain - AggoracleSender aggoracle.ChainSender EthTxManagerMock *EthTxManagerMock } @@ -70,25 +65,15 @@ type L2Environment struct { func NewE2EEnvWithEVML2(t *testing.T) *AggoracleWithEVMChain { t.Helper() - ctx := context.Background() - // Setup L1 + // Setup L1 environment l1Setup := L1Setup(t) - // Setup L2 EVM + // Setup L2 environment l2Setup := L2Setup(t) - oracle, err := aggoracle.New( - log.GetDefaultLogger(), l2Setup.AggoracleSender, - l1Setup.SimBackend.Client(), l1Setup.InfoTreeSync, - etherman.LatestBlock, time.Millisecond*20, //nolint:mnd - ) - require.NoError(t, err) - go oracle.Start(ctx) - return &AggoracleWithEVMChain{ L1Environment: *l1Setup, L2Environment: *l2Setup, - AggOracle: oracle, NetworkIDL2: rollupID, } } @@ -167,12 +152,6 @@ func L2Setup(t *testing.T) *L2Environment { ethTxManagerMock := NewEthTxManMock(t, l2Client, authL2) - const gerCheckFrequency = time.Millisecond * 50 - sender, err := chaingersender.NewEVMChainGERSender( - log.GetDefaultLogger(), gerL2Addr, l2Client.Client(), - ethTxManagerMock, 0, gerCheckFrequency, - ) - require.NoError(t, err) ctx := context.Background() // Reorg detector @@ -214,7 +193,6 @@ func L2Setup(t *testing.T) *L2Environment { BridgeSync: bridgeL2Sync, }, GERContract: gerL2Contract, - AggoracleSender: sender, EthTxManagerMock: ethTxManagerMock, } } diff --git a/test/helpers/ethtxmanmock_e2e.go b/test/helpers/ethtxmanmock_e2e.go index 1a42ea17c..30f28effd 100644 --- a/test/helpers/ethtxmanmock_e2e.go +++ b/test/helpers/ethtxmanmock_e2e.go @@ -73,9 +73,11 @@ func NewEthTxManMock( return } }). - Return(common.Hash{}, nil) + Return(common.Hash{}, nil). + Maybe() ethTxMock.On("Result", mock.Anything, mock.Anything). - Return(ethtxtypes.MonitoredTxResult{Status: ethtxtypes.MonitoredTxStatusMined}, nil) + Return(ethtxtypes.MonitoredTxResult{Status: ethtxtypes.MonitoredTxStatusMined}, nil). + Maybe() return ethTxMock } From 5ea271c5d6478b4e858f89e1e5e028f70935067d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20Negovanovi=C4=87?= Date: Thu, 26 Dec 2024 09:36:08 +0100 Subject: [PATCH 2/3] improve Rust build perf and cleanup --- Makefile | 2 +- bridgesync/e2e_test.go | 28 ++-- claimsponsor/e2e_test.go | 36 ++--- docs/SUMMARY.md | 1 - docs/non_evm_integration.md | 69 ---------- lastgersync/e2e_test.go | 24 ++-- sequencesender/mocks/mock_ethtxmanager.go | 63 +++++++++ sequencesender/sequencesender.go | 7 + test/Makefile | 7 +- test/helpers/e2e.go | 22 +-- test/helpers/mock_ethtxmanager.go | 155 +++++++++++++++++----- 11 files changed, 248 insertions(+), 166 deletions(-) delete mode 100644 docs/non_evm_integration.md diff --git a/Makefile b/Makefile index fad3c3950..b397985d6 100644 --- a/Makefile +++ b/Makefile @@ -60,7 +60,7 @@ build: build-rust build-go build-tools## Builds the binaries locally into ./tar .PHONY: build-rust build-rust: - export BUILD_SCRIPT_DISABLED=1 && cargo build --release + export BUILD_SCRIPT_DISABLED=1 && cargo build --release --jobs=$(shell nproc) .PHONY: build-go build-go: diff --git a/bridgesync/e2e_test.go b/bridgesync/e2e_test.go index 4b1fc94ae..57a32b6c8 100644 --- a/bridgesync/e2e_test.go +++ b/bridgesync/e2e_test.go @@ -22,7 +22,7 @@ func TestBridgeEventE2E(t *testing.T) { maxReorgDepth = 2 reorgEveryXIterations = 4 // every X blocks go back [1,maxReorgDepth] blocks ) - setup := helpers.NewE2EEnvWithEVML2(t) + l1Env, _ := helpers.NewL1EnvWithL2EVM(t) ctx := context.Background() // Send bridge txs bridgesSent := 0 @@ -39,8 +39,8 @@ func TestBridgeEventE2E(t *testing.T) { Metadata: []byte{}, } lastDepositCount++ - tx, err := setup.L1Environment.BridgeContract.BridgeAsset( - setup.L1Environment.Auth, + tx, err := l1Env.BridgeContract.BridgeAsset( + l1Env.Auth, bridge.DestinationNetwork, bridge.DestinationAddress, bridge.Amount, @@ -48,11 +48,11 @@ func TestBridgeEventE2E(t *testing.T) { true, nil, ) require.NoError(t, err) - helpers.CommitBlocks(t, setup.L1Environment.SimBackend, 1, blockTime) - bn, err := setup.L1Environment.SimBackend.Client().BlockNumber(ctx) + helpers.CommitBlocks(t, l1Env.SimBackend, 1, blockTime) + bn, err := l1Env.SimBackend.Client().BlockNumber(ctx) require.NoError(t, err) bridge.BlockNum = bn - receipt, err := setup.L1Environment.SimBackend.Client().TransactionReceipt(ctx, tx.Hash()) + receipt, err := l1Env.SimBackend.Client().TransactionReceipt(ctx, tx.Hash()) require.NoError(t, err) require.Equal(t, receipt.Status, types.ReceiptStatusSuccessful) expectedBridges = append(expectedBridges, bridge) @@ -61,9 +61,9 @@ func TestBridgeEventE2E(t *testing.T) { // Trigger reorg if i%reorgEveryXIterations == 0 { blocksToReorg := 1 + i%maxReorgDepth - bn, err := setup.L1Environment.SimBackend.Client().BlockNumber(ctx) + bn, err := l1Env.SimBackend.Client().BlockNumber(ctx) require.NoError(t, err) - helpers.Reorg(t, setup.L1Environment.SimBackend, uint64(blocksToReorg)) + helpers.Reorg(t, l1Env.SimBackend, uint64(blocksToReorg)) // Clean expected bridges lastValidBlock := bn - uint64(blocksToReorg) reorgEffective := false @@ -90,20 +90,20 @@ func TestBridgeEventE2E(t *testing.T) { // Wait for syncer to catch up time.Sleep(time.Second * 2) // sleeping since the processor could be up to date, but have pending reorgs - lb, err := setup.L1Environment.SimBackend.Client().BlockNumber(ctx) + lb, err := l1Env.SimBackend.Client().BlockNumber(ctx) require.NoError(t, err) - helpers.RequireProcessorUpdated(t, setup.L1Environment.BridgeSync, lb) + helpers.RequireProcessorUpdated(t, l1Env.BridgeSync, lb) // Get bridges - lastBlock, err := setup.L1Environment.SimBackend.Client().BlockNumber(ctx) + lastBlock, err := l1Env.SimBackend.Client().BlockNumber(ctx) require.NoError(t, err) - actualBridges, err := setup.L1Environment.BridgeSync.GetBridges(ctx, 0, lastBlock) + actualBridges, err := l1Env.BridgeSync.GetBridges(ctx, 0, lastBlock) require.NoError(t, err) // Assert bridges - expectedRoot, err := setup.L1Environment.BridgeContract.GetRoot(nil) + expectedRoot, err := l1Env.BridgeContract.GetRoot(nil) require.NoError(t, err) - root, err := setup.L1Environment.BridgeSync.GetExitRootByIndex(ctx, expectedBridges[len(expectedBridges)-1].DepositCount) + root, err := l1Env.BridgeSync.GetExitRootByIndex(ctx, expectedBridges[len(expectedBridges)-1].DepositCount) require.NoError(t, err) require.Equal(t, common.Hash(expectedRoot).Hex(), root.Hash.Hex()) require.Equal(t, expectedBridges, actualBridges) diff --git a/claimsponsor/e2e_test.go b/claimsponsor/e2e_test.go index d62568aca..f64b6aa71 100644 --- a/claimsponsor/e2e_test.go +++ b/claimsponsor/e2e_test.go @@ -21,19 +21,19 @@ import ( func TestE2EL1toEVML2(t *testing.T) { // start other needed components ctx := context.Background() - setup := helpers.NewE2EEnvWithEVML2(t) + l1Env, l2Env := helpers.NewL1EnvWithL2EVM(t) // start claim sponsor dbPathClaimSponsor := path.Join(t.TempDir(), "claimsponsorTestE2EL1toEVML2_cs.sqlite") claimer, err := claimsponsor.NewEVMClaimSponsor( log.GetDefaultLogger(), dbPathClaimSponsor, - setup.L2Environment.SimBackend.Client(), - setup.L2Environment.BridgeAddr, - setup.L2Environment.Auth.From, + l2Env.SimBackend.Client(), + l2Env.BridgeAddr, + l2Env.Auth.From, 200_000, 0, - setup.EthTxManagerMock, + l2Env.EthTxManagerMock, 0, 0, time.Millisecond*10, time.Millisecond*10, ) require.NoError(t, err) @@ -43,29 +43,29 @@ func TestE2EL1toEVML2(t *testing.T) { for i := uint32(0); i < 3; i++ { // Send bridges to L2, wait for GER to be injected on L2 amount := new(big.Int).SetUint64(uint64(i) + 1) - setup.L1Environment.Auth.Value = amount - _, err := setup.L1Environment.BridgeContract.BridgeAsset(setup.L1Environment.Auth, setup.NetworkIDL2, setup.L2Environment.Auth.From, amount, common.Address{}, true, nil) + l1Env.Auth.Value = amount + _, err := l1Env.BridgeContract.BridgeAsset(l1Env.Auth, l2Env.NetworkID, l2Env.Auth.From, amount, common.Address{}, true, nil) require.NoError(t, err) - setup.L1Environment.SimBackend.Commit() + l1Env.SimBackend.Commit() time.Sleep(time.Millisecond * 300) - expectedGER, err := setup.L1Environment.GERContract.GetLastGlobalExitRoot(&bind.CallOpts{Pending: false}) + expectedGER, err := l1Env.GERContract.GetLastGlobalExitRoot(&bind.CallOpts{Pending: false}) require.NoError(t, err) - _, err = setup.L2Environment.GERContract.InsertGlobalExitRoot(setup.L2Environment.Auth, expectedGER) + _, err = l2Env.GERContract.InsertGlobalExitRoot(l2Env.Auth, expectedGER) require.NoError(t, err) - setup.L2Environment.SimBackend.Commit() - gerIndex, err := setup.L2Environment.GERContract.GlobalExitRootMap(nil, expectedGER) + l2Env.SimBackend.Commit() + gerIndex, err := l2Env.GERContract.GlobalExitRootMap(nil, expectedGER) require.NoError(t, err) require.Equal(t, big.NewInt(int64(i)+1), gerIndex, fmt.Sprintf("iteration %d, GER: %s is not updated on L2", i, common.Bytes2Hex(expectedGER[:]))) // Build MP using bridgeSyncL1 & env.InfoTreeSync - info, err := setup.L1Environment.InfoTreeSync.GetInfoByIndex(ctx, i) + info, err := l1Env.InfoTreeSync.GetInfoByIndex(ctx, i) require.NoError(t, err) - localProof, err := setup.L1Environment.BridgeSync.GetProof(ctx, i, info.MainnetExitRoot) + localProof, err := l1Env.BridgeSync.GetProof(ctx, i, info.MainnetExitRoot) require.NoError(t, err) - rollupProof, err := setup.L1Environment.InfoTreeSync.GetRollupExitTreeMerkleProof(ctx, 0, common.Hash{}) + rollupProof, err := l1Env.InfoTreeSync.GetRollupExitTreeMerkleProof(ctx, 0, common.Hash{}) require.NoError(t, err) // Request to sponsor claim @@ -79,8 +79,8 @@ func TestE2EL1toEVML2(t *testing.T) { RollupExitRoot: info.RollupExitRoot, OriginNetwork: 0, OriginTokenAddress: common.Address{}, - DestinationNetwork: setup.NetworkIDL2, - DestinationAddress: setup.L2Environment.Auth.From, + DestinationNetwork: l2Env.NetworkID, + DestinationAddress: l2Env.Auth.From, Amount: amount, Metadata: nil, }) @@ -103,7 +103,7 @@ func TestE2EL1toEVML2(t *testing.T) { require.True(t, succeed) // Check on contract that is claimed - isClaimed, err := setup.L2Environment.BridgeContract.IsClaimed(&bind.CallOpts{Pending: false}, i, 0) + isClaimed, err := l2Env.BridgeContract.IsClaimed(&bind.CallOpts{Pending: false}, i, 0) require.NoError(t, err) require.True(t, isClaimed) } diff --git a/docs/SUMMARY.md b/docs/SUMMARY.md index 3bc963188..04254646d 100644 --- a/docs/SUMMARY.md +++ b/docs/SUMMARY.md @@ -3,4 +3,3 @@ - [Getting Started](./getting_started.md) - [Local Debug](./local_debug.md) - [DA Integration](./da_integration.md) -- [Non-EVM integrations](./non_evm_integration.md) diff --git a/docs/non_evm_integration.md b/docs/non_evm_integration.md deleted file mode 100644 index ed304ea58..000000000 --- a/docs/non_evm_integration.md +++ /dev/null @@ -1,69 +0,0 @@ -# Integrating non-EVM systems - -This guide explains how to connect a third-party execution environment to the AggLayer using the CDK. - -## Important note - -The following information is experimental, and there aren't any working examples of non-EVM integrations with the AggLayer yet. While we know what needs to be done conceptually, the implementation details are likely to evolve. Think of this as a rough overview of the effort involved, rather than a step-by-step guide towards a production deployment. - -## Key Concepts - -Any system (chain or not chain) should be able to interact with the [unified LxLy bridge](https://docs.polygon.technology/zkEVM/architecture/unified-LxLy) and settle using the [AggLayer](https://docs.polygon.technology/learn/agglayer/overview/); especially when using the [Pessimistic Proof](https://docs.polygon.technology/learn/agglayer/pessimistic_proof/) option. Support for additional proofs, such as consensus, execution, or data availability are planned for the future. But, for now, this guide is based solely on using the Pessimistic Proof for settlement. - -The CDK client handles the integration with both the unified LxLy bridge and AggLayer. Think of it as an SDK to bring your project into the AggLayer ecosystem. You'll need to write some custom code in an adapter/plugin style so that the CDK client can connect with your service. - -In some cases, you might need to write code in `Go`. When that happens, the code should be in a separate repo and imported into the CDK as a dependency. The goal is to provide implementations that can interact with the *smart contracts* of the system being integrated, allowing the CDK client to reuse the same logic across different systems. Basically, you’ll need to create some *adapters* for the new system, while the existing code handles the rest. - -## Components for integration - -### Smart contracts - -For EVM-based integrations, there are two relevant smart contracts: - -- [Global exit root](https://github.com/0xPolygonHermez/zkevm-contracts/blob/feature/sovereign-bridge/contracts/v2/sovereignChains/GlobalExitRootManagerL2SovereignChain.sol) -- [Bridge](https://github.com/0xPolygonHermez/zkevm-contracts/blob/feature/sovereign-bridge/contracts/v2/sovereignChains/BridgeL2SovereignChain.sol) - -The integrated system needs to implement similar functionality. It doesn't have to be a smart contract per se, and it doesn't need to be split into two parts, but it should perform the functions that we list here: - -- Bridge assets and messages to other networks. -- Handle incoming asset/message claims. -- Export local exit roots (a hash needed for other networks to claim assets). -- Import global exit roots (a hash needed for processing bridge claims). - -### AggOracle - -This component imports global exit roots into the smart contract(s). It should be implemented as a `Go` package, using the [EVM example](../aggoracle/chaingersender/evm.go) as a reference. It should implement the `ChainSender` interface defined [here](../aggoracle/oracle.go). - -### BridgeSync - -BridgeSync synchronizes information about bridges and claims originating from the L2 service attached to the CDK client. In other words, it monitors what's happening with the bridge smart contract, collects the necessary data for interacting with the AggLayer, and feeds the bridge service to enable claims on destination networks. - -> **Heads up:** These interfaces may change. - -To process events from non-EVM systems, you'll need a `downloader` and `driver`. The current setup needs some tweaks to support custom implementations. In short, you need to work with the [`Processor`](../bridgesync/processor.go), particularly the `ProcessorInterface` found [here](../sync/driver.go). The `Events` in `Block` are just interfaces, which should be parsed as `Event` structs defined in the [`Processor`](../bridgesync/processor.go). - -### Claim sponsor - -This component performs claims on behalf of users, which is crucial for systems with "gas" fees (transaction costs). Without it, gas-based systems could face a chicken/egg situation: How can users pay for a claim if they need a previous claim to get the funds to pay for it? - -The claim sponsor is optional and may not be needed in some setups. The [bridge RPC](../rpc/bridge.go) includes a config parameter to enable or disable it. To implement a claim sponsor that can perform claim transactions on the bridge smart contract, you'll need to implement the `ClaimSender` interface, defined [here](../claimsponsor/claimsponsor.go). - -### Last GER sync - -> **Warning:** These interfaces may also change. - -This component tracks which global exit roots have been imported. It helps the bridge service know when incoming bridges are ready to be claimed. The work needed is similar to that for the bridge sync: Implement the [`ProcessorInterface`](../sync/driver.go), with events of type `Event` defined [here](../lastgersync/processor.go). - -## Additional considerations - -### Bridge - -Once all components are implemented, the network should be connected to the unified LxLy bridge. However, keep in mind: - -- Outgoing bridges should work with current tools and UIs, but incoming bridges may not. When using the claim sponsor, things should just work. However, the claim sponsor is optional... The point being that the existing UIs are built to send EVM transactions to make the claim in the absence of claim sponsor. So any claim interaction beyond the auto-claim functionality will need UIs and tooling that are out of the sope of the CDK. -- Bridging assets/messages to another network is specific to the integrated system. You'll need to create mechanisms to interact with the *bridge smart contract* of your service for these actions. -- We’re moving towards an *in-CDK* bridge service (spec [here](https://hackmd.io/0vA-XU2BRHmH3Ab0j4ouZw)), replacing the current separate service ([here](https://github.com/0xPolygonHermez/zkevm-bridge-service)). There's no stable API yet, and SDKs/UIs are still in development. - -### AggLayer - -AggLayer integration will work once the components are ready, but initially, it will only support Pessimistic Proof. Later updates will add more security features like execution proofs, consensus proofs, data availability, and forced transactions. These will be optional, while Pessimistic Proof will remain mandatory. \ No newline at end of file diff --git a/lastgersync/e2e_test.go b/lastgersync/e2e_test.go index 88036ee84..2ec7eadfd 100644 --- a/lastgersync/e2e_test.go +++ b/lastgersync/e2e_test.go @@ -19,15 +19,15 @@ import ( func TestE2E(t *testing.T) { ctx := context.Background() - setup := helpers.NewE2EEnvWithEVML2(t) + l1Env, l2Env := helpers.NewL1EnvWithL2EVM(t) dbPathSyncer := path.Join(t.TempDir(), "lastgersyncTestE2E.sqlite") syncer, err := lastgersync.New( ctx, dbPathSyncer, - setup.L2Environment.ReorgDetector, - setup.L2Environment.SimBackend.Client(), - setup.L2Environment.GERAddr, - setup.InfoTreeSync, + l2Env.ReorgDetector, + l2Env.SimBackend.Client(), + l2Env.GERAddr, + l1Env.InfoTreeSync, 0, 0, etherman.LatestBlock, @@ -39,21 +39,21 @@ func TestE2E(t *testing.T) { for i := 0; i < 10; i++ { // Update GER on L1 - _, err := setup.L1Environment.GERContract.UpdateExitRoot(setup.L1Environment.Auth, common.HexToHash(strconv.Itoa(i))) + _, err := l1Env.GERContract.UpdateExitRoot(l1Env.Auth, common.HexToHash(strconv.Itoa(i))) require.NoError(t, err) - setup.L1Environment.SimBackend.Commit() + l1Env.SimBackend.Commit() time.Sleep(time.Millisecond * 150) - expectedGER, err := setup.L1Environment.GERContract.GetLastGlobalExitRoot(&bind.CallOpts{Pending: false}) + expectedGER, err := l1Env.GERContract.GetLastGlobalExitRoot(&bind.CallOpts{Pending: false}) require.NoError(t, err) - _, err = setup.L2Environment.GERContract.InsertGlobalExitRoot(setup.L2Environment.Auth, expectedGER) + _, err = l2Env.GERContract.InsertGlobalExitRoot(l2Env.Auth, expectedGER) require.NoError(t, err) - setup.L2Environment.SimBackend.Commit() - gerIndex, err := setup.L2Environment.GERContract.GlobalExitRootMap(nil, expectedGER) + l2Env.SimBackend.Commit() + gerIndex, err := l2Env.GERContract.GlobalExitRootMap(nil, expectedGER) require.NoError(t, err) require.Equal(t, big.NewInt(int64(i+1)), gerIndex, fmt.Sprintf("iteration %d, GER: %s is not updated on L2", i, common.Bytes2Hex(expectedGER[:]))) // Wait for syncer to catch up - lb, err := setup.L2Environment.SimBackend.Client().BlockNumber(ctx) + lb, err := l2Env.SimBackend.Client().BlockNumber(ctx) require.NoError(t, err) helpers.RequireProcessorUpdated(t, syncer, lb) diff --git a/sequencesender/mocks/mock_ethtxmanager.go b/sequencesender/mocks/mock_ethtxmanager.go index b8a58d0d2..3d0ebebcd 100644 --- a/sequencesender/mocks/mock_ethtxmanager.go +++ b/sequencesender/mocks/mock_ethtxmanager.go @@ -28,6 +28,69 @@ func (_m *EthTxManagerMock) EXPECT() *EthTxManagerMock_Expecter { return &EthTxManagerMock_Expecter{mock: &_m.Mock} } +// Add provides a mock function with given fields: ctx, to, value, data, gasOffset, sidecar +func (_m *EthTxManagerMock) Add(ctx context.Context, to *common.Address, value *big.Int, data []byte, gasOffset uint64, sidecar *types.BlobTxSidecar) (common.Hash, error) { + ret := _m.Called(ctx, to, value, data, gasOffset, sidecar) + + if len(ret) == 0 { + panic("no return value specified for Add") + } + + var r0 common.Hash + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *common.Address, *big.Int, []byte, uint64, *types.BlobTxSidecar) (common.Hash, error)); ok { + return rf(ctx, to, value, data, gasOffset, sidecar) + } + if rf, ok := ret.Get(0).(func(context.Context, *common.Address, *big.Int, []byte, uint64, *types.BlobTxSidecar) common.Hash); ok { + r0 = rf(ctx, to, value, data, gasOffset, sidecar) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(common.Hash) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *common.Address, *big.Int, []byte, uint64, *types.BlobTxSidecar) error); ok { + r1 = rf(ctx, to, value, data, gasOffset, sidecar) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// EthTxManagerMock_Add_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Add' +type EthTxManagerMock_Add_Call struct { + *mock.Call +} + +// Add is a helper method to define mock.On call +// - ctx context.Context +// - to *common.Address +// - value *big.Int +// - data []byte +// - gasOffset uint64 +// - sidecar *types.BlobTxSidecar +func (_e *EthTxManagerMock_Expecter) Add(ctx interface{}, to interface{}, value interface{}, data interface{}, gasOffset interface{}, sidecar interface{}) *EthTxManagerMock_Add_Call { + return &EthTxManagerMock_Add_Call{Call: _e.mock.On("Add", ctx, to, value, data, gasOffset, sidecar)} +} + +func (_c *EthTxManagerMock_Add_Call) Run(run func(ctx context.Context, to *common.Address, value *big.Int, data []byte, gasOffset uint64, sidecar *types.BlobTxSidecar)) *EthTxManagerMock_Add_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(*common.Address), args[2].(*big.Int), args[3].([]byte), args[4].(uint64), args[5].(*types.BlobTxSidecar)) + }) + return _c +} + +func (_c *EthTxManagerMock_Add_Call) Return(_a0 common.Hash, _a1 error) *EthTxManagerMock_Add_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *EthTxManagerMock_Add_Call) RunAndReturn(run func(context.Context, *common.Address, *big.Int, []byte, uint64, *types.BlobTxSidecar) (common.Hash, error)) *EthTxManagerMock_Add_Call { + _c.Call.Return(run) + return _c +} + // AddWithGas provides a mock function with given fields: ctx, to, value, data, gasOffset, sidecar, gas func (_m *EthTxManagerMock) AddWithGas(ctx context.Context, to *common.Address, value *big.Int, data []byte, gasOffset uint64, sidecar *types.BlobTxSidecar, gas uint64) (common.Hash, error) { ret := _m.Called(ctx, to, value, data, gasOffset, sidecar, gas) diff --git a/sequencesender/sequencesender.go b/sequencesender/sequencesender.go index 432b37779..590c97980 100644 --- a/sequencesender/sequencesender.go +++ b/sequencesender/sequencesender.go @@ -29,6 +29,13 @@ const ten = 10 // EthTxManager represents the eth tx manager interface type EthTxManager interface { Start() + Add(ctx context.Context, + to *common.Address, + value *big.Int, + data []byte, + gasOffset uint64, + sidecar *ethtypes.BlobTxSidecar, + ) (common.Hash, error) AddWithGas( ctx context.Context, to *common.Address, diff --git a/test/Makefile b/test/Makefile index 2e81a453a..4cbedecb7 100644 --- a/test/Makefile +++ b/test/Makefile @@ -36,12 +36,7 @@ generate-mocks-l1infotreesync: ## Generates mocks for l1infotreesync, using mock .PHONY: generate-mocks-helpers generate-mocks-helpers: ## Generates mocks for helpers, using mockery tool - export "GOROOT=$$(go env GOROOT)" && $$(go env GOPATH)/bin/mockery --name=EthTxManager --dir=../aggoracle/chaingersender --output=./helpers --outpkg=helpers --structname=EthTxManagerMock --filename=mock_ethtxmanager.go ${COMMON_MOCKERY_PARAMS} - -.PHONY: generate-mocks-aggoracle -generate-mocks-aggoracle: ## Generates mocks for aggoracle, using mockery tool - export "GOROOT=$$(go env GOROOT)" && $$(go env GOPATH)/bin/mockery --name=EthTxManager --dir ../aggoracle/chaingersender --output ../aggoracle/mocks --outpkg mocks --structname=EthTxManagerMock --filename=mock_ethtxmanager.go ${COMMON_MOCKERY_PARAMS} - export "GOROOT=$$(go env GOROOT)" && $$(go env GOPATH)/bin/mockery --name=L2GERManager --dir ../aggoracle/chaingersender --output ../aggoracle/mocks --outpkg mocks --structname=L2GERManagerMock --filename=mock_l2germanager.go ${COMMON_MOCKERY_PARAMS} + export "GOROOT=$$(go env GOROOT)" && $$(go env GOPATH)/bin/mockery --name=EthTxManager --dir=../sequencesender --output=./helpers --outpkg=helpers --structname=EthTxManagerMock --filename=mock_ethtxmanager.go ${COMMON_MOCKERY_PARAMS} .PHONY: generate-mocks-sync generate-mocks-sync: ## Generates mocks for sync, using mockery tool diff --git a/test/helpers/e2e.go b/test/helpers/e2e.go index 42d81463d..8f5f30740 100644 --- a/test/helpers/e2e.go +++ b/test/helpers/e2e.go @@ -30,12 +30,6 @@ const ( periodRetry = time.Millisecond * 100 ) -type AggoracleWithEVMChain struct { - L1Environment - L2Environment - NetworkIDL2 uint32 -} - // CommonEnvironment contains common setup results used in both L1 and L2 network setups. type CommonEnvironment struct { SimBackend *simulated.Backend @@ -59,23 +53,20 @@ type L2Environment struct { CommonEnvironment GERContract *globalexitrootmanagerl2sovereignchain.Globalexitrootmanagerl2sovereignchain EthTxManagerMock *EthTxManagerMock + NetworkID uint32 } -// NewE2EEnvWithEVML2 creates a new E2E environment with EVM L1 and L2 chains. -func NewE2EEnvWithEVML2(t *testing.T) *AggoracleWithEVMChain { +// NewL1EnvWithL2EVM creates a new E2E environment with EVM L1 and L2 chains. +func NewL1EnvWithL2EVM(t *testing.T) (*L1Environment, *L2Environment) { t.Helper() // Setup L1 environment l1Setup := L1Setup(t) // Setup L2 environment - l2Setup := L2Setup(t) + l2Setup := L2Setup(t, rollupID) - return &AggoracleWithEVMChain{ - L1Environment: *l1Setup, - L2Environment: *l2Setup, - NetworkIDL2: rollupID, - } + return l1Setup, l2Setup } // L1Setup creates a new L1 environment. @@ -144,7 +135,7 @@ func L1Setup(t *testing.T) *L1Environment { } // L2Setup creates a new L2 environment. -func L2Setup(t *testing.T) *L2Environment { +func L2Setup(t *testing.T, networkID uint32) *L2Environment { t.Helper() l2Client, authL2, gerL2Addr, gerL2Contract, @@ -194,6 +185,7 @@ func L2Setup(t *testing.T) *L2Environment { }, GERContract: gerL2Contract, EthTxManagerMock: ethTxManagerMock, + NetworkID: networkID, } } diff --git a/test/helpers/mock_ethtxmanager.go b/test/helpers/mock_ethtxmanager.go index ac10be2a8..7937bf1d1 100644 --- a/test/helpers/mock_ethtxmanager.go +++ b/test/helpers/mock_ethtxmanager.go @@ -3,12 +3,11 @@ package helpers import ( + context "context" big "math/big" common "github.com/ethereum/go-ethereum/common" - context "context" - mock "github.com/stretchr/testify/mock" types "github.com/ethereum/go-ethereum/core/types" @@ -92,9 +91,73 @@ func (_c *EthTxManagerMock_Add_Call) RunAndReturn(run func(context.Context, *com return _c } -// Remove provides a mock function with given fields: ctx, id -func (_m *EthTxManagerMock) Remove(ctx context.Context, id common.Hash) error { - ret := _m.Called(ctx, id) +// AddWithGas provides a mock function with given fields: ctx, to, value, data, gasOffset, sidecar, gas +func (_m *EthTxManagerMock) AddWithGas(ctx context.Context, to *common.Address, value *big.Int, data []byte, gasOffset uint64, sidecar *types.BlobTxSidecar, gas uint64) (common.Hash, error) { + ret := _m.Called(ctx, to, value, data, gasOffset, sidecar, gas) + + if len(ret) == 0 { + panic("no return value specified for AddWithGas") + } + + var r0 common.Hash + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *common.Address, *big.Int, []byte, uint64, *types.BlobTxSidecar, uint64) (common.Hash, error)); ok { + return rf(ctx, to, value, data, gasOffset, sidecar, gas) + } + if rf, ok := ret.Get(0).(func(context.Context, *common.Address, *big.Int, []byte, uint64, *types.BlobTxSidecar, uint64) common.Hash); ok { + r0 = rf(ctx, to, value, data, gasOffset, sidecar, gas) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(common.Hash) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *common.Address, *big.Int, []byte, uint64, *types.BlobTxSidecar, uint64) error); ok { + r1 = rf(ctx, to, value, data, gasOffset, sidecar, gas) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// EthTxManagerMock_AddWithGas_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'AddWithGas' +type EthTxManagerMock_AddWithGas_Call struct { + *mock.Call +} + +// AddWithGas is a helper method to define mock.On call +// - ctx context.Context +// - to *common.Address +// - value *big.Int +// - data []byte +// - gasOffset uint64 +// - sidecar *types.BlobTxSidecar +// - gas uint64 +func (_e *EthTxManagerMock_Expecter) AddWithGas(ctx interface{}, to interface{}, value interface{}, data interface{}, gasOffset interface{}, sidecar interface{}, gas interface{}) *EthTxManagerMock_AddWithGas_Call { + return &EthTxManagerMock_AddWithGas_Call{Call: _e.mock.On("AddWithGas", ctx, to, value, data, gasOffset, sidecar, gas)} +} + +func (_c *EthTxManagerMock_AddWithGas_Call) Run(run func(ctx context.Context, to *common.Address, value *big.Int, data []byte, gasOffset uint64, sidecar *types.BlobTxSidecar, gas uint64)) *EthTxManagerMock_AddWithGas_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(*common.Address), args[2].(*big.Int), args[3].([]byte), args[4].(uint64), args[5].(*types.BlobTxSidecar), args[6].(uint64)) + }) + return _c +} + +func (_c *EthTxManagerMock_AddWithGas_Call) Return(_a0 common.Hash, _a1 error) *EthTxManagerMock_AddWithGas_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *EthTxManagerMock_AddWithGas_Call) RunAndReturn(run func(context.Context, *common.Address, *big.Int, []byte, uint64, *types.BlobTxSidecar, uint64) (common.Hash, error)) *EthTxManagerMock_AddWithGas_Call { + _c.Call.Return(run) + return _c +} + +// Remove provides a mock function with given fields: ctx, hash +func (_m *EthTxManagerMock) Remove(ctx context.Context, hash common.Hash) error { + ret := _m.Called(ctx, hash) if len(ret) == 0 { panic("no return value specified for Remove") @@ -102,7 +165,7 @@ func (_m *EthTxManagerMock) Remove(ctx context.Context, id common.Hash) error { var r0 error if rf, ok := ret.Get(0).(func(context.Context, common.Hash) error); ok { - r0 = rf(ctx, id) + r0 = rf(ctx, hash) } else { r0 = ret.Error(0) } @@ -117,12 +180,12 @@ type EthTxManagerMock_Remove_Call struct { // Remove is a helper method to define mock.On call // - ctx context.Context -// - id common.Hash -func (_e *EthTxManagerMock_Expecter) Remove(ctx interface{}, id interface{}) *EthTxManagerMock_Remove_Call { - return &EthTxManagerMock_Remove_Call{Call: _e.mock.On("Remove", ctx, id)} +// - hash common.Hash +func (_e *EthTxManagerMock_Expecter) Remove(ctx interface{}, hash interface{}) *EthTxManagerMock_Remove_Call { + return &EthTxManagerMock_Remove_Call{Call: _e.mock.On("Remove", ctx, hash)} } -func (_c *EthTxManagerMock_Remove_Call) Run(run func(ctx context.Context, id common.Hash)) *EthTxManagerMock_Remove_Call { +func (_c *EthTxManagerMock_Remove_Call) Run(run func(ctx context.Context, hash common.Hash)) *EthTxManagerMock_Remove_Call { _c.Call.Run(func(args mock.Arguments) { run(args[0].(context.Context), args[1].(common.Hash)) }) @@ -139,9 +202,9 @@ func (_c *EthTxManagerMock_Remove_Call) RunAndReturn(run func(context.Context, c return _c } -// Result provides a mock function with given fields: ctx, id -func (_m *EthTxManagerMock) Result(ctx context.Context, id common.Hash) (zkevm_ethtx_managertypes.MonitoredTxResult, error) { - ret := _m.Called(ctx, id) +// Result provides a mock function with given fields: ctx, hash +func (_m *EthTxManagerMock) Result(ctx context.Context, hash common.Hash) (zkevm_ethtx_managertypes.MonitoredTxResult, error) { + ret := _m.Called(ctx, hash) if len(ret) == 0 { panic("no return value specified for Result") @@ -150,16 +213,16 @@ func (_m *EthTxManagerMock) Result(ctx context.Context, id common.Hash) (zkevm_e var r0 zkevm_ethtx_managertypes.MonitoredTxResult var r1 error if rf, ok := ret.Get(0).(func(context.Context, common.Hash) (zkevm_ethtx_managertypes.MonitoredTxResult, error)); ok { - return rf(ctx, id) + return rf(ctx, hash) } if rf, ok := ret.Get(0).(func(context.Context, common.Hash) zkevm_ethtx_managertypes.MonitoredTxResult); ok { - r0 = rf(ctx, id) + r0 = rf(ctx, hash) } else { r0 = ret.Get(0).(zkevm_ethtx_managertypes.MonitoredTxResult) } if rf, ok := ret.Get(1).(func(context.Context, common.Hash) error); ok { - r1 = rf(ctx, id) + r1 = rf(ctx, hash) } else { r1 = ret.Error(1) } @@ -174,12 +237,12 @@ type EthTxManagerMock_Result_Call struct { // Result is a helper method to define mock.On call // - ctx context.Context -// - id common.Hash -func (_e *EthTxManagerMock_Expecter) Result(ctx interface{}, id interface{}) *EthTxManagerMock_Result_Call { - return &EthTxManagerMock_Result_Call{Call: _e.mock.On("Result", ctx, id)} +// - hash common.Hash +func (_e *EthTxManagerMock_Expecter) Result(ctx interface{}, hash interface{}) *EthTxManagerMock_Result_Call { + return &EthTxManagerMock_Result_Call{Call: _e.mock.On("Result", ctx, hash)} } -func (_c *EthTxManagerMock_Result_Call) Run(run func(ctx context.Context, id common.Hash)) *EthTxManagerMock_Result_Call { +func (_c *EthTxManagerMock_Result_Call) Run(run func(ctx context.Context, hash common.Hash)) *EthTxManagerMock_Result_Call { _c.Call.Run(func(args mock.Arguments) { run(args[0].(context.Context), args[1].(common.Hash)) }) @@ -196,9 +259,9 @@ func (_c *EthTxManagerMock_Result_Call) RunAndReturn(run func(context.Context, c return _c } -// ResultsByStatus provides a mock function with given fields: ctx, statuses -func (_m *EthTxManagerMock) ResultsByStatus(ctx context.Context, statuses []zkevm_ethtx_managertypes.MonitoredTxStatus) ([]zkevm_ethtx_managertypes.MonitoredTxResult, error) { - ret := _m.Called(ctx, statuses) +// ResultsByStatus provides a mock function with given fields: ctx, status +func (_m *EthTxManagerMock) ResultsByStatus(ctx context.Context, status []zkevm_ethtx_managertypes.MonitoredTxStatus) ([]zkevm_ethtx_managertypes.MonitoredTxResult, error) { + ret := _m.Called(ctx, status) if len(ret) == 0 { panic("no return value specified for ResultsByStatus") @@ -207,10 +270,10 @@ func (_m *EthTxManagerMock) ResultsByStatus(ctx context.Context, statuses []zkev var r0 []zkevm_ethtx_managertypes.MonitoredTxResult var r1 error if rf, ok := ret.Get(0).(func(context.Context, []zkevm_ethtx_managertypes.MonitoredTxStatus) ([]zkevm_ethtx_managertypes.MonitoredTxResult, error)); ok { - return rf(ctx, statuses) + return rf(ctx, status) } if rf, ok := ret.Get(0).(func(context.Context, []zkevm_ethtx_managertypes.MonitoredTxStatus) []zkevm_ethtx_managertypes.MonitoredTxResult); ok { - r0 = rf(ctx, statuses) + r0 = rf(ctx, status) } else { if ret.Get(0) != nil { r0 = ret.Get(0).([]zkevm_ethtx_managertypes.MonitoredTxResult) @@ -218,7 +281,7 @@ func (_m *EthTxManagerMock) ResultsByStatus(ctx context.Context, statuses []zkev } if rf, ok := ret.Get(1).(func(context.Context, []zkevm_ethtx_managertypes.MonitoredTxStatus) error); ok { - r1 = rf(ctx, statuses) + r1 = rf(ctx, status) } else { r1 = ret.Error(1) } @@ -233,12 +296,12 @@ type EthTxManagerMock_ResultsByStatus_Call struct { // ResultsByStatus is a helper method to define mock.On call // - ctx context.Context -// - statuses []zkevm_ethtx_managertypes.MonitoredTxStatus -func (_e *EthTxManagerMock_Expecter) ResultsByStatus(ctx interface{}, statuses interface{}) *EthTxManagerMock_ResultsByStatus_Call { - return &EthTxManagerMock_ResultsByStatus_Call{Call: _e.mock.On("ResultsByStatus", ctx, statuses)} +// - status []zkevm_ethtx_managertypes.MonitoredTxStatus +func (_e *EthTxManagerMock_Expecter) ResultsByStatus(ctx interface{}, status interface{}) *EthTxManagerMock_ResultsByStatus_Call { + return &EthTxManagerMock_ResultsByStatus_Call{Call: _e.mock.On("ResultsByStatus", ctx, status)} } -func (_c *EthTxManagerMock_ResultsByStatus_Call) Run(run func(ctx context.Context, statuses []zkevm_ethtx_managertypes.MonitoredTxStatus)) *EthTxManagerMock_ResultsByStatus_Call { +func (_c *EthTxManagerMock_ResultsByStatus_Call) Run(run func(ctx context.Context, status []zkevm_ethtx_managertypes.MonitoredTxStatus)) *EthTxManagerMock_ResultsByStatus_Call { _c.Call.Run(func(args mock.Arguments) { run(args[0].(context.Context), args[1].([]zkevm_ethtx_managertypes.MonitoredTxStatus)) }) @@ -255,6 +318,38 @@ func (_c *EthTxManagerMock_ResultsByStatus_Call) RunAndReturn(run func(context.C return _c } +// Start provides a mock function with no fields +func (_m *EthTxManagerMock) Start() { + _m.Called() +} + +// EthTxManagerMock_Start_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Start' +type EthTxManagerMock_Start_Call struct { + *mock.Call +} + +// Start is a helper method to define mock.On call +func (_e *EthTxManagerMock_Expecter) Start() *EthTxManagerMock_Start_Call { + return &EthTxManagerMock_Start_Call{Call: _e.mock.On("Start")} +} + +func (_c *EthTxManagerMock_Start_Call) Run(run func()) *EthTxManagerMock_Start_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *EthTxManagerMock_Start_Call) Return() *EthTxManagerMock_Start_Call { + _c.Call.Return() + return _c +} + +func (_c *EthTxManagerMock_Start_Call) RunAndReturn(run func()) *EthTxManagerMock_Start_Call { + _c.Run(run) + return _c +} + // NewEthTxManagerMock creates a new instance of EthTxManagerMock. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. // The first argument is typically a *testing.T value. func NewEthTxManagerMock(t interface { From 05084c3da575735610b863454bc5363623f152bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20Negovanovi=C4=87?= Date: Thu, 26 Dec 2024 10:33:03 +0100 Subject: [PATCH 3/3] handle error when unmarashaling versions.json --- Makefile | 2 +- crates/cdk/build.rs | 8 +++++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index b397985d6..0174206ac 100644 --- a/Makefile +++ b/Makefile @@ -60,7 +60,7 @@ build: build-rust build-go build-tools## Builds the binaries locally into ./tar .PHONY: build-rust build-rust: - export BUILD_SCRIPT_DISABLED=1 && cargo build --release --jobs=$(shell nproc) + BUILD_SCRIPT_DISABLED=1 cargo build --release --jobs=$(shell nproc) .PHONY: build-go build-go: diff --git a/crates/cdk/build.rs b/crates/cdk/build.rs index cceff95c9..c616a0223 100644 --- a/crates/cdk/build.rs +++ b/crates/cdk/build.rs @@ -85,7 +85,13 @@ fn build_versions() -> std::io::Result<()> { let versions = versions.replace(", }", " }"); // The versions string is a JSON object we can parse - let versions_json: serde_json::Value = serde_json::from_str(&versions).unwrap(); + let versions_json: serde_json::Value = match serde_json::from_str(&versions) { + Ok(json) => json, + Err(e) => { + eprintln!("Failed to parse JSON: {}", e); + return Err(std::io::Error::new(std::io::ErrorKind::Other, "Failed to parse JSON")); + } + }; // Write the versions to a file let dest_path = Path::new(".").join("versions.json");