Skip to content

Commit

Permalink
rpcclient: CreateRawTransaction replaceable parameter
Browse files Browse the repository at this point in the history
Support the RPC `createrawtransaction` `replaceable` parameter, which allows disabling opt-in RBF.
  • Loading branch information
wydengyre committed Sep 15, 2023
1 parent 80f5a0f commit 518b4c8
Show file tree
Hide file tree
Showing 4 changed files with 24 additions and 19 deletions.
16 changes: 9 additions & 7 deletions btcjson/chainsvrcmds.go
Expand Up @@ -57,9 +57,10 @@ type TransactionInput struct {

// CreateRawTransactionCmd defines the createrawtransaction JSON-RPC command.
type CreateRawTransactionCmd struct {
Inputs []TransactionInput
Amounts map[string]float64 `jsonrpcusage:"{\"address\":amount,...}"` // In BTC
LockTime *int64
Inputs []TransactionInput
Amounts map[string]float64 `jsonrpcusage:"{\"address\":amount,...}"` // In BTC
LockTime *int64
Replaceable *bool
}

// NewCreateRawTransactionCmd returns a new instance which can be used to issue
Expand All @@ -68,16 +69,17 @@ type CreateRawTransactionCmd struct {
// Amounts are in BTC. Passing in nil and the empty slice as inputs is equivalent,
// both gets interpreted as the empty slice.
func NewCreateRawTransactionCmd(inputs []TransactionInput, amounts map[string]float64,
lockTime *int64) *CreateRawTransactionCmd {
lockTime *int64, replaceable *bool) *CreateRawTransactionCmd {
// to make sure we're serializing this to the empty list and not null, we
// explicitly initialize the list
if inputs == nil {
inputs = []TransactionInput{}
}
return &CreateRawTransactionCmd{
Inputs: inputs,
Amounts: amounts,
LockTime: lockTime,
Inputs: inputs,
Amounts: amounts,
LockTime: lockTime,
Replaceable: replaceable,
}
}

Expand Down
18 changes: 10 additions & 8 deletions btcjson/chainsvrcmds_test.go
Expand Up @@ -24,6 +24,7 @@ func TestChainSvrCmds(t *testing.T) {
t.Parallel()

testID := int(1)
trueB := true
tests := []struct {
name string
newCmd func() (interface{}, error)
Expand Down Expand Up @@ -53,7 +54,7 @@ func TestChainSvrCmds(t *testing.T) {
{Txid: "123", Vout: 1},
}
amounts := map[string]float64{"456": .0123}
return btcjson.NewCreateRawTransactionCmd(txInputs, amounts, nil)
return btcjson.NewCreateRawTransactionCmd(txInputs, amounts, nil, nil)
},
marshalled: `{"jsonrpc":"1.0","method":"createrawtransaction","params":[[{"txid":"123","vout":1}],{"456":0.0123}],"id":1}`,
unmarshalled: &btcjson.CreateRawTransactionCmd{
Expand All @@ -68,7 +69,7 @@ func TestChainSvrCmds(t *testing.T) {
},
staticCmd: func() interface{} {
amounts := map[string]float64{"456": .0123}
return btcjson.NewCreateRawTransactionCmd(nil, amounts, nil)
return btcjson.NewCreateRawTransactionCmd(nil, amounts, nil, nil)
},
marshalled: `{"jsonrpc":"1.0","method":"createrawtransaction","params":[[],{"456":0.0123}],"id":1}`,
unmarshalled: &btcjson.CreateRawTransactionCmd{
Expand All @@ -80,20 +81,21 @@ func TestChainSvrCmds(t *testing.T) {
name: "createrawtransaction optional",
newCmd: func() (interface{}, error) {
return btcjson.NewCmd("createrawtransaction", `[{"txid":"123","vout":1}]`,
`{"456":0.0123}`, int64(12312333333))
`{"456":0.0123}`, int64(12312333333), &trueB)
},
staticCmd: func() interface{} {
txInputs := []btcjson.TransactionInput{
{Txid: "123", Vout: 1},
}
amounts := map[string]float64{"456": .0123}
return btcjson.NewCreateRawTransactionCmd(txInputs, amounts, btcjson.Int64(12312333333))
return btcjson.NewCreateRawTransactionCmd(txInputs, amounts, btcjson.Int64(12312333333), &trueB)
},
marshalled: `{"jsonrpc":"1.0","method":"createrawtransaction","params":[[{"txid":"123","vout":1}],{"456":0.0123},12312333333],"id":1}`,
marshalled: `{"jsonrpc":"1.0","method":"createrawtransaction","params":[[{"txid":"123","vout":1}],{"456":0.0123},12312333333,true],"id":1}`,
unmarshalled: &btcjson.CreateRawTransactionCmd{
Inputs: []btcjson.TransactionInput{{Txid: "123", Vout: 1}},
Amounts: map[string]float64{"456": .0123},
LockTime: btcjson.Int64(12312333333),
Inputs: []btcjson.TransactionInput{{Txid: "123", Vout: 1}},
Amounts: map[string]float64{"456": .0123},
LockTime: btcjson.Int64(12312333333),
Replaceable: &trueB,
},
},
{
Expand Down
8 changes: 4 additions & 4 deletions rpcclient/rawtransactions.go
Expand Up @@ -291,23 +291,23 @@ func (r FutureCreateRawTransactionResult) Receive() (*wire.MsgTx, error) {
//
// See CreateRawTransaction for the blocking version and more details.
func (c *Client) CreateRawTransactionAsync(inputs []btcjson.TransactionInput,
amounts map[btcutil.Address]btcutil.Amount, lockTime *int64) FutureCreateRawTransactionResult {
amounts map[btcutil.Address]btcutil.Amount, lockTime *int64, replaceable *bool) FutureCreateRawTransactionResult {

convertedAmts := make(map[string]float64, len(amounts))
for addr, amount := range amounts {
convertedAmts[addr.String()] = amount.ToBTC()
}
cmd := btcjson.NewCreateRawTransactionCmd(inputs, convertedAmts, lockTime)
cmd := btcjson.NewCreateRawTransactionCmd(inputs, convertedAmts, lockTime, replaceable)
return c.SendCmd(cmd)
}

// CreateRawTransaction returns a new transaction spending the provided inputs
// and sending to the provided addresses. If the inputs are either nil or an
// empty slice, it is interpreted as an empty slice.
func (c *Client) CreateRawTransaction(inputs []btcjson.TransactionInput,
amounts map[btcutil.Address]btcutil.Amount, lockTime *int64) (*wire.MsgTx, error) {
amounts map[btcutil.Address]btcutil.Amount, lockTime *int64, replaceable *bool) (*wire.MsgTx, error) {

return c.CreateRawTransactionAsync(inputs, amounts, lockTime).Receive()
return c.CreateRawTransactionAsync(inputs, amounts, lockTime, replaceable).Receive()
}

// FutureSendRawTransactionResult is a future promise to deliver the result
Expand Down
1 change: 1 addition & 0 deletions rpcserverhelp.go
Expand Up @@ -54,6 +54,7 @@ var helpDescsEnUS = map[string]string{
"createrawtransaction-amounts--value": "n.nnn",
"createrawtransaction-amounts--desc": "The destination address as the key and the amount in BTC as the value",
"createrawtransaction-locktime": "Locktime value; a non-zero value will also locktime-activate the inputs",
"createrawtransaction-replaceable": "If false, do not mark this transaction as BIP125-replaceable.",
"createrawtransaction--result0": "Hex-encoded bytes of the serialized transaction",

// ScriptSig help.
Expand Down

0 comments on commit 518b4c8

Please sign in to comment.