aboutsummaryrefslogtreecommitdiff
path: root/src/main.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/main.h')
-rw-r--r--src/main.h208
1 files changed, 197 insertions, 11 deletions
diff --git a/src/main.h b/src/main.h
index 3b7621959a..2d3a9f5bd0 100644
--- a/src/main.h
+++ b/src/main.h
@@ -112,6 +112,8 @@ class CCoinsView;
class CCoinsViewCache;
class CScriptCheck;
+struct CBlockTemplate;
+
/** Register a wallet to receive updates from core */
void RegisterWallet(CWallet* pwalletIn);
/** Unregister a wallet from core */
@@ -121,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) */
@@ -130,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 */
@@ -147,7 +151,7 @@ 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 */
@@ -439,7 +443,7 @@ enum GetMinFee_mode
};
/** 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
{
@@ -546,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;
@@ -560,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;
@@ -585,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;
@@ -751,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);
@@ -769,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())
@@ -776,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
@@ -1098,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,
@@ -1206,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();
@@ -1262,7 +1407,6 @@ public:
return hash;
}
-
bool WriteToDisk(CDiskBlockPos &pos)
{
// Open history file to append
@@ -1336,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);
@@ -2006,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