@@ -2410,34 +2410,71 @@ bool CWallet::SelectCoins(const std::vector<COutput>& vAvailableCoins, const CAm
24102410 return res;
24112411}
24122412
2413- bool CWallet::SignTransaction (CMutableTransaction& tx)
2413+ bool CWallet::SignTransaction (CMutableTransaction& tx) const
24142414{
24152415 AssertLockHeld (cs_wallet);
24162416
2417- // sign the new tx
2418- int nIn = 0 ;
2417+ // Build coins map
2418+ std::map<COutPoint, Coin> coins ;
24192419 for (auto & input : tx.vin ) {
24202420 std::map<uint256, CWalletTx>::const_iterator mi = mapWallet.find (input.prevout .hash );
24212421 if (mi == mapWallet.end () || input.prevout .n >= mi->second .tx ->vout .size ()) {
24222422 return false ;
24232423 }
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+ }
24272446
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 ;
24322451 }
24332452
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 ());
24362475 }
2437- UpdateInput (input, sigdata);
2438- nIn++;
24392476 }
2440- return true ;
2477+ return false ;
24412478}
24422479
24432480bool 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
41554192 return it->second ;
41564193}
41574194
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+
41584206ScriptPubKeyMan* CWallet::GetScriptPubKeyMan (const CScript& script) const
41594207{
41604208 SignatureData sigdata;
0 commit comments