diff --git a/changelog.md b/changelog.md index 56dd363d05..120b77cfd3 100644 --- a/changelog.md +++ b/changelog.md @@ -2,6 +2,12 @@ ## Unreleased +### Features + +### Fixes + +* [1535](https://github.com/zeta-chain/node/issues/1535) - Avoid voting on wrong ballots due to false blockNumber in EVM tx receipt + ## Version: v12.0.0 ### Breaking Changes @@ -35,6 +41,7 @@ Getting the correct TSS address for Bitcoin now requires proviidng the Bitcoin c ### Fixes +* [1576](https://github.com/zeta-chain/node/pull/1576) - Fix zetaclient crash due to out of bound integer conversion and log prints. * [1575](https://github.com/zeta-chain/node/issues/1575) - Skip unsupported chain parameters by IsSupported flag * [1554](https://github.com/zeta-chain/node/pull/1554) - Screen out unconfirmed UTXOs that are not created by TSS itself * [1560](https://github.com/zeta-chain/node/issues/1560) - Zetaclient post evm-chain outtx hashes only when receipt is available diff --git a/zetaclient/bitcoin_client.go b/zetaclient/bitcoin_client.go index a316e3b4ac..a82e3a44cb 100644 --- a/zetaclient/bitcoin_client.go +++ b/zetaclient/bitcoin_client.go @@ -1326,7 +1326,7 @@ func (ob *BitcoinChainClient) LoadLastBlock() error { if ob.chain.ChainId == 18444 { // bitcoin regtest: start from block 100 ob.SetLastBlockHeightScanned(100) } - ob.logger.ChainLogger.Info().Msgf("%s: start scanning from block %d", ob.chain.String(), ob.lastBlock) + ob.logger.ChainLogger.Info().Msgf("%s: start scanning from block %d", ob.chain.String(), ob.GetLastBlockHeightScanned()) return nil } diff --git a/zetaclient/evm_client.go b/zetaclient/evm_client.go index 8a68ac121e..d88ee980f9 100644 --- a/zetaclient/evm_client.go +++ b/zetaclient/evm_client.go @@ -59,7 +59,7 @@ type EVMLog struct { const ( DonationMessage = "I am rich!" TopicsZetaSent = 3 // [signature, zetaTxSenderAddress, destinationChainId] https://github.com/zeta-chain/protocol-contracts/blob/d65814debf17648a6c67d757ba03646415842790/contracts/evm/ZetaConnector.base.sol#L34 - TopicsZetaReceived = 4 // [signature, sourceChainId, destinationAddress] https://github.com/zeta-chain/protocol-contracts/blob/d65814debf17648a6c67d757ba03646415842790/contracts/evm/ZetaConnector.base.sol#L45 + TopicsZetaReceived = 4 // [signature, sourceChainId, destinationAddress, internalSendHash] https://github.com/zeta-chain/protocol-contracts/blob/d65814debf17648a6c67d757ba03646415842790/contracts/evm/ZetaConnector.base.sol#L45 TopicsZetaReverted = 3 // [signature, destinationChainId, internalSendHash] https://github.com/zeta-chain/protocol-contracts/blob/d65814debf17648a6c67d757ba03646415842790/contracts/evm/ZetaConnector.base.sol#L54 TopicsWithdrawn = 3 // [signature, recipient, asset] https://github.com/zeta-chain/protocol-contracts/blob/d65814debf17648a6c67d757ba03646415842790/contracts/evm/ERC20Custody.sol#L43 TopicsDeposited = 2 // [signature, asset] https://github.com/zeta-chain/protocol-contracts/blob/d65814debf17648a6c67d757ba03646415842790/contracts/evm/ERC20Custody.sol#L42 @@ -721,14 +721,29 @@ func (ob *EVMChainClient) checkConfirmedTx(txHash string, nonce uint64) (*ethtyp return nil, nil, false } - // check confirmations - confHeight := receipt.BlockNumber.Uint64() + ob.GetChainParams().ConfirmationCount - if confHeight >= math.MaxInt64 { - log.Error().Msgf("confirmTxByHash: confHeight is too large for txHash %s nonce %d", txHash, nonce) + // cross-check receipt against the block + block, err := ob.GetBlockByNumberCached(receipt.BlockNumber.Uint64()) + if err != nil { + log.Error().Err(err).Msgf("confirmTxByHash: GetBlockByNumberCached error, txHash %s nonce %d block %d", + txHash, nonce, receipt.BlockNumber) + return nil, nil, false + } + // #nosec G701 non negative value + if receipt.TransactionIndex >= uint(len(block.Transactions())) { + log.Error().Msgf("confirmTxByHash: transaction index %d out of range [0, %d), txHash %s nonce %d block %d", + receipt.TransactionIndex, len(block.Transactions()), txHash, nonce, receipt.BlockNumber) return nil, nil, false } - if confHeight > ob.GetLastBlockHeight() { - log.Info().Msgf("confirmTxByHash: txHash %s nonce %d included but not confirmed: receipt block %d, current block %d", + txAtIndex := block.Transactions()[receipt.TransactionIndex] + if txAtIndex.Hash() != transaction.Hash() { + log.Error().Msgf("confirmTxByHash: transaction at index %d has different hash %s, txHash %s nonce %d block %d", + receipt.TransactionIndex, txAtIndex.Hash().Hex(), txHash, nonce, receipt.BlockNumber) + return nil, nil, false + } + + // check confirmations + if !ob.HasEnoughConfirmations(receipt, ob.GetLastBlockHeight()) { + log.Debug().Msgf("confirmTxByHash: txHash %s nonce %d included but not confirmed: receipt block %d, current block %d", txHash, nonce, receipt.BlockNumber, ob.GetLastBlockHeight()) return nil, nil, false } @@ -848,11 +863,11 @@ func (ob *EVMChainClient) observeInTX(sampledLogger zerolog.Logger) error { } // get and update latest block height - header, err := ob.evmClient.HeaderByNumber(context.Background(), nil) + blockNumber, err := ob.evmClient.BlockNumber(context.Background()) if err != nil { return err } - ob.SetLastBlockHeight(header.Number.Uint64()) + ob.SetLastBlockHeight(blockNumber) // increment prom counter counter, err := ob.GetPromCounter("rpc_getBlockByNumber_count") @@ -862,10 +877,10 @@ func (ob *EVMChainClient) observeInTX(sampledLogger zerolog.Logger) error { counter.Inc() // skip if current height is too low - if header.Number.Uint64() < ob.GetChainParams().ConfirmationCount { - return fmt.Errorf("observeInTX: skipping observer, current block number %d is too low", header.Number.Uint64()) + if blockNumber < ob.GetChainParams().ConfirmationCount { + return fmt.Errorf("observeInTX: skipping observer, current block number %d is too low", blockNumber) } - confirmedBlockNum := header.Number.Uint64() - ob.GetChainParams().ConfirmationCount + confirmedBlockNum := blockNumber - ob.GetChainParams().ConfirmationCount // skip if no new block is confirmed lastScanned := ob.GetLastBlockHeightScanned() diff --git a/zetaclient/zetacore_observer.go b/zetaclient/zetacore_observer.go index 51078aefd2..aff055c74f 100644 --- a/zetaclient/zetacore_observer.go +++ b/zetaclient/zetacore_observer.go @@ -2,6 +2,7 @@ package zetaclient import ( "fmt" + "math" "strings" "time" @@ -158,7 +159,7 @@ func (co *CoreObserver) startCctxScheduler() { co.logger.ZetaChainWatcher.Error().Err(err).Msgf("couldn't get operator balance") } else { diff := co.lastOperatorBalance.Sub(balance) - if diff.GT(sdkmath.NewInt(0)) { + if diff.GT(sdkmath.NewInt(0)) && diff.LT(sdkmath.NewInt(math.MaxInt64)) { co.ts.AddFeeEntry(bn, diff.Int64()) co.lastOperatorBalance = balance } @@ -355,7 +356,7 @@ func (co *CoreObserver) getUpdatedChainOb(chainID int64) (ChainClient, error) { curParams := chainOb.GetChainParams() if common.IsEVMChain(chainID) { evmCfg, found := co.cfg.GetEVMConfig(chainID) - if found && curParams != evmCfg.ChainParams { + if found && curParams.String() != evmCfg.ChainParams.String() { chainOb.SetChainParams(evmCfg.ChainParams) co.logger.ZetaChainWatcher.Info().Msgf( "updated chain params for chainID %d, new params: %v", @@ -365,7 +366,7 @@ func (co *CoreObserver) getUpdatedChainOb(chainID int64) (ChainClient, error) { } } else if common.IsBitcoinChain(chainID) { _, btcCfg, found := co.cfg.GetBTCConfig() - if found && curParams != btcCfg.ChainParams { + if found && curParams.String() != btcCfg.ChainParams.String() { chainOb.SetChainParams(btcCfg.ChainParams) co.logger.ZetaChainWatcher.Info().Msgf( "updated chain params for Bitcoin, new params: %v",