Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F12945036
merkleblock.cpp
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
6 KB
Subscribers
None
merkleblock.cpp
View Options
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2014 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include
"merkleblock.h"
#include
"hash.h"
#include
"consensus/consensus.h"
#include
"utilstrencodings.h"
using
namespace
std
;
CMerkleBlock
::
CMerkleBlock
(
const
CBlock
&
block
,
CBloomFilter
&
filter
)
{
header
=
block
.
GetBlockHeader
();
vector
<
bool
>
vMatch
;
vector
<
uint256
>
vHashes
;
vMatch
.
reserve
(
block
.
vtx
.
size
());
vHashes
.
reserve
(
block
.
vtx
.
size
());
for
(
unsigned
int
i
=
0
;
i
<
block
.
vtx
.
size
();
i
++
)
{
const
uint256
&
hash
=
block
.
vtx
[
i
].
GetHash
();
if
(
filter
.
IsRelevantAndUpdate
(
block
.
vtx
[
i
]))
{
vMatch
.
push_back
(
true
);
vMatchedTxn
.
push_back
(
make_pair
(
i
,
hash
));
}
else
vMatch
.
push_back
(
false
);
vHashes
.
push_back
(
hash
);
}
txn
=
CPartialMerkleTree
(
vHashes
,
vMatch
);
}
CMerkleBlock
::
CMerkleBlock
(
const
CBlock
&
block
,
const
std
::
set
<
uint256
>&
txids
)
{
header
=
block
.
GetBlockHeader
();
vector
<
bool
>
vMatch
;
vector
<
uint256
>
vHashes
;
vMatch
.
reserve
(
block
.
vtx
.
size
());
vHashes
.
reserve
(
block
.
vtx
.
size
());
for
(
unsigned
int
i
=
0
;
i
<
block
.
vtx
.
size
();
i
++
)
{
const
uint256
&
hash
=
block
.
vtx
[
i
].
GetHash
();
if
(
txids
.
count
(
hash
))
vMatch
.
push_back
(
true
);
else
vMatch
.
push_back
(
false
);
vHashes
.
push_back
(
hash
);
}
txn
=
CPartialMerkleTree
(
vHashes
,
vMatch
);
}
uint256
CPartialMerkleTree
::
CalcHash
(
int
height
,
unsigned
int
pos
,
const
std
::
vector
<
uint256
>
&
vTxid
)
{
if
(
height
==
0
)
{
// hash at height 0 is the txids themself
return
vTxid
[
pos
];
}
else
{
// calculate left hash
uint256
left
=
CalcHash
(
height
-1
,
pos
*
2
,
vTxid
),
right
;
// calculate right hash if not beyond the end of the array - copy left hash otherwise1
if
(
pos
*
2
+
1
<
CalcTreeWidth
(
height
-1
))
right
=
CalcHash
(
height
-1
,
pos
*
2
+
1
,
vTxid
);
else
right
=
left
;
// combine subhashes
return
Hash
(
BEGIN
(
left
),
END
(
left
),
BEGIN
(
right
),
END
(
right
));
}
}
void
CPartialMerkleTree
::
TraverseAndBuild
(
int
height
,
unsigned
int
pos
,
const
std
::
vector
<
uint256
>
&
vTxid
,
const
std
::
vector
<
bool
>
&
vMatch
)
{
// determine whether this node is the parent of at least one matched txid
bool
fParentOfMatch
=
false
;
for
(
unsigned
int
p
=
pos
<<
height
;
p
<
(
pos
+
1
)
<<
height
&&
p
<
nTransactions
;
p
++
)
fParentOfMatch
|=
vMatch
[
p
];
// store as flag bit
vBits
.
push_back
(
fParentOfMatch
);
if
(
height
==
0
||
!
fParentOfMatch
)
{
// if at height 0, or nothing interesting below, store hash and stop
vHash
.
push_back
(
CalcHash
(
height
,
pos
,
vTxid
));
}
else
{
// otherwise, don't store any hash, but descend into the subtrees
TraverseAndBuild
(
height
-1
,
pos
*
2
,
vTxid
,
vMatch
);
if
(
pos
*
2
+
1
<
CalcTreeWidth
(
height
-1
))
TraverseAndBuild
(
height
-1
,
pos
*
2
+
1
,
vTxid
,
vMatch
);
}
}
uint256
CPartialMerkleTree
::
TraverseAndExtract
(
int
height
,
unsigned
int
pos
,
unsigned
int
&
nBitsUsed
,
unsigned
int
&
nHashUsed
,
std
::
vector
<
uint256
>
&
vMatch
)
{
if
(
nBitsUsed
>=
vBits
.
size
())
{
// overflowed the bits array - failure
fBad
=
true
;
return
uint256
();
}
bool
fParentOfMatch
=
vBits
[
nBitsUsed
++
];
if
(
height
==
0
||
!
fParentOfMatch
)
{
// if at height 0, or nothing interesting below, use stored hash and do not descend
if
(
nHashUsed
>=
vHash
.
size
())
{
// overflowed the hash array - failure
fBad
=
true
;
return
uint256
();
}
const
uint256
&
hash
=
vHash
[
nHashUsed
++
];
if
(
height
==
0
&&
fParentOfMatch
)
// in case of height 0, we have a matched txid
vMatch
.
push_back
(
hash
);
return
hash
;
}
else
{
// otherwise, descend into the subtrees to extract matched txids and hashes
uint256
left
=
TraverseAndExtract
(
height
-1
,
pos
*
2
,
nBitsUsed
,
nHashUsed
,
vMatch
),
right
;
if
(
pos
*
2
+
1
<
CalcTreeWidth
(
height
-1
))
{
right
=
TraverseAndExtract
(
height
-1
,
pos
*
2
+
1
,
nBitsUsed
,
nHashUsed
,
vMatch
);
if
(
right
==
left
)
{
// The left and right branches should never be identical, as the transaction
// hashes covered by them must each be unique.
fBad
=
true
;
}
}
else
{
right
=
left
;
}
// and combine them before returning
return
Hash
(
BEGIN
(
left
),
END
(
left
),
BEGIN
(
right
),
END
(
right
));
}
}
CPartialMerkleTree
::
CPartialMerkleTree
(
const
std
::
vector
<
uint256
>
&
vTxid
,
const
std
::
vector
<
bool
>
&
vMatch
)
:
nTransactions
(
vTxid
.
size
()),
fBad
(
false
)
{
// reset state
vBits
.
clear
();
vHash
.
clear
();
// calculate height of tree
int
nHeight
=
0
;
while
(
CalcTreeWidth
(
nHeight
)
>
1
)
nHeight
++
;
// traverse the partial tree
TraverseAndBuild
(
nHeight
,
0
,
vTxid
,
vMatch
);
}
CPartialMerkleTree
::
CPartialMerkleTree
()
:
nTransactions
(
0
),
fBad
(
true
)
{}
uint256
CPartialMerkleTree
::
ExtractMatches
(
std
::
vector
<
uint256
>
&
vMatch
)
{
vMatch
.
clear
();
// An empty set will not work
if
(
nTransactions
==
0
)
return
uint256
();
// check for excessively high numbers of transactions
if
(
nTransactions
>
MAX_BLOCK_SIZE
/
60
)
// 60 is the lower bound for the size of a serialized CTransaction
return
uint256
();
// there can never be more hashes provided than one for every txid
if
(
vHash
.
size
()
>
nTransactions
)
return
uint256
();
// there must be at least one bit per node in the partial tree, and at least one node per hash
if
(
vBits
.
size
()
<
vHash
.
size
())
return
uint256
();
// calculate height of tree
int
nHeight
=
0
;
while
(
CalcTreeWidth
(
nHeight
)
>
1
)
nHeight
++
;
// traverse the partial tree
unsigned
int
nBitsUsed
=
0
,
nHashUsed
=
0
;
uint256
hashMerkleRoot
=
TraverseAndExtract
(
nHeight
,
0
,
nBitsUsed
,
nHashUsed
,
vMatch
);
// verify that no problems occured during the tree traversal
if
(
fBad
)
return
uint256
();
// verify that all bits were consumed (except for the padding caused by serializing it as a byte sequence)
if
((
nBitsUsed
+
7
)
/
8
!=
(
vBits
.
size
()
+
7
)
/
8
)
return
uint256
();
// verify that all hashes were consumed
if
(
nHashUsed
!=
vHash
.
size
())
return
uint256
();
return
hashMerkleRoot
;
}
File Metadata
Details
Attached
Mime Type
text/x-c++
Expires
Fri, Feb 7, 17:18 (1 d, 21 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
5081901
Default Alt Text
merkleblock.cpp (6 KB)
Attached To
rABC Bitcoin ABC
Event Timeline
Log In to Comment