| 339 | } |
| 340 | |
| 341 | CMutableTransaction ConstructTransaction(const UniValue& inputs_in, const UniValue& outputs_in, const UniValue& locktime, const UniValue& rbf) |
| 342 | { |
| 343 | if (inputs_in.isNull() || outputs_in.isNull()) |
| 344 | throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, arguments 1 and 2 must be non-null"); |
| 345 | |
| 346 | UniValue inputs = inputs_in.get_array(); |
| 347 | const bool outputs_is_obj = outputs_in.isObject(); |
| 348 | UniValue outputs = outputs_is_obj ? outputs_in.get_obj() : outputs_in.get_array(); |
| 349 | |
| 350 | CMutableTransaction rawTx; |
| 351 | |
| 352 | if (!locktime.isNull()) { |
| 353 | int64_t nLockTime = locktime.get_int64(); |
| 354 | if (nLockTime < 0 || nLockTime > std::numeric_limits<uint32_t>::max()) |
| 355 | throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, locktime out of range"); |
| 356 | rawTx.nLockTime = nLockTime; |
| 357 | } |
| 358 | |
| 359 | bool rbfOptIn = rbf.isTrue(); |
| 360 | |
| 361 | for (unsigned int idx = 0; idx < inputs.size(); idx++) { |
| 362 | const UniValue& input = inputs[idx]; |
| 363 | const UniValue& o = input.get_obj(); |
| 364 | |
| 365 | uint256 txid = ParseHashO(o, "txid"); |
| 366 | |
| 367 | const UniValue& vout_v = find_value(o, "vout"); |
| 368 | if (!vout_v.isNum()) |
| 369 | throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, missing vout key"); |
| 370 | int nOutput = vout_v.get_int(); |
| 371 | if (nOutput < 0) |
| 372 | throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, vout must be positive"); |
| 373 | |
| 374 | uint32_t nSequence; |
| 375 | if (rbfOptIn) { |
| 376 | nSequence = MAX_BIP125_RBF_SEQUENCE; |
| 377 | } else if (rawTx.nLockTime) { |
| 378 | nSequence = std::numeric_limits<uint32_t>::max() - 1; |
| 379 | } else { |
| 380 | nSequence = std::numeric_limits<uint32_t>::max(); |
| 381 | } |
| 382 | |
| 383 | // set the sequence number if passed in the parameters object |
| 384 | const UniValue& sequenceObj = find_value(o, "sequence"); |
| 385 | if (sequenceObj.isNum()) { |
| 386 | int64_t seqNr64 = sequenceObj.get_int64(); |
| 387 | if (seqNr64 < 0 || seqNr64 > std::numeric_limits<uint32_t>::max()) { |
| 388 | throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, sequence number is out of range"); |
| 389 | } else { |
| 390 | nSequence = (uint32_t)seqNr64; |
| 391 | } |
| 392 | } |
| 393 | |
| 394 | CTxIn in(COutPoint(txid, nOutput), CScript(), nSequence); |
| 395 | |
| 396 | rawTx.vin.push_back(in); |
| 397 | } |
| 398 |
no test coverage detected