diff --git a/changelog.md b/changelog.md index 1506dee6ee..9f40d4b256 100644 --- a/changelog.md +++ b/changelog.md @@ -55,6 +55,7 @@ * [2357](https://github.com/zeta-chain/node/pull/2357) - integrate base Signer structure into EVM/Bitcoin Signer * [2359](https://github.com/zeta-chain/node/pull/2359) - integrate base Observer structure into EVM/Bitcoin Observer * [2375](https://github.com/zeta-chain/node/pull/2375) - improve & speedup code formatting +* [2380](https://github.com/zeta-chain/node/pull/2380) - use `ChainInfo` in `authority` to allow dynamically support new chains * [2395](https://github.com/zeta-chain/node/pull/2395) - converge AppContext with ZetaCoreContext in zetaclient ### Tests diff --git a/cmd/zetaclientd/debug.go b/cmd/zetaclientd/debug.go index 08aadbe8a4..28a3932a8d 100644 --- a/cmd/zetaclientd/debug.go +++ b/cmd/zetaclientd/debug.go @@ -86,20 +86,20 @@ func debugCmd(_ *cobra.Command, args []string) error { if err != nil { return err } - chain := chains.GetChainFromChainID(chainID) - if chain == nil { + chain, found := chains.GetChainFromChainID(chainID, appContext.GetAdditionalChains()) + if !found { return fmt.Errorf("invalid chain id") } // get ballot identifier according to the chain type - if chains.IsEVMChain(chain.ChainId) { + if chains.IsEVMChain(chain.ChainId, appContext.GetAdditionalChains()) { evmObserver := evmobserver.Observer{} evmObserver.WithZetacoreClient(client) var ethRPC *ethrpc.EthRPC var client *ethclient.Client coinType := coin.CoinType_Cmd - for chain, evmConfig := range cfg.GetAllEVMConfigs() { - if chainID == chain { + for chainIDFromConfig, evmConfig := range cfg.GetAllEVMConfigs() { + if chainIDFromConfig == chainID { ethRPC = ethrpc.NewEthRPC(evmConfig.Endpoint) client, err = ethclient.Dial(evmConfig.Endpoint) if err != nil { @@ -107,7 +107,7 @@ func debugCmd(_ *cobra.Command, args []string) error { } evmObserver.WithEvmClient(client) evmObserver.WithEvmJSONRPC(ethRPC) - evmObserver.WithChain(*chains.GetChainFromChainID(chainID)) + evmObserver.WithChain(chain) } } hash := ethcommon.HexToHash(inboundHash) @@ -168,10 +168,10 @@ func debugCmd(_ *cobra.Command, args []string) error { fmt.Println("CoinType not detected") } fmt.Println("CoinType : ", coinType) - } else if chains.IsBitcoinChain(chain.ChainId) { + } else if chains.IsBitcoinChain(chain.ChainId, appContext.GetAdditionalChains()) { btcObserver := btcobserver.Observer{} btcObserver.WithZetacoreClient(client) - btcObserver.WithChain(*chains.GetChainFromChainID(chainID)) + btcObserver.WithChain(chain) connCfg := &rpcclient.ConnConfig{ Host: cfg.BitcoinConfig.RPCHost, User: cfg.BitcoinConfig.RPCUsername, diff --git a/pkg/chains/chain.go b/pkg/chains/chain.go index 681e13a5ae..46ead5f9f2 100644 --- a/pkg/chains/chain.go +++ b/pkg/chains/chain.go @@ -5,15 +5,9 @@ import ( "strings" "github.com/btcsuite/btcd/chaincfg" - "github.com/btcsuite/btcutil" ethcommon "github.com/ethereum/go-ethereum/common" ) -type SigninAlgo string - -// Chains represent a slice of Chain -type Chains []Chain - // Validate checks whether the chain is valid // The function check the chain ID is positive and all enum fields have a defined value func (chain Chain) Validate() error { @@ -44,11 +38,6 @@ func (chain Chain) Validate() error { return nil } -// IsEqual compare two chain to see whether they represent the same chain -func (chain Chain) IsEqual(c Chain) bool { - return chain.ChainId == c.ChainId -} - // IsZetaChain returns true if the chain is a ZetaChain chain func (chain Chain) IsZetaChain() bool { return chain.Network == Network_zeta @@ -63,13 +52,13 @@ func (chain Chain) IsExternalChain() bool { // on EVM chain, it is 20Bytes // on Bitcoin chain, it is P2WPKH address, []byte(bech32 encoded string) func (chain Chain) EncodeAddress(b []byte) (string, error) { - if IsEVMChain(chain.ChainId) { + if chain.Consensus == Consensus_ethereum { addr := ethcommon.BytesToAddress(b) if addr == (ethcommon.Address{}) { return "", fmt.Errorf("invalid EVM address") } return addr.Hex(), nil - } else if IsBitcoinChain(chain.ChainId) { + } else if chain.Consensus == Consensus_bitcoin { addrStr := string(b) chainParams, err := GetBTCChainParams(chain.ChainId) if err != nil { @@ -87,61 +76,54 @@ func (chain Chain) EncodeAddress(b []byte) (string, error) { return "", fmt.Errorf("chain (%d) not supported", chain.ChainId) } -func (chain Chain) BTCAddressFromWitnessProgram(witnessProgram []byte) (string, error) { - chainParams, err := GetBTCChainParams(chain.ChainId) - if err != nil { - return "", err - } - address, err := btcutil.NewAddressWitnessPubKeyHash(witnessProgram, chainParams) - if err != nil { - return "", err - } - return address.EncodeAddress(), nil +func (chain Chain) IsEVMChain() bool { + return chain.Consensus == Consensus_ethereum } -// DecodeAddress decode the address string to bytes -func (chain Chain) DecodeAddress(addr string) ([]byte, error) { - return DecodeAddressFromChainID(chain.ChainId, addr) +func (chain Chain) IsBitcoinChain() bool { + return chain.Consensus == Consensus_bitcoin } // DecodeAddressFromChainID decode the address string to bytes -func DecodeAddressFromChainID(chainID int64, addr string) ([]byte, error) { - if IsEVMChain(chainID) { +// additionalChains is a list of additional chains to search from +// in practice, it is used in the protocol to dynamically support new chains without doing an upgrade +func DecodeAddressFromChainID(chainID int64, addr string, additionalChains []Chain) ([]byte, error) { + switch { + case IsEVMChain(chainID, additionalChains): return ethcommon.HexToAddress(addr).Bytes(), nil - } else if IsBitcoinChain(chainID) { + case IsBitcoinChain(chainID, additionalChains): return []byte(addr), nil + default: + return nil, fmt.Errorf("chain (%d) not supported", chainID) } - return nil, fmt.Errorf("chain (%d) not supported", chainID) } // IsEVMChain returns true if the chain is an EVM chain or uses the ethereum consensus mechanism for block finality -func IsEVMChain(chainID int64) bool { - return ChainIDInChainList(chainID, ChainListByConsensus(Consensus_ethereum)) +// additionalChains is a list of additional chains to search from +// in practice, it is used in the protocol to dynamically support new chains without doing an upgrade +func IsEVMChain(chainID int64, additionalChains []Chain) bool { + return ChainIDInChainList(chainID, ChainListByConsensus(Consensus_ethereum, additionalChains)) } // IsBitcoinChain returns true if the chain is a Bitcoin-based chain or uses the bitcoin consensus mechanism for block finality -func IsBitcoinChain(chainID int64) bool { - return ChainIDInChainList(chainID, ChainListByConsensus(Consensus_bitcoin)) +// additionalChains is a list of additional chains to search from +// in practice, it is used in the protocol to dynamically support new chains without doing an upgrade +func IsBitcoinChain(chainID int64, additionalChains []Chain) bool { + return ChainIDInChainList(chainID, ChainListByConsensus(Consensus_bitcoin, additionalChains)) } // IsEthereumChain returns true if the chain is an Ethereum chain -func IsEthereumChain(chainID int64) bool { - return ChainIDInChainList(chainID, ChainListByNetwork(Network_eth)) +// additionalChains is a list of additional chains to search from +// in practice, it is used in the protocol to dynamically support new chains without doing an upgrade +func IsEthereumChain(chainID int64, additionalChains []Chain) bool { + return ChainIDInChainList(chainID, ChainListByNetwork(Network_eth, additionalChains)) } // IsZetaChain returns true if the chain is a Zeta chain -func IsZetaChain(chainID int64) bool { - return ChainIDInChainList(chainID, ChainListByNetwork(Network_zeta)) -} - -// IsHeaderSupportedChain returns true if the chain's consensus supports block header-based verification -func IsHeaderSupportedChain(chainID int64) bool { - return ChainIDInChainList(chainID, ChainListForHeaderSupport()) -} - -// SupportMerkleProof returns true if the chain supports block header-based verification -func (chain Chain) SupportMerkleProof() bool { - return IsEVMChain(chain.ChainId) || IsBitcoinChain(chain.ChainId) +// additionalChains is a list of additional chains to search from +// in practice, it is used in the protocol to dynamically support new chains without doing an upgrade +func IsZetaChain(chainID int64, additionalChains []Chain) bool { + return ChainIDInChainList(chainID, ChainListByNetwork(Network_zeta, additionalChains)) } // IsEmpty is to determinate whether the chain is empty @@ -149,45 +131,20 @@ func (chain Chain) IsEmpty() bool { return strings.TrimSpace(chain.String()) == "" } -// Has check whether chain c is in the list -func (chains Chains) Has(c Chain) bool { - for _, ch := range chains { - if ch.IsEqual(c) { - return true - } - } - return false -} - -// Distinct return a distinct set of chains, no duplicates -func (chains Chains) Distinct() Chains { - var newChains Chains - for _, chain := range chains { - if !newChains.Has(chain) { - newChains = append(newChains, chain) - } - } - return newChains -} - -func (chains Chains) Strings() []string { - str := make([]string, len(chains)) - for i, c := range chains { - str[i] = c.String() - } - return str -} - -func GetChainFromChainID(chainID int64) *Chain { - chains := DefaultChainsList() +// GetChainFromChainID returns the chain from the chain ID +// additionalChains is a list of additional chains to search from +// in practice, it is used in the protocol to dynamically support new chains without doing an upgrade +func GetChainFromChainID(chainID int64, additionalChains []Chain) (Chain, bool) { + chains := CombineDefaultChainsList(additionalChains) for _, chain := range chains { if chainID == chain.ChainId { - return chain + return chain, true } } - return nil + return Chain{}, false } +// GetBTCChainParams returns the bitcoin chain config params from the chain ID func GetBTCChainParams(chainID int64) (*chaincfg.Params, error) { switch chainID { case 18444: @@ -201,6 +158,7 @@ func GetBTCChainParams(chainID int64) (*chaincfg.Params, error) { } } +// GetBTCChainIDFromChainParams returns the bitcoin chain ID from the chain config params func GetBTCChainIDFromChainParams(params *chaincfg.Params) (int64, error) { switch params.Name { case chaincfg.RegressionNetParams.Name: @@ -214,13 +172,8 @@ func GetBTCChainIDFromChainParams(params *chaincfg.Params) (int64, error) { } } -// InChainList checks whether the chain is in the chain list -func (chain Chain) InChainList(chainList []*Chain) bool { - return ChainIDInChainList(chain.ChainId, chainList) -} - // ChainIDInChainList checks whether the chainID is in the chain list -func ChainIDInChainList(chainID int64, chainList []*Chain) bool { +func ChainIDInChainList(chainID int64, chainList []Chain) bool { for _, c := range chainList { if chainID == c.ChainId { return true diff --git a/pkg/chains/chain_test.go b/pkg/chains/chain_test.go index d14fd39a37..f495ba0c85 100644 --- a/pkg/chains/chain_test.go +++ b/pkg/chains/chain_test.go @@ -1,121 +1,120 @@ -package chains +package chains_test import ( - "encoding/hex" + "github.com/zeta-chain/zetacore/testutil/sample" "testing" - "github.com/btcsuite/btcd/btcec" "github.com/btcsuite/btcd/chaincfg" - "github.com/btcsuite/btcutil" ethcommon "github.com/ethereum/go-ethereum/common" "github.com/stretchr/testify/require" + "github.com/zeta-chain/zetacore/pkg/chains" ) func TestChain_Validate(t *testing.T) { tests := []struct { name string - chain Chain + chain chains.Chain errStr string }{ { name: "should pass if chain is valid", - chain: Chain{ + chain: chains.Chain{ ChainId: 42, - ChainName: ChainName_empty, - Network: Network_optimism, - NetworkType: NetworkType_testnet, - Vm: Vm_evm, - Consensus: Consensus_op_stack, + ChainName: chains.ChainName_empty, + Network: chains.Network_optimism, + NetworkType: chains.NetworkType_testnet, + Vm: chains.Vm_evm, + Consensus: chains.Consensus_op_stack, IsExternal: true, }, }, { name: "should error if chain ID is zero", - chain: Chain{ + chain: chains.Chain{ ChainId: 0, - ChainName: ChainName_empty, - Network: Network_optimism, - NetworkType: NetworkType_testnet, - Vm: Vm_evm, - Consensus: Consensus_op_stack, + ChainName: chains.ChainName_empty, + Network: chains.Network_optimism, + NetworkType: chains.NetworkType_testnet, + Vm: chains.Vm_evm, + Consensus: chains.Consensus_op_stack, IsExternal: true, }, errStr: "chain ID must be positive", }, { name: "should error if chain ID is negative", - chain: Chain{ + chain: chains.Chain{ ChainId: 0, - ChainName: ChainName_empty, - Network: Network_optimism, - NetworkType: NetworkType_testnet, - Vm: Vm_evm, - Consensus: Consensus_op_stack, + ChainName: chains.ChainName_empty, + Network: chains.Network_optimism, + NetworkType: chains.NetworkType_testnet, + Vm: chains.Vm_evm, + Consensus: chains.Consensus_op_stack, IsExternal: true, }, errStr: "chain ID must be positive", }, { name: "should error if chain name invalid", - chain: Chain{ + chain: chains.Chain{ ChainId: 42, - ChainName: ChainName_base_sepolia + 1, - Network: Network_optimism, - NetworkType: NetworkType_testnet, - Vm: Vm_evm, - Consensus: Consensus_op_stack, + ChainName: chains.ChainName_base_sepolia + 1, + Network: chains.Network_optimism, + NetworkType: chains.NetworkType_testnet, + Vm: chains.Vm_evm, + Consensus: chains.Consensus_op_stack, IsExternal: true, }, errStr: "invalid chain name", }, { name: "should error if network invalid", - chain: Chain{ + chain: chains.Chain{ ChainId: 42, - ChainName: ChainName_empty, - Network: Network_base + 1, - NetworkType: NetworkType_testnet, - Vm: Vm_evm, - Consensus: Consensus_op_stack, + ChainName: chains.ChainName_empty, + Network: chains.Network_base + 1, + NetworkType: chains.NetworkType_testnet, + Vm: chains.Vm_evm, + Consensus: chains.Consensus_op_stack, IsExternal: true, }, errStr: "invalid network", }, { name: "should error if network type invalid", - chain: Chain{ + chain: chains.Chain{ ChainId: 42, - ChainName: ChainName_empty, - Network: Network_base, - NetworkType: NetworkType_devnet + 1, - Vm: Vm_evm, - Consensus: Consensus_op_stack, + ChainName: chains.ChainName_empty, + Network: chains.Network_base, + NetworkType: chains.NetworkType_devnet + 1, + Vm: chains.Vm_evm, + Consensus: chains.Consensus_op_stack, IsExternal: true, }, errStr: "invalid network type", }, { name: "should error if vm invalid", - chain: Chain{ + chain: chains.Chain{ ChainId: 42, - ChainName: ChainName_empty, - Network: Network_base, - NetworkType: NetworkType_devnet, - Vm: Vm_evm + 1, - Consensus: Consensus_op_stack, + ChainName: chains.ChainName_empty, + Network: chains.Network_base, + NetworkType: chains.NetworkType_devnet, + Vm: chains.Vm_evm + 1, + Consensus: chains.Consensus_op_stack, IsExternal: true, }, errStr: "invalid vm", }, { name: "should error if consensus invalid", - chain: Chain{ + chain: chains.Chain{ ChainId: 42, - ChainName: ChainName_empty, - Network: Network_base, - NetworkType: NetworkType_devnet, - Vm: Vm_evm, - Consensus: Consensus_op_stack + 1, + ChainName: chains.ChainName_empty, + Network: chains.Network_base, + NetworkType: chains.NetworkType_devnet, + Vm: chains.Vm_evm, + Consensus: chains.Consensus_op_stack + 1, IsExternal: true, }, errStr: "invalid consensus", @@ -132,7 +131,7 @@ func TestChain_Validate(t *testing.T) { } t.Run("all default chains are valid", func(t *testing.T) { - for _, chain := range DefaultChainsList() { + for _, chain := range chains.DefaultChainsList() { require.NoError(t, chain.Validate()) } }) @@ -141,16 +140,17 @@ func TestChain_Validate(t *testing.T) { func TestChain_EncodeAddress(t *testing.T) { tests := []struct { name string - chain Chain + chain chains.Chain b []byte want string wantErr bool }{ { name: "should error if b is not a valid address on the bitcoin network", - chain: Chain{ - ChainName: ChainName_btc_testnet, + chain: chains.Chain{ + ChainName: chains.ChainName_btc_testnet, ChainId: 18332, + Consensus: chains.Consensus_bitcoin, }, b: []byte("bc1qk0cc73p8m7hswn8y2q080xa4e5pxapnqgp7h9c"), want: "", @@ -158,9 +158,10 @@ func TestChain_EncodeAddress(t *testing.T) { }, { name: "should pass if b is a valid address on the network", - chain: Chain{ - ChainName: ChainName_btc_mainnet, + chain: chains.Chain{ + ChainName: chains.ChainName_btc_mainnet, ChainId: 8332, + Consensus: chains.Consensus_bitcoin, }, b: []byte("bc1qk0cc73p8m7hswn8y2q080xa4e5pxapnqgp7h9c"), want: "bc1qk0cc73p8m7hswn8y2q080xa4e5pxapnqgp7h9c", @@ -168,8 +169,8 @@ func TestChain_EncodeAddress(t *testing.T) { }, { name: "should error if b is not a valid address on the evm network", - chain: Chain{ - ChainName: ChainName_goerli_testnet, + chain: chains.Chain{ + ChainName: chains.ChainName_goerli_testnet, ChainId: 5, }, b: ethcommon.Hex2Bytes("0x321"), @@ -178,8 +179,8 @@ func TestChain_EncodeAddress(t *testing.T) { }, { name: "should pass if b is a valid address on the evm network", - chain: Chain{ - ChainName: ChainName_goerli_testnet, + chain: chains.Chain{ + ChainName: chains.ChainName_goerli_testnet, ChainId: 5, }, b: []byte("0x321"), @@ -188,7 +189,7 @@ func TestChain_EncodeAddress(t *testing.T) { }, { name: "should error if chain not supported", - chain: Chain{ + chain: chains.Chain{ ChainName: 999, ChainId: 999, }, @@ -211,146 +212,125 @@ func TestChain_EncodeAddress(t *testing.T) { } } -func TestChain_DecodeAddress(t *testing.T) { +func TestChain_IsEVMChain(t *testing.T) { tests := []struct { - name string - chain Chain - b string - want []byte - wantErr bool + name string + chain chains.Chain + want bool }{ - { - name: "should decode on btc chain", - chain: Chain{ - ChainName: ChainName_btc_testnet, - ChainId: 18332, - }, - want: []byte("bc1qk0cc73p8m7hswn8y2q080xa4e5pxapnqgp7h9c"), - b: "bc1qk0cc73p8m7hswn8y2q080xa4e5pxapnqgp7h9c", - wantErr: false, - }, - { - name: "should decode on evm chain", - chain: Chain{ - ChainName: ChainName_goerli_testnet, - ChainId: 5, - }, - want: ethcommon.HexToAddress("0x321").Bytes(), - b: "0x321", - wantErr: false, - }, - { - name: "should error if chain not supported", - chain: Chain{ - ChainName: 999, - ChainId: 999, - }, - want: ethcommon.Hex2Bytes("0x321"), - b: "", - wantErr: true, - }, + {"Ethereum Mainnet", chains.Ethereum, true}, + {"Goerli Testnet", chains.Goerli, true}, + {"Sepolia Testnet", chains.Sepolia, true}, + {"Non-EVM", chains.BitcoinMainnet, false}, + {"Zeta Mainnet", chains.ZetaChainMainnet, false}, } - for _, tc := range tests { - tc := tc - t.Run(tc.name, func(t *testing.T) { - s, err := tc.chain.DecodeAddress(tc.b) - if tc.wantErr { - require.Error(t, err) - return - } - require.Equal(t, tc.want, s) + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + require.Equal(t, tt.want, tt.chain.IsEVMChain()) }) } } -func TestChain_InChainList(t *testing.T) { - require.True(t, ZetaChainMainnet.InChainList(ChainListByNetwork(Network_zeta))) - require.True(t, ZetaChainDevnet.InChainList(ChainListByNetwork(Network_zeta))) - require.True(t, ZetaChainPrivnet.InChainList(ChainListByNetwork(Network_zeta))) - require.True(t, ZetaChainTestnet.InChainList(ChainListByNetwork(Network_zeta))) - require.False(t, Ethereum.InChainList(ChainListByNetwork(Network_zeta))) -} - -func TestIsZetaChain(t *testing.T) { +func TestChain_IsBitcoinChain(t *testing.T) { tests := []struct { - name string - chainID int64 - want bool + name string + chain chains.Chain + want bool }{ - {"Zeta Mainnet", ZetaChainMainnet.ChainId, true}, - {"Zeta Testnet", ZetaChainTestnet.ChainId, true}, - {"Zeta Mocknet", ZetaChainDevnet.ChainId, true}, - {"Zeta Privnet", ZetaChainPrivnet.ChainId, true}, - {"Non-Zeta", Ethereum.ChainId, false}, + {"Bitcoin Mainnet", chains.BitcoinMainnet, true}, + {"Bitcoin Testnet", chains.BitcoinTestnet, true}, + {"Bitcoin Regtest", chains.BitcoinRegtest, true}, + {"Non-Bitcoin", chains.Ethereum, false}, + {"Zeta Mainnet", chains.ZetaChainMainnet, false}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - require.Equal(t, tt.want, IsZetaChain(tt.chainID)) + require.Equal(t, tt.want, tt.chain.IsBitcoinChain()) }) } } -func TestIsEVMChain(t *testing.T) { +func TestIsZetaChain(t *testing.T) { tests := []struct { name string chainID int64 want bool }{ - {"Ethereum Mainnet", Ethereum.ChainId, true}, - {"Goerli Testnet", Goerli.ChainId, true}, - {"Sepolia Testnet", Sepolia.ChainId, true}, - {"Non-EVM", BitcoinMainnet.ChainId, false}, - {"Zeta Mainnet", ZetaChainMainnet.ChainId, false}, + {"Zeta Mainnet", chains.ZetaChainMainnet.ChainId, true}, + {"Zeta Testnet", chains.ZetaChainTestnet.ChainId, true}, + {"Zeta Mocknet", chains.ZetaChainDevnet.ChainId, true}, + {"Zeta Privnet", chains.ZetaChainPrivnet.ChainId, true}, + {"Non-Zeta", chains.Ethereum.ChainId, false}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - require.Equal(t, tt.want, IsEVMChain(tt.chainID)) + require.Equal(t, tt.want, chains.IsZetaChain(tt.chainID, []chains.Chain{})) }) } } -func TestIsHeaderSupportedChain(t *testing.T) { +func TestDecodeAddressFromChainID(t *testing.T) { + ethAddr := sample.EthAddress() + tests := []struct { name string chainID int64 - want bool + addr string + want []byte + wantErr bool }{ - {"Ethereum Mainnet", Ethereum.ChainId, true}, - {"Goerli Testnet", Goerli.ChainId, true}, - {"Goerli Localnet", GoerliLocalnet.ChainId, true}, - {"Sepolia Testnet", Sepolia.ChainId, true}, - {"BSC Testnet", BscTestnet.ChainId, true}, - {"BSC Mainnet", BscMainnet.ChainId, true}, - {"BTC", BitcoinMainnet.ChainId, true}, - {"Zeta Mainnet", ZetaChainMainnet.ChainId, false}, + { + name: "Ethereum", + chainID: chains.Ethereum.ChainId, + addr: ethAddr.Hex(), + want: ethAddr.Bytes(), + }, + { + name: "Bitcoin", + chainID: chains.BitcoinMainnet.ChainId, + addr: "bc1qk0cc73p8m7hswn8y2q080xa4e5pxapnqgp7h9c", + want: []byte("bc1qk0cc73p8m7hswn8y2q080xa4e5pxapnqgp7h9c"), + }, + { + name: "Non-supported chain", + chainID: 9999, + wantErr: true, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - require.Equal(t, tt.want, IsHeaderSupportedChain(tt.chainID)) + got, err := chains.DecodeAddressFromChainID(tt.chainID, tt.addr, []chains.Chain{}) + if tt.wantErr { + require.Error(t, err) + return + } + require.NoError(t, err) + require.Equal(t, tt.want, got) }) + } } -func TestSupportMerkleProof(t *testing.T) { +func TestIsEVMChain(t *testing.T) { tests := []struct { - name string - chain Chain - want bool + name string + chainID int64 + want bool }{ - {"Ethereum Mainnet", Ethereum, true}, - {"BSC Testnet", BscTestnet, true}, - {"BSC Mainnet", BscMainnet, true}, - {"Non-EVM", BitcoinMainnet, true}, - {"Zeta Mainnet", ZetaChainMainnet, false}, + {"Ethereum Mainnet", chains.Ethereum.ChainId, true}, + {"Goerli Testnet", chains.Goerli.ChainId, true}, + {"Sepolia Testnet", chains.Sepolia.ChainId, true}, + {"Non-EVM", chains.BitcoinMainnet.ChainId, false}, + {"Zeta Mainnet", chains.ZetaChainMainnet.ChainId, false}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - require.Equal(t, tt.want, tt.chain.SupportMerkleProof()) + require.Equal(t, tt.want, chains.IsEVMChain(tt.chainID, []chains.Chain{})) }) } } @@ -361,16 +341,16 @@ func TestIsBitcoinChain(t *testing.T) { chainID int64 want bool }{ - {"Bitcoin Mainnet", BitcoinMainnet.ChainId, true}, - {"Bitcoin Testnet", BitcoinTestnet.ChainId, true}, - {"Bitcoin Regtest", BitcoinRegtest.ChainId, true}, - {"Non-Bitcoin", Ethereum.ChainId, false}, - {"Zeta Mainnet", ZetaChainMainnet.ChainId, false}, + {"Bitcoin Mainnet", chains.BitcoinMainnet.ChainId, true}, + {"Bitcoin Testnet", chains.BitcoinTestnet.ChainId, true}, + {"Bitcoin Regtest", chains.BitcoinRegtest.ChainId, true}, + {"Non-Bitcoin", chains.Ethereum.ChainId, false}, + {"Zeta Mainnet", chains.ZetaChainMainnet.ChainId, false}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - require.Equal(t, tt.want, IsBitcoinChain(tt.chainID)) + require.Equal(t, tt.want, chains.IsBitcoinChain(tt.chainID, []chains.Chain{})) }) } } @@ -381,128 +361,82 @@ func TestIsEthereumChain(t *testing.T) { chainID int64 want bool }{ - {"Ethereum Mainnet", Ethereum.ChainId, true}, - {"Goerli Testnet", Goerli.ChainId, true}, - {"Sepolia Testnet", Sepolia.ChainId, true}, - {"Non-Ethereum", BitcoinMainnet.ChainId, false}, - {"Zeta Mainnet", ZetaChainMainnet.ChainId, false}, + {"Ethereum Mainnet", chains.Ethereum.ChainId, true}, + {"Goerli Testnet", chains.Goerli.ChainId, true}, + {"Sepolia Testnet", chains.Sepolia.ChainId, true}, + {"Non-Ethereum", chains.BitcoinMainnet.ChainId, false}, + {"Zeta Mainnet", chains.ZetaChainMainnet.ChainId, false}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - require.Equal(t, tt.want, IsEthereumChain(tt.chainID)) + require.Equal(t, tt.want, chains.IsEthereumChain(tt.chainID, []chains.Chain{})) }) } } func TestChain_IsExternalChain(t *testing.T) { - require.False(t, ZetaChainMainnet.IsExternalChain()) - require.True(t, Ethereum.IsExternalChain()) + require.False(t, chains.ZetaChainMainnet.IsExternalChain()) + require.True(t, chains.Ethereum.IsExternalChain()) } func TestChain_IsZetaChain(t *testing.T) { - require.True(t, ZetaChainMainnet.IsZetaChain()) - require.False(t, Ethereum.IsZetaChain()) + require.True(t, chains.ZetaChainMainnet.IsZetaChain()) + require.False(t, chains.Ethereum.IsZetaChain()) } func TestChain_IsEmpty(t *testing.T) { - require.True(t, Chain{}.IsEmpty()) - require.False(t, ZetaChainMainnet.IsEmpty()) -} - -func TestChain_WitnessProgram(t *testing.T) { - // Ordinarily the private key would come from whatever storage mechanism - // is being used, but for this example just hard code it. - privKeyBytes, err := hex.DecodeString("22a47fa09a223f2aa079edf85a7c2" + - "d4f8720ee63e502ee2869afab7de234b80c") - require.NoError(t, err) - - t.Run("should return btc address", func(t *testing.T) { - _, pubKey := btcec.PrivKeyFromBytes(btcec.S256(), privKeyBytes) - pubKeyHash := btcutil.Hash160(pubKey.SerializeCompressed()) - addr, err := btcutil.NewAddressWitnessPubKeyHash(pubKeyHash, &chaincfg.RegressionNetParams) - require.NoError(t, err) - - chain := BitcoinTestnet - _, err = chain.BTCAddressFromWitnessProgram(addr.WitnessProgram()) - require.NoError(t, err) - }) - - t.Run("should fail for wrong chain id", func(t *testing.T) { - _, pubKey := btcec.PrivKeyFromBytes(btcec.S256(), privKeyBytes) - pubKeyHash := btcutil.Hash160(pubKey.SerializeCompressed()) - addr, err := btcutil.NewAddressWitnessPubKeyHash(pubKeyHash, &chaincfg.RegressionNetParams) - require.NoError(t, err) - - chain := Goerli - _, err = chain.BTCAddressFromWitnessProgram(addr.WitnessProgram()) - require.Error(t, err) - }) - - t.Run("should fail for wrong witness program", func(t *testing.T) { - _, pubKey := btcec.PrivKeyFromBytes(btcec.S256(), privKeyBytes) - pubKeyHash := btcutil.Hash160(pubKey.SerializeCompressed()) - addr, err := btcutil.NewAddressWitnessPubKeyHash(pubKeyHash, &chaincfg.RegressionNetParams) - require.NoError(t, err) - - chain := BitcoinTestnet - _, err = chain.BTCAddressFromWitnessProgram(addr.WitnessProgram()[0:19]) - require.Error(t, err) - }) -} - -func TestChains_Has(t *testing.T) { - chains := Chains{ZetaChainMainnet, ZetaChainTestnet} - require.True(t, chains.Has(ZetaChainMainnet)) - require.False(t, chains.Has(Ethereum)) -} - -func TestChains_Distinct(t *testing.T) { - chains := Chains{ZetaChainMainnet, ZetaChainMainnet, ZetaChainTestnet} - distinctChains := chains.Distinct() - require.Len(t, distinctChains, 2) -} - -func TestChains_Strings(t *testing.T) { - chains := Chains{ZetaChainMainnet, ZetaChainTestnet} - strings := chains.Strings() - expected := []string{chains[0].String(), chains[1].String()} - require.Equal(t, expected, strings) + require.True(t, chains.Chain{}.IsEmpty()) + require.False(t, chains.ZetaChainMainnet.IsEmpty()) } func TestGetChainFromChainID(t *testing.T) { - chain := GetChainFromChainID(ZetaChainMainnet.ChainId) - require.Equal(t, ZetaChainMainnet, *chain) - require.Nil(t, GetChainFromChainID(9999)) + chain, found := chains.GetChainFromChainID(chains.ZetaChainMainnet.ChainId, []chains.Chain{}) + require.EqualValues(t, chains.ZetaChainMainnet, chain) + require.True(t, found) + chain, found = chains.GetChainFromChainID(9999, []chains.Chain{}) + require.False(t, found) } func TestGetBTCChainParams(t *testing.T) { - params, err := GetBTCChainParams(BitcoinMainnet.ChainId) + params, err := chains.GetBTCChainParams(chains.BitcoinMainnet.ChainId) require.NoError(t, err) require.Equal(t, &chaincfg.MainNetParams, params) - _, err = GetBTCChainParams(9999) + _, err = chains.GetBTCChainParams(9999) require.Error(t, err) } func TestGetBTCChainIDFromChainParams(t *testing.T) { - chainID, err := GetBTCChainIDFromChainParams(&chaincfg.MainNetParams) + chainID, err := chains.GetBTCChainIDFromChainParams(&chaincfg.MainNetParams) require.NoError(t, err) require.Equal(t, int64(8332), chainID) - chainID, err = GetBTCChainIDFromChainParams(&chaincfg.RegressionNetParams) + chainID, err = chains.GetBTCChainIDFromChainParams(&chaincfg.RegressionNetParams) require.NoError(t, err) require.Equal(t, int64(18444), chainID) - chainID, err = GetBTCChainIDFromChainParams(&chaincfg.TestNet3Params) + chainID, err = chains.GetBTCChainIDFromChainParams(&chaincfg.TestNet3Params) require.NoError(t, err) require.Equal(t, int64(18332), chainID) - _, err = GetBTCChainIDFromChainParams(&chaincfg.Params{Name: "unknown"}) + _, err = chains.GetBTCChainIDFromChainParams(&chaincfg.Params{Name: "unknown"}) require.Error(t, err) } func TestChainIDInChainList(t *testing.T) { - require.True(t, ChainIDInChainList(ZetaChainMainnet.ChainId, ChainListByNetwork(Network_zeta))) - require.False(t, ChainIDInChainList(Ethereum.ChainId, ChainListByNetwork(Network_zeta))) + require.True( + t, + chains.ChainIDInChainList( + chains.ZetaChainMainnet.ChainId, + chains.ChainListByNetwork(chains.Network_zeta, []chains.Chain{}), + ), + ) + require.False( + t, + chains.ChainIDInChainList( + chains.Ethereum.ChainId, + chains.ChainListByNetwork(chains.Network_zeta, []chains.Chain{}), + ), + ) } diff --git a/pkg/chains/chains.go b/pkg/chains/chains.go index 11c6f952f0..333aa22001 100644 --- a/pkg/chains/chains.go +++ b/pkg/chains/chains.go @@ -265,14 +265,17 @@ var ( } ) +// ErrNotZetaChain is the error for chain not being a ZetaChain chain +var ErrNotZetaChain = fmt.Errorf("chain is not a ZetaChain chain") + // BtcNonceMarkOffset is the offset satoshi amount to calculate the nonce mark output func BtcNonceMarkOffset() int64 { return 2000 } // DefaultChainsList returns a list of default chains -func DefaultChainsList() []*Chain { - return chainListPointers([]Chain{ +func DefaultChainsList() []Chain { + return []Chain{ BitcoinMainnet, BscMainnet, Ethereum, @@ -293,13 +296,13 @@ func DefaultChainsList() []*Chain { OptimismSepolia, BaseMainnet, BaseSepolia, - }) + } } // ChainListByNetworkType returns a list of chains by network type -func ChainListByNetworkType(networkType NetworkType) []*Chain { - var chainList []*Chain - for _, chain := range DefaultChainsList() { +func ChainListByNetworkType(networkType NetworkType, additionalChains []Chain) []Chain { + var chainList []Chain + for _, chain := range CombineDefaultChainsList(additionalChains) { if chain.NetworkType == networkType { chainList = append(chainList, chain) } @@ -308,9 +311,9 @@ func ChainListByNetworkType(networkType NetworkType) []*Chain { } // ChainListByNetwork returns a list of chains by network -func ChainListByNetwork(network Network) []*Chain { - var chainList []*Chain - for _, chain := range DefaultChainsList() { +func ChainListByNetwork(network Network, additionalChains []Chain) []Chain { + var chainList []Chain + for _, chain := range CombineDefaultChainsList(additionalChains) { if chain.Network == network { chainList = append(chainList, chain) } @@ -319,9 +322,9 @@ func ChainListByNetwork(network Network) []*Chain { } // ExternalChainList returns a list chains that are not Zeta -func ExternalChainList() []*Chain { - var chainList []*Chain - for _, chain := range DefaultChainsList() { +func ExternalChainList(additionalChains []Chain) []Chain { + var chainList []Chain + for _, chain := range CombineDefaultChainsList(additionalChains) { if chain.IsExternal { chainList = append(chainList, chain) } @@ -330,9 +333,9 @@ func ExternalChainList() []*Chain { } // ChainListByConsensus returns a list of chains by consensus -func ChainListByConsensus(consensus Consensus) []*Chain { - var chainList []*Chain - for _, chain := range DefaultChainsList() { +func ChainListByConsensus(consensus Consensus, additionalChains []Chain) []Chain { + var chainList []Chain + for _, chain := range CombineDefaultChainsList(additionalChains) { if chain.Consensus == consensus { chainList = append(chainList, chain) } @@ -341,9 +344,9 @@ func ChainListByConsensus(consensus Consensus) []*Chain { } // ChainListForHeaderSupport returns a list of chains that support headers -func ChainListForHeaderSupport() []*Chain { - var chainList []*Chain - for _, chain := range DefaultChainsList() { +func ChainListForHeaderSupport(additionalChains []Chain) []Chain { + var chainList []Chain + for _, chain := range CombineDefaultChainsList(additionalChains) { if chain.Consensus == Consensus_ethereum || chain.Consensus == Consensus_bitcoin { chainList = append(chainList, chain) } @@ -351,14 +354,19 @@ func ChainListForHeaderSupport() []*Chain { return chainList } -// ZetaChainFromChainID returns a ZetaChain chain object from a Cosmos chain ID -func ZetaChainFromChainID(chainID string) (Chain, error) { +// ZetaChainFromCosmosChainID returns a ZetaChain chain object from a Cosmos chain ID +func ZetaChainFromCosmosChainID(chainID string) (Chain, error) { ethChainID, err := CosmosToEthChainID(chainID) if err != nil { return Chain{}, err } - switch ethChainID { + return ZetaChainFromChainID(ethChainID) +} + +// ZetaChainFromChainID returns a ZetaChain chain object from a chain ID +func ZetaChainFromChainID(chainID int64) (Chain, error) { + switch chainID { case ZetaChainPrivnet.ChainId: return ZetaChainPrivnet, nil case ZetaChainMainnet.ChainId: @@ -368,17 +376,37 @@ func ZetaChainFromChainID(chainID string) (Chain, error) { case ZetaChainDevnet.ChainId: return ZetaChainDevnet, nil default: - return Chain{}, fmt.Errorf("chain %d not found", ethChainID) + return Chain{}, ErrNotZetaChain } } -// TODO : https://github.com/zeta-chain/node/issues/2080 -// remove the usage of this function -// chainListPointers returns a list of chain pointers -func chainListPointers(chains []Chain) []*Chain { - var c []*Chain - for i := 0; i < len(chains); i++ { - c = append(c, &chains[i]) +// CombineDefaultChainsList combines the default chains list with a list of chains +// duplicated chain ID are overwritten by the second list +func CombineDefaultChainsList(chains []Chain) []Chain { + return CombineChainList(DefaultChainsList(), chains) +} + +// CombineChainList combines a list of chains with a list of chains +// duplicated chain ID are overwritten by the second list +func CombineChainList(base []Chain, additional []Chain) []Chain { + combined := make([]Chain, 0, len(base)+len(additional)) + combined = append(combined, base...) + + // map chain ID in combined to index in the list + chainIDIndexMap := make(map[int64]int) + for i, chain := range combined { + chainIDIndexMap[chain.ChainId] = i } - return c + + // add chains2 to combined + // if chain ID already exists in chains1, overwrite it + for _, chain := range additional { + if index, ok := chainIDIndexMap[chain.ChainId]; ok { + combined[index] = chain + } else { + combined = append(combined, chain) + } + } + + return combined } diff --git a/pkg/chains/chains_test.go b/pkg/chains/chains_test.go index dffb630086..5b85f39f22 100644 --- a/pkg/chains/chains_test.go +++ b/pkg/chains/chains_test.go @@ -1,59 +1,61 @@ -package chains +package chains_test import ( "testing" "github.com/stretchr/testify/require" + "github.com/zeta-chain/zetacore/pkg/chains" + "github.com/zeta-chain/zetacore/testutil/sample" ) func TestChainListByNetworkType(t *testing.T) { listTests := []struct { name string - networkType NetworkType - expected []*Chain + networkType chains.NetworkType + expected []chains.Chain }{ { "mainnet chains", - NetworkType_mainnet, - []*Chain{ - &ZetaChainMainnet, - &BitcoinMainnet, - &BscMainnet, - &Ethereum, - &Polygon, - &OptimismMainnet, - &BaseMainnet, + chains.NetworkType_mainnet, + []chains.Chain{ + chains.ZetaChainMainnet, + chains.BitcoinMainnet, + chains.BscMainnet, + chains.Ethereum, + chains.Polygon, + chains.OptimismMainnet, + chains.BaseMainnet, }, }, { "testnet chains", - NetworkType_testnet, - []*Chain{ - &ZetaChainTestnet, - &BitcoinTestnet, - &Mumbai, - &Amoy, - &BscTestnet, - &Goerli, - &Sepolia, - &OptimismSepolia, - &BaseSepolia, + chains.NetworkType_testnet, + []chains.Chain{ + chains.ZetaChainTestnet, + chains.BitcoinTestnet, + chains.Mumbai, + chains.Amoy, + chains.BscTestnet, + chains.Goerli, + chains.Sepolia, + chains.OptimismSepolia, + chains.BaseSepolia, }, }, { "privnet chains", - NetworkType_privnet, - []*Chain{ - &ZetaChainPrivnet, - &BitcoinRegtest, - &GoerliLocalnet, + chains.NetworkType_privnet, + []chains.Chain{ + chains.ZetaChainPrivnet, + chains.BitcoinRegtest, + chains.GoerliLocalnet, }, }, } for _, lt := range listTests { t.Run(lt.name, func(t *testing.T) { - require.ElementsMatch(t, lt.expected, ChainListByNetworkType(lt.networkType)) + require.ElementsMatch(t, lt.expected, chains.ChainListByNetworkType(lt.networkType, []chains.Chain{})) }) } } @@ -61,167 +63,209 @@ func TestChainListByNetworkType(t *testing.T) { func TestChainListByNetwork(t *testing.T) { listTests := []struct { name string - network Network - expected []*Chain + network chains.Network + expected []chains.Chain }{ { "Zeta", - Network_zeta, - []*Chain{&ZetaChainMainnet, &ZetaChainDevnet, &ZetaChainPrivnet, &ZetaChainTestnet}, + chains.Network_zeta, + []chains.Chain{ + chains.ZetaChainMainnet, + chains.ZetaChainDevnet, + chains.ZetaChainPrivnet, + chains.ZetaChainTestnet, + }, }, { "Btc", - Network_btc, - []*Chain{&BitcoinMainnet, &BitcoinTestnet, &BitcoinRegtest}, + chains.Network_btc, + []chains.Chain{chains.BitcoinMainnet, chains.BitcoinTestnet, chains.BitcoinRegtest}, }, { "Eth", - Network_eth, - []*Chain{&Ethereum, &Goerli, &Sepolia, &GoerliLocalnet}, + chains.Network_eth, + []chains.Chain{chains.Ethereum, chains.Goerli, chains.Sepolia, chains.GoerliLocalnet}, }, { "Bsc", - Network_bsc, - []*Chain{&BscMainnet, &BscTestnet}, + chains.Network_bsc, + []chains.Chain{chains.BscMainnet, chains.BscTestnet}, }, { "Polygon", - Network_polygon, - []*Chain{&Polygon, &Mumbai, &Amoy}, + chains.Network_polygon, + []chains.Chain{chains.Polygon, chains.Mumbai, chains.Amoy}, }, { "Optimism", - Network_optimism, - []*Chain{&OptimismMainnet, &OptimismSepolia}, + chains.Network_optimism, + []chains.Chain{chains.OptimismMainnet, chains.OptimismSepolia}, }, { "Base", - Network_base, - []*Chain{&BaseMainnet, &BaseSepolia}, + chains.Network_base, + []chains.Chain{chains.BaseMainnet, chains.BaseSepolia}, }, } for _, lt := range listTests { t.Run(lt.name, func(t *testing.T) { - require.ElementsMatch(t, lt.expected, ChainListByNetwork(lt.network)) + require.ElementsMatch(t, lt.expected, chains.ChainListByNetwork(lt.network, []chains.Chain{})) }) } } -func TestChainListFunctions(t *testing.T) { - listTests := []struct { - name string - function func() []*Chain - expected []*Chain - }{ - { - "DefaultChainsList", - DefaultChainsList, - []*Chain{ - &BitcoinMainnet, - &BscMainnet, - &Ethereum, - &BitcoinTestnet, - &Mumbai, - &Amoy, - &BscTestnet, - &Goerli, - &Sepolia, - &BitcoinRegtest, - &GoerliLocalnet, - &ZetaChainMainnet, - &ZetaChainTestnet, - &ZetaChainDevnet, - &ZetaChainPrivnet, - &Polygon, - &OptimismMainnet, - &OptimismSepolia, - &BaseMainnet, - &BaseSepolia, - }, - }, - { - "ExternalChainList", - ExternalChainList, - []*Chain{ - &BitcoinMainnet, - &BscMainnet, - &Ethereum, - &BitcoinTestnet, - &Mumbai, - &Amoy, - &BscTestnet, - &Goerli, - &Sepolia, - &BitcoinRegtest, - &GoerliLocalnet, - &Polygon, - &OptimismMainnet, - &OptimismSepolia, - &BaseMainnet, - &BaseSepolia, - }, - }, - } - for _, lt := range listTests { - t.Run(lt.name, func(t *testing.T) { - chains := lt.function() - require.ElementsMatch(t, lt.expected, chains) - }) - } +func TestDefaultChainList(t *testing.T) { + require.ElementsMatch(t, []chains.Chain{ + chains.BitcoinMainnet, + chains.BscMainnet, + chains.Ethereum, + chains.BitcoinTestnet, + chains.Mumbai, + chains.Amoy, + chains.BscTestnet, + chains.Goerli, + chains.Sepolia, + chains.BitcoinRegtest, + chains.GoerliLocalnet, + chains.ZetaChainMainnet, + chains.ZetaChainTestnet, + chains.ZetaChainDevnet, + chains.ZetaChainPrivnet, + chains.Polygon, + chains.OptimismMainnet, + chains.OptimismSepolia, + chains.BaseMainnet, + chains.BaseSepolia, + }, chains.DefaultChainsList()) } -func TestZetaChainFromChainID(t *testing.T) { +func TestExternalChainList(t *testing.T) { + require.ElementsMatch(t, []chains.Chain{ + chains.BitcoinMainnet, + chains.BscMainnet, + chains.Ethereum, + chains.BitcoinTestnet, + chains.Mumbai, + chains.Amoy, + chains.BscTestnet, + chains.Goerli, + chains.Sepolia, + chains.BitcoinRegtest, + chains.GoerliLocalnet, + chains.Polygon, + chains.OptimismMainnet, + chains.OptimismSepolia, + chains.BaseMainnet, + chains.BaseSepolia, + }, chains.ExternalChainList([]chains.Chain{})) +} + +func TestZetaChainFromCosmosChainID(t *testing.T) { tests := []struct { name string chainID string - expected Chain + expected chains.Chain wantErr bool }{ { name: "ZetaChainMainnet", chainID: "cosmoshub_7000-1", - expected: ZetaChainMainnet, + expected: chains.ZetaChainMainnet, wantErr: false, }, { name: "ZetaChainTestnet", chainID: "cosmoshub_7001-1", - expected: ZetaChainTestnet, + expected: chains.ZetaChainTestnet, wantErr: false, }, { name: "ZetaChainDevnet", chainID: "cosmoshub_70000-1", - expected: ZetaChainDevnet, + expected: chains.ZetaChainDevnet, wantErr: false, }, { name: "ZetaChainPrivnet", chainID: "cosmoshub_101-1", - expected: ZetaChainPrivnet, + expected: chains.ZetaChainPrivnet, wantErr: false, }, { name: "unknown chain", chainID: "cosmoshub_1234-1", - expected: Chain{}, + expected: chains.Chain{}, wantErr: true, }, { name: "invalid chain id", chainID: "cosmoshub_abc-1", - expected: Chain{}, + expected: chains.Chain{}, + wantErr: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result, err := chains.ZetaChainFromCosmosChainID(tt.chainID) + if tt.wantErr { + require.Error(t, err) + require.Equal(t, chains.Chain{}, result) + } else { + require.NoError(t, err) + require.Equal(t, tt.expected, result) + } + }) + } +} + +func TestZetaChainFromChainID(t *testing.T) { + tests := []struct { + name string + chainID int64 + expected chains.Chain + wantErr bool + }{ + { + name: "ZetaChainMainnet", + chainID: 7000, + expected: chains.ZetaChainMainnet, + wantErr: false, + }, + { + name: "ZetaChainTestnet", + chainID: 7001, + expected: chains.ZetaChainTestnet, + wantErr: false, + }, + { + name: "ZetaChainDevnet", + chainID: 70000, + expected: chains.ZetaChainDevnet, + wantErr: false, + }, + { + name: "ZetaChainPrivnet", + chainID: 101, + expected: chains.ZetaChainPrivnet, + wantErr: false, + }, + { + name: "unknown chain", + chainID: 1234, + expected: chains.Chain{}, wantErr: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - result, err := ZetaChainFromChainID(tt.chainID) + result, err := chains.ZetaChainFromChainID(tt.chainID) if tt.wantErr { require.Error(t, err) - require.Equal(t, Chain{}, result) + require.ErrorIs(t, err, chains.ErrNotZetaChain) + require.Equal(t, chains.Chain{}, result) } else { require.NoError(t, err) require.Equal(t, tt.expected, result) @@ -229,3 +273,119 @@ func TestZetaChainFromChainID(t *testing.T) { }) } } + +func TestCombineDefaultChainsList(t *testing.T) { + // prepare array containing pre-defined chains + // chain IDs are 11000 - 11009 to not conflict with the default chains + var chainList = make([]chains.Chain, 0, 10) + for i := int64(11000); i < 10; i++ { + chainList = append(chainList, sample.Chain(i)) + } + + bitcoinMainnetChainID := chains.BitcoinMainnet.ChainId + require.Equal( + t, + bitcoinMainnetChainID, + chains.DefaultChainsList()[0].ChainId, + "Bitcoin mainnet be the first in the default chain list for TestCombineDefaultChainsList tests", + ) + alternativeBitcoinMainnet := sample.Chain(bitcoinMainnetChainID) + + tests := []struct { + name string + list []chains.Chain + expected []chains.Chain + }{ + { + name: "empty list", + list: []chains.Chain{}, + expected: chains.DefaultChainsList(), + }, + { + name: "no duplicates", + list: chainList, + expected: append(chains.DefaultChainsList(), chainList...), + }, + { + name: "duplicates", + list: []chains.Chain{alternativeBitcoinMainnet}, + expected: append(chains.DefaultChainsList()[1:], alternativeBitcoinMainnet), + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + require.ElementsMatch(t, tt.expected, chains.CombineDefaultChainsList(tt.list)) + }) + } +} + +func TestCombineChainList(t *testing.T) { + // prepare array containing pre-defined chains + var chainList = make([]chains.Chain, 0, 10) + for i := int64(0); i < 10; i++ { + chainList = append(chainList, sample.Chain(i)) + } + + // prepare second array for duplicated chain IDs + var duplicatedChainList = make([]chains.Chain, 0, 10) + for i := int64(0); i < 10; i++ { + duplicatedChainList = append(duplicatedChainList, sample.Chain(i)) + } + + tests := []struct { + name string + list1 []chains.Chain + list2 []chains.Chain + expected []chains.Chain + }{ + { + name: "empty lists", + list1: []chains.Chain{}, + list2: []chains.Chain{}, + expected: []chains.Chain{}, + }, + { + name: "empty list 1", + list1: []chains.Chain{}, + list2: chainList, + expected: chainList, + }, + { + name: "empty list 2", + list1: chainList, + list2: []chains.Chain{}, + expected: chainList, + }, + { + name: "no duplicates", + list1: chainList[:5], + list2: chainList[5:], + expected: chainList, + }, + { + name: "all duplicates", + list1: chainList, + list2: duplicatedChainList, + expected: duplicatedChainList, + }, + { + name: "some duplicates", + list1: chainList[:5], + list2: duplicatedChainList[3:], + expected: append(chainList[:3], duplicatedChainList[3:]...), + }, + { + name: "one duplicate", + list1: chainList[:5], + list2: append(chainList[5:], duplicatedChainList[0]), + expected: append(chainList[1:], duplicatedChainList[0]), + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + require.ElementsMatch(t, tt.expected, chains.CombineChainList(tt.list1, tt.list2)) + }) + } +} diff --git a/pkg/chains/conversion.go b/pkg/chains/conversion.go index 200061c3ae..84b3eaf3aa 100644 --- a/pkg/chains/conversion.go +++ b/pkg/chains/conversion.go @@ -8,31 +8,17 @@ import ( ethcommon "github.com/ethereum/go-ethereum/common" ) -// A very special value to mark current nonce in UTXO +// NonceMarkAmount uses special value to mark current nonce in UTXO func NonceMarkAmount(nonce uint64) int64 { // #nosec G701 always in range return int64(nonce) + BtcNonceMarkOffset() } -// HashToString convert hash bytes to string -func HashToString(chainID int64, blockHash []byte) (string, error) { - if IsEVMChain(chainID) { - return hex.EncodeToString(blockHash), nil - } else if IsBitcoinChain(chainID) { - hash, err := chainhash.NewHash(blockHash) - if err != nil { - return "", err - } - return hash.String(), nil - } - return "", fmt.Errorf("cannot convert hash to string for chain %d", chainID) -} - // StringToHash convert string to hash bytes -func StringToHash(chainID int64, hash string) ([]byte, error) { - if IsEVMChain(chainID) { +func StringToHash(chainID int64, hash string, additionalChains []Chain) ([]byte, error) { + if IsEVMChain(chainID, additionalChains) { return ethcommon.HexToHash(hash).Bytes(), nil - } else if IsBitcoinChain(chainID) { + } else if IsBitcoinChain(chainID, additionalChains) { hash, err := chainhash.NewHashFromStr(hash) if err != nil { return nil, err diff --git a/pkg/chains/utils_test.go b/pkg/chains/utils_test.go index cb025e025b..915fa2b8ca 100644 --- a/pkg/chains/utils_test.go +++ b/pkg/chains/utils_test.go @@ -27,41 +27,6 @@ func TestNonceMarkAmount(t *testing.T) { } } -func TestHashToString(t *testing.T) { - evmChainId := int64(5) - btcChainId := int64(8332) - unknownChainId := int64(3) - mockEthBlockHash := []byte("0xc2339489a45f8976d45482ad6fa08751a1eae91f92d60645521ca0aff2422639") - mockBtcBlockHash := []byte("00000000000000000002dcaa3853ac587d4cafdd0aa1fff45942ab5798f29afd") - expectedBtcHash, err := chainhash.NewHashFromStr("00000000000000000002dcaa3853ac587d4cafdd0aa1fff45942ab5798f29afd") - require.NoError(t, err) - - tests := []struct { - name string - chainID int64 - blockHash []byte - expect string - wantErr bool - }{ - {"evm chain", evmChainId, mockEthBlockHash, hex.EncodeToString(mockEthBlockHash), false}, - {"btc chain", btcChainId, expectedBtcHash.CloneBytes(), expectedBtcHash.String(), false}, - {"btc chain invalid hash", btcChainId, mockBtcBlockHash, "", true}, - {"unknown chain", unknownChainId, mockEthBlockHash, "", true}, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - result, err := HashToString(tt.chainID, tt.blockHash) - if tt.wantErr { - require.Error(t, err) - } else { - require.NoError(t, err) - require.Equal(t, tt.expect, result) - } - }) - } -} - func TestStringToHash(t *testing.T) { evmChainId := int64(5) btcChainId := int64(8332) @@ -91,7 +56,7 @@ func TestStringToHash(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - result, err := StringToHash(tt.chainID, tt.hash) + result, err := StringToHash(tt.chainID, tt.hash, []Chain{}) if tt.wantErr { require.Error(t, err) } else { diff --git a/pkg/crypto/pubkey.go b/pkg/crypto/pubkey.go index 8c893664b0..545e5367ed 100644 --- a/pkg/crypto/pubkey.go +++ b/pkg/crypto/pubkey.go @@ -71,7 +71,7 @@ func (pubKey PubKey) String() string { // GetAddress will return an address for the given chain func (pubKey PubKey) GetAddress(chain chains.Chain) (chains.Address, error) { - if chains.IsEVMChain(chain.ChainId) { + if chain.IsEVMChain() { return pubKey.GetEVMAddress() } return chains.NoAddress, nil diff --git a/proto/zetachain/zetacore/observer/observer.proto b/proto/zetachain/zetacore/observer/observer.proto index 240f0025f0..7fc6eb5b7b 100644 --- a/proto/zetachain/zetacore/observer/observer.proto +++ b/proto/zetachain/zetacore/observer/observer.proto @@ -2,7 +2,6 @@ syntax = "proto3"; package zetachain.zetacore.observer; import "gogoproto/gogo.proto"; -import "zetachain/zetacore/pkg/chains/chains.proto"; option go_package = "github.com/zeta-chain/zetacore/x/observer/types"; diff --git a/proto/zetachain/zetacore/observer/params.proto b/proto/zetachain/zetacore/observer/params.proto index 1eb096fc0c..92d00763dd 100644 --- a/proto/zetachain/zetacore/observer/params.proto +++ b/proto/zetachain/zetacore/observer/params.proto @@ -3,7 +3,6 @@ package zetachain.zetacore.observer; import "gogoproto/gogo.proto"; import "zetachain/zetacore/observer/observer.proto"; -import "zetachain/zetacore/pkg/chains/chains.proto"; option go_package = "github.com/zeta-chain/zetacore/x/observer/types"; diff --git a/proto/zetachain/zetacore/observer/query.proto b/proto/zetachain/zetacore/observer/query.proto index 799bc1efb9..9ad1d71356 100644 --- a/proto/zetachain/zetacore/observer/query.proto +++ b/proto/zetachain/zetacore/observer/query.proto @@ -263,7 +263,9 @@ message QueryObserverSetResponse { repeated string observers = 1; } message QuerySupportedChains {} -message QuerySupportedChainsResponse { repeated pkg.chains.Chain chains = 1; } +message QuerySupportedChainsResponse { + repeated pkg.chains.Chain chains = 1 [ (gogoproto.nullable) = false ]; +} message QueryGetChainParamsForChainRequest { int64 chain_id = 1; } diff --git a/testutil/keeper/authority.go b/testutil/keeper/authority.go index 1e61bf9881..169b6df526 100644 --- a/testutil/keeper/authority.go +++ b/testutil/keeper/authority.go @@ -11,6 +11,7 @@ import ( "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" + "github.com/zeta-chain/zetacore/pkg/chains" "github.com/zeta-chain/zetacore/testutil/sample" "github.com/zeta-chain/zetacore/x/authority/keeper" "github.com/zeta-chain/zetacore/x/authority/types" @@ -79,6 +80,16 @@ func MockCheckAuthorization(m *mock.Mock, msg sdk.Msg, authorizationResult error m.On("CheckAuthorization", mock.Anything, msg).Return(authorizationResult).Once() } +// MockGetChainList mocks the GetAdditionalChainList method of the authority keeper. +func MockGetChainList(m *mock.Mock, chainList []chains.Chain) { + m.On("GetAdditionalChainList", mock.Anything).Return(chainList).Once() +} + +// MockGetChainListEmpty mocks the GetAdditionalChainList method of the authority keeper. +func MockGetChainListEmpty(m *mock.Mock) { + m.On("GetAdditionalChainList", mock.Anything).Return([]chains.Chain{}) +} + func SetAdminPolicies(ctx sdk.Context, ak *keeper.Keeper) string { admin := sample.AccAddress() ak.SetPolicies(ctx, types.Policies{Items: []*types.Policy{ diff --git a/testutil/keeper/crosschain.go b/testutil/keeper/crosschain.go index d2b1bc1d5b..140a9538c5 100644 --- a/testutil/keeper/crosschain.go +++ b/testutil/keeper/crosschain.go @@ -261,24 +261,14 @@ func GetCrosschainFungibleMock(t testing.TB, keeper *keeper.Keeper) *crosschainm return cfk } -func MockGetSupportedChainFromChainID(m *crosschainmocks.CrosschainObserverKeeper, senderChain *chains.Chain) { - if senderChain != nil { - m.On("GetSupportedChainFromChainID", mock.Anything, senderChain.ChainId). - Return(senderChain).Once() - } else { - m.On("GetSupportedChainFromChainID", mock.Anything, mock.Anything). - Return(&chains.Chain{}).Once() - } +func MockGetSupportedChainFromChainID(m *crosschainmocks.CrosschainObserverKeeper, senderChain chains.Chain) { + m.On("GetSupportedChainFromChainID", mock.Anything, senderChain.ChainId). + Return(senderChain, true).Once() } -func MockFailedGetSupportedChainFromChainID(m *crosschainmocks.CrosschainObserverKeeper, senderChain *chains.Chain) { - if senderChain != nil { - m.On("GetSupportedChainFromChainID", mock.Anything, senderChain.ChainId). - Return(nil).Once() - } else { - m.On("GetSupportedChainFromChainID", mock.Anything, mock.Anything). - Return(nil).Once() - } +func MockFailedGetSupportedChainFromChainID(m *crosschainmocks.CrosschainObserverKeeper, senderChain chains.Chain) { + m.On("GetSupportedChainFromChainID", mock.Anything, senderChain.ChainId). + Return(chains.Chain{}, false).Once() } func MockGetRevertGasLimitForERC20( @@ -304,7 +294,7 @@ func MockPayGasAndUpdateCCTX( asset string, ) { m2.On("GetSupportedChainFromChainID", mock.Anything, senderChain.ChainId). - Return(&senderChain).Twice() + Return(senderChain, true).Twice() m.On("GetForeignCoinFromAsset", mock.Anything, asset, senderChain.ChainId). Return(fungibletypes.ForeignCoins{ Zrc20ContractAddress: sample.EthAddress().String(), @@ -340,7 +330,7 @@ func MockUpdateNonce(m *crosschainmocks.CrosschainObserverKeeper, senderChain ch nonce = uint64(1) tss := sample.Tss() m.On("GetSupportedChainFromChainID", mock.Anything, senderChain.ChainId). - Return(senderChain) + Return(senderChain, true).Once() m.On("GetChainNonces", mock.Anything, senderChain.ChainName.String()). Return(observertypes.ChainNonces{Nonce: nonce}, true) m.On("GetTSS", mock.Anything). diff --git a/testutil/keeper/mocks/crosschain/authority.go b/testutil/keeper/mocks/crosschain/authority.go index 59edbd6d2d..d38c117dd6 100644 --- a/testutil/keeper/mocks/crosschain/authority.go +++ b/testutil/keeper/mocks/crosschain/authority.go @@ -4,6 +4,7 @@ package mocks import ( mock "github.com/stretchr/testify/mock" + chains "github.com/zeta-chain/zetacore/pkg/chains" types "github.com/cosmos/cosmos-sdk/types" ) @@ -31,6 +32,26 @@ func (_m *CrosschainAuthorityKeeper) CheckAuthorization(ctx types.Context, msg t return r0 } +// GetAdditionalChainList provides a mock function with given fields: ctx +func (_m *CrosschainAuthorityKeeper) GetAdditionalChainList(ctx types.Context) []chains.Chain { + ret := _m.Called(ctx) + + if len(ret) == 0 { + panic("no return value specified for GetAdditionalChainList") + } + + var r0 []chains.Chain + if rf, ok := ret.Get(0).(func(types.Context) []chains.Chain); ok { + r0 = rf(ctx) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]chains.Chain) + } + } + + return r0 +} + // NewCrosschainAuthorityKeeper creates a new instance of CrosschainAuthorityKeeper. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. // The first argument is typically a *testing.T value. func NewCrosschainAuthorityKeeper(t interface { diff --git a/testutil/keeper/mocks/crosschain/observer.go b/testutil/keeper/mocks/crosschain/observer.go index d504d1a9c8..6e6bd7d951 100644 --- a/testutil/keeper/mocks/crosschain/observer.go +++ b/testutil/keeper/mocks/crosschain/observer.go @@ -110,7 +110,7 @@ func (_m *CrosschainObserverKeeper) CheckIfTssPubkeyHasBeenGenerated(ctx types.C } // FindBallot provides a mock function with given fields: ctx, index, chain, observationType -func (_m *CrosschainObserverKeeper) FindBallot(ctx types.Context, index string, chain *chains.Chain, observationType observertypes.ObservationType) (observertypes.Ballot, bool, error) { +func (_m *CrosschainObserverKeeper) FindBallot(ctx types.Context, index string, chain chains.Chain, observationType observertypes.ObservationType) (observertypes.Ballot, bool, error) { ret := _m.Called(ctx, index, chain, observationType) if len(ret) == 0 { @@ -120,22 +120,22 @@ func (_m *CrosschainObserverKeeper) FindBallot(ctx types.Context, index string, var r0 observertypes.Ballot var r1 bool var r2 error - if rf, ok := ret.Get(0).(func(types.Context, string, *chains.Chain, observertypes.ObservationType) (observertypes.Ballot, bool, error)); ok { + if rf, ok := ret.Get(0).(func(types.Context, string, chains.Chain, observertypes.ObservationType) (observertypes.Ballot, bool, error)); ok { return rf(ctx, index, chain, observationType) } - if rf, ok := ret.Get(0).(func(types.Context, string, *chains.Chain, observertypes.ObservationType) observertypes.Ballot); ok { + if rf, ok := ret.Get(0).(func(types.Context, string, chains.Chain, observertypes.ObservationType) observertypes.Ballot); ok { r0 = rf(ctx, index, chain, observationType) } else { r0 = ret.Get(0).(observertypes.Ballot) } - if rf, ok := ret.Get(1).(func(types.Context, string, *chains.Chain, observertypes.ObservationType) bool); ok { + if rf, ok := ret.Get(1).(func(types.Context, string, chains.Chain, observertypes.ObservationType) bool); ok { r1 = rf(ctx, index, chain, observationType) } else { r1 = ret.Get(1).(bool) } - if rf, ok := ret.Get(2).(func(types.Context, string, *chains.Chain, observertypes.ObservationType) error); ok { + if rf, ok := ret.Get(2).(func(types.Context, string, chains.Chain, observertypes.ObservationType) error); ok { r2 = rf(ctx, index, chain, observationType) } else { r2 = ret.Error(2) @@ -557,39 +557,47 @@ func (_m *CrosschainObserverKeeper) GetPendingNonces(ctx types.Context, tss stri } // GetSupportedChainFromChainID provides a mock function with given fields: ctx, chainID -func (_m *CrosschainObserverKeeper) GetSupportedChainFromChainID(ctx types.Context, chainID int64) *chains.Chain { +func (_m *CrosschainObserverKeeper) GetSupportedChainFromChainID(ctx types.Context, chainID int64) (chains.Chain, bool) { ret := _m.Called(ctx, chainID) if len(ret) == 0 { panic("no return value specified for GetSupportedChainFromChainID") } - var r0 *chains.Chain - if rf, ok := ret.Get(0).(func(types.Context, int64) *chains.Chain); ok { + var r0 chains.Chain + var r1 bool + if rf, ok := ret.Get(0).(func(types.Context, int64) (chains.Chain, bool)); ok { + return rf(ctx, chainID) + } + if rf, ok := ret.Get(0).(func(types.Context, int64) chains.Chain); ok { r0 = rf(ctx, chainID) } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*chains.Chain) - } + r0 = ret.Get(0).(chains.Chain) } - return r0 + if rf, ok := ret.Get(1).(func(types.Context, int64) bool); ok { + r1 = rf(ctx, chainID) + } else { + r1 = ret.Get(1).(bool) + } + + return r0, r1 } // GetSupportedChains provides a mock function with given fields: ctx -func (_m *CrosschainObserverKeeper) GetSupportedChains(ctx types.Context) []*chains.Chain { +func (_m *CrosschainObserverKeeper) GetSupportedChains(ctx types.Context) []chains.Chain { ret := _m.Called(ctx) if len(ret) == 0 { panic("no return value specified for GetSupportedChains") } - var r0 []*chains.Chain - if rf, ok := ret.Get(0).(func(types.Context) []*chains.Chain); ok { + var r0 []chains.Chain + if rf, ok := ret.Get(0).(func(types.Context) []chains.Chain); ok { r0 = rf(ctx) } else { if ret.Get(0) != nil { - r0 = ret.Get(0).([]*chains.Chain) + r0 = ret.Get(0).([]chains.Chain) } } @@ -597,19 +605,19 @@ func (_m *CrosschainObserverKeeper) GetSupportedChains(ctx types.Context) []*cha } // GetSupportedForeignChains provides a mock function with given fields: ctx -func (_m *CrosschainObserverKeeper) GetSupportedForeignChains(ctx types.Context) []*chains.Chain { +func (_m *CrosschainObserverKeeper) GetSupportedForeignChains(ctx types.Context) []chains.Chain { ret := _m.Called(ctx) if len(ret) == 0 { panic("no return value specified for GetSupportedForeignChains") } - var r0 []*chains.Chain - if rf, ok := ret.Get(0).(func(types.Context) []*chains.Chain); ok { + var r0 []chains.Chain + if rf, ok := ret.Get(0).(func(types.Context) []chains.Chain); ok { r0 = rf(ctx) } else { if ret.Get(0) != nil { - r0 = ret.Get(0).([]*chains.Chain) + r0 = ret.Get(0).([]chains.Chain) } } diff --git a/testutil/keeper/mocks/fungible/authority.go b/testutil/keeper/mocks/fungible/authority.go index b3ed6cae5a..ed9dbd0e28 100644 --- a/testutil/keeper/mocks/fungible/authority.go +++ b/testutil/keeper/mocks/fungible/authority.go @@ -4,6 +4,7 @@ package mocks import ( mock "github.com/stretchr/testify/mock" + chains "github.com/zeta-chain/zetacore/pkg/chains" types "github.com/cosmos/cosmos-sdk/types" ) @@ -31,6 +32,26 @@ func (_m *FungibleAuthorityKeeper) CheckAuthorization(ctx types.Context, msg typ return r0 } +// GetAdditionalChainList provides a mock function with given fields: ctx +func (_m *FungibleAuthorityKeeper) GetAdditionalChainList(ctx types.Context) []chains.Chain { + ret := _m.Called(ctx) + + if len(ret) == 0 { + panic("no return value specified for GetAdditionalChainList") + } + + var r0 []chains.Chain + if rf, ok := ret.Get(0).(func(types.Context) []chains.Chain); ok { + r0 = rf(ctx) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]chains.Chain) + } + } + + return r0 +} + // NewFungibleAuthorityKeeper creates a new instance of FungibleAuthorityKeeper. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. // The first argument is typically a *testing.T value. func NewFungibleAuthorityKeeper(t interface { diff --git a/testutil/keeper/mocks/fungible/observer.go b/testutil/keeper/mocks/fungible/observer.go index bbe76b1afa..7a003686e4 100644 --- a/testutil/keeper/mocks/fungible/observer.go +++ b/testutil/keeper/mocks/fungible/observer.go @@ -15,19 +15,19 @@ type FungibleObserverKeeper struct { } // GetSupportedChains provides a mock function with given fields: ctx -func (_m *FungibleObserverKeeper) GetSupportedChains(ctx types.Context) []*chains.Chain { +func (_m *FungibleObserverKeeper) GetSupportedChains(ctx types.Context) []chains.Chain { ret := _m.Called(ctx) if len(ret) == 0 { panic("no return value specified for GetSupportedChains") } - var r0 []*chains.Chain - if rf, ok := ret.Get(0).(func(types.Context) []*chains.Chain); ok { + var r0 []chains.Chain + if rf, ok := ret.Get(0).(func(types.Context) []chains.Chain); ok { r0 = rf(ctx) } else { if ret.Get(0) != nil { - r0 = ret.Get(0).([]*chains.Chain) + r0 = ret.Get(0).([]chains.Chain) } } diff --git a/testutil/keeper/mocks/lightclient/authority.go b/testutil/keeper/mocks/lightclient/authority.go index 8592036260..8d058dbfc0 100644 --- a/testutil/keeper/mocks/lightclient/authority.go +++ b/testutil/keeper/mocks/lightclient/authority.go @@ -4,6 +4,7 @@ package mocks import ( mock "github.com/stretchr/testify/mock" + chains "github.com/zeta-chain/zetacore/pkg/chains" types "github.com/cosmos/cosmos-sdk/types" ) @@ -31,6 +32,26 @@ func (_m *LightclientAuthorityKeeper) CheckAuthorization(ctx types.Context, msg return r0 } +// GetAdditionalChainList provides a mock function with given fields: ctx +func (_m *LightclientAuthorityKeeper) GetAdditionalChainList(ctx types.Context) []chains.Chain { + ret := _m.Called(ctx) + + if len(ret) == 0 { + panic("no return value specified for GetAdditionalChainList") + } + + var r0 []chains.Chain + if rf, ok := ret.Get(0).(func(types.Context) []chains.Chain); ok { + r0 = rf(ctx) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]chains.Chain) + } + } + + return r0 +} + // NewLightclientAuthorityKeeper creates a new instance of LightclientAuthorityKeeper. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. // The first argument is typically a *testing.T value. func NewLightclientAuthorityKeeper(t interface { diff --git a/testutil/keeper/mocks/observer/authority.go b/testutil/keeper/mocks/observer/authority.go index 30a0d21b6d..9150ffcfc5 100644 --- a/testutil/keeper/mocks/observer/authority.go +++ b/testutil/keeper/mocks/observer/authority.go @@ -3,9 +3,11 @@ package mocks import ( - mock "github.com/stretchr/testify/mock" + chains "github.com/zeta-chain/zetacore/pkg/chains" authoritytypes "github.com/zeta-chain/zetacore/x/authority/types" + mock "github.com/stretchr/testify/mock" + types "github.com/cosmos/cosmos-sdk/types" ) @@ -32,6 +34,26 @@ func (_m *ObserverAuthorityKeeper) CheckAuthorization(ctx types.Context, msg typ return r0 } +// GetAdditionalChainList provides a mock function with given fields: ctx +func (_m *ObserverAuthorityKeeper) GetAdditionalChainList(ctx types.Context) []chains.Chain { + ret := _m.Called(ctx) + + if len(ret) == 0 { + panic("no return value specified for GetAdditionalChainList") + } + + var r0 []chains.Chain + if rf, ok := ret.Get(0).(func(types.Context) []chains.Chain); ok { + r0 = rf(ctx) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]chains.Chain) + } + } + + return r0 +} + // SetPolicies provides a mock function with given fields: ctx, policies func (_m *ObserverAuthorityKeeper) SetPolicies(ctx types.Context, policies authoritytypes.Policies) { _m.Called(ctx, policies) diff --git a/testutil/network/genesis_state.go b/testutil/network/genesis_state.go index 7f0bb2003c..ae6bc247bd 100644 --- a/testutil/network/genesis_state.go +++ b/testutil/network/genesis_state.go @@ -66,7 +66,7 @@ func SetupZetaGenesisState( } if setupChainNonces { - privatenetChains := chains.ChainListByNetworkType(chains.NetworkType_privnet) + privatenetChains := chains.ChainListByNetworkType(chains.NetworkType_privnet, []chains.Chain{}) chainNonceList := make([]observertypes.ChainNonces, len(privatenetChains)) for i, chain := range privatenetChains { chainNonceList[i] = observertypes.ChainNonces{ diff --git a/testutil/sample/authority.go b/testutil/sample/authority.go index be9ca2c555..d777373282 100644 --- a/testutil/sample/authority.go +++ b/testutil/sample/authority.go @@ -29,15 +29,11 @@ func Policies() authoritytypes.Policies { } func ChainInfo(startChainID int64) authoritytypes.ChainInfo { - chain1 := Chain(startChainID) - chain2 := Chain(startChainID + 1) - chain3 := Chain(startChainID + 2) - return authoritytypes.ChainInfo{ Chains: []chains.Chain{ - *chain1, - *chain2, - *chain3, + Chain(startChainID), + Chain(startChainID + 1), + Chain(startChainID + 2), }, } } diff --git a/testutil/sample/crosschain.go b/testutil/sample/crosschain.go index 38d490af62..c4353681bf 100644 --- a/testutil/sample/crosschain.go +++ b/testutil/sample/crosschain.go @@ -280,9 +280,9 @@ func InboundVote(coinType coin.CoinType, from, to int64) types.MsgVoteInbound { return types.MsgVoteInbound{ Creator: "", Sender: EthAddress().String(), - SenderChainId: Chain(from).GetChainId(), + SenderChainId: Chain(from).ChainId, Receiver: EthAddress().String(), - ReceiverChain: Chain(to).GetChainId(), + ReceiverChain: Chain(to).ChainId, Amount: UintInRange(10000000, 1000000000), Message: base64.StdEncoding.EncodeToString(Bytes()), InboundBlockHeight: Uint64InRange(1, 10000), diff --git a/testutil/sample/observer.go b/testutil/sample/observer.go index 3c1a38bc0d..96621ccb26 100644 --- a/testutil/sample/observer.go +++ b/testutil/sample/observer.go @@ -111,7 +111,7 @@ func ChainParamsSupported(chainID int64) *types.ChainParams { } func ChainParamsList() (cpl types.ChainParamsList) { - chainList := chains.ChainListByNetworkType(chains.NetworkType_privnet) + chainList := chains.ChainListByNetworkType(chains.NetworkType_privnet, []chains.Chain{}) for _, chain := range chainList { cpl.ChainParams = append(cpl.ChainParams, ChainParams(chain.ChainId)) diff --git a/testutil/sample/sample.go b/testutil/sample/sample.go index bdd7681ee1..1341be96e4 100644 --- a/testutil/sample/sample.go +++ b/testutil/sample/sample.go @@ -118,7 +118,7 @@ func GenDoc(t *testing.T) *types.GenesisDoc { return genDoc } -func Chain(chainID int64) *chains.Chain { +func Chain(chainID int64) chains.Chain { r := newRandFromSeed(chainID) chainNameLen := len(chains.ChainName_name) @@ -127,7 +127,7 @@ func Chain(chainID int64) *chains.Chain { vmLen := len(chains.Vm_name) consensusLen := len(chains.Consensus_name) - return &chains.Chain{ + return chains.Chain{ ChainId: chainID, ChainName: chains.ChainName(r.Intn(chainNameLen)), Network: chains.Network(r.Intn(networkLen)), diff --git a/x/authority/keeper/chain_info.go b/x/authority/keeper/chain_info.go index 5c9056fe0c..557ef7f1c4 100644 --- a/x/authority/keeper/chain_info.go +++ b/x/authority/keeper/chain_info.go @@ -4,6 +4,7 @@ import ( "github.com/cosmos/cosmos-sdk/store/prefix" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/zeta-chain/zetacore/pkg/chains" "github.com/zeta-chain/zetacore/x/authority/types" ) @@ -24,3 +25,15 @@ func (k Keeper) GetChainInfo(ctx sdk.Context) (val types.ChainInfo, found bool) k.cdc.MustUnmarshal(b, &val) return val, true } + +// GetAdditionalChainList returns the list of chains in chain info object +// additional chains are additional static chain information stored on-chain used in addition with the default chain information +// this list allow to add new chain support without doing an upgrade +// returns empty list if no chains are present +func (k Keeper) GetAdditionalChainList(ctx sdk.Context) []chains.Chain { + chainInfo, found := k.GetChainInfo(ctx) + if !found { + return nil + } + return chainInfo.Chains +} diff --git a/x/authority/keeper/chain_info_test.go b/x/authority/keeper/chain_info_test.go index 87424cb4dd..59f1714504 100644 --- a/x/authority/keeper/chain_info_test.go +++ b/x/authority/keeper/chain_info_test.go @@ -31,3 +31,19 @@ func TestKeeper_SetChainInfo(t *testing.T) { require.True(t, found) require.Equal(t, newChainInfo, got) } + +func TestKeeper_GetChainList(t *testing.T) { + k, ctx := keepertest.AuthorityKeeper(t) + + // Empty list + list := k.GetAdditionalChainList(ctx) + require.Empty(t, list) + + // Set chain info + chainInfo := sample.ChainInfo(42) + k.SetChainInfo(ctx, chainInfo) + + // Check list + list = k.GetAdditionalChainList(ctx) + require.Equal(t, chainInfo.Chains, list) +} diff --git a/x/authority/keeper/grpc_query_chain_info.go b/x/authority/keeper/grpc_query_chain_info.go index 695fcee025..f3632d71a6 100644 --- a/x/authority/keeper/grpc_query_chain_info.go +++ b/x/authority/keeper/grpc_query_chain_info.go @@ -7,6 +7,7 @@ import ( "google.golang.org/grpc/codes" "google.golang.org/grpc/status" + "github.com/zeta-chain/zetacore/pkg/chains" "github.com/zeta-chain/zetacore/x/authority/types" ) @@ -21,9 +22,10 @@ func (k Keeper) ChainInfo( ctx := sdk.UnwrapSDKContext(c) // fetch chain info + // if the object has not been initialized, return an object containing an empty list chainInfo, found := k.GetChainInfo(ctx) if !found { - return nil, status.Error(codes.NotFound, "chain info not found") + chainInfo.Chains = []chains.Chain{} } return &types.QueryGetChainInfoResponse{ChainInfo: chainInfo}, nil diff --git a/x/authority/keeper/grpc_query_chain_info_test.go b/x/authority/keeper/grpc_query_chain_info_test.go index 7529e27437..bd20475a31 100644 --- a/x/authority/keeper/grpc_query_chain_info_test.go +++ b/x/authority/keeper/grpc_query_chain_info_test.go @@ -1,6 +1,7 @@ package keeper_test import ( + "github.com/zeta-chain/zetacore/pkg/chains" "testing" "github.com/stretchr/testify/require" @@ -21,8 +22,13 @@ func TestKeeper_ChainInfo(t *testing.T) { t.Run("chain info not found", func(t *testing.T) { k, ctx := keepertest.AuthorityKeeper(t) - _, err := k.ChainInfo(ctx, &types.QueryGetChainInfoRequest{}) - require.ErrorContains(t, err, "chain info not found") + res, err := k.ChainInfo(ctx, &types.QueryGetChainInfoRequest{}) + require.NoError(t, err) + require.Equal(t, res, &types.QueryGetChainInfoResponse{ + ChainInfo: types.ChainInfo{ + Chains: []chains.Chain{}, + }, + }) }) t.Run("can retrieve chain info", func(t *testing.T) { diff --git a/x/crosschain/keeper/abci.go b/x/crosschain/keeper/abci.go index 4897ae6f66..ee6cfb3aa3 100644 --- a/x/crosschain/keeper/abci.go +++ b/x/crosschain/keeper/abci.go @@ -30,7 +30,7 @@ type CheckAndUpdateCctxGasPriceFunc func( // The function returns the number of cctxs updated and the gas price increase flags used func (k Keeper) IterateAndUpdateCctxGasPrice( ctx sdk.Context, - chains []*zetachains.Chain, + chains []zetachains.Chain, updateFunc CheckAndUpdateCctxGasPriceFunc, ) (int, observertypes.GasPriceIncreaseFlags) { // fetch the gas price increase flags or use default @@ -45,12 +45,14 @@ func (k Keeper) IterateAndUpdateCctxGasPrice( return 0, gasPriceIncreaseFlags } + additionalChains := k.GetAuthorityKeeper().GetAdditionalChainList(ctx) + cctxCount := 0 IterateChains: for _, chain := range chains { // support only external evm chains - if zetachains.IsEVMChain(chain.ChainId) && !zetachains.IsZetaChain(chain.ChainId) { + if zetachains.IsEVMChain(chain.ChainId, additionalChains) && !zetachains.IsZetaChain(chain.ChainId, additionalChains) { res, err := k.ListPendingCctx(sdk.UnwrapSDKContext(ctx), &types.QueryListPendingCctxRequest{ ChainId: chain.ChainId, Limit: gasPriceIncreaseFlags.MaxPendingCctxs, diff --git a/x/crosschain/keeper/abci_test.go b/x/crosschain/keeper/abci_test.go index 36736b254b..817f930079 100644 --- a/x/crosschain/keeper/abci_test.go +++ b/x/crosschain/keeper/abci_test.go @@ -42,7 +42,7 @@ func TestKeeper_IterateAndUpdateCctxGasPrice(t *testing.T) { } // add some evm and non-evm chains - supportedChains := []*chains.Chain{ + supportedChains := []chains.Chain{ {ChainId: chains.Ethereum.ChainId}, {ChainId: chains.BitcoinMainnet.ChainId}, {ChainId: chains.BscMainnet.ChainId}, diff --git a/x/crosschain/keeper/cctx_gateway_observers.go b/x/crosschain/keeper/cctx_gateway_observers.go index 7155e61cd0..18bf31afb8 100644 --- a/x/crosschain/keeper/cctx_gateway_observers.go +++ b/x/crosschain/keeper/cctx_gateway_observers.go @@ -41,7 +41,10 @@ func (c CCTXGatewayObservers) InitiateOutbound( outboundReceiverChainID := config.CCTX.GetCurrentOutboundParam().ReceiverChainId // TODO (https://github.com/zeta-chain/node/issues/1010): workaround for this bug noEthereumTxEvent := false - if chains.IsZetaChain(config.CCTX.InboundParams.SenderChainId) { + if chains.IsZetaChain( + config.CCTX.InboundParams.SenderChainId, + c.crosschainKeeper.GetAuthorityKeeper().GetAdditionalChainList(ctx), + ) { noEthereumTxEvent = true } diff --git a/x/crosschain/keeper/cctx_orchestrator_validate_outbound.go b/x/crosschain/keeper/cctx_orchestrator_validate_outbound.go index 77989b88fe..a1a25e9988 100644 --- a/x/crosschain/keeper/cctx_orchestrator_validate_outbound.go +++ b/x/crosschain/keeper/cctx_orchestrator_validate_outbound.go @@ -121,7 +121,7 @@ func (k Keeper) validateFailedOutboundObservers(ctx sdk.Context, cctx *types.Cro // if the cctx is of coin type cmd or the sender chain is zeta chain, then we do not revert, the cctx is aborted cctx.GetCurrentOutboundParam().TxFinalizationStatus = types.TxFinalizationStatus_Executed cctx.SetAbort("Outbound failed") - } else if chains.IsZetaChain(cctx.InboundParams.SenderChainId) { + } else if chains.IsZetaChain(cctx.InboundParams.SenderChainId, k.GetAuthorityKeeper().GetAdditionalChainList(ctx)) { switch cctx.InboundParams.CoinType { // Try revert if the coin-type is ZETA case coin.CoinType_Zeta: @@ -159,8 +159,7 @@ func (k Keeper) validateFailedOutbound( ) error { switch oldStatus { case types.CctxStatus_PendingOutbound: - senderChain := k.zetaObserverKeeper.GetSupportedChainFromChainID(ctx, cctx.InboundParams.SenderChainId) - if senderChain == nil { + if _, found := k.zetaObserverKeeper.GetSupportedChainFromChainID(ctx, cctx.InboundParams.SenderChainId); !found { return observertypes.ErrSupportedChains } diff --git a/x/crosschain/keeper/cctx_orchestrator_validate_outbound_test.go b/x/crosschain/keeper/cctx_orchestrator_validate_outbound_test.go index fff52e599a..4d97c166f4 100644 --- a/x/crosschain/keeper/cctx_orchestrator_validate_outbound_test.go +++ b/x/crosschain/keeper/cctx_orchestrator_validate_outbound_test.go @@ -248,18 +248,15 @@ func TestKeeper_ValidateFailedOutbound(t *testing.T) { asset := "" // mock successful GetRevertGasLimit for ERC20 - keepertest.MockGetRevertGasLimitForERC20(fungibleMock, asset, *senderChain, 100) + keepertest.MockGetRevertGasLimitForERC20(fungibleMock, asset, senderChain, 100) // mock successful PayGasAndUpdateCctx - keepertest.MockPayGasAndUpdateCCTX(fungibleMock, observerMock, ctx, *k, *senderChain, asset) - - // mock successful GetSupportedChainFromChainID - keepertest.MockGetSupportedChainFromChainID(observerMock, senderChain) + keepertest.MockPayGasAndUpdateCCTX(fungibleMock, observerMock, ctx, *k, senderChain, asset) // mock successful UpdateNonce - _ = keepertest.MockUpdateNonce(observerMock, *senderChain) + _ = keepertest.MockUpdateNonce(observerMock, senderChain) - cctx := GetERC20Cctx(t, receiver, *senderChain, asset, amount) + cctx := GetERC20Cctx(t, receiver, senderChain, asset, amount) cctx.CctxStatus.Status = types.CctxStatus_PendingOutbound err := k.ValidateOutboundObservers( ctx, @@ -288,18 +285,15 @@ func TestKeeper_ValidateFailedOutbound(t *testing.T) { asset := "" // mock successful GetRevertGasLimit for ERC20 - keepertest.MockGetRevertGasLimitForERC20(fungibleMock, asset, *senderChain, 0) + keepertest.MockGetRevertGasLimitForERC20(fungibleMock, asset, senderChain, 0) // mock successful PayGasAndUpdateCctx - keepertest.MockPayGasAndUpdateCCTX(fungibleMock, observerMock, ctx, *k, *senderChain, asset) - - // mock successful GetSupportedChainFromChainID - keepertest.MockGetSupportedChainFromChainID(observerMock, senderChain) + keepertest.MockPayGasAndUpdateCCTX(fungibleMock, observerMock, ctx, *k, senderChain, asset) // mock successful UpdateNonce - _ = keepertest.MockUpdateNonce(observerMock, *senderChain) + _ = keepertest.MockUpdateNonce(observerMock, senderChain) - cctx := GetERC20Cctx(t, receiver, *senderChain, asset, amount) + cctx := GetERC20Cctx(t, receiver, senderChain, asset, amount) cctx.CctxStatus.Status = types.CctxStatus_PendingOutbound err := k.ValidateOutboundObservers( ctx, @@ -328,10 +322,10 @@ func TestKeeper_ValidateFailedOutbound(t *testing.T) { asset := "" // mock successful GetRevertGasLimit for ERC20 - keepertest.MockGetRevertGasLimitForERC20(fungibleMock, asset, *senderChain, 100) + keepertest.MockGetRevertGasLimitForERC20(fungibleMock, asset, senderChain, 100) // mock successful PayGasAndUpdateCctx - keepertest.MockPayGasAndUpdateCCTX(fungibleMock, observerMock, ctx, *k, *senderChain, asset) + keepertest.MockPayGasAndUpdateCCTX(fungibleMock, observerMock, ctx, *k, senderChain, asset) // mock successful GetSupportedChainFromChainID keepertest.MockGetSupportedChainFromChainID(observerMock, senderChain) @@ -340,7 +334,7 @@ func TestKeeper_ValidateFailedOutbound(t *testing.T) { observerMock.On("GetChainNonces", mock.Anything, senderChain.ChainName.String()). Return(observertypes.ChainNonces{}, false) - cctx := GetERC20Cctx(t, receiver, *senderChain, asset, amount) + cctx := GetERC20Cctx(t, receiver, senderChain, asset, amount) cctx.CctxStatus.Status = types.CctxStatus_PendingOutbound err := k.ValidateOutboundObservers( ctx, @@ -367,7 +361,7 @@ func TestKeeper_ValidateFailedOutbound(t *testing.T) { asset := "" // mock successful GetRevertGasLimit for ERC20 - keepertest.MockGetRevertGasLimitForERC20(fungibleMock, asset, *senderChain, 100) + keepertest.MockGetRevertGasLimitForERC20(fungibleMock, asset, senderChain, 100) // mock successful GetSupportedChainFromChainID keepertest.MockGetSupportedChainFromChainID(observerMock, senderChain) @@ -375,7 +369,7 @@ func TestKeeper_ValidateFailedOutbound(t *testing.T) { // mock failed failed GetSupportedChainFromChainID to fail PayGasAndUpdateCctx keepertest.MockFailedGetSupportedChainFromChainID(observerMock, senderChain) - cctx := GetERC20Cctx(t, receiver, *senderChain, asset, amount) + cctx := GetERC20Cctx(t, receiver, senderChain, asset, amount) cctx.CctxStatus.Status = types.CctxStatus_PendingOutbound err := k.ValidateOutboundObservers( ctx, @@ -405,7 +399,7 @@ func TestKeeper_ValidateFailedOutbound(t *testing.T) { Zrc20ContractAddress: sample.EthAddress().String(), }, false).Once() - cctx := GetERC20Cctx(t, receiver, *senderChain, asset, amount) + cctx := GetERC20Cctx(t, receiver, senderChain, asset, amount) cctx.CctxStatus.Status = types.CctxStatus_PendingOutbound err := k.ValidateOutboundObservers( ctx, @@ -487,7 +481,7 @@ func TestKeeper_ValidateOutboundObservers(t *testing.T) { senderChain := getValidEthChain() asset := "" - cctx := GetERC20Cctx(t, receiver, *senderChain, asset, amount) + cctx := GetERC20Cctx(t, receiver, senderChain, asset, amount) cctx.CctxStatus.Status = types.CctxStatus_PendingOutbound oldOutboundParamsLen := len(cctx.OutboundParams) // mock failed GetRevertGasLimit for ERC20 @@ -521,7 +515,7 @@ func TestKeeper_ValidateOutboundObservers(t *testing.T) { senderChain := getValidEthChain() asset := "" - cctx := GetERC20Cctx(t, receiver, *senderChain, asset, amount) + cctx := GetERC20Cctx(t, receiver, senderChain, asset, amount) cctx.OutboundParams = append(cctx.OutboundParams, sample.OutboundParams(sample.Rand())) cctx.OutboundParams[1].ReceiverChainId = 5 cctx.OutboundParams[1].BallotIndex = "" @@ -529,7 +523,7 @@ func TestKeeper_ValidateOutboundObservers(t *testing.T) { cctx.CctxStatus.Status = types.CctxStatus_PendingOutbound // mock successful GetRevertGasLimit for ERC20 - keepertest.MockGetRevertGasLimitForERC20(fungibleMock, asset, *senderChain, 100) + keepertest.MockGetRevertGasLimitForERC20(fungibleMock, asset, senderChain, 100) err := k.ValidateOutboundObservers( ctx, @@ -554,20 +548,17 @@ func TestKeeper_ValidateOutboundObservers(t *testing.T) { senderChain := getValidEthChain() asset := "" - cctx := GetERC20Cctx(t, receiver, *senderChain, asset, amount) + cctx := GetERC20Cctx(t, receiver, senderChain, asset, amount) cctx.CctxStatus.Status = types.CctxStatus_PendingOutbound oldOutboundParamsLen := len(cctx.OutboundParams) // mock successful GetRevertGasLimit for ERC20 - keepertest.MockGetRevertGasLimitForERC20(fungibleMock, asset, *senderChain, 100) + keepertest.MockGetRevertGasLimitForERC20(fungibleMock, asset, senderChain, 100) // mock successful PayGasAndUpdateCctx - keepertest.MockPayGasAndUpdateCCTX(fungibleMock, observerMock, ctx, *k, *senderChain, asset) - - // mock successful GetSupportedChainFromChainID - keepertest.MockGetSupportedChainFromChainID(observerMock, senderChain) + keepertest.MockPayGasAndUpdateCCTX(fungibleMock, observerMock, ctx, *k, senderChain, asset) // mock successful UpdateNonce - _ = keepertest.MockUpdateNonce(observerMock, *senderChain) + _ = keepertest.MockUpdateNonce(observerMock, senderChain) err := k.ValidateOutboundObservers( ctx, diff --git a/x/crosschain/keeper/cctx_utils.go b/x/crosschain/keeper/cctx_utils.go index 3d3cf31cd5..8996ad0b5a 100644 --- a/x/crosschain/keeper/cctx_utils.go +++ b/x/crosschain/keeper/cctx_utils.go @@ -19,8 +19,8 @@ import ( // SetObserverOutboundInfo sets the CCTX outbound nonce to the next available nonce for the TSS address, and updates the nonce of blockchain state. // It also updates the PendingNonces that is used to track the unfulfilled outbound txs. func (k Keeper) SetObserverOutboundInfo(ctx sdk.Context, receiveChainID int64, cctx *types.CrossChainTx) error { - chain := k.GetObserverKeeper().GetSupportedChainFromChainID(ctx, receiveChainID) - if chain == nil { + chain, found := k.GetObserverKeeper().GetSupportedChainFromChainID(ctx, receiveChainID) + if !found { return zetaObserverTypes.ErrSupportedChains } diff --git a/x/crosschain/keeper/cctx_utils_test.go b/x/crosschain/keeper/cctx_utils_test.go index 798fcdd8c4..dc05117c4e 100644 --- a/x/crosschain/keeper/cctx_utils_test.go +++ b/x/crosschain/keeper/cctx_utils_test.go @@ -234,7 +234,7 @@ func TestKeeper_SetObserverOutboundInfo(t *testing.T) { observerMock := keepertest.GetCrosschainObserverMock(t, k) // mock failed GetSupportedChainFromChainID - keepertest.MockFailedGetSupportedChainFromChainID(observerMock, nil) + keepertest.MockFailedGetSupportedChainFromChainID(observerMock, sample.Chain(5)) err := k.SetObserverOutboundInfo(ctx, 5, nil) require.Error(t, err) @@ -248,7 +248,7 @@ func TestKeeper_SetObserverOutboundInfo(t *testing.T) { observerMock := keepertest.GetCrosschainObserverMock(t, k) // mock successful GetSupportedChainFromChainID - keepertest.MockGetSupportedChainFromChainID(observerMock, &chains.Chain{ + keepertest.MockGetSupportedChainFromChainID(observerMock, chains.Chain{ ChainName: 5, ChainId: 5, }) @@ -274,7 +274,7 @@ func TestKeeper_SetObserverOutboundInfo(t *testing.T) { observerMock := keepertest.GetCrosschainObserverMock(t, k) // mock successful GetSupportedChainFromChainID - keepertest.MockGetSupportedChainFromChainID(observerMock, &chains.Chain{ + keepertest.MockGetSupportedChainFromChainID(observerMock, chains.Chain{ ChainName: 5, ChainId: 5, }) @@ -304,7 +304,7 @@ func TestKeeper_SetObserverOutboundInfo(t *testing.T) { observerMock := keepertest.GetCrosschainObserverMock(t, k) // mock successful GetSupportedChainFromChainID - keepertest.MockGetSupportedChainFromChainID(observerMock, &chains.Chain{ + keepertest.MockGetSupportedChainFromChainID(observerMock, chains.Chain{ ChainName: 5, ChainId: 5, }) @@ -336,7 +336,7 @@ func TestKeeper_SetObserverOutboundInfo(t *testing.T) { observerMock := keepertest.GetCrosschainObserverMock(t, k) // mock successful GetSupportedChainFromChainID - keepertest.MockGetSupportedChainFromChainID(observerMock, &chains.Chain{ + keepertest.MockGetSupportedChainFromChainID(observerMock, chains.Chain{ ChainName: 5, ChainId: 5, }) @@ -370,7 +370,7 @@ func TestKeeper_SetObserverOutboundInfo(t *testing.T) { observerMock := keepertest.GetCrosschainObserverMock(t, k) // mock successful GetSupportedChainFromChainID - keepertest.MockGetSupportedChainFromChainID(observerMock, &chains.Chain{ + keepertest.MockGetSupportedChainFromChainID(observerMock, chains.Chain{ ChainName: 5, ChainId: 5, }) diff --git a/x/crosschain/keeper/events.go b/x/crosschain/keeper/events.go index c503835f14..42b32bc589 100644 --- a/x/crosschain/keeper/events.go +++ b/x/crosschain/keeper/events.go @@ -5,7 +5,6 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/zeta-chain/zetacore/pkg/chains" "github.com/zeta-chain/zetacore/x/crosschain/types" ) @@ -15,13 +14,11 @@ func EmitEventInboundFinalized(ctx sdk.Context, cctx *types.CrossChainTx) { MsgTypeUrl: sdk.MsgTypeURL(&types.MsgVoteInbound{}), CctxIndex: cctx.Index, Sender: cctx.InboundParams.Sender, - SenderChain: chains.GetChainFromChainID(cctx.InboundParams.SenderChainId).ChainName.String(), TxOrgin: cctx.InboundParams.TxOrigin, Asset: cctx.InboundParams.Asset, InboundHash: cctx.InboundParams.ObservedHash, InboundBlockHeight: strconv.FormatUint(cctx.InboundParams.ObservedExternalHeight, 10), Receiver: currentOutParam.Receiver, - ReceiverChain: chains.GetChainFromChainID(currentOutParam.ReceiverChainId).ChainName.String(), Amount: cctx.InboundParams.Amount.String(), RelayedMessage: cctx.RelayedMessage, NewStatus: cctx.CctxStatus.Status.String(), diff --git a/x/crosschain/keeper/evm_deposit.go b/x/crosschain/keeper/evm_deposit.go index 858c709f18..0b60a3c9e6 100644 --- a/x/crosschain/keeper/evm_deposit.go +++ b/x/crosschain/keeper/evm_deposit.go @@ -78,7 +78,7 @@ func (k Keeper) HandleEVMDeposit(ctx sdk.Context, cctx *types.CrossChainTx) (boo to = parsedAddress } - from, err := chains.DecodeAddressFromChainID(inboundSenderChainID, inboundSender) + from, err := chains.DecodeAddressFromChainID(inboundSenderChainID, inboundSender, k.GetAuthorityKeeper().GetAdditionalChainList(ctx)) if err != nil { return false, fmt.Errorf("HandleEVMDeposit: unable to decode address: %s", err.Error()) } diff --git a/x/crosschain/keeper/evm_hooks.go b/x/crosschain/keeper/evm_hooks.go index 2fc6310800..366dff4ee4 100644 --- a/x/crosschain/keeper/evm_hooks.go +++ b/x/crosschain/keeper/evm_hooks.go @@ -105,7 +105,7 @@ func (k Keeper) ProcessLogs( // If Validation fails, we will not process the event and return and error. This condition means that the event was correct, and emitted from a registered ZRC20 contract // But the information entered by the user is incorrect. In this case we can return an error and roll back the transaction - if err := ValidateZrc20WithdrawEvent(eventZrc20Withdrawal, coin.ForeignChainId); err != nil { + if err := k.ValidateZrc20WithdrawEvent(ctx, eventZrc20Withdrawal, coin.ForeignChainId); err != nil { return err } // If the event is valid, we will process it and create a new CCTX @@ -137,18 +137,21 @@ func (k Keeper) ProcessZRC20WithdrawalEvent( if !found { return fmt.Errorf("cannot find foreign coin with emittingContract address %s", event.Raw.Address.Hex()) } - receiverChain := k.zetaObserverKeeper.GetSupportedChainFromChainID(ctx, foreignCoin.ForeignChainId) - if receiverChain == nil { + + receiverChain, found := k.zetaObserverKeeper.GetSupportedChainFromChainID(ctx, foreignCoin.ForeignChainId) + if !found { return errorsmod.Wrapf( observertypes.ErrSupportedChains, "chain with chainID %d not supported", foreignCoin.ForeignChainId, ) } - senderChain, err := chains.ZetaChainFromChainID(ctx.ChainID()) + + senderChain, err := chains.ZetaChainFromCosmosChainID(ctx.ChainID()) if err != nil { return fmt.Errorf("ProcessZRC20WithdrawalEvent: failed to convert chainID: %s", err.Error()) } + toAddr, err := receiverChain.EncodeAddress(event.To) if err != nil { return fmt.Errorf("cannot encode address %s: %s", event.To, err.Error()) @@ -215,23 +218,27 @@ func (k Keeper) ProcessZetaSentEvent( receiverChainID := event.DestinationChainId - receiverChain := k.zetaObserverKeeper.GetSupportedChainFromChainID(ctx, receiverChainID.Int64()) - if receiverChain == nil { + receiverChain, found := k.zetaObserverKeeper.GetSupportedChainFromChainID(ctx, receiverChainID.Int64()) + if !found { return observertypes.ErrSupportedChains } + // Validation if we want to send ZETA to an external chain, but there is no ZETA token. chainParams, found := k.zetaObserverKeeper.GetChainParamsByChainID(ctx, receiverChain.ChainId) if !found { return observertypes.ErrChainParamsNotFound } + if receiverChain.IsExternalChain() && chainParams.ZetaTokenContractAddress == "" { return types.ErrUnableToSendCoinType } + toAddr := "0x" + hex.EncodeToString(event.DestinationAddress) - senderChain, err := chains.ZetaChainFromChainID(ctx.ChainID()) + senderChain, err := chains.ZetaChainFromCosmosChainID(ctx.ChainID()) if err != nil { return fmt.Errorf("ProcessZetaSentEvent: failed to convert chainID: %s", err.Error()) } + amount := math.NewUintFromBigInt(event.ZetaValueAndGas) messageString := base64.StdEncoding.EncodeToString(event.Message) // Bump gasLimit by event index (which is very unlikely to be larger than 1000) to always have different ZetaSent events msgs. @@ -264,29 +271,12 @@ func (k Keeper) ProcessZetaSentEvent( return nil } -// ParseZRC20WithdrawalEvent tries extracting ZRC20Withdrawal event from the input logs using the zrc20 contract; -// It only returns a not-nil event if the event has been correctly validated as a valid withdrawal event -func ParseZRC20WithdrawalEvent(log ethtypes.Log) (*zrc20.ZRC20Withdrawal, error) { - zrc20ZEVM, err := zrc20.NewZRC20Filterer(log.Address, bind.ContractFilterer(nil)) - if err != nil { - return nil, err - } - if len(log.Topics) == 0 { - return nil, fmt.Errorf("ParseZRC20WithdrawalEvent: invalid log - no topics") - } - event, err := zrc20ZEVM.ParseWithdrawal(log) - if err != nil { - return nil, err - } - return event, nil -} - // ValidateZrc20WithdrawEvent checks if the ZRC20Withdrawal event is valid // It verifies event information for BTC chains and returns an error if the event is invalid -func ValidateZrc20WithdrawEvent(event *zrc20.ZRC20Withdrawal, chainID int64) error { +func (k Keeper) ValidateZrc20WithdrawEvent(ctx sdk.Context, event *zrc20.ZRC20Withdrawal, chainID int64) error { // The event was parsed; that means the user has deposited tokens to the contract. - if chains.IsBitcoinChain(chainID) { + if chains.IsBitcoinChain(chainID, k.GetAuthorityKeeper().GetAdditionalChainList(ctx)) { if event.Value.Cmp(big.NewInt(constant.BTCWithdrawalDustAmount)) < 0 { return errorsmod.Wrapf( types.ErrInvalidWithdrawalAmount, @@ -306,6 +296,23 @@ func ValidateZrc20WithdrawEvent(event *zrc20.ZRC20Withdrawal, chainID int64) err return nil } +// ParseZRC20WithdrawalEvent tries extracting ZRC20Withdrawal event from the input logs using the zrc20 contract; +// It only returns a not-nil event if the event has been correctly validated as a valid withdrawal event +func ParseZRC20WithdrawalEvent(log ethtypes.Log) (*zrc20.ZRC20Withdrawal, error) { + zrc20ZEVM, err := zrc20.NewZRC20Filterer(log.Address, bind.ContractFilterer(nil)) + if err != nil { + return nil, err + } + if len(log.Topics) == 0 { + return nil, fmt.Errorf("ParseZRC20WithdrawalEvent: invalid log - no topics") + } + event, err := zrc20ZEVM.ParseWithdrawal(log) + if err != nil { + return nil, err + } + return event, nil +} + // ParseZetaSentEvent tries extracting ZetaSent event from connectorZEVM contract; // returns error if the log entry is not a ZetaSent event, or is not emitted from connectorZEVM // It only returns a not-nil event if all the error checks pass diff --git a/x/crosschain/keeper/evm_hooks_test.go b/x/crosschain/keeper/evm_hooks_test.go index 20b1c87e47..36b8938a8a 100644 --- a/x/crosschain/keeper/evm_hooks_test.go +++ b/x/crosschain/keeper/evm_hooks_test.go @@ -157,15 +157,17 @@ func TestParseZRC20WithdrawalEvent(t *testing.T) { } func TestValidateZrc20WithdrawEvent(t *testing.T) { t.Run("successfully validate a valid event", func(t *testing.T) { + k, ctx, _, _ := keepertest.CrosschainKeeper(t) btcMainNetWithdrawalEvent, err := crosschainkeeper.ParseZRC20WithdrawalEvent( *sample.GetValidZRC20WithdrawToBTC(t).Logs[3], ) require.NoError(t, err) - err = crosschainkeeper.ValidateZrc20WithdrawEvent(btcMainNetWithdrawalEvent, chains.BitcoinMainnet.ChainId) + err = k.ValidateZrc20WithdrawEvent(ctx, btcMainNetWithdrawalEvent, chains.BitcoinMainnet.ChainId) require.NoError(t, err) }) t.Run("unable to validate a btc withdrawal event with an invalid amount", func(t *testing.T) { + k, ctx, _, _ := keepertest.CrosschainKeeper(t) btcMainNetWithdrawalEvent, err := crosschainkeeper.ParseZRC20WithdrawalEvent( *sample.GetValidZRC20WithdrawToBTC(t).Logs[3], ) @@ -173,32 +175,34 @@ func TestValidateZrc20WithdrawEvent(t *testing.T) { // 1000 satoshis is the minimum amount that can be withdrawn btcMainNetWithdrawalEvent.Value = big.NewInt(constant.BTCWithdrawalDustAmount) - err = crosschainkeeper.ValidateZrc20WithdrawEvent(btcMainNetWithdrawalEvent, chains.BitcoinMainnet.ChainId) + err = k.ValidateZrc20WithdrawEvent(ctx, btcMainNetWithdrawalEvent, chains.BitcoinMainnet.ChainId) require.NoError(t, err) // 999 satoshis cannot be withdrawn btcMainNetWithdrawalEvent.Value = big.NewInt(constant.BTCWithdrawalDustAmount - 1) - err = crosschainkeeper.ValidateZrc20WithdrawEvent(btcMainNetWithdrawalEvent, chains.BitcoinMainnet.ChainId) + err = k.ValidateZrc20WithdrawEvent(ctx, btcMainNetWithdrawalEvent, chains.BitcoinMainnet.ChainId) require.ErrorContains(t, err, "less than minimum amount") }) t.Run("unable to validate a event with an invalid chain ID", func(t *testing.T) { + k, ctx, _, _ := keepertest.CrosschainKeeper(t) btcMainNetWithdrawalEvent, err := crosschainkeeper.ParseZRC20WithdrawalEvent( *sample.GetValidZRC20WithdrawToBTC(t).Logs[3], ) require.NoError(t, err) - err = crosschainkeeper.ValidateZrc20WithdrawEvent(btcMainNetWithdrawalEvent, chains.BitcoinTestnet.ChainId) + err = k.ValidateZrc20WithdrawEvent(ctx, btcMainNetWithdrawalEvent, chains.BitcoinTestnet.ChainId) require.ErrorContains(t, err, "invalid address") }) t.Run("unable to validate an unsupported address type", func(t *testing.T) { + k, ctx, _, _ := keepertest.CrosschainKeeper(t) btcMainNetWithdrawalEvent, err := crosschainkeeper.ParseZRC20WithdrawalEvent( *sample.GetValidZRC20WithdrawToBTC(t).Logs[3], ) require.NoError(t, err) btcMainNetWithdrawalEvent.To = []byte("04b2891ba8cb491828db3ebc8a780d43b169e7b3974114e6e50f9bab6ec" + "63c2f20f6d31b2025377d05c2a704d3bd799d0d56f3a8543d79a01ab6084a1cb204f260") - err = crosschainkeeper.ValidateZrc20WithdrawEvent(btcMainNetWithdrawalEvent, chains.BitcoinMainnet.ChainId) + err = k.ValidateZrc20WithdrawEvent(ctx, btcMainNetWithdrawalEvent, chains.BitcoinMainnet.ChainId) require.ErrorContains(t, err, "unsupported address") }) } @@ -313,7 +317,7 @@ func TestKeeper_ProcessZRC20WithdrawalEvent(t *testing.T) { ctx = ctx.WithChainID("test_21-1") err = k.ProcessZRC20WithdrawalEvent(ctx, event, emittingContract, txOrigin.Hex()) - require.ErrorContains(t, err, "failed to convert chainID: chain 21 not found") + require.ErrorContains(t, err, "failed to convert chainID") require.Empty(t, k.GetAllCrossChainTx(ctx)) }) diff --git a/x/crosschain/keeper/gas_payment.go b/x/crosschain/keeper/gas_payment.go index 58bfe4ffbf..efac718932 100644 --- a/x/crosschain/keeper/gas_payment.go +++ b/x/crosschain/keeper/gas_payment.go @@ -97,7 +97,7 @@ func (k Keeper) PayGasNativeAndUpdateCctx( cctx.InboundParams.CoinType.String(), ) } - if chain := k.zetaObserverKeeper.GetSupportedChainFromChainID(ctx, chainID); chain == nil { + if _, found := k.zetaObserverKeeper.GetSupportedChainFromChainID(ctx, chainID); !found { return observertypes.ErrSupportedChains } @@ -151,7 +151,7 @@ func (k Keeper) PayGasInERC20AndUpdateCctx( ) } - if chain := k.zetaObserverKeeper.GetSupportedChainFromChainID(ctx, chainID); chain == nil { + if _, found := k.zetaObserverKeeper.GetSupportedChainFromChainID(ctx, chainID); !found { return observertypes.ErrSupportedChains } // get gas params @@ -300,7 +300,7 @@ func (k Keeper) PayGasInZetaAndUpdateCctx( ) } - if chain := k.zetaObserverKeeper.GetSupportedChainFromChainID(ctx, chainID); chain == nil { + if _, found := k.zetaObserverKeeper.GetSupportedChainFromChainID(ctx, chainID); !found { return observertypes.ErrSupportedChains } diff --git a/x/crosschain/keeper/grpc_query_cctx_rate_limit.go b/x/crosschain/keeper/grpc_query_cctx_rate_limit.go index 270fb10b87..d2eb8d85ea 100644 --- a/x/crosschain/keeper/grpc_query_cctx_rate_limit.go +++ b/x/crosschain/keeper/grpc_query_cctx_rate_limit.go @@ -64,7 +64,7 @@ func (k Keeper) RateLimiterInput( // if a cctx is an outgoing cctx that orginates from ZetaChain // reverted incoming cctx has an external `SenderChainId` and should not be counted isCCTXOutgoing := func(cctx *types.CrossChainTx) bool { - return chains.IsZetaChain(cctx.InboundParams.SenderChainId) + return chains.IsZetaChain(cctx.InboundParams.SenderChainId, k.GetAuthorityKeeper().GetAdditionalChainList(ctx)) } // it is a past cctx if its nonce < `nonceLow`, @@ -272,7 +272,7 @@ func (k Keeper) ListPendingCctxWithinRateLimit( // if a cctx is outgoing from ZetaChain // reverted incoming cctx has an external `SenderChainId` and should not be counted isCCTXOutgoing := func(cctx *types.CrossChainTx) bool { - return chains.IsZetaChain(cctx.InboundParams.SenderChainId) + return chains.IsZetaChain(cctx.InboundParams.SenderChainId, k.GetAuthorityKeeper().GetAdditionalChainList(ctx)) } // query pending nonces for each foreign chain and get the lowest height of the pending cctxs diff --git a/x/crosschain/keeper/grpc_query_zeta_conversion_rate.go b/x/crosschain/keeper/grpc_query_zeta_conversion_rate.go index 184b398b66..7abf0f5401 100644 --- a/x/crosschain/keeper/grpc_query_zeta_conversion_rate.go +++ b/x/crosschain/keeper/grpc_query_zeta_conversion_rate.go @@ -19,25 +19,29 @@ func (k Keeper) ConvertGasToZeta( request *types.QueryConvertGasToZetaRequest, ) (*types.QueryConvertGasToZetaResponse, error) { ctx := sdk.UnwrapSDKContext(context) - chain := chains.GetChainFromChainID(request.ChainId) - if chain == nil { + chain, found := chains.GetChainFromChainID(request.ChainId, k.GetAuthorityKeeper().GetAdditionalChainList(ctx)) + if !found { return nil, zetaObserverTypes.ErrSupportedChains } + medianGasPrice, isFound := k.GetMedianGasPriceInUint(ctx, chain.ChainId) if !isFound { return nil, status.Error(codes.InvalidArgument, "invalid request: param chain") } + gasLimit := math.NewUintFromString(request.GasLimit) outTxGasFee := medianGasPrice.Mul(gasLimit) zrc20, err := k.fungibleKeeper.QuerySystemContractGasCoinZRC20(ctx, big.NewInt(chain.ChainId)) if err != nil { return nil, status.Error(codes.NotFound, "zrc20 not found") } + outTxGasFeeInZeta, err := k.fungibleKeeper.QueryUniswapV2RouterGetZetaAmountsIn(ctx, outTxGasFee.BigInt(), zrc20) if err != nil { return nil, status.Error(codes.Internal, "zQueryUniswapv2RouterGetAmountsIn failed") } + return &types.QueryConvertGasToZetaResponse{ OutboundGasInZeta: outTxGasFeeInZeta.String(), ProtocolFeeInZeta: types.GetProtocolFee().String(), diff --git a/x/crosschain/keeper/initiate_outbound.go b/x/crosschain/keeper/initiate_outbound.go index 954db18778..7435517f2f 100644 --- a/x/crosschain/keeper/initiate_outbound.go +++ b/x/crosschain/keeper/initiate_outbound.go @@ -24,8 +24,8 @@ type InitiateOutboundConfig struct { // which handles the state changes and error handling. func (k Keeper) InitiateOutbound(ctx sdk.Context, config InitiateOutboundConfig) (types.CctxStatus, error) { receiverChainID := config.CCTX.GetCurrentOutboundParam().ReceiverChainId - chainInfo := chains.GetChainFromChainID(receiverChainID) - if chainInfo == nil { + chainInfo, found := chains.GetChainFromChainID(receiverChainID, k.GetAuthorityKeeper().GetAdditionalChainList(ctx)) + if !found { return config.CCTX.CctxStatus.Status, cosmoserrors.Wrap( types.ErrInitiatitingOutbound, fmt.Sprintf( diff --git a/x/crosschain/keeper/initiate_outbound_test.go b/x/crosschain/keeper/initiate_outbound_test.go index 78175a76a8..212e1dae75 100644 --- a/x/crosschain/keeper/initiate_outbound_test.go +++ b/x/crosschain/keeper/initiate_outbound_test.go @@ -103,7 +103,7 @@ func TestKeeper_InitiateOutboundZEVMDeposit(t *testing.T) { keepertest.MockFailedGetSupportedChainFromChainID(observerMock, senderChain) // call InitiateOutbound - cctx := GetERC20Cctx(t, receiver, *senderChain, "", amount) + cctx := GetERC20Cctx(t, receiver, senderChain, "", amount) cctx.GetCurrentOutboundParam().ReceiverChainId = chains.ZetaChainPrivnet.ChainId newStatus, err := k.InitiateOutbound(ctx, keeper.InitiateOutboundConfig{CCTX: cctx, ShouldPayGas: true}) require.NoError(t, err) @@ -143,7 +143,7 @@ func TestKeeper_InitiateOutboundZEVMDeposit(t *testing.T) { Return(fungibletypes.ForeignCoins{}, false) // call InitiateOutbound - cctx := GetERC20Cctx(t, receiver, *senderChain, asset, amount) + cctx := GetERC20Cctx(t, receiver, senderChain, asset, amount) cctx.GetCurrentOutboundParam().ReceiverChainId = chains.ZetaChainPrivnet.ChainId newStatus, err := k.InitiateOutbound(ctx, keeper.InitiateOutboundConfig{CCTX: cctx, ShouldPayGas: true}) require.NoError(t, err) @@ -180,13 +180,13 @@ func TestKeeper_InitiateOutboundZEVMDeposit(t *testing.T) { keepertest.MockGetSupportedChainFromChainID(observerMock, senderChain) // mock successful GetRevertGasLimit for ERC20 - keepertest.MockGetRevertGasLimitForERC20(fungibleMock, asset, *senderChain, 100) + keepertest.MockGetRevertGasLimitForERC20(fungibleMock, asset, senderChain, 100) // mock unsuccessful PayGasInERC20AndUpdateCctx keepertest.MockFailedGetSupportedChainFromChainID(observerMock, senderChain) // call InitiateOutbound - cctx := GetERC20Cctx(t, receiver, *senderChain, asset, amount) + cctx := GetERC20Cctx(t, receiver, senderChain, asset, amount) cctx.GetCurrentOutboundParam().ReceiverChainId = chains.ZetaChainPrivnet.ChainId newStatus, err := k.InitiateOutbound(ctx, keeper.InitiateOutboundConfig{CCTX: cctx, ShouldPayGas: true}) require.NoError(t, err) @@ -225,13 +225,13 @@ func TestKeeper_InitiateOutboundZEVMDeposit(t *testing.T) { keepertest.MockGetSupportedChainFromChainID(observerMock, senderChain) // mock successful GetRevertGasLimit for ERC20 - keepertest.MockGetRevertGasLimitForERC20(fungibleMock, asset, *senderChain, 0) + keepertest.MockGetRevertGasLimitForERC20(fungibleMock, asset, senderChain, 0) // mock unsuccessful PayGasInERC20AndUpdateCctx keepertest.MockFailedGetSupportedChainFromChainID(observerMock, senderChain) // call InitiateOutbound - cctx := GetERC20Cctx(t, receiver, *senderChain, asset, amount) + cctx := GetERC20Cctx(t, receiver, senderChain, asset, amount) cctx.GetCurrentOutboundParam().ReceiverChainId = chains.ZetaChainPrivnet.ChainId newStatus, err := k.InitiateOutbound(ctx, keeper.InitiateOutboundConfig{CCTX: cctx, ShouldPayGas: true}) require.NoError(t, err) @@ -268,17 +268,17 @@ func TestKeeper_InitiateOutboundZEVMDeposit(t *testing.T) { keepertest.MockGetSupportedChainFromChainID(observerMock, senderChain) // mock successful GetRevertGasLimit for ERC20 - keepertest.MockGetRevertGasLimitForERC20(fungibleMock, asset, *senderChain, 100) + keepertest.MockGetRevertGasLimitForERC20(fungibleMock, asset, senderChain, 100) // mock successful PayGasAndUpdateCctx - keepertest.MockPayGasAndUpdateCCTX(fungibleMock, observerMock, ctx, *k, *senderChain, asset) + keepertest.MockPayGasAndUpdateCCTX(fungibleMock, observerMock, ctx, *k, senderChain, asset) // Mock unsuccessful UpdateNonce observerMock.On("GetChainNonces", mock.Anything, senderChain.ChainName.String()). Return(observertypes.ChainNonces{}, false) // call InitiateOutbound - cctx := GetERC20Cctx(t, receiver, *senderChain, asset, amount) + cctx := GetERC20Cctx(t, receiver, senderChain, asset, amount) cctx.GetCurrentOutboundParam().ReceiverChainId = chains.ZetaChainPrivnet.ChainId newStatus, err := k.InitiateOutbound(ctx, keeper.InitiateOutboundConfig{CCTX: cctx, ShouldPayGas: true}) require.NoError(t, err) @@ -306,19 +306,16 @@ func TestKeeper_InitiateOutboundZEVMDeposit(t *testing.T) { // mock unsuccessful HandleEVMDeposit which reverts , i.e returns err and isContractReverted = true keepertest.MockRevertForHandleEVMDeposit(fungibleMock, receiver, amount, senderChain.ChainId, errDeposit) - // Mock successful GetSupportedChainFromChainID - keepertest.MockGetSupportedChainFromChainID(observerMock, senderChain) - // mock successful GetRevertGasLimit for ERC20 - keepertest.MockGetRevertGasLimitForERC20(fungibleMock, asset, *senderChain, 100) + keepertest.MockGetRevertGasLimitForERC20(fungibleMock, asset, senderChain, 100) // mock successful PayGasAndUpdateCctx - keepertest.MockPayGasAndUpdateCCTX(fungibleMock, observerMock, ctx, *k, *senderChain, asset) + keepertest.MockPayGasAndUpdateCCTX(fungibleMock, observerMock, ctx, *k, senderChain, asset) // mock successful UpdateNonce - updatedNonce := keepertest.MockUpdateNonce(observerMock, *senderChain) + updatedNonce := keepertest.MockUpdateNonce(observerMock, senderChain) // call InitiateOutbound - cctx := GetERC20Cctx(t, receiver, *senderChain, asset, amount) + cctx := GetERC20Cctx(t, receiver, senderChain, asset, amount) cctx.GetCurrentOutboundParam().ReceiverChainId = chains.ZetaChainPrivnet.ChainId newStatus, err := k.InitiateOutbound(ctx, keeper.InitiateOutboundConfig{CCTX: cctx, ShouldPayGas: true}) require.NoError(t, err) @@ -352,10 +349,10 @@ func TestKeeper_InitiateOutboundZEVMDeposit(t *testing.T) { keepertest.MockGetSupportedChainFromChainID(observerMock, senderChain) // mock successful GetRevertGasLimit for ERC20 - keepertest.MockGetRevertGasLimitForERC20(fungibleMock, asset, *senderChain, 100) + keepertest.MockGetRevertGasLimitForERC20(fungibleMock, asset, senderChain, 100) // call InitiateOutbound - cctx := GetERC20Cctx(t, receiver, *senderChain, asset, amount) + cctx := GetERC20Cctx(t, receiver, senderChain, asset, amount) cctx.GetCurrentOutboundParam().ReceiverChainId = chains.ZetaChainPrivnet.ChainId cctx.OutboundParams = append(cctx.OutboundParams, cctx.GetCurrentOutboundParam()) newStatus, err := k.InitiateOutbound(ctx, keeper.InitiateOutboundConfig{CCTX: cctx, ShouldPayGas: true}) @@ -386,18 +383,27 @@ func TestKeeper_InitiateOutboundProcessCrosschainMsgPassing(t *testing.T) { receiverChain := getValidEthChain() // mock successful PayGasAndUpdateCctx - keepertest.MockPayGasAndUpdateCCTX(fungibleMock, observerMock, ctx, *k, *receiverChain, "") + keepertest.MockPayGasAndUpdateCCTX(fungibleMock, observerMock, ctx, *k, receiverChain, "") // mock successful UpdateNonce - updatedNonce := keepertest.MockUpdateNonce(observerMock, *receiverChain) + nonce := uint64(1) + tss := sample.Tss() + observerMock.On("GetChainNonces", mock.Anything, receiverChain.ChainName.String()). + Return(observertypes.ChainNonces{Nonce: nonce}, true) + observerMock.On("GetTSS", mock.Anything). + Return(tss, true) + observerMock.On("GetPendingNonces", mock.Anything, tss.TssPubkey, mock.Anything). + Return(observertypes.PendingNonces{NonceHigh: int64(nonce)}, true) + observerMock.On("SetChainNonces", mock.Anything, mock.Anything) + observerMock.On("SetPendingNonces", mock.Anything, mock.Anything) // call InitiateOutbound - cctx := GetERC20Cctx(t, receiver, *receiverChain, "", amount) + cctx := GetERC20Cctx(t, receiver, receiverChain, "", amount) newStatus, err := k.InitiateOutbound(ctx, keeper.InitiateOutboundConfig{CCTX: cctx, ShouldPayGas: true}) require.NoError(t, err) require.Equal(t, types.CctxStatus_PendingOutbound, cctx.CctxStatus.Status) require.Equal(t, types.CctxStatus_PendingOutbound, newStatus) - require.Equal(t, updatedNonce, cctx.GetCurrentOutboundParam().TssNonce) + require.Equal(t, nonce, cctx.GetCurrentOutboundParam().TssNonce) }) t.Run("unable to process crosschain msg passing PayGasAndUpdateCctx fails", func(t *testing.T) { @@ -413,10 +419,10 @@ func TestKeeper_InitiateOutboundProcessCrosschainMsgPassing(t *testing.T) { receiverChain := getValidEthChain() // mock unsuccessful PayGasAndUpdateCctx - keepertest.MockFailedGetSupportedChainFromChainID(observerMock, nil) + keepertest.MockFailedGetSupportedChainFromChainID(observerMock, receiverChain) // call InitiateOutbound - cctx := GetERC20Cctx(t, receiver, *receiverChain, "", amount) + cctx := GetERC20Cctx(t, receiver, receiverChain, "", amount) newStatus, err := k.InitiateOutbound(ctx, keeper.InitiateOutboundConfig{CCTX: cctx, ShouldPayGas: true}) require.ErrorIs(t, err, observertypes.ErrSupportedChains) require.Equal(t, types.CctxStatus_Aborted, cctx.CctxStatus.Status) @@ -438,14 +444,14 @@ func TestKeeper_InitiateOutboundProcessCrosschainMsgPassing(t *testing.T) { receiverChain := getValidEthChain() // mock successful PayGasAndUpdateCctx - keepertest.MockPayGasAndUpdateCCTX(fungibleMock, observerMock, ctx, *k, *receiverChain, "") + keepertest.MockPayGasAndUpdateCCTX(fungibleMock, observerMock, ctx, *k, receiverChain, "") // mock unsuccessful UpdateNonce observerMock.On("GetChainNonces", mock.Anything, receiverChain.ChainName.String()). Return(observertypes.ChainNonces{}, false) // call InitiateOutbound - cctx := GetERC20Cctx(t, receiver, *receiverChain, "", amount) + cctx := GetERC20Cctx(t, receiver, receiverChain, "", amount) newStatus, err := k.InitiateOutbound(ctx, keeper.InitiateOutboundConfig{CCTX: cctx, ShouldPayGas: true}) require.ErrorContains(t, err, "cannot find receiver chain nonce") require.Equal(t, types.CctxStatus_Aborted, cctx.CctxStatus.Status) @@ -467,7 +473,7 @@ func TestKeeper_InitiateOutboundFailures(t *testing.T) { receiverChain := getValidEthChain() receiverChain.ChainId = 123 // call InitiateOutbound - cctx := GetERC20Cctx(t, receiver, *receiverChain, "", amount) + cctx := GetERC20Cctx(t, receiver, receiverChain, "", amount) newStatus, err := k.InitiateOutbound(ctx, keeper.InitiateOutboundConfig{CCTX: cctx, ShouldPayGas: true}) require.Error(t, err) require.Equal(t, types.CctxStatus_PendingInbound, newStatus) diff --git a/x/crosschain/keeper/msg_server_add_inbound_tracker.go b/x/crosschain/keeper/msg_server_add_inbound_tracker.go index fd9b8fa2bd..ae35036e88 100644 --- a/x/crosschain/keeper/msg_server_add_inbound_tracker.go +++ b/x/crosschain/keeper/msg_server_add_inbound_tracker.go @@ -18,8 +18,8 @@ func (k msgServer) AddInboundTracker( msg *types.MsgAddInboundTracker, ) (*types.MsgAddInboundTrackerResponse, error) { ctx := sdk.UnwrapSDKContext(goCtx) - chain := k.GetObserverKeeper().GetSupportedChainFromChainID(ctx, msg.ChainId) - if chain == nil { + + if _, found := k.GetObserverKeeper().GetSupportedChainFromChainID(ctx, msg.ChainId); !found { return nil, observertypes.ErrSupportedChains } diff --git a/x/crosschain/keeper/msg_server_add_inbound_tracker_test.go b/x/crosschain/keeper/msg_server_add_inbound_tracker_test.go index 9d135d513d..0345cba1a1 100644 --- a/x/crosschain/keeper/msg_server_add_inbound_tracker_test.go +++ b/x/crosschain/keeper/msg_server_add_inbound_tracker_test.go @@ -33,7 +33,7 @@ func TestMsgServer_AddToInboundTracker(t *testing.T) { txHash := "string" chainID := getValidEthChainID() - observerMock.On("GetSupportedChainFromChainID", mock.Anything, mock.Anything).Return(&chains.Chain{}) + observerMock.On("GetSupportedChainFromChainID", mock.Anything, mock.Anything).Return(chains.Chain{}, true) observerMock.On("IsNonTombstonedObserver", mock.Anything, mock.Anything).Return(false) msg := types.MsgAddInboundTracker{ @@ -62,7 +62,7 @@ func TestMsgServer_AddToInboundTracker(t *testing.T) { chainID := getValidEthChainID() observerMock := keepertest.GetCrosschainObserverMock(t, k) - observerMock.On("GetSupportedChainFromChainID", mock.Anything, mock.Anything).Return(nil) + observerMock.On("GetSupportedChainFromChainID", mock.Anything, mock.Anything).Return(chains.Chain{}, false) msg := types.MsgAddInboundTracker{ Creator: sample.AccAddress(), @@ -92,7 +92,7 @@ func TestMsgServer_AddToInboundTracker(t *testing.T) { txHash := "string" chainID := getValidEthChainID() - observerMock.On("GetSupportedChainFromChainID", mock.Anything, mock.Anything).Return(&chains.Chain{}) + observerMock.On("GetSupportedChainFromChainID", mock.Anything, mock.Anything).Return(chains.Chain{}, true) observerMock.On("IsNonTombstonedObserver", mock.Anything, mock.Anything).Return(false) setSupportedChain(ctx, zk, chainID) @@ -127,7 +127,7 @@ func TestMsgServer_AddToInboundTracker(t *testing.T) { txHash := "string" chainID := getValidEthChainID() - observerMock.On("GetSupportedChainFromChainID", mock.Anything, mock.Anything).Return(&chains.Chain{}) + observerMock.On("GetSupportedChainFromChainID", mock.Anything, mock.Anything).Return(chains.Chain{}, true) observerMock.On("IsNonTombstonedObserver", mock.Anything, mock.Anything).Return(true) msg := types.MsgAddInboundTracker{ @@ -161,7 +161,7 @@ func TestMsgServer_AddToInboundTracker(t *testing.T) { txHash := "string" chainID := getValidEthChainID() - observerMock.On("GetSupportedChainFromChainID", mock.Anything, mock.Anything).Return(&chains.Chain{}) + observerMock.On("GetSupportedChainFromChainID", mock.Anything, mock.Anything).Return(chains.Chain{}, true) observerMock.On("IsNonTombstonedObserver", mock.Anything, mock.Anything).Return(false) lightclientMock.On("VerifyProof", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything). Return(nil, errors.New("error")) @@ -195,7 +195,7 @@ func TestMsgServer_AddToInboundTracker(t *testing.T) { txHash := "string" chainID := getValidEthChainID() - observerMock.On("GetSupportedChainFromChainID", mock.Anything, mock.Anything).Return(&chains.Chain{}) + observerMock.On("GetSupportedChainFromChainID", mock.Anything, mock.Anything).Return(chains.Chain{}, true) observerMock.On("IsNonTombstonedObserver", mock.Anything, mock.Anything).Return(false) lightclientMock.On("VerifyProof", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything). Return(sample.Bytes(), nil) @@ -231,7 +231,7 @@ func TestMsgServer_AddToInboundTracker(t *testing.T) { txHash := "string" chainID := getValidEthChainID() - observerMock.On("GetSupportedChainFromChainID", mock.Anything, mock.Anything).Return(&chains.Chain{}) + observerMock.On("GetSupportedChainFromChainID", mock.Anything, mock.Anything).Return(chains.Chain{}, true) observerMock.On("IsNonTombstonedObserver", mock.Anything, mock.Anything).Return(false) lightclientMock.On("VerifyProof", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything). Return(sample.Bytes(), nil) @@ -271,7 +271,7 @@ func TestMsgServer_AddToInboundTracker(t *testing.T) { txHash := "string" chainID := getValidEthChainID() - observerMock.On("GetSupportedChainFromChainID", mock.Anything, mock.Anything).Return(&chains.Chain{}) + observerMock.On("GetSupportedChainFromChainID", mock.Anything, mock.Anything).Return(chains.Chain{}, true) observerMock.On("IsNonTombstonedObserver", mock.Anything, mock.Anything).Return(false) observerMock.On("GetChainParamsByChainID", mock.Anything, mock.Anything). Return(sample.ChainParams(chains.Ethereum.ChainId), true) @@ -317,7 +317,7 @@ func TestMsgServer_AddToInboundTracker(t *testing.T) { observerMock := keepertest.GetCrosschainObserverMock(t, k) lightclientMock := keepertest.GetCrosschainLightclientMock(t, k) - observerMock.On("GetSupportedChainFromChainID", mock.Anything, mock.Anything).Return(&chains.Chain{}) + observerMock.On("GetSupportedChainFromChainID", mock.Anything, mock.Anything).Return(chains.Chain{}, true) observerMock.On("IsNonTombstonedObserver", mock.Anything, mock.Anything).Return(false) observerMock.On("GetChainParamsByChainID", mock.Anything, mock.Anything). Return(sample.ChainParams(chains.Ethereum.ChainId), true) diff --git a/x/crosschain/keeper/msg_server_add_outbound_tracker.go b/x/crosschain/keeper/msg_server_add_outbound_tracker.go index ce7b2f0c03..5a3c98e9e9 100644 --- a/x/crosschain/keeper/msg_server_add_outbound_tracker.go +++ b/x/crosschain/keeper/msg_server_add_outbound_tracker.go @@ -27,8 +27,7 @@ func (k msgServer) AddOutboundTracker( ctx := sdk.UnwrapSDKContext(goCtx) // check the chain is supported - chain := k.GetObserverKeeper().GetSupportedChainFromChainID(ctx, msg.ChainId) - if chain == nil { + if _, found := k.GetObserverKeeper().GetSupportedChainFromChainID(ctx, msg.ChainId); !found { return nil, observertypes.ErrSupportedChains } @@ -138,7 +137,7 @@ func verifyProofAndOutboundBody(ctx sdk.Context, k msgServer, msg *types.MsgAddO // get tss address var bitcoinChainID int64 - if chains.IsBitcoinChain(msg.ChainId) { + if chains.IsBitcoinChain(msg.ChainId, k.GetAuthorityKeeper().GetAdditionalChainList(ctx)) { bitcoinChainID = msg.ChainId } diff --git a/x/crosschain/keeper/msg_server_add_outbound_tracker_test.go b/x/crosschain/keeper/msg_server_add_outbound_tracker_test.go index e43800b2ac..7abe63fe15 100644 --- a/x/crosschain/keeper/msg_server_add_outbound_tracker_test.go +++ b/x/crosschain/keeper/msg_server_add_outbound_tracker_test.go @@ -39,7 +39,7 @@ func TestMsgServer_AddToOutboundTracker(t *testing.T) { authorityMock := keepertest.GetCrosschainAuthorityMock(t, k) observerMock := keepertest.GetCrosschainObserverMock(t, k) - observerMock.On("GetSupportedChainFromChainID", mock.Anything, mock.Anything).Return(&chains.Chain{}) + observerMock.On("GetSupportedChainFromChainID", mock.Anything, mock.Anything).Return(chains.Chain{}, true) observerMock.On("IsNonTombstonedObserver", mock.Anything, mock.Anything).Return(false) keepertest.MockCctxByNonce(t, ctx, *k, observerMock, types.CctxStatus_PendingOutbound, false) @@ -74,7 +74,7 @@ func TestMsgServer_AddToOutboundTracker(t *testing.T) { chainID := getEthereumChainID() hash := sample.Hash().Hex() - observerMock.On("GetSupportedChainFromChainID", mock.Anything, mock.Anything).Return(&chains.Chain{}) + observerMock.On("GetSupportedChainFromChainID", mock.Anything, mock.Anything).Return(chains.Chain{}, true) observerMock.On("IsNonTombstonedObserver", mock.Anything, mock.Anything).Return(true) keepertest.MockCctxByNonce(t, ctx, *k, observerMock, types.CctxStatus_PendingOutbound, false) @@ -110,7 +110,7 @@ func TestMsgServer_AddToOutboundTracker(t *testing.T) { existinghHash := sample.Hash().Hex() newHash := sample.Hash().Hex() - observerMock.On("GetSupportedChainFromChainID", mock.Anything, mock.Anything).Return(&chains.Chain{}) + observerMock.On("GetSupportedChainFromChainID", mock.Anything, mock.Anything).Return(chains.Chain{}, true) observerMock.On("IsNonTombstonedObserver", mock.Anything, mock.Anything).Return(false) keepertest.MockCctxByNonce(t, ctx, *k, observerMock, types.CctxStatus_PendingOutbound, false) @@ -163,7 +163,7 @@ func TestMsgServer_AddToOutboundTracker(t *testing.T) { } observerMock := keepertest.GetCrosschainObserverMock(t, k) - observerMock.On("GetSupportedChainFromChainID", mock.Anything, mock.Anything).Return(&chains.Chain{}) + observerMock.On("GetSupportedChainFromChainID", mock.Anything, mock.Anything).Return(chains.Chain{}, true) // set cctx status to outbound mined keepertest.MockCctxByNonce(t, ctx, *k, observerMock, types.CctxStatus_OutboundMined, false) @@ -187,7 +187,7 @@ func TestMsgServer_AddToOutboundTracker(t *testing.T) { admin := sample.AccAddress() observerMock := keepertest.GetCrosschainObserverMock(t, k) - observerMock.On("GetSupportedChainFromChainID", mock.Anything, mock.Anything).Return(nil) + observerMock.On("GetSupportedChainFromChainID", mock.Anything, mock.Anything).Return(chains.Chain{}, false) chainID := getEthereumChainID() @@ -214,7 +214,7 @@ func TestMsgServer_AddToOutboundTracker(t *testing.T) { observerMock := keepertest.GetCrosschainObserverMock(t, k) - observerMock.On("GetSupportedChainFromChainID", mock.Anything, mock.Anything).Return(&chains.Chain{}) + observerMock.On("GetSupportedChainFromChainID", mock.Anything, mock.Anything).Return(chains.Chain{}, true) keepertest.MockCctxByNonce(t, ctx, *k, observerMock, types.CctxStatus_PendingOutbound, true) chainID := getEthereumChainID() @@ -245,7 +245,7 @@ func TestMsgServer_AddToOutboundTracker(t *testing.T) { chainID := getEthereumChainID() newHash := sample.Hash().Hex() - observerMock.On("GetSupportedChainFromChainID", mock.Anything, mock.Anything).Return(&chains.Chain{}) + observerMock.On("GetSupportedChainFromChainID", mock.Anything, mock.Anything).Return(chains.Chain{}, true) observerMock.On("IsNonTombstonedObserver", mock.Anything, mock.Anything).Return(false) keepertest.MockCctxByNonce(t, ctx, *k, observerMock, types.CctxStatus_PendingOutbound, false) @@ -291,7 +291,7 @@ func TestMsgServer_AddToOutboundTracker(t *testing.T) { authorityMock := keepertest.GetCrosschainAuthorityMock(t, k) observerMock := keepertest.GetCrosschainObserverMock(t, k) - observerMock.On("GetSupportedChainFromChainID", mock.Anything, mock.Anything).Return(&chains.Chain{}) + observerMock.On("GetSupportedChainFromChainID", mock.Anything, mock.Anything).Return(chains.Chain{}, true) observerMock.On("IsNonTombstonedObserver", mock.Anything, mock.Anything).Return(false) keepertest.MockCctxByNonce(t, ctx, *k, observerMock, types.CctxStatus_PendingOutbound, false) @@ -340,7 +340,7 @@ func TestMsgServer_AddToOutboundTracker(t *testing.T) { observerMock := keepertest.GetCrosschainObserverMock(t, k) lightclientMock := keepertest.GetCrosschainLightclientMock(t, k) - observerMock.On("GetSupportedChainFromChainID", mock.Anything, mock.Anything).Return(&chains.Chain{}) + observerMock.On("GetSupportedChainFromChainID", mock.Anything, mock.Anything).Return(chains.Chain{}, true) observerMock.On("IsNonTombstonedObserver", mock.Anything, mock.Anything).Return(false) keepertest.MockCctxByNonce(t, ctx, *k, observerMock, types.CctxStatus_PendingOutbound, false) observerMock.On("GetTssAddress", mock.Anything, mock.Anything).Return(&observertypes.QueryGetTssAddressResponse{ @@ -359,6 +359,7 @@ func TestMsgServer_AddToOutboundTracker(t *testing.T) { Nonce: 42, } keepertest.MockCheckAuthorization(&authorityMock.Mock, &msg, authoritytypes.ErrUnauthorized) + keepertest.MockGetChainListEmpty(&authorityMock.Mock) _, err := msgServer.AddOutboundTracker(ctx, &msg) require.NoError(t, err) tracker, found := k.GetOutboundTracker(ctx, chainID, 42) @@ -384,7 +385,7 @@ func TestMsgServer_AddToOutboundTracker(t *testing.T) { observerMock := keepertest.GetCrosschainObserverMock(t, k) lightclientMock := keepertest.GetCrosschainLightclientMock(t, k) - observerMock.On("GetSupportedChainFromChainID", mock.Anything, mock.Anything).Return(&chains.Chain{}) + observerMock.On("GetSupportedChainFromChainID", mock.Anything, mock.Anything).Return(chains.Chain{}, true) observerMock.On("IsNonTombstonedObserver", mock.Anything, mock.Anything).Return(false) keepertest.MockCctxByNonce(t, ctx, *k, observerMock, types.CctxStatus_PendingOutbound, false) observerMock.On("GetTssAddress", mock.Anything, mock.Anything).Return(&observertypes.QueryGetTssAddressResponse{ @@ -418,6 +419,7 @@ func TestMsgServer_AddToOutboundTracker(t *testing.T) { Nonce: 42, } keepertest.MockCheckAuthorization(&authorityMock.Mock, &msg, authoritytypes.ErrUnauthorized) + keepertest.MockGetChainListEmpty(&authorityMock.Mock) _, err := msgServer.AddOutboundTracker(ctx, &msg) require.NoError(t, err) tracker, found := k.GetOutboundTracker(ctx, chainID, 42) @@ -444,7 +446,7 @@ func TestMsgServer_AddToOutboundTracker(t *testing.T) { observerMock := keepertest.GetCrosschainObserverMock(t, k) lightclientMock := keepertest.GetCrosschainLightclientMock(t, k) - observerMock.On("GetSupportedChainFromChainID", mock.Anything, mock.Anything).Return(&chains.Chain{}) + observerMock.On("GetSupportedChainFromChainID", mock.Anything, mock.Anything).Return(chains.Chain{}, true) observerMock.On("IsNonTombstonedObserver", mock.Anything, mock.Anything).Return(false) keepertest.MockCctxByNonce(t, ctx, *k, observerMock, types.CctxStatus_PendingOutbound, false) lightclientMock.On("VerifyProof", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything). @@ -481,7 +483,7 @@ func TestMsgServer_AddToOutboundTracker(t *testing.T) { observerMock := keepertest.GetCrosschainObserverMock(t, k) lightclientMock := keepertest.GetCrosschainLightclientMock(t, k) - observerMock.On("GetSupportedChainFromChainID", mock.Anything, mock.Anything).Return(&chains.Chain{}) + observerMock.On("GetSupportedChainFromChainID", mock.Anything, mock.Anything).Return(chains.Chain{}, true) observerMock.On("IsNonTombstonedObserver", mock.Anything, mock.Anything).Return(false) keepertest.MockCctxByNonce(t, ctx, *k, observerMock, types.CctxStatus_PendingOutbound, false) lightclientMock.On("VerifyProof", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything). @@ -500,6 +502,7 @@ func TestMsgServer_AddToOutboundTracker(t *testing.T) { Nonce: 42, } keepertest.MockCheckAuthorization(&authorityMock.Mock, &msg, authoritytypes.ErrUnauthorized) + keepertest.MockGetChainListEmpty(&authorityMock.Mock) _, err := msgServer.AddOutboundTracker(ctx, &msg) require.ErrorIs(t, err, observertypes.ErrTssNotFound) }) @@ -520,7 +523,7 @@ func TestMsgServer_AddToOutboundTracker(t *testing.T) { observerMock := keepertest.GetCrosschainObserverMock(t, k) lightclientMock := keepertest.GetCrosschainLightclientMock(t, k) - observerMock.On("GetSupportedChainFromChainID", mock.Anything, mock.Anything).Return(&chains.Chain{}) + observerMock.On("GetSupportedChainFromChainID", mock.Anything, mock.Anything).Return(chains.Chain{}, true) observerMock.On("IsNonTombstonedObserver", mock.Anything, mock.Anything).Return(false) keepertest.MockCctxByNonce(t, ctx, *k, observerMock, types.CctxStatus_PendingOutbound, false) observerMock.On("GetTssAddress", mock.Anything, mock.Anything).Return(&observertypes.QueryGetTssAddressResponse{ @@ -541,6 +544,7 @@ func TestMsgServer_AddToOutboundTracker(t *testing.T) { Nonce: 42, } keepertest.MockCheckAuthorization(&authorityMock.Mock, &msg, authoritytypes.ErrUnauthorized) + keepertest.MockGetChainListEmpty(&authorityMock.Mock) _, err := msgServer.AddOutboundTracker(ctx, &msg) require.ErrorIs(t, err, types.ErrTxBodyVerificationFail) }) diff --git a/x/crosschain/keeper/msg_server_migrate_tss_funds.go b/x/crosschain/keeper/msg_server_migrate_tss_funds.go index 05f218162f..f5558fe689 100644 --- a/x/crosschain/keeper/msg_server_migrate_tss_funds.go +++ b/x/crosschain/keeper/msg_server_migrate_tss_funds.go @@ -143,9 +143,14 @@ func (k Keeper) MigrateTSSFundsForChain( EffectiveGasPrice: sdkmath.Int{}, EffectiveGasLimit: 0, TssPubkey: currentTss.TssPubkey, - }}} + }}, + } + + // retrieve from authority keeper additional chains + additionalChains := k.GetAuthorityKeeper().GetAdditionalChainList(ctx) + // Set the sender and receiver addresses for EVM chain - if chains.IsEVMChain(chainID) { + if chains.IsEVMChain(chainID, additionalChains) { ethAddressOld, err := zetacrypto.GetTssAddrEVM(currentTss.TssPubkey) if err != nil { return err @@ -179,7 +184,7 @@ func (k Keeper) MigrateTSSFundsForChain( cctx.GetCurrentOutboundParam().Amount = amount.Sub(evmFee) } // Set the sender and receiver addresses for Bitcoin chain - if chains.IsBitcoinChain(chainID) { + if chains.IsBitcoinChain(chainID, additionalChains) { bitcoinNetParams, err := chains.BitcoinNetParamsFromChainID(chainID) if err != nil { return err diff --git a/x/crosschain/keeper/msg_server_migrate_tss_funds_test.go b/x/crosschain/keeper/msg_server_migrate_tss_funds_test.go index fbd3c870bf..9da596f876 100644 --- a/x/crosschain/keeper/msg_server_migrate_tss_funds_test.go +++ b/x/crosschain/keeper/msg_server_migrate_tss_funds_test.go @@ -99,7 +99,7 @@ func TestKeeper_MigrateTSSFundsForChain(t *testing.T) { msgServer := keeper.NewMsgServerImpl(*k) - indexString, _ := setupTssMigrationParams(zk, k, ctx, *chain, amount, true, true) + indexString, _ := setupTssMigrationParams(zk, k, ctx, chain, amount, true, true) gp, found := k.GetMedianGasPriceInUint(ctx, chain.ChainId) require.True(t, found) msg := crosschaintypes.MsgMigrateTssFunds{ @@ -108,6 +108,7 @@ func TestKeeper_MigrateTSSFundsForChain(t *testing.T) { Amount: amount, } keepertest.MockCheckAuthorization(&authorityMock.Mock, &msg, nil) + keepertest.MockGetChainListEmpty(&authorityMock.Mock) _, err := msgServer.MigrateTssFunds(ctx, &msg) require.NoError(t, err) hash := crypto.Keccak256Hash([]byte(indexString)) @@ -131,7 +132,7 @@ func TestKeeper_MigrateTSSFundsForChain(t *testing.T) { authorityMock := keepertest.GetCrosschainAuthorityMock(t, k) msgServer := keeper.NewMsgServerImpl(*k) - indexString, _ := setupTssMigrationParams(zk, k, ctx, *chain, amount, true, true) + indexString, _ := setupTssMigrationParams(zk, k, ctx, chain, amount, true, true) gp, found := k.GetMedianGasPriceInUint(ctx, chain.ChainId) require.True(t, found) @@ -141,6 +142,7 @@ func TestKeeper_MigrateTSSFundsForChain(t *testing.T) { Amount: amount, } keepertest.MockCheckAuthorization(&authorityMock.Mock, &msg, nil) + keepertest.MockGetChainListEmpty(&authorityMock.Mock) _, err := msgServer.MigrateTssFunds(ctx, &msg) require.NoError(t, err) hash := crypto.Keccak256Hash([]byte(indexString)) @@ -368,7 +370,7 @@ func TestMsgServer_MigrateTssFunds(t *testing.T) { msgServer := keeper.NewMsgServerImpl(*k) - indexString, _ := setupTssMigrationParams(zk, k, ctx, *chain, amount, true, true) + indexString, _ := setupTssMigrationParams(zk, k, ctx, chain, amount, true, true) msg := crosschaintypes.MsgMigrateTssFunds{ Creator: admin, @@ -376,6 +378,7 @@ func TestMsgServer_MigrateTssFunds(t *testing.T) { Amount: amount, } keepertest.MockCheckAuthorization(&authorityMock.Mock, &msg, nil) + keepertest.MockGetChainListEmpty(&authorityMock.Mock) _, err := msgServer.MigrateTssFunds(ctx, &msg) require.NoError(t, err) hash := crypto.Keccak256Hash([]byte(indexString)) @@ -398,7 +401,7 @@ func TestMsgServer_MigrateTssFunds(t *testing.T) { authorityMock := keepertest.GetCrosschainAuthorityMock(t, k) msgServer := keeper.NewMsgServerImpl(*k) - indexString, _ := setupTssMigrationParams(zk, k, ctx, *chain, amount, true, true) + indexString, _ := setupTssMigrationParams(zk, k, ctx, chain, amount, true, true) msg := crosschaintypes.MsgMigrateTssFunds{ Creator: admin, @@ -406,6 +409,7 @@ func TestMsgServer_MigrateTssFunds(t *testing.T) { Amount: amount, } keepertest.MockCheckAuthorization(&authorityMock.Mock, &msg, nil) + keepertest.MockGetChainListEmpty(&authorityMock.Mock) _, err := msgServer.MigrateTssFunds(ctx, &msg) require.ErrorContains(t, err, crosschaintypes.ErrCannotMigrateTssFunds.Error()) hash := crypto.Keccak256Hash([]byte(indexString)) @@ -425,7 +429,7 @@ func TestMsgServer_MigrateTssFunds(t *testing.T) { authorityMock := keepertest.GetCrosschainAuthorityMock(t, k) msgServer := keeper.NewMsgServerImpl(*k) - indexString, _ := setupTssMigrationParams(zk, k, ctx, *chain, amount, false, true) + indexString, _ := setupTssMigrationParams(zk, k, ctx, chain, amount, false, true) msg := crosschaintypes.MsgMigrateTssFunds{ Creator: admin, @@ -452,7 +456,7 @@ func TestMsgServer_MigrateTssFunds(t *testing.T) { authorityMock := keepertest.GetCrosschainAuthorityMock(t, k) msgServer := keeper.NewMsgServerImpl(*k) - indexString, tssPubkey := setupTssMigrationParams(zk, k, ctx, *chain, amount, true, true) + indexString, tssPubkey := setupTssMigrationParams(zk, k, ctx, chain, amount, true, true) k.GetObserverKeeper().SetPendingNonces(ctx, observertypes.PendingNonces{ NonceLow: 1, NonceHigh: 10, @@ -486,7 +490,7 @@ func TestMsgServer_MigrateTssFunds(t *testing.T) { authorityMock := keepertest.GetCrosschainAuthorityMock(t, k) msgServer := keeper.NewMsgServerImpl(*k) - indexString, tssPubkey := setupTssMigrationParams(zk, k, ctx, *chain, amount, true, true) + indexString, tssPubkey := setupTssMigrationParams(zk, k, ctx, chain, amount, true, true) k.GetObserverKeeper().SetPendingNonces(ctx, observertypes.PendingNonces{ NonceLow: 1, NonceHigh: 1, @@ -507,6 +511,7 @@ func TestMsgServer_MigrateTssFunds(t *testing.T) { Amount: amount, } keepertest.MockCheckAuthorization(&authorityMock.Mock, &msg, nil) + keepertest.MockGetChainListEmpty(&authorityMock.Mock) _, err := msgServer.MigrateTssFunds(ctx, &msg) require.ErrorIs(t, err, crosschaintypes.ErrCannotMigrateTssFunds) require.ErrorContains(t, err, "cannot migrate funds while there are pending migrations") @@ -532,7 +537,7 @@ func TestMsgServer_MigrateTssFunds(t *testing.T) { msgServer := keeper.NewMsgServerImpl(*k) - indexString, _ := setupTssMigrationParams(zk, k, ctx, *chain, amount, false, false) + indexString, _ := setupTssMigrationParams(zk, k, ctx, chain, amount, false, false) currentTss, found := k.GetObserverKeeper().GetTSS(ctx) require.True(t, found) newTss := sample.Tss() diff --git a/x/crosschain/keeper/msg_server_refund_aborted_tx_test.go b/x/crosschain/keeper/msg_server_refund_aborted_tx_test.go index bf3678ecaf..91ef323ad9 100644 --- a/x/crosschain/keeper/msg_server_refund_aborted_tx_test.go +++ b/x/crosschain/keeper/msg_server_refund_aborted_tx_test.go @@ -116,6 +116,7 @@ func TestMsgServer_RefundAbortedCCTX(t *testing.T) { RefundAddress: cctx.InboundParams.Sender, } keepertest.MockCheckAuthorization(&authorityMock.Mock, &msg, nil) + keepertest.MockGetChainListEmpty(&authorityMock.Mock) _, err := msgServer.RefundAbortedCCTX(ctx, &msg) require.NoError(t, err) @@ -160,6 +161,7 @@ func TestMsgServer_RefundAbortedCCTX(t *testing.T) { RefundAddress: cctx.InboundParams.Sender, } keepertest.MockCheckAuthorization(&authorityMock.Mock, &msg, nil) + keepertest.MockGetChainListEmpty(&authorityMock.Mock) _, err := msgServer.RefundAbortedCCTX(ctx, &msg) require.NoError(t, err) @@ -274,6 +276,7 @@ func TestMsgServer_RefundAbortedCCTX(t *testing.T) { RefundAddress: refundAddress.String(), } keepertest.MockCheckAuthorization(&authorityMock.Mock, &msg, nil) + keepertest.MockGetChainListEmpty(&authorityMock.Mock) _, err := msgServer.RefundAbortedCCTX(ctx, &msg) require.NoError(t, err) @@ -325,6 +328,7 @@ func TestMsgServer_RefundAbortedCCTX(t *testing.T) { RefundAddress: cctx.InboundParams.Sender, } keepertest.MockCheckAuthorization(&authorityMock.Mock, &msg, nil) + keepertest.MockGetChainListEmpty(&authorityMock.Mock) _, err := msgServer.RefundAbortedCCTX(ctx, &msg) require.NoError(t, err) diff --git a/x/crosschain/keeper/msg_server_vote_gas_price.go b/x/crosschain/keeper/msg_server_vote_gas_price.go index 2fd84affc3..a5fbaf4c0c 100644 --- a/x/crosschain/keeper/msg_server_vote_gas_price.go +++ b/x/crosschain/keeper/msg_server_vote_gas_price.go @@ -26,8 +26,8 @@ func (k msgServer) VoteGasPrice( ) (*types.MsgVoteGasPriceResponse, error) { ctx := sdk.UnwrapSDKContext(goCtx) - chain := k.zetaObserverKeeper.GetSupportedChainFromChainID(ctx, msg.ChainId) - if chain == nil { + chain, found := k.zetaObserverKeeper.GetSupportedChainFromChainID(ctx, msg.ChainId) + if !found { return nil, cosmoserrors.Wrap(types.ErrUnsupportedChain, fmt.Sprintf("ChainID : %d ", msg.ChainId)) } if ok := k.zetaObserverKeeper.IsNonTombstonedObserver(ctx, msg.Creator); !ok { diff --git a/x/crosschain/keeper/msg_server_vote_gas_price_test.go b/x/crosschain/keeper/msg_server_vote_gas_price_test.go index a876e2582c..b5da0f0c1e 100644 --- a/x/crosschain/keeper/msg_server_vote_gas_price_test.go +++ b/x/crosschain/keeper/msg_server_vote_gas_price_test.go @@ -21,7 +21,7 @@ func TestMsgServer_VoteGasPrice(t *testing.T) { }) observerMock := keepertest.GetCrosschainObserverMock(t, k) - keepertest.MockFailedGetSupportedChainFromChainID(observerMock, nil) + keepertest.MockFailedGetSupportedChainFromChainID(observerMock, sample.Chain(5)) msgServer := keeper.NewMsgServerImpl(*k) res, err := msgServer.VoteGasPrice(ctx, &types.MsgVoteGasPrice{ @@ -37,7 +37,7 @@ func TestMsgServer_VoteGasPrice(t *testing.T) { }) observerMock := keepertest.GetCrosschainObserverMock(t, k) - keepertest.MockGetSupportedChainFromChainID(observerMock, nil) + keepertest.MockGetSupportedChainFromChainID(observerMock, sample.Chain(5)) observerMock.On("IsNonTombstonedObserver", mock.Anything, mock.Anything).Return(false) msgServer := keeper.NewMsgServerImpl(*k) @@ -56,7 +56,7 @@ func TestMsgServer_VoteGasPrice(t *testing.T) { }) observerMock := keepertest.GetCrosschainObserverMock(t, k) - keepertest.MockGetSupportedChainFromChainID(observerMock, &chains.Chain{ + keepertest.MockGetSupportedChainFromChainID(observerMock, chains.Chain{ ChainId: 5, }) observerMock.On("IsNonTombstonedObserver", mock.Anything, mock.Anything).Return(true) @@ -81,7 +81,7 @@ func TestMsgServer_VoteGasPrice(t *testing.T) { }) observerMock := keepertest.GetCrosschainObserverMock(t, k) - keepertest.MockGetSupportedChainFromChainID(observerMock, &chains.Chain{ + keepertest.MockGetSupportedChainFromChainID(observerMock, chains.Chain{ ChainId: 5, }) observerMock.On("IsNonTombstonedObserver", mock.Anything, mock.Anything).Return(true) @@ -118,7 +118,7 @@ func TestMsgServer_VoteGasPrice(t *testing.T) { }) observerMock := keepertest.GetCrosschainObserverMock(t, k) - keepertest.MockGetSupportedChainFromChainID(observerMock, &chains.Chain{ + keepertest.MockGetSupportedChainFromChainID(observerMock, chains.Chain{ ChainId: 5, }) observerMock.On("IsNonTombstonedObserver", mock.Anything, mock.Anything).Return(true) @@ -164,7 +164,7 @@ func TestMsgServer_VoteGasPrice(t *testing.T) { }) observerMock := keepertest.GetCrosschainObserverMock(t, k) - keepertest.MockGetSupportedChainFromChainID(observerMock, &chains.Chain{ + keepertest.MockGetSupportedChainFromChainID(observerMock, chains.Chain{ ChainId: 5, }) observerMock.On("IsNonTombstonedObserver", mock.Anything, mock.Anything).Return(true) diff --git a/x/crosschain/keeper/msg_server_vote_inbound_tx_test.go b/x/crosschain/keeper/msg_server_vote_inbound_tx_test.go index 64a2153611..be03a407e5 100644 --- a/x/crosschain/keeper/msg_server_vote_inbound_tx_test.go +++ b/x/crosschain/keeper/msg_server_vote_inbound_tx_test.go @@ -53,10 +53,10 @@ func TestKeeper_VoteInbound(t *testing.T) { to, from := int64(1337), int64(101) supportedChains := zk.ObserverKeeper.GetSupportedChains(ctx) for _, chain := range supportedChains { - if chains.IsEVMChain(chain.ChainId) { + if chains.IsEVMChain(chain.ChainId, []chains.Chain{}) { from = chain.ChainId } - if chains.IsZetaChain(chain.ChainId) { + if chains.IsZetaChain(chain.ChainId, []chains.Chain{}) { to = chain.ChainId } } @@ -78,10 +78,14 @@ func TestKeeper_VoteInbound(t *testing.T) { ) require.NoError(t, err) } + + chain, found := zk.ObserverKeeper.GetSupportedChainFromChainID(ctx, msg.SenderChainId) + require.True(t, found) + ballot, _, _ := zk.ObserverKeeper.FindBallot( ctx, msg.Digest(), - zk.ObserverKeeper.GetSupportedChainFromChainID(ctx, msg.SenderChainId), + chain, observertypes.ObservationType_InboundTx, ) require.Equal(t, ballot.BallotStatus, observertypes.BallotStatus_BallotFinalized_SuccessObservation) @@ -201,10 +205,10 @@ func TestKeeper_VoteInbound(t *testing.T) { to, from := int64(1337), int64(101) supportedChains := zk.ObserverKeeper.GetSupportedChains(ctx) for _, chain := range supportedChains { - if chains.IsEVMChain(chain.ChainId) { + if chains.IsEVMChain(chain.ChainId, []chains.Chain{}) { from = chain.ChainId } - if chains.IsZetaChain(chain.ChainId) { + if chains.IsZetaChain(chain.ChainId, []chains.Chain{}) { to = chain.ChainId } } @@ -219,16 +223,20 @@ func TestKeeper_VoteInbound(t *testing.T) { ) require.NoError(t, err) } + + chain, found := zk.ObserverKeeper.GetSupportedChainFromChainID(ctx, msg.SenderChainId) + require.True(t, found) + ballot, _, _ := zk.ObserverKeeper.FindBallot( ctx, msg.Digest(), - zk.ObserverKeeper.GetSupportedChainFromChainID(ctx, msg.SenderChainId), + chain, observertypes.ObservationType_InboundTx, ) require.Equal(t, ballot.BallotStatus, observertypes.BallotStatus_BallotInProgress) require.Equal(t, ballot.Votes[0], observertypes.VoteType_SuccessObservation) require.Equal(t, ballot.Votes[1], observertypes.VoteType_NotYetVoted) - _, found := k.GetCrossChainTx(ctx, msg.Digest()) + _, found = k.GetCrossChainTx(ctx, msg.Digest()) require.False(t, found) }) @@ -307,7 +315,7 @@ func TestKeeper_SaveObservedInboundInformation(t *testing.T) { receiver := sample.EthAddress() amount := big.NewInt(42) senderChain := getValidEthChain() - cctx := GetERC20Cctx(t, receiver, *senderChain, "", amount) + cctx := GetERC20Cctx(t, receiver, senderChain, "", amount) eventIndex := sample.Uint64InRange(1, 100) k.SaveObservedInboundInformation(ctx, cctx, eventIndex) require.Equal(t, types.TxFinalizationStatus_Executed, cctx.InboundParams.TxFinalizationStatus) @@ -329,7 +337,7 @@ func TestKeeper_SaveObservedInboundInformation(t *testing.T) { receiver := sample.EthAddress() amount := big.NewInt(42) senderChain := getValidEthChain() - cctx := GetERC20Cctx(t, receiver, *senderChain, "", amount) + cctx := GetERC20Cctx(t, receiver, senderChain, "", amount) hash := sample.Hash() cctx.InboundParams.ObservedHash = hash.String() k.SetInboundTracker(ctx, types.InboundTracker{ diff --git a/x/crosschain/keeper/msg_server_vote_outbound_tx_test.go b/x/crosschain/keeper/msg_server_vote_outbound_tx_test.go index 1fe87d98ea..77e52acede 100644 --- a/x/crosschain/keeper/msg_server_vote_outbound_tx_test.go +++ b/x/crosschain/keeper/msg_server_vote_outbound_tx_test.go @@ -137,14 +137,14 @@ func TestKeeper_VoteOutbound(t *testing.T) { observer := sample.AccAddress() tss := sample.Tss() zk.ObserverKeeper.SetObserverSet(ctx, observertypes.ObserverSet{ObserverList: []string{observer}}) - cctx := GetERC20Cctx(t, receiver, *senderChain, asset, amount) + cctx := GetERC20Cctx(t, receiver, senderChain, asset, amount) cctx.GetCurrentOutboundParam().TssPubkey = tss.TssPubkey cctx.CctxStatus.Status = types.CctxStatus_PendingOutbound k.SetCrossChainTx(ctx, *cctx) observerMock.On("GetTSS", ctx).Return(observertypes.TSS{}, true).Once() // Successfully mock VoteOnOutboundBallot - keepertest.MockVoteOnOutboundSuccessBallot(observerMock, ctx, cctx, *senderChain, observer) + keepertest.MockVoteOnOutboundSuccessBallot(observerMock, ctx, cctx, senderChain, observer) // Successfully mock GetOutbound keepertest.MockGetOutbound(observerMock, ctx) @@ -188,23 +188,22 @@ func TestKeeper_VoteOutbound(t *testing.T) { observer := sample.AccAddress() tss := sample.Tss() zk.ObserverKeeper.SetObserverSet(ctx, observertypes.ObserverSet{ObserverList: []string{observer}}) - cctx := GetERC20Cctx(t, receiver, *senderChain, asset, amount) + cctx := GetERC20Cctx(t, receiver, senderChain, asset, amount) cctx.GetCurrentOutboundParam().TssPubkey = tss.TssPubkey cctx.CctxStatus.Status = types.CctxStatus_PendingOutbound k.SetCrossChainTx(ctx, *cctx) observerMock.On("GetTSS", ctx).Return(observertypes.TSS{}, true).Once() // Successfully mock VoteOnOutboundBallot - keepertest.MockVoteOnOutboundFailedBallot(observerMock, ctx, cctx, *senderChain, observer) + keepertest.MockVoteOnOutboundFailedBallot(observerMock, ctx, cctx, senderChain, observer) // Successfully mock GetOutbound keepertest.MockGetOutbound(observerMock, ctx) // Successfully mock ProcessOutbound - keepertest.MockGetRevertGasLimitForERC20(fungibleMock, asset, *senderChain, 100) - keepertest.MockPayGasAndUpdateCCTX(fungibleMock, observerMock, ctx, *k, *senderChain, asset) - keepertest.MockGetSupportedChainFromChainID(observerMock, senderChain) - _ = keepertest.MockUpdateNonce(observerMock, *senderChain) + keepertest.MockGetRevertGasLimitForERC20(fungibleMock, asset, senderChain, 100) + keepertest.MockPayGasAndUpdateCCTX(fungibleMock, observerMock, ctx, *k, senderChain, asset) + _ = keepertest.MockUpdateNonce(observerMock, senderChain) //Successfully mock SaveOutbound keepertest.MockSaveOutboundNewRevertCreated(observerMock, ctx, cctx, tss) @@ -248,21 +247,21 @@ func TestKeeper_VoteOutbound(t *testing.T) { observer := sample.AccAddress() tss := sample.Tss() zk.ObserverKeeper.SetObserverSet(ctx, observertypes.ObserverSet{ObserverList: []string{observer}}) - cctx := GetERC20Cctx(t, receiver, *senderChain, asset, amount) + cctx := GetERC20Cctx(t, receiver, senderChain, asset, amount) cctx.GetCurrentOutboundParam().TssPubkey = tss.TssPubkey cctx.CctxStatus.Status = types.CctxStatus_PendingOutbound k.SetCrossChainTx(ctx, *cctx) observerMock.On("GetTSS", ctx).Return(observertypes.TSS{}, true).Once() // Successfully mock VoteOnOutboundBallot - keepertest.MockVoteOnOutboundFailedBallot(observerMock, ctx, cctx, *senderChain, observer) + keepertest.MockVoteOnOutboundFailedBallot(observerMock, ctx, cctx, senderChain, observer) // Successfully mock GetOutbound keepertest.MockGetOutbound(observerMock, ctx) // Mock Failed ProcessOutbound - keepertest.MockGetRevertGasLimitForERC20(fungibleMock, asset, *senderChain, 100) - keepertest.MockPayGasAndUpdateCCTX(fungibleMock, observerMock, ctx, *k, *senderChain, asset) + keepertest.MockGetRevertGasLimitForERC20(fungibleMock, asset, senderChain, 100) + keepertest.MockPayGasAndUpdateCCTX(fungibleMock, observerMock, ctx, *k, senderChain, asset) observerMock.On("GetChainNonces", mock.Anything, senderChain.ChainName.String()). Return(observertypes.ChainNonces{}, false) keepertest.MockGetSupportedChainFromChainID(observerMock, senderChain) @@ -312,7 +311,7 @@ func TestKeeper_VoteOutbound(t *testing.T) { observer := sample.AccAddress() tss := sample.Tss() zk.ObserverKeeper.SetObserverSet(ctx, observertypes.ObserverSet{ObserverList: []string{observer}}) - cctx := GetERC20Cctx(t, receiver, *senderChain, asset, amount) + cctx := GetERC20Cctx(t, receiver, senderChain, asset, amount) cctx.GetCurrentOutboundParam().TssPubkey = tss.TssPubkey cctx.CctxStatus.Status = types.CctxStatus_PendingOutbound k.SetCrossChainTx(ctx, *cctx) @@ -321,7 +320,7 @@ func TestKeeper_VoteOutbound(t *testing.T) { observerMock.On("GetTSS", ctx).Return(observertypes.TSS{}, true).Once() // Successfully mock VoteOnOutboundBallot - keepertest.MockVoteOnOutboundFailedBallot(observerMock, ctx, cctx, *senderChain, observer) + keepertest.MockVoteOnOutboundFailedBallot(observerMock, ctx, cctx, senderChain, observer) // Successfully mock GetOutbound keepertest.MockGetOutbound(observerMock, ctx) @@ -330,7 +329,7 @@ func TestKeeper_VoteOutbound(t *testing.T) { fungibleMock.On("GetForeignCoinFromAsset", mock.Anything, mock.Anything, mock.Anything). Return(fungibletypes.ForeignCoins{}, false) - // Successfully mock GetSupportedChainFromChainID + // Successfully mock GetSupportedChainFromChainID keepertest.MockGetSupportedChainFromChainID(observerMock, senderChain) //Successfully mock SaveFailedOutbound @@ -379,7 +378,7 @@ func TestKeeper_VoteOutbound(t *testing.T) { }, ) sk.StakingKeeper.SetValidator(ctx, validator) - cctx := GetERC20Cctx(t, receiver, *senderChain, asset, amount) + cctx := GetERC20Cctx(t, receiver, senderChain, asset, amount) cctx.GetCurrentOutboundParam().TssPubkey = tss.TssPubkey cctx.CctxStatus.Status = types.CctxStatus_PendingOutbound k.SetCrossChainTx(ctx, *cctx) @@ -426,7 +425,7 @@ func TestKeeper_VoteOutbound(t *testing.T) { require.NoError(t, err) zk.ObserverKeeper.SetObserverSet(ctx, observertypes.ObserverSet{ObserverList: []string{accAddress.String()}}) sk.StakingKeeper.SetValidator(ctx, validator) - cctx := GetERC20Cctx(t, receiver, *senderChain, asset, amount) + cctx := GetERC20Cctx(t, receiver, senderChain, asset, amount) cctx.GetCurrentOutboundParam().TssPubkey = tss.TssPubkey cctx.CctxStatus.Status = types.CctxStatus_PendingOutbound k.SetCrossChainTx(ctx, *cctx) diff --git a/x/crosschain/keeper/msg_server_whitelist_erc20.go b/x/crosschain/keeper/msg_server_whitelist_erc20.go index 04ceb4a1a4..e3ace26baa 100644 --- a/x/crosschain/keeper/msg_server_whitelist_erc20.go +++ b/x/crosschain/keeper/msg_server_whitelist_erc20.go @@ -63,8 +63,8 @@ func (k msgServer) WhitelistERC20( return nil, errorsmod.Wrapf(types.ErrCannotFindTSSKeys, "Cannot create new admin cmd of type whitelistERC20") } - chain := k.zetaObserverKeeper.GetSupportedChainFromChainID(ctx, msg.ChainId) - if chain == nil { + chain, found := k.zetaObserverKeeper.GetSupportedChainFromChainID(ctx, msg.ChainId) + if !found { return nil, errorsmod.Wrapf(types.ErrInvalidChainID, "chain id (%d) not supported", msg.ChainId) } diff --git a/x/crosschain/keeper/refund.go b/x/crosschain/keeper/refund.go index 19afd1be1f..a741434705 100644 --- a/x/crosschain/keeper/refund.go +++ b/x/crosschain/keeper/refund.go @@ -70,7 +70,7 @@ func (k Keeper) RefundAmountOnZetaChainZeta( refundAmount := GetAbortedAmount(cctx) chainID := cctx.InboundParams.SenderChainId // check if chain is an EVM chain - if !chains.IsEVMChain(chainID) { + if !chains.IsEVMChain(chainID, k.GetAuthorityKeeper().GetAdditionalChainList(ctx)) { return errors.New("only EVM chains are supported for refund when coin type is Zeta") } if cctx.InboundParams.Amount.IsNil() || cctx.InboundParams.Amount.IsZero() { @@ -96,7 +96,7 @@ func (k Keeper) RefundAmountOnZetaChainERC20( if cctx.InboundParams.CoinType != coin.CoinType_ERC20 { return errors.New("unsupported coin type for refund on ZetaChain") } - if !chains.IsEVMChain(cctx.InboundParams.SenderChainId) { + if !chains.IsEVMChain(cctx.InboundParams.SenderChainId, k.GetAuthorityKeeper().GetAdditionalChainList(ctx)) { return errors.New("only EVM chains are supported for refund on ZetaChain") } diff --git a/x/crosschain/keeper/utils_test.go b/x/crosschain/keeper/utils_test.go index 4539bd1637..6da6a501a2 100644 --- a/x/crosschain/keeper/utils_test.go +++ b/x/crosschain/keeper/utils_test.go @@ -27,14 +27,14 @@ func getValidEthChainID() int64 { } // getValidEthChain() get a valid eth chain -func getValidEthChain() *chains.Chain { +func getValidEthChain() chains.Chain { goerli := chains.GoerliLocalnet - return &goerli + return goerli } -func getValidBTCChain() *chains.Chain { +func getValidBTCChain() chains.Chain { btcRegNet := chains.BitcoinRegtest - return &btcRegNet + return btcRegNet } func getValidBtcChainID() int64 { diff --git a/x/crosschain/migrations/v4/migrate.go b/x/crosschain/migrations/v4/migrate.go index 367e9c54eb..b71fe26b1b 100644 --- a/x/crosschain/migrations/v4/migrate.go +++ b/x/crosschain/migrations/v4/migrate.go @@ -177,7 +177,7 @@ func SetBitcoinFinalizedInbound(ctx sdk.Context, crosschainKeeper crosschainKeep for _, cctx := range crosschainKeeper.GetAllCrossChainTx(ctx) { if cctx.InboundParams != nil { // check if bitcoin inbound - if chains.IsBitcoinChain(cctx.InboundParams.SenderChainId) { + if chains.IsBitcoinChain(cctx.InboundParams.SenderChainId, []chains.Chain{}) { // add finalized inbound crosschainKeeper.AddFinalizedInbound( ctx, diff --git a/x/crosschain/migrations/v5/migrate.go b/x/crosschain/migrations/v5/migrate.go index fcb42dc4d0..bb650991f0 100644 --- a/x/crosschain/migrations/v5/migrate.go +++ b/x/crosschain/migrations/v5/migrate.go @@ -97,11 +97,11 @@ func SetZetaAccounting( switch cctx.InboundParams.CoinType { case coin.CoinType_ERC20: { - receiverChain := observerKeeper.GetSupportedChainFromChainID( + receiverChain, found := observerKeeper.GetSupportedChainFromChainID( ctx, cctx.GetCurrentOutboundParam().ReceiverChainId, ) - if receiverChain == nil { + if !found { ctx.Logger(). Error(fmt.Sprintf("Error getting chain from chain id: %d , cctx index", cctx.GetCurrentOutboundParam().ReceiverChainId), cctx.Index) continue diff --git a/x/crosschain/migrations/v5/migrate_test.go b/x/crosschain/migrations/v5/migrate_test.go index c95535a5b0..d3e55749c7 100644 --- a/x/crosschain/migrations/v5/migrate_test.go +++ b/x/crosschain/migrations/v5/migrate_test.go @@ -49,11 +49,11 @@ func TestMigrateStore(t *testing.T) { for _, cctx := range cctxListUpdated { switch cctx.InboundParams.CoinType { case coin.CoinType_ERC20: - receiverChain := zk.ObserverKeeper.GetSupportedChainFromChainID( + receiverChain, found := zk.ObserverKeeper.GetSupportedChainFromChainID( ctx, cctx.GetCurrentOutboundParam().ReceiverChainId, ) - require.NotNil(t, receiverChain) + require.True(t, found) if receiverChain.IsZetaChain() { require.True(t, cctx.CctxStatus.IsAbortRefunded) } else { diff --git a/x/crosschain/types/cctx_test.go b/x/crosschain/types/cctx_test.go index 1e2df98301..eecdf0cdf0 100644 --- a/x/crosschain/types/cctx_test.go +++ b/x/crosschain/types/cctx_test.go @@ -129,15 +129,6 @@ func TestCrossChainTx_Validate(t *testing.T) { require.ErrorContains(t, cctx.Validate(), "invalid index length 1") cctx = sample.CrossChainTx(t, "foo") cctx.InboundParams = sample.InboundParamsValidChainID(rand.New(rand.NewSource(42))) - cctx.InboundParams.SenderChainId = 1000 - require.ErrorContains(t, cctx.Validate(), "invalid sender chain id 1000") - cctx = sample.CrossChainTx(t, "foo") - cctx.OutboundParams = []*types.OutboundParams{sample.OutboundParamsValidChainID(rand.New(rand.NewSource(42)))} - cctx.InboundParams = sample.InboundParamsValidChainID(rand.New(rand.NewSource(42))) - cctx.InboundParams.ObservedHash = sample.Hash().String() - cctx.InboundParams.BallotIndex = sample.ZetaIndex(t) - cctx.OutboundParams[0].ReceiverChainId = 1000 - require.ErrorContains(t, cctx.Validate(), "invalid receiver chain id 1000") } func TestCrossChainTx_GetCurrentOutboundParam(t *testing.T) { diff --git a/x/crosschain/types/expected_keepers.go b/x/crosschain/types/expected_keepers.go index 6f35afa6c5..57f3d1492f 100644 --- a/x/crosschain/types/expected_keepers.go +++ b/x/crosschain/types/expected_keepers.go @@ -56,7 +56,7 @@ type ObserverKeeper interface { FindBallot( ctx sdk.Context, index string, - chain *chains.Chain, + chain chains.Chain, observationType observertypes.ObservationType, ) (ballot observertypes.Ballot, isNew bool, err error) AddBallotToList(ctx sdk.Context, ballot observertypes.Ballot) @@ -101,9 +101,9 @@ type ObserverKeeper interface { receiveStatus chains.ReceiveStatus, voter string, ) (bool, bool, observertypes.Ballot, string, error) - GetSupportedChainFromChainID(ctx sdk.Context, chainID int64) *chains.Chain - GetSupportedChains(ctx sdk.Context) []*chains.Chain - GetSupportedForeignChains(ctx sdk.Context) []*chains.Chain + GetSupportedChainFromChainID(ctx sdk.Context, chainID int64) (chains.Chain, bool) + GetSupportedChains(ctx sdk.Context) []chains.Chain + GetSupportedForeignChains(ctx sdk.Context) []chains.Chain } type FungibleKeeper interface { @@ -209,6 +209,7 @@ type FungibleKeeper interface { type AuthorityKeeper interface { CheckAuthorization(ctx sdk.Context, msg sdk.Msg) error + GetAdditionalChainList(ctx sdk.Context) (list []chains.Chain) } type LightclientKeeper interface { diff --git a/x/crosschain/types/inbound_params.go b/x/crosschain/types/inbound_params.go index f191d15e2d..18d75cd80f 100644 --- a/x/crosschain/types/inbound_params.go +++ b/x/crosschain/types/inbound_params.go @@ -2,8 +2,6 @@ package types import ( "fmt" - - "github.com/zeta-chain/zetacore/pkg/chains" ) func (m InboundParams) Validate() error { @@ -11,10 +9,6 @@ func (m InboundParams) Validate() error { return fmt.Errorf("sender cannot be empty") } - if chains.GetChainFromChainID(m.SenderChainId) == nil { - return fmt.Errorf("invalid sender chain id %d", m.SenderChainId) - } - if m.Amount.IsNil() { return fmt.Errorf("amount cannot be nil") } diff --git a/x/crosschain/types/inbound_params_test.go b/x/crosschain/types/inbound_params_test.go index 464f685475..42d92a8f3f 100644 --- a/x/crosschain/types/inbound_params_test.go +++ b/x/crosschain/types/inbound_params_test.go @@ -17,10 +17,6 @@ func TestInboundTxParams_Validate(t *testing.T) { inboundParams.Sender = "" require.ErrorContains(t, inboundParams.Validate(), "sender cannot be empty") - inboundParams = sample.InboundParamsValidChainID(r) - inboundParams.SenderChainId = 1000 - require.ErrorContains(t, inboundParams.Validate(), "invalid sender chain id 1000") - inboundParams = sample.InboundParamsValidChainID(r) inboundParams.Amount = sdkmath.Uint{} require.ErrorContains(t, inboundParams.Validate(), "amount cannot be nil") diff --git a/x/crosschain/types/message_add_inbound_tracker.go b/x/crosschain/types/message_add_inbound_tracker.go index 0734033569..1c4a0691e7 100644 --- a/x/crosschain/types/message_add_inbound_tracker.go +++ b/x/crosschain/types/message_add_inbound_tracker.go @@ -5,7 +5,6 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - "github.com/zeta-chain/zetacore/pkg/chains" "github.com/zeta-chain/zetacore/pkg/coin" ) @@ -48,20 +47,10 @@ func (msg *MsgAddInboundTracker) ValidateBasic() error { if err != nil { return errorsmod.Wrapf(sdkerrors.ErrInvalidAddress, "invalid creator address (%s)", err) } - chain := chains.GetChainFromChainID(msg.ChainId) - if chain == nil { - return errorsmod.Wrapf(ErrInvalidChainID, "chain id (%d)", msg.ChainId) - } - if msg.Proof != nil && !chain.SupportMerkleProof() { - return errorsmod.Wrapf( - ErrProofVerificationFail, - "chain id %d does not support proof-based trackers", - msg.ChainId, - ) - } + _, ok := coin.CoinType_value[msg.CoinType.String()] if !ok { - return errorsmod.Wrapf(ErrProofVerificationFail, "coin-type not supported") + return errorsmod.Wrapf(sdkerrors.ErrInvalidRequest, "coin-type not supported") } return nil } diff --git a/x/crosschain/types/message_add_inbound_tracker_test.go b/x/crosschain/types/message_add_inbound_tracker_test.go index 6251990d63..503c020c1d 100644 --- a/x/crosschain/types/message_add_inbound_tracker_test.go +++ b/x/crosschain/types/message_add_inbound_tracker_test.go @@ -10,7 +10,6 @@ import ( "github.com/zeta-chain/zetacore/pkg/chains" "github.com/zeta-chain/zetacore/pkg/coin" - "github.com/zeta-chain/zetacore/pkg/proofs" "github.com/zeta-chain/zetacore/testutil/sample" "github.com/zeta-chain/zetacore/x/crosschain/types" ) @@ -31,30 +30,6 @@ func TestMsgAddInboundTracker_ValidateBasic(t *testing.T) { ), err: sdkerrors.ErrInvalidAddress, }, - { - name: "invalid chain id", - msg: types.NewMsgAddInboundTracker( - sample.AccAddress(), - 42, - coin.CoinType_Gas, - "hash", - ), - err: errorsmod.Wrapf(types.ErrInvalidChainID, "chain id (%d)", 42), - }, - { - name: "invalid proof", - msg: &types.MsgAddInboundTracker{ - Creator: sample.AccAddress(), - ChainId: chains.ZetaChainTestnet.ChainId, - CoinType: coin.CoinType_Gas, - Proof: &proofs.Proof{}, - }, - err: errorsmod.Wrapf( - types.ErrProofVerificationFail, - "chain id %d does not support proof-based trackers", - chains.ZetaChainTestnet.ChainId, - ), - }, { name: "invalid coin type", msg: &types.MsgAddInboundTracker{ @@ -62,7 +37,7 @@ func TestMsgAddInboundTracker_ValidateBasic(t *testing.T) { ChainId: chains.ZetaChainTestnet.ChainId, CoinType: 5, }, - err: errorsmod.Wrapf(types.ErrProofVerificationFail, "coin-type not supported"), + err: errorsmod.Wrapf(sdkerrors.ErrInvalidRequest, "coin-type not supported"), }, { name: "valid", diff --git a/x/crosschain/types/message_migrate_tss_funds.go b/x/crosschain/types/message_migrate_tss_funds.go index 2de565c72d..0f4d5a2ecf 100644 --- a/x/crosschain/types/message_migrate_tss_funds.go +++ b/x/crosschain/types/message_migrate_tss_funds.go @@ -5,8 +5,6 @@ import ( sdkmath "cosmossdk.io/math" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - - "github.com/zeta-chain/zetacore/pkg/chains" ) const TypeMsgMigrateTssFunds = "MigrateTssFunds" @@ -47,9 +45,7 @@ func (msg *MsgMigrateTssFunds) ValidateBasic() error { if err != nil { return errorsmod.Wrapf(sdkerrors.ErrInvalidAddress, "invalid creator address (%s)", err) } - if chains.GetChainFromChainID(msg.ChainId) == nil { - return errorsmod.Wrapf(sdkerrors.ErrInvalidRequest, "invalid chain id (%d)", msg.ChainId) - } + if msg.Amount.IsZero() { return errorsmod.Wrapf(sdkerrors.ErrInvalidRequest, "amount cannot be zero") } diff --git a/x/crosschain/types/message_migrate_tss_funds_test.go b/x/crosschain/types/message_migrate_tss_funds_test.go index f07943bf59..5514af9034 100644 --- a/x/crosschain/types/message_migrate_tss_funds_test.go +++ b/x/crosschain/types/message_migrate_tss_funds_test.go @@ -29,15 +29,6 @@ func TestNewMsgMigrateTssFunds_ValidateBasic(t *testing.T) { ), error: true, }, - { - name: "invalid chain id", - msg: types.NewMsgMigrateTssFunds( - sample.AccAddress(), - 999, - sdkmath.NewUintFromString("100000"), - ), - error: true, - }, { name: "invalid amount", msg: types.NewMsgMigrateTssFunds( diff --git a/x/crosschain/types/outbound_params.go b/x/crosschain/types/outbound_params.go index 34458763dd..361462a1b4 100644 --- a/x/crosschain/types/outbound_params.go +++ b/x/crosschain/types/outbound_params.go @@ -3,8 +3,6 @@ package types import ( "fmt" "strconv" - - "github.com/zeta-chain/zetacore/pkg/chains" ) func (m OutboundParams) GetGasPriceUInt64() (uint64, error) { @@ -21,10 +19,6 @@ func (m OutboundParams) Validate() error { return fmt.Errorf("receiver cannot be empty") } - if chains.GetChainFromChainID(m.ReceiverChainId) == nil { - return fmt.Errorf("invalid receiver chain id %d", m.ReceiverChainId) - } - if m.Amount.IsNil() { return fmt.Errorf("amount cannot be nil") } diff --git a/x/crosschain/types/outbound_params_test.go b/x/crosschain/types/outbound_params_test.go index e5caa4b1b0..16bfc17844 100644 --- a/x/crosschain/types/outbound_params_test.go +++ b/x/crosschain/types/outbound_params_test.go @@ -16,10 +16,6 @@ func TestOutboundParams_Validate(t *testing.T) { outTxParams.Receiver = "" require.ErrorContains(t, outTxParams.Validate(), "receiver cannot be empty") - outTxParams = sample.OutboundParamsValidChainID(r) - outTxParams.ReceiverChainId = 1000 - require.ErrorContains(t, outTxParams.Validate(), "invalid receiver chain id 1000") - outTxParams = sample.OutboundParamsValidChainID(r) outTxParams.Amount = sdkmath.Uint{} require.ErrorContains(t, outTxParams.Validate(), "amount cannot be nil") diff --git a/x/crosschain/types/tx_body_verification.go b/x/crosschain/types/tx_body_verification.go index fbb8d4c6ea..84d71054f1 100644 --- a/x/crosschain/types/tx_body_verification.go +++ b/x/crosschain/types/tx_body_verification.go @@ -22,7 +22,10 @@ func VerifyInboundBody( tss observertypes.QueryGetTssAddressResponse, ) error { // verify message against transaction body - if chains.IsEVMChain(msg.ChainId) { + // NOTE: since this functionality is disabled on live network we don't provide on-chain additional chains for simplicity + // TODO: use authorityKeeper.GetChainInfo to provide additional chains + // https://github.com/zeta-chain/node/issues/2385 + if chains.IsEVMChain(msg.ChainId, []chains.Chain{}) { return verifyInboundBodyEVM(msg, txBytes, chainParams, tss) } @@ -79,9 +82,12 @@ func verifyInboundBodyEVM( // VerifyOutboundBody verifies the tx body for an outbound func VerifyOutboundBody(msg MsgAddOutboundTracker, txBytes []byte, tss observertypes.QueryGetTssAddressResponse) error { // verify message against transaction body - if chains.IsEVMChain(msg.ChainId) { + // NOTE: since this functionality is disabled on live network we don't provide on-chain additional chains for simplicity + // TODO: use authorityKeeper.GetChainInfo to provide additional chains + // https://github.com/zeta-chain/node/issues/2385 + if chains.IsEVMChain(msg.ChainId, []chains.Chain{}) { return verifyOutboundBodyEVM(msg, txBytes, tss.Eth) - } else if chains.IsBitcoinChain(msg.ChainId) { + } else if chains.IsBitcoinChain(msg.ChainId, []chains.Chain{}) { return verifyOutboundBodyBTC(msg, txBytes, tss.Btc) } return fmt.Errorf("cannot verify outbound body for chain %d", msg.ChainId) @@ -122,9 +128,6 @@ func verifyOutboundBodyEVM(msg MsgAddOutboundTracker, txBytes []byte, tssEth str // TODO: Implement tests for the function // https://github.com/zeta-chain/node/issues/1994 func verifyOutboundBodyBTC(msg MsgAddOutboundTracker, txBytes []byte, tssBtc string) error { - if !chains.IsBitcoinChain(msg.ChainId) { - return fmt.Errorf("not a Bitcoin chain ID %d", msg.ChainId) - } tx, err := btcutil.NewTxFromBytes(txBytes) if err != nil { return err diff --git a/x/crosschain/types/validate.go b/x/crosschain/types/validate.go index 58305ffa02..1f1dd3814d 100644 --- a/x/crosschain/types/validate.go +++ b/x/crosschain/types/validate.go @@ -20,15 +20,21 @@ func ValidateCCTXIndex(index string) error { } // ValidateHashForChain validates the hash for the chain +// NOTE: since these checks are currently not used, we don't provide additional chains for simplicity +// TODO: use authorityKeeper.GetChainInfo to provide additional chains +// https://github.com/zeta-chain/node/issues/2234 +// https://github.com/zeta-chain/node/issues/2385 +// NOTE: We should eventually not using these hard-coded checks at all since it might make the protocol too rigid +// Example: hash algorithm is changed for a chain: this required a upgrade on the protocol func ValidateHashForChain(hash string, chainID int64) error { - if chains.IsEthereumChain(chainID) || chains.IsZetaChain(chainID) { + if chains.IsEthereumChain(chainID, []chains.Chain{}) || chains.IsZetaChain(chainID, []chains.Chain{}) { _, err := hexutil.Decode(hash) if err != nil { return fmt.Errorf("hash must be a valid ethereum hash %s", hash) } return nil } - if chains.IsBitcoinChain(chainID) { + if chains.IsBitcoinChain(chainID, []chains.Chain{}) { r, err := regexp.Compile("^[a-fA-F0-9]{64}$") if err != nil { return fmt.Errorf("error compiling regex") @@ -42,18 +48,23 @@ func ValidateHashForChain(hash string, chainID int64) error { } // ValidateAddressForChain validates the address for the chain +// NOTE: since these checks are currently not used, we don't provide additional chains for simplicity +// TODO: use authorityKeeper.GetChainInfo to provide additional chains +// https://github.com/zeta-chain/node/issues/2234 +// https://github.com/zeta-chain/node/issues/2385 +// NOTE: We should eventually not using these hard-coded checks at all for same reasons as above func ValidateAddressForChain(address string, chainID int64) error { // we do not validate the address for zeta chain as the address field can be btc or eth address - if chains.IsZetaChain(chainID) { + if chains.IsZetaChain(chainID, []chains.Chain{}) { return nil } - if chains.IsEthereumChain(chainID) { + if chains.IsEthereumChain(chainID, []chains.Chain{}) { if !ethcommon.IsHexAddress(address) { return fmt.Errorf("invalid address %s , chain %d", address, chainID) } return nil } - if chains.IsBitcoinChain(chainID) { + if chains.IsBitcoinChain(chainID, []chains.Chain{}) { addr, err := chains.DecodeBtcAddress(address, chainID) if err != nil { return fmt.Errorf("invalid address %s , chain %d: %s", address, chainID, err) diff --git a/x/fungible/keeper/evm.go b/x/fungible/keeper/evm.go index 43bffb6e75..5a9d950b14 100644 --- a/x/fungible/keeper/evm.go +++ b/x/fungible/keeper/evm.go @@ -110,12 +110,13 @@ func (k Keeper) DeployZRC20Contract( erc20Contract string, gasLimit *big.Int, ) (common.Address, error) { - chain := chains.GetChainFromChainID(chainID) - if chain == nil { + chain, found := chains.GetChainFromChainID(chainID, k.GetAuthorityKeeper().GetAdditionalChainList(ctx)) + if !found { return common.Address{}, cosmoserrors.Wrapf(zetaObserverTypes.ErrSupportedChains, "chain %d not found", chainID) } + // Check if Contract has already been deployed for Asset - _, found := k.GetForeignCoinFromAsset(ctx, erc20Contract, chainID) + _, found = k.GetForeignCoinFromAsset(ctx, erc20Contract, chainID) if found { return common.Address{}, types.ErrForeignCoinAlreadyExist } diff --git a/x/fungible/keeper/gas_coin_and_pool.go b/x/fungible/keeper/gas_coin_and_pool.go index 1ee7ece40c..8e01e0dc49 100644 --- a/x/fungible/keeper/gas_coin_and_pool.go +++ b/x/fungible/keeper/gas_coin_and_pool.go @@ -28,8 +28,11 @@ func (k Keeper) SetupChainGasCoinAndPool( decimals uint8, gasLimit *big.Int, ) (ethcommon.Address, error) { - chain := chains.GetChainFromChainID(chainID) - if chain == nil { + // additional on-chain static chain information + additionalChains := k.GetAuthorityKeeper().GetAdditionalChainList(ctx) + + chain, found := chains.GetChainFromChainID(chainID, additionalChains) + if !found { return ethcommon.Address{}, zetaObserverTypes.ErrSupportedChains } name := fmt.Sprintf("%s-%s", gasAssetName, chain.ChainName) @@ -37,7 +40,7 @@ func (k Keeper) SetupChainGasCoinAndPool( transferGasLimit := gasLimit // Check if gas coin already exists - _, found := k.GetGasCoinForForeignCoin(ctx, chainID) + _, found = k.GetGasCoinForForeignCoin(ctx, chainID) if found { return ethcommon.Address{}, types.ErrForeignCoinAlreadyExist } @@ -45,7 +48,7 @@ func (k Keeper) SetupChainGasCoinAndPool( // default values if transferGasLimit == nil { transferGasLimit = big.NewInt(21_000) - if chains.IsBitcoinChain(chain.ChainId) { + if chains.IsBitcoinChain(chain.ChainId, additionalChains) { transferGasLimit = big.NewInt(100) // 100B for a typical tx } } diff --git a/x/fungible/keeper/grpc_query_gas_stability_pool.go b/x/fungible/keeper/grpc_query_gas_stability_pool.go index 321fdb7e5b..3541aad8d4 100644 --- a/x/fungible/keeper/grpc_query_gas_stability_pool.go +++ b/x/fungible/keeper/grpc_query_gas_stability_pool.go @@ -57,9 +57,6 @@ func (k Keeper) GasStabilityPoolBalanceAll( chains := k.observerKeeper.GetSupportedChains(ctx) balances := make([]types.QueryAllGasStabilityPoolBalanceResponse_Balance, 0, len(chains)) for _, chain := range chains { - if chain == nil { - return nil, status.Error(codes.Internal, "invalid chain") - } chainID := chain.ChainId balance, err := k.GetGasStabilityPoolBalance(ctx, chainID) diff --git a/x/fungible/keeper/grpc_query_gas_stability_pool_test.go b/x/fungible/keeper/grpc_query_gas_stability_pool_test.go index f503c76698..d2a256e927 100644 --- a/x/fungible/keeper/grpc_query_gas_stability_pool_test.go +++ b/x/fungible/keeper/grpc_query_gas_stability_pool_test.go @@ -79,32 +79,20 @@ func TestKeeper_GasStabilityPoolBalanceAll(t *testing.T) { UseObserverMock: true, }) observerMock := keepertest.GetFungibleObserverMock(t, k) - observerMock.On("GetSupportedChains", mock.Anything).Return([]*chains.Chain{}) + observerMock.On("GetSupportedChains", mock.Anything).Return([]chains.Chain{}) res, err := k.GasStabilityPoolBalanceAll(ctx, &types.QueryAllGasStabilityPoolBalance{}) require.NoError(t, err) require.Empty(t, res.Balances) }) - t.Run("should error if chain is nil", func(t *testing.T) { - k, ctx, _, _ := keepertest.FungibleKeeperWithMocks(t, keepertest.FungibleMockOptions{ - UseObserverMock: true, - }) - observerMock := keepertest.GetFungibleObserverMock(t, k) - observerMock.On("GetSupportedChains", mock.Anything).Return([]*chains.Chain{nil}) - - res, err := k.GasStabilityPoolBalanceAll(ctx, &types.QueryAllGasStabilityPoolBalance{}) - require.Error(t, err) - require.Nil(t, res) - }) - t.Run("should error if system contracts not deployed", func(t *testing.T) { k, ctx, _, _ := keepertest.FungibleKeeperWithMocks(t, keepertest.FungibleMockOptions{ UseObserverMock: true, }) observerMock := keepertest.GetFungibleObserverMock(t, k) chainID := 5 - observerMock.On("GetSupportedChains", mock.Anything).Return([]*chains.Chain{ + observerMock.On("GetSupportedChains", mock.Anything).Return([]chains.Chain{ { ChainName: chains.ChainName(chainID), ChainId: int64(chainID), @@ -124,7 +112,7 @@ func TestKeeper_GasStabilityPoolBalanceAll(t *testing.T) { observerMock := keepertest.GetFungibleObserverMock(t, k) chainID := 5 - observerMock.On("GetSupportedChains", mock.Anything).Return([]*chains.Chain{ + observerMock.On("GetSupportedChains", mock.Anything).Return([]chains.Chain{ { ChainName: chains.ChainName(chainID), ChainId: int64(chainID), diff --git a/x/fungible/keeper/msg_server_deploy_fungible_coin_zrc20_test.go b/x/fungible/keeper/msg_server_deploy_fungible_coin_zrc20_test.go index b37dd82cf7..903b63aa31 100644 --- a/x/fungible/keeper/msg_server_deploy_fungible_coin_zrc20_test.go +++ b/x/fungible/keeper/msg_server_deploy_fungible_coin_zrc20_test.go @@ -42,6 +42,7 @@ func TestMsgServer_DeployFungibleCoinZRC20(t *testing.T) { 1000000, ) keepertest.MockCheckAuthorization(&authorityMock.Mock, msg, nil) + keepertest.MockGetChainListEmpty(&authorityMock.Mock) res, err := msgServer.DeployFungibleCoinZRC20(ctx, msg) require.NoError(t, err) gasAddress := res.Address @@ -174,6 +175,7 @@ func TestMsgServer_DeployFungibleCoinZRC20(t *testing.T) { 1000000, ) keepertest.MockCheckAuthorization(&authorityMock.Mock, msg, nil) + keepertest.MockGetChainListEmpty(&authorityMock.Mock) _, err := keeper.NewMsgServerImpl(*k).DeployFungibleCoinZRC20(ctx, msg) require.Error(t, err) require.ErrorIs(t, err, observertypes.ErrSupportedChains) @@ -203,6 +205,7 @@ func TestMsgServer_DeployFungibleCoinZRC20(t *testing.T) { 1000000, ) keepertest.MockCheckAuthorization(&authorityMock.Mock, deployMsg, nil) + keepertest.MockGetChainListEmpty(&authorityMock.Mock) // Attempt to deploy the same gas token twice should result in error _, err := keeper.NewMsgServerImpl(*k).DeployFungibleCoinZRC20(ctx, deployMsg) diff --git a/x/fungible/keeper/msg_server_remove_foreign_coin_test.go b/x/fungible/keeper/msg_server_remove_foreign_coin_test.go index 01ac286e9e..9e02d8a6f0 100644 --- a/x/fungible/keeper/msg_server_remove_foreign_coin_test.go +++ b/x/fungible/keeper/msg_server_remove_foreign_coin_test.go @@ -25,6 +25,7 @@ func TestMsgServer_RemoveForeignCoin(t *testing.T) { admin := sample.AccAddress() authorityMock := keepertest.GetFungibleAuthorityMock(t, k) + keepertest.MockGetChainListEmpty(&authorityMock.Mock) chainID := getValidChainID(t) @@ -53,6 +54,7 @@ func TestMsgServer_RemoveForeignCoin(t *testing.T) { admin := sample.AccAddress() authorityMock := keepertest.GetFungibleAuthorityMock(t, k) + keepertest.MockGetChainListEmpty(&authorityMock.Mock) deploySystemContracts(t, ctx, k, sdkk.EvmKeeper) zrc20 := setupGasCoin(t, ctx, k, sdkk.EvmKeeper, chainID, "foo", "foo") diff --git a/x/fungible/keeper/msg_server_update_contract_bytecode_test.go b/x/fungible/keeper/msg_server_update_contract_bytecode_test.go index 287cc18046..dadb62d145 100644 --- a/x/fungible/keeper/msg_server_update_contract_bytecode_test.go +++ b/x/fungible/keeper/msg_server_update_contract_bytecode_test.go @@ -39,6 +39,7 @@ func TestKeeper_UpdateContractBytecode(t *testing.T) { msgServer := keeper.NewMsgServerImpl(*k) authorityMock := keepertest.GetFungibleAuthorityMock(t, k) + keepertest.MockGetChainListEmpty(&authorityMock.Mock) // sample chainIDs and addresses chainList := chains.DefaultChainsList() @@ -147,6 +148,7 @@ func TestKeeper_UpdateContractBytecode(t *testing.T) { codeHash, ) keepertest.MockCheckAuthorization(&authorityMock.Mock, msg, nil) + keepertest.MockGetChainListEmpty(&authorityMock.Mock) _, err = msgServer.UpdateContractBytecode(ctx, msg) require.NoError(t, err) balance, err = k.BalanceOfZRC4(ctx, zrc20, addr1) diff --git a/x/fungible/keeper/msg_server_update_system_contract_test.go b/x/fungible/keeper/msg_server_update_system_contract_test.go index bdea95980b..72b7bac265 100644 --- a/x/fungible/keeper/msg_server_update_system_contract_test.go +++ b/x/fungible/keeper/msg_server_update_system_contract_test.go @@ -30,6 +30,7 @@ func TestKeeper_UpdateSystemContract(t *testing.T) { admin := sample.AccAddress() authorityMock := keepertest.GetFungibleAuthorityMock(t, k) + keepertest.MockGetChainListEmpty(&authorityMock.Mock) queryZRC20SystemContract := func(contract common.Address) string { abi, err := zrc20.ZRC20MetaData.GetAbi() @@ -210,6 +211,7 @@ func TestKeeper_UpdateSystemContract(t *testing.T) { admin := sample.AccAddress() authorityMock := keepertest.GetFungibleAuthorityMock(t, k) + keepertest.MockGetChainListEmpty(&authorityMock.Mock) chains := chains.DefaultChainsList() require.True(t, len(chains) > 1) @@ -255,6 +257,7 @@ func TestKeeper_UpdateSystemContract(t *testing.T) { // can't update the system contract msg = types.NewMsgUpdateSystemContract(admin, newSystemContract.Hex()) keepertest.MockCheckAuthorization(&authorityMock.Mock, msg, nil) + keepertest.MockGetChainListEmpty(&authorityMock.Mock) _, err = msgServer.UpdateSystemContract(ctx, msg) require.ErrorIs(t, err, types.ErrContractCall) @@ -265,6 +268,7 @@ func TestKeeper_UpdateSystemContract(t *testing.T) { // can't update the system contract msg = types.NewMsgUpdateSystemContract(admin, newSystemContract.Hex()) keepertest.MockCheckAuthorization(&authorityMock.Mock, msg, nil) + keepertest.MockGetChainListEmpty(&authorityMock.Mock) _, err = msgServer.UpdateSystemContract(ctx, msg) require.ErrorIs(t, err, types.ErrContractCall) }) diff --git a/x/fungible/keeper/msg_server_update_zrc20_withdraw_fee_test.go b/x/fungible/keeper/msg_server_update_zrc20_withdraw_fee_test.go index fb156a1c36..160b2cfc46 100644 --- a/x/fungible/keeper/msg_server_update_zrc20_withdraw_fee_test.go +++ b/x/fungible/keeper/msg_server_update_zrc20_withdraw_fee_test.go @@ -31,6 +31,7 @@ func TestKeeper_UpdateZRC20WithdrawFee(t *testing.T) { // set coin admin admin := sample.AccAddress() authorityMock := keepertest.GetFungibleAuthorityMock(t, k) + keepertest.MockGetChainListEmpty(&authorityMock.Mock) // deploy the system contract and a ZRC20 contract deploySystemContracts(t, ctx, k, sdkk.EvmKeeper) diff --git a/x/fungible/types/expected_keepers.go b/x/fungible/types/expected_keepers.go index b2997566ff..ad0521ab81 100644 --- a/x/fungible/types/expected_keepers.go +++ b/x/fungible/types/expected_keepers.go @@ -36,7 +36,7 @@ type BankKeeper interface { } type ObserverKeeper interface { - GetSupportedChains(ctx sdk.Context) []*chains.Chain + GetSupportedChains(ctx sdk.Context) []chains.Chain } type EVMKeeper interface { @@ -60,4 +60,5 @@ type EVMKeeper interface { type AuthorityKeeper interface { CheckAuthorization(ctx sdk.Context, msg sdk.Msg) error + GetAdditionalChainList(ctx sdk.Context) (list []chains.Chain) } diff --git a/x/lightclient/keeper/grpc_query_prove.go b/x/lightclient/keeper/grpc_query_prove.go index 4a2017c65b..b231906501 100644 --- a/x/lightclient/keeper/grpc_query_prove.go +++ b/x/lightclient/keeper/grpc_query_prove.go @@ -24,7 +24,11 @@ func (k Keeper) Prove(c context.Context, req *types.QueryProveRequest) (*types.Q } ctx := sdk.UnwrapSDKContext(c) - blockHash, err := chains.StringToHash(req.ChainId, req.BlockHash) + // additionalChains is a list of additional chains to search from + // it is used in the protocol to dynamically support new chains without doing an upgrade + additionalChains := k.GetAuthorityKeeper().GetAdditionalChainList(ctx) + + blockHash, err := chains.StringToHash(req.ChainId, req.BlockHash, additionalChains) if err != nil { return nil, status.Error(codes.InvalidArgument, err.Error()) } @@ -40,7 +44,7 @@ func (k Keeper) Prove(c context.Context, req *types.QueryProveRequest) (*types.Q return nil, status.Error(codes.Internal, err.Error()) } if err == nil { - if chains.IsEVMChain(req.ChainId) { + if chains.IsEVMChain(req.ChainId, additionalChains) { var txx ethtypes.Transaction err = txx.UnmarshalBinary(txBytes) if err != nil { @@ -53,7 +57,7 @@ func (k Keeper) Prove(c context.Context, req *types.QueryProveRequest) (*types.Q ) } proven = true - } else if chains.IsBitcoinChain(req.ChainId) { + } else if chains.IsBitcoinChain(req.ChainId, additionalChains) { tx, err := btcutil.NewTxFromBytes(txBytes) if err != nil { return nil, status.Error(codes.Internal, fmt.Sprintf("failed to unmarshal btc transaction: %s", err)) diff --git a/x/lightclient/keeper/proof.go b/x/lightclient/keeper/proof.go index 7067ab3ac1..ddc26eb12f 100644 --- a/x/lightclient/keeper/proof.go +++ b/x/lightclient/keeper/proof.go @@ -23,8 +23,12 @@ func (k Keeper) VerifyProof( return nil, err } + // additionalChains is a list of additional chains to search from + // it is used in the protocol to dynamically support new chains without doing an upgrade + additionalChains := k.GetAuthorityKeeper().GetAdditionalChainList(ctx) + // get block header from the store - hashBytes, err := chains.StringToHash(chainID, blockHash) + hashBytes, err := chains.StringToHash(chainID, blockHash, additionalChains) if err != nil { return nil, cosmoserror.Wrapf( types.ErrInvalidBlockHash, diff --git a/x/lightclient/types/expected_keepers.go b/x/lightclient/types/expected_keepers.go index bee335d628..71f83b2c49 100644 --- a/x/lightclient/types/expected_keepers.go +++ b/x/lightclient/types/expected_keepers.go @@ -2,8 +2,11 @@ package types import ( sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/zeta-chain/zetacore/pkg/chains" ) type AuthorityKeeper interface { CheckAuthorization(ctx sdk.Context, msg sdk.Msg) error + GetAdditionalChainList(ctx sdk.Context) (list []chains.Chain) } diff --git a/x/lightclient/types/message_disable_verification_flags.go b/x/lightclient/types/message_disable_verification_flags.go index 5ee2964aa7..511821919c 100644 --- a/x/lightclient/types/message_disable_verification_flags.go +++ b/x/lightclient/types/message_disable_verification_flags.go @@ -4,8 +4,6 @@ import ( cosmoserrors "cosmossdk.io/errors" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - - "github.com/zeta-chain/zetacore/pkg/chains" ) const ( @@ -46,21 +44,12 @@ func (msg *MsgDisableHeaderVerification) ValidateBasic() error { if _, err := sdk.AccAddressFromBech32(msg.Creator); err != nil { return cosmoserrors.Wrapf(sdkerrors.ErrInvalidAddress, "invalid creator address (%s)", err) } - chainListForHeaderSupport := chains.ChainListForHeaderSupport() if len(msg.ChainIdList) == 0 { return cosmoserrors.Wrapf(sdkerrors.ErrInvalidRequest, "chain id list cannot be empty") } - if len(msg.ChainIdList) > len(chainListForHeaderSupport) { - return cosmoserrors.Wrapf(sdkerrors.ErrInvalidRequest, "chain id list cannot be greater than supported chains") - } - for _, chainID := range msg.ChainIdList { - if !chains.ChainIDInChainList(chainID, chainListForHeaderSupport) { - return cosmoserrors.Wrapf( - sdkerrors.ErrInvalidRequest, - "invalid chain id header not supported (%d)", - chainID, - ) - } + + if len(msg.ChainIdList) > MaxChainIDListLength { + return cosmoserrors.Wrapf(sdkerrors.ErrInvalidRequest, "chain id list too long") } return nil diff --git a/x/lightclient/types/message_disable_verification_flags_test.go b/x/lightclient/types/message_disable_verification_flags_test.go index 6ccde4a12b..8efb9d4c04 100644 --- a/x/lightclient/types/message_disable_verification_flags_test.go +++ b/x/lightclient/types/message_disable_verification_flags_test.go @@ -1,7 +1,6 @@ package types_test import ( - "fmt" "testing" sdk "github.com/cosmos/cosmos-sdk/types" @@ -43,26 +42,11 @@ func TestMsgDisableHeaderVerification_ValidateBasic(t *testing.T) { name: "chain id list is too long", msg: types.MsgDisableHeaderVerification{ Creator: sample.AccAddress(), - ChainIdList: make([]int64, 200), + ChainIdList: make([]int64, types.MaxChainIDListLength+1), }, err: func(t require.TestingT, err error, i ...interface{}) { require.ErrorIs(t, err, sdkerrors.ErrInvalidRequest) - require.ErrorContains(t, err, "chain id list cannot be greater than supported chains") - }, - }, - { - name: "invalid chain id", - msg: types.MsgDisableHeaderVerification{ - Creator: sample.AccAddress(), - ChainIdList: []int64{chains.ZetaChainPrivnet.ChainId}, - }, - err: func(t require.TestingT, err error, i ...interface{}) { - require.ErrorIs(t, err, sdkerrors.ErrInvalidRequest) - require.ErrorContains( - t, - err, - fmt.Sprintf("invalid chain id header not supported (%d)", chains.ZetaChainPrivnet.ChainId), - ) + require.ErrorContains(t, err, "chain id list too long") }, }, { diff --git a/x/lightclient/types/message_enable_verification_flags.go b/x/lightclient/types/message_enable_verification_flags.go index a77706699a..a0a9dac5bd 100644 --- a/x/lightclient/types/message_enable_verification_flags.go +++ b/x/lightclient/types/message_enable_verification_flags.go @@ -4,12 +4,14 @@ import ( cosmoserrors "cosmossdk.io/errors" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - - "github.com/zeta-chain/zetacore/pkg/chains" ) const ( TypeMsgEnableHeaderVerification = "enable_header_verification" + + // MaxChainIDListLength is the maximum number of chain IDs that can be enabled for header verification + // this is a value chosen arbitrarily to prevent abuse + MaxChainIDListLength = 200 ) var _ sdk.Msg = &MsgEnableHeaderVerification{} @@ -46,21 +48,12 @@ func (msg *MsgEnableHeaderVerification) ValidateBasic() error { if _, err := sdk.AccAddressFromBech32(msg.Creator); err != nil { return cosmoserrors.Wrapf(sdkerrors.ErrInvalidAddress, "invalid creator address (%s)", err) } - chainListForHeaderSupport := chains.ChainListForHeaderSupport() if len(msg.ChainIdList) == 0 { return cosmoserrors.Wrapf(sdkerrors.ErrInvalidRequest, "chain id list cannot be empty") } - if len(msg.ChainIdList) > len(chainListForHeaderSupport) { - return cosmoserrors.Wrapf(sdkerrors.ErrInvalidRequest, "chain id list cannot be greater than supported chains") - } - for _, chainID := range msg.ChainIdList { - if !chains.ChainIDInChainList(chainID, chainListForHeaderSupport) { - return cosmoserrors.Wrapf( - sdkerrors.ErrInvalidRequest, - "invalid chain id header not supported (%d)", - chainID, - ) - } + + if len(msg.ChainIdList) > MaxChainIDListLength { + return cosmoserrors.Wrapf(sdkerrors.ErrInvalidRequest, "chain id list too long") } return nil diff --git a/x/lightclient/types/message_enable_verification_flags_test.go b/x/lightclient/types/message_enable_verification_flags_test.go index 0bda67f1b9..2f738f36f0 100644 --- a/x/lightclient/types/message_enable_verification_flags_test.go +++ b/x/lightclient/types/message_enable_verification_flags_test.go @@ -1,7 +1,6 @@ package types_test import ( - "fmt" "testing" sdk "github.com/cosmos/cosmos-sdk/types" @@ -43,26 +42,11 @@ func TestMsgEnableHeaderVerification_ValidateBasic(t *testing.T) { name: "chain id list is too long", msg: types.MsgEnableHeaderVerification{ Creator: sample.AccAddress(), - ChainIdList: make([]int64, 200), + ChainIdList: make([]int64, types.MaxChainIDListLength+1), }, err: func(t require.TestingT, err error, i ...interface{}) { require.ErrorIs(t, err, sdkerrors.ErrInvalidRequest) - require.ErrorContains(t, err, "chain id list cannot be greater than supported chains") - }, - }, - { - name: "invalid chain id", - msg: types.MsgEnableHeaderVerification{ - Creator: sample.AccAddress(), - ChainIdList: []int64{chains.ZetaChainPrivnet.ChainId}, - }, - err: func(t require.TestingT, err error, i ...interface{}) { - require.ErrorIs(t, err, sdkerrors.ErrInvalidRequest) - require.ErrorContains( - t, - err, - fmt.Sprintf("invalid chain id header not supported (%d)", chains.ZetaChainPrivnet.ChainId), - ) + require.ErrorContains(t, err, "chain id list too long") }, }, { diff --git a/x/observer/keeper/chain_params.go b/x/observer/keeper/chain_params.go index a2354f9b2c..9277010c3c 100644 --- a/x/observer/keeper/chain_params.go +++ b/x/observer/keeper/chain_params.go @@ -43,41 +43,44 @@ func (k Keeper) GetChainParamsByChainID(ctx sdk.Context, chainID int64) (*types. // GetSupportedChainFromChainID returns the chain from the chain id // it returns nil if the chain doesn't exist or is not supported -func (k Keeper) GetSupportedChainFromChainID(ctx sdk.Context, chainID int64) *chains.Chain { +func (k Keeper) GetSupportedChainFromChainID(ctx sdk.Context, chainID int64) (chains.Chain, bool) { cpl, found := k.GetChainParamsList(ctx) if !found { - return nil + return chains.Chain{}, false } for _, cp := range cpl.ChainParams { if cp.ChainId == chainID && cp.IsSupported { - return chains.GetChainFromChainID(chainID) + return chains.GetChainFromChainID(chainID, k.GetAuthorityKeeper().GetAdditionalChainList(ctx)) } } - return nil + return chains.Chain{}, false } // GetSupportedChains returns the list of supported chains -func (k Keeper) GetSupportedChains(ctx sdk.Context) []*chains.Chain { +func (k Keeper) GetSupportedChains(ctx sdk.Context) []chains.Chain { cpl, found := k.GetChainParamsList(ctx) if !found { - return []*chains.Chain{} + return []chains.Chain{} } - var c []*chains.Chain + var c []chains.Chain for _, cp := range cpl.ChainParams { if cp.IsSupported { - c = append(c, chains.GetChainFromChainID(cp.ChainId)) + chain, found := chains.GetChainFromChainID(cp.ChainId, k.GetAuthorityKeeper().GetAdditionalChainList(ctx)) + if found { + c = append(c, chain) + } } } return c } // GetSupportedForeignChains returns the list of supported foreign chains -func (k Keeper) GetSupportedForeignChains(ctx sdk.Context) []*chains.Chain { +func (k Keeper) GetSupportedForeignChains(ctx sdk.Context) []chains.Chain { allChains := k.GetSupportedChains(ctx) - foreignChains := make([]*chains.Chain, 0) + foreignChains := make([]chains.Chain, 0) for _, chain := range allChains { if !chain.IsZetaChain() { foreignChains = append(foreignChains, chain) diff --git a/x/observer/keeper/chain_params_test.go b/x/observer/keeper/chain_params_test.go index 4d608f0462..733fafc0b8 100644 --- a/x/observer/keeper/chain_params_test.go +++ b/x/observer/keeper/chain_params_test.go @@ -16,26 +16,29 @@ func TestKeeper_GetSupportedChainFromChainID(t *testing.T) { k, ctx, _, _ := keepertest.ObserverKeeper(t) // no core params list - require.Nil(t, k.GetSupportedChainFromChainID(ctx, getValidEthChainIDWithIndex(t, 0))) + _, found := k.GetSupportedChainFromChainID(ctx, getValidEthChainIDWithIndex(t, 0)) + require.False(t, found) // core params list but chain not in list setSupportedChain(ctx, *k, getValidEthChainIDWithIndex(t, 0)) - require.Nil(t, k.GetSupportedChainFromChainID(ctx, getValidEthChainIDWithIndex(t, 1))) + _, found = k.GetSupportedChainFromChainID(ctx, getValidEthChainIDWithIndex(t, 1)) + require.False(t, found) // chain params list but chain not supported chainParams := sample.ChainParams(getValidEthChainIDWithIndex(t, 0)) k.SetChainParamsList(ctx, types.ChainParamsList{ ChainParams: []*types.ChainParams{chainParams}, }) - require.Nil(t, k.GetSupportedChainFromChainID(ctx, getValidEthChainIDWithIndex(t, 0))) + _, found = k.GetSupportedChainFromChainID(ctx, getValidEthChainIDWithIndex(t, 0)) + require.False(t, found) }) t.Run("return chain if chain found", func(t *testing.T) { k, ctx, _, _ := keepertest.ObserverKeeper(t) chainID := getValidEthChainIDWithIndex(t, 0) setSupportedChain(ctx, *k, getValidEthChainIDWithIndex(t, 1), chainID) - chain := k.GetSupportedChainFromChainID(ctx, chainID) - require.NotNil(t, chain) + chain, found := k.GetSupportedChainFromChainID(ctx, chainID) + require.True(t, found) require.EqualValues(t, chainID, chain.ChainId) }) } @@ -78,12 +81,14 @@ func TestKeeper_GetSupportedChains(t *testing.T) { t.Run("return list containing supported chains", func(t *testing.T) { k, ctx, _, _ := keepertest.ObserverKeeper(t) - require.Greater(t, len(chains.ExternalChainList()), 5) - supported1 := chains.ExternalChainList()[0] - supported2 := chains.ExternalChainList()[1] - unsupported := chains.ExternalChainList()[2] - supported3 := chains.ExternalChainList()[3] - supported4 := chains.ExternalChainList()[4] + chainList := chains.ExternalChainList([]chains.Chain{}) + + require.Greater(t, len(chainList), 5) + supported1 := chainList[0] + supported2 := chainList[1] + unsupported := chainList[2] + supported3 := chainList[3] + supported4 := chainList[4] var chainParamsList []*types.ChainParams chainParamsList = append(chainParamsList, sample.ChainParamsSupported(supported1.ChainId)) diff --git a/x/observer/keeper/grpc_query_supported_chain_test.go b/x/observer/keeper/grpc_query_supported_chain_test.go index 1b73c53394..0cdc276c9d 100644 --- a/x/observer/keeper/grpc_query_supported_chain_test.go +++ b/x/observer/keeper/grpc_query_supported_chain_test.go @@ -17,6 +17,6 @@ func TestKeeper_SupportedChains(t *testing.T) { res, err := k.SupportedChains(wctx, nil) require.NoError(t, err) - require.Equal(t, []*chains.Chain{}, res.Chains) + require.Equal(t, []chains.Chain{}, res.Chains) }) } diff --git a/x/observer/keeper/grpc_query_tss_funds_migrator_info.go b/x/observer/keeper/grpc_query_tss_funds_migrator_info.go index 7a2ab7e357..88558fd23a 100644 --- a/x/observer/keeper/grpc_query_tss_funds_migrator_info.go +++ b/x/observer/keeper/grpc_query_tss_funds_migrator_info.go @@ -22,7 +22,8 @@ func (k Keeper) TssFundsMigratorInfo( ctx := sdk.UnwrapSDKContext(goCtx) - if chains.GetChainFromChainID(req.ChainId) == nil { + _, found := chains.GetChainFromChainID(req.ChainId, k.GetAuthorityKeeper().GetAdditionalChainList(ctx)) + if !found { return nil, status.Error(codes.InvalidArgument, "invalid chain id") } diff --git a/x/observer/keeper/msg_server_remove_chain_params_test.go b/x/observer/keeper/msg_server_remove_chain_params_test.go index 5139f84086..c7b60d7c07 100644 --- a/x/observer/keeper/msg_server_remove_chain_params_test.go +++ b/x/observer/keeper/msg_server_remove_chain_params_test.go @@ -24,9 +24,11 @@ func TestMsgServer_RemoveChainParams(t *testing.T) { // mock the authority keeper for authorization authorityMock := keepertest.GetObserverAuthorityMock(t, k) - chain1 := chains.ExternalChainList()[0].ChainId - chain2 := chains.ExternalChainList()[1].ChainId - chain3 := chains.ExternalChainList()[2].ChainId + chainList := chains.ExternalChainList([]chains.Chain{}) + + chain1 := chainList[0].ChainId + chain2 := chainList[1].ChainId + chain3 := chainList[2].ChainId // set admin admin := sample.AccAddress() @@ -96,7 +98,7 @@ func TestMsgServer_RemoveChainParams(t *testing.T) { msg := types.MsgRemoveChainParams{ Creator: admin, - ChainId: chains.ExternalChainList()[0].ChainId, + ChainId: chains.ExternalChainList([]chains.Chain{})[0].ChainId, } keepertest.MockCheckAuthorization(&authorityMock.Mock, &msg, authoritytypes.ErrUnauthorized) _, err := srv.RemoveChainParams(sdk.WrapSDKContext(ctx), &msg) @@ -117,9 +119,11 @@ func TestMsgServer_RemoveChainParams(t *testing.T) { _, found := k.GetChainParamsList(ctx) require.False(t, found) + chainList := chains.ExternalChainList([]chains.Chain{}) + msg := types.MsgRemoveChainParams{ Creator: admin, - ChainId: chains.ExternalChainList()[0].ChainId, + ChainId: chainList[0].ChainId, } keepertest.MockCheckAuthorization(&authorityMock.Mock, &msg, nil) _, err := srv.RemoveChainParams(sdk.WrapSDKContext(ctx), &msg) @@ -128,16 +132,16 @@ func TestMsgServer_RemoveChainParams(t *testing.T) { // add chain params k.SetChainParamsList(ctx, types.ChainParamsList{ ChainParams: []*types.ChainParams{ - sample.ChainParams(chains.ExternalChainList()[0].ChainId), - sample.ChainParams(chains.ExternalChainList()[1].ChainId), - sample.ChainParams(chains.ExternalChainList()[2].ChainId), + sample.ChainParams(chainList[0].ChainId), + sample.ChainParams(chainList[1].ChainId), + sample.ChainParams(chainList[2].ChainId), }, }) // not found if chain ID not in list msg = types.MsgRemoveChainParams{ Creator: admin, - ChainId: chains.ExternalChainList()[3].ChainId, + ChainId: chainList[3].ChainId, } keepertest.MockCheckAuthorization(&authorityMock.Mock, &msg, nil) _, err = srv.RemoveChainParams(sdk.WrapSDKContext(ctx), &msg) diff --git a/x/observer/keeper/msg_server_reset_chain_nonces.go b/x/observer/keeper/msg_server_reset_chain_nonces.go index a3ea3ecc81..8cd61c97d6 100644 --- a/x/observer/keeper/msg_server_reset_chain_nonces.go +++ b/x/observer/keeper/msg_server_reset_chain_nonces.go @@ -27,8 +27,8 @@ func (k msgServer) ResetChainNonces( return nil, types.ErrTssNotFound } - chain := chains.GetChainFromChainID(msg.ChainId) - if chain == nil { + chain, found := chains.GetChainFromChainID(msg.ChainId, k.GetAuthorityKeeper().GetAdditionalChainList(ctx)) + if !found { return nil, types.ErrSupportedChains } diff --git a/x/observer/keeper/msg_server_reset_chain_nonces_test.go b/x/observer/keeper/msg_server_reset_chain_nonces_test.go index 53009d9608..0b1c76113c 100644 --- a/x/observer/keeper/msg_server_reset_chain_nonces_test.go +++ b/x/observer/keeper/msg_server_reset_chain_nonces_test.go @@ -74,6 +74,7 @@ func TestMsgServer_ResetChainNonces(t *testing.T) { ChainNonceHigh: 5, } keepertest.MockCheckAuthorization(&authorityMock.Mock, &msg, nil) + keepertest.MockGetChainListEmpty(&authorityMock.Mock) _, err := srv.ResetChainNonces(sdk.WrapSDKContext(ctx), &msg) require.ErrorIs(t, err, types.ErrSupportedChains) @@ -109,6 +110,7 @@ func TestMsgServer_ResetChainNonces(t *testing.T) { ChainNonceHigh: int64(nonceHigh), } keepertest.MockCheckAuthorization(&authorityMock.Mock, &msg, nil) + keepertest.MockGetChainListEmpty(&authorityMock.Mock) _, err := srv.ResetChainNonces(sdk.WrapSDKContext(ctx), &msg) require.NoError(t, err) diff --git a/x/observer/keeper/msg_server_update_chain_params_test.go b/x/observer/keeper/msg_server_update_chain_params_test.go index fc38200764..d8ad61820d 100644 --- a/x/observer/keeper/msg_server_update_chain_params_test.go +++ b/x/observer/keeper/msg_server_update_chain_params_test.go @@ -21,9 +21,11 @@ func TestMsgServer_UpdateChainParams(t *testing.T) { }) srv := keeper.NewMsgServerImpl(*k) - chain1 := chains.ExternalChainList()[0].ChainId - chain2 := chains.ExternalChainList()[1].ChainId - chain3 := chains.ExternalChainList()[2].ChainId + chainList := chains.ExternalChainList([]chains.Chain{}) + + chain1 := chainList[0].ChainId + chain2 := chainList[1].ChainId + chain3 := chainList[2].ChainId // set admin admin := sample.AccAddress() @@ -113,7 +115,7 @@ func TestMsgServer_UpdateChainParams(t *testing.T) { msg := types.MsgUpdateChainParams{ Creator: admin, - ChainParams: sample.ChainParams(chains.ExternalChainList()[0].ChainId), + ChainParams: sample.ChainParams(chains.ExternalChainList([]chains.Chain{})[0].ChainId), } keepertest.MockCheckAuthorization(&authorityMock.Mock, &msg, authoritytypes.ErrUnauthorized) _, err := srv.UpdateChainParams(sdk.WrapSDKContext(ctx), &msg) diff --git a/x/observer/keeper/msg_server_vote_blame.go b/x/observer/keeper/msg_server_vote_blame.go index 395b2fa9c1..217d5e5912 100644 --- a/x/observer/keeper/msg_server_vote_blame.go +++ b/x/observer/keeper/msg_server_vote_blame.go @@ -19,8 +19,8 @@ func (k msgServer) VoteBlame( observationType := types.ObservationType_TSSKeySign // GetChainFromChainID makes sure we are getting only supported chains , if a chain support has been turned on using gov proposal, this function returns nil - observationChain := k.GetSupportedChainFromChainID(ctx, vote.ChainId) - if observationChain == nil { + observationChain, found := k.GetSupportedChainFromChainID(ctx, vote.ChainId) + if !found { return nil, cosmoserrors.Wrap( crosschainTypes.ErrUnsupportedChain, fmt.Sprintf("ChainID %d, Blame vote", vote.ChainId), diff --git a/x/observer/keeper/msg_server_vote_block_header.go b/x/observer/keeper/msg_server_vote_block_header.go index 5e8c0e0bce..9ae7a35a56 100644 --- a/x/observer/keeper/msg_server_vote_block_header.go +++ b/x/observer/keeper/msg_server_vote_block_header.go @@ -18,8 +18,8 @@ func (k msgServer) VoteBlockHeader( ctx := sdk.UnwrapSDKContext(goCtx) // check if the chain is enabled - chain := k.GetSupportedChainFromChainID(ctx, msg.ChainId) - if chain == nil { + chain, found := k.GetSupportedChainFromChainID(ctx, msg.ChainId) + if !found { return nil, cosmoserrors.Wrapf(types.ErrSupportedChains, "chain id: %d", msg.ChainId) } diff --git a/x/observer/keeper/msg_server_vote_block_header_test.go b/x/observer/keeper/msg_server_vote_block_header_test.go index 0d41b1be0c..7ce0144e5f 100644 --- a/x/observer/keeper/msg_server_vote_block_header_test.go +++ b/x/observer/keeper/msg_server_vote_block_header_test.go @@ -93,6 +93,9 @@ func TestMsgServer_VoteBlockHeader(t *testing.T) { stakingMock := keepertest.GetObserverStakingMock(t, k) slashingMock := keepertest.GetObserverSlashingMock(t, k) lightclientMock := keepertest.GetObserverLightclientMock(t, k) + authorityMock := keepertest.GetObserverAuthorityMock(t, k) + + keepertest.MockGetChainListEmpty(&authorityMock.Mock) k.SetChainParamsList(ctx, types.ChainParamsList{ ChainParams: []*types.ChainParams{ @@ -131,6 +134,9 @@ func TestMsgServer_VoteBlockHeader(t *testing.T) { stakingMock := keepertest.GetObserverStakingMock(t, k) slashingMock := keepertest.GetObserverSlashingMock(t, k) lightclientMock := keepertest.GetObserverLightclientMock(t, k) + authorityMock := keepertest.GetObserverAuthorityMock(t, k) + + keepertest.MockGetChainListEmpty(&authorityMock.Mock) k.SetChainParamsList(ctx, types.ChainParamsList{ ChainParams: []*types.ChainParams{ @@ -176,6 +182,9 @@ func TestMsgServer_VoteBlockHeader(t *testing.T) { stakingMock := keepertest.GetObserverStakingMock(t, k) slashingMock := keepertest.GetObserverSlashingMock(t, k) lightclientMock := keepertest.GetObserverLightclientMock(t, k) + authorityMock := keepertest.GetObserverAuthorityMock(t, k) + + keepertest.MockGetChainListEmpty(&authorityMock.Mock) k.SetChainParamsList(ctx, types.ChainParamsList{ ChainParams: []*types.ChainParams{ @@ -250,6 +259,9 @@ func TestMsgServer_VoteBlockHeader(t *testing.T) { stakingMock := keepertest.GetObserverStakingMock(t, k) slashingMock := keepertest.GetObserverSlashingMock(t, k) lightclientMock := keepertest.GetObserverLightclientMock(t, k) + authorityMock := keepertest.GetObserverAuthorityMock(t, k) + + keepertest.MockGetChainListEmpty(&authorityMock.Mock) k.SetChainParamsList(ctx, types.ChainParamsList{ ChainParams: []*types.ChainParams{ diff --git a/x/observer/keeper/utils.go b/x/observer/keeper/utils.go index 8d37e82d57..3215a86307 100644 --- a/x/observer/keeper/utils.go +++ b/x/observer/keeper/utils.go @@ -56,7 +56,7 @@ func (k Keeper) IsNonTombstonedObserver(ctx sdk.Context, address string) bool { func (k Keeper) FindBallot( ctx sdk.Context, index string, - chain *chains.Chain, + chain chains.Chain, observationType types.ObservationType, ) (ballot types.Ballot, isNew bool, err error) { isNew = false diff --git a/x/observer/keeper/utils_test.go b/x/observer/keeper/utils_test.go index b11a4512ca..effd815ad5 100644 --- a/x/observer/keeper/utils_test.go +++ b/x/observer/keeper/utils_test.go @@ -314,7 +314,7 @@ func TestKeeper_FindBallot(t *testing.T) { t.Run("should err if chain params not found", func(t *testing.T) { k, ctx, _, _ := keepertest.ObserverKeeper(t) - _, _, err := k.FindBallot(ctx, "index", &chains.Chain{ + _, _, err := k.FindBallot(ctx, "index", chains.Chain{ ChainId: 987, }, types.ObservationType_InboundTx) require.Error(t, err) diff --git a/x/observer/keeper/vote_inbound.go b/x/observer/keeper/vote_inbound.go index b5fcdb1e38..676e93aeaa 100644 --- a/x/observer/keeper/vote_inbound.go +++ b/x/observer/keeper/vote_inbound.go @@ -29,8 +29,8 @@ func (k Keeper) VoteOnInboundBallot( // makes sure we are getting only supported chains // if a chain support has been turned on using gov proposal // this function returns nil - senderChain := k.GetSupportedChainFromChainID(ctx, senderChainID) - if senderChain == nil { + senderChain, found := k.GetSupportedChainFromChainID(ctx, senderChainID) + if !found { return false, false, sdkerrors.Wrap(types.ErrSupportedChains, fmt.Sprintf( "ChainID %d, Observation %s", senderChainID, @@ -44,8 +44,8 @@ func (k Keeper) VoteOnInboundBallot( } // makes sure we are getting only supported chains - receiverChain := k.GetSupportedChainFromChainID(ctx, receiverChainID) - if receiverChain == nil { + receiverChain, found := k.GetSupportedChainFromChainID(ctx, receiverChainID) + if !found { return false, false, sdkerrors.Wrap(types.ErrSupportedChains, fmt.Sprintf( "ChainID %d, Observation %s", receiverChainID, diff --git a/x/observer/keeper/vote_inbound_test.go b/x/observer/keeper/vote_inbound_test.go index 9f9fa09b58..99951e287c 100644 --- a/x/observer/keeper/vote_inbound_test.go +++ b/x/observer/keeper/vote_inbound_test.go @@ -114,6 +114,9 @@ func TestKeeper_VoteOnInboundBallot(t *testing.T) { observer := sample.AccAddress() stakingMock := keepertest.GetObserverStakingMock(t, k) slashingMock := keepertest.GetObserverSlashingMock(t, k) + authorityMock := keepertest.GetObserverAuthorityMock(t, k) + + keepertest.MockGetChainListEmpty(&authorityMock.Mock) k.SetCrosschainFlags(ctx, types.CrosschainFlags{ IsInboundEnabled: true, @@ -179,6 +182,9 @@ func TestKeeper_VoteOnInboundBallot(t *testing.T) { observer := sample.AccAddress() stakingMock := keepertest.GetObserverStakingMock(t, k) slashingMock := keepertest.GetObserverSlashingMock(t, k) + authorityMock := keepertest.GetObserverAuthorityMock(t, k) + + keepertest.MockGetChainListEmpty(&authorityMock.Mock) k.SetCrosschainFlags(ctx, types.CrosschainFlags{ IsInboundEnabled: true, @@ -221,6 +227,9 @@ func TestKeeper_VoteOnInboundBallot(t *testing.T) { observer := sample.AccAddress() stakingMock := keepertest.GetObserverStakingMock(t, k) slashingMock := keepertest.GetObserverSlashingMock(t, k) + authorityMock := keepertest.GetObserverAuthorityMock(t, k) + + keepertest.MockGetChainListEmpty(&authorityMock.Mock) k.SetCrosschainFlags(ctx, types.CrosschainFlags{ IsInboundEnabled: true, @@ -265,6 +274,9 @@ func TestKeeper_VoteOnInboundBallot(t *testing.T) { observer := sample.AccAddress() stakingMock := keepertest.GetObserverStakingMock(t, k) slashingMock := keepertest.GetObserverSlashingMock(t, k) + authorityMock := keepertest.GetObserverAuthorityMock(t, k) + + keepertest.MockGetChainListEmpty(&authorityMock.Mock) k.SetCrosschainFlags(ctx, types.CrosschainFlags{ IsInboundEnabled: true, @@ -316,6 +328,9 @@ func TestKeeper_VoteOnInboundBallot(t *testing.T) { observer := sample.AccAddress() stakingMock := keepertest.GetObserverStakingMock(t, k) slashingMock := keepertest.GetObserverSlashingMock(t, k) + authorityMock := keepertest.GetObserverAuthorityMock(t, k) + + keepertest.MockGetChainListEmpty(&authorityMock.Mock) // threshold high enough to not finalize ballot threshold, err := sdk.NewDecFromStr("0.7") @@ -369,6 +384,9 @@ func TestKeeper_VoteOnInboundBallot(t *testing.T) { observer := sample.AccAddress() stakingMock := keepertest.GetObserverStakingMock(t, k) slashingMock := keepertest.GetObserverSlashingMock(t, k) + authorityMock := keepertest.GetObserverAuthorityMock(t, k) + + keepertest.MockGetChainListEmpty(&authorityMock.Mock) k.SetCrosschainFlags(ctx, types.CrosschainFlags{ IsInboundEnabled: true, @@ -433,6 +451,9 @@ func TestKeeper_VoteOnInboundBallot(t *testing.T) { observer := sample.AccAddress() stakingMock := keepertest.GetObserverStakingMock(t, k) slashingMock := keepertest.GetObserverSlashingMock(t, k) + authorityMock := keepertest.GetObserverAuthorityMock(t, k) + + keepertest.MockGetChainListEmpty(&authorityMock.Mock) k.SetCrosschainFlags(ctx, types.CrosschainFlags{ IsInboundEnabled: true, diff --git a/x/observer/keeper/vote_outbound.go b/x/observer/keeper/vote_outbound.go index 0dc946f5b4..a8212980ed 100644 --- a/x/observer/keeper/vote_outbound.go +++ b/x/observer/keeper/vote_outbound.go @@ -23,8 +23,8 @@ func (k Keeper) VoteOnOutboundBallot( /* EDGE CASE : Params updated in during the finalization process i.e Inbound has been finalized but outbound is still pending */ - observationChain := k.GetSupportedChainFromChainID(ctx, outTxChainID) - if observationChain == nil { + observationChain, found := k.GetSupportedChainFromChainID(ctx, outTxChainID) + if !found { return false, false, ballot, "", observertypes.ErrSupportedChains } if observertypes.CheckReceiveStatus(receiveStatus) != nil { diff --git a/x/observer/keeper/vote_outbound_test.go b/x/observer/keeper/vote_outbound_test.go index 4d14e828ba..bc88b21303 100644 --- a/x/observer/keeper/vote_outbound_test.go +++ b/x/observer/keeper/vote_outbound_test.go @@ -102,6 +102,9 @@ func TestKeeper_VoteOnOutboundBallot(t *testing.T) { observer := sample.AccAddress() stakingMock := keepertest.GetObserverStakingMock(t, k) slashingMock := keepertest.GetObserverSlashingMock(t, k) + authorityMock := keepertest.GetObserverAuthorityMock(t, k) + + keepertest.MockGetChainListEmpty(&authorityMock.Mock) k.SetChainParamsList(ctx, types.ChainParamsList{ ChainParams: []*types.ChainParams{ @@ -140,6 +143,9 @@ func TestKeeper_VoteOnOutboundBallot(t *testing.T) { observer := sample.AccAddress() stakingMock := keepertest.GetObserverStakingMock(t, k) slashingMock := keepertest.GetObserverSlashingMock(t, k) + authorityMock := keepertest.GetObserverAuthorityMock(t, k) + + keepertest.MockGetChainListEmpty(&authorityMock.Mock) k.SetChainParamsList(ctx, types.ChainParamsList{ ChainParams: []*types.ChainParams{ @@ -182,6 +188,9 @@ func TestKeeper_VoteOnOutboundBallot(t *testing.T) { observer := sample.AccAddress() stakingMock := keepertest.GetObserverStakingMock(t, k) slashingMock := keepertest.GetObserverSlashingMock(t, k) + authorityMock := keepertest.GetObserverAuthorityMock(t, k) + + keepertest.MockGetChainListEmpty(&authorityMock.Mock) // threshold high enough to not finalize the ballot threshold, err := sdk.NewDecFromStr("0.7") @@ -228,6 +237,9 @@ func TestKeeper_VoteOnOutboundBallot(t *testing.T) { observer := sample.AccAddress() stakingMock := keepertest.GetObserverStakingMock(t, k) slashingMock := keepertest.GetObserverSlashingMock(t, k) + authorityMock := keepertest.GetObserverAuthorityMock(t, k) + + keepertest.MockGetChainListEmpty(&authorityMock.Mock) k.SetChainParamsList(ctx, types.ChainParamsList{ ChainParams: []*types.ChainParams{ @@ -286,6 +298,9 @@ func TestKeeper_VoteOnOutboundBallot(t *testing.T) { observer := sample.AccAddress() stakingMock := keepertest.GetObserverStakingMock(t, k) slashingMock := keepertest.GetObserverSlashingMock(t, k) + authorityMock := keepertest.GetObserverAuthorityMock(t, k) + + keepertest.MockGetChainListEmpty(&authorityMock.Mock) k.SetChainParamsList(ctx, types.ChainParamsList{ ChainParams: []*types.ChainParams{ diff --git a/x/observer/types/chain_params.go b/x/observer/types/chain_params.go index d67aa520ba..665be3de98 100644 --- a/x/observer/types/chain_params.go +++ b/x/observer/types/chain_params.go @@ -8,6 +8,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" ethchains "github.com/ethereum/go-ethereum/common" + "github.com/pkg/errors" "github.com/zeta-chain/zetacore/pkg/chains" ) @@ -54,15 +55,22 @@ func ValidateChainParams(params *ChainParams) error { if params == nil { return fmt.Errorf("chain params cannot be nil") } - chain := chains.GetChainFromChainID(params.ChainId) - if chain == nil { - return fmt.Errorf("ChainId %d not supported", params.ChainId) - } - // zeta chain skips the rest of the checks for now - if chain.IsZetaChain() { + + // TODO: ZetaChain chain params should be completely removed + // Once removed, this check is no longer necessary as all chasin params would need the same checks + // https://github.com/zeta-chain/node/issues/2419 + _, err := chains.ZetaChainFromChainID(params.ChainId) + if err == nil { + // zeta chain skips the rest of the checks for now return nil } + // ignore error from ZetaChainFromChainID if reason is chain is not zeta chain + // return error otherwise + if !errors.Is(err, chains.ErrNotZetaChain) { + return err + } + if params.ConfirmationCount == 0 { return errorsmod.Wrapf(sdkerrors.ErrInvalidRequest, "ConfirmationCount must be greater than 0") } @@ -90,38 +98,36 @@ func ValidateChainParams(params *ChainParams) error { ) } - // chain type specific checks - if chains.IsBitcoinChain(params.ChainId) { - if params.WatchUtxoTicker == 0 || params.WatchUtxoTicker > 300 { - return errorsmod.Wrapf( - sdkerrors.ErrInvalidRequest, - "WatchUtxoTicker %d out of range", - params.WatchUtxoTicker, - ) - } + // if WatchUtxoTicker defined, check validity + if params.WatchUtxoTicker > 300 { + return errorsmod.Wrapf( + sdkerrors.ErrInvalidRequest, + "WatchUtxoTicker %d out of range", + params.WatchUtxoTicker, + ) } - if chains.IsEVMChain(params.ChainId) { - if !validChainContractAddress(params.ZetaTokenContractAddress) { - return errorsmod.Wrapf( - sdkerrors.ErrInvalidRequest, - "invalid ZetaTokenContractAddress %s", - params.ZetaTokenContractAddress, - ) - } - if !validChainContractAddress(params.ConnectorContractAddress) { - return errorsmod.Wrapf( - sdkerrors.ErrInvalidRequest, - "invalid ConnectorContractAddress %s", - params.ConnectorContractAddress, - ) - } - if !validChainContractAddress(params.Erc20CustodyContractAddress) { - return errorsmod.Wrapf( - sdkerrors.ErrInvalidRequest, - "invalid Erc20CustodyContractAddress %s", - params.Erc20CustodyContractAddress, - ) - } + + // if contract addresses are defined, check validity + if params.ZetaTokenContractAddress != "" && !validChainContractAddress(params.ZetaTokenContractAddress) { + return errorsmod.Wrapf( + sdkerrors.ErrInvalidRequest, + "invalid ZetaTokenContractAddress %s", + params.ZetaTokenContractAddress, + ) + } + if params.ConnectorContractAddress != "" && !validChainContractAddress(params.ConnectorContractAddress) { + return errorsmod.Wrapf( + sdkerrors.ErrInvalidRequest, + "invalid ConnectorContractAddress %s", + params.ConnectorContractAddress, + ) + } + if params.Erc20CustodyContractAddress != "" && !validChainContractAddress(params.Erc20CustodyContractAddress) { + return errorsmod.Wrapf( + sdkerrors.ErrInvalidRequest, + "invalid Erc20CustodyContractAddress %s", + params.Erc20CustodyContractAddress, + ) } if params.BallotThreshold.IsNil() || params.BallotThreshold.GT(sdk.OneDec()) { diff --git a/x/observer/types/chain_params_test.go b/x/observer/types/chain_params_test.go index 1703b43f54..dff1311a9c 100644 --- a/x/observer/types/chain_params_test.go +++ b/x/observer/types/chain_params_test.go @@ -99,9 +99,9 @@ func (s *UpdateChainParamsSuite) TestCommonParams() { s.Validate(s.btcParams) } -func (s *UpdateChainParamsSuite) TestBTCParams() { +func (s *UpdateChainParamsSuite) TestBTCParamsInvalid() { copy := *s.btcParams - copy.WatchUtxoTicker = 0 + copy.WatchUtxoTicker = 301 err := types.ValidateChainParams(©) require.NotNil(s.T(), err) } diff --git a/x/observer/types/expected_keepers.go b/x/observer/types/expected_keepers.go index 5eb8b03468..4a556d4fa4 100644 --- a/x/observer/types/expected_keepers.go +++ b/x/observer/types/expected_keepers.go @@ -5,6 +5,7 @@ import ( slashingtypes "github.com/cosmos/cosmos-sdk/x/slashing/types" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" + "github.com/zeta-chain/zetacore/pkg/chains" "github.com/zeta-chain/zetacore/pkg/proofs" authoritytypes "github.com/zeta-chain/zetacore/x/authority/types" ) @@ -33,6 +34,7 @@ type StakingHooks interface { type AuthorityKeeper interface { CheckAuthorization(ctx sdk.Context, msg sdk.Msg) error + GetAdditionalChainList(ctx sdk.Context) (list []chains.Chain) // SetPolicies is solely used for the migration of policies from observer to authority SetPolicies(ctx sdk.Context, policies authoritytypes.Policies) diff --git a/x/observer/types/message_remove_chain_params.go b/x/observer/types/message_remove_chain_params.go index b34574e4de..708f87290f 100644 --- a/x/observer/types/message_remove_chain_params.go +++ b/x/observer/types/message_remove_chain_params.go @@ -4,8 +4,6 @@ import ( cosmoserrors "cosmossdk.io/errors" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - - "github.com/zeta-chain/zetacore/pkg/chains" ) const TypeMsgRemoveChainParams = "remove_chain_params" @@ -46,11 +44,5 @@ func (msg *MsgRemoveChainParams) ValidateBasic() error { return cosmoserrors.Wrapf(sdkerrors.ErrInvalidAddress, "invalid creator address (%s)", err) } - // Check if chain exists - chain := chains.GetChainFromChainID(msg.ChainId) - if chain == nil { - return cosmoserrors.Wrapf(sdkerrors.ErrInvalidChainID, "invalid chain id (%d)", msg.ChainId) - } - return nil } diff --git a/x/observer/types/message_remove_chain_params_test.go b/x/observer/types/message_remove_chain_params_test.go index b81f29ff77..69f8f83103 100644 --- a/x/observer/types/message_remove_chain_params_test.go +++ b/x/observer/types/message_remove_chain_params_test.go @@ -22,26 +22,17 @@ func TestMsgRemoveChainParams_ValidateBasic(t *testing.T) { name: "valid message", msg: types.NewMsgRemoveChainParams( sample.AccAddress(), - chains.ExternalChainList()[0].ChainId, + chains.ExternalChainList([]chains.Chain{})[0].ChainId, ), }, { name: "invalid address", msg: types.NewMsgRemoveChainParams( "invalid_address", - chains.ExternalChainList()[0].ChainId, + chains.ExternalChainList([]chains.Chain{})[0].ChainId, ), err: sdkerrors.ErrInvalidAddress, }, - - { - name: "invalid chain ID", - msg: types.NewMsgRemoveChainParams( - sample.AccAddress(), - 999, - ), - err: sdkerrors.ErrInvalidChainID, - }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { diff --git a/x/observer/types/message_reset_chain_nonces.go b/x/observer/types/message_reset_chain_nonces.go index ac14463af5..80e0a2d26b 100644 --- a/x/observer/types/message_reset_chain_nonces.go +++ b/x/observer/types/message_reset_chain_nonces.go @@ -6,8 +6,6 @@ import ( cosmoserrors "cosmossdk.io/errors" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - - "github.com/zeta-chain/zetacore/pkg/chains" ) const TypeMsgResetChainNonces = "reset_chain_nonces" @@ -55,12 +53,6 @@ func (msg *MsgResetChainNonces) ValidateBasic() error { return cosmoserrors.Wrapf(sdkerrors.ErrInvalidAddress, "invalid creator address (%s)", err) } - // Check if chain exists - chain := chains.GetChainFromChainID(msg.ChainId) - if chain == nil { - return cosmoserrors.Wrapf(sdkerrors.ErrInvalidChainID, "invalid chain id (%d)", msg.ChainId) - } - if msg.ChainNonceLow < 0 { return errors.New("chain nonce low must be greater or equal 0") } diff --git a/x/observer/types/message_reset_chain_nonces_test.go b/x/observer/types/message_reset_chain_nonces_test.go index d131d32ed6..41da6643d2 100644 --- a/x/observer/types/message_reset_chain_nonces_test.go +++ b/x/observer/types/message_reset_chain_nonces_test.go @@ -12,6 +12,8 @@ import ( ) func TestMsgResetChainNonces_ValidateBasic(t *testing.T) { + chainList := chains.ExternalChainList([]chains.Chain{}) + tests := []struct { name string msg types.MsgResetChainNonces @@ -21,7 +23,7 @@ func TestMsgResetChainNonces_ValidateBasic(t *testing.T) { name: "valid message chain nonce high greater than nonce low", msg: types.MsgResetChainNonces{ Creator: sample.AccAddress(), - ChainId: chains.ExternalChainList()[0].ChainId, + ChainId: chainList[0].ChainId, ChainNonceLow: 1, ChainNonceHigh: 5, }, @@ -31,7 +33,7 @@ func TestMsgResetChainNonces_ValidateBasic(t *testing.T) { name: "valid message chain nonce high same as nonce low", msg: types.MsgResetChainNonces{ Creator: sample.AccAddress(), - ChainId: chains.ExternalChainList()[0].ChainId, + ChainId: chainList[0].ChainId, ChainNonceLow: 1, ChainNonceHigh: 1, }, @@ -41,15 +43,7 @@ func TestMsgResetChainNonces_ValidateBasic(t *testing.T) { name: "invalid address", msg: types.MsgResetChainNonces{ Creator: "invalid_address", - ChainId: chains.ExternalChainList()[0].ChainId, - }, - wantErr: true, - }, - { - name: "invalid chain ID", - msg: types.MsgResetChainNonces{ - Creator: sample.AccAddress(), - ChainId: 999, + ChainId: chainList[0].ChainId, }, wantErr: true, }, @@ -57,7 +51,7 @@ func TestMsgResetChainNonces_ValidateBasic(t *testing.T) { name: "invalid chain nonce low", msg: types.MsgResetChainNonces{ Creator: sample.AccAddress(), - ChainId: chains.ExternalChainList()[0].ChainId, + ChainId: chainList[0].ChainId, ChainNonceLow: -1, }, wantErr: true, @@ -66,7 +60,7 @@ func TestMsgResetChainNonces_ValidateBasic(t *testing.T) { name: "invalid chain nonce high", msg: types.MsgResetChainNonces{ Creator: sample.AccAddress(), - ChainId: chains.ExternalChainList()[0].ChainId, + ChainId: chainList[0].ChainId, ChainNonceLow: 1, ChainNonceHigh: -1, }, @@ -76,7 +70,7 @@ func TestMsgResetChainNonces_ValidateBasic(t *testing.T) { name: "invalid chain nonce low greater than chain nonce high", msg: types.MsgResetChainNonces{ Creator: sample.AccAddress(), - ChainId: chains.ExternalChainList()[0].ChainId, + ChainId: chainList[0].ChainId, ChainNonceLow: 1, ChainNonceHigh: 0, }, diff --git a/x/observer/types/message_update_chain_params_test.go b/x/observer/types/message_update_chain_params_test.go index fe2d526631..69dd70ced8 100644 --- a/x/observer/types/message_update_chain_params_test.go +++ b/x/observer/types/message_update_chain_params_test.go @@ -13,6 +13,8 @@ import ( ) func TestMsgUpdateChainParams_ValidateBasic(t *testing.T) { + chainList := chains.ExternalChainList([]chains.Chain{}) + tests := []struct { name string msg *types.MsgUpdateChainParams @@ -22,14 +24,14 @@ func TestMsgUpdateChainParams_ValidateBasic(t *testing.T) { name: "valid message", msg: types.NewMsgUpdateChainParams( sample.AccAddress(), - sample.ChainParams(chains.ExternalChainList()[0].ChainId), + sample.ChainParams(chainList[0].ChainId), ), }, { name: "invalid address", msg: types.NewMsgUpdateChainParams( "invalid_address", - sample.ChainParams(chains.ExternalChainList()[0].ChainId), + sample.ChainParams(chainList[0].ChainId), ), err: sdkerrors.ErrInvalidAddress, }, diff --git a/x/observer/types/message_vote_blame.go b/x/observer/types/message_vote_blame.go index 2a06e84869..336a086185 100644 --- a/x/observer/types/message_vote_blame.go +++ b/x/observer/types/message_vote_blame.go @@ -5,8 +5,6 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/ethereum/go-ethereum/crypto" - - "github.com/zeta-chain/zetacore/pkg/chains" ) const TypeMsgVoteBlame = "vote_blame" @@ -34,9 +32,7 @@ func (m *MsgVoteBlame) ValidateBasic() error { if err != nil { return cosmoserrors.Wrapf(sdkerrors.ErrInvalidAddress, "invalid creator address (%s)", err) } - if chains.GetChainFromChainID(m.ChainId) == nil { - return cosmoserrors.Wrapf(sdkerrors.ErrInvalidChainID, "chain id (%d)", m.ChainId) - } + return nil } diff --git a/x/observer/types/message_vote_blame_test.go b/x/observer/types/message_vote_blame_test.go index 9514beac40..6385621a12 100644 --- a/x/observer/types/message_vote_blame_test.go +++ b/x/observer/types/message_vote_blame_test.go @@ -28,15 +28,6 @@ func TestNewMsgVoteBlameMsg_ValidateBasic(t *testing.T) { ), error: true, }, - { - name: "invalid chain id", - msg: types.NewMsgVoteBlameMsg( - sample.AccAddress(), - -1, - sample.BlameRecordsList(t, 1)[0], - ), - error: true, - }, { name: "valid", msg: types.NewMsgVoteBlameMsg( diff --git a/x/observer/types/message_vote_block_header.go b/x/observer/types/message_vote_block_header.go index 004b2ce199..ba52975251 100644 --- a/x/observer/types/message_vote_block_header.go +++ b/x/observer/types/message_vote_block_header.go @@ -6,7 +6,6 @@ import ( sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/ethereum/go-ethereum/crypto" - "github.com/zeta-chain/zetacore/pkg/chains" "github.com/zeta-chain/zetacore/pkg/proofs" ) @@ -59,10 +58,6 @@ func (msg *MsgVoteBlockHeader) ValidateBasic() error { return cosmoserrors.Wrapf(sdkerrors.ErrInvalidAddress, err.Error()) } - if !chains.IsHeaderSupportedChain(msg.ChainId) { - return cosmoserrors.Wrapf(sdkerrors.ErrInvalidRequest, "invalid chain id (%d)", msg.ChainId) - } - if len(msg.BlockHash) != 32 { return cosmoserrors.Wrapf(sdkerrors.ErrInvalidRequest, "invalid block hash length (%d)", len(msg.BlockHash)) } diff --git a/x/observer/types/observer.pb.go b/x/observer/types/observer.pb.go index 13d3e1c998..2d21b13149 100644 --- a/x/observer/types/observer.pb.go +++ b/x/observer/types/observer.pb.go @@ -7,7 +7,6 @@ import ( fmt "fmt" _ "github.com/cosmos/gogoproto/gogoproto" proto "github.com/cosmos/gogoproto/proto" - _ "github.com/zeta-chain/zetacore/pkg/chains" io "io" math "math" math_bits "math/bits" @@ -194,31 +193,30 @@ func init() { } var fileDescriptor_05af1bc65780862e = []byte{ - // 378 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x6c, 0x51, 0xdf, 0xaa, 0xd3, 0x30, - 0x18, 0x6f, 0xb6, 0x29, 0x9c, 0x1c, 0x8f, 0xeb, 0xc2, 0x84, 0x31, 0xa1, 0x8c, 0x79, 0x33, 0x86, - 0xb6, 0xa0, 0x4f, 0xa0, 0x43, 0x74, 0x38, 0x18, 0xb4, 0x1b, 0x82, 0x37, 0x23, 0x6d, 0x63, 0x1b, - 0x5c, 0x93, 0xd2, 0x7c, 0x95, 0xd5, 0xa7, 0xf0, 0x21, 0xbc, 0xf0, 0x51, 0xbc, 0xdc, 0xa5, 0x97, - 0xb2, 0xbd, 0x88, 0x24, 0x5d, 0x26, 0xc8, 0xb9, 0xca, 0xf7, 0xfb, 0x9b, 0x8b, 0x1f, 0x9e, 0x7f, - 0x63, 0x40, 0x93, 0x9c, 0x72, 0x11, 0x98, 0x4b, 0x56, 0x2c, 0x90, 0xb1, 0x62, 0xd5, 0x57, 0x56, - 0x5d, 0x0f, 0xbf, 0xac, 0x24, 0x48, 0xf2, 0xf4, 0xea, 0xf5, 0xad, 0xd7, 0xb7, 0x96, 0xf1, 0x30, - 0x93, 0x99, 0x34, 0xbe, 0x40, 0x5f, 0x6d, 0x64, 0x7c, 0x5f, 0x7d, 0xf9, 0x25, 0x0b, 0x0c, 0xa5, - 0x2e, 0x4f, 0xeb, 0x9d, 0xbe, 0xc4, 0xb7, 0xeb, 0x4b, 0x5b, 0xc4, 0x80, 0x3c, 0xc3, 0x77, 0xb6, - 0x7c, 0xb7, 0xe7, 0x0a, 0x46, 0x68, 0xd2, 0x9d, 0xdd, 0x84, 0x8f, 0x2c, 0xb9, 0xe2, 0x0a, 0xa6, - 0x1f, 0xf1, 0x60, 0x45, 0x15, 0xd8, 0xdc, 0x42, 0xd6, 0x02, 0xc8, 0x10, 0x3f, 0x48, 0xf4, 0x31, - 0x42, 0x13, 0x34, 0xeb, 0x85, 0x2d, 0x20, 0xcf, 0x31, 0xd9, 0x53, 0x05, 0xbb, 0x24, 0xa7, 0x22, - 0x63, 0xbb, 0x9c, 0xf1, 0x2c, 0x87, 0x51, 0x67, 0x82, 0x66, 0xdd, 0xd0, 0xd5, 0xca, 0xc2, 0x08, - 0xef, 0x0d, 0x3f, 0xdf, 0xe3, 0x7e, 0x5b, 0x4a, 0x81, 0x4b, 0xb1, 0x69, 0x4a, 0x46, 0x9e, 0xe0, - 0xc1, 0xdb, 0xa2, 0x84, 0xc6, 0x7e, 0xa6, 0x49, 0xd7, 0x21, 0x77, 0xf8, 0x66, 0x29, 0x62, 0x59, - 0x8b, 0x74, 0x73, 0x70, 0x11, 0x79, 0x8c, 0xf1, 0xba, 0x06, 0x8b, 0x3b, 0x5a, 0xde, 0x44, 0xd1, - 0x07, 0xd6, 0xbc, 0x63, 0xc2, 0xed, 0x6a, 0xb9, 0x85, 0x11, 0xcf, 0x84, 0xdb, 0x1b, 0xf7, 0x7e, - 0xfe, 0xf0, 0xd0, 0x7c, 0x85, 0x87, 0xb6, 0x75, 0x5b, 0xa6, 0x14, 0x58, 0xc8, 0xa8, 0x92, 0x42, - 0x87, 0xb7, 0x22, 0x65, 0x9f, 0xb9, 0x60, 0xa9, 0xeb, 0x98, 0xb0, 0x2c, 0x62, 0x05, 0x52, 0x63, - 0x44, 0xfa, 0xf8, 0xf6, 0x75, 0x5a, 0x70, 0xd1, 0x66, 0xdc, 0x4e, 0xdb, 0xf6, 0x66, 0xf9, 0xeb, - 0xe4, 0xa1, 0xe3, 0xc9, 0x43, 0x7f, 0x4e, 0x1e, 0xfa, 0x7e, 0xf6, 0x9c, 0xe3, 0xd9, 0x73, 0x7e, - 0x9f, 0x3d, 0xe7, 0x53, 0x90, 0x71, 0xc8, 0xeb, 0xd8, 0x4f, 0x64, 0x61, 0xf6, 0x78, 0xf1, 0xdf, - 0x34, 0x87, 0x7f, 0xdb, 0x43, 0x53, 0x32, 0x15, 0x3f, 0x34, 0xd3, 0xbc, 0xfa, 0x1b, 0x00, 0x00, - 0xff, 0xff, 0xc7, 0x4c, 0xd1, 0x68, 0x27, 0x02, 0x00, 0x00, + // 367 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x5c, 0x51, 0xcf, 0x8a, 0xda, 0x40, + 0x1c, 0xce, 0xa8, 0x2d, 0x38, 0xd6, 0x1a, 0x07, 0x0b, 0x62, 0x21, 0x88, 0xbd, 0x88, 0xb4, 0x09, + 0xb4, 0x4f, 0xd0, 0x4a, 0x69, 0xa5, 0x82, 0x90, 0x28, 0x85, 0x5e, 0x64, 0x92, 0x4c, 0x93, 0x01, + 0x33, 0x13, 0x32, 0xbf, 0x14, 0xd3, 0xa7, 0xe8, 0x43, 0xf4, 0xb0, 0x8f, 0xb2, 0x47, 0x8f, 0x7b, + 0x5c, 0xf4, 0x45, 0x96, 0x49, 0x76, 0x5c, 0xd8, 0xdb, 0xf7, 0xfd, 0xbe, 0x3f, 0xbf, 0xc3, 0x87, + 0x17, 0x7f, 0x19, 0xd0, 0x28, 0xa5, 0x5c, 0x78, 0x35, 0x92, 0x05, 0xf3, 0x64, 0xa8, 0x58, 0xf1, + 0x87, 0x15, 0x57, 0xe0, 0xe6, 0x85, 0x04, 0x49, 0xde, 0x5e, 0xbd, 0xae, 0xf1, 0xba, 0xc6, 0x32, + 0x19, 0x25, 0x32, 0x91, 0xb5, 0xcf, 0xd3, 0xa8, 0x89, 0xcc, 0x3e, 0xe2, 0xde, 0xe6, 0xd1, 0x11, + 0x30, 0x20, 0xef, 0x70, 0xdf, 0x04, 0xf6, 0x07, 0xae, 0x60, 0x8c, 0xa6, 0xed, 0x79, 0xd7, 0x7f, + 0x65, 0x8e, 0x6b, 0xae, 0x60, 0xf6, 0x13, 0x0f, 0xd7, 0x54, 0x81, 0xc9, 0x2d, 0x65, 0x29, 0x80, + 0x8c, 0xf0, 0x8b, 0x48, 0x83, 0x31, 0x9a, 0xa2, 0x79, 0xc7, 0x6f, 0x08, 0x79, 0x8f, 0xc9, 0x81, + 0x2a, 0xd8, 0x47, 0x29, 0x15, 0x09, 0xdb, 0xa7, 0x8c, 0x27, 0x29, 0x8c, 0x5b, 0x53, 0x34, 0x6f, + 0xfb, 0xb6, 0x56, 0x96, 0xb5, 0xf0, 0xbd, 0xbe, 0x2f, 0x0e, 0x78, 0xd0, 0x94, 0x52, 0xe0, 0x52, + 0x6c, 0xab, 0x9c, 0x91, 0x37, 0x78, 0xf8, 0x35, 0xcb, 0xa1, 0x32, 0xcf, 0xf4, 0xd1, 0xb6, 0x48, + 0x1f, 0x77, 0x57, 0x22, 0x94, 0xa5, 0x88, 0xb7, 0x47, 0x1b, 0x91, 0xd7, 0x18, 0x6f, 0x4a, 0x30, + 0xbc, 0xa5, 0xe5, 0x6d, 0x10, 0xfc, 0x60, 0xd5, 0x37, 0x26, 0xec, 0xb6, 0x96, 0x1b, 0x1a, 0xf0, + 0x44, 0xd8, 0x9d, 0x49, 0xe7, 0xe6, 0xbf, 0x83, 0x16, 0x6b, 0x3c, 0x32, 0xad, 0xbb, 0x3c, 0xa6, + 0xc0, 0x7c, 0x46, 0x95, 0x14, 0x3a, 0xbc, 0x13, 0x31, 0xfb, 0xcd, 0x05, 0x8b, 0x6d, 0xab, 0x0e, + 0xcb, 0x2c, 0x54, 0x20, 0x35, 0x47, 0x64, 0x80, 0x7b, 0x9f, 0xe3, 0x8c, 0x8b, 0x26, 0x63, 0xb7, + 0x9a, 0xb6, 0x2f, 0xab, 0xdb, 0xb3, 0x83, 0x4e, 0x67, 0x07, 0xdd, 0x9f, 0x1d, 0xf4, 0xef, 0xe2, + 0x58, 0xa7, 0x8b, 0x63, 0xdd, 0x5d, 0x1c, 0xeb, 0x97, 0x97, 0x70, 0x48, 0xcb, 0xd0, 0x8d, 0x64, + 0x56, 0x4f, 0xf8, 0xe1, 0xd9, 0x9a, 0xc7, 0xa7, 0x3d, 0xa1, 0xca, 0x99, 0x0a, 0x5f, 0xd6, 0xd3, + 0x7c, 0x7a, 0x08, 0x00, 0x00, 0xff, 0xff, 0x30, 0x6b, 0xf8, 0xf8, 0xfb, 0x01, 0x00, 0x00, } func (m *ObserverSet) Marshal() (dAtA []byte, err error) { diff --git a/x/observer/types/params.pb.go b/x/observer/types/params.pb.go index 0588f7228c..358881c06c 100644 --- a/x/observer/types/params.pb.go +++ b/x/observer/types/params.pb.go @@ -8,7 +8,6 @@ import ( github_com_cosmos_cosmos_sdk_types "github.com/cosmos/cosmos-sdk/types" _ "github.com/cosmos/gogoproto/gogoproto" proto "github.com/cosmos/gogoproto/proto" - _ "github.com/zeta-chain/zetacore/pkg/chains" io "io" math "math" math_bits "math/bits" @@ -260,47 +259,46 @@ func init() { } var fileDescriptor_e7fa4666eddf88e5 = []byte{ - // 626 bytes of a gzipped FileDescriptorProto + // 617 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x94, 0xc1, 0x4e, 0xd4, 0x40, 0x18, 0xc7, 0xb7, 0x2e, 0x22, 0xcc, 0x02, 0x0b, 0x0d, 0x6a, 0x81, 0xa4, 0xac, 0x24, 0x6a, 0x43, 0x42, 0x6b, 0xd0, 0xa3, 0x92, 0xc8, 0x72, 0x21, 0x62, 0x24, 0x05, 0x0f, 0x7a, 0x70, 0x32, 0x3b, - 0x1d, 0xda, 0xc9, 0xb6, 0xfd, 0x9a, 0x99, 0x29, 0x82, 0x4f, 0xe1, 0x3b, 0xf8, 0x32, 0x1c, 0x39, - 0x1a, 0x0f, 0xc4, 0xc0, 0x8b, 0x98, 0x4e, 0xa7, 0xcb, 0x0a, 0x86, 0x83, 0xa7, 0xce, 0x7c, 0xff, - 0xdf, 0xff, 0xbf, 0xdf, 0x6c, 0xbf, 0x0e, 0xf2, 0xbe, 0x31, 0x45, 0x68, 0x42, 0x78, 0x1e, 0xe8, - 0x15, 0x08, 0x16, 0xc0, 0x40, 0x32, 0x71, 0xcc, 0x44, 0x50, 0x10, 0x41, 0x32, 0xe9, 0x17, 0x02, - 0x14, 0xd8, 0x2b, 0x23, 0xd2, 0x6f, 0x48, 0xbf, 0x21, 0x97, 0x17, 0x63, 0x88, 0x41, 0x73, 0x41, - 0xb5, 0xaa, 0x2d, 0xcb, 0xeb, 0x77, 0x85, 0x37, 0x8b, 0x3b, 0xd8, 0x62, 0x18, 0x07, 0xba, 0x24, - 0xcd, 0xa3, 0x66, 0xd7, 0xbe, 0xa0, 0x6e, 0xbf, 0xda, 0xef, 0xeb, 0xfe, 0xf6, 0xb8, 0x54, 0xf6, - 0x3b, 0x34, 0xa3, 0x11, 0x5c, 0xf7, 0xec, 0x58, 0xbd, 0xb6, 0xd7, 0xd9, 0xf4, 0xfc, 0x3b, 0x9a, - 0xf6, 0xc7, 0x32, 0xc2, 0x0e, 0xbd, 0xde, 0xac, 0xfd, 0x98, 0x44, 0x9d, 0x31, 0xd1, 0x5e, 0x42, - 0x53, 0x75, 0x38, 0x8f, 0x9c, 0x4e, 0xcf, 0xf2, 0xda, 0xe1, 0x03, 0xbd, 0xdf, 0x8d, 0xec, 0x0d, - 0x64, 0x53, 0xc8, 0x8f, 0xb8, 0xc8, 0x88, 0xe2, 0x90, 0x63, 0x0a, 0x65, 0xae, 0x1c, 0xab, 0x67, - 0x79, 0x13, 0xe1, 0xc2, 0xb8, 0xd2, 0xaf, 0x04, 0xdb, 0x43, 0xf3, 0x31, 0x91, 0xb8, 0x10, 0x9c, - 0x32, 0xac, 0x38, 0x1d, 0x32, 0xe1, 0xdc, 0xd3, 0xf0, 0x5c, 0x4c, 0xe4, 0x7e, 0x55, 0x3e, 0xd4, - 0x55, 0xfb, 0x29, 0x9a, 0xe3, 0xf9, 0x00, 0xca, 0x3c, 0x6a, 0xb8, 0xb6, 0xe6, 0x66, 0x4d, 0xd5, - 0x60, 0xcf, 0x51, 0x17, 0x4a, 0xf5, 0x17, 0x37, 0x51, 0xe7, 0x35, 0x65, 0x03, 0xae, 0xa3, 0x85, - 0xaf, 0x44, 0xd1, 0x04, 0x97, 0xea, 0x04, 0x1a, 0xf4, 0xbe, 0x46, 0xbb, 0x5a, 0xf8, 0xa8, 0x4e, - 0xc0, 0xb0, 0x6f, 0x90, 0x7e, 0xd9, 0x58, 0xc1, 0x90, 0x55, 0x47, 0xca, 0x95, 0x20, 0x54, 0x61, - 0x12, 0x45, 0x82, 0x49, 0xe9, 0x4c, 0xf5, 0x2c, 0x6f, 0x3a, 0x74, 0x2a, 0xe4, 0xb0, 0x22, 0xfa, - 0x06, 0x78, 0x5b, 0xeb, 0xf6, 0x6b, 0xb4, 0x4c, 0x21, 0xcf, 0x19, 0x55, 0x20, 0x6e, 0xbb, 0xa7, - 0x6b, 0xf7, 0x88, 0xb8, 0xe9, 0xee, 0x23, 0x97, 0x09, 0xba, 0xf9, 0x02, 0xd3, 0x52, 0x2a, 0x88, - 0x4e, 0x6f, 0x27, 0x20, 0x9d, 0xb0, 0xa2, 0xa9, 0x7e, 0x0d, 0xfd, 0xa3, 0x85, 0xd1, 0xdf, 0x22, - 0x69, 0xc2, 0xa2, 0x32, 0x65, 0x98, 0xe7, 0x8a, 0x89, 0x63, 0x92, 0x3a, 0x33, 0xfa, 0x1d, 0x3a, - 0x0d, 0x71, 0x60, 0x80, 0x5d, 0xa3, 0xdb, 0x5b, 0x68, 0xe5, 0xb6, 0x3b, 0x05, 0x18, 0x92, 0x84, - 0x91, 0xc8, 0x99, 0xd5, 0xf6, 0xa5, 0x9b, 0xf6, 0xbd, 0x06, 0xb0, 0x3f, 0xa1, 0xf9, 0x01, 0x49, - 0x53, 0x50, 0x58, 0x25, 0x82, 0xc9, 0x04, 0xd2, 0xc8, 0x99, 0xab, 0x9a, 0xde, 0xf6, 0xcf, 0x2e, - 0x56, 0x5b, 0xbf, 0x2e, 0x56, 0x9f, 0xc5, 0x5c, 0x25, 0xe5, 0xc0, 0xa7, 0x90, 0x05, 0x14, 0x64, - 0x06, 0xd2, 0x3c, 0x36, 0x64, 0x34, 0x0c, 0xd4, 0x69, 0xc1, 0xa4, 0xbf, 0xc3, 0x68, 0xd8, 0xad, - 0x73, 0x0e, 0x9b, 0x18, 0xfb, 0x08, 0x3d, 0xce, 0x78, 0x8e, 0x9b, 0x19, 0xc6, 0x11, 0x4b, 0x59, - 0xac, 0x07, 0xcc, 0xe9, 0xfe, 0xd7, 0x2f, 0x3c, 0xcc, 0x78, 0xfe, 0xc1, 0xa4, 0xed, 0x8c, 0xc2, - 0xec, 0x27, 0x68, 0x86, 0x4b, 0x2c, 0xcb, 0xa2, 0x00, 0xa1, 0x58, 0xe4, 0xcc, 0xf7, 0x2c, 0x6f, - 0x2a, 0xec, 0x70, 0x79, 0xd0, 0x94, 0xd6, 0xb6, 0xd0, 0xa4, 0xf9, 0x3e, 0x5e, 0xa1, 0x47, 0xe6, - 0xbc, 0x19, 0x51, 0xa5, 0xe0, 0xea, 0x14, 0x0f, 0x52, 0xa0, 0x43, 0xa9, 0x67, 0xb6, 0x1d, 0x2e, - 0xd6, 0xea, 0x7b, 0x23, 0x6e, 0x6b, 0x6d, 0x7b, 0xf7, 0xec, 0xd2, 0xb5, 0xce, 0x2f, 0x5d, 0xeb, - 0xf7, 0xa5, 0x6b, 0x7d, 0xbf, 0x72, 0x5b, 0xe7, 0x57, 0x6e, 0xeb, 0xe7, 0x95, 0xdb, 0xfa, 0x1c, - 0x8c, 0xf5, 0x5e, 0x4d, 0xd9, 0xc6, 0x8d, 0x7b, 0xe1, 0xe4, 0xfa, 0x16, 0xd1, 0x07, 0x19, 0x4c, - 0xea, 0x7b, 0xe1, 0xe5, 0x9f, 0x00, 0x00, 0x00, 0xff, 0xff, 0xa1, 0x11, 0xb3, 0xd5, 0xce, 0x04, - 0x00, 0x00, + 0x1d, 0xb6, 0x93, 0x6d, 0xe7, 0xdb, 0xcc, 0x4c, 0x11, 0x7c, 0x0a, 0xdf, 0xc1, 0x97, 0xe1, 0xc8, + 0xd1, 0x78, 0x20, 0x06, 0x5e, 0xc4, 0x74, 0x3a, 0x5d, 0x56, 0x30, 0x1c, 0x3c, 0xed, 0xf4, 0xfb, + 0xff, 0xfe, 0xff, 0x7e, 0xb3, 0xf3, 0x75, 0x50, 0xf0, 0x8d, 0x69, 0x42, 0x53, 0xc2, 0x45, 0x64, + 0x56, 0x20, 0x59, 0x04, 0x3d, 0xc5, 0xe4, 0x31, 0x93, 0xd1, 0x90, 0x48, 0x92, 0xab, 0x70, 0x28, + 0x41, 0x83, 0xbb, 0x32, 0x22, 0xc3, 0x9a, 0x0c, 0x6b, 0x72, 0x79, 0xb1, 0x0f, 0x7d, 0x30, 0x5c, + 0x54, 0xae, 0x2a, 0xcb, 0xf2, 0xfa, 0x5d, 0xe1, 0xf5, 0xa2, 0x62, 0xd7, 0xbe, 0xa0, 0x76, 0xb7, + 0x24, 0xf7, 0xcd, 0x3b, 0xf7, 0xb8, 0xd2, 0xee, 0x3b, 0x34, 0x63, 0xcc, 0xb8, 0xea, 0xc3, 0x73, + 0x3a, 0xcd, 0xa0, 0xb5, 0x19, 0x84, 0x77, 0x34, 0x12, 0x8e, 0x65, 0xc4, 0x2d, 0x7a, 0xfd, 0xb0, + 0xf6, 0x63, 0x12, 0xb5, 0xc6, 0x44, 0x77, 0x09, 0x4d, 0x55, 0xe1, 0x3c, 0xf1, 0x5a, 0x1d, 0x27, + 0x68, 0xc6, 0x0f, 0xcc, 0xf3, 0x6e, 0xe2, 0x6e, 0x20, 0x97, 0x82, 0x38, 0xe2, 0x32, 0x27, 0x9a, + 0x83, 0xc0, 0x14, 0x0a, 0xa1, 0x3d, 0xa7, 0xe3, 0x04, 0x13, 0xf1, 0xc2, 0xb8, 0xd2, 0x2d, 0x05, + 0x37, 0x40, 0xf3, 0x7d, 0xa2, 0xf0, 0x50, 0x72, 0xca, 0xb0, 0xe6, 0x74, 0xc0, 0xa4, 0x77, 0xcf, + 0xc0, 0x73, 0x7d, 0xa2, 0xf6, 0xcb, 0xf2, 0xa1, 0xa9, 0xba, 0x4f, 0xd1, 0x1c, 0x17, 0x3d, 0x28, + 0x44, 0x52, 0x73, 0x4d, 0xc3, 0xcd, 0xda, 0xaa, 0xc5, 0x9e, 0xa3, 0x36, 0x14, 0xfa, 0x2f, 0x6e, + 0xa2, 0xca, 0xab, 0xcb, 0x16, 0x5c, 0x47, 0x0b, 0x5f, 0x89, 0xa6, 0x29, 0x2e, 0xf4, 0x09, 0xd4, + 0xe8, 0x7d, 0x83, 0xb6, 0x8d, 0xf0, 0x51, 0x9f, 0x80, 0x65, 0xdf, 0x20, 0x73, 0x80, 0x58, 0xc3, + 0x80, 0x95, 0x5b, 0x12, 0x5a, 0x12, 0xaa, 0x31, 0x49, 0x12, 0xc9, 0x94, 0xf2, 0xa6, 0x3a, 0x4e, + 0x30, 0x1d, 0x7b, 0x25, 0x72, 0x58, 0x12, 0x5d, 0x0b, 0xbc, 0xad, 0x74, 0xf7, 0x35, 0x5a, 0xa6, + 0x20, 0x04, 0xa3, 0x1a, 0xe4, 0x6d, 0xf7, 0x74, 0xe5, 0x1e, 0x11, 0x37, 0xdd, 0x5d, 0xe4, 0x33, + 0x49, 0x37, 0x5f, 0x60, 0x5a, 0x28, 0x0d, 0xc9, 0xe9, 0xed, 0x04, 0x64, 0x12, 0x56, 0x0c, 0xd5, + 0xad, 0xa0, 0x7f, 0xb4, 0x30, 0xfa, 0x5b, 0x14, 0x4d, 0x59, 0x52, 0x64, 0x0c, 0x73, 0xa1, 0x99, + 0x3c, 0x26, 0x99, 0x37, 0x63, 0xce, 0xd0, 0xab, 0x89, 0x03, 0x0b, 0xec, 0x5a, 0xdd, 0xdd, 0x42, + 0x2b, 0xb7, 0xdd, 0x19, 0xc0, 0x80, 0xa4, 0x8c, 0x24, 0xde, 0xac, 0xb1, 0x2f, 0xdd, 0xb4, 0xef, + 0xd5, 0x80, 0xfb, 0x09, 0xcd, 0xf7, 0x48, 0x96, 0x81, 0xc6, 0x3a, 0x95, 0x4c, 0xa5, 0x90, 0x25, + 0xde, 0x5c, 0xd9, 0xf4, 0x76, 0x78, 0x76, 0xb1, 0xda, 0xf8, 0x75, 0xb1, 0xfa, 0xac, 0xcf, 0x75, + 0x5a, 0xf4, 0x42, 0x0a, 0x79, 0x44, 0x41, 0xe5, 0xa0, 0xec, 0xcf, 0x86, 0x4a, 0x06, 0x91, 0x3e, + 0x1d, 0x32, 0x15, 0xee, 0x30, 0x1a, 0xb7, 0xab, 0x9c, 0xc3, 0x3a, 0xc6, 0x3d, 0x42, 0x8f, 0x73, + 0x2e, 0x70, 0x3d, 0xc3, 0x38, 0x61, 0x19, 0xeb, 0x9b, 0x01, 0xf3, 0xda, 0xff, 0xf5, 0x86, 0x87, + 0x39, 0x17, 0x1f, 0x6c, 0xda, 0xce, 0x28, 0xcc, 0x7d, 0x82, 0x66, 0xb8, 0xc2, 0xaa, 0x18, 0x0e, + 0x41, 0x6a, 0x96, 0x78, 0xf3, 0x1d, 0x27, 0x98, 0x8a, 0x5b, 0x5c, 0x1d, 0xd4, 0xa5, 0xb5, 0x2d, + 0x34, 0x69, 0xbf, 0x8f, 0x57, 0xe8, 0x91, 0xdd, 0x6f, 0x4e, 0x74, 0x21, 0xb9, 0x3e, 0xc5, 0xbd, + 0x0c, 0xe8, 0x40, 0x99, 0x99, 0x6d, 0xc6, 0x8b, 0x95, 0xfa, 0xde, 0x8a, 0xdb, 0x46, 0xdb, 0xde, + 0x3d, 0xbb, 0xf4, 0x9d, 0xf3, 0x4b, 0xdf, 0xf9, 0x7d, 0xe9, 0x3b, 0xdf, 0xaf, 0xfc, 0xc6, 0xf9, + 0x95, 0xdf, 0xf8, 0x79, 0xe5, 0x37, 0x3e, 0x47, 0x63, 0xbd, 0x97, 0x53, 0xb6, 0x71, 0xe3, 0x5e, + 0x38, 0xb9, 0xbe, 0x19, 0xcc, 0x46, 0x7a, 0x93, 0xe6, 0x5e, 0x78, 0xf9, 0x27, 0x00, 0x00, 0xff, + 0xff, 0xed, 0x67, 0xea, 0xcb, 0xa2, 0x04, 0x00, 0x00, } func (m *ChainParamsList) Marshal() (dAtA []byte, err error) { diff --git a/x/observer/types/query.pb.go b/x/observer/types/query.pb.go index 38d676df2b..6efedd0393 100644 --- a/x/observer/types/query.pb.go +++ b/x/observer/types/query.pb.go @@ -1329,7 +1329,7 @@ func (m *QuerySupportedChains) XXX_DiscardUnknown() { var xxx_messageInfo_QuerySupportedChains proto.InternalMessageInfo type QuerySupportedChainsResponse struct { - Chains []*chains.Chain `protobuf:"bytes,1,rep,name=chains,proto3" json:"chains,omitempty"` + Chains []chains.Chain `protobuf:"bytes,1,rep,name=chains,proto3" json:"chains"` } func (m *QuerySupportedChainsResponse) Reset() { *m = QuerySupportedChainsResponse{} } @@ -1365,7 +1365,7 @@ func (m *QuerySupportedChainsResponse) XXX_DiscardUnknown() { var xxx_messageInfo_QuerySupportedChainsResponse proto.InternalMessageInfo -func (m *QuerySupportedChainsResponse) GetChains() []*chains.Chain { +func (m *QuerySupportedChainsResponse) GetChains() []chains.Chain { if m != nil { return m.Chains } @@ -2301,150 +2301,150 @@ func init() { } var fileDescriptor_25b2aa420449a0c0 = []byte{ - // 2284 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x5a, 0xcf, 0x6f, 0x1b, 0xc7, - 0x15, 0xf6, 0x4a, 0x89, 0x22, 0x8d, 0x6c, 0xfd, 0x18, 0xcb, 0xb6, 0x42, 0x3b, 0xb2, 0x3c, 0x92, - 0x63, 0x59, 0x91, 0xb9, 0xb6, 0xec, 0xd4, 0xbf, 0x63, 0x8b, 0x6e, 0x24, 0xd9, 0x49, 0x6c, 0x87, - 0x74, 0x1b, 0xc0, 0x48, 0xcb, 0x2e, 0xc9, 0x21, 0xb9, 0xf5, 0x6a, 0x87, 0xd9, 0x19, 0x39, 0x61, - 0x54, 0x01, 0x45, 0x6f, 0xcd, 0xa1, 0x28, 0x50, 0xa0, 0xbd, 0x15, 0xb9, 0xf4, 0x58, 0xa0, 0x08, - 0x50, 0xb4, 0x40, 0xd1, 0x43, 0x4e, 0xcd, 0xa1, 0x87, 0x14, 0x2d, 0x8a, 0x9e, 0xda, 0xc0, 0xee, - 0x1f, 0x52, 0xec, 0xcc, 0x5b, 0x72, 0x77, 0xb9, 0xbb, 0x1c, 0xca, 0xea, 0x89, 0xdc, 0xd9, 0x79, - 0x6f, 0xbe, 0xef, 0xed, 0xcc, 0x7b, 0xdf, 0xce, 0x2c, 0x3a, 0xf3, 0x29, 0x15, 0x56, 0xb5, 0x69, - 0xd9, 0xae, 0x29, 0xff, 0x31, 0x8f, 0x9a, 0xac, 0xc2, 0xa9, 0xf7, 0x94, 0x7a, 0xe6, 0x47, 0xdb, - 0xd4, 0x6b, 0xe7, 0x5b, 0x1e, 0x13, 0x0c, 0x1f, 0xef, 0x74, 0xcc, 0x07, 0x1d, 0xf3, 0x41, 0xc7, - 0xdc, 0x72, 0x95, 0xf1, 0x2d, 0xc6, 0xcd, 0x8a, 0xc5, 0xa9, 0xb2, 0x32, 0x9f, 0x5e, 0xa8, 0x50, - 0x61, 0x5d, 0x30, 0x5b, 0x56, 0xc3, 0x76, 0x2d, 0x61, 0x33, 0x57, 0x39, 0xca, 0xcd, 0x34, 0x58, - 0x83, 0xc9, 0xbf, 0xa6, 0xff, 0x0f, 0x5a, 0x4f, 0x34, 0x18, 0x6b, 0x38, 0xd4, 0xb4, 0x5a, 0xb6, - 0x69, 0xb9, 0x2e, 0x13, 0xd2, 0x84, 0xc3, 0xdd, 0xa5, 0x2c, 0x94, 0x15, 0xcb, 0x71, 0x98, 0x80, - 0x9e, 0x99, 0x7c, 0x2a, 0x8e, 0xb5, 0x45, 0xa1, 0x63, 0x3e, 0xab, 0xa3, 0x6c, 0x2f, 0xbb, 0xcc, - 0xad, 0xd2, 0x00, 0xc2, 0x6a, 0x66, 0x7f, 0x8f, 0x71, 0xae, 0x8c, 0xea, 0x8e, 0xd5, 0xd0, 0x82, - 0xfd, 0x84, 0xb6, 0x1b, 0xd4, 0xd5, 0x41, 0xe3, 0xb2, 0x1a, 0x2d, 0x5b, 0xd5, 0x2a, 0xdb, 0x76, - 0x03, 0x9a, 0xcb, 0x59, 0xfd, 0x83, 0x3f, 0x3a, 0x28, 0x5a, 0x96, 0x67, 0x6d, 0x05, 0x78, 0xcf, - 0x67, 0xf6, 0xa4, 0x6e, 0xcd, 0x76, 0x1b, 0xd1, 0xa8, 0x9c, 0xce, 0xb2, 0x10, 0x9c, 0x67, 0xc0, - 0x6d, 0x3d, 0x69, 0xa8, 0x38, 0x73, 0xf8, 0xe9, 0xd3, 0xb7, 0xe5, 0x31, 0x56, 0xe7, 0xf0, 0x03, - 0x7d, 0x2f, 0xf5, 0x19, 0xbe, 0x5c, 0xdf, 0x76, 0x6b, 0xbc, 0xbc, 0x65, 0x37, 0x3c, 0x4b, 0x30, - 0x08, 0x08, 0x39, 0x8d, 0x16, 0xde, 0xf7, 0xe7, 0xe8, 0x23, 0xce, 0xd7, 0xfd, 0xfb, 0xef, 0xc1, - 0xed, 0xbb, 0x6e, 0x9d, 0xad, 0x39, 0x4e, 0x91, 0x7e, 0xb4, 0x4d, 0xb9, 0x20, 0x3f, 0x33, 0xd0, - 0x62, 0x76, 0x3f, 0xde, 0x62, 0x2e, 0xa7, 0xb8, 0x8e, 0x0e, 0xf7, 0x8e, 0xc5, 0x67, 0x8d, 0xf9, - 0xe1, 0xa5, 0xf1, 0xd5, 0xf3, 0xf9, 0x8c, 0x85, 0x93, 0x07, 0xd7, 0x61, 0xcf, 0x85, 0x97, 0xbe, - 0xfa, 0xf7, 0xc9, 0x03, 0xc5, 0x69, 0x11, 0x1b, 0x95, 0x93, 0x9b, 0x68, 0x3e, 0x15, 0x0f, 0x80, - 0xc6, 0xaf, 0xa2, 0x51, 0x35, 0x0f, 0xed, 0xda, 0xac, 0x31, 0x6f, 0x2c, 0x0d, 0x17, 0x5f, 0x91, - 0xd7, 0x77, 0x6b, 0xe4, 0xa7, 0x06, 0x3a, 0x95, 0x61, 0x0f, 0x64, 0x6a, 0x08, 0xf7, 0x92, 0x91, - 0xae, 0xf6, 0xce, 0x65, 0x2a, 0xce, 0x85, 0xac, 0xa2, 0x9c, 0x84, 0xb2, 0x41, 0xc5, 0x1d, 0xdf, - 0xdd, 0x7d, 0x39, 0xa9, 0x02, 0x12, 0x33, 0xe8, 0x65, 0xdb, 0xad, 0xd1, 0x4f, 0xe4, 0xb0, 0x63, - 0x45, 0x75, 0x41, 0x18, 0x3a, 0x9e, 0x68, 0x03, 0xc0, 0x1f, 0xa2, 0xf1, 0x50, 0x33, 0x20, 0x5e, - 0xca, 0x44, 0x1c, 0xea, 0x0f, 0x48, 0xc3, 0x2e, 0x48, 0x0d, 0x40, 0xae, 0x39, 0x4e, 0x02, 0xc8, - 0x75, 0x84, 0xba, 0xb9, 0x0d, 0x86, 0x7b, 0x3d, 0xaf, 0x12, 0x61, 0xde, 0x4f, 0x84, 0x79, 0x95, - 0x3e, 0x21, 0x11, 0xe6, 0x1f, 0x5a, 0x0d, 0x0a, 0xb6, 0xc5, 0x90, 0x25, 0xf9, 0xa3, 0x01, 0xbc, - 0xe2, 0xc3, 0xa4, 0xf1, 0x1a, 0x7e, 0x41, 0x5e, 0x78, 0x23, 0x82, 0x7c, 0x48, 0x22, 0x3f, 0xd3, - 0x17, 0xb9, 0x82, 0x13, 0x81, 0x5e, 0x47, 0x27, 0x02, 0xe4, 0x0f, 0x55, 0x76, 0xf8, 0xff, 0x84, - 0xe8, 0x4b, 0x03, 0xbd, 0x96, 0x32, 0x10, 0x04, 0xe9, 0x03, 0x34, 0x11, 0xcd, 0x4f, 0x10, 0xa7, - 0xe5, 0xcc, 0x38, 0x45, 0x7c, 0x41, 0xa4, 0x0e, 0xb5, 0xc2, 0x8d, 0xfb, 0x17, 0xab, 0x60, 0xf1, - 0x46, 0xc7, 0x6c, 0xcb, 0xe7, 0xa2, 0xb1, 0x78, 0x7f, 0x04, 0x6b, 0x37, 0xd9, 0x3c, 0x23, 0x0a, - 0xc6, 0x3e, 0x44, 0x81, 0xcc, 0x20, 0x1c, 0x2c, 0xbd, 0x47, 0xa5, 0x52, 0x90, 0x20, 0x1f, 0xa0, - 0xc3, 0x91, 0x56, 0x40, 0x71, 0x05, 0x0d, 0x3f, 0x2a, 0x95, 0x60, 0xe8, 0xf9, 0xec, 0x94, 0x51, - 0x2a, 0xc1, 0x80, 0xbe, 0x09, 0x79, 0x1b, 0xbd, 0xda, 0x71, 0xc8, 0xf9, 0x5a, 0xad, 0xe6, 0x51, - 0xde, 0x99, 0x4c, 0x4b, 0x68, 0xaa, 0x62, 0x8b, 0x2a, 0xb3, 0xdd, 0x72, 0x27, 0x48, 0x43, 0x32, - 0x48, 0x13, 0xd0, 0x7e, 0x07, 0x62, 0x75, 0xbb, 0x9b, 0x5c, 0xc2, 0x6e, 0x00, 0xde, 0x14, 0x1a, - 0xa6, 0xa2, 0x09, 0xa9, 0xc5, 0xff, 0xeb, 0xb7, 0x54, 0x44, 0x55, 0x3a, 0x1b, 0x2b, 0xfa, 0x7f, - 0xc9, 0x67, 0x06, 0x5a, 0xee, 0x75, 0x51, 0x68, 0xaf, 0xdb, 0xae, 0xe5, 0xd8, 0x9f, 0xd2, 0xda, - 0x26, 0xb5, 0x1b, 0x4d, 0x11, 0x40, 0x5b, 0x45, 0x47, 0xea, 0xc1, 0x9d, 0xb2, 0xcf, 0xb2, 0xdc, - 0x94, 0xf7, 0xe1, 0x21, 0x1e, 0xee, 0xdc, 0x7c, 0x4c, 0x85, 0xa5, 0x4c, 0x07, 0xa0, 0xf3, 0x3e, - 0x7a, 0x43, 0x0b, 0xcb, 0x00, 0xfc, 0x7e, 0x80, 0x8e, 0x06, 0x95, 0x60, 0xd3, 0xe6, 0x82, 0x79, - 0xed, 0xfd, 0x5e, 0xb2, 0xbf, 0x31, 0xd0, 0xb1, 0x9e, 0x21, 0x00, 0xe1, 0x1a, 0x1a, 0xf5, 0x4b, - 0x8c, 0x63, 0x73, 0x01, 0xcb, 0x54, 0x77, 0x96, 0xbc, 0x22, 0x38, 0x7f, 0xd7, 0xe6, 0x62, 0xff, - 0x96, 0x65, 0x13, 0xcd, 0x48, 0x98, 0x9b, 0x16, 0xff, 0x2e, 0x13, 0xb4, 0x16, 0xc4, 0xe1, 0x0d, - 0x34, 0xad, 0x74, 0x65, 0xd9, 0xae, 0x51, 0x57, 0xd8, 0x75, 0x9b, 0x7a, 0x10, 0xd3, 0x29, 0x75, - 0xe3, 0x6e, 0xa7, 0x1d, 0x2f, 0xa0, 0x43, 0x4f, 0x99, 0xa0, 0x5e, 0xd9, 0x52, 0x0f, 0x07, 0x42, - 0x7d, 0x50, 0x36, 0xc2, 0x03, 0x23, 0x97, 0xd0, 0x91, 0xd8, 0x48, 0x10, 0x8e, 0xe3, 0x68, 0xac, - 0x69, 0xf1, 0xb2, 0xdf, 0x59, 0x2d, 0xfb, 0xd1, 0xe2, 0x68, 0x13, 0x3a, 0x91, 0xf7, 0xd0, 0x9c, - 0xb4, 0x2a, 0xc8, 0x31, 0x0b, 0xed, 0xee, 0xa8, 0x7b, 0x41, 0x4a, 0x04, 0x1a, 0xf3, 0xfd, 0x7a, - 0x32, 0x88, 0x3d, 0xb0, 0x8d, 0x5e, 0xd8, 0xb8, 0x80, 0xc6, 0xfc, 0xeb, 0xb2, 0x68, 0xb7, 0xa8, - 0xe4, 0x35, 0xb1, 0x7a, 0x3a, 0xf3, 0x69, 0xf9, 0xfe, 0x1f, 0xb5, 0x5b, 0xb4, 0x38, 0xfa, 0x14, - 0xfe, 0x91, 0x3f, 0x0c, 0xa1, 0x93, 0xa9, 0x2c, 0x20, 0x0a, 0x03, 0x05, 0xfc, 0x2d, 0x34, 0x22, - 0x41, 0xfa, 0x91, 0x1e, 0x96, 0x33, 0xb4, 0x1f, 0x22, 0xc9, 0xb8, 0x08, 0x56, 0xf8, 0x03, 0x34, - 0xa5, 0xee, 0xca, 0x49, 0xa0, 0xb8, 0x0d, 0x4b, 0x6e, 0x2b, 0x99, 0x9e, 0x1e, 0x74, 0x8d, 0x24, - 0xc5, 0x49, 0x16, 0x6d, 0xc0, 0xf7, 0xd1, 0x21, 0x60, 0xc1, 0x85, 0x25, 0xb6, 0xf9, 0xec, 0x4b, - 0xd2, 0xeb, 0xd9, 0x4c, 0xaf, 0x2a, 0x2a, 0x25, 0x69, 0x50, 0x3c, 0x58, 0x09, 0x5d, 0x11, 0x8c, - 0xa6, 0x64, 0xe0, 0x1e, 0x40, 0xdf, 0x12, 0x15, 0xe4, 0x0a, 0x9a, 0x8d, 0xb7, 0x75, 0xa2, 0x78, - 0x02, 0x8d, 0x05, 0x6e, 0x55, 0x09, 0x1c, 0x2b, 0x76, 0x1b, 0xc8, 0x51, 0x98, 0xec, 0xa5, 0xed, - 0x56, 0x8b, 0x79, 0x82, 0xd6, 0x64, 0x8a, 0xe1, 0xe4, 0x43, 0xa8, 0xe3, 0xb1, 0xf6, 0x8e, 0xd7, - 0x1b, 0x68, 0x44, 0x49, 0x74, 0x58, 0xae, 0x8b, 0x49, 0x74, 0x5a, 0x4f, 0x1a, 0x79, 0x10, 0xf2, - 0xaa, 0x2a, 0x81, 0x0d, 0xb9, 0x85, 0x48, 0x44, 0xb7, 0x3d, 0x94, 0xaf, 0x1c, 0xeb, 0xcc, 0xd3, - 0xad, 0x7d, 0x1e, 0xe8, 0xf5, 0x34, 0x07, 0x80, 0xf2, 0x1d, 0x74, 0x50, 0x79, 0x50, 0xef, 0x34, - 0xfa, 0x0a, 0x50, 0xf9, 0x2b, 0x8e, 0x57, 0xbb, 0x17, 0xe4, 0x44, 0x4c, 0xa0, 0x42, 0x1f, 0xa8, - 0x7c, 0x6e, 0x4c, 0x8a, 0x06, 0x77, 0x01, 0xc9, 0x83, 0x44, 0x24, 0x2b, 0xba, 0x48, 0xe4, 0x54, - 0x8d, 0xa0, 0x09, 0xc9, 0xe5, 0xfb, 0xac, 0x46, 0xd7, 0xd4, 0xbb, 0x60, 0xb6, 0x5c, 0xfe, 0x61, - 0x17, 0x63, 0xc4, 0xa6, 0x1b, 0xad, 0xf0, 0x7b, 0xa5, 0x56, 0xb4, 0xc2, 0x7e, 0xc6, 0xdd, 0xee, - 0x45, 0x58, 0x29, 0x27, 0xe0, 0xdb, 0xaf, 0x9a, 0xf2, 0x45, 0x48, 0x29, 0x27, 0x51, 0xba, 0x87, - 0xc6, 0x43, 0xcd, 0x5a, 0x4a, 0x39, 0xc2, 0x28, 0x74, 0xb1, 0x7f, 0x05, 0x66, 0x1e, 0x12, 0xb8, - 0x3f, 0x55, 0x3a, 0xbb, 0x04, 0xeb, 0x8e, 0xd5, 0xe8, 0x4c, 0xa6, 0x1f, 0x1b, 0x90, 0x1d, 0x93, - 0xba, 0x00, 0xb5, 0xef, 0xa1, 0xa9, 0xf8, 0x1e, 0x83, 0xde, 0xac, 0x8a, 0xfa, 0x83, 0x32, 0x3a, - 0x59, 0x8d, 0x36, 0x93, 0x63, 0x50, 0x9b, 0x36, 0xa8, 0x78, 0x47, 0x6e, 0x4b, 0x04, 0xd8, 0xbe, - 0x03, 0x42, 0x21, 0x74, 0x03, 0x10, 0x5d, 0x47, 0x23, 0x6a, 0x07, 0x03, 0x70, 0x2c, 0x64, 0xe2, - 0x00, 0x63, 0x30, 0x21, 0x27, 0x41, 0xcf, 0x97, 0x9a, 0xec, 0xe3, 0x20, 0x8d, 0xdd, 0x09, 0x4d, - 0x19, 0x3f, 0x26, 0x73, 0x69, 0x3d, 0x00, 0xc0, 0xf7, 0xd1, 0x61, 0xc7, 0xe2, 0xa2, 0x1c, 0x8c, - 0x51, 0x0e, 0xcf, 0xe3, 0x7c, 0x26, 0x9a, 0x77, 0x2d, 0x2e, 0xa2, 0x4e, 0xa7, 0x9d, 0x78, 0x13, - 0xb9, 0x07, 0x18, 0x0b, 0x8e, 0xb5, 0x45, 0x93, 0x0a, 0xef, 0x59, 0x34, 0x25, 0x37, 0x94, 0x7a, - 0x0b, 0xd6, 0xa4, 0x6c, 0x0f, 0x95, 0xdd, 0x6a, 0x50, 0xc5, 0x7b, 0x7d, 0x75, 0x34, 0x11, 0x02, - 0x67, 0x6e, 0x9d, 0x01, 0x09, 0x92, 0x5d, 0x35, 0xfc, 0xee, 0xc5, 0x31, 0x35, 0x94, 0x5b, 0x67, - 0x84, 0x76, 0x57, 0x87, 0xba, 0x47, 0xab, 0xcc, 0xab, 0xed, 0xfb, 0xcb, 0xd8, 0xef, 0x8c, 0xee, - 0x5b, 0x5f, 0x74, 0x1c, 0xa0, 0xb2, 0x11, 0xa3, 0x32, 0xac, 0x47, 0x05, 0xe6, 0x66, 0x97, 0xd0, - 0xfe, 0xad, 0xc1, 0x12, 0xbc, 0x7b, 0x41, 0xf8, 0x65, 0xaa, 0x5d, 0x73, 0x6b, 0xf2, 0xe5, 0xa6, - 0x7f, 0xfd, 0xf1, 0xf3, 0xab, 0x7c, 0x9d, 0x02, 0x7d, 0xae, 0x2e, 0x48, 0x1d, 0xde, 0xc8, 0x92, - 0x9d, 0xa6, 0x3c, 0xd6, 0xe1, 0x81, 0x1f, 0xeb, 0xea, 0xe7, 0x8b, 0xe8, 0x65, 0x39, 0x10, 0xfe, - 0xb3, 0x81, 0x46, 0x03, 0xf5, 0x88, 0x2f, 0x64, 0x7a, 0x49, 0xd2, 0xb4, 0xb9, 0xd5, 0x41, 0x4c, - 0x14, 0x01, 0x72, 0xef, 0x27, 0x7f, 0xff, 0xef, 0x2f, 0x86, 0xbe, 0x8d, 0x0b, 0x72, 0x83, 0xed, - 0x9c, 0xda, 0x6b, 0xeb, 0x6c, 0xb1, 0x75, 0x74, 0xab, 0xb9, 0xd3, 0x23, 0xde, 0x76, 0xcd, 0x9d, - 0x88, 0xba, 0xdc, 0xc5, 0xff, 0x34, 0x10, 0xee, 0x55, 0x80, 0xf8, 0x7a, 0x7f, 0x58, 0xa9, 0xea, - 0x37, 0x77, 0x63, 0x6f, 0xc6, 0xc0, 0xee, 0x6d, 0xc9, 0xee, 0x16, 0xbe, 0x99, 0xc8, 0x0e, 0x28, - 0x55, 0xda, 0x21, 0x56, 0x49, 0x44, 0xf1, 0xaf, 0x0d, 0x34, 0x1e, 0x52, 0x63, 0xf8, 0x5c, 0x7f, - 0x50, 0xa1, 0xee, 0xb9, 0x37, 0x07, 0xea, 0xde, 0x01, 0x7f, 0x56, 0x82, 0x5f, 0xc0, 0xa7, 0x12, - 0xc1, 0x77, 0xd2, 0x22, 0xa7, 0x02, 0xff, 0xd6, 0x40, 0x93, 0x31, 0x71, 0xa7, 0x33, 0x81, 0x62, - 0x26, 0xb9, 0xab, 0x03, 0x9b, 0x74, 0xc0, 0xae, 0x48, 0xb0, 0xaf, 0xe3, 0xc5, 0x44, 0xb0, 0x3c, - 0x86, 0xed, 0x3f, 0x06, 0x3a, 0x9a, 0xac, 0xf6, 0xf0, 0xad, 0xfe, 0x18, 0x32, 0x85, 0x66, 0xee, - 0xf6, 0xde, 0x1d, 0x00, 0x97, 0x82, 0xe4, 0x72, 0x03, 0x5f, 0x4b, 0xe4, 0xd2, 0xa0, 0xa2, 0x1c, - 0x56, 0x7f, 0xe5, 0x3a, 0xf3, 0x54, 0x83, 0xb9, 0x13, 0x64, 0x98, 0x5d, 0xfc, 0x85, 0x81, 0x26, - 0xa2, 0xc3, 0xe0, 0xcb, 0x83, 0x02, 0x0b, 0x18, 0x5d, 0x19, 0xdc, 0x10, 0x98, 0x9c, 0x93, 0x4c, - 0xce, 0xe0, 0xd3, 0x5a, 0x4c, 0x7c, 0xd0, 0x11, 0x91, 0xa4, 0x87, 0xb8, 0x57, 0x11, 0x6a, 0x22, - 0x4e, 0xd0, 0x78, 0xe4, 0xbc, 0x44, 0xbc, 0x8c, 0x97, 0x12, 0x11, 0x87, 0x34, 0xa9, 0xb9, 0x23, - 0x65, 0xf0, 0xae, 0x3f, 0xf7, 0x27, 0x42, 0x9e, 0xd6, 0x1c, 0x47, 0x07, 0x77, 0xa2, 0x92, 0xd5, - 0xc1, 0x9d, 0xac, 0x4d, 0xc9, 0x92, 0xc4, 0x4d, 0xf0, 0x7c, 0x3f, 0xdc, 0xf8, 0x4f, 0x06, 0x9a, - 0x8c, 0xc9, 0x36, 0x9d, 0x14, 0x99, 0xaa, 0x2f, 0x75, 0x52, 0x64, 0xba, 0xf2, 0xec, 0x33, 0x45, - 0xe2, 0xa2, 0x14, 0xff, 0xd2, 0x40, 0x23, 0x4a, 0xec, 0xe1, 0x55, 0xad, 0x71, 0x23, 0x7a, 0x33, - 0x77, 0x71, 0x20, 0x1b, 0x80, 0xb8, 0x20, 0x21, 0xbe, 0x86, 0x8f, 0x27, 0x42, 0x54, 0x92, 0x13, - 0xff, 0xc5, 0x40, 0xd3, 0x3d, 0x62, 0x12, 0x5f, 0xd3, 0xc8, 0x68, 0x29, 0x1a, 0x35, 0x77, 0x7d, - 0x4f, 0xb6, 0x80, 0xf9, 0xaa, 0xc4, 0x7c, 0x11, 0x5f, 0x08, 0x63, 0xee, 0x3d, 0xc3, 0xe2, 0x4d, - 0xf6, 0x71, 0x4c, 0xe1, 0xe2, 0xbf, 0x19, 0x68, 0xba, 0x47, 0x48, 0xea, 0x30, 0x49, 0x53, 0xb2, - 0x3a, 0x4c, 0x52, 0x95, 0x2b, 0xb9, 0x23, 0x99, 0xdc, 0xc4, 0xd7, 0x93, 0x6b, 0xa8, 0x54, 0x3f, - 0xf1, 0x12, 0x1a, 0x93, 0xcd, 0xbb, 0xbe, 0xb4, 0xc1, 0x1b, 0x54, 0xc4, 0x24, 0x25, 0xd6, 0x5b, - 0x6f, 0x09, 0x6a, 0x57, 0xa7, 0x54, 0xa5, 0xe8, 0x57, 0xb2, 0x2a, 0x09, 0xad, 0xe0, 0xe5, 0xd4, - 0xa4, 0x68, 0x39, 0x4e, 0x59, 0x71, 0xf0, 0x00, 0xe8, 0x37, 0x06, 0x3a, 0x22, 0x9d, 0xf1, 0x98, - 0x12, 0xc4, 0x37, 0xb5, 0x63, 0x9b, 0x24, 0x4b, 0x73, 0x6f, 0xed, 0xd5, 0x1c, 0xc8, 0x6c, 0x4a, - 0x32, 0x05, 0x7c, 0x3b, 0xfb, 0xe9, 0xa8, 0x25, 0x6c, 0xb9, 0x35, 0x75, 0x70, 0x10, 0xaa, 0x54, - 0xe6, 0x8e, 0x6c, 0xd9, 0xc5, 0x5f, 0x1a, 0xe8, 0x50, 0x64, 0x0b, 0x1a, 0x7f, 0x4b, 0x6b, 0xb1, - 0xf6, 0xec, 0xe4, 0xe7, 0x2e, 0x0f, 0x6c, 0x07, 0x64, 0x6e, 0x49, 0x32, 0x57, 0xf1, 0xe5, 0xd4, - 0x27, 0x23, 0x38, 0x0f, 0xf4, 0xa6, 0xb9, 0x13, 0xdf, 0x5f, 0xdf, 0xc5, 0xbf, 0x1a, 0x42, 0x73, - 0xd9, 0xdb, 0xe8, 0x78, 0x63, 0x40, 0x70, 0x69, 0x87, 0x02, 0xb9, 0xcd, 0x17, 0x77, 0x04, 0xb4, - 0x2b, 0x92, 0xf6, 0x87, 0xf8, 0xb1, 0x0e, 0xed, 0x72, 0x53, 0xee, 0xb6, 0xdb, 0x55, 0xcb, 0x31, - 0x77, 0x12, 0x4f, 0x25, 0x76, 0x93, 0x22, 0xf3, 0x99, 0x21, 0x4f, 0x6d, 0xb0, 0xa9, 0x87, 0xba, - 0x73, 0x08, 0x94, 0x3b, 0xaf, 0x6f, 0x00, 0x74, 0xe6, 0x25, 0x9d, 0x1c, 0x9e, 0x4d, 0xa4, 0xe3, - 0x83, 0xf8, 0xdc, 0x40, 0xa8, 0x7b, 0x6e, 0x80, 0x35, 0x8a, 0x42, 0xcf, 0x41, 0x46, 0xee, 0xd2, - 0x60, 0x46, 0x80, 0xed, 0x8c, 0xc4, 0x76, 0x0a, 0x9f, 0x4c, 0xc4, 0x26, 0xba, 0x98, 0x7e, 0x6f, - 0xa0, 0xa9, 0xc8, 0xc1, 0x99, 0xaf, 0x2b, 0xf4, 0x92, 0x4e, 0xd2, 0x51, 0x69, 0xee, 0xda, 0x5e, - 0x4c, 0x01, 0xf4, 0xb2, 0x04, 0xbd, 0x88, 0x49, 0x22, 0xe8, 0xe8, 0x79, 0xe6, 0x5f, 0x0d, 0x34, - 0x93, 0x74, 0x86, 0xa8, 0x93, 0xa7, 0x32, 0x8e, 0x2e, 0x75, 0xf2, 0x54, 0xd6, 0xd1, 0x25, 0x79, - 0x53, 0x72, 0x30, 0xf1, 0xb9, 0xfe, 0x1c, 0x62, 0x32, 0x3a, 0x72, 0xb4, 0x3d, 0x80, 0x86, 0x8e, - 0xc6, 0xff, 0xca, 0xe0, 0x86, 0x5a, 0x8a, 0xb4, 0xda, 0xb5, 0x88, 0x28, 0xd2, 0x90, 0x27, 0x7d, - 0x45, 0xba, 0x37, 0xdc, 0xc9, 0xdf, 0x15, 0xf4, 0x51, 0xa4, 0x21, 0xdc, 0xbe, 0x74, 0x9a, 0x49, - 0xfa, 0x66, 0x44, 0x67, 0xce, 0x64, 0x7c, 0xab, 0xa2, 0x33, 0x67, 0xb2, 0x3e, 0x55, 0xe9, 0x13, - 0xf9, 0x86, 0x4c, 0xae, 0x11, 0x6b, 0xfc, 0x0f, 0x03, 0x1d, 0x4b, 0xf9, 0x9a, 0x07, 0xdf, 0xde, - 0x1b, 0x9a, 0xee, 0x07, 0x43, 0xb9, 0xb5, 0x17, 0xf0, 0x00, 0x94, 0x2e, 0x49, 0x4a, 0x79, 0xbc, - 0x92, 0x46, 0x69, 0xcd, 0x71, 0xe2, 0x3e, 0x78, 0xe1, 0xee, 0x57, 0xcf, 0xe6, 0x8c, 0xaf, 0x9f, - 0xcd, 0x19, 0xdf, 0x3c, 0x9b, 0x33, 0x7e, 0xfe, 0x7c, 0xee, 0xc0, 0xd7, 0xcf, 0xe7, 0x0e, 0xfc, - 0xeb, 0xf9, 0xdc, 0x81, 0xc7, 0x66, 0xc3, 0x16, 0xcd, 0xed, 0x4a, 0xbe, 0xca, 0xb6, 0x12, 0x85, - 0xe6, 0x27, 0xa1, 0xe4, 0xd6, 0x6e, 0x51, 0x5e, 0x19, 0x91, 0x9f, 0x48, 0x5d, 0xfc, 0x5f, 0x00, - 0x00, 0x00, 0xff, 0xff, 0xc1, 0xd9, 0x00, 0xc6, 0x18, 0x28, 0x00, 0x00, + // 2285 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x5a, 0xcf, 0x6f, 0xdc, 0xc6, + 0x15, 0x36, 0xa5, 0x44, 0x91, 0x9e, 0x6c, 0xfd, 0x18, 0xcb, 0xb6, 0xb2, 0x76, 0x64, 0x99, 0x92, + 0x63, 0x59, 0x91, 0x97, 0xb6, 0xec, 0xd4, 0xbf, 0xe2, 0xd8, 0x5a, 0x37, 0x92, 0xec, 0x24, 0xb6, + 0xb3, 0xeb, 0x36, 0x80, 0xd1, 0x76, 0xcb, 0xdd, 0x9d, 0xdd, 0x65, 0x4d, 0x71, 0x36, 0x9c, 0x91, + 0x93, 0x8d, 0x2a, 0xa0, 0xe8, 0xad, 0x39, 0x14, 0x05, 0x0a, 0xb4, 0xb7, 0x22, 0x97, 0x1e, 0x0b, + 0x14, 0x01, 0x8a, 0x16, 0x28, 0x7a, 0xc8, 0xa9, 0x39, 0xf4, 0x90, 0xa2, 0x45, 0xd1, 0x53, 0x6b, + 0xd8, 0xfd, 0x43, 0x0a, 0x0e, 0x1f, 0x77, 0x49, 0x2e, 0xc9, 0x9d, 0x95, 0x95, 0xd3, 0x2e, 0x87, + 0xef, 0xbd, 0xf9, 0xbe, 0xc7, 0x99, 0x37, 0x1f, 0x67, 0x08, 0x67, 0x3e, 0xa5, 0xc2, 0xac, 0x36, + 0x4d, 0xcb, 0x31, 0xe4, 0x3f, 0xe6, 0x52, 0x83, 0x55, 0x38, 0x75, 0x9f, 0x50, 0xd7, 0xf8, 0x68, + 0x9b, 0xba, 0xed, 0x7c, 0xcb, 0x65, 0x82, 0x91, 0xe3, 0x1d, 0xc3, 0x7c, 0x60, 0x98, 0x0f, 0x0c, + 0x73, 0xcb, 0x55, 0xc6, 0xb7, 0x18, 0x37, 0x2a, 0x26, 0xa7, 0xbe, 0x97, 0xf1, 0xe4, 0x42, 0x85, + 0x0a, 0xf3, 0x82, 0xd1, 0x32, 0x1b, 0x96, 0x63, 0x0a, 0x8b, 0x39, 0x7e, 0xa0, 0xdc, 0x4c, 0x83, + 0x35, 0x98, 0xfc, 0x6b, 0x78, 0xff, 0xb0, 0xf5, 0x44, 0x83, 0xb1, 0x86, 0x4d, 0x0d, 0xb3, 0x65, + 0x19, 0xa6, 0xe3, 0x30, 0x21, 0x5d, 0x38, 0xde, 0x5d, 0xca, 0x42, 0x59, 0x31, 0x6d, 0x9b, 0x09, + 0xb4, 0xcc, 0xe4, 0x53, 0xb1, 0xcd, 0x2d, 0x8a, 0x86, 0xf9, 0x2c, 0x43, 0xd9, 0x5e, 0x76, 0x98, + 0x53, 0xa5, 0x01, 0x84, 0xd5, 0x4c, 0x7b, 0x97, 0x71, 0xee, 0x3b, 0xd5, 0x6d, 0xb3, 0xa1, 0x04, + 0xfb, 0x31, 0x6d, 0x37, 0xa8, 0xa3, 0x82, 0xc6, 0x61, 0x35, 0x5a, 0x36, 0xab, 0x55, 0xb6, 0xed, + 0x04, 0x34, 0x97, 0xb3, 0xec, 0x83, 0x3f, 0x2a, 0x28, 0x5a, 0xa6, 0x6b, 0x6e, 0x05, 0x78, 0xcf, + 0x67, 0x5a, 0x52, 0xa7, 0x66, 0x39, 0x8d, 0x68, 0x56, 0x4e, 0x67, 0x79, 0x08, 0xce, 0x33, 0xe0, + 0xb6, 0x1e, 0x37, 0xfc, 0x3c, 0x73, 0xfc, 0xe9, 0x63, 0xdb, 0x72, 0x19, 0xab, 0x73, 0xfc, 0x41, + 0xdb, 0x4b, 0x7d, 0xba, 0x2f, 0xd7, 0xb7, 0x9d, 0x1a, 0x2f, 0x6f, 0x59, 0x0d, 0xd7, 0x14, 0x0c, + 0x13, 0xa2, 0x9f, 0x86, 0x85, 0x0f, 0xbc, 0x31, 0xfa, 0x90, 0xf3, 0x75, 0xef, 0xfe, 0xfb, 0x78, + 0xfb, 0x8e, 0x53, 0x67, 0x6b, 0xb6, 0x5d, 0xa4, 0x1f, 0x6d, 0x53, 0x2e, 0xf4, 0x9f, 0x6b, 0xb0, + 0x98, 0x6d, 0xc7, 0x5b, 0xcc, 0xe1, 0x94, 0xd4, 0xe1, 0x70, 0x6f, 0x5f, 0x7c, 0x56, 0x9b, 0x1f, + 0x5e, 0x1a, 0x5f, 0x3d, 0x9f, 0xcf, 0x98, 0x38, 0x79, 0x0c, 0x1d, 0x8e, 0x5c, 0x78, 0xe9, 0xab, + 0xff, 0x9c, 0x3c, 0x50, 0x9c, 0x16, 0xb1, 0x5e, 0xb9, 0x7e, 0x03, 0xe6, 0x53, 0xf1, 0x20, 0x68, + 0xf2, 0x2a, 0x8c, 0xfa, 0xe3, 0xd0, 0xaa, 0xcd, 0x6a, 0xf3, 0xda, 0xd2, 0x70, 0xf1, 0x15, 0x79, + 0x7d, 0xa7, 0xa6, 0xff, 0x4c, 0x83, 0x53, 0x19, 0xfe, 0x48, 0xa6, 0x06, 0xa4, 0x97, 0x8c, 0x0c, + 0xb5, 0x77, 0x2e, 0x53, 0x71, 0x2e, 0xfa, 0x2a, 0xe4, 0x24, 0x94, 0x0d, 0x2a, 0x6e, 0x7b, 0xe1, + 0xee, 0xc9, 0x41, 0x15, 0x90, 0x98, 0x81, 0x97, 0x2d, 0xa7, 0x46, 0x3f, 0x91, 0xdd, 0x8e, 0x15, + 0xfd, 0x0b, 0x9d, 0xc1, 0xf1, 0x44, 0x1f, 0x04, 0xfe, 0x00, 0xc6, 0x43, 0xcd, 0x88, 0x78, 0x29, + 0x13, 0x71, 0xc8, 0x1e, 0x91, 0x86, 0x43, 0xe8, 0x35, 0x04, 0xb9, 0x66, 0xdb, 0x09, 0x20, 0xd7, + 0x01, 0xba, 0xb5, 0x0d, 0xbb, 0x7b, 0x3d, 0xef, 0x17, 0xc2, 0xbc, 0x57, 0x08, 0xf3, 0x7e, 0xf9, + 0xc4, 0x42, 0x98, 0x7f, 0x60, 0x36, 0x28, 0xfa, 0x16, 0x43, 0x9e, 0xfa, 0x9f, 0x34, 0xe4, 0x15, + 0xef, 0x26, 0x8d, 0xd7, 0xf0, 0x0b, 0xf2, 0x22, 0x1b, 0x11, 0xe4, 0x43, 0x12, 0xf9, 0x99, 0xbe, + 0xc8, 0x7d, 0x38, 0x11, 0xe8, 0x75, 0x38, 0x11, 0x20, 0x7f, 0xe0, 0x57, 0x87, 0x6f, 0x26, 0x45, + 0x5f, 0x6a, 0xf0, 0x5a, 0x4a, 0x47, 0x98, 0xa4, 0x0f, 0x61, 0x22, 0x5a, 0x9f, 0x30, 0x4f, 0xcb, + 0x99, 0x79, 0x8a, 0xc4, 0xc2, 0x4c, 0x1d, 0x6a, 0x85, 0x1b, 0xf7, 0x2f, 0x57, 0xc1, 0xe4, 0x8d, + 0xf6, 0xd9, 0x96, 0xcf, 0x45, 0x61, 0xf2, 0xfe, 0x18, 0xe7, 0x6e, 0xb2, 0x7b, 0x46, 0x16, 0xb4, + 0x7d, 0xc8, 0x82, 0x3e, 0x03, 0x24, 0x98, 0x7a, 0x0f, 0x4b, 0xa5, 0xa0, 0x40, 0xde, 0x87, 0xc3, + 0x91, 0x56, 0x44, 0x71, 0x05, 0x86, 0x1f, 0x96, 0x4a, 0xd8, 0xf5, 0x7c, 0x76, 0xc9, 0x28, 0x95, + 0xb0, 0x43, 0xcf, 0x45, 0x7f, 0x07, 0x5e, 0xed, 0x04, 0xe4, 0x7c, 0xad, 0x56, 0x73, 0x29, 0xef, + 0x0c, 0xa6, 0x25, 0x98, 0xaa, 0x58, 0xa2, 0xca, 0x2c, 0xa7, 0xdc, 0x49, 0xd2, 0x90, 0x4c, 0xd2, + 0x04, 0xb6, 0xdf, 0xc6, 0x5c, 0xdd, 0xea, 0x16, 0x97, 0x70, 0x18, 0x84, 0x37, 0x05, 0xc3, 0x54, + 0x34, 0xb1, 0xb4, 0x78, 0x7f, 0xbd, 0x96, 0x8a, 0xa8, 0xca, 0x60, 0x63, 0x45, 0xef, 0xaf, 0xfe, + 0x99, 0x06, 0xcb, 0xbd, 0x21, 0x0a, 0xed, 0x75, 0xcb, 0x31, 0x6d, 0xeb, 0x53, 0x5a, 0xdb, 0xa4, + 0x56, 0xa3, 0x29, 0x02, 0x68, 0xab, 0x70, 0xa4, 0x1e, 0xdc, 0x29, 0x7b, 0x2c, 0xcb, 0x4d, 0x79, + 0x1f, 0x1f, 0xe2, 0xe1, 0xce, 0xcd, 0x47, 0x54, 0x98, 0xbe, 0xeb, 0x00, 0x74, 0x3e, 0x80, 0x37, + 0x94, 0xb0, 0x0c, 0xc0, 0xef, 0x87, 0x70, 0x34, 0x58, 0x09, 0x36, 0x2d, 0x2e, 0x98, 0xdb, 0xde, + 0xef, 0x29, 0xfb, 0x5b, 0x0d, 0x8e, 0xf5, 0x74, 0x81, 0x08, 0xd7, 0x60, 0xd4, 0x5b, 0x62, 0x6c, + 0x8b, 0x0b, 0x9c, 0xa6, 0xaa, 0xa3, 0xe4, 0x15, 0xc1, 0xf9, 0x7b, 0x16, 0x17, 0xfb, 0x37, 0x2d, + 0x9b, 0x30, 0x23, 0x61, 0x6e, 0x9a, 0xfc, 0xbb, 0x4c, 0xd0, 0x5a, 0x90, 0x87, 0x37, 0x60, 0xda, + 0xd7, 0x95, 0x65, 0xab, 0x46, 0x1d, 0x61, 0xd5, 0x2d, 0xea, 0x62, 0x4e, 0xa7, 0xfc, 0x1b, 0x77, + 0x3a, 0xed, 0x64, 0x01, 0x0e, 0x3d, 0x61, 0x82, 0xba, 0x65, 0xd3, 0x7f, 0x38, 0x98, 0xea, 0x83, + 0xb2, 0x11, 0x1f, 0x98, 0x7e, 0x09, 0x8e, 0xc4, 0x7a, 0xc2, 0x74, 0x1c, 0x87, 0xb1, 0xa6, 0xc9, + 0xcb, 0x9e, 0xb1, 0x3f, 0xed, 0x47, 0x8b, 0xa3, 0x4d, 0x34, 0xd2, 0xdf, 0x87, 0x39, 0xe9, 0x55, + 0x90, 0x7d, 0x16, 0xda, 0xdd, 0x5e, 0xf7, 0x82, 0x54, 0x17, 0x30, 0xe6, 0xc5, 0x75, 0x65, 0x12, + 0x7b, 0x60, 0x6b, 0xbd, 0xb0, 0x49, 0x01, 0xc6, 0xbc, 0xeb, 0xb2, 0x68, 0xb7, 0xa8, 0xe4, 0x35, + 0xb1, 0x7a, 0x3a, 0xf3, 0x69, 0x79, 0xf1, 0x1f, 0xb6, 0x5b, 0xb4, 0x38, 0xfa, 0x04, 0xff, 0xe9, + 0x7f, 0x1c, 0x82, 0x93, 0xa9, 0x2c, 0x30, 0x0b, 0x03, 0x25, 0xfc, 0x6d, 0x18, 0x91, 0x20, 0xbd, + 0x4c, 0x0f, 0xcb, 0x11, 0xda, 0x0f, 0x91, 0x64, 0x5c, 0x44, 0x2f, 0xf2, 0x21, 0x4c, 0xf9, 0x77, + 0xe5, 0x20, 0xf0, 0xb9, 0x0d, 0x4b, 0x6e, 0x2b, 0x99, 0x91, 0xee, 0x77, 0x9d, 0x24, 0xc5, 0x49, + 0x16, 0x6d, 0x20, 0xf7, 0xe0, 0x10, 0xb2, 0xe0, 0xc2, 0x14, 0xdb, 0x7c, 0xf6, 0x25, 0x19, 0xf5, + 0x6c, 0x66, 0x54, 0x3f, 0x2b, 0x25, 0xe9, 0x50, 0x3c, 0x58, 0x09, 0x5d, 0xe9, 0x04, 0xa6, 0x64, + 0xe2, 0xee, 0xa3, 0x6d, 0x89, 0x0a, 0xfd, 0x0a, 0xcc, 0xc6, 0xdb, 0x3a, 0x59, 0x3c, 0x01, 0x63, + 0x41, 0x58, 0x7f, 0x09, 0x1c, 0x2b, 0x76, 0x1b, 0xf4, 0xa3, 0x38, 0xd8, 0x4b, 0xdb, 0xad, 0x16, + 0x73, 0x05, 0xad, 0xc9, 0x12, 0xc3, 0xf5, 0x0a, 0xae, 0xe3, 0xb1, 0xf6, 0x4e, 0xd4, 0x02, 0x8c, + 0xf8, 0x12, 0x1d, 0xa7, 0xeb, 0x62, 0x12, 0x9d, 0xd6, 0xe3, 0x46, 0x1e, 0x85, 0xbc, 0x74, 0xc7, + 0x29, 0x8b, 0x9e, 0xfa, 0x4d, 0xd0, 0x23, 0xea, 0xed, 0x81, 0x7c, 0xf1, 0x58, 0x67, 0xae, 0xea, + 0x0a, 0xe8, 0xa2, 0x6a, 0x4f, 0x0b, 0x80, 0x58, 0xdf, 0x85, 0x83, 0x7e, 0x04, 0xff, 0xcd, 0x46, + 0x5d, 0x07, 0xfa, 0xf1, 0x8a, 0xe3, 0xd5, 0xee, 0x85, 0x7e, 0x22, 0x26, 0x53, 0xd1, 0x06, 0xd7, + 0x3f, 0x27, 0x26, 0x48, 0x83, 0xbb, 0x88, 0xe4, 0x7e, 0x22, 0x92, 0x15, 0x55, 0x24, 0x72, 0xc0, + 0x46, 0xd0, 0x84, 0x44, 0xf3, 0x3d, 0x56, 0xa3, 0x6b, 0xfe, 0x1b, 0x61, 0xb6, 0x68, 0xfe, 0x51, + 0x17, 0x63, 0xc4, 0xa7, 0x9b, 0xad, 0xf0, 0xdb, 0xa5, 0x52, 0xb6, 0xc2, 0x71, 0xc6, 0x9d, 0xee, + 0x45, 0x58, 0x2f, 0x27, 0xe0, 0xdb, 0xaf, 0x95, 0xe5, 0x8b, 0x90, 0x5e, 0x4e, 0xa2, 0x74, 0x17, + 0xc6, 0x43, 0xcd, 0x4a, 0x7a, 0x39, 0xc2, 0x28, 0x74, 0xb1, 0x7f, 0xcb, 0xcc, 0x3c, 0x96, 0x71, + 0x6f, 0xa8, 0x74, 0xf6, 0x0a, 0xd6, 0x6d, 0xb3, 0xd1, 0x19, 0x4c, 0x3f, 0xd1, 0xb0, 0x46, 0x26, + 0x99, 0x20, 0xb5, 0xef, 0xc3, 0x54, 0x7c, 0xa7, 0x41, 0x6d, 0x54, 0x45, 0xe3, 0xe1, 0xcc, 0x9c, + 0xac, 0x46, 0x9b, 0xf5, 0x63, 0xb8, 0x42, 0x6d, 0x50, 0xf1, 0xae, 0xdc, 0x9c, 0x08, 0xb0, 0x7d, + 0x07, 0xe5, 0x42, 0xe8, 0x06, 0x22, 0xba, 0x0e, 0x23, 0xfe, 0x3e, 0x06, 0xe2, 0x58, 0xc8, 0xc4, + 0x81, 0xce, 0xe8, 0xa2, 0x9f, 0x44, 0x55, 0x5f, 0x6a, 0xb2, 0x8f, 0x83, 0x62, 0x76, 0x3b, 0x34, + 0x64, 0xbc, 0x9c, 0xcc, 0xa5, 0x59, 0x20, 0x80, 0x1f, 0xc0, 0x61, 0xdb, 0xe4, 0xa2, 0x1c, 0xf4, + 0x51, 0x0e, 0x8f, 0xe3, 0x7c, 0x26, 0x9a, 0xf7, 0x4c, 0x2e, 0xa2, 0x41, 0xa7, 0xed, 0x78, 0x93, + 0x7e, 0x17, 0x31, 0x16, 0x6c, 0x73, 0x8b, 0x26, 0x2d, 0xbf, 0x67, 0x61, 0x4a, 0x6e, 0x2b, 0xf5, + 0x2e, 0x5b, 0x93, 0xb2, 0x3d, 0xb4, 0xf8, 0x56, 0x83, 0xb5, 0xbc, 0x37, 0x56, 0x47, 0x19, 0x01, + 0x06, 0x73, 0xea, 0x0c, 0x49, 0xe8, 0xd9, 0x6b, 0x87, 0x67, 0x5e, 0x1c, 0xf3, 0xbb, 0x72, 0xea, + 0x4c, 0xa7, 0xdd, 0xd9, 0xe1, 0xdf, 0xa3, 0x55, 0xe6, 0xd6, 0xf6, 0xfd, 0x95, 0xec, 0xf7, 0x5a, + 0xf7, 0xdd, 0x2f, 0xda, 0x0f, 0x52, 0xd9, 0x88, 0x51, 0x19, 0x56, 0xa3, 0x82, 0x63, 0xb3, 0x4b, + 0x68, 0xff, 0xe6, 0x60, 0x09, 0xdf, 0xc0, 0x30, 0xfd, 0xb2, 0xd4, 0xae, 0x39, 0x35, 0xf9, 0x8a, + 0xd3, 0x7f, 0xfd, 0xf1, 0xea, 0xab, 0x7c, 0xa9, 0x42, 0x95, 0xee, 0x5f, 0xe8, 0x75, 0x7c, 0x2f, + 0x4b, 0x0e, 0x9a, 0xf2, 0x58, 0x87, 0x07, 0x7e, 0xac, 0xab, 0x9f, 0x2f, 0xc2, 0xcb, 0xb2, 0x23, + 0xf2, 0x17, 0x0d, 0x46, 0x03, 0x0d, 0x49, 0x2e, 0x64, 0x46, 0x49, 0x52, 0xb6, 0xb9, 0xd5, 0x41, + 0x5c, 0x7c, 0x02, 0xfa, 0xdd, 0x9f, 0xfe, 0xe3, 0x7f, 0xbf, 0x1c, 0xfa, 0x36, 0x29, 0xc8, 0x6d, + 0xb6, 0x73, 0xfe, 0x8e, 0x5b, 0x67, 0xa3, 0xad, 0xa3, 0x5e, 0x8d, 0x9d, 0x1e, 0x09, 0xb7, 0x6b, + 0xec, 0x44, 0x34, 0xe6, 0x2e, 0xf9, 0x97, 0x06, 0xa4, 0x57, 0x07, 0x92, 0xeb, 0xfd, 0x61, 0xa5, + 0x6a, 0xe0, 0xdc, 0x5b, 0x7b, 0x73, 0x46, 0x76, 0xef, 0x48, 0x76, 0x37, 0xc9, 0x8d, 0x44, 0x76, + 0x48, 0xa9, 0xd2, 0x0e, 0xb1, 0x4a, 0x22, 0x4a, 0x7e, 0xa3, 0xc1, 0x78, 0x48, 0x93, 0x91, 0x73, + 0xfd, 0x41, 0x85, 0xcc, 0x73, 0x6f, 0x0e, 0x64, 0xde, 0x01, 0x7f, 0x56, 0x82, 0x5f, 0x20, 0xa7, + 0x12, 0xc1, 0x77, 0xca, 0x22, 0xa7, 0x82, 0xfc, 0x4e, 0x83, 0xc9, 0x98, 0xc4, 0x53, 0x19, 0x40, + 0x31, 0x97, 0xdc, 0xd5, 0x81, 0x5d, 0x3a, 0x60, 0x57, 0x24, 0xd8, 0xd7, 0xc9, 0x62, 0x22, 0x58, + 0x1e, 0xc3, 0xf6, 0x5f, 0x0d, 0x8e, 0x26, 0xab, 0x3d, 0x72, 0xb3, 0x3f, 0x86, 0x4c, 0xa1, 0x99, + 0xbb, 0xb5, 0xf7, 0x00, 0xc8, 0xa5, 0x20, 0xb9, 0xbc, 0x45, 0xae, 0x25, 0x72, 0x69, 0x50, 0x51, + 0x0e, 0xab, 0xbf, 0x72, 0x9d, 0xb9, 0x7e, 0x83, 0xb1, 0x13, 0x54, 0x98, 0x5d, 0xf2, 0x85, 0x06, + 0x13, 0xd1, 0x6e, 0xc8, 0xe5, 0x41, 0x81, 0x05, 0x8c, 0xae, 0x0c, 0xee, 0x88, 0x4c, 0xce, 0x49, + 0x26, 0x67, 0xc8, 0x69, 0x25, 0x26, 0x1e, 0xe8, 0x88, 0x48, 0x52, 0x43, 0xdc, 0xab, 0x08, 0x15, + 0x11, 0x27, 0x68, 0x3c, 0xfd, 0xbc, 0x44, 0xbc, 0x4c, 0x96, 0x12, 0x11, 0x87, 0x34, 0xa9, 0xb1, + 0x23, 0x65, 0xf0, 0xae, 0x37, 0xf6, 0x27, 0x42, 0x91, 0xd6, 0x6c, 0x5b, 0x05, 0x77, 0xa2, 0x92, + 0x55, 0xc1, 0x9d, 0xac, 0x4d, 0xf5, 0x25, 0x89, 0x5b, 0x27, 0xf3, 0xfd, 0x70, 0x93, 0x3f, 0x6b, + 0x30, 0x19, 0x93, 0x6d, 0x2a, 0x25, 0x32, 0x55, 0x5f, 0xaa, 0x94, 0xc8, 0x74, 0xe5, 0xd9, 0x67, + 0x88, 0xc4, 0x45, 0x29, 0xf9, 0x95, 0x06, 0x23, 0xbe, 0xd8, 0x23, 0xab, 0x4a, 0xfd, 0x46, 0xf4, + 0x66, 0xee, 0xe2, 0x40, 0x3e, 0x08, 0x71, 0x41, 0x42, 0x7c, 0x8d, 0x1c, 0x4f, 0x84, 0xe8, 0x4b, + 0x4e, 0xf2, 0x57, 0x0d, 0xa6, 0x7b, 0xc4, 0x24, 0xb9, 0xa6, 0x50, 0xd1, 0x52, 0x34, 0x6a, 0xee, + 0xfa, 0x9e, 0x7c, 0x11, 0xf3, 0x55, 0x89, 0xf9, 0x22, 0xb9, 0x10, 0xc6, 0xdc, 0x7b, 0x92, 0xc5, + 0x9b, 0xec, 0xe3, 0x98, 0xc2, 0x25, 0x7f, 0xd7, 0x60, 0xba, 0x47, 0x48, 0xaa, 0x30, 0x49, 0x53, + 0xb2, 0x2a, 0x4c, 0x52, 0x95, 0xab, 0x7e, 0x5b, 0x32, 0xb9, 0x41, 0xae, 0x27, 0xaf, 0xa1, 0x52, + 0xfd, 0xc4, 0x97, 0xd0, 0x98, 0x6c, 0xde, 0xf5, 0xa4, 0x0d, 0xd9, 0xa0, 0x22, 0x26, 0x29, 0x89, + 0xda, 0x7c, 0x4b, 0x50, 0xbb, 0x2a, 0x4b, 0x55, 0x8a, 0x7e, 0xd5, 0x57, 0x25, 0xa1, 0x15, 0xb2, + 0x9c, 0x5a, 0x14, 0x4d, 0xdb, 0x2e, 0xfb, 0x1c, 0x5c, 0x04, 0xfa, 0x54, 0x83, 0x23, 0x32, 0x18, + 0x8f, 0x29, 0x41, 0x72, 0x43, 0x39, 0xb7, 0x49, 0xb2, 0x34, 0xf7, 0xf6, 0x5e, 0xdd, 0x91, 0xcc, + 0xa6, 0x24, 0x53, 0x20, 0xb7, 0xb2, 0x9f, 0x8e, 0x3f, 0x85, 0x4d, 0xa7, 0xe6, 0x1f, 0x1f, 0x84, + 0x56, 0x2a, 0x63, 0x47, 0xb6, 0xec, 0x92, 0x2f, 0x35, 0x38, 0x14, 0xd9, 0x88, 0x26, 0xdf, 0x52, + 0x9a, 0xac, 0x3d, 0xfb, 0xf9, 0xb9, 0xcb, 0x03, 0xfb, 0x21, 0x99, 0x9b, 0x92, 0xcc, 0x55, 0x72, + 0x39, 0xf5, 0xc9, 0x08, 0xce, 0x03, 0xbd, 0x69, 0xec, 0xc4, 0x77, 0xd9, 0x77, 0xc9, 0xaf, 0x87, + 0x60, 0x2e, 0x7b, 0x33, 0x9d, 0x6c, 0x0c, 0x08, 0x2e, 0xed, 0x68, 0x20, 0xb7, 0xf9, 0xe2, 0x81, + 0x90, 0x76, 0x45, 0xd2, 0xfe, 0x1e, 0x79, 0xa4, 0x42, 0xbb, 0xdc, 0x94, 0x7b, 0xee, 0x56, 0xd5, + 0xb4, 0x8d, 0x9d, 0xc4, 0xb3, 0x89, 0xdd, 0xa4, 0xcc, 0x7c, 0xa6, 0xc9, 0xb3, 0x1b, 0x62, 0xa8, + 0xa1, 0xee, 0x1c, 0x05, 0xe5, 0xce, 0xab, 0x3b, 0x20, 0x9d, 0x79, 0x49, 0x27, 0x47, 0x66, 0x13, + 0xe9, 0x78, 0x20, 0x3e, 0xd7, 0x00, 0xba, 0xa7, 0x07, 0x44, 0x61, 0x51, 0xe8, 0x39, 0xce, 0xc8, + 0x5d, 0x1a, 0xcc, 0x09, 0xb1, 0x9d, 0x91, 0xd8, 0x4e, 0x91, 0x93, 0x89, 0xd8, 0x44, 0x17, 0xd3, + 0x1f, 0x34, 0x98, 0x8a, 0x1c, 0x9f, 0x79, 0xba, 0x42, 0xad, 0xe8, 0x24, 0x1d, 0x98, 0xe6, 0xae, + 0xed, 0xc5, 0x15, 0x41, 0x2f, 0x4b, 0xd0, 0x8b, 0x44, 0x4f, 0x04, 0x1d, 0x3d, 0xd5, 0xfc, 0x9b, + 0x06, 0x33, 0x49, 0x27, 0x89, 0x2a, 0x75, 0x2a, 0xe3, 0x00, 0x53, 0xa5, 0x4e, 0x65, 0x1d, 0x60, + 0xea, 0x6f, 0x4a, 0x0e, 0x06, 0x39, 0xd7, 0x9f, 0x43, 0x4c, 0x46, 0x47, 0x0e, 0xb8, 0x07, 0xd0, + 0xd0, 0xd1, 0xfc, 0x5f, 0x19, 0xdc, 0x51, 0x49, 0x91, 0x56, 0xbb, 0x1e, 0x11, 0x45, 0x1a, 0x8a, + 0xa4, 0xae, 0x48, 0xf7, 0x86, 0x3b, 0xf9, 0xeb, 0x82, 0x3e, 0x8a, 0x34, 0x84, 0xdb, 0x93, 0x4e, + 0x33, 0x49, 0x5f, 0x8e, 0xa8, 0x8c, 0x99, 0x8c, 0x2f, 0x56, 0x54, 0xc6, 0x4c, 0xd6, 0x07, 0x2b, + 0x7d, 0x32, 0xdf, 0x90, 0xc5, 0x35, 0xe2, 0x4d, 0xfe, 0xa9, 0xc1, 0xb1, 0x94, 0x6f, 0x7a, 0xc8, + 0xad, 0xbd, 0xa1, 0xe9, 0x7e, 0x36, 0x94, 0x5b, 0x7b, 0x81, 0x08, 0x48, 0xe9, 0x92, 0xa4, 0x94, + 0x27, 0x2b, 0x69, 0x94, 0xd6, 0x6c, 0x3b, 0x1e, 0x83, 0x17, 0xee, 0x7c, 0xf5, 0x6c, 0x4e, 0xfb, + 0xfa, 0xd9, 0x9c, 0xf6, 0xf4, 0xd9, 0x9c, 0xf6, 0x8b, 0xe7, 0x73, 0x07, 0xbe, 0x7e, 0x3e, 0x77, + 0xe0, 0xdf, 0xcf, 0xe7, 0x0e, 0x3c, 0x32, 0x1a, 0x96, 0x68, 0x6e, 0x57, 0xf2, 0x55, 0xb6, 0x95, + 0x28, 0x34, 0x3f, 0x09, 0x15, 0xb7, 0x76, 0x8b, 0xf2, 0xca, 0x88, 0xfc, 0x50, 0xea, 0xe2, 0xff, + 0x03, 0x00, 0x00, 0xff, 0xff, 0x7d, 0x2a, 0xd9, 0xa1, 0x1e, 0x28, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -8220,7 +8220,7 @@ func (m *QuerySupportedChainsResponse) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.Chains = append(m.Chains, &chains.Chain{}) + m.Chains = append(m.Chains, chains.Chain{}) if err := m.Chains[len(m.Chains)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } diff --git a/zetaclient/chains/base/signer.go b/zetaclient/chains/base/signer.go index 0fc9ca4837..2ac38e048d 100644 --- a/zetaclient/chains/base/signer.go +++ b/zetaclient/chains/base/signer.go @@ -34,14 +34,14 @@ type Signer struct { // NewSigner creates a new base signer func NewSigner( chain chains.Chain, - zetacoreContext *context.AppContext, + appContext *context.AppContext, tss interfaces.TSSSigner, ts *metrics.TelemetryServer, logger Logger, ) *Signer { return &Signer{ chain: chain, - appContext: zetacoreContext, + appContext: appContext, tss: tss, ts: ts, logger: Logger{ diff --git a/zetaclient/chains/evm/observer/inbound.go b/zetaclient/chains/evm/observer/inbound.go index 20823f533b..889d2215ac 100644 --- a/zetaclient/chains/evm/observer/inbound.go +++ b/zetaclient/chains/evm/observer/inbound.go @@ -642,8 +642,11 @@ func (ob *Observer) BuildInboundVoteMsgForDepositedEvent( func (ob *Observer) BuildInboundVoteMsgForZetaSentEvent( event *zetaconnector.ZetaConnectorNonEthZetaSent, ) *types.MsgVoteInbound { - destChain := chains.GetChainFromChainID(event.DestinationChainId.Int64()) - if destChain == nil { + destChain, found := chains.GetChainFromChainID( + event.DestinationChainId.Int64(), + ob.AppContext().GetAdditionalChains(), + ) + if !found { ob.Logger().Inbound.Warn().Msgf("chain id not supported %d", event.DestinationChainId.Int64()) return nil } @@ -667,7 +670,7 @@ func (ob *Observer) BuildInboundVoteMsgForZetaSentEvent( if strings.EqualFold(destAddr, paramsDest.ZetaTokenContractAddress) { ob.Logger().Inbound.Warn(). - Msgf("potential attack attempt: %s destination address is ZETA token contract address %s", destChain, destAddr) + Msgf("potential attack attempt: %s destination address is ZETA token contract address %s", destChain.String(), destAddr) return nil } } diff --git a/zetaclient/chains/evm/observer/observer_test.go b/zetaclient/chains/evm/observer/observer_test.go index 6cb97dd65d..e38ff877a1 100644 --- a/zetaclient/chains/evm/observer/observer_test.go +++ b/zetaclient/chains/evm/observer/observer_test.go @@ -63,6 +63,7 @@ func getZetacoreContext( nil, "", *sample.CrosschainFlags(), + []chains.Chain{}, sample.HeaderSupportedChains(), true, ) diff --git a/zetaclient/chains/evm/signer/outbound_data.go b/zetaclient/chains/evm/signer/outbound_data.go index 070c73597e..3e84fa83db 100644 --- a/zetaclient/chains/evm/signer/outbound_data.go +++ b/zetaclient/chains/evm/signer/outbound_data.go @@ -16,6 +16,7 @@ import ( "github.com/zeta-chain/zetacore/x/crosschain/types" "github.com/zeta-chain/zetacore/zetaclient/chains/evm/observer" "github.com/zeta-chain/zetacore/zetaclient/chains/interfaces" + clientcontext "github.com/zeta-chain/zetacore/zetaclient/context" ) const ( @@ -69,7 +70,7 @@ func (txData *OutboundData) SetupGas( cctx *types.CrossChainTx, logger zerolog.Logger, client interfaces.EVMRPCClient, - chain *chains.Chain, + chain chains.Chain, ) error { txData.gasLimit = cctx.GetCurrentOutboundParam().GasLimit if txData.gasLimit < MinGasLimit { @@ -89,10 +90,10 @@ func (txData *OutboundData) SetupGas( // we should possibly remove it completely and return an error if no GasPrice is provided because it means no fee is processed on ZetaChain specified, ok := new(big.Int).SetString(cctx.GetCurrentOutboundParam().GasPrice, 10) if !ok { - if chains.IsEthereumChain(chain.ChainId) { + if chain.Network == chains.Network_eth { suggested, err := client.SuggestGasPrice(context.Background()) if err != nil { - return errors.Join(err, fmt.Errorf("cannot get gas price from chain %s ", chain)) + return errors.Join(err, fmt.Errorf("cannot get gas price from chain %s ", chain.String())) } txData.gasPrice = roundUpToNearestGwei(suggested) } else { @@ -111,6 +112,7 @@ func (txData *OutboundData) SetupGas( // cctx will be skipped and false otherwise. // 3. error func NewOutboundData( + appontext *clientcontext.AppContext, cctx *types.CrossChainTx, evmObserver *observer.Observer, evmRPC interfaces.EVMRPCClient, @@ -132,8 +134,8 @@ func NewOutboundData( return nil, true, nil } - toChain := chains.GetChainFromChainID(txData.toChainID.Int64()) - if toChain == nil { + toChain, found := chains.GetChainFromChainID(txData.toChainID.Int64(), appontext.GetAdditionalChains()) + if !found { return nil, true, fmt.Errorf("unknown chain: %d", txData.toChainID.Int64()) } @@ -156,7 +158,7 @@ func NewOutboundData( // Get sendHash logger.Info(). - Msgf("chain %s minting %d to %s, nonce %d, finalized zeta bn %d", toChain, cctx.InboundParams.Amount, txData.to.Hex(), nonce, cctx.InboundParams.FinalizedZetaHeight) + Msgf("chain %s minting %d to %s, nonce %d, finalized zeta bn %d", toChain.String(), cctx.InboundParams.Amount, txData.to.Hex(), nonce, cctx.InboundParams.FinalizedZetaHeight) cctxIndex, err := hex.DecodeString(cctx.Index[2:]) // remove the leading 0x if err != nil || len(cctxIndex) != 32 { return nil, true, fmt.Errorf("decode CCTX %s error", cctx.Index) diff --git a/zetaclient/chains/evm/signer/outbound_data_test.go b/zetaclient/chains/evm/signer/outbound_data_test.go index d7df5a33d1..f5e3d39d3b 100644 --- a/zetaclient/chains/evm/signer/outbound_data_test.go +++ b/zetaclient/chains/evm/signer/outbound_data_test.go @@ -53,14 +53,14 @@ func TestSigner_SetupGas(t *testing.T) { t.Run("SetupGas_success", func(t *testing.T) { chain := chains.BscMainnet - err := txData.SetupGas(cctx, logger, evmSigner.EvmClient(), &chain) + err := txData.SetupGas(cctx, logger, evmSigner.EvmClient(), chain) require.NoError(t, err) }) t.Run("SetupGas_error", func(t *testing.T) { cctx.GetCurrentOutboundParam().GasPrice = "invalidGasPrice" chain := chains.BscMainnet - err := txData.SetupGas(cctx, logger, evmSigner.EvmClient(), &chain) + err := txData.SetupGas(cctx, logger, evmSigner.EvmClient(), chain) require.ErrorContains(t, err, "cannot convert gas price") }) } @@ -75,7 +75,14 @@ func TestSigner_NewOutboundData(t *testing.T) { t.Run("NewOutboundData success", func(t *testing.T) { cctx := getCCTX(t) - _, skip, err := NewOutboundData(cctx, mockObserver, evmSigner.EvmClient(), zerolog.Logger{}, 123) + _, skip, err := NewOutboundData( + evmSigner.AppContext(), + cctx, + mockObserver, + evmSigner.EvmClient(), + zerolog.Logger{}, + 123, + ) require.False(t, skip) require.NoError(t, err) }) @@ -83,7 +90,14 @@ func TestSigner_NewOutboundData(t *testing.T) { t.Run("NewOutboundData skip", func(t *testing.T) { cctx := getCCTX(t) cctx.CctxStatus.Status = types.CctxStatus_Aborted - _, skip, err := NewOutboundData(cctx, mockObserver, evmSigner.EvmClient(), zerolog.Logger{}, 123) + _, skip, err := NewOutboundData( + evmSigner.AppContext(), + cctx, + mockObserver, + evmSigner.EvmClient(), + zerolog.Logger{}, + 123, + ) require.NoError(t, err) require.True(t, skip) }) @@ -91,7 +105,14 @@ func TestSigner_NewOutboundData(t *testing.T) { t.Run("NewOutboundData unknown chain", func(t *testing.T) { cctx := getInvalidCCTX(t) require.NoError(t, err) - _, skip, err := NewOutboundData(cctx, mockObserver, evmSigner.EvmClient(), zerolog.Logger{}, 123) + _, skip, err := NewOutboundData( + evmSigner.AppContext(), + cctx, + mockObserver, + evmSigner.EvmClient(), + zerolog.Logger{}, + 123, + ) require.ErrorContains(t, err, "unknown chain") require.True(t, skip) }) @@ -100,7 +121,14 @@ func TestSigner_NewOutboundData(t *testing.T) { cctx := getCCTX(t) require.NoError(t, err) cctx.GetCurrentOutboundParam().GasPrice = "invalidGasPrice" - _, skip, err := NewOutboundData(cctx, mockObserver, evmSigner.EvmClient(), zerolog.Logger{}, 123) + _, skip, err := NewOutboundData( + evmSigner.AppContext(), + cctx, + mockObserver, + evmSigner.EvmClient(), + zerolog.Logger{}, + 123, + ) require.True(t, skip) require.ErrorContains(t, err, "cannot convert gas price") }) diff --git a/zetaclient/chains/evm/signer/signer.go b/zetaclient/chains/evm/signer/signer.go index 8bba72d777..db4a15c856 100644 --- a/zetaclient/chains/evm/signer/signer.go +++ b/zetaclient/chains/evm/signer/signer.go @@ -363,7 +363,7 @@ func (signer *Signer) TryProcessOutbound( } // Setup Transaction input - txData, skipTx, err := NewOutboundData(cctx, evmObserver, signer.client, logger, height) + txData, skipTx, err := NewOutboundData(signer.AppContext(), cctx, evmObserver, signer.client, logger, height) if err != nil { logger.Err(err).Msg("error setting up transaction input fields") return @@ -372,8 +372,14 @@ func (signer *Signer) TryProcessOutbound( return } - // Get destination chain for logging - toChain := chains.GetChainFromChainID(txData.toChainID.Int64()) + toChain, found := chains.GetChainFromChainID( + txData.toChainID.Int64(), + signer.AppContext().GetAdditionalChains(), + ) + if !found { + logger.Warn().Msgf("unknown chain: %d", txData.toChainID.Int64()) + return + } // Get cross-chain flags crossChainflags := signer.AppContext().GetCrossChainFlags() @@ -425,7 +431,7 @@ func (signer *Signer) TryProcessOutbound( logger.Info().Msgf( "SignWithdrawTx: %d => %s, nonce %d, gasPrice %d", cctx.InboundParams.SenderChainId, - toChain, + toChain.String(), cctx.GetCurrentOutboundParam().TssNonce, txData.gasPrice, ) @@ -434,7 +440,7 @@ func (signer *Signer) TryProcessOutbound( logger.Info().Msgf( "SignERC20WithdrawTx: %d => %s, nonce %d, gasPrice %d", cctx.InboundParams.SenderChainId, - toChain, + toChain.String(), cctx.GetCurrentOutboundParam().TssNonce, txData.gasPrice, ) @@ -443,7 +449,7 @@ func (signer *Signer) TryProcessOutbound( logger.Info().Msgf( "SignOutbound: %d => %s, nonce %d, gasPrice %d", cctx.InboundParams.SenderChainId, - toChain, + toChain.String(), cctx.GetCurrentOutboundParam().TssNonce, txData.gasPrice, ) @@ -459,7 +465,7 @@ func (signer *Signer) TryProcessOutbound( logger.Info().Msgf( "SignRevertTx: %d => %s, nonce %d, gasPrice %d", cctx.InboundParams.SenderChainId, - toChain, cctx.GetCurrentOutboundParam().TssNonce, + toChain.String(), cctx.GetCurrentOutboundParam().TssNonce, txData.gasPrice, ) txData.srcChainID = big.NewInt(cctx.OutboundParams[0].ReceiverChainId) @@ -469,7 +475,7 @@ func (signer *Signer) TryProcessOutbound( logger.Info().Msgf( "SignWithdrawTx: %d => %s, nonce %d, gasPrice %d", cctx.InboundParams.SenderChainId, - toChain, + toChain.String(), cctx.GetCurrentOutboundParam().TssNonce, txData.gasPrice, ) @@ -477,7 +483,7 @@ func (signer *Signer) TryProcessOutbound( case coin.CoinType_ERC20: logger.Info().Msgf("SignERC20WithdrawTx: %d => %s, nonce %d, gasPrice %d", cctx.InboundParams.SenderChainId, - toChain, + toChain.String(), cctx.GetCurrentOutboundParam().TssNonce, txData.gasPrice, ) @@ -491,7 +497,7 @@ func (signer *Signer) TryProcessOutbound( logger.Info().Msgf( "SignRevertTx: %d => %s, nonce %d, gasPrice %d", cctx.InboundParams.SenderChainId, - toChain, + toChain.String(), cctx.GetCurrentOutboundParam().TssNonce, txData.gasPrice, ) @@ -507,7 +513,7 @@ func (signer *Signer) TryProcessOutbound( logger.Info().Msgf( "SignOutbound: %d => %s, nonce %d, gasPrice %d", cctx.InboundParams.SenderChainId, - toChain, + toChain.String(), cctx.GetCurrentOutboundParam().TssNonce, txData.gasPrice, ) @@ -521,7 +527,7 @@ func (signer *Signer) TryProcessOutbound( logger.Info().Msgf( "Key-sign success: %d => %s, nonce %d", cctx.InboundParams.SenderChainId, - toChain, + toChain.String(), cctx.GetCurrentOutboundParam().TssNonce, ) @@ -539,45 +545,52 @@ func (signer *Signer) BroadcastOutbound( txData *OutboundData, ) { // Get destination chain for logging - toChain := chains.GetChainFromChainID(txData.toChainID.Int64()) + toChain, found := chains.GetChainFromChainID( + txData.toChainID.Int64(), + signer.AppContext().GetAdditionalChains(), + ) + if !found { + logger.Warn().Msgf("BroadcastOutbound: unknown chain %d", txData.toChainID.Int64()) + return + } + if tx == nil { logger.Warn().Msgf("BroadcastOutbound: no tx to broadcast %s", cctx.Index) + return } // broadcast transaction - if tx != nil { - outboundHash := tx.Hash().Hex() - - // try broacasting tx with increasing backoff (1s, 2s, 4s, 8s, 16s) in case of RPC error - backOff := broadcastBackoff - for i := 0; i < broadcastRetries; i++ { - time.Sleep(backOff) - err := signer.Broadcast(tx) - if err != nil { - log.Warn(). - Err(err). - Msgf("BroadcastOutbound: error broadcasting tx %s on chain %d nonce %d retry %d signer %s", - outboundHash, toChain.ChainId, cctx.GetCurrentOutboundParam().TssNonce, i, myID) - retry, report := zetacore.HandleBroadcastError( - err, - strconv.FormatUint(cctx.GetCurrentOutboundParam().TssNonce, 10), - toChain.String(), - outboundHash, - ) - if report { - signer.reportToOutboundTracker(zetacoreClient, toChain.ChainId, tx.Nonce(), outboundHash, logger) - } - if !retry { - break - } - backOff *= 2 - continue + outboundHash := tx.Hash().Hex() + + // try broacasting tx with increasing backoff (1s, 2s, 4s, 8s, 16s) in case of RPC error + backOff := broadcastBackoff + for i := 0; i < broadcastRetries; i++ { + time.Sleep(backOff) + err := signer.Broadcast(tx) + if err != nil { + log.Warn(). + Err(err). + Msgf("BroadcastOutbound: error broadcasting tx %s on chain %d nonce %d retry %d signer %s", + outboundHash, toChain.ChainId, cctx.GetCurrentOutboundParam().TssNonce, i, myID) + retry, report := zetacore.HandleBroadcastError( + err, + strconv.FormatUint(cctx.GetCurrentOutboundParam().TssNonce, 10), + toChain.String(), + outboundHash, + ) + if report { + signer.reportToOutboundTracker(zetacoreClient, toChain.ChainId, tx.Nonce(), outboundHash, logger) + } + if !retry { + break } - logger.Info().Msgf("BroadcastOutbound: broadcasted tx %s on chain %d nonce %d signer %s", - outboundHash, toChain.ChainId, cctx.GetCurrentOutboundParam().TssNonce, myID) - signer.reportToOutboundTracker(zetacoreClient, toChain.ChainId, tx.Nonce(), outboundHash, logger) - break // successful broadcast; no need to retry + backOff *= 2 + continue } + logger.Info().Msgf("BroadcastOutbound: broadcasted tx %s on chain %d nonce %d signer %s", + outboundHash, toChain.ChainId, cctx.GetCurrentOutboundParam().TssNonce, myID) + signer.reportToOutboundTracker(zetacoreClient, toChain.ChainId, tx.Nonce(), outboundHash, logger) + break // successful broadcast; no need to retry } } diff --git a/zetaclient/chains/evm/signer/signer_test.go b/zetaclient/chains/evm/signer/signer_test.go index 13aaac87b1..fd412b4bfd 100644 --- a/zetaclient/chains/evm/signer/signer_test.go +++ b/zetaclient/chains/evm/signer/signer_test.go @@ -180,7 +180,14 @@ func TestSigner_SignOutbound(t *testing.T) { cctx := getCCTX(t) mockObserver, err := getNewEvmChainObserver(t, tss) require.NoError(t, err) - txData, skip, err := NewOutboundData(cctx, mockObserver, evmSigner.EvmClient(), zerolog.Logger{}, 123) + txData, skip, err := NewOutboundData( + evmSigner.AppContext(), + cctx, + mockObserver, + evmSigner.EvmClient(), + zerolog.Logger{}, + 123, + ) require.False(t, skip) require.NoError(t, err) @@ -214,7 +221,14 @@ func TestSigner_SignRevertTx(t *testing.T) { cctx := getCCTX(t) mockObserver, err := getNewEvmChainObserver(t, tss) require.NoError(t, err) - txData, skip, err := NewOutboundData(cctx, mockObserver, evmSigner.EvmClient(), zerolog.Logger{}, 123) + txData, skip, err := NewOutboundData( + evmSigner.AppContext(), + cctx, + mockObserver, + evmSigner.EvmClient(), + zerolog.Logger{}, + 123, + ) require.False(t, skip) require.NoError(t, err) @@ -252,7 +266,14 @@ func TestSigner_SignCancelTx(t *testing.T) { cctx := getCCTX(t) mockObserver, err := getNewEvmChainObserver(t, tss) require.NoError(t, err) - txData, skip, err := NewOutboundData(cctx, mockObserver, evmSigner.EvmClient(), zerolog.Logger{}, 123) + txData, skip, err := NewOutboundData( + evmSigner.AppContext(), + cctx, + mockObserver, + evmSigner.EvmClient(), + zerolog.Logger{}, + 123, + ) require.False(t, skip) require.NoError(t, err) @@ -290,7 +311,14 @@ func TestSigner_SignWithdrawTx(t *testing.T) { cctx := getCCTX(t) mockObserver, err := getNewEvmChainObserver(t, tss) require.NoError(t, err) - txData, skip, err := NewOutboundData(cctx, mockObserver, evmSigner.EvmClient(), zerolog.Logger{}, 123) + txData, skip, err := NewOutboundData( + evmSigner.AppContext(), + cctx, + mockObserver, + evmSigner.EvmClient(), + zerolog.Logger{}, + 123, + ) require.False(t, skip) require.NoError(t, err) @@ -326,7 +354,14 @@ func TestSigner_SignCommandTx(t *testing.T) { cctx := getCCTX(t) mockObserver, err := getNewEvmChainObserver(t, nil) require.NoError(t, err) - txData, skip, err := NewOutboundData(cctx, mockObserver, evmSigner.EvmClient(), zerolog.Logger{}, 123) + txData, skip, err := NewOutboundData( + evmSigner.AppContext(), + cctx, + mockObserver, + evmSigner.EvmClient(), + zerolog.Logger{}, + 123, + ) require.False(t, skip) require.NoError(t, err) @@ -371,7 +406,14 @@ func TestSigner_SignERC20WithdrawTx(t *testing.T) { cctx := getCCTX(t) mockObserver, err := getNewEvmChainObserver(t, tss) require.NoError(t, err) - txData, skip, err := NewOutboundData(cctx, mockObserver, evmSigner.EvmClient(), zerolog.Logger{}, 123) + txData, skip, err := NewOutboundData( + evmSigner.AppContext(), + cctx, + mockObserver, + evmSigner.EvmClient(), + zerolog.Logger{}, + 123, + ) require.False(t, skip) require.NoError(t, err) @@ -409,7 +451,14 @@ func TestSigner_BroadcastOutbound(t *testing.T) { cctx := getCCTX(t) mockObserver, err := getNewEvmChainObserver(t, nil) require.NoError(t, err) - txData, skip, err := NewOutboundData(cctx, mockObserver, evmSigner.EvmClient(), zerolog.Logger{}, 123) + txData, skip, err := NewOutboundData( + evmSigner.AppContext(), + cctx, + mockObserver, + evmSigner.EvmClient(), + zerolog.Logger{}, + 123, + ) require.False(t, skip) require.NoError(t, err) @@ -459,7 +508,14 @@ func TestSigner_SignWhitelistERC20Cmd(t *testing.T) { cctx := getCCTX(t) mockObserver, err := getNewEvmChainObserver(t, tss) require.NoError(t, err) - txData, skip, err := NewOutboundData(cctx, mockObserver, evmSigner.EvmClient(), zerolog.Logger{}, 123) + txData, skip, err := NewOutboundData( + evmSigner.AppContext(), + cctx, + mockObserver, + evmSigner.EvmClient(), + zerolog.Logger{}, + 123, + ) require.False(t, skip) require.NoError(t, err) @@ -502,7 +558,14 @@ func TestSigner_SignMigrateTssFundsCmd(t *testing.T) { cctx := getCCTX(t) mockObserver, err := getNewEvmChainObserver(t, tss) require.NoError(t, err) - txData, skip, err := NewOutboundData(cctx, mockObserver, evmSigner.EvmClient(), zerolog.Logger{}, 123) + txData, skip, err := NewOutboundData( + evmSigner.AppContext(), + cctx, + mockObserver, + evmSigner.EvmClient(), + zerolog.Logger{}, + 123, + ) require.False(t, skip) require.NoError(t, err) diff --git a/zetaclient/context/app.go b/zetaclient/context/app.go index c40e769492..4888443ea9 100644 --- a/zetaclient/context/app.go +++ b/zetaclient/context/app.go @@ -25,6 +25,10 @@ type AppContext struct { currentTssPubkey string crosschainFlags observertypes.CrosschainFlags + // additionalChains is a list of additional static chain information to use when searching from chain IDs + // it is stored in the protocol to dynamically support new chains without doing an upgrade + additionalChain []chains.Chain + // blockHeaderEnabledChains is used to store the list of chains that have block header verification enabled // All chains in this list will have Enabled flag set to true blockHeaderEnabledChains []lightclienttypes.HeaderSupportedChain @@ -173,12 +177,12 @@ func (a *AppContext) GetBTCChainParams() (chains.Chain, *observertypes.ChainPara return chains.Chain{}, nil, false } - chain := chains.GetChainFromChainID(a.bitcoinChainParams.ChainId) - if chain == nil { + chain, found := chains.GetChainFromChainID(a.bitcoinChainParams.ChainId, a.additionalChain) + if !found { return chains.Chain{}, nil, false } - return *chain, a.bitcoinChainParams, true + return chain, a.bitcoinChainParams, true } // GetCrossChainFlags returns crosschain flags @@ -189,6 +193,13 @@ func (a *AppContext) GetCrossChainFlags() observertypes.CrosschainFlags { return a.crosschainFlags } +// GetAdditionalChains returns additional chains +func (a *AppContext) GetAdditionalChains() []chains.Chain { + a.mu.RLock() + defer a.mu.RUnlock() + return a.additionalChain +} + // GetAllHeaderEnabledChains returns all verification flags func (a *AppContext) GetAllHeaderEnabledChains() []lightclienttypes.HeaderSupportedChain { a.mu.RLock() @@ -220,6 +231,7 @@ func (a *AppContext) Update( btcChainParams *observertypes.ChainParams, tssPubKey string, crosschainFlags observertypes.CrosschainFlags, + additionalChains []chains.Chain, blockHeaderEnabledChains []lightclienttypes.HeaderSupportedChain, init bool, ) { @@ -249,6 +261,7 @@ func (a *AppContext) Update( a.chainsEnabled = newChains a.crosschainFlags = crosschainFlags + a.additionalChain = additionalChains a.blockHeaderEnabledChains = blockHeaderEnabledChains // update chain params for bitcoin if it has config in file diff --git a/zetaclient/context/app_test.go b/zetaclient/context/app_test.go index 99b56c7d88..640e5d7386 100644 --- a/zetaclient/context/app_test.go +++ b/zetaclient/context/app_test.go @@ -165,6 +165,7 @@ func TestAppContextUpdate(t *testing.T) { btcChainParamsToUpdate, tssPubKeyToUpdate, *crosschainFlags, + []chains.Chain{}, verificationFlags, false, ) @@ -265,6 +266,7 @@ func TestAppContextUpdate(t *testing.T) { btcChainParamsToUpdate, tssPubKeyToUpdate, *crosschainFlags, + []chains.Chain{}, verificationFlags, false, ) @@ -409,6 +411,7 @@ func TestGetBTCChainAndConfig(t *testing.T) { &observertypes.ChainParams{ChainId: 123}, "", observertypes.CrosschainFlags{}, + []chains.Chain{}, nil, true, ) @@ -426,6 +429,7 @@ func TestGetBTCChainAndConfig(t *testing.T) { &observertypes.ChainParams{ChainId: chains.BitcoinMainnet.ChainId}, "", observertypes.CrosschainFlags{}, + []chains.Chain{}, nil, true, ) @@ -469,6 +473,7 @@ func TestGetBlockHeaderEnabledChains(t *testing.T) { &observertypes.ChainParams{ChainId: chains.BitcoinMainnet.ChainId}, "", observertypes.CrosschainFlags{}, + []chains.Chain{}, []lightclienttypes.HeaderSupportedChain{ {ChainId: 1, Enabled: true}, }, @@ -491,6 +496,39 @@ func TestGetBlockHeaderEnabledChains(t *testing.T) { assert.Empty(t, chain) } +func TestGetAdditionalChains(t *testing.T) { + // ARRANGE + // Given app config + appContext := context.New(config.New(), zerolog.Nop()) + + additionalChains := []chains.Chain{ + sample.Chain(1), + sample.Chain(2), + sample.Chain(3), + } + + // That was eventually updated + appContext.Update( + &observertypes.Keygen{}, + []chains.Chain{}, + nil, + &observertypes.ChainParams{}, + "", + observertypes.CrosschainFlags{}, + additionalChains, + []lightclienttypes.HeaderSupportedChain{ + {ChainId: 1, Enabled: true}, + }, + true, + ) + + // ACT + found := appContext.GetAdditionalChains() + + // ASSERT + assert.EqualValues(t, additionalChains, found) +} + func makeAppContext( evmChain chains.Chain, evmChainParams *observertypes.ChainParams, @@ -517,6 +555,7 @@ func makeAppContext( nil, "", ccFlags, + []chains.Chain{}, headerSupportedChains, true, ) diff --git a/zetaclient/orchestrator/orchestrator.go b/zetaclient/orchestrator/orchestrator.go index 348baac514..b233c9d582 100644 --- a/zetaclient/orchestrator/orchestrator.go +++ b/zetaclient/orchestrator/orchestrator.go @@ -135,7 +135,7 @@ func (oc *Orchestrator) GetUpdatedSigner( return nil, fmt.Errorf("signer not found for chainID %d", chainID) } // update EVM signer parameters only. BTC signer doesn't use chain parameters for now. - if chains.IsEVMChain(chainID) { + if chains.IsEVMChain(chainID, appContext.GetAdditionalChains()) { evmParams, found := appContext.GetEVMChainParams(chainID) if found { // update zeta connector and ERC20 custody addresses @@ -167,14 +167,14 @@ func (oc *Orchestrator) GetUpdatedChainObserver( } // update chain observer chain parameters curParams := observer.GetChainParams() - if chains.IsEVMChain(chainID) { + if chains.IsEVMChain(chainID, appContext.GetAdditionalChains()) { evmParams, found := appContext.GetEVMChainParams(chainID) if found && !observertypes.ChainParamsEqual(curParams, *evmParams) { observer.SetChainParams(*evmParams) oc.logger.Std.Info().Msgf( "updated chain params for chainID %d, new params: %v", chainID, *evmParams) } - } else if chains.IsBitcoinChain(chainID) { + } else if chains.IsBitcoinChain(chainID, appContext.GetAdditionalChains()) { _, btcParams, found := appContext.GetBTCChainParams() if found && !observertypes.ChainParamsEqual(curParams, *btcParams) { @@ -319,9 +319,9 @@ func (oc *Orchestrator) StartCctxScheduler(appContext *context.AppContext) { // #nosec G701 range is verified zetaHeight := uint64(bn) - if chains.IsEVMChain(c.ChainId) { + if chains.IsEVMChain(c.ChainId, appContext.GetAdditionalChains()) { oc.ScheduleCctxEVM(zetaHeight, c.ChainId, cctxList, ob, signer) - } else if chains.IsBitcoinChain(c.ChainId) { + } else if chains.IsBitcoinChain(c.ChainId, appContext.GetAdditionalChains()) { oc.ScheduleCctxBTC(zetaHeight, c.ChainId, cctxList, ob, signer) } else { oc.logger.Std.Error().Msgf("StartCctxScheduler: unsupported chain %d", c.ChainId) diff --git a/zetaclient/orchestrator/orchestrator_test.go b/zetaclient/orchestrator/orchestrator_test.go index 69930bdbcf..9eab334bfe 100644 --- a/zetaclient/orchestrator/orchestrator_test.go +++ b/zetaclient/orchestrator/orchestrator_test.go @@ -80,6 +80,7 @@ func CreateAppContext( btcChainParams, "", *ccFlags, + []chains.Chain{}, verificationFlags, true, ) diff --git a/zetaclient/supplychecker/zeta_supply_checker.go b/zetaclient/supplychecker/zeta_supply_checker.go index 4c16ffd203..3355d4ff5e 100644 --- a/zetaclient/supplychecker/zeta_supply_checker.go +++ b/zetaclient/supplychecker/zeta_supply_checker.go @@ -68,12 +68,15 @@ func NewZetaSupplyChecker( } for chainID := range zetaSupplyChecker.evmClient { - chain := chains.GetChainFromChainID(chainID) - if chain.IsExternalChain() && chains.IsEVMChain(chain.ChainId) && !chains.IsEthereumChain(chain.ChainId) { - zetaSupplyChecker.externalEvmChain = append(zetaSupplyChecker.externalEvmChain, *chain) + chain, found := chains.GetChainFromChainID(chainID, appContext.GetAdditionalChains()) + if !found { + return zetaSupplyChecker, fmt.Errorf("chain not found for chain id %d", chainID) } - if chains.IsEthereumChain(chain.ChainId) { - zetaSupplyChecker.ethereumChain = *chain + if chain.IsExternalChain() && chain.IsEVMChain() && + chain.Network != chains.Network_eth { + zetaSupplyChecker.externalEvmChain = append(zetaSupplyChecker.externalEvmChain, chain) + } else { + zetaSupplyChecker.ethereumChain = chain } } diff --git a/zetaclient/zetacore/client.go b/zetaclient/zetacore/client.go index 140520fe11..53d1d5958c 100644 --- a/zetaclient/zetacore/client.go +++ b/zetaclient/zetacore/client.go @@ -83,7 +83,7 @@ func NewClient( seqMap[keyType] = 0 } - zetaChain, err := chains.ZetaChainFromChainID(chainID) + zetaChain, err := chains.ZetaChainFromCosmosChainID(chainID) if err != nil { return nil, fmt.Errorf("invalid chain id %s, %w", chainID, err) } @@ -111,7 +111,7 @@ func (c *Client) UpdateChainID(chainID string) error { if c.chainID != chainID { c.chainID = chainID - zetaChain, err := chains.ZetaChainFromChainID(chainID) + zetaChain, err := chains.ZetaChainFromCosmosChainID(chainID) if err != nil { return fmt.Errorf("invalid chain id %s, %w", chainID, err) } @@ -210,6 +210,11 @@ func (c *Client) UpdateZetacoreContext(coreContext *context.AppContext, init boo c.pause <- struct{}{} // notify Orchestrator to stop Observers, Signers, and Orchestrator itself } + additionalChains, err := c.GetAdditionalChains() + if err != nil { + return fmt.Errorf("failed to additional chains: %w", err) + } + chainParams, err := c.GetChainParams() if err != nil { return fmt.Errorf("failed to get chain params: %w", err) @@ -225,9 +230,9 @@ func (c *Client) UpdateZetacoreContext(coreContext *context.AppContext, init boo sampledLogger.Warn().Err(err).Msgf("Invalid chain params for chain %d", chainParam.ChainId) continue } - if chains.IsBitcoinChain(chainParam.ChainId) { + if chains.IsBitcoinChain(chainParam.ChainId, additionalChains) { newBTCParams = chainParam - } else if chains.IsEVMChain(chainParam.ChainId) { + } else if chains.IsEVMChain(chainParam.ChainId, additionalChains) { newEVMParams[chainParam.ChainId] = chainParam } } @@ -238,7 +243,7 @@ func (c *Client) UpdateZetacoreContext(coreContext *context.AppContext, init boo } newChains := make([]chains.Chain, len(supportedChains)) for i, chain := range supportedChains { - newChains[i] = *chain + newChains[i] = chain } keyGen, err := c.GetKeyGen() if err != nil { @@ -272,6 +277,7 @@ func (c *Client) UpdateZetacoreContext(coreContext *context.AppContext, init boo newBTCParams, tssPubKey, crosschainFlags, + additionalChains, blockHeaderEnabledChains, init, ) diff --git a/zetaclient/zetacore/query.go b/zetaclient/zetacore/query.go index e90be274ff..52a9a8e5fc 100644 --- a/zetaclient/zetacore/query.go +++ b/zetaclient/zetacore/query.go @@ -19,6 +19,7 @@ import ( "github.com/zeta-chain/zetacore/cmd/zetacored/config" "github.com/zeta-chain/zetacore/pkg/chains" "github.com/zeta-chain/zetacore/pkg/proofs" + authoritytypes "github.com/zeta-chain/zetacore/x/authority/types" crosschaintypes "github.com/zeta-chain/zetacore/x/crosschain/types" lightclienttypes "github.com/zeta-chain/zetacore/x/lightclient/types" observertypes "github.com/zeta-chain/zetacore/x/observer/types" @@ -480,7 +481,7 @@ func (c *Client) GetBlockHeaderChainState(chainID int64) (lightclienttypes.Query } // GetSupportedChains returns the supported chains -func (c *Client) GetSupportedChains() ([]*chains.Chain, error) { +func (c *Client) GetSupportedChains() ([]chains.Chain, error) { client := observertypes.NewQueryClient(c.grpcConn) resp, err := client.SupportedChains(context.Background(), &observertypes.QuerySupportedChains{}) if err != nil { @@ -489,6 +490,16 @@ func (c *Client) GetSupportedChains() ([]*chains.Chain, error) { return resp.GetChains(), nil } +// GetAdditionalChains returns the additional chains +func (c *Client) GetAdditionalChains() ([]chains.Chain, error) { + client := authoritytypes.NewQueryClient(c.grpcConn) + resp, err := client.ChainInfo(context.Background(), &authoritytypes.QueryGetChainInfoRequest{}) + if err != nil { + return nil, err + } + return resp.GetChainInfo().Chains, nil +} + // GetPendingNonces returns the pending nonces func (c *Client) GetPendingNonces() (*observertypes.QueryAllPendingNoncesResponse, error) { client := observertypes.NewQueryClient(c.grpcConn) diff --git a/zetaclient/zetacore/query_test.go b/zetaclient/zetacore/query_test.go index 70898b8e11..baba533cfa 100644 --- a/zetaclient/zetacore/query_test.go +++ b/zetaclient/zetacore/query_test.go @@ -1,6 +1,7 @@ package zetacore import ( + authoritytypes "github.com/zeta-chain/zetacore/x/authority/types" "net" "testing" @@ -815,7 +816,7 @@ func TestZetacore_GetBlockHeaderChainState(t *testing.T) { func TestZetacore_GetSupportedChains(t *testing.T) { expectedOutput := observertypes.QuerySupportedChainsResponse{ - Chains: []*chains.Chain{ + Chains: []chains.Chain{ { ChainName: chains.BitcoinMainnet.ChainName, ChainId: chains.BitcoinMainnet.ChainId, @@ -850,6 +851,29 @@ func TestZetacore_GetSupportedChains(t *testing.T) { require.Equal(t, expectedOutput.Chains, resp) } +func TestZetacore_GetAdditionalChains(t *testing.T) { + expectedOutput := authoritytypes.QueryGetChainInfoResponse{ + ChainInfo: authoritytypes.ChainInfo{ + Chains: []chains.Chain{ + chains.BitcoinMainnet, + chains.Ethereum, + }, + }, + } + input := observertypes.QuerySupportedChains{} + method := "/zetachain.zetacore.authority.Query/ChainInfo" + server := setupMockServer(t, authoritytypes.RegisterQueryServer, method, input, expectedOutput) + server.Serve() + defer closeMockServer(t, server) + + client, err := setupZetacoreClient() + require.NoError(t, err) + + resp, err := client.GetAdditionalChains() + require.NoError(t, err) + require.Equal(t, expectedOutput.ChainInfo.Chains, resp) +} + func TestZetacore_GetPendingNonces(t *testing.T) { expectedOutput := observertypes.QueryAllPendingNoncesResponse{ PendingNonces: []observertypes.PendingNonces{ diff --git a/zetaclient/zetacore/tx.go b/zetaclient/zetacore/tx.go index 1cf1c5c40e..2ef142d03f 100644 --- a/zetaclient/zetacore/tx.go +++ b/zetaclient/zetacore/tx.go @@ -61,13 +61,13 @@ func GetInboundVoteMessage( } // GasPriceMultiplier returns the gas price multiplier for the given chain -func GasPriceMultiplier(chainID int64) (float64, error) { - if chains.IsEVMChain(chainID) { +func GasPriceMultiplier(chain chains.Chain) (float64, error) { + if chain.IsEVMChain() { return clientcommon.EVMOutboundGasPriceMultiplier, nil - } else if chains.IsBitcoinChain(chainID) { + } else if chain.IsBitcoinChain() { return clientcommon.BTCOutboundGasPriceMultiplier, nil } - return 0, fmt.Errorf("cannot get gas price multiplier for unknown chain %d", chainID) + return 0, fmt.Errorf("cannot get gas price multiplier for unknown chain %d", chain.ChainId) } // WrapMessageWithAuthz wraps a message with an authz message @@ -89,7 +89,7 @@ func (c *Client) WrapMessageWithAuthz(msg sdk.Msg) (sdk.Msg, clientauthz.Signer, // TODO(revamp): rename to PostVoteGasPrice func (c *Client) PostGasPrice(chain chains.Chain, gasPrice uint64, supply string, blockNum uint64) (string, error) { // apply gas price multiplier for the chain - multiplier, err := GasPriceMultiplier(chain.ChainId) + multiplier, err := GasPriceMultiplier(chain) if err != nil { return "", err } diff --git a/zetaclient/zetacore/tx_test.go b/zetaclient/zetacore/tx_test.go index fbf9a10e7d..d53e93bda9 100644 --- a/zetaclient/zetacore/tx_test.go +++ b/zetaclient/zetacore/tx_test.go @@ -4,6 +4,8 @@ import ( "bytes" "encoding/hex" "errors" + "github.com/zeta-chain/zetacore/testutil/sample" + authoritytypes "github.com/zeta-chain/zetacore/x/authority/types" "math/big" "net" "os" @@ -41,68 +43,70 @@ const ( func Test_GasPriceMultiplier(t *testing.T) { tt := []struct { name string - chainID int64 + chain chains.Chain multiplier float64 fail bool }{ { name: "get Ethereum multiplier", - chainID: 1, + chain: chains.Ethereum, multiplier: 1.2, fail: false, }, { name: "get Goerli multiplier", - chainID: 5, + chain: chains.Goerli, multiplier: 1.2, fail: false, }, { name: "get BSC multiplier", - chainID: 56, + chain: chains.BscMainnet, multiplier: 1.2, fail: false, }, { name: "get BSC Testnet multiplier", - chainID: 97, + chain: chains.BscTestnet, multiplier: 1.2, fail: false, }, { name: "get Polygon multiplier", - chainID: 137, + chain: chains.Polygon, multiplier: 1.2, fail: false, }, { name: "get Mumbai Testnet multiplier", - chainID: 80001, + chain: chains.Mumbai, multiplier: 1.2, fail: false, }, { name: "get Bitcoin multiplier", - chainID: 8332, + chain: chains.BitcoinMainnet, multiplier: 2.0, fail: false, }, { name: "get Bitcoin Testnet multiplier", - chainID: 18332, + chain: chains.BitcoinTestnet, multiplier: 2.0, fail: false, }, { - name: "get unknown chain gas price multiplier", - chainID: 1234, + name: "get unknown chain gas price multiplier", + chain: chains.Chain{ + Consensus: chains.Consensus_tendermint, + }, multiplier: 1.0, fail: true, }, } for _, tc := range tt { t.Run(tc.name, func(t *testing.T) { - multiplier, err := GasPriceMultiplier(tc.chainID) + multiplier, err := GasPriceMultiplier(tc.chain) if tc.fail { require.Error(t, err) return @@ -209,6 +213,7 @@ func TestZetacore_UpdateZetacoreContext(t *testing.T) { grpcmock.RegisterService(upgradetypes.RegisterQueryServer), grpcmock.RegisterService(observertypes.RegisterQueryServer), grpcmock.RegisterService(lightclienttypes.RegisterQueryServer), + grpcmock.RegisterService(authoritytypes.RegisterQueryServer), grpcmock.WithPlanner(planner.FirstMatch()), grpcmock.WithListener(listener), func(s *grpcmock.Server) { @@ -246,7 +251,7 @@ func TestZetacore_UpdateZetacoreContext(t *testing.T) { UnlimitedTimes(). WithPayload(observertypes.QuerySupportedChains{}). Return(observertypes.QuerySupportedChainsResponse{ - Chains: []*chains.Chain{ + Chains: []chains.Chain{ { chains.BitcoinMainnet.ChainId, chains.BitcoinMainnet.ChainName, @@ -319,6 +324,20 @@ func TestZetacore_UpdateZetacoreContext(t *testing.T) { Enabled: false, }, }}) + + method = "/zetachain.zetacore.authority.Query/ChainInfo" + s.ExpectUnary(method). + UnlimitedTimes(). + WithPayload(authoritytypes.QueryGetChainInfoRequest{}). + Return(authoritytypes.QueryGetChainInfoResponse{ + ChainInfo: authoritytypes.ChainInfo{ + Chains: []chains.Chain{ + sample.Chain(1000), + sample.Chain(1001), + sample.Chain(1002), + }, + }, + }) }, )(t)