From 77d644a7db7650b3e8c504929476636c73ad264e Mon Sep 17 00:00:00 2001 From: Felipe Madero Date: Wed, 28 Aug 2024 17:19:49 -0300 Subject: [PATCH 01/19] nit --- examples/{subnet_ multisig.go => subnet_multisig.go} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename examples/{subnet_ multisig.go => subnet_multisig.go} (100%) diff --git a/examples/subnet_ multisig.go b/examples/subnet_multisig.go similarity index 100% rename from examples/subnet_ multisig.go rename to examples/subnet_multisig.go From 9162bc82dea9b08f09d2b2f076440d81371382d6 Mon Sep 17 00:00:00 2001 From: Felipe Madero Date: Wed, 28 Aug 2024 21:38:05 -0300 Subject: [PATCH 02/19] adding teleporter deploy --- examples/interchain.go | 54 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 examples/interchain.go diff --git a/examples/interchain.go b/examples/interchain.go new file mode 100644 index 0000000..6327fbe --- /dev/null +++ b/examples/interchain.go @@ -0,0 +1,54 @@ +// Copyright (C) 2024, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +package main + +import ( + "fmt" + "os" + + "github.com/ava-labs/avalanche-tooling-sdk-go/interchain/icm" +) + +func fatal(err error) { + fmt.Println(err) + os.Exit(1) +} + +func main() { + icmVersion, err := icm.GetLatestVersion() + if err != nil { + fatal(err) + } + td := icm.Deployer{} + if err := td.DownloadAssets(icmVersion); err != nil { + fatal(err) + } + chain1MessengerAlreadyDeployed, chain1MessengerAddress, chain1RegistryAddress, err := td.Deploy( + os.Getenv("CHAIN1_RPC"), + os.Getenv("CHAIN1_PK"), + true, + true, + ) + if err != nil { + fatal(err) + } + chain2MessengerAlreadyDeployed, chain2MessengerAddress, chain2RegistryAddress, err := td.Deploy( + os.Getenv("CHAIN2_RPC"), + os.Getenv("CHAIN2_PK"), + true, + true, + ) + if err != nil { + fatal(err) + } + chain1RegistryAddress = "0x4bC756894C6CB10A5735816E25132486F5a1cE8f" + chain2RegistryAddress = "0x302a91b43d974Cd6f12f4Eae8cADBc8efB7359c8" + fmt.Println(chain1MessengerAlreadyDeployed) + fmt.Println(chain1MessengerAddress) + fmt.Println(chain1RegistryAddress) + fmt.Println(chain2MessengerAlreadyDeployed) + fmt.Println(chain2MessengerAddress) + fmt.Println(chain2RegistryAddress) + +} From e2857c16767caf4f71847b590192fcce5fb3e2c6 Mon Sep 17 00:00:00 2001 From: Felipe Madero Date: Wed, 28 Aug 2024 22:21:09 -0300 Subject: [PATCH 03/19] nit --- examples/interchain.go | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/examples/interchain.go b/examples/interchain.go index 6327fbe..433389d 100644 --- a/examples/interchain.go +++ b/examples/interchain.go @@ -6,8 +6,13 @@ package main import ( "fmt" "os" + "path/filepath" + "github.com/ava-labs/avalanche-tooling-sdk-go/avalanche" "github.com/ava-labs/avalanche-tooling-sdk-go/interchain/icm" + "github.com/ava-labs/avalanche-tooling-sdk-go/interchain/relayer" + "github.com/ava-labs/avalanche-tooling-sdk-go/utils" + "github.com/ava-labs/avalanchego/utils/logging" ) func fatal(err error) { @@ -51,4 +56,23 @@ func main() { fmt.Println(chain2MessengerAddress) fmt.Println(chain2RegistryAddress) + network := avalanche.FujiNetwork() + + relayerDir := os.Getenv("RELAYER_DIR") + if relayerDir == "" { + fatal(fmt.Errorf("must define RELAYER_DIR env var")) + } + relayerDir = utils.ExpandHome(relayerDir) + if !utils.DirectoryExists(relayerDir) { + fatal(fmt.Errorf("relayer directory %q does not exits", relayerDir)) + } + + relayerConfig := relayer.CreateBaseRelayerConfig( + logging.Info.LowerString(), + filepath.Join(relayerDir, "storage"), + 0, + network, + ) + fmt.Printf("%#v\n", relayerConfig) + } From 3557b0a2efc50d67de02434a05279a1e99487deb Mon Sep 17 00:00:00 2001 From: Felipe Madero Date: Wed, 28 Aug 2024 22:48:40 -0300 Subject: [PATCH 04/19] adding relayer conf generation --- examples/interchain.go | 98 ++++++++++++++++++++++++++++++++---------- 1 file changed, 75 insertions(+), 23 deletions(-) diff --git a/examples/interchain.go b/examples/interchain.go index 433389d..88e5280 100644 --- a/examples/interchain.go +++ b/examples/interchain.go @@ -11,60 +11,88 @@ import ( "github.com/ava-labs/avalanche-tooling-sdk-go/avalanche" "github.com/ava-labs/avalanche-tooling-sdk-go/interchain/icm" "github.com/ava-labs/avalanche-tooling-sdk-go/interchain/relayer" + "github.com/ava-labs/avalanche-tooling-sdk-go/key" "github.com/ava-labs/avalanche-tooling-sdk-go/utils" + "github.com/ava-labs/avalanchego/ids" "github.com/ava-labs/avalanchego/utils/logging" ) -func fatal(err error) { - fmt.Println(err) - os.Exit(1) -} - func main() { icmVersion, err := icm.GetLatestVersion() if err != nil { - fatal(err) + panic(err) } td := icm.Deployer{} if err := td.DownloadAssets(icmVersion); err != nil { - fatal(err) + panic(err) } + chain1RPC := os.Getenv("CHAIN1_RPC") + chain1PK := os.Getenv("CHAIN1_PK") + chain2RPC := os.Getenv("CHAIN2_RPC") + chain2PK := os.Getenv("CHAIN2_PK") chain1MessengerAlreadyDeployed, chain1MessengerAddress, chain1RegistryAddress, err := td.Deploy( - os.Getenv("CHAIN1_RPC"), - os.Getenv("CHAIN1_PK"), + chain1RPC, + chain1PK, true, true, ) if err != nil { - fatal(err) + panic(err) + } + if !chain1MessengerAlreadyDeployed { + panic(fmt.Errorf("icm already deployed to %s", chain1RPC)) } chain2MessengerAlreadyDeployed, chain2MessengerAddress, chain2RegistryAddress, err := td.Deploy( - os.Getenv("CHAIN2_RPC"), - os.Getenv("CHAIN2_PK"), + chain2RPC, + chain2PK, true, true, ) if err != nil { - fatal(err) + panic(err) } + if !chain2MessengerAlreadyDeployed { + panic(fmt.Errorf("icm already deployed to %s", chain2RPC)) + } + chain1RegistryAddress = "0x4bC756894C6CB10A5735816E25132486F5a1cE8f" chain2RegistryAddress = "0x302a91b43d974Cd6f12f4Eae8cADBc8efB7359c8" - fmt.Println(chain1MessengerAlreadyDeployed) - fmt.Println(chain1MessengerAddress) - fmt.Println(chain1RegistryAddress) - fmt.Println(chain2MessengerAlreadyDeployed) - fmt.Println(chain2MessengerAddress) - fmt.Println(chain2RegistryAddress) network := avalanche.FujiNetwork() relayerDir := os.Getenv("RELAYER_DIR") if relayerDir == "" { - fatal(fmt.Errorf("must define RELAYER_DIR env var")) + panic(fmt.Errorf("must define RELAYER_DIR env var")) } relayerDir = utils.ExpandHome(relayerDir) if !utils.DirectoryExists(relayerDir) { - fatal(fmt.Errorf("relayer directory %q does not exits", relayerDir)) + panic(fmt.Errorf("relayer directory %q does not exits", relayerDir)) + } + + chain1RelayerKey, err := key.NewSoft() + if err != nil { + panic(err) + } + chain2RelayerKey, err := key.NewSoft() + if err != nil { + panic(err) + } + + chain1SubnetID, err := ids.FromString(os.Getenv("CHAIN1_SUBNET_ID")) + if err != nil { + panic(err) + } + chain1BlockchainID, err := ids.FromString(os.Getenv("CHAIN1_BLOCKCHAIN_ID")) + if err != nil { + panic(err) + } + chain2SubnetID, err := ids.FromString(os.Getenv("CHAIN2_SUBNET_ID")) + if err != nil { + panic(err) + } + chain2BlockchainID, err := ids.FromString(os.Getenv("CHAIN2_BLOCKCHAIN_ID")) + if err != nil { + panic(err) } relayerConfig := relayer.CreateBaseRelayerConfig( @@ -73,6 +101,30 @@ func main() { 0, network, ) - fmt.Printf("%#v\n", relayerConfig) - + relayer.AddBlockchainToRelayerConfig( + relayerConfig, + chain1RPC, + "", + chain1SubnetID, + chain1BlockchainID, + chain1RegistryAddress, + chain1MessengerAddress, + chain1RelayerKey.C(), + chain1RelayerKey.PrivKeyHex(), + ) + relayer.AddBlockchainToRelayerConfig( + relayerConfig, + chain2RPC, + "", + chain2SubnetID, + chain2BlockchainID, + chain2RegistryAddress, + chain2MessengerAddress, + chain2RelayerKey.C(), + chain2RelayerKey.PrivKeyHex(), + ) + relayerConfigPath := filepath.Join(relayerDir, "config.json") + if err := relayer.SaveRelayerConfig(relayerConfig, relayerConfigPath); err != nil { + panic(err) + } } From 3cd17ddd8c06140a82662d19f10c29ffe2cdf2b5 Mon Sep 17 00:00:00 2001 From: Felipe Madero Date: Thu, 29 Aug 2024 00:51:42 -0300 Subject: [PATCH 05/19] add funding to relayer --- examples/interchain.go | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/examples/interchain.go b/examples/interchain.go index 88e5280..4f1b532 100644 --- a/examples/interchain.go +++ b/examples/interchain.go @@ -127,4 +127,40 @@ func main() { if err := relayer.SaveRelayerConfig(relayerConfig, relayerConfigPath); err != nil { panic(err) } + + if err := relayer.FundRelayer( + relayerConfig, + chain1BlockchainID, + chain1PK, + nil, + nil, + ); err != nil { + panic(err) + } + if err := relayer.FundRelayer( + relayerConfig, + chain2BlockchainID, + chain2PK, + nil, + nil, + ); err != nil { + panic(err) + } + + binPath, err := relayer.InstallLatest(relayerDir, "") + if err != nil { + panic(err) + } + + relayerLogPath := filepath.Join(relayerDir, "log.json") + + pid, err := relayer.Execute(binPath, relayerConfigPath, relayerLogPath, "") + if err != nil { + if bs, err := os.ReadFile(relayerLogPath); err == nil { + fmt.Println(string(bs)) + } + panic(err) + } + + fmt.Println(pid) } From 061fa269def49c5602a658fd5565bb3e3a40f3a3 Mon Sep 17 00:00:00 2001 From: Felipe Madero Date: Thu, 29 Aug 2024 12:23:26 -0300 Subject: [PATCH 06/19] set example for interchain --- examples/interchain.go | 193 +++++++++++++++++++++++++++--------- interchain/icm/msg.go | 170 +++++++++++++++++++++++++++++++ interchain/relayer/conf.go | 6 +- interchain/relayer/local.go | 46 +++++++++ 4 files changed, 363 insertions(+), 52 deletions(-) create mode 100644 interchain/icm/msg.go diff --git a/examples/interchain.go b/examples/interchain.go index 4f1b532..ca5e3e4 100644 --- a/examples/interchain.go +++ b/examples/interchain.go @@ -5,31 +5,102 @@ package main import ( "fmt" + "math/big" "os" "path/filepath" "github.com/ava-labs/avalanche-tooling-sdk-go/avalanche" + "github.com/ava-labs/avalanche-tooling-sdk-go/evm" "github.com/ava-labs/avalanche-tooling-sdk-go/interchain/icm" "github.com/ava-labs/avalanche-tooling-sdk-go/interchain/relayer" "github.com/ava-labs/avalanche-tooling-sdk-go/key" "github.com/ava-labs/avalanche-tooling-sdk-go/utils" "github.com/ava-labs/avalanchego/ids" "github.com/ava-labs/avalanchego/utils/logging" + "github.com/ethereum/go-ethereum/common" ) func main() { - icmVersion, err := icm.GetLatestVersion() - if err != nil { - panic(err) - } - td := icm.Deployer{} - if err := td.DownloadAssets(icmVersion); err != nil { + if err := CallInterchainExample(); err != nil { panic(err) } +} + +// Fuji ICM Example +// +// Deploys ICM into CHAIN1_RPC and CHAIN2_RPC, +// paying deploy fees with CHAIN1_PK and CHAIN2_PK +// +// Downloads and executes a relayer in a local process +// and sets it to listen to CHAIN1 and CHAIN2. +// Subnet IDs and Blockchain IDs are provided to fullfill +// relayer conf +// +// All relayer data is saved into RELAYER_DIR, that must +// exist beforehand +func CallInterchainExample() error { chain1RPC := os.Getenv("CHAIN1_RPC") chain1PK := os.Getenv("CHAIN1_PK") + chain1SubnetID, err := ids.FromString(os.Getenv("CHAIN1_SUBNET_ID")) + if err != nil { + return err + } + chain1BlockchainID, err := ids.FromString(os.Getenv("CHAIN1_BLOCKCHAIN_ID")) + if err != nil { + return err + } chain2RPC := os.Getenv("CHAIN2_RPC") chain2PK := os.Getenv("CHAIN2_PK") + chain2SubnetID, err := ids.FromString(os.Getenv("CHAIN2_SUBNET_ID")) + if err != nil { + return err + } + chain2BlockchainID, err := ids.FromString(os.Getenv("CHAIN2_BLOCKCHAIN_ID")) + if err != nil { + return err + } + relayerDir := os.Getenv("RELAYER_DIR") + if relayerDir == "" { + return fmt.Errorf("must define RELAYER_DIR env var") + } + relayerDir = utils.ExpandHome(relayerDir) + if !utils.DirectoryExists(relayerDir) { + return fmt.Errorf("relayer directory %q must exist", relayerDir) + } + return InterchainExample( + avalanche.FujiNetwork(), + chain1RPC, + chain1PK, + chain1SubnetID, + chain1BlockchainID, + chain2RPC, + chain2PK, + chain2SubnetID, + chain2BlockchainID, + relayerDir, + ) +} + +func InterchainExample( + network avalanche.Network, + chain1RPC string, + chain1PK string, + chain1SubnetID ids.ID, + chain1BlockchainID ids.ID, + chain2RPC string, + chain2PK string, + chain2SubnetID ids.ID, + chain2BlockchainID ids.ID, + relayerDir string, +) error { + icmVersion, err := icm.GetLatestVersion() + if err != nil { + return err + } + td := icm.Deployer{} + if err := td.DownloadAssets(icmVersion); err != nil { + return err + } chain1MessengerAlreadyDeployed, chain1MessengerAddress, chain1RegistryAddress, err := td.Deploy( chain1RPC, chain1PK, @@ -37,10 +108,10 @@ func main() { true, ) if err != nil { - panic(err) + return err } if !chain1MessengerAlreadyDeployed { - panic(fmt.Errorf("icm already deployed to %s", chain1RPC)) + return fmt.Errorf("icm already deployed to %s", chain1RPC) } chain2MessengerAlreadyDeployed, chain2MessengerAddress, chain2RegistryAddress, err := td.Deploy( chain2RPC, @@ -49,55 +120,29 @@ func main() { true, ) if err != nil { - panic(err) + return err } if !chain2MessengerAlreadyDeployed { - panic(fmt.Errorf("icm already deployed to %s", chain2RPC)) + return fmt.Errorf("icm already deployed to %s", chain2RPC) } chain1RegistryAddress = "0x4bC756894C6CB10A5735816E25132486F5a1cE8f" chain2RegistryAddress = "0x302a91b43d974Cd6f12f4Eae8cADBc8efB7359c8" - network := avalanche.FujiNetwork() - - relayerDir := os.Getenv("RELAYER_DIR") - if relayerDir == "" { - panic(fmt.Errorf("must define RELAYER_DIR env var")) - } - relayerDir = utils.ExpandHome(relayerDir) - if !utils.DirectoryExists(relayerDir) { - panic(fmt.Errorf("relayer directory %q does not exits", relayerDir)) - } - chain1RelayerKey, err := key.NewSoft() if err != nil { - panic(err) + return err } chain2RelayerKey, err := key.NewSoft() if err != nil { - panic(err) + return err } - chain1SubnetID, err := ids.FromString(os.Getenv("CHAIN1_SUBNET_ID")) - if err != nil { - panic(err) - } - chain1BlockchainID, err := ids.FromString(os.Getenv("CHAIN1_BLOCKCHAIN_ID")) - if err != nil { - panic(err) - } - chain2SubnetID, err := ids.FromString(os.Getenv("CHAIN2_SUBNET_ID")) - if err != nil { - panic(err) - } - chain2BlockchainID, err := ids.FromString(os.Getenv("CHAIN2_BLOCKCHAIN_ID")) - if err != nil { - panic(err) - } + relayerStorageDir := filepath.Join(relayerDir, "storage") relayerConfig := relayer.CreateBaseRelayerConfig( logging.Info.LowerString(), - filepath.Join(relayerDir, "storage"), + relayerStorageDir, 0, network, ) @@ -125,31 +170,33 @@ func main() { ) relayerConfigPath := filepath.Join(relayerDir, "config.json") if err := relayer.SaveRelayerConfig(relayerConfig, relayerConfigPath); err != nil { - panic(err) + return err } + desiredRelayerBalance := big.NewInt(0).Mul(big.NewInt(1e18), big.NewInt(10)) // 10 TOKENS + if err := relayer.FundRelayer( relayerConfig, chain1BlockchainID, chain1PK, nil, - nil, + desiredRelayerBalance, ); err != nil { - panic(err) + return err } if err := relayer.FundRelayer( relayerConfig, chain2BlockchainID, chain2PK, nil, - nil, + desiredRelayerBalance, ); err != nil { - panic(err) + return err } binPath, err := relayer.InstallLatest(relayerDir, "") if err != nil { - panic(err) + return err } relayerLogPath := filepath.Join(relayerDir, "log.json") @@ -159,8 +206,58 @@ func main() { if bs, err := os.ReadFile(relayerLogPath); err == nil { fmt.Println(string(bs)) } - panic(err) + return err + } + + if err := relayer.WaitForInitialization(relayerConfigPath, relayerLogPath, 0, 0); err != nil { + return err + } + + message := "hello world" + encodedMessage := []byte("hello world") + tx, receipt, err := icm.SendCrossChainMessage( + chain1RPC, + common.HexToAddress(chain1MessengerAddress), + chain1PK, + chain2BlockchainID, + common.Address{}, + encodedMessage, + ) + if err != nil { + return err + } + if err == evm.ErrFailedReceiptStatus { + txHash := tx.Hash().String() + trace, err := evm.GetTrace(chain1RPC, txHash) + if err != nil { + fmt.Printf("error obtaining tx trace: %s\n", err) + } else { + fmt.Printf("trace: %#v\n", trace) + } + return fmt.Errorf("source receipt status for tx %s is not ReceiptStatusSuccessful", txHash) + } + + event, err := evm.GetEventFromLogs(receipt.Logs, icm.ParseSendCrossChainMessage) + if err != nil { + return err + } + + if chain2BlockchainID != ids.ID(event.DestinationBlockchainID[:]) { + return fmt.Errorf("invalid destination blockchain id at source event, expected %s, got %s", chain2BlockchainID, ids.ID(event.DestinationBlockchainID[:])) + } + if message != string(event.Message.Message) { + return fmt.Errorf("invalid message content at source event, expected %s, got %s", message, string(event.Message.Message)) + } + + if err := icm.WaitForMessageReception( + chain2RPC, + chain2MessengerAddress, + event.MessageID, + 0, + 0, + ); err != nil { + return err } - fmt.Println(pid) + return relayer.Cleanup(pid, "", relayerStorageDir) } diff --git a/interchain/icm/msg.go b/interchain/icm/msg.go new file mode 100644 index 0000000..390b270 --- /dev/null +++ b/interchain/icm/msg.go @@ -0,0 +1,170 @@ +// Copyright (C) 2022, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. +package icm + +import ( + "fmt" + "math/big" + "time" + + "github.com/ava-labs/avalanche-tooling-sdk-go/evm" + "github.com/ava-labs/avalanchego/ids" + "github.com/ava-labs/subnet-evm/core/types" + "github.com/ethereum/go-ethereum/common" +) + +func GetNextMessageID( + rpcURL string, + messengerAddress common.Address, + destinationBlockchainID ids.ID, +) (ids.ID, error) { + out, err := evm.CallToMethod( + rpcURL, + messengerAddress, + "getNextMessageID(bytes32)->(bytes32)", + destinationBlockchainID, + ) + if err != nil { + return ids.Empty, err + } + received, b := out[0].([32]byte) + if !b { + return ids.Empty, fmt.Errorf("error at getNextMessageID call, expected ids.ID, got %T", out[0]) + } + return received, nil +} + +func MessageReceived( + rpcURL string, + messengerAddress common.Address, + messageID ids.ID, +) (bool, error) { + out, err := evm.CallToMethod( + rpcURL, + messengerAddress, + "messageReceived(bytes32)->(bool)", + messageID, + ) + if err != nil { + return false, err + } + received, b := out[0].(bool) + if !b { + return false, fmt.Errorf("error at messageReceived call, expected bool, got %T", out[0]) + } + return received, nil +} + +func WaitForMessageReception( + rpcEndpoint string, + messengerAddress string, + messageID ids.ID, + checkInterval time.Duration, + checkTimeout time.Duration, +) error { + if checkInterval == 0 { + checkInterval = 100 * time.Millisecond + } + if checkTimeout == 0 { + checkTimeout = 10 * time.Second + } + t0 := time.Now() + for { + if b, err := MessageReceived( + rpcEndpoint, + common.HexToAddress(messengerAddress), + messageID, + ); err != nil { + return err + } else if b { + break + } + elapsed := time.Since(t0) + if elapsed > checkTimeout { + return fmt.Errorf("timeout waiting for icm message id %s to be received", messageID.String()) + } + time.Sleep(checkInterval) + } + return nil +} + +func SendCrossChainMessage( + rpcURL string, + messengerAddress common.Address, + privateKey string, + destinationBlockchainID ids.ID, + destinationAddress common.Address, + message []byte, +) (*types.Transaction, *types.Receipt, error) { + type FeeInfo struct { + FeeTokenAddress common.Address + Amount *big.Int + } + type Params struct { + DestinationBlockchainID [32]byte + DestinationAddress common.Address + FeeInfo FeeInfo + RequiredGasLimit *big.Int + AllowedRelayerAddresses []common.Address + Message []byte + } + params := Params{ + DestinationBlockchainID: destinationBlockchainID, + DestinationAddress: destinationAddress, + FeeInfo: FeeInfo{ + FeeTokenAddress: common.Address{}, + Amount: big.NewInt(0), + }, + RequiredGasLimit: big.NewInt(1), + AllowedRelayerAddresses: []common.Address{}, + Message: message, + } + return evm.TxToMethod( + rpcURL, + privateKey, + messengerAddress, + nil, + "sendCrossChainMessage((bytes32, address, (address, uint256), uint256, [address], bytes))->(bytes32)", + params, + ) +} + +// events + +type TeleporterMessageReceipt struct { + ReceivedMessageNonce *big.Int + RelayerRewardAddress common.Address +} +type TeleporterFeeInfo struct { + FeeTokenAddress common.Address + Amount *big.Int +} +type TeleporterMessage struct { + MessageNonce *big.Int + OriginSenderAddress common.Address + DestinationBlockchainID [32]byte + DestinationAddress common.Address + RequiredGasLimit *big.Int + AllowedRelayerAddresses []common.Address + Receipts []TeleporterMessageReceipt + Message []byte +} +type TeleporterMessengerSendCrossChainMessage struct { + MessageID [32]byte + DestinationBlockchainID [32]byte + Message TeleporterMessage + FeeInfo TeleporterFeeInfo +} + +func ParseSendCrossChainMessage(log types.Log) (*TeleporterMessengerSendCrossChainMessage, error) { + event := new(TeleporterMessengerSendCrossChainMessage) + if err := evm.UnpackLog( + "SendCrossChainMessage(bytes32,bytes32,(uint256,address,bytes32,address,uint256,[address],[(uint256,address)],bytes),(address,uint256))", + []int{0, 1}, + log, + event, + ); err != nil { + return nil, err + } + return event, nil +} diff --git a/interchain/relayer/conf.go b/interchain/relayer/conf.go index 617a4dd..b21dec6 100644 --- a/interchain/relayer/conf.go +++ b/interchain/relayer/conf.go @@ -19,8 +19,6 @@ import ( "github.com/ethereum/go-ethereum/crypto" ) -var defaultRequiredBalance = big.NewInt(0).Mul(big.NewInt(1e18), big.NewInt(500)) // 500 AVAX - func GetSourceConfig( relayerConfig *config.Config, blockchainID ids.ID, @@ -109,8 +107,8 @@ func FundRelayerAddress( amount *big.Int, requiredMinBalance *big.Int, ) error { - if requiredMinBalance == nil { - requiredMinBalance = defaultRequiredBalance + if amount == nil && requiredMinBalance == nil { + return fmt.Errorf("failure funding relayer: you must provide an amount or a required balance") } client, err := evm.GetClient(rpcEndpoint) if err != nil { diff --git a/interchain/relayer/local.go b/interchain/relayer/local.go index 0a47bcc..1db318c 100644 --- a/interchain/relayer/local.go +++ b/interchain/relayer/local.go @@ -76,6 +76,52 @@ func Execute( return process.Execute(binPath, args, logWriter, logWriter, runFilePath, localRelayerSetupTime) } +func WaitForInitialization( + configPath string, + logPath string, + checkInterval time.Duration, + checkTimeout time.Duration, +) error { + config, err := LoadRelayerConfig(configPath) + if err != nil { + return err + } + sourceBlockchains := []string{} + for _, source := range config.SourceBlockchains { + sourceBlockchains = append(sourceBlockchains, source.BlockchainID) + } + if checkInterval == 0 { + checkInterval = 100 * time.Millisecond + } + if checkTimeout == 0 { + checkTimeout = 10 * time.Second + } + t0 := time.Now() + for { + bs, err := os.ReadFile(logPath) + if err != nil { + return err + } + sourcesInitialized := 0 + for _, l := range strings.Split(string(bs), "\n") { + for _, sourceBlockchain := range sourceBlockchains { + if strings.Contains(l, "Listener initialized") && strings.Contains(l, sourceBlockchain) { + sourcesInitialized++ + } + } + } + if sourcesInitialized == len(sourceBlockchains) { + break + } + elapsed := time.Since(t0) + if elapsed > checkTimeout { + return fmt.Errorf("timeout waiting for relayer initialization") + } + time.Sleep(checkInterval) + } + return nil +} + func IsRunning(pid int, runFilePath string) (bool, int, *os.Process, error) { return process.IsRunning(pid, runFilePath) } From da38867d6ce52eef2d14d5f53c8e6eb2b3269cf9 Mon Sep 17 00:00:00 2001 From: Felipe Madero Date: Thu, 29 Aug 2024 14:40:39 -0300 Subject: [PATCH 07/19] refactors --- examples/interchain.go | 230 +++++++++++++----- interchain/icm/icm.go | 30 +-- .../localrelayer.go} | 5 +- 3 files changed, 178 insertions(+), 87 deletions(-) rename interchain/relayer/{local.go => localrelayer/localrelayer.go} (95%) diff --git a/examples/interchain.go b/examples/interchain.go index ca5e3e4..88e6ec0 100644 --- a/examples/interchain.go +++ b/examples/interchain.go @@ -13,10 +13,12 @@ import ( "github.com/ava-labs/avalanche-tooling-sdk-go/evm" "github.com/ava-labs/avalanche-tooling-sdk-go/interchain/icm" "github.com/ava-labs/avalanche-tooling-sdk-go/interchain/relayer" + "github.com/ava-labs/avalanche-tooling-sdk-go/interchain/relayer/localrelayer" "github.com/ava-labs/avalanche-tooling-sdk-go/key" "github.com/ava-labs/avalanche-tooling-sdk-go/utils" "github.com/ava-labs/avalanchego/ids" "github.com/ava-labs/avalanchego/utils/logging" + "github.com/ava-labs/awm-relayer/config" "github.com/ethereum/go-ethereum/common" ) @@ -81,6 +83,9 @@ func CallInterchainExample() error { ) } +// Deploys ICM in two chains +// Deploys a relayes to interconnect them +// Send an example msg func InterchainExample( network avalanche.Network, chain1RPC string, @@ -93,42 +98,18 @@ func InterchainExample( chain2BlockchainID ids.ID, relayerDir string, ) error { - icmVersion, err := icm.GetLatestVersion() - if err != nil { - return err - } - td := icm.Deployer{} - if err := td.DownloadAssets(icmVersion); err != nil { - return err - } - chain1MessengerAlreadyDeployed, chain1MessengerAddress, chain1RegistryAddress, err := td.Deploy( + // Deploy ICM + chain1RegistryAddress, chain1MessengerAddress, chain2RegistryAddress, chain2MessengerAddress, err := SetupICM( chain1RPC, chain1PK, - true, - true, - ) - if err != nil { - return err - } - if !chain1MessengerAlreadyDeployed { - return fmt.Errorf("icm already deployed to %s", chain1RPC) - } - chain2MessengerAlreadyDeployed, chain2MessengerAddress, chain2RegistryAddress, err := td.Deploy( chain2RPC, chain2PK, - true, - true, ) if err != nil { return err } - if !chain2MessengerAlreadyDeployed { - return fmt.Errorf("icm already deployed to %s", chain2RPC) - } - - chain1RegistryAddress = "0x4bC756894C6CB10A5735816E25132486F5a1cE8f" - chain2RegistryAddress = "0x302a91b43d974Cd6f12f4Eae8cADBc8efB7359c8" + // Creates a couple of keys for the Relayer chain1RelayerKey, err := key.NewSoft() if err != nil { return err @@ -138,43 +119,31 @@ func InterchainExample( return err } + // Creates relayer config for the two chains + relayerConfigPath := filepath.Join(relayerDir, "config.json") relayerStorageDir := filepath.Join(relayerDir, "storage") - - relayerConfig := relayer.CreateBaseRelayerConfig( - logging.Info.LowerString(), + relayerConfig, err := SetupRelayerConf( + relayerConfigPath, relayerStorageDir, - 0, network, - ) - relayer.AddBlockchainToRelayerConfig( - relayerConfig, chain1RPC, - "", + chain1PK, chain1SubnetID, chain1BlockchainID, chain1RegistryAddress, chain1MessengerAddress, - chain1RelayerKey.C(), - chain1RelayerKey.PrivKeyHex(), - ) - relayer.AddBlockchainToRelayerConfig( - relayerConfig, + chain1RelayerKey, chain2RPC, - "", + chain2PK, chain2SubnetID, chain2BlockchainID, chain2RegistryAddress, chain2MessengerAddress, - chain2RelayerKey.C(), - chain2RelayerKey.PrivKeyHex(), + chain2RelayerKey, ) - relayerConfigPath := filepath.Join(relayerDir, "config.json") - if err := relayer.SaveRelayerConfig(relayerConfig, relayerConfigPath); err != nil { - return err - } - - desiredRelayerBalance := big.NewInt(0).Mul(big.NewInt(1e18), big.NewInt(10)) // 10 TOKENS + // Fund the relayer keys with 10 TOKENS each + desiredRelayerBalance := big.NewInt(0).Mul(big.NewInt(1e18), big.NewInt(10)) if err := relayer.FundRelayer( relayerConfig, chain1BlockchainID, @@ -194,34 +163,163 @@ func InterchainExample( return err } - binPath, err := relayer.InstallLatest(relayerDir, "") + // install and execute a relayer on localhost + // also wait for proper initialization + relayerLogPath := filepath.Join(relayerDir, "logs.txt") + pid, _, err := StartLocalRelayer( + relayerConfigPath, + relayerLogPath, + relayerDir, + ) if err != nil { return err } - relayerLogPath := filepath.Join(relayerDir, "log.json") + // send a message from chain1 to chain2 + if err := TestMessageDelivery( + chain1RPC, + chain1PK, + chain1MessengerAddress, + chain2BlockchainID, + chain2RPC, + chain2MessengerAddress, + []byte("hello world"), + ); err != nil { + return err + } + + // stops the relayer and cleans up + return localrelayer.Cleanup(pid, "", relayerStorageDir) +} - pid, err := relayer.Execute(binPath, relayerConfigPath, relayerLogPath, "") +func SetupICM( + chain1RPC string, + chain1PK string, + chain2RPC string, + chain2PK string, +) (string, string, string, string, error) { + // Get latest version of ICM + icmVersion, err := icm.GetLatestVersion() if err != nil { - if bs, err := os.ReadFile(relayerLogPath); err == nil { + return "", "", "", "", err + } + // Deploys ICM Messenger and Registry to Chain1 and Chain2 + td := icm.Deployer{} + if err := td.DownloadAssets(icmVersion); err != nil { + return "", "", "", "", err + } + _, chain1RegistryAddress, chain1MessengerAddress, err := td.Deploy( + chain1RPC, + chain1PK, + true, + ) + if err != nil { + return "", "", "", "", err + } + _, chain2RegistryAddress, chain2MessengerAddress, err := td.Deploy( + chain2RPC, + chain2PK, + true, + ) + if err != nil { + return "", "", "", "", err + } + return chain1RegistryAddress, chain1MessengerAddress, chain2RegistryAddress, chain2MessengerAddress, nil +} + +func SetupRelayerConf( + configPath string, + storageDir string, + network avalanche.Network, + chain1RPC string, + chain1PK string, + chain1SubnetID ids.ID, + chain1BlockchainID ids.ID, + chain1RegistryAddress string, + chain1MessengerAddress string, + chain1RelayerKey *key.SoftKey, + chain2RPC string, + chain2PK string, + chain2SubnetID ids.ID, + chain2BlockchainID ids.ID, + chain2RegistryAddress string, + chain2MessengerAddress string, + chain2RelayerKey *key.SoftKey, +) (*config.Config, error) { + // Creates relayer config + config := relayer.CreateBaseRelayerConfig( + logging.Info.LowerString(), + storageDir, + 0, + network, + ) + relayer.AddBlockchainToRelayerConfig( + config, + chain1RPC, + "", + chain1SubnetID, + chain1BlockchainID, + chain1RegistryAddress, + chain1MessengerAddress, + chain1RelayerKey.C(), + chain1RelayerKey.PrivKeyHex(), + ) + relayer.AddBlockchainToRelayerConfig( + config, + chain2RPC, + "", + chain2SubnetID, + chain2BlockchainID, + chain2RegistryAddress, + chain2MessengerAddress, + chain2RelayerKey.C(), + chain2RelayerKey.PrivKeyHex(), + ) + if err := relayer.SaveRelayerConfig(config, configPath); err != nil { + return nil, err + } + return config, nil +} + +func StartLocalRelayer( + configPath string, + logPath string, + installDir string, +) (int, string, error) { + binPath, err := localrelayer.InstallLatest(installDir, "") + if err != nil { + return 0, "", err + } + pid, err := localrelayer.Execute(binPath, configPath, logPath, "") + if err != nil { + if bs, err := os.ReadFile(logPath); err == nil { fmt.Println(string(bs)) } - return err + return pid, binPath, err } - - if err := relayer.WaitForInitialization(relayerConfigPath, relayerLogPath, 0, 0); err != nil { - return err + if err := localrelayer.WaitForInitialization(configPath, logPath, 0, 0); err != nil { + return pid, binPath, err } + return pid, binPath, nil +} - message := "hello world" - encodedMessage := []byte("hello world") +func TestMessageDelivery( + chain1RPC string, + chain1PK string, + chain1MessengerAddress string, + chain2BlockchainID ids.ID, + chain2RPC string, + chain2MessengerAddress string, + message []byte, +) error { + // send message request to chain1 tx, receipt, err := icm.SendCrossChainMessage( chain1RPC, common.HexToAddress(chain1MessengerAddress), chain1PK, chain2BlockchainID, common.Address{}, - encodedMessage, + message, ) if err != nil { return err @@ -237,27 +335,29 @@ func InterchainExample( return fmt.Errorf("source receipt status for tx %s is not ReceiptStatusSuccessful", txHash) } + // get from chain1 event logs the message id event, err := evm.GetEventFromLogs(receipt.Logs, icm.ParseSendCrossChainMessage) if err != nil { return err } - + messageID := event.MessageID + // also veryfies some input params if chain2BlockchainID != ids.ID(event.DestinationBlockchainID[:]) { return fmt.Errorf("invalid destination blockchain id at source event, expected %s, got %s", chain2BlockchainID, ids.ID(event.DestinationBlockchainID[:])) } - if message != string(event.Message.Message) { + if string(message) != string(event.Message.Message) { return fmt.Errorf("invalid message content at source event, expected %s, got %s", message, string(event.Message.Message)) } + // wait for chain2 to receive the message if err := icm.WaitForMessageReception( chain2RPC, chain2MessengerAddress, - event.MessageID, + messageID, 0, 0, ); err != nil { return err } - - return relayer.Cleanup(pid, "", relayerStorageDir) + return nil } diff --git a/interchain/icm/icm.go b/interchain/icm/icm.go index c321894..2d83cf9 100644 --- a/interchain/icm/icm.go +++ b/interchain/icm/icm.go @@ -138,32 +138,22 @@ func (t *Deployer) DownloadAssets(version string) error { } // Deploys messenger and registry -// If messenger is already deployed, will avoid deploying registry -// (to force, set deployMessenger to false) +// If messenger is already deployed, will avoid deploying registry, +// unless [forceRegistryDeploy] is set func (t *Deployer) Deploy( rpcURL string, privateKey string, - deployMessenger bool, - deployRegistry bool, + forceRegistryDeploy bool, ) (bool, string, string, error) { - var ( - messengerAddress string - registryAddress string - messengerAlreadyDeployed bool - err error + var registryAddress string + messengerAlreadyDeployed, messengerAddress, err := t.DeployMessenger( + rpcURL, + privateKey, ) - if deployMessenger { - messengerAlreadyDeployed, messengerAddress, err = t.DeployMessenger( - rpcURL, - privateKey, - ) - } - if err == nil && deployRegistry { - if !deployMessenger || !messengerAlreadyDeployed { - registryAddress, err = t.DeployRegistry(rpcURL, privateKey) - } + if !messengerAlreadyDeployed || forceRegistryDeploy { + registryAddress, err = t.DeployRegistry(rpcURL, privateKey) } - return messengerAlreadyDeployed, messengerAddress, registryAddress, err + return messengerAlreadyDeployed, registryAddress, messengerAddress, err } func (t *Deployer) DeployMessenger( diff --git a/interchain/relayer/local.go b/interchain/relayer/localrelayer/localrelayer.go similarity index 95% rename from interchain/relayer/local.go rename to interchain/relayer/localrelayer/localrelayer.go index 1db318c..9c4f29b 100644 --- a/interchain/relayer/local.go +++ b/interchain/relayer/localrelayer/localrelayer.go @@ -1,6 +1,6 @@ // Copyright (C) 2022, Ava Labs, Inc. All rights reserved // See the file LICENSE for licensing terms. -package relayer +package localrelayer import ( "fmt" @@ -11,6 +11,7 @@ import ( "github.com/ava-labs/avalanche-tooling-sdk-go/constants" "github.com/ava-labs/avalanche-tooling-sdk-go/install" + "github.com/ava-labs/avalanche-tooling-sdk-go/interchain/relayer" "github.com/ava-labs/avalanche-tooling-sdk-go/process" ) @@ -82,7 +83,7 @@ func WaitForInitialization( checkInterval time.Duration, checkTimeout time.Duration, ) error { - config, err := LoadRelayerConfig(configPath) + config, err := relayer.LoadRelayerConfig(configPath) if err != nil { return err } From f180a779770196bd067a4ad88083db579cc79a23 Mon Sep 17 00:00:00 2001 From: Felipe Madero Date: Thu, 29 Aug 2024 14:45:04 -0300 Subject: [PATCH 08/19] add comments --- examples/interchain.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/examples/interchain.go b/examples/interchain.go index 88e6ec0..40ad3bf 100644 --- a/examples/interchain.go +++ b/examples/interchain.go @@ -99,6 +99,7 @@ func InterchainExample( relayerDir string, ) error { // Deploy ICM + fmt.Println("Deploying ICM") chain1RegistryAddress, chain1MessengerAddress, chain2RegistryAddress, chain2MessengerAddress, err := SetupICM( chain1RPC, chain1PK, @@ -141,8 +142,10 @@ func InterchainExample( chain2MessengerAddress, chain2RelayerKey, ) + fmt.Printf("Generated relayer conf on %s\n", relayerConfigPath) // Fund the relayer keys with 10 TOKENS each + fmt.Printf("Funding relayer keys %s, %s\n", chain1RelayerKey.C(), chain2RelayerKey.C()) desiredRelayerBalance := big.NewInt(0).Mul(big.NewInt(1e18), big.NewInt(10)) if err := relayer.FundRelayer( relayerConfig, @@ -166,6 +169,7 @@ func InterchainExample( // install and execute a relayer on localhost // also wait for proper initialization relayerLogPath := filepath.Join(relayerDir, "logs.txt") + fmt.Printf("Executing local relayer with logs %s\n", relayerLogPath) pid, _, err := StartLocalRelayer( relayerConfigPath, relayerLogPath, @@ -176,6 +180,7 @@ func InterchainExample( } // send a message from chain1 to chain2 + fmt.Println("Verifying message delivery") if err := TestMessageDelivery( chain1RPC, chain1PK, @@ -189,6 +194,7 @@ func InterchainExample( } // stops the relayer and cleans up + fmt.Println("Cleaning up") return localrelayer.Cleanup(pid, "", relayerStorageDir) } From 3483f09b86a7bac3502d5f642ad9f1d05e41712a Mon Sep 17 00:00:00 2001 From: Felipe Madero Date: Thu, 29 Aug 2024 22:48:36 -0300 Subject: [PATCH 09/19] defer cleanup --- examples/interchain.go | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/examples/interchain.go b/examples/interchain.go index 40ad3bf..4a08a95 100644 --- a/examples/interchain.go +++ b/examples/interchain.go @@ -179,9 +179,12 @@ func InterchainExample( return err } + // defer stopping relayer and cleaning up + defer localrelayer.Cleanup(pid, "", relayerStorageDir) + // send a message from chain1 to chain2 fmt.Println("Verifying message delivery") - if err := TestMessageDelivery( + return TestMessageDelivery( chain1RPC, chain1PK, chain1MessengerAddress, @@ -189,13 +192,7 @@ func InterchainExample( chain2RPC, chain2MessengerAddress, []byte("hello world"), - ); err != nil { - return err - } - - // stops the relayer and cleans up - fmt.Println("Cleaning up") - return localrelayer.Cleanup(pid, "", relayerStorageDir) + ) } func SetupICM( From 59fb75c27cf5203d3692536afcbb6910ab338901 Mon Sep 17 00:00:00 2001 From: Felipe Madero Date: Thu, 29 Aug 2024 22:51:24 -0300 Subject: [PATCH 10/19] add final print --- examples/interchain.go | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/examples/interchain.go b/examples/interchain.go index 4a08a95..1d58a20 100644 --- a/examples/interchain.go +++ b/examples/interchain.go @@ -184,7 +184,7 @@ func InterchainExample( // send a message from chain1 to chain2 fmt.Println("Verifying message delivery") - return TestMessageDelivery( + if err := TestMessageDelivery( chain1RPC, chain1PK, chain1MessengerAddress, @@ -192,7 +192,13 @@ func InterchainExample( chain2RPC, chain2MessengerAddress, []byte("hello world"), - ) + ); err != nil { + return err + } + + fmt.Println("Message succesfully delivered") + + return nil } func SetupICM( From f4ed892d754e74b02b564b51ce4addb3a83b09eb Mon Sep 17 00:00:00 2001 From: Raymond Sukanto Date: Fri, 30 Aug 2024 16:07:49 +0700 Subject: [PATCH 11/19] change example format --- examples/interchain.go | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/examples/interchain.go b/examples/interchain.go index 1d58a20..7ee6123 100644 --- a/examples/interchain.go +++ b/examples/interchain.go @@ -1,7 +1,7 @@ // Copyright (C) 2024, Ava Labs, Inc. All rights reserved. // See the file LICENSE for licensing terms. -package main +package examples import ( "fmt" @@ -22,12 +22,6 @@ import ( "github.com/ethereum/go-ethereum/common" ) -func main() { - if err := CallInterchainExample(); err != nil { - panic(err) - } -} - // Fuji ICM Example // // Deploys ICM into CHAIN1_RPC and CHAIN2_RPC, @@ -38,9 +32,8 @@ func main() { // Subnet IDs and Blockchain IDs are provided to fullfill // relayer conf // -// All relayer data is saved into RELAYER_DIR, that must -// exist beforehand -func CallInterchainExample() error { +// All relayer data is saved into an existing RELAYER_DIR +func Interchain() error { chain1RPC := os.Getenv("CHAIN1_RPC") chain1PK := os.Getenv("CHAIN1_PK") chain1SubnetID, err := ids.FromString(os.Getenv("CHAIN1_SUBNET_ID")) From 139365348a95948a31ee5be6624db64a6b352429 Mon Sep 17 00:00:00 2001 From: Raymond Sukanto Date: Fri, 30 Aug 2024 16:59:35 +0700 Subject: [PATCH 12/19] update example --- examples/interchain.go | 85 +++++++++++++++++++------------------- interchain/relayer/conf.go | 8 ++-- 2 files changed, 46 insertions(+), 47 deletions(-) diff --git a/examples/interchain.go b/examples/interchain.go index 7ee6123..48f4b63 100644 --- a/examples/interchain.go +++ b/examples/interchain.go @@ -15,7 +15,6 @@ import ( "github.com/ava-labs/avalanche-tooling-sdk-go/interchain/relayer" "github.com/ava-labs/avalanche-tooling-sdk-go/interchain/relayer/localrelayer" "github.com/ava-labs/avalanche-tooling-sdk-go/key" - "github.com/ava-labs/avalanche-tooling-sdk-go/utils" "github.com/ava-labs/avalanchego/ids" "github.com/ava-labs/avalanchego/utils/logging" "github.com/ava-labs/awm-relayer/config" @@ -33,48 +32,48 @@ import ( // relayer conf // // All relayer data is saved into an existing RELAYER_DIR -func Interchain() error { - chain1RPC := os.Getenv("CHAIN1_RPC") - chain1PK := os.Getenv("CHAIN1_PK") - chain1SubnetID, err := ids.FromString(os.Getenv("CHAIN1_SUBNET_ID")) - if err != nil { - return err - } - chain1BlockchainID, err := ids.FromString(os.Getenv("CHAIN1_BLOCKCHAIN_ID")) - if err != nil { - return err - } - chain2RPC := os.Getenv("CHAIN2_RPC") - chain2PK := os.Getenv("CHAIN2_PK") - chain2SubnetID, err := ids.FromString(os.Getenv("CHAIN2_SUBNET_ID")) - if err != nil { - return err - } - chain2BlockchainID, err := ids.FromString(os.Getenv("CHAIN2_BLOCKCHAIN_ID")) - if err != nil { - return err - } - relayerDir := os.Getenv("RELAYER_DIR") - if relayerDir == "" { - return fmt.Errorf("must define RELAYER_DIR env var") - } - relayerDir = utils.ExpandHome(relayerDir) - if !utils.DirectoryExists(relayerDir) { - return fmt.Errorf("relayer directory %q must exist", relayerDir) - } - return InterchainExample( - avalanche.FujiNetwork(), - chain1RPC, - chain1PK, - chain1SubnetID, - chain1BlockchainID, - chain2RPC, - chain2PK, - chain2SubnetID, - chain2BlockchainID, - relayerDir, - ) -} +//func Interchain() error { +// chain1RPC := os.Getenv("CHAIN1_RPC") +// chain1PK := os.Getenv("CHAIN1_PK") +// chain1SubnetID, err := ids.FromString(os.Getenv("CHAIN1_SUBNET_ID")) +// if err != nil { +// return err +// } +// chain1BlockchainID, err := ids.FromString(os.Getenv("CHAIN1_BLOCKCHAIN_ID")) +// if err != nil { +// return err +// } +// chain2RPC := os.Getenv("CHAIN2_RPC") +// chain2PK := os.Getenv("CHAIN2_PK") +// chain2SubnetID, err := ids.FromString(os.Getenv("CHAIN2_SUBNET_ID")) +// if err != nil { +// return err +// } +// chain2BlockchainID, err := ids.FromString(os.Getenv("CHAIN2_BLOCKCHAIN_ID")) +// if err != nil { +// return err +// } +// relayerDir := os.Getenv("RELAYER_DIR") +// if relayerDir == "" { +// return fmt.Errorf("must define RELAYER_DIR env var") +// } +// relayerDir = utils.ExpandHome(relayerDir) +// if !utils.DirectoryExists(relayerDir) { +// return fmt.Errorf("relayer directory %q must exist", relayerDir) +// } +// return InterchainExample( +// avalanche.FujiNetwork(), +// chain1RPC, +// chain1PK, +// chain1SubnetID, +// chain1BlockchainID, +// chain2RPC, +// chain2PK, +// chain2SubnetID, +// chain2BlockchainID, +// relayerDir, +// ) +//} // Deploys ICM in two chains // Deploys a relayes to interconnect them diff --git a/interchain/relayer/conf.go b/interchain/relayer/conf.go index b21dec6..c1d1858 100644 --- a/interchain/relayer/conf.go +++ b/interchain/relayer/conf.go @@ -51,8 +51,8 @@ func GetDestinationConfig( return nil } -// fund the relayer private key associated to [blockchainID] -// at [relayerConfig]. if [amount] > 0 transfers it to the account. if, +// FundRelayer funds the relayer private key associated to [blockchainID] specified in +// [relayerConfig]. If [amount] > 0 transfers it to the account. if, // afterwards, balance < [requiredMinBalance], transfers remaining amount for that // if [requiredMinBalance] is nil, uses [defaultRequiredBalance] func FundRelayer( @@ -75,7 +75,7 @@ func FundRelayer( ) } -// fund [relayerPrivateKey] at [rpcEndpoint] +// FundRelayerPrivateKey funds [relayerPrivateKey] at [rpcEndpoint] // see FundRelayer for [amount]/[requiredMinBalance] logic func FundRelayerPrivateKey( rpcEndpoint string, @@ -98,7 +98,7 @@ func FundRelayerPrivateKey( ) } -// fund [relayerAddress] at [rpcEndpoint] +// FundRelayerAddress funds [relayerAddress] at [rpcEndpoint] // see FundRelayer for [amount]/[requiredMinBalance] logic func FundRelayerAddress( rpcEndpoint string, From 99ce7cf454e868d20df4b4d9175dcc0951df1402 Mon Sep 17 00:00:00 2001 From: Raymond Sukanto Date: Fri, 30 Aug 2024 17:13:44 +0700 Subject: [PATCH 13/19] update example --- examples/interchain.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/interchain.go b/examples/interchain.go index 48f4b63..1df814e 100644 --- a/examples/interchain.go +++ b/examples/interchain.go @@ -322,9 +322,6 @@ func TestMessageDelivery( common.Address{}, message, ) - if err != nil { - return err - } if err == evm.ErrFailedReceiptStatus { txHash := tx.Hash().String() trace, err := evm.GetTrace(chain1RPC, txHash) @@ -335,6 +332,9 @@ func TestMessageDelivery( } return fmt.Errorf("source receipt status for tx %s is not ReceiptStatusSuccessful", txHash) } + if err != nil { + return err + } // get from chain1 event logs the message id event, err := evm.GetEventFromLogs(receipt.Logs, icm.ParseSendCrossChainMessage) From 3334cbcaddd51345be0dca46cbc98032b5c34557 Mon Sep 17 00:00:00 2001 From: Raymond Sukanto Date: Fri, 30 Aug 2024 17:14:27 +0700 Subject: [PATCH 14/19] update example --- examples/interchain.go | 85 +++++++++++++++++++++--------------------- 1 file changed, 43 insertions(+), 42 deletions(-) diff --git a/examples/interchain.go b/examples/interchain.go index 1df814e..d4d9bcb 100644 --- a/examples/interchain.go +++ b/examples/interchain.go @@ -5,6 +5,7 @@ package examples import ( "fmt" + "github.com/ava-labs/avalanche-tooling-sdk-go/utils" "math/big" "os" "path/filepath" @@ -32,48 +33,48 @@ import ( // relayer conf // // All relayer data is saved into an existing RELAYER_DIR -//func Interchain() error { -// chain1RPC := os.Getenv("CHAIN1_RPC") -// chain1PK := os.Getenv("CHAIN1_PK") -// chain1SubnetID, err := ids.FromString(os.Getenv("CHAIN1_SUBNET_ID")) -// if err != nil { -// return err -// } -// chain1BlockchainID, err := ids.FromString(os.Getenv("CHAIN1_BLOCKCHAIN_ID")) -// if err != nil { -// return err -// } -// chain2RPC := os.Getenv("CHAIN2_RPC") -// chain2PK := os.Getenv("CHAIN2_PK") -// chain2SubnetID, err := ids.FromString(os.Getenv("CHAIN2_SUBNET_ID")) -// if err != nil { -// return err -// } -// chain2BlockchainID, err := ids.FromString(os.Getenv("CHAIN2_BLOCKCHAIN_ID")) -// if err != nil { -// return err -// } -// relayerDir := os.Getenv("RELAYER_DIR") -// if relayerDir == "" { -// return fmt.Errorf("must define RELAYER_DIR env var") -// } -// relayerDir = utils.ExpandHome(relayerDir) -// if !utils.DirectoryExists(relayerDir) { -// return fmt.Errorf("relayer directory %q must exist", relayerDir) -// } -// return InterchainExample( -// avalanche.FujiNetwork(), -// chain1RPC, -// chain1PK, -// chain1SubnetID, -// chain1BlockchainID, -// chain2RPC, -// chain2PK, -// chain2SubnetID, -// chain2BlockchainID, -// relayerDir, -// ) -//} +func Interchain() error { + chain1RPC := os.Getenv("CHAIN1_RPC") + chain1PK := os.Getenv("CHAIN1_PK") + chain1SubnetID, err := ids.FromString(os.Getenv("CHAIN1_SUBNET_ID")) + if err != nil { + return err + } + chain1BlockchainID, err := ids.FromString(os.Getenv("CHAIN1_BLOCKCHAIN_ID")) + if err != nil { + return err + } + chain2RPC := os.Getenv("CHAIN2_RPC") + chain2PK := os.Getenv("CHAIN2_PK") + chain2SubnetID, err := ids.FromString(os.Getenv("CHAIN2_SUBNET_ID")) + if err != nil { + return err + } + chain2BlockchainID, err := ids.FromString(os.Getenv("CHAIN2_BLOCKCHAIN_ID")) + if err != nil { + return err + } + relayerDir := os.Getenv("RELAYER_DIR") + if relayerDir == "" { + return fmt.Errorf("must define RELAYER_DIR env var") + } + relayerDir = utils.ExpandHome(relayerDir) + if !utils.DirectoryExists(relayerDir) { + return fmt.Errorf("relayer directory %q must exist", relayerDir) + } + return InterchainExample( + avalanche.FujiNetwork(), + chain1RPC, + chain1PK, + chain1SubnetID, + chain1BlockchainID, + chain2RPC, + chain2PK, + chain2SubnetID, + chain2BlockchainID, + relayerDir, + ) +} // Deploys ICM in two chains // Deploys a relayes to interconnect them From 83b068328d3a521e00b750738893f10118cc5645 Mon Sep 17 00:00:00 2001 From: Raymond Sukanto Date: Fri, 30 Aug 2024 17:20:15 +0700 Subject: [PATCH 15/19] update example --- examples/interchain.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/interchain.go b/examples/interchain.go index d4d9bcb..0c4fd5c 100644 --- a/examples/interchain.go +++ b/examples/interchain.go @@ -343,7 +343,7 @@ func TestMessageDelivery( return err } messageID := event.MessageID - // also veryfies some input params + // also verifies some input params if chain2BlockchainID != ids.ID(event.DestinationBlockchainID[:]) { return fmt.Errorf("invalid destination blockchain id at source event, expected %s, got %s", chain2BlockchainID, ids.ID(event.DestinationBlockchainID[:])) } From 385bf5189f48ccd95adf6b763642a7eec5b05173 Mon Sep 17 00:00:00 2001 From: Felipe Madero Date: Mon, 2 Sep 2024 12:47:25 -0300 Subject: [PATCH 16/19] address PR comments --- examples/interchain.go | 50 ++++++++++++++++++++++++++------------ interchain/relayer/conf.go | 19 ++++++++++++--- 2 files changed, 51 insertions(+), 18 deletions(-) diff --git a/examples/interchain.go b/examples/interchain.go index 0c4fd5c..9f1ab77 100644 --- a/examples/interchain.go +++ b/examples/interchain.go @@ -5,11 +5,12 @@ package examples import ( "fmt" - "github.com/ava-labs/avalanche-tooling-sdk-go/utils" "math/big" "os" "path/filepath" + "github.com/ava-labs/avalanche-tooling-sdk-go/utils" + "github.com/ava-labs/avalanche-tooling-sdk-go/avalanche" "github.com/ava-labs/avalanche-tooling-sdk-go/evm" "github.com/ava-labs/avalanche-tooling-sdk-go/interchain/icm" @@ -91,8 +92,9 @@ func InterchainExample( chain2BlockchainID ids.ID, relayerDir string, ) error { - // Deploy ICM - fmt.Println("Deploying ICM") + // Deploy Interchain Messenger (ICM) + // More information: https://github.com/ava-labs/teleporter + fmt.Println("Deploying Interchain Messenger") chain1RegistryAddress, chain1MessengerAddress, chain2RegistryAddress, chain2MessengerAddress, err := SetupICM( chain1RPC, chain1PK, @@ -103,7 +105,14 @@ func InterchainExample( return err } - // Creates a couple of keys for the Relayer + // Create keys for relayer operations: pay fees and receive rewards + // At destination blockchain, the relayer needs to pay fees for smart contract + // calls used to deliver messages. For that, it needs information on properly + // funded private keys at destination. + // Besides this, some source blockchain may provide incentives to relayers + // that send their messages. For that, the relayer needs to be configured with + // the address that will receive such payments at source. + // More information: https: //github.com/ava-labs/awm-relayer/blob/main/relayer/README.md chain1RelayerKey, err := key.NewSoft() if err != nil { return err @@ -114,6 +123,11 @@ func InterchainExample( } // Creates relayer config for the two chains + // The relayer can be configured to listed for new ICM messages + // from a set of source blockchains, and then deliver those + // to a set of destination blockchains. + // Here we are configuring chain1 and chain2 both as source + // and as destination, so we can send messages in any direction. relayerConfigPath := filepath.Join(relayerDir, "config.json") relayerStorageDir := filepath.Join(relayerDir, "storage") relayerConfig, err := SetupRelayerConf( @@ -121,14 +135,12 @@ func InterchainExample( relayerStorageDir, network, chain1RPC, - chain1PK, chain1SubnetID, chain1BlockchainID, chain1RegistryAddress, chain1MessengerAddress, chain1RelayerKey, chain2RPC, - chain2PK, chain2SubnetID, chain2BlockchainID, chain2RegistryAddress, @@ -137,9 +149,13 @@ func InterchainExample( ) fmt.Printf("Generated relayer conf on %s\n", relayerConfigPath) - // Fund the relayer keys with 10 TOKENS each + // Fund each relayer key with 10 TOKENs + // Where TOKEN is the native gas token of each blockchain + // Assumes that the TOKEN decimals are 18, so, this equals + // to 1e18 of the smallest gas amount in each chain fmt.Printf("Funding relayer keys %s, %s\n", chain1RelayerKey.C(), chain2RelayerKey.C()) desiredRelayerBalance := big.NewInt(0).Mul(big.NewInt(1e18), big.NewInt(10)) + // chain1PK will have a balance 10 native gas tokens on chain. if err := relayer.FundRelayer( relayerConfig, chain1BlockchainID, @@ -149,6 +165,7 @@ func InterchainExample( ); err != nil { return err } + // chain2PK will have a balance 10 native gas tokens on chain2 if err := relayer.FundRelayer( relayerConfig, chain2BlockchainID, @@ -234,27 +251,29 @@ func SetupRelayerConf( storageDir string, network avalanche.Network, chain1RPC string, - chain1PK string, chain1SubnetID ids.ID, chain1BlockchainID ids.ID, chain1RegistryAddress string, chain1MessengerAddress string, chain1RelayerKey *key.SoftKey, chain2RPC string, - chain2PK string, chain2SubnetID ids.ID, chain2BlockchainID ids.ID, chain2RegistryAddress string, chain2MessengerAddress string, chain2RelayerKey *key.SoftKey, ) (*config.Config, error) { - // Creates relayer config + // Create a base relayer config config := relayer.CreateBaseRelayerConfig( logging.Info.LowerString(), storageDir, 0, network, ) + // Add blockchain chain1 to the relayer config, + // setting it both as source and as destination. + // So the relayer will both listed for new messages in it, + // and send to it new messages from other blockchains. relayer.AddBlockchainToRelayerConfig( config, chain1RPC, @@ -266,6 +285,10 @@ func SetupRelayerConf( chain1RelayerKey.C(), chain1RelayerKey.PrivKeyHex(), ) + // Add blockchain chain2 to the relayer config, + // setting it both as source and as destination. + // So the relayer will both listed for new messages in it, + // and send to it new messages from other blockchains. relayer.AddBlockchainToRelayerConfig( config, chain2RPC, @@ -352,14 +375,11 @@ func TestMessageDelivery( } // wait for chain2 to receive the message - if err := icm.WaitForMessageReception( + return icm.WaitForMessageReception( chain2RPC, chain2MessengerAddress, messageID, 0, 0, - ); err != nil { - return err - } - return nil + ) } diff --git a/interchain/relayer/conf.go b/interchain/relayer/conf.go index c1d1858..aa942a9 100644 --- a/interchain/relayer/conf.go +++ b/interchain/relayer/conf.go @@ -52,9 +52,11 @@ func GetDestinationConfig( } // FundRelayer funds the relayer private key associated to [blockchainID] specified in -// [relayerConfig]. If [amount] > 0 transfers it to the account. if, -// afterwards, balance < [requiredMinBalance], transfers remaining amount for that -// if [requiredMinBalance] is nil, uses [defaultRequiredBalance] +// [relayerConfig]. Receives one of two amount specs: +// 1) if [amount] > 0, transfers it to the account. +// 2) if [requiredMinBalance] > 0, checks the balance in the account, and +// if balance < [requiredMinBalance], transfers the amount needed so as +// balance == [requiredMinBalance] func FundRelayer( relayerConfig *config.Config, blockchainID ids.ID, @@ -245,6 +247,7 @@ func AddBlockchainToRelayerConfigFile( return SaveRelayerConfig(relayerConfig, relayerConfigPath) } +// Creates a base relayer config func CreateBaseRelayerConfig( logLevel string, storageLocation string, @@ -271,6 +274,9 @@ func CreateBaseRelayerConfig( return relayerConfig } +// Adds blockchain to the relayer config, setting it as source. +// So the relayer will listed for new messages in it, +// sending those to other blockchains. func AddSourceToRelayerConfig( relayerConfig *config.Config, rpcEndpoint string, @@ -317,6 +323,9 @@ func AddSourceToRelayerConfig( } } +// Adds a blockchain to the relayer config, +// setting it as destination. +// So the relayer will send to it new messages from other blockchains. func AddDestinationToRelayerConfig( relayerConfig *config.Config, rpcEndpoint string, @@ -338,6 +347,10 @@ func AddDestinationToRelayerConfig( } } +// Adds a blockchain to the relayer config, +// setting it both as source and as destination. +// So the relayer will both listed for new messages in it, +// and send to it new messages from other blockchains. func AddBlockchainToRelayerConfig( relayerConfig *config.Config, rpcEndpoint string, From c642f60271994eebfeda2801ec2fa33adcb36ba6 Mon Sep 17 00:00:00 2001 From: Felipe Madero Date: Tue, 3 Sep 2024 10:35:11 -0300 Subject: [PATCH 17/19] rename filename with space in --- examples/{subnet_ add_validator.go => subnet_add_validator.go} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename examples/{subnet_ add_validator.go => subnet_add_validator.go} (100%) diff --git a/examples/subnet_ add_validator.go b/examples/subnet_add_validator.go similarity index 100% rename from examples/subnet_ add_validator.go rename to examples/subnet_add_validator.go From e34f62a705a0646d145a523633d0c26c4f7335e4 Mon Sep 17 00:00:00 2001 From: Felipe Madero Date: Tue, 3 Sep 2024 11:29:25 -0300 Subject: [PATCH 18/19] address PR comments --- examples/interchain.go | 164 ++++++++++-------- .../interchain_messenger.go} | 2 +- .../{icm => interchainmessenger}/msg.go | 2 +- interchain/relayer/conf.go | 111 +----------- .../relayer/localrelayer/localrelayer.go | 6 +- node/{dockerCompose.go => docker_compose.go} | 0 node/{dockerConfig.go => docker_config.go} | 0 node/{dockerImage.go => docker_image.go} | 0 node/{dockerSsh.go => docker_ssh.go} | 0 node/{nodeResult.go => node_result.go} | 0 vm/{evmSettings.go => evm_settings.go} | 0 11 files changed, 98 insertions(+), 187 deletions(-) rename interchain/{icm/icm.go => interchainmessenger/interchain_messenger.go} (99%) rename interchain/{icm => interchainmessenger}/msg.go (99%) rename node/{dockerCompose.go => docker_compose.go} (100%) rename node/{dockerConfig.go => docker_config.go} (100%) rename node/{dockerImage.go => docker_image.go} (100%) rename node/{dockerSsh.go => docker_ssh.go} (100%) rename node/{nodeResult.go => node_result.go} (100%) rename vm/{evmSettings.go => evm_settings.go} (100%) diff --git a/examples/interchain.go b/examples/interchain.go index 9f1ab77..980ab4b 100644 --- a/examples/interchain.go +++ b/examples/interchain.go @@ -12,8 +12,9 @@ import ( "github.com/ava-labs/avalanche-tooling-sdk-go/utils" "github.com/ava-labs/avalanche-tooling-sdk-go/avalanche" + "github.com/ava-labs/avalanche-tooling-sdk-go/constants" "github.com/ava-labs/avalanche-tooling-sdk-go/evm" - "github.com/ava-labs/avalanche-tooling-sdk-go/interchain/icm" + "github.com/ava-labs/avalanche-tooling-sdk-go/interchain/interchainmessenger" "github.com/ava-labs/avalanche-tooling-sdk-go/interchain/relayer" "github.com/ava-labs/avalanche-tooling-sdk-go/interchain/relayer/localrelayer" "github.com/ava-labs/avalanche-tooling-sdk-go/key" @@ -23,60 +24,6 @@ import ( "github.com/ethereum/go-ethereum/common" ) -// Fuji ICM Example -// -// Deploys ICM into CHAIN1_RPC and CHAIN2_RPC, -// paying deploy fees with CHAIN1_PK and CHAIN2_PK -// -// Downloads and executes a relayer in a local process -// and sets it to listen to CHAIN1 and CHAIN2. -// Subnet IDs and Blockchain IDs are provided to fullfill -// relayer conf -// -// All relayer data is saved into an existing RELAYER_DIR -func Interchain() error { - chain1RPC := os.Getenv("CHAIN1_RPC") - chain1PK := os.Getenv("CHAIN1_PK") - chain1SubnetID, err := ids.FromString(os.Getenv("CHAIN1_SUBNET_ID")) - if err != nil { - return err - } - chain1BlockchainID, err := ids.FromString(os.Getenv("CHAIN1_BLOCKCHAIN_ID")) - if err != nil { - return err - } - chain2RPC := os.Getenv("CHAIN2_RPC") - chain2PK := os.Getenv("CHAIN2_PK") - chain2SubnetID, err := ids.FromString(os.Getenv("CHAIN2_SUBNET_ID")) - if err != nil { - return err - } - chain2BlockchainID, err := ids.FromString(os.Getenv("CHAIN2_BLOCKCHAIN_ID")) - if err != nil { - return err - } - relayerDir := os.Getenv("RELAYER_DIR") - if relayerDir == "" { - return fmt.Errorf("must define RELAYER_DIR env var") - } - relayerDir = utils.ExpandHome(relayerDir) - if !utils.DirectoryExists(relayerDir) { - return fmt.Errorf("relayer directory %q must exist", relayerDir) - } - return InterchainExample( - avalanche.FujiNetwork(), - chain1RPC, - chain1PK, - chain1SubnetID, - chain1BlockchainID, - chain2RPC, - chain2PK, - chain2SubnetID, - chain2BlockchainID, - relayerDir, - ) -} - // Deploys ICM in two chains // Deploys a relayes to interconnect them // Send an example msg @@ -130,8 +77,7 @@ func InterchainExample( // and as destination, so we can send messages in any direction. relayerConfigPath := filepath.Join(relayerDir, "config.json") relayerStorageDir := filepath.Join(relayerDir, "storage") - relayerConfig, err := SetupRelayerConf( - relayerConfigPath, + relayerConfig, relayerBytes, err := SetupRelayerConf( relayerStorageDir, network, chain1RPC, @@ -147,6 +93,12 @@ func InterchainExample( chain2MessengerAddress, chain2RelayerKey, ) + if err != nil { + return err + } + if err := os.WriteFile(relayerConfigPath, relayerBytes, constants.WriteReadReadPerms); err != nil { + return err + } fmt.Printf("Generated relayer conf on %s\n", relayerConfigPath) // Fund each relayer key with 10 TOKENs @@ -190,7 +142,7 @@ func InterchainExample( } // defer stopping relayer and cleaning up - defer localrelayer.Cleanup(pid, "", relayerStorageDir) + defer func() { _ = localrelayer.Cleanup(pid, "", relayerStorageDir) }() // send a message from chain1 to chain2 fmt.Println("Verifying message delivery") @@ -206,7 +158,7 @@ func InterchainExample( return err } - fmt.Println("Message succesfully delivered") + fmt.Println("Message successfully delivered") return nil } @@ -218,12 +170,12 @@ func SetupICM( chain2PK string, ) (string, string, string, string, error) { // Get latest version of ICM - icmVersion, err := icm.GetLatestVersion() + icmVersion, err := interchainmessenger.GetLatestVersion() if err != nil { return "", "", "", "", err } // Deploys ICM Messenger and Registry to Chain1 and Chain2 - td := icm.Deployer{} + td := interchainmessenger.Deployer{} if err := td.DownloadAssets(icmVersion); err != nil { return "", "", "", "", err } @@ -247,7 +199,6 @@ func SetupICM( } func SetupRelayerConf( - configPath string, storageDir string, network avalanche.Network, chain1RPC string, @@ -262,7 +213,7 @@ func SetupRelayerConf( chain2RegistryAddress string, chain2MessengerAddress string, chain2RelayerKey *key.SoftKey, -) (*config.Config, error) { +) (*config.Config, []byte, error) { // Create a base relayer config config := relayer.CreateBaseRelayerConfig( logging.Info.LowerString(), @@ -300,10 +251,8 @@ func SetupRelayerConf( chain2RelayerKey.C(), chain2RelayerKey.PrivKeyHex(), ) - if err := relayer.SaveRelayerConfig(config, configPath); err != nil { - return nil, err - } - return config, nil + bs, err := relayer.SerializeRelayerConfig(config) + return config, bs, err } func StartLocalRelayer( @@ -338,7 +287,7 @@ func TestMessageDelivery( message []byte, ) error { // send message request to chain1 - tx, receipt, err := icm.SendCrossChainMessage( + tx, receipt, err := interchainmessenger.SendCrossChainMessage( chain1RPC, common.HexToAddress(chain1MessengerAddress), chain1PK, @@ -361,21 +310,16 @@ func TestMessageDelivery( } // get from chain1 event logs the message id - event, err := evm.GetEventFromLogs(receipt.Logs, icm.ParseSendCrossChainMessage) + event, err := evm.GetEventFromLogs(receipt.Logs, interchainmessenger.ParseSendCrossChainMessage) if err != nil { return err } messageID := event.MessageID - // also verifies some input params - if chain2BlockchainID != ids.ID(event.DestinationBlockchainID[:]) { - return fmt.Errorf("invalid destination blockchain id at source event, expected %s, got %s", chain2BlockchainID, ids.ID(event.DestinationBlockchainID[:])) - } - if string(message) != string(event.Message.Message) { - return fmt.Errorf("invalid message content at source event, expected %s, got %s", message, string(event.Message.Message)) - } + fmt.Println("Source Event Destination Blockchain ID: ", ids.ID(event.DestinationBlockchainID[:])) + fmt.Println("Source Event Message: ", string(event.Message.Message)) // wait for chain2 to receive the message - return icm.WaitForMessageReception( + return interchainmessenger.WaitForMessageReception( chain2RPC, chain2MessengerAddress, messageID, @@ -383,3 +327,69 @@ func TestMessageDelivery( 0, ) } + +// Fuji ICM Example +// +// Deploys ICM into CHAIN1_RPC and CHAIN2_RPC, +// paying deploy fees with CHAIN1_PK and CHAIN2_PK +// +// Downloads and executes a relayer in a local process +// and sets it to listen to CHAIN1 and CHAIN2. +// Subnet IDs and Blockchain IDs are provided to fulfill +// relayer conf +// +// All relayer data is saved into an existing RELAYER_DIR +// +// Example environment setup values: +// export CHAIN1_SUBNET_ID=2AgDoogVySMLkkqfMgzxWSKZWVVmXvNRVixQ5WL7fSUC7sRhTH +// export CHAIN1_BLOCKCHAIN_ID=2Z28jccJqQGCPdF5ee8P3aJq2fsrvyy6F4nhQphGJstTjk9ZsR +// export CHAIN1_RPC=http://36.172.121.333:9650/ext/bc/${CHAIN1_BLOCKCHAIN_ID}/rpc +// export CHAIN1_PK=(64 digit hexadecimal) +// export CHAIN2_SUBNET_ID=2YRENAJfNtBPYB6D4xC1pPV8tn2srdytrsJa6JC3neF2Au5FBc +// export CHAIN2_BLOCKCHAIN_ID=NJT2wqkbNNx9T2cAFsqLNfVVZDamyJyrbRS5fxtevBuMLHwJ8 +// export CHAIN2_RPC=http://36.172.121.123:9650/ext/bc/${CHAIN2_BLOCKCHAIN_ID}/rpc +// export CHAIN2_PK=3c82b8787e887a8798f922d95a948bcffa8d1989898a9898ffffee1000ed7c21 +// export CHAIN2_PK=(64 digit hexadecimal) +// export RELAYER_DIR=~/relayer_rundir/ +func Interchain() error { + chain1RPC := os.Getenv("CHAIN1_RPC") + chain1PK := os.Getenv("CHAIN1_PK") + chain1SubnetID, err := ids.FromString(os.Getenv("CHAIN1_SUBNET_ID")) + if err != nil { + return err + } + chain1BlockchainID, err := ids.FromString(os.Getenv("CHAIN1_BLOCKCHAIN_ID")) + if err != nil { + return err + } + chain2RPC := os.Getenv("CHAIN2_RPC") + chain2PK := os.Getenv("CHAIN2_PK") + chain2SubnetID, err := ids.FromString(os.Getenv("CHAIN2_SUBNET_ID")) + if err != nil { + return err + } + chain2BlockchainID, err := ids.FromString(os.Getenv("CHAIN2_BLOCKCHAIN_ID")) + if err != nil { + return err + } + relayerDir := os.Getenv("RELAYER_DIR") + if relayerDir == "" { + return fmt.Errorf("must define RELAYER_DIR env var") + } + relayerDir = utils.ExpandHome(relayerDir) + if !utils.DirectoryExists(relayerDir) { + return fmt.Errorf("relayer directory %q must exist", relayerDir) + } + return InterchainExample( + avalanche.FujiNetwork(), + chain1RPC, + chain1PK, + chain1SubnetID, + chain1BlockchainID, + chain2RPC, + chain2PK, + chain2SubnetID, + chain2BlockchainID, + relayerDir, + ) +} diff --git a/interchain/icm/icm.go b/interchain/interchainmessenger/interchain_messenger.go similarity index 99% rename from interchain/icm/icm.go rename to interchain/interchainmessenger/interchain_messenger.go index 2d83cf9..a2a048d 100644 --- a/interchain/icm/icm.go +++ b/interchain/interchainmessenger/interchain_messenger.go @@ -1,6 +1,6 @@ // Copyright (C) 2022, Ava Labs, Inc. All rights reserved. // See the file LICENSE for licensing terms. -package icm +package interchainmessenger import ( "fmt" diff --git a/interchain/icm/msg.go b/interchain/interchainmessenger/msg.go similarity index 99% rename from interchain/icm/msg.go rename to interchain/interchainmessenger/msg.go index 390b270..6368260 100644 --- a/interchain/icm/msg.go +++ b/interchain/interchainmessenger/msg.go @@ -1,6 +1,6 @@ // Copyright (C) 2022, Ava Labs, Inc. All rights reserved. // See the file LICENSE for licensing terms. -package icm +package interchainmessenger import ( "fmt" diff --git a/interchain/relayer/conf.go b/interchain/relayer/conf.go index aa942a9..9c92a17 100644 --- a/interchain/relayer/conf.go +++ b/interchain/relayer/conf.go @@ -6,11 +6,9 @@ import ( "encoding/json" "fmt" "math/big" - "os" "strings" "github.com/ava-labs/avalanche-tooling-sdk-go/avalanche" - "github.com/ava-labs/avalanche-tooling-sdk-go/constants" "github.com/ava-labs/avalanche-tooling-sdk-go/evm" "github.com/ava-labs/avalanche-tooling-sdk-go/utils" "github.com/ava-labs/avalanchego/ids" @@ -134,117 +132,16 @@ func FundRelayerAddress( ) } -func LoadRelayerConfig(relayerConfigPath string) (*config.Config, error) { +func UnserializeRelayerConfig(relayerConfigBytes []byte) (*config.Config, error) { relayerConfig := config.Config{} - bs, err := os.ReadFile(relayerConfigPath) - if err != nil { - return nil, err - } - if err := json.Unmarshal(bs, &relayerConfig); err != nil { + if err := json.Unmarshal(relayerConfigBytes, &relayerConfig); err != nil { return nil, err } return &relayerConfig, nil } -func SaveRelayerConfig(relayerConfig *config.Config, relayerConfigPath string) error { - bs, err := json.MarshalIndent(relayerConfig, "", " ") - if err != nil { - return err - } - return os.WriteFile(relayerConfigPath, bs, constants.WriteReadReadPerms) -} - -func CreateBaseRelayerConfigFile( - relayerConfigPath string, - logLevel string, - storageLocation string, - metricsPort uint16, - network avalanche.Network, -) error { - relayerConfig := CreateBaseRelayerConfig( - logLevel, - storageLocation, - metricsPort, - network, - ) - return SaveRelayerConfig(relayerConfig, relayerConfigPath) -} - -func AddSourceToRelayerConfigFile( - relayerConfigPath string, - rpcEndpoint string, - wsEndpoint string, - subnetID ids.ID, - blockchainID ids.ID, - icmRegistryAddress string, - icmMessengerAddress string, - relayerRewardAddress string, -) error { - relayerConfig, err := LoadRelayerConfig(relayerConfigPath) - if err != nil { - return err - } - AddSourceToRelayerConfig( - relayerConfig, - rpcEndpoint, - wsEndpoint, - subnetID, - blockchainID, - icmRegistryAddress, - icmMessengerAddress, - relayerRewardAddress, - ) - return SaveRelayerConfig(relayerConfig, relayerConfigPath) -} - -func AddDestinationToRelayerConfigFile( - relayerConfigPath string, - rpcEndpoint string, - subnetID ids.ID, - blockchainID ids.ID, - relayerPrivateKey string, -) error { - relayerConfig, err := LoadRelayerConfig(relayerConfigPath) - if err != nil { - return err - } - AddDestinationToRelayerConfig( - relayerConfig, - rpcEndpoint, - subnetID, - blockchainID, - relayerPrivateKey, - ) - return SaveRelayerConfig(relayerConfig, relayerConfigPath) -} - -func AddBlockchainToRelayerConfigFile( - relayerConfigPath string, - rpcEndpoint string, - wsEndpoint string, - subnetID ids.ID, - blockchainID ids.ID, - icmRegistryAddress string, - icmMessengerAddress string, - relayerRewardAddress string, - relayerPrivateKey string, -) error { - relayerConfig, err := LoadRelayerConfig(relayerConfigPath) - if err != nil { - return err - } - AddBlockchainToRelayerConfig( - relayerConfig, - rpcEndpoint, - wsEndpoint, - subnetID, - blockchainID, - icmRegistryAddress, - icmMessengerAddress, - relayerRewardAddress, - relayerPrivateKey, - ) - return SaveRelayerConfig(relayerConfig, relayerConfigPath) +func SerializeRelayerConfig(relayerConfig *config.Config) ([]byte, error) { + return json.MarshalIndent(relayerConfig, "", " ") } // Creates a base relayer config diff --git a/interchain/relayer/localrelayer/localrelayer.go b/interchain/relayer/localrelayer/localrelayer.go index 9c4f29b..e49b195 100644 --- a/interchain/relayer/localrelayer/localrelayer.go +++ b/interchain/relayer/localrelayer/localrelayer.go @@ -83,7 +83,11 @@ func WaitForInitialization( checkInterval time.Duration, checkTimeout time.Duration, ) error { - config, err := relayer.LoadRelayerConfig(configPath) + configBytes, err := os.ReadFile(configPath) + if err != nil { + return err + } + config, err := relayer.UnserializeRelayerConfig(configBytes) if err != nil { return err } diff --git a/node/dockerCompose.go b/node/docker_compose.go similarity index 100% rename from node/dockerCompose.go rename to node/docker_compose.go diff --git a/node/dockerConfig.go b/node/docker_config.go similarity index 100% rename from node/dockerConfig.go rename to node/docker_config.go diff --git a/node/dockerImage.go b/node/docker_image.go similarity index 100% rename from node/dockerImage.go rename to node/docker_image.go diff --git a/node/dockerSsh.go b/node/docker_ssh.go similarity index 100% rename from node/dockerSsh.go rename to node/docker_ssh.go diff --git a/node/nodeResult.go b/node/node_result.go similarity index 100% rename from node/nodeResult.go rename to node/node_result.go diff --git a/vm/evmSettings.go b/vm/evm_settings.go similarity index 100% rename from vm/evmSettings.go rename to vm/evm_settings.go From 0c724494e254bdeb025c2f57a957cb11bdf6973f Mon Sep 17 00:00:00 2001 From: Felipe Madero Date: Tue, 3 Sep 2024 11:31:25 -0300 Subject: [PATCH 19/19] nit --- .../{interchain_messenger.go => interchainmessenger.go} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename interchain/interchainmessenger/{interchain_messenger.go => interchainmessenger.go} (100%) diff --git a/interchain/interchainmessenger/interchain_messenger.go b/interchain/interchainmessenger/interchainmessenger.go similarity index 100% rename from interchain/interchainmessenger/interchain_messenger.go rename to interchain/interchainmessenger/interchainmessenger.go