Skip to content

Commit

Permalink
refactor: replace docker-based inscription builder sidecar with Golan…
Browse files Browse the repository at this point in the history
…g implementation (#3082)

* initiate bitcoin inscription builder using golang

* use the tokenizer in the upgraded btcd package

* add changelog entry

* fix CI unit test failure

* replace 80 with btcd defined constant; update comments

* replace hardcoded number with btcd defined constant

* fix coderabbit comment and tidy go mod

* remove randomness in E2E fee estimation
  • Loading branch information
ws4charlie authored Nov 4, 2024
1 parent b317941 commit 7474ab5
Show file tree
Hide file tree
Showing 15 changed files with 304 additions and 345 deletions.
1 change: 1 addition & 0 deletions changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
* [2899](https://github.com/zeta-chain/node/pull/2899) - remove btc deposit fee v1 and improve unit tests
* [2952](https://github.com/zeta-chain/node/pull/2952) - add error_message to cctx.status
* [3039](https://github.com/zeta-chain/node/pull/3039) - use `btcd` native APIs to handle Bitcoin Taproot address
* [3082](https://github.com/zeta-chain/node/pull/3082) - replace docker-based bitcoin sidecar inscription build with Golang implementation

### Tests

Expand Down
1 change: 1 addition & 0 deletions cmd/zetae2e/local/local.go
Original file line number Diff line number Diff line change
Expand Up @@ -310,6 +310,7 @@ func localE2ETest(cmd *cobra.Command, _ []string) {
e2etests.TestBitcoinStdMemoDepositAndCallName,
e2etests.TestBitcoinStdMemoDepositAndCallRevertName,
e2etests.TestBitcoinStdMemoDepositAndCallRevertOtherAddressName,
e2etests.TestBitcoinStdMemoInscribedDepositAndCallName,
e2etests.TestBitcoinWithdrawSegWitName,
e2etests.TestBitcoinWithdrawInvalidAddressName,
e2etests.TestZetaWithdrawBTCRevertName,
Expand Down
12 changes: 0 additions & 12 deletions contrib/localnet/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -227,18 +227,6 @@ services:
-rpcauth=smoketest:63acf9b8dccecce914d85ff8c044b78b$$5892f9bbc84f4364e79f0970039f88bdd823f168d4acc76099ab97b14a766a99
-txindex=1

bitcoin-node-sidecar:
image: ghcr.io/zeta-chain/node-localnet-bitcoin-sidecar:e0205d7
container_name: bitcoin-node-sidecar
hostname: bitcoin-node-sidecar
networks:
mynetwork:
ipv4_address: 172.20.0.111
environment:
- PORT=8000
ports:
- "8000:8000"

solana:
image: solana-local:latest
container_name: solana
Expand Down
18 changes: 10 additions & 8 deletions e2e/e2etests/e2etests.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ const (
TestBitcoinStdMemoDepositAndCallName = "bitcoin_std_memo_deposit_and_call"
TestBitcoinStdMemoDepositAndCallRevertName = "bitcoin_std_memo_deposit_and_call_revert"
TestBitcoinStdMemoDepositAndCallRevertOtherAddressName = "bitcoin_std_memo_deposit_and_call_revert_other_address"
TestBitcoinStdMemoInscribedDepositAndCallName = "bitcoin_std_memo_inscribed_deposit_and_call"
TestBitcoinWithdrawSegWitName = "bitcoin_withdraw_segwit"
TestBitcoinWithdrawTaprootName = "bitcoin_withdraw_taproot"
TestBitcoinWithdrawMultipleName = "bitcoin_withdraw_multiple"
Expand All @@ -89,7 +90,6 @@ const (
TestBitcoinWithdrawP2SHName = "bitcoin_withdraw_p2sh"
TestBitcoinWithdrawInvalidAddressName = "bitcoin_withdraw_invalid"
TestBitcoinWithdrawRestrictedName = "bitcoin_withdraw_restricted"
TestExtractBitcoinInscriptionMemoName = "bitcoin_memo_from_inscription"

/*
Application tests
Expand Down Expand Up @@ -497,13 +497,6 @@ var AllE2ETests = []runner.E2ETest{
},
TestBitcoinDonation,
),
runner.NewE2ETest(
TestExtractBitcoinInscriptionMemoName,
"extract memo from BTC inscription", []runner.ArgDefinition{
{Description: "amount in btc", DefaultValue: "0.1"},
},
TestExtractBitcoinInscriptionMemo,
),
runner.NewE2ETest(
TestBitcoinDepositName,
"deposit Bitcoin into ZEVM",
Expand Down Expand Up @@ -559,6 +552,15 @@ var AllE2ETests = []runner.E2ETest{
},
TestBitcoinStdMemoDepositAndCallRevertOtherAddress,
),
runner.NewE2ETest(
TestBitcoinStdMemoInscribedDepositAndCallName,
"deposit Bitcoin into ZEVM and call a contract with inscribed standard memo",
[]runner.ArgDefinition{
{Description: "amount in btc", DefaultValue: "0.1"},
{Description: "fee rate", DefaultValue: "10"},
},
TestBitcoinStdMemoInscribedDepositAndCall,
),
runner.NewE2ETest(
TestBitcoinWithdrawSegWitName,
"withdraw BTC from ZEVM to a SegWit address",
Expand Down
64 changes: 64 additions & 0 deletions e2e/e2etests/test_bitcoin_std_memo_inscribed_deposit_and_call.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package e2etests

import (
"math/big"

"github.com/stretchr/testify/require"

"github.com/zeta-chain/node/e2e/runner"
"github.com/zeta-chain/node/e2e/utils"
"github.com/zeta-chain/node/pkg/memo"
testcontract "github.com/zeta-chain/node/testutil/contracts"
crosschaintypes "github.com/zeta-chain/node/x/crosschain/types"
zetabitcoin "github.com/zeta-chain/node/zetaclient/chains/bitcoin"
)

func TestBitcoinStdMemoInscribedDepositAndCall(r *runner.E2ERunner, args []string) {
// ARRANGE
// Given BTC address
r.SetBtcAddress(r.Name, false)

// Start mining blocks
stop := r.MineBlocksIfLocalBitcoin()
defer stop()

// Given amount to send and fee rate
require.Len(r, args, 2)
amount := parseFloat(r, args[0])
feeRate := parseInt(r, args[1])

// deploy an example contract in ZEVM
contractAddr, _, contract, err := testcontract.DeployExample(r.ZEVMAuth, r.ZEVMClient)
require.NoError(r, err)

// create a standard memo > 80 bytes
memo := &memo.InboundMemo{
Header: memo.Header{
Version: 0,
EncodingFmt: memo.EncodingFmtCompactShort,
OpCode: memo.OpCodeDepositAndCall,
},
FieldsV0: memo.FieldsV0{
Receiver: contractAddr,
Payload: []byte("for use case that passes a large memo > 80 bytes, inscripting the memo is the way to go"),
},
}
memoBytes, err := memo.EncodeToBytes()
require.NoError(r, err)

// ACT
// Send BTC to TSS address with memo
txHash, depositAmount := r.InscribeToTSSFromDeployerWithMemo(amount, memoBytes, int64(feeRate))

// ASSERT
// wait for the cctx to be mined
cctx := utils.WaitCctxMinedByInboundHash(r.Ctx, txHash.String(), r.CctxClient, r.Logger, r.CctxTimeout)
r.Logger.CCTX(*cctx, "bitcoin_std_memo_inscribed_deposit_and_call")
utils.RequireCCTXStatus(r, cctx, crosschaintypes.CctxStatus_OutboundMined)

// check if example contract has been called, 'bar' value should be set to correct amount
depositFeeSats, err := zetabitcoin.GetSatoshis(zetabitcoin.DefaultDepositorFee)
require.NoError(r, err)
receiveAmount := depositAmount - depositFeeSats
utils.MustHaveCalledExampleContract(r, contract, big.NewInt(receiveAmount))
}
57 changes: 0 additions & 57 deletions e2e/e2etests/test_extract_bitcoin_inscription_memo.go

This file was deleted.

2 changes: 1 addition & 1 deletion e2e/runner/accounting.go
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ func (r *E2ERunner) CheckBtcTSSBalance() error {
)
}
// #nosec G115 test - always in range
r.Logger.Print(
r.Logger.Info(
"BTC: Balance (%d) >= ZRC20 TotalSupply (%d)",
int64(tssTotalBalance*1e8),
zrc20Supply.Int64()-10000000,
Expand Down
54 changes: 28 additions & 26 deletions e2e/runner/bitcoin.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import (
"bytes"
"encoding/hex"
"fmt"
"net/http"
"sort"
"time"

Expand Down Expand Up @@ -331,44 +330,47 @@ func (r *E2ERunner) sendToAddrFromDeployerWithMemo(
// InscribeToTSSFromDeployerWithMemo creates an inscription that is sent to the tss address with the corresponding memo
func (r *E2ERunner) InscribeToTSSFromDeployerWithMemo(
amount float64,
inputUTXOs []btcjson.ListUnspentResult,
memo []byte,
) *chainhash.Hash {
// TODO: replace builder with Go function to enable instructions
// https://github.com/zeta-chain/node/issues/2759
builder := InscriptionBuilder{sidecarURL: "http://bitcoin-node-sidecar:8000", client: http.Client{}}

address, err := builder.GenerateCommitAddress(memo)
require.NoError(r, err)
r.Logger.Info("received inscription commit address %s", address)

receiver, err := chains.DecodeBtcAddress(address, r.GetBitcoinChainID())
feeRate int64,
) (*chainhash.Hash, int64) {
// list deployer utxos
utxos, err := r.ListDeployerUTXOs()
require.NoError(r, err)

txnHash, err := r.sendToAddrFromDeployerWithMemo(amount, receiver, inputUTXOs, []byte(constant.DonationMessage))
// generate commit address
builder := NewTapscriptSpender(r.BitcoinParams)
receiver, err := builder.GenerateCommitAddress(memo)
require.NoError(r, err)
r.Logger.Info("obtained inscription commit txn hash %s", txnHash.String())
r.Logger.Info("received inscription commit address: %s", receiver)

// sendToAddrFromDeployerWithMemo makes sure index is 0
outpointIdx := 0
hexTx, err := builder.GenerateRevealTxn(r.BTCTSSAddress.String(), txnHash.String(), outpointIdx, amount)
// send funds to the commit address
commitTxHash, err := r.sendToAddrFromDeployerWithMemo(amount, receiver, utxos, nil)
require.NoError(r, err)
r.Logger.Info("obtained inscription commit txn hash: %s", commitTxHash.String())

// Decode the hex string into raw bytes
rawTxBytes, err := hex.DecodeString(hexTx)
// parameters to build the reveal transaction
commitOutputIdx := uint32(0)
commitAmount, err := zetabitcoin.GetSatoshis(amount)
require.NoError(r, err)

// Deserialize the raw bytes into a wire.MsgTx structure
msgTx := wire.NewMsgTx(wire.TxVersion)
err = msgTx.Deserialize(bytes.NewReader(rawTxBytes))
// build the reveal transaction to spend above funds
revealTx, err := builder.BuildRevealTxn(
r.BTCTSSAddress,
wire.OutPoint{
Hash: *commitTxHash,
Index: commitOutputIdx,
},
commitAmount,
feeRate,
)
require.NoError(r, err)
r.Logger.Info("recovered inscription reveal txn %s", hexTx)

txid, err := r.BtcRPCClient.SendRawTransaction(msgTx, true)
// submit the reveal transaction
txid, err := r.BtcRPCClient.SendRawTransaction(revealTx, true)
require.NoError(r, err)
r.Logger.Info("txid: %+v", txid)
r.Logger.Info("reveal txid: %s", txid.String())

return txid
return txid, revealTx.TxOut[0].Value
}

// GetBitcoinChainID gets the bitcoin chain ID from the network params
Expand Down
Loading

0 comments on commit 7474ab5

Please sign in to comment.