Search in sources :

Example 11 with KVEntry

use of com.jd.blockchain.ledger.merkletree.KVEntry in project jdchain-core by blockchain-jd-com.

the class MerkleHashSortTreeTest method testAddDataWithHashConfliction.

/**
 * 测试加入存在哈希冲突(基于 {@link MerkleHashSortTree#MURMUR3_HASH_POLICY}
 * 哈希策略)的数据时是否能够正确处理;<br>
 */
@Test
public void testAddDataWithHashConfliction() {
    // 8 位哈希最多有 256 个值,设置数据的总数大于 256 必然产生哈希冲突,可以验证哈希桶处理多个 key 的情况;
    int count = 300;
    List<VersioningKVData<String, byte[]>> dataList = generateDatas(count);
    VersioningKVData<String, byte[]>[] datas = toArray(dataList);
    TreeOptions treeOption = createTreeOptions();
    MemoryKVStorage storage = new MemoryKVStorage();
    MerkleHashSortTree merkleTree = new HashTreeIn8Bits(treeOption, KEY_PREFIX, storage);
    setDatas(merkleTree, datas);
    assertDataExist(merkleTree, datas);
    // 未提交之前查不到信息;
    assertNull(merkleTree.getRootHash());
    assertEquals(0, merkleTree.getTotalKeys());
    KVEntry 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);
    // 提交;
    merkleTree.commit();
    assertEquals(count, merkleTree.getTotalKeys());
    // 重新加载;
    HashDigest rootHash = merkleTree.getRootHash();
    assertNotNull(rootHash);
    merkleTree = new HashTreeIn8Bits(rootHash, treeOption, KEY_PREFIX, storage);
    assertEquals(count, merkleTree.getTotalKeys());
    assertDataExist(merkleTree, datas);
    // 验证迭代器;
    SkippingIterator<KVEntry> kvIter = merkleTree.iterator();
    assertDataEquals(datas, kvIter);
    // 验证增加不同版本;
    {
        VersioningKVData<String, byte[]> newData = createNewVersion(datas, 2);
        VersioningKVData<String, byte[]> newData1 = createNewVersion(datas, 26);
        VersioningKVData<String, byte[]> newData2 = createNewVersion(datas, 8);
        VersioningKVData<String, byte[]> newData3 = createNewVersion(datas, 2);
        merkleTree.setData(newData.getKey(), newData.getVersion(), newData.getValue());
        merkleTree.setData(newData1.getKey(), newData1.getVersion(), newData1.getValue());
        merkleTree.setData(newData2.getKey(), newData2.getVersion(), newData2.getValue());
        merkleTree.setData(newData3.getKey(), newData3.getVersion(), newData3.getValue());
        // 验证最新数据;
        assertDataExist(merkleTree, datas);
        // 迭代器返回不包含未提交的数据;
        // kvIter = merkleTree.iterator();
        // assertDataEquals(datas, kvIter);
        merkleTree.commit();
        // 验证提交之后的数据;
        kvIter = merkleTree.iterator();
        assertDataEquals(datas, kvIter);
    }
}
Also used : KVEntry(com.jd.blockchain.ledger.merkletree.KVEntry) TreeOptions(com.jd.blockchain.ledger.merkletree.TreeOptions) HashDigest(com.jd.blockchain.crypto.HashDigest) MemoryKVStorage(com.jd.blockchain.storage.service.utils.MemoryKVStorage) MerkleHashSortTree(com.jd.blockchain.ledger.merkletree.MerkleHashSortTree) VersioningKVData(com.jd.blockchain.storage.service.utils.VersioningKVData) Test(org.junit.Test)

Example 12 with KVEntry

use of com.jd.blockchain.ledger.merkletree.KVEntry in project jdchain-core by blockchain-jd-com.

the class MerkleHashSortTreeTest method testCancel.

/**
 * 验证 HashSortingMerkleTree 在未提交之前,新增的数据记录可读和可回滚特性;
 */
@Test
public void testCancel() {
    // 数据集合长度为 1024 时也能正常生成;
    int count = 1024;
    List<VersioningKVData<String, byte[]>> dataList = generateDatas(count);
    VersioningKVData<String, byte[]>[] datas = toArray(dataList);
    MerkleHashSortTree merkleTree = newMerkleTree(datas);
    assertTrue(merkleTree.isUpdated());
    // 未提交之前查不到信息;
    assertNull(merkleTree.getRootHash());
    assertEquals(0, merkleTree.getTotalKeys());
    KVEntry 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());
    dt = merkleTree.getData("KEY-69");
    assertNull(dt);
    dt = merkleTree.getData("KEY-69", 0);
    assertNull(dt);
    dt = merkleTree.getData("KEY-69", 1);
    assertNull(dt);
    // 对于新创建的空的默克尔树的 updated 属性为 true,回滚之后仍然是空的,此时预期 updated 属性为 true;
    assertTrue(merkleTree.isUpdated());
    // 加入数据,提交后继续加入数据,验证能够正常回滚到上一次提交;
    setDatas(merkleTree, datas);
    merkleTree.commit();
    assertDataExist(merkleTree, datas);
    int count2 = 200;
    List<VersioningKVData<String, byte[]>> dataList2 = generateDatasFrom(count, count2);
    VersioningKVData<String, byte[]>[] datas2 = toArray(dataList2);
    setDatas(merkleTree, datas2);
    // 在回滚之前,验证全部的数据都存在;
    assertDataExist(merkleTree, datas);
    assertDataExist(merkleTree, datas2);
    // 回滚未提交的第二批数据;
    merkleTree.cancel();
    // 验证仅剩第一批数据;
    assertDataExist(merkleTree, datas);
    assertDataNotExist(merkleTree, datas2);
}
Also used : KVEntry(com.jd.blockchain.ledger.merkletree.KVEntry) HashDigest(com.jd.blockchain.crypto.HashDigest) MerkleHashSortTree(com.jd.blockchain.ledger.merkletree.MerkleHashSortTree) VersioningKVData(com.jd.blockchain.storage.service.utils.VersioningKVData) Test(org.junit.Test)

Example 13 with KVEntry

use of com.jd.blockchain.ledger.merkletree.KVEntry in project jdchain-core by blockchain-jd-com.

the class MerkleHashSortTreeTest method testSpecialUseCase_1.

@Test
public void testSpecialUseCase_1() {
    TreeOptions treeOptions = createTreeOptions();
    MemoryKVStorage storage = new MemoryKVStorage();
    MerkleHashSortTree merkleTree = new MerkleHashSortTree(treeOptions, KEY_PREFIX, storage);
    byte[] key = Base58Utils.decode("j5sXmpcomtM2QMUNWeQWsF8bNFFnyeXoCjVAekEeLSscgY");
    byte[] value = BytesUtils.toBytes("Special Use-Case VALUE");
    long version = 0;
    merkleTree.setData(key, version, value);
    KVEntry mkdata = merkleTree.getData(key);
    assertNotNull(mkdata);
    merkleTree.commit();
    mkdata = merkleTree.getData(key);
    assertNotNull(mkdata);
    MerkleTree merkleTreeReload = new MerkleHashSortTree(merkleTree.getRootHash(), treeOptions, KEY_PREFIX, storage);
    mkdata = merkleTreeReload.getData(key);
    assertNotNull(mkdata);
}
Also used : MerkleTree(com.jd.blockchain.ledger.merkletree.MerkleTree) KVEntry(com.jd.blockchain.ledger.merkletree.KVEntry) TreeOptions(com.jd.blockchain.ledger.merkletree.TreeOptions) MemoryKVStorage(com.jd.blockchain.storage.service.utils.MemoryKVStorage) MerkleHashSortTree(com.jd.blockchain.ledger.merkletree.MerkleHashSortTree) Test(org.junit.Test)

Example 14 with KVEntry

use of com.jd.blockchain.ledger.merkletree.KVEntry in project jdchain-core by blockchain-jd-com.

the class MerkleHashSortTreeTest method testReloadTreeAddNewDataNode.

/**
 * 对已存在的树进行重载,增加新的数据节点,通过重载树验证新节点是否添加成功,total keys 与total records
 * 是否符合预期,新添加的数据节点Key具有一定的规律
 */
@Test
public void testReloadTreeAddNewDataNode() {
    TreeOptions cryptoSetting = createTreeOptions();
    MemoryKVStorage storage = new MemoryKVStorage();
    int count = 1024;
    List<VersioningKVData<String, byte[]>> dataList = generateDatas(count);
    VersioningKVData<String, byte[]>[] datas = toArray(dataList);
    MerkleHashSortTree merkleTree = newMerkleTree_with_committed(datas, cryptoSetting, storage);
    HashDigest rootHash0 = merkleTree.getRootHash();
    assertNotNull(rootHash0);
    assertEquals(count, merkleTree.getTotalKeys());
    // reload and add one data item;
    MerkleHashSortTree merkleTree_reload = new MerkleHashSortTree(rootHash0, cryptoSetting, KEY_PREFIX, storage);
    assertEquals(count, merkleTree_reload.getTotalKeys());
    assertEquals(rootHash0, merkleTree_reload.getRootHash());
    VersioningKVData<String, byte[]> data1025 = new VersioningKVData<String, byte[]>("KEY-1025", 0, BytesUtils.toBytes("NEW-VALUE-1025-VERSION-0"));
    merkleTree_reload.setData(data1025.getKey(), data1025.getVersion(), data1025.getValue());
    merkleTree_reload.commit();
    HashDigest rootHash1 = merkleTree_reload.getRootHash();
    assertNotNull(rootHash1);
    assertNotEquals(rootHash0, rootHash1);
    KVEntry data1025_reload_0 = merkleTree_reload.getData(data1025.getKey(), 0);
    assertNotNull(data1025_reload_0);
    KVEntry data0_reload_0 = merkleTree_reload.getData("KEY-0", 0);
    assertNotNull(data0_reload_0);
    System.out.println("mkl reload total keys = " + merkleTree_reload.getTotalKeys());
    assertEquals(count + 1, merkleTree_reload.getTotalKeys());
    MerkleHashSortTree merkleTree_reload_1 = new MerkleHashSortTree(rootHash1, cryptoSetting, KEY_PREFIX, storage);
    assertEquals(count + 1, merkleTree_reload_1.getTotalKeys());
    assertEquals(rootHash1, merkleTree_reload_1.getRootHash());
    HashDigest rootHash2 = merkleTree_reload_1.getRootHash();
    assertNotNull(rootHash2);
    assertNotEquals(rootHash0, rootHash2);
    KVEntry data1025_reload_1 = merkleTree_reload_1.getData(data1025.getKey(), 0);
    assertNotNull(data1025_reload_1);
    KVEntry data0_reload_1 = merkleTree_reload_1.getData("KEY-0", 0);
    assertNotNull(data0_reload_1);
    System.out.println("mkl reload total keys = " + merkleTree_reload_1.getTotalKeys());
    assertEquals(count + 1, merkleTree_reload_1.getTotalKeys());
}
Also used : KVEntry(com.jd.blockchain.ledger.merkletree.KVEntry) TreeOptions(com.jd.blockchain.ledger.merkletree.TreeOptions) HashDigest(com.jd.blockchain.crypto.HashDigest) MemoryKVStorage(com.jd.blockchain.storage.service.utils.MemoryKVStorage) MerkleHashSortTree(com.jd.blockchain.ledger.merkletree.MerkleHashSortTree) VersioningKVData(com.jd.blockchain.storage.service.utils.VersioningKVData) Test(org.junit.Test)

Example 15 with KVEntry

use of com.jd.blockchain.ledger.merkletree.KVEntry in project jdchain-core by blockchain-jd-com.

the class MerkleHashSortTreeTest method assertDataEquals.

private void assertDataEquals(VersioningKVData<String, byte[]>[] datas, SkippingIterator<KVEntry> kvIter) {
    Map<String, VersioningKVData<String, byte[]>> dataMap = new HashMap<>();
    for (VersioningKVData<String, byte[]> dt : datas) {
        dataMap.put(dt.getKey(), dt);
    }
    assertEquals(datas.length, kvIter.getTotalCount());
    Set<String> keyReadSet = new HashSet<String>();
    while (kvIter.hasNext()) {
        KVEntry kvEntry = (KVEntry) kvIter.next();
        String strKey = kvEntry.getKey().toUTF8String();
        assertFalse(keyReadSet.contains(strKey));
        assertTrue(dataMap.containsKey(strKey));
        VersioningKVData<String, byte[]> dt = dataMap.get(strKey);
        assertEquals(dt.getVersion(), kvEntry.getVersion());
        assertArrayEquals(dt.getValue(), kvEntry.getValue().toBytes());
        keyReadSet.add(strKey);
    }
}
Also used : KVEntry(com.jd.blockchain.ledger.merkletree.KVEntry) HashMap(java.util.HashMap) VersioningKVData(com.jd.blockchain.storage.service.utils.VersioningKVData) HashSet(java.util.HashSet)

Aggregations

KVEntry (com.jd.blockchain.ledger.merkletree.KVEntry)31 HashDigest (com.jd.blockchain.crypto.HashDigest)20 VersioningKVData (com.jd.blockchain.storage.service.utils.VersioningKVData)20 Test (org.junit.Test)20 MemoryKVStorage (com.jd.blockchain.storage.service.utils.MemoryKVStorage)17 MerkleHashTrie (com.jd.blockchain.ledger.proof.MerkleHashTrie)11 CryptoSetting (com.jd.blockchain.ledger.CryptoSetting)10 MerkleHashSortTree (com.jd.blockchain.ledger.merkletree.MerkleHashSortTree)9 ArrayList (java.util.ArrayList)8 TreeOptions (com.jd.blockchain.ledger.merkletree.TreeOptions)7 Bytes (utils.Bytes)5 HashMap (java.util.HashMap)3 MerkleTree (com.jd.blockchain.ledger.merkletree.MerkleTree)2 SecureRandom (java.security.SecureRandom)1 HashSet (java.util.HashSet)1 Random (java.util.Random)1 DataEntry (utils.DataEntry)1