use of com.jd.blockchain.ledger.proof.MerkleHashTrie in project jdchain-core by blockchain-jd-com.
the class MerkleHashTrieTest method testMerkleProofCorrectness.
/**
* 测试 Merkle 证明的正确性;
*/
@Test
public void testMerkleProofCorrectness() {
// 长度为 0 的情况;
int count = 0;
// System.out.printf("\r\n\r\n================= %s 个节点 =================\r\n\r\n", count);
List<VersioningKVData<String, byte[]>> dataList = generateDatas(count);
VersioningKVData<String, byte[]>[] datas = toArray(dataList);
MerkleHashTrie merkleTree = newMerkleTree_with_committed(datas);
HashDigest rootHash0 = merkleTree.getRootHash();
assertNotNull(rootHash0);
// 预期空的默克尔树中查询任何数据的证明都获得 null 返回;
MerkleProof proof = merkleTree.getProof("KEY-0");
assertNull(proof);
// 长度为 1 的情况;
count = 1;
// System.out.printf("\r\n\r\n================= %s 个节点 =================\r\n\r\n", count);
dataList = generateDatas(count);
datas = toArray(dataList);
merkleTree = newMerkleTree_with_committed(datas);
HashDigest rootHash1 = merkleTree.getRootHash();
assertNotNull(rootHash1);
// TODO: 暂时忽略默克尔证明的测试;
// // 预期在只有 1 条数据的情况下可以正常得到该数据的默克尔证明;
// MerkleProof proof1_0 = merkleTree.getProof("KEY-0");
// assertNotNull(proof1_0);
// // 依照设计,预期任何默克尔证明都至少有 4 条路径;
// assertMerkleProofPath(proof1_0, merkleTree.getRootHash(), merkleTree.getData("KEY-0"));
// 长度为 2 的情况;
count = 2;
// System.out.printf("\r\n\r\n================= %s 个节点 =================\r\n\r\n", count);
dataList = generateDatas(count);
datas = toArray(dataList);
merkleTree = newMerkleTree_with_committed(datas);
HashDigest rootHash2 = merkleTree.getRootHash();
assertNotNull(rootHash2);
// TODO: 暂时忽略默克尔证明的测试;
// MerkleProof proof2_0 = merkleTree.getProof("KEY-0");
// assertNotNull(proof2_0);
// // 依照设计,预期任何默克尔证明都至少有 4 条路径;
// assertMerkleProofPath(proof2_0, merkleTree.getRootHash(), merkleTree.getData("KEY-0"));
// 长度为 16 的情况;
count = 16;
// System.out.printf("\r\n\r\n================= %s 个节点 =================\r\n\r\n", count);
dataList = generateDatas(count);
datas = toArray(dataList);
merkleTree = newMerkleTree_with_committed(datas);
HashDigest rootHash16 = merkleTree.getRootHash();
assertNotNull(rootHash16);
// TODO: 暂时忽略默克尔证明的测试;
// MerkleProof proof16_0 = merkleTree.getProof("KEY-0");
// assertNotNull(proof16_0);
// // 依照设计,预期任何默克尔证明都至少有 4 条路径;
// assertMerkleProofPath(proof16_0, merkleTree.getRootHash(), merkleTree.getData("KEY-0"));
// 长度为 32 的情况;
count = 32;
// System.out.printf("\r\n\r\n================= %s 个节点 =================\r\n\r\n", count);
dataList = generateDatas(count);
datas = toArray(dataList);
merkleTree = newMerkleTree_with_committed(datas);
HashDigest rootHash32 = merkleTree.getRootHash();
assertNotNull(rootHash32);
// TODO: 暂时忽略默克尔证明的测试;
// MerkleProof proof32_0 = merkleTree.getProof("KEY-0");
// assertNotNull(proof32_0);
// // 依照设计,预期任何默克尔证明都至少有 4 条路径;
// assertMerkleProofPath(proof32_0, merkleTree.getRootHash(), merkleTree.getData("KEY-0"));
// 长度为 1025 的情况;
count = 1025;
// System.out.printf("\r\n\r\n================= %s 个节点 =================\r\n\r\n", count);
dataList = generateDatas(count);
datas = toArray(dataList);
merkleTree = newMerkleTree_with_committed(datas);
HashDigest rootHash1025 = merkleTree.getRootHash();
assertNotNull(rootHash1025);
// TODO: 暂时忽略默克尔证明的测试;
// MerkleProof proof1025 = merkleTree.getProof("KEY-0");
// assertNotNull(proof1025);
// // 依照设计,预期任何默克尔证明都至少有 4 条路径;
// assertMerkleProofPath(proof1025, merkleTree.getRootHash(), merkleTree.getData("KEY-0"));
}
use of com.jd.blockchain.ledger.proof.MerkleHashTrie in project jdchain-core by blockchain-jd-com.
the class MerkleHashTrieTest method testImmutability.
/**
* 测试 Merkle 根哈希的不变性,即相同的数据集合得到相同的默克尔树根哈希,与数据加入的先后顺序无关;
*/
@Test
public void testImmutability() {
// 长度为 0 的情况;
int count = 0;
// System.out.printf("\r\n\r\n================= %s 个节点 =================\r\n\r\n", count);
List<VersioningKVData<String, byte[]>> dataList = generateDatas(count);
VersioningKVData<String, byte[]>[] datas = toArray(dataList);
HashDigest rootHash0_1 = buildMerkleRootHash(datas);
HashDigest rootHash0_2 = buildMerkleRootHash(datas);
assertNotNull(rootHash0_1);
assertNotNull(rootHash0_2);
assertEquals(rootHash0_1, rootHash0_2);
// 长度为 1 的情况;
count = 1;
// System.out.printf("\r\n\r\n================= %s 个节点 =================\r\n\r\n", count);
dataList = generateDatas(count);
datas = toArray(dataList);
HashDigest rootHash1_1 = buildMerkleRootHash(datas);
HashDigest rootHash1_2 = buildMerkleRootHash(datas);
assertNotNull(rootHash1_1);
assertNotNull(rootHash1_2);
assertEquals(rootHash1_1, rootHash1_2);
// 长度为 2 的情况;
count = 2;
// System.out.printf("\r\n\r\n================= %s 个节点 =================\r\n\r\n", count);
dataList = generateDatas(count);
datas = toArray(dataList);
VersioningKVData<String, byte[]>[] datas1 = toArray(dataList);
datas1[0] = datas[1];
datas1[1] = datas[0];
HashDigest rootHash2_1 = buildMerkleRootHash(datas);
HashDigest rootHash2_2 = buildMerkleRootHash(datas1);
assertNotNull(rootHash2_1);
assertNotNull(rootHash2_2);
assertEquals(rootHash2_1, rootHash2_2);
// 长度为 8 的情况;
count = 8;
// System.out.printf("\r\n\r\n================= %s 个节点 =================\r\n\r\n", count);
dataList = generateDatas(count);
datas = toArray(dataList);
datas1 = getRandomSortingCopy(datas);
HashDigest rootHash_N1 = buildMerkleRootHash(datas);
HashDigest rootHash_N2 = buildMerkleRootHash(datas1);
assertNotNull(rootHash_N1);
assertNotNull(rootHash_N2);
assertEquals(rootHash_N1, rootHash_N2);
// 长度为 16 的情况;
count = 16;
// System.out.printf("\r\n\r\n================= %s 个节点 =================\r\n\r\n", count);
dataList = generateDatas(count);
datas = toArray(dataList);
datas1 = getRandomSortingCopy(datas);
rootHash_N1 = buildMerkleRootHash(datas);
rootHash_N2 = buildMerkleRootHash(datas1);
assertNotNull(rootHash_N1);
assertNotNull(rootHash_N2);
assertEquals(rootHash_N1, rootHash_N2);
// 长度为 32 的情况;
count = 32;
// System.out.printf("\r\n\r\n================= %s 个节点 =================\r\n\r\n", count);
dataList = generateDatas(count);
datas = toArray(dataList);
datas1 = getRandomSortingCopy(datas);
rootHash_N1 = buildMerkleRootHash(datas);
rootHash_N2 = buildMerkleRootHash(datas1);
assertNotNull(rootHash_N1);
assertNotNull(rootHash_N2);
assertEquals(rootHash_N1, rootHash_N2);
// 长度为 1025 的情况;
count = 1025;
// System.out.printf("\r\n\r\n================= %s 个节点 =================\r\n\r\n", count);
dataList = generateDatas(count);
datas = toArray(dataList);
datas1 = getRandomSortingCopy(datas);
MerkleHashTrie merkleTree = newMerkleTree_with_committed(datas);
MerkleHashTrie merkleTree1 = newMerkleTree_with_committed(datas1);
assertEquals(rootHash_N1, rootHash_N2);
assertEqualsTrie(merkleTree, merkleTree1);
}
use of com.jd.blockchain.ledger.proof.MerkleHashTrie in project jdchain-core by blockchain-jd-com.
the class MerkleHashTrieTest method testCancel.
/**
* 验证 HashSortingMerkleTree 在未提交之前,新增的数据记录可读和可回滚特性;
*/
@Test
public void testCancel() {
// 数据集合长度为 1024 时也能正常生成;
int count = 1024;
List<VersioningKVData<String, byte[]>> dataList = generateDatas(count);
VersioningKVData<String, byte[]>[] datas = toArray(dataList);
MerkleHashTrie merkleTree = newMerkleTree(datas);
assertTrue(merkleTree.isUpdated());
// 未提交之前查不到信息;
assertNull(merkleTree.getRootHash());
assertEquals(0, merkleTree.getTotalKeys());
assertEquals(0, merkleTree.getTotalRecords());
MerkleTrieData dt = merkleTree.getData("KEY-69");
assertNotNull(dt);
assertEquals(0, dt.getVersion());
dt = merkleTree.getData("KEY-69", 0);
assertNotNull(dt);
assertEquals(0, dt.getVersion());
dt = merkleTree.getData("KEY-69", 1);
assertNull(dt);
VersioningKVData<String, byte[]> data69 = new VersioningKVData<String, byte[]>("KEY-69", 1, BytesUtils.toBytes("NEW-VALUE-VERSION-1"));
merkleTree.setData(data69.getKey(), data69.getVersion(), data69.getValue());
dt = merkleTree.getData("KEY-69", 1);
assertNotNull(dt);
assertEquals(1, dt.getVersion());
assertTrue(merkleTree.isUpdated());
// 回滚全部数据;
merkleTree.cancel();
HashDigest rootHash = merkleTree.getRootHash();
assertNull(rootHash);
assertEquals(0, merkleTree.getTotalKeys());
// 由于 KEY-69 写入了 2 个版本的记录;
assertEquals(0, merkleTree.getTotalRecords());
dt = merkleTree.getData("KEY-69");
assertNull(dt);
dt = merkleTree.getData("KEY-69", 0);
assertNull(dt);
dt = merkleTree.getData("KEY-69", 1);
assertNull(dt);
assertFalse(merkleTree.isUpdated());
}
use of com.jd.blockchain.ledger.proof.MerkleHashTrie in project jdchain-core by blockchain-jd-com.
the class MerkleHashTrieTest method testMerkleTreeKeysDiffMultiCommit.
/**
* 构造KEY固定的两棵树,多次执行commit, 验证是否能得到预期的差异数据
*/
@Test
public void testMerkleTreeKeysDiffMultiCommit() {
List<VersioningKVData<String, byte[]>> newdataList = new ArrayList<VersioningKVData<String, byte[]>>();
List<String> newdataListString = new ArrayList<String>();
List<String> newdataListString1 = new ArrayList<String>();
CryptoSetting cryptoSetting = createCryptoSetting();
MemoryKVStorage storage = new MemoryKVStorage();
int count = 10240;
int newAddCount = 5700;
List<VersioningKVData<String, byte[]>> dataList = generateDatas(count);
VersioningKVData<String, byte[]>[] datas = toArray(dataList);
MerkleHashTrie merkleTree = newMerkleTree_with_committed(datas, cryptoSetting, storage);
HashDigest rootHash0 = merkleTree.getRootHash();
assertNotNull(rootHash0);
assertEquals(count, merkleTree.getTotalKeys());
assertEquals(count, merkleTree.getTotalRecords());
// reload and add random key data item;
MerkleHashTrie merkleTree_reload = new MerkleHashTrie(rootHash0, cryptoSetting, KEY_PREFIX, storage, false);
assertEquals(count, merkleTree_reload.getTotalKeys());
assertEquals(count, merkleTree_reload.getTotalRecords());
assertEquals(rootHash0, merkleTree_reload.getRootHash());
newdataListString = generateNewDatasString(count, newAddCount);
for (int i = 0; i < newAddCount; i++) {
VersioningKVData<String, byte[]> newdataKV = new VersioningKVData<String, byte[]>(newdataListString.get(i), 0, BytesUtils.toBytes("NEW-VALUE"));
merkleTree_reload.setData(newdataKV.getKey(), newdataKV.getVersion(), newdataKV.getValue());
}
// first commit
merkleTree_reload.commit();
HashDigest rootHash1 = merkleTree_reload.getRootHash();
assertNotNull(rootHash1);
assertNotEquals(rootHash0, rootHash1);
assertEquals(count + newAddCount, merkleTree_reload.getTotalKeys());
assertEquals(count + newAddCount, merkleTree_reload.getTotalRecords());
int newAddCount1 = 200;
newdataListString1 = generateNewDatasString(count + newAddCount, newAddCount1);
for (int i = 0; i < newAddCount1; i++) {
VersioningKVData<String, byte[]> newdataKV = new VersioningKVData<String, byte[]>(newdataListString1.get(i), 0, BytesUtils.toBytes("NEW-VALUE"));
merkleTree_reload.setData(newdataKV.getKey(), newdataKV.getVersion(), newdataKV.getValue());
}
// second commit
merkleTree_reload.commit();
HashDigest rootHash2 = merkleTree_reload.getRootHash();
assertNotNull(rootHash2);
assertNotEquals(rootHash1, rootHash2);
assertEquals(count + newAddCount + newAddCount1, merkleTree_reload.getTotalKeys());
assertEquals(count + newAddCount + newAddCount1, merkleTree_reload.getTotalRecords());
SkippingIterator<KVEntry> diffIterator = merkleTree_reload.getKeyDiffIterator(merkleTree);
// max boundary skip test
assertEquals(newAddCount + newAddCount1, diffIterator.getTotalCount());
assertEquals(-1, diffIterator.getCursor());
assertTrue(diffIterator.hasNext());
long skipped = diffIterator.skip(newAddCount + newAddCount1);
assertEquals(newAddCount + newAddCount1, skipped);
assertFalse(diffIterator.hasNext());
// re-interator and random skip test
int skipNum = 200;
diffIterator = merkleTree_reload.getKeyDiffIterator(merkleTree);
assertEquals(newAddCount + newAddCount1, diffIterator.getTotalCount());
assertEquals(-1, diffIterator.getCursor());
assertTrue(diffIterator.hasNext());
long skipped1 = diffIterator.skip(skipNum);
assertEquals(skipNum, skipped1);
int diffNum = 0;
// TODO: 无效的验证逻辑; by huanghaiquan at 2020-07-15;
// while (diffIterator.hasNext()) {
// MerkleData data = diffIterator.next();
// assertNotNull(data);
// assertFalse(dataList.contains(new String(data.getKey())));
// assertTrue(newdataListString.contains(new String(data.getKey()))
// || newdataListString1.contains(new String(data.getKey())));
// diffNum++;
// }
// assertEquals(diffNum, diffIterator.getCount() - skipNum);
// re-interator and next test
diffIterator = merkleTree_reload.getKeyDiffIterator(merkleTree);
int diffNum1 = 0;
while (diffIterator.hasNext()) {
KVEntry data = diffIterator.next();
assertNotNull(data);
diffNum1++;
}
assertFalse(diffIterator.hasNext());
assertEquals(newAddCount + newAddCount1 - 1, diffIterator.getCursor());
assertEquals(newAddCount + newAddCount1, diffIterator.getTotalCount());
assertEquals(diffNum1, diffIterator.getTotalCount());
// re-interator and test next key consistency
diffIterator = merkleTree_reload.getKeyDiffIterator(merkleTree);
// TODO: 无效的验证逻辑; by huanghaiquan at 2020-07-15;
// while (diffIterator.hasNext()) {
// MerkleData data = diffIterator.next();
// assertNotNull(data);
// assertFalse(dataList.contains(new String(data.getKey())));
// assertTrue(newdataListString.contains(new String(data.getKey()))
// || newdataListString1.contains(new String(data.getKey())));
// }
}
use of com.jd.blockchain.ledger.proof.MerkleHashTrie in project jdchain-core by blockchain-jd-com.
the class MerkleHashTrieTest method testReadUncommitting.
/**
* 验证 HashSortingMerkleTree 在未提交之前的总数和根哈希维持不变的特性,新增的数据记录可读,但是具有临时性,一旦回滚则被清除;
*/
@Test
public void testReadUncommitting() {
// 数据集合长度为 1024 时也能正常生成;
int count = 500;
List<VersioningKVData<String, byte[]>> dataList = generateDatas(count);
VersioningKVData<String, byte[]>[] datas = toArray(dataList);
MerkleHashTrie merkleTree = newMerkleTree(datas);
// 未提交之前查不到信息;
assertNull(merkleTree.getRootHash());
assertEquals(0, merkleTree.getTotalKeys());
assertEquals(0, merkleTree.getTotalRecords());
MerkleTrieData dt = merkleTree.getData("KEY-69");
assertNotNull(dt);
assertEquals(0, dt.getVersion());
dt = merkleTree.getData("KEY-69", 0);
assertNotNull(dt);
assertEquals(0, dt.getVersion());
dt = merkleTree.getData("KEY-69", 1);
assertNull(dt);
VersioningKVData<String, byte[]> data69 = new VersioningKVData<String, byte[]>("KEY-69", 1, BytesUtils.toBytes("NEW-VALUE-VERSION-1"));
merkleTree.setData(data69.getKey(), data69.getVersion(), data69.getValue());
dt = merkleTree.getData("KEY-69", 1);
assertNotNull(dt);
assertEquals(1, dt.getVersion());
merkleTree.commit();
HashDigest rootHash = merkleTree.getRootHash();
assertNotNull(rootHash);
assertEquals(count, merkleTree.getTotalKeys());
// 由于 KEY-69 写入了 2 个版本的记录;
assertEquals(count + 1, merkleTree.getTotalRecords());
dt = merkleTree.getData("KEY-69");
assertNotNull(dt);
assertEquals(1, dt.getVersion());
dt = merkleTree.getData("KEY-69", 0);
assertNotNull(dt);
assertEquals(0, dt.getVersion());
dt = merkleTree.getData("KEY-69", 1);
assertNotNull(dt);
assertEquals(1, dt.getVersion());
// merkleTree.print();
// TODO: 暂时忽略默克尔证明的测试;
// for (VersioningKVData<String, byte[]> data : datas) {
// assertMerkleProof(data, merkleTree);
// }
}
Aggregations