From bbb6967247309eca4024c14c39f702940cc7d664 Mon Sep 17 00:00:00 2001 From: bruwbird Date: Thu, 21 Mar 2024 13:08:18 +0900 Subject: [PATCH 1/2] btcclient+btcjson: feeRate to BTC/kvB defaultMaxFeeRate was set to 1e8 / 10(sat/kb) as a parameter. But BTC/kvB is the expected value, so the units was wrong. This commit updates defaultMaxFeeRate to BTC/kvB and sets it to 0.1, which is the default value of Bitcoin Core. This commit also updates the comment to reflect the change. Because maxFeeRate sanity check has been added in bitcoin core v27.0 or later, sendrawtransaction cannot be executed without this change. --- btcjson/chainsvrcmds.go | 5 +++-- btcjson/chainsvrcmds_test.go | 8 ++++---- rpcclient/rawtransactions.go | 6 +++--- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/btcjson/chainsvrcmds.go b/btcjson/chainsvrcmds.go index 956b4db604..fb690a19c3 100644 --- a/btcjson/chainsvrcmds.go +++ b/btcjson/chainsvrcmds.go @@ -862,7 +862,7 @@ func (a *AllowHighFeesOrMaxFeeRate) UnmarshalJSON(data []byte) error { case bool: a.Value = Bool(v) case float64: - a.Value = Int32(int32(v)) + a.Value = Float64(v) default: return fmt.Errorf("invalid allowhighfees or maxfeerate value: "+ "%v", unmarshalled) @@ -893,9 +893,10 @@ func NewSendRawTransactionCmd(hexTx string, allowHighFees *bool) *SendRawTransac // NewSendRawTransactionCmd returns a new instance which can be used to issue a // sendrawtransaction JSON-RPC command to a bitcoind node. +// maxFeeRate is the maximum fee rate for the transaction in BTC/kvB. // // A 0 maxFeeRate indicates that a maximum fee rate won't be enforced. -func NewBitcoindSendRawTransactionCmd(hexTx string, maxFeeRate int32) *SendRawTransactionCmd { +func NewBitcoindSendRawTransactionCmd(hexTx string, maxFeeRate float64) *SendRawTransactionCmd { return &SendRawTransactionCmd{ HexTx: hexTx, FeeSetting: &AllowHighFeesOrMaxFeeRate{ diff --git a/btcjson/chainsvrcmds_test.go b/btcjson/chainsvrcmds_test.go index d3143a528c..38113a687e 100644 --- a/btcjson/chainsvrcmds_test.go +++ b/btcjson/chainsvrcmds_test.go @@ -1257,16 +1257,16 @@ func TestChainSvrCmds(t *testing.T) { { name: "sendrawtransaction optional, bitcoind >= 0.19.0", newCmd: func() (interface{}, error) { - return btcjson.NewCmd("sendrawtransaction", "1122", &btcjson.AllowHighFeesOrMaxFeeRate{Value: btcjson.Int32(1234)}) + return btcjson.NewCmd("sendrawtransaction", "1122", &btcjson.AllowHighFeesOrMaxFeeRate{Value: btcjson.Float64(0.1234)}) }, staticCmd: func() interface{} { - return btcjson.NewBitcoindSendRawTransactionCmd("1122", 1234) + return btcjson.NewBitcoindSendRawTransactionCmd("1122", 0.1234) }, - marshalled: `{"jsonrpc":"1.0","method":"sendrawtransaction","params":["1122",1234],"id":1}`, + marshalled: `{"jsonrpc":"1.0","method":"sendrawtransaction","params":["1122",0.1234],"id":1}`, unmarshalled: &btcjson.SendRawTransactionCmd{ HexTx: "1122", FeeSetting: &btcjson.AllowHighFeesOrMaxFeeRate{ - Value: btcjson.Int32(1234), + Value: btcjson.Float64(0.1234), }, }, }, diff --git a/rpcclient/rawtransactions.go b/rpcclient/rawtransactions.go index 9c95041fd4..5834ccf202 100644 --- a/rpcclient/rawtransactions.go +++ b/rpcclient/rawtransactions.go @@ -17,9 +17,9 @@ import ( ) const ( - // defaultMaxFeeRate is the default maximum fee rate in sat/KB enforced + // defaultMaxFeeRate is the default maximum fee rate in BTC/kvB enforced // by bitcoind v0.19.0 or after for transaction broadcast. - defaultMaxFeeRate = btcutil.SatoshiPerBitcoin / 10 + defaultMaxFeeRate float64 = 0.1 ) // SigHashType enumerates the available signature hashing types that the @@ -365,7 +365,7 @@ func (c *Client) SendRawTransactionAsync(tx *wire.MsgTx, allowHighFees bool) Fut if version.SupportUnifiedSoftForks() { // Using a 0 MaxFeeRate is interpreted as a maximum fee rate not // being enforced by bitcoind. - var maxFeeRate int32 + var maxFeeRate float64 if !allowHighFees { maxFeeRate = defaultMaxFeeRate } From 80b27f547157399c64b1717a4a528871bbfb7f5b Mon Sep 17 00:00:00 2001 From: bruwbird Date: Sat, 23 Mar 2024 11:14:22 +0900 Subject: [PATCH 2/2] btcclient+btcjson: add type alias for BTC/kvB Added type alias BTC/kvB to explicitly indicate that it represents the fee in BTC for a transaction size of 1 kB. Because bitcoind uses its own fee rate type (BTC/kvB instead of sat/kWU we use in lnd), define the type in btcjson package, as it's the only place where we actually use BTC/kvB. --- btcjson/chainsvrcmds.go | 14 +++++++++----- rpcclient/rawtransactions.go | 8 ++++---- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/btcjson/chainsvrcmds.go b/btcjson/chainsvrcmds.go index fb690a19c3..22552e7bcd 100644 --- a/btcjson/chainsvrcmds.go +++ b/btcjson/chainsvrcmds.go @@ -16,6 +16,10 @@ import ( "github.com/btcsuite/btcd/wire" ) +// BTCPerkvB is the units used to represent Bitcoin transaction fees. +// This unit represents the fee in BTC for a transaction size of 1 kB. +type BTCPerkvB = float64 + // AddNodeSubCmd defines the type used in the addnode JSON-RPC command for the // sub command field. type AddNodeSubCmd string @@ -142,7 +146,7 @@ type FundRawTransactionOpts struct { ChangeType *ChangeType `json:"change_type,omitempty"` IncludeWatching *bool `json:"includeWatching,omitempty"` LockUnspents *bool `json:"lockUnspents,omitempty"` - FeeRate *float64 `json:"feeRate,omitempty"` // BTC/kB + FeeRate *BTCPerkvB `json:"feeRate,omitempty"` // BTC/kB SubtractFeeFromOutputs []int `json:"subtractFeeFromOutputs,omitempty"` Replaceable *bool `json:"replaceable,omitempty"` ConfTarget *int `json:"conf_target,omitempty"` @@ -822,7 +826,7 @@ func NewSearchRawTransactionsCmd(address string, verbose, skip, count *int, vinE } // AllowHighFeesOrMaxFeeRate defines a type that can either be the legacy -// allowhighfees boolean field or the new maxfeerate int field. +// allowhighfees boolean field or the new maxfeerate float64 field. type AllowHighFeesOrMaxFeeRate struct { Value interface{} } @@ -896,7 +900,7 @@ func NewSendRawTransactionCmd(hexTx string, allowHighFees *bool) *SendRawTransac // maxFeeRate is the maximum fee rate for the transaction in BTC/kvB. // // A 0 maxFeeRate indicates that a maximum fee rate won't be enforced. -func NewBitcoindSendRawTransactionCmd(hexTx string, maxFeeRate float64) *SendRawTransactionCmd { +func NewBitcoindSendRawTransactionCmd(hexTx string, maxFeeRate BTCPerkvB) *SendRawTransactionCmd { return &SendRawTransactionCmd{ HexTx: hexTx, FeeSetting: &AllowHighFeesOrMaxFeeRate{ @@ -1051,13 +1055,13 @@ type TestMempoolAcceptCmd struct { // Reject transactions whose fee rate is higher than the specified // value, expressed in BTC/kvB, optional, default="0.10". - MaxFeeRate float64 `json:"omitempty"` + MaxFeeRate BTCPerkvB `json:"omitempty"` } // NewTestMempoolAcceptCmd returns a new instance which can be used to issue a // testmempoolaccept JSON-RPC command. func NewTestMempoolAcceptCmd(rawTxns []string, - maxFeeRate float64) *TestMempoolAcceptCmd { + maxFeeRate BTCPerkvB) *TestMempoolAcceptCmd { return &TestMempoolAcceptCmd{ RawTxns: rawTxns, diff --git a/rpcclient/rawtransactions.go b/rpcclient/rawtransactions.go index 5834ccf202..609d2a5100 100644 --- a/rpcclient/rawtransactions.go +++ b/rpcclient/rawtransactions.go @@ -19,7 +19,7 @@ import ( const ( // defaultMaxFeeRate is the default maximum fee rate in BTC/kvB enforced // by bitcoind v0.19.0 or after for transaction broadcast. - defaultMaxFeeRate float64 = 0.1 + defaultMaxFeeRate btcjson.BTCPerkvB = 0.1 ) // SigHashType enumerates the available signature hashing types that the @@ -365,7 +365,7 @@ func (c *Client) SendRawTransactionAsync(tx *wire.MsgTx, allowHighFees bool) Fut if version.SupportUnifiedSoftForks() { // Using a 0 MaxFeeRate is interpreted as a maximum fee rate not // being enforced by bitcoind. - var maxFeeRate float64 + var maxFeeRate btcjson.BTCPerkvB if !allowHighFees { maxFeeRate = defaultMaxFeeRate } @@ -915,7 +915,7 @@ func (r FutureTestMempoolAcceptResult) Receive() ( // // See TestMempoolAccept for the blocking version and more details. func (c *Client) TestMempoolAcceptAsync(txns []*wire.MsgTx, - maxFeeRate float64) FutureTestMempoolAcceptResult { + maxFeeRate btcjson.BTCPerkvB) FutureTestMempoolAcceptResult { // Due to differences in the testmempoolaccept API for different // backends, we'll need to inspect our version and construct the @@ -1010,7 +1010,7 @@ func (c *Client) TestMempoolAcceptAsync(txns []*wire.MsgTx, // // The maximum number of transactions allowed is 25. func (c *Client) TestMempoolAccept(txns []*wire.MsgTx, - maxFeeRate float64) ([]*btcjson.TestMempoolAcceptResult, error) { + maxFeeRate btcjson.BTCPerkvB) ([]*btcjson.TestMempoolAcceptResult, error) { return c.TestMempoolAcceptAsync(txns, maxFeeRate).Receive() }