diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 6941e5fb..c0044997 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -16,20 +16,20 @@ jobs: # Needed for multi-platform builds - name: Set up QEMU - uses: docker/setup-qemu-action@v2 + uses: docker/setup-qemu-action@v3 # Needed for multi-platform builds - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v2 + uses: docker/setup-buildx-action@v3 - name: Log in to Docker Hub - uses: docker/login-action@v2 + uses: docker/login-action@v3 with: username: ${{ secrets.DOCKER_USERNAME }} password: ${{ secrets.DOCKER_PASSWORD }} - name: Build and Push to Docker Hub - uses: docker/build-push-action@v4 + uses: docker/build-push-action@v5 with: platforms: linux/amd64,linux/arm64 push: true diff --git a/README.md b/README.md index 42e945fd..fa1fbce7 100644 --- a/README.md +++ b/README.md @@ -3,10 +3,12 @@ Standalone relayer for cross-chain Avalanche Warp Message delivery. ## Usage ---- + ### Building + Build the relayer by running the included build script: -``` + +```bash ./scripts/build.sh ``` @@ -14,17 +16,23 @@ Build a Docker image by running the included build script: ``` ./scripts/build-local-image.sh ``` + ### Running + The relayer binary accepts a path to a JSON configuration file as the sole argument. Command line configuration arguments are not currently supported. -``` + +```bash ./build/awm-relayer --config-file path-to-config ``` ## Architecture ---- + **Note:** The relayer in its current state supports Teleporter messages between `subnet-evm` instances. A handful of abstractions have been added to make the relayer extensible to other Warp message formats and VM types, but this work is ongoing. + ### Components + The relayer consists of the following components: + - At the global level: - *P2P App Network*: issues signature `AppRequests` - *P-Chain client*: gets the validators for a subnet @@ -34,6 +42,7 @@ The relayer consists of the following components: - *Destination RPC client*: broadcasts transactions to the destination ### Data flow +
@@ -70,4 +79,11 @@ Then, in the root of the `awm-relayer` project, run: AVALANCHEGO_BUILD_PATH=~/tmp/e2e-test/avalanchego DATA_DIR=~/tmp/e2e-test/data ./scripts/e2e_test.sh ``` -Note that any additional E2E tests that run VMs other than `subnet-evm` will need to install and setup the VM binary in the same way. \ No newline at end of file +Note that any additional E2E tests that run VMs other than `subnet-evm` will need to install and setup the VM binary in the same way. +### Generate Mocks + +We use [gomock](https://pkg.go.dev/go.uber.org/mock/gomock) to generate mocks for testing. To generate mocks, run the following command at the root of the project: + +```bash +go generate ./... +``` diff --git a/config/config_test.go b/config/config_test.go index f124d3c3..b5d64e73 100644 --- a/config/config_test.go +++ b/config/config_test.go @@ -14,7 +14,6 @@ import ( "github.com/ava-labs/awm-relayer/utils" "github.com/ethereum/go-ethereum/common" - "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -62,10 +61,12 @@ var ( func TestGetDestinationRPCEndpoint(t *testing.T) { testCases := []struct { + name string s DestinationSubnet expectedResult string }{ { + name: "No encrypt connection", s: DestinationSubnet{ EncryptConnection: false, APINodeHost: "127.0.0.1", @@ -76,6 +77,7 @@ func TestGetDestinationRPCEndpoint(t *testing.T) { expectedResult: fmt.Sprintf("http://127.0.0.1:9650/ext/bc/%s/rpc", testChainID), }, { + name: "Encrypt connection", s: DestinationSubnet{ EncryptConnection: true, APINodeHost: "127.0.0.1", @@ -86,6 +88,7 @@ func TestGetDestinationRPCEndpoint(t *testing.T) { expectedResult: fmt.Sprintf("https://127.0.0.1:9650/ext/bc/%s/rpc", testChainID), }, { + name: "No port", s: DestinationSubnet{ EncryptConnection: false, APINodeHost: "api.avax.network", @@ -96,6 +99,7 @@ func TestGetDestinationRPCEndpoint(t *testing.T) { expectedResult: fmt.Sprintf("http://api.avax.network/ext/bc/%s/rpc", testChainID), }, { + name: "Primary subnet", s: DestinationSubnet{ EncryptConnection: false, APINodeHost: "127.0.0.1", @@ -106,6 +110,7 @@ func TestGetDestinationRPCEndpoint(t *testing.T) { expectedResult: "http://127.0.0.1:9650/ext/bc/C/rpc", }, { + name: "Override with set rpc endpoint", s: DestinationSubnet{ EncryptConnection: false, APINodeHost: "127.0.0.1", @@ -118,19 +123,23 @@ func TestGetDestinationRPCEndpoint(t *testing.T) { }, } - for i, testCase := range testCases { - res := testCase.s.GetNodeRPCEndpoint() - assert.Equal(t, testCase.expectedResult, res, fmt.Sprintf("test case %d failed", i)) + for _, testCase := range testCases { + t.Run(testCase.name, func(t *testing.T) { + res := testCase.s.GetNodeRPCEndpoint() + require.Equal(t, testCase.expectedResult, res) + }) } } func TestGetSourceSubnetEndpoints(t *testing.T) { testCases := []struct { + name string s SourceSubnet expectedWsResult string expectedRpcResult string }{ { + name: "No encrypt connection", s: SourceSubnet{ EncryptConnection: false, APINodeHost: "127.0.0.1", @@ -142,6 +151,7 @@ func TestGetSourceSubnetEndpoints(t *testing.T) { expectedRpcResult: fmt.Sprintf("http://127.0.0.1:9650/ext/bc/%s/rpc", testChainID), }, { + name: "Encrypt connection", s: SourceSubnet{ EncryptConnection: true, APINodeHost: "127.0.0.1", @@ -153,6 +163,7 @@ func TestGetSourceSubnetEndpoints(t *testing.T) { expectedRpcResult: fmt.Sprintf("https://127.0.0.1:9650/ext/bc/%s/rpc", testChainID), }, { + name: "No port", s: SourceSubnet{ EncryptConnection: false, APINodeHost: "api.avax.network", @@ -164,6 +175,7 @@ func TestGetSourceSubnetEndpoints(t *testing.T) { expectedRpcResult: fmt.Sprintf("http://api.avax.network/ext/bc/%s/rpc", testChainID), }, { + name: "Primary subnet", s: SourceSubnet{ EncryptConnection: false, APINodeHost: "127.0.0.1", @@ -175,6 +187,7 @@ func TestGetSourceSubnetEndpoints(t *testing.T) { expectedRpcResult: "http://127.0.0.1:9650/ext/bc/C/rpc", }, { + name: "Override with set endpoints", s: SourceSubnet{ EncryptConnection: false, APINodeHost: "127.0.0.1", @@ -189,9 +202,11 @@ func TestGetSourceSubnetEndpoints(t *testing.T) { }, } - for i, testCase := range testCases { - assert.Equal(t, testCase.expectedWsResult, testCase.s.GetNodeWSEndpoint(), fmt.Sprintf("test case %d failed", i)) - assert.Equal(t, testCase.expectedRpcResult, testCase.s.GetNodeRPCEndpoint(), fmt.Sprintf("test case %d failed", i)) + for _, testCase := range testCases { + t.Run(testCase.name, func(t *testing.T) { + require.Equal(t, testCase.expectedWsResult, testCase.s.GetNodeWSEndpoint()) + require.Equal(t, testCase.expectedRpcResult, testCase.s.GetNodeRPCEndpoint()) + }) } } @@ -203,11 +218,12 @@ func TestGetRelayerAccountInfo(t *testing.T) { } testCases := []struct { + name string s DestinationSubnet expectedResult retStruct }{ - // valid { + name: "valid", s: DestinationSubnet{ AccountPrivateKey: "56289e99c94b6912bfc12adc093c9b51124f0dc54ac7a766b2bc5ccf558d8027", }, @@ -219,8 +235,8 @@ func TestGetRelayerAccountInfo(t *testing.T) { err: nil, }, }, - // invalid, with 0x prefix. Should be sanitized before being set in DestinationSubnet { + name: "invalid 0x prefix", s: DestinationSubnet{ AccountPrivateKey: "0x56289e99c94b6912bfc12adc093c9b51124f0dc54ac7a766b2bc5ccf558d8027", }, @@ -232,8 +248,8 @@ func TestGetRelayerAccountInfo(t *testing.T) { err: ErrInvalidPrivateKey, }, }, - // invalid { + name: "invalid private key", s: DestinationSubnet{ AccountPrivateKey: "invalid56289e99c94b6912bfc12adc093c9b51124f0dc54ac7a766b2bc5ccf558d8027", }, @@ -247,13 +263,15 @@ func TestGetRelayerAccountInfo(t *testing.T) { }, } - for i, testCase := range testCases { - pk, addr, err := testCase.s.GetRelayerAccountInfo() - assert.Equal(t, testCase.expectedResult.err, err, fmt.Sprintf("test case %d had unexpected error", i)) - if err == nil { - assert.Equal(t, testCase.expectedResult.pk.D.Int64(), pk.D.Int64(), fmt.Sprintf("test case %d had mismatched pk", i)) - assert.Equal(t, testCase.expectedResult.addr, addr, fmt.Sprintf("test case %d had mismatched address", i)) - } + for _, testCase := range testCases { + t.Run(testCase.name, func(t *testing.T) { + pk, addr, err := testCase.s.GetRelayerAccountInfo() + require.Equal(t, testCase.expectedResult.err, err) + if err == nil { + require.Equal(t, testCase.expectedResult.pk.D.Int64(), pk.D.Int64()) + require.Equal(t, testCase.expectedResult.addr, addr) + } + }) } } @@ -270,12 +288,11 @@ type getRelayerAccountPrivateKeyTestCase struct { // Sets up the config file temporary environment and runs the test case. func runGetRelayerAccountPrivateKeyTest(t *testing.T, testCase getRelayerAccountPrivateKeyTestCase) { - require := require.New(t) root := t.TempDir() cfg := testCase.configModifier(testCase.baseConfig) cfgBytes, err := json.Marshal(cfg) - require.NoError(err) + require.NoError(t, err) configFile := setupConfigJSON(t, root, string(cfgBytes)) @@ -284,13 +301,12 @@ func runGetRelayerAccountPrivateKeyTest(t *testing.T, testCase getRelayerAccount fs := BuildFlagSet() v, err := BuildViper(fs, flags) - require.NoError(err) + require.NoError(t, err) parsedCfg, optionOverwritten, err := BuildConfig(v) - require.NoError(err) - assert.Equal(t, optionOverwritten, testCase.expectedOverwritten) - if !testCase.resultVerifier(parsedCfg) { - t.Errorf("unexpected config.") - } + require.NoError(t, err) + require.Equal(t, optionOverwritten, testCase.expectedOverwritten) + + require.True(t, testCase.resultVerifier(parsedCfg)) } func TestGetRelayerAccountPrivateKey_set_pk_in_config(t *testing.T) { @@ -381,3 +397,16 @@ func setupConfigJSON(t *testing.T, rootPath string, value string) string { require.NoError(t, os.WriteFile(configFilePath, []byte(value), 0o600)) return configFilePath } + +func TestGetRelayerAccountInfoSkipChainConfigCheckCompatible(t *testing.T) { + accountPrivateKey := "56289e99c94b6912bfc12adc093c9b51124f0dc54ac7a766b2bc5ccf558d8027" + expectedAddress := "0x8db97C7cEcE249c2b98bDC0226Cc4C2A57BF52FC" + + info := DestinationSubnet{ + AccountPrivateKey: accountPrivateKey, + } + _, address, err := info.GetRelayerAccountInfo() + + require.NoError(t, err) + require.Equal(t, expectedAddress, address.String()) +} diff --git a/go.mod b/go.mod index 6ad7e584..941c5ee5 100644 --- a/go.mod +++ b/go.mod @@ -16,7 +16,7 @@ require ( github.com/spf13/viper v1.16.0 github.com/stretchr/testify v1.8.4 go.uber.org/mock v0.2.0 - go.uber.org/zap v1.25.0 + go.uber.org/zap v1.26.0 ) require ( diff --git a/go.sum b/go.sum index f9eb5c9f..6285d971 100644 --- a/go.sum +++ b/go.sum @@ -70,7 +70,6 @@ github.com/ava-labs/coreth v0.12.5-rc.3/go.mod h1:HI+jTIflnDFBd0bledgkgid1Uurwr8 github.com/ava-labs/subnet-evm v0.5.4 h1:4+UHva8rhGlvH4gDYpI0Lt6/J5ie1DqQa6kEmbebArI= github.com/ava-labs/subnet-evm v0.5.4/go.mod h1:PAyhfYnECzA17N62i7OAdKazjfSsN2l8KR5nOspg39I= github.com/aymerick/raymond v2.0.3-0.20180322193309-b565731e1464+incompatible/go.mod h1:osfaiScAUVup+UC9Nfq76eWqDhXlp+4UYaA8uhTBO6g= -github.com/benbjohnson/clock v1.3.0 h1:ip6w0uFQkncKQ979AypyG0ER7mqUSBdKLOgAle/AT8A= 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/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ= @@ -615,8 +614,8 @@ go.uber.org/mock v0.2.0 h1:TaP3xedm7JaAgScZO7tlvlKrqT0p7I6OsdGB5YNSMDU= go.uber.org/mock v0.2.0/go.mod h1:J0y0rp9L3xiff1+ZBfKxlC1fz2+aO16tw0tsDOixfuM= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= -go.uber.org/zap v1.25.0 h1:4Hvk6GtkucQ790dqmj7l1eEnRdKm3k3ZUrUMS2d5+5c= -go.uber.org/zap v1.25.0/go.mod h1:JIAUzQIH94IC4fOJQm7gMmBJP5k7wQfdcnYdPoEXJYk= +go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo= +go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so= golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= diff --git a/messages/message_manager.go b/messages/message_manager.go index 46d608ab..00251353 100644 --- a/messages/message_manager.go +++ b/messages/message_manager.go @@ -1,6 +1,8 @@ // Copyright (C) 2023, Ava Labs, Inc. All rights reserved. // See the file LICENSE for licensing terms. +//go:generate mockgen -source=$GOFILE -destination=./mocks/mock_message_manager.go -package=mocks + package messages import ( diff --git a/messages/mocks/mock_message_manager.go b/messages/mocks/mock_message_manager.go new file mode 100644 index 00000000..eba2032f --- /dev/null +++ b/messages/mocks/mock_message_manager.go @@ -0,0 +1,66 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: message_manager.go + +// Package mocks is a generated GoMock package. +package mocks + +import ( + reflect "reflect" + + ids "github.com/ava-labs/avalanchego/ids" + warp "github.com/ava-labs/avalanchego/vms/platformvm/warp" + vmtypes "github.com/ava-labs/awm-relayer/vms/vmtypes" + gomock "go.uber.org/mock/gomock" +) + +// MockMessageManager is a mock of MessageManager interface. +type MockMessageManager struct { + ctrl *gomock.Controller + recorder *MockMessageManagerMockRecorder +} + +// MockMessageManagerMockRecorder is the mock recorder for MockMessageManager. +type MockMessageManagerMockRecorder struct { + mock *MockMessageManager +} + +// NewMockMessageManager creates a new mock instance. +func NewMockMessageManager(ctrl *gomock.Controller) *MockMessageManager { + mock := &MockMessageManager{ctrl: ctrl} + mock.recorder = &MockMessageManagerMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockMessageManager) EXPECT() *MockMessageManagerMockRecorder { + return m.recorder +} + +// SendMessage mocks base method. +func (m *MockMessageManager) SendMessage(signedMessage *warp.Message, parsedVmPayload []byte, destinationChainID ids.ID) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SendMessage", signedMessage, parsedVmPayload, destinationChainID) + ret0, _ := ret[0].(error) + return ret0 +} + +// SendMessage indicates an expected call of SendMessage. +func (mr *MockMessageManagerMockRecorder) SendMessage(signedMessage, parsedVmPayload, destinationChainID interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SendMessage", reflect.TypeOf((*MockMessageManager)(nil).SendMessage), signedMessage, parsedVmPayload, destinationChainID) +} + +// ShouldSendMessage mocks base method. +func (m *MockMessageManager) ShouldSendMessage(warpMessageInfo *vmtypes.WarpMessageInfo, destinationChainID ids.ID) (bool, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ShouldSendMessage", warpMessageInfo, destinationChainID) + ret0, _ := ret[0].(bool) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ShouldSendMessage indicates an expected call of ShouldSendMessage. +func (mr *MockMessageManagerMockRecorder) ShouldSendMessage(warpMessageInfo, destinationChainID interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ShouldSendMessage", reflect.TypeOf((*MockMessageManager)(nil).ShouldSendMessage), warpMessageInfo, destinationChainID) +} diff --git a/messages/teleporter/config_test.go b/messages/teleporter/config_test.go new file mode 100644 index 00000000..1c98a707 --- /dev/null +++ b/messages/teleporter/config_test.go @@ -0,0 +1,40 @@ +package teleporter + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +func TestConfigValidate(t *testing.T) { + testCases := []struct { + name string + rewardAddress string + isError bool + }{ + { + name: "valid", + rewardAddress: "0x27aE10273D17Cd7e80de8580A51f476960626e5f", + isError: false, + }, + { + name: "invalid", + rewardAddress: "0x27aE10273D17Cd7e80de8580A51f476960626e5", + isError: true, + }, + } + + for _, test := range testCases { + t.Run(test.name, func(t *testing.T) { + c := &Config{ + RewardAddress: test.rewardAddress, + } + err := c.Validate() + if test.isError { + require.Error(t, err) + } else { + require.NoError(t, err) + } + }) + } +} diff --git a/messages/teleporter/message.go b/messages/teleporter/message.go index 2507e601..0d55672d 100644 --- a/messages/teleporter/message.go +++ b/messages/teleporter/message.go @@ -40,7 +40,7 @@ type ReceiveCrossChainMessageInput struct { // MessageReceivedInput is the input to messageReceived call // in the contract deployed on the destination chain type MessageReceivedInput struct { - OriginChainID ids.ID `json:"relayerRewardAddress"` + OriginChainID ids.ID `json:"originChainID"` MessageID *big.Int `json:"messageID"` } @@ -84,6 +84,10 @@ func UnpackMessageReceivedResult(result []byte) (bool, error) { return success, err } +func PackMessageReceivedOutput(success bool) ([]byte, error) { + return EVMTeleporterContractABI.PackOutput("messageReceived", success) +} + // CAUTION: PackEvent is documented as not supporting struct types, so this should only be used for testing puposes. // In a real setting, the Teleporter contract should pack the event. // PackSendCrossChainMessageEvent packs the SendCrossChainMessage event type. diff --git a/messages/teleporter/message_manager_test.go b/messages/teleporter/message_manager_test.go new file mode 100644 index 00000000..e2393e34 --- /dev/null +++ b/messages/teleporter/message_manager_test.go @@ -0,0 +1,170 @@ +// Copyright (C) 2023, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +package teleporter + +import ( + "math/big" + "testing" + + "github.com/ava-labs/avalanchego/ids" + "github.com/ava-labs/avalanchego/utils/logging" + "github.com/ava-labs/avalanchego/vms/platformvm/warp" + "github.com/ava-labs/awm-relayer/config" + "github.com/ava-labs/awm-relayer/vms" + mock_evm "github.com/ava-labs/awm-relayer/vms/evm/mocks" + mock_vms "github.com/ava-labs/awm-relayer/vms/mocks" + "github.com/ava-labs/awm-relayer/vms/vmtypes" + "github.com/ethereum/go-ethereum/common" + "github.com/stretchr/testify/require" + "go.uber.org/mock/gomock" +) + +var ( + messageProtocolAddress = common.HexToHash("0xd81545385803bCD83bd59f58Ba2d2c0562387F83") + messageProtocolConfig = config.MessageProtocolConfig{ + MessageFormat: config.TELEPORTER.String(), + Settings: map[string]interface{}{ + "reward-address": "0x27aE10273D17Cd7e80de8580A51f476960626e5f", + }, + } + destinationChainIDString = "S4mMqUXe7vHsGiRAma6bv3CKnyaLssyAxmQ2KvFpX1KEvfFCD" + validRelayerAddress = common.HexToAddress("0x0123456789abcdef0123456789abcdef01234567") + validTeleporterMessage = TeleporterMessage{ + MessageID: big.NewInt(1), + SenderAddress: common.HexToAddress("0x0123456789abcdef0123456789abcdef01234567"), + DestinationAddress: common.HexToAddress("0x0123456789abcdef0123456789abcdef01234567"), + RequiredGasLimit: big.NewInt(2), + AllowedRelayerAddresses: []common.Address{ + validRelayerAddress, + }, + Receipts: []TeleporterMessageReceipt{ + { + ReceivedMessageID: big.NewInt(1), + RelayerRewardAddress: common.HexToAddress("0x0123456789abcdef0123456789abcdef01234567"), + }, + }, + Message: []byte{1, 2, 3, 4}, + } +) + +func TestShouldSendMessage(t *testing.T) { + ctrl := gomock.NewController(t) + logger := logging.NoLog{} + destinationChainID, err := ids.FromString(destinationChainIDString) + require.NoError(t, err) + + mockClient := mock_vms.NewMockDestinationClient(ctrl) + destinationClients := map[ids.ID]vms.DestinationClient{ + destinationChainID: mockClient, + } + + messageManager, err := NewMessageManager( + logger, + messageProtocolAddress, + messageProtocolConfig, + destinationClients, + ) + require.NoError(t, err) + + validMessageBytes, err := PackSendCrossChainMessageEvent(common.HexToHash(destinationChainID.Hex()), validTeleporterMessage) + require.NoError(t, err) + + messageNotDelivered, err := PackMessageReceivedOutput(false) + require.NoError(t, err) + + messageDelivered, err := PackMessageReceivedOutput(true) + require.NoError(t, err) + + warpUnsignedMessage, err := warp.NewUnsignedMessage(0, ids.Empty, validMessageBytes) + require.NoError(t, err) + testCases := []struct { + name string + destinationChainID ids.ID + warpMessageInfo *vmtypes.WarpMessageInfo + senderAddressResult common.Address + senderAddressTimes int + clientResult *mock_evm.MockClient + clientTimes int + callContractResult []byte + callContractTimes int + expectedError bool + expectedResult bool + }{ + { + name: "valid message", + destinationChainID: destinationChainID, + warpMessageInfo: &vmtypes.WarpMessageInfo{ + WarpUnsignedMessage: warpUnsignedMessage, + WarpPayload: validMessageBytes, + }, + senderAddressResult: validRelayerAddress, + senderAddressTimes: 1, + clientResult: mock_evm.NewMockClient(ctrl), + clientTimes: 1, + callContractResult: messageNotDelivered, + callContractTimes: 1, + expectedResult: true, + }, + { + name: "invalid message", + destinationChainID: destinationChainID, + warpMessageInfo: &vmtypes.WarpMessageInfo{ + WarpUnsignedMessage: warpUnsignedMessage, + WarpPayload: []byte{1, 2, 3, 4}, + }, + expectedError: true, + }, + { + name: "invalid destination chain id", + destinationChainID: ids.Empty, + warpMessageInfo: &vmtypes.WarpMessageInfo{ + WarpUnsignedMessage: warpUnsignedMessage, + WarpPayload: validMessageBytes, + }, + expectedError: true, + }, + { + name: "not allowed", + destinationChainID: destinationChainID, + warpMessageInfo: &vmtypes.WarpMessageInfo{ + WarpUnsignedMessage: warpUnsignedMessage, + WarpPayload: validMessageBytes, + }, + senderAddressResult: common.Address{}, + senderAddressTimes: 1, + expectedResult: false, + }, + { + name: "message already delivered", + destinationChainID: destinationChainID, + warpMessageInfo: &vmtypes.WarpMessageInfo{ + WarpUnsignedMessage: warpUnsignedMessage, + WarpPayload: validMessageBytes, + }, + senderAddressResult: validRelayerAddress, + senderAddressTimes: 1, + clientResult: mock_evm.NewMockClient(ctrl), + clientTimes: 1, + callContractResult: messageDelivered, + callContractTimes: 1, + expectedResult: false, + }, + } + for _, test := range testCases { + t.Run(test.name, func(t *testing.T) { + mockClient.EXPECT().SenderAddress().Return(test.senderAddressResult).Times(test.senderAddressTimes) + mockClient.EXPECT().Client().Return(test.clientResult).Times(test.clientTimes) + if test.clientResult != nil { + test.clientResult.EXPECT().CallContract(gomock.Any(), gomock.Any(), gomock.Any()).Return(test.callContractResult, nil).Times(test.callContractTimes) + } + result, err := messageManager.ShouldSendMessage(test.warpMessageInfo, test.destinationChainID) + if test.expectedError { + require.Error(t, err) + } else { + require.NoError(t, err) + require.Equal(t, test.expectedResult, result) + } + }) + } +} diff --git a/messages/teleporter/message_test.go b/messages/teleporter/message_test.go index 0f5d3e37..cf7d5fb9 100644 --- a/messages/teleporter/message_test.go +++ b/messages/teleporter/message_test.go @@ -5,12 +5,11 @@ package teleporter import ( "bytes" - "encoding/hex" "math/big" "testing" "github.com/ethereum/go-ethereum/common" - "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func testTeleporterMessage(messageID int64) TeleporterMessage { @@ -34,7 +33,10 @@ func testTeleporterMessage(messageID int64) TeleporterMessage { } func TestPackUnpackTeleporterMessage(t *testing.T) { - message := testTeleporterMessage(4) + var ( + messageID int64 = 4 + ) + message := testTeleporterMessage(messageID) b, err := PackSendCrossChainMessageEvent(common.HexToHash("0x03"), message) if err != nil { @@ -48,29 +50,14 @@ func TestPackUnpackTeleporterMessage(t *testing.T) { t.FailNow() } - if unpacked.MessageID.Cmp(message.MessageID) != 0 { - t.Errorf("message ids do not match. expected: %d actual: %d", message.MessageID.Uint64(), unpacked.MessageID.Uint64()) - } - if unpacked.SenderAddress != message.SenderAddress { - t.Errorf("sender addresses do not match. expected: %s actual: %s", message.SenderAddress.Hex(), unpacked.SenderAddress.Hex()) - } - if unpacked.DestinationAddress != message.DestinationAddress { - t.Errorf("destination addresses do not match. expected: %s actual: %s", message.DestinationAddress.Hex(), unpacked.DestinationAddress.Hex()) - } - if unpacked.RequiredGasLimit.Cmp(message.RequiredGasLimit) != 0 { - t.Errorf("required gas limits do not match. expected: %d actual: %d", message.RequiredGasLimit.Uint64(), unpacked.RequiredGasLimit.Uint64()) - } for i := 0; i < len(message.AllowedRelayerAddresses); i++ { - if unpacked.AllowedRelayerAddresses[i] != message.AllowedRelayerAddresses[i] { - t.Errorf("allowed relayer addresses %d do not match. expected: %s actual: %s", i, message.AllowedRelayerAddresses[i].Hex(), unpacked.AllowedRelayerAddresses[i].Hex()) - } + require.Equal(t, unpacked.AllowedRelayerAddresses[i], message.AllowedRelayerAddresses[i]) } + for i := 0; i < len(message.Receipts); i++ { - assert.Equal(t, 0, unpacked.Receipts[i].ReceivedMessageID.Cmp(message.Receipts[i].ReceivedMessageID)) - assert.Equal(t, message.Receipts[i].RelayerRewardAddress, unpacked.Receipts[i].RelayerRewardAddress) + require.Equal(t, message.Receipts[i].ReceivedMessageID, unpacked.Receipts[i].ReceivedMessageID) + require.Equal(t, message.Receipts[i].RelayerRewardAddress, unpacked.Receipts[i].RelayerRewardAddress) } - if !bytes.Equal(unpacked.Message, message.Message) { - t.Errorf("messages do not match. expected: %s actual: %s", hex.EncodeToString(message.Message), hex.EncodeToString(unpacked.Message)) - } + require.True(t, bytes.Equal(message.Message, unpacked.Message)) } diff --git a/relayer/message_relayer.go b/relayer/message_relayer.go index 89e066c3..a88ca365 100644 --- a/relayer/message_relayer.go +++ b/relayer/message_relayer.go @@ -311,7 +311,7 @@ func (r *messageRelayer) createSignedMessage(requestID uint32) (*warp.Message, e } // As soon as the signatures exceed the stake weight threshold we try to aggregate and send the transaction. - if utils.CheckStakeWeightExceedsThreshold(accumulatedSignatureWeight, totalValidatorWeight) { + if utils.CheckStakeWeightExceedsThreshold(accumulatedSignatureWeight, totalValidatorWeight, utils.DefaultQuorumNumerator, utils.DefaultQuorumDenominator) { aggSig, vdrBitSet, err := r.aggregateSignatures(signatureMap) if err != nil { r.logger.Error( diff --git a/utils/utils.go b/utils/utils.go index 0f41b0dc..29fa3f6f 100644 --- a/utils/utils.go +++ b/utils/utils.go @@ -26,8 +26,6 @@ const ( ) var ( - Uint256Max = (&big.Int{}).SetBytes(common.Hex2Bytes("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF")) - // Errors ErrNilInput = errors.New("nil input") ErrTooLarge = errors.New("exceeds uint256 maximum value") @@ -38,18 +36,17 @@ var ( // // CheckStakeWeightExceedsThreshold returns true if the accumulated signature weight is at least [quorumNum]/[quorumDen] of [totalWeight]. -func CheckStakeWeightExceedsThreshold(accumulatedSignatureWeight *big.Int, totalWeight uint64) bool { +func CheckStakeWeightExceedsThreshold(accumulatedSignatureWeight *big.Int, totalWeight uint64, quorumNumerator uint64, quorumDenominator uint64) bool { if accumulatedSignatureWeight == nil { return false } // Verifies that quorumNum * totalWeight <= quorumDen * sigWeight - scaledTotalWeight := new(big.Int).SetUint64(totalWeight) - scaledTotalWeight.Mul(scaledTotalWeight, new(big.Int).SetUint64(DefaultQuorumNumerator)) - scaledSigWeight := new(big.Int).Mul(accumulatedSignatureWeight, new(big.Int).SetUint64(DefaultQuorumDenominator)) + totalWeightBI := new(big.Int).SetUint64(totalWeight) + scaledTotalWeight := new(big.Int).Mul(totalWeightBI, new(big.Int).SetUint64(quorumNumerator)) + scaledSigWeight := new(big.Int).Mul(accumulatedSignatureWeight, new(big.Int).SetUint64(quorumDenominator)) - thresholdMet := scaledTotalWeight.Cmp(scaledSigWeight) != 1 - return thresholdMet + return scaledTotalWeight.Cmp(scaledSigWeight) != 1 } // @@ -63,11 +60,12 @@ func BigToHashSafe(in *big.Int) (common.Hash, error) { return common.Hash{}, ErrNilInput } - if in.Cmp(Uint256Max) > 0 { + bytes := in.Bytes() + if len(bytes) > common.HashLength { return common.Hash{}, ErrTooLarge } - return common.BigToHash(in), nil + return common.BytesToHash(bytes), nil } func ConvertProtocol(URLString, protocol string) (string, error) { diff --git a/utils/utils_test.go b/utils/utils_test.go index e066d366..4d12ace9 100644 --- a/utils/utils_test.go +++ b/utils/utils_test.go @@ -3,40 +3,51 @@ package utils -import "testing" +import ( + "math/big" + "testing" + + "github.com/stretchr/testify/require" +) func TestConvertProtocol(t *testing.T) { testCases := []struct { + name string urlString string protocol string expectedUrl string expectedError bool }{ { + name: "valid http to https", urlString: "http://www.hello.com", protocol: "https", expectedUrl: "https://www.hello.com", expectedError: false, }, { + name: "valid https to http", urlString: "https://www.hello.com", protocol: "http", expectedUrl: "http://www.hello.com", expectedError: false, }, { + name: "valid http to http", urlString: "http://www.hello.com", protocol: "http", expectedUrl: "http://www.hello.com", expectedError: false, }, { + name: "valid https to https", urlString: "https://www.hello.com", protocol: "https", expectedUrl: "https://www.hello.com", expectedError: false, }, { + name: "invalid protocol", urlString: "http://www.hello.com", protocol: "\n", expectedUrl: "", @@ -44,45 +55,104 @@ func TestConvertProtocol(t *testing.T) { }, } - for i, testCase := range testCases { - actualUrl, err := ConvertProtocol(testCase.urlString, testCase.protocol) - if err != nil && !testCase.expectedError { - t.Errorf("test case %d failed with unexpected error", i) - } - if err == nil && testCase.expectedError { - t.Errorf("test case %d did not produce expected error", i) - } - if actualUrl != testCase.expectedUrl { - t.Errorf("test case %d had unexpected URL. Actual: %s, Expected: %s", i, actualUrl, testCase.expectedUrl) - } + for _, testCase := range testCases { + t.Run(testCase.name, func(t *testing.T) { + actualUrl, err := ConvertProtocol(testCase.urlString, testCase.protocol) + + if testCase.expectedError { + require.Error(t, err) + } else { + require.NoError(t, err) + require.Equal(t, testCase.expectedUrl, actualUrl) + } + }) } } func TestSanitizeHexString(t *testing.T) { testCases := []struct { + name string hash string expectedResult string }{ - // Remove leading 0x from hex string { + name: "remove leading 0x", hash: "0x1234", expectedResult: "1234", }, - // Return original hex string { + name: "return original non leading 0x", hash: "1234", expectedResult: "1234", }, - // Return original string, leading 0x is not hex { + name: "return original length not divisible by 2", hash: "0x1234g", expectedResult: "0x1234g", }, } - for i, testCase := range testCases { - actualResult := SanitizeHexString(testCase.hash) - if actualResult != testCase.expectedResult { - t.Errorf("test case %d had unexpected result. Actual: %s, Expected: %s", i, actualResult, testCase.expectedResult) - } + for _, testCase := range testCases { + t.Run(testCase.name, func(t *testing.T) { + actualResult := SanitizeHexString(testCase.hash) + require.Equal(t, testCase.expectedResult, actualResult) + }) + } +} + +func TestCheckStakeWeightExceedsThreshold(t *testing.T) { + testCases := []struct { + name string + accumulatedSignatureWeight uint64 + totalWeight uint64 + quorumNumerator uint64 + quorumDenominator uint64 + expectedResult bool + }{ + { + name: "zero case", + accumulatedSignatureWeight: 0, + totalWeight: 0, + quorumNumerator: 0, + quorumDenominator: 0, + expectedResult: true, + }, + { + name: "valid case", + accumulatedSignatureWeight: 67_000_000, + totalWeight: 100_000_000, + quorumNumerator: 67, + quorumDenominator: 100, + expectedResult: true, + }, + { + name: "invalid case", + accumulatedSignatureWeight: 66_999_999, + totalWeight: 100_000_000, + quorumNumerator: 67, + quorumDenominator: 100, + expectedResult: false, + }, + { + name: "valid 100 percent case", + accumulatedSignatureWeight: 67_000_000, + totalWeight: 67_000_000, + quorumNumerator: 100, + quorumDenominator: 100, + expectedResult: true, + }, + { + name: "invalid 100 percent case", + accumulatedSignatureWeight: 66_999_999, + totalWeight: 67_000_000, + quorumNumerator: 100, + quorumDenominator: 100, + expectedResult: false, + }, + } + for _, testCase := range testCases { + t.Run(testCase.name, func(t *testing.T) { + actualResult := CheckStakeWeightExceedsThreshold(new(big.Int).SetUint64(testCase.accumulatedSignatureWeight), testCase.totalWeight, testCase.quorumNumerator, testCase.quorumDenominator) + require.Equal(t, testCase.expectedResult, actualResult) + }) } } diff --git a/vms/destination_client.go b/vms/destination_client.go index cf66810d..1d5f88f8 100644 --- a/vms/destination_client.go +++ b/vms/destination_client.go @@ -1,6 +1,8 @@ // Copyright (C) 2023, Ava Labs, Inc. All rights reserved. // See the file LICENSE for licensing terms. +//go:generate mockgen -source=$GOFILE -destination=./mocks/mock_destination_client.go -package=mocks + package vms import ( @@ -44,8 +46,8 @@ func NewDestinationClient(logger logging.Logger, subnetInfo config.DestinationSu // CreateDestinationClients creates destination clients for all subnets configured as destinations func CreateDestinationClients(logger logging.Logger, relayerConfig config.Config) (map[ids.ID]DestinationClient, error) { destinationClients := make(map[ids.ID]DestinationClient) - for _, s := range relayerConfig.DestinationSubnets { - chainID, err := ids.FromString(s.ChainID) + for _, subnetInfo := range relayerConfig.DestinationSubnets { + chainID, err := ids.FromString(subnetInfo.ChainID) if err != nil { logger.Error( "Failed to decode base-58 encoded source chain ID", @@ -62,7 +64,7 @@ func CreateDestinationClients(logger logging.Logger, relayerConfig config.Config continue } - destinationClient, err := NewDestinationClient(logger, s) + destinationClient, err := NewDestinationClient(logger, subnetInfo) if err != nil { logger.Error( "Could not create destination client", diff --git a/vms/evm/contract_message_test.go b/vms/evm/contract_message_test.go index 96da6191..fbc50c91 100644 --- a/vms/evm/contract_message_test.go +++ b/vms/evm/contract_message_test.go @@ -13,7 +13,7 @@ import ( "github.com/ava-labs/awm-relayer/config" warpPayload "github.com/ava-labs/subnet-evm/warp/payload" "github.com/ethereum/go-ethereum/common" - "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" "go.uber.org/mock/gomock" ) @@ -47,30 +47,44 @@ func createUnsignedMessage() *warp.UnsignedMessage { } func TestUnpack(t *testing.T) { - ctrl := gomock.NewController(t) - - m := NewContractMessage(logging.NewMockLogger(ctrl), config.SourceSubnet{}) + mockLogger := logging.NewMockLogger(gomock.NewController(t)) + m := NewContractMessage(mockLogger, config.SourceSubnet{}) testCases := []struct { - input string - networkID uint32 + name string + input string + networkID uint32 + errorLogTimes int + expectError bool }{ { - input: "0000000000007fc93d85c6d62c5b2ac0b519c87010ea5294012d1e407030d6acd0021cac10d50000005200000000000027ae10273d17cd7e80de8580a51f476960626e5f0000000000000000000000000000000000000000000000000000000000000000123412341234123412341234123412341234123400000000", - networkID: 0, + name: "valid", + input: "0000000000007fc93d85c6d62c5b2ac0b519c87010ea5294012d1e407030d6acd0021cac10d50000005200000000000027ae10273d17cd7e80de8580a51f476960626e5f0000000000000000000000000000000000000000000000000000000000000000123412341234123412341234123412341234123400000000", + networkID: 0, + errorLogTimes: 0, + expectError: false, + }, + { + name: "invalid", + errorLogTimes: 1, + input: "1000000000007fc93d85c6d62c5b2ac0b519c87010ea5294012d1e407030d6acd0021cac10d50000005200000000000027ae10273d17cd7e80de8580a51f476960626e5f0000000000000000000000000000000000000000000000000000000000000000123412341234123412341234123412341234123400000000", + expectError: true, }, } for _, testCase := range testCases { - input, err := hex.DecodeString(testCase.input) - if err != nil { - t.Errorf("failed to decode test input: %v", err) - } - msg, err := m.UnpackWarpMessage(input) - if err != nil { - t.Errorf("failed to unpack message: %v", err) - } + t.Run(testCase.name, func(t *testing.T) { + input, err := hex.DecodeString(testCase.input) + require.NoError(t, err) - assert.Equal(t, testCase.networkID, msg.WarpUnsignedMessage.NetworkID) + mockLogger.EXPECT().Error(gomock.Any(), gomock.Any()).Times(testCase.errorLogTimes) + msg, err := m.UnpackWarpMessage(input) + if testCase.expectError { + require.Error(t, err) + } else { + require.NoError(t, err) + require.Equal(t, testCase.networkID, msg.WarpUnsignedMessage.NetworkID) + } + }) } } diff --git a/vms/evm/destination_client.go b/vms/evm/destination_client.go index 38452d54..56497870 100644 --- a/vms/evm/destination_client.go +++ b/vms/evm/destination_client.go @@ -1,6 +1,8 @@ // Copyright (C) 2023, Ava Labs, Inc. All rights reserved. // See the file LICENSE for licensing terms. +//go:generate mockgen -source=$GOFILE -destination=./mocks/mock_eth_client.go -package=mocks + package evm import ( @@ -29,6 +31,11 @@ const ( MaxPriorityFeePerGas = 2500000000 // 2.5 gwei ) +// Client interface wraps the ethclient.Client interface for mocking purposes. +type Client interface { + ethclient.Client +} + // Implements DestinationClient type destinationClient struct { client ethclient.Client diff --git a/vms/evm/destination_client_test.go b/vms/evm/destination_client_test.go new file mode 100644 index 00000000..b0315e5d --- /dev/null +++ b/vms/evm/destination_client_test.go @@ -0,0 +1,117 @@ +// (c) 2023, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +package evm + +import ( + "fmt" + "math/big" + "sync" + "testing" + + "github.com/ava-labs/avalanchego/utils/logging" + avalancheWarp "github.com/ava-labs/avalanchego/vms/platformvm/warp" + "github.com/ava-labs/awm-relayer/config" + mock_ethclient "github.com/ava-labs/awm-relayer/vms/evm/mocks" + "github.com/stretchr/testify/require" + "go.uber.org/mock/gomock" +) + +var destinationSubnet = config.DestinationSubnet{ + SubnetID: "2TGBXcnwx5PqiXWiqxAKUaNSqDguXNh1mxnp82jui68hxJSZAx", + ChainID: "S4mMqUXe7vHsGiRAma6bv3CKnyaLssyAxmQ2KvFpX1KEvfFCD", + VM: config.EVM.String(), + APINodeHost: "127.0.0.1", + APINodePort: 9650, + EncryptConnection: false, + RPCEndpoint: "https://subnets.avax.network/mysubnet/rpc", + AccountPrivateKey: "56289e99c94b6912bfc12adc093c9b51124f0dc54ac7a766b2bc5ccf558d8027", +} + +func TestSendTx(t *testing.T) { + ctrl := gomock.NewController(t) + mockClient := mock_ethclient.NewMockClient(ctrl) + pk, eoa, err := destinationSubnet.GetRelayerAccountInfo() + require.NoError(t, err) + + destinationClient := &destinationClient{ + lock: &sync.Mutex{}, + logger: logging.NoLog{}, + client: mockClient, + pk: pk, + eoa: eoa, + } + + testError := fmt.Errorf("call errored") + testCases := []struct { + name string + chainIDErr error + chainIDTimes int + estimateBaseFeeErr error + estimateBaseFeeTimes int + suggestGasTipCapErr error + suggestGasTipCapTimes int + sendTransactionErr error + sendTransactionTimes int + expectError bool + }{ + { + name: "valid", + chainIDTimes: 1, + estimateBaseFeeTimes: 1, + suggestGasTipCapTimes: 1, + sendTransactionTimes: 1, + }, + { + name: "invalid chainID", + chainIDErr: testError, + chainIDTimes: 1, + expectError: true, + }, + { + name: "invalid estimateBaseFee", + chainIDTimes: 1, + estimateBaseFeeErr: testError, + estimateBaseFeeTimes: 1, + expectError: true, + }, + { + name: "invalid suggestGasTipCap", + chainIDTimes: 1, + estimateBaseFeeTimes: 1, + suggestGasTipCapErr: testError, + suggestGasTipCapTimes: 1, + expectError: true, + }, + { + name: "invalid sendTransaction", + chainIDTimes: 1, + estimateBaseFeeTimes: 1, + suggestGasTipCapTimes: 1, + sendTransactionErr: testError, + sendTransactionTimes: 1, + expectError: true, + }, + } + + for _, test := range testCases { + t.Run(test.name, func(t *testing.T) { + warpMsg := &avalancheWarp.Message{} + toAddress := "0x27aE10273D17Cd7e80de8580A51f476960626e5f" + + gomock.InOrder( + mockClient.EXPECT().ChainID(gomock.Any()).Return(new(big.Int), test.chainIDErr).Times(test.chainIDTimes), + mockClient.EXPECT().EstimateBaseFee(gomock.Any()).Return(new(big.Int), test.estimateBaseFeeErr).Times(test.estimateBaseFeeTimes), + mockClient.EXPECT().SuggestGasTipCap(gomock.Any()).Return(new(big.Int), test.suggestGasTipCapErr).Times(test.suggestGasTipCapTimes), + mockClient.EXPECT().SendTransaction(gomock.Any(), gomock.Any()).Return(test.sendTransactionErr).Times(test.sendTransactionTimes), + ) + + err := destinationClient.SendTx(warpMsg, toAddress, 0, []byte{}) + if test.expectError { + require.Error(t, err) + } else { + require.NoError(t, err) + } + }) + } +} diff --git a/vms/evm/mocks/mock_eth_client.go b/vms/evm/mocks/mock_eth_client.go new file mode 100644 index 00000000..92fbf1a6 --- /dev/null +++ b/vms/evm/mocks/mock_eth_client.go @@ -0,0 +1,561 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: destination_client.go + +// Package mocks is a generated GoMock package. +package mocks + +import ( + context "context" + big "math/big" + reflect "reflect" + + ids "github.com/ava-labs/avalanchego/ids" + types "github.com/ava-labs/subnet-evm/core/types" + interfaces "github.com/ava-labs/subnet-evm/interfaces" + common "github.com/ethereum/go-ethereum/common" + gomock "go.uber.org/mock/gomock" +) + +// MockClient is a mock of Client interface. +type MockClient struct { + ctrl *gomock.Controller + recorder *MockClientMockRecorder +} + +// MockClientMockRecorder is the mock recorder for MockClient. +type MockClientMockRecorder struct { + mock *MockClient +} + +// NewMockClient creates a new mock instance. +func NewMockClient(ctrl *gomock.Controller) *MockClient { + mock := &MockClient{ctrl: ctrl} + mock.recorder = &MockClientMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockClient) EXPECT() *MockClientMockRecorder { + return m.recorder +} + +// AcceptedCallContract mocks base method. +func (m *MockClient) AcceptedCallContract(arg0 context.Context, arg1 interfaces.CallMsg) ([]byte, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "AcceptedCallContract", arg0, arg1) + ret0, _ := ret[0].([]byte) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// AcceptedCallContract indicates an expected call of AcceptedCallContract. +func (mr *MockClientMockRecorder) AcceptedCallContract(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AcceptedCallContract", reflect.TypeOf((*MockClient)(nil).AcceptedCallContract), arg0, arg1) +} + +// AcceptedCodeAt mocks base method. +func (m *MockClient) AcceptedCodeAt(arg0 context.Context, arg1 common.Address) ([]byte, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "AcceptedCodeAt", arg0, arg1) + ret0, _ := ret[0].([]byte) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// AcceptedCodeAt indicates an expected call of AcceptedCodeAt. +func (mr *MockClientMockRecorder) AcceptedCodeAt(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AcceptedCodeAt", reflect.TypeOf((*MockClient)(nil).AcceptedCodeAt), arg0, arg1) +} + +// AcceptedNonceAt mocks base method. +func (m *MockClient) AcceptedNonceAt(arg0 context.Context, arg1 common.Address) (uint64, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "AcceptedNonceAt", arg0, arg1) + ret0, _ := ret[0].(uint64) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// AcceptedNonceAt indicates an expected call of AcceptedNonceAt. +func (mr *MockClientMockRecorder) AcceptedNonceAt(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AcceptedNonceAt", reflect.TypeOf((*MockClient)(nil).AcceptedNonceAt), arg0, arg1) +} + +// AssetBalanceAt mocks base method. +func (m *MockClient) AssetBalanceAt(arg0 context.Context, arg1 common.Address, arg2 ids.ID, arg3 *big.Int) (*big.Int, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "AssetBalanceAt", arg0, arg1, arg2, arg3) + ret0, _ := ret[0].(*big.Int) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// AssetBalanceAt indicates an expected call of AssetBalanceAt. +func (mr *MockClientMockRecorder) AssetBalanceAt(arg0, arg1, arg2, arg3 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AssetBalanceAt", reflect.TypeOf((*MockClient)(nil).AssetBalanceAt), arg0, arg1, arg2, arg3) +} + +// BalanceAt mocks base method. +func (m *MockClient) BalanceAt(arg0 context.Context, arg1 common.Address, arg2 *big.Int) (*big.Int, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "BalanceAt", arg0, arg1, arg2) + ret0, _ := ret[0].(*big.Int) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// BalanceAt indicates an expected call of BalanceAt. +func (mr *MockClientMockRecorder) BalanceAt(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BalanceAt", reflect.TypeOf((*MockClient)(nil).BalanceAt), arg0, arg1, arg2) +} + +// BlockByHash mocks base method. +func (m *MockClient) BlockByHash(arg0 context.Context, arg1 common.Hash) (*types.Block, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "BlockByHash", arg0, arg1) + ret0, _ := ret[0].(*types.Block) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// BlockByHash indicates an expected call of BlockByHash. +func (mr *MockClientMockRecorder) BlockByHash(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BlockByHash", reflect.TypeOf((*MockClient)(nil).BlockByHash), arg0, arg1) +} + +// BlockByNumber mocks base method. +func (m *MockClient) BlockByNumber(arg0 context.Context, arg1 *big.Int) (*types.Block, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "BlockByNumber", arg0, arg1) + ret0, _ := ret[0].(*types.Block) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// BlockByNumber indicates an expected call of BlockByNumber. +func (mr *MockClientMockRecorder) BlockByNumber(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BlockByNumber", reflect.TypeOf((*MockClient)(nil).BlockByNumber), arg0, arg1) +} + +// BlockNumber mocks base method. +func (m *MockClient) BlockNumber(arg0 context.Context) (uint64, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "BlockNumber", arg0) + ret0, _ := ret[0].(uint64) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// BlockNumber indicates an expected call of BlockNumber. +func (mr *MockClientMockRecorder) BlockNumber(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BlockNumber", reflect.TypeOf((*MockClient)(nil).BlockNumber), arg0) +} + +// CallContract mocks base method. +func (m *MockClient) CallContract(arg0 context.Context, arg1 interfaces.CallMsg, arg2 *big.Int) ([]byte, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "CallContract", arg0, arg1, arg2) + ret0, _ := ret[0].([]byte) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// CallContract indicates an expected call of CallContract. +func (mr *MockClientMockRecorder) CallContract(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CallContract", reflect.TypeOf((*MockClient)(nil).CallContract), arg0, arg1, arg2) +} + +// CallContractAtHash mocks base method. +func (m *MockClient) CallContractAtHash(ctx context.Context, msg interfaces.CallMsg, blockHash common.Hash) ([]byte, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "CallContractAtHash", ctx, msg, blockHash) + ret0, _ := ret[0].([]byte) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// CallContractAtHash indicates an expected call of CallContractAtHash. +func (mr *MockClientMockRecorder) CallContractAtHash(ctx, msg, blockHash interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CallContractAtHash", reflect.TypeOf((*MockClient)(nil).CallContractAtHash), ctx, msg, blockHash) +} + +// ChainID mocks base method. +func (m *MockClient) ChainID(arg0 context.Context) (*big.Int, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ChainID", arg0) + ret0, _ := ret[0].(*big.Int) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ChainID indicates an expected call of ChainID. +func (mr *MockClientMockRecorder) ChainID(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ChainID", reflect.TypeOf((*MockClient)(nil).ChainID), arg0) +} + +// Close mocks base method. +func (m *MockClient) Close() { + m.ctrl.T.Helper() + m.ctrl.Call(m, "Close") +} + +// Close indicates an expected call of Close. +func (mr *MockClientMockRecorder) Close() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Close", reflect.TypeOf((*MockClient)(nil).Close)) +} + +// CodeAt mocks base method. +func (m *MockClient) CodeAt(arg0 context.Context, arg1 common.Address, arg2 *big.Int) ([]byte, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "CodeAt", arg0, arg1, arg2) + ret0, _ := ret[0].([]byte) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// CodeAt indicates an expected call of CodeAt. +func (mr *MockClientMockRecorder) CodeAt(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CodeAt", reflect.TypeOf((*MockClient)(nil).CodeAt), arg0, arg1, arg2) +} + +// EstimateBaseFee mocks base method. +func (m *MockClient) EstimateBaseFee(arg0 context.Context) (*big.Int, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "EstimateBaseFee", arg0) + ret0, _ := ret[0].(*big.Int) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// EstimateBaseFee indicates an expected call of EstimateBaseFee. +func (mr *MockClientMockRecorder) EstimateBaseFee(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EstimateBaseFee", reflect.TypeOf((*MockClient)(nil).EstimateBaseFee), arg0) +} + +// EstimateGas mocks base method. +func (m *MockClient) EstimateGas(arg0 context.Context, arg1 interfaces.CallMsg) (uint64, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "EstimateGas", arg0, arg1) + ret0, _ := ret[0].(uint64) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// EstimateGas indicates an expected call of EstimateGas. +func (mr *MockClientMockRecorder) EstimateGas(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EstimateGas", reflect.TypeOf((*MockClient)(nil).EstimateGas), arg0, arg1) +} + +// FeeHistory mocks base method. +func (m *MockClient) FeeHistory(ctx context.Context, blockCount uint64, lastBlock *big.Int, rewardPercentiles []float64) (*interfaces.FeeHistory, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "FeeHistory", ctx, blockCount, lastBlock, rewardPercentiles) + ret0, _ := ret[0].(*interfaces.FeeHistory) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// FeeHistory indicates an expected call of FeeHistory. +func (mr *MockClientMockRecorder) FeeHistory(ctx, blockCount, lastBlock, rewardPercentiles interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FeeHistory", reflect.TypeOf((*MockClient)(nil).FeeHistory), ctx, blockCount, lastBlock, rewardPercentiles) +} + +// FilterLogs mocks base method. +func (m *MockClient) FilterLogs(arg0 context.Context, arg1 interfaces.FilterQuery) ([]types.Log, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "FilterLogs", arg0, arg1) + ret0, _ := ret[0].([]types.Log) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// FilterLogs indicates an expected call of FilterLogs. +func (mr *MockClientMockRecorder) FilterLogs(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FilterLogs", reflect.TypeOf((*MockClient)(nil).FilterLogs), arg0, arg1) +} + +// HeaderByHash mocks base method. +func (m *MockClient) HeaderByHash(arg0 context.Context, arg1 common.Hash) (*types.Header, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "HeaderByHash", arg0, arg1) + ret0, _ := ret[0].(*types.Header) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// HeaderByHash indicates an expected call of HeaderByHash. +func (mr *MockClientMockRecorder) HeaderByHash(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HeaderByHash", reflect.TypeOf((*MockClient)(nil).HeaderByHash), arg0, arg1) +} + +// HeaderByNumber mocks base method. +func (m *MockClient) HeaderByNumber(arg0 context.Context, arg1 *big.Int) (*types.Header, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "HeaderByNumber", arg0, arg1) + ret0, _ := ret[0].(*types.Header) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// HeaderByNumber indicates an expected call of HeaderByNumber. +func (mr *MockClientMockRecorder) HeaderByNumber(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HeaderByNumber", reflect.TypeOf((*MockClient)(nil).HeaderByNumber), arg0, arg1) +} + +// NetworkID mocks base method. +func (m *MockClient) NetworkID(arg0 context.Context) (*big.Int, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "NetworkID", arg0) + ret0, _ := ret[0].(*big.Int) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// NetworkID indicates an expected call of NetworkID. +func (mr *MockClientMockRecorder) NetworkID(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NetworkID", reflect.TypeOf((*MockClient)(nil).NetworkID), arg0) +} + +// NonceAt mocks base method. +func (m *MockClient) NonceAt(arg0 context.Context, arg1 common.Address, arg2 *big.Int) (uint64, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "NonceAt", arg0, arg1, arg2) + ret0, _ := ret[0].(uint64) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// NonceAt indicates an expected call of NonceAt. +func (mr *MockClientMockRecorder) NonceAt(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NonceAt", reflect.TypeOf((*MockClient)(nil).NonceAt), arg0, arg1, arg2) +} + +// SendTransaction mocks base method. +func (m *MockClient) SendTransaction(arg0 context.Context, arg1 *types.Transaction) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SendTransaction", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// SendTransaction indicates an expected call of SendTransaction. +func (mr *MockClientMockRecorder) SendTransaction(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SendTransaction", reflect.TypeOf((*MockClient)(nil).SendTransaction), arg0, arg1) +} + +// StorageAt mocks base method. +func (m *MockClient) StorageAt(arg0 context.Context, arg1 common.Address, arg2 common.Hash, arg3 *big.Int) ([]byte, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "StorageAt", arg0, arg1, arg2, arg3) + ret0, _ := ret[0].([]byte) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// StorageAt indicates an expected call of StorageAt. +func (mr *MockClientMockRecorder) StorageAt(arg0, arg1, arg2, arg3 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StorageAt", reflect.TypeOf((*MockClient)(nil).StorageAt), arg0, arg1, arg2, arg3) +} + +// SubscribeFilterLogs mocks base method. +func (m *MockClient) SubscribeFilterLogs(arg0 context.Context, arg1 interfaces.FilterQuery, arg2 chan<- types.Log) (interfaces.Subscription, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SubscribeFilterLogs", arg0, arg1, arg2) + ret0, _ := ret[0].(interfaces.Subscription) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// SubscribeFilterLogs indicates an expected call of SubscribeFilterLogs. +func (mr *MockClientMockRecorder) SubscribeFilterLogs(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SubscribeFilterLogs", reflect.TypeOf((*MockClient)(nil).SubscribeFilterLogs), arg0, arg1, arg2) +} + +// SubscribeNewAcceptedTransactions mocks base method. +func (m *MockClient) SubscribeNewAcceptedTransactions(arg0 context.Context, arg1 chan<- *common.Hash) (interfaces.Subscription, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SubscribeNewAcceptedTransactions", arg0, arg1) + ret0, _ := ret[0].(interfaces.Subscription) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// SubscribeNewAcceptedTransactions indicates an expected call of SubscribeNewAcceptedTransactions. +func (mr *MockClientMockRecorder) SubscribeNewAcceptedTransactions(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SubscribeNewAcceptedTransactions", reflect.TypeOf((*MockClient)(nil).SubscribeNewAcceptedTransactions), arg0, arg1) +} + +// SubscribeNewHead mocks base method. +func (m *MockClient) SubscribeNewHead(arg0 context.Context, arg1 chan<- *types.Header) (interfaces.Subscription, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SubscribeNewHead", arg0, arg1) + ret0, _ := ret[0].(interfaces.Subscription) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// SubscribeNewHead indicates an expected call of SubscribeNewHead. +func (mr *MockClientMockRecorder) SubscribeNewHead(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SubscribeNewHead", reflect.TypeOf((*MockClient)(nil).SubscribeNewHead), arg0, arg1) +} + +// SubscribeNewPendingTransactions mocks base method. +func (m *MockClient) SubscribeNewPendingTransactions(arg0 context.Context, arg1 chan<- *common.Hash) (interfaces.Subscription, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SubscribeNewPendingTransactions", arg0, arg1) + ret0, _ := ret[0].(interfaces.Subscription) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// SubscribeNewPendingTransactions indicates an expected call of SubscribeNewPendingTransactions. +func (mr *MockClientMockRecorder) SubscribeNewPendingTransactions(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SubscribeNewPendingTransactions", reflect.TypeOf((*MockClient)(nil).SubscribeNewPendingTransactions), arg0, arg1) +} + +// SuggestGasPrice mocks base method. +func (m *MockClient) SuggestGasPrice(arg0 context.Context) (*big.Int, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SuggestGasPrice", arg0) + ret0, _ := ret[0].(*big.Int) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// SuggestGasPrice indicates an expected call of SuggestGasPrice. +func (mr *MockClientMockRecorder) SuggestGasPrice(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SuggestGasPrice", reflect.TypeOf((*MockClient)(nil).SuggestGasPrice), arg0) +} + +// SuggestGasTipCap mocks base method. +func (m *MockClient) SuggestGasTipCap(arg0 context.Context) (*big.Int, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SuggestGasTipCap", arg0) + ret0, _ := ret[0].(*big.Int) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// SuggestGasTipCap indicates an expected call of SuggestGasTipCap. +func (mr *MockClientMockRecorder) SuggestGasTipCap(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SuggestGasTipCap", reflect.TypeOf((*MockClient)(nil).SuggestGasTipCap), arg0) +} + +// SyncProgress mocks base method. +func (m *MockClient) SyncProgress(ctx context.Context) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SyncProgress", ctx) + ret0, _ := ret[0].(error) + return ret0 +} + +// SyncProgress indicates an expected call of SyncProgress. +func (mr *MockClientMockRecorder) SyncProgress(ctx interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SyncProgress", reflect.TypeOf((*MockClient)(nil).SyncProgress), ctx) +} + +// TransactionByHash mocks base method. +func (m *MockClient) TransactionByHash(arg0 context.Context, arg1 common.Hash) (*types.Transaction, bool, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "TransactionByHash", arg0, arg1) + ret0, _ := ret[0].(*types.Transaction) + ret1, _ := ret[1].(bool) + ret2, _ := ret[2].(error) + return ret0, ret1, ret2 +} + +// TransactionByHash indicates an expected call of TransactionByHash. +func (mr *MockClientMockRecorder) TransactionByHash(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TransactionByHash", reflect.TypeOf((*MockClient)(nil).TransactionByHash), arg0, arg1) +} + +// TransactionCount mocks base method. +func (m *MockClient) TransactionCount(arg0 context.Context, arg1 common.Hash) (uint, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "TransactionCount", arg0, arg1) + ret0, _ := ret[0].(uint) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// TransactionCount indicates an expected call of TransactionCount. +func (mr *MockClientMockRecorder) TransactionCount(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TransactionCount", reflect.TypeOf((*MockClient)(nil).TransactionCount), arg0, arg1) +} + +// TransactionInBlock mocks base method. +func (m *MockClient) TransactionInBlock(arg0 context.Context, arg1 common.Hash, arg2 uint) (*types.Transaction, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "TransactionInBlock", arg0, arg1, arg2) + ret0, _ := ret[0].(*types.Transaction) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// TransactionInBlock indicates an expected call of TransactionInBlock. +func (mr *MockClientMockRecorder) TransactionInBlock(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TransactionInBlock", reflect.TypeOf((*MockClient)(nil).TransactionInBlock), arg0, arg1, arg2) +} + +// TransactionReceipt mocks base method. +func (m *MockClient) TransactionReceipt(arg0 context.Context, arg1 common.Hash) (*types.Receipt, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "TransactionReceipt", arg0, arg1) + ret0, _ := ret[0].(*types.Receipt) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// TransactionReceipt indicates an expected call of TransactionReceipt. +func (mr *MockClientMockRecorder) TransactionReceipt(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TransactionReceipt", reflect.TypeOf((*MockClient)(nil).TransactionReceipt), arg0, arg1) +} + +// TransactionSender mocks base method. +func (m *MockClient) TransactionSender(arg0 context.Context, arg1 *types.Transaction, arg2 common.Hash, arg3 uint) (common.Address, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "TransactionSender", arg0, arg1, arg2, arg3) + ret0, _ := ret[0].(common.Address) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// TransactionSender indicates an expected call of TransactionSender. +func (mr *MockClientMockRecorder) TransactionSender(arg0, arg1, arg2, arg3 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TransactionSender", reflect.TypeOf((*MockClient)(nil).TransactionSender), arg0, arg1, arg2, arg3) +} diff --git a/vms/mocks/mock_destination_client.go b/vms/mocks/mock_destination_client.go new file mode 100644 index 00000000..b612cfe7 --- /dev/null +++ b/vms/mocks/mock_destination_client.go @@ -0,0 +1,93 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: destination_client.go + +// Package mocks is a generated GoMock package. +package mocks + +import ( + reflect "reflect" + + ids "github.com/ava-labs/avalanchego/ids" + warp "github.com/ava-labs/avalanchego/vms/platformvm/warp" + common "github.com/ethereum/go-ethereum/common" + gomock "go.uber.org/mock/gomock" +) + +// MockDestinationClient is a mock of DestinationClient interface. +type MockDestinationClient struct { + ctrl *gomock.Controller + recorder *MockDestinationClientMockRecorder +} + +// MockDestinationClientMockRecorder is the mock recorder for MockDestinationClient. +type MockDestinationClientMockRecorder struct { + mock *MockDestinationClient +} + +// NewMockDestinationClient creates a new mock instance. +func NewMockDestinationClient(ctrl *gomock.Controller) *MockDestinationClient { + mock := &MockDestinationClient{ctrl: ctrl} + mock.recorder = &MockDestinationClientMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockDestinationClient) EXPECT() *MockDestinationClientMockRecorder { + return m.recorder +} + +// Client mocks base method. +func (m *MockDestinationClient) Client() interface{} { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Client") + ret0, _ := ret[0].(interface{}) + return ret0 +} + +// Client indicates an expected call of Client. +func (mr *MockDestinationClientMockRecorder) Client() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Client", reflect.TypeOf((*MockDestinationClient)(nil).Client)) +} + +// DestinationChainID mocks base method. +func (m *MockDestinationClient) DestinationChainID() ids.ID { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DestinationChainID") + ret0, _ := ret[0].(ids.ID) + return ret0 +} + +// DestinationChainID indicates an expected call of DestinationChainID. +func (mr *MockDestinationClientMockRecorder) DestinationChainID() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DestinationChainID", reflect.TypeOf((*MockDestinationClient)(nil).DestinationChainID)) +} + +// SendTx mocks base method. +func (m *MockDestinationClient) SendTx(signedMessage *warp.Message, toAddress string, gasLimit uint64, callData []byte) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SendTx", signedMessage, toAddress, gasLimit, callData) + ret0, _ := ret[0].(error) + return ret0 +} + +// SendTx indicates an expected call of SendTx. +func (mr *MockDestinationClientMockRecorder) SendTx(signedMessage, toAddress, gasLimit, callData interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SendTx", reflect.TypeOf((*MockDestinationClient)(nil).SendTx), signedMessage, toAddress, gasLimit, callData) +} + +// SenderAddress mocks base method. +func (m *MockDestinationClient) SenderAddress() common.Address { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SenderAddress") + ret0, _ := ret[0].(common.Address) + return ret0 +} + +// SenderAddress indicates an expected call of SenderAddress. +func (mr *MockDestinationClientMockRecorder) SenderAddress() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SenderAddress", reflect.TypeOf((*MockDestinationClient)(nil).SenderAddress)) +}