Skip to content

Commit

Permalink
add block header test
Browse files Browse the repository at this point in the history
  • Loading branch information
lumtis committed Dec 28, 2023
1 parent 28431c6 commit 256d5d2
Show file tree
Hide file tree
Showing 7 changed files with 163 additions and 15 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,11 @@ func bitcoinTestRoutine(
bitcoinRunner.WaitForMinedCCTX(txERC20Deposit)

// 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
if err := bitcoinRunner.RunSmokeTestsFromNames(
smoketests.AllSmokeTests,
smoketests.TestBlockHeaderBitcoinName,
smoketests.TestBitcoinWithdrawName,
smoketests.TestSendZetaOutBTCRevertName,
smoketests.TestCrosschainSwapName,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,11 @@ func ethereumTestRoutine(
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
if err := ethereumRunner.RunSmokeTestsFromNames(
smoketests.AllSmokeTests,
smoketests.TestBlockHeaderEthereumName,
smoketests.TestContextUpgradeName,
smoketests.TestEtherDepositAndCallName,
smoketests.TestDepositAndCallRefundName,
Expand Down
4 changes: 0 additions & 4 deletions contrib/localnet/orchestrator/smoketest/runner/bitcoin.go
Original file line number Diff line number Diff line change
Expand Up @@ -101,10 +101,6 @@ func (sm *SmokeTestRunner) DepositBTC() {
break
}
}

// prove the two transactions of the deposit
sm.Logger.InfoLoud("Bitcoin Merkle Proof\n")

_ = txHash1
_ = txHash2
//sm.ProveBTCTransaction(txHash1)
Expand Down
18 changes: 12 additions & 6 deletions contrib/localnet/orchestrator/smoketest/smoketests/smoketests.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ const (
TestUpdateBytecodeName = "update_bytecode"
TestEtherDepositAndCallName = "eth_deposit_and_call"
TestDepositEtherLiquidityCapName = "deposit_eth_liquidity_cap"
TestBlockHeadersName = "block_headers"
TestBlockHeaderEthereumName = "block_headers_eth"
TestBlockHeaderBitcoinName = "block_headers_bitcoin"
TestMyTestName = "my_test"
)

Expand Down Expand Up @@ -117,11 +118,16 @@ var AllSmokeTests = []runner.SmokeTest{
"deposit Ethers into ZEVM with a liquidity cap",
TestDepositEtherLiquidityCap,
},
//{
// TestBlockHeadersName,
// "fetch block headers of EVM on ZetaChain",
// TestBlockHeaders,
//},
{
TestBlockHeaderEthereumName,
"test Ethereum tx can be proven on ZetaChain",
TestEthereumMerkelProof,
},
{
TestBlockHeaderBitcoinName,
"test Bitcoin tx can be proven on ZetaChain",
TestBTCMerkelProof,
},
{
TestMyTestName,
"performing custom test",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,67 @@ package smoketests
import (
"context"
"encoding/hex"
"fmt"
"time"

"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcutil"
"github.com/zeta-chain/zetacore/common"
"github.com/zeta-chain/zetacore/common/bitcoin"
"github.com/zeta-chain/zetacore/contrib/localnet/orchestrator/smoketest/runner"
observertypes "github.com/zeta-chain/zetacore/x/observer/types"
"time"
"github.com/zeta-chain/zetacore/zetaclient"
)

var blockHeaderTimeout = 30 * time.Second
var blockHeaderBTCTimeout = 5 * time.Minute

func TestBTCMerkelProof(sm *runner.SmokeTestRunner) {
// mine blocks
stop := sm.MineBlocks()

utxos, err := sm.BtcRPCClient.ListUnspent()
if err != nil {
panic(err)
}
spendableAmount := 0.0
spendableUTXOs := 0
for _, utxo := range utxos {
if utxo.Spendable {
spendableAmount += utxo.Amount
spendableUTXOs++
}
}

if spendableAmount < 1.1 {
panic(fmt.Errorf("not enough spendable BTC to run the test; have %f", spendableAmount))
}
if spendableUTXOs < 2 {
panic(fmt.Errorf("not enough spendable BTC UTXOs to run the test; have %d", spendableUTXOs))
}

sm.Logger.Info("ListUnspent:")
sm.Logger.Info(" spendableAmount: %f", spendableAmount)
sm.Logger.Info(" spendableUTXOs: %d", spendableUTXOs)
sm.Logger.Info("Now sending two txs to TSS address...")

// send two transactions to the TSS address
txHash, err := sm.SendToTSSFromDeployerToDeposit(
sm.BTCTSSAddress,
1.1+zetaclient.BtcDepositorFeeMin,
utxos[:2],
sm.BtcRPCClient,
sm.BTCDeployerAddress,
)
if err != nil {
panic(err)
}
sm.Logger.Info("BTC tx sent: %s", txHash.String())

// check that the tx is in the block header
proveBTCTransaction(sm, txHash)

// stop mining
stop <- struct{}{}
}

func proveBTCTransaction(sm *runner.SmokeTestRunner, txHash *chainhash.Hash) {
Expand Down Expand Up @@ -81,7 +129,7 @@ func proveBTCTransaction(sm *runner.SmokeTestRunner, txHash *chainhash.Hash) {
hash := header.BlockHash()
for {
// timeout
if time.Since(startTime) > blockHeaderTimeout {
if time.Since(startTime) > blockHeaderBTCTimeout {
panic("timed out waiting for block header to show up in observer")
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,99 @@
package smoketests

import "github.com/zeta-chain/zetacore/contrib/localnet/orchestrator/smoketest/runner"
import (
"context"
"math/big"
"time"

ethtypes "github.com/ethereum/go-ethereum/core/types"
"github.com/zeta-chain/zetacore/common"
"github.com/zeta-chain/zetacore/common/ethereum"
"github.com/zeta-chain/zetacore/contrib/localnet/orchestrator/smoketest/runner"
"github.com/zeta-chain/zetacore/contrib/localnet/orchestrator/smoketest/utils"
observertypes "github.com/zeta-chain/zetacore/x/observer/types"
)

var blockHeaderETHTimeout = 5 * time.Minute

func TestEthereumMerkelProof(sm *runner.SmokeTestRunner) {
// send eth to TSS address
value := big.NewInt(100000000000000000) // in wei (0.1 eth)
signedTx, err := sm.SendEther(sm.TSSAddress, value, nil)
if err != nil {
panic(err)
}

sm.Logger.Info("GOERLI tx sent: %s; to %s, nonce %d", signedTx.Hash().String(), signedTx.To().Hex(), signedTx.Nonce())
receipt := utils.MustWaitForTxReceipt(sm.GoerliClient, signedTx, sm.Logger)
if receipt.Status == 0 {
panic("deposit failed")
}

// check that the tx is in the block header
proveEthTransaction(sm, receipt)
}

func proveEthTransaction(sm *runner.SmokeTestRunner, receipt *ethtypes.Receipt) {
startTime := time.Now()

txHash := receipt.TxHash
blockHash := receipt.BlockHash

// #nosec G701 smoketest - always in range
txIndex := int(receipt.TransactionIndex)

block, err := sm.GoerliClient.BlockByHash(context.Background(), blockHash)
if err != nil {
panic(err)
}
for {
// check timeout
if time.Since(startTime) > blockHeaderETHTimeout {
panic("timeout waiting for block header")
}

_, err := sm.ObserverClient.GetBlockHeaderByHash(context.Background(), &observertypes.QueryGetBlockHeaderByHashRequest{
BlockHash: blockHash.Bytes(),
})
if err != nil {
sm.Logger.Info("WARN: block header not found; retrying... error: %s", err.Error())
} else {
sm.Logger.Info("OK: block header found")
break
}

time.Sleep(2 * time.Second)
}

trie := ethereum.NewTrie(block.Transactions())
if trie.Hash() != block.Header().TxHash {
panic("tx root hash & block tx root mismatch")
}
txProof, err := trie.GenerateProof(txIndex)
if err != nil {
panic("error generating txProof")
}
val, err := txProof.Verify(block.TxHash(), txIndex)
if err != nil {
panic("error verifying txProof")
}
var txx ethtypes.Transaction
err = txx.UnmarshalBinary(val)
if err != nil {
panic("error unmarshalling txProof'd tx")
}
res, err := sm.ObserverClient.Prove(context.Background(), &observertypes.QueryProveRequest{
BlockHash: blockHash.Hex(),
TxIndex: int64(txIndex),
TxHash: txHash.Hex(),
Proof: common.NewEthereumProof(txProof),
ChainId: common.GoerliLocalnetChain().ChainId,
})
if err != nil {
panic(err)
}
if !res.Valid {
panic("txProof invalid") // FIXME: don't do this in production
}
sm.Logger.Info("OK: txProof verified")
}
2 changes: 1 addition & 1 deletion contrib/localnet/orchestrator/smoketest/utils/zetacore.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import (
const (
FungibleAdminName = "fungibleadmin"

CctxTimeout = 120 * time.Second
CctxTimeout = 4 * time.Minute
)

// WaitCctxMinedByInTxHash waits until cctx is mined; returns the cctxIndex (the last one)
Expand Down

0 comments on commit 256d5d2

Please sign in to comment.