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
commit 333b9a0d0b
37 changed files with 1166 additions and 309 deletions

View File

@ -3,8 +3,8 @@ $(package)_crate_name=sapling-crypto
$(package)_download_path=https://github.com/zcash-hackworks/$($(package)_crate_name)/archive/
$(package)_file_name=$(package)-$($(package)_git_commit).tar.gz
$(package)_download_file=$($(package)_git_commit).tar.gz
$(package)_sha256_hash=5eb4040bc223a689341b3f1a1fc53d6064c4c032b23ae0c2c653b063e1da24db
$(package)_git_commit=e554b473dd10885d232f42237c13282f5b6fee43
$(package)_sha256_hash=5062b9e752066ad959f14063d496b0a156ce96004a13a6823494249793c01f96
$(package)_git_commit=7beeb52730e24724ee10ea2458ecf7776cb59c58
$(package)_crate_versioned_name=$($(package)_crate_name)
define $(package)_preprocess_cmds

View File

@ -3,8 +3,8 @@ $(package)_version=0.1
$(package)_download_path=https://github.com/zcash/$(package)/archive/
$(package)_file_name=$(package)-$($(package)_git_commit).tar.gz
$(package)_download_file=$($(package)_git_commit).tar.gz
$(package)_sha256_hash=b63ba98d569d332764f27706038c04d03ac7e2c836dc15dc4eaa24b04b8c7f4a
$(package)_git_commit=6cc1813ae3bb1e42224fd8ca0a8977b95c576738
$(package)_sha256_hash=c5442a57d8961aab12fd395a5004edbb96b973511fab3949a087faa2a865a002
$(package)_git_commit=ef676eff5084d394e6c6eaf2b9d9817effe662a7
$(package)_dependencies=rust $(rust_crates)
$(package)_patches=cargo.config

View File

@ -8,7 +8,7 @@ replace-with = "vendored-sources"
[source."https://github.com/zcash-hackworks/sapling-crypto"]
git = "https://github.com/zcash-hackworks/sapling-crypto"
rev = "e554b473dd10885d232f42237c13282f5b6fee43"
rev = "7beeb52730e24724ee10ea2458ecf7776cb59c58"
replace-with = "vendored-sources"
[source.vendored-sources]

View File

@ -32,6 +32,12 @@ JSON_TEST_FILES = \
test/data/merkle_witness_serialization.json \
test/data/merkle_path.json \
test/data/merkle_commitments.json \
test/data/merkle_roots_sapling.json \
test/data/merkle_roots_empty_sapling.json \
test/data/merkle_serialization_sapling.json \
test/data/merkle_witness_serialization_sapling.json \
test/data/merkle_path_sapling.json \
test/data/merkle_commitments_sapling.json \
test/data/g1_compressed.json \
test/data/g2_compressed.json

View File

@ -152,10 +152,10 @@ public:
boost::optional<uint32_t> nCachedBranchId;
//! The anchor for the tree state up to the start of this block
uint256 hashAnchor;
uint256 hashSproutAnchor;
//! (memory only) The anchor for the tree state up to the end of this block
uint256 hashAnchorEnd;
uint256 hashFinalSproutRoot;
//! Change in value held by the Sprout circuit over this block.
//! Will be boost::none for older blocks on old nodes until a reindex has taken place.
@ -169,7 +169,7 @@ public:
//! block header
int nVersion;
uint256 hashMerkleRoot;
uint256 hashReserved;
uint256 hashFinalSaplingRoot;
unsigned int nTime;
unsigned int nBits;
uint256 nNonce;
@ -192,15 +192,15 @@ public:
nChainTx = 0;
nStatus = 0;
nCachedBranchId = boost::none;
hashAnchor = uint256();
hashAnchorEnd = uint256();
hashSproutAnchor = uint256();
hashFinalSproutRoot = uint256();
nSequenceId = 0;
nSproutValue = boost::none;
nChainSproutValue = boost::none;
nVersion = 0;
hashMerkleRoot = uint256();
hashReserved = uint256();
hashFinalSaplingRoot = uint256();
nTime = 0;
nBits = 0;
nNonce = uint256();
@ -218,7 +218,7 @@ public:
nVersion = block.nVersion;
hashMerkleRoot = block.hashMerkleRoot;
hashReserved = block.hashReserved;
hashFinalSaplingRoot = block.hashFinalSaplingRoot;
nTime = block.nTime;
nBits = block.nBits;
nNonce = block.nNonce;
@ -250,7 +250,7 @@ public:
if (pprev)
block.hashPrevBlock = pprev->GetBlockHash();
block.hashMerkleRoot = hashMerkleRoot;
block.hashReserved = hashReserved;
block.hashFinalSaplingRoot = hashFinalSaplingRoot;
block.nTime = nTime;
block.nBits = nBits;
block.nNonce = nNonce;
@ -366,13 +366,13 @@ public:
READWRITE(branchId);
}
}
READWRITE(hashAnchor);
READWRITE(hashSproutAnchor);
// block header
READWRITE(this->nVersion);
READWRITE(hashPrev);
READWRITE(hashMerkleRoot);
READWRITE(hashReserved);
READWRITE(hashFinalSaplingRoot);
READWRITE(nTime);
READWRITE(nBits);
READWRITE(nNonce);
@ -391,7 +391,7 @@ public:
block.nVersion = nVersion;
block.hashPrevBlock = hashPrev;
block.hashMerkleRoot = hashMerkleRoot;
block.hashReserved = hashReserved;
block.hashFinalSaplingRoot = hashFinalSaplingRoot;
block.nTime = nTime;
block.nBits = nBits;
block.nNonce = nNonce;

View File

@ -42,16 +42,19 @@ bool CCoins::Spend(uint32_t nPos)
Cleanup();
return true;
}
bool CCoinsView::GetAnchorAt(const uint256 &rt, ZCIncrementalMerkleTree &tree) const { return false; }
bool CCoinsView::GetNullifier(const uint256 &nullifier, NullifierType type) const { return false; }
bool CCoinsView::GetSproutAnchorAt(const uint256 &rt, ZCIncrementalMerkleTree &tree) const { return false; }
bool CCoinsView::GetSaplingAnchorAt(const uint256 &rt, ZCSaplingIncrementalMerkleTree &tree) const { return false; }
bool CCoinsView::GetNullifier(const uint256 &nullifier, ShieldedType type) const { return false; }
bool CCoinsView::GetCoins(const uint256 &txid, CCoins &coins) const { return false; }
bool CCoinsView::HaveCoins(const uint256 &txid) const { return false; }
uint256 CCoinsView::GetBestBlock() const { return uint256(); }
uint256 CCoinsView::GetBestAnchor() const { return uint256(); };
uint256 CCoinsView::GetBestAnchor(ShieldedType type) const { return uint256(); };
bool CCoinsView::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; }
bool CCoinsView::GetStats(CCoinsStats &stats) const { return false; }
@ -59,19 +62,22 @@ bool CCoinsView::GetStats(CCoinsStats &stats) const { return false; }
CCoinsViewBacked::CCoinsViewBacked(CCoinsView *viewIn) : base(viewIn) { }
bool CCoinsViewBacked::GetAnchorAt(const uint256 &rt, ZCIncrementalMerkleTree &tree) const { return base->GetAnchorAt(rt, tree); }
bool CCoinsViewBacked::GetNullifier(const uint256 &nullifier, NullifierType type) const { return base->GetNullifier(nullifier, type); }
bool CCoinsViewBacked::GetSproutAnchorAt(const uint256 &rt, ZCIncrementalMerkleTree &tree) const { return base->GetSproutAnchorAt(rt, tree); }
bool CCoinsViewBacked::GetSaplingAnchorAt(const uint256 &rt, ZCSaplingIncrementalMerkleTree &tree) const { return base->GetSaplingAnchorAt(rt, tree); }
bool CCoinsViewBacked::GetNullifier(const uint256 &nullifier, ShieldedType type) const { return base->GetNullifier(nullifier, type); }
bool CCoinsViewBacked::GetCoins(const uint256 &txid, CCoins &coins) const { return base->GetCoins(txid, coins); }
bool CCoinsViewBacked::HaveCoins(const uint256 &txid) const { return base->HaveCoins(txid); }
uint256 CCoinsViewBacked::GetBestBlock() const { return base->GetBestBlock(); }
uint256 CCoinsViewBacked::GetBestAnchor() const { return base->GetBestAnchor(); }
uint256 CCoinsViewBacked::GetBestAnchor(ShieldedType type) const { return base->GetBestAnchor(type); }
void CCoinsViewBacked::SetBackend(CCoinsView &viewIn) { base = &viewIn; }
bool CCoinsViewBacked::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 base->BatchWrite(mapCoins, hashBlock, hashAnchor, mapAnchors, mapSproutNullifiers, mapSaplingNullifiers); }
CNullifiersMap &mapSaplingNullifiers) { return base->BatchWrite(mapCoins, hashBlock, hashSproutAnchor, hashSaplingAnchor, mapSproutAnchors, mapSaplingAnchors, mapSproutNullifiers, mapSaplingNullifiers); }
bool CCoinsViewBacked::GetStats(CCoinsStats &stats) const { return base->GetStats(stats); }
CCoinsKeyHasher::CCoinsKeyHasher() : salt(GetRandHash()) {}
@ -85,7 +91,8 @@ CCoinsViewCache::~CCoinsViewCache()
size_t CCoinsViewCache::DynamicMemoryUsage() const {
return memusage::DynamicUsage(cacheCoins) +
memusage::DynamicUsage(cacheAnchors) +
memusage::DynamicUsage(cacheSproutAnchors) +
memusage::DynamicUsage(cacheSaplingAnchors) +
memusage::DynamicUsage(cacheSproutNullifiers) +
memusage::DynamicUsage(cacheSaplingNullifiers) +
cachedCoinsUsage;
@ -110,9 +117,9 @@ CCoinsMap::const_iterator CCoinsViewCache::FetchCoins(const uint256 &txid) const
}
bool CCoinsViewCache::GetAnchorAt(const uint256 &rt, ZCIncrementalMerkleTree &tree) const {
CAnchorsMap::const_iterator it = cacheAnchors.find(rt);
if (it != cacheAnchors.end()) {
bool CCoinsViewCache::GetSproutAnchorAt(const uint256 &rt, ZCIncrementalMerkleTree &tree) const {
CAnchorsSproutMap::const_iterator it = cacheSproutAnchors.find(rt);
if (it != cacheSproutAnchors.end()) {
if (it->second.entered) {
tree = it->second.tree;
return true;
@ -121,11 +128,11 @@ bool CCoinsViewCache::GetAnchorAt(const uint256 &rt, ZCIncrementalMerkleTree &tr
}
}
if (!base->GetAnchorAt(rt, tree)) {
if (!base->GetSproutAnchorAt(rt, tree)) {
return false;
}
CAnchorsMap::iterator ret = cacheAnchors.insert(std::make_pair(rt, CAnchorsCacheEntry())).first;
CAnchorsSproutMap::iterator ret = cacheSproutAnchors.insert(std::make_pair(rt, CAnchorsSproutCacheEntry())).first;
ret->second.entered = true;
ret->second.tree = tree;
cachedCoinsUsage += ret->second.tree.DynamicMemoryUsage();
@ -133,17 +140,40 @@ bool CCoinsViewCache::GetAnchorAt(const uint256 &rt, ZCIncrementalMerkleTree &tr
return true;
}
bool CCoinsViewCache::GetNullifier(const uint256 &nullifier, NullifierType type) const {
bool CCoinsViewCache::GetSaplingAnchorAt(const uint256 &rt, ZCSaplingIncrementalMerkleTree &tree) const {
CAnchorsSaplingMap::const_iterator it = cacheSaplingAnchors.find(rt);
if (it != cacheSaplingAnchors.end()) {
if (it->second.entered) {
tree = it->second.tree;
return true;
} else {
return false;
}
}
if (!base->GetSaplingAnchorAt(rt, tree)) {
return false;
}
CAnchorsSaplingMap::iterator ret = cacheSaplingAnchors.insert(std::make_pair(rt, CAnchorsSaplingCacheEntry())).first;
ret->second.entered = true;
ret->second.tree = tree;
cachedCoinsUsage += ret->second.tree.DynamicMemoryUsage();
return true;
}
bool CCoinsViewCache::GetNullifier(const uint256 &nullifier, ShieldedType type) const {
CNullifiersMap* cacheToUse;
switch (type) {
case SPROUT_NULLIFIER:
case SPROUT:
cacheToUse = &cacheSproutNullifiers;
break;
case SAPLING_NULLIFIER:
case SAPLING:
cacheToUse = &cacheSaplingNullifiers;
break;
default:
throw std::runtime_error("Unknown nullifier type");
throw std::runtime_error("Unknown shielded type");
}
CNullifiersMap::iterator it = cacheToUse->find(nullifier);
if (it != cacheToUse->end())
@ -158,10 +188,17 @@ bool CCoinsViewCache::GetNullifier(const uint256 &nullifier, NullifierType type)
return tmp;
}
void CCoinsViewCache::PushAnchor(const ZCIncrementalMerkleTree &tree) {
template<typename Tree, typename Cache, typename CacheIterator, typename CacheEntry>
void CCoinsViewCache::AbstractPushAnchor(
const Tree &tree,
ShieldedType type,
Cache &cacheAnchors,
uint256 &hash
)
{
uint256 newrt = tree.root();
auto currentRoot = GetBestAnchor();
auto currentRoot = GetBestAnchor(type);
// We don't want to overwrite an anchor we already have.
// This occurs when a block doesn't modify mapAnchors at all,
@ -169,24 +206,67 @@ void CCoinsViewCache::PushAnchor(const ZCIncrementalMerkleTree &tree) {
// different way (make all blocks modify mapAnchors somehow)
// but this is simpler to reason about.
if (currentRoot != newrt) {
auto insertRet = cacheAnchors.insert(std::make_pair(newrt, CAnchorsCacheEntry()));
CAnchorsMap::iterator ret = insertRet.first;
auto insertRet = cacheAnchors.insert(std::make_pair(newrt, CacheEntry()));
CacheIterator ret = insertRet.first;
ret->second.entered = true;
ret->second.tree = tree;
ret->second.flags = CAnchorsCacheEntry::DIRTY;
ret->second.flags = CacheEntry::DIRTY;
if (insertRet.second) {
// An insert took place
cachedCoinsUsage += ret->second.tree.DynamicMemoryUsage();
}
hashAnchor = newrt;
hash = newrt;
}
}
void CCoinsViewCache::PopAnchor(const uint256 &newrt) {
auto currentRoot = GetBestAnchor();
void CCoinsViewCache::PushSproutAnchor(const ZCIncrementalMerkleTree &tree) {
AbstractPushAnchor<ZCIncrementalMerkleTree, CAnchorsSproutMap, CAnchorsSproutMap::iterator, CAnchorsSproutCacheEntry>(
tree,
SPROUT,
cacheSproutAnchors,
hashSproutAnchor
);
}
void CCoinsViewCache::PushSaplingAnchor(const ZCSaplingIncrementalMerkleTree &tree) {
AbstractPushAnchor<ZCSaplingIncrementalMerkleTree, CAnchorsSaplingMap, CAnchorsSaplingMap::iterator, CAnchorsSaplingCacheEntry>(
tree,
SAPLING,
cacheSaplingAnchors,
hashSaplingAnchor
);
}
template<>
void CCoinsViewCache::BringBestAnchorIntoCache(
const uint256 &currentRoot,
ZCIncrementalMerkleTree &tree
)
{
assert(GetSproutAnchorAt(currentRoot, tree));
}
template<>
void CCoinsViewCache::BringBestAnchorIntoCache(
const uint256 &currentRoot,
ZCSaplingIncrementalMerkleTree &tree
)
{
assert(GetSaplingAnchorAt(currentRoot, tree));
}
template<typename Tree, typename Cache, typename CacheEntry>
void CCoinsViewCache::AbstractPopAnchor(
const uint256 &newrt,
ShieldedType type,
Cache &cacheAnchors,
uint256 &hash
)
{
auto currentRoot = GetBestAnchor(type);
// Blocks might not change the commitment tree, in which
// case restoring the "old" anchor during a reorg must
@ -195,18 +275,41 @@ void CCoinsViewCache::PopAnchor(const uint256 &newrt) {
// Bring the current best anchor into our local cache
// so that its tree exists in memory.
{
ZCIncrementalMerkleTree tree;
assert(GetAnchorAt(currentRoot, tree));
Tree tree;
BringBestAnchorIntoCache(currentRoot, tree);
}
// Mark the anchor as unentered, removing it from view
cacheAnchors[currentRoot].entered = false;
// Mark the cache entry as dirty so it's propagated
cacheAnchors[currentRoot].flags = CAnchorsCacheEntry::DIRTY;
cacheAnchors[currentRoot].flags = CacheEntry::DIRTY;
// Mark the new root as the best anchor
hashAnchor = newrt;
hash = newrt;
}
}
void CCoinsViewCache::PopAnchor(const uint256 &newrt, ShieldedType type) {
switch (type) {
case SPROUT:
AbstractPopAnchor<ZCIncrementalMerkleTree, CAnchorsSproutMap, CAnchorsSproutCacheEntry>(
newrt,
SPROUT,
cacheSproutAnchors,
hashSproutAnchor
);
break;
case SAPLING:
AbstractPopAnchor<ZCSaplingIncrementalMerkleTree, CAnchorsSaplingMap, CAnchorsSaplingCacheEntry>(
newrt,
SAPLING,
cacheSaplingAnchors,
hashSaplingAnchor
);
break;
default:
throw std::runtime_error("Unknown shielded type");
}
}
@ -280,10 +383,21 @@ uint256 CCoinsViewCache::GetBestBlock() const {
}
uint256 CCoinsViewCache::GetBestAnchor() const {
if (hashAnchor.IsNull())
hashAnchor = base->GetBestAnchor();
return hashAnchor;
uint256 CCoinsViewCache::GetBestAnchor(ShieldedType type) const {
switch (type) {
case SPROUT:
if (hashSproutAnchor.IsNull())
hashSproutAnchor = base->GetBestAnchor(type);
return hashSproutAnchor;
break;
case SAPLING:
if (hashSaplingAnchor.IsNull())
hashSaplingAnchor = base->GetBestAnchor(type);
return hashSaplingAnchor;
break;
default:
throw std::runtime_error("Unknown shielded type");
}
}
void CCoinsViewCache::SetBestBlock(const uint256 &hashBlockIn) {
@ -312,10 +426,45 @@ void BatchWriteNullifiers(CNullifiersMap &mapNullifiers, CNullifiersMap &cacheNu
}
}
template<typename Map, typename MapIterator, typename MapEntry>
void BatchWriteAnchors(
Map &mapAnchors,
Map &cacheAnchors,
size_t &cachedCoinsUsage
)
{
for (MapIterator child_it = mapAnchors.begin(); child_it != mapAnchors.end();)
{
if (child_it->second.flags & MapEntry::DIRTY) {
MapIterator parent_it = cacheAnchors.find(child_it->first);
if (parent_it == cacheAnchors.end()) {
MapEntry& entry = cacheAnchors[child_it->first];
entry.entered = child_it->second.entered;
entry.tree = child_it->second.tree;
entry.flags = MapEntry::DIRTY;
cachedCoinsUsage += entry.tree.DynamicMemoryUsage();
} else {
if (parent_it->second.entered != child_it->second.entered) {
// The parent may have removed the entry.
parent_it->second.entered = child_it->second.entered;
parent_it->second.flags |= MapEntry::DIRTY;
}
}
}
MapIterator itOld = child_it++;
mapAnchors.erase(itOld);
}
}
bool CCoinsViewCache::BatchWrite(CCoinsMap &mapCoins,
const uint256 &hashBlockIn,
const uint256 &hashAnchorIn,
CAnchorsMap &mapAnchors,
const uint256 &hashSproutAnchorIn,
const uint256 &hashSaplingAnchorIn,
CAnchorsSproutMap &mapSproutAnchors,
CAnchorsSaplingMap &mapSaplingAnchors,
CNullifiersMap &mapSproutNullifiers,
CNullifiersMap &mapSaplingNullifiers) {
assert(!hasModifier);
@ -354,43 +503,23 @@ bool CCoinsViewCache::BatchWrite(CCoinsMap &mapCoins,
mapCoins.erase(itOld);
}
for (CAnchorsMap::iterator child_it = mapAnchors.begin(); child_it != mapAnchors.end();)
{
if (child_it->second.flags & CAnchorsCacheEntry::DIRTY) {
CAnchorsMap::iterator parent_it = cacheAnchors.find(child_it->first);
if (parent_it == cacheAnchors.end()) {
CAnchorsCacheEntry& entry = cacheAnchors[child_it->first];
entry.entered = child_it->second.entered;
entry.tree = child_it->second.tree;
entry.flags = CAnchorsCacheEntry::DIRTY;
cachedCoinsUsage += entry.tree.DynamicMemoryUsage();
} else {
if (parent_it->second.entered != child_it->second.entered) {
// The parent may have removed the entry.
parent_it->second.entered = child_it->second.entered;
parent_it->second.flags |= CAnchorsCacheEntry::DIRTY;
}
}
}
CAnchorsMap::iterator itOld = child_it++;
mapAnchors.erase(itOld);
}
::BatchWriteAnchors<CAnchorsSproutMap, CAnchorsSproutMap::iterator, CAnchorsSproutCacheEntry>(mapSproutAnchors, cacheSproutAnchors, cachedCoinsUsage);
::BatchWriteAnchors<CAnchorsSaplingMap, CAnchorsSaplingMap::iterator, CAnchorsSaplingCacheEntry>(mapSaplingAnchors, cacheSaplingAnchors, cachedCoinsUsage);
::BatchWriteNullifiers(mapSproutNullifiers, cacheSproutNullifiers);
::BatchWriteNullifiers(mapSaplingNullifiers, cacheSaplingNullifiers);
hashAnchor = hashAnchorIn;
hashSproutAnchor = hashSproutAnchorIn;
hashSaplingAnchor = hashSaplingAnchorIn;
hashBlock = hashBlockIn;
return true;
}
bool CCoinsViewCache::Flush() {
bool fOk = base->BatchWrite(cacheCoins, hashBlock, hashAnchor, cacheAnchors, cacheSproutNullifiers, cacheSaplingNullifiers);
bool fOk = base->BatchWrite(cacheCoins, hashBlock, hashSproutAnchor, hashSaplingAnchor, cacheSproutAnchors, cacheSaplingAnchors, cacheSproutNullifiers, cacheSaplingNullifiers);
cacheCoins.clear();
cacheAnchors.clear();
cacheSproutAnchors.clear();
cacheSaplingAnchors.clear();
cacheSproutNullifiers.clear();
cacheSaplingNullifiers.clear();
cachedCoinsUsage = 0;
@ -430,7 +559,7 @@ bool CCoinsViewCache::HaveJoinSplitRequirements(const CTransaction& tx) const
{
BOOST_FOREACH(const uint256& nullifier, joinsplit.nullifiers)
{
if (GetNullifier(nullifier, SPROUT_NULLIFIER)) {
if (GetNullifier(nullifier, SPROUT)) {
// If the nullifier is set, this transaction
// double-spends!
return false;
@ -441,7 +570,7 @@ bool CCoinsViewCache::HaveJoinSplitRequirements(const CTransaction& tx) const
auto it = intermediates.find(joinsplit.anchor);
if (it != intermediates.end()) {
tree = it->second;
} else if (!GetAnchorAt(joinsplit.anchor, tree)) {
} else if (!GetSproutAnchorAt(joinsplit.anchor, tree)) {
return false;
}
@ -454,8 +583,13 @@ bool CCoinsViewCache::HaveJoinSplitRequirements(const CTransaction& tx) const
}
for (const SpendDescription &spendDescription : tx.vShieldedSpend) {
if (GetNullifier(spendDescription.nullifier, SAPLING_NULLIFIER)) // Prevent double spends
if (GetNullifier(spendDescription.nullifier, SAPLING)) // Prevent double spends
return false;
ZCSaplingIncrementalMerkleTree tree;
if (!GetSaplingAnchorAt(spendDescription.anchor, tree)) {
return false;
}
}
return true;

View File

@ -273,7 +273,7 @@ struct CCoinsCacheEntry
CCoinsCacheEntry() : coins(), flags(0) {}
};
struct CAnchorsCacheEntry
struct CAnchorsSproutCacheEntry
{
bool entered; // This will be false if the anchor is removed from the cache
ZCIncrementalMerkleTree tree; // The tree itself
@ -283,7 +283,20 @@ struct CAnchorsCacheEntry
DIRTY = (1 << 0), // This cache entry is potentially different from the version in the parent view.
};
CAnchorsCacheEntry() : entered(false), flags(0) {}
CAnchorsSproutCacheEntry() : entered(false), flags(0) {}
};
struct CAnchorsSaplingCacheEntry
{
bool entered; // This will be false if the anchor is removed from the cache
ZCSaplingIncrementalMerkleTree tree; // The tree itself
unsigned char flags;
enum Flags {
DIRTY = (1 << 0), // This cache entry is potentially different from the version in the parent view.
};
CAnchorsSaplingCacheEntry() : entered(false), flags(0) {}
};
struct CNullifiersCacheEntry
@ -298,14 +311,15 @@ struct CNullifiersCacheEntry
CNullifiersCacheEntry() : entered(false), flags(0) {}
};
enum NullifierType
enum ShieldedType
{
SPROUT_NULLIFIER,
SAPLING_NULLIFIER,
SPROUT,
SAPLING,
};
typedef boost::unordered_map<uint256, CCoinsCacheEntry, CCoinsKeyHasher> CCoinsMap;
typedef boost::unordered_map<uint256, CAnchorsCacheEntry, CCoinsKeyHasher> CAnchorsMap;
typedef boost::unordered_map<uint256, CAnchorsSproutCacheEntry, CCoinsKeyHasher> CAnchorsSproutMap;
typedef boost::unordered_map<uint256, CAnchorsSaplingCacheEntry, CCoinsKeyHasher> CAnchorsSaplingMap;
typedef boost::unordered_map<uint256, CNullifiersCacheEntry, CCoinsKeyHasher> CNullifiersMap;
struct CCoinsStats
@ -326,11 +340,14 @@ struct CCoinsStats
class CCoinsView
{
public:
//! Retrieve the tree at a particular anchored root in the chain
virtual bool GetAnchorAt(const uint256 &rt, ZCIncrementalMerkleTree &tree) const;
//! Retrieve the tree (Sprout) at a particular anchored root in the chain
virtual bool GetSproutAnchorAt(const uint256 &rt, ZCIncrementalMerkleTree &tree) const;
//! Retrieve the tree (Sapling) at a particular anchored root in the chain
virtual bool GetSaplingAnchorAt(const uint256 &rt, ZCSaplingIncrementalMerkleTree &tree) const;
//! Determine whether a nullifier is spent or not
virtual bool GetNullifier(const uint256 &nullifier, NullifierType type) const;
virtual bool GetNullifier(const uint256 &nullifier, ShieldedType type) const;
//! Retrieve the CCoins (unspent transaction outputs) for a given txid
virtual bool GetCoins(const uint256 &txid, CCoins &coins) const;
@ -343,14 +360,16 @@ public:
virtual uint256 GetBestBlock() const;
//! Get the current "tip" or the latest anchored tree root in the chain
virtual uint256 GetBestAnchor() const;
virtual uint256 GetBestAnchor(ShieldedType type) const;
//! Do a bulk modification (multiple CCoins changes + BestBlock change).
//! The passed mapCoins can be modified.
virtual 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);
@ -370,17 +389,20 @@ protected:
public:
CCoinsViewBacked(CCoinsView *viewIn);
bool GetAnchorAt(const uint256 &rt, ZCIncrementalMerkleTree &tree) const;
bool GetNullifier(const uint256 &nullifier, NullifierType type) const;
bool GetSproutAnchorAt(const uint256 &rt, ZCIncrementalMerkleTree &tree) const;
bool GetSaplingAnchorAt(const uint256 &rt, ZCSaplingIncrementalMerkleTree &tree) const;
bool GetNullifier(const uint256 &nullifier, ShieldedType type) const;
bool GetCoins(const uint256 &txid, CCoins &coins) const;
bool HaveCoins(const uint256 &txid) const;
uint256 GetBestBlock() const;
uint256 GetBestAnchor() const;
uint256 GetBestAnchor(ShieldedType type) const;
void SetBackend(CCoinsView &viewIn);
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);
bool GetStats(CCoinsStats &stats) const;
@ -423,8 +445,10 @@ protected:
*/
mutable uint256 hashBlock;
mutable CCoinsMap cacheCoins;
mutable uint256 hashAnchor;
mutable CAnchorsMap cacheAnchors;
mutable uint256 hashSproutAnchor;
mutable uint256 hashSaplingAnchor;
mutable CAnchorsSproutMap cacheSproutAnchors;
mutable CAnchorsSaplingMap cacheSaplingAnchors;
mutable CNullifiersMap cacheSproutNullifiers;
mutable CNullifiersMap cacheSaplingNullifiers;
@ -436,28 +460,35 @@ public:
~CCoinsViewCache();
// Standard CCoinsView methods
bool GetAnchorAt(const uint256 &rt, ZCIncrementalMerkleTree &tree) const;
bool GetNullifier(const uint256 &nullifier, NullifierType type) const;
bool GetSproutAnchorAt(const uint256 &rt, ZCIncrementalMerkleTree &tree) const;
bool GetSaplingAnchorAt(const uint256 &rt, ZCSaplingIncrementalMerkleTree &tree) const;
bool GetNullifier(const uint256 &nullifier, ShieldedType type) const;
bool GetCoins(const uint256 &txid, CCoins &coins) const;
bool HaveCoins(const uint256 &txid) const;
uint256 GetBestBlock() const;
uint256 GetBestAnchor() const;
uint256 GetBestAnchor(ShieldedType type) const;
void SetBestBlock(const uint256 &hashBlock);
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);
// Adds the tree to mapAnchors and sets the current commitment
// Adds the tree to mapSproutAnchors and sets the current commitment
// root to this root.
void PushAnchor(const ZCIncrementalMerkleTree &tree);
void PushSproutAnchor(const ZCIncrementalMerkleTree &tree);
// Adds the tree to mapSaplingAnchors and sets the current commitment
// root to this root.
void PushSaplingAnchor(const ZCSaplingIncrementalMerkleTree &tree);
// Removes the current commitment root from mapAnchors and sets
// the new current root.
void PopAnchor(const uint256 &rt);
void PopAnchor(const uint256 &rt, ShieldedType type);
// Marks nullifiers for a given transaction as spent or not.
void SetNullifiers(const CTransaction& tx, bool spent);
@ -520,6 +551,31 @@ private:
* By making the copy constructor private, we prevent accidentally using it when one intends to create a cache on top of a base cache.
*/
CCoinsViewCache(const CCoinsViewCache &);
//! Generalized interface for popping anchors
template<typename Tree, typename Cache, typename CacheEntry>
void AbstractPopAnchor(
const uint256 &newrt,
ShieldedType type,
Cache &cacheAnchors,
uint256 &hash
);
//! Generalized interface for pushing anchors
template<typename Tree, typename Cache, typename CacheIterator, typename CacheEntry>
void AbstractPushAnchor(
const Tree &tree,
ShieldedType type,
Cache &cacheAnchors,
uint256 &hash
);
//! Interface for bringing an anchor into the cache.
template<typename Tree>
void BringBestAnchorIntoCache(
const uint256 &currentRoot,
Tree &tree
);
};
#endif // BITCOIN_COINS_H

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;

View File

@ -1306,13 +1306,13 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
}
BOOST_FOREACH(const JSDescription &joinsplit, tx.vjoinsplit) {
BOOST_FOREACH(const uint256 &nf, joinsplit.nullifiers) {
if (pool.nullifierExists(nf, SPROUT_NULLIFIER)) {
if (pool.nullifierExists(nf, SPROUT)) {
return false;
}
}
}
for (const SpendDescription &spendDescription : tx.vShieldedSpend) {
if (pool.nullifierExists(spendDescription.nullifier, SAPLING_NULLIFIER)) {
if (pool.nullifierExists(spendDescription.nullifier, SAPLING)) {
return false;
}
}
@ -2150,8 +2150,19 @@ bool DisconnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex
}
}
// set the old best anchor back
view.PopAnchor(blockUndo.old_tree_root);
// set the old best Sprout anchor back
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
view.SetBestBlock(pindex->pprev->GetBlockHash());
@ -2296,9 +2307,9 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
view.SetBestBlock(pindex->GetBlockHash());
// Before the genesis block, there was an empty tree
ZCIncrementalMerkleTree tree;
pindex->hashAnchor = tree.root();
pindex->hashSproutAnchor = tree.root();
// The genesis block contained no JoinSplits
pindex->hashAnchorEnd = pindex->hashAnchor;
pindex->hashFinalSproutRoot = pindex->hashSproutAnchor;
}
return true;
}
@ -2331,22 +2342,25 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
// Construct the incremental merkle tree at the current
// block position,
auto old_tree_root = view.GetBestAnchor();
auto old_sprout_tree_root = view.GetBestAnchor(SPROUT);
// saving the top anchor in the block index as we go.
if (!fJustCheck) {
pindex->hashAnchor = 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
// that is on the tip of our chain
assert(view.GetAnchorAt(old_tree_root, tree));
assert(view.GetSproutAnchorAt(old_sprout_tree_root, sprout_tree));
{
// Consistency check: the root of the tree we're given should
// 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
auto consensusBranchId = CurrentEpochBranchId(pindex->nHeight, Params().GetConsensus());
@ -2404,19 +2418,34 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
BOOST_FOREACH(const uint256 &note_commitment, joinsplit.commitments) {
// 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));
pos.nTxOffset += ::GetSerializeSize(tx, SER_DISK, CLIENT_VERSION);
}
view.PushAnchor(tree);
view.PushSproutAnchor(sprout_tree);
view.PushSaplingAnchor(sapling_tree);
if (!fJustCheck) {
pindex->hashAnchorEnd = 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;
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);
@ -2659,7 +2688,8 @@ bool static DisconnectTip(CValidationState &state, bool fBare = false) {
if (!ReadBlockFromDisk(block, pindexDelete))
return AbortNode(state, "Failed to read block");
// Apply the block atomically to the chain state.
uint256 anchorBeforeDisconnect = pcoinsTip->GetBestAnchor();
uint256 sproutAnchorBeforeDisconnect = pcoinsTip->GetBestAnchor(SPROUT);
uint256 saplingAnchorBeforeDisconnect = pcoinsTip->GetBestAnchor(SAPLING);
int64_t nStart = GetTimeMicros();
{
CCoinsViewCache view(pcoinsTip);
@ -2668,7 +2698,8 @@ bool static DisconnectTip(CValidationState &state, bool fBare = false) {
assert(view.Flush());
}
LogPrint("bench", "- Disconnect block: %.2fms\n", (GetTimeMicros() - nStart) * 0.001);
uint256 anchorAfterDisconnect = pcoinsTip->GetBestAnchor();
uint256 sproutAnchorAfterDisconnect = pcoinsTip->GetBestAnchor(SPROUT);
uint256 saplingAnchorAfterDisconnect = pcoinsTip->GetBestAnchor(SAPLING);
// Write the chain state to disk, if necessary.
if (!FlushStateToDisk(state, FLUSH_STATE_IF_NEEDED))
return false;
@ -2682,10 +2713,15 @@ bool static DisconnectTip(CValidationState &state, bool fBare = false) {
if (tx.IsCoinBase() || !AcceptToMemoryPool(mempool, stateDummy, tx, false, NULL))
mempool.remove(tx, removed, true);
}
if (anchorBeforeDisconnect != anchorAfterDisconnect) {
if (sproutAnchorBeforeDisconnect != sproutAnchorAfterDisconnect) {
// The anchor may not change between block disconnects,
// in which case we don't want to evict from the mempool yet!
mempool.removeWithAnchor(anchorBeforeDisconnect);
mempool.removeWithAnchor(sproutAnchorBeforeDisconnect, SPROUT);
}
if (saplingAnchorBeforeDisconnect != saplingAnchorAfterDisconnect) {
// The anchor may not change between block disconnects,
// in which case we don't want to evict from the mempool yet!
mempool.removeWithAnchor(saplingAnchorBeforeDisconnect, SAPLING);
}
}
@ -2693,7 +2729,7 @@ bool static DisconnectTip(CValidationState &state, bool fBare = false) {
UpdateTip(pindexDelete->pprev);
// Get the current commitment tree
ZCIncrementalMerkleTree newTree;
assert(pcoinsTip->GetAnchorAt(pcoinsTip->GetBestAnchor(), newTree));
assert(pcoinsTip->GetSproutAnchorAt(pcoinsTip->GetBestAnchor(SPROUT), newTree));
// Let wallets know transactions went from 1-confirmed to
// 0-confirmed or conflicted:
BOOST_FOREACH(const CTransaction &tx, block.vtx) {
@ -2727,7 +2763,7 @@ bool static ConnectTip(CValidationState &state, CBlockIndex *pindexNew, CBlock *
}
// Get the current commitment tree
ZCIncrementalMerkleTree oldTree;
assert(pcoinsTip->GetAnchorAt(pcoinsTip->GetBestAnchor(), oldTree));
assert(pcoinsTip->GetSproutAnchorAt(pcoinsTip->GetBestAnchor(SPROUT), oldTree));
// Apply the block atomically to the chain state.
int64_t nTime2 = GetTimeMicros(); nTimeReadFromDisk += nTime2 - nTime1;
int64_t nTime3;
@ -3928,12 +3964,12 @@ bool static LoadBlockIndexDB()
{
CBlockIndex* pindex = item.second;
// - This relationship will always be true even if pprev has multiple
// children, because hashAnchor is technically a property of pprev,
// children, because hashSproutAnchor is technically a property of pprev,
// not its children.
// - This will miss chain tips; we handle the best tip below, and other
// tips will be handled by ConnectTip during a re-org.
if (pindex->pprev) {
pindex->pprev->hashAnchorEnd = pindex->hashAnchor;
pindex->pprev->hashFinalSproutRoot = pindex->hashSproutAnchor;
}
}
@ -3942,8 +3978,8 @@ bool static LoadBlockIndexDB()
if (it == mapBlockIndex.end())
return true;
chainActive.SetTip(it->second);
// Set hashAnchorEnd for the end of best chain
it->second->hashAnchorEnd = pcoinsTip->GetBestAnchor();
// Set hashFinalSproutRoot for the end of best chain
it->second->hashFinalSproutRoot = pcoinsTip->GetBestAnchor(SPROUT);
PruneBlockIndexCandidates();

View File

@ -149,6 +149,9 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn)
const int64_t nMedianTimePast = pindexPrev->GetMedianTimePast();
CCoinsViewCache view(pcoinsTip);
ZCSaplingIncrementalMerkleTree sapling_tree;
assert(view.GetSaplingAnchorAt(view.GetBestAnchor(SAPLING), sapling_tree));
// Priority order to process transactions
list<COrphan> vOrphan; // list memory doesn't move
map<uint256, vector<COrphan*> > mapDependers;
@ -301,6 +304,10 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn)
UpdateCoins(tx, view, nHeight);
BOOST_FOREACH(const OutputDescription &outDescription, tx.vShieldedOutput) {
sapling_tree.append(outDescription.cm);
}
// Added
pblock->vtx.push_back(tx);
pblocktemplate->vTxFees.push_back(nTxFees);
@ -374,7 +381,7 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn)
// Fill in header
pblock->hashPrevBlock = pindexPrev->GetBlockHash();
pblock->hashReserved = uint256();
pblock->hashFinalSaplingRoot = sapling_tree.root();
UpdateTime(pblock, Params().GetConsensus(), pindexPrev);
pblock->nBits = GetNextWorkRequired(pindexPrev, pblock, Params().GetConsensus());
pblock->nSolution.clear();

View File

@ -112,12 +112,12 @@ uint256 CBlock::CheckMerkleBranch(uint256 hash, const std::vector<uint256>& vMer
std::string CBlock::ToString() const
{
std::stringstream s;
s << strprintf("CBlock(hash=%s, ver=%d, hashPrevBlock=%s, hashMerkleRoot=%s, hashReserved=%s, nTime=%u, nBits=%08x, nNonce=%s, vtx=%u)\n",
s << strprintf("CBlock(hash=%s, ver=%d, hashPrevBlock=%s, hashMerkleRoot=%s, hashFinalSaplingRoot=%s, nTime=%u, nBits=%08x, nNonce=%s, vtx=%u)\n",
GetHash().ToString(),
nVersion,
hashPrevBlock.ToString(),
hashMerkleRoot.ToString(),
hashReserved.ToString(),
hashFinalSaplingRoot.ToString(),
nTime, nBits, nNonce.ToString(),
vtx.size());
for (unsigned int i = 0; i < vtx.size(); i++)

View File

@ -26,7 +26,7 @@ public:
int32_t nVersion;
uint256 hashPrevBlock;
uint256 hashMerkleRoot;
uint256 hashReserved;
uint256 hashFinalSaplingRoot;
uint32_t nTime;
uint32_t nBits;
uint256 nNonce;
@ -44,7 +44,7 @@ public:
READWRITE(this->nVersion);
READWRITE(hashPrevBlock);
READWRITE(hashMerkleRoot);
READWRITE(hashReserved);
READWRITE(hashFinalSaplingRoot);
READWRITE(nTime);
READWRITE(nBits);
READWRITE(nNonce);
@ -56,7 +56,7 @@ public:
nVersion = CBlockHeader::CURRENT_VERSION;
hashPrevBlock.SetNull();
hashMerkleRoot.SetNull();
hashReserved.SetNull();
hashFinalSaplingRoot.SetNull();
nTime = 0;
nBits = 0;
nNonce = uint256();
@ -118,7 +118,7 @@ public:
block.nVersion = nVersion;
block.hashPrevBlock = hashPrevBlock;
block.hashMerkleRoot = hashMerkleRoot;
block.hashReserved = hashReserved;
block.hashFinalSaplingRoot = hashFinalSaplingRoot;
block.nTime = nTime;
block.nBits = nBits;
block.nNonce = nNonce;
@ -158,7 +158,7 @@ public:
READWRITE(this->nVersion);
READWRITE(hashPrevBlock);
READWRITE(hashMerkleRoot);
READWRITE(hashReserved);
READWRITE(hashFinalSaplingRoot);
READWRITE(nTime);
READWRITE(nBits);
}

View File

@ -155,7 +155,7 @@ UniValue blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool tx
result.push_back(Pair("bits", strprintf("%08x", block.nBits)));
result.push_back(Pair("difficulty", GetDifficulty(blockindex)));
result.push_back(Pair("chainwork", blockindex->nChainWork.GetHex()));
result.push_back(Pair("anchor", blockindex->hashAnchorEnd.GetHex()));
result.push_back(Pair("anchor", blockindex->hashFinalSproutRoot.GetHex()));
UniValue valuePools(UniValue::VARR);
valuePools.push_back(ValuePoolDesc("sprout", blockindex->nChainSproutValue, blockindex->nSproutValue));
@ -770,7 +770,7 @@ UniValue getblockchaininfo(const UniValue& params, bool fHelp)
obj.push_back(Pair("pruned", fPruneMode));
ZCIncrementalMerkleTree tree;
pcoinsTip->GetAnchorAt(pcoinsTip->GetBestAnchor(), tree);
pcoinsTip->GetSproutAnchorAt(pcoinsTip->GetBestAnchor(SPROUT), tree);
obj.push_back(Pair("commitments", static_cast<uint64_t>(tree.size())));
CBlockIndex* tip = chainActive.Tip();

View File

@ -25,26 +25,29 @@ namespace
class CCoinsViewTest : public CCoinsView
{
uint256 hashBestBlock_;
uint256 hashBestAnchor_;
uint256 hashBestSproutAnchor_;
uint256 hashBestSaplingAnchor_;
std::map<uint256, CCoins> map_;
std::map<uint256, ZCIncrementalMerkleTree> mapAnchors_;
std::map<uint256, ZCIncrementalMerkleTree> mapSproutAnchors_;
std::map<uint256, ZCSaplingIncrementalMerkleTree> mapSaplingAnchors_;
std::map<uint256, bool> mapSproutNullifiers_;
std::map<uint256, bool> mapSaplingNullifiers_;
public:
CCoinsViewTest() {
hashBestAnchor_ = ZCIncrementalMerkleTree::empty_root();
hashBestSproutAnchor_ = ZCIncrementalMerkleTree::empty_root();
hashBestSaplingAnchor_ = ZCSaplingIncrementalMerkleTree::empty_root();
}
bool GetAnchorAt(const uint256& rt, ZCIncrementalMerkleTree &tree) const {
bool GetSproutAnchorAt(const uint256& rt, ZCIncrementalMerkleTree &tree) const {
if (rt == ZCIncrementalMerkleTree::empty_root()) {
ZCIncrementalMerkleTree new_tree;
tree = new_tree;
return true;
}
std::map<uint256, ZCIncrementalMerkleTree>::const_iterator it = mapAnchors_.find(rt);
if (it == mapAnchors_.end()) {
std::map<uint256, ZCIncrementalMerkleTree>::const_iterator it = mapSproutAnchors_.find(rt);
if (it == mapSproutAnchors_.end()) {
return false;
} else {
tree = it->second;
@ -52,18 +55,34 @@ public:
}
}
bool GetNullifier(const uint256 &nf, NullifierType type) const
bool GetSaplingAnchorAt(const uint256& rt, ZCSaplingIncrementalMerkleTree &tree) const {
if (rt == ZCSaplingIncrementalMerkleTree::empty_root()) {
ZCSaplingIncrementalMerkleTree new_tree;
tree = new_tree;
return true;
}
std::map<uint256, ZCSaplingIncrementalMerkleTree>::const_iterator it = mapSaplingAnchors_.find(rt);
if (it == mapSaplingAnchors_.end()) {
return false;
} else {
tree = it->second;
return true;
}
}
bool GetNullifier(const uint256 &nf, ShieldedType type) const
{
const std::map<uint256, bool>* mapToUse;
switch (type) {
case SPROUT_NULLIFIER:
case SPROUT:
mapToUse = &mapSproutNullifiers_;
break;
case SAPLING_NULLIFIER:
case SAPLING:
mapToUse = &mapSaplingNullifiers_;
break;
default:
throw std::runtime_error("Unknown nullifier type");
throw std::runtime_error("Unknown shielded type");
}
std::map<uint256, bool>::const_iterator it = mapToUse->find(nf);
if (it == mapToUse->end()) {
@ -75,7 +94,18 @@ public:
}
}
uint256 GetBestAnchor() const { return hashBestAnchor_; }
uint256 GetBestAnchor(ShieldedType type) const {
switch (type) {
case SPROUT:
return hashBestSproutAnchor_;
break;
case SAPLING:
return hashBestSaplingAnchor_;
break;
default:
throw std::runtime_error("Unknown shielded type");
}
}
bool GetCoins(const uint256& txid, CCoins& coins) const
{
@ -114,8 +144,10 @@ public:
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)
{
@ -127,25 +159,38 @@ public:
}
mapCoins.erase(it++);
}
for (CAnchorsMap::iterator it = mapAnchors.begin(); it != mapAnchors.end(); ) {
for (CAnchorsSproutMap::iterator it = mapSproutAnchors.begin(); it != mapSproutAnchors.end(); ) {
if (it->second.entered) {
std::map<uint256, ZCIncrementalMerkleTree>::iterator ret =
mapAnchors_.insert(std::make_pair(it->first, ZCIncrementalMerkleTree())).first;
mapSproutAnchors_.insert(std::make_pair(it->first, ZCIncrementalMerkleTree())).first;
ret->second = it->second.tree;
} else {
mapAnchors_.erase(it->first);
mapSproutAnchors_.erase(it->first);
}
mapAnchors.erase(it++);
mapSproutAnchors.erase(it++);
}
for (CAnchorsSaplingMap::iterator it = mapSaplingAnchors.begin(); it != mapSaplingAnchors.end(); ) {
if (it->second.entered) {
std::map<uint256, ZCSaplingIncrementalMerkleTree>::iterator ret =
mapSaplingAnchors_.insert(std::make_pair(it->first, ZCSaplingIncrementalMerkleTree())).first;
ret->second = it->second.tree;
} else {
mapSaplingAnchors_.erase(it->first);
}
mapSaplingAnchors.erase(it++);
}
BatchWriteNullifiers(mapSproutNullifiers, mapSproutNullifiers_);
BatchWriteNullifiers(mapSaplingNullifiers, mapSaplingNullifiers_);
mapCoins.clear();
mapAnchors.clear();
mapSproutAnchors.clear();
mapSaplingAnchors.clear();
hashBestBlock_ = hashBlock;
hashBestAnchor_ = hashAnchor;
hashBestSproutAnchor_ = hashSproutAnchor;
hashBestSaplingAnchor_ = hashSaplingAnchor;
return true;
}
@ -161,7 +206,8 @@ public:
{
// Manually recompute the dynamic usage of the whole data, and compare it.
size_t ret = memusage::DynamicUsage(cacheCoins) +
memusage::DynamicUsage(cacheAnchors) +
memusage::DynamicUsage(cacheSproutAnchors) +
memusage::DynamicUsage(cacheSaplingAnchors) +
memusage::DynamicUsage(cacheSproutNullifiers) +
memusage::DynamicUsage(cacheSaplingNullifiers);
for (CCoinsMap::iterator it = cacheCoins.begin(); it != cacheCoins.end(); it++) {
@ -215,11 +261,11 @@ BOOST_FIXTURE_TEST_SUITE(coins_tests, BasicTestingSetup)
void checkNullifierCache(const CCoinsViewCacheTest &cache, const TxWithNullifiers &txWithNullifiers, bool shouldBeInCache) {
// Make sure the nullifiers have not gotten mixed up
BOOST_CHECK(!cache.GetNullifier(txWithNullifiers.sproutNullifier, SAPLING_NULLIFIER));
BOOST_CHECK(!cache.GetNullifier(txWithNullifiers.saplingNullifier, SPROUT_NULLIFIER));
BOOST_CHECK(!cache.GetNullifier(txWithNullifiers.sproutNullifier, SAPLING));
BOOST_CHECK(!cache.GetNullifier(txWithNullifiers.saplingNullifier, SPROUT));
// Check if the nullifiers either are or are not in the cache
bool containsSproutNullifier = cache.GetNullifier(txWithNullifiers.sproutNullifier, SPROUT_NULLIFIER);
bool containsSaplingNullifier = cache.GetNullifier(txWithNullifiers.saplingNullifier, SAPLING_NULLIFIER);
bool containsSproutNullifier = cache.GetNullifier(txWithNullifiers.sproutNullifier, SPROUT);
bool containsSaplingNullifier = cache.GetNullifier(txWithNullifiers.saplingNullifier, SAPLING);
BOOST_CHECK(containsSproutNullifier == shouldBeInCache);
BOOST_CHECK(containsSaplingNullifier == shouldBeInCache);
}
@ -325,21 +371,21 @@ BOOST_AUTO_TEST_CASE(anchor_pop_regression_test)
tree.append(cm);
// Add the anchor
cache1.PushAnchor(tree);
cache1.PushSproutAnchor(tree);
cache1.Flush();
// Remove the anchor
cache1.PopAnchor(ZCIncrementalMerkleTree::empty_root());
cache1.PopAnchor(ZCIncrementalMerkleTree::empty_root(), SPROUT);
cache1.Flush();
// Add the anchor back
cache1.PushAnchor(tree);
cache1.PushSproutAnchor(tree);
cache1.Flush();
// The base contains the anchor, of course!
{
ZCIncrementalMerkleTree checktree;
BOOST_CHECK(cache1.GetAnchorAt(tree.root(), checktree));
BOOST_CHECK(cache1.GetSproutAnchorAt(tree.root(), checktree));
BOOST_CHECK(checktree.root() == tree.root());
}
}
@ -355,15 +401,15 @@ BOOST_AUTO_TEST_CASE(anchor_pop_regression_test)
tree.append(cm);
// Add the anchor and flush to disk
cache1.PushAnchor(tree);
cache1.PushSproutAnchor(tree);
cache1.Flush();
// Remove the anchor, but don't flush yet!
cache1.PopAnchor(ZCIncrementalMerkleTree::empty_root());
cache1.PopAnchor(ZCIncrementalMerkleTree::empty_root(), SPROUT);
{
CCoinsViewCacheTest cache2(&cache1); // Build cache on top
cache2.PushAnchor(tree); // Put the same anchor back!
cache2.PushSproutAnchor(tree); // Put the same anchor back!
cache2.Flush(); // Flush to cache1
}
@ -372,7 +418,7 @@ BOOST_AUTO_TEST_CASE(anchor_pop_regression_test)
// treestate...
{
ZCIncrementalMerkleTree checktree;
BOOST_CHECK(cache1.GetAnchorAt(tree.root(), checktree));
BOOST_CHECK(cache1.GetSproutAnchorAt(tree.root(), checktree));
BOOST_CHECK(checktree.root() == tree.root()); // Oh, shucks.
}
@ -381,7 +427,7 @@ BOOST_AUTO_TEST_CASE(anchor_pop_regression_test)
cache1.Flush();
{
ZCIncrementalMerkleTree checktree;
BOOST_CHECK(cache1.GetAnchorAt(tree.root(), checktree));
BOOST_CHECK(cache1.GetSproutAnchorAt(tree.root(), checktree));
BOOST_CHECK(checktree.root() == tree.root()); // Oh, shucks.
}
}
@ -398,12 +444,12 @@ BOOST_AUTO_TEST_CASE(anchor_regression_test)
ZCIncrementalMerkleTree tree;
uint256 cm = GetRandHash();
tree.append(cm);
cache1.PushAnchor(tree);
cache1.PushSproutAnchor(tree);
cache1.Flush();
cache1.PopAnchor(ZCIncrementalMerkleTree::empty_root());
BOOST_CHECK(cache1.GetBestAnchor() == ZCIncrementalMerkleTree::empty_root());
BOOST_CHECK(!cache1.GetAnchorAt(tree.root(), tree));
cache1.PopAnchor(ZCIncrementalMerkleTree::empty_root(), SPROUT);
BOOST_CHECK(cache1.GetBestAnchor(SPROUT) == ZCIncrementalMerkleTree::empty_root());
BOOST_CHECK(!cache1.GetSproutAnchorAt(tree.root(), tree));
}
// Also correct behavior:
@ -415,13 +461,13 @@ BOOST_AUTO_TEST_CASE(anchor_regression_test)
ZCIncrementalMerkleTree tree;
uint256 cm = GetRandHash();
tree.append(cm);
cache1.PushAnchor(tree);
cache1.PushSproutAnchor(tree);
cache1.Flush();
cache1.PopAnchor(ZCIncrementalMerkleTree::empty_root());
cache1.PopAnchor(ZCIncrementalMerkleTree::empty_root(), SPROUT);
cache1.Flush();
BOOST_CHECK(cache1.GetBestAnchor() == ZCIncrementalMerkleTree::empty_root());
BOOST_CHECK(!cache1.GetAnchorAt(tree.root(), tree));
BOOST_CHECK(cache1.GetBestAnchor(SPROUT) == ZCIncrementalMerkleTree::empty_root());
BOOST_CHECK(!cache1.GetSproutAnchorAt(tree.root(), tree));
}
// Works because we bring the anchor in from parent cache.
@ -433,19 +479,19 @@ BOOST_AUTO_TEST_CASE(anchor_regression_test)
ZCIncrementalMerkleTree tree;
uint256 cm = GetRandHash();
tree.append(cm);
cache1.PushAnchor(tree);
cache1.PushSproutAnchor(tree);
cache1.Flush();
{
// Pop anchor.
CCoinsViewCacheTest cache2(&cache1);
BOOST_CHECK(cache2.GetAnchorAt(tree.root(), tree));
cache2.PopAnchor(ZCIncrementalMerkleTree::empty_root());
BOOST_CHECK(cache2.GetSproutAnchorAt(tree.root(), tree));
cache2.PopAnchor(ZCIncrementalMerkleTree::empty_root(), SPROUT);
cache2.Flush();
}
BOOST_CHECK(cache1.GetBestAnchor() == ZCIncrementalMerkleTree::empty_root());
BOOST_CHECK(!cache1.GetAnchorAt(tree.root(), tree));
BOOST_CHECK(cache1.GetBestAnchor(SPROUT) == ZCIncrementalMerkleTree::empty_root());
BOOST_CHECK(!cache1.GetSproutAnchorAt(tree.root(), tree));
}
// Was broken:
@ -457,18 +503,18 @@ BOOST_AUTO_TEST_CASE(anchor_regression_test)
ZCIncrementalMerkleTree tree;
uint256 cm = GetRandHash();
tree.append(cm);
cache1.PushAnchor(tree);
cache1.PushSproutAnchor(tree);
cache1.Flush();
{
// Pop anchor.
CCoinsViewCacheTest cache2(&cache1);
cache2.PopAnchor(ZCIncrementalMerkleTree::empty_root());
cache2.PopAnchor(ZCIncrementalMerkleTree::empty_root(), SPROUT);
cache2.Flush();
}
BOOST_CHECK(cache1.GetBestAnchor() == ZCIncrementalMerkleTree::empty_root());
BOOST_CHECK(!cache1.GetAnchorAt(tree.root(), tree));
BOOST_CHECK(cache1.GetBestAnchor(SPROUT) == ZCIncrementalMerkleTree::empty_root());
BOOST_CHECK(!cache1.GetSproutAnchorAt(tree.root(), tree));
}
}
@ -502,22 +548,22 @@ BOOST_AUTO_TEST_CASE(anchors_flush_test)
{
CCoinsViewCacheTest cache(&base);
ZCIncrementalMerkleTree tree;
BOOST_CHECK(cache.GetAnchorAt(cache.GetBestAnchor(), tree));
BOOST_CHECK(cache.GetSproutAnchorAt(cache.GetBestAnchor(SPROUT), tree));
appendRandomCommitment(tree);
newrt = tree.root();
cache.PushAnchor(tree);
cache.PushSproutAnchor(tree);
cache.Flush();
}
{
CCoinsViewCacheTest cache(&base);
ZCIncrementalMerkleTree tree;
BOOST_CHECK(cache.GetAnchorAt(cache.GetBestAnchor(), tree));
BOOST_CHECK(cache.GetSproutAnchorAt(cache.GetBestAnchor(SPROUT), tree));
// Get the cached entry.
BOOST_CHECK(cache.GetAnchorAt(cache.GetBestAnchor(), tree));
BOOST_CHECK(cache.GetSproutAnchorAt(cache.GetBestAnchor(SPROUT), tree));
uint256 check_rt = tree.root();
@ -610,13 +656,13 @@ BOOST_AUTO_TEST_CASE(anchors_test)
CCoinsViewTest base;
CCoinsViewCacheTest cache(&base);
BOOST_CHECK(cache.GetBestAnchor() == ZCIncrementalMerkleTree::empty_root());
BOOST_CHECK(cache.GetBestAnchor(SPROUT) == ZCIncrementalMerkleTree::empty_root());
{
ZCIncrementalMerkleTree tree;
BOOST_CHECK(cache.GetAnchorAt(cache.GetBestAnchor(), tree));
BOOST_CHECK(cache.GetBestAnchor() == tree.root());
BOOST_CHECK(cache.GetSproutAnchorAt(cache.GetBestAnchor(SPROUT), tree));
BOOST_CHECK(cache.GetBestAnchor(SPROUT) == tree.root());
appendRandomCommitment(tree);
appendRandomCommitment(tree);
appendRandomCommitment(tree);
@ -631,12 +677,12 @@ BOOST_AUTO_TEST_CASE(anchors_test)
uint256 newrt = tree.root();
uint256 newrt2;
cache.PushAnchor(tree);
BOOST_CHECK(cache.GetBestAnchor() == newrt);
cache.PushSproutAnchor(tree);
BOOST_CHECK(cache.GetBestAnchor(SPROUT) == newrt);
{
ZCIncrementalMerkleTree confirm_same;
BOOST_CHECK(cache.GetAnchorAt(cache.GetBestAnchor(), confirm_same));
BOOST_CHECK(cache.GetSproutAnchorAt(cache.GetBestAnchor(SPROUT), confirm_same));
BOOST_CHECK(confirm_same.root() == newrt);
}
@ -646,26 +692,26 @@ BOOST_AUTO_TEST_CASE(anchors_test)
newrt2 = tree.root();
cache.PushAnchor(tree);
BOOST_CHECK(cache.GetBestAnchor() == newrt2);
cache.PushSproutAnchor(tree);
BOOST_CHECK(cache.GetBestAnchor(SPROUT) == newrt2);
ZCIncrementalMerkleTree test_tree;
BOOST_CHECK(cache.GetAnchorAt(cache.GetBestAnchor(), test_tree));
BOOST_CHECK(cache.GetSproutAnchorAt(cache.GetBestAnchor(SPROUT), test_tree));
BOOST_CHECK(tree.root() == test_tree.root());
{
ZCIncrementalMerkleTree test_tree2;
cache.GetAnchorAt(newrt, test_tree2);
cache.GetSproutAnchorAt(newrt, test_tree2);
BOOST_CHECK(test_tree2.root() == newrt);
}
{
cache.PopAnchor(newrt);
cache.PopAnchor(newrt, SPROUT);
ZCIncrementalMerkleTree obtain_tree;
assert(!cache.GetAnchorAt(newrt2, obtain_tree)); // should have been popped off
assert(cache.GetAnchorAt(newrt, obtain_tree));
assert(!cache.GetSproutAnchorAt(newrt2, obtain_tree)); // should have been popped off
assert(cache.GetSproutAnchorAt(newrt, obtain_tree));
assert(obtain_tree.root() == newrt);
}

View File

@ -0,0 +1,18 @@
[
"556f3af94225d46b1ef652abc9005dee873b2e245eef07fd5be587e0f21023b0",
"d814b127a6c6b8f07ed03f0f6e2843ff04c9851ff824a4e5b4dad5b5f3475722",
"ec030e6d7460f91668cc842ceb78cdb54470469e78cd59cf903d3a6e1aa03e7c",
"b0a0d08406b9e3693ee4c062bd1e6816f95bf14f5a13aafa1d57942c6c1d4250",
"92fc3e7298eb327a88abcc406fbe595e45dddd9b4209803b2e0baa3a8663ecaa",
"f607dd230ada93d14f4de1d9008a5e64a59af87c2e4f64a5f9e55e0cd44867f8",
"ae0bfc1e123edcb6252251611650f3667371f781b60302385c414716c75e8abc",
"91a5e54bf9a9b57e1c163904999ad1527f1e126c685111e18193decca2dd1ada",
"c674f7836089063143fc18b673b2d92f888c63380e3680385d47bcdbd5fe273a",
"7c1dbdb260441b89a08ba411d5f8406e81abd9dc85382f307999fdf77d8fcac8",
"02372c746664e0898576972ca6d0500c7c8ec42f144622349d133b06e837faf0",
"08c6d7dd3d2e387f7b84d6769f2b6cbe308918ab81e0f7321bd0945868d7d4e6",
"a6e8c4061f2ad984d19f2c0a4436b9800e529069c0b0d3186d4683e83bb7eb8c",
"837cc2391338956026521beca5c81b541b7f2d1ead7758bf4d1588dbbcb8fa22",
"1cc467cfd2b504e156c9a38bc5c0e4f5ea6cc208054d2d0653a7e561ac3a3ef4",
"15ac4057a9a94536eca9802de65e985319e89627c9c64bc94626b712bc61363a"
]

View File

@ -0,0 +1,122 @@
[
"0420c22d0dcb70b0a84c3440f839a64c9e5259066fff49f6c96a2068bb7fa70ff096201f2610f0650d97f4ecde80d8dab101794631236623c51df290320b2a4c18c21620fe60df1ce575aaab663d158a20f9e560f7bdc5179f1527b3a33e4f587b44ffbc20225747f3b5d5dab4e5a424f81f85c904ff43286e0f3fd07ef0b8c6a627b114d80000000000000000",
"0420c22d0dcb70b0a84c3440f839a64c9e5259066fff49f6c96a2068bb7fa70ff096201f2610f0650d97f4ecde80d8dab101794631236623c51df290320b2a4c18c21620c054f0548d44fb121f3e22fe87517c806628adfd0f3cddc67c982f4adc26b62a20225747f3b5d5dab4e5a424f81f85c904ff43286e0f3fd07ef0b8c6a627b114d80000000000000000",
"0420c22d0dcb70b0a84c3440f839a64c9e5259066fff49f6c96a2068bb7fa70ff096201f2610f0650d97f4ecde80d8dab101794631236623c51df290320b2a4c18c21620c054f0548d44fb121f3e22fe87517c806628adfd0f3cddc67c982f4adc26b62a20b02310f2e087e55bfd07ef5e242e3b87ee5d00c9ab52f61e6bd42542f93a6f550100000000000000",
"0420c22d0dcb70b0a84c3440f839a64c9e5259066fff49f6c96a2068bb7fa70ff096201f2610f0650d97f4ecde80d8dab101794631236623c51df290320b2a4c18c21620cb37f4591361cd846141e7852c3726b37dd9b011cc55eef2ac931dfe769ff55a20225747f3b5d5dab4e5a424f81f85c904ff43286e0f3fd07ef0b8c6a627b114d80000000000000000",
"0420c22d0dcb70b0a84c3440f839a64c9e5259066fff49f6c96a2068bb7fa70ff096201f2610f0650d97f4ecde80d8dab101794631236623c51df290320b2a4c18c21620cb37f4591361cd846141e7852c3726b37dd9b011cc55eef2ac931dfe769ff55a20b02310f2e087e55bfd07ef5e242e3b87ee5d00c9ab52f61e6bd42542f93a6f550100000000000000",
"0420c22d0dcb70b0a84c3440f839a64c9e5259066fff49f6c96a2068bb7fa70ff096201f2610f0650d97f4ecde80d8dab101794631236623c51df290320b2a4c18c216206a0fa2d0c5c7b8236092de86d99068ce04511d5adbdd848ccf7c969dbf7338ca2050421d6c2c94571dfaaa135a4ff15bf916681ebd62c0e43e69e3b90684d0a0b00200000000000000",
"0420c22d0dcb70b0a84c3440f839a64c9e5259066fff49f6c96a2068bb7fa70ff096200504f659ffb9358e5fba924944396b345006a0abc2cbfd207c97d6b2323bdc2020cb37f4591361cd846141e7852c3726b37dd9b011cc55eef2ac931dfe769ff55a20225747f3b5d5dab4e5a424f81f85c904ff43286e0f3fd07ef0b8c6a627b114d80000000000000000",
"0420c22d0dcb70b0a84c3440f839a64c9e5259066fff49f6c96a2068bb7fa70ff096200504f659ffb9358e5fba924944396b345006a0abc2cbfd207c97d6b2323bdc2020cb37f4591361cd846141e7852c3726b37dd9b011cc55eef2ac931dfe769ff55a20b02310f2e087e55bfd07ef5e242e3b87ee5d00c9ab52f61e6bd42542f93a6f550100000000000000",
"0420c22d0dcb70b0a84c3440f839a64c9e5259066fff49f6c96a2068bb7fa70ff096200504f659ffb9358e5fba924944396b345006a0abc2cbfd207c97d6b2323bdc20206a0fa2d0c5c7b8236092de86d99068ce04511d5adbdd848ccf7c969dbf7338ca2050421d6c2c94571dfaaa135a4ff15bf916681ebd62c0e43e69e3b90684d0a0b00200000000000000",
"0420c22d0dcb70b0a84c3440f839a64c9e5259066fff49f6c96a2068bb7fa70ff096200504f659ffb9358e5fba924944396b345006a0abc2cbfd207c97d6b2323bdc20206a0fa2d0c5c7b8236092de86d99068ce04511d5adbdd848ccf7c969dbf7338ca207c3ea01a6e3a3d90cf59cd789e467044b5cd78eb2c84cc6816f960746d0e03ec0300000000000000",
"0420c22d0dcb70b0a84c3440f839a64c9e5259066fff49f6c96a2068bb7fa70ff096207315163946951eb4895ff12f6b0724c6062f021e669b99fed24dfacd28c9c04420cb37f4591361cd846141e7852c3726b37dd9b011cc55eef2ac931dfe769ff55a20225747f3b5d5dab4e5a424f81f85c904ff43286e0f3fd07ef0b8c6a627b114d80000000000000000",
"0420c22d0dcb70b0a84c3440f839a64c9e5259066fff49f6c96a2068bb7fa70ff096207315163946951eb4895ff12f6b0724c6062f021e669b99fed24dfacd28c9c04420cb37f4591361cd846141e7852c3726b37dd9b011cc55eef2ac931dfe769ff55a20b02310f2e087e55bfd07ef5e242e3b87ee5d00c9ab52f61e6bd42542f93a6f550100000000000000",
"0420c22d0dcb70b0a84c3440f839a64c9e5259066fff49f6c96a2068bb7fa70ff096207315163946951eb4895ff12f6b0724c6062f021e669b99fed24dfacd28c9c044206a0fa2d0c5c7b8236092de86d99068ce04511d5adbdd848ccf7c969dbf7338ca2050421d6c2c94571dfaaa135a4ff15bf916681ebd62c0e43e69e3b90684d0a0b00200000000000000",
"0420c22d0dcb70b0a84c3440f839a64c9e5259066fff49f6c96a2068bb7fa70ff096207315163946951eb4895ff12f6b0724c6062f021e669b99fed24dfacd28c9c044206a0fa2d0c5c7b8236092de86d99068ce04511d5adbdd848ccf7c969dbf7338ca207c3ea01a6e3a3d90cf59cd789e467044b5cd78eb2c84cc6816f960746d0e03ec0300000000000000",
"0420c22d0dcb70b0a84c3440f839a64c9e5259066fff49f6c96a2068bb7fa70ff09620197fda6b43eb91b445cf8a19541a6b064e9221cf6d43d67987d4cd0c646121e620fe60df1ce575aaab663d158a20f9e560f7bdc5179f1527b3a33e4f587b44ffbc20f86748d40c5ee5f9a5644f2e7cf89aa5645e8a00d9e14d4fd193da0a23dd07f60400000000000000",
"0420c22d0dcb70b0a84c3440f839a64c9e5259066fff49f6c96a2068bb7fa70ff09620c4952dd79bbb887a721fde83eeb847a32117311e7dd0d107625ab11063b7b7aa20cb37f4591361cd846141e7852c3726b37dd9b011cc55eef2ac931dfe769ff55a20225747f3b5d5dab4e5a424f81f85c904ff43286e0f3fd07ef0b8c6a627b114d80000000000000000",
"0420c22d0dcb70b0a84c3440f839a64c9e5259066fff49f6c96a2068bb7fa70ff09620c4952dd79bbb887a721fde83eeb847a32117311e7dd0d107625ab11063b7b7aa20cb37f4591361cd846141e7852c3726b37dd9b011cc55eef2ac931dfe769ff55a20b02310f2e087e55bfd07ef5e242e3b87ee5d00c9ab52f61e6bd42542f93a6f550100000000000000",
"0420c22d0dcb70b0a84c3440f839a64c9e5259066fff49f6c96a2068bb7fa70ff09620c4952dd79bbb887a721fde83eeb847a32117311e7dd0d107625ab11063b7b7aa206a0fa2d0c5c7b8236092de86d99068ce04511d5adbdd848ccf7c969dbf7338ca2050421d6c2c94571dfaaa135a4ff15bf916681ebd62c0e43e69e3b90684d0a0b00200000000000000",
"0420c22d0dcb70b0a84c3440f839a64c9e5259066fff49f6c96a2068bb7fa70ff09620c4952dd79bbb887a721fde83eeb847a32117311e7dd0d107625ab11063b7b7aa206a0fa2d0c5c7b8236092de86d99068ce04511d5adbdd848ccf7c969dbf7338ca207c3ea01a6e3a3d90cf59cd789e467044b5cd78eb2c84cc6816f960746d0e03ec0300000000000000",
"0420c22d0dcb70b0a84c3440f839a64c9e5259066fff49f6c96a2068bb7fa70ff09620197fda6b43eb91b445cf8a19541a6b064e9221cf6d43d67987d4cd0c646121e620c4a10647b2ed9dfd93323f5b2044550c5763cf198da5297d1778c894337253c620f86748d40c5ee5f9a5644f2e7cf89aa5645e8a00d9e14d4fd193da0a23dd07f60400000000000000",
"0420c22d0dcb70b0a84c3440f839a64c9e5259066fff49f6c96a2068bb7fa70ff09620197fda6b43eb91b445cf8a19541a6b064e9221cf6d43d67987d4cd0c646121e620c4a10647b2ed9dfd93323f5b2044550c5763cf198da5297d1778c894337253c620aaec63863aaa0b2e3b8009429bdddd455e59be6f40ccab887a32eb98723efc920500000000000000",
"0420c22d0dcb70b0a84c3440f839a64c9e5259066fff49f6c96a2068bb7fa70ff096201dab0949ba4bae1d065b07b0b308e6a197e118f7614caab5f137ad66dfe6ab8e20cb37f4591361cd846141e7852c3726b37dd9b011cc55eef2ac931dfe769ff55a20225747f3b5d5dab4e5a424f81f85c904ff43286e0f3fd07ef0b8c6a627b114d80000000000000000",
"0420c22d0dcb70b0a84c3440f839a64c9e5259066fff49f6c96a2068bb7fa70ff096201dab0949ba4bae1d065b07b0b308e6a197e118f7614caab5f137ad66dfe6ab8e20cb37f4591361cd846141e7852c3726b37dd9b011cc55eef2ac931dfe769ff55a20b02310f2e087e55bfd07ef5e242e3b87ee5d00c9ab52f61e6bd42542f93a6f550100000000000000",
"0420c22d0dcb70b0a84c3440f839a64c9e5259066fff49f6c96a2068bb7fa70ff096201dab0949ba4bae1d065b07b0b308e6a197e118f7614caab5f137ad66dfe6ab8e206a0fa2d0c5c7b8236092de86d99068ce04511d5adbdd848ccf7c969dbf7338ca2050421d6c2c94571dfaaa135a4ff15bf916681ebd62c0e43e69e3b90684d0a0b00200000000000000",
"0420c22d0dcb70b0a84c3440f839a64c9e5259066fff49f6c96a2068bb7fa70ff096201dab0949ba4bae1d065b07b0b308e6a197e118f7614caab5f137ad66dfe6ab8e206a0fa2d0c5c7b8236092de86d99068ce04511d5adbdd848ccf7c969dbf7338ca207c3ea01a6e3a3d90cf59cd789e467044b5cd78eb2c84cc6816f960746d0e03ec0300000000000000",
"0420c22d0dcb70b0a84c3440f839a64c9e5259066fff49f6c96a2068bb7fa70ff09620197fda6b43eb91b445cf8a19541a6b064e9221cf6d43d67987d4cd0c646121e620022293d64836b72bc9d1ae36d6e115c8f7cf0a3f5e75d74059f69f81fd56142620f86748d40c5ee5f9a5644f2e7cf89aa5645e8a00d9e14d4fd193da0a23dd07f60400000000000000",
"0420c22d0dcb70b0a84c3440f839a64c9e5259066fff49f6c96a2068bb7fa70ff09620197fda6b43eb91b445cf8a19541a6b064e9221cf6d43d67987d4cd0c646121e620022293d64836b72bc9d1ae36d6e115c8f7cf0a3f5e75d74059f69f81fd56142620aaec63863aaa0b2e3b8009429bdddd455e59be6f40ccab887a32eb98723efc920500000000000000",
"0420c22d0dcb70b0a84c3440f839a64c9e5259066fff49f6c96a2068bb7fa70ff09620197fda6b43eb91b445cf8a19541a6b064e9221cf6d43d67987d4cd0c646121e62065d0fa354e4efa95de2eee9329f18bc7db58d03501471348bfdeca4554eb2e3420da1adda2ccde9381e11151686c121e7f52d19a990439161c7eb5a9f94be5a5910600000000000000",
"04203f117e549d8140c4bd97b3d8d73dfeaaa458491730e870e7fd4a3d472493c31c201dab0949ba4bae1d065b07b0b308e6a197e118f7614caab5f137ad66dfe6ab8e20cb37f4591361cd846141e7852c3726b37dd9b011cc55eef2ac931dfe769ff55a20225747f3b5d5dab4e5a424f81f85c904ff43286e0f3fd07ef0b8c6a627b114d80000000000000000",
"04203f117e549d8140c4bd97b3d8d73dfeaaa458491730e870e7fd4a3d472493c31c201dab0949ba4bae1d065b07b0b308e6a197e118f7614caab5f137ad66dfe6ab8e20cb37f4591361cd846141e7852c3726b37dd9b011cc55eef2ac931dfe769ff55a20b02310f2e087e55bfd07ef5e242e3b87ee5d00c9ab52f61e6bd42542f93a6f550100000000000000",
"04203f117e549d8140c4bd97b3d8d73dfeaaa458491730e870e7fd4a3d472493c31c201dab0949ba4bae1d065b07b0b308e6a197e118f7614caab5f137ad66dfe6ab8e206a0fa2d0c5c7b8236092de86d99068ce04511d5adbdd848ccf7c969dbf7338ca2050421d6c2c94571dfaaa135a4ff15bf916681ebd62c0e43e69e3b90684d0a0b00200000000000000",
"04203f117e549d8140c4bd97b3d8d73dfeaaa458491730e870e7fd4a3d472493c31c201dab0949ba4bae1d065b07b0b308e6a197e118f7614caab5f137ad66dfe6ab8e206a0fa2d0c5c7b8236092de86d99068ce04511d5adbdd848ccf7c969dbf7338ca207c3ea01a6e3a3d90cf59cd789e467044b5cd78eb2c84cc6816f960746d0e03ec0300000000000000",
"04203f117e549d8140c4bd97b3d8d73dfeaaa458491730e870e7fd4a3d472493c31c20197fda6b43eb91b445cf8a19541a6b064e9221cf6d43d67987d4cd0c646121e620022293d64836b72bc9d1ae36d6e115c8f7cf0a3f5e75d74059f69f81fd56142620f86748d40c5ee5f9a5644f2e7cf89aa5645e8a00d9e14d4fd193da0a23dd07f60400000000000000",
"04203f117e549d8140c4bd97b3d8d73dfeaaa458491730e870e7fd4a3d472493c31c20197fda6b43eb91b445cf8a19541a6b064e9221cf6d43d67987d4cd0c646121e620022293d64836b72bc9d1ae36d6e115c8f7cf0a3f5e75d74059f69f81fd56142620aaec63863aaa0b2e3b8009429bdddd455e59be6f40ccab887a32eb98723efc920500000000000000",
"04203f117e549d8140c4bd97b3d8d73dfeaaa458491730e870e7fd4a3d472493c31c20197fda6b43eb91b445cf8a19541a6b064e9221cf6d43d67987d4cd0c646121e62065d0fa354e4efa95de2eee9329f18bc7db58d03501471348bfdeca4554eb2e3420da1adda2ccde9381e11151686c121e7f52d19a990439161c7eb5a9f94be5a5910600000000000000",
"04203f117e549d8140c4bd97b3d8d73dfeaaa458491730e870e7fd4a3d472493c31c20197fda6b43eb91b445cf8a19541a6b064e9221cf6d43d67987d4cd0c646121e62065d0fa354e4efa95de2eee9329f18bc7db58d03501471348bfdeca4554eb2e3420bc8a5ec71647415c380203b681f7717366f3501661512225b6dc3e121efc0bae0700000000000000",
"04206eb318a627c0ff6ffcef86f2353dcec1c7a51aaea37aa43182020fc06c1df9da201dab0949ba4bae1d065b07b0b308e6a197e118f7614caab5f137ad66dfe6ab8e20cb37f4591361cd846141e7852c3726b37dd9b011cc55eef2ac931dfe769ff55a20225747f3b5d5dab4e5a424f81f85c904ff43286e0f3fd07ef0b8c6a627b114d80000000000000000",
"04206eb318a627c0ff6ffcef86f2353dcec1c7a51aaea37aa43182020fc06c1df9da201dab0949ba4bae1d065b07b0b308e6a197e118f7614caab5f137ad66dfe6ab8e20cb37f4591361cd846141e7852c3726b37dd9b011cc55eef2ac931dfe769ff55a20b02310f2e087e55bfd07ef5e242e3b87ee5d00c9ab52f61e6bd42542f93a6f550100000000000000",
"04206eb318a627c0ff6ffcef86f2353dcec1c7a51aaea37aa43182020fc06c1df9da201dab0949ba4bae1d065b07b0b308e6a197e118f7614caab5f137ad66dfe6ab8e206a0fa2d0c5c7b8236092de86d99068ce04511d5adbdd848ccf7c969dbf7338ca2050421d6c2c94571dfaaa135a4ff15bf916681ebd62c0e43e69e3b90684d0a0b00200000000000000",
"04206eb318a627c0ff6ffcef86f2353dcec1c7a51aaea37aa43182020fc06c1df9da201dab0949ba4bae1d065b07b0b308e6a197e118f7614caab5f137ad66dfe6ab8e206a0fa2d0c5c7b8236092de86d99068ce04511d5adbdd848ccf7c969dbf7338ca207c3ea01a6e3a3d90cf59cd789e467044b5cd78eb2c84cc6816f960746d0e03ec0300000000000000",
"04206eb318a627c0ff6ffcef86f2353dcec1c7a51aaea37aa43182020fc06c1df9da20197fda6b43eb91b445cf8a19541a6b064e9221cf6d43d67987d4cd0c646121e620022293d64836b72bc9d1ae36d6e115c8f7cf0a3f5e75d74059f69f81fd56142620f86748d40c5ee5f9a5644f2e7cf89aa5645e8a00d9e14d4fd193da0a23dd07f60400000000000000",
"04206eb318a627c0ff6ffcef86f2353dcec1c7a51aaea37aa43182020fc06c1df9da20197fda6b43eb91b445cf8a19541a6b064e9221cf6d43d67987d4cd0c646121e620022293d64836b72bc9d1ae36d6e115c8f7cf0a3f5e75d74059f69f81fd56142620aaec63863aaa0b2e3b8009429bdddd455e59be6f40ccab887a32eb98723efc920500000000000000",
"04206eb318a627c0ff6ffcef86f2353dcec1c7a51aaea37aa43182020fc06c1df9da20197fda6b43eb91b445cf8a19541a6b064e9221cf6d43d67987d4cd0c646121e62065d0fa354e4efa95de2eee9329f18bc7db58d03501471348bfdeca4554eb2e3420da1adda2ccde9381e11151686c121e7f52d19a990439161c7eb5a9f94be5a5910600000000000000",
"04206eb318a627c0ff6ffcef86f2353dcec1c7a51aaea37aa43182020fc06c1df9da20197fda6b43eb91b445cf8a19541a6b064e9221cf6d43d67987d4cd0c646121e62065d0fa354e4efa95de2eee9329f18bc7db58d03501471348bfdeca4554eb2e3420bc8a5ec71647415c380203b681f7717366f3501661512225b6dc3e121efc0bae0700000000000000",
"04206de08a5115fbf297232c7c9aa0f8cb78ee9a7fc467d0dfc1fe889f2f1e340ac4201f2610f0650d97f4ecde80d8dab101794631236623c51df290320b2a4c18c21620fe60df1ce575aaab663d158a20f9e560f7bdc5179f1527b3a33e4f587b44ffbc20c8ca8f7df7fd9979302f3885dcd9ab816e40f8d511a48ba0891b4460b2bd1d7c0800000000000000",
"042078bbb59b43ce3baff1db1248b4493bc9bd4dd6c1a3b62b1d0d0a5433b0abb648201dab0949ba4bae1d065b07b0b308e6a197e118f7614caab5f137ad66dfe6ab8e20cb37f4591361cd846141e7852c3726b37dd9b011cc55eef2ac931dfe769ff55a20225747f3b5d5dab4e5a424f81f85c904ff43286e0f3fd07ef0b8c6a627b114d80000000000000000",
"042078bbb59b43ce3baff1db1248b4493bc9bd4dd6c1a3b62b1d0d0a5433b0abb648201dab0949ba4bae1d065b07b0b308e6a197e118f7614caab5f137ad66dfe6ab8e20cb37f4591361cd846141e7852c3726b37dd9b011cc55eef2ac931dfe769ff55a20b02310f2e087e55bfd07ef5e242e3b87ee5d00c9ab52f61e6bd42542f93a6f550100000000000000",
"042078bbb59b43ce3baff1db1248b4493bc9bd4dd6c1a3b62b1d0d0a5433b0abb648201dab0949ba4bae1d065b07b0b308e6a197e118f7614caab5f137ad66dfe6ab8e206a0fa2d0c5c7b8236092de86d99068ce04511d5adbdd848ccf7c969dbf7338ca2050421d6c2c94571dfaaa135a4ff15bf916681ebd62c0e43e69e3b90684d0a0b00200000000000000",
"042078bbb59b43ce3baff1db1248b4493bc9bd4dd6c1a3b62b1d0d0a5433b0abb648201dab0949ba4bae1d065b07b0b308e6a197e118f7614caab5f137ad66dfe6ab8e206a0fa2d0c5c7b8236092de86d99068ce04511d5adbdd848ccf7c969dbf7338ca207c3ea01a6e3a3d90cf59cd789e467044b5cd78eb2c84cc6816f960746d0e03ec0300000000000000",
"042078bbb59b43ce3baff1db1248b4493bc9bd4dd6c1a3b62b1d0d0a5433b0abb64820197fda6b43eb91b445cf8a19541a6b064e9221cf6d43d67987d4cd0c646121e620022293d64836b72bc9d1ae36d6e115c8f7cf0a3f5e75d74059f69f81fd56142620f86748d40c5ee5f9a5644f2e7cf89aa5645e8a00d9e14d4fd193da0a23dd07f60400000000000000",
"042078bbb59b43ce3baff1db1248b4493bc9bd4dd6c1a3b62b1d0d0a5433b0abb64820197fda6b43eb91b445cf8a19541a6b064e9221cf6d43d67987d4cd0c646121e620022293d64836b72bc9d1ae36d6e115c8f7cf0a3f5e75d74059f69f81fd56142620aaec63863aaa0b2e3b8009429bdddd455e59be6f40ccab887a32eb98723efc920500000000000000",
"042078bbb59b43ce3baff1db1248b4493bc9bd4dd6c1a3b62b1d0d0a5433b0abb64820197fda6b43eb91b445cf8a19541a6b064e9221cf6d43d67987d4cd0c646121e62065d0fa354e4efa95de2eee9329f18bc7db58d03501471348bfdeca4554eb2e3420da1adda2ccde9381e11151686c121e7f52d19a990439161c7eb5a9f94be5a5910600000000000000",
"042078bbb59b43ce3baff1db1248b4493bc9bd4dd6c1a3b62b1d0d0a5433b0abb64820197fda6b43eb91b445cf8a19541a6b064e9221cf6d43d67987d4cd0c646121e62065d0fa354e4efa95de2eee9329f18bc7db58d03501471348bfdeca4554eb2e3420bc8a5ec71647415c380203b681f7717366f3501661512225b6dc3e121efc0bae0700000000000000",
"04206de08a5115fbf297232c7c9aa0f8cb78ee9a7fc467d0dfc1fe889f2f1e340ac4201f2610f0650d97f4ecde80d8dab101794631236623c51df290320b2a4c18c21620c91d1d80ecb6cd0be622f9c277c61d19530c86abcc673b93c279abd8384d787620c8ca8f7df7fd9979302f3885dcd9ab816e40f8d511a48ba0891b4460b2bd1d7c0800000000000000",
"04206de08a5115fbf297232c7c9aa0f8cb78ee9a7fc467d0dfc1fe889f2f1e340ac4201f2610f0650d97f4ecde80d8dab101794631236623c51df290320b2a4c18c21620c91d1d80ecb6cd0be622f9c277c61d19530c86abcc673b93c279abd8384d7876203a27fed5dbbc475d3880360e38638c882fd9b273b618fc433106896083f774c60900000000000000",
"04208c026cdb0a983dec0d6a34f397abc8f0839514454f87632ce6d8102c25d04260201dab0949ba4bae1d065b07b0b308e6a197e118f7614caab5f137ad66dfe6ab8e20cb37f4591361cd846141e7852c3726b37dd9b011cc55eef2ac931dfe769ff55a20225747f3b5d5dab4e5a424f81f85c904ff43286e0f3fd07ef0b8c6a627b114d80000000000000000",
"04208c026cdb0a983dec0d6a34f397abc8f0839514454f87632ce6d8102c25d04260201dab0949ba4bae1d065b07b0b308e6a197e118f7614caab5f137ad66dfe6ab8e20cb37f4591361cd846141e7852c3726b37dd9b011cc55eef2ac931dfe769ff55a20b02310f2e087e55bfd07ef5e242e3b87ee5d00c9ab52f61e6bd42542f93a6f550100000000000000",
"04208c026cdb0a983dec0d6a34f397abc8f0839514454f87632ce6d8102c25d04260201dab0949ba4bae1d065b07b0b308e6a197e118f7614caab5f137ad66dfe6ab8e206a0fa2d0c5c7b8236092de86d99068ce04511d5adbdd848ccf7c969dbf7338ca2050421d6c2c94571dfaaa135a4ff15bf916681ebd62c0e43e69e3b90684d0a0b00200000000000000",
"04208c026cdb0a983dec0d6a34f397abc8f0839514454f87632ce6d8102c25d04260201dab0949ba4bae1d065b07b0b308e6a197e118f7614caab5f137ad66dfe6ab8e206a0fa2d0c5c7b8236092de86d99068ce04511d5adbdd848ccf7c969dbf7338ca207c3ea01a6e3a3d90cf59cd789e467044b5cd78eb2c84cc6816f960746d0e03ec0300000000000000",
"04208c026cdb0a983dec0d6a34f397abc8f0839514454f87632ce6d8102c25d0426020197fda6b43eb91b445cf8a19541a6b064e9221cf6d43d67987d4cd0c646121e620022293d64836b72bc9d1ae36d6e115c8f7cf0a3f5e75d74059f69f81fd56142620f86748d40c5ee5f9a5644f2e7cf89aa5645e8a00d9e14d4fd193da0a23dd07f60400000000000000",
"04208c026cdb0a983dec0d6a34f397abc8f0839514454f87632ce6d8102c25d0426020197fda6b43eb91b445cf8a19541a6b064e9221cf6d43d67987d4cd0c646121e620022293d64836b72bc9d1ae36d6e115c8f7cf0a3f5e75d74059f69f81fd56142620aaec63863aaa0b2e3b8009429bdddd455e59be6f40ccab887a32eb98723efc920500000000000000",
"04208c026cdb0a983dec0d6a34f397abc8f0839514454f87632ce6d8102c25d0426020197fda6b43eb91b445cf8a19541a6b064e9221cf6d43d67987d4cd0c646121e62065d0fa354e4efa95de2eee9329f18bc7db58d03501471348bfdeca4554eb2e3420da1adda2ccde9381e11151686c121e7f52d19a990439161c7eb5a9f94be5a5910600000000000000",
"04208c026cdb0a983dec0d6a34f397abc8f0839514454f87632ce6d8102c25d0426020197fda6b43eb91b445cf8a19541a6b064e9221cf6d43d67987d4cd0c646121e62065d0fa354e4efa95de2eee9329f18bc7db58d03501471348bfdeca4554eb2e3420bc8a5ec71647415c380203b681f7717366f3501661512225b6dc3e121efc0bae0700000000000000",
"04206de08a5115fbf297232c7c9aa0f8cb78ee9a7fc467d0dfc1fe889f2f1e340ac4201f2610f0650d97f4ecde80d8dab101794631236623c51df290320b2a4c18c21620e184db737209fe4b1277cca58b2e6b52c35d3bd71e990ffe0115c4f6bbfa381020c8ca8f7df7fd9979302f3885dcd9ab816e40f8d511a48ba0891b4460b2bd1d7c0800000000000000",
"04206de08a5115fbf297232c7c9aa0f8cb78ee9a7fc467d0dfc1fe889f2f1e340ac4201f2610f0650d97f4ecde80d8dab101794631236623c51df290320b2a4c18c21620e184db737209fe4b1277cca58b2e6b52c35d3bd71e990ffe0115c4f6bbfa3810203a27fed5dbbc475d3880360e38638c882fd9b273b618fc433106896083f774c60900000000000000",
"04206de08a5115fbf297232c7c9aa0f8cb78ee9a7fc467d0dfc1fe889f2f1e340ac4201f2610f0650d97f4ecde80d8dab101794631236623c51df290320b2a4c18c216201be5b76ecb233cd650efcff47cd0be43056324a78a48a97df7faec851bc7dcda20e6d4d7685894d01b32f7e081ab188930be6c2b9f76d6847b7f382e3dddd7c6080a00000000000000",
"0420677c207a1612b09f2e5d38d372d6e6358bc7223a6c7da695d602501e7a01033c201dab0949ba4bae1d065b07b0b308e6a197e118f7614caab5f137ad66dfe6ab8e20cb37f4591361cd846141e7852c3726b37dd9b011cc55eef2ac931dfe769ff55a20225747f3b5d5dab4e5a424f81f85c904ff43286e0f3fd07ef0b8c6a627b114d80000000000000000",
"0420677c207a1612b09f2e5d38d372d6e6358bc7223a6c7da695d602501e7a01033c201dab0949ba4bae1d065b07b0b308e6a197e118f7614caab5f137ad66dfe6ab8e20cb37f4591361cd846141e7852c3726b37dd9b011cc55eef2ac931dfe769ff55a20b02310f2e087e55bfd07ef5e242e3b87ee5d00c9ab52f61e6bd42542f93a6f550100000000000000",
"0420677c207a1612b09f2e5d38d372d6e6358bc7223a6c7da695d602501e7a01033c201dab0949ba4bae1d065b07b0b308e6a197e118f7614caab5f137ad66dfe6ab8e206a0fa2d0c5c7b8236092de86d99068ce04511d5adbdd848ccf7c969dbf7338ca2050421d6c2c94571dfaaa135a4ff15bf916681ebd62c0e43e69e3b90684d0a0b00200000000000000",
"0420677c207a1612b09f2e5d38d372d6e6358bc7223a6c7da695d602501e7a01033c201dab0949ba4bae1d065b07b0b308e6a197e118f7614caab5f137ad66dfe6ab8e206a0fa2d0c5c7b8236092de86d99068ce04511d5adbdd848ccf7c969dbf7338ca207c3ea01a6e3a3d90cf59cd789e467044b5cd78eb2c84cc6816f960746d0e03ec0300000000000000",
"0420677c207a1612b09f2e5d38d372d6e6358bc7223a6c7da695d602501e7a01033c20197fda6b43eb91b445cf8a19541a6b064e9221cf6d43d67987d4cd0c646121e620022293d64836b72bc9d1ae36d6e115c8f7cf0a3f5e75d74059f69f81fd56142620f86748d40c5ee5f9a5644f2e7cf89aa5645e8a00d9e14d4fd193da0a23dd07f60400000000000000",
"0420677c207a1612b09f2e5d38d372d6e6358bc7223a6c7da695d602501e7a01033c20197fda6b43eb91b445cf8a19541a6b064e9221cf6d43d67987d4cd0c646121e620022293d64836b72bc9d1ae36d6e115c8f7cf0a3f5e75d74059f69f81fd56142620aaec63863aaa0b2e3b8009429bdddd455e59be6f40ccab887a32eb98723efc920500000000000000",
"0420677c207a1612b09f2e5d38d372d6e6358bc7223a6c7da695d602501e7a01033c20197fda6b43eb91b445cf8a19541a6b064e9221cf6d43d67987d4cd0c646121e62065d0fa354e4efa95de2eee9329f18bc7db58d03501471348bfdeca4554eb2e3420da1adda2ccde9381e11151686c121e7f52d19a990439161c7eb5a9f94be5a5910600000000000000",
"0420677c207a1612b09f2e5d38d372d6e6358bc7223a6c7da695d602501e7a01033c20197fda6b43eb91b445cf8a19541a6b064e9221cf6d43d67987d4cd0c646121e62065d0fa354e4efa95de2eee9329f18bc7db58d03501471348bfdeca4554eb2e3420bc8a5ec71647415c380203b681f7717366f3501661512225b6dc3e121efc0bae0700000000000000",
"04206de08a5115fbf297232c7c9aa0f8cb78ee9a7fc467d0dfc1fe889f2f1e340ac4207417b3f92f30771c261160269f694ec7c14b21cf14e01735460e9e9b47f6dffc20e184db737209fe4b1277cca58b2e6b52c35d3bd71e990ffe0115c4f6bbfa381020c8ca8f7df7fd9979302f3885dcd9ab816e40f8d511a48ba0891b4460b2bd1d7c0800000000000000",
"04206de08a5115fbf297232c7c9aa0f8cb78ee9a7fc467d0dfc1fe889f2f1e340ac4207417b3f92f30771c261160269f694ec7c14b21cf14e01735460e9e9b47f6dffc20e184db737209fe4b1277cca58b2e6b52c35d3bd71e990ffe0115c4f6bbfa3810203a27fed5dbbc475d3880360e38638c882fd9b273b618fc433106896083f774c60900000000000000",
"04206de08a5115fbf297232c7c9aa0f8cb78ee9a7fc467d0dfc1fe889f2f1e340ac4207417b3f92f30771c261160269f694ec7c14b21cf14e01735460e9e9b47f6dffc201be5b76ecb233cd650efcff47cd0be43056324a78a48a97df7faec851bc7dcda20e6d4d7685894d01b32f7e081ab188930be6c2b9f76d6847b7f382e3dddd7c6080a00000000000000",
"04206de08a5115fbf297232c7c9aa0f8cb78ee9a7fc467d0dfc1fe889f2f1e340ac4207417b3f92f30771c261160269f694ec7c14b21cf14e01735460e9e9b47f6dffc201be5b76ecb233cd650efcff47cd0be43056324a78a48a97df7faec851bc7dcda20f0fa37e8063b139d342246142fc48e7c0c50d0a62c97768589e06466742c37020b00000000000000",
"042020307a3cff449ca02018e525dbd37e2180b023dbe68ffbff1218f0f1149f12c4201dab0949ba4bae1d065b07b0b308e6a197e118f7614caab5f137ad66dfe6ab8e20cb37f4591361cd846141e7852c3726b37dd9b011cc55eef2ac931dfe769ff55a20225747f3b5d5dab4e5a424f81f85c904ff43286e0f3fd07ef0b8c6a627b114d80000000000000000",
"042020307a3cff449ca02018e525dbd37e2180b023dbe68ffbff1218f0f1149f12c4201dab0949ba4bae1d065b07b0b308e6a197e118f7614caab5f137ad66dfe6ab8e20cb37f4591361cd846141e7852c3726b37dd9b011cc55eef2ac931dfe769ff55a20b02310f2e087e55bfd07ef5e242e3b87ee5d00c9ab52f61e6bd42542f93a6f550100000000000000",
"042020307a3cff449ca02018e525dbd37e2180b023dbe68ffbff1218f0f1149f12c4201dab0949ba4bae1d065b07b0b308e6a197e118f7614caab5f137ad66dfe6ab8e206a0fa2d0c5c7b8236092de86d99068ce04511d5adbdd848ccf7c969dbf7338ca2050421d6c2c94571dfaaa135a4ff15bf916681ebd62c0e43e69e3b90684d0a0b00200000000000000",
"042020307a3cff449ca02018e525dbd37e2180b023dbe68ffbff1218f0f1149f12c4201dab0949ba4bae1d065b07b0b308e6a197e118f7614caab5f137ad66dfe6ab8e206a0fa2d0c5c7b8236092de86d99068ce04511d5adbdd848ccf7c969dbf7338ca207c3ea01a6e3a3d90cf59cd789e467044b5cd78eb2c84cc6816f960746d0e03ec0300000000000000",
"042020307a3cff449ca02018e525dbd37e2180b023dbe68ffbff1218f0f1149f12c420197fda6b43eb91b445cf8a19541a6b064e9221cf6d43d67987d4cd0c646121e620022293d64836b72bc9d1ae36d6e115c8f7cf0a3f5e75d74059f69f81fd56142620f86748d40c5ee5f9a5644f2e7cf89aa5645e8a00d9e14d4fd193da0a23dd07f60400000000000000",
"042020307a3cff449ca02018e525dbd37e2180b023dbe68ffbff1218f0f1149f12c420197fda6b43eb91b445cf8a19541a6b064e9221cf6d43d67987d4cd0c646121e620022293d64836b72bc9d1ae36d6e115c8f7cf0a3f5e75d74059f69f81fd56142620aaec63863aaa0b2e3b8009429bdddd455e59be6f40ccab887a32eb98723efc920500000000000000",
"042020307a3cff449ca02018e525dbd37e2180b023dbe68ffbff1218f0f1149f12c420197fda6b43eb91b445cf8a19541a6b064e9221cf6d43d67987d4cd0c646121e62065d0fa354e4efa95de2eee9329f18bc7db58d03501471348bfdeca4554eb2e3420da1adda2ccde9381e11151686c121e7f52d19a990439161c7eb5a9f94be5a5910600000000000000",
"042020307a3cff449ca02018e525dbd37e2180b023dbe68ffbff1218f0f1149f12c420197fda6b43eb91b445cf8a19541a6b064e9221cf6d43d67987d4cd0c646121e62065d0fa354e4efa95de2eee9329f18bc7db58d03501471348bfdeca4554eb2e3420bc8a5ec71647415c380203b681f7717366f3501661512225b6dc3e121efc0bae0700000000000000",
"04206de08a5115fbf297232c7c9aa0f8cb78ee9a7fc467d0dfc1fe889f2f1e340ac4201ef29413a2eb9b0aea89d61def9e74f61453bc5b8a2799e86020ec1468c71c7820e184db737209fe4b1277cca58b2e6b52c35d3bd71e990ffe0115c4f6bbfa381020c8ca8f7df7fd9979302f3885dcd9ab816e40f8d511a48ba0891b4460b2bd1d7c0800000000000000",
"04206de08a5115fbf297232c7c9aa0f8cb78ee9a7fc467d0dfc1fe889f2f1e340ac4201ef29413a2eb9b0aea89d61def9e74f61453bc5b8a2799e86020ec1468c71c7820e184db737209fe4b1277cca58b2e6b52c35d3bd71e990ffe0115c4f6bbfa3810203a27fed5dbbc475d3880360e38638c882fd9b273b618fc433106896083f774c60900000000000000",
"04206de08a5115fbf297232c7c9aa0f8cb78ee9a7fc467d0dfc1fe889f2f1e340ac4201ef29413a2eb9b0aea89d61def9e74f61453bc5b8a2799e86020ec1468c71c78201be5b76ecb233cd650efcff47cd0be43056324a78a48a97df7faec851bc7dcda20e6d4d7685894d01b32f7e081ab188930be6c2b9f76d6847b7f382e3dddd7c6080a00000000000000",
"04206de08a5115fbf297232c7c9aa0f8cb78ee9a7fc467d0dfc1fe889f2f1e340ac4201ef29413a2eb9b0aea89d61def9e74f61453bc5b8a2799e86020ec1468c71c78201be5b76ecb233cd650efcff47cd0be43056324a78a48a97df7faec851bc7dcda20f0fa37e8063b139d342246142fc48e7c0c50d0a62c97768589e06466742c37020b00000000000000",
"04206de08a5115fbf297232c7c9aa0f8cb78ee9a7fc467d0dfc1fe889f2f1e340ac420d04e93b1b3d6620676e56be7175514ebf0bc03a7f5571403d4547e691102b78a20fe60df1ce575aaab663d158a20f9e560f7bdc5179f1527b3a33e4f587b44ffbc2022fab8bcdb88154dbf5877ad1e2d7f1b541bc8a5ec1b52266095381339c27c830c00000000000000",
"04207493b4b9a35a32120f630e420efc048a71c0d73d6910561e8ba6076e37694636201dab0949ba4bae1d065b07b0b308e6a197e118f7614caab5f137ad66dfe6ab8e20cb37f4591361cd846141e7852c3726b37dd9b011cc55eef2ac931dfe769ff55a20225747f3b5d5dab4e5a424f81f85c904ff43286e0f3fd07ef0b8c6a627b114d80000000000000000",
"04207493b4b9a35a32120f630e420efc048a71c0d73d6910561e8ba6076e37694636201dab0949ba4bae1d065b07b0b308e6a197e118f7614caab5f137ad66dfe6ab8e20cb37f4591361cd846141e7852c3726b37dd9b011cc55eef2ac931dfe769ff55a20b02310f2e087e55bfd07ef5e242e3b87ee5d00c9ab52f61e6bd42542f93a6f550100000000000000",
"04207493b4b9a35a32120f630e420efc048a71c0d73d6910561e8ba6076e37694636201dab0949ba4bae1d065b07b0b308e6a197e118f7614caab5f137ad66dfe6ab8e206a0fa2d0c5c7b8236092de86d99068ce04511d5adbdd848ccf7c969dbf7338ca2050421d6c2c94571dfaaa135a4ff15bf916681ebd62c0e43e69e3b90684d0a0b00200000000000000",
"04207493b4b9a35a32120f630e420efc048a71c0d73d6910561e8ba6076e37694636201dab0949ba4bae1d065b07b0b308e6a197e118f7614caab5f137ad66dfe6ab8e206a0fa2d0c5c7b8236092de86d99068ce04511d5adbdd848ccf7c969dbf7338ca207c3ea01a6e3a3d90cf59cd789e467044b5cd78eb2c84cc6816f960746d0e03ec0300000000000000",
"04207493b4b9a35a32120f630e420efc048a71c0d73d6910561e8ba6076e3769463620197fda6b43eb91b445cf8a19541a6b064e9221cf6d43d67987d4cd0c646121e620022293d64836b72bc9d1ae36d6e115c8f7cf0a3f5e75d74059f69f81fd56142620f86748d40c5ee5f9a5644f2e7cf89aa5645e8a00d9e14d4fd193da0a23dd07f60400000000000000",
"04207493b4b9a35a32120f630e420efc048a71c0d73d6910561e8ba6076e3769463620197fda6b43eb91b445cf8a19541a6b064e9221cf6d43d67987d4cd0c646121e620022293d64836b72bc9d1ae36d6e115c8f7cf0a3f5e75d74059f69f81fd56142620aaec63863aaa0b2e3b8009429bdddd455e59be6f40ccab887a32eb98723efc920500000000000000",
"04207493b4b9a35a32120f630e420efc048a71c0d73d6910561e8ba6076e3769463620197fda6b43eb91b445cf8a19541a6b064e9221cf6d43d67987d4cd0c646121e62065d0fa354e4efa95de2eee9329f18bc7db58d03501471348bfdeca4554eb2e3420da1adda2ccde9381e11151686c121e7f52d19a990439161c7eb5a9f94be5a5910600000000000000",
"04207493b4b9a35a32120f630e420efc048a71c0d73d6910561e8ba6076e3769463620197fda6b43eb91b445cf8a19541a6b064e9221cf6d43d67987d4cd0c646121e62065d0fa354e4efa95de2eee9329f18bc7db58d03501471348bfdeca4554eb2e3420bc8a5ec71647415c380203b681f7717366f3501661512225b6dc3e121efc0bae0700000000000000",
"04206de08a5115fbf297232c7c9aa0f8cb78ee9a7fc467d0dfc1fe889f2f1e340ac4209c308bfafdf79fafdad22d765cdc484c4c3360878d2de6d3cd95069a9db58c6a20e184db737209fe4b1277cca58b2e6b52c35d3bd71e990ffe0115c4f6bbfa381020c8ca8f7df7fd9979302f3885dcd9ab816e40f8d511a48ba0891b4460b2bd1d7c0800000000000000",
"04206de08a5115fbf297232c7c9aa0f8cb78ee9a7fc467d0dfc1fe889f2f1e340ac4209c308bfafdf79fafdad22d765cdc484c4c3360878d2de6d3cd95069a9db58c6a20e184db737209fe4b1277cca58b2e6b52c35d3bd71e990ffe0115c4f6bbfa3810203a27fed5dbbc475d3880360e38638c882fd9b273b618fc433106896083f774c60900000000000000",
"04206de08a5115fbf297232c7c9aa0f8cb78ee9a7fc467d0dfc1fe889f2f1e340ac4209c308bfafdf79fafdad22d765cdc484c4c3360878d2de6d3cd95069a9db58c6a201be5b76ecb233cd650efcff47cd0be43056324a78a48a97df7faec851bc7dcda20e6d4d7685894d01b32f7e081ab188930be6c2b9f76d6847b7f382e3dddd7c6080a00000000000000",
"04206de08a5115fbf297232c7c9aa0f8cb78ee9a7fc467d0dfc1fe889f2f1e340ac4209c308bfafdf79fafdad22d765cdc484c4c3360878d2de6d3cd95069a9db58c6a201be5b76ecb233cd650efcff47cd0be43056324a78a48a97df7faec851bc7dcda20f0fa37e8063b139d342246142fc48e7c0c50d0a62c97768589e06466742c37020b00000000000000",
"04206de08a5115fbf297232c7c9aa0f8cb78ee9a7fc467d0dfc1fe889f2f1e340ac420d04e93b1b3d6620676e56be7175514ebf0bc03a7f5571403d4547e691102b78a2024714e547866d846699654cf8ffa6245589f518fc575a833966236cd38ce2a0a2022fab8bcdb88154dbf5877ad1e2d7f1b541bc8a5ec1b52266095381339c27c830c00000000000000",
"04206de08a5115fbf297232c7c9aa0f8cb78ee9a7fc467d0dfc1fe889f2f1e340ac420d04e93b1b3d6620676e56be7175514ebf0bc03a7f5571403d4547e691102b78a2024714e547866d846699654cf8ffa6245589f518fc575a833966236cd38ce2a0a208cebb73be883466d18d3b0c06990520e80b936440a2c9fd184d92a1f06c4e8a60d00000000000000",
"0420920d71bf7104c10b4d780495bb772e8d44a507dbf616963a1b3d2410c9d40800201dab0949ba4bae1d065b07b0b308e6a197e118f7614caab5f137ad66dfe6ab8e20cb37f4591361cd846141e7852c3726b37dd9b011cc55eef2ac931dfe769ff55a20225747f3b5d5dab4e5a424f81f85c904ff43286e0f3fd07ef0b8c6a627b114d80000000000000000",
"0420920d71bf7104c10b4d780495bb772e8d44a507dbf616963a1b3d2410c9d40800201dab0949ba4bae1d065b07b0b308e6a197e118f7614caab5f137ad66dfe6ab8e20cb37f4591361cd846141e7852c3726b37dd9b011cc55eef2ac931dfe769ff55a20b02310f2e087e55bfd07ef5e242e3b87ee5d00c9ab52f61e6bd42542f93a6f550100000000000000",
"0420920d71bf7104c10b4d780495bb772e8d44a507dbf616963a1b3d2410c9d40800201dab0949ba4bae1d065b07b0b308e6a197e118f7614caab5f137ad66dfe6ab8e206a0fa2d0c5c7b8236092de86d99068ce04511d5adbdd848ccf7c969dbf7338ca2050421d6c2c94571dfaaa135a4ff15bf916681ebd62c0e43e69e3b90684d0a0b00200000000000000",
"0420920d71bf7104c10b4d780495bb772e8d44a507dbf616963a1b3d2410c9d40800201dab0949ba4bae1d065b07b0b308e6a197e118f7614caab5f137ad66dfe6ab8e206a0fa2d0c5c7b8236092de86d99068ce04511d5adbdd848ccf7c969dbf7338ca207c3ea01a6e3a3d90cf59cd789e467044b5cd78eb2c84cc6816f960746d0e03ec0300000000000000",
"0420920d71bf7104c10b4d780495bb772e8d44a507dbf616963a1b3d2410c9d4080020197fda6b43eb91b445cf8a19541a6b064e9221cf6d43d67987d4cd0c646121e620022293d64836b72bc9d1ae36d6e115c8f7cf0a3f5e75d74059f69f81fd56142620f86748d40c5ee5f9a5644f2e7cf89aa5645e8a00d9e14d4fd193da0a23dd07f60400000000000000",
"0420920d71bf7104c10b4d780495bb772e8d44a507dbf616963a1b3d2410c9d4080020197fda6b43eb91b445cf8a19541a6b064e9221cf6d43d67987d4cd0c646121e620022293d64836b72bc9d1ae36d6e115c8f7cf0a3f5e75d74059f69f81fd56142620aaec63863aaa0b2e3b8009429bdddd455e59be6f40ccab887a32eb98723efc920500000000000000",
"0420920d71bf7104c10b4d780495bb772e8d44a507dbf616963a1b3d2410c9d4080020197fda6b43eb91b445cf8a19541a6b064e9221cf6d43d67987d4cd0c646121e62065d0fa354e4efa95de2eee9329f18bc7db58d03501471348bfdeca4554eb2e3420da1adda2ccde9381e11151686c121e7f52d19a990439161c7eb5a9f94be5a5910600000000000000",
"0420920d71bf7104c10b4d780495bb772e8d44a507dbf616963a1b3d2410c9d4080020197fda6b43eb91b445cf8a19541a6b064e9221cf6d43d67987d4cd0c646121e62065d0fa354e4efa95de2eee9329f18bc7db58d03501471348bfdeca4554eb2e3420bc8a5ec71647415c380203b681f7717366f3501661512225b6dc3e121efc0bae0700000000000000",
"04206de08a5115fbf297232c7c9aa0f8cb78ee9a7fc467d0dfc1fe889f2f1e340ac4208850ac1e804fc8f724dc410aded78f99e07c18000e4bc97458d1c8b6357eae0220e184db737209fe4b1277cca58b2e6b52c35d3bd71e990ffe0115c4f6bbfa381020c8ca8f7df7fd9979302f3885dcd9ab816e40f8d511a48ba0891b4460b2bd1d7c0800000000000000",
"04206de08a5115fbf297232c7c9aa0f8cb78ee9a7fc467d0dfc1fe889f2f1e340ac4208850ac1e804fc8f724dc410aded78f99e07c18000e4bc97458d1c8b6357eae0220e184db737209fe4b1277cca58b2e6b52c35d3bd71e990ffe0115c4f6bbfa3810203a27fed5dbbc475d3880360e38638c882fd9b273b618fc433106896083f774c60900000000000000",
"04206de08a5115fbf297232c7c9aa0f8cb78ee9a7fc467d0dfc1fe889f2f1e340ac4208850ac1e804fc8f724dc410aded78f99e07c18000e4bc97458d1c8b6357eae02201be5b76ecb233cd650efcff47cd0be43056324a78a48a97df7faec851bc7dcda20e6d4d7685894d01b32f7e081ab188930be6c2b9f76d6847b7f382e3dddd7c6080a00000000000000",
"04206de08a5115fbf297232c7c9aa0f8cb78ee9a7fc467d0dfc1fe889f2f1e340ac4208850ac1e804fc8f724dc410aded78f99e07c18000e4bc97458d1c8b6357eae02201be5b76ecb233cd650efcff47cd0be43056324a78a48a97df7faec851bc7dcda20f0fa37e8063b139d342246142fc48e7c0c50d0a62c97768589e06466742c37020b00000000000000",
"04206de08a5115fbf297232c7c9aa0f8cb78ee9a7fc467d0dfc1fe889f2f1e340ac420d04e93b1b3d6620676e56be7175514ebf0bc03a7f5571403d4547e691102b78a20bbb52416fefd25274a8a4e9513319cd7b85fa96244796ff402755618d717a1b02022fab8bcdb88154dbf5877ad1e2d7f1b541bc8a5ec1b52266095381339c27c830c00000000000000",
"04206de08a5115fbf297232c7c9aa0f8cb78ee9a7fc467d0dfc1fe889f2f1e340ac420d04e93b1b3d6620676e56be7175514ebf0bc03a7f5571403d4547e691102b78a20bbb52416fefd25274a8a4e9513319cd7b85fa96244796ff402755618d717a1b0208cebb73be883466d18d3b0c06990520e80b936440a2c9fd184d92a1f06c4e8a60d00000000000000",
"04206de08a5115fbf297232c7c9aa0f8cb78ee9a7fc467d0dfc1fe889f2f1e340ac420d04e93b1b3d6620676e56be7175514ebf0bc03a7f5571403d4547e691102b78a206ceafae082a15d1b4eb70e9eb7a880e5ee2e3d1d04bfdcc03dd73ed2571c6b8e203a3661bc12b72646c94bc6c92796e81953985ee62d80a9ec3645a9a95740ac150e00000000000000"
]

View File

@ -0,0 +1,65 @@
[
"8000000000000000000000000000000000000000000000000000000000000000",
"fe60df1ce575aaab663d158a20f9e560f7bdc5179f1527b3a33e4f587b44ffbc",
"1f2610f0650d97f4ecde80d8dab101794631236623c51df290320b2a4c18c216",
"c22d0dcb70b0a84c3440f839a64c9e5259066fff49f6c96a2068bb7fa70ff096",
"52e5469fe719b6afe793c04001a3d92b5af5fcfdf8ba48be2b525ba2db9bf512",
"30560b31aabdc42d32187b57a8c5ed1a0705f0c4079c04fe0c2b70c86612664a",
"056aa19504cf135de6edce4385c447a52888e39dc3816dd29ce85e5cc47d1fd4",
"ff80c661d1fc13591c8d94bd5e5b479efda5ad4e4dc2c232e2c0861903abe716",
"daf8231d59386bd3e9251f010bbe38f44c52275364582f0a1e37200e743e3d56",
"bf14721cc3074ed98066b6eb5f4d83d4a19194915d82ea17e84769d42a62d432",
"7e032b38db8a2e7f9656907f6f74fb7dda94f1d9738c602fbf088d96ac531fc4",
"125abf9164a1f289b4c500c1d871fc88be31c05ad18fd2d96aec2666ed4b70e8",
"69fdd736cce22c44a1050f58fbf4d97db711161302615f46a3d2376a7fdcf556",
"f183596d48ace7d5fe015614c0e466853552cd0badfe4a7e06e387768810b734",
"cd2470c445ae60707986368f7d9db4b34215fb07f6f589677e620c2f42e5840a",
"dcd9f71637d61be27d7b0d0dccd89f9d83de33125b398a686fd05b7eed566026",
"b0152c9b87ce45a02011ed82bbbfce63fb25ae48dbd8cda2fb8cb88d5c2e45c2",
"171bdcbad563410aa9b04ba1fc735151417d450413ae6beef96132bf7310804c",
"a543382d65c96824096b2e625070c7304e2a178a2652a3f0b802bcd9b6ba9f34",
"7f1b88575e956c7332291accb93c9ec53807ca3f511c7699b0bed7b220625112",
"aab00f50fa8f16823bcb954c390ea36950d1e155d19b3cd654781892ac9f1b18",
"73896fbbeea33cf50e1983c24b9395637bcbd1aae6a80675118e1fcc34c4999c",
"e198373975b7953b97d3a105146035492b85dc846f23fe027badd917707b5750",
"e8cede5b9bd42b85d0b188c252bcd3e51c0347b9da6d467d46c0d084db29049c",
"a16cfc7bd8c30be41d110dfc3dd924b05c6b8760e9383a032ef171b2b48ee376",
"448eafd2ff159deae09074cac05dad691b583720c32cf832a16d3d476727bab0",
"5b695b68bd8aa44169d65cdba5ba214cbfb7acf3be934cc147884416ee976ea6",
"41443e9afbf3289a9249f8234ce1f5d2f39ad80e6bf2251d5f4f41bdaf74fe78",
"97c3ab5715d6abd6bdca6854005b6937445b2e13b9adc9dcb6088e9e09681e54",
"9a892c8bfb1327c1f0080b9df0a00ccc5d80e9097c552ef877dec16d68b2a2fc",
"116b047f5a11972b57b36f67e06b3afc010f50e97e6621d744a82dabc7da770a",
"885d2752a3eea80578daff0d588b06077ad1301de5e87209b0714d36d68ab22a",
"6aaf09bcfd27e7ac76aa8fdc74768c0115efa036be11288af89e2ee1cd197742",
"97594310912cc3bcb754e3ba8a60ed8d0f50652475c5bd654191c8faee138ab8",
"a7738d727058a69732e6b75036b321395a4c03b5fa8c482434e03642d6eda2a6",
"c3844d5cd1311e13cb78bf621c93aca5981d03caa7c156310e8c3297878eeb8a",
"798c68f9549fadaffa21b6e557c1c5ead3d16d2db3ac3de7f29cfe2f351e2436",
"87b16cdd406cde2693803894071336fb9efbff101fec12c3bec481190ad22b3a",
"6055d5f60d1b202ab6d7a8e2f63fe434e1c2e389262a82e27b31ed07565f60f4",
"6bfbf247dc13e36239738575bafe5cc13fe5b2f505f870f65262101ede3233e8",
"57c269b80810b91891cf716e1857bf53826545e00f79ba4f8b915a2fd6267c38",
"896bc8135fe0783b54e28817e3c7bbc8bfccd1e022a41465f9c201dab1e42ff2",
"40d35aff33fb5e8c384d4c8252b41f71e9d423a548967a09c4f91f3eef2c38c8",
"2803400ed4bad786302917a17420f69e1fbcd23ec296eb6c199911b3c3dcd8fc",
"5bbef9832cec827a42a152cfd890822866063a96b59507573b1a8c2beb3d0bcc",
"71ad975ec2e034795969eeb387c342140c036b34c972011d34fa040a229df3f8",
"53de2c90267917af80d36fd051cdc89e00182a625c466571028aafdec64d79e0",
"9f713993500d3fa1cd16358624a6aa45ad11e479b5c340d09ff5f40e5a35127c",
"054ef1a5769d76af58eb30f0f1c73cd7bac9638fd92cb677ea1e78fba89e1396",
"45d831a19c20a00dface52b15acea0ea2d5cde27e165939d0fe4b9ff4544f618",
"ab33f64bb9c0cd54682f6c4fd6bf4a5e702f3f2f8484e4ebb8f2417ff2ba9260",
"e4cce49ee7b2685d29e29b079f2eafb0bc4ad8c135bb6b37563bc8e92a5dc2bc",
"75629b841de3fabb0798f802797d5384c0b828485d8056c4b1c58d39fefe881c",
"38ea6af92304ca8ed7c57f50a1578722d096df4cba1bd225c79377a2a1fbab3c",
"f300ab0bf7fe78c2f73da8d557a75a89d9c0b0176375d94b69be97af52bb74f2",
"23854c956b5f6ae2ca6b4b64311b62887913b911e65affe4383ff8c8e6387258",
"390b494667d4ada2da0d41d3ff9980cb20326d2c2c348ad6c4a4fbe1ecbad82c",
"b35578a91591060f7b8869f4cfbeb4e7e7b7b2cb62994e26fa7815aaa4811278",
"af7b7d4bf7952008f95387b59366d8730a35b33103d1e59ae3bf37dae1fe3e3a",
"24ba940af944e3d1d0e43a72d7c15694e52f6b0c084f0ed677f4836346d7285a",
"406a0b8e00cb09cef5159d952c01a531d03fdc3026f75ca21429ddc0c924642a",
"87999570ec0ae957e5052c3e3d37a7146ffc8a5cdbd57ebc9862a9e239943222",
"aff7851ce8e5ba4047cc539bcc1b2df062b8b571efeeb49ea023d3433bae8246"
]

View File

@ -0,0 +1,18 @@
[
"d550175b5487e5ee74fc74703306b372ca50d6a0adc18e3ce5f7aed5951a641c",
"cfa1dadc77cf65b09e19100c26570c80520844167e926bc0314e9d6730c93626",
"7a1afdd852818faae15aed1d36970fadc57ef44c32d8052194549471e2dfd0d8",
"4a649f3597a687b4e254d064c18cd08419424d208abb8e8b7abf46abcdc8492a",
"bd8b624aea2a2883762ff07e0944943542a7de14d6fe9da7c0e2afe55c0da306",
"0daf0cd2fc50eee569b90d94421e78b27f0a2f598c1a833a350c6c075cc4bba2",
"c6f383f0a8fa5127262e2b7602c87a65e4ed9a80aab2f6ee5df6a33fa78a3298",
"d1ae9b7370c5892bfa669915aecade849b01e36689b36bbe1fa46846edacbff0",
"0823f19e48c98093c43b455723b04eb047d2bdebcfbdd22ece8f68cc26ee0b70",
"541d51b310300abd11032f0fbc9dfa389f653e884a81016a3ab482ff30d64420",
"82a9f0ffcf811b98c5ffc4e29acda3d7e5b7834faecc7624bbb2985b949a506a",
"32dbec464312bbf6b5cfaabe5fd913168e27f08f1bae5bd9ec67436c0376b34c",
"12402e3a518b911712e5bcc16ff90ab22bcb6aa6d2aa7100e359b2b6e20bf3aa",
"03ae56fee9cfe40e369d9204402b0b0c7b64c18fbd08abbef8d245cbeaafadb6",
"c99c2d22235998b9f1b34f7b35657294da004c860cea4946f9e143843f837b9c",
"d59c6ef4a7083993049e034fee53bf770c5c7cfd0b9491b1aca2c6471a316dca"
]

View File

@ -0,0 +1,18 @@
[
"01b02310f2e087e55bfd07ef5e242e3b87ee5d00c9ab52f61e6bd42542f93a6f550000",
"01b02310f2e087e55bfd07ef5e242e3b87ee5d00c9ab52f61e6bd42542f93a6f5501225747f3b5d5dab4e5a424f81f85c904ff43286e0f3fd07ef0b8c6a627b114d800",
"017c3ea01a6e3a3d90cf59cd789e467044b5cd78eb2c84cc6816f960746d0e03ec0001016a0fa2d0c5c7b8236092de86d99068ce04511d5adbdd848ccf7c969dbf7338ca",
"017c3ea01a6e3a3d90cf59cd789e467044b5cd78eb2c84cc6816f960746d0e03ec0150421d6c2c94571dfaaa135a4ff15bf916681ebd62c0e43e69e3b90684d0a0b001016a0fa2d0c5c7b8236092de86d99068ce04511d5adbdd848ccf7c969dbf7338ca",
"01aaec63863aaa0b2e3b8009429bdddd455e59be6f40ccab887a32eb98723efc9200020001197fda6b43eb91b445cf8a19541a6b064e9221cf6d43d67987d4cd0c646121e6",
"01aaec63863aaa0b2e3b8009429bdddd455e59be6f40ccab887a32eb98723efc9201f86748d40c5ee5f9a5644f2e7cf89aa5645e8a00d9e14d4fd193da0a23dd07f6020001197fda6b43eb91b445cf8a19541a6b064e9221cf6d43d67987d4cd0c646121e6",
"01bc8a5ec71647415c380203b681f7717366f3501661512225b6dc3e121efc0bae00020165d0fa354e4efa95de2eee9329f18bc7db58d03501471348bfdeca4554eb2e3401197fda6b43eb91b445cf8a19541a6b064e9221cf6d43d67987d4cd0c646121e6",
"01bc8a5ec71647415c380203b681f7717366f3501661512225b6dc3e121efc0bae01da1adda2ccde9381e11151686c121e7f52d19a990439161c7eb5a9f94be5a591020165d0fa354e4efa95de2eee9329f18bc7db58d03501471348bfdeca4554eb2e3401197fda6b43eb91b445cf8a19541a6b064e9221cf6d43d67987d4cd0c646121e6",
"013a27fed5dbbc475d3880360e38638c882fd9b273b618fc433106896083f774c600030000016de08a5115fbf297232c7c9aa0f8cb78ee9a7fc467d0dfc1fe889f2f1e340ac4",
"013a27fed5dbbc475d3880360e38638c882fd9b273b618fc433106896083f774c601c8ca8f7df7fd9979302f3885dcd9ab816e40f8d511a48ba0891b4460b2bd1d7c030000016de08a5115fbf297232c7c9aa0f8cb78ee9a7fc467d0dfc1fe889f2f1e340ac4",
"01f0fa37e8063b139d342246142fc48e7c0c50d0a62c97768589e06466742c37020003011be5b76ecb233cd650efcff47cd0be43056324a78a48a97df7faec851bc7dcda00016de08a5115fbf297232c7c9aa0f8cb78ee9a7fc467d0dfc1fe889f2f1e340ac4",
"01f0fa37e8063b139d342246142fc48e7c0c50d0a62c97768589e06466742c370201e6d4d7685894d01b32f7e081ab188930be6c2b9f76d6847b7f382e3dddd7c60803011be5b76ecb233cd650efcff47cd0be43056324a78a48a97df7faec851bc7dcda00016de08a5115fbf297232c7c9aa0f8cb78ee9a7fc467d0dfc1fe889f2f1e340ac4",
"018cebb73be883466d18d3b0c06990520e80b936440a2c9fd184d92a1f06c4e8a600030001d04e93b1b3d6620676e56be7175514ebf0bc03a7f5571403d4547e691102b78a016de08a5115fbf297232c7c9aa0f8cb78ee9a7fc467d0dfc1fe889f2f1e340ac4",
"018cebb73be883466d18d3b0c06990520e80b936440a2c9fd184d92a1f06c4e8a60122fab8bcdb88154dbf5877ad1e2d7f1b541bc8a5ec1b52266095381339c27c83030001d04e93b1b3d6620676e56be7175514ebf0bc03a7f5571403d4547e691102b78a016de08a5115fbf297232c7c9aa0f8cb78ee9a7fc467d0dfc1fe889f2f1e340ac4",
"01f43e3aac61e5a753062d4d0508c26ceaf5e4c0c58ba3c956e104b5d2cf67c41c0003016ceafae082a15d1b4eb70e9eb7a880e5ee2e3d1d04bfdcc03dd73ed2571c6b8e01d04e93b1b3d6620676e56be7175514ebf0bc03a7f5571403d4547e691102b78a016de08a5115fbf297232c7c9aa0f8cb78ee9a7fc467d0dfc1fe889f2f1e340ac4",
"01f43e3aac61e5a753062d4d0508c26ceaf5e4c0c58ba3c956e104b5d2cf67c41c013a3661bc12b72646c94bc6c92796e81953985ee62d80a9ec3645a9a95740ac1503016ceafae082a15d1b4eb70e9eb7a880e5ee2e3d1d04bfdcc03dd73ed2571c6b8e01d04e93b1b3d6620676e56be7175514ebf0bc03a7f5571403d4547e691102b78a016de08a5115fbf297232c7c9aa0f8cb78ee9a7fc467d0dfc1fe889f2f1e340ac4"
]

View File

@ -0,0 +1,138 @@
[
"00000001b02310f2e087e55bfd07ef5e242e3b87ee5d00c9ab52f61e6bd42542f93a6f5500",
"00000002b02310f2e087e55bfd07ef5e242e3b87ee5d00c9ab52f61e6bd42542f93a6f55225747f3b5d5dab4e5a424f81f85c904ff43286e0f3fd07ef0b8c6a627b114d800",
"01b02310f2e087e55bfd07ef5e242e3b87ee5d00c9ab52f61e6bd42542f93a6f55000001225747f3b5d5dab4e5a424f81f85c904ff43286e0f3fd07ef0b8c6a627b114d800",
"00000002b02310f2e087e55bfd07ef5e242e3b87ee5d00c9ab52f61e6bd42542f93a6f55225747f3b5d5dab4e5a424f81f85c904ff43286e0f3fd07ef0b8c6a627b114d801017c3ea01a6e3a3d90cf59cd789e467044b5cd78eb2c84cc6816f960746d0e03ec0000",
"01b02310f2e087e55bfd07ef5e242e3b87ee5d00c9ab52f61e6bd42542f93a6f55000001225747f3b5d5dab4e5a424f81f85c904ff43286e0f3fd07ef0b8c6a627b114d801017c3ea01a6e3a3d90cf59cd789e467044b5cd78eb2c84cc6816f960746d0e03ec0000",
"01b02310f2e087e55bfd07ef5e242e3b87ee5d00c9ab52f61e6bd42542f93a6f5501225747f3b5d5dab4e5a424f81f85c904ff43286e0f3fd07ef0b8c6a627b114d8000001017c3ea01a6e3a3d90cf59cd789e467044b5cd78eb2c84cc6816f960746d0e03ec0000",
"00000003b02310f2e087e55bfd07ef5e242e3b87ee5d00c9ab52f61e6bd42542f93a6f55225747f3b5d5dab4e5a424f81f85c904ff43286e0f3fd07ef0b8c6a627b114d8cb37f4591361cd846141e7852c3726b37dd9b011cc55eef2ac931dfe769ff55a00",
"01b02310f2e087e55bfd07ef5e242e3b87ee5d00c9ab52f61e6bd42542f93a6f55000002225747f3b5d5dab4e5a424f81f85c904ff43286e0f3fd07ef0b8c6a627b114d8cb37f4591361cd846141e7852c3726b37dd9b011cc55eef2ac931dfe769ff55a00",
"01b02310f2e087e55bfd07ef5e242e3b87ee5d00c9ab52f61e6bd42542f93a6f5501225747f3b5d5dab4e5a424f81f85c904ff43286e0f3fd07ef0b8c6a627b114d80001cb37f4591361cd846141e7852c3726b37dd9b011cc55eef2ac931dfe769ff55a00",
"017c3ea01a6e3a3d90cf59cd789e467044b5cd78eb2c84cc6816f960746d0e03ec0001016a0fa2d0c5c7b8236092de86d99068ce04511d5adbdd848ccf7c969dbf7338ca0150421d6c2c94571dfaaa135a4ff15bf916681ebd62c0e43e69e3b90684d0a0b000",
"00000003b02310f2e087e55bfd07ef5e242e3b87ee5d00c9ab52f61e6bd42542f93a6f55225747f3b5d5dab4e5a424f81f85c904ff43286e0f3fd07ef0b8c6a627b114d8cb37f4591361cd846141e7852c3726b37dd9b011cc55eef2ac931dfe769ff55a0101aaec63863aaa0b2e3b8009429bdddd455e59be6f40ccab887a32eb98723efc920000",
"01b02310f2e087e55bfd07ef5e242e3b87ee5d00c9ab52f61e6bd42542f93a6f55000002225747f3b5d5dab4e5a424f81f85c904ff43286e0f3fd07ef0b8c6a627b114d8cb37f4591361cd846141e7852c3726b37dd9b011cc55eef2ac931dfe769ff55a0101aaec63863aaa0b2e3b8009429bdddd455e59be6f40ccab887a32eb98723efc920000",
"01b02310f2e087e55bfd07ef5e242e3b87ee5d00c9ab52f61e6bd42542f93a6f5501225747f3b5d5dab4e5a424f81f85c904ff43286e0f3fd07ef0b8c6a627b114d80001cb37f4591361cd846141e7852c3726b37dd9b011cc55eef2ac931dfe769ff55a0101aaec63863aaa0b2e3b8009429bdddd455e59be6f40ccab887a32eb98723efc920000",
"017c3ea01a6e3a3d90cf59cd789e467044b5cd78eb2c84cc6816f960746d0e03ec0001016a0fa2d0c5c7b8236092de86d99068ce04511d5adbdd848ccf7c969dbf7338ca0150421d6c2c94571dfaaa135a4ff15bf916681ebd62c0e43e69e3b90684d0a0b00101aaec63863aaa0b2e3b8009429bdddd455e59be6f40ccab887a32eb98723efc920000",
"017c3ea01a6e3a3d90cf59cd789e467044b5cd78eb2c84cc6816f960746d0e03ec0150421d6c2c94571dfaaa135a4ff15bf916681ebd62c0e43e69e3b90684d0a0b001016a0fa2d0c5c7b8236092de86d99068ce04511d5adbdd848ccf7c969dbf7338ca000101aaec63863aaa0b2e3b8009429bdddd455e59be6f40ccab887a32eb98723efc920000",
"00000003b02310f2e087e55bfd07ef5e242e3b87ee5d00c9ab52f61e6bd42542f93a6f55225747f3b5d5dab4e5a424f81f85c904ff43286e0f3fd07ef0b8c6a627b114d8cb37f4591361cd846141e7852c3726b37dd9b011cc55eef2ac931dfe769ff55a0101aaec63863aaa0b2e3b8009429bdddd455e59be6f40ccab887a32eb98723efc9201f86748d40c5ee5f9a5644f2e7cf89aa5645e8a00d9e14d4fd193da0a23dd07f600",
"01b02310f2e087e55bfd07ef5e242e3b87ee5d00c9ab52f61e6bd42542f93a6f55000002225747f3b5d5dab4e5a424f81f85c904ff43286e0f3fd07ef0b8c6a627b114d8cb37f4591361cd846141e7852c3726b37dd9b011cc55eef2ac931dfe769ff55a0101aaec63863aaa0b2e3b8009429bdddd455e59be6f40ccab887a32eb98723efc9201f86748d40c5ee5f9a5644f2e7cf89aa5645e8a00d9e14d4fd193da0a23dd07f600",
"01b02310f2e087e55bfd07ef5e242e3b87ee5d00c9ab52f61e6bd42542f93a6f5501225747f3b5d5dab4e5a424f81f85c904ff43286e0f3fd07ef0b8c6a627b114d80001cb37f4591361cd846141e7852c3726b37dd9b011cc55eef2ac931dfe769ff55a0101aaec63863aaa0b2e3b8009429bdddd455e59be6f40ccab887a32eb98723efc9201f86748d40c5ee5f9a5644f2e7cf89aa5645e8a00d9e14d4fd193da0a23dd07f600",
"017c3ea01a6e3a3d90cf59cd789e467044b5cd78eb2c84cc6816f960746d0e03ec0001016a0fa2d0c5c7b8236092de86d99068ce04511d5adbdd848ccf7c969dbf7338ca0150421d6c2c94571dfaaa135a4ff15bf916681ebd62c0e43e69e3b90684d0a0b00101aaec63863aaa0b2e3b8009429bdddd455e59be6f40ccab887a32eb98723efc9201f86748d40c5ee5f9a5644f2e7cf89aa5645e8a00d9e14d4fd193da0a23dd07f600",
"017c3ea01a6e3a3d90cf59cd789e467044b5cd78eb2c84cc6816f960746d0e03ec0150421d6c2c94571dfaaa135a4ff15bf916681ebd62c0e43e69e3b90684d0a0b001016a0fa2d0c5c7b8236092de86d99068ce04511d5adbdd848ccf7c969dbf7338ca000101aaec63863aaa0b2e3b8009429bdddd455e59be6f40ccab887a32eb98723efc9201f86748d40c5ee5f9a5644f2e7cf89aa5645e8a00d9e14d4fd193da0a23dd07f600",
"01aaec63863aaa0b2e3b8009429bdddd455e59be6f40ccab887a32eb98723efc9200020001197fda6b43eb91b445cf8a19541a6b064e9221cf6d43d67987d4cd0c646121e601f86748d40c5ee5f9a5644f2e7cf89aa5645e8a00d9e14d4fd193da0a23dd07f600",
"00000003b02310f2e087e55bfd07ef5e242e3b87ee5d00c9ab52f61e6bd42542f93a6f55225747f3b5d5dab4e5a424f81f85c904ff43286e0f3fd07ef0b8c6a627b114d8cb37f4591361cd846141e7852c3726b37dd9b011cc55eef2ac931dfe769ff55a0101bc8a5ec71647415c380203b681f7717366f3501661512225b6dc3e121efc0bae00010165d0fa354e4efa95de2eee9329f18bc7db58d03501471348bfdeca4554eb2e34",
"01b02310f2e087e55bfd07ef5e242e3b87ee5d00c9ab52f61e6bd42542f93a6f55000002225747f3b5d5dab4e5a424f81f85c904ff43286e0f3fd07ef0b8c6a627b114d8cb37f4591361cd846141e7852c3726b37dd9b011cc55eef2ac931dfe769ff55a0101bc8a5ec71647415c380203b681f7717366f3501661512225b6dc3e121efc0bae00010165d0fa354e4efa95de2eee9329f18bc7db58d03501471348bfdeca4554eb2e34",
"01b02310f2e087e55bfd07ef5e242e3b87ee5d00c9ab52f61e6bd42542f93a6f5501225747f3b5d5dab4e5a424f81f85c904ff43286e0f3fd07ef0b8c6a627b114d80001cb37f4591361cd846141e7852c3726b37dd9b011cc55eef2ac931dfe769ff55a0101bc8a5ec71647415c380203b681f7717366f3501661512225b6dc3e121efc0bae00010165d0fa354e4efa95de2eee9329f18bc7db58d03501471348bfdeca4554eb2e34",
"017c3ea01a6e3a3d90cf59cd789e467044b5cd78eb2c84cc6816f960746d0e03ec0001016a0fa2d0c5c7b8236092de86d99068ce04511d5adbdd848ccf7c969dbf7338ca0150421d6c2c94571dfaaa135a4ff15bf916681ebd62c0e43e69e3b90684d0a0b00101bc8a5ec71647415c380203b681f7717366f3501661512225b6dc3e121efc0bae00010165d0fa354e4efa95de2eee9329f18bc7db58d03501471348bfdeca4554eb2e34",
"017c3ea01a6e3a3d90cf59cd789e467044b5cd78eb2c84cc6816f960746d0e03ec0150421d6c2c94571dfaaa135a4ff15bf916681ebd62c0e43e69e3b90684d0a0b001016a0fa2d0c5c7b8236092de86d99068ce04511d5adbdd848ccf7c969dbf7338ca000101bc8a5ec71647415c380203b681f7717366f3501661512225b6dc3e121efc0bae00010165d0fa354e4efa95de2eee9329f18bc7db58d03501471348bfdeca4554eb2e34",
"01aaec63863aaa0b2e3b8009429bdddd455e59be6f40ccab887a32eb98723efc9200020001197fda6b43eb91b445cf8a19541a6b064e9221cf6d43d67987d4cd0c646121e601f86748d40c5ee5f9a5644f2e7cf89aa5645e8a00d9e14d4fd193da0a23dd07f60101bc8a5ec71647415c380203b681f7717366f3501661512225b6dc3e121efc0bae0000",
"01aaec63863aaa0b2e3b8009429bdddd455e59be6f40ccab887a32eb98723efc9201f86748d40c5ee5f9a5644f2e7cf89aa5645e8a00d9e14d4fd193da0a23dd07f6020001197fda6b43eb91b445cf8a19541a6b064e9221cf6d43d67987d4cd0c646121e6000101bc8a5ec71647415c380203b681f7717366f3501661512225b6dc3e121efc0bae0000",
"00000004b02310f2e087e55bfd07ef5e242e3b87ee5d00c9ab52f61e6bd42542f93a6f55225747f3b5d5dab4e5a424f81f85c904ff43286e0f3fd07ef0b8c6a627b114d8cb37f4591361cd846141e7852c3726b37dd9b011cc55eef2ac931dfe769ff55a1dab0949ba4bae1d065b07b0b308e6a197e118f7614caab5f137ad66dfe6ab8e00",
"01b02310f2e087e55bfd07ef5e242e3b87ee5d00c9ab52f61e6bd42542f93a6f55000003225747f3b5d5dab4e5a424f81f85c904ff43286e0f3fd07ef0b8c6a627b114d8cb37f4591361cd846141e7852c3726b37dd9b011cc55eef2ac931dfe769ff55a1dab0949ba4bae1d065b07b0b308e6a197e118f7614caab5f137ad66dfe6ab8e00",
"01b02310f2e087e55bfd07ef5e242e3b87ee5d00c9ab52f61e6bd42542f93a6f5501225747f3b5d5dab4e5a424f81f85c904ff43286e0f3fd07ef0b8c6a627b114d80002cb37f4591361cd846141e7852c3726b37dd9b011cc55eef2ac931dfe769ff55a1dab0949ba4bae1d065b07b0b308e6a197e118f7614caab5f137ad66dfe6ab8e00",
"017c3ea01a6e3a3d90cf59cd789e467044b5cd78eb2c84cc6816f960746d0e03ec0001016a0fa2d0c5c7b8236092de86d99068ce04511d5adbdd848ccf7c969dbf7338ca0250421d6c2c94571dfaaa135a4ff15bf916681ebd62c0e43e69e3b90684d0a0b01dab0949ba4bae1d065b07b0b308e6a197e118f7614caab5f137ad66dfe6ab8e00",
"017c3ea01a6e3a3d90cf59cd789e467044b5cd78eb2c84cc6816f960746d0e03ec0150421d6c2c94571dfaaa135a4ff15bf916681ebd62c0e43e69e3b90684d0a0b001016a0fa2d0c5c7b8236092de86d99068ce04511d5adbdd848ccf7c969dbf7338ca011dab0949ba4bae1d065b07b0b308e6a197e118f7614caab5f137ad66dfe6ab8e00",
"01aaec63863aaa0b2e3b8009429bdddd455e59be6f40ccab887a32eb98723efc9200020001197fda6b43eb91b445cf8a19541a6b064e9221cf6d43d67987d4cd0c646121e602f86748d40c5ee5f9a5644f2e7cf89aa5645e8a00d9e14d4fd193da0a23dd07f6022293d64836b72bc9d1ae36d6e115c8f7cf0a3f5e75d74059f69f81fd56142600",
"01aaec63863aaa0b2e3b8009429bdddd455e59be6f40ccab887a32eb98723efc9201f86748d40c5ee5f9a5644f2e7cf89aa5645e8a00d9e14d4fd193da0a23dd07f6020001197fda6b43eb91b445cf8a19541a6b064e9221cf6d43d67987d4cd0c646121e601022293d64836b72bc9d1ae36d6e115c8f7cf0a3f5e75d74059f69f81fd56142600",
"01bc8a5ec71647415c380203b681f7717366f3501661512225b6dc3e121efc0bae00020165d0fa354e4efa95de2eee9329f18bc7db58d03501471348bfdeca4554eb2e3401197fda6b43eb91b445cf8a19541a6b064e9221cf6d43d67987d4cd0c646121e601da1adda2ccde9381e11151686c121e7f52d19a990439161c7eb5a9f94be5a59100",
"00000004b02310f2e087e55bfd07ef5e242e3b87ee5d00c9ab52f61e6bd42542f93a6f55225747f3b5d5dab4e5a424f81f85c904ff43286e0f3fd07ef0b8c6a627b114d8cb37f4591361cd846141e7852c3726b37dd9b011cc55eef2ac931dfe769ff55a1dab0949ba4bae1d065b07b0b308e6a197e118f7614caab5f137ad66dfe6ab8e01013a27fed5dbbc475d3880360e38638c882fd9b273b618fc433106896083f774c60000",
"01b02310f2e087e55bfd07ef5e242e3b87ee5d00c9ab52f61e6bd42542f93a6f55000003225747f3b5d5dab4e5a424f81f85c904ff43286e0f3fd07ef0b8c6a627b114d8cb37f4591361cd846141e7852c3726b37dd9b011cc55eef2ac931dfe769ff55a1dab0949ba4bae1d065b07b0b308e6a197e118f7614caab5f137ad66dfe6ab8e01013a27fed5dbbc475d3880360e38638c882fd9b273b618fc433106896083f774c60000",
"01b02310f2e087e55bfd07ef5e242e3b87ee5d00c9ab52f61e6bd42542f93a6f5501225747f3b5d5dab4e5a424f81f85c904ff43286e0f3fd07ef0b8c6a627b114d80002cb37f4591361cd846141e7852c3726b37dd9b011cc55eef2ac931dfe769ff55a1dab0949ba4bae1d065b07b0b308e6a197e118f7614caab5f137ad66dfe6ab8e01013a27fed5dbbc475d3880360e38638c882fd9b273b618fc433106896083f774c60000",
"017c3ea01a6e3a3d90cf59cd789e467044b5cd78eb2c84cc6816f960746d0e03ec0001016a0fa2d0c5c7b8236092de86d99068ce04511d5adbdd848ccf7c969dbf7338ca0250421d6c2c94571dfaaa135a4ff15bf916681ebd62c0e43e69e3b90684d0a0b01dab0949ba4bae1d065b07b0b308e6a197e118f7614caab5f137ad66dfe6ab8e01013a27fed5dbbc475d3880360e38638c882fd9b273b618fc433106896083f774c60000",
"017c3ea01a6e3a3d90cf59cd789e467044b5cd78eb2c84cc6816f960746d0e03ec0150421d6c2c94571dfaaa135a4ff15bf916681ebd62c0e43e69e3b90684d0a0b001016a0fa2d0c5c7b8236092de86d99068ce04511d5adbdd848ccf7c969dbf7338ca011dab0949ba4bae1d065b07b0b308e6a197e118f7614caab5f137ad66dfe6ab8e01013a27fed5dbbc475d3880360e38638c882fd9b273b618fc433106896083f774c60000",
"01aaec63863aaa0b2e3b8009429bdddd455e59be6f40ccab887a32eb98723efc9200020001197fda6b43eb91b445cf8a19541a6b064e9221cf6d43d67987d4cd0c646121e602f86748d40c5ee5f9a5644f2e7cf89aa5645e8a00d9e14d4fd193da0a23dd07f6022293d64836b72bc9d1ae36d6e115c8f7cf0a3f5e75d74059f69f81fd56142601013a27fed5dbbc475d3880360e38638c882fd9b273b618fc433106896083f774c60000",
"01aaec63863aaa0b2e3b8009429bdddd455e59be6f40ccab887a32eb98723efc9201f86748d40c5ee5f9a5644f2e7cf89aa5645e8a00d9e14d4fd193da0a23dd07f6020001197fda6b43eb91b445cf8a19541a6b064e9221cf6d43d67987d4cd0c646121e601022293d64836b72bc9d1ae36d6e115c8f7cf0a3f5e75d74059f69f81fd56142601013a27fed5dbbc475d3880360e38638c882fd9b273b618fc433106896083f774c60000",
"01bc8a5ec71647415c380203b681f7717366f3501661512225b6dc3e121efc0bae00020165d0fa354e4efa95de2eee9329f18bc7db58d03501471348bfdeca4554eb2e3401197fda6b43eb91b445cf8a19541a6b064e9221cf6d43d67987d4cd0c646121e601da1adda2ccde9381e11151686c121e7f52d19a990439161c7eb5a9f94be5a59101013a27fed5dbbc475d3880360e38638c882fd9b273b618fc433106896083f774c60000",
"01bc8a5ec71647415c380203b681f7717366f3501661512225b6dc3e121efc0bae01da1adda2ccde9381e11151686c121e7f52d19a990439161c7eb5a9f94be5a591020165d0fa354e4efa95de2eee9329f18bc7db58d03501471348bfdeca4554eb2e3401197fda6b43eb91b445cf8a19541a6b064e9221cf6d43d67987d4cd0c646121e60001013a27fed5dbbc475d3880360e38638c882fd9b273b618fc433106896083f774c60000",
"00000004b02310f2e087e55bfd07ef5e242e3b87ee5d00c9ab52f61e6bd42542f93a6f55225747f3b5d5dab4e5a424f81f85c904ff43286e0f3fd07ef0b8c6a627b114d8cb37f4591361cd846141e7852c3726b37dd9b011cc55eef2ac931dfe769ff55a1dab0949ba4bae1d065b07b0b308e6a197e118f7614caab5f137ad66dfe6ab8e01013a27fed5dbbc475d3880360e38638c882fd9b273b618fc433106896083f774c601c8ca8f7df7fd9979302f3885dcd9ab816e40f8d511a48ba0891b4460b2bd1d7c00",
"01b02310f2e087e55bfd07ef5e242e3b87ee5d00c9ab52f61e6bd42542f93a6f55000003225747f3b5d5dab4e5a424f81f85c904ff43286e0f3fd07ef0b8c6a627b114d8cb37f4591361cd846141e7852c3726b37dd9b011cc55eef2ac931dfe769ff55a1dab0949ba4bae1d065b07b0b308e6a197e118f7614caab5f137ad66dfe6ab8e01013a27fed5dbbc475d3880360e38638c882fd9b273b618fc433106896083f774c601c8ca8f7df7fd9979302f3885dcd9ab816e40f8d511a48ba0891b4460b2bd1d7c00",
"01b02310f2e087e55bfd07ef5e242e3b87ee5d00c9ab52f61e6bd42542f93a6f5501225747f3b5d5dab4e5a424f81f85c904ff43286e0f3fd07ef0b8c6a627b114d80002cb37f4591361cd846141e7852c3726b37dd9b011cc55eef2ac931dfe769ff55a1dab0949ba4bae1d065b07b0b308e6a197e118f7614caab5f137ad66dfe6ab8e01013a27fed5dbbc475d3880360e38638c882fd9b273b618fc433106896083f774c601c8ca8f7df7fd9979302f3885dcd9ab816e40f8d511a48ba0891b4460b2bd1d7c00",
"017c3ea01a6e3a3d90cf59cd789e467044b5cd78eb2c84cc6816f960746d0e03ec0001016a0fa2d0c5c7b8236092de86d99068ce04511d5adbdd848ccf7c969dbf7338ca0250421d6c2c94571dfaaa135a4ff15bf916681ebd62c0e43e69e3b90684d0a0b01dab0949ba4bae1d065b07b0b308e6a197e118f7614caab5f137ad66dfe6ab8e01013a27fed5dbbc475d3880360e38638c882fd9b273b618fc433106896083f774c601c8ca8f7df7fd9979302f3885dcd9ab816e40f8d511a48ba0891b4460b2bd1d7c00",
"017c3ea01a6e3a3d90cf59cd789e467044b5cd78eb2c84cc6816f960746d0e03ec0150421d6c2c94571dfaaa135a4ff15bf916681ebd62c0e43e69e3b90684d0a0b001016a0fa2d0c5c7b8236092de86d99068ce04511d5adbdd848ccf7c969dbf7338ca011dab0949ba4bae1d065b07b0b308e6a197e118f7614caab5f137ad66dfe6ab8e01013a27fed5dbbc475d3880360e38638c882fd9b273b618fc433106896083f774c601c8ca8f7df7fd9979302f3885dcd9ab816e40f8d511a48ba0891b4460b2bd1d7c00",
"01aaec63863aaa0b2e3b8009429bdddd455e59be6f40ccab887a32eb98723efc9200020001197fda6b43eb91b445cf8a19541a6b064e9221cf6d43d67987d4cd0c646121e602f86748d40c5ee5f9a5644f2e7cf89aa5645e8a00d9e14d4fd193da0a23dd07f6022293d64836b72bc9d1ae36d6e115c8f7cf0a3f5e75d74059f69f81fd56142601013a27fed5dbbc475d3880360e38638c882fd9b273b618fc433106896083f774c601c8ca8f7df7fd9979302f3885dcd9ab816e40f8d511a48ba0891b4460b2bd1d7c00",
"01aaec63863aaa0b2e3b8009429bdddd455e59be6f40ccab887a32eb98723efc9201f86748d40c5ee5f9a5644f2e7cf89aa5645e8a00d9e14d4fd193da0a23dd07f6020001197fda6b43eb91b445cf8a19541a6b064e9221cf6d43d67987d4cd0c646121e601022293d64836b72bc9d1ae36d6e115c8f7cf0a3f5e75d74059f69f81fd56142601013a27fed5dbbc475d3880360e38638c882fd9b273b618fc433106896083f774c601c8ca8f7df7fd9979302f3885dcd9ab816e40f8d511a48ba0891b4460b2bd1d7c00",
"01bc8a5ec71647415c380203b681f7717366f3501661512225b6dc3e121efc0bae00020165d0fa354e4efa95de2eee9329f18bc7db58d03501471348bfdeca4554eb2e3401197fda6b43eb91b445cf8a19541a6b064e9221cf6d43d67987d4cd0c646121e601da1adda2ccde9381e11151686c121e7f52d19a990439161c7eb5a9f94be5a59101013a27fed5dbbc475d3880360e38638c882fd9b273b618fc433106896083f774c601c8ca8f7df7fd9979302f3885dcd9ab816e40f8d511a48ba0891b4460b2bd1d7c00",
"01bc8a5ec71647415c380203b681f7717366f3501661512225b6dc3e121efc0bae01da1adda2ccde9381e11151686c121e7f52d19a990439161c7eb5a9f94be5a591020165d0fa354e4efa95de2eee9329f18bc7db58d03501471348bfdeca4554eb2e3401197fda6b43eb91b445cf8a19541a6b064e9221cf6d43d67987d4cd0c646121e60001013a27fed5dbbc475d3880360e38638c882fd9b273b618fc433106896083f774c601c8ca8f7df7fd9979302f3885dcd9ab816e40f8d511a48ba0891b4460b2bd1d7c00",
"013a27fed5dbbc475d3880360e38638c882fd9b273b618fc433106896083f774c600030000016de08a5115fbf297232c7c9aa0f8cb78ee9a7fc467d0dfc1fe889f2f1e340ac401c8ca8f7df7fd9979302f3885dcd9ab816e40f8d511a48ba0891b4460b2bd1d7c00",
"00000004b02310f2e087e55bfd07ef5e242e3b87ee5d00c9ab52f61e6bd42542f93a6f55225747f3b5d5dab4e5a424f81f85c904ff43286e0f3fd07ef0b8c6a627b114d8cb37f4591361cd846141e7852c3726b37dd9b011cc55eef2ac931dfe769ff55a1dab0949ba4bae1d065b07b0b308e6a197e118f7614caab5f137ad66dfe6ab8e0101f0fa37e8063b139d342246142fc48e7c0c50d0a62c97768589e06466742c37020001011be5b76ecb233cd650efcff47cd0be43056324a78a48a97df7faec851bc7dcda",
"01b02310f2e087e55bfd07ef5e242e3b87ee5d00c9ab52f61e6bd42542f93a6f55000003225747f3b5d5dab4e5a424f81f85c904ff43286e0f3fd07ef0b8c6a627b114d8cb37f4591361cd846141e7852c3726b37dd9b011cc55eef2ac931dfe769ff55a1dab0949ba4bae1d065b07b0b308e6a197e118f7614caab5f137ad66dfe6ab8e0101f0fa37e8063b139d342246142fc48e7c0c50d0a62c97768589e06466742c37020001011be5b76ecb233cd650efcff47cd0be43056324a78a48a97df7faec851bc7dcda",
"01b02310f2e087e55bfd07ef5e242e3b87ee5d00c9ab52f61e6bd42542f93a6f5501225747f3b5d5dab4e5a424f81f85c904ff43286e0f3fd07ef0b8c6a627b114d80002cb37f4591361cd846141e7852c3726b37dd9b011cc55eef2ac931dfe769ff55a1dab0949ba4bae1d065b07b0b308e6a197e118f7614caab5f137ad66dfe6ab8e0101f0fa37e8063b139d342246142fc48e7c0c50d0a62c97768589e06466742c37020001011be5b76ecb233cd650efcff47cd0be43056324a78a48a97df7faec851bc7dcda",
"017c3ea01a6e3a3d90cf59cd789e467044b5cd78eb2c84cc6816f960746d0e03ec0001016a0fa2d0c5c7b8236092de86d99068ce04511d5adbdd848ccf7c969dbf7338ca0250421d6c2c94571dfaaa135a4ff15bf916681ebd62c0e43e69e3b90684d0a0b01dab0949ba4bae1d065b07b0b308e6a197e118f7614caab5f137ad66dfe6ab8e0101f0fa37e8063b139d342246142fc48e7c0c50d0a62c97768589e06466742c37020001011be5b76ecb233cd650efcff47cd0be43056324a78a48a97df7faec851bc7dcda",
"017c3ea01a6e3a3d90cf59cd789e467044b5cd78eb2c84cc6816f960746d0e03ec0150421d6c2c94571dfaaa135a4ff15bf916681ebd62c0e43e69e3b90684d0a0b001016a0fa2d0c5c7b8236092de86d99068ce04511d5adbdd848ccf7c969dbf7338ca011dab0949ba4bae1d065b07b0b308e6a197e118f7614caab5f137ad66dfe6ab8e0101f0fa37e8063b139d342246142fc48e7c0c50d0a62c97768589e06466742c37020001011be5b76ecb233cd650efcff47cd0be43056324a78a48a97df7faec851bc7dcda",
"01aaec63863aaa0b2e3b8009429bdddd455e59be6f40ccab887a32eb98723efc9200020001197fda6b43eb91b445cf8a19541a6b064e9221cf6d43d67987d4cd0c646121e602f86748d40c5ee5f9a5644f2e7cf89aa5645e8a00d9e14d4fd193da0a23dd07f6022293d64836b72bc9d1ae36d6e115c8f7cf0a3f5e75d74059f69f81fd5614260101f0fa37e8063b139d342246142fc48e7c0c50d0a62c97768589e06466742c37020001011be5b76ecb233cd650efcff47cd0be43056324a78a48a97df7faec851bc7dcda",
"01aaec63863aaa0b2e3b8009429bdddd455e59be6f40ccab887a32eb98723efc9201f86748d40c5ee5f9a5644f2e7cf89aa5645e8a00d9e14d4fd193da0a23dd07f6020001197fda6b43eb91b445cf8a19541a6b064e9221cf6d43d67987d4cd0c646121e601022293d64836b72bc9d1ae36d6e115c8f7cf0a3f5e75d74059f69f81fd5614260101f0fa37e8063b139d342246142fc48e7c0c50d0a62c97768589e06466742c37020001011be5b76ecb233cd650efcff47cd0be43056324a78a48a97df7faec851bc7dcda",
"01bc8a5ec71647415c380203b681f7717366f3501661512225b6dc3e121efc0bae00020165d0fa354e4efa95de2eee9329f18bc7db58d03501471348bfdeca4554eb2e3401197fda6b43eb91b445cf8a19541a6b064e9221cf6d43d67987d4cd0c646121e601da1adda2ccde9381e11151686c121e7f52d19a990439161c7eb5a9f94be5a5910101f0fa37e8063b139d342246142fc48e7c0c50d0a62c97768589e06466742c37020001011be5b76ecb233cd650efcff47cd0be43056324a78a48a97df7faec851bc7dcda",
"01bc8a5ec71647415c380203b681f7717366f3501661512225b6dc3e121efc0bae01da1adda2ccde9381e11151686c121e7f52d19a990439161c7eb5a9f94be5a591020165d0fa354e4efa95de2eee9329f18bc7db58d03501471348bfdeca4554eb2e3401197fda6b43eb91b445cf8a19541a6b064e9221cf6d43d67987d4cd0c646121e6000101f0fa37e8063b139d342246142fc48e7c0c50d0a62c97768589e06466742c37020001011be5b76ecb233cd650efcff47cd0be43056324a78a48a97df7faec851bc7dcda",
"013a27fed5dbbc475d3880360e38638c882fd9b273b618fc433106896083f774c600030000016de08a5115fbf297232c7c9aa0f8cb78ee9a7fc467d0dfc1fe889f2f1e340ac401c8ca8f7df7fd9979302f3885dcd9ab816e40f8d511a48ba0891b4460b2bd1d7c0101f0fa37e8063b139d342246142fc48e7c0c50d0a62c97768589e06466742c37020000",
"013a27fed5dbbc475d3880360e38638c882fd9b273b618fc433106896083f774c601c8ca8f7df7fd9979302f3885dcd9ab816e40f8d511a48ba0891b4460b2bd1d7c030000016de08a5115fbf297232c7c9aa0f8cb78ee9a7fc467d0dfc1fe889f2f1e340ac4000101f0fa37e8063b139d342246142fc48e7c0c50d0a62c97768589e06466742c37020000",
"00000004b02310f2e087e55bfd07ef5e242e3b87ee5d00c9ab52f61e6bd42542f93a6f55225747f3b5d5dab4e5a424f81f85c904ff43286e0f3fd07ef0b8c6a627b114d8cb37f4591361cd846141e7852c3726b37dd9b011cc55eef2ac931dfe769ff55a1dab0949ba4bae1d065b07b0b308e6a197e118f7614caab5f137ad66dfe6ab8e0101f0fa37e8063b139d342246142fc48e7c0c50d0a62c97768589e06466742c370201e6d4d7685894d01b32f7e081ab188930be6c2b9f76d6847b7f382e3dddd7c60801011be5b76ecb233cd650efcff47cd0be43056324a78a48a97df7faec851bc7dcda",
"01b02310f2e087e55bfd07ef5e242e3b87ee5d00c9ab52f61e6bd42542f93a6f55000003225747f3b5d5dab4e5a424f81f85c904ff43286e0f3fd07ef0b8c6a627b114d8cb37f4591361cd846141e7852c3726b37dd9b011cc55eef2ac931dfe769ff55a1dab0949ba4bae1d065b07b0b308e6a197e118f7614caab5f137ad66dfe6ab8e0101f0fa37e8063b139d342246142fc48e7c0c50d0a62c97768589e06466742c370201e6d4d7685894d01b32f7e081ab188930be6c2b9f76d6847b7f382e3dddd7c60801011be5b76ecb233cd650efcff47cd0be43056324a78a48a97df7faec851bc7dcda",
"01b02310f2e087e55bfd07ef5e242e3b87ee5d00c9ab52f61e6bd42542f93a6f5501225747f3b5d5dab4e5a424f81f85c904ff43286e0f3fd07ef0b8c6a627b114d80002cb37f4591361cd846141e7852c3726b37dd9b011cc55eef2ac931dfe769ff55a1dab0949ba4bae1d065b07b0b308e6a197e118f7614caab5f137ad66dfe6ab8e0101f0fa37e8063b139d342246142fc48e7c0c50d0a62c97768589e06466742c370201e6d4d7685894d01b32f7e081ab188930be6c2b9f76d6847b7f382e3dddd7c60801011be5b76ecb233cd650efcff47cd0be43056324a78a48a97df7faec851bc7dcda",
"017c3ea01a6e3a3d90cf59cd789e467044b5cd78eb2c84cc6816f960746d0e03ec0001016a0fa2d0c5c7b8236092de86d99068ce04511d5adbdd848ccf7c969dbf7338ca0250421d6c2c94571dfaaa135a4ff15bf916681ebd62c0e43e69e3b90684d0a0b01dab0949ba4bae1d065b07b0b308e6a197e118f7614caab5f137ad66dfe6ab8e0101f0fa37e8063b139d342246142fc48e7c0c50d0a62c97768589e06466742c370201e6d4d7685894d01b32f7e081ab188930be6c2b9f76d6847b7f382e3dddd7c60801011be5b76ecb233cd650efcff47cd0be43056324a78a48a97df7faec851bc7dcda",
"017c3ea01a6e3a3d90cf59cd789e467044b5cd78eb2c84cc6816f960746d0e03ec0150421d6c2c94571dfaaa135a4ff15bf916681ebd62c0e43e69e3b90684d0a0b001016a0fa2d0c5c7b8236092de86d99068ce04511d5adbdd848ccf7c969dbf7338ca011dab0949ba4bae1d065b07b0b308e6a197e118f7614caab5f137ad66dfe6ab8e0101f0fa37e8063b139d342246142fc48e7c0c50d0a62c97768589e06466742c370201e6d4d7685894d01b32f7e081ab188930be6c2b9f76d6847b7f382e3dddd7c60801011be5b76ecb233cd650efcff47cd0be43056324a78a48a97df7faec851bc7dcda",
"01aaec63863aaa0b2e3b8009429bdddd455e59be6f40ccab887a32eb98723efc9200020001197fda6b43eb91b445cf8a19541a6b064e9221cf6d43d67987d4cd0c646121e602f86748d40c5ee5f9a5644f2e7cf89aa5645e8a00d9e14d4fd193da0a23dd07f6022293d64836b72bc9d1ae36d6e115c8f7cf0a3f5e75d74059f69f81fd5614260101f0fa37e8063b139d342246142fc48e7c0c50d0a62c97768589e06466742c370201e6d4d7685894d01b32f7e081ab188930be6c2b9f76d6847b7f382e3dddd7c60801011be5b76ecb233cd650efcff47cd0be43056324a78a48a97df7faec851bc7dcda",
"01aaec63863aaa0b2e3b8009429bdddd455e59be6f40ccab887a32eb98723efc9201f86748d40c5ee5f9a5644f2e7cf89aa5645e8a00d9e14d4fd193da0a23dd07f6020001197fda6b43eb91b445cf8a19541a6b064e9221cf6d43d67987d4cd0c646121e601022293d64836b72bc9d1ae36d6e115c8f7cf0a3f5e75d74059f69f81fd5614260101f0fa37e8063b139d342246142fc48e7c0c50d0a62c97768589e06466742c370201e6d4d7685894d01b32f7e081ab188930be6c2b9f76d6847b7f382e3dddd7c60801011be5b76ecb233cd650efcff47cd0be43056324a78a48a97df7faec851bc7dcda",
"01bc8a5ec71647415c380203b681f7717366f3501661512225b6dc3e121efc0bae00020165d0fa354e4efa95de2eee9329f18bc7db58d03501471348bfdeca4554eb2e3401197fda6b43eb91b445cf8a19541a6b064e9221cf6d43d67987d4cd0c646121e601da1adda2ccde9381e11151686c121e7f52d19a990439161c7eb5a9f94be5a5910101f0fa37e8063b139d342246142fc48e7c0c50d0a62c97768589e06466742c370201e6d4d7685894d01b32f7e081ab188930be6c2b9f76d6847b7f382e3dddd7c60801011be5b76ecb233cd650efcff47cd0be43056324a78a48a97df7faec851bc7dcda",
"01bc8a5ec71647415c380203b681f7717366f3501661512225b6dc3e121efc0bae01da1adda2ccde9381e11151686c121e7f52d19a990439161c7eb5a9f94be5a591020165d0fa354e4efa95de2eee9329f18bc7db58d03501471348bfdeca4554eb2e3401197fda6b43eb91b445cf8a19541a6b064e9221cf6d43d67987d4cd0c646121e6000101f0fa37e8063b139d342246142fc48e7c0c50d0a62c97768589e06466742c370201e6d4d7685894d01b32f7e081ab188930be6c2b9f76d6847b7f382e3dddd7c60801011be5b76ecb233cd650efcff47cd0be43056324a78a48a97df7faec851bc7dcda",
"013a27fed5dbbc475d3880360e38638c882fd9b273b618fc433106896083f774c600030000016de08a5115fbf297232c7c9aa0f8cb78ee9a7fc467d0dfc1fe889f2f1e340ac402c8ca8f7df7fd9979302f3885dcd9ab816e40f8d511a48ba0891b4460b2bd1d7ce184db737209fe4b1277cca58b2e6b52c35d3bd71e990ffe0115c4f6bbfa381000",
"013a27fed5dbbc475d3880360e38638c882fd9b273b618fc433106896083f774c601c8ca8f7df7fd9979302f3885dcd9ab816e40f8d511a48ba0891b4460b2bd1d7c030000016de08a5115fbf297232c7c9aa0f8cb78ee9a7fc467d0dfc1fe889f2f1e340ac401e184db737209fe4b1277cca58b2e6b52c35d3bd71e990ffe0115c4f6bbfa381000",
"01f0fa37e8063b139d342246142fc48e7c0c50d0a62c97768589e06466742c37020003011be5b76ecb233cd650efcff47cd0be43056324a78a48a97df7faec851bc7dcda00016de08a5115fbf297232c7c9aa0f8cb78ee9a7fc467d0dfc1fe889f2f1e340ac401e6d4d7685894d01b32f7e081ab188930be6c2b9f76d6847b7f382e3dddd7c60800",
"00000004b02310f2e087e55bfd07ef5e242e3b87ee5d00c9ab52f61e6bd42542f93a6f55225747f3b5d5dab4e5a424f81f85c904ff43286e0f3fd07ef0b8c6a627b114d8cb37f4591361cd846141e7852c3726b37dd9b011cc55eef2ac931dfe769ff55a1dab0949ba4bae1d065b07b0b308e6a197e118f7614caab5f137ad66dfe6ab8e01018cebb73be883466d18d3b0c06990520e80b936440a2c9fd184d92a1f06c4e8a600020001d04e93b1b3d6620676e56be7175514ebf0bc03a7f5571403d4547e691102b78a",
"01b02310f2e087e55bfd07ef5e242e3b87ee5d00c9ab52f61e6bd42542f93a6f55000003225747f3b5d5dab4e5a424f81f85c904ff43286e0f3fd07ef0b8c6a627b114d8cb37f4591361cd846141e7852c3726b37dd9b011cc55eef2ac931dfe769ff55a1dab0949ba4bae1d065b07b0b308e6a197e118f7614caab5f137ad66dfe6ab8e01018cebb73be883466d18d3b0c06990520e80b936440a2c9fd184d92a1f06c4e8a600020001d04e93b1b3d6620676e56be7175514ebf0bc03a7f5571403d4547e691102b78a",
"01b02310f2e087e55bfd07ef5e242e3b87ee5d00c9ab52f61e6bd42542f93a6f5501225747f3b5d5dab4e5a424f81f85c904ff43286e0f3fd07ef0b8c6a627b114d80002cb37f4591361cd846141e7852c3726b37dd9b011cc55eef2ac931dfe769ff55a1dab0949ba4bae1d065b07b0b308e6a197e118f7614caab5f137ad66dfe6ab8e01018cebb73be883466d18d3b0c06990520e80b936440a2c9fd184d92a1f06c4e8a600020001d04e93b1b3d6620676e56be7175514ebf0bc03a7f5571403d4547e691102b78a",
"017c3ea01a6e3a3d90cf59cd789e467044b5cd78eb2c84cc6816f960746d0e03ec0001016a0fa2d0c5c7b8236092de86d99068ce04511d5adbdd848ccf7c969dbf7338ca0250421d6c2c94571dfaaa135a4ff15bf916681ebd62c0e43e69e3b90684d0a0b01dab0949ba4bae1d065b07b0b308e6a197e118f7614caab5f137ad66dfe6ab8e01018cebb73be883466d18d3b0c06990520e80b936440a2c9fd184d92a1f06c4e8a600020001d04e93b1b3d6620676e56be7175514ebf0bc03a7f5571403d4547e691102b78a",
"017c3ea01a6e3a3d90cf59cd789e467044b5cd78eb2c84cc6816f960746d0e03ec0150421d6c2c94571dfaaa135a4ff15bf916681ebd62c0e43e69e3b90684d0a0b001016a0fa2d0c5c7b8236092de86d99068ce04511d5adbdd848ccf7c969dbf7338ca011dab0949ba4bae1d065b07b0b308e6a197e118f7614caab5f137ad66dfe6ab8e01018cebb73be883466d18d3b0c06990520e80b936440a2c9fd184d92a1f06c4e8a600020001d04e93b1b3d6620676e56be7175514ebf0bc03a7f5571403d4547e691102b78a",
"01aaec63863aaa0b2e3b8009429bdddd455e59be6f40ccab887a32eb98723efc9200020001197fda6b43eb91b445cf8a19541a6b064e9221cf6d43d67987d4cd0c646121e602f86748d40c5ee5f9a5644f2e7cf89aa5645e8a00d9e14d4fd193da0a23dd07f6022293d64836b72bc9d1ae36d6e115c8f7cf0a3f5e75d74059f69f81fd56142601018cebb73be883466d18d3b0c06990520e80b936440a2c9fd184d92a1f06c4e8a600020001d04e93b1b3d6620676e56be7175514ebf0bc03a7f5571403d4547e691102b78a",
"01aaec63863aaa0b2e3b8009429bdddd455e59be6f40ccab887a32eb98723efc9201f86748d40c5ee5f9a5644f2e7cf89aa5645e8a00d9e14d4fd193da0a23dd07f6020001197fda6b43eb91b445cf8a19541a6b064e9221cf6d43d67987d4cd0c646121e601022293d64836b72bc9d1ae36d6e115c8f7cf0a3f5e75d74059f69f81fd56142601018cebb73be883466d18d3b0c06990520e80b936440a2c9fd184d92a1f06c4e8a600020001d04e93b1b3d6620676e56be7175514ebf0bc03a7f5571403d4547e691102b78a",
"01bc8a5ec71647415c380203b681f7717366f3501661512225b6dc3e121efc0bae00020165d0fa354e4efa95de2eee9329f18bc7db58d03501471348bfdeca4554eb2e3401197fda6b43eb91b445cf8a19541a6b064e9221cf6d43d67987d4cd0c646121e601da1adda2ccde9381e11151686c121e7f52d19a990439161c7eb5a9f94be5a59101018cebb73be883466d18d3b0c06990520e80b936440a2c9fd184d92a1f06c4e8a600020001d04e93b1b3d6620676e56be7175514ebf0bc03a7f5571403d4547e691102b78a",
"01bc8a5ec71647415c380203b681f7717366f3501661512225b6dc3e121efc0bae01da1adda2ccde9381e11151686c121e7f52d19a990439161c7eb5a9f94be5a591020165d0fa354e4efa95de2eee9329f18bc7db58d03501471348bfdeca4554eb2e3401197fda6b43eb91b445cf8a19541a6b064e9221cf6d43d67987d4cd0c646121e60001018cebb73be883466d18d3b0c06990520e80b936440a2c9fd184d92a1f06c4e8a600020001d04e93b1b3d6620676e56be7175514ebf0bc03a7f5571403d4547e691102b78a",
"013a27fed5dbbc475d3880360e38638c882fd9b273b618fc433106896083f774c600030000016de08a5115fbf297232c7c9aa0f8cb78ee9a7fc467d0dfc1fe889f2f1e340ac402c8ca8f7df7fd9979302f3885dcd9ab816e40f8d511a48ba0891b4460b2bd1d7ce184db737209fe4b1277cca58b2e6b52c35d3bd71e990ffe0115c4f6bbfa381001018cebb73be883466d18d3b0c06990520e80b936440a2c9fd184d92a1f06c4e8a60000",
"013a27fed5dbbc475d3880360e38638c882fd9b273b618fc433106896083f774c601c8ca8f7df7fd9979302f3885dcd9ab816e40f8d511a48ba0891b4460b2bd1d7c030000016de08a5115fbf297232c7c9aa0f8cb78ee9a7fc467d0dfc1fe889f2f1e340ac401e184db737209fe4b1277cca58b2e6b52c35d3bd71e990ffe0115c4f6bbfa381001018cebb73be883466d18d3b0c06990520e80b936440a2c9fd184d92a1f06c4e8a60000",
"01f0fa37e8063b139d342246142fc48e7c0c50d0a62c97768589e06466742c37020003011be5b76ecb233cd650efcff47cd0be43056324a78a48a97df7faec851bc7dcda00016de08a5115fbf297232c7c9aa0f8cb78ee9a7fc467d0dfc1fe889f2f1e340ac401e6d4d7685894d01b32f7e081ab188930be6c2b9f76d6847b7f382e3dddd7c60801018cebb73be883466d18d3b0c06990520e80b936440a2c9fd184d92a1f06c4e8a60000",
"01f0fa37e8063b139d342246142fc48e7c0c50d0a62c97768589e06466742c370201e6d4d7685894d01b32f7e081ab188930be6c2b9f76d6847b7f382e3dddd7c60803011be5b76ecb233cd650efcff47cd0be43056324a78a48a97df7faec851bc7dcda00016de08a5115fbf297232c7c9aa0f8cb78ee9a7fc467d0dfc1fe889f2f1e340ac40001018cebb73be883466d18d3b0c06990520e80b936440a2c9fd184d92a1f06c4e8a60000",
"00000004b02310f2e087e55bfd07ef5e242e3b87ee5d00c9ab52f61e6bd42542f93a6f55225747f3b5d5dab4e5a424f81f85c904ff43286e0f3fd07ef0b8c6a627b114d8cb37f4591361cd846141e7852c3726b37dd9b011cc55eef2ac931dfe769ff55a1dab0949ba4bae1d065b07b0b308e6a197e118f7614caab5f137ad66dfe6ab8e01018cebb73be883466d18d3b0c06990520e80b936440a2c9fd184d92a1f06c4e8a60122fab8bcdb88154dbf5877ad1e2d7f1b541bc8a5ec1b52266095381339c27c83020001d04e93b1b3d6620676e56be7175514ebf0bc03a7f5571403d4547e691102b78a",
"01b02310f2e087e55bfd07ef5e242e3b87ee5d00c9ab52f61e6bd42542f93a6f55000003225747f3b5d5dab4e5a424f81f85c904ff43286e0f3fd07ef0b8c6a627b114d8cb37f4591361cd846141e7852c3726b37dd9b011cc55eef2ac931dfe769ff55a1dab0949ba4bae1d065b07b0b308e6a197e118f7614caab5f137ad66dfe6ab8e01018cebb73be883466d18d3b0c06990520e80b936440a2c9fd184d92a1f06c4e8a60122fab8bcdb88154dbf5877ad1e2d7f1b541bc8a5ec1b52266095381339c27c83020001d04e93b1b3d6620676e56be7175514ebf0bc03a7f5571403d4547e691102b78a",
"01b02310f2e087e55bfd07ef5e242e3b87ee5d00c9ab52f61e6bd42542f93a6f5501225747f3b5d5dab4e5a424f81f85c904ff43286e0f3fd07ef0b8c6a627b114d80002cb37f4591361cd846141e7852c3726b37dd9b011cc55eef2ac931dfe769ff55a1dab0949ba4bae1d065b07b0b308e6a197e118f7614caab5f137ad66dfe6ab8e01018cebb73be883466d18d3b0c06990520e80b936440a2c9fd184d92a1f06c4e8a60122fab8bcdb88154dbf5877ad1e2d7f1b541bc8a5ec1b52266095381339c27c83020001d04e93b1b3d6620676e56be7175514ebf0bc03a7f5571403d4547e691102b78a",
"017c3ea01a6e3a3d90cf59cd789e467044b5cd78eb2c84cc6816f960746d0e03ec0001016a0fa2d0c5c7b8236092de86d99068ce04511d5adbdd848ccf7c969dbf7338ca0250421d6c2c94571dfaaa135a4ff15bf916681ebd62c0e43e69e3b90684d0a0b01dab0949ba4bae1d065b07b0b308e6a197e118f7614caab5f137ad66dfe6ab8e01018cebb73be883466d18d3b0c06990520e80b936440a2c9fd184d92a1f06c4e8a60122fab8bcdb88154dbf5877ad1e2d7f1b541bc8a5ec1b52266095381339c27c83020001d04e93b1b3d6620676e56be7175514ebf0bc03a7f5571403d4547e691102b78a",
"017c3ea01a6e3a3d90cf59cd789e467044b5cd78eb2c84cc6816f960746d0e03ec0150421d6c2c94571dfaaa135a4ff15bf916681ebd62c0e43e69e3b90684d0a0b001016a0fa2d0c5c7b8236092de86d99068ce04511d5adbdd848ccf7c969dbf7338ca011dab0949ba4bae1d065b07b0b308e6a197e118f7614caab5f137ad66dfe6ab8e01018cebb73be883466d18d3b0c06990520e80b936440a2c9fd184d92a1f06c4e8a60122fab8bcdb88154dbf5877ad1e2d7f1b541bc8a5ec1b52266095381339c27c83020001d04e93b1b3d6620676e56be7175514ebf0bc03a7f5571403d4547e691102b78a",
"01aaec63863aaa0b2e3b8009429bdddd455e59be6f40ccab887a32eb98723efc9200020001197fda6b43eb91b445cf8a19541a6b064e9221cf6d43d67987d4cd0c646121e602f86748d40c5ee5f9a5644f2e7cf89aa5645e8a00d9e14d4fd193da0a23dd07f6022293d64836b72bc9d1ae36d6e115c8f7cf0a3f5e75d74059f69f81fd56142601018cebb73be883466d18d3b0c06990520e80b936440a2c9fd184d92a1f06c4e8a60122fab8bcdb88154dbf5877ad1e2d7f1b541bc8a5ec1b52266095381339c27c83020001d04e93b1b3d6620676e56be7175514ebf0bc03a7f5571403d4547e691102b78a",
"01aaec63863aaa0b2e3b8009429bdddd455e59be6f40ccab887a32eb98723efc9201f86748d40c5ee5f9a5644f2e7cf89aa5645e8a00d9e14d4fd193da0a23dd07f6020001197fda6b43eb91b445cf8a19541a6b064e9221cf6d43d67987d4cd0c646121e601022293d64836b72bc9d1ae36d6e115c8f7cf0a3f5e75d74059f69f81fd56142601018cebb73be883466d18d3b0c06990520e80b936440a2c9fd184d92a1f06c4e8a60122fab8bcdb88154dbf5877ad1e2d7f1b541bc8a5ec1b52266095381339c27c83020001d04e93b1b3d6620676e56be7175514ebf0bc03a7f5571403d4547e691102b78a",
"01bc8a5ec71647415c380203b681f7717366f3501661512225b6dc3e121efc0bae00020165d0fa354e4efa95de2eee9329f18bc7db58d03501471348bfdeca4554eb2e3401197fda6b43eb91b445cf8a19541a6b064e9221cf6d43d67987d4cd0c646121e601da1adda2ccde9381e11151686c121e7f52d19a990439161c7eb5a9f94be5a59101018cebb73be883466d18d3b0c06990520e80b936440a2c9fd184d92a1f06c4e8a60122fab8bcdb88154dbf5877ad1e2d7f1b541bc8a5ec1b52266095381339c27c83020001d04e93b1b3d6620676e56be7175514ebf0bc03a7f5571403d4547e691102b78a",
"01bc8a5ec71647415c380203b681f7717366f3501661512225b6dc3e121efc0bae01da1adda2ccde9381e11151686c121e7f52d19a990439161c7eb5a9f94be5a591020165d0fa354e4efa95de2eee9329f18bc7db58d03501471348bfdeca4554eb2e3401197fda6b43eb91b445cf8a19541a6b064e9221cf6d43d67987d4cd0c646121e60001018cebb73be883466d18d3b0c06990520e80b936440a2c9fd184d92a1f06c4e8a60122fab8bcdb88154dbf5877ad1e2d7f1b541bc8a5ec1b52266095381339c27c83020001d04e93b1b3d6620676e56be7175514ebf0bc03a7f5571403d4547e691102b78a",
"013a27fed5dbbc475d3880360e38638c882fd9b273b618fc433106896083f774c600030000016de08a5115fbf297232c7c9aa0f8cb78ee9a7fc467d0dfc1fe889f2f1e340ac402c8ca8f7df7fd9979302f3885dcd9ab816e40f8d511a48ba0891b4460b2bd1d7ce184db737209fe4b1277cca58b2e6b52c35d3bd71e990ffe0115c4f6bbfa381001018cebb73be883466d18d3b0c06990520e80b936440a2c9fd184d92a1f06c4e8a60122fab8bcdb88154dbf5877ad1e2d7f1b541bc8a5ec1b52266095381339c27c8300",
"013a27fed5dbbc475d3880360e38638c882fd9b273b618fc433106896083f774c601c8ca8f7df7fd9979302f3885dcd9ab816e40f8d511a48ba0891b4460b2bd1d7c030000016de08a5115fbf297232c7c9aa0f8cb78ee9a7fc467d0dfc1fe889f2f1e340ac401e184db737209fe4b1277cca58b2e6b52c35d3bd71e990ffe0115c4f6bbfa381001018cebb73be883466d18d3b0c06990520e80b936440a2c9fd184d92a1f06c4e8a60122fab8bcdb88154dbf5877ad1e2d7f1b541bc8a5ec1b52266095381339c27c8300",
"01f0fa37e8063b139d342246142fc48e7c0c50d0a62c97768589e06466742c37020003011be5b76ecb233cd650efcff47cd0be43056324a78a48a97df7faec851bc7dcda00016de08a5115fbf297232c7c9aa0f8cb78ee9a7fc467d0dfc1fe889f2f1e340ac401e6d4d7685894d01b32f7e081ab188930be6c2b9f76d6847b7f382e3dddd7c60801018cebb73be883466d18d3b0c06990520e80b936440a2c9fd184d92a1f06c4e8a60122fab8bcdb88154dbf5877ad1e2d7f1b541bc8a5ec1b52266095381339c27c8300",
"01f0fa37e8063b139d342246142fc48e7c0c50d0a62c97768589e06466742c370201e6d4d7685894d01b32f7e081ab188930be6c2b9f76d6847b7f382e3dddd7c60803011be5b76ecb233cd650efcff47cd0be43056324a78a48a97df7faec851bc7dcda00016de08a5115fbf297232c7c9aa0f8cb78ee9a7fc467d0dfc1fe889f2f1e340ac40001018cebb73be883466d18d3b0c06990520e80b936440a2c9fd184d92a1f06c4e8a60122fab8bcdb88154dbf5877ad1e2d7f1b541bc8a5ec1b52266095381339c27c8300",
"018cebb73be883466d18d3b0c06990520e80b936440a2c9fd184d92a1f06c4e8a600030001d04e93b1b3d6620676e56be7175514ebf0bc03a7f5571403d4547e691102b78a016de08a5115fbf297232c7c9aa0f8cb78ee9a7fc467d0dfc1fe889f2f1e340ac40122fab8bcdb88154dbf5877ad1e2d7f1b541bc8a5ec1b52266095381339c27c8300",
"00000004b02310f2e087e55bfd07ef5e242e3b87ee5d00c9ab52f61e6bd42542f93a6f55225747f3b5d5dab4e5a424f81f85c904ff43286e0f3fd07ef0b8c6a627b114d8cb37f4591361cd846141e7852c3726b37dd9b011cc55eef2ac931dfe769ff55a1dab0949ba4bae1d065b07b0b308e6a197e118f7614caab5f137ad66dfe6ab8e0101f43e3aac61e5a753062d4d0508c26ceaf5e4c0c58ba3c956e104b5d2cf67c41c0002016ceafae082a15d1b4eb70e9eb7a880e5ee2e3d1d04bfdcc03dd73ed2571c6b8e01d04e93b1b3d6620676e56be7175514ebf0bc03a7f5571403d4547e691102b78a",
"01b02310f2e087e55bfd07ef5e242e3b87ee5d00c9ab52f61e6bd42542f93a6f55000003225747f3b5d5dab4e5a424f81f85c904ff43286e0f3fd07ef0b8c6a627b114d8cb37f4591361cd846141e7852c3726b37dd9b011cc55eef2ac931dfe769ff55a1dab0949ba4bae1d065b07b0b308e6a197e118f7614caab5f137ad66dfe6ab8e0101f43e3aac61e5a753062d4d0508c26ceaf5e4c0c58ba3c956e104b5d2cf67c41c0002016ceafae082a15d1b4eb70e9eb7a880e5ee2e3d1d04bfdcc03dd73ed2571c6b8e01d04e93b1b3d6620676e56be7175514ebf0bc03a7f5571403d4547e691102b78a",
"01b02310f2e087e55bfd07ef5e242e3b87ee5d00c9ab52f61e6bd42542f93a6f5501225747f3b5d5dab4e5a424f81f85c904ff43286e0f3fd07ef0b8c6a627b114d80002cb37f4591361cd846141e7852c3726b37dd9b011cc55eef2ac931dfe769ff55a1dab0949ba4bae1d065b07b0b308e6a197e118f7614caab5f137ad66dfe6ab8e0101f43e3aac61e5a753062d4d0508c26ceaf5e4c0c58ba3c956e104b5d2cf67c41c0002016ceafae082a15d1b4eb70e9eb7a880e5ee2e3d1d04bfdcc03dd73ed2571c6b8e01d04e93b1b3d6620676e56be7175514ebf0bc03a7f5571403d4547e691102b78a",
"017c3ea01a6e3a3d90cf59cd789e467044b5cd78eb2c84cc6816f960746d0e03ec0001016a0fa2d0c5c7b8236092de86d99068ce04511d5adbdd848ccf7c969dbf7338ca0250421d6c2c94571dfaaa135a4ff15bf916681ebd62c0e43e69e3b90684d0a0b01dab0949ba4bae1d065b07b0b308e6a197e118f7614caab5f137ad66dfe6ab8e0101f43e3aac61e5a753062d4d0508c26ceaf5e4c0c58ba3c956e104b5d2cf67c41c0002016ceafae082a15d1b4eb70e9eb7a880e5ee2e3d1d04bfdcc03dd73ed2571c6b8e01d04e93b1b3d6620676e56be7175514ebf0bc03a7f5571403d4547e691102b78a",
"017c3ea01a6e3a3d90cf59cd789e467044b5cd78eb2c84cc6816f960746d0e03ec0150421d6c2c94571dfaaa135a4ff15bf916681ebd62c0e43e69e3b90684d0a0b001016a0fa2d0c5c7b8236092de86d99068ce04511d5adbdd848ccf7c969dbf7338ca011dab0949ba4bae1d065b07b0b308e6a197e118f7614caab5f137ad66dfe6ab8e0101f43e3aac61e5a753062d4d0508c26ceaf5e4c0c58ba3c956e104b5d2cf67c41c0002016ceafae082a15d1b4eb70e9eb7a880e5ee2e3d1d04bfdcc03dd73ed2571c6b8e01d04e93b1b3d6620676e56be7175514ebf0bc03a7f5571403d4547e691102b78a",
"01aaec63863aaa0b2e3b8009429bdddd455e59be6f40ccab887a32eb98723efc9200020001197fda6b43eb91b445cf8a19541a6b064e9221cf6d43d67987d4cd0c646121e602f86748d40c5ee5f9a5644f2e7cf89aa5645e8a00d9e14d4fd193da0a23dd07f6022293d64836b72bc9d1ae36d6e115c8f7cf0a3f5e75d74059f69f81fd5614260101f43e3aac61e5a753062d4d0508c26ceaf5e4c0c58ba3c956e104b5d2cf67c41c0002016ceafae082a15d1b4eb70e9eb7a880e5ee2e3d1d04bfdcc03dd73ed2571c6b8e01d04e93b1b3d6620676e56be7175514ebf0bc03a7f5571403d4547e691102b78a",
"01aaec63863aaa0b2e3b8009429bdddd455e59be6f40ccab887a32eb98723efc9201f86748d40c5ee5f9a5644f2e7cf89aa5645e8a00d9e14d4fd193da0a23dd07f6020001197fda6b43eb91b445cf8a19541a6b064e9221cf6d43d67987d4cd0c646121e601022293d64836b72bc9d1ae36d6e115c8f7cf0a3f5e75d74059f69f81fd5614260101f43e3aac61e5a753062d4d0508c26ceaf5e4c0c58ba3c956e104b5d2cf67c41c0002016ceafae082a15d1b4eb70e9eb7a880e5ee2e3d1d04bfdcc03dd73ed2571c6b8e01d04e93b1b3d6620676e56be7175514ebf0bc03a7f5571403d4547e691102b78a",
"01bc8a5ec71647415c380203b681f7717366f3501661512225b6dc3e121efc0bae00020165d0fa354e4efa95de2eee9329f18bc7db58d03501471348bfdeca4554eb2e3401197fda6b43eb91b445cf8a19541a6b064e9221cf6d43d67987d4cd0c646121e601da1adda2ccde9381e11151686c121e7f52d19a990439161c7eb5a9f94be5a5910101f43e3aac61e5a753062d4d0508c26ceaf5e4c0c58ba3c956e104b5d2cf67c41c0002016ceafae082a15d1b4eb70e9eb7a880e5ee2e3d1d04bfdcc03dd73ed2571c6b8e01d04e93b1b3d6620676e56be7175514ebf0bc03a7f5571403d4547e691102b78a",
"01bc8a5ec71647415c380203b681f7717366f3501661512225b6dc3e121efc0bae01da1adda2ccde9381e11151686c121e7f52d19a990439161c7eb5a9f94be5a591020165d0fa354e4efa95de2eee9329f18bc7db58d03501471348bfdeca4554eb2e3401197fda6b43eb91b445cf8a19541a6b064e9221cf6d43d67987d4cd0c646121e6000101f43e3aac61e5a753062d4d0508c26ceaf5e4c0c58ba3c956e104b5d2cf67c41c0002016ceafae082a15d1b4eb70e9eb7a880e5ee2e3d1d04bfdcc03dd73ed2571c6b8e01d04e93b1b3d6620676e56be7175514ebf0bc03a7f5571403d4547e691102b78a",
"013a27fed5dbbc475d3880360e38638c882fd9b273b618fc433106896083f774c600030000016de08a5115fbf297232c7c9aa0f8cb78ee9a7fc467d0dfc1fe889f2f1e340ac402c8ca8f7df7fd9979302f3885dcd9ab816e40f8d511a48ba0891b4460b2bd1d7ce184db737209fe4b1277cca58b2e6b52c35d3bd71e990ffe0115c4f6bbfa38100101f43e3aac61e5a753062d4d0508c26ceaf5e4c0c58ba3c956e104b5d2cf67c41c0001016ceafae082a15d1b4eb70e9eb7a880e5ee2e3d1d04bfdcc03dd73ed2571c6b8e",
"013a27fed5dbbc475d3880360e38638c882fd9b273b618fc433106896083f774c601c8ca8f7df7fd9979302f3885dcd9ab816e40f8d511a48ba0891b4460b2bd1d7c030000016de08a5115fbf297232c7c9aa0f8cb78ee9a7fc467d0dfc1fe889f2f1e340ac401e184db737209fe4b1277cca58b2e6b52c35d3bd71e990ffe0115c4f6bbfa38100101f43e3aac61e5a753062d4d0508c26ceaf5e4c0c58ba3c956e104b5d2cf67c41c0001016ceafae082a15d1b4eb70e9eb7a880e5ee2e3d1d04bfdcc03dd73ed2571c6b8e",
"01f0fa37e8063b139d342246142fc48e7c0c50d0a62c97768589e06466742c37020003011be5b76ecb233cd650efcff47cd0be43056324a78a48a97df7faec851bc7dcda00016de08a5115fbf297232c7c9aa0f8cb78ee9a7fc467d0dfc1fe889f2f1e340ac401e6d4d7685894d01b32f7e081ab188930be6c2b9f76d6847b7f382e3dddd7c6080101f43e3aac61e5a753062d4d0508c26ceaf5e4c0c58ba3c956e104b5d2cf67c41c0001016ceafae082a15d1b4eb70e9eb7a880e5ee2e3d1d04bfdcc03dd73ed2571c6b8e",
"01f0fa37e8063b139d342246142fc48e7c0c50d0a62c97768589e06466742c370201e6d4d7685894d01b32f7e081ab188930be6c2b9f76d6847b7f382e3dddd7c60803011be5b76ecb233cd650efcff47cd0be43056324a78a48a97df7faec851bc7dcda00016de08a5115fbf297232c7c9aa0f8cb78ee9a7fc467d0dfc1fe889f2f1e340ac4000101f43e3aac61e5a753062d4d0508c26ceaf5e4c0c58ba3c956e104b5d2cf67c41c0001016ceafae082a15d1b4eb70e9eb7a880e5ee2e3d1d04bfdcc03dd73ed2571c6b8e",
"018cebb73be883466d18d3b0c06990520e80b936440a2c9fd184d92a1f06c4e8a600030001d04e93b1b3d6620676e56be7175514ebf0bc03a7f5571403d4547e691102b78a016de08a5115fbf297232c7c9aa0f8cb78ee9a7fc467d0dfc1fe889f2f1e340ac40122fab8bcdb88154dbf5877ad1e2d7f1b541bc8a5ec1b52266095381339c27c830101f43e3aac61e5a753062d4d0508c26ceaf5e4c0c58ba3c956e104b5d2cf67c41c0000",
"018cebb73be883466d18d3b0c06990520e80b936440a2c9fd184d92a1f06c4e8a60122fab8bcdb88154dbf5877ad1e2d7f1b541bc8a5ec1b52266095381339c27c83030001d04e93b1b3d6620676e56be7175514ebf0bc03a7f5571403d4547e691102b78a016de08a5115fbf297232c7c9aa0f8cb78ee9a7fc467d0dfc1fe889f2f1e340ac4000101f43e3aac61e5a753062d4d0508c26ceaf5e4c0c58ba3c956e104b5d2cf67c41c0000",
"00000005b02310f2e087e55bfd07ef5e242e3b87ee5d00c9ab52f61e6bd42542f93a6f55225747f3b5d5dab4e5a424f81f85c904ff43286e0f3fd07ef0b8c6a627b114d8cb37f4591361cd846141e7852c3726b37dd9b011cc55eef2ac931dfe769ff55a1dab0949ba4bae1d065b07b0b308e6a197e118f7614caab5f137ad66dfe6ab8e920d71bf7104c10b4d780495bb772e8d44a507dbf616963a1b3d2410c9d4080000",
"01b02310f2e087e55bfd07ef5e242e3b87ee5d00c9ab52f61e6bd42542f93a6f55000004225747f3b5d5dab4e5a424f81f85c904ff43286e0f3fd07ef0b8c6a627b114d8cb37f4591361cd846141e7852c3726b37dd9b011cc55eef2ac931dfe769ff55a1dab0949ba4bae1d065b07b0b308e6a197e118f7614caab5f137ad66dfe6ab8e920d71bf7104c10b4d780495bb772e8d44a507dbf616963a1b3d2410c9d4080000",
"01b02310f2e087e55bfd07ef5e242e3b87ee5d00c9ab52f61e6bd42542f93a6f5501225747f3b5d5dab4e5a424f81f85c904ff43286e0f3fd07ef0b8c6a627b114d80003cb37f4591361cd846141e7852c3726b37dd9b011cc55eef2ac931dfe769ff55a1dab0949ba4bae1d065b07b0b308e6a197e118f7614caab5f137ad66dfe6ab8e920d71bf7104c10b4d780495bb772e8d44a507dbf616963a1b3d2410c9d4080000",
"017c3ea01a6e3a3d90cf59cd789e467044b5cd78eb2c84cc6816f960746d0e03ec0001016a0fa2d0c5c7b8236092de86d99068ce04511d5adbdd848ccf7c969dbf7338ca0350421d6c2c94571dfaaa135a4ff15bf916681ebd62c0e43e69e3b90684d0a0b01dab0949ba4bae1d065b07b0b308e6a197e118f7614caab5f137ad66dfe6ab8e920d71bf7104c10b4d780495bb772e8d44a507dbf616963a1b3d2410c9d4080000",
"017c3ea01a6e3a3d90cf59cd789e467044b5cd78eb2c84cc6816f960746d0e03ec0150421d6c2c94571dfaaa135a4ff15bf916681ebd62c0e43e69e3b90684d0a0b001016a0fa2d0c5c7b8236092de86d99068ce04511d5adbdd848ccf7c969dbf7338ca021dab0949ba4bae1d065b07b0b308e6a197e118f7614caab5f137ad66dfe6ab8e920d71bf7104c10b4d780495bb772e8d44a507dbf616963a1b3d2410c9d4080000",
"01aaec63863aaa0b2e3b8009429bdddd455e59be6f40ccab887a32eb98723efc9200020001197fda6b43eb91b445cf8a19541a6b064e9221cf6d43d67987d4cd0c646121e603f86748d40c5ee5f9a5644f2e7cf89aa5645e8a00d9e14d4fd193da0a23dd07f6022293d64836b72bc9d1ae36d6e115c8f7cf0a3f5e75d74059f69f81fd561426920d71bf7104c10b4d780495bb772e8d44a507dbf616963a1b3d2410c9d4080000",
"01aaec63863aaa0b2e3b8009429bdddd455e59be6f40ccab887a32eb98723efc9201f86748d40c5ee5f9a5644f2e7cf89aa5645e8a00d9e14d4fd193da0a23dd07f6020001197fda6b43eb91b445cf8a19541a6b064e9221cf6d43d67987d4cd0c646121e602022293d64836b72bc9d1ae36d6e115c8f7cf0a3f5e75d74059f69f81fd561426920d71bf7104c10b4d780495bb772e8d44a507dbf616963a1b3d2410c9d4080000",
"01bc8a5ec71647415c380203b681f7717366f3501661512225b6dc3e121efc0bae00020165d0fa354e4efa95de2eee9329f18bc7db58d03501471348bfdeca4554eb2e3401197fda6b43eb91b445cf8a19541a6b064e9221cf6d43d67987d4cd0c646121e602da1adda2ccde9381e11151686c121e7f52d19a990439161c7eb5a9f94be5a591920d71bf7104c10b4d780495bb772e8d44a507dbf616963a1b3d2410c9d4080000",
"01bc8a5ec71647415c380203b681f7717366f3501661512225b6dc3e121efc0bae01da1adda2ccde9381e11151686c121e7f52d19a990439161c7eb5a9f94be5a591020165d0fa354e4efa95de2eee9329f18bc7db58d03501471348bfdeca4554eb2e3401197fda6b43eb91b445cf8a19541a6b064e9221cf6d43d67987d4cd0c646121e601920d71bf7104c10b4d780495bb772e8d44a507dbf616963a1b3d2410c9d4080000",
"013a27fed5dbbc475d3880360e38638c882fd9b273b618fc433106896083f774c600030000016de08a5115fbf297232c7c9aa0f8cb78ee9a7fc467d0dfc1fe889f2f1e340ac403c8ca8f7df7fd9979302f3885dcd9ab816e40f8d511a48ba0891b4460b2bd1d7ce184db737209fe4b1277cca58b2e6b52c35d3bd71e990ffe0115c4f6bbfa38108850ac1e804fc8f724dc410aded78f99e07c18000e4bc97458d1c8b6357eae0200",
"013a27fed5dbbc475d3880360e38638c882fd9b273b618fc433106896083f774c601c8ca8f7df7fd9979302f3885dcd9ab816e40f8d511a48ba0891b4460b2bd1d7c030000016de08a5115fbf297232c7c9aa0f8cb78ee9a7fc467d0dfc1fe889f2f1e340ac402e184db737209fe4b1277cca58b2e6b52c35d3bd71e990ffe0115c4f6bbfa38108850ac1e804fc8f724dc410aded78f99e07c18000e4bc97458d1c8b6357eae0200",
"01f0fa37e8063b139d342246142fc48e7c0c50d0a62c97768589e06466742c37020003011be5b76ecb233cd650efcff47cd0be43056324a78a48a97df7faec851bc7dcda00016de08a5115fbf297232c7c9aa0f8cb78ee9a7fc467d0dfc1fe889f2f1e340ac402e6d4d7685894d01b32f7e081ab188930be6c2b9f76d6847b7f382e3dddd7c6088850ac1e804fc8f724dc410aded78f99e07c18000e4bc97458d1c8b6357eae0200",
"01f0fa37e8063b139d342246142fc48e7c0c50d0a62c97768589e06466742c370201e6d4d7685894d01b32f7e081ab188930be6c2b9f76d6847b7f382e3dddd7c60803011be5b76ecb233cd650efcff47cd0be43056324a78a48a97df7faec851bc7dcda00016de08a5115fbf297232c7c9aa0f8cb78ee9a7fc467d0dfc1fe889f2f1e340ac4018850ac1e804fc8f724dc410aded78f99e07c18000e4bc97458d1c8b6357eae0200",
"018cebb73be883466d18d3b0c06990520e80b936440a2c9fd184d92a1f06c4e8a600030001d04e93b1b3d6620676e56be7175514ebf0bc03a7f5571403d4547e691102b78a016de08a5115fbf297232c7c9aa0f8cb78ee9a7fc467d0dfc1fe889f2f1e340ac40222fab8bcdb88154dbf5877ad1e2d7f1b541bc8a5ec1b52266095381339c27c83bbb52416fefd25274a8a4e9513319cd7b85fa96244796ff402755618d717a1b000",
"018cebb73be883466d18d3b0c06990520e80b936440a2c9fd184d92a1f06c4e8a60122fab8bcdb88154dbf5877ad1e2d7f1b541bc8a5ec1b52266095381339c27c83030001d04e93b1b3d6620676e56be7175514ebf0bc03a7f5571403d4547e691102b78a016de08a5115fbf297232c7c9aa0f8cb78ee9a7fc467d0dfc1fe889f2f1e340ac401bbb52416fefd25274a8a4e9513319cd7b85fa96244796ff402755618d717a1b000",
"01f43e3aac61e5a753062d4d0508c26ceaf5e4c0c58ba3c956e104b5d2cf67c41c0003016ceafae082a15d1b4eb70e9eb7a880e5ee2e3d1d04bfdcc03dd73ed2571c6b8e01d04e93b1b3d6620676e56be7175514ebf0bc03a7f5571403d4547e691102b78a016de08a5115fbf297232c7c9aa0f8cb78ee9a7fc467d0dfc1fe889f2f1e340ac4013a3661bc12b72646c94bc6c92796e81953985ee62d80a9ec3645a9a95740ac1500"
]

View File

@ -260,6 +260,9 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
}
*/
// These tests assume null hashFinalSaplingRoot (before Sapling)
pblock->hashFinalSaplingRoot = uint256();
CValidationState state;
BOOST_CHECK(ProcessNewBlock(state, NULL, pblock, true, NULL));
BOOST_CHECK_MESSAGE(state.IsValid(), state.GetRejectReason());

View File

@ -17,7 +17,8 @@
using namespace std;
static const char DB_ANCHOR = 'A';
static const char DB_SPROUT_ANCHOR = 'A';
static const char DB_SAPLING_ANCHOR = 'X';
static const char DB_NULLIFIER = 's';
static const char DB_SAPLING_NULLIFIER = 'S';
static const char DB_COINS = 'c';
@ -26,7 +27,8 @@ static const char DB_TXINDEX = 't';
static const char DB_BLOCK_INDEX = 'b';
static const char DB_BEST_BLOCK = 'B';
static const char DB_BEST_ANCHOR = 'a';
static const char DB_BEST_SPROUT_ANCHOR = 'a';
static const char DB_BEST_SAPLING_ANCHOR = 'x';
static const char DB_FLAG = 'F';
static const char DB_REINDEX_FLAG = 'R';
static const char DB_LAST_BLOCK = 'l';
@ -40,30 +42,42 @@ CCoinsViewDB::CCoinsViewDB(size_t nCacheSize, bool fMemory, bool fWipe) : db(Get
}
bool CCoinsViewDB::GetAnchorAt(const uint256 &rt, ZCIncrementalMerkleTree &tree) const {
bool CCoinsViewDB::GetSproutAnchorAt(const uint256 &rt, ZCIncrementalMerkleTree &tree) const {
if (rt == ZCIncrementalMerkleTree::empty_root()) {
ZCIncrementalMerkleTree new_tree;
tree = new_tree;
return true;
}
bool read = db.Read(make_pair(DB_ANCHOR, rt), tree);
bool read = db.Read(make_pair(DB_SPROUT_ANCHOR, rt), tree);
return read;
}
bool CCoinsViewDB::GetNullifier(const uint256 &nf, NullifierType type) const {
bool CCoinsViewDB::GetSaplingAnchorAt(const uint256 &rt, ZCSaplingIncrementalMerkleTree &tree) const {
if (rt == ZCSaplingIncrementalMerkleTree::empty_root()) {
ZCSaplingIncrementalMerkleTree new_tree;
tree = new_tree;
return true;
}
bool read = db.Read(make_pair(DB_SAPLING_ANCHOR, rt), tree);
return read;
}
bool CCoinsViewDB::GetNullifier(const uint256 &nf, ShieldedType type) const {
bool spent = false;
char dbChar;
switch (type) {
case SPROUT_NULLIFIER:
case SPROUT:
dbChar = DB_NULLIFIER;
break;
case SAPLING_NULLIFIER:
case SAPLING:
dbChar = DB_SAPLING_NULLIFIER;
break;
default:
throw runtime_error("Unknown nullifier type");
throw runtime_error("Unknown shielded type");
}
return db.Read(make_pair(dbChar, nf), spent);
}
@ -83,10 +97,22 @@ uint256 CCoinsViewDB::GetBestBlock() const {
return hashBestChain;
}
uint256 CCoinsViewDB::GetBestAnchor() const {
uint256 CCoinsViewDB::GetBestAnchor(ShieldedType type) const {
uint256 hashBestAnchor;
if (!db.Read(DB_BEST_ANCHOR, hashBestAnchor))
return ZCIncrementalMerkleTree::empty_root();
switch (type) {
case SPROUT:
if (!db.Read(DB_BEST_SPROUT_ANCHOR, hashBestAnchor))
return ZCIncrementalMerkleTree::empty_root();
break;
case SAPLING:
if (!db.Read(DB_BEST_SAPLING_ANCHOR, hashBestAnchor))
return ZCSaplingIncrementalMerkleTree::empty_root();
break;
default:
throw runtime_error("Unknown shielded type");
}
return hashBestAnchor;
}
@ -105,10 +131,29 @@ void BatchWriteNullifiers(CDBBatch& batch, CNullifiersMap& mapToUse, const char&
}
}
template<typename Map, typename MapIterator, typename MapEntry>
void BatchWriteAnchors(CDBBatch& batch, Map& mapToUse, const char& dbChar)
{
for (MapIterator it = mapToUse.begin(); it != mapToUse.end();) {
if (it->second.flags & MapEntry::DIRTY) {
if (!it->second.entered)
batch.Erase(make_pair(dbChar, it->first));
else {
batch.Write(make_pair(dbChar, it->first), it->second.tree);
}
// TODO: changed++?
}
MapIterator itOld = it++;
mapToUse.erase(itOld);
}
}
bool CCoinsViewDB::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) {
CDBBatch batch(db);
@ -127,26 +172,18 @@ bool CCoinsViewDB::BatchWrite(CCoinsMap &mapCoins,
mapCoins.erase(itOld);
}
for (CAnchorsMap::iterator it = mapAnchors.begin(); it != mapAnchors.end();) {
if (it->second.flags & CAnchorsCacheEntry::DIRTY) {
if (!it->second.entered)
batch.Erase(make_pair(DB_ANCHOR, it->first));
else {
batch.Write(make_pair(DB_ANCHOR, it->first), it->second.tree);
}
// TODO: changed++?
}
CAnchorsMap::iterator itOld = it++;
mapAnchors.erase(itOld);
}
::BatchWriteAnchors<CAnchorsSproutMap, CAnchorsSproutMap::iterator, CAnchorsSproutCacheEntry>(batch, mapSproutAnchors, DB_SPROUT_ANCHOR);
::BatchWriteAnchors<CAnchorsSaplingMap, CAnchorsSaplingMap::iterator, CAnchorsSaplingCacheEntry>(batch, mapSaplingAnchors, DB_SAPLING_ANCHOR);
::BatchWriteNullifiers(batch, mapSproutNullifiers, DB_NULLIFIER);
::BatchWriteNullifiers(batch, mapSaplingNullifiers, DB_SAPLING_NULLIFIER);
if (!hashBlock.IsNull())
batch.Write(DB_BEST_BLOCK, hashBlock);
if (!hashAnchor.IsNull())
batch.Write(DB_BEST_ANCHOR, hashAnchor);
if (!hashSproutAnchor.IsNull())
batch.Write(DB_BEST_SPROUT_ANCHOR, hashSproutAnchor);
if (!hashSaplingAnchor.IsNull())
batch.Write(DB_BEST_SAPLING_ANCHOR, hashSaplingAnchor);
LogPrint("coindb", "Committing %u changed transactions (out of %u) to coin database...\n", (unsigned int)changed, (unsigned int)count);
return db.WriteBatch(batch);
@ -284,10 +321,10 @@ bool CBlockTreeDB::LoadBlockIndexGuts()
pindexNew->nFile = diskindex.nFile;
pindexNew->nDataPos = diskindex.nDataPos;
pindexNew->nUndoPos = diskindex.nUndoPos;
pindexNew->hashAnchor = diskindex.hashAnchor;
pindexNew->hashSproutAnchor = diskindex.hashSproutAnchor;
pindexNew->nVersion = diskindex.nVersion;
pindexNew->hashMerkleRoot = diskindex.hashMerkleRoot;
pindexNew->hashReserved = diskindex.hashReserved;
pindexNew->hashFinalSaplingRoot = diskindex.hashFinalSaplingRoot;
pindexNew->nTime = diskindex.nTime;
pindexNew->nBits = diskindex.nBits;
pindexNew->nNonce = diskindex.nNonce;

View File

@ -35,16 +35,19 @@ protected:
public:
CCoinsViewDB(size_t nCacheSize, bool fMemory = false, bool fWipe = false);
bool GetAnchorAt(const uint256 &rt, ZCIncrementalMerkleTree &tree) const;
bool GetNullifier(const uint256 &nf, NullifierType type) const;
bool GetSproutAnchorAt(const uint256 &rt, ZCIncrementalMerkleTree &tree) const;
bool GetSaplingAnchorAt(const uint256 &rt, ZCSaplingIncrementalMerkleTree &tree) const;
bool GetNullifier(const uint256 &nf, ShieldedType type) const;
bool GetCoins(const uint256 &txid, CCoins &coins) const;
bool HaveCoins(const uint256 &txid) const;
uint256 GetBestBlock() const;
uint256 GetBestAnchor() const;
uint256 GetBestAnchor(ShieldedType type) const;
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);
bool GetStats(CCoinsStats &stats) const;

View File

@ -206,7 +206,7 @@ void CTxMemPool::removeForReorg(const CCoinsViewCache *pcoins, unsigned int nMem
}
void CTxMemPool::removeWithAnchor(const uint256 &invalidRoot)
void CTxMemPool::removeWithAnchor(const uint256 &invalidRoot, ShieldedType type)
{
// If a block is disconnected from the tip, and the root changed,
// we must invalidate transactions from the mempool which spend
@ -217,11 +217,26 @@ void CTxMemPool::removeWithAnchor(const uint256 &invalidRoot)
for (indexed_transaction_set::const_iterator it = mapTx.begin(); it != mapTx.end(); it++) {
const CTransaction& tx = it->GetTx();
BOOST_FOREACH(const JSDescription& joinsplit, tx.vjoinsplit) {
if (joinsplit.anchor == invalidRoot) {
transactionsToRemove.push_back(tx);
break;
}
switch (type) {
case SPROUT:
BOOST_FOREACH(const JSDescription& joinsplit, tx.vjoinsplit) {
if (joinsplit.anchor == invalidRoot) {
transactionsToRemove.push_back(tx);
break;
}
}
break;
case SAPLING:
BOOST_FOREACH(const SpendDescription& spendDescription, tx.vShieldedSpend) {
if (spendDescription.anchor == invalidRoot) {
transactionsToRemove.push_back(tx);
break;
}
}
break;
default:
throw runtime_error("Unknown shielded type");
break;
}
}
@ -394,7 +409,7 @@ void CTxMemPool::check(const CCoinsViewCache *pcoins) const
BOOST_FOREACH(const JSDescription &joinsplit, tx.vjoinsplit) {
BOOST_FOREACH(const uint256 &nf, joinsplit.nullifiers) {
assert(!pcoins->GetNullifier(nf, SPROUT_NULLIFIER));
assert(!pcoins->GetNullifier(nf, SPROUT));
}
ZCIncrementalMerkleTree tree;
@ -402,7 +417,7 @@ void CTxMemPool::check(const CCoinsViewCache *pcoins) const
if (it != intermediates.end()) {
tree = it->second;
} else {
assert(pcoins->GetAnchorAt(joinsplit.anchor, tree));
assert(pcoins->GetSproutAnchorAt(joinsplit.anchor, tree));
}
BOOST_FOREACH(const uint256& commitment, joinsplit.commitments)
@ -413,7 +428,10 @@ void CTxMemPool::check(const CCoinsViewCache *pcoins) const
intermediates.insert(std::make_pair(tree.root(), tree));
}
for (const SpendDescription &spendDescription : tx.vShieldedSpend) {
assert(!pcoins->GetNullifier(spendDescription.nullifier, SAPLING_NULLIFIER));
ZCSaplingIncrementalMerkleTree tree;
assert(pcoins->GetSaplingAnchorAt(spendDescription.anchor, tree));
assert(!pcoins->GetNullifier(spendDescription.nullifier, SAPLING));
}
if (fDependsWait)
waitingOnDependants.push_back(&(*it));
@ -452,21 +470,21 @@ void CTxMemPool::check(const CCoinsViewCache *pcoins) const
assert(it->first == it->second.ptx->vin[it->second.n].prevout);
}
checkNullifiers(SPROUT_NULLIFIER);
checkNullifiers(SAPLING_NULLIFIER);
checkNullifiers(SPROUT);
checkNullifiers(SAPLING);
assert(totalTxSize == checkTotal);
assert(innerUsage == cachedInnerUsage);
}
void CTxMemPool::checkNullifiers(NullifierType type) const
void CTxMemPool::checkNullifiers(ShieldedType type) const
{
const std::map<uint256, const CTransaction*>* mapToUse;
switch (type) {
case SPROUT_NULLIFIER:
case SPROUT:
mapToUse = &mapSproutNullifiers;
break;
case SAPLING_NULLIFIER:
case SAPLING:
mapToUse = &mapSaplingNullifiers;
break;
default:
@ -582,12 +600,12 @@ bool CTxMemPool::HasNoInputsOf(const CTransaction &tx) const
return true;
}
bool CTxMemPool::nullifierExists(const uint256& nullifier, NullifierType type) const
bool CTxMemPool::nullifierExists(const uint256& nullifier, ShieldedType type) const
{
switch (type) {
case SPROUT_NULLIFIER:
case SPROUT:
return mapSproutNullifiers.count(nullifier);
case SAPLING_NULLIFIER:
case SAPLING:
return mapSaplingNullifiers.count(nullifier);
default:
throw runtime_error("Unknown nullifier type");
@ -596,7 +614,7 @@ bool CTxMemPool::nullifierExists(const uint256& nullifier, NullifierType type) c
CCoinsViewMemPool::CCoinsViewMemPool(CCoinsView *baseIn, CTxMemPool &mempoolIn) : CCoinsViewBacked(baseIn), mempool(mempoolIn) { }
bool CCoinsViewMemPool::GetNullifier(const uint256 &nf, NullifierType type) const
bool CCoinsViewMemPool::GetNullifier(const uint256 &nf, ShieldedType type) const
{
return mempool.nullifierExists(nf, type) || base->GetNullifier(nf, type);
}

View File

@ -134,7 +134,7 @@ private:
std::map<uint256, const CTransaction*> mapSproutNullifiers;
std::map<uint256, const CTransaction*> mapSaplingNullifiers;
void checkNullifiers(NullifierType type) const;
void checkNullifiers(ShieldedType type) const;
public:
typedef boost::multi_index_container<
@ -169,7 +169,7 @@ public:
bool addUnchecked(const uint256& hash, const CTxMemPoolEntry &entry, bool fCurrentEstimate = true);
void remove(const CTransaction &tx, std::list<CTransaction>& removed, bool fRecursive = false);
void removeWithAnchor(const uint256 &invalidRoot);
void removeWithAnchor(const uint256 &invalidRoot, ShieldedType type);
void removeForReorg(const CCoinsViewCache *pcoins, unsigned int nMemPoolHeight, int flags);
void removeConflicts(const CTransaction &tx, std::list<CTransaction>& removed);
void removeExpired(unsigned int nBlockHeight);
@ -192,7 +192,7 @@ public:
void ApplyDeltas(const uint256 hash, double &dPriorityDelta, CAmount &nFeeDelta);
void ClearPrioritisation(const uint256 hash);
bool nullifierExists(const uint256& nullifier, NullifierType type) const;
bool nullifierExists(const uint256& nullifier, ShieldedType type) const;
unsigned long size()
{
@ -243,7 +243,7 @@ protected:
public:
CCoinsViewMemPool(CCoinsView *baseIn, CTxMemPool &mempoolIn);
bool GetNullifier(const uint256 &txid, NullifierType type) const;
bool GetNullifier(const uint256 &txid, ShieldedType type) const;
bool GetCoins(const uint256 &txid, CCoins &coins) const;
bool HaveCoins(const uint256 &txid) const;
};

View File

@ -67,14 +67,14 @@ class CBlockUndo
{
public:
std::vector<CTxUndo> vtxundo; // for all but the coinbase
uint256 old_tree_root;
uint256 old_sprout_tree_root;
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action) {
READWRITE(vtxundo);
READWRITE(old_tree_root);
READWRITE(old_sprout_tree_root);
}
};

View File

@ -429,7 +429,7 @@ bool AsyncRPCOperation_mergetoaddress::main_impl()
auto it = intermediates.find(prevJoinSplit.anchor);
if (it != intermediates.end()) {
tree = it->second;
} else if (!pcoinsTip->GetAnchorAt(prevJoinSplit.anchor, tree)) {
} else if (!pcoinsTip->GetSproutAnchorAt(prevJoinSplit.anchor, tree)) {
throw JSONRPCError(RPC_WALLET_ERROR, "Could not find previous JoinSplit anchor");
}
@ -693,7 +693,7 @@ UniValue AsyncRPCOperation_mergetoaddress::perform_joinsplit(MergeToAddressJSInf
uint256 anchor;
{
LOCK(cs_main);
anchor = pcoinsTip->GetBestAnchor(); // As there are no inputs, ask the wallet for the best anchor
anchor = pcoinsTip->GetBestAnchor(SPROUT); // As there are no inputs, ask the wallet for the best anchor
}
return perform_joinsplit(info, witnesses, anchor);
}

View File

@ -545,7 +545,7 @@ bool AsyncRPCOperation_sendmany::main_impl() {
auto it = intermediates.find(prevJoinSplit.anchor);
if (it != intermediates.end()) {
tree = it->second;
} else if (!pcoinsTip->GetAnchorAt(prevJoinSplit.anchor, tree)) {
} else if (!pcoinsTip->GetSproutAnchorAt(prevJoinSplit.anchor, tree)) {
throw JSONRPCError(RPC_WALLET_ERROR, "Could not find previous JoinSplit anchor");
}
@ -914,7 +914,7 @@ UniValue AsyncRPCOperation_sendmany::perform_joinsplit(AsyncJoinSplitInfo & info
uint256 anchor;
{
LOCK(cs_main);
anchor = pcoinsTip->GetBestAnchor(); // As there are no inputs, ask the wallet for the best anchor
anchor = pcoinsTip->GetBestAnchor(SPROUT); // As there are no inputs, ask the wallet for the best anchor
}
return perform_joinsplit(info, witnesses, anchor);
}

View File

@ -314,7 +314,7 @@ UniValue AsyncRPCOperation_shieldcoinbase::perform_joinsplit(ShieldCoinbaseJSInf
{
LOCK(cs_main);
consensusBranchId = CurrentEpochBranchId(chainActive.Height() + 1, Params().GetConsensus());
anchor = pcoinsTip->GetBestAnchor();
anchor = pcoinsTip->GetBestAnchor(SPROUT);
}

View File

@ -1765,7 +1765,7 @@ void CWallet::WitnessNoteCommitment(std::vector<uint256> commitments,
// Consistency check: we should be able to find the current tree
// in our CCoins view.
ZCIncrementalMerkleTree dummy_tree;
assert(pcoinsTip->GetAnchorAt(current_anchor, dummy_tree));
assert(pcoinsTip->GetSproutAnchorAt(current_anchor, dummy_tree));
pindex = chainActive.Next(pindex);
}
@ -1819,7 +1819,7 @@ int CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate)
ZCIncrementalMerkleTree tree;
// This should never fail: we should always be able to get the tree
// state on the path to the tip of our chain
assert(pcoinsTip->GetAnchorAt(pindex->hashAnchor, tree));
assert(pcoinsTip->GetSproutAnchorAt(pindex->hashSproutAnchor, tree));
// Increment note witness caches
IncrementNoteWitnesses(pindex, &block, tree);

View File

@ -5,10 +5,41 @@
#include "zcash/IncrementalMerkleTree.hpp"
#include "crypto/sha256.h"
#include "zcash/util.h"
#include "librustzcash.h"
namespace libzcash {
SHA256Compress SHA256Compress::combine(const SHA256Compress& a, const SHA256Compress& b)
PedersenHash PedersenHash::combine(
const PedersenHash& a,
const PedersenHash& b,
size_t depth
)
{
PedersenHash res = PedersenHash();
librustzcash_merkle_hash(
depth,
a.begin(),
b.begin(),
res.begin()
);
return res;
}
PedersenHash PedersenHash::uncommitted() {
PedersenHash res = PedersenHash();
librustzcash_tree_uncommitted(res.begin());
return res;
}
SHA256Compress SHA256Compress::combine(
const SHA256Compress& a,
const SHA256Compress& b,
size_t depth
)
{
SHA256Compress res = SHA256Compress();
@ -111,7 +142,7 @@ void IncrementalMerkleTree<Depth, Hash>::append(Hash obj) {
right = obj;
} else {
// Combine the leaves and propagate it up the tree
boost::optional<Hash> combined = Hash::combine(*left, *right);
boost::optional<Hash> combined = Hash::combine(*left, *right, 0);
// Set the "left" leaf to the object and make the "right" leaf none
left = obj;
@ -120,7 +151,7 @@ void IncrementalMerkleTree<Depth, Hash>::append(Hash obj) {
for (size_t i = 0; i < Depth; i++) {
if (i < parents.size()) {
if (parents[i]) {
combined = Hash::combine(*parents[i], *combined);
combined = Hash::combine(*parents[i], *combined, i+1);
parents[i] = boost::none;
} else {
parents[i] = *combined;
@ -202,15 +233,15 @@ Hash IncrementalMerkleTree<Depth, Hash>::root(size_t depth,
Hash combine_left = left ? *left : filler.next(0);
Hash combine_right = right ? *right : filler.next(0);
Hash root = Hash::combine(combine_left, combine_right);
Hash root = Hash::combine(combine_left, combine_right, 0);
size_t d = 1;
BOOST_FOREACH(const boost::optional<Hash>& parent, parents) {
if (parent) {
root = Hash::combine(*parent, root);
root = Hash::combine(*parent, root, d);
} else {
root = Hash::combine(root, filler.next(d));
root = Hash::combine(root, filler.next(d), d);
}
d++;
@ -219,7 +250,7 @@ Hash IncrementalMerkleTree<Depth, Hash>::root(size_t depth,
// We may not have parents for ancestor trees, so we fill
// the rest in here.
while (d < depth) {
root = Hash::combine(root, filler.next(d));
root = Hash::combine(root, filler.next(d), d);
d++;
}
@ -323,4 +354,10 @@ template class IncrementalMerkleTree<INCREMENTAL_MERKLE_TREE_DEPTH_TESTING, SHA2
template class IncrementalWitness<INCREMENTAL_MERKLE_TREE_DEPTH, SHA256Compress>;
template class IncrementalWitness<INCREMENTAL_MERKLE_TREE_DEPTH_TESTING, SHA256Compress>;
template class IncrementalMerkleTree<SAPLING_INCREMENTAL_MERKLE_TREE_DEPTH, PedersenHash>;
template class IncrementalMerkleTree<INCREMENTAL_MERKLE_TREE_DEPTH_TESTING, PedersenHash>;
template class IncrementalWitness<SAPLING_INCREMENTAL_MERKLE_TREE_DEPTH, PedersenHash>;
template class IncrementalWitness<INCREMENTAL_MERKLE_TREE_DEPTH_TESTING, PedersenHash>;
} // end namespace `libzcash`

View File

@ -57,9 +57,9 @@ template<size_t Depth, typename Hash>
class EmptyMerkleRoots {
public:
EmptyMerkleRoots() {
empty_roots.at(0) = Hash();
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));
empty_roots.at(d) = Hash::combine(empty_roots.at(d-1), empty_roots.at(d-1), d-1);
}
}
Hash empty_root(size_t depth) {
@ -213,7 +213,29 @@ public:
SHA256Compress() : uint256() {}
SHA256Compress(uint256 contents) : uint256(contents) { }
static SHA256Compress combine(const SHA256Compress& a, const SHA256Compress& b);
static SHA256Compress combine(
const SHA256Compress& a,
const SHA256Compress& b,
size_t depth
);
static SHA256Compress uncommitted() {
return SHA256Compress();
}
};
class PedersenHash : public uint256 {
public:
PedersenHash() : uint256() {}
PedersenHash(uint256 contents) : uint256(contents) { }
static PedersenHash combine(
const PedersenHash& a,
const PedersenHash& b,
size_t depth
);
static PedersenHash uncommitted();
};
template<size_t Depth, typename Hash>
@ -227,4 +249,10 @@ typedef libzcash::IncrementalMerkleTree<INCREMENTAL_MERKLE_TREE_DEPTH_TESTING, l
typedef libzcash::IncrementalWitness<INCREMENTAL_MERKLE_TREE_DEPTH, libzcash::SHA256Compress> ZCIncrementalWitness;
typedef libzcash::IncrementalWitness<INCREMENTAL_MERKLE_TREE_DEPTH_TESTING, libzcash::SHA256Compress> ZCTestingIncrementalWitness;
typedef libzcash::IncrementalMerkleTree<SAPLING_INCREMENTAL_MERKLE_TREE_DEPTH, libzcash::PedersenHash> ZCSaplingIncrementalMerkleTree;
typedef libzcash::IncrementalMerkleTree<INCREMENTAL_MERKLE_TREE_DEPTH_TESTING, libzcash::PedersenHash> ZCSaplingTestingIncrementalMerkleTree;
typedef libzcash::IncrementalWitness<SAPLING_INCREMENTAL_MERKLE_TREE_DEPTH, libzcash::PedersenHash> ZCSaplingIncrementalWitness;
typedef libzcash::IncrementalWitness<INCREMENTAL_MERKLE_TREE_DEPTH_TESTING, libzcash::PedersenHash> ZCSaplingTestingIncrementalWitness;
#endif /* ZC_INCREMENTALMERKLETREE_H_ */

View File

@ -6,6 +6,8 @@
#define INCREMENTAL_MERKLE_TREE_DEPTH 29
#define INCREMENTAL_MERKLE_TREE_DEPTH_TESTING 4
#define SAPLING_INCREMENTAL_MERKLE_TREE_DEPTH 32
#define ZC_NOTEPLAINTEXT_LEADING 1
#define ZC_V_SIZE 8
#define ZC_RHO_SIZE 32

View File

@ -366,7 +366,7 @@ public:
return false;
}
bool GetNullifier(const uint256 &nf, NullifierType type) const {
bool GetNullifier(const uint256 &nf, ShieldedType type) const {
return false;
}
@ -381,7 +381,7 @@ public:
bool BatchWrite(CCoinsMap &mapCoins,
const uint256 &hashBlock,
const uint256 &hashAnchor,
CAnchorsMap &mapAnchors,
CAnchorsSproutMap &mapSproutAnchors,
CNullifiersMap &mapSproutNullifiers,
CNullifiersMap& mapSaplingNullifiers) {
return false;