Line data Source code
1 : // Copyright (c) 2010 Satoshi Nakamoto
2 : // Copyright (c) 2009-2021 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 :
6 : #include <rpc/rawtransaction_util.h>
7 :
8 : #include <coins.h>
9 : #include <consensus/amount.h>
10 : #include <core_io.h>
11 : #include <interfaces/chain.h>
12 : #include <key_io.h>
13 : #include <policy/policy.h>
14 : #include <primitives/transaction.h>
15 : #include <rpc/request.h>
16 : #include <rpc/util.h>
17 : #include <script/signingprovider.h>
18 : #include <univalue.h>
19 : #include <util/strencodings.h>
20 : #include <validation.h>
21 : #include <txmempool.h>
22 : #include <util/translation.h>
23 :
24 2370 : CMutableTransaction ConstructTransaction(const UniValue& inputs_in, const UniValue& outputs_in, const UniValue& locktime)
25 : {
26 2370 : if (outputs_in.isNull()) {
27 56 : throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, output argument must be non-null");
28 : }
29 :
30 2369 : UniValue inputs;
31 2369 : if (inputs_in.isNull()) {
32 577 : inputs = UniValue::VARR;
33 577 : } else {
34 1792 : inputs = inputs_in.get_array();
35 : }
36 :
37 2369 : const bool outputs_is_obj = outputs_in.isObject();
38 2369 : UniValue outputs = outputs_is_obj ? outputs_in.get_obj() : outputs_in.get_array();
39 :
40 2367 : CMutableTransaction rawTx;
41 2367 : if (!locktime.isNull()) {
42 364 : int64_t nLockTime = locktime.getInt<int64_t>();
43 364 : if (nLockTime < 0 || nLockTime > LOCKTIME_MAX)
44 4 : throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, locktime out of range");
45 360 : rawTx.nLockTime = nLockTime;
46 360 : }
47 :
48 18389 : for (unsigned int idx = 0; idx < inputs.size(); idx++) {
49 16044 : const UniValue& input = inputs[idx];
50 16044 : const UniValue& o = input.get_obj();
51 :
52 16042 : uint256 txid = ParseHashO(o, "txid");
53 :
54 16036 : const UniValue& vout_v = o.find_value("vout");
55 16036 : if (!vout_v.isNum())
56 4 : throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, missing vout key");
57 16032 : int nOutput = vout_v.getInt<int>();
58 16032 : if (nOutput < 0)
59 2 : throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, vout cannot be negative");
60 :
61 : uint32_t nSequence;
62 16030 : if (rawTx.nLockTime) {
63 8 : nSequence = CTxIn::MAX_SEQUENCE_NONFINAL; /* CTxIn::SEQUENCE_FINAL - 1 */
64 8 : } else {
65 16022 : nSequence = CTxIn::SEQUENCE_FINAL;
66 : }
67 :
68 : // set the sequence number if passed in the parameters object
69 16030 : const UniValue& sequenceObj = o.find_value("sequence");
70 16030 : if (sequenceObj.isNum()) {
71 26 : int64_t seqNr64 = sequenceObj.getInt<int64_t>();
72 26 : if (seqNr64 < 0 || seqNr64 > CTxIn::SEQUENCE_FINAL)
73 4 : throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, sequence number is out of range");
74 : else
75 22 : nSequence = (uint32_t)seqNr64;
76 22 : }
77 :
78 16026 : CTxIn in(COutPoint(txid, nOutput), CScript(), nSequence);
79 :
80 16026 : rawTx.vin.push_back(in);
81 16026 : }
82 :
83 2345 : if (!outputs_is_obj) {
84 : // Translate array of key-value pairs into dict
85 736 : UniValue outputs_dict = UniValue(UniValue::VOBJ);
86 1843 : for (size_t i = 0; i < outputs.size(); ++i) {
87 1111 : const UniValue& output = outputs[i];
88 1111 : if (!output.isObject()) {
89 2 : throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, key-value pair not an object as expected");
90 : }
91 1109 : if (output.size() != 1) {
92 2 : throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, key-value pair must contain exactly one key");
93 : }
94 1107 : outputs_dict.pushKVs(output);
95 1107 : }
96 732 : outputs = std::move(outputs_dict);
97 736 : }
98 :
99 : // Duplicate checking
100 2341 : std::set<CTxDestination> destinations;
101 2341 : bool has_data{false};
102 :
103 21587 : for (const std::string& name_ : outputs.getKeys()) {
104 19273 : if (name_ == "data") {
105 42 : if (has_data) {
106 4 : throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, duplicate key: data");
107 : }
108 38 : has_data = true;
109 38 : std::vector<unsigned char> data = ParseHexV(outputs[name_].getValStr(), "Data");
110 :
111 30 : CTxOut out(0, CScript() << OP_RETURN << data);
112 30 : rawTx.vout.push_back(out);
113 30 : } else {
114 19231 : CTxDestination destination = DecodeDestination(name_);
115 19231 : if (!IsValidDestination(destination)) {
116 3 : throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, std::string("Invalid Dash address: ") + name_);
117 : }
118 :
119 19228 : if (!destinations.insert(destination).second) {
120 8 : throw JSONRPCError(RPC_INVALID_PARAMETER, std::string("Invalid parameter, duplicated address: ") + name_);
121 : }
122 :
123 19220 : CScript scriptPubKey = GetScriptForDestination(destination);
124 19220 : CAmount nAmount = AmountFromValue(outputs[name_]);
125 :
126 19216 : CTxOut out(nAmount, scriptPubKey);
127 19216 : rawTx.vout.push_back(out);
128 19220 : }
129 : }
130 :
131 2314 : return rawTx;
132 2415 : }
133 :
134 : /** Pushes a JSON object for script verification or signing errors to vErrorsRet. */
135 73 : static void TxInErrorToJSON(const CTxIn& txin, UniValue& vErrorsRet, const std::string& strMessage)
136 : {
137 73 : UniValue entry(UniValue::VOBJ);
138 73 : entry.pushKV("txid", txin.prevout.hash.ToString());
139 73 : entry.pushKV("vout", (uint64_t)txin.prevout.n);
140 73 : entry.pushKV("scriptSig", HexStr(txin.scriptSig));
141 73 : entry.pushKV("sequence", (uint64_t)txin.nSequence);
142 73 : entry.pushKV("error", strMessage);
143 73 : vErrorsRet.push_back(entry);
144 73 : }
145 :
146 2014 : void ParsePrevouts(const UniValue& prevTxsUnival, FillableSigningProvider* keystore, std::map<COutPoint, Coin>& coins)
147 : {
148 2014 : if (!prevTxsUnival.isNull()) {
149 86 : const UniValue& prevTxs = prevTxsUnival.get_array();
150 150 : for (unsigned int idx = 0; idx < prevTxs.size(); ++idx) {
151 92 : const UniValue& p = prevTxs[idx];
152 92 : if (!p.isObject()) {
153 28 : throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "expected object with {\"txid'\",\"vout\",\"scriptPubKey\"}");
154 : }
155 :
156 92 : const UniValue& prevOut = p.get_obj();
157 :
158 184 : RPCTypeCheckObj(prevOut,
159 368 : {
160 92 : {"txid", UniValueType(UniValue::VSTR)},
161 92 : {"vout", UniValueType(UniValue::VNUM)},
162 92 : {"scriptPubKey", UniValueType(UniValue::VSTR)},
163 : });
164 :
165 80 : uint256 txid = ParseHashO(prevOut, "txid");
166 :
167 80 : int nOut = prevOut.find_value("vout").getInt<int>();
168 80 : if (nOut < 0) {
169 0 : throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "vout cannot be negative");
170 : }
171 :
172 80 : COutPoint out(txid, nOut);
173 80 : std::vector<unsigned char> pkData(ParseHexO(prevOut, "scriptPubKey"));
174 80 : CScript scriptPubKey(pkData.begin(), pkData.end());
175 :
176 : {
177 80 : auto coin = coins.find(out);
178 134 : if (coin != coins.end() && !coin->second.IsSpent() && coin->second.out.scriptPubKey != scriptPubKey) {
179 0 : std::string err("Previous output scriptPubKey mismatch:\n");
180 0 : err = err + ScriptToAsmStr(coin->second.out.scriptPubKey) + "\nvs:\n"+
181 0 : ScriptToAsmStr(scriptPubKey);
182 0 : throw JSONRPCError(RPC_DESERIALIZATION_ERROR, err);
183 0 : }
184 80 : Coin newcoin;
185 80 : newcoin.out.scriptPubKey = scriptPubKey;
186 80 : newcoin.out.nValue = 0;
187 80 : if (prevOut.exists("amount")) {
188 48 : newcoin.out.nValue = AmountFromValue(prevOut.find_value("amount"));
189 48 : }
190 80 : newcoin.nHeight = 1;
191 80 : coins[out] = std::move(newcoin);
192 80 : }
193 :
194 : // if redeemScript and private keys were given, add redeemScript to the keystore so it can be signed
195 80 : const bool is_p2sh = scriptPubKey.IsPayToScriptHash();
196 80 : if (keystore && is_p2sh) {
197 96 : RPCTypeCheckObj(prevOut,
198 96 : {
199 48 : {"redeemScript", UniValueType(UniValue::VSTR)},
200 : });
201 40 : const UniValue& rs{prevOut.find_value("redeemScript")};
202 40 : if (rs.isNull()) {
203 0 : throw JSONRPCError(RPC_INVALID_PARAMETER, "Missing redeemScript");
204 : }
205 :
206 40 : std::vector<unsigned char> scriptData(ParseHexV(rs, "redeemScript"));
207 40 : CScript script(scriptData.begin(), scriptData.end());
208 40 : keystore->AddCScript(script);
209 :
210 40 : if (is_p2sh) {
211 40 : const CTxDestination p2sh{ScriptHash(script)};
212 40 : if (scriptPubKey == GetScriptForDestination(p2sh)) {
213 : // traditional p2sh; arguably an error if
214 : // we got here with rs.IsNull(), because
215 : // that means the p2sh script was specified
216 : // via witnessScript param, but for now
217 : // we'll just quietly accept it
218 32 : } else {
219 : // otherwise, can't generate scriptPubKey from
220 : // either script, so we got unusable parameters
221 8 : throw JSONRPCError(RPC_INVALID_PARAMETER, "redeemScript does not match scriptPubKey");
222 : }
223 32 : }
224 32 : if (rs.isNull()) {
225 0 : throw JSONRPCError(RPC_INVALID_PARAMETER, "Missing redeemScript");
226 : }
227 40 : }
228 80 : }
229 58 : }
230 2014 : }
231 :
232 344 : void SignTransaction(CMutableTransaction& mtx, const SigningProvider* keystore, const std::map<COutPoint, Coin>& coins, const UniValue& hashType, UniValue& result)
233 : {
234 344 : int nHashType = ParseSighashString(hashType);
235 :
236 : // Script verification errors
237 344 : std::map<int, bilingual_str> input_errors;
238 :
239 344 : bool complete = SignTransaction(mtx, keystore, coins, nHashType, input_errors);
240 344 : SignTransactionResultToJSON(mtx, complete, coins, input_errors, result);
241 344 : }
242 :
243 1986 : void SignTransactionResultToJSON(CMutableTransaction& mtx, bool complete, const std::map<COutPoint, Coin>& coins, const std::map<int, bilingual_str>& input_errors, UniValue& result)
244 : {
245 : // Make errors UniValue
246 1986 : UniValue vErrors(UniValue::VARR);
247 2059 : for (const auto& err_pair : input_errors) {
248 73 : if (err_pair.second.original == "Missing amount") {
249 : // This particular error needs to be an exception for some reason
250 0 : throw JSONRPCError(RPC_TYPE_ERROR, strprintf("Missing amount for %s", coins.at(mtx.vin.at(err_pair.first).prevout).out.ToString()));
251 : }
252 73 : TxInErrorToJSON(mtx.vin.at(err_pair.first), vErrors, err_pair.second.original);
253 : }
254 :
255 1986 : result.pushKV("hex", EncodeHexTx(CTransaction(mtx)));
256 1986 : result.pushKV("complete", complete);
257 1986 : if (!vErrors.empty()) {
258 69 : if (result.exists("errors")) {
259 0 : vErrors.push_backV(result["errors"].getValues());
260 0 : }
261 69 : result.pushKV("errors", vErrors);
262 69 : }
263 1986 : }
|