Skip to content

Commit 5447622

Browse files
committed
[Wallet] Do not store Merkle branches in the wallet
Backport of bitcoin#6550 Assume that when a wallet transaction has a valid block hash and transaction position in it, the transaction is actually there. We're already trusting wallet data in a much more fundamental way anyway. To prevent backward compatibility issues, a new record is used for storing the block locator in the wallet. Old wallets will see a wallet file synchronized up to the genesis block, and rescan automatically.
1 parent adfcb46 commit 5447622

File tree

10 files changed

+23
-70
lines changed

10 files changed

+23
-70
lines changed

src/chainparams.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,7 @@ class CMainParams : public CChainParams
205205
txNew.vout[0].scriptPubKey = CScript() << ParseHex("04c10e83b2703ccf322f7dbd62dd5855ac7c10bd055814ce121ba32607d573b8810c02c0582aed05b4deb9c4b77b26d92428c61256cd42774babea0a073b2ed0c9") << OP_CHECKSIG;
206206
genesis.vtx.push_back(txNew);
207207
genesis.hashPrevBlock = 0;
208-
genesis.hashMerkleRoot = genesis.BuildMerkleTree();
208+
genesis.hashMerkleRoot = genesis.ComputeMerkleRoot();
209209
genesis.nVersion = 1;
210210
genesis.nTime = 1454124731;
211211
genesis.nBits = 0x1e0ffff0;

src/main.cpp

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4375,6 +4375,9 @@ bool CheckBlock(const CBlock& block, CValidationState& state, bool fCheckPOW, bo
43754375
LogPrint("debug", "%s: block=%s is proof of stake=%d\n", __func__, block.GetHash().ToString().c_str(), IsPoS);
43764376

43774377

4378+
if (block.fChecked)
4379+
return true;
4380+
43784381
// Check that the header is valid (particularly PoW). This is mostly
43794382
// redundant with the call in AcceptBlockHeader.
43804383
if (!CheckBlockHeader(block, state, !IsPoS))
@@ -4393,7 +4396,7 @@ bool CheckBlock(const CBlock& block, CValidationState& state, bool fCheckPOW, bo
43934396
// Check the merkle root.
43944397
if (fCheckMerkleRoot) {
43954398
bool mutated;
4396-
uint256 hashMerkleRoot2 = block.BuildMerkleTree(&mutated);
4399+
uint256 hashMerkleRoot2 = block.ComputeMerkleRoot(&mutated);
43974400
if (block.hashMerkleRoot != hashMerkleRoot2)
43984401
return state.DoS(100, error("%s : hashMerkleRoot mismatch", __func__),
43994402
REJECT_INVALID, "bad-txnmrklroot", true);
@@ -4526,7 +4529,6 @@ bool CheckBlock(const CBlock& block, CValidationState& state, bool fCheckPOW, bo
45264529
}
45274530
}
45284531

4529-
45304532
unsigned int nSigOps = 0;
45314533
for (const CTransaction& tx : block.vtx) {
45324534
nSigOps += GetLegacySigOpCount(tx);
@@ -4536,6 +4538,9 @@ bool CheckBlock(const CBlock& block, CValidationState& state, bool fCheckPOW, bo
45364538
return state.DoS(100, error("%s : out-of-bounds SigOpCount", __func__),
45374539
REJECT_INVALID, "bad-blk-sigops", true);
45384540

4541+
if (fCheckPOW && fCheckMerkleRoot && fCheckSig)
4542+
block.fChecked = true;
4543+
45394544
return true;
45404545
}
45414546

src/miner.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -569,7 +569,7 @@ void IncrementExtraNonce(CBlock* pblock, CBlockIndex* pindexPrev, unsigned int&
569569
assert(txCoinbase.vin[0].scriptSig.size() <= 100);
570570

571571
pblock->vtx[0] = txCoinbase;
572-
pblock->hashMerkleRoot = pblock->BuildMerkleTree();
572+
pblock->hashMerkleRoot = pblock->ComputeMerkleRoot();
573573
}
574574

575575
#ifdef ENABLE_WALLET

src/primitives/block.cpp

Lines changed: 2 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ uint256 CBlockHeader::GetHash() const
2121
return Hash(BEGIN(nVersion), END(nAccumulatorCheckpoint));
2222
}
2323

24-
uint256 CBlock::BuildMerkleTree(bool* fMutated) const
24+
uint256 CBlock::ComputeMerkleRoot(bool* fMutated) const
2525
{
2626
/* WARNING! If you're reading this because you're learning about crypto
2727
and/or designing a new system that will use merkle trees, keep in mind
@@ -58,7 +58,7 @@ uint256 CBlock::BuildMerkleTree(bool* fMutated) const
5858
known ways of changing the transactions without affecting the merkle
5959
root.
6060
*/
61-
vMerkleTree.clear();
61+
std::vector<uint256> vMerkleTree;
6262
vMerkleTree.reserve(vtx.size() * 2 + 16); // Safe upper bound for the number of total nodes.
6363
for (std::vector<CTransaction>::const_iterator it(vtx.begin()); it != vtx.end(); ++it)
6464
vMerkleTree.push_back(it->GetHash());
@@ -84,37 +84,6 @@ uint256 CBlock::BuildMerkleTree(bool* fMutated) const
8484
return (vMerkleTree.empty() ? uint256() : vMerkleTree.back());
8585
}
8686

87-
std::vector<uint256> CBlock::GetMerkleBranch(int nIndex) const
88-
{
89-
if (vMerkleTree.empty())
90-
BuildMerkleTree();
91-
std::vector<uint256> vMerkleBranch;
92-
int j = 0;
93-
for (int nSize = vtx.size(); nSize > 1; nSize = (nSize + 1) / 2)
94-
{
95-
int i = std::min(nIndex^1, nSize-1);
96-
vMerkleBranch.push_back(vMerkleTree[j+i]);
97-
nIndex >>= 1;
98-
j += nSize;
99-
}
100-
return vMerkleBranch;
101-
}
102-
103-
uint256 CBlock::CheckMerkleBranch(uint256 hash, const std::vector<uint256>& vMerkleBranch, int nIndex)
104-
{
105-
if (nIndex == -1)
106-
return uint256();
107-
for (std::vector<uint256>::const_iterator it(vMerkleBranch.begin()); it != vMerkleBranch.end(); ++it)
108-
{
109-
if (nIndex & 1)
110-
hash = Hash(BEGIN(*it), END(*it), BEGIN(hash), END(hash));
111-
else
112-
hash = Hash(BEGIN(hash), END(hash), BEGIN(*it), END(*it));
113-
nIndex >>= 1;
114-
}
115-
return hash;
116-
}
117-
11887
std::string CBlock::ToString() const
11988
{
12089
std::stringstream s;
@@ -129,10 +98,6 @@ std::string CBlock::ToString() const
12998
{
13099
s << " " << vtx[i].ToString() << "\n";
131100
}
132-
s << " vMerkleTree: ";
133-
for (unsigned int i = 0; i < vMerkleTree.size(); i++)
134-
s << " " << vMerkleTree[i].ToString();
135-
s << "\n";
136101
return s.str();
137102
}
138103

src/primitives/block.h

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ class CBlock : public CBlockHeader
9494

9595
// memory only
9696
mutable CScript payee;
97-
mutable std::vector<uint256> vMerkleTree;
97+
mutable bool fChecked;
9898

9999
CBlock()
100100
{
@@ -121,7 +121,7 @@ class CBlock : public CBlockHeader
121121
{
122122
CBlockHeader::SetNull();
123123
vtx.clear();
124-
vMerkleTree.clear();
124+
fChecked = false;
125125
payee = CScript();
126126
vchBlockSig.clear();
127127
}
@@ -157,14 +157,12 @@ class CBlock : public CBlockHeader
157157
return IsProofOfStake()? std::make_pair(vtx[1].vin[0].prevout, nTime) : std::make_pair(COutPoint(), (unsigned int)0);
158158
}
159159

160-
// Build the in-memory merkle tree for this block and return the merkle root.
160+
// Build the merkle tree for this block and return the merkle root.
161161
// If non-NULL, *mutated is set to whether mutation was detected in the merkle
162162
// tree (a duplication of transactions in the block leading to an identical
163163
// merkle root).
164-
uint256 BuildMerkleTree(bool* mutated = NULL) const;
164+
uint256 ComputeMerkleRoot(bool* mutated = NULL) const;
165165

166-
std::vector<uint256> GetMerkleBranch(int nIndex) const;
167-
static uint256 CheckMerkleBranch(uint256 hash, const std::vector<uint256>& vMerkleBranch, int nIndex);
168166
std::string ToString() const;
169167
void print() const;
170168
};

src/test/miner_tests.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
8282
pblock->vtx[0] = CTransaction(txCoinbase);
8383
if (txFirst.size() < 2)
8484
txFirst.push_back(new CTransaction(pblock->vtx[0]));
85-
pblock->hashMerkleRoot = pblock->BuildMerkleTree();
85+
pblock->hashMerkleRoot = pblock->ComputeMerkleRoot();
8686
pblock->nNonce = blockinfo[i].nonce;
8787
CValidationState state;
8888
BOOST_CHECK(ProcessNewBlock(state, NULL, pblock));

src/test/pmt_tests.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ BOOST_AUTO_TEST_CASE(pmt_test1)
4545
}
4646

4747
// calculate actual merkle root and height
48-
uint256 merkleRoot1 = block.BuildMerkleTree();
48+
uint256 merkleRoot1 = block.ComputeMerkleRoot();
4949
std::vector<uint256> vTxid(nTx, 0);
5050
for (unsigned int j=0; j<nTx; j++)
5151
vTxid[j] = block.vtx[j].GetHash();

src/wallet/wallet.cpp

Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -700,8 +700,7 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn, bool fFromLoadWallet)
700700
wtx.hashBlock = wtxIn.hashBlock;
701701
fUpdated = true;
702702
}
703-
if (wtxIn.nIndex != -1 && (wtxIn.vMerkleBranch != wtx.vMerkleBranch || wtxIn.nIndex != wtx.nIndex)) {
704-
wtx.vMerkleBranch = wtxIn.vMerkleBranch;
703+
if (wtxIn.nIndex != -1 && wtxIn.nIndex != wtx.nIndex) {
705704
wtx.nIndex = wtxIn.nIndex;
706705
fUpdated = true;
707706
}
@@ -3647,15 +3646,11 @@ int CMerkleTx::SetMerkleBranch(const CBlock& block)
36473646
if (block.vtx[nIndex] == *(CTransaction*)this)
36483647
break;
36493648
if (nIndex == (int)block.vtx.size()) {
3650-
vMerkleBranch.clear();
36513649
nIndex = -1;
36523650
LogPrintf("ERROR: SetMerkleBranch() : couldn't find tx in block\n");
36533651
return 0;
36543652
}
36553653

3656-
// Fill in merkle branch
3657-
vMerkleBranch = block.GetMerkleBranch(nIndex);
3658-
36593654
// Is the tx in a block that's in the main chain
36603655
BlockMap::iterator mi = mapBlockIndex.find(hashBlock);
36613656
if (mi == mapBlockIndex.end())
@@ -3681,13 +3676,6 @@ int CMerkleTx::GetDepthInMainChainINTERNAL(const CBlockIndex*& pindexRet) const
36813676
if (!pindex || !chainActive.Contains(pindex))
36823677
return 0;
36833678

3684-
// Make sure the merkle branch connects to this block
3685-
if (!fMerkleVerified) {
3686-
if (CBlock::CheckMerkleBranch(GetHash(), vMerkleBranch, nIndex) != pindex->hashMerkleRoot)
3687-
return 0;
3688-
fMerkleVerified = true;
3689-
}
3690-
36913679
pindexRet = pindex;
36923680
return chainActive.Height() - pindex->nHeight + 1;
36933681
}

src/wallet/wallet.h

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -766,13 +766,8 @@ class CMerkleTx : public CTransaction
766766

767767
public:
768768
uint256 hashBlock;
769-
std::vector<uint256> vMerkleBranch;
770769
int nIndex;
771770

772-
// memory only
773-
mutable bool fMerkleVerified;
774-
775-
776771
CMerkleTx()
777772
{
778773
Init();
@@ -787,14 +782,14 @@ class CMerkleTx : public CTransaction
787782
{
788783
hashBlock = 0;
789784
nIndex = -1;
790-
fMerkleVerified = false;
791785
}
792786

793787
ADD_SERIALIZE_METHODS;
794788

795789
template <typename Stream, typename Operation>
796790
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion)
797791
{
792+
std::vector<uint256> vMerkleBranch; // For compatibility with older versions.
798793
READWRITE(*(CTransaction*)this);
799794
nVersion = this->nVersion;
800795
READWRITE(hashBlock);

src/wallet/walletdb.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -197,12 +197,14 @@ bool CWalletDB::EraseMultiSig(const CScript& dest)
197197
bool CWalletDB::WriteBestBlock(const CBlockLocator& locator)
198198
{
199199
nWalletDBUpdated++;
200-
return Write(std::string("bestblock"), locator);
200+
Write(std::string("bestblock"), CBlockLocator()); // Write empty block locator so versions that require a merkle branch automatically rescan
201+
return Write(std::string("bestblock_nomerkle"), locator);
201202
}
202203

203204
bool CWalletDB::ReadBestBlock(CBlockLocator& locator)
204205
{
205-
return Read(std::string("bestblock"), locator);
206+
if (Read(std::string("bestblock"), locator) && !locator.vHave.empty()) return true;
207+
return Read(std::string("bestblock_nomerkle"), locator);
206208
}
207209

208210
bool CWalletDB::WriteOrderPosNext(int64_t nOrderPosNext)

0 commit comments

Comments
 (0)