From d1e3a4cacc5d218d45c1f1c8450869747db11c3a Mon Sep 17 00:00:00 2001 From: dragosrebegea Date: Mon, 12 Aug 2024 18:49:21 +0300 Subject: [PATCH 1/6] add events filter query block number range --- bridges/ethMultiversX/bridgeExecutor.go | 2 +- bridges/ethMultiversX/bridgeExecutor_test.go | 10 +- bridges/ethMultiversX/interface.go | 2 +- clients/ethereum/client.go | 113 ++++++++++-------- clients/ethereum/client_test.go | 44 ++++--- clients/multiversx/client.go | 66 +++++----- cmd/bridge/main.go | 8 +- common/batch.go | 7 +- config/config.go | 18 ++- config/tomlConfigs_test.go | 37 +++--- factory/ethMultiversXBridgeComponents.go | 30 ++--- factory/ethMultiversXBridgeComponents_test.go | 10 +- integrationTests/relayers/common.go | 10 +- testsCommon/bridge/ethereumClientStub.go | 6 +- 14 files changed, 212 insertions(+), 151 deletions(-) diff --git a/bridges/ethMultiversX/bridgeExecutor.go b/bridges/ethMultiversX/bridgeExecutor.go index db9aa9a6..e78af854 100644 --- a/bridges/ethMultiversX/bridgeExecutor.go +++ b/bridges/ethMultiversX/bridgeExecutor.go @@ -474,7 +474,7 @@ func (executor *bridgeExecutor) addBatchSCMetadata(ctx context.Context, transfer return nil, ErrNilBatch } - events, err := executor.ethereumClient.GetBatchSCMetadata(ctx, transfers.ID) + events, err := executor.ethereumClient.GetBatchSCMetadata(ctx, transfers.ID, int64(transfers.BlockNumber)) if err != nil { return nil, err } diff --git a/bridges/ethMultiversX/bridgeExecutor_test.go b/bridges/ethMultiversX/bridgeExecutor_test.go index 7cd2f1c3..0b260512 100644 --- a/bridges/ethMultiversX/bridgeExecutor_test.go +++ b/bridges/ethMultiversX/bridgeExecutor_test.go @@ -361,7 +361,7 @@ func TestEthToMultiversXBridgeExecutor_GetAndStoreBatchFromEthereum(t *testing.T assert.Equal(t, providedNonce, nonce) return expectedBatch, false, nil }, - GetBatchSCMetadataCalled: func(ctx context.Context, nonce uint64) ([]*contract.ERC20SafeERC20SCDeposit, error) { + GetBatchSCMetadataCalled: func(ctx context.Context, nonce uint64, blockNumber int64) ([]*contract.ERC20SafeERC20SCDeposit, error) { return make([]*contract.ERC20SafeERC20SCDeposit, 0), nil }, } @@ -389,7 +389,7 @@ func TestEthToMultiversXBridgeExecutor_GetAndStoreBatchFromEthereum(t *testing.T assert.Equal(t, providedNonce, nonce) return expectedBatch, true, nil }, - GetBatchSCMetadataCalled: func(ctx context.Context, nonce uint64) ([]*contract.ERC20SafeERC20SCDeposit, error) { + GetBatchSCMetadataCalled: func(ctx context.Context, nonce uint64, blockNumber int64) ([]*contract.ERC20SafeERC20SCDeposit, error) { return make([]*contract.ERC20SafeERC20SCDeposit, 0), nil }, } @@ -421,7 +421,7 @@ func TestEthToMultiversXBridgeExecutor_GetAndStoreBatchFromEthereum(t *testing.T assert.Equal(t, providedNonce, nonce) return expectedBatch, true, nil }, - GetBatchSCMetadataCalled: func(ctx context.Context, nonce uint64) ([]*contract.ERC20SafeERC20SCDeposit, error) { + GetBatchSCMetadataCalled: func(ctx context.Context, nonce uint64, blockNumber int64) ([]*contract.ERC20SafeERC20SCDeposit, error) { return []*contract.ERC20SafeERC20SCDeposit{{ DepositNonce: big.NewInt(0).SetUint64(depositNonce), CallData: depositData, @@ -461,7 +461,7 @@ func TestEthToMultiversXBridgeExecutor_GetAndStoreBatchFromEthereum(t *testing.T assert.Equal(t, providedNonce, nonce) return expectedBatch, true, nil }, - GetBatchSCMetadataCalled: func(ctx context.Context, nonce uint64) ([]*contract.ERC20SafeERC20SCDeposit, error) { + GetBatchSCMetadataCalled: func(ctx context.Context, nonce uint64, blockNumber int64) ([]*contract.ERC20SafeERC20SCDeposit, error) { return []*contract.ERC20SafeERC20SCDeposit{{ DepositNonce: big.NewInt(0).SetUint64(depositNonce), CallData: depositData, @@ -494,7 +494,7 @@ func TestEthToMultiversXBridgeExecutor_GetAndStoreBatchFromEthereum(t *testing.T assert.Equal(t, providedNonce, nonce) return expectedBatch, true, nil }, - GetBatchSCMetadataCalled: func(ctx context.Context, nonce uint64) ([]*contract.ERC20SafeERC20SCDeposit, error) { + GetBatchSCMetadataCalled: func(ctx context.Context, nonce uint64, blockNumber int64) ([]*contract.ERC20SafeERC20SCDeposit, error) { return []*contract.ERC20SafeERC20SCDeposit{{ DepositNonce: big.NewInt(0).SetUint64(depositNonce), CallData: depositData, diff --git a/bridges/ethMultiversX/interface.go b/bridges/ethMultiversX/interface.go index cd2edca5..279c812e 100644 --- a/bridges/ethMultiversX/interface.go +++ b/bridges/ethMultiversX/interface.go @@ -53,7 +53,7 @@ type EthereumClient interface { GetTransactionsStatuses(ctx context.Context, batchId uint64) ([]byte, error) GetQuorumSize(ctx context.Context) (*big.Int, error) IsQuorumReached(ctx context.Context, msgHash common.Hash) (bool, error) - GetBatchSCMetadata(ctx context.Context, nonce uint64) ([]*contract.ERC20SafeERC20SCDeposit, error) + GetBatchSCMetadata(ctx context.Context, nonce uint64, blockNumber int64) ([]*contract.ERC20SafeERC20SCDeposit, error) CheckClientAvailability(ctx context.Context) error CheckRequiredBalance(ctx context.Context, erc20Address common.Address, value *big.Int) error TotalBalances(ctx context.Context, token common.Address) (*big.Int, error) diff --git a/clients/ethereum/client.go b/clients/ethereum/client.go index 062fd05a..f8e08916 100644 --- a/clients/ethereum/client.go +++ b/clients/ethereum/client.go @@ -23,43 +23,47 @@ import ( ) const ( - messagePrefix = "\u0019Ethereum Signed Message:\n32" - minQuorumValue = uint64(1) - minAllowedDelta = 1 + messagePrefix = "\u0019Ethereum Signed Message:\n32" + minQuorumValue = uint64(1) + minClientAvailabilityAllowDelta = 1 ) // ArgsEthereumClient is the DTO used in the ethereum's client constructor type ArgsEthereumClient struct { - ClientWrapper ClientWrapper - Erc20ContractsHandler Erc20ContractsHolder - Log chainCore.Logger - AddressConverter core.AddressConverter - Broadcaster Broadcaster - PrivateKey *ecdsa.PrivateKey - TokensMapper TokensMapper - SignatureHolder SignaturesHolder - SafeContractAddress common.Address - GasHandler GasHandler - TransferGasLimitBase uint64 - TransferGasLimitForEach uint64 - AllowDelta uint64 + ClientWrapper ClientWrapper + Erc20ContractsHandler Erc20ContractsHolder + Log chainCore.Logger + AddressConverter core.AddressConverter + Broadcaster Broadcaster + PrivateKey *ecdsa.PrivateKey + TokensMapper TokensMapper + SignatureHolder SignaturesHolder + SafeContractAddress common.Address + GasHandler GasHandler + TransferGasLimitBase uint64 + TransferGasLimitForEach uint64 + ClientAvailabilityAllowDelta uint64 + EventsBlockRangeFrom int64 + EventsBlockRangeTo int64 } type client struct { - clientWrapper ClientWrapper - erc20ContractsHandler Erc20ContractsHolder - log chainCore.Logger - addressConverter core.AddressConverter - broadcaster Broadcaster - privateKey *ecdsa.PrivateKey - publicKey *ecdsa.PublicKey - tokensMapper TokensMapper - signatureHolder SignaturesHolder - safeContractAddress common.Address - gasHandler GasHandler - transferGasLimitBase uint64 - transferGasLimitForEach uint64 - allowDelta uint64 + clientWrapper ClientWrapper + erc20ContractsHandler Erc20ContractsHolder + log chainCore.Logger + addressConverter core.AddressConverter + broadcaster Broadcaster + privateKey *ecdsa.PrivateKey + publicKey *ecdsa.PublicKey + tokensMapper TokensMapper + signatureHolder SignaturesHolder + safeContractAddress common.Address + gasHandler GasHandler + transferGasLimitBase uint64 + transferGasLimitForEach uint64 + clientAvailabilityAllowDelta uint64 + eventsBlockRangeFrom int64 + eventsBlockRangeTo int64 lastBlockNumber uint64 retriesAvailabilityCheck uint64 @@ -80,20 +84,22 @@ func NewEthereumClient(args ArgsEthereumClient) (*client, error) { } c := &client{ - clientWrapper: args.ClientWrapper, - erc20ContractsHandler: args.Erc20ContractsHandler, - log: args.Log, - addressConverter: args.AddressConverter, - broadcaster: args.Broadcaster, - privateKey: args.PrivateKey, - publicKey: publicKeyECDSA, - tokensMapper: args.TokensMapper, - signatureHolder: args.SignatureHolder, - safeContractAddress: args.SafeContractAddress, - gasHandler: args.GasHandler, - transferGasLimitBase: args.TransferGasLimitBase, - transferGasLimitForEach: args.TransferGasLimitForEach, - allowDelta: args.AllowDelta, + clientWrapper: args.ClientWrapper, + erc20ContractsHandler: args.Erc20ContractsHandler, + log: args.Log, + addressConverter: args.AddressConverter, + broadcaster: args.Broadcaster, + privateKey: args.PrivateKey, + publicKey: publicKeyECDSA, + tokensMapper: args.TokensMapper, + signatureHolder: args.SignatureHolder, + safeContractAddress: args.SafeContractAddress, + gasHandler: args.GasHandler, + transferGasLimitBase: args.TransferGasLimitBase, + transferGasLimitForEach: args.TransferGasLimitForEach, + clientAvailabilityAllowDelta: args.ClientAvailabilityAllowDelta, + eventsBlockRangeFrom: args.EventsBlockRangeFrom, + eventsBlockRangeTo: args.EventsBlockRangeTo, } c.log.Info("NewEthereumClient", @@ -137,9 +143,13 @@ func checkArgs(args ArgsEthereumClient) error { if args.TransferGasLimitForEach == 0 { return errInvalidGasLimit } - if args.AllowDelta < minAllowedDelta { + if args.ClientAvailabilityAllowDelta < minClientAvailabilityAllowDelta { return fmt.Errorf("%w for args.AllowedDelta, got: %d, minimum: %d", - clients.ErrInvalidValue, args.AllowDelta, minAllowedDelta) + clients.ErrInvalidValue, args.ClientAvailabilityAllowDelta, minClientAvailabilityAllowDelta) + } + if args.EventsBlockRangeFrom > args.EventsBlockRangeTo { + return fmt.Errorf("%w, args.EventsBlockRangeFrom: %d, args.EventsBlockRangeTo: %d", + clients.ErrInvalidValue, args.EventsBlockRangeFrom, args.EventsBlockRangeTo) } return nil } @@ -162,8 +172,9 @@ func (c *client) GetBatch(ctx context.Context, nonce uint64) (*bridgeCommon.Tran } transferBatch := &bridgeCommon.TransferBatch{ - ID: batch.Nonce.Uint64(), - Deposits: make([]*bridgeCommon.DepositTransfer, 0, batch.DepositsCount), + ID: batch.Nonce.Uint64(), + BlockNumber: batch.BlockNumber, + Deposits: make([]*bridgeCommon.DepositTransfer, 0, batch.DepositsCount), } cachedTokens := make(map[string][]byte) for i := range deposits { @@ -202,7 +213,7 @@ func (c *client) GetBatch(ctx context.Context, nonce uint64) (*bridgeCommon.Tran } // GetBatchSCMetadata returns the emitted logs in a batch that hold metadata for SC execution on MVX -func (c *client) GetBatchSCMetadata(ctx context.Context, nonce uint64) ([]*contract.ERC20SafeERC20SCDeposit, error) { +func (c *client) GetBatchSCMetadata(ctx context.Context, nonce uint64, blockNumber int64) ([]*contract.ERC20SafeERC20SCDeposit, error) { scExecAbi, err := contract.ERC20SafeMetaData.GetAbi() if err != nil { return nil, err @@ -214,6 +225,8 @@ func (c *client) GetBatchSCMetadata(ctx context.Context, nonce uint64) ([]*contr {scExecAbi.Events["ERC20SCDeposit"].ID}, {common.BytesToHash(new(big.Int).SetUint64(nonce).Bytes())}, }, + FromBlock: big.NewInt(blockNumber + c.eventsBlockRangeFrom), + ToBlock: big.NewInt(blockNumber + c.eventsBlockRangeTo), } logs, err := c.clientWrapper.FilterLogs(ctx, query) @@ -401,7 +414,7 @@ func (c *client) CheckClientAvailability(ctx context.Context) error { // if we reached this point we will need to increment the retries counter defer c.incrementRetriesAvailabilityCheck() - if c.retriesAvailabilityCheck > c.allowDelta { + if c.retriesAvailabilityCheck > c.clientAvailabilityAllowDelta { message := fmt.Sprintf("block %d fetched for %d times in a row", currentBlock, c.retriesAvailabilityCheck) c.setStatusForAvailabilityCheck(ethmultiversx.Unavailable, message, currentBlock) diff --git a/clients/ethereum/client_test.go b/clients/ethereum/client_test.go index a6a214ce..e6460975 100644 --- a/clients/ethereum/client_test.go +++ b/clients/ethereum/client_test.go @@ -54,12 +54,14 @@ func createMockEthereumClientArgs() ArgsEthereumClient { return append([]byte("ERC20"), sourceBytes...), nil }, }, - SignatureHolder: &testsCommon.SignaturesHolderStub{}, - SafeContractAddress: testsCommon.CreateRandomEthereumAddress(), - GasHandler: &testsCommon.GasHandlerStub{}, - TransferGasLimitBase: 50, - TransferGasLimitForEach: 20, - AllowDelta: 5, + SignatureHolder: &testsCommon.SignaturesHolderStub{}, + SafeContractAddress: testsCommon.CreateRandomEthereumAddress(), + GasHandler: &testsCommon.GasHandlerStub{}, + TransferGasLimitBase: 50, + TransferGasLimitForEach: 20, + ClientAvailabilityAllowDelta: 5, + EventsBlockRangeFrom: -100, + EventsBlockRangeTo: 400, } } @@ -185,11 +187,11 @@ func TestNewEthereumClient(t *testing.T) { assert.Equal(t, errInvalidGasLimit, err) assert.True(t, check.IfNil(c)) }) - t.Run("invalid AllowDelta should error", func(t *testing.T) { + t.Run("invalid ClientAvailabilityAllowDelta should error", func(t *testing.T) { t.Parallel() args := createMockEthereumClientArgs() - args.AllowDelta = 0 + args.ClientAvailabilityAllowDelta = 0 c, err := NewEthereumClient(args) @@ -197,6 +199,20 @@ func TestNewEthereumClient(t *testing.T) { assert.True(t, errors.Is(err, clients.ErrInvalidValue)) assert.True(t, strings.Contains(err.Error(), "for args.AllowedDelta")) }) + t.Run("invalid events block range from should error", func(t *testing.T) { + t.Parallel() + + args := createMockEthereumClientArgs() + args.EventsBlockRangeFrom = 100 + args.EventsBlockRangeTo = 50 + + c, err := NewEthereumClient(args) + + assert.True(t, check.IfNil(c)) + assert.True(t, errors.Is(err, clients.ErrInvalidValue)) + assert.True(t, strings.Contains(err.Error(), "args.EventsBlockRangeFrom")) + assert.True(t, strings.Contains(err.Error(), "args.EventsBlockRangeTo")) + }) t.Run("should work", func(t *testing.T) { args := createMockEthereumClientArgs() c, err := NewEthereumClient(args) @@ -1144,14 +1160,14 @@ func TestClient_CheckClientAvailability(t *testing.T) { statusHandler.SetStringMetric(bridgeCore.MetricLastMultiversXClientError, "random") // this will just increment the retry counter - for i := 0; i < int(args.AllowDelta); i++ { + for i := 0; i < int(args.ClientAvailabilityAllowDelta); i++ { err := c.CheckClientAvailability(context.Background()) assert.Nil(t, err) checkStatusHandler(t, statusHandler, ethmultiversx.Available, "") } for i := 0; i < 10; i++ { - message := fmt.Sprintf("block %d fetched for %d times in a row", currentNonce, args.AllowDelta+uint64(i+1)) + message := fmt.Sprintf("block %d fetched for %d times in a row", currentNonce, args.ClientAvailabilityAllowDelta+uint64(i+1)) err := c.CheckClientAvailability(context.Background()) assert.Nil(t, err) checkStatusHandler(t, statusHandler, ethmultiversx.Unavailable, message) @@ -1164,14 +1180,14 @@ func TestClient_CheckClientAvailability(t *testing.T) { incrementor = 0 // this will just increment the retry counter - for i := 0; i < int(args.AllowDelta); i++ { + for i := 0; i < int(args.ClientAvailabilityAllowDelta); i++ { err := c.CheckClientAvailability(context.Background()) assert.Nil(t, err) checkStatusHandler(t, statusHandler, ethmultiversx.Available, "") } for i := 0; i < 10; i++ { - message := fmt.Sprintf("block %d fetched for %d times in a row", currentNonce, args.AllowDelta+uint64(i+1)) + message := fmt.Sprintf("block %d fetched for %d times in a row", currentNonce, args.ClientAvailabilityAllowDelta+uint64(i+1)) err := c.CheckClientAvailability(context.Background()) assert.Nil(t, err) checkStatusHandler(t, statusHandler, ethmultiversx.Unavailable, message) @@ -1211,7 +1227,7 @@ func TestClient_GetBatchSCMetadata(t *testing.T) { }, } c, _ := NewEthereumClient(args) - batch, err := c.GetBatchSCMetadata(context.Background(), 0) + batch, err := c.GetBatchSCMetadata(context.Background(), 0, 0) assert.Nil(t, batch) assert.Equal(t, expectedErr, err) }) @@ -1239,7 +1255,7 @@ func TestClient_GetBatchSCMetadata(t *testing.T) { }, } c, _ := NewEthereumClient(args) - batch, err := c.GetBatchSCMetadata(context.Background(), expectedEvent.BatchId.Uint64()) + batch, err := c.GetBatchSCMetadata(context.Background(), expectedEvent.BatchId.Uint64(), 500) assert.Nil(t, err) assert.Equal(t, 1, len(batch)) diff --git a/clients/multiversx/client.go b/clients/multiversx/client.go index 8ecd9cd7..99778529 100644 --- a/clients/multiversx/client.go +++ b/clients/multiversx/client.go @@ -28,11 +28,11 @@ import ( ) const ( - proposeTransferFuncName = "proposeMultiTransferEsdtBatch" - proposeSetStatusFuncName = "proposeEsdtSafeSetCurrentTransactionBatchStatus" - signFuncName = "sign" - performActionFuncName = "performAction" - minAllowedDelta = 1 + proposeTransferFuncName = "proposeMultiTransferEsdtBatch" + proposeSetStatusFuncName = "proposeEsdtSafeSetCurrentTransactionBatchStatus" + signFuncName = "sign" + performActionFuncName = "performAction" + minClientAvailabilityAllowDelta = 1 multiversXDataGetterLogId = "MultiversXEth-MultiversXDataGetter" ) @@ -49,24 +49,24 @@ type ClientArgs struct { TokensMapper TokensMapper RoleProvider roleProvider StatusHandler bridgeCore.StatusHandler - AllowDelta uint64 + ClientAvailabilityAllowDelta uint64 } // client represents the MultiversX Client implementation type client struct { *mxClientDataGetter - codec *parsers.MultiversxCodec - txHandler txHandler - tokensMapper TokensMapper - relayerPublicKey crypto.PublicKey - relayerAddress core.AddressHandler - multisigContractAddress core.AddressHandler - safeContractAddress core.AddressHandler - log logger.Logger - gasMapConfig config.MultiversXGasMapConfig - addressPublicKeyConverter bridgeCore.AddressConverter - statusHandler bridgeCore.StatusHandler - allowDelta uint64 + codec *parsers.MultiversxCodec + txHandler txHandler + tokensMapper TokensMapper + relayerPublicKey crypto.PublicKey + relayerAddress core.AddressHandler + multisigContractAddress core.AddressHandler + safeContractAddress core.AddressHandler + log logger.Logger + gasMapConfig config.MultiversXGasMapConfig + addressPublicKeyConverter bridgeCore.AddressConverter + statusHandler bridgeCore.StatusHandler + clientAvailabilityAllowDelta uint64 lastNonce uint64 retriesAvailabilityCheck uint64 @@ -135,17 +135,17 @@ func NewClient(args ClientArgs) (*client, error) { singleSigner: &singlesig.Ed25519Signer{}, roleProvider: args.RoleProvider, }, - mxClientDataGetter: getter, - relayerPublicKey: publicKey, - relayerAddress: relayerAddress, - multisigContractAddress: args.MultisigContractAddress, - safeContractAddress: args.SafeContractAddress, - log: args.Log, - gasMapConfig: args.GasMapConfig, - addressPublicKeyConverter: addressConverter, - tokensMapper: args.TokensMapper, - statusHandler: args.StatusHandler, - allowDelta: args.AllowDelta, + mxClientDataGetter: getter, + relayerPublicKey: publicKey, + relayerAddress: relayerAddress, + multisigContractAddress: args.MultisigContractAddress, + safeContractAddress: args.SafeContractAddress, + log: args.Log, + gasMapConfig: args.GasMapConfig, + addressPublicKeyConverter: addressConverter, + tokensMapper: args.TokensMapper, + statusHandler: args.StatusHandler, + clientAvailabilityAllowDelta: args.ClientAvailabilityAllowDelta, } bech32RelayerAddress, _ := relayerAddress.AddressAsBech32String() @@ -182,9 +182,9 @@ func checkArgs(args ClientArgs) error { if check.IfNil(args.StatusHandler) { return clients.ErrNilStatusHandler } - if args.AllowDelta < minAllowedDelta { - return fmt.Errorf("%w for args.AllowedDelta, got: %d, minimum: %d", - clients.ErrInvalidValue, args.AllowDelta, minAllowedDelta) + if args.ClientAvailabilityAllowDelta < minClientAvailabilityAllowDelta { + return fmt.Errorf("%w for args.ClientAvailabilityAllowDelta, got: %d, minimum: %d", + clients.ErrInvalidValue, args.ClientAvailabilityAllowDelta, minClientAvailabilityAllowDelta) } err := checkGasMapValues(args.GasMapConfig) if err != nil { @@ -516,7 +516,7 @@ func (c *client) CheckClientAvailability(ctx context.Context) error { // if we reached this point we will need to increment the retries counter defer c.incrementRetriesAvailabilityCheck() - if c.retriesAvailabilityCheck > c.allowDelta { + if c.retriesAvailabilityCheck > c.clientAvailabilityAllowDelta { message := fmt.Sprintf("nonce %d fetched for %d times in a row", currentNonce, c.retriesAvailabilityCheck) c.setStatusForAvailabilityCheck(ethmultiversx.Unavailable, message, currentNonce) diff --git a/cmd/bridge/main.go b/cmd/bridge/main.go index f1f9653c..6a84da96 100644 --- a/cmd/bridge/main.go +++ b/cmd/bridge/main.go @@ -162,10 +162,10 @@ func startRelay(ctx *cli.Context, version string) error { ProxyURL: cfg.MultiversX.NetworkAddress, SameScState: false, ShouldBeSynced: false, - FinalityCheck: cfg.MultiversX.ProxyFinalityCheck, - AllowedDeltaToFinal: cfg.MultiversX.ProxyMaxNoncesDelta, - CacheExpirationTime: time.Second * time.Duration(cfg.MultiversX.ProxyCacherExpirationSeconds), - EntityType: sdkCore.RestAPIEntityType(cfg.MultiversX.ProxyRestAPIEntityType), + FinalityCheck: cfg.MultiversX.Proxy.FinalityCheck, + AllowedDeltaToFinal: cfg.MultiversX.Proxy.MaxNoncesDelta, + CacheExpirationTime: time.Second * time.Duration(cfg.MultiversX.Proxy.CacherExpirationSeconds), + EntityType: sdkCore.RestAPIEntityType(cfg.MultiversX.Proxy.RestAPIEntityType), } proxy, err := blockchain.NewProxy(argsProxy) if err != nil { diff --git a/common/batch.go b/common/batch.go index eeeb817d..933ba6a8 100644 --- a/common/batch.go +++ b/common/batch.go @@ -12,9 +12,10 @@ var log = logger.GetOrCreate("clients") // TransferBatch is the transfer batch structure agnostic of any chain implementation type TransferBatch struct { - ID uint64 `json:"batchId"` - Deposits []*DepositTransfer `json:"deposits"` - Statuses []byte `json:"statuses"` + ID uint64 `json:"batchId"` + BlockNumber uint64 `json:"blockNumber"` + Deposits []*DepositTransfer `json:"deposits"` + Statuses []byte `json:"statuses"` } // Clone will deep clone the current TransferBatch instance diff --git a/config/config.go b/config/config.go index c653fe9d..1976d3d0 100644 --- a/config/config.go +++ b/config/config.go @@ -38,7 +38,9 @@ type EthereumConfig struct { GasStation GasStationConfig MaxRetriesOnQuorumReached uint64 IntervalToWaitForTransferInSeconds uint64 - MaxBlocksDelta uint64 + ClientAvailabilityAllowDelta uint64 + EventsBlockRangeFrom int64 + EventsBlockRangeTo int64 } // GasStationConfig represents the configuration for the gas station handler @@ -147,10 +149,16 @@ type MultiversXConfig struct { GasMap MultiversXGasMapConfig MaxRetriesOnQuorumReached uint64 MaxRetriesOnWasTransferProposed uint64 - ProxyCacherExpirationSeconds uint64 - ProxyRestAPIEntityType string - ProxyMaxNoncesDelta int - ProxyFinalityCheck bool + ClientAvailabilityAllowDelta uint64 + Proxy ProxyConfig +} + +// ProxyConfig represents the configuration for the MultiversX proxy +type ProxyConfig struct { + CacherExpirationSeconds uint64 + RestAPIEntityType string + MaxNoncesDelta int + FinalityCheck bool } // MultiversXGasMapConfig represents the gas limits for MultiversX operations diff --git a/config/tomlConfigs_test.go b/config/tomlConfigs_test.go index e5a8ba23..4934e44b 100644 --- a/config/tomlConfigs_test.go +++ b/config/tomlConfigs_test.go @@ -34,8 +34,10 @@ func TestConfigs(t *testing.T) { GasPriceSelector: "SafeGasPrice", GasPriceMultiplier: 1000000000, }, - MaxRetriesOnQuorumReached: 3, - MaxBlocksDelta: 10, + MaxRetriesOnQuorumReached: 3, + ClientAvailabilityAllowDelta: 10, + EventsBlockRangeFrom: -100, + EventsBlockRangeTo: 400, }, MultiversX: MultiversXConfig{ NetworkAddress: "https://devnet-gateway.multiversx.com", @@ -54,10 +56,13 @@ func TestConfigs(t *testing.T) { }, MaxRetriesOnQuorumReached: 3, MaxRetriesOnWasTransferProposed: 3, - ProxyCacherExpirationSeconds: 600, - ProxyRestAPIEntityType: "observer", - ProxyMaxNoncesDelta: 7, - ProxyFinalityCheck: true, + ClientAvailabilityAllowDelta: 10, + Proxy: ProxyConfig{ + CacherExpirationSeconds: 600, + RestAPIEntityType: "observer", + MaxNoncesDelta: 7, + FinalityCheck: true, + }, }, P2P: ConfigP2P{ Port: "10010", @@ -222,7 +227,9 @@ func TestConfigs(t *testing.T) { GasLimitForEach = 30000 IntervalToWaitForTransferInSeconds = 600 #10 minutes MaxRetriesOnQuorumReached = 3 - MaxBlocksDelta = 10 + ClientAvailabilityAllowDelta = 10 + EventsBlockRangeFrom = -100 + EventsBlockRangeTo = 400 [Eth.GasStation] Enabled = true URL = "https://api.etherscan.io/api?module=gastracker&action=gasoracle" # gas station URL. Suggestion to provide the api-key here @@ -243,13 +250,15 @@ func TestConfigs(t *testing.T) { IntervalToResendTxsInSeconds = 60 # the time in seconds between nonce reads MaxRetriesOnQuorumReached = 3 MaxRetriesOnWasTransferProposed = 3 - ProxyCacherExpirationSeconds = 600 # the caching time in seconds - - # valid options for ProxyRestAPIEntityType are "observer" and "proxy". Any other value will trigger an error. - # "observer" is useful when querying an observer, directly and "proxy" is useful when querying a squad's proxy (gateway) - ProxyRestAPIEntityType = "observer" - ProxyFinalityCheck = true - ProxyMaxNoncesDelta = 7 # the number of maximum blocks allowed to be "in front" of what the metachain has notarized + ClientAvailabilityAllowDelta = 10 + [MultiversX.Proxy] + CacherExpirationSeconds = 600 # the caching time in seconds + + # valid options for ProxyRestAPIEntityType are "observer" and "proxy". Any other value will trigger an error. + # "observer" is useful when querying an observer, directly and "proxy" is useful when querying a squad's proxy (gateway) + RestAPIEntityType = "observer" + FinalityCheck = true + MaxNoncesDelta = 7 # the number of maximum blocks allowed to be "in front" of what the metachain has notarized [MultiversX.GasMap] Sign = 8000000 ProposeTransferBase = 11000000 diff --git a/factory/ethMultiversXBridgeComponents.go b/factory/ethMultiversXBridgeComponents.go index e084fe24..53e4dba7 100644 --- a/factory/ethMultiversXBridgeComponents.go +++ b/factory/ethMultiversXBridgeComponents.go @@ -302,7 +302,7 @@ func (components *ethMultiversXBridgeComponents) createMultiversXClient(args Arg TokensMapper: tokensMapper, RoleProvider: components.multiversXRoleProvider, StatusHandler: args.MultiversXClientStatusHandler, - AllowDelta: uint64(chainConfigs.ProxyMaxNoncesDelta), + ClientAvailabilityAllowDelta: chainConfigs.ClientAvailabilityAllowDelta, } components.multiversXClient, err = multiversx.NewClient(clientArgs) @@ -397,19 +397,21 @@ func (components *ethMultiversXBridgeComponents) createEthereumClient(args ArgsE ethClientLogId := components.evmCompatibleChain.EvmCompatibleChainClientLogId() argsEthClient := ethereum.ArgsEthereumClient{ - ClientWrapper: args.ClientWrapper, - Erc20ContractsHandler: args.Erc20ContractsHolder, - Log: core.NewLoggerWithIdentifier(logger.GetOrCreate(ethClientLogId), ethClientLogId), - AddressConverter: components.addressConverter, - Broadcaster: components.broadcaster, - PrivateKey: privateKey, - TokensMapper: tokensMapper, - SignatureHolder: signaturesHolder, - SafeContractAddress: safeContractAddress, - GasHandler: gs, - TransferGasLimitBase: ethereumConfigs.GasLimitBase, - TransferGasLimitForEach: ethereumConfigs.GasLimitForEach, - AllowDelta: ethereumConfigs.MaxBlocksDelta, + ClientWrapper: args.ClientWrapper, + Erc20ContractsHandler: args.Erc20ContractsHolder, + Log: core.NewLoggerWithIdentifier(logger.GetOrCreate(ethClientLogId), ethClientLogId), + AddressConverter: components.addressConverter, + Broadcaster: components.broadcaster, + PrivateKey: privateKey, + TokensMapper: tokensMapper, + SignatureHolder: signaturesHolder, + SafeContractAddress: safeContractAddress, + GasHandler: gs, + TransferGasLimitBase: ethereumConfigs.GasLimitBase, + TransferGasLimitForEach: ethereumConfigs.GasLimitForEach, + ClientAvailabilityAllowDelta: ethereumConfigs.ClientAvailabilityAllowDelta, + EventsBlockRangeFrom: ethereumConfigs.EventsBlockRangeFrom, + EventsBlockRangeTo: ethereumConfigs.EventsBlockRangeTo, } components.ethClient, err = ethereum.NewEthereumClient(argsEthClient) diff --git a/factory/ethMultiversXBridgeComponents_test.go b/factory/ethMultiversXBridgeComponents_test.go index 007467ef..8553230f 100644 --- a/factory/ethMultiversXBridgeComponents_test.go +++ b/factory/ethMultiversXBridgeComponents_test.go @@ -52,7 +52,7 @@ func createMockEthMultiversXBridgeArgs() ArgsEthereumToMultiversXBridge { }, MaxRetriesOnQuorumReached: 1, IntervalToWaitForTransferInSeconds: 1, - MaxBlocksDelta: 10, + ClientAvailabilityAllowDelta: 10, }, MultiversX: config.MultiversXConfig{ PrivateKeyFile: "testdata/grace.pem", @@ -63,7 +63,13 @@ func createMockEthMultiversXBridgeArgs() ArgsEthereumToMultiversXBridge { GasMap: testsCommon.CreateTestMultiversXGasMap(), MaxRetriesOnQuorumReached: 1, MaxRetriesOnWasTransferProposed: 1, - ProxyMaxNoncesDelta: 5, + ClientAvailabilityAllowDelta: 10, + Proxy: config.ProxyConfig{ + CacherExpirationSeconds: 600, + RestAPIEntityType: "observer", + MaxNoncesDelta: 10, + FinalityCheck: true, + }, }, Relayer: config.ConfigRelayer{ RoleProvider: config.RoleProviderConfig{ diff --git a/integrationTests/relayers/common.go b/integrationTests/relayers/common.go index 0f7120b9..3f28ea45 100644 --- a/integrationTests/relayers/common.go +++ b/integrationTests/relayers/common.go @@ -76,7 +76,7 @@ func CreateBridgeComponentsConfig(index int, workingDir string) config.Config { }, MaxRetriesOnQuorumReached: 1, IntervalToWaitForTransferInSeconds: 1, - MaxBlocksDelta: 5, + ClientAvailabilityAllowDelta: 5, }, MultiversX: config.MultiversXConfig{ NetworkAddress: "mock", @@ -87,7 +87,13 @@ func CreateBridgeComponentsConfig(index int, workingDir string) config.Config { GasMap: testsCommon.CreateTestMultiversXGasMap(), MaxRetriesOnQuorumReached: 1, MaxRetriesOnWasTransferProposed: 3, - ProxyMaxNoncesDelta: 5, + ClientAvailabilityAllowDelta: 5, + Proxy: config.ProxyConfig{ + CacherExpirationSeconds: 600, + RestAPIEntityType: "observer", + MaxNoncesDelta: 10, + FinalityCheck: true, + }, }, P2P: config.ConfigP2P{}, StateMachine: map[string]config.ConfigStateMachine{ diff --git a/testsCommon/bridge/ethereumClientStub.go b/testsCommon/bridge/ethereumClientStub.go index e545e243..902042e0 100644 --- a/testsCommon/bridge/ethereumClientStub.go +++ b/testsCommon/bridge/ethereumClientStub.go @@ -21,7 +21,7 @@ type EthereumClientStub struct { GetTransactionsStatusesCalled func(ctx context.Context, batchId uint64) ([]byte, error) GetQuorumSizeCalled func(ctx context.Context) (*big.Int, error) IsQuorumReachedCalled func(ctx context.Context, msgHash common.Hash) (bool, error) - GetBatchSCMetadataCalled func(ctx context.Context, nonce uint64) ([]*contract.ERC20SafeERC20SCDeposit, error) + GetBatchSCMetadataCalled func(ctx context.Context, nonce uint64, blockNumber int64) ([]*contract.ERC20SafeERC20SCDeposit, error) CheckRequiredBalanceCalled func(ctx context.Context, erc20Address common.Address, value *big.Int) error TotalBalancesCalled func(ctx context.Context, account common.Address) (*big.Int, error) MintBalancesCalled func(ctx context.Context, account common.Address) (*big.Int, error) @@ -111,9 +111,9 @@ func (stub *EthereumClientStub) IsQuorumReached(ctx context.Context, msgHash com } // GetBatchSCMetadata - -func (stub *EthereumClientStub) GetBatchSCMetadata(ctx context.Context, nonce uint64) ([]*contract.ERC20SafeERC20SCDeposit, error) { +func (stub *EthereumClientStub) GetBatchSCMetadata(ctx context.Context, nonce uint64, blockNumber int64) ([]*contract.ERC20SafeERC20SCDeposit, error) { if stub.GetBatchSCMetadataCalled != nil { - return stub.GetBatchSCMetadataCalled(ctx, nonce) + return stub.GetBatchSCMetadataCalled(ctx, nonce, blockNumber) } return []*contract.ERC20SafeERC20SCDeposit{}, errNotImplemented From 29d42cd81bce90320144081b893e4d1e4637b64d Mon Sep 17 00:00:00 2001 From: dragosrebegea Date: Mon, 12 Aug 2024 20:37:00 +0300 Subject: [PATCH 2/6] fix tests --- clients/multiversx/client_test.go | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/clients/multiversx/client_test.go b/clients/multiversx/client_test.go index 751dde73..b5dd5c1c 100644 --- a/clients/multiversx/client_test.go +++ b/clients/multiversx/client_test.go @@ -63,9 +63,9 @@ func createMockClientArgs() ClientArgs { return append([]byte("converted "), sourceBytes...), nil }, }, - RoleProvider: &roleproviders.MultiversXRoleProviderStub{}, - StatusHandler: &testsCommon.StatusHandlerStub{}, - AllowDelta: 5, + RoleProvider: &roleproviders.MultiversXRoleProviderStub{}, + StatusHandler: &testsCommon.StatusHandlerStub{}, + ClientAvailabilityAllowDelta: 5, } } @@ -213,7 +213,7 @@ func TestNewClient(t *testing.T) { t.Parallel() args := createMockClientArgs() - args.AllowDelta = 0 + args.ClientAvailabilityAllowDelta = 0 c, err := NewClient(args) @@ -1076,14 +1076,14 @@ func TestClient_CheckClientAvailability(t *testing.T) { statusHandler.SetStringMetric(bridgeCore.MetricLastMultiversXClientError, "random") // this will just increment the retry counter - for i := 0; i < int(args.AllowDelta); i++ { + for i := 0; i < int(args.ClientAvailabilityAllowDelta); i++ { err := c.CheckClientAvailability(context.Background()) assert.Nil(t, err) checkStatusHandler(t, statusHandler, ethmultiversx.Available, "") } for i := 0; i < 10; i++ { - message := fmt.Sprintf("nonce %d fetched for %d times in a row", currentNonce, args.AllowDelta+uint64(i+1)) + message := fmt.Sprintf("nonce %d fetched for %d times in a row", currentNonce, args.ClientAvailabilityAllowDelta+uint64(i+1)) err := c.CheckClientAvailability(context.Background()) assert.Nil(t, err) checkStatusHandler(t, statusHandler, ethmultiversx.Unavailable, message) @@ -1096,14 +1096,14 @@ func TestClient_CheckClientAvailability(t *testing.T) { incrementor = 0 // this will just increment the retry counter - for i := 0; i < int(args.AllowDelta); i++ { + for i := 0; i < int(args.ClientAvailabilityAllowDelta); i++ { err := c.CheckClientAvailability(context.Background()) assert.Nil(t, err) checkStatusHandler(t, statusHandler, ethmultiversx.Available, "") } for i := 0; i < 10; i++ { - message := fmt.Sprintf("nonce %d fetched for %d times in a row", currentNonce, args.AllowDelta+uint64(i+1)) + message := fmt.Sprintf("nonce %d fetched for %d times in a row", currentNonce, args.ClientAvailabilityAllowDelta+uint64(i+1)) err := c.CheckClientAvailability(context.Background()) assert.Nil(t, err) checkStatusHandler(t, statusHandler, ethmultiversx.Unavailable, message) From e8edbeb5c9a907f813da47c596e16fc4e79839c0 Mon Sep 17 00:00:00 2001 From: dragosrebegea Date: Mon, 12 Aug 2024 20:46:04 +0300 Subject: [PATCH 3/6] fix tests --- clients/multiversx/client_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/clients/multiversx/client_test.go b/clients/multiversx/client_test.go index b5dd5c1c..0d282f95 100644 --- a/clients/multiversx/client_test.go +++ b/clients/multiversx/client_test.go @@ -209,7 +209,7 @@ func TestNewClient(t *testing.T) { require.True(t, check.IfNil(c)) require.Equal(t, clients.ErrNilStatusHandler, err) }) - t.Run("invalid AllowDelta should error", func(t *testing.T) { + t.Run("invalid ClientAvailabilityAllowDelta should error", func(t *testing.T) { t.Parallel() args := createMockClientArgs() @@ -219,7 +219,7 @@ func TestNewClient(t *testing.T) { require.True(t, check.IfNil(c)) require.True(t, errors.Is(err, clients.ErrInvalidValue)) - require.True(t, strings.Contains(err.Error(), "for args.AllowedDelta")) + require.True(t, strings.Contains(err.Error(), "for args.ClientAvailabilityAllowDelta")) }) t.Run("should work", func(t *testing.T) { t.Parallel() From 2c2353e70df211cc47acf94f9c6e5accb82e4632 Mon Sep 17 00:00:00 2001 From: dragosrebegea Date: Tue, 13 Aug 2024 09:56:03 +0300 Subject: [PATCH 4/6] fix indentation --- config/tomlConfigs_test.go | 4 ++-- integrationTests/relayers/common.go | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/config/tomlConfigs_test.go b/config/tomlConfigs_test.go index 4934e44b..ea1f6800 100644 --- a/config/tomlConfigs_test.go +++ b/config/tomlConfigs_test.go @@ -228,8 +228,8 @@ func TestConfigs(t *testing.T) { IntervalToWaitForTransferInSeconds = 600 #10 minutes MaxRetriesOnQuorumReached = 3 ClientAvailabilityAllowDelta = 10 - EventsBlockRangeFrom = -100 - EventsBlockRangeTo = 400 + EventsBlockRangeFrom = -100 + EventsBlockRangeTo = 400 [Eth.GasStation] Enabled = true URL = "https://api.etherscan.io/api?module=gastracker&action=gasoracle" # gas station URL. Suggestion to provide the api-key here diff --git a/integrationTests/relayers/common.go b/integrationTests/relayers/common.go index 3f28ea45..e69a2c06 100644 --- a/integrationTests/relayers/common.go +++ b/integrationTests/relayers/common.go @@ -77,6 +77,8 @@ func CreateBridgeComponentsConfig(index int, workingDir string) config.Config { MaxRetriesOnQuorumReached: 1, IntervalToWaitForTransferInSeconds: 1, ClientAvailabilityAllowDelta: 5, + EventsBlockRangeFrom: -5, + EventsBlockRangeTo: 50, }, MultiversX: config.MultiversXConfig{ NetworkAddress: "mock", From 07e505290432e2e758169e39a2d2097fb753fcf9 Mon Sep 17 00:00:00 2001 From: dragosrebegea Date: Tue, 13 Aug 2024 10:00:02 +0300 Subject: [PATCH 5/6] fix indentation --- config/tomlConfigs_test.go | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/config/tomlConfigs_test.go b/config/tomlConfigs_test.go index ea1f6800..7163fd9d 100644 --- a/config/tomlConfigs_test.go +++ b/config/tomlConfigs_test.go @@ -250,15 +250,15 @@ func TestConfigs(t *testing.T) { IntervalToResendTxsInSeconds = 60 # the time in seconds between nonce reads MaxRetriesOnQuorumReached = 3 MaxRetriesOnWasTransferProposed = 3 - ClientAvailabilityAllowDelta = 10 - [MultiversX.Proxy] - CacherExpirationSeconds = 600 # the caching time in seconds - - # valid options for ProxyRestAPIEntityType are "observer" and "proxy". Any other value will trigger an error. - # "observer" is useful when querying an observer, directly and "proxy" is useful when querying a squad's proxy (gateway) - RestAPIEntityType = "observer" - FinalityCheck = true - MaxNoncesDelta = 7 # the number of maximum blocks allowed to be "in front" of what the metachain has notarized + ClientAvailabilityAllowDelta = 10 + [MultiversX.Proxy] + CacherExpirationSeconds = 600 # the caching time in seconds + + # valid options for ProxyRestAPIEntityType are "observer" and "proxy". Any other value will trigger an error. + # "observer" is useful when querying an observer, directly and "proxy" is useful when querying a squad's proxy (gateway) + RestAPIEntityType = "observer" + FinalityCheck = true + MaxNoncesDelta = 7 # the number of maximum blocks allowed to be "in front" of what the metachain has notarized [MultiversX.GasMap] Sign = 8000000 ProposeTransferBase = 11000000 From 29820c705f7295a03ff8df2eeefe76fcbc18431d Mon Sep 17 00:00:00 2001 From: dragosrebegea Date: Tue, 13 Aug 2024 10:25:55 +0300 Subject: [PATCH 6/6] add new configs in config.toml --- cmd/bridge/config/config.toml | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/cmd/bridge/config/config.toml b/cmd/bridge/config/config.toml index d64e9116..70e3d547 100644 --- a/cmd/bridge/config/config.toml +++ b/cmd/bridge/config/config.toml @@ -8,7 +8,7 @@ GasLimitForEach = 30000 IntervalToWaitForTransferInSeconds = 600 #10 minutes MaxRetriesOnQuorumReached = 3 - MaxBlocksDelta = 10 + ClientAvailabilityAllowDelta = 10 [Eth.GasStation] Enabled = true URL = "https://api.etherscan.io/api?module=gastracker&action=gasoracle" # gas station URL. Suggestion to provide the api-key here @@ -29,13 +29,15 @@ IntervalToResendTxsInSeconds = 60 # the time in seconds between nonce reads MaxRetriesOnQuorumReached = 3 MaxRetriesOnWasTransferProposed = 3 - ProxyCacherExpirationSeconds = 600 # the caching time in seconds + ClientAvailabilityAllowDelta = 10 + [MultiversX.Proxy] + CacherExpirationSeconds = 600 # the caching time in seconds - # valid options for ProxyRestAPIEntityType are "observer" and "proxy". Any other value will trigger an error. - # "observer" is useful when querying an observer, directly and "proxy" is useful when querying a squad's proxy (gateway) - ProxyRestAPIEntityType = "observer" - ProxyFinalityCheck = true - ProxyMaxNoncesDelta = 7 # the number of maximum blocks allowed to be "in front" of what the metachain has notarized + # valid options for ProxyRestAPIEntityType are "observer" and "proxy". Any other value will trigger an error. + # "observer" is useful when querying an observer, directly and "proxy" is useful when querying a squad's proxy (gateway) + RestAPIEntityType = "observer" + FinalityCheck = true + MaxNoncesDelta = 7 # the number of maximum blocks allowed to be "in front" of what the metachain has notarized [MultiversX.GasMap] Sign = 8000000 ProposeTransferBase = 11000000