diff options
Diffstat (limited to 'src/rpcrawtransaction.cpp')
-rw-r--r-- | src/rpcrawtransaction.cpp | 87 |
1 files changed, 43 insertions, 44 deletions
diff --git a/src/rpcrawtransaction.cpp b/src/rpcrawtransaction.cpp index cb5bae62da..c62898316c 100644 --- a/src/rpcrawtransaction.cpp +++ b/src/rpcrawtransaction.cpp @@ -118,7 +118,7 @@ Value getrawtransaction(const Array& params, bool fHelp) CTransaction tx; uint256 hashBlock = 0; - if (!GetTransaction(hash, tx, hashBlock)) + if (!GetTransaction(hash, tx, hashBlock, true)) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "No information available about transaction"); CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION); @@ -335,26 +335,22 @@ Value signrawtransaction(const Array& params, bool fHelp) bool fComplete = true; // Fetch previous transactions (inputs): - map<COutPoint, CScript> mapPrevOut; - for (unsigned int i = 0; i < mergedTx.vin.size(); i++) + CCoinsView viewDummy; + CCoinsViewCache view(viewDummy); { - CTransaction tempTx; - MapPrevTx mapPrevTx; - CTxDB txdb("r"); - map<uint256, CTxIndex> unused; - bool fInvalid; - - // FetchInputs aborts on failure, so we go one at a time. - tempTx.vin.push_back(mergedTx.vin[i]); - tempTx.FetchInputs(txdb, unused, false, false, mapPrevTx, fInvalid); - - // Copy results into mapPrevOut: - BOOST_FOREACH(const CTxIn& txin, tempTx.vin) - { + LOCK(mempool.cs); + CCoinsDB coinsdb("r"); + CCoinsViewDB viewDB(coinsdb); + CCoinsViewMemPool viewMempool(viewDB, mempool); + view.SetBackend(viewMempool); // temporarily switch cache backend to db+mempool view + + BOOST_FOREACH(const CTxIn& txin, mergedTx.vin) { const uint256& prevHash = txin.prevout.hash; - if (mapPrevTx.count(prevHash) && mapPrevTx[prevHash].second.vout.size()>txin.prevout.n) - mapPrevOut[txin.prevout] = mapPrevTx[prevHash].second.vout[txin.prevout.n].scriptPubKey; + CCoins coins; + view.GetCoins(prevHash, coins); // this is certainly allowed to fail } + + view.SetBackend(viewDummy); // switch back to avoid locking db/mempool too long } // Add previous txouts given in the RPC call: @@ -386,20 +382,19 @@ Value signrawtransaction(const Array& params, bool fHelp) vector<unsigned char> pkData(ParseHex(pkHex)); CScript scriptPubKey(pkData.begin(), pkData.end()); - COutPoint outpoint(txid, nOut); - if (mapPrevOut.count(outpoint)) - { - // Complain if scriptPubKey doesn't match - if (mapPrevOut[outpoint] != scriptPubKey) - { + CCoins coins; + if (view.GetCoins(txid, coins)) { + if (coins.IsAvailable(nOut) && coins.vout[nOut].scriptPubKey != scriptPubKey) { string err("Previous output scriptPubKey mismatch:\n"); - err = err + mapPrevOut[outpoint].ToString() + "\nvs:\n"+ + err = err + coins.vout[nOut].scriptPubKey.ToString() + "\nvs:\n"+ scriptPubKey.ToString(); throw JSONRPCError(RPC_DESERIALIZATION_ERROR, err); } + // what todo if txid is known, but the actual output isn't? } - else - mapPrevOut[outpoint] = scriptPubKey; + coins.vout[nOut].scriptPubKey = scriptPubKey; + coins.vout[nOut].nValue = 0; // we don't know the actual output value + view.SetCoins(txid, coins); } } @@ -452,12 +447,13 @@ Value signrawtransaction(const Array& params, bool fHelp) for (unsigned int i = 0; i < mergedTx.vin.size(); i++) { CTxIn& txin = mergedTx.vin[i]; - if (mapPrevOut.count(txin.prevout) == 0) + CCoins coins; + if (!view.GetCoins(txin.prevout.hash, coins) || !coins.IsAvailable(txin.prevout.n)) { fComplete = false; continue; } - const CScript& prevPubKey = mapPrevOut[txin.prevout]; + const CScript& prevPubKey = coins.vout[txin.prevout.n].scriptPubKey; txin.scriptSig.clear(); // Only sign SIGHASH_SINGLE if there's a corresponding output: @@ -505,24 +501,27 @@ Value sendrawtransaction(const Array& params, bool fHelp) } uint256 hashTx = tx.GetHash(); - // See if the transaction is already in a block - // or in the memory pool: - CTransaction existingTx; - uint256 hashBlock = 0; - if (GetTransaction(hashTx, existingTx, hashBlock)) + bool fHave = false; + CCoins existingCoins; { - if (hashBlock != 0) - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("transaction already in block ")+hashBlock.GetHex()); + CCoinsDB coinsdb("r"); + { + CCoinsViewDB coinsviewDB(coinsdb); + CCoinsViewMemPool coinsview(coinsviewDB, mempool); + fHave = coinsview.GetCoins(hashTx, existingCoins); + } + if (!fHave) { + // push to local node + if (!tx.AcceptToMemoryPool(coinsdb)) + throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX rejected"); + } + } + if (fHave) { + if (existingCoins.nHeight < 1000000000) + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "transaction already in block chain"); // Not in block, but already in the memory pool; will drop // through to re-relay it. - } - else - { - // push to local node - CTxDB txdb("r"); - if (!tx.AcceptToMemoryPool(txdb)) - throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX rejected"); - + } else { SyncWithWallets(tx, NULL, true); } RelayMessage(CInv(MSG_TX, hashTx), tx); |