Skip to content

Commit b5fa132

Browse files
committed
Merge pull request #5181
afd4b94 Move CMerkleBlock and CPartialMerkleTree to their own file (Matt Corallo)
2 parents 4c83c0e + afd4b94 commit b5fa132

File tree

9 files changed

+318
-294
lines changed

9 files changed

+318
-294
lines changed

src/Makefile.am

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@ BITCOIN_CORE_H = \
101101
leveldbwrapper.h \
102102
limitedmap.h \
103103
main.h \
104+
merkleblock.h \
104105
miner.h \
105106
mruset.h \
106107
netbase.h \
@@ -168,6 +169,7 @@ libbitcoin_server_a_SOURCES = \
168169
init.cpp \
169170
leveldbwrapper.cpp \
170171
main.cpp \
172+
merkleblock.cpp \
171173
miner.cpp \
172174
net.cpp \
173175
noui.cpp \

src/bitcoin-tx.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,17 @@
44

55
#include "base58.h"
66
#include "clientversion.h"
7+
#include "primitives/block.h" // for MAX_BLOCK_SIZE
78
#include "primitives/transaction.h"
89
#include "core_io.h"
10+
#include "coins.h"
911
#include "keystore.h"
10-
#include "main.h" // for MAX_BLOCK_SIZE
1112
#include "script/script.h"
1213
#include "script/sign.h"
1314
#include "ui_interface.h" // for _(...)
1415
#include "univalue/univalue.h"
1516
#include "util.h"
17+
#include "utilstrencodings.h"
1618
#include "utilmoneystr.h"
1719

1820
#include <stdio.h>

src/main.cpp

Lines changed: 1 addition & 153 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include "checkpoints.h"
1212
#include "checkqueue.h"
1313
#include "init.h"
14+
#include "merkleblock.h"
1415
#include "net.h"
1516
#include "pow.h"
1617
#include "txdb.h"
@@ -2721,159 +2722,6 @@ bool TestBlockValidity(CValidationState &state, const CBlock& block, CBlockIndex
27212722

27222723

27232724

2724-
CMerkleBlock::CMerkleBlock(const CBlock& block, CBloomFilter& filter)
2725-
{
2726-
header = block.GetBlockHeader();
2727-
2728-
vector<bool> vMatch;
2729-
vector<uint256> vHashes;
2730-
2731-
vMatch.reserve(block.vtx.size());
2732-
vHashes.reserve(block.vtx.size());
2733-
2734-
for (unsigned int i = 0; i < block.vtx.size(); i++)
2735-
{
2736-
const uint256& hash = block.vtx[i].GetHash();
2737-
if (filter.IsRelevantAndUpdate(block.vtx[i]))
2738-
{
2739-
vMatch.push_back(true);
2740-
vMatchedTxn.push_back(make_pair(i, hash));
2741-
}
2742-
else
2743-
vMatch.push_back(false);
2744-
vHashes.push_back(hash);
2745-
}
2746-
2747-
txn = CPartialMerkleTree(vHashes, vMatch);
2748-
}
2749-
2750-
2751-
2752-
2753-
2754-
2755-
2756-
2757-
uint256 CPartialMerkleTree::CalcHash(int height, unsigned int pos, const std::vector<uint256> &vTxid) {
2758-
if (height == 0) {
2759-
// hash at height 0 is the txids themself
2760-
return vTxid[pos];
2761-
} else {
2762-
// calculate left hash
2763-
uint256 left = CalcHash(height-1, pos*2, vTxid), right;
2764-
// calculate right hash if not beyond the end of the array - copy left hash otherwise1
2765-
if (pos*2+1 < CalcTreeWidth(height-1))
2766-
right = CalcHash(height-1, pos*2+1, vTxid);
2767-
else
2768-
right = left;
2769-
// combine subhashes
2770-
return Hash(BEGIN(left), END(left), BEGIN(right), END(right));
2771-
}
2772-
}
2773-
2774-
void CPartialMerkleTree::TraverseAndBuild(int height, unsigned int pos, const std::vector<uint256> &vTxid, const std::vector<bool> &vMatch) {
2775-
// determine whether this node is the parent of at least one matched txid
2776-
bool fParentOfMatch = false;
2777-
for (unsigned int p = pos << height; p < (pos+1) << height && p < nTransactions; p++)
2778-
fParentOfMatch |= vMatch[p];
2779-
// store as flag bit
2780-
vBits.push_back(fParentOfMatch);
2781-
if (height==0 || !fParentOfMatch) {
2782-
// if at height 0, or nothing interesting below, store hash and stop
2783-
vHash.push_back(CalcHash(height, pos, vTxid));
2784-
} else {
2785-
// otherwise, don't store any hash, but descend into the subtrees
2786-
TraverseAndBuild(height-1, pos*2, vTxid, vMatch);
2787-
if (pos*2+1 < CalcTreeWidth(height-1))
2788-
TraverseAndBuild(height-1, pos*2+1, vTxid, vMatch);
2789-
}
2790-
}
2791-
2792-
uint256 CPartialMerkleTree::TraverseAndExtract(int height, unsigned int pos, unsigned int &nBitsUsed, unsigned int &nHashUsed, std::vector<uint256> &vMatch) {
2793-
if (nBitsUsed >= vBits.size()) {
2794-
// overflowed the bits array - failure
2795-
fBad = true;
2796-
return 0;
2797-
}
2798-
bool fParentOfMatch = vBits[nBitsUsed++];
2799-
if (height==0 || !fParentOfMatch) {
2800-
// if at height 0, or nothing interesting below, use stored hash and do not descend
2801-
if (nHashUsed >= vHash.size()) {
2802-
// overflowed the hash array - failure
2803-
fBad = true;
2804-
return 0;
2805-
}
2806-
const uint256 &hash = vHash[nHashUsed++];
2807-
if (height==0 && fParentOfMatch) // in case of height 0, we have a matched txid
2808-
vMatch.push_back(hash);
2809-
return hash;
2810-
} else {
2811-
// otherwise, descend into the subtrees to extract matched txids and hashes
2812-
uint256 left = TraverseAndExtract(height-1, pos*2, nBitsUsed, nHashUsed, vMatch), right;
2813-
if (pos*2+1 < CalcTreeWidth(height-1))
2814-
right = TraverseAndExtract(height-1, pos*2+1, nBitsUsed, nHashUsed, vMatch);
2815-
else
2816-
right = left;
2817-
// and combine them before returning
2818-
return Hash(BEGIN(left), END(left), BEGIN(right), END(right));
2819-
}
2820-
}
2821-
2822-
CPartialMerkleTree::CPartialMerkleTree(const std::vector<uint256> &vTxid, const std::vector<bool> &vMatch) : nTransactions(vTxid.size()), fBad(false) {
2823-
// reset state
2824-
vBits.clear();
2825-
vHash.clear();
2826-
2827-
// calculate height of tree
2828-
int nHeight = 0;
2829-
while (CalcTreeWidth(nHeight) > 1)
2830-
nHeight++;
2831-
2832-
// traverse the partial tree
2833-
TraverseAndBuild(nHeight, 0, vTxid, vMatch);
2834-
}
2835-
2836-
CPartialMerkleTree::CPartialMerkleTree() : nTransactions(0), fBad(true) {}
2837-
2838-
uint256 CPartialMerkleTree::ExtractMatches(std::vector<uint256> &vMatch) {
2839-
vMatch.clear();
2840-
// An empty set will not work
2841-
if (nTransactions == 0)
2842-
return 0;
2843-
// check for excessively high numbers of transactions
2844-
if (nTransactions > MAX_BLOCK_SIZE / 60) // 60 is the lower bound for the size of a serialized CTransaction
2845-
return 0;
2846-
// there can never be more hashes provided than one for every txid
2847-
if (vHash.size() > nTransactions)
2848-
return 0;
2849-
// there must be at least one bit per node in the partial tree, and at least one node per hash
2850-
if (vBits.size() < vHash.size())
2851-
return 0;
2852-
// calculate height of tree
2853-
int nHeight = 0;
2854-
while (CalcTreeWidth(nHeight) > 1)
2855-
nHeight++;
2856-
// traverse the partial tree
2857-
unsigned int nBitsUsed = 0, nHashUsed = 0;
2858-
uint256 hashMerkleRoot = TraverseAndExtract(nHeight, 0, nBitsUsed, nHashUsed, vMatch);
2859-
// verify that no problems occured during the tree traversal
2860-
if (fBad)
2861-
return 0;
2862-
// verify that all bits were consumed (except for the padding caused by serializing it as a byte sequence)
2863-
if ((nBitsUsed+7)/8 != (vBits.size()+7)/8)
2864-
return 0;
2865-
// verify that all hashes were consumed
2866-
if (nHashUsed != vHash.size())
2867-
return 0;
2868-
return hashMerkleRoot;
2869-
}
2870-
2871-
2872-
2873-
2874-
2875-
2876-
28772725
bool AbortNode(const std::string &strMessage, const std::string &userMessage) {
28782726
strMiscWarning = strMessage;
28792727
LogPrintf("*** %s\n", strMessage);

src/main.h

Lines changed: 0 additions & 138 deletions
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,6 @@ class CValidationState;
4949
struct CBlockTemplate;
5050
struct CNodeStateStats;
5151

52-
/** The maximum allowed size for a serialized block, in bytes (network rule) */
53-
static const unsigned int MAX_BLOCK_SIZE = 1000000;
5452
/** Default for -blockmaxsize and -blockminsize, which control the range of sizes the mining code will create **/
5553
static const unsigned int DEFAULT_BLOCK_MAX_SIZE = 750000;
5654
static const unsigned int DEFAULT_BLOCK_MIN_SIZE = 0;
@@ -358,110 +356,6 @@ class CScriptCheck
358356
ScriptError GetScriptError() const { return error; }
359357
};
360358

361-
/** Data structure that represents a partial merkle tree.
362-
*
363-
* It represents a subset of the txid's of a known block, in a way that
364-
* allows recovery of the list of txid's and the merkle root, in an
365-
* authenticated way.
366-
*
367-
* The encoding works as follows: we traverse the tree in depth-first order,
368-
* storing a bit for each traversed node, signifying whether the node is the
369-
* parent of at least one matched leaf txid (or a matched txid itself). In
370-
* case we are at the leaf level, or this bit is 0, its merkle node hash is
371-
* stored, and its children are not explorer further. Otherwise, no hash is
372-
* stored, but we recurse into both (or the only) child branch. During
373-
* decoding, the same depth-first traversal is performed, consuming bits and
374-
* hashes as they written during encoding.
375-
*
376-
* The serialization is fixed and provides a hard guarantee about the
377-
* encoded size:
378-
*
379-
* SIZE <= 10 + ceil(32.25*N)
380-
*
381-
* Where N represents the number of leaf nodes of the partial tree. N itself
382-
* is bounded by:
383-
*
384-
* N <= total_transactions
385-
* N <= 1 + matched_transactions*tree_height
386-
*
387-
* The serialization format:
388-
* - uint32 total_transactions (4 bytes)
389-
* - varint number of hashes (1-3 bytes)
390-
* - uint256[] hashes in depth-first order (<= 32*N bytes)
391-
* - varint number of bytes of flag bits (1-3 bytes)
392-
* - byte[] flag bits, packed per 8 in a byte, least significant bit first (<= 2*N-1 bits)
393-
* The size constraints follow from this.
394-
*/
395-
class CPartialMerkleTree
396-
{
397-
protected:
398-
/** the total number of transactions in the block */
399-
unsigned int nTransactions;
400-
401-
/** node-is-parent-of-matched-txid bits */
402-
std::vector<bool> vBits;
403-
404-
/** txids and internal hashes */
405-
std::vector<uint256> vHash;
406-
407-
/** flag set when encountering invalid data */
408-
bool fBad;
409-
410-
/** helper function to efficiently calculate the number of nodes at given height in the merkle tree */
411-
unsigned int CalcTreeWidth(int height) {
412-
return (nTransactions+(1 << height)-1) >> height;
413-
}
414-
415-
/** calculate the hash of a node in the merkle tree (at leaf level: the txid's themselves) */
416-
uint256 CalcHash(int height, unsigned int pos, const std::vector<uint256> &vTxid);
417-
418-
/** recursive function that traverses tree nodes, storing the data as bits and hashes */
419-
void TraverseAndBuild(int height, unsigned int pos, const std::vector<uint256> &vTxid, const std::vector<bool> &vMatch);
420-
421-
/**
422-
* recursive function that traverses tree nodes, consuming the bits and hashes produced by TraverseAndBuild.
423-
* it returns the hash of the respective node.
424-
*/
425-
uint256 TraverseAndExtract(int height, unsigned int pos, unsigned int &nBitsUsed, unsigned int &nHashUsed, std::vector<uint256> &vMatch);
426-
427-
public:
428-
429-
/** serialization implementation */
430-
ADD_SERIALIZE_METHODS;
431-
432-
template <typename Stream, typename Operation>
433-
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
434-
READWRITE(nTransactions);
435-
READWRITE(vHash);
436-
std::vector<unsigned char> vBytes;
437-
if (ser_action.ForRead()) {
438-
READWRITE(vBytes);
439-
CPartialMerkleTree &us = *(const_cast<CPartialMerkleTree*>(this));
440-
us.vBits.resize(vBytes.size() * 8);
441-
for (unsigned int p = 0; p < us.vBits.size(); p++)
442-
us.vBits[p] = (vBytes[p / 8] & (1 << (p % 8))) != 0;
443-
us.fBad = false;
444-
} else {
445-
vBytes.resize((vBits.size()+7)/8);
446-
for (unsigned int p = 0; p < vBits.size(); p++)
447-
vBytes[p / 8] |= vBits[p] << (p % 8);
448-
READWRITE(vBytes);
449-
}
450-
}
451-
452-
/** Construct a partial merkle tree from a list of transaction id's, and a mask that selects a subset of them */
453-
CPartialMerkleTree(const std::vector<uint256> &vTxid, const std::vector<bool> &vMatch);
454-
455-
CPartialMerkleTree();
456-
457-
/**
458-
* extract the matching txid's represented by this partial merkle tree.
459-
* returns the merkle root, or 0 in case of failure
460-
*/
461-
uint256 ExtractMatches(std::vector<uint256> &vMatch);
462-
};
463-
464-
465359

466360
/** Functions for disk access for blocks */
467361
bool WriteBlockToDisk(CBlock& block, CDiskBlockPos& pos);
@@ -652,38 +546,6 @@ struct CBlockTemplate
652546

653547

654548

655-
/**
656-
* Used to relay blocks as header + vector<merkle branch>
657-
* to filtered nodes.
658-
*/
659-
class CMerkleBlock
660-
{
661-
public:
662-
/** Public only for unit testing */
663-
CBlockHeader header;
664-
CPartialMerkleTree txn;
665-
666-
public:
667-
/** Public only for unit testing and relay testing (not relayed) */
668-
std::vector<std::pair<unsigned int, uint256> > vMatchedTxn;
669-
670-
/**
671-
* Create from a CBlock, filtering transactions according to filter
672-
* Note that this will call IsRelevantAndUpdate on the filter for each transaction,
673-
* thus the filter will likely be modified.
674-
*/
675-
CMerkleBlock(const CBlock& block, CBloomFilter& filter);
676-
677-
ADD_SERIALIZE_METHODS;
678-
679-
template <typename Stream, typename Operation>
680-
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
681-
READWRITE(header);
682-
READWRITE(txn);
683-
}
684-
};
685-
686-
687549
class CValidationInterface {
688550
protected:
689551
virtual void SyncTransaction(const CTransaction &tx, const CBlock *pblock) {};

0 commit comments

Comments
 (0)