aboutsummaryrefslogtreecommitdiff
path: root/src/main.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/main.cpp')
-rw-r--r--src/main.cpp162
1 files changed, 153 insertions, 9 deletions
diff --git a/src/main.cpp b/src/main.cpp
index d7543e3f13..6567c77e93 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -20,9 +20,11 @@
#include <sstream>
+#include <boost/dynamic_bitset.hpp>
#include <boost/algorithm/string/replace.hpp>
#include <boost/filesystem.hpp>
#include <boost/filesystem/fstream.hpp>
+#include <boost/thread.hpp>
using namespace std;
using namespace boost;
@@ -643,7 +645,7 @@ bool IsFinalTx(const CTransaction &tx, int nBlockHeight, int64_t nBlockTime)
// 2. P2SH scripts with a crazy number of expensive
// CHECKSIG/CHECKMULTISIG operations
//
-bool AreInputsStandard(const CTransaction& tx, CCoinsViewCache& mapInputs)
+bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs)
{
if (tx.IsCoinBase())
return true; // Coinbases don't use vin normally
@@ -716,7 +718,7 @@ unsigned int GetLegacySigOpCount(const CTransaction& tx)
return nSigOps;
}
-unsigned int GetP2SHSigOpCount(const CTransaction& tx, CCoinsViewCache& inputs)
+unsigned int GetP2SHSigOpCount(const CTransaction& tx, const CCoinsViewCache& inputs)
{
if (tx.IsCoinBase())
return 0;
@@ -1022,7 +1024,7 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
pool.addUnchecked(hash, entry);
}
- g_signals.SyncTransaction(tx, NULL);
+ SyncWithWallets(tx, NULL);
return true;
}
@@ -1469,7 +1471,7 @@ bool VerifySignature(const CCoins& txFrom, const CTransaction& txTo, unsigned in
return CScriptCheck(txFrom, txTo, nIn, flags, nHashType)();
}
-bool CheckInputs(const CTransaction& tx, CValidationState &state, CCoinsViewCache &inputs, bool fScriptChecks, unsigned int flags, std::vector<CScriptCheck> *pvChecks)
+bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsViewCache &inputs, bool fScriptChecks, unsigned int flags, std::vector<CScriptCheck> *pvChecks)
{
if (!tx.IsCoinBase())
{
@@ -1857,10 +1859,6 @@ bool ConnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, C
int64_t nTime3 = GetTimeMicros(); nTimeIndex += nTime3 - nTime2;
LogPrint("bench", " - Index writing: %.2fms [%.2fs]\n", 0.001 * (nTime3 - nTime2), nTimeIndex * 0.000001);
- // Watch for transactions paying to me
- BOOST_FOREACH(const CTransaction& tx, block.vtx)
- g_signals.SyncTransaction(tx, &block);
-
// Watch for changes to the previous coinbase transaction.
static uint256 hashPrevBestCoinBase;
g_signals.UpdatedTransaction(hashPrevBestCoinBase);
@@ -3237,7 +3235,7 @@ bool LoadExternalBlockFile(FILE* fileIn, CDiskBlockPos *dbp)
}
}
uint64_t nRewind = blkdat.GetPos();
- while (blkdat.good() && !blkdat.eof()) {
+ while (!blkdat.eof()) {
boost::this_thread::interruption_point();
blkdat.SetPos(nRewind);
@@ -3521,6 +3519,75 @@ void static ProcessGetData(CNode* pfrom)
}
}
+struct CCoin {
+ uint32_t nTxVer; // Don't call this nVersion, that name has a special meaning inside IMPLEMENT_SERIALIZE
+ uint32_t nHeight;
+ CTxOut out;
+
+ IMPLEMENT_SERIALIZE(
+ READWRITE(nTxVer);
+ READWRITE(nHeight);
+ READWRITE(out);
+ )
+};
+
+bool ProcessGetUTXOs(const vector<COutPoint> &vOutPoints, bool fCheckMemPool, vector<unsigned char> *result, vector<CCoin> *resultCoins)
+{
+ // Defined by BIP 64.
+ //
+ // Allows a peer to retrieve the CTxOut structures corresponding to the given COutPoints.
+ // Note that this data is not authenticated by anything: this code could just invent any
+ // old rubbish and hand it back, with the peer being unable to tell unless they are checking
+ // the outpoints against some out of band data.
+ //
+ // Also the answer could change the moment after we give it. However some apps can tolerate
+ // this, because they're only using the result as a hint or are willing to trust the results
+ // based on something else. For example we may be a "trusted node" for the peer, or it may
+ // be checking the results given by several nodes for consistency, it may
+ // run the UTXOs returned against scriptSigs of transactions obtained elsewhere (after checking
+ // for a standard script form), and because the height in which the UTXO was defined is provided
+ // a client that has a map of heights to block headers (as SPV clients do, for recent blocks)
+ // can request the creating block via hash.
+ //
+ // IMPORTANT: Clients expect ordering to be preserved!
+ if (vOutPoints.size() > MAX_INV_SZ)
+ return error("message getutxos size() = %u", vOutPoints.size());
+
+ LogPrint("net", "getutxos for %d queries %s mempool\n", vOutPoints.size(), fCheckMemPool ? "with" : "without");
+
+ boost::dynamic_bitset<unsigned char> hits(vOutPoints.size());
+ {
+ LOCK2(cs_main, mempool.cs);
+ CCoinsViewMemPool cvMemPool(*pcoinsTip, mempool);
+ CCoinsViewCache view(fCheckMemPool ? cvMemPool : *pcoinsTip);
+ for (size_t i = 0; i < vOutPoints.size(); i++)
+ {
+ CCoins coins;
+ uint256 hash = vOutPoints[i].hash;
+ if (view.GetCoins(hash, coins))
+ {
+ mempool.pruneSpent(hash, coins);
+ if (coins.IsAvailable(vOutPoints[i].n))
+ {
+ hits[i] = true;
+ // Safe to index into vout here because IsAvailable checked if it's off the end of the array, or if
+ // n is valid but points to an already spent output (IsNull).
+ CCoin coin;
+ coin.nTxVer = coins.nVersion;
+ coin.nHeight = coins.nHeight;
+ coin.out = coins.vout.at(vOutPoints[i].n);
+ assert(!coin.out.IsNull());
+ resultCoins->push_back(coin);
+ }
+ }
+ }
+ }
+
+ boost::to_block_range(hits, std::back_inserter(*result));
+ return true;
+}
+
+
bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, int64_t nTimeReceived)
{
RandAddSeedPerfmon();
@@ -3869,6 +3936,22 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
}
+ else if (strCommand == "getutxos")
+ {
+ bool fCheckMemPool;
+ vector<COutPoint> vOutPoints;
+ vRecv >> fCheckMemPool;
+ vRecv >> vOutPoints;
+
+ vector<unsigned char> bitmap;
+ vector<CCoin> outs;
+ if (ProcessGetUTXOs(vOutPoints, fCheckMemPool, &bitmap, &outs))
+ pfrom->PushMessage("utxos", chainActive.Height(), chainActive.Tip()->GetBlockHash(), bitmap, outs);
+ else
+ Misbehaving(pfrom->GetId(), 20);
+ }
+
+
else if (strCommand == "tx")
{
vector<uint256> vWorkQueue;
@@ -4573,7 +4656,68 @@ bool SendMessages(CNode* pto, bool fSendTrickle)
}
+bool CBlockUndo::WriteToDisk(CDiskBlockPos &pos, const uint256 &hashBlock)
+{
+ // Open history file to append
+ CAutoFile fileout = CAutoFile(OpenUndoFile(pos), SER_DISK, CLIENT_VERSION);
+ if (!fileout)
+ return error("CBlockUndo::WriteToDisk : OpenUndoFile failed");
+
+ // Write index header
+ unsigned int nSize = fileout.GetSerializeSize(*this);
+ fileout << FLATDATA(Params().MessageStart()) << nSize;
+
+ // Write undo data
+ long fileOutPos = ftell(fileout);
+ if (fileOutPos < 0)
+ return error("CBlockUndo::WriteToDisk : ftell failed");
+ pos.nPos = (unsigned int)fileOutPos;
+ fileout << *this;
+
+ // calculate & write checksum
+ CHashWriter hasher(SER_GETHASH, PROTOCOL_VERSION);
+ hasher << hashBlock;
+ hasher << *this;
+ fileout << hasher.GetHash();
+
+ // Flush stdio buffers and commit to disk before returning
+ fflush(fileout);
+ if (!IsInitialBlockDownload())
+ FileCommit(fileout);
+
+ return true;
+}
+
+bool CBlockUndo::ReadFromDisk(const CDiskBlockPos &pos, const uint256 &hashBlock)
+{
+ // Open history file to read
+ CAutoFile filein = CAutoFile(OpenUndoFile(pos, true), SER_DISK, CLIENT_VERSION);
+ if (!filein)
+ return error("CBlockUndo::ReadFromDisk : OpenBlockFile failed");
+
+ // Read block
+ uint256 hashChecksum;
+ try {
+ filein >> *this;
+ filein >> hashChecksum;
+ }
+ catch (std::exception &e) {
+ return error("%s : Deserialize or I/O error - %s", __func__, e.what());
+ }
+
+ // Verify checksum
+ CHashWriter hasher(SER_GETHASH, PROTOCOL_VERSION);
+ hasher << hashBlock;
+ hasher << *this;
+ if (hashChecksum != hasher.GetHash())
+ return error("CBlockUndo::ReadFromDisk : Checksum mismatch");
+
+ return true;
+}
+ std::string CBlockFileInfo::ToString() const {
+ return strprintf("CBlockFileInfo(blocks=%u, size=%u, heights=%u...%u, time=%s...%s)", nBlocks, nSize, nHeightFirst, nHeightLast, DateTimeStrFormat("%Y-%m-%d", nTimeFirst).c_str(), DateTimeStrFormat("%Y-%m-%d", nTimeLast).c_str());
+ }