aboutsummaryrefslogtreecommitdiff
path: root/src/main.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/main.h')
-rw-r--r--src/main.h259
1 files changed, 238 insertions, 21 deletions
diff --git a/src/main.h b/src/main.h
index 8bceffbaf9..2d3a9f5bd0 100644
--- a/src/main.h
+++ b/src/main.h
@@ -53,6 +53,8 @@ inline bool MoneyRange(int64 nValue) { return (nValue >= 0 && nValue <= MAX_MONE
static const int COINBASE_MATURITY = 100;
/** Threshold for nLockTime: below this value it is interpreted as block number, otherwise as UNIX timestamp. */
static const unsigned int LOCKTIME_THRESHOLD = 500000000; // Tue Nov 5 00:53:20 1985 UTC
+/** Maximum number of script-checking threads allowed */
+static const int MAX_SCRIPTCHECK_THREADS = 16;
#ifdef USE_UPNP
static const int fHaveUPnP = true;
#else
@@ -90,6 +92,7 @@ extern unsigned char pchMessageStart[4];
extern bool fImporting;
extern bool fReindex;
extern bool fBenchmark;
+extern int nScriptCheckThreads;
extern unsigned int nCoinCacheSize;
// Settings
@@ -107,6 +110,9 @@ class CCoins;
class CTxUndo;
class CCoinsView;
class CCoinsViewCache;
+class CScriptCheck;
+
+struct CBlockTemplate;
/** Register a wallet to receive updates from core */
void RegisterWallet(CWallet* pwalletIn);
@@ -117,7 +123,7 @@ void SyncWithWallets(const uint256 &hash, const CTransaction& tx, const CBlock*
/** Process an incoming block */
bool ProcessBlock(CNode* pfrom, CBlock* pblock, CDiskBlockPos *dbp = NULL);
/** Check whether enough disk space is available for an incoming block */
-bool CheckDiskSpace(uint64 nAdditionalBytes=0);
+bool CheckDiskSpace(uint64 nAdditionalBytes = 0);
/** Open a block file (blk?????.dat) */
FILE* OpenBlockFile(const CDiskBlockPos &pos, bool fReadOnly = false);
/** Open an undo file (rev?????.dat) */
@@ -126,6 +132,8 @@ FILE* OpenUndoFile(const CDiskBlockPos &pos, bool fReadOnly = false);
bool LoadExternalBlockFile(FILE* fileIn, CDiskBlockPos *dbp = NULL);
/** Load the block tree and coins database from disk */
bool LoadBlockIndex();
+/** Verify consistency of the block and coin databases */
+bool VerifyDB();
/** Print the loaded block tree */
void PrintBlockTree();
/** Find a block by height in the currently-connected chain */
@@ -136,10 +144,14 @@ bool ProcessMessages(CNode* pfrom);
bool SendMessages(CNode* pto, bool fSendTrickle);
/** Run the importer thread, which deals with reindexing, loading bootstrap.dat, and whatever is passed to -loadblock */
void ThreadImport(void *parg);
+/** Run an instance of the script checking thread */
+void ThreadScriptCheck(void* parg);
+/** Stop the script checking threads */
+void ThreadScriptCheckQuit();
/** Run the miner threads */
void GenerateBitcoins(bool fGenerate, CWallet* pwallet);
/** Generate a new block, without valid proof-of-work */
-CBlock* CreateNewBlock(CReserveKey& reservekey);
+CBlockTemplate* CreateNewBlock(CReserveKey& reservekey);
/** Modify the extranonce in a block */
void IncrementExtraNonce(CBlock* pblock, CBlockIndex* pindexPrev, unsigned int& nExtraNonce);
/** Do mining precalculation */
@@ -164,6 +176,8 @@ bool SetBestChain(CBlockIndex* pindexNew);
bool ConnectBestBlock();
/** Create a new block index entry for a given block hash */
CBlockIndex * InsertBlockIndex(uint256 hash);
+/** Verify a signature */
+bool VerifySignature(const CCoins& txFrom, const CTransaction& txTo, unsigned int nIn, unsigned int flags, int nHashType);
@@ -428,16 +442,8 @@ enum GetMinFee_mode
GMF_SEND,
};
-// Modes for script/signature checking
-enum CheckSig_mode
-{
- CS_NEVER, // never validate scripts
- CS_AFTER_CHECKPOINT, // validate scripts after the last checkpoint
- CS_ALWAYS // always validate scripts
-};
-
/** The basic transaction that is broadcasted on the network and contained in
- * blocks. A transaction can contain multiple inputs and outputs.
+ * blocks. A transaction can contain multiple inputs and outputs.
*/
class CTransaction
{
@@ -544,13 +550,11 @@ public:
/** Check for standard transaction types
@param[in] mapInputs Map of previous transactions that have outputs we're spending
@return True if all inputs (scriptSigs) use only standard transaction forms
- @see CTransaction::FetchInputs
*/
bool AreInputsStandard(CCoinsViewCache& mapInputs) const;
/** Count ECDSA signature operations the old-fashioned (pre-0.6) way
@return number of sigops this transaction's outputs will produce when spent
- @see CTransaction::FetchInputs
*/
unsigned int GetLegacySigOpCount() const;
@@ -558,7 +562,6 @@ public:
@param[in] mapInputs Map of previous transactions that have outputs we're spending
@return maximum number of sigops required to validate this transaction's inputs
- @see CTransaction::FetchInputs
*/
unsigned int GetP2SHSigOpCount(CCoinsViewCache& mapInputs) const;
@@ -583,7 +586,6 @@ public:
@param[in] mapInputs Map of previous transactions that have outputs we're spending
@return Sum of value of all inputs (scriptSigs)
- @see CTransaction::FetchInputs
*/
int64 GetValueIn(CCoinsViewCache& mapInputs) const;
@@ -639,8 +641,11 @@ public:
bool HaveInputs(CCoinsViewCache &view) const;
// Check whether all inputs of this transaction are valid (no double spends, scripts & sigs, amounts)
- // This does not modify the UTXO set
- bool CheckInputs(CCoinsViewCache &view, enum CheckSig_mode csmode, unsigned int flags = SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC) const;
+ // This does not modify the UTXO set. If pvChecks is not NULL, script checks are pushed onto it
+ // instead of being performed inline.
+ bool CheckInputs(CCoinsViewCache &view, bool fScriptChecks = true,
+ unsigned int flags = SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC,
+ std::vector<CScriptCheck> *pvChecks = NULL) const;
// Apply the effects of this transaction on the UTXO set represented by view
bool UpdateCoins(CCoinsViewCache &view, CTxUndo &txundo, int nHeight, const uint256 &txhash) const;
@@ -746,7 +751,7 @@ public:
READWRITE(vtxundo);
)
- bool WriteToDisk(CDiskBlockPos &pos)
+ bool WriteToDisk(CDiskBlockPos &pos, const uint256 &hashBlock)
{
// Open history file to append
CAutoFile fileout = CAutoFile(OpenUndoFile(pos), SER_DISK, CLIENT_VERSION);
@@ -764,6 +769,12 @@ public:
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())
@@ -771,6 +782,43 @@ public:
return true;
}
+
+ bool 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;
+ }
+ catch (std::exception &e) {
+ return error("%s() : deserialize or I/O error", __PRETTY_FUNCTION__);
+ }
+
+ // for compatibility with pre-release code that didn't write checksums to undo data
+ // TODO: replace by a simply 'filein >> hashChecksum' in the above try block
+ try {
+ filein >> hashChecksum;
+ } catch (std::exception &e) {
+ hashChecksum = 0;
+ }
+ uint32_t hashInit = hashChecksum.Get64(0) & 0xFFFFFFFFUL;
+ if (hashChecksum == 0 || memcmp(&hashInit, pchMessageStart, 4) == 0)
+ return true;
+
+ // Verify checksum
+ CHashWriter hasher(SER_GETHASH, PROTOCOL_VERSION);
+ hasher << hashBlock;
+ hasher << *this;
+ if (hashChecksum != hasher.GetHash())
+ return error("CBlockUndo::ReadFromDisk() : checksum mismatch");
+
+ return true;
+ }
};
/** pruned version of CTransaction: only retains metadata and unspent transaction outputs
@@ -1013,7 +1061,33 @@ public:
}
};
+/** Closure representing one script verification
+ * Note that this stores references to the spending transaction */
+class CScriptCheck
+{
+private:
+ CScript scriptPubKey;
+ const CTransaction *ptxTo;
+ unsigned int nIn;
+ unsigned int nFlags;
+ int nHashType;
+public:
+ CScriptCheck() {}
+ CScriptCheck(const CCoins& txFromIn, const CTransaction& txToIn, unsigned int nInIn, unsigned int nFlagsIn, int nHashTypeIn) :
+ scriptPubKey(txFromIn.vout[txToIn.vin[nInIn].prevout.n].scriptPubKey),
+ ptxTo(&txToIn), nIn(nInIn), nFlags(nFlagsIn), nHashType(nHashTypeIn) { }
+
+ bool operator()() const;
+
+ void swap(CScriptCheck &check) {
+ scriptPubKey.swap(check.scriptPubKey);
+ std::swap(ptxTo, check.ptxTo);
+ std::swap(nIn, check.nIn);
+ std::swap(nFlags, check.nFlags);
+ std::swap(nHashType, check.nHashType);
+ }
+};
/** A transaction with a merkle branch linking it to the block chain. */
class CMerkleTx : public CTransaction
@@ -1067,11 +1141,101 @@ public:
+/** Data structure that represents a partial merkle tree.
+ *
+ * It respresents a subset of the txid's of a known block, in a way that
+ * allows recovery of the list of txid's and the merkle root, in an
+ * authenticated way.
+ *
+ * The encoding works as follows: we traverse the tree in depth-first order,
+ * storing a bit for each traversed node, signifying whether the node is the
+ * parent of at least one matched leaf txid (or a matched txid itself). In
+ * case we are at the leaf level, or this bit is 0, its merkle node hash is
+ * stored, and its children are not explorer further. Otherwise, no hash is
+ * stored, but we recurse into both (or the only) child branch. During
+ * decoding, the same depth-first traversal is performed, consuming bits and
+ * hashes as they written during encoding.
+ *
+ * The serialization is fixed and provides a hard guarantee about the
+ * encoded size:
+ *
+ * SIZE <= 10 + ceil(32.25*N)
+ *
+ * Where N represents the number of leaf nodes of the partial tree. N itself
+ * is bounded by:
+ *
+ * N <= total_transactions
+ * N <= 1 + matched_transactions*tree_height
+ *
+ * The serialization format:
+ * - uint32 total_transactions (4 bytes)
+ * - varint number of hashes (1-3 bytes)
+ * - uint256[] hashes in depth-first order (<= 32*N bytes)
+ * - varint number of bytes of flag bits (1-3 bytes)
+ * - byte[] flag bits, packed per 8 in a byte, least significant bit first (<= 2*N-1 bits)
+ * The size constraints follow from this.
+ */
+class CPartialMerkleTree
+{
+protected:
+ // the total number of transactions in the block
+ unsigned int nTransactions;
+
+ // node-is-parent-of-matched-txid bits
+ std::vector<bool> vBits;
+
+ // txids and internal hashes
+ std::vector<uint256> vHash;
+
+ // flag set when encountering invalid data
+ bool fBad;
+
+ // helper function to efficiently calculate the number of nodes at given height in the merkle tree
+ unsigned int CalcTreeWidth(int height) {
+ return (nTransactions+(1 << height)-1) >> height;
+ }
+
+ // calculate the hash of a node in the merkle tree (at leaf level: the txid's themself)
+ uint256 CalcHash(int height, unsigned int pos, const std::vector<uint256> &vTxid);
+
+ // recursive function that traverses tree nodes, storing the data as bits and hashes
+ void TraverseAndBuild(int height, unsigned int pos, const std::vector<uint256> &vTxid, const std::vector<bool> &vMatch);
+ // recursive function that traverses tree nodes, consuming the bits and hashes produced by TraverseAndBuild.
+ // it returns the hash of the respective node.
+ uint256 TraverseAndExtract(int height, unsigned int pos, unsigned int &nBitsUsed, unsigned int &nHashUsed, std::vector<uint256> &vMatch);
+public:
+ // serialization implementation
+ IMPLEMENT_SERIALIZE(
+ READWRITE(nTransactions);
+ READWRITE(vHash);
+ std::vector<unsigned char> vBytes;
+ if (fRead) {
+ READWRITE(vBytes);
+ CPartialMerkleTree &us = *(const_cast<CPartialMerkleTree*>(this));
+ us.vBits.resize(vBytes.size() * 8);
+ for (unsigned int p = 0; p < us.vBits.size(); p++)
+ us.vBits[p] = (vBytes[p / 8] & (1 << (p % 8))) != 0;
+ us.fBad = false;
+ } else {
+ vBytes.resize((vBits.size()+7)/8);
+ for (unsigned int p = 0; p < vBits.size(); p++)
+ vBytes[p / 8] |= vBits[p] << (p % 8);
+ READWRITE(vBytes);
+ }
+ )
+ // Construct a partial merkle tree from a list of transaction id's, and a mask that selects a subset of them
+ CPartialMerkleTree(const std::vector<uint256> &vTxid, const std::vector<bool> &vMatch);
+ CPartialMerkleTree();
+
+ // extract the matching txid's represented by this partial merkle tree.
+ // returns the merkle root, or 0 in case of failure
+ uint256 ExtractMatches(std::vector<uint256> &vMatch);
+};
/** Nodes collect new transactions into a block, hash them into a hash tree,
@@ -1175,6 +1339,18 @@ public:
nDoS = 0;
}
+ CBlockHeader GetBlockHeader() const
+ {
+ CBlockHeader block;
+ block.nVersion = nVersion;
+ block.hashPrevBlock = hashPrevBlock;
+ block.hashMerkleRoot = hashMerkleRoot;
+ block.nTime = nTime;
+ block.nBits = nBits;
+ block.nNonce = nNonce;
+ return block;
+ }
+
uint256 BuildMerkleTree() const
{
vMerkleTree.clear();
@@ -1231,7 +1407,6 @@ public:
return hash;
}
-
bool WriteToDisk(CDiskBlockPos &pos)
{
// Open history file to append
@@ -1305,8 +1480,11 @@ public:
}
- // Undo the effects of this block (with given index) on the UTXO set represented by coins
- bool DisconnectBlock(CBlockIndex *pindex, CCoinsViewCache &coins);
+ /** Undo the effects of this block (with given index) on the UTXO set represented by coins.
+ * In case pfClean is provided, operation will try to be tolerant about errors, and *pfClean
+ * will be true if no problems were found. Otherwise, the return value will be false in case
+ * of problems. Note that in any case, coins may be modified. */
+ bool DisconnectBlock(CBlockIndex *pindex, CCoinsViewCache &coins, bool *pfClean = NULL);
// Apply the effects of this block (with given index) on the UTXO set represented by coins
bool ConnectBlock(CBlockIndex *pindex, CCoinsViewCache &coins, bool fJustCheck=false);
@@ -1975,4 +2153,43 @@ extern CCoinsViewCache *pcoinsTip;
/** Global variable that points to the active block tree (protected by cs_main) */
extern CBlockTreeDB *pblocktree;
+struct CBlockTemplate
+{
+ CBlock block;
+ std::vector<int64_t> vTxFees;
+ std::vector<int64_t> vTxSigOps;
+};
+
+
+
+
+
+
+/** Used to relay blocks as header + vector<merkle branch>
+ * to filtered nodes.
+ */
+class CMerkleBlock
+{
+public:
+ // Public only for unit testing
+ CBlockHeader header;
+ CPartialMerkleTree txn;
+
+public:
+ // Public only for unit testing and relay testing
+ // (not relayed)
+ std::vector<std::pair<unsigned int, uint256> > vMatchedTxn;
+
+ // Create from a CBlock, filtering transactions according to filter
+ // Note that this will call IsRelevantAndUpdate on the filter for each transaction,
+ // thus the filter will likely be modified.
+ CMerkleBlock(const CBlock& block, CBloomFilter& filter);
+
+ IMPLEMENT_SERIALIZE
+ (
+ READWRITE(header);
+ READWRITE(txn);
+ )
+};
+
#endif