Skip to content

Commit

Permalink
Auto merge of #4131 - zebambam:defer_expensive_intialization_of_empty…
Browse files Browse the repository at this point in the history
…_merkle_trees, r=<try>

Deferred initialization of EmptyMerklePath structures till first use …

…to reduce monolith startup penalty for fuzzing. These structures were previously filled statically at load time.

The performance cost of monolith startup even with an alternative main function is significant when you're loading it many times.

Notes on the approach to fuzzing (why do this patch?):

Yes there are other ways to write fuzzers, but their cost is also higher than necessary. This allows us to access any namespace we need within the monolith and know that at least the build requisites are available without having to do a lot of mocking, shimming, etc.. for each fuzzer.

Notes on the structure of the change:

Larry convinced me to use "LOCK" in the end, which meant bringing in another header. I've added optimization around the lock so that it's not needed every time.

I've added calls to initialize into the comparison operator as well as the accessor. I think that's all the places that are relevant.
  • Loading branch information
zkbot committed Sep 12, 2019
2 parents 0650772 + cf89467 commit 7523619
Showing 1 changed file with 15 additions and 5 deletions.
20 changes: 15 additions & 5 deletions src/zcash/IncrementalMerkleTree.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

#include "uint256.h"
#include "serialize.h"
#include "sync.h"

#include "Zcash.h"
#include "zcash/util.h"
Expand Down Expand Up @@ -57,25 +58,34 @@ class MerklePath {
template<size_t Depth, typename Hash>
class EmptyMerkleRoots {
public:
EmptyMerkleRoots() {
empty_roots.at(0) = Hash::uncommitted();
for (size_t d = 1; d <= Depth; d++) {
empty_roots.at(d) = Hash::combine(empty_roots.at(d-1), empty_roots.at(d-1), d-1);
void initialize() {
LOCK(cs);
if (!initialized) {
empty_roots.at(0) = Hash::uncommitted();
for (size_t d = 1; d <= Depth; d++) {
empty_roots.at(d) = Hash::combine(empty_roots.at(d-1), empty_roots.at(d-1), d-1);
}
initialized = true;
}
}
EmptyMerkleRoots() { initialized = false; }
Hash empty_root(size_t depth) {
initialize();
return empty_roots.at(depth);
}
template <size_t D, typename H>
friend bool operator==(const EmptyMerkleRoots<D, H>& a,
const EmptyMerkleRoots<D, H>& b);
private:
std::array<Hash, Depth+1> empty_roots;
CCriticalSection cs;
mutable bool initialized;
mutable std::array<Hash, Depth+1> empty_roots;
};

template<size_t Depth, typename Hash>
bool operator==(const EmptyMerkleRoots<Depth, Hash>& a,
const EmptyMerkleRoots<Depth, Hash>& b) {
a.initialize(); b.initialize();
return a.empty_roots == b.empty_roots;
}

Expand Down

0 comments on commit 7523619

Please sign in to comment.