From 1acb88472e606f5e893c815c09a40e1f4d6e7112 Mon Sep 17 00:00:00 2001 From: Donald Adu-Poku Date: Thu, 21 Jun 2018 23:54:42 +0000 Subject: [PATCH] multi: add amount field to TransactionInput. This adds an amount field to TransactionInput intended for specifying the prev out amount when creating a transaction. createraw/ssrtx/sgentx/transaction rpcs are also updated accordingly as well as associated tests. A typo in assignField is also corrected. --- dcrjson/chainsvrcmds.go | 7 ++++--- dcrjson/chainsvrcmds_test.go | 16 ++++++++-------- dcrjson/cmdparse.go | 2 +- docs/json_rpc_api.md | 4 ++-- rpcserver.go | 33 ++++++++++++++++++++++++++++++--- rpcserverhelp.go | 7 ++++--- 6 files changed, 49 insertions(+), 20 deletions(-) diff --git a/dcrjson/chainsvrcmds.go b/dcrjson/chainsvrcmds.go index 4ddecf53..1499cae7 100644 --- a/dcrjson/chainsvrcmds.go +++ b/dcrjson/chainsvrcmds.go @@ -64,9 +64,10 @@ func NewAddNodeCmd(addr string, subCmd AddNodeSubCmd) *AddNodeCmd { // TransactionInput represents the inputs to a transaction. Specifically a // transaction hash and output number pair. Contains Decred additions. type TransactionInput struct { - Txid string `json:"txid"` - Vout uint32 `json:"vout"` - Tree int8 `json:"tree"` + Amount float64 `json:"amount,omitempty"` + Txid string `json:"txid"` + Vout uint32 `json:"vout"` + Tree int8 `json:"tree"` } // CreateRawTransactionCmd defines the createrawtransaction JSON-RPC command. diff --git a/dcrjson/chainsvrcmds_test.go b/dcrjson/chainsvrcmds_test.go index 31bbb3f4..437cc028 100644 --- a/dcrjson/chainsvrcmds_test.go +++ b/dcrjson/chainsvrcmds_test.go @@ -44,38 +44,38 @@ func TestChainSvrCmds(t *testing.T) { { name: "createrawtransaction", newCmd: func() (interface{}, error) { - return dcrjson.NewCmd("createrawtransaction", `[{"txid":"123","vout":1}]`, + return dcrjson.NewCmd("createrawtransaction", `[{"amount":0.0123,"txid":"123","vout":1}]`, `{"456":0.0123}`) }, staticCmd: func() interface{} { txInputs := []dcrjson.TransactionInput{ - {Txid: "123", Vout: 1}, + {Amount: 0.0123, Txid: "123", Vout: 1}, } amounts := map[string]float64{"456": .0123} return dcrjson.NewCreateRawTransactionCmd(txInputs, amounts, nil, nil) }, - marshalled: `{"jsonrpc":"1.0","method":"createrawtransaction","params":[[{"txid":"123","vout":1,"tree":0}],{"456":0.0123}],"id":1}`, + marshalled: `{"jsonrpc":"1.0","method":"createrawtransaction","params":[[{"amount":0.0123,"txid":"123","vout":1,"tree":0}],{"456":0.0123}],"id":1}`, unmarshalled: &dcrjson.CreateRawTransactionCmd{ - Inputs: []dcrjson.TransactionInput{{Txid: "123", Vout: 1}}, + Inputs: []dcrjson.TransactionInput{{Amount: 0.0123, 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}]`, + return dcrjson.NewCmd("createrawtransaction", `[{"amount":0.0123,"txid":"123","vout":1,"tree":0}]`, `{"456":0.0123}`, int64(12312333333), int64(12312333333)) }, staticCmd: func() interface{} { txInputs := []dcrjson.TransactionInput{ - {Txid: "123", Vout: 1}, + {Amount: 0.0123, Txid: "123", Vout: 1}, } amounts := map[string]float64{"456": .0123} return dcrjson.NewCreateRawTransactionCmd(txInputs, amounts, dcrjson.Int64(12312333333), dcrjson.Int64(12312333333)) }, - marshalled: `{"jsonrpc":"1.0","method":"createrawtransaction","params":[[{"txid":"123","vout":1,"tree":0}],{"456":0.0123},12312333333,12312333333],"id":1}`, + marshalled: `{"jsonrpc":"1.0","method":"createrawtransaction","params":[[{"amount":0.0123,"txid":"123","vout":1,"tree":0}],{"456":0.0123},12312333333,12312333333],"id":1}`, unmarshalled: &dcrjson.CreateRawTransactionCmd{ - Inputs: []dcrjson.TransactionInput{{Txid: "123", Vout: 1}}, + Inputs: []dcrjson.TransactionInput{{Amount: 0.0123, Txid: "123", Vout: 1}}, Amounts: map[string]float64{"456": .0123}, LockTime: dcrjson.Int64(12312333333), Expiry: dcrjson.Int64(12312333333), diff --git a/dcrjson/cmdparse.go b/dcrjson/cmdparse.go index 28682c7d..2f09d952 100644 --- a/dcrjson/cmdparse.go +++ b/dcrjson/cmdparse.go @@ -472,7 +472,7 @@ func assignField(paramNum int, fieldName string, dest reflect.Value, src reflect err := json.Unmarshal([]byte(src.String()), &concreteVal) if err != nil { str := fmt.Sprintf("parameter #%d '%s' must "+ - "be valid JSON which unsmarshals to a %v", + "be valid JSON which unmarshals to a %v", paramNum, fieldName, destBaseType) return makeError(ErrInvalidType, str) } diff --git a/docs/json_rpc_api.md b/docs/json_rpc_api.md index b6ebcc93..7479ed1e 100644 --- a/docs/json_rpc_api.md +++ b/docs/json_rpc_api.md @@ -214,10 +214,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.
`hash`: `(string, required)` the hash of the input.
`vout`: (numeric, required) the specific output of the input transaction to redeem transaction.

`[{"txid": "hash", "vout": n}, ...]`

2. `addresses and amounts`: `(JSON object, required)` - json object with addresses as keys and amounts as values.
`address`: `(numeric, required)` the address to send to as the key and the amount in DCR as the value.

`{"address": n.nnn, ...}`| +|Parameters|1. `transaction inputs`: `(JSON array, required)` json array of json objects.
`amount`: `(numeric)` the previous output amount.
`hash`: `(string, required)` the hash of the input.
`vout`: (numeric, required) the specific output of the input transaction to redeem transaction.

`[{"amount": n.nnn, "txid": "hash", "vout": n}, ...]`

2. `addresses and amounts`: `(JSON object, required)` - json object with addresses as keys and output amounts as values.
`address`: `(string, required)` the address to send the specified output amount to.

`{"address": n.nnn, ...}`| |Description|Returns a new transaction spending the provided inputs and sending to the provided addresses.The transaction inputs are not signed in the created transaction.

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}]`

2. addresses and amounts ```{"13cgrTP7wgbZYWrY9BZ22BV6p82QXQT3nY": 0.49213337}```| +|Example Parameters|1. transaction inputs `[{"amount":0.49213337, "txid":"e6da89de7a6b8508ce8f371a3d0535b04b5e108cb1a6e9284602d3bfd357c018", "vout":1}]`

2. addresses and amounts ```{"13cgrTP7wgbZYWrY9BZ22BV6p82QXQT3nY": 0.49213337}```| |Example Return|Newlines added for display purposes. The actual return does not contain newlines.
`010000000118c057d3bfd3024628e9a6b18c105e4bb035053d1a378fce08856b7ade89dae6010000`
`0000ffffffff0199efee02000000001976a9141cb013db35ecccc156fdfd81d03a11c51998f99388`
`ac00000000`| [Return to Overview](#MethodOverview)
diff --git a/rpcserver.go b/rpcserver.go index dc7048f9..f95c74f8 100644 --- a/rpcserver.go +++ b/rpcserver.go @@ -648,8 +648,17 @@ func handleCreateRawTransaction(s *rpcServer, cmd interface{}, closeChan <-chan "or stake") } + prevOutV := wire.NullValueIn + if input.Amount > 0 { + amt, err := dcrutil.NewAmount(input.Amount) + if err != nil { + return nil, rpcInvalidError(err.Error()) + } + prevOutV = int64(amt) + } + prevOut := wire.NewOutPoint(txHash, input.Vout, input.Tree) - txIn := wire.NewTxIn(prevOut, wire.NullValueIn, []byte{}) + txIn := wire.NewTxIn(prevOut, prevOutV, []byte{}) if c.LockTime != nil && *c.LockTime != 0 { txIn.Sequence = wire.MaxTxInSequenceNum - 1 } @@ -1003,8 +1012,17 @@ func handleCreateRawSSGenTx(s *rpcServer, cmd interface{}, closeChan <-chan stru "TxTreeStake type") } + prevOutV := wire.NullValueIn + if input.Amount > 0 { + amt, err := dcrutil.NewAmount(input.Amount) + if err != nil { + return nil, rpcInvalidError(err.Error()) + } + prevOutV = int64(amt) + } + prevOut := wire.NewOutPoint(txHash, input.Vout, input.Tree) - txIn := wire.NewTxIn(prevOut, wire.NullValueIn, []byte{}) + txIn := wire.NewTxIn(prevOut, prevOutV, []byte{}) mtx.AddTxIn(txIn) } @@ -1144,8 +1162,17 @@ func handleCreateRawSSRtx(s *rpcServer, cmd interface{}, closeChan <-chan struct "TxTreeStake type") } + prevOutV := wire.NullValueIn + if input.Amount > 0 { + amt, err := dcrutil.NewAmount(input.Amount) + if err != nil { + return nil, rpcInvalidError(err.Error()) + } + prevOutV = int64(amt) + } + prevOut := wire.NewOutPoint(txHash, input.Vout, input.Tree) - txIn := wire.NewTxIn(prevOut, wire.NullValueIn, []byte{}) + txIn := wire.NewTxIn(prevOut, prevOutV, []byte{}) mtx.AddTxIn(txIn) } diff --git a/rpcserverhelp.go b/rpcserverhelp.go index 2fb3d282..bab1aef4 100644 --- a/rpcserverhelp.go +++ b/rpcserverhelp.go @@ -41,9 +41,10 @@ var helpDescsEnUS = map[string]string{ "node-connectsubcmd": "'perm' to make the connected peer a permanent one, 'temp' to try a single connect to a peer", // TransactionInput help. - "transactioninput-txid": "The hash of the input transaction", - "transactioninput-vout": "The specific output of the input transaction to redeem", - "transactioninput-tree": "The tree that the transaction input is located", + "transactioninput-amount": "The previous output amount", + "transactioninput-txid": "The hash of the input transaction", + "transactioninput-vout": "The specific output of the input transaction to redeem", + "transactioninput-tree": "The tree that the transaction input is located", // TODO review cmd help messages for stake stuff // CreateRawSSTxCmd help. "createrawsstx--synopsis": "Returns a new transaction spending the provided inputs and sending to the provided addresses.\n" +