@@ -2410,34 +2410,71 @@ bool CWallet::SelectCoins(const std::vector<COutput>& vAvailableCoins, const CAm
2410
2410
return res;
2411
2411
}
2412
2412
2413
- bool CWallet::SignTransaction (CMutableTransaction& tx)
2413
+ bool CWallet::SignTransaction (CMutableTransaction& tx) const
2414
2414
{
2415
2415
AssertLockHeld (cs_wallet);
2416
2416
2417
- // sign the new tx
2418
- int nIn = 0 ;
2417
+ // Build coins map
2418
+ std::map<COutPoint, Coin> coins ;
2419
2419
for (auto & input : tx.vin ) {
2420
2420
std::map<uint256, CWalletTx>::const_iterator mi = mapWallet.find (input.prevout .hash );
2421
2421
if (mi == mapWallet.end () || input.prevout .n >= mi->second .tx ->vout .size ()) {
2422
2422
return false ;
2423
2423
}
2424
- const CScript& scriptPubKey = mi->second .tx ->vout [input.prevout .n ].scriptPubKey ;
2425
- const CAmount& amount = mi->second .tx ->vout [input.prevout .n ].nValue ;
2426
- SignatureData sigdata;
2424
+ const CWalletTx& wtx = mi->second ;
2425
+ coins[input.prevout ] = Coin (wtx.tx ->vout [input.prevout .n ], wtx.m_confirm .block_height , wtx.IsCoinBase ());
2426
+ }
2427
+ std::map<int , std::string> input_errors;
2428
+ return SignTransaction (tx, coins, SIGHASH_ALL, input_errors);
2429
+ }
2430
+
2431
+ bool CWallet::SignTransaction (CMutableTransaction& tx, const std::map<COutPoint, Coin>& coins, int sighash, std::map<int , std::string>& input_errors) const
2432
+ {
2433
+ // Sign the tx with ScriptPubKeyMans
2434
+ // Because each ScriptPubKeyMan can sign more than one input, we need to keep track of each ScriptPubKeyMan that has signed this transaction.
2435
+ // Each iteration, we may sign more txins than the txin that is specified in that iteration.
2436
+ // We assume that each input is signed by only one ScriptPubKeyMan.
2437
+ std::set<uint256> visited_spk_mans;
2438
+ for (unsigned int i = 0 ; i < tx.vin .size (); i++) {
2439
+ // Get the prevout
2440
+ CTxIn& txin = tx.vin [i];
2441
+ auto coin = coins.find (txin.prevout );
2442
+ if (coin == coins.end () || coin->second .IsSpent ()) {
2443
+ input_errors[i] = " Input not found or already spent" ;
2444
+ continue ;
2445
+ }
2427
2446
2428
- std::unique_ptr<SigningProvider> provider = GetSigningProvider (scriptPubKey);
2429
- if (!provider) {
2430
- // We don't know about this scriptpbuKey;
2431
- return false ;
2447
+ // Check if this input is complete
2448
+ SignatureData sigdata = DataFromTransaction (tx, i, coin-> second . out );
2449
+ if (sigdata. complete ) {
2450
+ continue ;
2432
2451
}
2433
2452
2434
- if (!ProduceSignature (*provider, MutableTransactionSignatureCreator (&tx, nIn, amount, SIGHASH_ALL), scriptPubKey, sigdata)) {
2435
- return false ;
2453
+ // Input needs to be signed, find the right ScriptPubKeyMan
2454
+ std::set<ScriptPubKeyMan*> spk_mans = GetScriptPubKeyMans (coin->second .out .scriptPubKey , sigdata);
2455
+ if (spk_mans.size () == 0 ) {
2456
+ input_errors[i] = " Unable to sign input, missing keys" ;
2457
+ continue ;
2458
+ }
2459
+
2460
+ for (auto & spk_man : spk_mans) {
2461
+ // If we've already been signed by this spk_man, skip it
2462
+ if (visited_spk_mans.count (spk_man->GetID ()) > 0 ) {
2463
+ continue ;
2464
+ }
2465
+
2466
+ // Sign the tx.
2467
+ // spk_man->SignTransaction will return true if the transaction is complete,
2468
+ // so we can exit early and return true if that happens.
2469
+ if (spk_man->SignTransaction (tx, coins, sighash, input_errors)) {
2470
+ return true ;
2471
+ }
2472
+
2473
+ // Add this spk_man to visited_spk_mans so we can skip it later
2474
+ visited_spk_mans.insert (spk_man->GetID ());
2436
2475
}
2437
- UpdateInput (input, sigdata);
2438
- nIn++;
2439
2476
}
2440
- return true ;
2477
+ return false ;
2441
2478
}
2442
2479
2443
2480
bool CWallet::FundTransaction (CMutableTransaction& tx, CAmount& nFeeRet, int & nChangePosInOut, std::string& strFailReason, bool lockUnspents, const std::set<int >& setSubtractFeeFromOutputs, CCoinControl coinControl)
@@ -4155,6 +4192,17 @@ ScriptPubKeyMan* CWallet::GetScriptPubKeyMan(const OutputType& type, bool intern
4155
4192
return it->second ;
4156
4193
}
4157
4194
4195
+ std::set<ScriptPubKeyMan*> CWallet::GetScriptPubKeyMans (const CScript& script, SignatureData& sigdata) const
4196
+ {
4197
+ std::set<ScriptPubKeyMan*> spk_mans;
4198
+ for (const auto & spk_man_pair : m_spk_managers) {
4199
+ if (spk_man_pair.second ->CanProvide (script, sigdata)) {
4200
+ spk_mans.insert (spk_man_pair.second .get ());
4201
+ }
4202
+ }
4203
+ return spk_mans;
4204
+ }
4205
+
4158
4206
ScriptPubKeyMan* CWallet::GetScriptPubKeyMan (const CScript& script) const
4159
4207
{
4160
4208
SignatureData sigdata;
0 commit comments