diff --git a/bridges/ethMultiversX/bridgeExecutor.go b/bridges/ethMultiversX/bridgeExecutor.go index 5b2280d9..e5308be7 100644 --- a/bridges/ethMultiversX/bridgeExecutor.go +++ b/bridges/ethMultiversX/bridgeExecutor.go @@ -2,12 +2,14 @@ package ethmultiversx import ( "context" + "encoding/hex" "fmt" "math/big" "time" "github.com/ethereum/go-ethereum/common" "github.com/multiversx/mx-bridge-eth-go/clients" + "github.com/multiversx/mx-bridge-eth-go/clients/ethereum/contract" "github.com/multiversx/mx-bridge-eth-go/core" "github.com/multiversx/mx-bridge-eth-go/core/batchProcessor" "github.com/multiversx/mx-chain-core-go/core/check" @@ -17,9 +19,11 @@ import ( // splits - represent the number of times we split the maximum interval // we wait for the transfer confirmation on Ethereum const splits = 10 - const minRetries = 1 +// MissingCallData is a placeholder for wrongly initiated contract calls that do not contain data +const MissingCallData = "" + // ArgsBridgeExecutor is the arguments DTO struct used in both bridges type ArgsBridgeExecutor struct { Log logger.Logger @@ -450,11 +454,64 @@ func (executor *bridgeExecutor) GetAndStoreBatchFromEthereum(ctx context.Context ErrBatchNotFound, nonce, batch.ID, len(batch.Deposits)) } + batch, err = executor.addBatchSCMetadata(ctx, batch) + if err != nil { + return err + } executor.batch = batch return nil } +// addBatchSCMetadata fetches the logs containing sc calls metadata for the current batch +func (executor *bridgeExecutor) addBatchSCMetadata(ctx context.Context, transfers *clients.TransferBatch) (*clients.TransferBatch, error) { + if transfers == nil { + return nil, ErrNilBatch + } + + if !executor.hasSCCalls(transfers) { + return transfers, nil + } + + events, err := executor.ethereumClient.GetBatchSCMetadata(ctx, transfers.ID) + if err != nil { + return nil, err + } + + for i, t := range transfers.Deposits { + transfers.Deposits[i] = executor.addMetadataToTransfer(t, events) + } + + return transfers, nil +} + +func (executor *bridgeExecutor) addMetadataToTransfer(transfer *clients.DepositTransfer, events []*contract.SCExecProxyERC20SCDeposit) *clients.DepositTransfer { + for _, event := range events { + if event.DepositNonce == transfer.Nonce { + transfer.ExtraGasLimit = event.MvxGasLimit + transfer.Data = []byte(event.CallData) + if len(transfer.Data) == 0 { + // will add a dummy data so the relayers won't panic + transfer.Data = []byte(MissingCallData) + } + transfer.DisplayableData = hex.EncodeToString(transfer.Data) + + return transfer + } + } + return transfer +} + +func (executor *bridgeExecutor) hasSCCalls(transfers *clients.TransferBatch) bool { + for _, t := range transfers.Deposits { + if executor.ethereumClient.IsDepositSCCall(t) { + return true + } + } + + return false +} + // WasTransferPerformedOnEthereum returns true if the batch was performed on Ethereum func (executor *bridgeExecutor) WasTransferPerformedOnEthereum(ctx context.Context) (bool, error) { if executor.batch == nil { diff --git a/bridges/ethMultiversX/bridgeExecutor_test.go b/bridges/ethMultiversX/bridgeExecutor_test.go index 49f3cfa2..915a5f4d 100644 --- a/bridges/ethMultiversX/bridgeExecutor_test.go +++ b/bridges/ethMultiversX/bridgeExecutor_test.go @@ -11,6 +11,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/multiversx/mx-bridge-eth-go/clients" + "github.com/multiversx/mx-bridge-eth-go/clients/ethereum/contract" "github.com/multiversx/mx-bridge-eth-go/core" "github.com/multiversx/mx-bridge-eth-go/core/batchProcessor" "github.com/multiversx/mx-bridge-eth-go/testsCommon" @@ -363,6 +364,76 @@ func TestEthToMultiversXBridgeExecutor_GetAndStoreBatchFromEthereum(t *testing.T assert.True(t, expectedBatch == executor.GetStoredBatch()) // pointer testing assert.True(t, expectedBatch == executor.batch) }) + t.Run("should add deposits metadata for sc calls", func(t *testing.T) { + args := createMockExecutorArgs() + providedNonce := uint64(8346) + depositNonce := uint64(100) + depositData := "testData" + expectedBatch := &clients.TransferBatch{ + ID: providedNonce, + Deposits: []*clients.DepositTransfer{ + { + Nonce: depositNonce, + }, + }, + } + args.EthereumClient = &bridgeTests.EthereumClientStub{ + GetBatchCalled: func(ctx context.Context, nonce uint64) (*clients.TransferBatch, error) { + assert.Equal(t, providedNonce, nonce) + return expectedBatch, nil + }, + GetBatchSCMetadataCalled: func(ctx context.Context, nonce uint64) ([]*contract.SCExecProxyERC20SCDeposit, error) { + return []*contract.SCExecProxyERC20SCDeposit{{ + DepositNonce: depositNonce, + CallData: depositData, + }}, nil + }, + IsDepositSCCallCalled: func(deposit *clients.DepositTransfer) bool { + return deposit.Nonce == depositNonce + }, + } + executor, _ := NewBridgeExecutor(args) + err := executor.GetAndStoreBatchFromEthereum(context.Background(), providedNonce) + + assert.Nil(t, err) + assert.True(t, expectedBatch == executor.GetStoredBatch()) // pointer testing + assert.Equal(t, depositData, string(executor.batch.Deposits[0].Data)) + }) + t.Run("should add deposits metadata for sc calls even if with invalid data", func(t *testing.T) { + args := createMockExecutorArgs() + providedNonce := uint64(8346) + depositNonce := uint64(100) + depositData := "" + expectedBatch := &clients.TransferBatch{ + ID: providedNonce, + Deposits: []*clients.DepositTransfer{ + { + Nonce: depositNonce, + }, + }, + } + args.EthereumClient = &bridgeTests.EthereumClientStub{ + GetBatchCalled: func(ctx context.Context, nonce uint64) (*clients.TransferBatch, error) { + assert.Equal(t, providedNonce, nonce) + return expectedBatch, nil + }, + GetBatchSCMetadataCalled: func(ctx context.Context, nonce uint64) ([]*contract.SCExecProxyERC20SCDeposit, error) { + return []*contract.SCExecProxyERC20SCDeposit{{ + DepositNonce: depositNonce, + CallData: depositData, + }}, nil + }, + IsDepositSCCallCalled: func(deposit *clients.DepositTransfer) bool { + return deposit.Nonce == depositNonce + }, + } + executor, _ := NewBridgeExecutor(args) + err := executor.GetAndStoreBatchFromEthereum(context.Background(), providedNonce) + + assert.Nil(t, err) + assert.True(t, expectedBatch == executor.GetStoredBatch()) // pointer testing + assert.Equal(t, MissingCallData, string(executor.batch.Deposits[0].Data)) + }) } func TestEthToMultiversXBridgeExecutor_GetLastExecutedEthBatchIDFromMultiversX(t *testing.T) { diff --git a/bridges/ethMultiversX/interface.go b/bridges/ethMultiversX/interface.go index d6120ea6..e088cdd9 100644 --- a/bridges/ethMultiversX/interface.go +++ b/bridges/ethMultiversX/interface.go @@ -6,6 +6,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/multiversx/mx-bridge-eth-go/clients" + "github.com/multiversx/mx-bridge-eth-go/clients/ethereum/contract" "github.com/multiversx/mx-bridge-eth-go/core/batchProcessor" ) @@ -40,6 +41,7 @@ type MultiversXClient interface { type EthereumClient interface { GetBatch(ctx context.Context, nonce uint64) (*clients.TransferBatch, error) WasExecuted(ctx context.Context, batchID uint64) (bool, error) + IsDepositSCCall(deposit *clients.DepositTransfer) bool GenerateMessageHash(batch *batchProcessor.ArgListsBatch, batchId uint64) (common.Hash, error) BroadcastSignatureForMessageHash(msgHash common.Hash) @@ -47,6 +49,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.SCExecProxyERC20SCDeposit, error) CheckClientAvailability(ctx context.Context) error CheckRequiredBalance(ctx context.Context, erc20Address common.Address, value *big.Int) error TokenMintedBalances(ctx context.Context, token common.Address) (*big.Int, error) diff --git a/bridges/ethMultiversX/steps/ethToMultiversX/constants.go b/bridges/ethMultiversX/steps/ethToMultiversX/constants.go index 4aec9996..32cf2aa5 100644 --- a/bridges/ethMultiversX/steps/ethToMultiversX/constants.go +++ b/bridges/ethMultiversX/steps/ethToMultiversX/constants.go @@ -4,7 +4,7 @@ const ( // GettingPendingBatchFromEthereum is the step identifier for fetching the pending batch from the Ethereum chain GettingPendingBatchFromEthereum = "get pending batch from Ethereum" - // ProposingTransferOnMultiversX is the step idetifier for proposing transfer on MultiversX + // ProposingTransferOnMultiversX is the step identifier for proposing transfer on MultiversX ProposingTransferOnMultiversX = "propose transfer" // SigningProposedTransferOnMultiversX is the step identifier for signing proposed transfer diff --git a/bridges/ethMultiversX/steps/ethToMultiversX/step01GetPending_test.go b/bridges/ethMultiversX/steps/ethToMultiversX/step01GetPending_test.go index 3ba437a1..f13917b2 100644 --- a/bridges/ethMultiversX/steps/ethToMultiversX/step01GetPending_test.go +++ b/bridges/ethMultiversX/steps/ethToMultiversX/step01GetPending_test.go @@ -13,9 +13,11 @@ import ( var expectedError = errors.New("expected error") var testBatch = &clients.TransferBatch{ - ID: 112233, - Deposits: nil, - Statuses: nil, + ID: 112233, + Deposits: []*clients.DepositTransfer{ + {}, + }, + Statuses: []byte{0}, } func TestExecuteGetPending(t *testing.T) { diff --git a/bridges/ethMultiversX/steps/interface.go b/bridges/ethMultiversX/steps/interface.go index d842b6c3..629bf2f6 100644 --- a/bridges/ethMultiversX/steps/interface.go +++ b/bridges/ethMultiversX/steps/interface.go @@ -15,6 +15,7 @@ type Executor interface { GetBatchFromMultiversX(ctx context.Context) (*clients.TransferBatch, error) StoreBatchFromMultiversX(batch *clients.TransferBatch) error GetStoredBatch() *clients.TransferBatch + GetLastExecutedEthBatchIDFromMultiversX(ctx context.Context) (uint64, error) VerifyLastDepositNonceExecutedOnEthereumBatch(ctx context.Context) error diff --git a/bridges/ethMultiversX/topology/topologyHandler.go b/bridges/ethMultiversX/topology/topologyHandler.go index 49e69534..d3fed22d 100644 --- a/bridges/ethMultiversX/topology/topologyHandler.go +++ b/bridges/ethMultiversX/topology/topologyHandler.go @@ -69,9 +69,9 @@ func (t *topologyHandler) MyTurnAsLeader() bool { } t.log.Debug(msg, - "leader", t.addressConverter.ToBech32String(leaderAddress), + "leader", t.addressConverter.ToBech32StringSilent(leaderAddress), "index", index, - "self address", t.addressConverter.ToBech32String(t.addressBytes)) + "self address", t.addressConverter.ToBech32StringSilent(t.addressBytes)) return isLeader } diff --git a/clients/batch.go b/clients/batch.go index 601c0630..27290d8e 100644 --- a/clients/batch.go +++ b/clients/batch.go @@ -74,12 +74,15 @@ type DepositTransfer struct { ConvertedTokenBytes []byte `json:"-"` DisplayableToken string `json:"token"` Amount *big.Int `json:"amount"` + ExtraGasLimit uint64 `json:"gasLimit"` + Data []byte `json:"-"` + DisplayableData string `json:"data"` } // String will convert the deposit transfer to a string func (dt *DepositTransfer) String() string { - return fmt.Sprintf("to: %s, from: %s, token address: %s, amount: %v, deposit nonce: %d", - dt.DisplayableTo, dt.DisplayableFrom, dt.DisplayableToken, dt.Amount, dt.Nonce) + return fmt.Sprintf("to: %s, from: %s, token address: %s, amount: %v, deposit nonce: %d, gas limit: %d, hex data: %s", + dt.DisplayableTo, dt.DisplayableFrom, dt.DisplayableToken, dt.Amount, dt.Nonce, dt.ExtraGasLimit, dt.DisplayableData) } // Clone will deep clone the current DepositTransfer instance @@ -94,12 +97,15 @@ func (dt *DepositTransfer) Clone() *DepositTransfer { ConvertedTokenBytes: make([]byte, len(dt.ConvertedTokenBytes)), DisplayableToken: dt.DisplayableToken, Amount: big.NewInt(0), + Data: make([]byte, len(dt.Data)), + DisplayableData: dt.DisplayableData, } copy(cloned.ToBytes, dt.ToBytes) copy(cloned.FromBytes, dt.FromBytes) copy(cloned.TokenBytes, dt.TokenBytes) copy(cloned.ConvertedTokenBytes, dt.ConvertedTokenBytes) + copy(cloned.Data, dt.Data) if dt.Amount != nil { cloned.Amount.Set(dt.Amount) } diff --git a/clients/batchValidator/batchValidator_test.go b/clients/batchValidator/batchValidator_test.go index 5d4aaad2..2b3a7e60 100644 --- a/clients/batchValidator/batchValidator_test.go +++ b/clients/batchValidator/batchValidator_test.go @@ -92,7 +92,7 @@ func TestBatchValidator_ValidateBatch(t *testing.T) { }, Statuses: []byte{0x3, 0x4}, } - expectedJsonString := `{"batchId":1,"deposits":[{"nonce":1,"to":"to1","from":"from1","token":"token1","amount":1000000000000000000001},{"nonce":2,"to":"to2","from":"from2","token":"token2","amount":1000000000000000000002}],"statuses":"AwQ="}` + expectedJsonString := `{"batchId":1,"deposits":[{"nonce":1,"to":"to1","from":"from1","token":"token1","amount":1000000000000000000001,"gasLimit":0,"data":""},{"nonce":2,"to":"to2","from":"from2","token":"token2","amount":1000000000000000000002,"gasLimit":0,"data":""}],"statuses":"AwQ="}` t.Run("server errors with Bad Request, but no reason", func(t *testing.T) { t.Parallel() diff --git a/clients/batch_test.go b/clients/batch_test.go index 2f362c4d..196a1633 100644 --- a/clients/batch_test.go +++ b/clients/batch_test.go @@ -20,6 +20,7 @@ func TestDepositTransfer_Clone(t *testing.T) { DisplayableToken: "token", Amount: big.NewInt(7463), ConvertedTokenBytes: []byte("converted token"), + Data: []byte("tx data"), } cloned := dt.Clone() @@ -42,7 +43,7 @@ func TestDepositTransfer_String(t *testing.T) { Amount: big.NewInt(7463), } - expectedString := "to: to, from: from, token address: token, amount: 7463, deposit nonce: 112334" + expectedString := "to: to, from: from, token address: token, amount: 7463, deposit nonce: 112334, gas limit: 0, hex data: " assert.Equal(t, expectedString, dt.String()) } @@ -62,6 +63,7 @@ func TestTransferBatch_Clone(t *testing.T) { DisplayableToken: "token1", Amount: big.NewInt(3344), ConvertedTokenBytes: []byte("converted token1"), + Data: []byte("tx data"), }, { Nonce: 2, @@ -73,6 +75,7 @@ func TestTransferBatch_Clone(t *testing.T) { DisplayableToken: "token2", Amount: big.NewInt(5566), ConvertedTokenBytes: []byte("converted token2"), + Data: []byte("tx data"), }, }, Statuses: []byte{Executed, Rejected}, @@ -115,8 +118,8 @@ func TestTransferBatch_String(t *testing.T) { } expectedString := `Batch id 2243: - to: to1, from: from1, token address: token1, amount: 3344, deposit nonce: 1 - to: to2, from: from2, token address: token2, amount: 5566, deposit nonce: 2 + to: to1, from: from1, token address: token1, amount: 3344, deposit nonce: 1, gas limit: 0, hex data: + to: to2, from: from2, token address: token2, amount: 5566, deposit nonce: 2, gas limit: 0, hex data: Statuses: 0304` assert.Equal(t, expectedString, tb.String()) } diff --git a/clients/ethereum/client.go b/clients/ethereum/client.go index c46bddbb..dc1c817d 100644 --- a/clients/ethereum/client.go +++ b/clients/ethereum/client.go @@ -1,18 +1,21 @@ package ethereum import ( + "bytes" "context" "crypto/ecdsa" "fmt" "math/big" "sync" + "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/crypto" "github.com/multiversx/mx-bridge-eth-go/bridges/ethMultiversX" "github.com/multiversx/mx-bridge-eth-go/clients" + "github.com/multiversx/mx-bridge-eth-go/clients/ethereum/contract" "github.com/multiversx/mx-bridge-eth-go/core" "github.com/multiversx/mx-bridge-eth-go/core/batchProcessor" chainCore "github.com/multiversx/mx-chain-core-go/core" @@ -36,6 +39,7 @@ type ArgsEthereumClient struct { TokensMapper TokensMapper SignatureHolder SignaturesHolder SafeContractAddress common.Address + SCExecProxyAddress common.Address GasHandler GasHandler TransferGasLimitBase uint64 TransferGasLimitForEach uint64 @@ -53,6 +57,7 @@ type client struct { tokensMapper TokensMapper signatureHolder SignaturesHolder safeContractAddress common.Address + scExecProxyAddress common.Address gasHandler GasHandler transferGasLimitBase uint64 transferGasLimitForEach uint64 @@ -87,6 +92,7 @@ func NewEthereumClient(args ArgsEthereumClient) (*client, error) { tokensMapper: args.TokensMapper, signatureHolder: args.SignatureHolder, safeContractAddress: args.SafeContractAddress, + scExecProxyAddress: args.SCExecProxyAddress, gasHandler: args.GasHandler, transferGasLimitBase: args.TransferGasLimitBase, transferGasLimitForEach: args.TransferGasLimitForEach, @@ -172,7 +178,7 @@ func (c *client) GetBatch(ctx context.Context, nonce uint64) (*clients.TransferB depositTransfer := &clients.DepositTransfer{ Nonce: deposit.Nonce.Uint64(), ToBytes: toBytes, - DisplayableTo: c.addressConverter.ToBech32String(toBytes), + DisplayableTo: c.addressConverter.ToBech32StringSilent(toBytes), FromBytes: fromBytes, DisplayableFrom: c.addressConverter.ToHexString(fromBytes), TokenBytes: tokenBytes, @@ -198,6 +204,42 @@ func (c *client) GetBatch(ctx context.Context, nonce uint64) (*clients.TransferB return transferBatch, nil } +// 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.SCExecProxyERC20SCDeposit, error) { + scExecAbi, err := contract.SCExecProxyMetaData.GetAbi() + if err != nil { + return nil, err + } + + query := ethereum.FilterQuery{ + Addresses: []common.Address{c.scExecProxyAddress}, + Topics: [][]common.Hash{ + {scExecAbi.Events["ERC20SCDeposit"].ID}, + {common.BytesToHash(new(big.Int).SetUint64(nonce).Bytes())}, + }, + } + + logs, err := c.clientWrapper.FilterLogs(ctx, query) + if err != nil { + return nil, err + } + + depositEvents := make([]*contract.SCExecProxyERC20SCDeposit, 0) + for _, vLog := range logs { + event := new(contract.SCExecProxyERC20SCDeposit) + err = scExecAbi.UnpackIntoInterface(event, "ERC20SCDeposit", vLog.Data) + if err != nil { + return nil, err + } + + // Add this manually since UnpackIntoInterface only unpacks non-indexed arguments + event.BatchNonce = nonce + depositEvents = append(depositEvents, event) + } + + return depositEvents, nil +} + // WasExecuted returns true if the batch ID was executed func (c *client) WasExecuted(ctx context.Context, batchID uint64) (bool, error) { return c.clientWrapper.WasBatchExecuted(ctx, big.NewInt(0).SetUint64(batchID)) @@ -234,6 +276,15 @@ func (c *client) GenerateMessageHash(batch *batchProcessor.ArgListsBatch, batchI return crypto.Keccak256Hash(append([]byte(messagePrefix), hash.Bytes()...)), nil } +// IsDepositSCCall checks whether a deposit should be treated as a SC interaction +func (c *client) IsDepositSCCall(deposit *clients.DepositTransfer) bool { + if deposit == nil { + return false + } + + return bytes.Equal(deposit.FromBytes, c.scExecProxyAddress.Bytes()) +} + func generateTransferArgs() (abi.Arguments, error) { addressesType, err := abi.NewType("address[]", "", nil) if err != nil { diff --git a/clients/ethereum/client_test.go b/clients/ethereum/client_test.go index 12229078..e3c16262 100644 --- a/clients/ethereum/client_test.go +++ b/clients/ethereum/client_test.go @@ -9,6 +9,7 @@ import ( "strings" "testing" + "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" @@ -53,6 +54,7 @@ func createMockEthereumClientArgs() ArgsEthereumClient { }, SignatureHolder: &testsCommon.SignaturesHolderStub{}, SafeContractAddress: testsCommon.CreateRandomEthereumAddress(), + SCExecProxyAddress: testsCommon.CreateRandomEthereumAddress(), GasHandler: &testsCommon.GasHandlerStub{}, TransferGasLimitBase: 50, TransferGasLimitForEach: 20, @@ -312,13 +314,15 @@ func TestClient_GetBatch(t *testing.T) { }, } + bech32Recipient1Address, _ := recipient1.AddressAsBech32String() + bech32Recipient2Address, _ := recipient2.AddressAsBech32String() expectedBatch := &clients.TransferBatch{ ID: 112243, Deposits: []*clients.DepositTransfer{ { Nonce: 10, ToBytes: recipient1.AddressBytes(), - DisplayableTo: c.addressConverter.ToBech32String(recipient1.AddressBytes()), + DisplayableTo: bech32Recipient1Address, FromBytes: from1[:], DisplayableFrom: hex.EncodeToString(from1[:]), TokenBytes: token1[:], @@ -329,7 +333,7 @@ func TestClient_GetBatch(t *testing.T) { { Nonce: 30, ToBytes: recipient2.AddressBytes(), - DisplayableTo: c.addressConverter.ToBech32String(recipient2.AddressBytes()), + DisplayableTo: bech32Recipient2Address, FromBytes: from2[:], DisplayableFrom: hex.EncodeToString(from2[:]), TokenBytes: token2[:], @@ -878,6 +882,43 @@ func TestClient_IsQuorumReached(t *testing.T) { }) } +func TestClient_IsDepositSCCall(t *testing.T) { + t.Parallel() + + t.Run("nil deposit returns false", func(t *testing.T) { + t.Parallel() + + args := createMockEthereumClientArgs() + c, _ := NewEthereumClient(args) + + assert.False(t, c.IsDepositSCCall(nil)) + }) + + t.Run("returns true for matching addresses", func(t *testing.T) { + t.Parallel() + + args := createMockEthereumClientArgs() + c, _ := NewEthereumClient(args) + + deposit := &clients.DepositTransfer{ + FromBytes: args.SCExecProxyAddress.Bytes(), + } + assert.True(t, c.IsDepositSCCall(deposit)) + }) + + t.Run("returns false for non matching addresses", func(t *testing.T) { + t.Parallel() + + args := createMockEthereumClientArgs() + c, _ := NewEthereumClient(args) + + deposit := &clients.DepositTransfer{ + FromBytes: []byte("different_addr"), + } + assert.False(t, c.IsDepositSCCall(deposit)) + }) +} + func TestClient_CheckClientAvailability(t *testing.T) { t.Parallel() @@ -968,6 +1009,60 @@ func TestClient_CheckClientAvailability(t *testing.T) { }) } +func TestClient_GetBatchSCMetadata(t *testing.T) { + t.Parallel() + + t.Run("returns error on filter logs error", func(t *testing.T) { + t.Parallel() + + expectedErr := errors.New("filter logs err") + args := createMockEthereumClientArgs() + args.ClientWrapper = &bridgeTests.EthereumClientWrapperStub{ + FilterLogsCalled: func(ctx context.Context, q ethereum.FilterQuery) ([]types.Log, error) { + return nil, expectedErr + }, + } + c, _ := NewEthereumClient(args) + batch, err := c.GetBatchSCMetadata(context.Background(), 0) + assert.Nil(t, batch) + assert.Equal(t, expectedErr, err) + }) + + t.Run("returns expected logs", func(t *testing.T) { + scExecAbi, _ := contract.SCExecProxyMetaData.GetAbi() + expectedEvent := &contract.SCExecProxyERC20SCDeposit{ + BatchNonce: 1, + DepositNonce: 1, + MvxGasLimit: 1, + CallData: "call_data_to_unpack", + } + + eventInputs := scExecAbi.Events["ERC20SCDeposit"].Inputs.NonIndexed() + packedArgs, _ := eventInputs.Pack(expectedEvent.DepositNonce, + expectedEvent.MvxGasLimit, expectedEvent.CallData) + + args := createMockEthereumClientArgs() + args.ClientWrapper = &bridgeTests.EthereumClientWrapperStub{ + FilterLogsCalled: func(ctx context.Context, q ethereum.FilterQuery) ([]types.Log, error) { + return []types.Log{ + { + Data: packedArgs, + }, + }, nil + }, + } + c, _ := NewEthereumClient(args) + batch, err := c.GetBatchSCMetadata(context.Background(), expectedEvent.BatchNonce) + + assert.Nil(t, err) + assert.Equal(t, 1, len(batch)) + assert.Equal(t, expectedEvent.BatchNonce, batch[0].BatchNonce) + assert.Equal(t, expectedEvent.DepositNonce, batch[0].DepositNonce) + assert.Equal(t, expectedEvent.MvxGasLimit, batch[0].MvxGasLimit) + assert.Equal(t, expectedEvent.CallData, batch[0].CallData) + }) +} + func resetClient(c *client) { c.mut.Lock() c.retriesAvailabilityCheck = 0 diff --git a/clients/ethereum/contract/scExecProxy.go b/clients/ethereum/contract/scExecProxy.go new file mode 100644 index 00000000..02ccf932 --- /dev/null +++ b/clients/ethereum/contract/scExecProxy.go @@ -0,0 +1,658 @@ +// Code generated - DO NOT EDIT. +// This file is a generated binding and any manual changes will be lost. + +package contract + +import ( + "errors" + "math/big" + "strings" + + ethereum "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" + "github.com/ethereum/go-ethereum/event" +) + +// Reference imports to suppress errors if they are not otherwise used. +var ( + _ = errors.New + _ = big.NewInt + _ = strings.NewReader + _ = ethereum.NotFound + _ = bind.Bind + _ = common.Big1 + _ = types.BloomLookup + _ = event.NewSubscription + _ = abi.ConvertType +) + +// SCExecProxyMetaData contains all meta data concerning the SCExecProxy contract. +var SCExecProxyMetaData = &bind.MetaData{ + ABI: "[{\"inputs\":[{\"internalType\":\"contractERC20Safe\",\"name\":\"erc20Safe\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousAdmin\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newAdmin\",\"type\":\"address\"}],\"name\":\"AdminRoleTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"batchNonce\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"depositNonce\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"mvxGasLimit\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"string\",\"name\":\"callData\",\"type\":\"string\"}],\"name\":\"ERC20SCDeposit\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"admin\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"tokenAddress\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes32\",\"name\":\"recipientAddress\",\"type\":\"bytes32\"},{\"internalType\":\"uint64\",\"name\":\"mvxGasLimit\",\"type\":\"uint64\"},{\"internalType\":\"string\",\"name\":\"callData\",\"type\":\"string\"}],\"name\":\"deposit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"isSafePaused\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"renounceAdmin\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"safe\",\"outputs\":[{\"internalType\":\"contractERC20Safe\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contractERC20Safe\",\"name\":\"erc20Safe\",\"type\":\"address\"}],\"name\":\"setSafe\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newAdmin\",\"type\":\"address\"}],\"name\":\"transferAdmin\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", +} + +// SCExecProxyABI is the input ABI used to generate the binding from. +// Deprecated: Use SCExecProxyMetaData.ABI instead. +var SCExecProxyABI = SCExecProxyMetaData.ABI + +// SCExecProxy is an auto generated Go binding around an Ethereum contract. +type SCExecProxy struct { + SCExecProxyCaller // Read-only binding to the contract + SCExecProxyTransactor // Write-only binding to the contract + SCExecProxyFilterer // Log filterer for contract events +} + +// SCExecProxyCaller is an auto generated read-only Go binding around an Ethereum contract. +type SCExecProxyCaller struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// SCExecProxyTransactor is an auto generated write-only Go binding around an Ethereum contract. +type SCExecProxyTransactor struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// SCExecProxyFilterer is an auto generated log filtering Go binding around an Ethereum contract events. +type SCExecProxyFilterer struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// SCExecProxySession is an auto generated Go binding around an Ethereum contract, +// with pre-set call and transact options. +type SCExecProxySession struct { + Contract *SCExecProxy // Generic contract binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// SCExecProxyCallerSession is an auto generated read-only Go binding around an Ethereum contract, +// with pre-set call options. +type SCExecProxyCallerSession struct { + Contract *SCExecProxyCaller // Generic contract caller binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session +} + +// SCExecProxyTransactorSession is an auto generated write-only Go binding around an Ethereum contract, +// with pre-set transact options. +type SCExecProxyTransactorSession struct { + Contract *SCExecProxyTransactor // Generic contract transactor binding to set the session for + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// SCExecProxyRaw is an auto generated low-level Go binding around an Ethereum contract. +type SCExecProxyRaw struct { + Contract *SCExecProxy // Generic contract binding to access the raw methods on +} + +// SCExecProxyCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. +type SCExecProxyCallerRaw struct { + Contract *SCExecProxyCaller // Generic read-only contract binding to access the raw methods on +} + +// SCExecProxyTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. +type SCExecProxyTransactorRaw struct { + Contract *SCExecProxyTransactor // Generic write-only contract binding to access the raw methods on +} + +// NewSCExecProxy creates a new instance of SCExecProxy, bound to a specific deployed contract. +func NewSCExecProxy(address common.Address, backend bind.ContractBackend) (*SCExecProxy, error) { + contract, err := bindSCExecProxy(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &SCExecProxy{SCExecProxyCaller: SCExecProxyCaller{contract: contract}, SCExecProxyTransactor: SCExecProxyTransactor{contract: contract}, SCExecProxyFilterer: SCExecProxyFilterer{contract: contract}}, nil +} + +// NewSCExecProxyCaller creates a new read-only instance of SCExecProxy, bound to a specific deployed contract. +func NewSCExecProxyCaller(address common.Address, caller bind.ContractCaller) (*SCExecProxyCaller, error) { + contract, err := bindSCExecProxy(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &SCExecProxyCaller{contract: contract}, nil +} + +// NewSCExecProxyTransactor creates a new write-only instance of SCExecProxy, bound to a specific deployed contract. +func NewSCExecProxyTransactor(address common.Address, transactor bind.ContractTransactor) (*SCExecProxyTransactor, error) { + contract, err := bindSCExecProxy(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &SCExecProxyTransactor{contract: contract}, nil +} + +// NewSCExecProxyFilterer creates a new log filterer instance of SCExecProxy, bound to a specific deployed contract. +func NewSCExecProxyFilterer(address common.Address, filterer bind.ContractFilterer) (*SCExecProxyFilterer, error) { + contract, err := bindSCExecProxy(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &SCExecProxyFilterer{contract: contract}, nil +} + +// bindSCExecProxy binds a generic wrapper to an already deployed contract. +func bindSCExecProxy(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := SCExecProxyMetaData.GetAbi() + if err != nil { + return nil, err + } + return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_SCExecProxy *SCExecProxyRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _SCExecProxy.Contract.SCExecProxyCaller.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_SCExecProxy *SCExecProxyRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _SCExecProxy.Contract.SCExecProxyTransactor.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_SCExecProxy *SCExecProxyRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _SCExecProxy.Contract.SCExecProxyTransactor.contract.Transact(opts, method, params...) +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_SCExecProxy *SCExecProxyCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _SCExecProxy.Contract.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_SCExecProxy *SCExecProxyTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _SCExecProxy.Contract.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_SCExecProxy *SCExecProxyTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _SCExecProxy.Contract.contract.Transact(opts, method, params...) +} + +// Admin is a free data retrieval call binding the contract method 0xf851a440. +// +// Solidity: function admin() view returns(address) +func (_SCExecProxy *SCExecProxyCaller) Admin(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _SCExecProxy.contract.Call(opts, &out, "admin") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +// Admin is a free data retrieval call binding the contract method 0xf851a440. +// +// Solidity: function admin() view returns(address) +func (_SCExecProxy *SCExecProxySession) Admin() (common.Address, error) { + return _SCExecProxy.Contract.Admin(&_SCExecProxy.CallOpts) +} + +// Admin is a free data retrieval call binding the contract method 0xf851a440. +// +// Solidity: function admin() view returns(address) +func (_SCExecProxy *SCExecProxyCallerSession) Admin() (common.Address, error) { + return _SCExecProxy.Contract.Admin(&_SCExecProxy.CallOpts) +} + +// IsSafePaused is a free data retrieval call binding the contract method 0xa0579640. +// +// Solidity: function isSafePaused() view returns(bool) +func (_SCExecProxy *SCExecProxyCaller) IsSafePaused(opts *bind.CallOpts) (bool, error) { + var out []interface{} + err := _SCExecProxy.contract.Call(opts, &out, "isSafePaused") + + if err != nil { + return *new(bool), err + } + + out0 := *abi.ConvertType(out[0], new(bool)).(*bool) + + return out0, err + +} + +// IsSafePaused is a free data retrieval call binding the contract method 0xa0579640. +// +// Solidity: function isSafePaused() view returns(bool) +func (_SCExecProxy *SCExecProxySession) IsSafePaused() (bool, error) { + return _SCExecProxy.Contract.IsSafePaused(&_SCExecProxy.CallOpts) +} + +// IsSafePaused is a free data retrieval call binding the contract method 0xa0579640. +// +// Solidity: function isSafePaused() view returns(bool) +func (_SCExecProxy *SCExecProxyCallerSession) IsSafePaused() (bool, error) { + return _SCExecProxy.Contract.IsSafePaused(&_SCExecProxy.CallOpts) +} + +// Safe is a free data retrieval call binding the contract method 0x186f0354. +// +// Solidity: function safe() view returns(address) +func (_SCExecProxy *SCExecProxyCaller) Safe(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _SCExecProxy.contract.Call(opts, &out, "safe") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +// Safe is a free data retrieval call binding the contract method 0x186f0354. +// +// Solidity: function safe() view returns(address) +func (_SCExecProxy *SCExecProxySession) Safe() (common.Address, error) { + return _SCExecProxy.Contract.Safe(&_SCExecProxy.CallOpts) +} + +// Safe is a free data retrieval call binding the contract method 0x186f0354. +// +// Solidity: function safe() view returns(address) +func (_SCExecProxy *SCExecProxyCallerSession) Safe() (common.Address, error) { + return _SCExecProxy.Contract.Safe(&_SCExecProxy.CallOpts) +} + +// Deposit is a paid mutator transaction binding the contract method 0xb9930981. +// +// Solidity: function deposit(address tokenAddress, uint256 amount, bytes32 recipientAddress, uint64 mvxGasLimit, string callData) returns() +func (_SCExecProxy *SCExecProxyTransactor) Deposit(opts *bind.TransactOpts, tokenAddress common.Address, amount *big.Int, recipientAddress [32]byte, mvxGasLimit uint64, callData string) (*types.Transaction, error) { + return _SCExecProxy.contract.Transact(opts, "deposit", tokenAddress, amount, recipientAddress, mvxGasLimit, callData) +} + +// Deposit is a paid mutator transaction binding the contract method 0xb9930981. +// +// Solidity: function deposit(address tokenAddress, uint256 amount, bytes32 recipientAddress, uint64 mvxGasLimit, string callData) returns() +func (_SCExecProxy *SCExecProxySession) Deposit(tokenAddress common.Address, amount *big.Int, recipientAddress [32]byte, mvxGasLimit uint64, callData string) (*types.Transaction, error) { + return _SCExecProxy.Contract.Deposit(&_SCExecProxy.TransactOpts, tokenAddress, amount, recipientAddress, mvxGasLimit, callData) +} + +// Deposit is a paid mutator transaction binding the contract method 0xb9930981. +// +// Solidity: function deposit(address tokenAddress, uint256 amount, bytes32 recipientAddress, uint64 mvxGasLimit, string callData) returns() +func (_SCExecProxy *SCExecProxyTransactorSession) Deposit(tokenAddress common.Address, amount *big.Int, recipientAddress [32]byte, mvxGasLimit uint64, callData string) (*types.Transaction, error) { + return _SCExecProxy.Contract.Deposit(&_SCExecProxy.TransactOpts, tokenAddress, amount, recipientAddress, mvxGasLimit, callData) +} + +// RenounceAdmin is a paid mutator transaction binding the contract method 0x8bad0c0a. +// +// Solidity: function renounceAdmin() returns() +func (_SCExecProxy *SCExecProxyTransactor) RenounceAdmin(opts *bind.TransactOpts) (*types.Transaction, error) { + return _SCExecProxy.contract.Transact(opts, "renounceAdmin") +} + +// RenounceAdmin is a paid mutator transaction binding the contract method 0x8bad0c0a. +// +// Solidity: function renounceAdmin() returns() +func (_SCExecProxy *SCExecProxySession) RenounceAdmin() (*types.Transaction, error) { + return _SCExecProxy.Contract.RenounceAdmin(&_SCExecProxy.TransactOpts) +} + +// RenounceAdmin is a paid mutator transaction binding the contract method 0x8bad0c0a. +// +// Solidity: function renounceAdmin() returns() +func (_SCExecProxy *SCExecProxyTransactorSession) RenounceAdmin() (*types.Transaction, error) { + return _SCExecProxy.Contract.RenounceAdmin(&_SCExecProxy.TransactOpts) +} + +// SetSafe is a paid mutator transaction binding the contract method 0x5db0cb94. +// +// Solidity: function setSafe(address erc20Safe) returns() +func (_SCExecProxy *SCExecProxyTransactor) SetSafe(opts *bind.TransactOpts, erc20Safe common.Address) (*types.Transaction, error) { + return _SCExecProxy.contract.Transact(opts, "setSafe", erc20Safe) +} + +// SetSafe is a paid mutator transaction binding the contract method 0x5db0cb94. +// +// Solidity: function setSafe(address erc20Safe) returns() +func (_SCExecProxy *SCExecProxySession) SetSafe(erc20Safe common.Address) (*types.Transaction, error) { + return _SCExecProxy.Contract.SetSafe(&_SCExecProxy.TransactOpts, erc20Safe) +} + +// SetSafe is a paid mutator transaction binding the contract method 0x5db0cb94. +// +// Solidity: function setSafe(address erc20Safe) returns() +func (_SCExecProxy *SCExecProxyTransactorSession) SetSafe(erc20Safe common.Address) (*types.Transaction, error) { + return _SCExecProxy.Contract.SetSafe(&_SCExecProxy.TransactOpts, erc20Safe) +} + +// TransferAdmin is a paid mutator transaction binding the contract method 0x75829def. +// +// Solidity: function transferAdmin(address newAdmin) returns() +func (_SCExecProxy *SCExecProxyTransactor) TransferAdmin(opts *bind.TransactOpts, newAdmin common.Address) (*types.Transaction, error) { + return _SCExecProxy.contract.Transact(opts, "transferAdmin", newAdmin) +} + +// TransferAdmin is a paid mutator transaction binding the contract method 0x75829def. +// +// Solidity: function transferAdmin(address newAdmin) returns() +func (_SCExecProxy *SCExecProxySession) TransferAdmin(newAdmin common.Address) (*types.Transaction, error) { + return _SCExecProxy.Contract.TransferAdmin(&_SCExecProxy.TransactOpts, newAdmin) +} + +// TransferAdmin is a paid mutator transaction binding the contract method 0x75829def. +// +// Solidity: function transferAdmin(address newAdmin) returns() +func (_SCExecProxy *SCExecProxyTransactorSession) TransferAdmin(newAdmin common.Address) (*types.Transaction, error) { + return _SCExecProxy.Contract.TransferAdmin(&_SCExecProxy.TransactOpts, newAdmin) +} + +// SCExecProxyAdminRoleTransferredIterator is returned from FilterAdminRoleTransferred and is used to iterate over the raw logs and unpacked data for AdminRoleTransferred events raised by the SCExecProxy contract. +type SCExecProxyAdminRoleTransferredIterator struct { + Event *SCExecProxyAdminRoleTransferred // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *SCExecProxyAdminRoleTransferredIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(SCExecProxyAdminRoleTransferred) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(SCExecProxyAdminRoleTransferred) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *SCExecProxyAdminRoleTransferredIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *SCExecProxyAdminRoleTransferredIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// SCExecProxyAdminRoleTransferred represents a AdminRoleTransferred event raised by the SCExecProxy contract. +type SCExecProxyAdminRoleTransferred struct { + PreviousAdmin common.Address + NewAdmin common.Address + Raw types.Log // Blockchain specific contextual infos +} + +// FilterAdminRoleTransferred is a free log retrieval operation binding the contract event 0xe379ac64de02d8184ca1a871ac486cb8137de77e485ede140e97057b9c765ffd. +// +// Solidity: event AdminRoleTransferred(address indexed previousAdmin, address indexed newAdmin) +func (_SCExecProxy *SCExecProxyFilterer) FilterAdminRoleTransferred(opts *bind.FilterOpts, previousAdmin []common.Address, newAdmin []common.Address) (*SCExecProxyAdminRoleTransferredIterator, error) { + + var previousAdminRule []interface{} + for _, previousAdminItem := range previousAdmin { + previousAdminRule = append(previousAdminRule, previousAdminItem) + } + var newAdminRule []interface{} + for _, newAdminItem := range newAdmin { + newAdminRule = append(newAdminRule, newAdminItem) + } + + logs, sub, err := _SCExecProxy.contract.FilterLogs(opts, "AdminRoleTransferred", previousAdminRule, newAdminRule) + if err != nil { + return nil, err + } + return &SCExecProxyAdminRoleTransferredIterator{contract: _SCExecProxy.contract, event: "AdminRoleTransferred", logs: logs, sub: sub}, nil +} + +// WatchAdminRoleTransferred is a free log subscription operation binding the contract event 0xe379ac64de02d8184ca1a871ac486cb8137de77e485ede140e97057b9c765ffd. +// +// Solidity: event AdminRoleTransferred(address indexed previousAdmin, address indexed newAdmin) +func (_SCExecProxy *SCExecProxyFilterer) WatchAdminRoleTransferred(opts *bind.WatchOpts, sink chan<- *SCExecProxyAdminRoleTransferred, previousAdmin []common.Address, newAdmin []common.Address) (event.Subscription, error) { + + var previousAdminRule []interface{} + for _, previousAdminItem := range previousAdmin { + previousAdminRule = append(previousAdminRule, previousAdminItem) + } + var newAdminRule []interface{} + for _, newAdminItem := range newAdmin { + newAdminRule = append(newAdminRule, newAdminItem) + } + + logs, sub, err := _SCExecProxy.contract.WatchLogs(opts, "AdminRoleTransferred", previousAdminRule, newAdminRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(SCExecProxyAdminRoleTransferred) + if err := _SCExecProxy.contract.UnpackLog(event, "AdminRoleTransferred", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseAdminRoleTransferred is a log parse operation binding the contract event 0xe379ac64de02d8184ca1a871ac486cb8137de77e485ede140e97057b9c765ffd. +// +// Solidity: event AdminRoleTransferred(address indexed previousAdmin, address indexed newAdmin) +func (_SCExecProxy *SCExecProxyFilterer) ParseAdminRoleTransferred(log types.Log) (*SCExecProxyAdminRoleTransferred, error) { + event := new(SCExecProxyAdminRoleTransferred) + if err := _SCExecProxy.contract.UnpackLog(event, "AdminRoleTransferred", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// SCExecProxyERC20SCDepositIterator is returned from FilterERC20SCDeposit and is used to iterate over the raw logs and unpacked data for ERC20SCDeposit events raised by the SCExecProxy contract. +type SCExecProxyERC20SCDepositIterator struct { + Event *SCExecProxyERC20SCDeposit // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *SCExecProxyERC20SCDepositIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(SCExecProxyERC20SCDeposit) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(SCExecProxyERC20SCDeposit) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *SCExecProxyERC20SCDepositIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *SCExecProxyERC20SCDepositIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// SCExecProxyERC20SCDeposit represents a ERC20SCDeposit event raised by the SCExecProxy contract. +type SCExecProxyERC20SCDeposit struct { + BatchNonce uint64 + DepositNonce uint64 + MvxGasLimit uint64 + CallData string + Raw types.Log // Blockchain specific contextual infos +} + +// FilterERC20SCDeposit is a free log retrieval operation binding the contract event 0x4f330e92497d6cc47fffe9408a15ace7b6012d2999529e32dd9b3de825e4f748. +// +// Solidity: event ERC20SCDeposit(uint64 indexed batchNonce, uint64 depositNonce, uint64 mvxGasLimit, string callData) +func (_SCExecProxy *SCExecProxyFilterer) FilterERC20SCDeposit(opts *bind.FilterOpts, batchNonce []uint64) (*SCExecProxyERC20SCDepositIterator, error) { + + var batchNonceRule []interface{} + for _, batchNonceItem := range batchNonce { + batchNonceRule = append(batchNonceRule, batchNonceItem) + } + + logs, sub, err := _SCExecProxy.contract.FilterLogs(opts, "ERC20SCDeposit", batchNonceRule) + if err != nil { + return nil, err + } + return &SCExecProxyERC20SCDepositIterator{contract: _SCExecProxy.contract, event: "ERC20SCDeposit", logs: logs, sub: sub}, nil +} + +// WatchERC20SCDeposit is a free log subscription operation binding the contract event 0x4f330e92497d6cc47fffe9408a15ace7b6012d2999529e32dd9b3de825e4f748. +// +// Solidity: event ERC20SCDeposit(uint64 indexed batchNonce, uint64 depositNonce, uint64 mvxGasLimit, string callData) +func (_SCExecProxy *SCExecProxyFilterer) WatchERC20SCDeposit(opts *bind.WatchOpts, sink chan<- *SCExecProxyERC20SCDeposit, batchNonce []uint64) (event.Subscription, error) { + + var batchNonceRule []interface{} + for _, batchNonceItem := range batchNonce { + batchNonceRule = append(batchNonceRule, batchNonceItem) + } + + logs, sub, err := _SCExecProxy.contract.WatchLogs(opts, "ERC20SCDeposit", batchNonceRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(SCExecProxyERC20SCDeposit) + if err := _SCExecProxy.contract.UnpackLog(event, "ERC20SCDeposit", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseERC20SCDeposit is a log parse operation binding the contract event 0x4f330e92497d6cc47fffe9408a15ace7b6012d2999529e32dd9b3de825e4f748. +// +// Solidity: event ERC20SCDeposit(uint64 indexed batchNonce, uint64 depositNonce, uint64 mvxGasLimit, string callData) +func (_SCExecProxy *SCExecProxyFilterer) ParseERC20SCDeposit(log types.Log) (*SCExecProxyERC20SCDeposit, error) { + event := new(SCExecProxyERC20SCDeposit) + if err := _SCExecProxy.contract.UnpackLog(event, "ERC20SCDeposit", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} diff --git a/clients/ethereum/interface.go b/clients/ethereum/interface.go index d3ee7602..063e65d5 100644 --- a/clients/ethereum/interface.go +++ b/clients/ethereum/interface.go @@ -4,6 +4,7 @@ import ( "context" "math/big" + "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" @@ -30,6 +31,7 @@ type ClientWrapper interface { TokenMintedBalances(ctx context.Context, token common.Address) (*big.Int, error) WhitelistedTokensMintBurn(ctx context.Context, token common.Address) (bool, error) IsPaused(ctx context.Context) (bool, error) + FilterLogs(ctx context.Context, q ethereum.FilterQuery) ([]types.Log, error) } // Erc20ContractsHolder defines the Ethereum ERC20 contract operations diff --git a/clients/ethereum/wrappers/ethereumChainWrapper.go b/clients/ethereum/wrappers/ethereumChainWrapper.go index 02e1c53e..c95296a4 100644 --- a/clients/ethereum/wrappers/ethereumChainWrapper.go +++ b/clients/ethereum/wrappers/ethereumChainWrapper.go @@ -4,6 +4,7 @@ import ( "context" "math/big" + "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" @@ -90,6 +91,12 @@ func (wrapper *ethereumChainWrapper) ChainID(ctx context.Context) (*big.Int, err return wrapper.blockchainClient.ChainID(ctx) } +// FilterLogs executes a query and returns matching logs and events +func (wrapper *ethereumChainWrapper) FilterLogs(ctx context.Context, q ethereum.FilterQuery) ([]types.Log, error) { + wrapper.AddIntMetric(core.MetricNumEthClientRequests, 1) + return wrapper.blockchainClient.FilterLogs(ctx, q) +} + // BlockNumber returns the current ethereum block number func (wrapper *ethereumChainWrapper) BlockNumber(ctx context.Context) (uint64, error) { wrapper.AddIntMetric(core.MetricNumEthClientRequests, 1) diff --git a/clients/ethereum/wrappers/ethereumChainWrapper_test.go b/clients/ethereum/wrappers/ethereumChainWrapper_test.go index 7bb468d0..079401ef 100644 --- a/clients/ethereum/wrappers/ethereumChainWrapper_test.go +++ b/clients/ethereum/wrappers/ethereumChainWrapper_test.go @@ -4,8 +4,10 @@ import ( "context" "errors" "math/big" + "reflect" "testing" + "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" @@ -63,6 +65,16 @@ func TestNewMultiSigContractWrapper(t *testing.T) { assert.True(t, check.IfNil(wrapper)) assert.Equal(t, errNilMultiSigContract, err) }) + t.Run("nil sc exec contract", func(t *testing.T) { + t.Parallel() + + args, _ := createMockArgsEthereumChainWrapper() + args.MultiSigContract = nil + + wrapper, err := NewEthereumChainWrapper(args) + assert.True(t, check.IfNil(wrapper)) + assert.Equal(t, errNilMultiSigContract, err) + }) t.Run("should work", func(t *testing.T) { t.Parallel() @@ -295,3 +307,45 @@ func TestEthereumChainWrapper_IsPaused(t *testing.T) { assert.True(t, result) assert.True(t, handlerCalled) } + +func TestEthereumChainWrapper_FilterLogs(t *testing.T) { + t.Parallel() + + expectedError := errors.New("expected error") + args, _ := createMockArgsEthereumChainWrapper() + + t.Run("returns error", func(t *testing.T) { + args.BlockchainClient = &interactors.BlockchainClientStub{ + FilterLogsCalled: func(ctx context.Context, q ethereum.FilterQuery) ([]types.Log, error) { + return nil, expectedError + }, + } + + wrapper, _ := NewEthereumChainWrapper(args) + + logs, err := wrapper.FilterLogs(context.Background(), ethereum.FilterQuery{}) + + assert.Nil(t, logs) + assert.Equal(t, expectedError, err) + }) + + t.Run("returns expected logs", func(t *testing.T) { + expectedLogs := []types.Log{ + { + Index: 1, + }, + } + args.BlockchainClient = &interactors.BlockchainClientStub{ + FilterLogsCalled: func(ctx context.Context, q ethereum.FilterQuery) ([]types.Log, error) { + return expectedLogs, nil + }, + } + + wrapper, _ := NewEthereumChainWrapper(args) + logs, err := wrapper.FilterLogs(context.Background(), ethereum.FilterQuery{}) + + assert.Nil(t, err) + assert.True(t, reflect.DeepEqual(expectedLogs, logs)) + }) + +} diff --git a/clients/ethereum/wrappers/interface.go b/clients/ethereum/wrappers/interface.go index bb41a6f6..ab78d1d0 100644 --- a/clients/ethereum/wrappers/interface.go +++ b/clients/ethereum/wrappers/interface.go @@ -4,6 +4,7 @@ import ( "context" "math/big" + "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" @@ -35,4 +36,5 @@ type blockchainClient interface { NonceAt(ctx context.Context, account common.Address, blockNumber *big.Int) (uint64, error) ChainID(ctx context.Context) (*big.Int, error) BalanceAt(ctx context.Context, account common.Address, blockNumber *big.Int) (*big.Int, error) + FilterLogs(ctx context.Context, q ethereum.FilterQuery) ([]types.Log, error) } diff --git a/clients/multiversx/client.go b/clients/multiversx/client.go index 9d47907f..448bb034 100644 --- a/clients/multiversx/client.go +++ b/clients/multiversx/client.go @@ -66,6 +66,11 @@ type client struct { mut sync.RWMutex } +type scCallExtraGas struct { + basicGas uint64 + performAction uint64 +} + // NewClient returns a new MultiversX Client instance func NewClient(args ClientArgs) (*client, error) { err := checkArgs(args) @@ -76,7 +81,6 @@ func NewClient(args ClientArgs) (*client, error) { argNonceHandler := nonceHandlerV2.ArgsNonceTransactionsHandlerV2{ Proxy: args.Proxy, IntervalToResend: time.Second * time.Duration(args.IntervalToResendTxsInSeconds), - Creator: &nonceHandlerV2.AddressNonceHandlerCreator{}, } nonceTxsHandler, err := nonceHandlerV2.NewNonceTransactionHandlerV2(argNonceHandler) if err != nil { @@ -107,11 +111,16 @@ func NewClient(args ClientArgs) (*client, error) { return nil, clients.ErrNilAddressConverter } + bech23MultisigAddress, err := args.MultisigContractAddress.AddressAsBech32String() + if err != nil { + return nil, fmt.Errorf("%w for %x", err, args.MultisigContractAddress.AddressBytes()) + } + c := &client{ txHandler: &transactionHandler{ proxy: args.Proxy, relayerAddress: relayerAddress, - multisigAddressAsBech32: addressConverter.ToBech32String(args.MultisigContractAddress.AddressBytes()), + multisigAddressAsBech32: bech23MultisigAddress, nonceTxHandler: nonceTxsHandler, relayerPrivateKey: args.RelayerPrivateKey, singleSigner: &singlesig.Ed25519Signer{}, @@ -129,9 +138,10 @@ func NewClient(args ClientArgs) (*client, error) { allowDelta: args.AllowDelta, } + bech32RelayerAddress, _ := relayerAddress.AddressAsBech32String() c.log.Info("NewMultiversXClient", - "relayer address", addressConverter.ToBech32String(relayerAddress.AddressBytes()), - "safe contract address", addressConverter.ToBech32String(args.MultisigContractAddress.AddressBytes())) + "relayer address", bech32RelayerAddress, + "safe contract address", bech23MultisigAddress) return c, nil } @@ -232,7 +242,7 @@ func (c *client) createPendingBatchFromResponse(ctx context.Context, responseDat deposit := &clients.DepositTransfer{ Nonce: depositNonce, FromBytes: responseData[i+2], - DisplayableFrom: c.addressPublicKeyConverter.ToBech32String(responseData[i+2]), + DisplayableFrom: c.addressPublicKeyConverter.ToBech32StringSilent(responseData[i+2]), ToBytes: responseData[i+3], DisplayableTo: c.addressPublicKeyConverter.ToHexStringWithPrefix(responseData[i+3]), TokenBytes: responseData[i+4], @@ -310,9 +320,17 @@ func (c *client) ProposeTransfer(ctx context.Context, batch *clients.TransferBat ArgBytes(dt.ConvertedTokenBytes). ArgBigInt(dt.Amount). ArgInt64(int64(dt.Nonce)) + + if len(dt.Data) > 0 { + // SC call type of transfer + txBuilder.ArgBytes(dt.Data).ArgInt64(int64(dt.ExtraGasLimit)) + } } + scCallGas := c.computeExtraGasForSCCallsBasic(batch) + gasLimit := c.gasMapConfig.ProposeTransferBase + uint64(len(batch.Deposits))*c.gasMapConfig.ProposeTransferForEach + gasLimit += scCallGas.basicGas hash, err := c.txHandler.SendTransactionReturnHash(ctx, txBuilder, gasLimit) if err == nil { c.log.Info("proposed transfer"+batch.String(), "transaction hash", hash) @@ -351,7 +369,10 @@ func (c *client) PerformAction(ctx context.Context, actionID uint64, batch *clie txBuilder := c.createCommonTxDataBuilder(performActionFuncName, int64(actionID)) + scCallGas := c.computeExtraGasForSCCallsBasic(batch) + gasLimit := c.gasMapConfig.PerformActionBase + uint64(len(batch.Statuses))*c.gasMapConfig.PerformActionForEach + gasLimit += scCallGas.basicGas + scCallGas.performAction hash, err := c.txHandler.SendTransactionReturnHash(ctx, txBuilder, gasLimit) if err == nil { @@ -361,6 +382,24 @@ func (c *client) PerformAction(ctx context.Context, actionID uint64, batch *clie return hash, err } +func (c *client) computeExtraGasForSCCallsBasic(batch *clients.TransferBatch) scCallExtraGas { + result := scCallExtraGas{} + for _, deposit := range batch.Deposits { + if len(deposit.Data) == 0 { + continue + } + + computedLen := 2 // 2 extra arguments separators (@) + computedLen += len(deposit.Data) * 2 // the data is hexed, so, double the size + computedLen += len(big.NewInt(int64(deposit.ExtraGasLimit)).Bytes()) * 2 // the gas is converted to bytes, then hexed + + result.basicGas += uint64(computedLen) * c.gasMapConfig.ScCallPerByte + result.performAction += c.gasMapConfig.ScCallPerformForEach + } + + return result +} + func (c *client) checkIsPaused(ctx context.Context) error { isPaused, err := c.IsPaused(ctx) if err != nil { diff --git a/clients/multiversx/client_test.go b/clients/multiversx/client_test.go index de40b64a..425ce5d0 100644 --- a/clients/multiversx/client_test.go +++ b/clients/multiversx/client_test.go @@ -45,6 +45,8 @@ func createMockClientArgs() ClientArgs { ProposeStatusForEach: 50, PerformActionBase: 60, PerformActionForEach: 70, + ScCallPerByte: 80, + ScCallPerformForEach: 90, }, Proxy: &interactors.ProxyStub{}, Log: logger.GetOrCreate("test"), @@ -545,6 +547,54 @@ func TestClient_ProposeTransfer(t *testing.T) { }, } + hash, err := c.ProposeTransfer(context.Background(), batch) + assert.Nil(t, err) + assert.Equal(t, expectedHash, hash) + assert.True(t, sendWasCalled) + }) + t.Run("should propose transfer with SC call", func(t *testing.T) { + t.Parallel() + + args := createMockClientArgs() + args.Proxy = createMockProxy(make([][]byte, 0)) + expectedHash := "expected hash" + c, _ := NewClient(args) + sendWasCalled := false + batch := createMockBatch() + batch.Deposits[0].ExtraGasLimit = 37373 + batch.Deposits[0].Data = []byte("doSomething@7788") + batch.Deposits[0].DisplayableData = hex.EncodeToString(batch.Deposits[0].Data) + + c.txHandler = &bridgeTests.TxHandlerStub{ + SendTransactionReturnHashCalled: func(ctx context.Context, builder builders.TxDataBuilder, gasLimit uint64) (string, error) { + sendWasCalled = true + + dataField, err := builder.ToDataString() + assert.Nil(t, err) + + dataStrings := []string{ + proposeTransferFuncName, + hex.EncodeToString(big.NewInt(int64(batch.ID)).Bytes()), + } + extraGas := uint64(0) + for _, dt := range batch.Deposits { + dataStrings = append(dataStrings, depositToStrings(dt)...) + if len(dt.Data) > 0 { + gasLimitBytes := big.NewInt(int64(dt.ExtraGasLimit)).Bytes() + extraGas += (uint64(len(dt.Data)+len(gasLimitBytes))*2 + 2) * args.GasMapConfig.ScCallPerByte + } + } + + expectedDataField := strings.Join(dataStrings, "@") + assert.Equal(t, expectedDataField, dataField) + + expectedGasLimit := c.gasMapConfig.ProposeTransferBase + uint64(len(batch.Deposits))*c.gasMapConfig.ProposeTransferForEach + extraGas + assert.Equal(t, expectedGasLimit, gasLimit) + + return expectedHash, nil + }, + } + hash, err := c.ProposeTransfer(context.Background(), batch) assert.Nil(t, err) assert.Equal(t, expectedHash, hash) @@ -561,6 +611,11 @@ func depositToStrings(dt *clients.DepositTransfer) []string { hex.EncodeToString(big.NewInt(int64(dt.Nonce)).Bytes()), } + if len(dt.Data) > 0 { + result = append(result, hex.EncodeToString(dt.Data)) + result = append(result, hex.EncodeToString(big.NewInt(int64(dt.ExtraGasLimit)).Bytes())) + } + return result } @@ -706,8 +761,58 @@ func TestClient_PerformAction(t *testing.T) { } expectedDataField := strings.Join(dataStrings, "@") assert.Equal(t, expectedDataField, dataField) - expectedGasdLimit := c.gasMapConfig.PerformActionBase + uint64(len(batch.Statuses))*c.gasMapConfig.PerformActionForEach - assert.Equal(t, expectedGasdLimit, gasLimit) + expectedGasLimit := c.gasMapConfig.PerformActionBase + uint64(len(batch.Statuses))*c.gasMapConfig.PerformActionForEach + assert.Equal(t, expectedGasLimit, gasLimit) + + return expectedHash, nil + }, + } + + hash, err := c.PerformAction(context.Background(), actionID, batch) + assert.Nil(t, err) + assert.Equal(t, expectedHash, hash) + assert.True(t, sendWasCalled) + }) + t.Run("should perform action with SC call", func(t *testing.T) { + t.Parallel() + + args := createMockClientArgs() + args.Proxy = createMockProxy(make([][]byte, 0)) + expectedHash := "expected hash" + c, _ := NewClient(args) + sendWasCalled := false + batch := createMockBatch() + batch.Deposits[0].ExtraGasLimit = 37373 + batch.Deposits[0].Data = []byte("doSomething@7788") + batch.Deposits[0].DisplayableData = hex.EncodeToString(batch.Deposits[0].Data) + + c.txHandler = &bridgeTests.TxHandlerStub{ + SendTransactionReturnHashCalled: func(ctx context.Context, builder builders.TxDataBuilder, gasLimit uint64) (string, error) { + sendWasCalled = true + + dataField, err := builder.ToDataString() + assert.Nil(t, err) + + dataStrings := []string{ + performActionFuncName, + hex.EncodeToString(big.NewInt(int64(actionID)).Bytes()), + } + expectedDataField := strings.Join(dataStrings, "@") + assert.Equal(t, expectedDataField, dataField) + + extraGas := uint64(0) + for _, dt := range batch.Deposits { + dataStrings = append(dataStrings, depositToStrings(dt)...) + if len(dt.Data) > 0 { + gasLimitBytes := big.NewInt(int64(dt.ExtraGasLimit)).Bytes() + extraGas += (uint64(len(dt.Data)+len(gasLimitBytes))*2 + 2) * args.GasMapConfig.ScCallPerByte + extraGas += args.GasMapConfig.ScCallPerformForEach + } + } + + expectedGasLimit := c.gasMapConfig.PerformActionBase + uint64(len(batch.Statuses))*c.gasMapConfig.PerformActionForEach + expectedGasLimit += extraGas + assert.Equal(t, expectedGasLimit, gasLimit) return expectedHash, nil }, diff --git a/clients/multiversx/mxClientDataGetter.go b/clients/multiversx/mxClientDataGetter.go index 48e70cea..97331632 100644 --- a/clients/multiversx/mxClientDataGetter.go +++ b/clients/multiversx/mxClientDataGetter.go @@ -46,13 +46,14 @@ type ArgsMXClientDataGetter struct { } type mxClientDataGetter struct { - multisigContractAddress core.AddressHandler - relayerAddress core.AddressHandler - proxy Proxy - log logger.Logger - mutNodeStatus sync.Mutex - wasShardIDFetched bool - shardID uint32 + multisigContractAddress core.AddressHandler + bech32MultisigContractAddress string + relayerAddress core.AddressHandler + proxy Proxy + log logger.Logger + mutNodeStatus sync.Mutex + wasShardIDFetched bool + shardID uint32 } // NewMXClientDataGetter creates a new instance of the dataGetter type @@ -69,12 +70,17 @@ func NewMXClientDataGetter(args ArgsMXClientDataGetter) (*mxClientDataGetter, er if check.IfNil(args.MultisigContractAddress) { return nil, fmt.Errorf("%w for the MultisigContractAddress argument", errNilAddressHandler) } + bech32Address, err := args.MultisigContractAddress.AddressAsBech32String() + if err != nil { + return nil, fmt.Errorf("%w for %x", err, args.MultisigContractAddress.AddressBytes()) + } return &mxClientDataGetter{ - multisigContractAddress: args.MultisigContractAddress, - relayerAddress: args.RelayerAddress, - proxy: args.Proxy, - log: args.Log, + multisigContractAddress: args.MultisigContractAddress, + bech32MultisigContractAddress: bech32Address, + relayerAddress: args.RelayerAddress, + proxy: args.Proxy, + log: args.Log, }, nil } @@ -133,7 +139,7 @@ func (dataGetter *mxClientDataGetter) getShardID(ctx context.Context) (uint32, e } var err error - dataGetter.shardID, err = dataGetter.proxy.GetShardOfAddress(ctx, dataGetter.multisigContractAddress.AddressAsBech32String()) + dataGetter.shardID, err = dataGetter.proxy.GetShardOfAddress(ctx, dataGetter.bech32MultisigContractAddress) if err == nil { dataGetter.wasShardIDFetched = true } @@ -356,7 +362,7 @@ func (dataGetter *mxClientDataGetter) GetTransactionsStatuses(ctx context.Contex return nil, fmt.Errorf("%w for batch ID %v", errNoStatusForBatchID, batchID) } - isFinished, err := dataGetter.parseBool(values[0], getStatusesAfterExecutionFuncName, dataGetter.multisigContractAddress.AddressAsBech32String()) + isFinished, err := dataGetter.parseBool(values[0], getStatusesAfterExecutionFuncName, dataGetter.bech32MultisigContractAddress) if err != nil { return nil, err } @@ -469,6 +475,11 @@ func addBatchInfo(builder builders.VMQueryBuilder, batch *clients.TransferBatch) ArgBytes(dt.ConvertedTokenBytes). ArgBigInt(dt.Amount). ArgInt64(int64(dt.Nonce)) + + if len(dt.Data) > 0 { + // SC call type of transfer + builder.ArgBytes(dt.Data).ArgInt64(int64(dt.ExtraGasLimit)) + } } } diff --git a/clients/multiversx/mxClientDataGetter_test.go b/clients/multiversx/mxClientDataGetter_test.go index b111f519..06e2ab2c 100644 --- a/clients/multiversx/mxClientDataGetter_test.go +++ b/clients/multiversx/mxClientDataGetter_test.go @@ -16,6 +16,7 @@ import ( "github.com/multiversx/mx-chain-core-go/data/vm" logger "github.com/multiversx/mx-chain-logger-go" "github.com/multiversx/mx-sdk-go/builders" + "github.com/multiversx/mx-sdk-go/core" "github.com/multiversx/mx-sdk-go/data" "github.com/stretchr/testify/assert" ) @@ -40,6 +41,12 @@ func createMockArgsMXClientDataGetter() ArgsMXClientDataGetter { return args } +func getBech32Address(addressHandler core.AddressHandler) string { + bech32Address, _ := addressHandler.AddressAsBech32String() + + return bech32Address +} + func createMockProxy(returningBytes [][]byte) *interactors.ProxyStub { return &interactors.ProxyStub{ ExecuteVMQueryCalled: func(ctx context.Context, vmRequest *data.VmValueRequest) (*data.VmValuesResponseData, error) { @@ -173,7 +180,7 @@ func TestMXClientDataGetter_ExecuteQueryReturningBytes(t *testing.T) { dg, _ := NewMXClientDataGetter(args) - expectedErr := NewQueryResponseError(returnCode, returnMessage, calledFunction, dg.multisigContractAddress.AddressAsBech32String(), calledArgs...) + expectedErr := NewQueryResponseError(returnCode, returnMessage, calledFunction, getBech32Address(dg.multisigContractAddress), calledArgs...) dg.proxy = &interactors.ProxyStub{ ExecuteVMQueryCalled: func(ctx context.Context, vmRequest *data.VmValueRequest) (*data.VmValuesResponseData, error) { return &data.VmValuesResponseData{ @@ -193,9 +200,9 @@ func TestMXClientDataGetter_ExecuteQueryReturningBytes(t *testing.T) { } request := &data.VmValueRequest{ - Address: dg.multisigContractAddress.AddressAsBech32String(), + Address: getBech32Address(dg.multisigContractAddress), FuncName: calledFunction, - CallerAddr: dg.relayerAddress.AddressAsBech32String(), + CallerAddr: getBech32Address(dg.relayerAddress), CallValue: "0", Args: calledArgs, } @@ -229,9 +236,9 @@ func TestMXClientDataGetter_ExecuteQueryReturningBytes(t *testing.T) { } request := &data.VmValueRequest{ - Address: dg.multisigContractAddress.AddressAsBech32String(), + Address: getBech32Address(dg.multisigContractAddress), FuncName: calledFunction, - CallerAddr: dg.relayerAddress.AddressAsBech32String(), + CallerAddr: getBech32Address(dg.relayerAddress), CallValue: "0", Args: calledArgs, } @@ -439,8 +446,8 @@ func TestMXClientDataGetter_GetCurrentBatchAsDataBytes(t *testing.T) { returningBytes := [][]byte{[]byte("buff0"), []byte("buff1"), []byte("buff2")} args.Proxy = &interactors.ProxyStub{ ExecuteVMQueryCalled: func(ctx context.Context, vmRequest *data.VmValueRequest) (*data.VmValuesResponseData, error) { - assert.Equal(t, args.MultisigContractAddress.AddressAsBech32String(), vmRequest.Address) - assert.Equal(t, args.RelayerAddress.AddressAsBech32String(), vmRequest.CallerAddr) + assert.Equal(t, getBech32Address(args.MultisigContractAddress), vmRequest.Address) + assert.Equal(t, getBech32Address(args.RelayerAddress), vmRequest.CallerAddr) assert.Equal(t, 0, len(vmRequest.CallValue)) assert.Equal(t, getCurrentTxBatchFuncName, vmRequest.FuncName) @@ -491,8 +498,8 @@ func TestMXClientDataGetter_GetTokenIdForErc20Address(t *testing.T) { returningBytes := [][]byte{[]byte(erdAddress)} args.Proxy = &interactors.ProxyStub{ ExecuteVMQueryCalled: func(ctx context.Context, vmRequest *data.VmValueRequest) (*data.VmValuesResponseData, error) { - assert.Equal(t, args.MultisigContractAddress.AddressAsBech32String(), vmRequest.Address) - assert.Equal(t, args.RelayerAddress.AddressAsBech32String(), vmRequest.CallerAddr) + assert.Equal(t, getBech32Address(args.MultisigContractAddress), vmRequest.Address) + assert.Equal(t, getBech32Address(args.RelayerAddress), vmRequest.CallerAddr) assert.Equal(t, 0, len(vmRequest.CallValue)) assert.Equal(t, []string{hex.EncodeToString([]byte(erc20Address))}, vmRequest.Args) assert.Equal(t, getTokenIdForErc20AddressFuncName, vmRequest.FuncName) @@ -522,8 +529,8 @@ func TestMXClientDataGetter_GetERC20AddressForTokenId(t *testing.T) { returningBytes := [][]byte{[]byte(erc20Address)} args.Proxy = &interactors.ProxyStub{ ExecuteVMQueryCalled: func(ctx context.Context, vmRequest *data.VmValueRequest) (*data.VmValuesResponseData, error) { - assert.Equal(t, args.MultisigContractAddress.AddressAsBech32String(), vmRequest.Address) - assert.Equal(t, args.RelayerAddress.AddressAsBech32String(), vmRequest.CallerAddr) + assert.Equal(t, getBech32Address(args.MultisigContractAddress), vmRequest.Address) + assert.Equal(t, getBech32Address(args.RelayerAddress), vmRequest.CallerAddr) assert.Equal(t, 0, len(vmRequest.CallValue)) assert.Equal(t, []string{hex.EncodeToString([]byte(erdAddress))}, vmRequest.Args) assert.Equal(t, getErc20AddressForTokenIdFuncName, vmRequest.FuncName) @@ -565,8 +572,8 @@ func TestMXClientDataGetter_WasProposedTransfer(t *testing.T) { args.Proxy = &interactors.ProxyStub{ ExecuteVMQueryCalled: func(ctx context.Context, vmRequest *data.VmValueRequest) (*data.VmValuesResponseData, error) { proxyCalled = true - assert.Equal(t, args.RelayerAddress.AddressAsBech32String(), vmRequest.CallerAddr) - assert.Equal(t, args.MultisigContractAddress.AddressAsBech32String(), vmRequest.Address) + assert.Equal(t, getBech32Address(args.RelayerAddress), vmRequest.CallerAddr) + assert.Equal(t, getBech32Address(args.MultisigContractAddress), vmRequest.Address) assert.Equal(t, "", vmRequest.CallValue) assert.Equal(t, wasTransferActionProposedFuncName, vmRequest.FuncName) @@ -601,6 +608,59 @@ func TestMXClientDataGetter_WasProposedTransfer(t *testing.T) { batch := createMockBatch() + result, err := dg.WasProposedTransfer(context.Background(), batch) + assert.True(t, result) + assert.Nil(t, err) + assert.True(t, proxyCalled) + }) + t.Run("should work with SC calls", func(t *testing.T) { + t.Parallel() + + args := createMockArgsMXClientDataGetter() + proxyCalled := false + args.Proxy = &interactors.ProxyStub{ + ExecuteVMQueryCalled: func(ctx context.Context, vmRequest *data.VmValueRequest) (*data.VmValuesResponseData, error) { + proxyCalled = true + assert.Equal(t, getBech32Address(args.RelayerAddress), vmRequest.CallerAddr) + assert.Equal(t, getBech32Address(args.MultisigContractAddress), vmRequest.Address) + assert.Equal(t, "", vmRequest.CallValue) + assert.Equal(t, wasTransferActionProposedFuncName, vmRequest.FuncName) + + expectedArgs := []string{ + hex.EncodeToString(big.NewInt(112233).Bytes()), + + hex.EncodeToString([]byte("from1")), + hex.EncodeToString([]byte("to1")), + hex.EncodeToString([]byte("converted_token1")), + hex.EncodeToString(big.NewInt(2).Bytes()), + hex.EncodeToString(big.NewInt(1).Bytes()), + hex.EncodeToString([]byte("doSomething@7738")), + hex.EncodeToString(big.NewInt(5).Bytes()), + + hex.EncodeToString([]byte("from2")), + hex.EncodeToString([]byte("to2")), + hex.EncodeToString([]byte("converted_token2")), + hex.EncodeToString(big.NewInt(4).Bytes()), + hex.EncodeToString(big.NewInt(3).Bytes()), + } + + assert.Equal(t, expectedArgs, vmRequest.Args) + + return &data.VmValuesResponseData{ + Data: &vm.VMOutputApi{ + ReturnCode: okCodeAfterExecution, + ReturnData: [][]byte{{1}}, + }, + }, nil + }, + } + + dg, _ := NewMXClientDataGetter(args) + + batch := createMockBatch() + batch.Deposits[0].Data = []byte("doSomething@7738") + batch.Deposits[0].ExtraGasLimit = 5 + result, err := dg.WasProposedTransfer(context.Background(), batch) assert.True(t, result) assert.Nil(t, err) @@ -616,8 +676,8 @@ func TestMXClientDataGetter_WasExecuted(t *testing.T) { args.Proxy = &interactors.ProxyStub{ ExecuteVMQueryCalled: func(ctx context.Context, vmRequest *data.VmValueRequest) (*data.VmValuesResponseData, error) { proxyCalled = true - assert.Equal(t, args.RelayerAddress.AddressAsBech32String(), vmRequest.CallerAddr) - assert.Equal(t, args.MultisigContractAddress.AddressAsBech32String(), vmRequest.Address) + assert.Equal(t, getBech32Address(args.RelayerAddress), vmRequest.CallerAddr) + assert.Equal(t, getBech32Address(args.MultisigContractAddress), vmRequest.Address) assert.Equal(t, "", vmRequest.CallValue) assert.Equal(t, wasActionExecutedFuncName, vmRequest.FuncName) @@ -686,8 +746,57 @@ func TestMXClientDataGetter_GetActionIDForProposeTransfer(t *testing.T) { args.Proxy = &interactors.ProxyStub{ ExecuteVMQueryCalled: func(ctx context.Context, vmRequest *data.VmValueRequest) (*data.VmValuesResponseData, error) { proxyCalled = true - assert.Equal(t, args.RelayerAddress.AddressAsBech32String(), vmRequest.CallerAddr) - assert.Equal(t, args.MultisigContractAddress.AddressAsBech32String(), vmRequest.Address) + assert.Equal(t, getBech32Address(args.RelayerAddress), vmRequest.CallerAddr) + assert.Equal(t, getBech32Address(args.MultisigContractAddress), vmRequest.Address) + assert.Equal(t, "", vmRequest.CallValue) + assert.Equal(t, getActionIdForTransferBatchFuncName, vmRequest.FuncName) + + expectedArgs := []string{ + hex.EncodeToString(big.NewInt(112233).Bytes()), + + hex.EncodeToString([]byte("from1")), + hex.EncodeToString([]byte("to1")), + hex.EncodeToString([]byte("converted_token1")), + hex.EncodeToString(big.NewInt(2).Bytes()), + hex.EncodeToString(big.NewInt(1).Bytes()), + + hex.EncodeToString([]byte("from2")), + hex.EncodeToString([]byte("to2")), + hex.EncodeToString([]byte("converted_token2")), + hex.EncodeToString(big.NewInt(4).Bytes()), + hex.EncodeToString(big.NewInt(3).Bytes()), + } + + assert.Equal(t, expectedArgs, vmRequest.Args) + + return &data.VmValuesResponseData{ + Data: &vm.VMOutputApi{ + ReturnCode: okCodeAfterExecution, + ReturnData: [][]byte{big.NewInt(1234).Bytes()}, + }, + }, nil + }, + } + + dg, _ := NewMXClientDataGetter(args) + + batch := createMockBatch() + + result, err := dg.GetActionIDForProposeTransfer(context.Background(), batch) + assert.Equal(t, uint64(1234), result) + assert.Nil(t, err) + assert.True(t, proxyCalled) + }) + t.Run("should work with SC calls", func(t *testing.T) { + t.Parallel() + + args := createMockArgsMXClientDataGetter() + proxyCalled := false + args.Proxy = &interactors.ProxyStub{ + ExecuteVMQueryCalled: func(ctx context.Context, vmRequest *data.VmValueRequest) (*data.VmValuesResponseData, error) { + proxyCalled = true + assert.Equal(t, getBech32Address(args.RelayerAddress), vmRequest.CallerAddr) + assert.Equal(t, getBech32Address(args.MultisigContractAddress), vmRequest.Address) assert.Equal(t, "", vmRequest.CallValue) assert.Equal(t, getActionIdForTransferBatchFuncName, vmRequest.FuncName) @@ -699,6 +808,8 @@ func TestMXClientDataGetter_GetActionIDForProposeTransfer(t *testing.T) { hex.EncodeToString([]byte("converted_token1")), hex.EncodeToString(big.NewInt(2).Bytes()), hex.EncodeToString(big.NewInt(1).Bytes()), + hex.EncodeToString([]byte("doSomething@7742")), + hex.EncodeToString(big.NewInt(5).Bytes()), hex.EncodeToString([]byte("from2")), hex.EncodeToString([]byte("to2")), @@ -721,6 +832,8 @@ func TestMXClientDataGetter_GetActionIDForProposeTransfer(t *testing.T) { dg, _ := NewMXClientDataGetter(args) batch := createMockBatch() + batch.Deposits[0].Data = []byte("doSomething@7742") + batch.Deposits[0].ExtraGasLimit = 5 result, err := dg.GetActionIDForProposeTransfer(context.Background(), batch) assert.Equal(t, uint64(1234), result) @@ -751,8 +864,8 @@ func TestMXClientDataGetter_WasProposedSetStatus(t *testing.T) { args.Proxy = &interactors.ProxyStub{ ExecuteVMQueryCalled: func(ctx context.Context, vmRequest *data.VmValueRequest) (*data.VmValuesResponseData, error) { proxyCalled = true - assert.Equal(t, args.RelayerAddress.AddressAsBech32String(), vmRequest.CallerAddr) - assert.Equal(t, args.MultisigContractAddress.AddressAsBech32String(), vmRequest.Address) + assert.Equal(t, getBech32Address(args.RelayerAddress), vmRequest.CallerAddr) + assert.Equal(t, getBech32Address(args.MultisigContractAddress), vmRequest.Address) assert.Equal(t, "", vmRequest.CallValue) assert.Equal(t, wasSetCurrentTransactionBatchStatusActionProposedFuncName, vmRequest.FuncName) @@ -877,8 +990,8 @@ func TestMXClientDataGetter_GetTransactionsStatuses(t *testing.T) { args.Proxy = &interactors.ProxyStub{ ExecuteVMQueryCalled: func(ctx context.Context, vmRequest *data.VmValueRequest) (*data.VmValuesResponseData, error) { proxyCalled = true - assert.Equal(t, args.RelayerAddress.AddressAsBech32String(), vmRequest.CallerAddr) - assert.Equal(t, args.MultisigContractAddress.AddressAsBech32String(), vmRequest.Address) + assert.Equal(t, getBech32Address(args.RelayerAddress), vmRequest.CallerAddr) + assert.Equal(t, getBech32Address(args.MultisigContractAddress), vmRequest.Address) assert.Equal(t, "", vmRequest.CallValue) assert.Equal(t, getStatusesAfterExecutionFuncName, vmRequest.FuncName) @@ -929,8 +1042,8 @@ func TestMXClientDataGetter_GetActionIDForSetStatusOnPendingTransfer(t *testing. args.Proxy = &interactors.ProxyStub{ ExecuteVMQueryCalled: func(ctx context.Context, vmRequest *data.VmValueRequest) (*data.VmValuesResponseData, error) { proxyCalled = true - assert.Equal(t, args.RelayerAddress.AddressAsBech32String(), vmRequest.CallerAddr) - assert.Equal(t, args.MultisigContractAddress.AddressAsBech32String(), vmRequest.Address) + assert.Equal(t, getBech32Address(args.RelayerAddress), vmRequest.CallerAddr) + assert.Equal(t, getBech32Address(args.MultisigContractAddress), vmRequest.Address) assert.Equal(t, "", vmRequest.CallValue) assert.Equal(t, getActionIdForSetCurrentTransactionBatchStatusFuncName, vmRequest.FuncName) @@ -970,8 +1083,8 @@ func TestMXClientDataGetter_QuorumReached(t *testing.T) { args.Proxy = &interactors.ProxyStub{ ExecuteVMQueryCalled: func(ctx context.Context, vmRequest *data.VmValueRequest) (*data.VmValuesResponseData, error) { proxyCalled = true - assert.Equal(t, args.RelayerAddress.AddressAsBech32String(), vmRequest.CallerAddr) - assert.Equal(t, args.MultisigContractAddress.AddressAsBech32String(), vmRequest.Address) + assert.Equal(t, getBech32Address(args.RelayerAddress), vmRequest.CallerAddr) + assert.Equal(t, getBech32Address(args.MultisigContractAddress), vmRequest.Address) assert.Equal(t, "", vmRequest.CallValue) assert.Equal(t, quorumReachedFuncName, vmRequest.FuncName) @@ -1004,8 +1117,8 @@ func TestMXClientDataGetter_GetLastExecutedEthBatchID(t *testing.T) { args.Proxy = &interactors.ProxyStub{ ExecuteVMQueryCalled: func(ctx context.Context, vmRequest *data.VmValueRequest) (*data.VmValuesResponseData, error) { proxyCalled = true - assert.Equal(t, args.RelayerAddress.AddressAsBech32String(), vmRequest.CallerAddr) - assert.Equal(t, args.MultisigContractAddress.AddressAsBech32String(), vmRequest.Address) + assert.Equal(t, getBech32Address(args.RelayerAddress), vmRequest.CallerAddr) + assert.Equal(t, getBech32Address(args.MultisigContractAddress), vmRequest.Address) assert.Equal(t, "", vmRequest.CallValue) assert.Equal(t, getLastExecutedEthBatchIdFuncName, vmRequest.FuncName) assert.Nil(t, vmRequest.Args) @@ -1036,8 +1149,8 @@ func TestMXClientDataGetter_GetLastExecutedEthTxID(t *testing.T) { args.Proxy = &interactors.ProxyStub{ ExecuteVMQueryCalled: func(ctx context.Context, vmRequest *data.VmValueRequest) (*data.VmValuesResponseData, error) { proxyCalled = true - assert.Equal(t, args.RelayerAddress.AddressAsBech32String(), vmRequest.CallerAddr) - assert.Equal(t, args.MultisigContractAddress.AddressAsBech32String(), vmRequest.Address) + assert.Equal(t, getBech32Address(args.RelayerAddress), vmRequest.CallerAddr) + assert.Equal(t, getBech32Address(args.MultisigContractAddress), vmRequest.Address) assert.Equal(t, "", vmRequest.CallValue) assert.Equal(t, getLastExecutedEthTxId, vmRequest.FuncName) assert.Nil(t, vmRequest.Args) @@ -1068,8 +1181,8 @@ func TestMXClientDataGetter_WasSigned(t *testing.T) { args.Proxy = &interactors.ProxyStub{ ExecuteVMQueryCalled: func(ctx context.Context, vmRequest *data.VmValueRequest) (*data.VmValuesResponseData, error) { proxyCalled = true - assert.Equal(t, args.RelayerAddress.AddressAsBech32String(), vmRequest.CallerAddr) - assert.Equal(t, args.MultisigContractAddress.AddressAsBech32String(), vmRequest.Address) + assert.Equal(t, getBech32Address(args.RelayerAddress), vmRequest.CallerAddr) + assert.Equal(t, getBech32Address(args.MultisigContractAddress), vmRequest.Address) assert.Equal(t, "", vmRequest.CallValue) assert.Equal(t, signedFuncName, vmRequest.FuncName) @@ -1103,8 +1216,8 @@ func TestMXClientDataGetter_GetAllStakedRelayers(t *testing.T) { providedRelayers := [][]byte{[]byte("relayer1"), []byte("relayer2")} args.Proxy = &interactors.ProxyStub{ ExecuteVMQueryCalled: func(ctx context.Context, vmRequest *data.VmValueRequest) (*data.VmValuesResponseData, error) { - assert.Equal(t, args.RelayerAddress.AddressAsBech32String(), vmRequest.CallerAddr) - assert.Equal(t, args.MultisigContractAddress.AddressAsBech32String(), vmRequest.Address) + assert.Equal(t, getBech32Address(args.RelayerAddress), vmRequest.CallerAddr) + assert.Equal(t, getBech32Address(args.MultisigContractAddress), vmRequest.Address) assert.Equal(t, "", vmRequest.CallValue) assert.Equal(t, getAllStakedRelayersFuncName, vmRequest.FuncName) @@ -1241,8 +1354,8 @@ func TestMultiversXClientDataGetter_IsPaused(t *testing.T) { args.Proxy = &interactors.ProxyStub{ ExecuteVMQueryCalled: func(ctx context.Context, vmRequest *data.VmValueRequest) (*data.VmValuesResponseData, error) { proxyCalled = true - assert.Equal(t, args.RelayerAddress.AddressAsBech32String(), vmRequest.CallerAddr) - assert.Equal(t, args.MultisigContractAddress.AddressAsBech32String(), vmRequest.Address) + assert.Equal(t, getBech32Address(args.RelayerAddress), vmRequest.CallerAddr) + assert.Equal(t, getBech32Address(args.MultisigContractAddress), vmRequest.Address) assert.Equal(t, "", vmRequest.CallValue) assert.Equal(t, isPausedFuncName, vmRequest.FuncName) assert.Empty(t, vmRequest.Args) diff --git a/clients/multiversx/transactionHandler.go b/clients/multiversx/transactionHandler.go index 5fe62248..c9c1c031 100644 --- a/clients/multiversx/transactionHandler.go +++ b/clients/multiversx/transactionHandler.go @@ -45,12 +45,17 @@ func (txHandler *transactionHandler) signTransaction(ctx context.Context, builde return nil, err } + bech32Address, err := txHandler.relayerAddress.AddressAsBech32String() + if err != nil { + return nil, err + } + tx := &transaction.FrontendTransaction{ ChainID: networkConfig.ChainID, Version: networkConfig.MinTransactionVersion, GasLimit: gasLimit, Data: dataBytes, - Sender: txHandler.relayerAddress.AddressAsBech32String(), + Sender: bech32Address, Receiver: txHandler.multisigAddressAsBech32, Value: "0", } diff --git a/clients/multiversx/transactionHandler_test.go b/clients/multiversx/transactionHandler_test.go index 82999a9b..0bb86aaf 100644 --- a/clients/multiversx/transactionHandler_test.go +++ b/clients/multiversx/transactionHandler_test.go @@ -141,7 +141,7 @@ func TestTransactionHandler_SendTransactionReturnHash(t *testing.T) { txHandlerInstance.nonceTxHandler = &bridgeTests.NonceTransactionsHandlerStub{ ApplyNonceAndGasPriceCalled: func(ctx context.Context, address core.AddressHandler, tx *transaction.FrontendTransaction) error { - if address.AddressAsBech32String() == relayerAddress { + if getBech32Address(address) == relayerAddress { tx.Nonce = nonce tx.GasPrice = minGasPrice diff --git a/clients/roleProviders/multiversXRoleProvider.go b/clients/roleProviders/multiversXRoleProvider.go index 7365397c..9b718848 100644 --- a/clients/roleProviders/multiversXRoleProvider.go +++ b/clients/roleProviders/multiversXRoleProvider.go @@ -77,7 +77,12 @@ func (erp *multiversXRoleProvider) processResults(results [][]byte) error { return fmt.Errorf("%w for index %d, malformed address: %s", ErrInvalidAddressBytes, i, hex.EncodeToString(result)) } - currentList = append(currentList, address.AddressAsBech32String()) + bech32Address, err := address.AddressAsBech32String() + if err != nil { + return fmt.Errorf("%w for index %d, malformed address: %s", err, i, hex.EncodeToString(result)) + } + + currentList = append(currentList, bech32Address) temporaryMap[string(address.AddressBytes())] = struct{}{} } diff --git a/cmd/bridge/config/config.toml b/cmd/bridge/config/config.toml index 8228d852..3838f848 100644 --- a/cmd/bridge/config/config.toml +++ b/cmd/bridge/config/config.toml @@ -3,6 +3,7 @@ NetworkAddress = "http://127.0.0.1:8545" # a network address MultisigContractAddress = "3009d97FfeD62E57d444e552A9eDF9Ee6Bc8644c" # the eth address for the bridge contract SafeContractAddress = "A6504Cc508889bbDBd4B748aFf6EA6b5D0d2684c" + SCExecProxyAddress = "A6504Cc508889bbDBd4B748aFf6EA6b5D0d2684c" # eth address for bridge sc execution logic PrivateKeyFile = "keys/ethereum.sk" # the path to the file containing the relayer eth private key GasLimitBase = 350000 GasLimitForEach = 30000 @@ -43,6 +44,8 @@ ProposeStatusForEach = 7000000 PerformActionBase = 40000000 PerformActionForEach = 5500000 + ScCallPerByte = 100000 # 1500 tx data field + the rest for the actual storage in the contract + ScCallPerformForEach = 10000000 [P2P] Port = "10010" @@ -55,6 +58,10 @@ [P2P.Transports.TCP] ListenAddress = "/ip4/0.0.0.0/tcp/%d" # TCP listen address PreventPortReuse = false + [P2P.ResourceLimiter] + Type = "default autoscale" #available options "default autoscale", "infinite", "default with manual scale". + ManualSystemMemoryInMB = 0 # not taken into account if the type is not "default with manual scale" + ManualMaximumFD = 0 # not taken into account if the type is not "default with manual scale" [P2P.AntifloodConfig] Enabled = true NumConcurrentResolverJobs = 50 diff --git a/cmd/bridge/main.go b/cmd/bridge/main.go index d6adc687..839662ae 100644 --- a/cmd/bridge/main.go +++ b/cmd/bridge/main.go @@ -19,6 +19,7 @@ import ( "github.com/multiversx/mx-bridge-eth-go/factory" "github.com/multiversx/mx-bridge-eth-go/p2p" "github.com/multiversx/mx-bridge-eth-go/status" + "github.com/multiversx/mx-chain-communication-go/p2p/libp2p" chainCore "github.com/multiversx/mx-chain-core-go/core" "github.com/multiversx/mx-chain-core-go/core/check" "github.com/multiversx/mx-chain-core-go/data/typeConverters/uint64ByteSlice" @@ -29,7 +30,6 @@ import ( "github.com/multiversx/mx-chain-crypto-go/signing/secp256k1/singlesig" chainFactory "github.com/multiversx/mx-chain-go/cmd/node/factory" chainCommon "github.com/multiversx/mx-chain-go/common" - chainP2P "github.com/multiversx/mx-chain-go/p2p" p2pConfig "github.com/multiversx/mx-chain-go/p2p/config" p2pFactory "github.com/multiversx/mx-chain-go/p2p/factory" "github.com/multiversx/mx-chain-go/statusHandler" @@ -38,7 +38,6 @@ import ( "github.com/multiversx/mx-chain-go/update/disabled" logger "github.com/multiversx/mx-chain-logger-go" "github.com/multiversx/mx-chain-logger-go/file" - "github.com/multiversx/mx-chain-p2p-go/libp2p" "github.com/multiversx/mx-sdk-go/blockchain" sdkCore "github.com/multiversx/mx-sdk-go/core" "github.com/urfave/cli" @@ -359,9 +358,8 @@ func buildNetMessenger(cfg config.Config, marshalizer marshal.Marshalizer) (p2p. Port: cfg.P2P.Port, MaximumExpectedPeerCount: 0, ThresholdMinConnectedPeers: 0, - Transports: p2pConfig.P2PTransportConfig{ - TCP: cfg.P2P.Transport, - }, + Transports: cfg.P2P.Transports, + ResourceLimiter: cfg.P2P.ResourceLimiter, } peerDiscoveryConfig := p2pConfig.KadDhtPeerDiscoveryConfig{ Enabled: true, @@ -408,11 +406,10 @@ func buildNetMessenger(cfg config.Config, marshalizer marshal.Marshalizer) (p2p. p2pPrivKey, _ := p2pKeyGen.GeneratePair() args := libp2p.ArgsNetworkMessenger{ - Marshalizer: marshalizer, + Marshaller: marshalizer, P2pConfig: p2pCfg, SyncTimer: &libp2p.LocalSyncTimer{}, PreferredPeersHolder: disabled.NewPreferredPeersHolder(), - NodeOperationMode: chainP2P.NormalOperation, PeersRatingHandler: peersRatingHandler, ConnectionWatcherType: disabledWatcher, P2pPrivateKey: p2pPrivKey, diff --git a/config/config.go b/config/config.go index c8556847..6bb03463 100644 --- a/config/config.go +++ b/config/config.go @@ -32,6 +32,7 @@ type EthereumConfig struct { NetworkAddress string MultisigContractAddress string SafeContractAddress string + SCExecProxyAddress string PrivateKeyFile string IntervalToResendTxsInSeconds uint64 GasLimitBase uint64 @@ -62,7 +63,7 @@ type ConfigP2P struct { ProtocolID string Transports p2pConfig.P2PTransportConfig AntifloodConfig config.AntifloodConfig - Transport p2pConfig.P2PTCPTransport + ResourceLimiter p2pConfig.P2PResourceLimiterConfig } // ConfigRelayer configuration for general relayer configuration @@ -169,6 +170,8 @@ type MultiversXGasMapConfig struct { ProposeStatusForEach uint64 PerformActionBase uint64 PerformActionForEach uint64 + ScCallPerByte uint64 + ScCallPerformForEach uint64 } // PeersRatingConfig will hold settings related to peers rating diff --git a/config/tomlConfigs_test.go b/config/tomlConfigs_test.go index d13c87f4..574a0e9b 100644 --- a/config/tomlConfigs_test.go +++ b/config/tomlConfigs_test.go @@ -3,9 +3,9 @@ package config import ( "testing" + "github.com/multiversx/mx-chain-communication-go/p2p/config" chainConfig "github.com/multiversx/mx-chain-go/config" p2pConfig "github.com/multiversx/mx-chain-go/p2p/config" - "github.com/multiversx/mx-chain-p2p-go/config" "github.com/pelletier/go-toml" "github.com/stretchr/testify/require" ) @@ -71,6 +71,11 @@ func TestConfigs(t *testing.T) { WebSocketAddress: "", WebTransportAddress: "", }, + ResourceLimiter: config.ResourceLimiterConfig{ + Type: "default autoscale", + ManualSystemMemoryInMB: 1, + ManualMaximumFD: 2, + }, AntifloodConfig: chainConfig.AntifloodConfig{ Enabled: true, NumConcurrentResolverJobs: 50, @@ -268,6 +273,10 @@ func TestConfigs(t *testing.T) { [P2P.Transports.TCP] ListenAddress = "/ip4/0.0.0.0/tcp/%d" # TCP listen address PreventPortReuse = false + [P2P.ResourceLimiter] + Type = "default autoscale" #available options "default autoscale", "infinite", "default with manual scale". + ManualSystemMemoryInMB = 1 # not taken into account if the type is not "default with manual scale" + ManualMaximumFD = 2 # not taken into account if the type is not "default with manual scale" [P2P.AntifloodConfig] Enabled = true NumConcurrentResolverJobs = 50 diff --git a/core/converters/converters.go b/core/converters/converters.go index 78b731e3..d1549019 100644 --- a/core/converters/converters.go +++ b/core/converters/converters.go @@ -6,13 +6,11 @@ import ( "github.com/multiversx/mx-chain-core-go/core" "github.com/multiversx/mx-chain-core-go/core/pubkeyConverter" - logger "github.com/multiversx/mx-chain-logger-go" sdkCore "github.com/multiversx/mx-sdk-go/core" ) -var log = logger.GetOrCreate("core") - const hexPrefix = "0x" +const hrp = "erd" type addressConverter struct { converter core.PubkeyConverter @@ -22,7 +20,7 @@ type addressConverter struct { func NewAddressConverter() (*addressConverter, error) { var err error ac := &addressConverter{} - ac.converter, err = pubkeyConverter.NewBech32PubkeyConverter(sdkCore.AddressBytesLen, log) + ac.converter, err = pubkeyConverter.NewBech32PubkeyConverter(sdkCore.AddressBytesLen, hrp) if err != nil { return nil, err } @@ -41,10 +39,17 @@ func (ac *addressConverter) ToHexStringWithPrefix(addressBytes []byte) string { } // ToBech32String will convert the addressBytes to the bech32 representation -func (ac *addressConverter) ToBech32String(addressBytes []byte) string { +func (ac *addressConverter) ToBech32String(addressBytes []byte) (string, error) { return ac.converter.Encode(addressBytes) } +// ToBech32StringSilent will try to convert the addressBytes to the bech32 representation +func (ac *addressConverter) ToBech32StringSilent(addressBytes []byte) string { + bech32Address, _ := ac.converter.Encode(addressBytes) + + return bech32Address +} + // IsInterfaceNil returns true if there is no value under the interface func (ac *addressConverter) IsInterfaceNil() bool { return ac == nil diff --git a/core/converters/converters_test.go b/core/converters/converters_test.go index 0fe47324..51033ec2 100644 --- a/core/converters/converters_test.go +++ b/core/converters/converters_test.go @@ -46,13 +46,17 @@ func TestAddressConverter_ToBech32String(t *testing.T) { assert.False(t, check.IfNil(addrConv)) t.Run("invalid bytes should return empty", func(t *testing.T) { - str := addrConv.ToBech32String([]byte("invalid")) - assert.Equal(t, "", str) + str, errLocal := addrConv.ToBech32String([]byte("invalid")) + assert.NotNil(t, errLocal) + assert.Contains(t, errLocal.Error(), "wrong size when encoding address, expected length 32, received 7") + assert.Empty(t, str) }) t.Run("should work", func(t *testing.T) { expected := "erd1r69gk66fmedhhcg24g2c5kn2f2a5k4kvpr6jfw67dn2lyydd8cfswy6ede" bytes, _ := hex.DecodeString("1e8a8b6b49de5b7be10aaa158a5a6a4abb4b56cc08f524bb5e6cd5f211ad3e13") - assert.Equal(t, expected, addrConv.ToBech32String(bytes)) + bech32Address, errLocal := addrConv.ToBech32String(bytes) + assert.Equal(t, expected, bech32Address) + assert.Nil(t, errLocal) }) } diff --git a/core/types.go b/core/types.go index 31d2c39d..23682467 100644 --- a/core/types.go +++ b/core/types.go @@ -32,7 +32,8 @@ type Timer interface { type AddressConverter interface { ToHexString(addressBytes []byte) string ToHexStringWithPrefix(addressBytes []byte) string - ToBech32String(addressBytes []byte) string + ToBech32String(addressBytes []byte) (string, error) + ToBech32StringSilent(addressBytes []byte) string IsInterfaceNil() bool } diff --git a/factory/ethMultiversXBridgeComponents.go b/factory/ethMultiversXBridgeComponents.go index 37970c74..09a67111 100644 --- a/factory/ethMultiversXBridgeComponents.go +++ b/factory/ethMultiversXBridgeComponents.go @@ -387,6 +387,7 @@ func (components *ethMultiversXBridgeComponents) createEthereumClient(args ArgsE } safeContractAddress := common.HexToAddress(ethereumConfigs.SafeContractAddress) + scExecProxyAddress := common.HexToAddress(ethereumConfigs.SCExecProxyAddress) ethClientLogId := components.evmCompatibleChain.EvmCompatibleChainClientLogId() argsEthClient := ethereum.ArgsEthereumClient{ @@ -399,6 +400,7 @@ func (components *ethMultiversXBridgeComponents) createEthereumClient(args ArgsE TokensMapper: tokensMapper, SignatureHolder: signaturesHolder, SafeContractAddress: safeContractAddress, + SCExecProxyAddress: scExecProxyAddress, GasHandler: gs, TransferGasLimitBase: ethereumConfigs.GasLimitBase, TransferGasLimitForEach: ethereumConfigs.GasLimitForEach, diff --git a/factory/ethMultiversXBridgeComponents_test.go b/factory/ethMultiversXBridgeComponents_test.go index ebd446eb..39c92192 100644 --- a/factory/ethMultiversXBridgeComponents_test.go +++ b/factory/ethMultiversXBridgeComponents_test.go @@ -418,6 +418,7 @@ func TestEthMultiversXBridgeComponents_RelayerAddresses(t *testing.T) { args := createMockEthMultiversXBridgeArgs() components, _ := NewEthMultiversXBridgeComponents(args) - assert.Equal(t, "erd1r69gk66fmedhhcg24g2c5kn2f2a5k4kvpr6jfw67dn2lyydd8cfswy6ede", components.MultiversXRelayerAddress().AddressAsBech32String()) + bech32Address, _ := components.MultiversXRelayerAddress().AddressAsBech32String() + assert.Equal(t, "erd1r69gk66fmedhhcg24g2c5kn2f2a5k4kvpr6jfw67dn2lyydd8cfswy6ede", bech32Address) assert.Equal(t, "0x3FE464Ac5aa562F7948322F92020F2b668D543d8", components.EthereumRelayerAddress().String()) } diff --git a/factory/storageFactory.go b/factory/storageFactory.go index 41cd9e8c..02073eb5 100644 --- a/factory/storageFactory.go +++ b/factory/storageFactory.go @@ -11,11 +11,18 @@ import ( // CreateUnitStorer based on the config and the working directory func CreateUnitStorer(config config.StorageConfig, workingDir string) (core.Storer, error) { + dbConfigHandler := factory.NewDBConfigHandler(config.DB) + persisterCreator, err := factory.NewPersisterFactory(dbConfigHandler) + if err != nil { + return nil, err + } + statusMetricsDbConfig := factory.GetDBFromConfig(config.DB) dbPath := path.Join(workingDir, config.DB.FilePath) statusMetricsDbConfig.FilePath = dbPath return storageunit.NewStorageUnitFromConf( factory.GetCacherFromConfig(config.Cache), - statusMetricsDbConfig) + statusMetricsDbConfig, + persisterCreator) } diff --git a/go.mod b/go.mod index b06f9a1e..05009b94 100644 --- a/go.mod +++ b/go.mod @@ -4,16 +4,16 @@ go 1.20 require ( github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792 - github.com/ethereum/go-ethereum v1.13.5 + github.com/ethereum/go-ethereum v1.13.7 github.com/gin-contrib/cors v1.4.0 github.com/gin-contrib/pprof v1.4.0 github.com/gin-gonic/gin v1.9.1 - github.com/multiversx/mx-chain-core-go v1.1.37 - github.com/multiversx/mx-chain-crypto-go v1.2.6 - github.com/multiversx/mx-chain-go v1.5.15 - github.com/multiversx/mx-chain-logger-go v1.0.11 - github.com/multiversx/mx-chain-p2p-go v1.0.18 - github.com/multiversx/mx-sdk-go v1.3.6-rc1 + github.com/multiversx/mx-chain-communication-go v1.0.12 + github.com/multiversx/mx-chain-core-go v1.2.18 + github.com/multiversx/mx-chain-crypto-go v1.2.9 + github.com/multiversx/mx-chain-go v1.6.7 + github.com/multiversx/mx-chain-logger-go v1.0.13 + github.com/multiversx/mx-sdk-go v1.3.11 github.com/pelletier/go-toml v1.9.3 github.com/stretchr/testify v1.8.4 github.com/urfave/cli v1.22.10 @@ -21,10 +21,10 @@ require ( require ( github.com/Microsoft/go-winio v0.6.1 // indirect - github.com/beevik/ntp v0.3.0 // indirect + github.com/beevik/ntp v1.3.0 // indirect github.com/benbjohnson/clock v1.3.5 // indirect github.com/beorn7/perks v1.0.1 // indirect - github.com/bits-and-blooms/bitset v1.7.0 // indirect + github.com/bits-and-blooms/bitset v1.10.0 // indirect github.com/btcsuite/btcd/btcec/v2 v2.3.2 // indirect github.com/btcsuite/btcd/btcutil v1.1.3 // indirect github.com/bytedance/sonic v1.9.1 // indirect @@ -55,7 +55,6 @@ require ( github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect github.com/go-playground/validator/v10 v10.14.0 // indirect - github.com/go-stack/stack v1.8.1 // indirect github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect github.com/goccy/go-json v0.10.2 // indirect github.com/godbus/dbus/v5 v5.1.0 // indirect @@ -71,7 +70,7 @@ require ( github.com/hashicorp/go-multierror v1.1.1 // indirect github.com/hashicorp/golang-lru v0.6.0 // indirect github.com/hashicorp/golang-lru/v2 v2.0.2 // indirect - github.com/holiman/uint256 v1.2.3 // indirect + github.com/holiman/uint256 v1.2.4 // indirect github.com/huin/goupnp v1.3.0 // indirect github.com/ipfs/boxo v0.8.1 // indirect github.com/ipfs/go-cid v0.4.1 // indirect @@ -123,8 +122,8 @@ require ( github.com/multiformats/go-multistream v0.4.1 // indirect github.com/multiformats/go-varint v0.0.7 // indirect github.com/multiversx/concurrent-map v0.1.4 // indirect - github.com/multiversx/mx-chain-storage-go v1.0.7 // indirect - github.com/multiversx/mx-chain-vm-common-go v1.3.42 // indirect + github.com/multiversx/mx-chain-storage-go v1.0.14 // indirect + github.com/multiversx/mx-chain-vm-common-go v1.5.9 // indirect github.com/onsi/ginkgo/v2 v2.9.7 // indirect github.com/opencontainers/runtime-spec v1.0.2 // indirect github.com/opentracing/opentracing-go v1.2.0 // indirect @@ -146,10 +145,9 @@ require ( github.com/raulk/go-watchdog v1.3.0 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/shirou/gopsutil v3.21.11+incompatible // indirect - github.com/smartystreets/assertions v1.13.1 // indirect github.com/spaolacci/murmur3 v1.1.0 // indirect github.com/supranational/blst v0.3.11 // indirect - github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 // indirect + github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d // indirect github.com/tklauser/go-sysconf v0.3.12 // indirect github.com/tklauser/numcpus v0.6.1 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect @@ -167,16 +165,16 @@ require ( go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.24.0 // indirect golang.org/x/arch v0.3.0 // indirect - golang.org/x/crypto v0.14.0 // indirect - golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect - golang.org/x/mod v0.12.0 // indirect - golang.org/x/net v0.17.0 // indirect - golang.org/x/sync v0.3.0 // indirect - golang.org/x/sys v0.13.0 // indirect - golang.org/x/text v0.13.0 // indirect - golang.org/x/tools v0.13.0 // indirect + golang.org/x/crypto v0.17.0 // indirect + golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa // indirect + golang.org/x/mod v0.14.0 // indirect + golang.org/x/net v0.19.0 // indirect + golang.org/x/sync v0.5.0 // indirect + golang.org/x/sys v0.15.0 // indirect + golang.org/x/text v0.14.0 // indirect + golang.org/x/tools v0.15.0 // indirect gonum.org/v1/gonum v0.11.0 // indirect - google.golang.org/protobuf v1.30.0 // indirect + google.golang.org/protobuf v1.31.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect lukechampine.com/blake3 v1.2.1 // indirect rsc.io/tmplfunc v0.0.3 // indirect diff --git a/go.sum b/go.sum index 76ab7132..58e436bb 100644 --- a/go.sum +++ b/go.sum @@ -14,8 +14,8 @@ github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5 github.com/VictoriaMetrics/fastcache v1.12.1 h1:i0mICQuojGDL3KblA7wUNlY5lOK6a4bwt3uRKnkZU40= github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII= github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= -github.com/beevik/ntp v0.3.0 h1:xzVrPrE4ziasFXgBVBZJDP0Wg/KpMwk2KHJ4Ba8GrDw= -github.com/beevik/ntp v0.3.0/go.mod h1:hIHWr+l3+/clUnF44zdK+CWW7fO8dR5cIylAQ76NRpg= +github.com/beevik/ntp v1.3.0 h1:/w5VhpW5BGKS37vFm1p9oVk/t4HnnkKZAZIubHM6F7Q= +github.com/beevik/ntp v1.3.0/go.mod h1:vD6h1um4kzXpqmLTuu0cCLcC+NfvC0IC+ltmEDA8E78= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/benbjohnson/clock v1.3.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/benbjohnson/clock v1.3.5 h1:VvXlSJBzZpA/zum6Sj74hxwYI2DIxRWuNIoXAzHZz5o= @@ -23,8 +23,8 @@ github.com/benbjohnson/clock v1.3.5/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZx github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= -github.com/bits-and-blooms/bitset v1.7.0 h1:YjAGVd3XmtK9ktAbX8Zg2g2PwLIMjGREZJHlV4j7NEo= -github.com/bits-and-blooms/bitset v1.7.0/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edYb8uY+O0FJTyyDA= +github.com/bits-and-blooms/bitset v1.10.0 h1:ePXTeiPEazB5+opbv5fr8umg2R/1NlzgDsyepwsSr88= +github.com/bits-and-blooms/bitset v1.10.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8= github.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBTaaSFSlLx/70C2HPIMNZpVV8+vt/A+FMnYP11g= github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ= github.com/btcsuite/btcd v0.22.0-beta.0.20220111032746-97732e52810c/go.mod h1:tjmYdS6MLJ5/s0Fj4DbLgSbDHbEqLJrtnHecBFkdz5M= @@ -62,6 +62,9 @@ github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XL github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY= github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams= github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk= +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/cilium/ebpf v0.2.0/go.mod h1:To2CFviqOWL/M0gIMsvSMlqe7em/l1ALkX1PyjrX2Qs= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= @@ -86,6 +89,7 @@ github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:ma github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w= github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/crate-crypto/go-ipa v0.0.0-20231025140028-3c0104f4b233 h1:d28BXYi+wUpz1KBmiF9bWrjEMacUEREV6MBi2ODnrfQ= github.com/crate-crypto/go-kzg-4844 v0.7.0 h1:C0vgZRk4q4EZ/JgPfzuSoxdCq3C3mOZMBShovmncxvA= github.com/crate-crypto/go-kzg-4844 v0.7.0/go.mod h1:1kMhvPgI0Ky3yIa+9lFySEBUBXkYxeOi8ZF1sYioxhc= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= @@ -118,8 +122,8 @@ github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1m github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/ethereum/c-kzg-4844 v0.4.0 h1:3MS1s4JtA868KpJxroZoepdV0ZKBp3u/O5HcZ7R3nlY= github.com/ethereum/c-kzg-4844 v0.4.0/go.mod h1:VewdlzQmpT5QSrVhbBuGoCdFJkpaJlO1aQputP83wc0= -github.com/ethereum/go-ethereum v1.13.5 h1:U6TCRciCqZRe4FPXmy1sMGxTfuk8P7u2UoinF3VbaFk= -github.com/ethereum/go-ethereum v1.13.5/go.mod h1:yMTu38GSuyxaYzQMViqNmQ1s3cE84abZexQmTgenWk0= +github.com/ethereum/go-ethereum v1.13.7 h1:71qnF0T75JuxLqLt0Qj6eZrB//awJ/yqpUPXQAaBFmA= +github.com/ethereum/go-ethereum v1.13.7/go.mod h1:sc48XYQxCzH3fG9BcrXCOOgQk2JfZzNAmIKnceogzsA= github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5 h1:FtmdgXiUlNeRsoNMFlKLDt+S+6hbjVMEW6RGQ7aUf7c= github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= github.com/flynn/noise v1.0.0 h1:DlTHqmzmvcEiKj+4RYo/imoswx/4r6iBlCMfVtrMXpQ= @@ -129,11 +133,13 @@ github.com/francoispqt/gojay v1.2.13/go.mod h1:ehT5mTG4ua4581f1++1WLG0vPdaA9HaiD github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU= github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU= github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA= github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff h1:tY80oXqGNY4FhTFhk+o9oFHGINQ/+vhlm8HFzi6znCI= +github.com/gballet/go-verkle v0.1.1-0.20231031103413-a67434b50f46 h1:BAIP2GihuqhwdILrV+7GJel5lyPV3u1+PgzrWLc0TkE= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/gin-contrib/cors v1.4.0 h1:oJ6gwtUl3lqV0WEIwM/LxPF1QZ5qe2lGWdY2+bz7y0g= github.com/gin-contrib/cors v1.4.0/go.mod h1:bs9pNM0x/UsmHPBWT2xZz9ROh8xYjYkiURUfmBoMlcs= @@ -164,8 +170,7 @@ github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91 github.com/go-playground/validator/v10 v10.10.0/go.mod h1:74x4gJWsvQexRdW8Pn3dXSGrTK4nAUsbPlLADvpJkos= github.com/go-playground/validator/v10 v10.14.0 h1:vgvQWe3XCz3gIeFDm/HnTIbj6UGmg/+t63MyGU2n5js= github.com/go-playground/validator/v10 v10.14.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= -github.com/go-stack/stack v1.8.1 h1:ntEHSVwIt7PNXNpgPmVfMrNhLtgjlmnZha2kOpuRiDw= -github.com/go-stack/stack v1.8.1/go.mod h1:dcoOX6HbPZSZptuspn9bctJ+N/CnF5gGygcUP3XYfe4= +github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= github.com/go-yaml/yaml v2.1.0+incompatible/go.mod h1:w2MrLa16VYP0jy6N7M5kHaCkaLENm+P+Tv+MfurjSw0= @@ -202,6 +207,7 @@ github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QD github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= @@ -220,10 +226,12 @@ github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ= github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8= github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20230602150820-91b7bce49751 h1:hR7/MlvK23p6+lIw9SN1TigNLn9ZnF3W4SYRKq2gAHs= github.com/google/pprof v0.0.0-20230602150820-91b7bce49751/go.mod h1:Jh3hGz2jkYak8qXPD19ryItVnUgpgeqzdkY/D0EaeuA= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= @@ -250,14 +258,16 @@ github.com/hashicorp/golang-lru v0.6.0 h1:uL2shRDx7RTrOrTCUZEGP/wJUFiUI8QT6E7z5o github.com/hashicorp/golang-lru v0.6.0/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/hashicorp/golang-lru/v2 v2.0.2 h1:Dwmkdr5Nc/oBiXgJS3CDHNhJtIHkuZ3DZF5twqnfBdU= github.com/hashicorp/golang-lru/v2 v2.0.2/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= -github.com/herumi/bls-go-binary v1.0.0 h1:PRPF6vPd35zyDy+tp86HwNnGdufCH2lZL0wZGxYvkRs= +github.com/herumi/bls-go-binary v1.28.2 h1:F0AezsC0M1a9aZjk7g0l2hMb1F56Xtpfku97pDndNZE= +github.com/holiman/billy v0.0.0-20230718173358-1c7e68d277a7 h1:3JQNjnMRil1yD0IfZKHF9GxxWKDJGj8I0IqOUol//sw= github.com/holiman/billy v0.0.0-20230718173358-1c7e68d277a7 h1:3JQNjnMRil1yD0IfZKHF9GxxWKDJGj8I0IqOUol//sw= github.com/holiman/bloomfilter/v2 v2.0.3 h1:73e0e/V0tCydx14a0SCYS/EWCxgwLZ18CZcZKVu0fao= -github.com/holiman/uint256 v1.2.3 h1:K8UWO1HUJpRMXBxbmaY1Y8IAMZC/RsKB+ArEnnK4l5o= -github.com/holiman/uint256 v1.2.3/go.mod h1:SC8Ryt4n+UBbPbIBKaG9zbbDlp4jOru9xFZmPzLUTxw= +github.com/holiman/uint256 v1.2.4 h1:jUc4Nk8fm9jZabQuqr2JzednajVmBpC+oiTiXZJEApU= +github.com/holiman/uint256 v1.2.4/go.mod h1:EOMSn4q6Nyt9P6efbI3bueV4e1b3dGlUCXeiRV4ng7E= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/huin/goupnp v1.3.0 h1:UvLUlWDNpoUdYzb2TCn+MuTWtcjXKSza2n6CBdQ0xXc= github.com/huin/goupnp v1.3.0/go.mod h1:gnGPsThkYa7bFi/KWmEysQRf48l2dvR5bxr2OFckNX8= +github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ipfs/boxo v0.8.1 h1:3DkKBCK+3rdEB5t77WDShUXXhktYwH99mkAsgajsKrU= github.com/ipfs/boxo v0.8.1/go.mod h1:xJ2hVb4La5WyD7GvKYE0lq2g1rmQZoCD2K4WNrV6aZI= github.com/ipfs/go-cid v0.4.1 h1:A/T3qGvxi4kpKWWcPC/PgbvDA2bjVLO7n4UeVwnbs/s= @@ -411,38 +421,44 @@ github.com/multiformats/go-varint v0.0.7 h1:sWSGR+f/eu5ABZA2ZpYKBILXTTs9JWpdEM/n github.com/multiformats/go-varint v0.0.7/go.mod h1:r8PUYw/fD/SjBCiKOoDlGF6QawOELpZAu9eioSos/OU= github.com/multiversx/concurrent-map v0.1.4 h1:hdnbM8VE4b0KYJaGY5yJS2aNIW9TFFsUYwbO0993uPI= github.com/multiversx/concurrent-map v0.1.4/go.mod h1:8cWFRJDOrWHOTNSqgYCUvwT7c7eFQ4U2vKMOp4A/9+o= -github.com/multiversx/mx-chain-core-go v1.1.37 h1:2EYoUWjr+8zUYEt3TBMnQ+0UUZwDb71HA+KBwqDUpVQ= -github.com/multiversx/mx-chain-core-go v1.1.37/go.mod h1:8gGEQv6BWuuJwhd25qqhCOZbBSv9mk+hLeKvinSaSMk= -github.com/multiversx/mx-chain-crypto-go v1.2.6 h1:yxsjAQGh62los+iYmORMfh3w9qen0xbYlmwU0juNSeg= -github.com/multiversx/mx-chain-crypto-go v1.2.6/go.mod h1:rOj0Rr19HTOYt9YTeym7RKxlHt91NXln3LVKjHKVmA0= -github.com/multiversx/mx-chain-go v1.5.15 h1:1KCbVLQN8GEiVz/Q5k20hBXcAOLSPLLATTk8iZBiA0o= -github.com/multiversx/mx-chain-go v1.5.15/go.mod h1:uiCW8+L8aAU/LU7a3sOZMsffCCyUvIJaW57uGnhKnLk= -github.com/multiversx/mx-chain-logger-go v1.0.11 h1:DFsHa+sc5fKwhDR50I8uBM99RTDTEW68ESyr5ALRDwE= -github.com/multiversx/mx-chain-logger-go v1.0.11/go.mod h1:1srDkP0DQucWQ+rYfaq0BX2qLnULsUdRPADpYUTM6dA= -github.com/multiversx/mx-chain-p2p-go v1.0.18 h1:Dc+ngk8AV1UdBeZMzZP2MkxDyfoNrD/vY77umvo3SqQ= -github.com/multiversx/mx-chain-p2p-go v1.0.18/go.mod h1:Xy1B8X+AaGafDNcI6QZsTxO6bBf4akEyq+WdGRWSCpI= -github.com/multiversx/mx-chain-storage-go v1.0.7 h1:UqLo/OLTD3IHiE/TB/SEdNRV1GG2f1R6vIP5ehHwCNw= -github.com/multiversx/mx-chain-storage-go v1.0.7/go.mod h1:gtKoV32Cg2Uy8deHzF8Ud0qAl0zv92FvWgPSYIP0Zmg= -github.com/multiversx/mx-chain-vm-common-go v1.3.42 h1:avhgUwi6f+wpHqaBk76j6islLzUlSRBXwisKoZnUXpk= -github.com/multiversx/mx-chain-vm-common-go v1.3.42/go.mod h1:r+aILrY07ue89PH+D+B+Pp0viO1U3kN98t1pXneSgkE= -github.com/multiversx/mx-sdk-go v1.3.6-rc1 h1:PbFamoNvgij3n7I9X6U1GZdHQCVgh2pP5WP34X93DxA= -github.com/multiversx/mx-sdk-go v1.3.6-rc1/go.mod h1:Ia84QV0gLAYn2q7a8p0J4iBWCHkDd9X5YeJ9pbtDU0k= +github.com/multiversx/mx-chain-communication-go v1.0.12 h1:67WOaf87gpwouydD1AAOHw5LMGZh7NfITrp/KqFY3Tw= +github.com/multiversx/mx-chain-communication-go v1.0.12/go.mod h1:+oaUowpq+SqrEmAsMPGwhz44g7L81loWb6AiNQU9Ms4= +github.com/multiversx/mx-chain-core-go v1.2.18 h1:fnub2eFL7XYOLrKKVZAPPsaM1TWEnaK5qqY3FLUv168= +github.com/multiversx/mx-chain-core-go v1.2.18/go.mod h1:BILOGHUOIG5dNNX8cgkzCNfDaVtoYrJRYcPnpxRMH84= +github.com/multiversx/mx-chain-crypto-go v1.2.9 h1:OEfF2kOQrtzUl273Z3DEcshjlTVUfPpJMd0R0SvTrlU= +github.com/multiversx/mx-chain-crypto-go v1.2.9/go.mod h1:fkaWKp1rbQN9wPKya5jeoRyC+c/SyN/NfggreyeBw+8= +github.com/multiversx/mx-chain-go v1.6.7 h1:kpIKm/slhyr+yEFMXs57CzUUzGuAMkLPfIW1ux0tkkY= +github.com/multiversx/mx-chain-go v1.6.7/go.mod h1:TEDnRLYgEKGq93x4Kv2BJODkGlVBKlhulYMegxUOyAE= +github.com/multiversx/mx-chain-logger-go v1.0.13 h1:eru/TETo0MkO4ZTnXsQDKf4PBRpAXmqjT02klNT/JnY= +github.com/multiversx/mx-chain-logger-go v1.0.13/go.mod h1:MZJhTAtZTJxT+yK2EHc4ZW3YOHUc1UdjCD0iahRNBZk= +github.com/multiversx/mx-chain-storage-go v1.0.14 h1:h0acoqPS3FKJ4S3cKBEriTU0OabSQnpxai5WKhi1YCs= +github.com/multiversx/mx-chain-storage-go v1.0.14/go.mod h1:sJ2q49tgjxNpMpsHysjABqCAB0FLBmDblbjBkQ8XfmA= +github.com/multiversx/mx-chain-vm-common-go v1.5.9 h1:PnGimbMScV5WXFjumzAmcAcnWrw5e9PQABuIcKKUgZw= +github.com/multiversx/mx-chain-vm-common-go v1.5.9/go.mod h1:sqkKMCnwkWl8DURdb9q7pctK8IANghdHY1KJLE0ox2c= +github.com/multiversx/mx-sdk-go v1.3.11 h1:Vbegs3X6Se1injnU9Dhc2Kh0U6fwGr5DxWfZApV0VRg= +github.com/multiversx/mx-sdk-go v1.3.11/go.mod h1:ch7K2Py424Fp88fj1fRYD7apIjGpcRrmFUpVW7Jl5CY= github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo= github.com/neelance/sourcemap v0.0.0-20151028013722-8c68805598ab/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= +github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= +github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= +github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= +github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c= github.com/onsi/ginkgo/v2 v2.9.7 h1:06xGQy5www2oN160RtEZoTvnP2sPhEfePYmCDc2szss= github.com/onsi/ginkgo/v2 v2.9.7/go.mod h1:cxrmXWykAwTwhQsJOPfdIDiJ+l2RYq7U8hFU+M/1uw0= github.com/onsi/gomega v1.4.1/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= +github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= +github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro= github.com/onsi/gomega v1.27.7 h1:fVih9JD6ogIiHUN6ePK7HJidyEDpWGVB5mzM7cWNXoU= github.com/opencontainers/runtime-spec v1.0.2 h1:UfAcuLBJB9Coz72x1hgl8O5RVzTdNiaglX6v2DM6FI0= github.com/opencontainers/runtime-spec v1.0.2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= @@ -530,7 +546,6 @@ github.com/shurcooL/webdavfs v0.0.0-20170829043945-18c3829fa133/go.mod h1:hKmq5k github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/smartystreets/assertions v1.2.0/go.mod h1:tcbTF8ujkAEcZ8TElKY+i30BzYlVhC/LOxJk7iOWnoo= github.com/smartystreets/assertions v1.13.1 h1:Ef7KhSmjZcK6AVf9YbJdvPYG9avaF0ZxudX+ThRdWfU= -github.com/smartystreets/assertions v1.13.1/go.mod h1:cXr/IwVfSo/RbCSPhoAPv73p3hlSdrBH/b3SdnW/LMY= github.com/smartystreets/goconvey v1.7.2 h1:9RBaZCeXEQ3UselpuwUQHltGVXvdwm6cv1hgR6gDIPg= github.com/smartystreets/goconvey v1.7.2/go.mod h1:Vw0tHAZW6lzCRk3xgdin6fKYcG+G3Pg9vgXWeJpQFMM= github.com/sourcegraph/annotate v0.0.0-20160123013949-f4cad6c6324d/go.mod h1:UdhH50NIW0fCiwBSr0co2m7BnFLdv4fQTgdqdJTHFeE= @@ -544,9 +559,11 @@ github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpE github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= @@ -555,8 +572,11 @@ github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcU github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/supranational/blst v0.3.11 h1:LyU6FolezeWAhvQk0k6O/d49jqgO52MSDDfYgbeoEm4= github.com/supranational/blst v0.3.11/go.mod h1:jZJtfjgudtNl4en1tzwPIV3KjUnQUvG3/j+w+fVonLw= -github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 h1:epCh84lMvA70Z7CTTCmYQn2CKbY8j86K7/FAIr141uY= +github.com/supranational/blst v0.3.11 h1:LyU6FolezeWAhvQk0k6O/d49jqgO52MSDDfYgbeoEm4= +github.com/supranational/blst v0.3.11/go.mod h1:jZJtfjgudtNl4en1tzwPIV3KjUnQUvG3/j+w+fVonLw= github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc= +github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d h1:vfofYNRScrDdvS342BElfbETmL1Aiz3i2t0zfRj16Hs= +github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d/go.mod h1:RRCYJbIwD5jmqPI9XoAFR0OcDxqUctll6zUj/+B4S48= github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA= github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU= github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI= @@ -586,6 +606,7 @@ github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRT github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/yusufpapurcu/wmi v1.2.2 h1:KBNDSne4vP5mbSWnJbO+51IMOXJB67QiYCSBrubbPRg= github.com/yusufpapurcu/wmi v1.2.2/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA= @@ -604,7 +625,7 @@ go.uber.org/dig v1.17.0/go.mod h1:rTxpf7l5I0eBTlE6/9RL+lDybC7WFwY2QH55ZSjy1mU= go.uber.org/fx v1.19.2 h1:SyFgYQFr1Wl0AYstE8vyYIzP4bFz2URrScjwC4cwUvY= go.uber.org/fx v1.19.2/go.mod h1:43G1VcqSzbIv77y00p1DRAsyZS8WdzuYdhZXmEUkMyQ= go.uber.org/goleak v1.1.11-0.20210813005559-691160354723/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= -go.uber.org/goleak v1.1.12 h1:gZAh5/EyT/HQwlpkCy6wTpqfH9H8Lz8zbm3dZh+OyzA= +go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A= go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= @@ -630,11 +651,13 @@ golang.org/x/crypto v0.0.0-20200602180216-279210d13fed/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc= -golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.10.0/go.mod h1:o4eNf7Ede1fv+hwOwZsTHl9EsPFO6q6ZvYR8vYfY45I= +golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k= +golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g= -golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k= +golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa h1:FRnLl4eNAQl8hwxVVC17teOw8kdjVDVAiFMtgUdTSRQ= +golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa/go.mod h1:zk2irFbV9DP96SEBUUAy67IdHUaZuSnrz1n472HUCLE= golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= @@ -646,8 +669,10 @@ golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzB golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc= -golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0= +golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -668,8 +693,15 @@ golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwY golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= -golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= -golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= +golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= +golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= +golang.org/x/net v0.11.0/go.mod h1:2L/ixqYpgIVXmeoSA/4Lu7BzTG4KIyPIryS4IsOd1oQ= +golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c= +golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -683,8 +715,10 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= -golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE= +golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180810173357-98c5dad5d1a0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -697,6 +731,7 @@ golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -704,27 +739,43 @@ golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200814200057-3d37ad5750ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= -golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= +golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= +golang.org/x/term v0.9.0/go.mod h1:M6DEAAIenWoTxdKrOltXcmDY3rSplQUkrvaDU5FcQyo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= -golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.10.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= @@ -743,15 +794,19 @@ golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.13.0 h1:Iey4qkscZuv0VvIt8E0neZjtPVQFSc870HQ448QgEmQ= -golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/tools v0.15.0 h1:zdAyfUGbYmuVokhzVmghFl2ZJh5QhcfebBgmVPFYA+8= +golang.org/x/tools v0.15.0/go.mod h1:hpksKq4dtpQWS1uQ61JkdqWM3LscIS6Slf+VVkm+wQk= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= gonum.org/v1/gonum v0.11.0 h1:f1IJhK4Km5tBJmaiJXtk/PkL4cdVX6J+tGiM187uT5E= gonum.org/v1/gonum v0.11.0/go.mod h1:fSG4YDCxxUZQJ7rKsQrj0gMOg00Il0Z96/qMA4bVQhA= google.golang.org/api v0.0.0-20180910000450-7ca32eb868bf/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= @@ -788,8 +843,8 @@ google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlba google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= -google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= +google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= diff --git a/integrationTests/mock/ethereumChainMock.go b/integrationTests/mock/ethereumChainMock.go index a212334d..e40607fa 100644 --- a/integrationTests/mock/ethereumChainMock.go +++ b/integrationTests/mock/ethereumChainMock.go @@ -6,6 +6,7 @@ import ( "math/big" "sync" + "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" @@ -37,6 +38,7 @@ type EthereumChainMock struct { relayers []common.Address ProposeMultiTransferEsdtBatchCalled func() BalanceAtCalled func(ctx context.Context, account common.Address, blockNumber *big.Int) (*big.Int, error) + FilterLogsCalled func(ctx context.Context, q ethereum.FilterQuery) ([]types.Log, error) } // NewEthereumChainMock - @@ -252,6 +254,15 @@ func (mock *EthereumChainMock) BalanceAt(ctx context.Context, account common.Add return big.NewInt(0), nil } +// FilterLogs - +func (mock *EthereumChainMock) FilterLogs(ctx context.Context, q ethereum.FilterQuery) ([]types.Log, error) { + if mock.FilterLogsCalled != nil { + return mock.FilterLogsCalled(ctx, q) + } + + return []types.Log{}, nil +} + // IsPaused - func (mock *EthereumChainMock) IsPaused(_ context.Context) (bool, error) { return false, nil diff --git a/integrationTests/mock/multiversXContractStateMock.go b/integrationTests/mock/multiversXContractStateMock.go index f1258168..58e8efb2 100644 --- a/integrationTests/mock/multiversXContractStateMock.go +++ b/integrationTests/mock/multiversXContractStateMock.go @@ -27,11 +27,13 @@ type multiversXProposedTransfer struct { // Transfer - type Transfer struct { - From []byte - To []byte - Token string - Amount *big.Int - Nonce *big.Int + From []byte + To []byte + Token string + Amount *big.Int + Nonce *big.Int + ExtraGas uint64 + Data []byte } // MultiversXPendingBatch - @@ -169,23 +171,24 @@ func (mock *multiversXContractStateMock) createProposedTransfer(dataSplit []stri BatchId: big.NewInt(0).SetBytes(buff), } - for i := 2; i < len(dataSplit); i += 5 { - from, errDecode := hex.DecodeString(dataSplit[i]) + currentIndex := 2 + for currentIndex < len(dataSplit) { + from, errDecode := hex.DecodeString(dataSplit[currentIndex]) if errDecode != nil { panic(errDecode) } - to, errDecode := hex.DecodeString(dataSplit[i+1]) + to, errDecode := hex.DecodeString(dataSplit[currentIndex+1]) if errDecode != nil { panic(errDecode) } - amountBytes, errDecode := hex.DecodeString(dataSplit[i+3]) + amountBytes, errDecode := hex.DecodeString(dataSplit[currentIndex+3]) if errDecode != nil { panic(errDecode) } - nonceBytes, errDecode := hex.DecodeString(dataSplit[i+4]) + nonceBytes, errDecode := hex.DecodeString(dataSplit[currentIndex+4]) if errDecode != nil { panic(errDecode) } @@ -193,12 +196,30 @@ func (mock *multiversXContractStateMock) createProposedTransfer(dataSplit []stri t := Transfer{ From: from, To: to, - Token: dataSplit[i+2], + Token: dataSplit[currentIndex+2], Amount: big.NewInt(0).SetBytes(amountBytes), Nonce: big.NewInt(0).SetBytes(nonceBytes), } + indexIncrementValue := 5 + if core.IsSmartContractAddress(to) { + indexIncrementValue += 2 + t.Data, errDecode = hex.DecodeString(dataSplit[currentIndex+5]) + if errDecode != nil { + panic(errDecode) + } + + var extraGasBytes []byte + extraGasBytes, errDecode = hex.DecodeString(dataSplit[currentIndex+6]) + if errDecode != nil { + panic(errDecode) + } + + t.ExtraGas = big.NewInt(0).SetBytes(extraGasBytes).Uint64() + } + transfer.Transfers = append(transfer.Transfers, t) + currentIndex += indexIncrementValue } hash, err := core.CalculateHash(integrationTests.TestMarshalizer, integrationTests.TestHasher, transfer) @@ -445,9 +466,10 @@ func (mock *multiversXContractStateMock) vmRequestSigned(request *data.VmValueRe } address := data.NewAddressFromBytes(addressBytes) - _, found = actionIDMap[address.AddressAsBech32String()] + bech32Address, _ := address.AddressAsBech32String() + _, found = actionIDMap[bech32Address] if !found { - log.Error("action ID not found", "address", address.AddressAsBech32String()) + log.Error("action ID not found", "address", bech32Address) } return createOkVmResponse([][]byte{BoolToByteSlice(found)}) diff --git a/integrationTests/relayers/ethToMultiversX_test.go b/integrationTests/relayers/ethToMultiversX_test.go index b42828ce..5550d37f 100644 --- a/integrationTests/relayers/ethToMultiversX_test.go +++ b/integrationTests/relayers/ethToMultiversX_test.go @@ -8,7 +8,10 @@ import ( "testing" "time" + "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + ethmultiversx "github.com/multiversx/mx-bridge-eth-go/bridges/ethMultiversX" "github.com/multiversx/mx-bridge-eth-go/clients" "github.com/multiversx/mx-bridge-eth-go/clients/chain" "github.com/multiversx/mx-bridge-eth-go/clients/ethereum/contract" @@ -26,6 +29,13 @@ import ( "github.com/stretchr/testify/require" ) +type argsForSCCallsTest struct { + providedScCallData string + providedExtraGas uint64 + expectedScCallData string + expectedExtraGas uint64 +} + func TestRelayersShouldExecuteTransferFromEthToMultiversX(t *testing.T) { if testing.Short() { t.Skip("this is not a short test") @@ -141,12 +151,213 @@ func TestRelayersShouldExecuteTransferFromEthToMultiversX(t *testing.T) { assert.Equal(t, value1, transfer.Transfers[0].Amount) assert.Equal(t, depositor1, common.BytesToAddress(transfer.Transfers[0].From)) assert.Equal(t, txNonceOnEthereum+1, transfer.Transfers[0].Nonce.Uint64()) + assert.Empty(t, transfer.Transfers[0].Data) + assert.Zero(t, transfer.Transfers[0].ExtraGas) + + assert.Equal(t, destination2.AddressBytes(), transfer.Transfers[1].To) + assert.Equal(t, hex.EncodeToString([]byte(ticker2)), transfer.Transfers[1].Token) + assert.Equal(t, value2, transfer.Transfers[1].Amount) + assert.Equal(t, depositor2, common.BytesToAddress(transfer.Transfers[1].From)) + assert.Equal(t, txNonceOnEthereum+2, transfer.Transfers[1].Nonce.Uint64()) + assert.Empty(t, transfer.Transfers[1].Data) + assert.Zero(t, transfer.Transfers[1].ExtraGas) +} + +func TestRelayersShouldExecuteTransferFromEthToMultiversXHavingTxsWithSCcalls(t *testing.T) { + if testing.Short() { + t.Skip("this is not a short test") + } + + t.Run("correct SC call", func(t *testing.T) { + testArgs := argsForSCCallsTest{ + providedScCallData: "doSomething@aabbcc@001122", + providedExtraGas: uint64(3737373), + expectedScCallData: "doSomething@aabbcc@001122", + expectedExtraGas: uint64(3737373), + } + + testRelayersShouldExecuteTransferFromEthToMultiversXHavingTxsWithSCcalls(t, testArgs) + }) + t.Run("invalid SC call", func(t *testing.T) { + testArgs := argsForSCCallsTest{ + providedScCallData: "", + providedExtraGas: 0, + expectedScCallData: ethmultiversx.MissingCallData, + expectedExtraGas: 0, + } + + testRelayersShouldExecuteTransferFromEthToMultiversXHavingTxsWithSCcalls(t, testArgs) + }) +} + +func testRelayersShouldExecuteTransferFromEthToMultiversXHavingTxsWithSCcalls(t *testing.T, args argsForSCCallsTest) { + safeContractEthAddress := testsCommon.CreateRandomEthereumAddress() + scExecProxyEthAddress := testsCommon.CreateRandomEthereumAddress() + + token1Erc20 := testsCommon.CreateRandomEthereumAddress() + ticker1 := "tck-000001" + + token2Erc20 := testsCommon.CreateRandomEthereumAddress() + ticker2 := "tck-000002" + + token3Erc20 := testsCommon.CreateRandomEthereumAddress() + ticker3 := "tck-000003" + + value1 := big.NewInt(111111111) + destination1 := testsCommon.CreateRandomMultiversXAddress() + depositor1 := testsCommon.CreateRandomEthereumAddress() + + value2 := big.NewInt(222222222) + destination2 := testsCommon.CreateRandomMultiversXAddress() + depositor2 := testsCommon.CreateRandomEthereumAddress() + + value3 := big.NewInt(333333333) + destination3Sc := testsCommon.CreateRandomMultiversXSCAddress() + + tokens := []common.Address{token1Erc20, token2Erc20, token3Erc20} + availableBalances := []*big.Int{value1, value2, value3} + + erc20ContractsHolder := createMockErc20ContractsHolder(tokens, safeContractEthAddress, availableBalances) + + batchNonceOnEthereum := uint64(345) + txNonceOnEthereum := uint64(772634) + batch := contract.Batch{ + Nonce: big.NewInt(int64(batchNonceOnEthereum) + 1), + BlockNumber: 0, + LastUpdatedBlockNumber: 0, + DepositsCount: 3, + } + + numRelayers := 3 + ethereumChainMock := mock.NewEthereumChainMock() + ethereumChainMock.AddBatch(batch) + ethereumChainMock.AddDepositToBatch(batchNonceOnEthereum+1, contract.Deposit{ + Nonce: big.NewInt(int64(txNonceOnEthereum) + 1), + TokenAddress: token1Erc20, + Amount: value1, + Depositor: depositor1, + Recipient: destination1.AddressSlice(), + Status: 0, + }) + ethereumChainMock.AddDepositToBatch(batchNonceOnEthereum+1, contract.Deposit{ + Nonce: big.NewInt(int64(txNonceOnEthereum) + 2), + TokenAddress: token2Erc20, + Amount: value2, + Depositor: depositor2, + Recipient: destination2.AddressSlice(), + Status: 0, + }) + ethereumChainMock.AddDepositToBatch(batchNonceOnEthereum+1, contract.Deposit{ + Nonce: big.NewInt(int64(txNonceOnEthereum) + 3), + TokenAddress: token3Erc20, + Amount: value3, + Depositor: scExecProxyEthAddress, + Recipient: destination3Sc.AddressSlice(), + Status: 0, + }) + ethereumChainMock.AddBatch(batch) + ethereumChainMock.SetQuorum(numRelayers) + + ethereumChainMock.FilterLogsCalled = func(ctx context.Context, q ethereum.FilterQuery) ([]types.Log, error) { + expectedBatchNonceHash := []common.Hash{ + common.BytesToHash(big.NewInt(int64(batchNonceOnEthereum + 1)).Bytes()), + } + require.Equal(t, 2, len(q.Topics)) + assert.Equal(t, expectedBatchNonceHash, q.Topics[1]) + + scExecAbi, err := contract.SCExecProxyMetaData.GetAbi() + require.Nil(t, err) + + eventInputs := scExecAbi.Events["ERC20SCDeposit"].Inputs.NonIndexed() + packedArgs, err := eventInputs.Pack(txNonceOnEthereum+3, args.providedExtraGas, args.providedScCallData) + require.Nil(t, err) + + scLog := types.Log{ + Data: packedArgs, + } + + return []types.Log{scLog}, nil + } + + multiversXChainMock := mock.NewMultiversXChainMock() + multiversXChainMock.AddTokensPair(token1Erc20, ticker1) + multiversXChainMock.AddTokensPair(token2Erc20, ticker2) + multiversXChainMock.AddTokensPair(token3Erc20, ticker3) + multiversXChainMock.SetLastExecutedEthBatchID(batchNonceOnEthereum) + multiversXChainMock.SetLastExecutedEthTxId(txNonceOnEthereum) + multiversXChainMock.GetStatusesAfterExecutionHandler = func() []byte { + return []byte{clients.Executed, clients.Rejected, clients.Executed} + } + multiversXChainMock.SetQuorum(numRelayers) + + relayers := make([]bridgeComponents, 0, numRelayers) + defer func() { + for _, r := range relayers { + _ = r.Close() + } + }() + + messengers := integrationTests.CreateLinkedMessengers(numRelayers) + + ctx, cancel := context.WithTimeout(context.Background(), time.Second*120) + defer cancel() + multiversXChainMock.ProcessFinishedHandler = func() { + log.Info("multiversXChainMock.ProcessFinishedHandler called") + asyncCancelCall(cancel, time.Second*5) + } + + for i := 0; i < numRelayers; i++ { + argsBridgeComponents := createMockBridgeComponentsArgs(i, messengers[i], multiversXChainMock, ethereumChainMock) + argsBridgeComponents.Configs.GeneralConfig.Eth.SafeContractAddress = safeContractEthAddress.Hex() + argsBridgeComponents.Configs.GeneralConfig.Eth.SCExecProxyAddress = scExecProxyEthAddress.Hex() + argsBridgeComponents.Erc20ContractsHolder = erc20ContractsHolder + relayer, err := factory.NewEthMultiversXBridgeComponents(argsBridgeComponents) + require.Nil(t, err) + + multiversXChainMock.AddRelayer(relayer.MultiversXRelayerAddress()) + ethereumChainMock.AddRelayer(relayer.EthereumRelayerAddress()) + + go func() { + err = relayer.Start() + integrationTests.Log.LogIfError(err) + require.Nil(t, err) + }() + + relayers = append(relayers, relayer) + } + + <-ctx.Done() + time.Sleep(time.Second * 5) + + assert.NotNil(t, multiversXChainMock.PerformedActionID()) + transfer := multiversXChainMock.ProposedTransfer() + require.NotNil(t, transfer) + require.Equal(t, 3, len(transfer.Transfers)) + assert.Equal(t, batchNonceOnEthereum+1, transfer.BatchId.Uint64()) + + assert.Equal(t, destination1.AddressBytes(), transfer.Transfers[0].To) + assert.Equal(t, hex.EncodeToString([]byte(ticker1)), transfer.Transfers[0].Token) + assert.Equal(t, value1, transfer.Transfers[0].Amount) + assert.Equal(t, depositor1, common.BytesToAddress(transfer.Transfers[0].From)) + assert.Equal(t, txNonceOnEthereum+1, transfer.Transfers[0].Nonce.Uint64()) + assert.Empty(t, transfer.Transfers[0].Data) + assert.Zero(t, transfer.Transfers[0].ExtraGas) assert.Equal(t, destination2.AddressBytes(), transfer.Transfers[1].To) assert.Equal(t, hex.EncodeToString([]byte(ticker2)), transfer.Transfers[1].Token) assert.Equal(t, value2, transfer.Transfers[1].Amount) assert.Equal(t, depositor2, common.BytesToAddress(transfer.Transfers[1].From)) assert.Equal(t, txNonceOnEthereum+2, transfer.Transfers[1].Nonce.Uint64()) + assert.Empty(t, transfer.Transfers[1].Data) + assert.Zero(t, transfer.Transfers[1].ExtraGas) + + assert.Equal(t, destination3Sc.AddressBytes(), transfer.Transfers[2].To) + assert.Equal(t, hex.EncodeToString([]byte(ticker3)), transfer.Transfers[2].Token) + assert.Equal(t, value3, transfer.Transfers[2].Amount) + assert.Equal(t, scExecProxyEthAddress, common.BytesToAddress(transfer.Transfers[2].From)) + assert.Equal(t, txNonceOnEthereum+3, transfer.Transfers[2].Nonce.Uint64()) + assert.Equal(t, args.expectedScCallData, string(transfer.Transfers[2].Data)) + assert.Equal(t, args.expectedExtraGas, transfer.Transfers[2].ExtraGas) } func createMockBridgeComponentsArgs( diff --git a/integrationTests/testscommon.go b/integrationTests/testscommon.go index 4593755c..57ca5e8c 100644 --- a/integrationTests/testscommon.go +++ b/integrationTests/testscommon.go @@ -5,6 +5,7 @@ import ( "github.com/multiversx/mx-bridge-eth-go/core" "github.com/multiversx/mx-bridge-eth-go/testsCommon/crypto" + "github.com/multiversx/mx-chain-communication-go/p2p/libp2p" "github.com/multiversx/mx-chain-core-go/hashing/blake2b" "github.com/multiversx/mx-chain-core-go/marshal" "github.com/multiversx/mx-chain-crypto-go/signing" @@ -14,7 +15,6 @@ import ( p2pConfig "github.com/multiversx/mx-chain-go/p2p/config" "github.com/multiversx/mx-chain-go/testscommon/p2pmocks" logger "github.com/multiversx/mx-chain-logger-go" - "github.com/multiversx/mx-chain-p2p-go/libp2p" ) // Log - @@ -98,6 +98,11 @@ func CreateMessengerWithNoDiscovery() p2p.Messenger { ListenAddress: "/ip4/127.0.0.1/tcp/%d", }, }, + ResourceLimiter: p2pConfig.P2PResourceLimiterConfig{ + Type: "default autoscale", + ManualSystemMemoryInMB: 0, + ManualMaximumFD: 0, + }, }, KadDhtPeerDiscovery: p2pConfig.KadDhtPeerDiscoveryConfig{ Enabled: false, @@ -114,21 +119,16 @@ func CreateMessengerWithNoDiscovery() p2p.Messenger { // CreateMessengerFromConfig creates a new libp2p messenger with provided configuration func CreateMessengerFromConfig(p2pConfig p2pConfig.P2PConfig) p2p.Messenger { arg := libp2p.ArgsNetworkMessenger{ - Marshalizer: &marshal.JsonMarshalizer{}, + Marshaller: &marshal.JsonMarshalizer{}, P2pConfig: p2pConfig, SyncTimer: &libp2p.LocalSyncTimer{}, PreferredPeersHolder: &p2pmocks.PeersHolderStub{}, - NodeOperationMode: p2p.NormalOperation, ConnectionWatcherType: "disabled", PeersRatingHandler: &p2pmocks.PeersRatingHandlerStub{}, P2pPrivateKey: crypto.NewPrivateKeyMock(), P2pSingleSigner: &crypto.SingleSignerStub{}, P2pKeyGenerator: &crypto.KeyGenStub{}, - } - - if p2pConfig.Sharding.AdditionalConnections.MaxFullHistoryObservers > 0 { - // we deliberately set this, automatically choose full archive node mode - arg.NodeOperationMode = p2p.FullArchiveMode + Logger: Log, } libP2PMes, err := libp2p.NewNetworkMessenger(arg) diff --git a/p2p/broadcaster.go b/p2p/broadcaster.go index e59d773d..16688eb9 100644 --- a/p2p/broadcaster.go +++ b/p2p/broadcaster.go @@ -139,7 +139,7 @@ func (b *broadcaster) RegisterOnTopics() error { } // ProcessReceivedMessage will be called by the network messenger whenever a new message is received -func (b *broadcaster) ProcessReceivedMessage(message p2p.MessageP2P, fromConnectedPeer chainCore.PeerID) error { +func (b *broadcaster) ProcessReceivedMessage(message p2p.MessageP2P, fromConnectedPeer chainCore.PeerID, _ p2p.MessageHandler) error { msg, err := b.preProcessMessage(message, fromConnectedPeer) if err != nil { b.log.Debug("got message", "topic", message.Topic(), "error", err) @@ -152,8 +152,9 @@ func (b *broadcaster) ProcessReceivedMessage(message p2p.MessageP2P, fromConnect return fmt.Errorf("%w for peer: %s", ErrPeerNotWhitelisted, hexPkBytes) } + address, _ := addr.AddressAsBech32String() b.log.Trace("got message", "topic", message.Topic(), - "msg.Payload", msg.Payload, "msg.Nonce", msg.Nonce, "msg.PublicKey", addr.AddressAsBech32String()) + "msg.Payload", msg.Payload, "msg.Nonce", msg.Nonce, "msg.PublicKey", address) err = b.processNonce(msg) if err != nil { @@ -165,7 +166,7 @@ func (b *broadcaster) ProcessReceivedMessage(message p2p.MessageP2P, fromConnect err = b.canProcessMessage(message, fromConnectedPeer) if err != nil { b.log.Debug("can't process message", "peer", fromConnectedPeer, "topic", message.Topic(), "msg.Payload", msg.Payload, - "msg.Nonce", msg.Nonce, "msg.PublicKey", addr.AddressAsBech32String(), "error", err) + "msg.Nonce", msg.Nonce, "msg.PublicKey", address, "error", err) return err } diff --git a/p2p/broadcaster_test.go b/p2p/broadcaster_test.go index 6b65a296..07fd7ecb 100644 --- a/p2p/broadcaster_test.go +++ b/p2p/broadcaster_test.go @@ -213,7 +213,7 @@ func TestBroadcaster_ProcessReceivedMessage(t *testing.T) { DataField: []byte("gibberish"), } - err := b.ProcessReceivedMessage(p2pMsg, "") + err := b.ProcessReceivedMessage(p2pMsg, "", nil) assert.NotNil(t, err) }) t.Run("public key not whitelisted", func(t *testing.T) { @@ -234,7 +234,7 @@ func TestBroadcaster_ProcessReceivedMessage(t *testing.T) { DataField: buff, } - err := b.ProcessReceivedMessage(p2pMsg, "") + err := b.ProcessReceivedMessage(p2pMsg, "", nil) assert.True(t, errors.Is(err, ErrPeerNotWhitelisted)) assert.True(t, isWhiteListedCalled) }) @@ -250,11 +250,11 @@ func TestBroadcaster_ProcessReceivedMessage(t *testing.T) { DataField: buff, } - err := b.ProcessReceivedMessage(p2pMsg, "") + err := b.ProcessReceivedMessage(p2pMsg, "", nil) assert.Equal(t, ErrNonceTooLowInReceivedMessage, err) b.nonces[string(msg.PublicKeyBytes)] = msg.Nonce - err = b.ProcessReceivedMessage(p2pMsg, "") + err = b.ProcessReceivedMessage(p2pMsg, "", nil) assert.Equal(t, ErrNonceTooLowInReceivedMessage, err) }) t.Run("joined topic should send stored messages from clients", func(t *testing.T) { @@ -301,7 +301,7 @@ func TestBroadcaster_ProcessReceivedMessage(t *testing.T) { TopicField: args.Name + signTopicSuffix, PeerField: pid, } - _ = b.ProcessReceivedMessage(p2pMsg, "") + _ = b.ProcessReceivedMessage(p2pMsg, "", nil) msg2, buff2 := createSignedMessageAndMarshaledBytes(1) p2pMsg = &p2pMocks.P2PMessageMock{ @@ -310,7 +310,7 @@ func TestBroadcaster_ProcessReceivedMessage(t *testing.T) { PeerField: pid, } - err = b.ProcessReceivedMessage(p2pMsg, "") + err = b.ProcessReceivedMessage(p2pMsg, "", nil) assert.Nil(t, err) assert.True(t, sendWasCalled) @@ -349,7 +349,7 @@ func TestBroadcaster_ProcessReceivedMessage(t *testing.T) { TopicField: args.Name + signTopicSuffix, } - err := b.ProcessReceivedMessage(p2pMsg, "") + err := b.ProcessReceivedMessage(p2pMsg, "", nil) assert.Nil(t, err) p2pMsg = &p2pMocks.P2PMessageMock{ @@ -357,7 +357,7 @@ func TestBroadcaster_ProcessReceivedMessage(t *testing.T) { TopicField: args.Name + signTopicSuffix, } - err = b.ProcessReceivedMessage(p2pMsg, "") + err = b.ProcessReceivedMessage(p2pMsg, "", nil) assert.Nil(t, err) assert.Equal(t, 2, len(b.SortedPublicKeys())) @@ -383,7 +383,7 @@ func TestBroadcaster_ProcessReceivedMessage(t *testing.T) { TopicField: args.Name + signTopicSuffix, } - err := b.ProcessReceivedMessage(p2pMsg, "") + err := b.ProcessReceivedMessage(p2pMsg, "", nil) assert.Nil(t, err) assert.Equal(t, 1, len(b.SortedPublicKeys())) @@ -422,7 +422,7 @@ func TestBroadcaster_ProcessReceivedMessage(t *testing.T) { TopicField: args.Name + signTopicSuffix, } - err = b.ProcessReceivedMessage(p2pMsg, "p1") + err = b.ProcessReceivedMessage(p2pMsg, "p1", nil) assert.Nil(t, err) p2pMsg = &p2pMocks.P2PMessageMock{ @@ -430,7 +430,7 @@ func TestBroadcaster_ProcessReceivedMessage(t *testing.T) { TopicField: args.Name + signTopicSuffix, } - err = b.ProcessReceivedMessage(p2pMsg, "p1") + err = b.ProcessReceivedMessage(p2pMsg, "p1", nil) assert.True(t, strings.Contains(err.Error(), "system busy")) }) t.Run("sign should store message", func(t *testing.T) { @@ -451,7 +451,7 @@ func TestBroadcaster_ProcessReceivedMessage(t *testing.T) { TopicField: args.Name + signTopicSuffix, } - err := b.ProcessReceivedMessage(p2pMsg, "") + err := b.ProcessReceivedMessage(p2pMsg, "", nil) assert.Nil(t, err) p2pMsg = &p2pMocks.P2PMessageMock{ @@ -459,7 +459,7 @@ func TestBroadcaster_ProcessReceivedMessage(t *testing.T) { TopicField: args.Name + signTopicSuffix, } - err = b.ProcessReceivedMessage(p2pMsg, "") + err = b.ProcessReceivedMessage(p2pMsg, "", nil) assert.Nil(t, err) assert.Equal(t, [][]byte{msg1.PublicKeyBytes, msg2.PublicKeyBytes}, b.SortedPublicKeys()) diff --git a/testsCommon/addressGenerators.go b/testsCommon/addressGenerators.go index 2cbbf4f8..e0d8c55d 100644 --- a/testsCommon/addressGenerators.go +++ b/testsCommon/addressGenerators.go @@ -23,3 +23,13 @@ func CreateRandomMultiversXAddress() sdkCore.AddressHandler { return data.NewAddressFromBytes(buff) } + +// CreateRandomMultiversXSCAddress will create a random MultiversX smart contract address +func CreateRandomMultiversXSCAddress() sdkCore.AddressHandler { + buff := make([]byte, 22) + _, _ = rand.Read(buff) + + firstPart := append(make([]byte, 8), []byte{5, 0}...) + + return data.NewAddressFromBytes(append(firstPart, buff...)) +} diff --git a/testsCommon/bridge/ethereumClientStub.go b/testsCommon/bridge/ethereumClientStub.go index 76e6310d..47b274ad 100644 --- a/testsCommon/bridge/ethereumClientStub.go +++ b/testsCommon/bridge/ethereumClientStub.go @@ -6,6 +6,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/multiversx/mx-bridge-eth-go/clients" + "github.com/multiversx/mx-bridge-eth-go/clients/ethereum/contract" "github.com/multiversx/mx-bridge-eth-go/core/batchProcessor" ) @@ -20,6 +21,8 @@ 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) + IsDepositSCCallCalled func(deposit *clients.DepositTransfer) bool + GetBatchSCMetadataCalled func(ctx context.Context, nonce uint64) ([]*contract.SCExecProxyERC20SCDeposit, error) CheckRequiredBalanceCalled func(ctx context.Context, erc20Address common.Address, value *big.Int) error TokenMintedBalancesCalled func(ctx context.Context, token common.Address) (*big.Int, error) WhitelistedTokensMintBurnCalled func(ctx context.Context, token common.Address) (bool, error) @@ -104,6 +107,24 @@ func (stub *EthereumClientStub) IsQuorumReached(ctx context.Context, msgHash com return false, errNotImplemented } +// IsDepositSCCall - +func (stub *EthereumClientStub) IsDepositSCCall(deposit *clients.DepositTransfer) bool { + if stub.IsDepositSCCallCalled != nil { + return stub.IsDepositSCCallCalled(deposit) + } + + return false +} + +// GetBatchSCMetadata - +func (stub *EthereumClientStub) GetBatchSCMetadata(ctx context.Context, nonce uint64) ([]*contract.SCExecProxyERC20SCDeposit, error) { + if stub.GetBatchSCMetadataCalled != nil { + return stub.GetBatchSCMetadataCalled(ctx, nonce) + } + + return []*contract.SCExecProxyERC20SCDeposit{}, nil +} + // CheckRequiredBalance - func (stub *EthereumClientStub) CheckRequiredBalance(ctx context.Context, erc20Address common.Address, value *big.Int) error { if stub.CheckRequiredBalanceCalled != nil { diff --git a/testsCommon/bridge/ethereumClientWrapperStub.go b/testsCommon/bridge/ethereumClientWrapperStub.go index c9db506c..deb6e504 100644 --- a/testsCommon/bridge/ethereumClientWrapperStub.go +++ b/testsCommon/bridge/ethereumClientWrapperStub.go @@ -5,6 +5,7 @@ import ( "errors" "math/big" + "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" @@ -36,6 +37,7 @@ type EthereumClientWrapperStub struct { GetAllMetricsCalled func() core.GeneralMetrics NameCalled func() string IsPausedCalled func(ctx context.Context) (bool, error) + FilterLogsCalled func(ctx context.Context, q ethereum.FilterQuery) ([]types.Log, error) } // SetIntMetric - @@ -191,6 +193,15 @@ func (stub *EthereumClientWrapperStub) BalanceAt(ctx context.Context, account co return big.NewInt(0), nil } +// FilterLogs - +func (stub *EthereumClientWrapperStub) FilterLogs(ctx context.Context, q ethereum.FilterQuery) ([]types.Log, error) { + if stub.FilterLogsCalled != nil { + return stub.FilterLogsCalled(ctx, q) + } + + return []types.Log{}, nil +} + // IsPaused - func (stub *EthereumClientWrapperStub) IsPaused(ctx context.Context) (bool, error) { if stub.IsPausedCalled != nil { diff --git a/testsCommon/gasMap.go b/testsCommon/gasMap.go index f2617cfd..39aa12c9 100644 --- a/testsCommon/gasMap.go +++ b/testsCommon/gasMap.go @@ -14,5 +14,7 @@ func CreateTestMultiversXGasMap() config.MultiversXGasMapConfig { ProposeStatusForEach: 105, PerformActionBase: 106, PerformActionForEach: 107, + ScCallPerByte: 108, + ScCallPerformForEach: 109, } } diff --git a/testsCommon/interactors/blockchainClientStub.go b/testsCommon/interactors/blockchainClientStub.go index 53cfd3f6..81de954e 100644 --- a/testsCommon/interactors/blockchainClientStub.go +++ b/testsCommon/interactors/blockchainClientStub.go @@ -4,7 +4,9 @@ import ( "context" "math/big" + "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" ) // BlockchainClientStub - @@ -13,6 +15,7 @@ type BlockchainClientStub struct { NonceAtCalled func(ctx context.Context, account common.Address, blockNumber *big.Int) (uint64, error) ChainIDCalled func(ctx context.Context) (*big.Int, error) BalanceAtCalled func(ctx context.Context, account common.Address, blockNumber *big.Int) (*big.Int, error) + FilterLogsCalled func(ctx context.Context, q ethereum.FilterQuery) ([]types.Log, error) } // BlockNumber - @@ -51,6 +54,15 @@ func (bcs *BlockchainClientStub) BalanceAt(ctx context.Context, account common.A return big.NewInt(0), nil } +// FilterLogs - +func (bcs *BlockchainClientStub) FilterLogs(ctx context.Context, q ethereum.FilterQuery) ([]types.Log, error) { + if bcs.FilterLogsCalled != nil { + return bcs.FilterLogsCalled(ctx, q) + } + + return nil, nil +} + // IsInterfaceNil returns true if there is no value under the interface func (bcs *BlockchainClientStub) IsInterfaceNil() bool { return bcs == nil diff --git a/testsCommon/p2p/p2pMessageMock.go b/testsCommon/p2p/p2pMessageMock.go index 3218fc94..6224f1c3 100644 --- a/testsCommon/p2p/p2pMessageMock.go +++ b/testsCommon/p2p/p2pMessageMock.go @@ -1,6 +1,7 @@ package p2p import ( + "github.com/multiversx/mx-chain-communication-go/p2p" "github.com/multiversx/mx-chain-core-go/core" ) @@ -62,6 +63,11 @@ func (msg *P2PMessageMock) Payload() []byte { return msg.PayloadField } +// BroadcastMethod - +func (msg *P2PMessageMock) BroadcastMethod() p2p.BroadcastMethod { + return p2p.Broadcast +} + // IsInterfaceNil returns true if there is no value under the interface func (msg *P2PMessageMock) IsInterfaceNil() bool { return msg == nil