mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-10-11 12:03:04 +02:00
Refactor rawtransaction's SignTransaction into generic SignTransaction function
This commit is contained in:
@@ -272,55 +272,27 @@ void SignTransaction(CMutableTransaction& mtx, const SigningProvider* keystore,
|
||||
{
|
||||
int nHashType = ParseSighashString(hashType);
|
||||
|
||||
bool fHashSingle = ((nHashType & ~SIGHASH_ANYONECANPAY) == SIGHASH_SINGLE);
|
||||
|
||||
// Script verification errors
|
||||
std::map<int, std::string> input_errors;
|
||||
|
||||
bool complete = SignTransaction(mtx, keystore, coins, nHashType, input_errors);
|
||||
SignTransactionResultToJSON(mtx, complete, coins, input_errors, result);
|
||||
}
|
||||
|
||||
void SignTransactionResultToJSON(CMutableTransaction& mtx, bool complete, const std::map<COutPoint, Coin>& coins, std::map<int, std::string>& input_errors, UniValue& result)
|
||||
{
|
||||
// Make errors UniValue
|
||||
UniValue vErrors(UniValue::VARR);
|
||||
|
||||
// Use CTransaction for the constant parts of the
|
||||
// transaction to avoid rehashing.
|
||||
const CTransaction txConst(mtx);
|
||||
// Sign what we can:
|
||||
for (unsigned int i = 0; i < mtx.vin.size(); i++) {
|
||||
CTxIn& txin = mtx.vin[i];
|
||||
auto coin = coins.find(txin.prevout);
|
||||
if (coin == coins.end() || coin->second.IsSpent()) {
|
||||
TxInErrorToJSON(txin, vErrors, "Input not found or already spent");
|
||||
continue;
|
||||
}
|
||||
const CScript& prevPubKey = coin->second.out.scriptPubKey;
|
||||
const CAmount& amount = coin->second.out.nValue;
|
||||
|
||||
SignatureData sigdata = DataFromTransaction(mtx, i, coin->second.out);
|
||||
// Only sign SIGHASH_SINGLE if there's a corresponding output:
|
||||
if (!fHashSingle || (i < mtx.vout.size())) {
|
||||
ProduceSignature(*keystore, MutableTransactionSignatureCreator(&mtx, i, amount, nHashType), prevPubKey, sigdata);
|
||||
}
|
||||
|
||||
UpdateInput(txin, sigdata);
|
||||
|
||||
// amount must be specified for valid segwit signature
|
||||
if (amount == MAX_MONEY && !txin.scriptWitness.IsNull()) {
|
||||
throw JSONRPCError(RPC_TYPE_ERROR, strprintf("Missing amount for %s", coin->second.out.ToString()));
|
||||
}
|
||||
|
||||
ScriptError serror = SCRIPT_ERR_OK;
|
||||
if (!VerifyScript(txin.scriptSig, prevPubKey, &txin.scriptWitness, STANDARD_SCRIPT_VERIFY_FLAGS, TransactionSignatureChecker(&txConst, i, amount), &serror)) {
|
||||
if (serror == SCRIPT_ERR_INVALID_STACK_OPERATION) {
|
||||
// Unable to sign input and verification failed (possible attempt to partially sign).
|
||||
TxInErrorToJSON(txin, vErrors, "Unable to sign input, invalid stack size (possibly missing key)");
|
||||
} else if (serror == SCRIPT_ERR_SIG_NULLFAIL) {
|
||||
// Verification failed (possibly due to insufficient signatures).
|
||||
TxInErrorToJSON(txin, vErrors, "CHECK(MULTI)SIG failing with non-zero signature (possibly need more signatures)");
|
||||
} else {
|
||||
TxInErrorToJSON(txin, vErrors, ScriptErrorString(serror));
|
||||
}
|
||||
for (const auto& err_pair : input_errors) {
|
||||
if (err_pair.second == "Missing amount") {
|
||||
// This particular error needs to be an exception for some reason
|
||||
throw JSONRPCError(RPC_TYPE_ERROR, strprintf("Missing amount for %s", coins.at(mtx.vin.at(err_pair.first).prevout).out.ToString()));
|
||||
}
|
||||
TxInErrorToJSON(mtx.vin.at(err_pair.first), vErrors, err_pair.second);
|
||||
}
|
||||
bool fComplete = vErrors.empty();
|
||||
|
||||
result.pushKV("hex", EncodeHexTx(CTransaction(mtx)));
|
||||
result.pushKV("complete", fComplete);
|
||||
result.pushKV("complete", complete);
|
||||
if (!vErrors.empty()) {
|
||||
if (result.exists("errors")) {
|
||||
vErrors.push_backV(result["errors"].getValues());
|
||||
|
Reference in New Issue
Block a user