Add consensus support for Sapling merkle trees.
This commit is contained in:
@@ -7,13 +7,6 @@
|
|||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
uint256 CBlockIndex::GetSaplingAnchorEnd() const {
|
|
||||||
// TODO: The block header's hashFinalSaplingRoot is only guaranteed to
|
|
||||||
// be valid on or after the Sapling activation height.
|
|
||||||
|
|
||||||
return hashFinalSaplingRoot;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* CChain implementation
|
* CChain implementation
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -321,9 +321,6 @@ public:
|
|||||||
//! Efficiently find an ancestor of this block.
|
//! Efficiently find an ancestor of this block.
|
||||||
CBlockIndex* GetAncestor(int height);
|
CBlockIndex* GetAncestor(int height);
|
||||||
const CBlockIndex* GetAncestor(int height) const;
|
const CBlockIndex* GetAncestor(int height) const;
|
||||||
|
|
||||||
//! Get the root of the Sapling merkle tree (at the end of this block)
|
|
||||||
uint256 GetSaplingAnchorEnd() const;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Used to marshal pointers into hashes for db storage. */
|
/** Used to marshal pointers into hashes for db storage. */
|
||||||
|
|||||||
@@ -585,9 +585,12 @@ bool CCoinsViewCache::HaveJoinSplitRequirements(const CTransaction& tx) const
|
|||||||
for (const SpendDescription &spendDescription : tx.vShieldedSpend) {
|
for (const SpendDescription &spendDescription : tx.vShieldedSpend) {
|
||||||
if (GetNullifier(spendDescription.nullifier, SAPLING)) // Prevent double spends
|
if (GetNullifier(spendDescription.nullifier, SAPLING)) // Prevent double spends
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Sapling anchor checks
|
ZCSaplingIncrementalMerkleTree tree;
|
||||||
|
if (!GetSaplingAnchorAt(spendDescription.anchor, tree)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
51
src/main.cpp
51
src/main.cpp
@@ -2149,8 +2149,19 @@ bool DisconnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// set the old best anchor back
|
// set the old best Sprout anchor back
|
||||||
view.PopAnchor(blockUndo.old_tree_root, SPROUT);
|
view.PopAnchor(blockUndo.old_sprout_tree_root, SPROUT);
|
||||||
|
|
||||||
|
// set the old best Sapling anchor back
|
||||||
|
// We can get this from the `hashFinalSaplingRoot` of the last block
|
||||||
|
// However, this is only reliable if the last block was on or after
|
||||||
|
// the Sapling activation height. Otherwise, the last anchor was the
|
||||||
|
// empty root.
|
||||||
|
if (NetworkUpgradeActive(pindex->pprev->nHeight, Params().GetConsensus(), Consensus::UPGRADE_SAPLING)) {
|
||||||
|
view.PopAnchor(pindex->pprev->hashFinalSaplingRoot, SAPLING);
|
||||||
|
} else {
|
||||||
|
view.PopAnchor(ZCSaplingIncrementalMerkleTree::empty_root(), SAPLING);
|
||||||
|
}
|
||||||
|
|
||||||
// move best block pointer to prevout block
|
// move best block pointer to prevout block
|
||||||
view.SetBestBlock(pindex->pprev->GetBlockHash());
|
view.SetBestBlock(pindex->pprev->GetBlockHash());
|
||||||
@@ -2330,22 +2341,25 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
|
|||||||
|
|
||||||
// Construct the incremental merkle tree at the current
|
// Construct the incremental merkle tree at the current
|
||||||
// block position,
|
// block position,
|
||||||
auto old_tree_root = view.GetBestAnchor(SPROUT);
|
auto old_sprout_tree_root = view.GetBestAnchor(SPROUT);
|
||||||
// saving the top anchor in the block index as we go.
|
// saving the top anchor in the block index as we go.
|
||||||
if (!fJustCheck) {
|
if (!fJustCheck) {
|
||||||
pindex->hashSproutAnchor = old_tree_root;
|
pindex->hashSproutAnchor = old_sprout_tree_root;
|
||||||
}
|
}
|
||||||
ZCIncrementalMerkleTree tree;
|
ZCIncrementalMerkleTree sprout_tree;
|
||||||
// This should never fail: we should always be able to get the root
|
// This should never fail: we should always be able to get the root
|
||||||
// that is on the tip of our chain
|
// that is on the tip of our chain
|
||||||
assert(view.GetSproutAnchorAt(old_tree_root, tree));
|
assert(view.GetSproutAnchorAt(old_sprout_tree_root, sprout_tree));
|
||||||
|
|
||||||
{
|
{
|
||||||
// Consistency check: the root of the tree we're given should
|
// Consistency check: the root of the tree we're given should
|
||||||
// match what we asked for.
|
// match what we asked for.
|
||||||
assert(tree.root() == old_tree_root);
|
assert(sprout_tree.root() == old_sprout_tree_root);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ZCSaplingIncrementalMerkleTree sapling_tree;
|
||||||
|
assert(view.GetSaplingAnchorAt(view.GetBestAnchor(SAPLING), sapling_tree));
|
||||||
|
|
||||||
// Grab the consensus branch ID for the block's height
|
// Grab the consensus branch ID for the block's height
|
||||||
auto consensusBranchId = CurrentEpochBranchId(pindex->nHeight, Params().GetConsensus());
|
auto consensusBranchId = CurrentEpochBranchId(pindex->nHeight, Params().GetConsensus());
|
||||||
|
|
||||||
@@ -2403,19 +2417,34 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
|
|||||||
BOOST_FOREACH(const uint256 ¬e_commitment, joinsplit.commitments) {
|
BOOST_FOREACH(const uint256 ¬e_commitment, joinsplit.commitments) {
|
||||||
// Insert the note commitments into our temporary tree.
|
// Insert the note commitments into our temporary tree.
|
||||||
|
|
||||||
tree.append(note_commitment);
|
sprout_tree.append(note_commitment);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BOOST_FOREACH(const OutputDescription &outputDescription, tx.vShieldedOutput) {
|
||||||
|
sapling_tree.append(outputDescription.cm);
|
||||||
|
}
|
||||||
|
|
||||||
vPos.push_back(std::make_pair(tx.GetHash(), pos));
|
vPos.push_back(std::make_pair(tx.GetHash(), pos));
|
||||||
pos.nTxOffset += ::GetSerializeSize(tx, SER_DISK, CLIENT_VERSION);
|
pos.nTxOffset += ::GetSerializeSize(tx, SER_DISK, CLIENT_VERSION);
|
||||||
}
|
}
|
||||||
|
|
||||||
view.PushSproutAnchor(tree);
|
view.PushSproutAnchor(sprout_tree);
|
||||||
|
view.PushSaplingAnchor(sapling_tree);
|
||||||
if (!fJustCheck) {
|
if (!fJustCheck) {
|
||||||
pindex->hashFinalSproutRoot = tree.root();
|
pindex->hashFinalSproutRoot = sprout_tree.root();
|
||||||
|
}
|
||||||
|
blockundo.old_sprout_tree_root = old_sprout_tree_root;
|
||||||
|
|
||||||
|
// If Sapling is active, block.hashFinalSaplingRoot must be the
|
||||||
|
// same as the root of the Sapling tree
|
||||||
|
if (NetworkUpgradeActive(pindex->nHeight, chainparams.GetConsensus(), Consensus::UPGRADE_SAPLING)) {
|
||||||
|
if (block.hashFinalSaplingRoot != sapling_tree.root()) {
|
||||||
|
return state.DoS(100,
|
||||||
|
error("ConnectBlock(): block's hashFinalSaplingRoot is incorrect"),
|
||||||
|
REJECT_INVALID, "bad-sapling-root-in-block");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
blockundo.old_tree_root = old_tree_root;
|
|
||||||
|
|
||||||
int64_t nTime1 = GetTimeMicros(); nTimeConnect += nTime1 - nTimeStart;
|
int64_t nTime1 = GetTimeMicros(); nTimeConnect += nTime1 - nTimeStart;
|
||||||
LogPrint("bench", " - Connect %u transactions: %.2fms (%.3fms/tx, %.3fms/txin) [%.2fs]\n", (unsigned)block.vtx.size(), 0.001 * (nTime1 - nTimeStart), 0.001 * (nTime1 - nTimeStart) / block.vtx.size(), nInputs <= 1 ? 0 : 0.001 * (nTime1 - nTimeStart) / (nInputs-1), nTimeConnect * 0.000001);
|
LogPrint("bench", " - Connect %u transactions: %.2fms (%.3fms/tx, %.3fms/txin) [%.2fs]\n", (unsigned)block.vtx.size(), 0.001 * (nTime1 - nTimeStart), 0.001 * (nTime1 - nTimeStart) / block.vtx.size(), nInputs <= 1 ? 0 : 0.001 * (nTime1 - nTimeStart) / (nInputs-1), nTimeConnect * 0.000001);
|
||||||
|
|||||||
@@ -67,14 +67,14 @@ class CBlockUndo
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
std::vector<CTxUndo> vtxundo; // for all but the coinbase
|
std::vector<CTxUndo> vtxundo; // for all but the coinbase
|
||||||
uint256 old_tree_root;
|
uint256 old_sprout_tree_root;
|
||||||
|
|
||||||
ADD_SERIALIZE_METHODS;
|
ADD_SERIALIZE_METHODS;
|
||||||
|
|
||||||
template <typename Stream, typename Operation>
|
template <typename Stream, typename Operation>
|
||||||
inline void SerializationOp(Stream& s, Operation ser_action) {
|
inline void SerializationOp(Stream& s, Operation ser_action) {
|
||||||
READWRITE(vtxundo);
|
READWRITE(vtxundo);
|
||||||
READWRITE(old_tree_root);
|
READWRITE(old_sprout_tree_root);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user