From d11453e9ebe5cadc4751d4b933665b71e551e4aa Mon Sep 17 00:00:00 2001 From: Matthew Lam Date: Tue, 29 Aug 2023 00:53:54 +0000 Subject: [PATCH 01/14] draft for adding unit testing --- config/config_test.go | 40 +- messages/teleporter/config_test.go | 40 ++ messages/teleporter/message_test.go | 60 ++- relayer/message_relayer.go | 2 +- utils/utils.go | 17 +- utils/utils_test.go | 75 +++- vms/destination_client.go | 6 +- vms/evm/contract_message_test.go | 19 +- vms/evm/destination_client_test.go | 193 ++++++++++ vms/evm/mock/mock_eth_client.go | 561 ++++++++++++++++++++++++++++ 10 files changed, 930 insertions(+), 83 deletions(-) create mode 100644 messages/teleporter/config_test.go create mode 100644 vms/evm/destination_client_test.go create mode 100644 vms/evm/mock/mock_eth_client.go diff --git a/config/config_test.go b/config/config_test.go index 5c99b1d5..2b2beb4c 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" ) @@ -120,7 +119,7 @@ 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)) + require.Equal(t, testCase.expectedResult, res, fmt.Sprintf("test case %d failed", i)) } } @@ -184,7 +183,7 @@ func TestGetSourceSubnetWSEndpoint(t *testing.T) { for i, testCase := range testCases { res := testCase.s.GetNodeWSEndpoint() - assert.Equal(t, testCase.expectedResult, res, fmt.Sprintf("test case %d failed", i)) + require.Equal(t, testCase.expectedResult, res, fmt.Sprintf("test case %d failed", i)) } } @@ -242,10 +241,10 @@ 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)) + require.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)) + require.Equal(t, testCase.expectedResult.pk.D.Int64(), pk.D.Int64(), fmt.Sprintf("test case %d had mismatched pk", i)) + require.Equal(t, testCase.expectedResult.addr, addr, fmt.Sprintf("test case %d had mismatched address", i)) } } } @@ -263,12 +262,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)) @@ -277,13 +275,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), "unexpected config") } func TestGetRelayerAccountPrivateKey_set_pk_in_config(t *testing.T) { @@ -351,7 +348,7 @@ func TestGetRelayerAccountPrivateKey_set_pk_with_global_env(t *testing.T) { }, envSetter: func() { // Overwrite the PK for the first subnet using an env var - varName := fmt.Sprintf("%s", accountPrivateKeyEnvVarName) + varName := accountPrivateKeyEnvVarName t.Setenv(varName, testPk2) }, expectedOverwritten: true, @@ -375,3 +372,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/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_test.go b/messages/teleporter/message_test.go index 62740217..831ac517 100644 --- a/messages/teleporter/message_test.go +++ b/messages/teleporter/message_test.go @@ -10,7 +10,7 @@ import ( "testing" "github.com/ethereum/go-ethereum/common" - "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func testTeleporterMessage(messageID int64) TeleporterMessage { @@ -35,49 +35,41 @@ func testTeleporterMessage(messageID int64) TeleporterMessage { // Pack the SendCrossChainMessage event type. PackEvent is documented as not supporting struct types, so this should be used // with caution. Here, we only use it for testing purposes. In a real setting, the Teleporter contract should pack the event. -func packTeleporterMessage(destinationChainID common.Hash, message TeleporterMessage) ([]byte, error) { - _, hashes, err := EVMTeleporterContractABI.PackEvent("SendCrossChainMessage", destinationChainID, message.MessageID, message) - return hashes, err +func packSendCrossChainMessageEvent(destinationChainID common.Hash, message TeleporterMessage) ([]common.Hash, []byte, error) { + return EVMTeleporterContractABI.PackEvent("SendCrossChainMessage", destinationChainID, message.MessageID, message) } func TestPackUnpackTeleporterMessage(t *testing.T) { - message := testTeleporterMessage(4) + var ( + messageID int64 = 4 + destinationChainID = common.HexToHash("0x03") + ) + message := testTeleporterMessage(messageID) - b, err := packTeleporterMessage(common.HexToHash("0x03"), message) - if err != nil { - t.Errorf("failed to pack teleporter message: %v", err) - t.FailNow() - } + topics, b, err := packSendCrossChainMessageEvent(destinationChainID, message) + require.NoError(t, err) + + // Three events where the first event topics[0] is the event signature. + require.Equal(t, len(topics), 3) + require.Equal(t, destinationChainID, topics[1]) + require.Equal(t, new(big.Int).SetInt64(messageID), topics[2].Big()) unpacked, err := unpackTeleporterMessage(b) - if err != nil { - t.Errorf("failed to unpack teleporter message: %v", err) - t.FailNow() - } + require.NoError(t, err) + + require.Equalf(t, message.MessageID, unpacked.MessageID, "message ids do not match. expected: %d actual: %d", message.MessageID.Uint64(), unpacked.MessageID.Uint64()) + require.Equalf(t, message.SenderAddress, unpacked.SenderAddress, "sender addresses do not match. expected: %s actual: %s", message.SenderAddress.Hex(), unpacked.SenderAddress.Hex()) + require.Equal(t, message.DestinationAddress, unpacked.DestinationAddress, "destination addresses do not match. expected: %s actual: %s", message.DestinationAddress.Hex(), unpacked.DestinationAddress.Hex()) + require.Equalf(t, message.RequiredGasLimit, unpacked.RequiredGasLimit, "required gas limits do not match. expected: %d actual: %d", message.RequiredGasLimit.Uint64(), unpacked.RequiredGasLimit.Uint64()) - 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.Equalf(t, unpacked.AllowedRelayerAddresses[i], message.AllowedRelayerAddresses[i], "allowed relayer addresses %d do not match.", 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.Truef(t, bytes.Equal(message.Message, unpacked.Message), "messages do not match. expected: %s actual: %s", hex.EncodeToString(message.Message), hex.EncodeToString(unpacked.Message)) } diff --git a/relayer/message_relayer.go b/relayer/message_relayer.go index 4d6dc0af..35dd2561 100644 --- a/relayer/message_relayer.go +++ b/relayer/message_relayer.go @@ -313,7 +313,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 59dc31ba..85b71c36 100644 --- a/utils/utils.go +++ b/utils/utils.go @@ -26,8 +26,7 @@ const ( ) var ( - Uint256Max = (&big.Int{}).SetBytes(common.Hex2Bytes("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF")) - + MaxHashInputLength = 32 // Errors ErrNilInput = errors.New("nil input") ErrTooLarge = errors.New("exceeds uint256 maximum value") @@ -38,15 +37,15 @@ 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 @@ -58,16 +57,18 @@ func CheckStakeWeightExceedsThreshold(accumulatedSignatureWeight *big.Int, total // BigToHashSafe ensures that a bignum value is able to fit into a 32 byte buffer before converting it to a common.Hash // Returns an error if overflow/truncation would occur by trying to perfom this operation. +// TODO is this function still needed? It works for negative numbers now. func BigToHashSafe(in *big.Int) (common.Hash, error) { if in == nil { return common.Hash{}, ErrNilInput } - if in.Cmp(Uint256Max) > 0 { + bytes := in.Bytes() + if len(bytes) > MaxHashInputLength { 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 9b3a9156..7c09d132 100644 --- a/utils/utils_test.go +++ b/utils/utils_test.go @@ -3,7 +3,12 @@ package utils -import "testing" +import ( + "math/big" + "testing" + + "github.com/stretchr/testify/require" +) func TestConvertProtocol(t *testing.T) { testCases := []struct { @@ -46,15 +51,13 @@ 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) + + if testCase.expectedError { + require.Error(t, err, "Test case %d failed", i) + } else { + require.NoError(t, err, "Test case %d failed", i) } + require.Equal(t, testCase.expectedUrl, actualUrl, "Test case %d failed", i) } } @@ -81,8 +84,56 @@ func TestSanitizeHashString(t *testing.T) { } for i, testCase := range testCases { actualResult := SanitizeHashString(testCase.hash) - if actualResult != testCase.expectedResult { - t.Errorf("test case %d had unexpected result. Actual: %s, Expected: %s", i, actualResult, testCase.expectedResult) - } + require.Equal(t, testCase.expectedResult, actualResult, "Test case %d failed", i) + } +} + +func TestCheckStakeWeightExceedsThreshold(t *testing.T) { + testCases := []struct { + accumulatedSignatureWeight uint64 + totalWeight uint64 + quorumNumerator uint64 + quorumDenominator uint64 + expectedResult bool + }{ + { + accumulatedSignatureWeight: 0, + totalWeight: 0, + quorumNumerator: 0, + quorumDenominator: 0, + expectedResult: true, + }, + { + accumulatedSignatureWeight: 67_000_000, + totalWeight: 100_000_000, + quorumNumerator: 67, + quorumDenominator: 100, + expectedResult: true, + }, + { + accumulatedSignatureWeight: 66_999_999, + totalWeight: 100_000_000, + quorumNumerator: 67, + quorumDenominator: 100, + expectedResult: false, + }, + { + accumulatedSignatureWeight: 67_000_000, + totalWeight: 67_000_000, + quorumNumerator: 100, + quorumDenominator: 100, + expectedResult: true, + }, + { + accumulatedSignatureWeight: 66_999_999, + totalWeight: 67_000_000, + quorumNumerator: 100, + quorumDenominator: 100, + expectedResult: false, + }, + } + for i, testCase := range testCases { + actualResult := CheckStakeWeightExceedsThreshold(new(big.Int).SetUint64(testCase.accumulatedSignatureWeight), testCase.totalWeight, testCase.quorumNumerator, testCase.quorumDenominator) + require.Equal(t, testCase.expectedResult, actualResult, "Test case %d failed", i) } } diff --git a/vms/destination_client.go b/vms/destination_client.go index cec3b06b..43dbe8e3 100644 --- a/vms/destination_client.go +++ b/vms/destination_client.go @@ -38,8 +38,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", @@ -55,7 +55,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 476a45af..2536d84a 100644 --- a/vms/evm/contract_message_test.go +++ b/vms/evm/contract_message_test.go @@ -14,7 +14,7 @@ import ( warpPayload "github.com/ava-labs/subnet-evm/warp/payload" "github.com/ethereum/go-ethereum/common" "github.com/golang/mock/gomock" - "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) // Used to create a valid unsigned message for testing. Should not be used directly in tests. @@ -46,9 +46,11 @@ func createUnsignedMessage() *warp.UnsignedMessage { } func TestUnpack(t *testing.T) { - ctrl := gomock.NewController(t) + ctrl := logging.NewMockLogger(gomock.NewController(t)) - m := NewContractMessage(logging.NewMockLogger(ctrl), config.SourceSubnet{}) + m := NewContractMessage(ctrl, config.SourceSubnet{}) + + // ctrl.EXPECT().Error(nil, nil).Return(nil).AnyTimes() testCases := []struct { input string @@ -62,14 +64,11 @@ func TestUnpack(t *testing.T) { for _, testCase := range testCases { input, err := hex.DecodeString(testCase.input) - if err != nil { - t.Errorf("failed to decode test input: %v", err) - } + require.NoErrorf(t, err, "failed to decode test input: %v", err) + msg, err := m.UnpackWarpMessage(input) - if err != nil { - t.Errorf("failed to unpack message: %v", err) - } + require.NoErrorf(t, err, "failed to unpack message: %v", err) - assert.Equal(t, testCase.networkID, msg.WarpUnsignedMessage.NetworkID) + require.Equal(t, testCase.networkID, msg.WarpUnsignedMessage.NetworkID) } } diff --git a/vms/evm/destination_client_test.go b/vms/evm/destination_client_test.go new file mode 100644 index 00000000..7f38bd54 --- /dev/null +++ b/vms/evm/destination_client_test.go @@ -0,0 +1,193 @@ +// (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/ids" + "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/mock" + "github.com/ethereum/go-ethereum/common" + "github.com/golang/mock/gomock" + "github.com/stretchr/testify/require" +) + +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) + } + }) + } +} + +func TestIsAllowedRelayer(t *testing.T) { + _, eoa, err := destinationSubnet.GetRelayerAccountInfo() + require.NoError(t, err) + + tdc := &destinationClient{ + logger: logging.NoLog{}, + eoa: eoa, + } + + invalidRelayer := common.Address{1} + testCases := []struct { + name string + allowedRelayers []common.Address + expected bool + }{ + { + name: "empty allowed relayers", + allowedRelayers: []common.Address{}, + expected: true, + }, + { + name: "invalid relayer", + allowedRelayers: []common.Address{invalidRelayer}, + expected: false, + }, + { + name: "valid relayer", + allowedRelayers: []common.Address{eoa}, + expected: true, + }, + } + + for _, test := range testCases { + t.Run(test.name, func(t *testing.T) { + output := tdc.isAllowedRelayer(test.allowedRelayers) + require.Equal(t, test.expected, output) + }) + } +} + +func TestIsDestination(t *testing.T) { + validChainID := ids.ID{1, 2, 3, 4, 5, 6, 7, 8} + invalidChainID := ids.Empty + logger := logging.NoLog{} + tdc := &destinationClient{ + logger: logger, + destinationChainID: validChainID, + } + + testCases := []struct { + name string + chainID ids.ID + expected bool + }{ + { + name: "valid", + chainID: validChainID, + expected: true, + }, + { + name: "invalid", + chainID: invalidChainID, + expected: false, + }, + } + + for _, test := range testCases { + t.Run(test.name, func(t *testing.T) { + output := tdc.isDestination(test.chainID) + require.Equal(t, test.expected, output) + }) + } +} diff --git a/vms/evm/mock/mock_eth_client.go b/vms/evm/mock/mock_eth_client.go new file mode 100644 index 00000000..1295a0f3 --- /dev/null +++ b/vms/evm/mock/mock_eth_client.go @@ -0,0 +1,561 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: github.com/ava-labs/subnet-evm/ethclient (interfaces: Client) + +// Package mock_ethclient is a generated GoMock package. +package mock_ethclient + +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 "github.com/golang/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(arg0 context.Context, arg1 interfaces.CallMsg, arg2 common.Hash) ([]byte, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "CallContractAtHash", arg0, arg1, arg2) + ret0, _ := ret[0].([]byte) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// CallContractAtHash indicates an expected call of CallContractAtHash. +func (mr *MockClientMockRecorder) CallContractAtHash(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CallContractAtHash", reflect.TypeOf((*MockClient)(nil).CallContractAtHash), arg0, arg1, arg2) +} + +// 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(arg0 context.Context, arg1 uint64, arg2 *big.Int, arg3 []float64) (*interfaces.FeeHistory, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "FeeHistory", arg0, arg1, arg2, arg3) + ret0, _ := ret[0].(*interfaces.FeeHistory) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// FeeHistory indicates an expected call of FeeHistory. +func (mr *MockClientMockRecorder) FeeHistory(arg0, arg1, arg2, arg3 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FeeHistory", reflect.TypeOf((*MockClient)(nil).FeeHistory), arg0, arg1, arg2, arg3) +} + +// 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(arg0 context.Context) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SyncProgress", arg0) + ret0, _ := ret[0].(error) + return ret0 +} + +// SyncProgress indicates an expected call of SyncProgress. +func (mr *MockClientMockRecorder) SyncProgress(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SyncProgress", reflect.TypeOf((*MockClient)(nil).SyncProgress), arg0) +} + +// 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) +} From 32987d95ed82e6f52b32ac8dea066f8bf3339e65 Mon Sep 17 00:00:00 2001 From: Matthew Lam Date: Tue, 29 Aug 2023 22:01:32 +0000 Subject: [PATCH 02/14] teleporter message manager should send message tests --- config/config_test.go | 2 +- messages/mock/mock_message_manager.go | 66 ++++++++++ messages/teleporter/message_manager_test.go | 131 ++++++++++++++++++++ vms/mock/mock_destination_client.go | 65 ++++++++++ 4 files changed, 263 insertions(+), 1 deletion(-) create mode 100644 messages/mock/mock_message_manager.go create mode 100644 messages/teleporter/message_manager_test.go create mode 100644 vms/mock/mock_destination_client.go diff --git a/config/config_test.go b/config/config_test.go index 2b2beb4c..6832d225 100644 --- a/config/config_test.go +++ b/config/config_test.go @@ -38,7 +38,7 @@ var ( EncryptConnection: false, MessageContracts: map[string]MessageProtocolConfig{ testAddress: { - MessageFormat: "teleporter", + MessageFormat: TELEPORTER.String(), }, }, }, diff --git a/messages/mock/mock_message_manager.go b/messages/mock/mock_message_manager.go new file mode 100644 index 00000000..86a59c1c --- /dev/null +++ b/messages/mock/mock_message_manager.go @@ -0,0 +1,66 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: ./message_manager.go + +// Package mock_messages is a generated GoMock package. +package mock_messages + +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/message_manager_test.go b/messages/teleporter/message_manager_test.go new file mode 100644 index 00000000..dfc91b96 --- /dev/null +++ b/messages/teleporter/message_manager_test.go @@ -0,0 +1,131 @@ +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_vms "github.com/ava-labs/awm-relayer/vms/mock" + "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" + validTeleporterMessage = TeleporterMessage{ + MessageID: big.NewInt(1), + SenderAddress: common.HexToAddress("0x0123456789abcdef0123456789abcdef01234567"), + DestinationAddress: common.HexToAddress("0x0123456789abcdef0123456789abcdef01234567"), + RequiredGasLimit: big.NewInt(2), + AllowedRelayerAddresses: []common.Address{ + common.HexToAddress("0x0123456789abcdef0123456789abcdef01234567"), + }, + 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) + + warpUnsignedMessage, err := warp.NewUnsignedMessage(0, ids.Empty, validMessageBytes) + require.NoError(t, err) + testCases := []struct { + name string + destinationChainID ids.ID + warpMessageInfo *vmtypes.WarpMessageInfo + allowedResult bool + allowedTimes int + expectedError bool + expectedResult bool + }{ + { + name: "valid message", + destinationChainID: destinationChainID, + warpMessageInfo: &vmtypes.WarpMessageInfo{ + WarpUnsignedMessage: warpUnsignedMessage, + WarpPayload: validMessageBytes, + }, + allowedResult: true, + allowedTimes: 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, + }, + allowedResult: false, + allowedTimes: 1, + expectedResult: false, + }, + } + for _, test := range testCases { + t.Run(test.name, func(t *testing.T) { + mockClient.EXPECT().Allowed(gomock.Any(), gomock.Any()).Return(test.allowedResult).Times(test.allowedTimes) + 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/vms/mock/mock_destination_client.go b/vms/mock/mock_destination_client.go new file mode 100644 index 00000000..8d4651aa --- /dev/null +++ b/vms/mock/mock_destination_client.go @@ -0,0 +1,65 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: ./destination_client.go + +// Package mock_vms is a generated GoMock package. +package mock_vms + +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 +} + +// Allowed mocks base method. +func (m *MockDestinationClient) Allowed(chainID ids.ID, allowedRelayers []common.Address) bool { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Allowed", chainID, allowedRelayers) + ret0, _ := ret[0].(bool) + return ret0 +} + +// Allowed indicates an expected call of Allowed. +func (mr *MockDestinationClientMockRecorder) Allowed(chainID, allowedRelayers interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Allowed", reflect.TypeOf((*MockDestinationClient)(nil).Allowed), chainID, allowedRelayers) +} + +// 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) +} From 0ca7dc96f9f05d6cd8e922b5064adf2694c6e415 Mon Sep 17 00:00:00 2001 From: Matthew Lam Date: Fri, 1 Sep 2023 17:54:46 +0000 Subject: [PATCH 03/14] remove commented code --- vms/evm/contract_message_test.go | 3 --- 1 file changed, 3 deletions(-) diff --git a/vms/evm/contract_message_test.go b/vms/evm/contract_message_test.go index 05ab91fb..8116c96b 100644 --- a/vms/evm/contract_message_test.go +++ b/vms/evm/contract_message_test.go @@ -47,11 +47,8 @@ func createUnsignedMessage() *warp.UnsignedMessage { func TestUnpack(t *testing.T) { ctrl := logging.NewMockLogger(gomock.NewController(t)) - m := NewContractMessage(ctrl, config.SourceSubnet{}) - // ctrl.EXPECT().Error(nil, nil).Return(nil).AnyTimes() - testCases := []struct { input string networkID uint32 From 4f33eae095e92c4309e45d4d58c41b4c49562f81 Mon Sep 17 00:00:00 2001 From: Matthew Lam Date: Wed, 6 Sep 2023 00:08:45 +0000 Subject: [PATCH 04/14] add license and rename to mocks --- messages/teleporter/message_manager_test.go | 5 ++++- vms/destination_client.go | 2 ++ vms/{mock => mocks}/mock_destination_client.go | 0 3 files changed, 6 insertions(+), 1 deletion(-) rename vms/{mock => mocks}/mock_destination_client.go (100%) diff --git a/messages/teleporter/message_manager_test.go b/messages/teleporter/message_manager_test.go index dfc91b96..17fbb40b 100644 --- a/messages/teleporter/message_manager_test.go +++ b/messages/teleporter/message_manager_test.go @@ -1,3 +1,6 @@ +// Copyright (C) 2023, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + package teleporter import ( @@ -9,7 +12,7 @@ import ( "github.com/ava-labs/avalanchego/vms/platformvm/warp" "github.com/ava-labs/awm-relayer/config" "github.com/ava-labs/awm-relayer/vms" - mock_vms "github.com/ava-labs/awm-relayer/vms/mock" + 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" diff --git a/vms/destination_client.go b/vms/destination_client.go index 43dbe8e3..ec5c7480 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=./mock/mock_destination_client.go -package=mocks + package vms import ( diff --git a/vms/mock/mock_destination_client.go b/vms/mocks/mock_destination_client.go similarity index 100% rename from vms/mock/mock_destination_client.go rename to vms/mocks/mock_destination_client.go From b9349fcfaac60f12cd10969fdc363f74e5de417d Mon Sep 17 00:00:00 2001 From: Matthew Lam Date: Wed, 6 Sep 2023 00:31:35 +0000 Subject: [PATCH 05/14] create wrapper interface for mock and use go generates --- go.mod | 2 +- messages/message_manager.go | 2 ++ .../{mock => mocks}/mock_message_manager.go | 6 ++-- vms/destination_client.go | 2 +- vms/evm/destination_client.go | 7 ++++ vms/evm/destination_client_test.go | 4 +-- vms/evm/{mock => mocks}/mock_eth_client.go | 32 +++++++++---------- vms/mocks/mock_destination_client.go | 6 ++-- 8 files changed, 35 insertions(+), 26 deletions(-) rename messages/{mock => mocks}/mock_message_manager.go (95%) rename vms/evm/{mock => mocks}/mock_eth_client.go (94%) diff --git a/go.mod b/go.mod index bbe4297d..91ca888c 100644 --- a/go.mod +++ b/go.mod @@ -11,6 +11,7 @@ require ( github.com/spf13/pflag v1.0.5 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 ) @@ -36,7 +37,6 @@ require ( github.com/spf13/cast v1.5.1 // indirect github.com/spf13/jwalterweatherman v1.1.0 // indirect github.com/subosito/gotenv v1.4.2 // indirect - go.uber.org/mock v0.2.0 // indirect golang.org/x/exp v0.0.0-20230206171751-46f607a40771 // indirect gopkg.in/ini.v1 v1.67.0 // indirect ) diff --git a/messages/message_manager.go b/messages/message_manager.go index 3a7601e6..ea83e8a0 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/mock/mock_message_manager.go b/messages/mocks/mock_message_manager.go similarity index 95% rename from messages/mock/mock_message_manager.go rename to messages/mocks/mock_message_manager.go index 86a59c1c..eba2032f 100644 --- a/messages/mock/mock_message_manager.go +++ b/messages/mocks/mock_message_manager.go @@ -1,8 +1,8 @@ // Code generated by MockGen. DO NOT EDIT. -// Source: ./message_manager.go +// Source: message_manager.go -// Package mock_messages is a generated GoMock package. -package mock_messages +// Package mocks is a generated GoMock package. +package mocks import ( reflect "reflect" diff --git a/vms/destination_client.go b/vms/destination_client.go index ec5c7480..9ea00997 100644 --- a/vms/destination_client.go +++ b/vms/destination_client.go @@ -1,7 +1,7 @@ // Copyright (C) 2023, Ava Labs, Inc. All rights reserved. // See the file LICENSE for licensing terms. -//go:generate mockgen -source=$GOFILE -destination=./mock/mock_destination_client.go -package=mocks +//go:generate mockgen -source=$GOFILE -destination=./mocks/mock_destination_client.go -package=mocks package vms diff --git a/vms/evm/destination_client.go b/vms/evm/destination_client.go index 57ade4ce..4a746060 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 index 7f38bd54..14403ab2 100644 --- a/vms/evm/destination_client_test.go +++ b/vms/evm/destination_client_test.go @@ -13,10 +13,10 @@ import ( "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/mock" + mock_ethclient "github.com/ava-labs/awm-relayer/vms/evm/mocks" "github.com/ethereum/go-ethereum/common" - "github.com/golang/mock/gomock" "github.com/stretchr/testify/require" + "go.uber.org/mock/gomock" ) var destinationSubnet = config.DestinationSubnet{ diff --git a/vms/evm/mock/mock_eth_client.go b/vms/evm/mocks/mock_eth_client.go similarity index 94% rename from vms/evm/mock/mock_eth_client.go rename to vms/evm/mocks/mock_eth_client.go index 1295a0f3..92fbf1a6 100644 --- a/vms/evm/mock/mock_eth_client.go +++ b/vms/evm/mocks/mock_eth_client.go @@ -1,8 +1,8 @@ // Code generated by MockGen. DO NOT EDIT. -// Source: github.com/ava-labs/subnet-evm/ethclient (interfaces: Client) +// Source: destination_client.go -// Package mock_ethclient is a generated GoMock package. -package mock_ethclient +// Package mocks is a generated GoMock package. +package mocks import ( context "context" @@ -13,7 +13,7 @@ import ( 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 "github.com/golang/mock/gomock" + gomock "go.uber.org/mock/gomock" ) // MockClient is a mock of Client interface. @@ -175,18 +175,18 @@ func (mr *MockClientMockRecorder) CallContract(arg0, arg1, arg2 interface{}) *go } // CallContractAtHash mocks base method. -func (m *MockClient) CallContractAtHash(arg0 context.Context, arg1 interfaces.CallMsg, arg2 common.Hash) ([]byte, error) { +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", arg0, arg1, arg2) + 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(arg0, arg1, arg2 interface{}) *gomock.Call { +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), arg0, arg1, arg2) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CallContractAtHash", reflect.TypeOf((*MockClient)(nil).CallContractAtHash), ctx, msg, blockHash) } // ChainID mocks base method. @@ -262,18 +262,18 @@ func (mr *MockClientMockRecorder) EstimateGas(arg0, arg1 interface{}) *gomock.Ca } // FeeHistory mocks base method. -func (m *MockClient) FeeHistory(arg0 context.Context, arg1 uint64, arg2 *big.Int, arg3 []float64) (*interfaces.FeeHistory, error) { +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", arg0, arg1, arg2, arg3) + 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(arg0, arg1, arg2, arg3 interface{}) *gomock.Call { +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), arg0, arg1, arg2, arg3) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FeeHistory", reflect.TypeOf((*MockClient)(nil).FeeHistory), ctx, blockCount, lastBlock, rewardPercentiles) } // FilterLogs mocks base method. @@ -471,17 +471,17 @@ func (mr *MockClientMockRecorder) SuggestGasTipCap(arg0 interface{}) *gomock.Cal } // SyncProgress mocks base method. -func (m *MockClient) SyncProgress(arg0 context.Context) error { +func (m *MockClient) SyncProgress(ctx context.Context) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "SyncProgress", arg0) + ret := m.ctrl.Call(m, "SyncProgress", ctx) ret0, _ := ret[0].(error) return ret0 } // SyncProgress indicates an expected call of SyncProgress. -func (mr *MockClientMockRecorder) SyncProgress(arg0 interface{}) *gomock.Call { +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), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SyncProgress", reflect.TypeOf((*MockClient)(nil).SyncProgress), ctx) } // TransactionByHash mocks base method. diff --git a/vms/mocks/mock_destination_client.go b/vms/mocks/mock_destination_client.go index 8d4651aa..2a0b4fbf 100644 --- a/vms/mocks/mock_destination_client.go +++ b/vms/mocks/mock_destination_client.go @@ -1,8 +1,8 @@ // Code generated by MockGen. DO NOT EDIT. -// Source: ./destination_client.go +// Source: destination_client.go -// Package mock_vms is a generated GoMock package. -package mock_vms +// Package mocks is a generated GoMock package. +package mocks import ( reflect "reflect" From 6647e82cfec83a67cecc256f0ce03b65e987eb7f Mon Sep 17 00:00:00 2001 From: Matthew Lam Date: Wed, 6 Sep 2023 00:34:21 +0000 Subject: [PATCH 06/14] add to README about generating mocks --- README.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/README.md b/README.md index 5e2536b4..6492e5b6 100644 --- a/README.md +++ b/README.md @@ -37,3 +37,15 @@ The relayer consists of the following components:
+ +## Testing + +--- + +### 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 ./... +``` \ No newline at end of file From f5a8c4dae6a5ebf810dbc85f60c51d113a73a569 Mon Sep 17 00:00:00 2001 From: Matthew Lam Date: Wed, 6 Sep 2023 00:50:05 +0000 Subject: [PATCH 07/14] clean up go mod --- go.mod | 1 - go.sum | 3 --- utils/utils.go | 6 ++---- 3 files changed, 2 insertions(+), 8 deletions(-) diff --git a/go.mod b/go.mod index 91ca888c..97992a62 100644 --- a/go.mod +++ b/go.mod @@ -6,7 +6,6 @@ require ( github.com/ava-labs/avalanchego v1.10.9 github.com/ava-labs/subnet-evm v0.5.4 github.com/ethereum/go-ethereum v1.12.0 - github.com/golang/mock v1.6.0 github.com/prometheus/client_golang v1.16.0 github.com/spf13/pflag v1.0.5 github.com/spf13/viper v1.16.0 diff --git a/go.sum b/go.sum index cc461fb8..532aaf38 100644 --- a/go.sum +++ b/go.sum @@ -217,8 +217,6 @@ github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= -github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= -github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -818,7 +816,6 @@ golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4f golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= -golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= 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= diff --git a/utils/utils.go b/utils/utils.go index 85b71c36..f12deeb8 100644 --- a/utils/utils.go +++ b/utils/utils.go @@ -26,7 +26,6 @@ const ( ) var ( - MaxHashInputLength = 32 // Errors ErrNilInput = errors.New("nil input") ErrTooLarge = errors.New("exceeds uint256 maximum value") @@ -47,8 +46,7 @@ func CheckStakeWeightExceedsThreshold(accumulatedSignatureWeight *big.Int, total 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 } // @@ -64,7 +62,7 @@ func BigToHashSafe(in *big.Int) (common.Hash, error) { } bytes := in.Bytes() - if len(bytes) > MaxHashInputLength { + if len(bytes) > common.HashLength { return common.Hash{}, ErrTooLarge } From 6e99847ba24188c55dd7693fc8c4a87d29d4fb21 Mon Sep 17 00:00:00 2001 From: Matthew Lam Date: Fri, 8 Sep 2023 17:28:27 +0000 Subject: [PATCH 08/14] remove extra logs on require checks --- config/config_test.go | 3 +-- messages/teleporter/message_test.go | 17 ++++++++--------- vms/evm/contract_message_test.go | 4 ++-- 3 files changed, 11 insertions(+), 13 deletions(-) diff --git a/config/config_test.go b/config/config_test.go index 6832d225..7325a7f3 100644 --- a/config/config_test.go +++ b/config/config_test.go @@ -348,8 +348,7 @@ func TestGetRelayerAccountPrivateKey_set_pk_with_global_env(t *testing.T) { }, envSetter: func() { // Overwrite the PK for the first subnet using an env var - varName := accountPrivateKeyEnvVarName - t.Setenv(varName, testPk2) + t.Setenv(accountPrivateKeyEnvVarName, testPk2) }, expectedOverwritten: true, resultVerifier: func(c Config) bool { diff --git a/messages/teleporter/message_test.go b/messages/teleporter/message_test.go index 831ac517..b17bf2c9 100644 --- a/messages/teleporter/message_test.go +++ b/messages/teleporter/message_test.go @@ -5,7 +5,6 @@ package teleporter import ( "bytes" - "encoding/hex" "math/big" "testing" @@ -41,8 +40,8 @@ func packSendCrossChainMessageEvent(destinationChainID common.Hash, message Tele func TestPackUnpackTeleporterMessage(t *testing.T) { var ( - messageID int64 = 4 - destinationChainID = common.HexToHash("0x03") + messageID int64 = 4 + destinationChainID common.Hash = common.HexToHash("0x03") ) message := testTeleporterMessage(messageID) @@ -57,13 +56,13 @@ func TestPackUnpackTeleporterMessage(t *testing.T) { unpacked, err := unpackTeleporterMessage(b) require.NoError(t, err) - require.Equalf(t, message.MessageID, unpacked.MessageID, "message ids do not match. expected: %d actual: %d", message.MessageID.Uint64(), unpacked.MessageID.Uint64()) - require.Equalf(t, message.SenderAddress, unpacked.SenderAddress, "sender addresses do not match. expected: %s actual: %s", message.SenderAddress.Hex(), unpacked.SenderAddress.Hex()) - require.Equal(t, message.DestinationAddress, unpacked.DestinationAddress, "destination addresses do not match. expected: %s actual: %s", message.DestinationAddress.Hex(), unpacked.DestinationAddress.Hex()) - require.Equalf(t, message.RequiredGasLimit, unpacked.RequiredGasLimit, "required gas limits do not match. expected: %d actual: %d", message.RequiredGasLimit.Uint64(), unpacked.RequiredGasLimit.Uint64()) + require.Equal(t, message.MessageID, unpacked.MessageID) + require.Equal(t, message.SenderAddress, unpacked.SenderAddress) + require.Equal(t, message.DestinationAddress, unpacked.DestinationAddress) + require.Equal(t, message.RequiredGasLimit, unpacked.RequiredGasLimit) for i := 0; i < len(message.AllowedRelayerAddresses); i++ { - require.Equalf(t, unpacked.AllowedRelayerAddresses[i], message.AllowedRelayerAddresses[i], "allowed relayer addresses %d do not match.", i) + require.Equal(t, unpacked.AllowedRelayerAddresses[i], message.AllowedRelayerAddresses[i]) } for i := 0; i < len(message.Receipts); i++ { @@ -71,5 +70,5 @@ func TestPackUnpackTeleporterMessage(t *testing.T) { require.Equal(t, message.Receipts[i].RelayerRewardAddress, unpacked.Receipts[i].RelayerRewardAddress) } - require.Truef(t, bytes.Equal(message.Message, unpacked.Message), "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/vms/evm/contract_message_test.go b/vms/evm/contract_message_test.go index 8116c96b..0e24c61f 100644 --- a/vms/evm/contract_message_test.go +++ b/vms/evm/contract_message_test.go @@ -61,10 +61,10 @@ func TestUnpack(t *testing.T) { for _, testCase := range testCases { input, err := hex.DecodeString(testCase.input) - require.NoErrorf(t, err, "failed to decode test input: %v", err) + require.NoError(t, err) msg, err := m.UnpackWarpMessage(input) - require.NoErrorf(t, err, "failed to unpack message: %v", err) + require.NoError(t, err) require.Equal(t, testCase.networkID, msg.WarpUnsignedMessage.NetworkID) } From c4b2c0607a2fb24f2d5aebcfb5d3cedfcc4803e3 Mon Sep 17 00:00:00 2001 From: Matthew Lam Date: Fri, 8 Sep 2023 17:39:53 +0000 Subject: [PATCH 09/14] clean up logging test id --- config/config_test.go | 28 +++++++++++++++++----------- utils/utils_test.go | 29 ++++++++++++++++++----------- 2 files changed, 35 insertions(+), 22 deletions(-) diff --git a/config/config_test.go b/config/config_test.go index 7325a7f3..a58194aa 100644 --- a/config/config_test.go +++ b/config/config_test.go @@ -118,8 +118,10 @@ func TestGetDestinationRPCEndpoint(t *testing.T) { } for i, testCase := range testCases { - res := testCase.s.GetNodeRPCEndpoint() - require.Equal(t, testCase.expectedResult, res, fmt.Sprintf("test case %d failed", i)) + t.Run(fmt.Sprintf("test_%d", i), func(t *testing.T) { + res := testCase.s.GetNodeRPCEndpoint() + require.Equal(t, testCase.expectedResult, res) + }) } } @@ -182,8 +184,10 @@ func TestGetSourceSubnetWSEndpoint(t *testing.T) { } for i, testCase := range testCases { - res := testCase.s.GetNodeWSEndpoint() - require.Equal(t, testCase.expectedResult, res, fmt.Sprintf("test case %d failed", i)) + t.Run(fmt.Sprintf("test_%d", i), func(t *testing.T) { + res := testCase.s.GetNodeWSEndpoint() + require.Equal(t, testCase.expectedResult, res) + }) } } @@ -240,12 +244,14 @@ func TestGetRelayerAccountInfo(t *testing.T) { } for i, testCase := range testCases { - pk, addr, err := testCase.s.GetRelayerAccountInfo() - require.Equal(t, testCase.expectedResult.err, err, fmt.Sprintf("test case %d had unexpected error", i)) - if err == nil { - require.Equal(t, testCase.expectedResult.pk.D.Int64(), pk.D.Int64(), fmt.Sprintf("test case %d had mismatched pk", i)) - require.Equal(t, testCase.expectedResult.addr, addr, fmt.Sprintf("test case %d had mismatched address", i)) - } + t.Run(fmt.Sprintf("test_%d", i), 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) + } + }) } } @@ -280,7 +286,7 @@ func runGetRelayerAccountPrivateKeyTest(t *testing.T, testCase getRelayerAccount require.NoError(t, err) require.Equal(t, optionOverwritten, testCase.expectedOverwritten) - require.True(t, testCase.resultVerifier(parsedCfg), "unexpected config") + require.True(t, testCase.resultVerifier(parsedCfg)) } func TestGetRelayerAccountPrivateKey_set_pk_in_config(t *testing.T) { diff --git a/utils/utils_test.go b/utils/utils_test.go index 7c09d132..160fe71f 100644 --- a/utils/utils_test.go +++ b/utils/utils_test.go @@ -4,6 +4,7 @@ package utils import ( + "fmt" "math/big" "testing" @@ -50,14 +51,16 @@ func TestConvertProtocol(t *testing.T) { } for i, testCase := range testCases { - actualUrl, err := ConvertProtocol(testCase.urlString, testCase.protocol) + t.Run(fmt.Sprintf("test_%d", i), func(t *testing.T) { + actualUrl, err := ConvertProtocol(testCase.urlString, testCase.protocol) - if testCase.expectedError { - require.Error(t, err, "Test case %d failed", i) - } else { - require.NoError(t, err, "Test case %d failed", i) - } - require.Equal(t, testCase.expectedUrl, actualUrl, "Test case %d failed", i) + if testCase.expectedError { + require.Error(t, err) + } else { + require.NoError(t, err) + } + require.Equal(t, testCase.expectedUrl, actualUrl) + }) } } @@ -83,8 +86,10 @@ func TestSanitizeHashString(t *testing.T) { }, } for i, testCase := range testCases { - actualResult := SanitizeHashString(testCase.hash) - require.Equal(t, testCase.expectedResult, actualResult, "Test case %d failed", i) + t.Run(fmt.Sprintf("test_%d", i), func(t *testing.T) { + actualResult := SanitizeHashString(testCase.hash) + require.Equal(t, testCase.expectedResult, actualResult) + }) } } @@ -133,7 +138,9 @@ func TestCheckStakeWeightExceedsThreshold(t *testing.T) { }, } for i, testCase := range testCases { - actualResult := CheckStakeWeightExceedsThreshold(new(big.Int).SetUint64(testCase.accumulatedSignatureWeight), testCase.totalWeight, testCase.quorumNumerator, testCase.quorumDenominator) - require.Equal(t, testCase.expectedResult, actualResult, "Test case %d failed", i) + t.Run(fmt.Sprintf("test_%d", i), func(t *testing.T) { + actualResult := CheckStakeWeightExceedsThreshold(new(big.Int).SetUint64(testCase.accumulatedSignatureWeight), testCase.totalWeight, testCase.quorumNumerator, testCase.quorumDenominator) + require.Equal(t, testCase.expectedResult, actualResult) + }) } } From 1619aa74d400bc97e9e5b1b5137ed6500460d29e Mon Sep 17 00:00:00 2001 From: Matthew Lam Date: Wed, 20 Sep 2023 19:10:04 +0000 Subject: [PATCH 10/14] fixing unit tests --- go.mod | 2 +- messages/teleporter/message.go | 6 +- messages/teleporter/message_manager_test.go | 66 ++++++++++++++---- vms/evm/destination_client_test.go | 76 --------------------- 4 files changed, 57 insertions(+), 93 deletions(-) diff --git a/go.mod b/go.mod index 97992a62..2689cb97 100644 --- a/go.mod +++ b/go.mod @@ -6,6 +6,7 @@ require ( github.com/ava-labs/avalanchego v1.10.9 github.com/ava-labs/subnet-evm v0.5.4 github.com/ethereum/go-ethereum v1.12.0 + github.com/pkg/errors v0.9.1 github.com/prometheus/client_golang v1.16.0 github.com/spf13/pflag v1.0.5 github.com/spf13/viper v1.16.0 @@ -30,7 +31,6 @@ require ( github.com/magiconair/properties v1.8.7 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/pelletier/go-toml/v2 v2.0.8 // indirect - github.com/pkg/errors v0.9.1 // indirect github.com/rogpeppe/go-internal v1.9.0 // indirect github.com/spf13/afero v1.9.5 // indirect github.com/spf13/cast v1.5.1 // indirect diff --git a/messages/teleporter/message.go b/messages/teleporter/message.go index 7729b394..a2f41af0 100644 --- a/messages/teleporter/message.go +++ b/messages/teleporter/message.go @@ -38,7 +38,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"` } @@ -73,6 +73,10 @@ func packMessageReceivedMessage(inputStruct MessageReceivedInput) ([]byte, error return EVMTeleporterContractABI.Pack("messageReceived", inputStruct.OriginChainID, inputStruct.MessageID) } +func packMessageReceivedOutput(success bool) ([]byte, error) { + return EVMTeleporterContractABI.PackOutput("messageReceived", success) +} + func unpackMessageReceivedResult(result []byte) (bool, error) { var success bool err := EVMTeleporterContractABI.UnpackIntoInterface(&success, "messageReceived", result) diff --git a/messages/teleporter/message_manager_test.go b/messages/teleporter/message_manager_test.go index 17fbb40b..54eb2d6b 100644 --- a/messages/teleporter/message_manager_test.go +++ b/messages/teleporter/message_manager_test.go @@ -12,6 +12,7 @@ import ( "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" @@ -28,13 +29,14 @@ var ( }, } 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{ - common.HexToAddress("0x0123456789abcdef0123456789abcdef01234567"), + validRelayerAddress, }, Receipts: []TeleporterMessageReceipt{ { @@ -56,6 +58,7 @@ func TestShouldSendMessage(t *testing.T) { destinationClients := map[ids.ID]vms.DestinationClient{ destinationChainID: mockClient, } + messageManager, err := NewMessageManager( logger, messageProtocolAddress, @@ -67,16 +70,26 @@ func TestShouldSendMessage(t *testing.T) { _, 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 - allowedResult bool - allowedTimes int - expectedError bool - expectedResult bool + 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", @@ -85,9 +98,13 @@ func TestShouldSendMessage(t *testing.T) { WarpUnsignedMessage: warpUnsignedMessage, WarpPayload: validMessageBytes, }, - allowedResult: true, - allowedTimes: 1, - expectedResult: true, + senderAddressResult: validRelayerAddress, + senderAddressTimes: 1, + clientResult: mock_evm.NewMockClient(ctrl), + clientTimes: 1, + callContractResult: messageNotDelivered, + callContractTimes: 1, + expectedResult: true, }, { name: "invalid message", @@ -114,14 +131,33 @@ func TestShouldSendMessage(t *testing.T) { WarpUnsignedMessage: warpUnsignedMessage, WarpPayload: validMessageBytes, }, - allowedResult: false, - allowedTimes: 1, - expectedResult: false, + 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().Allowed(gomock.Any(), gomock.Any()).Return(test.allowedResult).Times(test.allowedTimes) + 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) diff --git a/vms/evm/destination_client_test.go b/vms/evm/destination_client_test.go index 14403ab2..b0315e5d 100644 --- a/vms/evm/destination_client_test.go +++ b/vms/evm/destination_client_test.go @@ -9,12 +9,10 @@ import ( "sync" "testing" - "github.com/ava-labs/avalanchego/ids" "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/ethereum/go-ethereum/common" "github.com/stretchr/testify/require" "go.uber.org/mock/gomock" ) @@ -117,77 +115,3 @@ func TestSendTx(t *testing.T) { }) } } - -func TestIsAllowedRelayer(t *testing.T) { - _, eoa, err := destinationSubnet.GetRelayerAccountInfo() - require.NoError(t, err) - - tdc := &destinationClient{ - logger: logging.NoLog{}, - eoa: eoa, - } - - invalidRelayer := common.Address{1} - testCases := []struct { - name string - allowedRelayers []common.Address - expected bool - }{ - { - name: "empty allowed relayers", - allowedRelayers: []common.Address{}, - expected: true, - }, - { - name: "invalid relayer", - allowedRelayers: []common.Address{invalidRelayer}, - expected: false, - }, - { - name: "valid relayer", - allowedRelayers: []common.Address{eoa}, - expected: true, - }, - } - - for _, test := range testCases { - t.Run(test.name, func(t *testing.T) { - output := tdc.isAllowedRelayer(test.allowedRelayers) - require.Equal(t, test.expected, output) - }) - } -} - -func TestIsDestination(t *testing.T) { - validChainID := ids.ID{1, 2, 3, 4, 5, 6, 7, 8} - invalidChainID := ids.Empty - logger := logging.NoLog{} - tdc := &destinationClient{ - logger: logger, - destinationChainID: validChainID, - } - - testCases := []struct { - name string - chainID ids.ID - expected bool - }{ - { - name: "valid", - chainID: validChainID, - expected: true, - }, - { - name: "invalid", - chainID: invalidChainID, - expected: false, - }, - } - - for _, test := range testCases { - t.Run(test.name, func(t *testing.T) { - output := tdc.isDestination(test.chainID) - require.Equal(t, test.expected, output) - }) - } -} From 70caea1d1a973ec9483128b38d4e12984e7f0812 Mon Sep 17 00:00:00 2001 From: Matthew Lam Date: Wed, 20 Sep 2023 19:29:56 +0000 Subject: [PATCH 11/14] add error case unit test --- messages/teleporter/message_manager_test.go | 2 +- utils/utils_test.go | 2 +- vms/evm/contract_message_test.go | 42 +++++++++++++++------ 3 files changed, 32 insertions(+), 14 deletions(-) diff --git a/messages/teleporter/message_manager_test.go b/messages/teleporter/message_manager_test.go index 54eb2d6b..da62f4e8 100644 --- a/messages/teleporter/message_manager_test.go +++ b/messages/teleporter/message_manager_test.go @@ -163,8 +163,8 @@ func TestShouldSendMessage(t *testing.T) { require.Error(t, err) } else { require.NoError(t, err) + require.Equal(t, test.expectedResult, result) } - require.Equal(t, test.expectedResult, result) }) } } diff --git a/utils/utils_test.go b/utils/utils_test.go index 160fe71f..f8b5b151 100644 --- a/utils/utils_test.go +++ b/utils/utils_test.go @@ -58,8 +58,8 @@ func TestConvertProtocol(t *testing.T) { require.Error(t, err) } else { require.NoError(t, err) + require.Equal(t, testCase.expectedUrl, actualUrl) } - require.Equal(t, testCase.expectedUrl, actualUrl) }) } } diff --git a/vms/evm/contract_message_test.go b/vms/evm/contract_message_test.go index 7c34cfa5..fbc50c91 100644 --- a/vms/evm/contract_message_test.go +++ b/vms/evm/contract_message_test.go @@ -47,26 +47,44 @@ func createUnsignedMessage() *warp.UnsignedMessage { } func TestUnpack(t *testing.T) { - ctrl := logging.NewMockLogger(gomock.NewController(t)) - m := NewContractMessage(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) - require.NoError(t, err) - - msg, err := m.UnpackWarpMessage(input) - require.NoError(t, err) + t.Run(testCase.name, func(t *testing.T) { + input, err := hex.DecodeString(testCase.input) + require.NoError(t, err) - require.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) + } + }) } } From d4c9f5ed7e5554129f8a5de9ea85c015692e5573 Mon Sep 17 00:00:00 2001 From: Matthew Lam Date: Wed, 20 Sep 2023 19:48:13 +0000 Subject: [PATCH 12/14] add testcase names --- config/config_test.go | 31 ++++++++++++++++++++++--------- utils/utils_test.go | 32 ++++++++++++++++++++++---------- 2 files changed, 44 insertions(+), 19 deletions(-) diff --git a/config/config_test.go b/config/config_test.go index c04038cd..7c2a1a71 100644 --- a/config/config_test.go +++ b/config/config_test.go @@ -61,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", @@ -75,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", @@ -85,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", @@ -95,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", @@ -105,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", @@ -117,8 +123,8 @@ func TestGetDestinationRPCEndpoint(t *testing.T) { }, } - for i, testCase := range testCases { - t.Run(fmt.Sprintf("test_%d", i), func(t *testing.T) { + for _, testCase := range testCases { + t.Run(testCase.name, func(t *testing.T) { res := testCase.s.GetNodeRPCEndpoint() require.Equal(t, testCase.expectedResult, res) }) @@ -127,11 +133,13 @@ func TestGetDestinationRPCEndpoint(t *testing.T) { 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", @@ -143,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", @@ -154,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", @@ -165,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", @@ -176,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", @@ -190,8 +202,8 @@ func TestGetSourceSubnetEndpoints(t *testing.T) { }, } - for i, testCase := range testCases { - t.Run(fmt.Sprintf("test_%d", i), func(t *testing.T) { + 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()) }) @@ -206,11 +218,12 @@ func TestGetRelayerAccountInfo(t *testing.T) { } testCases := []struct { + name string s DestinationSubnet expectedResult retStruct }{ - // valid { + name: "valid", s: DestinationSubnet{ AccountPrivateKey: "56289e99c94b6912bfc12adc093c9b51124f0dc54ac7a766b2bc5ccf558d8027", }, @@ -222,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", }, @@ -235,8 +248,8 @@ func TestGetRelayerAccountInfo(t *testing.T) { err: ErrInvalidPrivateKey, }, }, - // invalid { + name: "invalid private key", s: DestinationSubnet{ AccountPrivateKey: "invalid56289e99c94b6912bfc12adc093c9b51124f0dc54ac7a766b2bc5ccf558d8027", }, @@ -250,8 +263,8 @@ func TestGetRelayerAccountInfo(t *testing.T) { }, } - for i, testCase := range testCases { - t.Run(fmt.Sprintf("test_%d", i), func(t *testing.T) { + 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 { diff --git a/utils/utils_test.go b/utils/utils_test.go index f8b5b151..c83a7193 100644 --- a/utils/utils_test.go +++ b/utils/utils_test.go @@ -4,7 +4,6 @@ package utils import ( - "fmt" "math/big" "testing" @@ -13,36 +12,42 @@ import ( 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: "", @@ -50,8 +55,8 @@ func TestConvertProtocol(t *testing.T) { }, } - for i, testCase := range testCases { - t.Run(fmt.Sprintf("test_%d", i), func(t *testing.T) { + for _, testCase := range testCases { + t.Run(testCase.name, func(t *testing.T) { actualUrl, err := ConvertProtocol(testCase.urlString, testCase.protocol) if testCase.expectedError { @@ -66,27 +71,28 @@ func TestConvertProtocol(t *testing.T) { func TestSanitizeHashString(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 { - t.Run(fmt.Sprintf("test_%d", i), func(t *testing.T) { + for _, testCase := range testCases { + t.Run(testCase.name, func(t *testing.T) { actualResult := SanitizeHashString(testCase.hash) require.Equal(t, testCase.expectedResult, actualResult) }) @@ -95,6 +101,7 @@ func TestSanitizeHashString(t *testing.T) { func TestCheckStakeWeightExceedsThreshold(t *testing.T) { testCases := []struct { + name string accumulatedSignatureWeight uint64 totalWeight uint64 quorumNumerator uint64 @@ -102,6 +109,7 @@ func TestCheckStakeWeightExceedsThreshold(t *testing.T) { expectedResult bool }{ { + name: "zero case", accumulatedSignatureWeight: 0, totalWeight: 0, quorumNumerator: 0, @@ -109,6 +117,7 @@ func TestCheckStakeWeightExceedsThreshold(t *testing.T) { expectedResult: true, }, { + name: "valid case", accumulatedSignatureWeight: 67_000_000, totalWeight: 100_000_000, quorumNumerator: 67, @@ -116,6 +125,7 @@ func TestCheckStakeWeightExceedsThreshold(t *testing.T) { expectedResult: true, }, { + name: "invalid case", accumulatedSignatureWeight: 66_999_999, totalWeight: 100_000_000, quorumNumerator: 67, @@ -123,6 +133,7 @@ func TestCheckStakeWeightExceedsThreshold(t *testing.T) { expectedResult: false, }, { + name: "valid 100 percent case", accumulatedSignatureWeight: 67_000_000, totalWeight: 67_000_000, quorumNumerator: 100, @@ -130,6 +141,7 @@ func TestCheckStakeWeightExceedsThreshold(t *testing.T) { expectedResult: true, }, { + name: "invalid 100 percent case", accumulatedSignatureWeight: 66_999_999, totalWeight: 67_000_000, quorumNumerator: 100, @@ -137,8 +149,8 @@ func TestCheckStakeWeightExceedsThreshold(t *testing.T) { expectedResult: false, }, } - for i, testCase := range testCases { - t.Run(fmt.Sprintf("test_%d", i), func(t *testing.T) { + 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) }) From 46381f391ac5af045f3e2136994a0ea04ea8fd16 Mon Sep 17 00:00:00 2001 From: Matthew Lam Date: Fri, 22 Sep 2023 17:20:58 +0000 Subject: [PATCH 13/14] remove TODO --- utils/utils.go | 1 - 1 file changed, 1 deletion(-) diff --git a/utils/utils.go b/utils/utils.go index f12deeb8..992df19f 100644 --- a/utils/utils.go +++ b/utils/utils.go @@ -55,7 +55,6 @@ func CheckStakeWeightExceedsThreshold(accumulatedSignatureWeight *big.Int, total // BigToHashSafe ensures that a bignum value is able to fit into a 32 byte buffer before converting it to a common.Hash // Returns an error if overflow/truncation would occur by trying to perfom this operation. -// TODO is this function still needed? It works for negative numbers now. func BigToHashSafe(in *big.Int) (common.Hash, error) { if in == nil { return common.Hash{}, ErrNilInput From 412f95b862b025da131d94e7e0fc40b9d3f51394 Mon Sep 17 00:00:00 2001 From: Matthew Lam Date: Fri, 22 Sep 2023 20:00:10 +0000 Subject: [PATCH 14/14] clean up readme --- README.md | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 6492e5b6..2d574749 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,14 +42,13 @@ The relayer consists of the following components: - *Destination RPC client*: broadcasts transactions to the destination ### Data flow +
## Testing ---- - ### 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: