diff --git a/changelog.md b/changelog.md index 3613de1487..1076597713 100644 --- a/changelog.md +++ b/changelog.md @@ -2,16 +2,30 @@ ## Unreleased -* ci: adding typescript publishing pipeline. +## Version: v12.0.0 ### Breaking Changes -* PendingNonces :Changed from `/zeta-chain/crosschain/pendingNonces/{chain_id}/{address}` to `/zeta-chain/observer/pendingNonces/{chain_id}/{address}` . It returns all the pending nonces for a chain id and address. This returns the current pending nonces for the chain. -* ChainNonces : Changed from `/zeta-chain/criosschain/chainNonces/{chain_id}` to`/zeta-chain/observer/chainNonces/{chain_id}` . It returns all the chain nonces for a chain id. This returns the current nonce oof the TSS address for the chain. -* ChainNoncesAll :Changed from `/zeta-chain/observer/chainNonces` to `/zeta-chain/observer/chainNonces` . It returns all the chain nonces for all chains. This returns the current nonce of the TSS address for all chains. -* GetTssAddress : Changed from `/zeta-chain/observer/get_tss_address/` to `/zeta-chain/observer/getTssAddress/{bitcoin_chain_id}` . Optional bitcoing chain id can now now passed as a parameter to fetch the correct tss for required BTC chain.This parameter only affects the BTC tss address in the response. +TSS and chain validation related queries have been moved from `crosschain` module to `observer` module: +* `PendingNonces` :Changed from `/zeta-chain/crosschain/pendingNonces/{chain_id}/{address}` to `/zeta-chain/observer/pendingNonces/{chain_id}/{address}` . It returns all the pending nonces for a chain id and address. This returns the current pending nonces for the chain. +* `ChainNonces` : Changed from `/zeta-chain/crosschain/chainNonces/{chain_id}` to`/zeta-chain/observer/chainNonces/{chain_id}` . It returns all the chain nonces for a chain id. This returns the current nonce of the TSS address for the chain. +* `ChainNoncesAll` :Changed from `/zeta-chain/crosschain/chainNonces` to `/zeta-chain/observer/chainNonces` . It returns all the chain nonces for all chains. This returns the current nonce of the TSS address for all chains. + +All chains now have the same observer set: +* `ObserversByChain`: `/zeta-chain/observer/observers_by_chain/{observation_chain}` has been removed and replaced with `/zeta-chain/observer/observer_set`. All chains have the same observer set. +* `AllObserverMappers`: `/zeta-chain/observer/all_observer_mappers` has been removed. `/zeta-chain/observer/observer_set` should be used to get observers. + +Observer params and core params have been merged into chain params: +* `Params`: `/zeta-chain/observer/params` no longer returns observer params. Observer params data have been moved to chain params described below. +* `GetCoreParams`: Renamed into `GetChainParams`. `/zeta-chain/observer/get_core_params` moved to `/zeta-chain/observer/get_chain_params`. +* `GetCoreParamsByChain`: Renamed into `GetChainParamsForChain`. `/zeta-chain/observer/get_core_params_by_chain` moved to `/zeta-chain/observer/get_chain_params_by_chain`. + +Getting the correct TSS address for Bitcoin now requires proviidng the Bitcoin chain id: +* `GetTssAddress` : Changed from `/zeta-chain/observer/get_tss_address/` to `/zeta-chain/observer/getTssAddress/{bitcoin_chain_id}` . Optional bitcoin chain id can now be passed as a parameter to fetch the correct tss for required BTC chain. This parameter only affects the BTC tss address in the response. ### Features + +* [1549](https://github.com/zeta-chain/node/pull/1549) - add monitoring for vote tx results in ZetaClient * [1498](https://github.com/zeta-chain/node/pull/1498) - Add monitoring(grafana, prometheus, ethbalance) for localnet testing * [1395](https://github.com/zeta-chain/node/pull/1395) - Add state variable to track aborted zeta amount * [1410](https://github.com/zeta-chain/node/pull/1410) - `snapshots` commands @@ -40,6 +54,7 @@ * [1525](https://github.com/zeta-chain/node/pull/1525) - relax EVM chain block header length check 1024->4096 * [1522](https://github.com/zeta-chain/node/pull/1522/files) - block `distribution` module account from receiving zeta * [1528](https://github.com/zeta-chain/node/pull/1528) - fix panic caused on decoding malformed BTC addresses +* [1557](https://github.com/zeta-chain/node/pull/1557) - remove decreaseAllowance and increaseAllowance checks * [1536](https://github.com/zeta-chain/node/pull/1536) - add index to check previously finalized inbounds * [1556](https://github.com/zeta-chain/node/pull/1556) - add emptiness check for topic array in event parsing * [1546](https://github.com/zeta-chain/node/pull/1546) - fix reset of pending nonces on genesis import @@ -66,6 +81,7 @@ * Update --ledger flag hint ### Chores + * [1446](https://github.com/zeta-chain/node/pull/1446) - renamed file `zetaclientd/aux.go` to `zetaclientd/utils.go` to avoid complaints from go package resolver. * [1499](https://github.com/zeta-chain/node/pull/1499) - Add scripts to localnet to help test gov proposals * [1442](https://github.com/zeta-chain/node/pull/1442) - remove build types in `.goreleaser.yaml` @@ -77,7 +93,9 @@ * [1538](https://github.com/zeta-chain/node/pull/1538) - improve stateful e2e testing ### CI + * Removed private runners and unused GitHub Action +* Adding typescript publishing pipeline. ## Version: v11.0.0 diff --git a/cmd/zetae2e/local/bitcoin.go b/cmd/zetae2e/local/bitcoin.go index 73a1bdaeee..a27d619138 100644 --- a/cmd/zetae2e/local/bitcoin.go +++ b/cmd/zetae2e/local/bitcoin.go @@ -16,6 +16,7 @@ func bitcoinTestRoutine( conf config.Config, deployerRunner *runner.SmokeTestRunner, verbose bool, + initBitcoinNetwork bool, ) func() error { return func() (err error) { // return an error on panic @@ -47,23 +48,19 @@ func bitcoinTestRoutine( startTime := time.Now() // funding the account - txZetaSend := deployerRunner.SendZetaOnEvm(UserBitcoinAddress, 1000) txUSDTSend := deployerRunner.SendUSDTOnEvm(UserBitcoinAddress, 1000) - - bitcoinRunner.WaitForTxReceiptOnEvm(txZetaSend) bitcoinRunner.WaitForTxReceiptOnEvm(txUSDTSend) // depositing the necessary tokens on ZetaChain - txZetaDeposit := bitcoinRunner.DepositZeta() txEtherDeposit := bitcoinRunner.DepositEther(false) txERC20Deposit := bitcoinRunner.DepositERC20() - bitcoinRunner.SetupBitcoinAccount() - bitcoinRunner.DepositBTC(false) - bitcoinRunner.SetupZEVMSwapApp() - bitcoinRunner.WaitForMinedCCTX(txZetaDeposit) + bitcoinRunner.WaitForMinedCCTX(txEtherDeposit) bitcoinRunner.WaitForMinedCCTX(txERC20Deposit) + bitcoinRunner.SetupBitcoinAccount(initBitcoinNetwork) + bitcoinRunner.DepositBTC(false) + // run bitcoin test // Note: due to the extensive block generation in Bitcoin localnet, block header test is run first // to make it faster to catch up with the latest block header diff --git a/cmd/zetae2e/local/erc20.go b/cmd/zetae2e/local/erc20.go index c745077547..8e5a286fa8 100644 --- a/cmd/zetae2e/local/erc20.go +++ b/cmd/zetae2e/local/erc20.go @@ -47,17 +47,12 @@ func erc20TestRoutine( startTime := time.Now() // funding the account - txZetaSend := deployerRunner.SendZetaOnEvm(UserERC20Address, 1000) txUSDTSend := deployerRunner.SendUSDTOnEvm(UserERC20Address, 10) - - erc20Runner.WaitForTxReceiptOnEvm(txZetaSend) erc20Runner.WaitForTxReceiptOnEvm(txUSDTSend) // depositing the necessary tokens on ZetaChain - txZetaDeposit := erc20Runner.DepositZeta() txEtherDeposit := erc20Runner.DepositEther(false) txERC20Deposit := erc20Runner.DepositERC20() - erc20Runner.WaitForMinedCCTX(txZetaDeposit) erc20Runner.WaitForMinedCCTX(txEtherDeposit) erc20Runner.WaitForMinedCCTX(txERC20Deposit) diff --git a/cmd/zetae2e/local/ethereum.go b/cmd/zetae2e/local/ethereum.go index f8328035ba..74a57a6470 100644 --- a/cmd/zetae2e/local/ethereum.go +++ b/cmd/zetae2e/local/ethereum.go @@ -46,18 +46,10 @@ func ethereumTestRoutine( ethereumRunner.Logger.Print("🏃 starting Ethereum tests") startTime := time.Now() - // funding the account - txZetaSend := deployerRunner.SendZetaOnEvm(UserEtherAddress, 1000) - ethereumRunner.WaitForTxReceiptOnEvm(txZetaSend) - // depositing the necessary tokens on ZetaChain - txZetaDeposit := ethereumRunner.DepositZeta() txEtherDeposit := ethereumRunner.DepositEther(false) - ethereumRunner.WaitForMinedCCTX(txZetaDeposit) ethereumRunner.WaitForMinedCCTX(txEtherDeposit) - ethereumRunner.SetupContextApp() - // run ethereum test // Note: due to the extensive block generation in Ethereum localnet, block header test is run first // to make it faster to catch up with the latest block header diff --git a/cmd/zetae2e/local/local.go b/cmd/zetae2e/local/local.go index 72023b8e9b..f1a723f26e 100644 --- a/cmd/zetae2e/local/local.go +++ b/cmd/zetae2e/local/local.go @@ -201,7 +201,6 @@ func localE2ETest(cmd *cobra.Command, _ []string) { deployerRunner.SetZEVMContracts() deployerRunner.MintUSDTOnEvm(10000) logger.Print("✅ setup completed in %s", time.Since(startTime)) - deployerRunner.PrintContractAddresses() } // if a config output is specified, write the config @@ -220,6 +219,8 @@ func localE2ETest(cmd *cobra.Command, _ []string) { logger.Print("✅ config file written in %s", configOut) } + deployerRunner.PrintContractAddresses() + // if setup only, quit if setupOnly { os.Exit(0) @@ -230,7 +231,7 @@ func localE2ETest(cmd *cobra.Command, _ []string) { if !skipRegular { eg.Go(erc20TestRoutine(conf, deployerRunner, verbose)) eg.Go(zetaTestRoutine(conf, deployerRunner, verbose)) - eg.Go(bitcoinTestRoutine(conf, deployerRunner, verbose)) + eg.Go(bitcoinTestRoutine(conf, deployerRunner, verbose, !skipSetup)) eg.Go(ethereumTestRoutine(conf, deployerRunner, verbose)) } if testAdmin { diff --git a/contrib/localnet/orchestrator/smoketest/cmd/smoketest/local/bitcoin.go b/contrib/localnet/orchestrator/smoketest/cmd/smoketest/local/bitcoin.go index 6813be52b1..f791e1c29b 100644 --- a/contrib/localnet/orchestrator/smoketest/cmd/smoketest/local/bitcoin.go +++ b/contrib/localnet/orchestrator/smoketest/cmd/smoketest/local/bitcoin.go @@ -57,9 +57,8 @@ func bitcoinTestRoutine( txZetaDeposit := bitcoinRunner.DepositZeta() txEtherDeposit := bitcoinRunner.DepositEther(false) txERC20Deposit := bitcoinRunner.DepositERC20() - bitcoinRunner.SetupBitcoinAccount() + bitcoinRunner.SetupBitcoinAccount(true) bitcoinRunner.DepositBTC(true) - bitcoinRunner.SetupZEVMSwapApp() bitcoinRunner.WaitForMinedCCTX(txZetaDeposit) bitcoinRunner.WaitForMinedCCTX(txEtherDeposit) bitcoinRunner.WaitForMinedCCTX(txERC20Deposit) diff --git a/contrib/localnet/orchestrator/smoketest/cmd/smoketest/local/ethereum.go b/contrib/localnet/orchestrator/smoketest/cmd/smoketest/local/ethereum.go index 82e62ca976..7f2eae6792 100644 --- a/contrib/localnet/orchestrator/smoketest/cmd/smoketest/local/ethereum.go +++ b/contrib/localnet/orchestrator/smoketest/cmd/smoketest/local/ethereum.go @@ -56,8 +56,6 @@ func ethereumTestRoutine( ethereumRunner.WaitForMinedCCTX(txZetaDeposit) ethereumRunner.WaitForMinedCCTX(txEtherDeposit) - ethereumRunner.SetupContextApp() - // run ethereum test // Note: due to the extensive block generation in Ethereum localnet, block header test is run first // to make it faster to catch up with the latest block header diff --git a/contrib/localnet/orchestrator/smoketest/runner/accounting.go b/contrib/localnet/orchestrator/smoketest/runner/accounting.go index 8e9dcd0e02..98cad6f2f8 100644 --- a/contrib/localnet/orchestrator/smoketest/runner/accounting.go +++ b/contrib/localnet/orchestrator/smoketest/runner/accounting.go @@ -57,6 +57,7 @@ func (sm *SmokeTestRunner) CheckBtcTSSBalance() error { btcBalance += utxo.Amount } } + zrc20Supply, err := sm.BTCZRC20.TotalSupply(&bind.CallOpts{}) if err != nil { return err @@ -67,10 +68,15 @@ func (sm *SmokeTestRunner) CheckBtcTSSBalance() error { // #nosec G701 smoketest - always in range if int64(btcBalance*1e8) < (zrc20Supply.Int64() - 10000000) { // #nosec G701 smoketest - always in range - return fmt.Errorf("BTC: TSS Balance (%d) < ZRC20 TotalSupply (%d) ", int64(btcBalance*1e8), zrc20Supply) + return fmt.Errorf( + "BTC: TSS Balance (%d) < ZRC20 TotalSupply (%d)", + int64(btcBalance*1e8), + zrc20Supply.Int64()-10000000, + ) } // #nosec G701 smoketest - always in range - sm.Logger.Info("BTC: Balance (%d) >= ZRC20 TotalSupply (%d)", int64(btcBalance*1e8), zrc20Supply) + sm.Logger.Info("BTC: Balance (%d) >= ZRC20 TotalSupply (%d)", int64(btcBalance*1e8), zrc20Supply.Int64()-10000000) + return nil } diff --git a/contrib/localnet/orchestrator/smoketest/runner/setup_bitcoin.go b/contrib/localnet/orchestrator/smoketest/runner/setup_bitcoin.go index 10ad22eb7d..1b4a1ce671 100644 --- a/contrib/localnet/orchestrator/smoketest/runner/setup_bitcoin.go +++ b/contrib/localnet/orchestrator/smoketest/runner/setup_bitcoin.go @@ -11,15 +11,14 @@ import ( "github.com/btcsuite/btcutil" ) -func (sm *SmokeTestRunner) SetupBitcoinAccount() { +func (sm *SmokeTestRunner) SetupBitcoinAccount(initNetwork bool) { sm.Logger.Print("⚙️ setting up Bitcoin account") startTime := time.Now() defer func() { sm.Logger.Print("✅ Bitcoin account setup in %s\n", time.Since(startTime)) }() - btc := sm.BtcRPCClient - _, err := btc.CreateWallet(sm.Name, rpcclient.WithCreateWalletBlank()) + _, err := sm.BtcRPCClient.CreateWallet(sm.Name, rpcclient.WithCreateWalletBlank()) if err != nil { if !strings.Contains(err.Error(), "Database already exists") { panic(err) @@ -28,20 +27,23 @@ func (sm *SmokeTestRunner) SetupBitcoinAccount() { sm.setBtcAddress() - err = btc.ImportAddress(sm.BTCTSSAddress.EncodeAddress()) - if err != nil { - panic(err) - } + if initNetwork { + // import the TSS address + err = sm.BtcRPCClient.ImportAddress(sm.BTCTSSAddress.EncodeAddress()) + if err != nil { + panic(err) + } - // mine some blocks to get some BTC into the deployer address - _, err = btc.GenerateToAddress(101, sm.BTCDeployerAddress, nil) - if err != nil { - panic(err) - } + // mine some blocks to get some BTC into the deployer address + _, err = sm.BtcRPCClient.GenerateToAddress(101, sm.BTCDeployerAddress, nil) + if err != nil { + panic(err) + } - _, err = btc.GenerateToAddress(4, sm.BTCDeployerAddress, nil) - if err != nil { - panic(err) + _, err = sm.BtcRPCClient.GenerateToAddress(4, sm.BTCDeployerAddress, nil) + if err != nil { + panic(err) + } } } diff --git a/contrib/localnet/orchestrator/smoketest/runner/setup_zeta.go b/contrib/localnet/orchestrator/smoketest/runner/setup_zeta.go index 5a266f3156..4ce1ba196a 100644 --- a/contrib/localnet/orchestrator/smoketest/runner/setup_zeta.go +++ b/contrib/localnet/orchestrator/smoketest/runner/setup_zeta.go @@ -115,12 +115,12 @@ func (sm *SmokeTestRunner) SetZEVMContracts() { sm.SystemContract = SystemContract sm.SystemContractAddr = systemContractAddr + // set ZRC20 contracts sm.SetupETHZRC20() sm.SetupBTCZRC20() -} -func (sm *SmokeTestRunner) SetupZEVMSwapApp() { - zevmSwapAppAddr, tx, zevmSwapApp, err := zevmswap.DeployZEVMSwapApp( + // deploy ZEVMSwapApp and ContextApp + zevmSwapAppAddr, txZEVMSwapApp, zevmSwapApp, err := zevmswap.DeployZEVMSwapApp( sm.ZevmAuth, sm.ZevmClient, sm.UniswapV2RouterAddr, @@ -129,25 +129,23 @@ func (sm *SmokeTestRunner) SetupZEVMSwapApp() { if err != nil { panic(err) } - receipt := utils.MustWaitForTxReceipt(sm.Ctx, sm.ZevmClient, tx, sm.Logger, sm.ReceiptTimeout) + + contextAppAddr, txContextApp, contextApp, err := contextapp.DeployContextApp(sm.ZevmAuth, sm.ZevmClient) + if err != nil { + panic(err) + } + + receipt := utils.MustWaitForTxReceipt(sm.Ctx, sm.ZevmClient, txZEVMSwapApp, sm.Logger, sm.ReceiptTimeout) if receipt.Status != 1 { panic("ZEVMSwapApp deployment failed") } - sm.Logger.Info("ZEVMSwapApp contract address: %s, tx hash: %s", zevmSwapAppAddr.Hex(), tx.Hash().Hex()) sm.ZEVMSwapAppAddr = zevmSwapAppAddr sm.ZEVMSwapApp = zevmSwapApp -} -func (sm *SmokeTestRunner) SetupContextApp() { - contextAppAddr, tx, contextApp, err := contextapp.DeployContextApp(sm.ZevmAuth, sm.ZevmClient) - if err != nil { - panic(err) - } - receipt := utils.MustWaitForTxReceipt(sm.Ctx, sm.ZevmClient, tx, sm.Logger, sm.ReceiptTimeout) + receipt = utils.MustWaitForTxReceipt(sm.Ctx, sm.ZevmClient, txContextApp, sm.Logger, sm.ReceiptTimeout) if receipt.Status != 1 { panic("ContextApp deployment failed") } - sm.Logger.Info("ContextApp contract address: %s, tx hash: %s", contextAppAddr.Hex(), tx.Hash().Hex()) sm.ContextAppAddr = contextAppAddr sm.ContextApp = contextApp } diff --git a/contrib/localnet/orchestrator/start-upgrade.sh b/contrib/localnet/orchestrator/start-upgrade.sh index 1d8c5aa570..f13666aa57 100644 --- a/contrib/localnet/orchestrator/start-upgrade.sh +++ b/contrib/localnet/orchestrator/start-upgrade.sh @@ -47,7 +47,7 @@ fi echo "E2E setup passed, waiting for upgrade height..." # Restart zetaclients at upgrade height -/work/restart-zetaclientd.sh -u 180 -n 2 +/work/restart-zetaclientd.sh -u 200 -n 2 echo "waiting 10 seconds for node to restart..." diff --git a/contrib/localnet/scripts/genesis-stateful.sh b/contrib/localnet/scripts/genesis-stateful.sh index 5099fcfc4a..d9d377f42f 100755 --- a/contrib/localnet/scripts/genesis-stateful.sh +++ b/contrib/localnet/scripts/genesis-stateful.sh @@ -100,12 +100,23 @@ then cat $HOME/.zetacored/config/genesis.json | jq '.consensus_params["block"]["max_gas"]="500000000"' > $HOME/.zetacored/config/tmp_genesis.json && mv $HOME/.zetacored/config/tmp_genesis.json $HOME/.zetacored/config/genesis.json cat $HOME/.zetacored/config/genesis.json | jq '.app_state["gov"]["voting_params"]["voting_period"]="100s"' > $HOME/.zetacored/config/tmp_genesis.json && mv $HOME/.zetacored/config/tmp_genesis.json $HOME/.zetacored/config/genesis.json - # set fungible admin account as admin for fungible token +# set fungible admin account as admin for fungible token zetacored add-genesis-account zeta1srsq755t654agc0grpxj4y3w0znktrpr9tcdgk 100000000000000000000000000azeta zetacored add-genesis-account zeta1n0rn6sne54hv7w2uu93fl48ncyqz97d3kty6sh 100000000000000000000000000azeta # Funds the localnet_gov_admin account cat $HOME/.zetacored/config/genesis.json | jq '.app_state["observer"]["params"]["admin_policy"][0]["address"]="zeta1srsq755t654agc0grpxj4y3w0znktrpr9tcdgk"' > $HOME/.zetacored/config/tmp_genesis.json && mv $HOME/.zetacored/config/tmp_genesis.json $HOME/.zetacored/config/genesis.json cat $HOME/.zetacored/config/genesis.json | jq '.app_state["observer"]["params"]["admin_policy"][1]["address"]="zeta1srsq755t654agc0grpxj4y3w0znktrpr9tcdgk"' > $HOME/.zetacored/config/tmp_genesis.json && mv $HOME/.zetacored/config/tmp_genesis.json $HOME/.zetacored/config/genesis.json +# give balance to deployer account to deploy contracts directly on zEVM + zetacored add-genesis-account zeta1uhznv7uzyjq84s3q056suc8pkme85lkvhrz3dd 100000000000000000000000000azeta +# erc20 tester + zetacored add-genesis-account zeta1datate7xmwm4uk032f9rmcu0cwy7ch7kg6y6zv 100000000000000000000000000azeta +# zeta tester + zetacored add-genesis-account zeta1tnp0hvsq4y5mxuhrq9h3jfwulxywpq0ads0rer 100000000000000000000000000azeta +# bitcoin tester + zetacored add-genesis-account zeta19q7czqysah6qg0n4y3l2a08gfzqxydla492v80 100000000000000000000000000azeta +# ethers tester + zetacored add-genesis-account zeta134rakuus43xn63yucgxhn88ywj8ewcv6ezn2ga 100000000000000000000000000azeta + # 3. Copy the genesis.json to all the nodes .And use it to create a gentx for every node zetacored gentx operator 1000000000000000000000azeta --chain-id=$CHAINID --keyring-backend=$KEYRING # Copy host gentx to other nodes @@ -175,7 +186,7 @@ echo if [ $HOSTNAME = "zetacore0" ] then -/root/.zetacored/cosmovisor/genesis/bin/zetacored tx gov submit-legacy-proposal software-upgrade $UpgradeName --from hotkey --deposit 100000000azeta --upgrade-height 180 --title $UpgradeName --description $UpgradeName --keyring-backend test --chain-id $CHAINID --yes --no-validate --fees=200azeta --broadcast-mode block +/root/.zetacored/cosmovisor/genesis/bin/zetacored tx gov submit-legacy-proposal software-upgrade $UpgradeName --from hotkey --deposit 100000000azeta --upgrade-height 200 --title $UpgradeName --description $UpgradeName --keyring-backend test --chain-id $CHAINID --yes --no-validate --fees=200azeta --broadcast-mode block fi sleep 8 diff --git a/contrib/localnet/scripts/genesis.sh b/contrib/localnet/scripts/genesis.sh index 4ed0d22270..93c8833541 100755 --- a/contrib/localnet/scripts/genesis.sh +++ b/contrib/localnet/scripts/genesis.sh @@ -91,12 +91,24 @@ then cat $HOME/.zetacored/config/genesis.json | jq '.app_state["gov"]["voting_params"]["voting_period"]="100s"' > $HOME/.zetacored/config/tmp_genesis.json && mv $HOME/.zetacored/config/tmp_genesis.json $HOME/.zetacored/config/genesis.json cat $HOME/.zetacored/config/genesis.json | jq '.app_state["feemarket"]["params"]["min_gas_price"]="10000000000.0000"' > $HOME/.zetacored/config/tmp_genesis.json && mv $HOME/.zetacored/config/tmp_genesis.json $HOME/.zetacored/config/genesis.json - # set admin account +# set admin account zetacored add-genesis-account zeta1srsq755t654agc0grpxj4y3w0znktrpr9tcdgk 100000000000000000000000000azeta zetacored add-genesis-account zeta1n0rn6sne54hv7w2uu93fl48ncyqz97d3kty6sh 100000000000000000000000000azeta # Funds the localnet_gov_admin account cat $HOME/.zetacored/config/genesis.json | jq '.app_state["observer"]["params"]["admin_policy"][0]["address"]="zeta1srsq755t654agc0grpxj4y3w0znktrpr9tcdgk"' > $HOME/.zetacored/config/tmp_genesis.json && mv $HOME/.zetacored/config/tmp_genesis.json $HOME/.zetacored/config/genesis.json cat $HOME/.zetacored/config/genesis.json | jq '.app_state["observer"]["params"]["admin_policy"][1]["address"]="zeta1srsq755t654agc0grpxj4y3w0znktrpr9tcdgk"' > $HOME/.zetacored/config/tmp_genesis.json && mv $HOME/.zetacored/config/tmp_genesis.json $HOME/.zetacored/config/genesis.json +# give balance to runner accounts to deploy contracts directly on zEVM +# deployer + zetacored add-genesis-account zeta1uhznv7uzyjq84s3q056suc8pkme85lkvhrz3dd 100000000000000000000000000azeta +# erc20 tester + zetacored add-genesis-account zeta1datate7xmwm4uk032f9rmcu0cwy7ch7kg6y6zv 100000000000000000000000000azeta +# zeta tester + zetacored add-genesis-account zeta1tnp0hvsq4y5mxuhrq9h3jfwulxywpq0ads0rer 100000000000000000000000000azeta +# bitcoin tester + zetacored add-genesis-account zeta19q7czqysah6qg0n4y3l2a08gfzqxydla492v80 100000000000000000000000000azeta +# ethers tester + zetacored add-genesis-account zeta134rakuus43xn63yucgxhn88ywj8ewcv6ezn2ga 100000000000000000000000000azeta + # 3. Copy the genesis.json to all the nodes .And use it to create a gentx for every node zetacored gentx operator 1000000000000000000000azeta --chain-id=$CHAINID --keyring-backend=$KEYRING --gas-prices 20000000000azeta # Copy host gentx to other nodes diff --git a/x/crosschain/keeper/evm_hooks.go b/x/crosschain/keeper/evm_hooks.go index f2b9f6bc8d..5b896473a8 100644 --- a/x/crosschain/keeper/evm_hooks.go +++ b/x/crosschain/keeper/evm_hooks.go @@ -1,17 +1,14 @@ package keeper import ( - "bytes" "encoding/hex" "fmt" "math/big" - "strings" errorsmod "cosmossdk.io/errors" "cosmossdk.io/math" "github.com/btcsuite/btcutil" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/accounts/abi/bind" ethcommon "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core" @@ -21,7 +18,6 @@ import ( zrc20 "github.com/zeta-chain/protocol-contracts/pkg/contracts/zevm/zrc20.sol" "github.com/zeta-chain/zetacore/cmd/zetacored/config" "github.com/zeta-chain/zetacore/common" - "github.com/zeta-chain/zetacore/x/crosschain/types" fungibletypes "github.com/zeta-chain/zetacore/x/fungible/types" zetaObserverTypes "github.com/zeta-chain/zetacore/x/observer/types" @@ -49,27 +45,6 @@ func (k Keeper) PostTxProcessing( msg core.Message, receipt *ethtypes.Receipt, ) error { - abiStr := "[{\"inputs\":[{\"internalType\":\"string\",\"name\":\"name_\",\"type\":\"string\"}," + - "{\"internalType\":\"string\",\"name\":\"symbol_\",\"type\":\"string\"},{\"internalType\":\"uint8\",\"name\":\"decimals_\",\"type\":\"uint8\"},{\"internalType\":\"uint256\",\"name\":\"chainid_\",\"type\":\"uint256\"},{\"internalType\":\"enumCoinType\",\"name\":\"coinType_\",\"type\":\"uint8\"},{\"internalType\":\"uint256\",\"name\":\"gasLimit_\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"systemContractAddress_\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"CallerIsNotFungibleModule\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"GasFeeTransferFailed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidSender\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"LowAllowance\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"LowBalance\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZeroAddress\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZeroGasCoin\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZeroGasPrice\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"Approval\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"from\",\"type\":\"bytes\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"Deposit\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"Transfer\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"gasLimit\",\"type\":\"uint256\"}],\"name\":\"UpdatedGasLimit\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"protocolFlatFee\",\"type\":\"uint256\"}],\"name\":\"UpdatedProtocolFlatFee\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"systemContract\",\"type\":\"address\"}],\"name\":\"UpdatedSystemContract\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"to\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"gasfee\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"protocolFlatFee\",\"type\":\"uint256\"}],\"name\":\"Withdrawal\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"CHAIN_ID\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"COIN_TYPE\",\"outputs\":[{\"internalType\":\"enumCoinType\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"FUNGIBLE_MODULE_ADDRESS\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"GAS_LIMIT\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"PROTOCOL_FLAT_FEE\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"SYSTEM_CONTRACT_ADDRESS\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"}],\"name\":\"allowance\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"approve\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"balanceOf\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"burn\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"decimals\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"decreaseAllowance\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"deposit\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"increaseAllowance\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"name\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"symbol\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"totalSupply\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"transfer\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"transferFrom\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"gasLimit\",\"type\":\"uint256\"}],\"name\":\"updateGasLimit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"protocolFlatFee\",\"type\":\"uint256\"}],\"name\":\"updateProtocolFlatFee\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"}],\"name\":\"updateSystemContractAddress\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"to\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"withdraw\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"withdrawGasFee\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]" - - inputData := msg.Data() - if len(inputData) >= 4 { - // Check if method exist in ABI - methodID := inputData[:4] - parsedABI, err := abi.JSON(strings.NewReader(abiStr)) - if err != nil { - return err - } - for _, method := range parsedABI.Methods { - if bytes.Equal(methodID, method.ID) { - // Check if deactivated method - if method.Name == "increaseAllowance" || method.Name == "decreaseAllowance" { - return fmt.Errorf("%s not allowed", method.Name) - } - } - } - } - var emittingContract ethcommon.Address if msg.To() != nil { emittingContract = *msg.To() diff --git a/x/crosschain/keeper/migrator.go b/x/crosschain/keeper/migrator.go index 30c1274b8a..cfdc1bba94 100644 --- a/x/crosschain/keeper/migrator.go +++ b/x/crosschain/keeper/migrator.go @@ -31,5 +31,5 @@ func (m Migrator) Migrate2to3(ctx sdk.Context) error { // Migrate3to4 migrates the store from consensus version 3 to 4 func (m Migrator) Migrate3to4(ctx sdk.Context) error { - return v4.MigrateStore(ctx, m.crossChainKeeper.zetaObserverKeeper, m.crossChainKeeper.storeKey, m.crossChainKeeper.cdc) + return v4.MigrateStore(ctx, m.crossChainKeeper.zetaObserverKeeper, m.crossChainKeeper) } diff --git a/x/crosschain/migrations/v4/migrate.go b/x/crosschain/migrations/v4/migrate.go index 1d94748fcc..e4b368e44c 100644 --- a/x/crosschain/migrations/v4/migrate.go +++ b/x/crosschain/migrations/v4/migrate.go @@ -13,24 +13,34 @@ import ( observertypes "github.com/zeta-chain/zetacore/x/observer/types" ) +// crosschainKeeper is an interface to prevent cyclic dependency +type crosschainKeeper interface { + GetStoreKey() storetypes.StoreKey + GetCodec() codec.Codec + GetAllCrossChainTx(ctx sdk.Context) []types.CrossChainTx + AddFinalizedInbound(ctx sdk.Context, inboundTxHash string, senderChainID int64, height uint64) +} + // MigrateStore migrates the x/crosschain module state from the consensus version 3 to 4 // It initializes the aborted zeta amount to 0 func MigrateStore( ctx sdk.Context, observerKeeper types.ObserverKeeper, - crossChainStoreKey storetypes.StoreKey, - cdc codec.BinaryCodec, + crosschainKeeper crosschainKeeper, ) error { - SetZetaAccounting(ctx, crossChainStoreKey, cdc) - MoveTssToObserverModule(ctx, observerKeeper, crossChainStoreKey, cdc) - MoveNonceToObserverModule(ctx, observerKeeper, crossChainStoreKey, cdc) + SetZetaAccounting(ctx, crosschainKeeper.GetStoreKey(), crosschainKeeper.GetCodec()) + MoveTssToObserverModule(ctx, observerKeeper, crosschainKeeper.GetStoreKey(), crosschainKeeper.GetCodec()) + MoveNonceToObserverModule(ctx, observerKeeper, crosschainKeeper.GetStoreKey(), crosschainKeeper.GetCodec()) + SetBitcoinFinalizedInbound(ctx, crosschainKeeper) + return nil } func SetZetaAccounting( ctx sdk.Context, crossChainStoreKey storetypes.StoreKey, - cdc codec.BinaryCodec) { + cdc codec.BinaryCodec, +) { p := types.KeyPrefix(fmt.Sprintf("%s", types.SendKey)) prefixedStore := prefix.NewStore(ctx.KVStore(crossChainStoreKey), p) abortedAmountZeta := sdkmath.ZeroUint() @@ -124,7 +134,8 @@ func MoveNonceToObserverModule( func MoveTssToObserverModule(ctx sdk.Context, observerKeeper types.ObserverKeeper, crossChainStoreKey storetypes.StoreKey, - cdc codec.BinaryCodec) { + cdc codec.BinaryCodec, +) { // Using New Types from observer module as the structure is the same var tss observertypes.TSS var tssHistory []observertypes.TSS @@ -159,3 +170,21 @@ func MoveTssToObserverModule(ctx sdk.Context, observerKeeper.SetTSS(ctx, tss) } } + +// SetBitcoinFinalizedInbound sets the finalized inbound for bitcoin chains to prevent new ballots from being created with same intxhash +func SetBitcoinFinalizedInbound(ctx sdk.Context, crosschainKeeper crosschainKeeper) { + for _, cctx := range crosschainKeeper.GetAllCrossChainTx(ctx) { + if cctx.InboundTxParams != nil { + // check if bitcoin inbound + if common.IsBitcoinChain(cctx.InboundTxParams.SenderChainId) { + // add finalized inbound + crosschainKeeper.AddFinalizedInbound( + ctx, + cctx.InboundTxParams.InboundTxObservedHash, + cctx.InboundTxParams.SenderChainId, + 0, + ) + } + } + } +} diff --git a/x/crosschain/migrations/v4/migrate_test.go b/x/crosschain/migrations/v4/migrate_test.go index eb119873e1..5ff2f9ee54 100644 --- a/x/crosschain/migrations/v4/migrate_test.go +++ b/x/crosschain/migrations/v4/migrate_test.go @@ -10,6 +10,7 @@ import ( "github.com/cosmos/cosmos-sdk/store/prefix" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" "github.com/zeta-chain/zetacore/common" keepertest "github.com/zeta-chain/zetacore/testutil/keeper" "github.com/zeta-chain/zetacore/testutil/sample" @@ -23,7 +24,7 @@ func TestMigrateStore(t *testing.T) { t.Run("test migrate store add zeta accounting", func(t *testing.T) { k, ctx, _, _ := keepertest.CrosschainKeeper(t) amountZeta := SetRandomCctx(ctx, *k) - err := v4.MigrateStore(ctx, k.GetObserverKeeper(), k.GetStoreKey(), k.GetCodec()) + err := v4.MigrateStore(ctx, k.GetObserverKeeper(), k) assert.NoError(t, err) zetaAccounting, found := k.GetZetaAccounting(ctx) assert.True(t, found) @@ -44,7 +45,7 @@ func TestMigrateStore(t *testing.T) { store.Set(observertypes.KeyPrefix(fmt.Sprintf("%d", tss1.FinalizedZetaHeight)), tss1Bytes) store.Set(observertypes.KeyPrefix(fmt.Sprintf("%d", tss2.FinalizedZetaHeight)), tss2Bytes) - err := v4.MigrateStore(ctx, k.GetObserverKeeper(), k.GetStoreKey(), k.GetCodec()) + err := v4.MigrateStore(ctx, k.GetObserverKeeper(), k) assert.NoError(t, err) tss, found := zk.ObserverKeeper.GetTSS(ctx) @@ -72,7 +73,7 @@ func TestMigrateStore(t *testing.T) { for _, nonce := range nonceToCctxList { store.Set(types.KeyPrefix(fmt.Sprintf("%s-%d-%d", nonce.Tss, nonce.ChainId, nonce.Nonce)), k.GetCodec().MustMarshal(&nonce)) } - err := v4.MigrateStore(ctx, k.GetObserverKeeper(), k.GetStoreKey(), k.GetCodec()) + err := v4.MigrateStore(ctx, k.GetObserverKeeper(), k) assert.NoError(t, err) pn, err := k.GetObserverKeeper().GetAllPendingNonces(ctx) assert.NoError(t, err) @@ -85,6 +86,75 @@ func TestMigrateStore(t *testing.T) { assert.Equal(t, pendingNonces, pn) assert.Equal(t, chainNonces, k.GetObserverKeeper().GetAllChainNonces(ctx)) assert.Equal(t, nonceToCctxList, k.GetObserverKeeper().GetAllNonceToCctx(ctx)) + }) +} + +func TestSetBitcoinFinalizedInbound(t *testing.T) { + t.Run("test setting finalized inbound for Bitcoin", func(t *testing.T) { + k, ctx, _, _ := keepertest.CrosschainKeeper(t) + + // set some cctxs with Bitcoin and non-Bitcoin chains + k.SetCrossChainTx(ctx, types.CrossChainTx{ + Index: "0", + InboundTxParams: &types.InboundTxParams{ + SenderChainId: common.GoerliChain().ChainId, + InboundTxObservedHash: "0xaaa", + }, + }) + k.SetCrossChainTx(ctx, types.CrossChainTx{ + Index: "1", + InboundTxParams: &types.InboundTxParams{ + SenderChainId: common.BtcMainnetChain().ChainId, + InboundTxObservedHash: "0x111", + }, + }) + k.SetCrossChainTx(ctx, types.CrossChainTx{ + Index: "2", + InboundTxParams: &types.InboundTxParams{ + SenderChainId: common.EthChain().ChainId, + InboundTxObservedHash: "0xbbb", + }, + }) + k.SetCrossChainTx(ctx, types.CrossChainTx{ + Index: "3", + InboundTxParams: &types.InboundTxParams{ + SenderChainId: common.BtcTestNetChain().ChainId, + InboundTxObservedHash: "0x222", + }, + }) + k.SetCrossChainTx(ctx, types.CrossChainTx{ + Index: "4", + InboundTxParams: &types.InboundTxParams{ + SenderChainId: common.BtcTestNetChain().ChainId, + InboundTxObservedHash: "0x333", + }, + }) + k.SetCrossChainTx(ctx, types.CrossChainTx{ + Index: "5", + InboundTxParams: &types.InboundTxParams{ + SenderChainId: common.MumbaiChain().ChainId, + InboundTxObservedHash: "0xccc", + }, + }) + k.SetCrossChainTx(ctx, types.CrossChainTx{ + Index: "6", + InboundTxParams: &types.InboundTxParams{ + SenderChainId: common.BtcRegtestChain().ChainId, + InboundTxObservedHash: "0x444", + }, + }) + + // migration + v4.SetBitcoinFinalizedInbound(ctx, k) + + // check finalized inbound + require.False(t, k.IsFinalizedInbound(ctx, "0xaaa", common.GoerliChain().ChainId, 0)) + require.False(t, k.IsFinalizedInbound(ctx, "0xbbb", common.EthChain().ChainId, 0)) + require.False(t, k.IsFinalizedInbound(ctx, "0xccc", common.MumbaiChain().ChainId, 0)) + require.True(t, k.IsFinalizedInbound(ctx, "0x111", common.BtcMainnetChain().ChainId, 0)) + require.True(t, k.IsFinalizedInbound(ctx, "0x222", common.BtcTestNetChain().ChainId, 0)) + require.True(t, k.IsFinalizedInbound(ctx, "0x333", common.BtcTestNetChain().ChainId, 0)) + require.True(t, k.IsFinalizedInbound(ctx, "0x444", common.BtcRegtestChain().ChainId, 0)) }) } diff --git a/x/observer/keeper/migrator.go b/x/observer/keeper/migrator.go index e256358d87..47b8ecfcc7 100644 --- a/x/observer/keeper/migrator.go +++ b/x/observer/keeper/migrator.go @@ -35,5 +35,5 @@ func (m Migrator) Migrate3to4(ctx sdk.Context) error { } func (m Migrator) Migrate4to5(ctx sdk.Context) error { - return v5.MigrateStore(ctx, m.observerKeeper.storeKey, m.observerKeeper.cdc) + return v5.MigrateStore(ctx, m.observerKeeper) } diff --git a/x/observer/migrations/v4/migrate.go b/x/observer/migrations/v4/migrate.go index a23cc28dd5..7444c46233 100644 --- a/x/observer/migrations/v4/migrate.go +++ b/x/observer/migrations/v4/migrate.go @@ -19,10 +19,7 @@ type observerKeeper interface { } func MigrateStore(ctx sdk.Context, observerKeeper observerKeeper) error { - if err := MigrateCrosschainFlags(ctx, observerKeeper.StoreKey(), observerKeeper.Codec()); err != nil { - return err - } - return MigrateObserverParams(ctx, observerKeeper) + return MigrateCrosschainFlags(ctx, observerKeeper.StoreKey(), observerKeeper.Codec()) } func MigrateCrosschainFlags(ctx sdk.Context, observerStoreKey storetypes.StoreKey, cdc codec.BinaryCodec) error { @@ -45,31 +42,3 @@ func MigrateCrosschainFlags(ctx sdk.Context, observerStoreKey storetypes.StoreKe store.Set([]byte{0}, b) return nil } - -// MigrateObserverParams migrates the observer params to the chain params -// the function assumes that each oberver params entry has a corresponding chain params entry -// if the chain is not found, the observer params entry is ignored because it is considered as not supported -func MigrateObserverParams(ctx sdk.Context, observerKeeper observerKeeper) error { - chainParamsList, found := observerKeeper.GetChainParamsList(ctx) - if !found { - // no chain params found, nothing to migrate - return nil - } - - // search for the observer params with chain params entry - observerParams := observerKeeper.GetParams(ctx).ObserverParams - for _, observerParam := range observerParams { - for i := range chainParamsList.ChainParams { - // if the chain is found, update the chain params with the observer params - if chainParamsList.ChainParams[i].ChainId == observerParam.Chain.ChainId { - chainParamsList.ChainParams[i].MinObserverDelegation = observerParam.MinObserverDelegation - chainParamsList.ChainParams[i].BallotThreshold = observerParam.BallotThreshold - chainParamsList.ChainParams[i].IsSupported = observerParam.IsSupported - break - } - } - } - - observerKeeper.SetChainParamsList(ctx, chainParamsList) - return nil -} diff --git a/x/observer/migrations/v4/migrate_test.go b/x/observer/migrations/v4/migrate_test.go index 3a64fd97ab..b7d025fa60 100644 --- a/x/observer/migrations/v4/migrate_test.go +++ b/x/observer/migrations/v4/migrate_test.go @@ -4,12 +4,8 @@ import ( "testing" "github.com/cosmos/cosmos-sdk/store/prefix" - sdk "github.com/cosmos/cosmos-sdk/types" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - "github.com/zeta-chain/zetacore/common" keepertest "github.com/zeta-chain/zetacore/testutil/keeper" - "github.com/zeta-chain/zetacore/testutil/sample" v4 "github.com/zeta-chain/zetacore/x/observer/migrations/v4" "github.com/zeta-chain/zetacore/x/observer/types" ) @@ -33,75 +29,3 @@ func TestMigrateCrosschainFlags(t *testing.T) { assert.True(t, flags.BlockHeaderVerificationFlags.IsBtcTypeChainEnabled) assert.True(t, flags.BlockHeaderVerificationFlags.IsEthTypeChainEnabled) } - -func TestMigrateObserverParams(t *testing.T) { - k, ctx := keepertest.ObserverKeeper(t) - - // set chain params - previousChainParamsList := types.ChainParamsList{ - ChainParams: []*types.ChainParams{ - sample.ChainParams(1), - sample.ChainParams(2), - sample.ChainParams(3), - sample.ChainParams(4), - }, - } - k.SetChainParamsList(ctx, previousChainParamsList) - - // set observer params - dec42, err := sdk.NewDecFromStr("0.42") - require.NoError(t, err) - dec43, err := sdk.NewDecFromStr("0.43") - require.NoError(t, err) - dec1000, err := sdk.NewDecFromStr("1000.0") - require.NoError(t, err) - dec1001, err := sdk.NewDecFromStr("1001.0") - require.NoError(t, err) - params := types.Params{ - ObserverParams: []*types.ObserverParams{ - { - Chain: &common.Chain{ChainId: 2}, - BallotThreshold: dec42, - MinObserverDelegation: dec1000, - IsSupported: true, - }, - { - Chain: &common.Chain{ChainId: 3}, - BallotThreshold: dec43, - MinObserverDelegation: dec1001, - IsSupported: true, - }, - }, - } - k.SetParams(ctx, params) - - // perform migration - err = v4.MigrateObserverParams(ctx, *k) - require.NoError(t, err) - - // check chain params - newChainParamsList, found := k.GetChainParamsList(ctx) - require.True(t, found) - - // unchanged values - require.EqualValues(t, previousChainParamsList.ChainParams[0], newChainParamsList.ChainParams[0]) - require.EqualValues(t, previousChainParamsList.ChainParams[3], newChainParamsList.ChainParams[3]) - - // changed values - require.EqualValues(t, dec42, newChainParamsList.ChainParams[1].BallotThreshold) - require.EqualValues(t, dec1000, newChainParamsList.ChainParams[1].MinObserverDelegation) - require.EqualValues(t, dec43, newChainParamsList.ChainParams[2].BallotThreshold) - require.EqualValues(t, dec1001, newChainParamsList.ChainParams[2].MinObserverDelegation) - require.True(t, newChainParamsList.ChainParams[1].IsSupported) - require.True(t, newChainParamsList.ChainParams[2].IsSupported) - - // check remaining values are unchanged - previousChainParamsList.ChainParams[1].BallotThreshold = dec42 - previousChainParamsList.ChainParams[2].BallotThreshold = dec43 - previousChainParamsList.ChainParams[1].MinObserverDelegation = dec1000 - previousChainParamsList.ChainParams[2].MinObserverDelegation = dec1001 - previousChainParamsList.ChainParams[1].IsSupported = true - previousChainParamsList.ChainParams[2].IsSupported = true - require.EqualValues(t, previousChainParamsList.ChainParams[1], newChainParamsList.ChainParams[1]) - require.EqualValues(t, previousChainParamsList.ChainParams[2], newChainParamsList.ChainParams[2]) -} diff --git a/x/observer/migrations/v5/migrate.go b/x/observer/migrations/v5/migrate.go index a5666ff43b..a626ce192b 100644 --- a/x/observer/migrations/v5/migrate.go +++ b/x/observer/migrations/v5/migrate.go @@ -8,7 +8,24 @@ import ( "github.com/zeta-chain/zetacore/x/observer/types" ) -func MigrateStore(ctx sdk.Context, observerStoreKey storetypes.StoreKey, cdc codec.BinaryCodec) error { +// observerKeeper prevents circular dependency +type observerKeeper interface { + GetParams(ctx sdk.Context) types.Params + SetParams(ctx sdk.Context, params types.Params) + GetChainParamsList(ctx sdk.Context) (params types.ChainParamsList, found bool) + SetChainParamsList(ctx sdk.Context, params types.ChainParamsList) + StoreKey() storetypes.StoreKey + Codec() codec.BinaryCodec +} + +func MigrateStore(ctx sdk.Context, observerKeeper observerKeeper) error { + if err := MigrateObserverMapper(ctx, observerKeeper.StoreKey(), observerKeeper.Codec()); err != nil { + return err + } + return MigrateObserverParams(ctx, observerKeeper) +} + +func MigrateObserverMapper(ctx sdk.Context, observerStoreKey storetypes.StoreKey, cdc codec.BinaryCodec) error { var legacyObserverMappers []*types.ObserverMapper legacyObserverMapperStore := prefix.NewStore(ctx.KVStore(observerStoreKey), types.KeyPrefix(types.ObserverMapperKey)) iterator := sdk.KVStorePrefixIterator(legacyObserverMapperStore, []byte{}) @@ -35,3 +52,31 @@ func MigrateStore(ctx sdk.Context, observerStoreKey storetypes.StoreKey, cdc cod } return nil } + +// MigrateObserverParams migrates the observer params to the chain params +// the function assumes that each observer params entry has a corresponding chain params entry +// if the chain is not found, the observer params entry is ignored because it is considered as not supported +func MigrateObserverParams(ctx sdk.Context, observerKeeper observerKeeper) error { + chainParamsList, found := observerKeeper.GetChainParamsList(ctx) + if !found { + // no chain params found, nothing to migrate + return nil + } + + // search for the observer params with chain params entry + observerParams := observerKeeper.GetParams(ctx).ObserverParams + for _, observerParam := range observerParams { + for i := range chainParamsList.ChainParams { + // if the chain is found, update the chain params with the observer params + if chainParamsList.ChainParams[i].ChainId == observerParam.Chain.ChainId { + chainParamsList.ChainParams[i].MinObserverDelegation = observerParam.MinObserverDelegation + chainParamsList.ChainParams[i].BallotThreshold = observerParam.BallotThreshold + chainParamsList.ChainParams[i].IsSupported = observerParam.IsSupported + break + } + } + } + + observerKeeper.SetChainParamsList(ctx, chainParamsList) + return nil +} diff --git a/x/observer/migrations/v5/migrate_test.go b/x/observer/migrations/v5/migrate_test.go index 61e2c86739..d97b3dde69 100644 --- a/x/observer/migrations/v5/migrate_test.go +++ b/x/observer/migrations/v5/migrate_test.go @@ -6,13 +6,15 @@ import ( "github.com/cosmos/cosmos-sdk/store/prefix" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "github.com/zeta-chain/zetacore/common" keepertest "github.com/zeta-chain/zetacore/testutil/keeper" "github.com/zeta-chain/zetacore/testutil/sample" v5 "github.com/zeta-chain/zetacore/x/observer/migrations/v5" "github.com/zeta-chain/zetacore/x/observer/types" ) -func TestMigrateStore(t *testing.T) { +func TestMigrateObserverMapper(t *testing.T) { t.Run("TestMigrateStore", func(t *testing.T) { k, ctx := keepertest.ObserverKeeper(t) legacyObserverMapperStore := prefix.NewStore(ctx.KVStore(k.StoreKey()), types.KeyPrefix(types.ObserverMapperKey)) @@ -20,7 +22,7 @@ func TestMigrateStore(t *testing.T) { for _, legacyObserverMapper := range legacyObserverMapperList { legacyObserverMapperStore.Set(types.KeyPrefix(legacyObserverMapper.Index), k.Codec().MustMarshal(legacyObserverMapper)) } - err := v5.MigrateStore(ctx, k.StoreKey(), k.Codec()) + err := v5.MigrateObserverMapper(ctx, k.StoreKey(), k.Codec()) assert.NoError(t, err) observerSet, found := k.GetObserverSet(ctx) assert.True(t, found) @@ -40,3 +42,75 @@ func TestMigrateStore(t *testing.T) { assert.Equal(t, 0, len(observerMappers)) }) } + +func TestMigrateObserverParams(t *testing.T) { + k, ctx := keepertest.ObserverKeeper(t) + + // set chain params + previousChainParamsList := types.ChainParamsList{ + ChainParams: []*types.ChainParams{ + sample.ChainParams(1), + sample.ChainParams(2), + sample.ChainParams(3), + sample.ChainParams(4), + }, + } + k.SetChainParamsList(ctx, previousChainParamsList) + + // set observer params + dec42, err := sdk.NewDecFromStr("0.42") + require.NoError(t, err) + dec43, err := sdk.NewDecFromStr("0.43") + require.NoError(t, err) + dec1000, err := sdk.NewDecFromStr("1000.0") + require.NoError(t, err) + dec1001, err := sdk.NewDecFromStr("1001.0") + require.NoError(t, err) + params := types.Params{ + ObserverParams: []*types.ObserverParams{ + { + Chain: &common.Chain{ChainId: 2}, + BallotThreshold: dec42, + MinObserverDelegation: dec1000, + IsSupported: true, + }, + { + Chain: &common.Chain{ChainId: 3}, + BallotThreshold: dec43, + MinObserverDelegation: dec1001, + IsSupported: true, + }, + }, + } + k.SetParams(ctx, params) + + // perform migration + err = v5.MigrateObserverParams(ctx, *k) + require.NoError(t, err) + + // check chain params + newChainParamsList, found := k.GetChainParamsList(ctx) + require.True(t, found) + + // unchanged values + require.EqualValues(t, previousChainParamsList.ChainParams[0], newChainParamsList.ChainParams[0]) + require.EqualValues(t, previousChainParamsList.ChainParams[3], newChainParamsList.ChainParams[3]) + + // changed values + require.EqualValues(t, dec42, newChainParamsList.ChainParams[1].BallotThreshold) + require.EqualValues(t, dec1000, newChainParamsList.ChainParams[1].MinObserverDelegation) + require.EqualValues(t, dec43, newChainParamsList.ChainParams[2].BallotThreshold) + require.EqualValues(t, dec1001, newChainParamsList.ChainParams[2].MinObserverDelegation) + require.True(t, newChainParamsList.ChainParams[1].IsSupported) + require.True(t, newChainParamsList.ChainParams[2].IsSupported) + + // check remaining values are unchanged + previousChainParamsList.ChainParams[1].BallotThreshold = dec42 + previousChainParamsList.ChainParams[2].BallotThreshold = dec43 + previousChainParamsList.ChainParams[1].MinObserverDelegation = dec1000 + previousChainParamsList.ChainParams[2].MinObserverDelegation = dec1001 + previousChainParamsList.ChainParams[1].IsSupported = true + previousChainParamsList.ChainParams[2].IsSupported = true + require.EqualValues(t, previousChainParamsList.ChainParams[1], newChainParamsList.ChainParams[1]) + require.EqualValues(t, previousChainParamsList.ChainParams[2], newChainParamsList.ChainParams[2]) +} diff --git a/zetaclient/bitcoin_client.go b/zetaclient/bitcoin_client.go index 39649a0307..a316e3b4ac 100644 --- a/zetaclient/bitcoin_client.go +++ b/zetaclient/bitcoin_client.go @@ -451,9 +451,9 @@ func (ob *BitcoinChainClient) IsSendOutTxProcessed(sendHash string, nonce uint64 } else if inMempool { // still in mempool (should avoid unnecessary Tss keysign) ob.logger.ObserveOutTx.Info().Msgf("IsSendOutTxProcessed: outTx %s is still in mempool", outTxID) return true, false, nil - } else { // included - ob.setIncludedTx(nonce, txResult) } + // included + ob.setIncludedTx(nonce, txResult) // Get tx result again in case it is just included res = ob.getIncludedTx(nonce) diff --git a/zetaclient/broadcast.go b/zetaclient/broadcast.go index 5b07ea08b3..73a94f9421 100644 --- a/zetaclient/broadcast.go +++ b/zetaclient/broadcast.go @@ -6,18 +6,17 @@ import ( "strconv" "strings" - "github.com/zeta-chain/zetacore/cmd/zetacored/config" - - "github.com/zeta-chain/zetacore/common/cosmos" - "github.com/zeta-chain/zetacore/zetaclient/hsm" - "github.com/cosmos/cosmos-sdk/client" clienttx "github.com/cosmos/cosmos-sdk/client/tx" sdktypes "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/tx/signing" + authtx "github.com/cosmos/cosmos-sdk/x/auth/tx" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" flag "github.com/spf13/pflag" rpchttp "github.com/tendermint/tendermint/rpc/client/http" + "github.com/zeta-chain/zetacore/cmd/zetacored/config" + "github.com/zeta-chain/zetacore/common/cosmos" + "github.com/zeta-chain/zetacore/zetaclient/hsm" ) const ( @@ -179,3 +178,12 @@ func (b *ZetaCoreBridge) SignTx( } return clienttx.Sign(txf, name, txBuilder, overwriteSig) } + +// QueryTxResult query the result of a tx +func (b *ZetaCoreBridge) QueryTxResult(hash string) (*sdktypes.TxResponse, error) { + ctx, err := b.GetContext() + if err != nil { + return nil, err + } + return authtx.QueryTx(ctx, hash) +} diff --git a/zetaclient/tx.go b/zetaclient/tx.go index 218ac9d9a6..38a02052ed 100644 --- a/zetaclient/tx.go +++ b/zetaclient/tx.go @@ -3,6 +3,7 @@ package zetaclient import ( "fmt" "math/big" + "strings" "time" "cosmossdk.io/math" @@ -144,6 +145,9 @@ func (b *ZetaCoreBridge) PostSend(zetaGasLimit uint64, msg *types.MsgVoteOnObser for i := 0; i < DefaultRetryCount; i++ { zetaTxHash, err := b.Broadcast(zetaGasLimit, authzMsg, authzSigner) if err == nil { + // monitor the result of the transaction + go b.MonitorTxResult(zetaTxHash, true) + return zetaTxHash, ballotIndex, nil } b.logger.Debug().Err(err).Msgf("PostSend broadcast fail | Retry count : %d", i+1) @@ -205,6 +209,9 @@ func (b *ZetaCoreBridge) PostReceiveConfirmation( for i := 0; i < DefaultRetryCount; i++ { zetaTxHash, err := b.Broadcast(gasLimit, authzMsg, authzSigner) if err == nil { + // monitor the result of the transaction + go b.MonitorTxResult(zetaTxHash, true) + return zetaTxHash, ballotIndex, nil } b.logger.Debug().Err(err).Msgf("PostReceive broadcast fail | Retry count : %d", i+1) @@ -301,3 +308,40 @@ func (b *ZetaCoreBridge) PostAddBlockHeader(chainID int64, blockHash []byte, hei } return "", fmt.Errorf("post add block header failed after %d retries", DefaultRetryCount) } + +// MonitorTxResult monitors the result of a tx (used for inbound and outbound vote txs) +func (b *ZetaCoreBridge) MonitorTxResult(zetaTxHash string, isInbound bool) { + var lastErr error + ticker := 5 * time.Second + retry := 10 + prefix := "MonitorOutboundTxResult" + if isInbound { + prefix = "MonitorInboundTxResult" + } + + for i := 0; i < retry; i++ { + time.Sleep(ticker) + txResult, err := b.QueryTxResult(zetaTxHash) + if err == nil { + // the inbound vote tx shouldn't fail to execute + if strings.Contains(txResult.RawLog, "failed to execute message") { + b.logger.Error().Msgf( + "%s: failed to execute vote, txHash: %s, txResult %s", + prefix, + zetaTxHash, + txResult.String(), + ) + } + return + } + lastErr = err + } + + b.logger.Error().Err(lastErr).Msgf( + "%s: unable to query tx result for txHash %s, err %s", + prefix, + zetaTxHash, + lastErr.Error(), + ) + return +}