Bitcoin ABC  0.26.3
P2P Digital Currency
rawtransaction_util.cpp
Go to the documentation of this file.
1 // Copyright (c) 2010 Satoshi Nakamoto
2 // Copyright (c) 2009-2019 The Bitcoin Core developers
3 // Distributed under the MIT software license, see the accompanying
4 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
5 
7 
8 #include <coins.h>
9 #include <consensus/amount.h>
10 #include <core_io.h>
11 #include <key_io.h>
12 #include <policy/policy.h>
13 #include <primitives/transaction.h>
14 #include <rpc/request.h>
15 #include <rpc/util.h>
16 #include <script/sign.h>
17 #include <script/signingprovider.h>
18 #include <tinyformat.h>
19 #include <univalue.h>
20 #include <util/strencodings.h>
21 
23  const UniValue &inputs_in,
24  const UniValue &outputs_in,
25  const UniValue &locktime) {
26  if (outputs_in.isNull()) {
27  throw JSONRPCError(
29  "Invalid parameter, output argument must be non-null");
30  }
31 
32  UniValue inputs;
33  if (inputs_in.isNull()) {
34  inputs = UniValue::VARR;
35  } else {
36  inputs = inputs_in.get_array();
37  }
38 
39  const bool outputs_is_obj = outputs_in.isObject();
40  UniValue outputs =
41  outputs_is_obj ? outputs_in.get_obj() : outputs_in.get_array();
42 
43  CMutableTransaction rawTx;
44 
45  if (!locktime.isNull()) {
46  int64_t nLockTime = locktime.get_int64();
47  if (nLockTime < 0 || nLockTime > std::numeric_limits<uint32_t>::max()) {
49  "Invalid parameter, locktime out of range");
50  }
51 
52  rawTx.nLockTime = nLockTime;
53  }
54 
55  for (size_t idx = 0; idx < inputs.size(); idx++) {
56  const UniValue &input = inputs[idx];
57  const UniValue &o = input.get_obj();
58 
59  TxId txid(ParseHashO(o, "txid"));
60 
61  const UniValue &vout_v = o.find_value("vout");
62  if (vout_v.isNull()) {
64  "Invalid parameter, missing vout key");
65  }
66 
67  if (!vout_v.isNum()) {
69  "Invalid parameter, vout must be a number");
70  }
71 
72  int nOutput = vout_v.get_int();
73  if (nOutput < 0) {
75  "Invalid parameter, vout cannot be negative");
76  }
77 
78  uint32_t nSequence =
79  (rawTx.nLockTime ? std::numeric_limits<uint32_t>::max() - 1
80  : std::numeric_limits<uint32_t>::max());
81 
82  // Set the sequence number if passed in the parameters object.
83  const UniValue &sequenceObj = o.find_value("sequence");
84  if (sequenceObj.isNum()) {
85  int64_t seqNr64 = sequenceObj.get_int64();
86  if (seqNr64 < 0 || seqNr64 > std::numeric_limits<uint32_t>::max()) {
87  throw JSONRPCError(
89  "Invalid parameter, sequence number is out of range");
90  }
91 
92  nSequence = uint32_t(seqNr64);
93  }
94 
95  CTxIn in(COutPoint(txid, nOutput), CScript(), nSequence);
96  rawTx.vin.push_back(in);
97  }
98 
99  if (!outputs_is_obj) {
100  // Translate array of key-value pairs into dict
101  UniValue outputs_dict = UniValue(UniValue::VOBJ);
102  for (size_t i = 0; i < outputs.size(); ++i) {
103  const UniValue &output = outputs[i];
104  if (!output.isObject()) {
106  "Invalid parameter, key-value pair not an "
107  "object as expected");
108  }
109  if (output.size() != 1) {
111  "Invalid parameter, key-value pair must "
112  "contain exactly one key");
113  }
114  outputs_dict.pushKVs(output);
115  }
116  outputs = std::move(outputs_dict);
117  }
118 
119  // Duplicate checking
120  std::set<CTxDestination> destinations;
121  bool has_data{false};
122 
123  for (const std::string &name_ : outputs.getKeys()) {
124  if (name_ == "data") {
125  if (has_data) {
127  "Invalid parameter, duplicate key: data");
128  }
129  has_data = true;
130  std::vector<uint8_t> data =
131  ParseHexV(outputs[name_].getValStr(), "Data");
132 
133  CTxOut out(Amount::zero(), CScript() << OP_RETURN << data);
134  rawTx.vout.push_back(out);
135  } else {
136  CTxDestination destination = DecodeDestination(name_, params);
137  if (!IsValidDestination(destination)) {
139  std::string("Invalid Bitcoin address: ") +
140  name_);
141  }
142 
143  if (!destinations.insert(destination).second) {
144  throw JSONRPCError(
146  std::string("Invalid parameter, duplicated address: ") +
147  name_);
148  }
149 
150  CScript scriptPubKey = GetScriptForDestination(destination);
151  Amount nAmount = AmountFromValue(outputs[name_]);
152 
153  CTxOut out(nAmount, scriptPubKey);
154  rawTx.vout.push_back(out);
155  }
156  }
157 
158  return rawTx;
159 }
160 
164 static void TxInErrorToJSON(const CTxIn &txin, UniValue &vErrorsRet,
165  const std::string &strMessage) {
166  UniValue entry(UniValue::VOBJ);
167  entry.pushKV("txid", txin.prevout.GetTxId().ToString());
168  entry.pushKV("vout", uint64_t(txin.prevout.GetN()));
169  entry.pushKV("scriptSig", HexStr(txin.scriptSig));
170  entry.pushKV("sequence", uint64_t(txin.nSequence));
171  entry.pushKV("error", strMessage);
172  vErrorsRet.push_back(entry);
173 }
174 
175 void ParsePrevouts(const UniValue &prevTxsUnival,
176  FillableSigningProvider *keystore,
177  std::map<COutPoint, Coin> &coins) {
178  if (!prevTxsUnival.isNull()) {
179  UniValue prevTxs = prevTxsUnival.get_array();
180  for (size_t idx = 0; idx < prevTxs.size(); ++idx) {
181  const UniValue &p = prevTxs[idx];
182  if (!p.isObject()) {
184  "expected object with "
185  "{\"txid'\",\"vout\",\"scriptPubKey\"}");
186  }
187 
188  UniValue prevOut = p.get_obj();
189 
190  RPCTypeCheckObj(prevOut,
191  {
192  {"txid", UniValueType(UniValue::VSTR)},
193  {"vout", UniValueType(UniValue::VNUM)},
194  {"scriptPubKey", UniValueType(UniValue::VSTR)},
195  // "amount" is also required but check is done
196  // below due to UniValue::VNUM erroneously
197  // not accepting quoted numerics
198  // (which are valid JSON)
199  });
200 
201  TxId txid(ParseHashO(prevOut, "txid"));
202 
203  int nOut = prevOut.find_value("vout").get_int();
204  if (nOut < 0) {
206  "vout cannot be negative");
207  }
208 
209  COutPoint out(txid, nOut);
210  std::vector<uint8_t> pkData(ParseHexO(prevOut, "scriptPubKey"));
211  CScript scriptPubKey(pkData.begin(), pkData.end());
212 
213  {
214  auto coin = coins.find(out);
215  if (coin != coins.end() && !coin->second.IsSpent() &&
216  coin->second.GetTxOut().scriptPubKey != scriptPubKey) {
217  std::string err("Previous output scriptPubKey mismatch:\n");
218  err = err +
219  ScriptToAsmStr(coin->second.GetTxOut().scriptPubKey) +
220  "\nvs:\n" + ScriptToAsmStr(scriptPubKey);
222  }
223 
224  CTxOut txout;
225  txout.scriptPubKey = scriptPubKey;
226  txout.nValue = MAX_MONEY;
227  if (prevOut.exists("amount")) {
228  txout.nValue =
229  AmountFromValue(prevOut.find_value("amount"));
230  } else {
231  // amount param is required in replay-protected txs.
232  // Note that we must check for its presence here rather
233  // than use RPCTypeCheckObj() above, since UniValue::VNUM
234  // parser incorrectly parses numerics with quotes, eg
235  // "3.12" as a string when JSON allows it to also parse
236  // as numeric. And we have to accept numerics with quotes
237  // because our own dogfood (our rpc results) always
238  // produces decimal numbers that are quoted
239  // eg getbalance returns "3.14152" rather than 3.14152
240  throw JSONRPCError(RPC_INVALID_PARAMETER, "Missing amount");
241  }
242  coins[out] = Coin(txout, 1, false);
243  }
244 
245  // If redeemScript and private keys were given, add redeemScript to
246  // the keystore so it can be signed
247  if (keystore && scriptPubKey.IsPayToScriptHash()) {
249  prevOut, {
250  {"redeemScript", UniValueType(UniValue::VSTR)},
251  });
252  const UniValue &v{prevOut.find_value("redeemScript")};
253  if (!v.isNull()) {
254  std::vector<uint8_t> rsData(ParseHexV(v, "redeemScript"));
255  CScript redeemScript(rsData.begin(), rsData.end());
256  keystore->AddCScript(redeemScript);
257  }
258  }
259  }
260  }
261 }
262 
264  const std::map<COutPoint, Coin> &coins,
265  const UniValue &hashType, UniValue &result) {
266  SigHashType sigHashType = ParseSighashString(hashType);
267  if (!sigHashType.hasForkId()) {
269  "Signature must use SIGHASH_FORKID");
270  }
271 
272  // Script verification errors
273  std::map<int, std::string> input_errors;
274 
275  bool complete =
276  SignTransaction(mtx, keystore, coins, sigHashType, input_errors);
277  SignTransactionResultToJSON(mtx, complete, coins, input_errors, result);
278 }
279 
281  const std::map<COutPoint, Coin> &coins,
282  const std::map<int, std::string> &input_errors,
283  UniValue &result) {
284  // Make errors UniValue
285  UniValue vErrors(UniValue::VARR);
286  for (const auto &err_pair : input_errors) {
287  if (err_pair.second == "Missing amount") {
288  // This particular error needs to be an exception for some reason
289  throw JSONRPCError(
291  strprintf("Missing amount for %s",
292  coins.at(mtx.vin.at(err_pair.first).prevout)
293  .GetTxOut()
294  .ToString()));
295  }
296  TxInErrorToJSON(mtx.vin.at(err_pair.first), vErrors, err_pair.second);
297  }
298 
299  result.pushKV("hex", EncodeHexTx(CTransaction(mtx)));
300  result.pushKV("complete", complete);
301  if (!vErrors.empty()) {
302  if (result.exists("errors")) {
303  vErrors.push_backV(result["errors"].getValues());
304  }
305  result.pushKV("errors", vErrors);
306  }
307 }
static constexpr Amount MAX_MONEY
No amount larger than this (in satoshi) is valid.
Definition: amount.h:165
CChainParams defines various tweakable parameters of a given instance of the Bitcoin system.
Definition: chainparams.h:74
A mutable version of CTransaction.
Definition: transaction.h:274
std::vector< CTxOut > vout
Definition: transaction.h:277
std::vector< CTxIn > vin
Definition: transaction.h:276
An outpoint - a combination of a transaction hash and an index n into its vout.
Definition: transaction.h:20
uint32_t GetN() const
Definition: transaction.h:36
const TxId & GetTxId() const
Definition: transaction.h:35
Serialized script, used inside transaction inputs and outputs.
Definition: script.h:431
bool IsPayToScriptHash() const
Definition: script.cpp:373
The basic transaction that is broadcasted on the network and contained in blocks.
Definition: transaction.h:192
An input of a transaction.
Definition: transaction.h:59
uint32_t nSequence
Definition: transaction.h:63
CScript scriptSig
Definition: transaction.h:62
COutPoint prevout
Definition: transaction.h:61
An output of a transaction.
Definition: transaction.h:128
CScript scriptPubKey
Definition: transaction.h:131
Amount nValue
Definition: transaction.h:130
A UTXO entry.
Definition: coins.h:27
Fillable signing provider that keeps keys in an address->secret map.
virtual bool AddCScript(const CScript &redeemScript)
Signature hash type wrapper class.
Definition: sighashtype.h:37
bool hasForkId() const
Definition: sighashtype.h:77
An interface to be implemented by keystores that support signing.
const UniValue & find_value(std::string_view key) const
Definition: univalue.cpp:234
@ VOBJ
Definition: univalue.h:27
@ VSTR
Definition: univalue.h:27
@ VARR
Definition: univalue.h:27
@ VNUM
Definition: univalue.h:27
int64_t get_int64() const
bool isNull() const
Definition: univalue.h:89
const UniValue & get_obj() const
size_t size() const
Definition: univalue.h:80
const std::vector< std::string > & getKeys() const
bool empty() const
Definition: univalue.h:78
bool pushKVs(const UniValue &obj)
Definition: univalue.cpp:146
bool push_back(const UniValue &val)
Definition: univalue.cpp:108
const UniValue & get_array() const
bool exists(const std::string &key) const
Definition: univalue.h:87
bool pushKV(const std::string &key, const UniValue &val)
Definition: univalue.cpp:133
bool isNum() const
Definition: univalue.h:94
bool push_backV(const std::vector< UniValue > &vec)
Definition: univalue.cpp:117
bool isObject() const
Definition: univalue.h:96
int get_int() const
std::string ToString() const
Definition: uint256.h:78
std::string ScriptToAsmStr(const CScript &script, const bool fAttemptSighashDecode=false)
Create the assembly string representation of a CScript object.
Definition: core_write.cpp:106
std::string EncodeHexTx(const CTransaction &tx, const int serializeFlags=0)
Definition: core_write.cpp:169
SigHashType ParseSighashString(const UniValue &sighash)
Definition: core_read.cpp:271
CTxDestination DecodeDestination(const std::string &addr, const CChainParams &params)
Definition: key_io.cpp:174
void SignTransaction(CMutableTransaction &mtx, const SigningProvider *keystore, const std::map< COutPoint, Coin > &coins, const UniValue &hashType, UniValue &result)
Sign a transaction with the given keystore and previous transactions.
void SignTransactionResultToJSON(CMutableTransaction &mtx, bool complete, const std::map< COutPoint, Coin > &coins, const std::map< int, std::string > &input_errors, UniValue &result)
CMutableTransaction ConstructTransaction(const CChainParams &params, const UniValue &inputs_in, const UniValue &outputs_in, const UniValue &locktime)
Create a transaction from univalue parameters.
static void TxInErrorToJSON(const CTxIn &txin, UniValue &vErrorsRet, const std::string &strMessage)
Pushes a JSON object for script verification or signing errors to vErrorsRet.
void ParsePrevouts(const UniValue &prevTxsUnival, FillableSigningProvider *keystore, std::map< COutPoint, Coin > &coins)
Parse a prevtxs UniValue array and get the map of coins from it.
UniValue JSONRPCError(int code, const std::string &message)
Definition: request.cpp:57
@ RPC_TYPE_ERROR
Unexpected type was passed as parameter.
Definition: protocol.h:40
@ RPC_INVALID_PARAMETER
Invalid, missing or duplicate parameter.
Definition: protocol.h:46
@ RPC_DESERIALIZATION_ERROR
Error parsing or validating structure in raw format.
Definition: protocol.h:50
@ RPC_INVALID_ADDRESS_OR_KEY
Invalid address or key.
Definition: protocol.h:42
std::vector< uint8_t > ParseHexV(const UniValue &v, std::string strName)
Definition: util.cpp:119
Amount AmountFromValue(const UniValue &value)
Definition: util.cpp:80
std::vector< uint8_t > ParseHexO(const UniValue &o, std::string strKey)
Definition: util.cpp:133
uint256 ParseHashO(const UniValue &o, std::string strKey)
Definition: util.cpp:115
void RPCTypeCheckObj(const UniValue &o, const std::map< std::string, UniValueType > &typesExpected, bool fAllowNull, bool fStrict)
Check for expected keys/value types in an Object.
Definition: util.cpp:51
@ OP_RETURN
Definition: script.h:84
bool IsValidDestination(const CTxDestination &dest)
Check whether a CTxDestination is a CNoDestination.
Definition: standard.cpp:263
CScript GetScriptForDestination(const CTxDestination &dest)
Generate a Bitcoin scriptPubKey for the given CTxDestination.
Definition: standard.cpp:243
std::variant< CNoDestination, PKHash, ScriptHash > CTxDestination
A txout script template with a specific destination.
Definition: standard.h:92
std::string HexStr(const Span< const uint8_t > s)
Convert a span of bytes to a lower-case hexadecimal string.
Definition: amount.h:19
static constexpr Amount zero() noexcept
Definition: amount.h:32
A TxId is the identifier of a transaction.
Definition: txid.h:14
Wrapper for UniValue::VType, which includes typeAny: used to denote don't care type.
Definition: util.h:44
#define strprintf
Format arguments and return the string or write to given std::ostream (see tinyformat::format doc for...
Definition: tinyformat.h:1202