btcjson: Add optional locktime to createrawtransaction

rpcserver:
If the locktime is given, the transaction inputs will be set to a
non-max value, activating the locktime.  The locktime for the
new transaction will be set to the given value.

This mimics Bitcoin Core commit 212bcca92089f406d9313dbe6d0e1d25143d61ff
This commit is contained in:
David Hill 2015-10-23 11:47:27 -04:00
parent 489ba8d31d
commit 4b7206b54f
5 changed files with 51 additions and 8 deletions

View file

@ -53,18 +53,22 @@ type TransactionInput struct {
// CreateRawTransactionCmd defines the createrawtransaction JSON-RPC command.
type CreateRawTransactionCmd struct {
Inputs []TransactionInput
Amounts map[string]float64 `jsonrpcusage:"{\"address\":amount,...}"` // In BTC
Inputs []TransactionInput
Amounts map[string]float64 `jsonrpcusage:"{\"address\":amount,...}"` // In BTC
LockTime *int64
}
// NewCreateRawTransactionCmd returns a new instance which can be used to issue
// a createrawtransaction JSON-RPC command.
//
// Amounts are in BTC.
func NewCreateRawTransactionCmd(inputs []TransactionInput, amounts map[string]float64) *CreateRawTransactionCmd {
func NewCreateRawTransactionCmd(inputs []TransactionInput, amounts map[string]float64,
lockTime *int64) *CreateRawTransactionCmd {
return &CreateRawTransactionCmd{
Inputs: inputs,
Amounts: amounts,
Inputs: inputs,
Amounts: amounts,
LockTime: lockTime,
}
}

View file

@ -51,7 +51,7 @@ func TestChainSvrCmds(t *testing.T) {
{Txid: "123", Vout: 1},
}
amounts := map[string]float64{"456": .0123}
return btcjson.NewCreateRawTransactionCmd(txInputs, amounts)
return btcjson.NewCreateRawTransactionCmd(txInputs, amounts, nil)
},
marshalled: `{"jsonrpc":"1.0","method":"createrawtransaction","params":[[{"txid":"123","vout":1}],{"456":0.0123}],"id":1}`,
unmarshalled: &btcjson.CreateRawTransactionCmd{
@ -59,6 +59,27 @@ func TestChainSvrCmds(t *testing.T) {
Amounts: map[string]float64{"456": .0123},
},
},
{
name: "createrawtransaction optional",
newCmd: func() (interface{}, error) {
return btcjson.NewCmd("createrawtransaction", `[{"txid":"123","vout":1}]`,
`{"456":0.0123}`, 12312333333)
},
staticCmd: func() interface{} {
txInputs := []btcjson.TransactionInput{
{Txid: "123", Vout: 1},
}
amounts := map[string]float64{"456": .0123}
return btcjson.NewCreateRawTransactionCmd(txInputs, amounts, btcjson.Int64(12312333333))
},
marshalled: `{"jsonrpc":"1.0","method":"createrawtransaction","params":[[{"txid":"123","vout":1}],{"456":0.0123},12312333333],"id":1}`,
unmarshalled: &btcjson.CreateRawTransactionCmd{
Inputs: []btcjson.TransactionInput{{Txid: "123", Vout: 1}},
Amounts: map[string]float64{"456": .0123},
LockTime: btcjson.Int64(12312333333),
},
},
{
name: "decoderawtransaction",
newCmd: func() (interface{}, error) {

View file

@ -199,10 +199,10 @@ the method name for further details such as parameter and return information.
| | |
|---|---|
|Method|createrawtransaction|
|Parameters|1. transaction inputs (JSON array, required) - json array of json objects<br />`[`<br />&nbsp;&nbsp;`{`<br />&nbsp;&nbsp;&nbsp;&nbsp;`"txid": "hash", (string, required) the hash of the input transaction`<br />&nbsp;&nbsp;&nbsp;&nbsp;`"vout": n (numeric, required) the specific output of the input transaction to redeem`<br />&nbsp;&nbsp;`}, ...`<br />`]`<br />2. addresses and amounts (JSON object, required) - json object with addresses as keys and amounts as values<br />`{`<br />&nbsp;&nbsp;`"address": n.nnn (numeric, required) the address to send to as the key and the amount in BTC as the value`<br />&nbsp;&nbsp;`, ...`<br />`}`|
|Parameters|1. transaction inputs (JSON array, required) - json array of json objects<br />`[`<br />&nbsp;&nbsp;`{`<br />&nbsp;&nbsp;&nbsp;&nbsp;`"txid": "hash", (string, required) the hash of the input transaction`<br />&nbsp;&nbsp;&nbsp;&nbsp;`"vout": n (numeric, required) the specific output of the input transaction to redeem`<br />&nbsp;&nbsp;`}, ...`<br />`]`<br />2. addresses and amounts (JSON object, required) - json object with addresses as keys and amounts as values<br />`{`<br />&nbsp;&nbsp;`"address": n.nnn (numeric, required) the address to send to as the key and the amount in BTC as the value`<br />&nbsp;&nbsp;`, ...`<br />`}`<br />3. locktime (int64, optional, default=0) - specifies the transaction locktime. If non-zero, the inputs will also have their locktimes activated. |
|Description|Returns a new transaction spending the provided inputs and sending to the provided addresses.<br />The transaction inputs are not signed in the created transaction.<br />The `signrawtransaction` RPC command provided by wallet must be used to sign the resulting transaction.|
|Returns|`"transaction" (string) hex-encoded bytes of the serialized transaction`|
|Example Parameters|1. transaction inputs `[{"txid":"e6da89de7a6b8508ce8f371a3d0535b04b5e108cb1a6e9284602d3bfd357c018","vout":1}]`<br />2. addresses and amounts `{"13cgrTP7wgbZYWrY9BZ22BV6p82QXQT3nY": 0.49213337}`|
|Example Parameters|1. transaction inputs `[{"txid":"e6da89de7a6b8508ce8f371a3d0535b04b5e108cb1a6e9284602d3bfd357c018","vout":1}]`<br />2. addresses and amounts `{"13cgrTP7wgbZYWrY9BZ22BV6p82QXQT3nY": 0.49213337}`<br />3. locktime `0`|
|Example Return|`010000000118c057d3bfd3024628e9a6b18c105e4bb035053d1a378fce08856b7ade89dae6010000`<br />`0000ffffffff0199efee02000000001976a9141cb013db35ecccc156fdfd81d03a11c51998f99388`<br />`ac00000000`<br /><font color="orange">**Newlines added for display purposes. The actual return does not contain newlines.**</font>|
[Return to Overview](#MethodOverview)<br />

View file

@ -511,6 +511,15 @@ func messageToHex(msg wire.Message) (string, error) {
func handleCreateRawTransaction(s *rpcServer, cmd interface{}, closeChan <-chan struct{}) (interface{}, error) {
c := cmd.(*btcjson.CreateRawTransactionCmd)
// Validate the locktime, if given.
if c.LockTime != nil &&
(*c.LockTime < 0 || *c.LockTime > int64(wire.MaxTxInSequenceNum)) {
return nil, &btcjson.RPCError{
Code: btcjson.ErrRPCInvalidParameter,
Message: "Locktime out of range",
}
}
// Add all transaction inputs to a new transaction after performing
// some validity checks.
mtx := wire.NewMsgTx()
@ -522,6 +531,9 @@ func handleCreateRawTransaction(s *rpcServer, cmd interface{}, closeChan <-chan
prevOut := wire.NewOutPoint(txHash, uint32(input.Vout))
txIn := wire.NewTxIn(prevOut, []byte{})
if c.LockTime != nil && *c.LockTime != 0 {
txIn.Sequence = wire.MaxTxInSequenceNum - 1
}
mtx.AddTxIn(txIn)
}
@ -584,6 +596,11 @@ func handleCreateRawTransaction(s *rpcServer, cmd interface{}, closeChan <-chan
mtx.AddTxOut(txOut)
}
// Set the Locktime, if given.
if c.LockTime != nil {
mtx.LockTime = uint32(*c.LockTime)
}
// Return the serialized and hex-encoded transaction. Note that this
// is intentionally not directly returning because the first return
// value is a string and it would result in returning an empty string to

View file

@ -52,6 +52,7 @@ var helpDescsEnUS = map[string]string{
"createrawtransaction-amounts--key": "address",
"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--result0": "Hex-encoded bytes of the serialized transaction",
// ScriptSig help.