btcjson+rpcserverhelp: restore bitcoind compatibility
The PR #1594 introduced a change that made the order of parameters relevant, if one of them is nil. This makes it harder to be backward compatible with the same JSON message if an existing parameter in bitcoind was re-purposed to have a different meaning.
This commit is contained in:
parent
65d2b7a18c
commit
9e8bb3eddb
3 changed files with 93 additions and 19 deletions
|
@ -11,6 +11,7 @@ import (
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"reflect"
|
||||||
|
|
||||||
"github.com/btcsuite/btcd/wire"
|
"github.com/btcsuite/btcd/wire"
|
||||||
)
|
)
|
||||||
|
@ -819,11 +820,60 @@ 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.
|
||||||
|
type AllowHighFeesOrMaxFeeRate struct {
|
||||||
|
Value interface{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// String returns the string representation of this struct, used for printing
|
||||||
|
// the marshaled default value in the help text.
|
||||||
|
func (a AllowHighFeesOrMaxFeeRate) String() string {
|
||||||
|
b, _ := a.MarshalJSON()
|
||||||
|
return string(b)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalJSON implements the json.Marshaler interface
|
||||||
|
func (a AllowHighFeesOrMaxFeeRate) MarshalJSON() ([]byte, error) {
|
||||||
|
// The default value is false which only works with the legacy versions.
|
||||||
|
if a.Value == nil ||
|
||||||
|
(reflect.ValueOf(a.Value).Kind() == reflect.Ptr &&
|
||||||
|
reflect.ValueOf(a.Value).IsNil()) {
|
||||||
|
|
||||||
|
return json.Marshal(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
return json.Marshal(a.Value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalJSON implements the json.Unmarshaler interface
|
||||||
|
func (a *AllowHighFeesOrMaxFeeRate) UnmarshalJSON(data []byte) error {
|
||||||
|
if len(data) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var unmarshalled interface{}
|
||||||
|
if err := json.Unmarshal(data, &unmarshalled); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
switch v := unmarshalled.(type) {
|
||||||
|
case bool:
|
||||||
|
a.Value = Bool(v)
|
||||||
|
case float64:
|
||||||
|
a.Value = Int32(int32(v))
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("invalid allowhighfees or maxfeerate value: "+
|
||||||
|
"%v", unmarshalled)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// SendRawTransactionCmd defines the sendrawtransaction JSON-RPC command.
|
// SendRawTransactionCmd defines the sendrawtransaction JSON-RPC command.
|
||||||
type SendRawTransactionCmd struct {
|
type SendRawTransactionCmd struct {
|
||||||
HexTx string
|
HexTx string
|
||||||
AllowHighFees *bool `jsonrpcdefault:"false"`
|
FeeSetting *AllowHighFeesOrMaxFeeRate `jsonrpcdefault:"false"`
|
||||||
MaxFeeRate *int32
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewSendRawTransactionCmd returns a new instance which can be used to issue a
|
// NewSendRawTransactionCmd returns a new instance which can be used to issue a
|
||||||
|
@ -834,7 +884,9 @@ type SendRawTransactionCmd struct {
|
||||||
func NewSendRawTransactionCmd(hexTx string, allowHighFees *bool) *SendRawTransactionCmd {
|
func NewSendRawTransactionCmd(hexTx string, allowHighFees *bool) *SendRawTransactionCmd {
|
||||||
return &SendRawTransactionCmd{
|
return &SendRawTransactionCmd{
|
||||||
HexTx: hexTx,
|
HexTx: hexTx,
|
||||||
AllowHighFees: allowHighFees,
|
FeeSetting: &AllowHighFeesOrMaxFeeRate{
|
||||||
|
Value: allowHighFees,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -845,7 +897,9 @@ func NewSendRawTransactionCmd(hexTx string, allowHighFees *bool) *SendRawTransac
|
||||||
func NewBitcoindSendRawTransactionCmd(hexTx string, maxFeeRate int32) *SendRawTransactionCmd {
|
func NewBitcoindSendRawTransactionCmd(hexTx string, maxFeeRate int32) *SendRawTransactionCmd {
|
||||||
return &SendRawTransactionCmd{
|
return &SendRawTransactionCmd{
|
||||||
HexTx: hexTx,
|
HexTx: hexTx,
|
||||||
MaxFeeRate: &maxFeeRate,
|
FeeSetting: &AllowHighFeesOrMaxFeeRate{
|
||||||
|
Value: &maxFeeRate,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1224,21 +1224,23 @@ func TestChainSvrCmds(t *testing.T) {
|
||||||
{
|
{
|
||||||
name: "sendrawtransaction",
|
name: "sendrawtransaction",
|
||||||
newCmd: func() (interface{}, error) {
|
newCmd: func() (interface{}, error) {
|
||||||
return btcjson.NewCmd("sendrawtransaction", "1122")
|
return btcjson.NewCmd("sendrawtransaction", "1122", &btcjson.AllowHighFeesOrMaxFeeRate{})
|
||||||
},
|
},
|
||||||
staticCmd: func() interface{} {
|
staticCmd: func() interface{} {
|
||||||
return btcjson.NewSendRawTransactionCmd("1122", nil)
|
return btcjson.NewSendRawTransactionCmd("1122", nil)
|
||||||
},
|
},
|
||||||
marshalled: `{"jsonrpc":"1.0","method":"sendrawtransaction","params":["1122"],"id":1}`,
|
marshalled: `{"jsonrpc":"1.0","method":"sendrawtransaction","params":["1122",false],"id":1}`,
|
||||||
unmarshalled: &btcjson.SendRawTransactionCmd{
|
unmarshalled: &btcjson.SendRawTransactionCmd{
|
||||||
HexTx: "1122",
|
HexTx: "1122",
|
||||||
AllowHighFees: btcjson.Bool(false),
|
FeeSetting: &btcjson.AllowHighFeesOrMaxFeeRate{
|
||||||
|
Value: btcjson.Bool(false),
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "sendrawtransaction optional",
|
name: "sendrawtransaction optional",
|
||||||
newCmd: func() (interface{}, error) {
|
newCmd: func() (interface{}, error) {
|
||||||
return btcjson.NewCmd("sendrawtransaction", "1122", false)
|
return btcjson.NewCmd("sendrawtransaction", "1122", &btcjson.AllowHighFeesOrMaxFeeRate{Value: btcjson.Bool(false)})
|
||||||
},
|
},
|
||||||
staticCmd: func() interface{} {
|
staticCmd: func() interface{} {
|
||||||
return btcjson.NewSendRawTransactionCmd("1122", btcjson.Bool(false))
|
return btcjson.NewSendRawTransactionCmd("1122", btcjson.Bool(false))
|
||||||
|
@ -1246,7 +1248,25 @@ func TestChainSvrCmds(t *testing.T) {
|
||||||
marshalled: `{"jsonrpc":"1.0","method":"sendrawtransaction","params":["1122",false],"id":1}`,
|
marshalled: `{"jsonrpc":"1.0","method":"sendrawtransaction","params":["1122",false],"id":1}`,
|
||||||
unmarshalled: &btcjson.SendRawTransactionCmd{
|
unmarshalled: &btcjson.SendRawTransactionCmd{
|
||||||
HexTx: "1122",
|
HexTx: "1122",
|
||||||
AllowHighFees: btcjson.Bool(false),
|
FeeSetting: &btcjson.AllowHighFeesOrMaxFeeRate{
|
||||||
|
Value: btcjson.Bool(false),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "sendrawtransaction optional, bitcoind >= 0.19.0",
|
||||||
|
newCmd: func() (interface{}, error) {
|
||||||
|
return btcjson.NewCmd("sendrawtransaction", "1122", &btcjson.AllowHighFeesOrMaxFeeRate{Value: btcjson.Int32(1234)})
|
||||||
|
},
|
||||||
|
staticCmd: func() interface{} {
|
||||||
|
return btcjson.NewBitcoindSendRawTransactionCmd("1122", 1234)
|
||||||
|
},
|
||||||
|
marshalled: `{"jsonrpc":"1.0","method":"sendrawtransaction","params":["1122",1234],"id":1}`,
|
||||||
|
unmarshalled: &btcjson.SendRawTransactionCmd{
|
||||||
|
HexTx: "1122",
|
||||||
|
FeeSetting: &btcjson.AllowHighFeesOrMaxFeeRate{
|
||||||
|
Value: btcjson.Int32(1234),
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
@ -563,9 +563,9 @@ var helpDescsEnUS = map[string]string{
|
||||||
// SendRawTransactionCmd help.
|
// SendRawTransactionCmd help.
|
||||||
"sendrawtransaction--synopsis": "Submits the serialized, hex-encoded transaction to the local peer and relays it to the network.",
|
"sendrawtransaction--synopsis": "Submits the serialized, hex-encoded transaction to the local peer and relays it to the network.",
|
||||||
"sendrawtransaction-hextx": "Serialized, hex-encoded signed transaction",
|
"sendrawtransaction-hextx": "Serialized, hex-encoded signed transaction",
|
||||||
"sendrawtransaction-allowhighfees": "Whether or not to allow insanely high fees (btcd does not yet implement this parameter, so it has no effect)",
|
"sendrawtransaction-feesetting": "Whether or not to allow insanely high fees in bitcoind < v0.19.0 or the max fee rate for bitcoind v0.19.0 and later (btcd does not yet implement this parameter, so it has no effect)",
|
||||||
"sendrawtransaction-maxfeerate": "Used by bitcoind on or after v0.19.0",
|
|
||||||
"sendrawtransaction--result0": "The hash of the transaction",
|
"sendrawtransaction--result0": "The hash of the transaction",
|
||||||
|
"allowhighfeesormaxfeerate-value": "Either the boolean value for the allowhighfees parameter in bitcoind < v0.19.0 or the numerical value for the maxfeerate field in bitcoind v0.19.0 and later",
|
||||||
|
|
||||||
// SetGenerateCmd help.
|
// SetGenerateCmd help.
|
||||||
"setgenerate--synopsis": "Set the server to generate coins (mine) or not.",
|
"setgenerate--synopsis": "Set the server to generate coins (mine) or not.",
|
||||||
|
|
Loading…
Reference in a new issue