diff --git a/changelog.md b/changelog.md index 8a7d3298f0..d76a340213 100644 --- a/changelog.md +++ b/changelog.md @@ -14,7 +14,9 @@ * [1690](https://github.com/zeta-chain/node/issues/1690) - double watched gas prices and fix btc scheduler * [1687](https://github.com/zeta-chain/node/pull/1687) - only use EVM supported chains for gas stability pool * [1692](https://github.com/zeta-chain/node/pull/1692) - fix get params query for emissions module -* ([1733](https://github.com/zeta-chain/node/pull/1733)) - remove the unnecessary 2x multiplier in the convertGasToZeta RPC +* [1707](https://github.com/zeta-chain/node/issues/1707) - fix bitcoin fee rate estimation +* [1712](https://github.com/zeta-chain/node/issues/1712) - increase EVM outtx inclusion timeout to 20 minutes +* [1733](https://github.com/zeta-chain/node/pull/1733)) - remove the unnecessary 2x multiplier in the convertGasToZeta RPC * [1721](https://github.com/zeta-chain/node/issues/1721) - zetaclient should provide bitcoin_chain_id when querying TSS address ### Tests diff --git a/zetaclient/bitcoin_client.go b/zetaclient/bitcoin_client.go index 44b19a7b8b..aeb44fe4b2 100644 --- a/zetaclient/bitcoin_client.go +++ b/zetaclient/bitcoin_client.go @@ -589,7 +589,7 @@ func (ob *BitcoinChainClient) PostGasPrice() error { return nil } // EstimateSmartFee returns the fees per kilobyte (BTC/kb) targeting given block confirmation - feeResult, err := ob.rpcClient.EstimateSmartFee(1, &btcjson.EstimateModeConservative) + feeResult, err := ob.rpcClient.EstimateSmartFee(1, &btcjson.EstimateModeEconomical) if err != nil { return err } diff --git a/zetaclient/bitcoin_client_rpc_test.go b/zetaclient/bitcoin_client_rpc_test.go index 49685b1f58..5bb5091259 100644 --- a/zetaclient/bitcoin_client_rpc_test.go +++ b/zetaclient/bitcoin_client_rpc_test.go @@ -1,19 +1,22 @@ -//go:build btc_regtest -// +build btc_regtest - package zetaclient import ( "encoding/hex" + "fmt" "math/big" + "strings" "testing" + "time" "github.com/btcsuite/btcd/btcjson" "github.com/btcsuite/btcd/chaincfg/chainhash" + "github.com/btcsuite/btcd/rpcclient" "github.com/ethereum/go-ethereum/crypto" + "github.com/pkg/errors" "github.com/rs/zerolog/log" "github.com/stretchr/testify/suite" "github.com/zeta-chain/zetacore/common" + "github.com/zeta-chain/zetacore/zetaclient/config" ) type BitcoinClientTestSuite struct { @@ -35,7 +38,7 @@ func (suite *BitcoinClientTestSuite) SetupTest() { PrivKey: privateKey, } //client, err := NewBitcoinClient(common.BtcTestNetChain(), nil, tss, "", nil) - client, err := NewBitcoinClient(common.BtcRegtestChain(), nil, tss, "/tmp", nil) + client, err := NewBitcoinClient(common.BtcRegtestChain(), nil, tss, "/tmp", nil, log.Logger, config.BTCConfig{}, nil) suite.Require().NoError(err) suite.BitcoinChainClient = client skBytes, err := hex.DecodeString(skHex) @@ -68,11 +71,20 @@ func (suite *BitcoinClientTestSuite) SetupTest() { } func (suite *BitcoinClientTestSuite) TearDownSuite() { - } -func (suite *BitcoinClientTestSuite) Test0() { - +func getFeeRate(client *rpcclient.Client, confTarget int64, estimateMode *btcjson.EstimateSmartFeeMode) (*big.Int, error) { + feeResult, err := client.EstimateSmartFee(confTarget, estimateMode) + if err != nil { + return nil, err + } + if feeResult.Errors != nil { + return nil, errors.New(strings.Join(feeResult.Errors, ", ")) + } + if feeResult.FeeRate == nil { + return nil, errors.New("fee rate is nil") + } + return new(big.Int).SetInt64(int64(*feeResult.FeeRate * 1e8)), nil } // All methods that begin with "Test" are run as tests within a @@ -158,6 +170,63 @@ func (suite *BitcoinClientTestSuite) Test3() { suite.Require().NoError(err) suite.T().Logf("block number %d", bn) } -func TestBitcoinChainClient(t *testing.T) { - suite.Run(t, new(BitcoinClientTestSuite)) + +// func TestBitcoinChainClient(t *testing.T) { +// suite.Run(t, new(BitcoinClientTestSuite)) +// } + +func LiveTestBitcoinFeeRate(t *testing.T) { + // mainnet config + connCfg := &rpcclient.ConnConfig{ + Host: "127.0.0.1:8332", // mainnet endpoint goes here + User: "username", + Pass: "password", + Params: "mainnet", + HTTPPostMode: true, + DisableTLS: true, + } + client, err := rpcclient.New(connCfg, nil) + if err != nil { + t.Error(err) + } + bn, err := client.GetBlockCount() + if err != nil { + t.Error(err) + } + + // get fee rate for 1 block target + feeRateConservative1, errCon1 := getFeeRate(client, 1, &btcjson.EstimateModeConservative) + if errCon1 != nil { + t.Error(errCon1) + } + feeRateEconomical1, errEco1 := getFeeRate(client, 1, &btcjson.EstimateModeEconomical) + if errEco1 != nil { + t.Error(errEco1) + } + // get fee rate for 2 block target + feeRateConservative2, errCon2 := getFeeRate(client, 2, &btcjson.EstimateModeConservative) + if errCon2 != nil { + t.Error(errCon2) + } + feeRateEconomical2, errEco2 := getFeeRate(client, 2, &btcjson.EstimateModeEconomical) + if errEco2 != nil { + t.Error(errEco2) + } + fmt.Printf("Block: %d, Conservative-1 fee rate: %d, Economical-1 fee rate: %d\n", bn, feeRateConservative1.Uint64(), feeRateEconomical1.Uint64()) + fmt.Printf("Block: %d, Conservative-2 fee rate: %d, Economical-2 fee rate: %d\n", bn, feeRateConservative2.Uint64(), feeRateEconomical2.Uint64()) + + // monitor fee rate every 5 minutes + for { + time.Sleep(time.Duration(5) * time.Minute) + bn, err = client.GetBlockCount() + feeRateConservative1, errCon1 = getFeeRate(client, 1, &btcjson.EstimateModeConservative) + feeRateEconomical1, errEco1 = getFeeRate(client, 1, &btcjson.EstimateModeEconomical) + feeRateConservative2, errCon2 = getFeeRate(client, 2, &btcjson.EstimateModeConservative) + feeRateEconomical2, errEco2 = getFeeRate(client, 2, &btcjson.EstimateModeEconomical) + if err != nil || errCon1 != nil || errEco1 != nil || errCon2 != nil || errEco2 != nil { + continue + } + fmt.Printf("Block: %d, Conservative-1 fee rate: %d, Economical-1 fee rate: %d\n", bn, feeRateConservative1.Uint64(), feeRateEconomical1.Uint64()) + fmt.Printf("Block: %d, Conservative-2 fee rate: %d, Economical-2 fee rate: %d\n", bn, feeRateConservative2.Uint64(), feeRateEconomical2.Uint64()) + } } diff --git a/zetaclient/evm_signer.go b/zetaclient/evm_signer.go index 05a476a64b..831047bf9b 100644 --- a/zetaclient/evm_signer.go +++ b/zetaclient/evm_signer.go @@ -27,7 +27,7 @@ import ( ) const ( - OutTxInclusionTimeout = 10 * time.Minute + OutTxInclusionTimeout = 20 * time.Minute OutTxTrackerReportTimeout = 10 * time.Minute ZetaBlockTime = 6500 * time.Millisecond ) diff --git a/zetaclient/interfaces.go b/zetaclient/interfaces.go index ba58afed09..0ef1b7ca50 100644 --- a/zetaclient/interfaces.go +++ b/zetaclient/interfaces.go @@ -8,6 +8,7 @@ import ( "github.com/btcsuite/btcd/btcjson" "github.com/btcsuite/btcd/chaincfg/chainhash" + "github.com/btcsuite/btcd/rpcclient" "github.com/btcsuite/btcd/wire" "github.com/btcsuite/btcutil" "github.com/ethereum/go-ethereum/accounts/abi/bind" @@ -99,7 +100,12 @@ type ZetaCoreBridger interface { // BTCRPCClient is the interface for BTC RPC client type BTCRPCClient interface { GetNetworkInfo() (*btcjson.GetNetworkInfoResult, error) + CreateWallet(name string, opts ...rpcclient.CreateWalletOpt) (*btcjson.CreateWalletResult, error) + GetNewAddress(account string) (btcutil.Address, error) + GenerateToAddress(numBlocks int64, address btcutil.Address, maxTries *int64) ([]*chainhash.Hash, error) + GetBalance(account string) (btcutil.Amount, error) SendRawTransaction(tx *wire.MsgTx, allowHighFees bool) (*chainhash.Hash, error) + ListUnspent() ([]btcjson.ListUnspentResult, error) ListUnspentMinMaxAddresses(minConf int, maxConf int, addrs []btcutil.Address) ([]btcjson.ListUnspentResult, error) EstimateSmartFee(confTarget int64, mode *btcjson.EstimateSmartFeeMode) (*btcjson.EstimateSmartFeeResult, error) GetTransaction(txHash *chainhash.Hash) (*btcjson.GetTransactionResult, error)