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

test: allow running Bitcoin tests on live networks (tentative) #2303

Merged
merged 11 commits into from
Jun 6, 2024
6 changes: 3 additions & 3 deletions e2e/e2etests/helper_bitcoin.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ func withdrawBTCZRC20(r *runner.E2ERunner, to btcutil.Address, amount *big.Int)
}

// mine blocks if testing on regnet
var stop chan struct{}
var stop func()
isRegnet := chains.IsBitcoinRegnet(r.GetBitcoinChainID())
if isRegnet {
stop = r.MineBlocks()
Expand All @@ -81,7 +81,7 @@ func withdrawBTCZRC20(r *runner.E2ERunner, to btcutil.Address, amount *big.Int)
}

// mine 10 blocks to confirm the withdraw tx
_, err = r.BtcRPCClient.GenerateToAddress(10, to, nil)
_, err = r.GenerateToAddressOnLocalBitcoin(10, to)
lumtis marked this conversation as resolved.
Show resolved Hide resolved
if err != nil {
panic(err)
}
Expand Down Expand Up @@ -119,7 +119,7 @@ func withdrawBTCZRC20(r *runner.E2ERunner, to btcutil.Address, amount *big.Int)

// stop mining
if isRegnet {
stop <- struct{}{}
stop()
}

return rawTx
Expand Down
4 changes: 2 additions & 2 deletions e2e/e2etests/test_bitcoin_withdraw_invalid_address.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ func withdrawToInvalidAddress(r *runner.E2ERunner, amount *big.Int) {
}

// mine blocks if testing on regnet
var stop chan struct{}
var stop func()
isRegnet := chains.IsBitcoinRegnet(r.GetBitcoinChainID())
if isRegnet {
stop = r.MineBlocks()
Expand All @@ -66,6 +66,6 @@ func withdrawToInvalidAddress(r *runner.E2ERunner, amount *big.Int) {

// stop mining
if isRegnet {
stop <- struct{}{}
stop()
}
}
4 changes: 2 additions & 2 deletions e2e/e2etests/test_bitcoin_withdraw_multiple.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ package e2etests
// go func() {
// for {
// time.Sleep(3 * time.Second)
// _, err = r.BtcRPCClient.GenerateToAddress(1, r.BTCDeployerAddress, nil)
// _, err = r.GenerateToAddressOnLocalBitcoin(1, r.BTCDeployerAddress)
// if err != nil {
// panic(err)
// }
Expand All @@ -64,7 +64,7 @@ package e2etests
// if receipt.Status != 1 {
// panic(fmt.Errorf("withdraw receipt status is not 1"))
// }
// _, err = r.BtcRPCClient.GenerateToAddress(10, r.BTCDeployerAddress, nil)
// _, err = r.GenerateToAddressOnLocalBitcoin(10, r.BTCDeployerAddress)
// if err != nil {
// panic(err)
// }
Expand Down
28 changes: 7 additions & 21 deletions e2e/e2etests/test_crosschain_swap.go
Original file line number Diff line number Diff line change
Expand Up @@ -110,13 +110,13 @@ func TestCrosschainSwap(r *runner.E2ERunner, _ []string) {
}

// mine 10 blocks to confirm the outbound tx
_, err = r.BtcRPCClient.GenerateToAddress(10, r.BTCDeployerAddress, nil)
_, err = r.GenerateToAddressOnLocalBitcoin(10, r.BTCDeployerAddress)
if err != nil {
panic(err)
}

// mine blocks if testing on regnet
var stop chan struct{}
var stop func()
isRegnet := chains.IsBitcoinRegnet(r.GetBitcoinChainID())
if isRegnet {
stop = r.MineBlocks()
Expand All @@ -137,8 +137,8 @@ func TestCrosschainSwap(r *runner.E2ERunner, _ []string) {
r.Logger.Info("cctx2 outbound tx hash %s", cctx2.GetCurrentOutboundParam().Hash)

r.Logger.Info("******* Second test: BTC -> ERC20ZRC20")
// list deployer utxos that have at least 1 BTC
utxos, err := r.ListDeployerUTXOs(1.0)
// list deployer utxos
utxos, err := r.ListDeployerUTXOs()
lumtis marked this conversation as resolved.
Show resolved Hide resolved
if err != nil {
panic(err)
}
Expand All @@ -151,14 +151,7 @@ func TestCrosschainSwap(r *runner.E2ERunner, _ []string) {
memo = append(r.ZEVMSwapAppAddr.Bytes(), memo...)
r.Logger.Info("memo length %d", len(memo))

txID, err := r.SendToTSSFromDeployerWithMemo(
r.BTCTSSAddress,
0.01,
utxos[0:1],
r.BtcRPCClient,
memo,
r.BTCDeployerAddress,
)
txID, err := r.SendToTSSFromDeployerWithMemo(0.01, utxos[0:1], memo)
if err != nil {
panic(err)
}
Expand Down Expand Up @@ -200,14 +193,7 @@ func TestCrosschainSwap(r *runner.E2ERunner, _ []string) {
r.Logger.Info("memo length %d", len(memo))

amount := 0.1
txid, err := r.SendToTSSFromDeployerWithMemo(
r.BTCTSSAddress,
amount,
utxos[1:2],
r.BtcRPCClient,
memo,
r.BTCDeployerAddress,
)
txid, err := r.SendToTSSFromDeployerWithMemo(amount, utxos[1:2], memo)
if err != nil {
panic(err)
}
Expand Down Expand Up @@ -240,6 +226,6 @@ func TestCrosschainSwap(r *runner.E2ERunner, _ []string) {

// stop mining
if isRegnet {
stop <- struct{}{}
stop()
}
}
122 changes: 52 additions & 70 deletions e2e/runner/bitcoin.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import (

"github.com/btcsuite/btcd/btcjson"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/rpcclient"
"github.com/btcsuite/btcd/txscript"
"github.com/btcsuite/btcd/wire"
"github.com/btcsuite/btcutil"
Expand All @@ -29,8 +28,8 @@ import (

var blockHeaderBTCTimeout = 5 * time.Minute

// ListDeployerUTXOs list the deployer's UTXOs that have at least `minAmount`
func (runner *E2ERunner) ListDeployerUTXOs(minAmount float64) ([]btcjson.ListUnspentResult, error) {
// ListDeployerUTXOs list the deployer's UTXOs
func (runner *E2ERunner) ListDeployerUTXOs() ([]btcjson.ListUnspentResult, error) {
// query UTXOs from node
utxos, err := runner.BtcRPCClient.ListUnspentMinMaxAddresses(
1,
Expand All @@ -41,23 +40,15 @@ func (runner *E2ERunner) ListDeployerUTXOs(minAmount float64) ([]btcjson.ListUns
return nil, err
}

// filter UTXOs by `minAmount`
filtered := []btcjson.ListUnspentResult{}
for _, utxo := range utxos {
if utxo.Amount >= minAmount {
filtered = append(filtered, utxo)
}
}

return filtered, nil
return utxos, nil
}

// DepositBTCWithAmount deposits BTC on ZetaChain with a specific amount
func (runner *E2ERunner) DepositBTCWithAmount(amount float64) (txHash *chainhash.Hash) {
runner.Logger.Print("⏳ depositing BTC into ZEVM")

// list deployer utxos that have at least 1 BTC
utxos, err := runner.ListDeployerUTXOs(1.0)
// list deployer utxos
utxos, err := runner.ListDeployerUTXOs()
if err != nil {
panic(err)
}
Expand All @@ -72,7 +63,11 @@ func (runner *E2ERunner) DepositBTCWithAmount(amount float64) (txHash *chainhash
}

if spendableAmount < amount {
panic(fmt.Errorf("not enough spendable BTC to run the test; have %f", spendableAmount))
panic(fmt.Errorf(
"not enough spendable BTC to run the test; have %f, require %f",
spendableAmount,
amount,
))
}

runner.Logger.Info("ListUnspent:")
Expand All @@ -81,13 +76,7 @@ func (runner *E2ERunner) DepositBTCWithAmount(amount float64) (txHash *chainhash
runner.Logger.Info("Now sending two txs to TSS address...")

amount = amount + zetabitcoin.DefaultDepositorFee
txHash, err = runner.SendToTSSFromDeployerToDeposit(
runner.BTCTSSAddress,
amount,
utxos,
runner.BtcRPCClient,
runner.BTCDeployerAddress,
)
txHash, err = runner.SendToTSSFromDeployerToDeposit(amount, utxos)
if err != nil {
panic(err)
}
Expand All @@ -104,8 +93,8 @@ func (runner *E2ERunner) DepositBTC(testHeader bool) {
runner.Logger.Print("✅ BTC deposited in %s", time.Since(startTime))
}()

// list deployer utxos that have at least 1 BTC
utxos, err := runner.ListDeployerUTXOs(1.0)
// list deployer utxos
utxos, err := runner.ListDeployerUTXOs()
if err != nil {
panic(err)
}
Expand Down Expand Up @@ -133,38 +122,19 @@ func (runner *E2ERunner) DepositBTC(testHeader bool) {

// send two transactions to the TSS address
amount1 := 1.1 + zetabitcoin.DefaultDepositorFee
txHash1, err := runner.SendToTSSFromDeployerToDeposit(
runner.BTCTSSAddress,
amount1,
utxos[:2],
runner.BtcRPCClient,
runner.BTCDeployerAddress,
)
txHash1, err := runner.SendToTSSFromDeployerToDeposit(amount1, utxos[:2])
if err != nil {
panic(err)
}
amount2 := 0.05 + zetabitcoin.DefaultDepositorFee
txHash2, err := runner.SendToTSSFromDeployerToDeposit(
runner.BTCTSSAddress,
amount2,
utxos[2:4],
runner.BtcRPCClient,
runner.BTCDeployerAddress,
)
txHash2, err := runner.SendToTSSFromDeployerToDeposit(amount2, utxos[2:4])
if err != nil {
panic(err)
}

// send a donation to the TSS address to compensate for the funds minted automatically during pool creation
// and prevent accounting errors
_, err = runner.SendToTSSFromDeployerWithMemo(
runner.BTCTSSAddress,
0.11,
utxos[4:5],
runner.BtcRPCClient,
[]byte(constant.DonationMessage),
runner.BTCDeployerAddress,
)
_, err = runner.SendToTSSFromDeployerWithMemo(0.11, utxos[4:5], []byte(constant.DonationMessage))
if err != nil {
panic(err)
}
Expand Down Expand Up @@ -201,31 +171,22 @@ func (runner *E2ERunner) DepositBTC(testHeader bool) {
}
}

func (runner *E2ERunner) SendToTSSFromDeployerToDeposit(
to btcutil.Address,
amount float64,
inputUTXOs []btcjson.ListUnspentResult,
btc *rpcclient.Client,
btcDeployerAddress *btcutil.AddressWitnessPubKeyHash,
) (*chainhash.Hash, error) {
return runner.SendToTSSFromDeployerWithMemo(
to,
amount,
inputUTXOs,
btc,
runner.DeployerAddress.Bytes(),
btcDeployerAddress,
)
func (runner *E2ERunner) SendToTSSFromDeployerToDeposit(amount float64, inputUTXOs []btcjson.ListUnspentResult) (
*chainhash.Hash,
error,
) {
return runner.SendToTSSFromDeployerWithMemo(amount, inputUTXOs, runner.DeployerAddress.Bytes())
}

func (runner *E2ERunner) SendToTSSFromDeployerWithMemo(
to btcutil.Address,
amount float64,
inputUTXOs []btcjson.ListUnspentResult,
btcRPC *rpcclient.Client,
memo []byte,
btcDeployerAddress *btcutil.AddressWitnessPubKeyHash,
) (*chainhash.Hash, error) {
btcRPC := runner.BtcRPCClient
to := runner.BTCTSSAddress
btcDeployerAddress := runner.BTCDeployerAddress

// prepare inputs
inputs := make([]btcjson.TransactionInput, len(inputUTXOs))
inputSats := btcutil.Amount(0)
Expand Down Expand Up @@ -312,7 +273,7 @@ func (runner *E2ERunner) SendToTSSFromDeployerWithMemo(
panic(err)
}
runner.Logger.Info("txid: %+v", txid)
_, err = btcRPC.GenerateToAddress(6, btcDeployerAddress, nil)
_, err = runner.GenerateToAddressOnLocalBitcoin(6, btcDeployerAddress)
if err != nil {
panic(err)
}
Expand Down Expand Up @@ -359,25 +320,46 @@ func (runner *E2ERunner) GetBitcoinChainID() int64 {
return chainID
}

// IsLocalBitcoin returns true if the runner is running on a local bitcoin network
func (runner *E2ERunner) IsLocalBitcoin() bool {
lumtis marked this conversation as resolved.
Show resolved Hide resolved
return runner.BitcoinParams.Name == chains.BitcoinRegnetParams.Name
}

// GenerateToAddressOnLocalBitcoin generates blocks to an address if the runner is interacting
// with a local bitcoin network
func (runner *E2ERunner) GenerateToAddressOnLocalBitcoin(
numBlocks int64,
address btcutil.Address,
) ([]*chainhash.Hash, error) {
// if not local bitcoin network, do nothing
if runner.IsLocalBitcoin() {
return runner.BtcRPCClient.GenerateToAddress(numBlocks, address, nil)
}
return nil, nil
}

// MineBlocks mines blocks on the BTC chain at a rate of 1 blocks every 5 seconds
// and returns a channel that can be used to stop the mining
func (runner *E2ERunner) MineBlocks() chan struct{} {
stop := make(chan struct{})
func (runner *E2ERunner) MineBlocks() func() {
lumtis marked this conversation as resolved.
Show resolved Hide resolved
stopChan := make(chan struct{})
go func() {
for {
select {
case <-stop:
case <-stopChan:
return
default:
_, err := runner.BtcRPCClient.GenerateToAddress(1, runner.BTCDeployerAddress, nil)
_, err := runner.GenerateToAddressOnLocalBitcoin(1, runner.BTCDeployerAddress)
if err != nil {
panic(err)
}
time.Sleep(3 * time.Second)
}
}
}()
return stop

return func() {
close(stopChan)
}
}

// ProveBTCTransaction proves that a BTC transaction is in a block header and that the block header is in ZetaChain
Expand Down
4 changes: 2 additions & 2 deletions e2e/runner/setup_bitcoin.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,12 @@ func (runner *E2ERunner) SetupBitcoinAccount(initNetwork bool) {
}

// mine some blocks to get some BTC into the deployer address
_, err = runner.BtcRPCClient.GenerateToAddress(101, runner.BTCDeployerAddress, nil)
_, err = runner.GenerateToAddressOnLocalBitcoin(101, runner.BTCDeployerAddress)
if err != nil {
panic(err)
}

_, err = runner.BtcRPCClient.GenerateToAddress(4, runner.BTCDeployerAddress, nil)
_, err = runner.GenerateToAddressOnLocalBitcoin(4, runner.BTCDeployerAddress)
if err != nil {
panic(err)
}
Expand Down
Loading