Skip to content

Commit

Permalink
dcrjson: Add optional locktime to createrawtransaction
Browse files Browse the repository at this point in the history
Upstream commit 4b7206b
  • Loading branch information
davecgh committed May 21, 2016
2 parents 29a04bc + 4b7206b commit 1987376
Show file tree
Hide file tree
Showing 7 changed files with 94 additions and 18 deletions.
16 changes: 10 additions & 6 deletions dcrjson/chainsvrcmds.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,18 +55,22 @@ type TransactionInput struct {

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

// NewCreateRawTransactionCmd returns a new instance which can be used to issue
// a createrawtransaction JSON-RPC command.
//
// Amounts are in DCR.
func NewCreateRawTransactionCmd(inputs []TransactionInput, amounts map[string]float64) *CreateRawTransactionCmd {
// Amounts are in BTC.
func NewCreateRawTransactionCmd(inputs []TransactionInput, amounts map[string]float64,
lockTime *int64) *CreateRawTransactionCmd {

return &CreateRawTransactionCmd{
Inputs: inputs,
Amounts: amounts,
Inputs: inputs,
Amounts: amounts,
LockTime: lockTime,
}
}

Expand Down
22 changes: 21 additions & 1 deletion dcrjson/chainsvrcmds_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,14 +52,34 @@ func TestChainSvrCmds(t *testing.T) {
{Txid: "123", Vout: 1},
}
amounts := map[string]float64{"456": .0123}
return dcrjson.NewCreateRawTransactionCmd(txInputs, amounts)
return dcrjson.NewCreateRawTransactionCmd(txInputs, amounts, nil)
},
marshalled: `{"jsonrpc":"1.0","method":"createrawtransaction","params":[[{"txid":"123","vout":1,"tree":0}],{"456":0.0123}],"id":1}`,
unmarshalled: &dcrjson.CreateRawTransactionCmd{
Inputs: []dcrjson.TransactionInput{{Txid: "123", Vout: 1}},
Amounts: map[string]float64{"456": .0123},
},
},
{
name: "createrawtransaction optional",
newCmd: func() (interface{}, error) {
return dcrjson.NewCmd("createrawtransaction", `[{"txid":"123","vout":1,"tree":0}]`,
`{"456":0.0123}`, 12312333333)
},
staticCmd: func() interface{} {
txInputs := []dcrjson.TransactionInput{
{Txid: "123", Vout: 1},
}
amounts := map[string]float64{"456": .0123}
return dcrjson.NewCreateRawTransactionCmd(txInputs, amounts, dcrjson.Int64(12312333333))
},
marshalled: `{"jsonrpc":"1.0","method":"createrawtransaction","params":[[{"txid":"123","vout":1,"tree":0}],{"456":0.0123},12312333333],"id":1}`,
unmarshalled: &dcrjson.CreateRawTransactionCmd{
Inputs: []dcrjson.TransactionInput{{Txid: "123", Vout: 1}},
Amounts: map[string]float64{"456": .0123},
LockTime: dcrjson.Int64(12312333333),
},
},
{
name: "decoderawtransaction",
newCmd: func() (interface{}, error) {
Expand Down
4 changes: 2 additions & 2 deletions docs/json_rpc_api.md
Original file line number Diff line number Diff line change
Expand Up @@ -1466,10 +1466,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 />

Expand Down
5 changes: 2 additions & 3 deletions policy.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,8 @@ func calcMinRequiredTxRelayFee(serializedSize int64, minRelayTxFee dcrutil.Amoun
// Calculate the minimum fee for a transaction to be allowed into the
// mempool and relayed by scaling the base fee (which is the minimum
// free transaction relay fee). minTxRelayFee is in Atom/KB, so
// divide the transaction size by 1000 to convert to kilobytes. Also,
// integer division is used so fees only increase on full kilobyte
// boundaries.
// multiply by serializedSize (which is in bytes) and divide by 1000 to
// get minimum Atoms.
minFee := (serializedSize * int64(minRelayTxFee)) / 1000

if minFee == 0 && minRelayTxFee > 0 {
Expand Down
42 changes: 37 additions & 5 deletions policy_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,16 +23,18 @@ func TestCalcMinRequiredTxRelayFee(t *testing.T) {
want int64 // Expected fee.
}{
{
"zero value with default minimum relay fee",
0,
defaultMinRelayTxFee,
int64(defaultMinRelayTxFee),
// Ensure combination of size and fee that are less than
// 1000 produce a non-zero fee.
"250 bytes with relay fee of 3",
250,
3,
3,
},
{
"1000 bytes with default minimum relay fee",
1000,
defaultMinRelayTxFee,
int64(defaultMinRelayTxFee),
1000000,
},
{
"max standard tx size with default minimum relay fee",
Expand All @@ -46,6 +48,36 @@ func TestCalcMinRequiredTxRelayFee(t *testing.T) {
dcrutil.MaxAmount,
dcrutil.MaxAmount,
},
{
"1500 bytes with 5000 relay fee",
1500,
5000,
7500,
},
{
"1500 bytes with 3000 relay fee",
1500,
3000,
4500,
},
{
"782 bytes with 5000 relay fee",
782,
5000,
3910,
},
{
"782 bytes with 3000 relay fee",
782,
3000,
2346,
},
{
"782 bytes with 2550 relay fee",
782,
2550,
1994,
},
}

for _, test := range tests {
Expand Down
22 changes: 21 additions & 1 deletion rpcserver.go
Original file line number Diff line number Diff line change
Expand Up @@ -561,6 +561,15 @@ func messageToHex(msg wire.Message) (string, error) {
func handleCreateRawTransaction(s *rpcServer, cmd interface{}, closeChan <-chan struct{}) (interface{}, error) {
c := cmd.(*dcrjson.CreateRawTransactionCmd)

// Validate the locktime, if given.
if c.LockTime != nil &&
(*c.LockTime < 0 || *c.LockTime > int64(wire.MaxTxInSequenceNum)) {
return nil, &dcrjson.RPCError{
Code: dcrjson.ErrRPCInvalidParameter,
Message: "Locktime out of range",
}
}

// Add all transaction inputs to a new transaction after performing
// some validity checks.
mtx := wire.NewMsgTx()
Expand All @@ -580,6 +589,9 @@ func handleCreateRawTransaction(s *rpcServer, cmd interface{}, closeChan <-chan

prevOut := wire.NewOutPoint(txHash, uint32(input.Vout), int8(input.Tree))
txIn := wire.NewTxIn(prevOut, []byte{})
if c.LockTime != nil && *c.LockTime != 0 {
txIn.Sequence = wire.MaxTxInSequenceNum - 1
}
mtx.AddTxIn(txIn)
}

Expand Down Expand Up @@ -645,7 +657,15 @@ func handleCreateRawTransaction(s *rpcServer, cmd interface{}, closeChan <-chan
mtx.AddTxOut(txOut)
}

// Return the serialized and hex-encoded transaction.
// 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
// the client instead of nothing (nil) in the case of an error.
mtxHex, err := messageToHex(mtx)
if err != nil {
return nil, err
Expand Down
1 change: 1 addition & 0 deletions rpcserverhelp.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,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 DCR 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.
Expand Down

0 comments on commit 1987376

Please sign in to comment.