Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: use JSON RPC for inbound tx observation (including blob tx in Decun upgrade) #1836

Merged
merged 12 commits into from
Mar 7, 2024
Merged
1 change: 1 addition & 0 deletions changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
### Features

* [1789](https://github.com/zeta-chain/node/issues/1789) - block cross-chain transactions that involve restricted addresses
* [1755](https://github.com/zeta-chain/node/issues/1755) - use evm JSON RPC for inbound tx (including blob tx) observation.
* [1815](https://github.com/zeta-chain/node/pull/1815) - add authority module for authorized actions

### Tests
Expand Down
27 changes: 17 additions & 10 deletions cmd/zetaclientd/debug.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import (
"strings"
"sync"

"github.com/ethereum/go-ethereum/ethclient"
"github.com/onrik/ethrpc"
"github.com/zeta-chain/zetacore/zetaclient/bitcoin"
corecontext "github.com/zeta-chain/zetacore/zetaclient/core_context"
"github.com/zeta-chain/zetacore/zetaclient/evm"
Expand All @@ -18,7 +20,6 @@ import (
"github.com/btcsuite/btcd/rpcclient"
sdk "github.com/cosmos/cosmos-sdk/types"
ethcommon "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/rs/zerolog"
"github.com/spf13/cobra"
"github.com/zeta-chain/zetacore/common"
Expand Down Expand Up @@ -101,26 +102,33 @@ func DebugCmd() *cobra.Command {
}
ob.WithZetaClient(bridge)
ob.WithLogger(chainLogger)
client := &ethclient.Client{}
var ethRPC *ethrpc.EthRPC
var client *ethclient.Client
coinType := common.CoinType_Cmd
for chain, evmConfig := range cfg.GetAllEVMConfigs() {
if chainID == chain {
ethRPC = ethrpc.NewEthRPC(evmConfig.Endpoint)
client, err = ethclient.Dial(evmConfig.Endpoint)
if err != nil {
return err
}
ob.WithEvmClient(client)
ob.WithEvmJSONRPC(ethRPC)
ob.WithChain(*common.GetChainFromChainID(chainID))
}
}
hash := ethcommon.HexToHash(txHash)
tx, isPending, err := client.TransactionByHash(context.Background(), hash)
tx, isPending, err := ob.TransactionByHash(txHash)
if err != nil {
return fmt.Errorf("tx not found on chain %s , %d", err.Error(), chain.ChainId)
}
if isPending {
return fmt.Errorf("tx is still pending")
}
receipt, err := client.TransactionReceipt(context.Background(), hash)
if err != nil {
return fmt.Errorf("tx receipt not found on chain %s, %d", err.Error(), chain.ChainId)
}

for _, chainParams := range chainParams {
if chainParams.ChainId == chainID {
Expand All @@ -135,32 +143,31 @@ func DebugCmd() *cobra.Command {
return fmt.Errorf("missing chain params for chain %d", chainID)
}
evmChainParams.ZetaTokenContractAddress = chainParams.ZetaTokenContractAddress
if strings.EqualFold(tx.To().Hex(), chainParams.ConnectorContractAddress) {
if strings.EqualFold(tx.To, chainParams.ConnectorContractAddress) {
coinType = common.CoinType_Zeta
} else if strings.EqualFold(tx.To().Hex(), chainParams.Erc20CustodyContractAddress) {
} else if strings.EqualFold(tx.To, chainParams.Erc20CustodyContractAddress) {
coinType = common.CoinType_ERC20
} else if strings.EqualFold(tx.To().Hex(), tssEthAddress) {
} else if strings.EqualFold(tx.To, tssEthAddress) {
coinType = common.CoinType_Gas
}

}
}

switch coinType {
case common.CoinType_Zeta:
ballotIdentifier, err = ob.CheckReceiptForCoinTypeZeta(txHash, false)
ballotIdentifier, err = ob.CheckAndVoteInboundTokenZeta(tx, receipt, false)
if err != nil {
return err
}

case common.CoinType_ERC20:
ballotIdentifier, err = ob.CheckReceiptForCoinTypeERC20(txHash, false)
ballotIdentifier, err = ob.CheckAndVoteInboundTokenERC20(tx, receipt, false)
if err != nil {
return err
}

case common.CoinType_Gas:
ballotIdentifier, err = ob.CheckReceiptForCoinTypeGas(txHash, false)
ballotIdentifier, err = ob.CheckAndVoteInboundTokenGas(tx, receipt, false)
if err != nil {
return err
}
Expand Down
4 changes: 4 additions & 0 deletions cmd/zetaclientd/start.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"syscall"
"time"

ethcommon "github.com/ethereum/go-ethereum/common"
"github.com/libp2p/go-libp2p/core"
maddr "github.com/multiformats/go-multiaddr"
"github.com/pkg/errors"
Expand Down Expand Up @@ -208,6 +209,9 @@ func start(_ *cobra.Command, _ []string) error {

// Defensive check: Make sure the tss address is set to the current TSS address and not the newly generated one
tss.CurrentPubkey = currentTss.TssPubkey
if tss.EVMAddress() == (ethcommon.Address{}) || tss.BTCAddress() == "" {
startLogger.Error().Msg("TSS address is not set in zetacore")
}
startLogger.Info().Msgf("Current TSS address \n ETH : %s \n BTC : %s \n PubKey : %s ", tss.EVMAddress(), tss.BTCAddress(), tss.CurrentPubkey)
if len(appContext.ZetaCoreContext().GetEnabledChains()) == 0 {
startLogger.Error().Msgf("No chains enabled in updated config %s ", cfg.String())
Expand Down
11 changes: 11 additions & 0 deletions cmd/zetaclientd/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,9 @@ func CreateSignerMap(
loggers.Std.Error().Msgf("ChainParam not found for chain %s", evmConfig.Chain.String())
continue
}
if !evmChainParams.IsSupported {
continue
}
mpiAddress := ethcommon.HexToAddress(evmChainParams.ConnectorContractAddress)
erc20CustodyAddress := ethcommon.HexToAddress(evmChainParams.Erc20CustodyContractAddress)
signer, err := evm.NewEVMSigner(evmConfig.Chain, evmConfig.Endpoint, tss, config.GetConnectorABI(), config.GetERC20CustodyABI(), mpiAddress, erc20CustodyAddress, loggers, ts)
Expand Down Expand Up @@ -104,6 +107,14 @@ func CreateChainClientMap(
if evmConfig.Chain.IsZetaChain() {
continue
}
evmChainParams, found := appContext.ZetaCoreContext().GetEVMChainParams(evmConfig.Chain.ChainId)
if !found {
loggers.Std.Error().Msgf("ChainParam not found for chain %s", evmConfig.Chain.String())
continue
}
if !evmChainParams.IsSupported {
continue
}
co, err := evm.NewEVMChainClient(appContext, bridge, tss, dbpath, loggers, *evmConfig, ts)
if err != nil {
loggers.Std.Error().Err(err).Msgf("NewEVMChainClient error for chain %s", evmConfig.Chain.String())
Expand Down
4 changes: 4 additions & 0 deletions common/constant.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,8 @@ package common
const (
// DefaultGasPriceMultiplier is the default gas price multiplier for outbond txs
DefaultGasPriceMultiplier = 2

// DonationMessage is the message for donation transactions
ws4charlie marked this conversation as resolved.
Show resolved Hide resolved
// Transaction sent to the TSS or ERC20 Custody address containing this message are considered as a donation
DonationMessage = "I am rich!"
)
4 changes: 2 additions & 2 deletions e2e/e2etests/test_donation.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ package e2etests
import (
"math/big"

"github.com/zeta-chain/zetacore/common"
"github.com/zeta-chain/zetacore/e2e/runner"
"github.com/zeta-chain/zetacore/e2e/utils"
"github.com/zeta-chain/zetacore/zetaclient/evm"
)

// TestDonationEther tests donation of ether to the tss address
Expand All @@ -19,7 +19,7 @@ func TestDonationEther(r *runner.E2ERunner, args []string) {
panic("Invalid amount specified for TestDonationEther.")
}

txDonation, err := r.SendEther(r.TSSAddress, amount, []byte(evm.DonationMessage))
txDonation, err := r.SendEther(r.TSSAddress, amount, []byte(common.DonationMessage))
if err != nil {
panic(err)
}
Expand Down
2 changes: 1 addition & 1 deletion e2e/runner/bitcoin.go
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ func (runner *E2ERunner) DepositBTC(testHeader bool) {
0.11,
utxos[4:5],
btc,
[]byte(zetabitcoin.DonationMessage),
[]byte(common.DonationMessage),
runner.BTCDeployerAddress,
)
if err != nil {
Expand Down
4 changes: 2 additions & 2 deletions e2e/runner/setup_evm.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@ import (
"github.com/zeta-chain/protocol-contracts/pkg/contracts/evm/erc20custody.sol"
zetaeth "github.com/zeta-chain/protocol-contracts/pkg/contracts/evm/zeta.eth.sol"
zetaconnectoreth "github.com/zeta-chain/protocol-contracts/pkg/contracts/evm/zetaconnector.eth.sol"
"github.com/zeta-chain/zetacore/common"
"github.com/zeta-chain/zetacore/e2e/config"
"github.com/zeta-chain/zetacore/e2e/contracts/erc20"
"github.com/zeta-chain/zetacore/e2e/contracts/testdapp"
"github.com/zeta-chain/zetacore/e2e/utils"
"github.com/zeta-chain/zetacore/zetaclient/evm"
)

const (
Expand Down Expand Up @@ -62,7 +62,7 @@ func (runner *E2ERunner) SetupEVM(contractsDeployed bool) {

// donate to the TSS address to avoid account errors because deploying gas token ZRC20 will automatically mint
// gas token on ZetaChain to initialize the pool
txDonation, err := runner.SendEther(runner.TSSAddress, big.NewInt(101000000000000000), []byte(evm.DonationMessage))
txDonation, err := runner.SendEther(runner.TSSAddress, big.NewInt(101000000000000000), []byte(common.DonationMessage))
if err != nil {
panic(err)
}
Expand Down
3 changes: 1 addition & 2 deletions zetaclient/bitcoin/bitcoin_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,6 @@
btcBlocksPerDay = 144 // for LRU block cache size
bigValueSats = 200000000 // 2 BTC
bigValueConfirmationCount = 6 // 6 confirmations for value >= 2 BTC
DonationMessage = "I am rich!"
)

func (ob *BTCChainClient) WithZetaClient(bridge *zetabridge.ZetaCoreBridge) {
Expand Down Expand Up @@ -769,7 +768,7 @@
logger.Warn().Err(err).Msgf("error hex decoding memo")
return nil, fmt.Errorf("error hex decoding memo: %s", err)
}
if bytes.Equal(memoBytes, []byte(DonationMessage)) {
if bytes.Equal(memoBytes, []byte(common.DonationMessage)) {

Check warning on line 771 in zetaclient/bitcoin/bitcoin_client.go

View check run for this annotation

Codecov / codecov/patch

zetaclient/bitcoin/bitcoin_client.go#L771

Added line #L771 was not covered by tests
logger.Info().Msgf("donation tx: %s; value %f", tx.Txid, value)
return nil, fmt.Errorf("donation tx: %s; value %f", tx.Txid, value)
}
Expand Down
45 changes: 16 additions & 29 deletions zetaclient/bitcoin/bitcoin_client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ import (
"github.com/rs/zerolog/log"
"github.com/stretchr/testify/require"
"github.com/zeta-chain/zetacore/common"
crosschaintypes "github.com/zeta-chain/zetacore/x/crosschain/types"
observertypes "github.com/zeta-chain/zetacore/x/observer/types"
"github.com/zeta-chain/zetacore/zetaclient/testutils"
"github.com/zeta-chain/zetacore/zetaclient/testutils/stub"
Expand All @@ -30,18 +29,6 @@ func MockBTCClientMainnet() *BTCChainClient {
}
}

// LoadTxRawResultNCctx loads archived outtx raw result and corresponding cctx
func LoadTxRawResultNCctx(t *testing.T, fileTxResult string, fileCctx string) (btcjson.TxRawResult, *crosschaintypes.CrossChainTx) {
var rawResult btcjson.TxRawResult
err := testutils.LoadObjectFromJSONFile(&rawResult, path.Join("../", testutils.TestDataPathBTC, "outtx_8332_148_raw_result.json"))
require.NoError(t, err)

var cctx crosschaintypes.CrossChainTx
err = testutils.LoadObjectFromJSONFile(&cctx, path.Join("../", testutils.TestDataPathCctx, "cctx_8332_148.json"))
require.NoError(t, err)
return rawResult, &cctx
}

func TestConfirmationThreshold(t *testing.T) {
client := &BTCChainClient{Mu: &sync.Mutex{}}
t.Run("should return confirmations in chain param", func(t *testing.T) {
Expand Down Expand Up @@ -194,20 +181,20 @@ func TestCalcDepositorFee828440(t *testing.T) {
func TestCheckTSSVout(t *testing.T) {
// the archived outtx raw result file and cctx file
// https://blockstream.info/tx/030cd813443f7b70cc6d8a544d320c6d8465e4528fc0f3410b599dc0b26753a0
fileCctx := path.Join("../", testutils.TestDataPathCctx, "cctx_8332_148.json")
fileTxResult := path.Join("../", testutils.TestDataPathBTC, "outtx_8332_148_raw_result.json")
chainID := int64(8332)
nonce := uint64(148)

// create mainnet mock client
btcClient := MockBTCClientMainnet()

t.Run("valid TSS vout should pass", func(t *testing.T) {
rawResult, cctx := LoadTxRawResultNCctx(t, fileTxResult, fileCctx)
rawResult, cctx := testutils.LoadBTCTxRawResultNCctx(t, chainID, nonce)
params := cctx.GetCurrentOutTxParam()
err := btcClient.checkTSSVout(params, rawResult.Vout)
require.NoError(t, err)
})
t.Run("should fail if vout length < 2 or > 3", func(t *testing.T) {
_, cctx := LoadTxRawResultNCctx(t, fileTxResult, fileCctx)
_, cctx := testutils.LoadBTCTxRawResultNCctx(t, chainID, nonce)
params := cctx.GetCurrentOutTxParam()

err := btcClient.checkTSSVout(params, []btcjson.Vout{{}})
Expand All @@ -217,7 +204,7 @@ func TestCheckTSSVout(t *testing.T) {
require.ErrorContains(t, err, "invalid number of vouts")
})
t.Run("should fail if vout 0 is not to the TSS address", func(t *testing.T) {
rawResult, cctx := LoadTxRawResultNCctx(t, fileTxResult, fileCctx)
rawResult, cctx := testutils.LoadBTCTxRawResultNCctx(t, chainID, nonce)
params := cctx.GetCurrentOutTxParam()

// not TSS address, bc1qh297vdt8xq6df5xae9z8gzd4jsu9a392mp0dus
Expand All @@ -226,7 +213,7 @@ func TestCheckTSSVout(t *testing.T) {
require.ErrorContains(t, err, "not match TSS address")
})
t.Run("should fail if vout 0 not match nonce mark", func(t *testing.T) {
rawResult, cctx := LoadTxRawResultNCctx(t, fileTxResult, fileCctx)
rawResult, cctx := testutils.LoadBTCTxRawResultNCctx(t, chainID, nonce)
params := cctx.GetCurrentOutTxParam()

// not match nonce mark
Expand All @@ -235,7 +222,7 @@ func TestCheckTSSVout(t *testing.T) {
require.ErrorContains(t, err, "not match nonce-mark amount")
})
t.Run("should fail if vout 1 is not to the receiver address", func(t *testing.T) {
rawResult, cctx := LoadTxRawResultNCctx(t, fileTxResult, fileCctx)
rawResult, cctx := testutils.LoadBTCTxRawResultNCctx(t, chainID, nonce)
params := cctx.GetCurrentOutTxParam()

// not receiver address, bc1qh297vdt8xq6df5xae9z8gzd4jsu9a392mp0dus
Expand All @@ -244,7 +231,7 @@ func TestCheckTSSVout(t *testing.T) {
require.ErrorContains(t, err, "not match params receiver")
})
t.Run("should fail if vout 1 not match payment amount", func(t *testing.T) {
rawResult, cctx := LoadTxRawResultNCctx(t, fileTxResult, fileCctx)
rawResult, cctx := testutils.LoadBTCTxRawResultNCctx(t, chainID, nonce)
params := cctx.GetCurrentOutTxParam()

// not match payment amount
Expand All @@ -253,7 +240,7 @@ func TestCheckTSSVout(t *testing.T) {
require.ErrorContains(t, err, "not match params amount")
})
t.Run("should fail if vout 2 is not to the TSS address", func(t *testing.T) {
rawResult, cctx := LoadTxRawResultNCctx(t, fileTxResult, fileCctx)
rawResult, cctx := testutils.LoadBTCTxRawResultNCctx(t, chainID, nonce)
params := cctx.GetCurrentOutTxParam()

// not TSS address, bc1qh297vdt8xq6df5xae9z8gzd4jsu9a392mp0dus
Expand All @@ -266,15 +253,15 @@ func TestCheckTSSVout(t *testing.T) {
func TestCheckTSSVoutCancelled(t *testing.T) {
// the archived outtx raw result file and cctx file
// https://blockstream.info/tx/030cd813443f7b70cc6d8a544d320c6d8465e4528fc0f3410b599dc0b26753a0
fileCctx := path.Join("../", testutils.TestDataPathCctx, "cctx_8332_148.json")
fileTxResult := path.Join("../", testutils.TestDataPathBTC, "outtx_8332_148_raw_result.json")
chainID := int64(8332)
nonce := uint64(148)

// create mainnet mock client
btcClient := MockBTCClientMainnet()

t.Run("valid TSS vout should pass", func(t *testing.T) {
// remove change vout to simulate cancelled tx
rawResult, cctx := LoadTxRawResultNCctx(t, fileTxResult, fileCctx)
rawResult, cctx := testutils.LoadBTCTxRawResultNCctx(t, chainID, nonce)
rawResult.Vout[1] = rawResult.Vout[2]
rawResult.Vout = rawResult.Vout[:2]
params := cctx.GetCurrentOutTxParam()
Expand All @@ -283,7 +270,7 @@ func TestCheckTSSVoutCancelled(t *testing.T) {
require.NoError(t, err)
})
t.Run("should fail if vout length < 1 or > 2", func(t *testing.T) {
_, cctx := LoadTxRawResultNCctx(t, fileTxResult, fileCctx)
_, cctx := testutils.LoadBTCTxRawResultNCctx(t, chainID, nonce)
params := cctx.GetCurrentOutTxParam()

err := btcClient.checkTSSVoutCancelled(params, []btcjson.Vout{})
Expand All @@ -294,7 +281,7 @@ func TestCheckTSSVoutCancelled(t *testing.T) {
})
t.Run("should fail if vout 0 is not to the TSS address", func(t *testing.T) {
// remove change vout to simulate cancelled tx
rawResult, cctx := LoadTxRawResultNCctx(t, fileTxResult, fileCctx)
rawResult, cctx := testutils.LoadBTCTxRawResultNCctx(t, chainID, nonce)
rawResult.Vout[1] = rawResult.Vout[2]
rawResult.Vout = rawResult.Vout[:2]
params := cctx.GetCurrentOutTxParam()
Expand All @@ -306,7 +293,7 @@ func TestCheckTSSVoutCancelled(t *testing.T) {
})
t.Run("should fail if vout 0 not match nonce mark", func(t *testing.T) {
// remove change vout to simulate cancelled tx
rawResult, cctx := LoadTxRawResultNCctx(t, fileTxResult, fileCctx)
rawResult, cctx := testutils.LoadBTCTxRawResultNCctx(t, chainID, nonce)
rawResult.Vout[1] = rawResult.Vout[2]
rawResult.Vout = rawResult.Vout[:2]
params := cctx.GetCurrentOutTxParam()
Expand All @@ -318,7 +305,7 @@ func TestCheckTSSVoutCancelled(t *testing.T) {
})
t.Run("should fail if vout 1 is not to the TSS address", func(t *testing.T) {
// remove change vout to simulate cancelled tx
rawResult, cctx := LoadTxRawResultNCctx(t, fileTxResult, fileCctx)
rawResult, cctx := testutils.LoadBTCTxRawResultNCctx(t, chainID, nonce)
rawResult.Vout[1] = rawResult.Vout[2]
rawResult.Vout = rawResult.Vout[:2]
params := cctx.GetCurrentOutTxParam()
Expand Down
Loading
Loading