Auto merge of #3170 - ebfull:sapling-merkle-tree, r=ebfull

Sapling merkle tree implementation

Closes #3056.

Please also review https://github.com/zcash/librustzcash/pull/8

This PR:

1. Introduces ZCSaplingIncrementalMerkleTree using Pedersen hashes.
2. Adds support for Sapling anchors into consensus rules. (Adds commitments, checks anchors are correct, handles block (dis)connects, etc.)
3. Handles mempool eviction for obsolete anchors.
4. Enforces correctness of block's Sapling root field
5. Changes miner to correctly apply the Sapling root to the block header
6. Handles mempool consistency checks for anchors
This commit is contained in:
Homu
2018-05-07 20:37:46 -07:00
37 changed files with 1166 additions and 309 deletions

View File

@@ -19,11 +19,15 @@ class FakeCoinsViewDB : public CCoinsView {
public:
FakeCoinsViewDB() {}
bool GetAnchorAt(const uint256 &rt, ZCIncrementalMerkleTree &tree) const {
bool GetSproutAnchorAt(const uint256 &rt, ZCIncrementalMerkleTree &tree) const {
return false;
}
bool GetNullifier(const uint256 &nf, NullifierType type) const {
bool GetSaplingAnchorAt(const uint256 &rt, ZCSaplingIncrementalMerkleTree &tree) const {
return false;
}
bool GetNullifier(const uint256 &nf, ShieldedType type) const {
return false;
}
@@ -47,15 +51,17 @@ public:
return a;
}
uint256 GetBestAnchor() const {
uint256 GetBestAnchor(ShieldedType type) const {
uint256 a;
return a;
}
bool BatchWrite(CCoinsMap &mapCoins,
const uint256 &hashBlock,
const uint256 &hashAnchor,
CAnchorsMap &mapAnchors,
const uint256 &hashSproutAnchor,
const uint256 &hashSaplingAnchor,
CAnchorsSproutMap &mapSproutAnchors,
CAnchorsSaplingMap &mapSaplingAnchors,
CNullifiersMap &mapSproutNullifiers,
CNullifiersMap &mapSaplingNullifiers) {
return false;

View File

@@ -7,6 +7,13 @@
#include "test/data/merkle_path.json.h"
#include "test/data/merkle_commitments.json.h"
#include "test/data/merkle_roots_sapling.json.h"
#include "test/data/merkle_roots_empty_sapling.json.h"
#include "test/data/merkle_serialization_sapling.json.h"
#include "test/data/merkle_witness_serialization_sapling.json.h"
#include "test/data/merkle_path_sapling.json.h"
#include "test/data/merkle_commitments_sapling.json.h"
#include <iostream>
#include <stdexcept>
@@ -51,7 +58,8 @@ void test_tree(
UniValue root_tests,
UniValue ser_tests,
UniValue witness_ser_tests,
UniValue path_tests
UniValue path_tests,
bool libsnark_test
)
{
size_t witness_ser_i = 0;
@@ -106,10 +114,9 @@ void test_tree(
ASSERT_THROW(wit.element(), std::runtime_error);
} else {
auto path = wit.path();
expect_test_vector(path_tests[path_i++], path);
{
expect_test_vector(path_tests[path_i++], path);
if (libsnark_test) {
typedef Fr<default_r1cs_ppzksnark_pp> FieldT;
protoboard<FieldT> pb;
@@ -188,7 +195,31 @@ TEST(merkletree, vectors) {
UniValue path_tests = read_json(MAKE_STRING(json_tests::merkle_path));
UniValue commitment_tests = read_json(MAKE_STRING(json_tests::merkle_commitments));
test_tree<ZCTestingIncrementalMerkleTree, ZCTestingIncrementalWitness>(commitment_tests, root_tests, ser_tests, witness_ser_tests, path_tests);
test_tree<ZCTestingIncrementalMerkleTree, ZCTestingIncrementalWitness>(
commitment_tests,
root_tests,
ser_tests,
witness_ser_tests,
path_tests,
true
);
}
TEST(merkletree, SaplingVectors) {
UniValue root_tests = read_json(MAKE_STRING(json_tests::merkle_roots_sapling));
UniValue ser_tests = read_json(MAKE_STRING(json_tests::merkle_serialization_sapling));
UniValue witness_ser_tests = read_json(MAKE_STRING(json_tests::merkle_witness_serialization_sapling));
UniValue path_tests = read_json(MAKE_STRING(json_tests::merkle_path_sapling));
UniValue commitment_tests = read_json(MAKE_STRING(json_tests::merkle_commitments_sapling));
test_tree<ZCSaplingTestingIncrementalMerkleTree, ZCSaplingTestingIncrementalWitness>(
commitment_tests,
root_tests,
ser_tests,
witness_ser_tests,
path_tests,
false
);
}
TEST(merkletree, emptyroots) {
@@ -204,6 +235,19 @@ TEST(merkletree, emptyroots) {
ASSERT_TRUE(INCREMENTAL_MERKLE_TREE_DEPTH <= 64);
}
TEST(merkletree, EmptyrootsSapling) {
UniValue empty_roots = read_json(MAKE_STRING(json_tests::merkle_roots_empty_sapling));
libzcash::EmptyMerkleRoots<62, libzcash::PedersenHash> emptyroots;
for (size_t depth = 0; depth <= 62; depth++) {
expect_test_vector(empty_roots[depth], emptyroots.empty_root(depth));
}
// Double check that we're testing (at least) all the empty roots we'll use.
ASSERT_TRUE(INCREMENTAL_MERKLE_TREE_DEPTH <= 62);
}
TEST(merkletree, emptyroot) {
// This literal is the depth-20 empty tree root with the bytes reversed to
// account for the fact that uint256S() loads a big-endian representation of
@@ -213,6 +257,15 @@ TEST(merkletree, emptyroot) {
ASSERT_TRUE(ZCIncrementalMerkleTree::empty_root() == expected);
}
TEST(merkletree, EmptyrootSapling) {
// This literal is the depth-20 empty tree root with the bytes reversed to
// account for the fact that uint256S() loads a big-endian representation of
// an integer which converted to little-endian internally.
uint256 expected = uint256S("427719cde12e9ef88a2811be36a0ef15018c7674dc8faa76ace727fdbc09af6a");
ASSERT_TRUE(ZCSaplingIncrementalMerkleTree::empty_root() == expected);
}
TEST(merkletree, deserializeInvalid) {
// attempt to deserialize a small tree from a serialized large tree
// (exceeds depth well-formedness check)

View File

@@ -3,13 +3,13 @@
#include "uint256.h"
TEST(PedersenHash, TestAPI) {
const uint256 a = uint256S("0acaa62d40fcdd9192ed35ea9df31660ccf7f6c60566530faaa444fb5d0d410e");
const uint256 b = uint256S("6041357de59ba64959d1b60f93de24dfe5ea1e26ed9e8a73d35b225a1845ba70");
const uint256 a = uint256S("7082b0badf222555f0ca66a0636fef330668cfb957acb74989bb3f02b4655350");
const uint256 b = uint256S("0e5da2185a44dacbce5179b7647857a7fb247bc9f06d8b9a9265d9a7beac8206");
uint256 result;
librustzcash_merkle_hash(25, a.begin(), b.begin(), result.begin());
uint256 expected_result = uint256S("4253b36834b3f64cc6182f1816911e1c9460cb88afeafb155244dd0038ad4717");
uint256 expected_result = uint256S("e8e2b51c00bb224aa8df57f511d306293878896818f41863326fcd2c16cdca42");
ASSERT_TRUE(result == expected_result);
}

View File

@@ -21,11 +21,15 @@ class FakeCoinsViewDB : public CCoinsView {
public:
FakeCoinsViewDB() {}
bool GetAnchorAt(const uint256 &rt, ZCIncrementalMerkleTree &tree) const {
bool GetSproutAnchorAt(const uint256 &rt, ZCIncrementalMerkleTree &tree) const {
return false;
}
bool GetNullifier(const uint256 &nf, NullifierType type) const {
bool GetSaplingAnchorAt(const uint256 &rt, ZCSaplingIncrementalMerkleTree &tree) const {
return false;
}
bool GetNullifier(const uint256 &nf, ShieldedType type) const {
return false;
}
@@ -42,15 +46,17 @@ public:
return a;
}
uint256 GetBestAnchor() const {
uint256 GetBestAnchor(ShieldedType type) const {
uint256 a;
return a;
}
bool BatchWrite(CCoinsMap &mapCoins,
const uint256 &hashBlock,
const uint256 &hashAnchor,
CAnchorsMap &mapAnchors,
const uint256 &hashSproutAnchor,
const uint256 &hashSaplingAnchor,
CAnchorsSproutMap &mapSproutAnchors,
CAnchorsSaplingMap &mapSaplingAnchors,
CNullifiersMap &mapSproutNullifiers,
CNullifiersMap saplingNullifiersMap) {
return false;