提交 4eccfc4b 编写于 作者: B Bart Wyatt

start some testing for proofs we want to do, modify merkle tree to make proofs...

start some testing for proofs we want to do, modify merkle tree to make proofs more concise.  fix bugs
上级 5545c5df
......@@ -91,7 +91,7 @@ namespace eosio { namespace chain {
void region_trace::calculate_root() {
vector<digest_type> cycle_roots;
cycle_roots.reserve(cycle_traces.size());
for (uint32_t index; index < cycle_traces.size(); index++) {
for (uint32_t index = 0; index < cycle_traces.size(); index++) {
const auto& c_trace = cycle_traces.at(index);
digest_type::encoder enc;
......@@ -105,7 +105,7 @@ namespace eosio { namespace chain {
digest_type block_trace::calculate_action_merkle_root()const {
vector<digest_type> region_roots;
region_roots.reserve(region_traces.size());
for (uint32_t index; index < region_roots.size(); index++) {
for (uint32_t index = 0; index < region_roots.size(); index++) {
const auto& r_trace = region_traces.at(index);
digest_type::encoder enc;
......
#pragma once
#include <eosio/chain/types.hpp>
#include <eosio/chain/merkle.hpp>
#include <fc/io/raw.hpp>
namespace eosio { namespace chain {
......@@ -182,7 +183,7 @@ class incremental_merkle_impl {
// calculate the partially realized node value by implying the "right" value is identical
// to the "left" value
top = DigestType::hash(std::make_pair(top, top));
top = DigestType::hash(make_canonical_pair(top, top));
partial = true;
} else {
// we are collapsing from a "right" value and an fully-realized "left"
......@@ -198,7 +199,7 @@ class incremental_merkle_impl {
}
// calculate the node
top = DigestType::hash(std::make_pair(left_value, top));
top = DigestType::hash(make_canonical_pair(left_value, top));
}
// move up a level in the tree
......
......@@ -3,6 +3,13 @@
namespace eosio { namespace chain {
digest_type make_canonical_left(const digest_type& val);
digest_type make_canonical_right(const digest_type& val);
inline auto make_canonical_pair(const digest_type& l, const digest_type& r) {
return make_pair(make_canonical_left(l), make_canonical_right(r));
};
/**
* Calculates the merkle root of a set of digests, if ids is odd it will duplicate the last id.
*/
......
......@@ -3,6 +3,26 @@
namespace eosio { namespace chain {
/**
* in order to keep proofs concise, before hashing we set the first bit
* of the previous hashes to 0 or 1 to indicate the side it is on
*
* this relieves our proofs from having to indicate left vs right contactenation
* as the node values will imply it
*/
digest_type make_canonical_left(const digest_type& val) {
digest_type canonical_l = val;
canonical_l._hash[0] &= 0xFFFFFFFFFFFFFF7FULL;
return canonical_l;
}
digest_type make_canonical_right(const digest_type& val) {
digest_type canonical_r = val;
canonical_r._hash[0] |= 0x0000000000000080ULL;
return canonical_r;
}
digest_type merkle(vector<digest_type> ids) {
if( 0 == ids.size() ) { return digest_type(); }
......@@ -10,8 +30,9 @@ digest_type merkle(vector<digest_type> ids) {
if( ids.size() % 2 )
ids.push_back(ids.back());
for (int i = 0; i < ids.size() / 2; i++)
ids[i] = digest_type::hash( make_pair(ids[2*i], ids[(2*i)+1]) );
for (int i = 0; i < ids.size() / 2; i++) {
ids[i] = digest_type::hash(make_canonical_pair(ids[2 * i], ids[(2 * i) + 1]));
}
ids.resize(ids.size() / 2);
}
......
#include <boost/test/unit_test.hpp>
#include <eosio/testing/tester.hpp>
#include <eosio/chain/merkle.hpp>
using namespace eosio;
using namespace eosio::chain;
using namespace eosio::testing;
struct merkle_node {
digest_type digest;
optional<size_t> left;
optional<size_t> right;
optional<size_t> parent;
};
BOOST_AUTO_TEST_SUITE(proof_tests)
BOOST_FIXTURE_TEST_CASE( prove_block_in_chain, tester ) { try {
vector<block_id_type> known_blocks;
known_blocks.reserve(100);
block_header last_block_header;
// register a callback on new blocks to record block information
control->applied_block.connect([&](const block_trace& bt){
known_blocks.emplace_back(bt.block.id());
last_block_header = bt.block;
});
produce_blocks(100);
vector<merkle_node> nodes;
vector<digest_type> ids;
nodes.reserve(100);
ids.reserve(100);
for (const auto& blk_id: known_blocks) {
nodes.emplace_back(merkle_node{blk_id});
ids.push_back(blk_id);
}
size_t num_nodes = 100;
size_t base = 0;
while (num_nodes > 1) {
size_t new_nodes = (num_nodes / 2) + (num_nodes % 2);
for(size_t idx = 0; idx < new_nodes; idx++) {
size_t l_idx = idx * 2;
size_t r_idx = l_idx + 1;
size_t left = base + l_idx;
if (r_idx >= num_nodes) {
nodes.emplace_back(
merkle_node{
digest_type::hash(make_canonical_pair(nodes[left].digest, nodes[left].digest)),
left
});
nodes[left].parent.emplace(nodes.size() - 1);
} else {
size_t right = base + r_idx;
nodes.emplace_back(
merkle_node{
digest_type::hash(make_canonical_pair(nodes[left].digest, nodes[right].digest)),
left,
right
});
nodes[left].parent.emplace(nodes.size() - 1);
nodes[right].parent.emplace(nodes.size() - 1);
}
}
base += num_nodes;
num_nodes = new_nodes;
}
BOOST_REQUIRE_EQUAL((std::string)nodes.back().digest, (std::string)merkle(ids));
produce_block();
BOOST_REQUIRE_EQUAL((std::string)nodes.back().digest, (std::string)last_block_header.block_mroot);
for (int idx = 0; idx < 100; idx++) {
size_t leaf = idx;
digest_type current = ids.at(idx);
vector<digest_type> path;
while (nodes[leaf].parent.valid()) {
size_t parent = *nodes[leaf].parent;
if (leaf == *nodes[parent].left) {
if (nodes[parent].right.valid()) {
size_t right = *nodes[parent].right;
path.emplace_back(make_canonical_right(nodes[right].digest));
current = digest_type::hash(make_canonical_pair(nodes[leaf].digest, nodes[right].digest));
} else {
path.emplace_back(make_canonical_right(nodes[leaf].digest));
current = digest_type::hash(make_canonical_pair(nodes[leaf].digest, nodes[leaf].digest));
}
} else {
size_t left = *nodes[parent].left;
path.emplace_back(make_canonical_left(nodes[left].digest));
current = digest_type::hash(make_canonical_pair(nodes[left].digest, nodes[leaf].digest));
}
leaf = parent;
}
BOOST_REQUIRE_EQUAL(std::string(current), std::string(last_block_header.block_mroot));
/** UNCOMMENT TO PRODUCE PROOFS TO STD OUT
std::cout << idx << ":" << std::string(known_blocks.at(idx)) << " = ";
for (const auto& e: path) {
std::cout << std::string(e) << " ";
}
std::cout << "-> " << std::string(last_block_header.block_mroot) << std::endl;
*/
}
} FC_LOG_AND_RETHROW() } /// transfer_test
/**
* This test case will attempt to allow one account to transfer on behalf
* of another account by updating the active authority.
*/
BOOST_AUTO_TEST_CASE( prove_action_in_block ) { try {
} FC_LOG_AND_RETHROW() }
BOOST_AUTO_TEST_SUITE_END()
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册