diff options
author | MeshCollider <dobsonsa68@gmail.com> | 2019-03-21 20:57:40 +1300 |
---|---|---|
committer | MeshCollider <dobsonsa68@gmail.com> | 2019-03-21 20:58:43 +1300 |
commit | 2607d960a02e21098092e95ba6bc2a64c93e6127 (patch) | |
tree | e4078a747e44c27eee9ab35e7c2894a9c9bb3232 /src/rpc/rawtransaction.cpp | |
parent | b3f82284ba9035411b3d2d83b507549a4b12cfc8 (diff) | |
parent | d358466de15ef29c1d2bccb9aebab360d574d1d0 (diff) |
Merge #10973: Refactor: separate wallet from node
d358466de Remove remaining wallet accesses to node globals (Russell Yanofsky)
b1b2b2389 Remove use of CCoinsViewMemPool::GetCoin in wallet code (Russell Yanofsky)
4e4d9e9f8 Remove use of CRPCTable::appendCommand in wallet code (Russell Yanofsky)
91868e628 Remove use CValidationInterface in wallet code (Russell Yanofsky)
Pull request description:
This PR is the last in a chain of PRs (#14437, #14711, and #15288) that make the wallet code access node state through an abstract [`Chain`](https://github.com/ryanofsky/bitcoin/blob/pr/wipc-sep/src/interfaces/chain.h) class in [`src/interfaces/`](https://github.com/ryanofsky/bitcoin/tree/pr/wipc-sep/src/interfaces) instead of using global variables like `cs_main`, `chainActive`, and `g_connman`. After this PR, wallet code no longer accesses global variables declared outside the wallet directory, and no longer calls functions accessing those globals (as verified by the `hide-globals` script in #10244).
This PR and the previous PRs have been refactoring changes that do not affect behavior. Previous PRs have consisted of lots of mechanical changes like:
```diff
- wtx.nTimeReceived = GetAdjustedTime();
+ wtx.nTimeReceived = m_chain->getAdjustedTime();
```
This PR is smaller, but less mechanical. It replaces last few bits of wallet code that access node state directly (through `CValidationInterface`, `CRPCTable`, and `CCoinsViewMemPool` interfaces) with code that uses the `Chain` interface.
These changes allow followup PR #10102 (multiprocess gui & wallet PR) to work without any significant updates to wallet code. Additionally they:
* Provide a single place to describe the interface between wallet and node code.
* Can make better wallet testing possible, because the `Chain` object consists of virtual methods that can be overloaded for mocking. (This could be used to test edge cases in the rescan code, for example).
Tree-SHA512: e6291d8a3c50bdff18a9c8ad11e729beb30b5b7040d7aaf31ba678800b4a97b2dd2be76340b1e5c01fe2827d67d37ed1bb4c8380cf8ed653aadfea003e9b22e7
Diffstat (limited to 'src/rpc/rawtransaction.cpp')
-rw-r--r-- | src/rpc/rawtransaction.cpp | 44 |
1 files changed, 21 insertions, 23 deletions
diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp index 1d58725a58..0cd1494512 100644 --- a/src/rpc/rawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -11,6 +11,7 @@ #include <core_io.h> #include <index/txindex.h> #include <init.h> +#include <interfaces/chain.h> #include <key_io.h> #include <keystore.h> #include <merkleblock.h> @@ -791,23 +792,20 @@ static UniValue combinerawtransaction(const JSONRPCRequest& request) return EncodeHexTx(CTransaction(mergedTx)); } +// TODO(https://github.com/bitcoin/bitcoin/pull/10973#discussion_r267084237): +// This function is called from both wallet and node rpcs +// (signrawtransactionwithwallet and signrawtransactionwithkey). It should be +// moved to a util file so wallet code doesn't need to link against node code. +// Also the dependency on interfaces::Chain should be removed, so +// signrawtransactionwithkey doesn't need access to a Chain instance. UniValue SignTransaction(interfaces::Chain& chain, CMutableTransaction& mtx, const UniValue& prevTxsUnival, CBasicKeyStore *keystore, bool is_temp_keystore, const UniValue& hashType) { // Fetch previous transactions (inputs): - CCoinsView viewDummy; - CCoinsViewCache view(&viewDummy); - { - LOCK2(cs_main, mempool.cs); - CCoinsViewCache &viewChain = *pcoinsTip; - CCoinsViewMemPool viewMempool(&viewChain, mempool); - view.SetBackend(viewMempool); // temporarily switch cache backend to db+mempool view - - for (const CTxIn& txin : mtx.vin) { - view.AccessCoin(txin.prevout); // Load entries from viewChain into view; can fail. - } - - view.SetBackend(viewDummy); // switch back to avoid locking mempool for too long + std::map<COutPoint, Coin> coins; + for (const CTxIn& txin : mtx.vin) { + coins[txin.prevout]; // Create empty map entry keyed by prevout. } + chain.findCoins(coins); // Add previous txouts given in the RPC call: if (!prevTxsUnival.isNull()) { @@ -839,10 +837,10 @@ UniValue SignTransaction(interfaces::Chain& chain, CMutableTransaction& mtx, con CScript scriptPubKey(pkData.begin(), pkData.end()); { - const Coin& coin = view.AccessCoin(out); - if (!coin.IsSpent() && coin.out.scriptPubKey != scriptPubKey) { + auto coin = coins.find(out); + if (coin != coins.end() && !coin->second.IsSpent() && coin->second.out.scriptPubKey != scriptPubKey) { std::string err("Previous output scriptPubKey mismatch:\n"); - err = err + ScriptToAsmStr(coin.out.scriptPubKey) + "\nvs:\n"+ + err = err + ScriptToAsmStr(coin->second.out.scriptPubKey) + "\nvs:\n"+ ScriptToAsmStr(scriptPubKey); throw JSONRPCError(RPC_DESERIALIZATION_ERROR, err); } @@ -853,7 +851,7 @@ UniValue SignTransaction(interfaces::Chain& chain, CMutableTransaction& mtx, con newcoin.out.nValue = AmountFromValue(find_value(prevOut, "amount")); } newcoin.nHeight = 1; - view.AddCoin(out, std::move(newcoin), true); + coins[out] = std::move(newcoin); } // if redeemScript and private keys were given, add redeemScript to the keystore so it can be signed @@ -897,15 +895,15 @@ UniValue SignTransaction(interfaces::Chain& chain, CMutableTransaction& mtx, con // Sign what we can: for (unsigned int i = 0; i < mtx.vin.size(); i++) { CTxIn& txin = mtx.vin[i]; - const Coin& coin = view.AccessCoin(txin.prevout); - if (coin.IsSpent()) { + 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.out.scriptPubKey; - const CAmount& amount = coin.out.nValue; + const CScript& prevPubKey = coin->second.out.scriptPubKey; + const CAmount& amount = coin->second.out.nValue; - SignatureData sigdata = DataFromTransaction(mtx, i, coin.out); + 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); @@ -915,7 +913,7 @@ UniValue SignTransaction(interfaces::Chain& chain, CMutableTransaction& mtx, con // 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.out.ToString())); + throw JSONRPCError(RPC_TYPE_ERROR, strprintf("Missing amount for %s", coin->second.out.ToString())); } ScriptError serror = SCRIPT_ERR_OK; |