Search in sources :

Example 1 with MerkleValue

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

the class MerkleSortTreeTest method testIterator.

@Test
public void testIterator() {
    TreeOptions options = createTreeOptions();
    MemoryKVStorage storage = new MemoryKVStorage();
    MerkleSortTree<byte[]> mst = MerkleSortTree.createBytesTree(options, DEFAULT_MKL_KEY_PREFIX, storage);
    // 验证空的迭代器;
    SkippingIterator<MerkleValue<byte[]>> iter = mst.bytesIterator();
    assertEquals(0, iter.getTotalCount());
    assertEquals(-1, iter.getCursor());
    assertFalse(iter.hasNext());
    assertNull(iter.next());
    // 加入数据,验证顺序数据插入的生成的迭代器;
    int count1 = 10;
    byte[][] datas1 = generateRandomData(count1);
    long[] ids1 = generateSeqenceIDs(0, count1);
    HashMap<Long, byte[]> dataMap = new HashMap<Long, byte[]>();
    mapIdValues(ids1, datas1, dataMap);
    addDatasAndCommit(ids1, datas1, mst);
    iter = mst.iterator();
    assertIteratorSortedAndEquals(iter, count1, ids1, dataMap);
    // 随机加入;验证迭代器返回有序的序列;
    Set<Long> excludingIDs = createIdSet(ids1);
    int count2 = (int) power(4, 8) + 1;
    byte[][] datas2 = generateRandomData(count2);
    long[] ids2 = generateRandomIDs(count2, excludingIDs, true);
    mapIdValues(ids2, datas2, dataMap);
    addDatasAndCommit(ids2, datas2, mst);
    long[] totalIds = ArrayUtils.concat(ids1, ids2);
    Arrays.sort(totalIds);
    long totalCount = count1 + count2;
    iter = mst.iterator();
    assertIteratorSortedAndEquals(iter, totalCount, totalIds, dataMap);
    // 验证有跳跃的情形;
    iter = mst.iterator();
    assertEquals(-1, iter.getCursor());
    int index = -1;
    long skipped = 1;
    iter.skip(skipped);
    index += skipped;
    assertEquals(index, iter.getCursor());
    MerkleValue<byte[]> merkleData = iter.next();
    index++;
    assertEquals(index, iter.getCursor());
    assertNotNull(merkleData);
    assertEquals(totalIds[index], merkleData.getId());
    skipped = 2;
    iter.skip(skipped);
    index += skipped;
    assertEquals(index, iter.getCursor());
    merkleData = iter.next();
    index++;
    assertEquals(index, iter.getCursor());
    assertNotNull(merkleData);
    assertEquals(totalIds[index], merkleData.getId());
    skipped = 3;
    iter.skip(skipped);
    index += skipped;
    assertEquals(index, iter.getCursor());
    merkleData = iter.next();
    index++;
    assertEquals(index, iter.getCursor());
    assertNotNull(merkleData);
    assertEquals(totalIds[index], merkleData.getId());
    SecureRandom random = new SecureRandom();
    for (int j = 0; j < 100; j++) {
        skipped = random.nextInt(100);
        iter.skip(skipped);
        index += skipped;
        assertEquals(index, iter.getCursor());
        merkleData = iter.next();
        index++;
        assertEquals(index, iter.getCursor());
        assertNotNull(merkleData);
        assertEquals(totalIds[index], merkleData.getId());
    }
    // 验证直接跳跃到倒数第 1 条的情形;
    long left = iter.getCount();
    iter.skip(left - 1);
    assertTrue(iter.hasNext());
    assertEquals(1, iter.getCount());
    merkleData = iter.next();
    assertEquals(totalCount - 1, iter.getCursor());
    assertNotNull(merkleData);
    assertEquals(totalIds[(int) totalCount - 1], merkleData.getId());
    assertFalse(iter.hasNext());
    merkleData = iter.next();
    assertNull(merkleData);
    // 验证直接跳跃到末尾的情形;
    iter = mst.iterator();
    assertTrue(iter.hasNext());
    long c = iter.skip(totalCount);
    assertEquals(totalCount, c);
    assertFalse(iter.hasNext());
    merkleData = iter.next();
    assertNull(merkleData);
}
Also used : HashMap(java.util.HashMap) SecureRandom(java.security.SecureRandom) TreeOptions(com.jd.blockchain.ledger.merkletree.TreeOptions) MemoryKVStorage(com.jd.blockchain.storage.service.utils.MemoryKVStorage) MerkleValue(com.jd.blockchain.ledger.merkletree.MerkleValue) Test(org.junit.Test)

Example 2 with MerkleValue

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

the class MerkleSortTreeTest method testMultiDataCountIterator.

/**
 * 测试包含数据策略中计数大于 1 的数据迭代;
 */
@Test
public void testMultiDataCountIterator() {
    TreeOptions options = createTreeOptions();
    MemoryKVStorage storage = new MemoryKVStorage();
    DataPolicy<byte[]> bytesDataPolicy = new DefaultDataPolicy<byte[]>() {

        @Override
        public byte[] updateData(long id, byte[] origData, byte[] newData) {
            ByteArrayOutputStream out = new ByteArrayOutputStream();
            if (origData == null) {
                BytesUtils.writeInt(1, out);
            } else {
                int count = BytesUtils.toInt(origData) + 1;
                BytesUtils.writeInt(count, out);
                out.write(origData, 4, origData.length - 4);
            }
            BytesEncoding.writeInNormal(newData, out);
            return out.toByteArray();
        }

        @Override
        public long count(long id, byte[] data) {
            return BytesUtils.toInt(data);
        }

        @Override
        public SkippingIterator<MerkleValue<byte[]>> iterator(long id, byte[] bytesData, long count, BytesConverter<byte[]> converter) {
            byte[][] values = new byte[(int) count][];
            ByteArrayInputStream in = new ByteArrayInputStream(bytesData, 4, bytesData.length - 4);
            for (int i = 0; i < values.length; i++) {
                values[i] = BytesEncoding.readInNormal(in);
            }
            return new BytesEntriesIterator(id, values);
        }
    };
    MerkleSortTree<byte[]> mst = MerkleSortTree.createBytesTree(options, DEFAULT_MKL_KEY_PREFIX, storage, bytesDataPolicy);
    int count = 16;
    byte[][] datas = generateRandomData(count);
    long[] ids = new long[count];
    int startIndex = 10;
    for (int i = 0; i < startIndex; i++) {
        ids[i] = i;
    }
    // 从 10 开始,连续3条不同的记录使用相同的 编码;
    int testId = startIndex + 2;
    ids[startIndex] = testId;
    ids[startIndex + 1] = testId;
    ids[startIndex + 2] = testId;
    for (int i = 0; i < ids.length - startIndex - 3; i++) {
        ids[startIndex + i + 3] = startIndex + i + 5;
    }
    addDatas(ids, datas, mst);
    mst.commit();
    // 验证所有的数据都能够正常检索;
    SkippingIterator<MerkleValue<byte[]>> iter = mst.iterator();
    assertEquals(count, iter.getTotalCount());
    assertIteratorEquals(count, datas, ids, 0, iter);
    // 验证略过中间数据也能够正常检索:跳跃到连续 id 的前一条;
    iter = mst.iterator();
    iter.skip(startIndex - 1);
    int i = startIndex - 1;
    assertIteratorEquals(count - (startIndex - 1), datas, ids, startIndex - 1, iter);
    // 验证略过中间数据也能够正常检索:跳跃到连续 id 的第1条;
    iter = mst.iterator();
    iter.skip(startIndex);
    i = startIndex;
    {
        MerkleValue<byte[]> v = iter.next();
        assertNotNull(v);
        assertEquals(testId, v.getId());
        assertArrayEquals(datas[i], v.getValue());
        v = iter.next();
        assertNotNull(v);
        assertEquals(testId, v.getId());
        assertArrayEquals(datas[i + 1], v.getValue());
        v = iter.next();
        assertNotNull(v);
        assertEquals(testId, v.getId());
        assertArrayEquals(datas[i + 2], v.getValue());
    }
    assertIteratorEquals(count - (i + 3), datas, ids, i + 3, iter);
    // 验证略过中间数据也能够正常检索:跳跃到连续 id 的第2条;
    iter = mst.iterator();
    iter.skip(startIndex + 1);
    i = startIndex;
    {
        MerkleValue<byte[]> v = iter.next();
        assertNotNull(v);
        assertEquals(testId, v.getId());
        assertArrayEquals(datas[i + 1], v.getValue());
        v = iter.next();
        assertNotNull(v);
        assertEquals(testId, v.getId());
        assertArrayEquals(datas[i + 2], v.getValue());
    }
    assertIteratorEquals(count - (i + 3), datas, ids, i + 3, iter);
    // 验证略过中间数据也能够正常检索:跳跃到连续 id 的第3条;
    iter = mst.iterator();
    iter.skip(startIndex + 2);
    i = startIndex;
    {
        MerkleValue<byte[]> v = iter.next();
        assertNotNull(v);
        assertEquals(testId, v.getId());
        assertArrayEquals(datas[i + 2], v.getValue());
    }
    assertIteratorEquals(count - (i + 3), datas, ids, i + 3, iter);
    // 验证略过中间数据也能够正常检索:跳跃到连续 id 第3条;
    iter = mst.iterator();
    iter.skip(startIndex + 3);
    assertIteratorEquals(count - (startIndex + 3), datas, ids, startIndex + 3, iter);
}
Also used : DefaultDataPolicy(com.jd.blockchain.ledger.merkletree.DefaultDataPolicy) ByteArrayOutputStream(java.io.ByteArrayOutputStream) TreeOptions(com.jd.blockchain.ledger.merkletree.TreeOptions) ByteArrayInputStream(java.io.ByteArrayInputStream) MemoryKVStorage(com.jd.blockchain.storage.service.utils.MemoryKVStorage) BytesConverter(com.jd.blockchain.ledger.merkletree.BytesConverter) MerkleValue(com.jd.blockchain.ledger.merkletree.MerkleValue) Test(org.junit.Test)

Example 3 with MerkleValue

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

the class MerkleHashSortTreeTest method testHashBucket.

/**
 */
@Test
public void testHashBucket() {
    byte[][] keys = new byte[4][];
    byte[][] values = new byte[4][];
    for (int i = 0; i < keys.length; i++) {
        keys[i] = BytesUtils.toBytes("KEY-" + i);
        values[i] = RandomUtils.generateRandomBytes(16);
    }
    TreeOptions treeOptions = TreeOptions.build().setDefaultHashAlgorithm(ClassicAlgorithm.SHA256.code());
    Bytes bucketPrefix = Bytes.fromString("BUCKET");
    MemoryKVStorage kvStorage = new MemoryKVStorage();
    MerkleHashBucket hashBucket = new MerkleHashBucket(100, keys[0], values[0], TreeDegree.D3, treeOptions, bucketPrefix, kvStorage);
    // 验证初始化之后的数据是否正确;
    assertEquals(1, hashBucket.getKeysCount());
    MerkleValue<byte[]> value = hashBucket.getValue(keys[0]);
    assertNotNull(value);
    assertEquals(0, value.getId());
    assertArrayEquals(values[0], value.getValue());
    assertEquals(0, hashBucket.getVersion(keys[0]));
    MerkleValue<byte[]> value_v1 = hashBucket.getValue(keys[0], 1);
    assertNull(value_v1);
    MerkleValue<byte[]> value1_v1 = hashBucket.getValue(keys[1], 0);
    assertNull(value1_v1);
    // 提交数据;
    hashBucket.commit();
    // 模拟对默尔克哈希桶的存储;
    byte[] bucketBytes = BinaryProtocol.encode(hashBucket, HashBucketEntry.class);
    HashBucketEntry bucketEntry = BinaryProtocol.decode(bucketBytes);
    // 重新加载;
    hashBucket = new MerkleHashBucket(100, bucketEntry.getKeySet(), TreeDegree.D3, treeOptions, bucketPrefix, kvStorage);
    // 验证重新加载之后的数据正确性;
    value = hashBucket.getValue(keys[0]);
    assertNotNull(value);
    assertEquals(0, value.getId());
    assertArrayEquals(values[0], value.getValue());
    assertEquals(0, hashBucket.getVersion(keys[0]));
    assertEquals(1, hashBucket.getKeysCount());
    SkippingIterator<MerkleValue<HashEntry>> keysIterator = hashBucket.iterator();
    assertEquals(1, keysIterator.getTotalCount());
    assertTrue(keysIterator.hasNext());
    MerkleValue<HashEntry> entry = keysIterator.next();
    assertNotNull(entry);
    assertTrue(entry.getValue() instanceof BytesKeyValue);
    BytesKeyValue kv = (BytesKeyValue) entry.getValue();
    assertArrayEquals(keys[0], kv.getKey().toBytes());
    assertArrayEquals(values[0], kv.getValue().toBytes());
    // 验证加入新的键;
    for (int i = 1; i < keys.length; i++) {
        hashBucket.setValue(keys[i], 0, values[i]);
    }
    assertEquals(keys.length, hashBucket.getKeysCount());
    for (int i = 0; i < keys.length; i++) {
        value = hashBucket.getValue(keys[i]);
        assertNotNull(value);
        // id 即版本;
        assertEquals(0, value.getId());
        assertArrayEquals(values[i], value.getValue());
        assertEquals(0, hashBucket.getVersion(keys[i]));
    }
    hashBucket.commit();
    // 重新加载并验证数据;
    bucketBytes = BinaryProtocol.encode(hashBucket, HashBucketEntry.class);
    bucketEntry = BinaryProtocol.decode(bucketBytes);
    hashBucket = new MerkleHashBucket(100, bucketEntry.getKeySet(), TreeDegree.D3, treeOptions, bucketPrefix, kvStorage);
    assertEquals(keys.length, hashBucket.getKeysCount());
    for (int i = 0; i < keys.length; i++) {
        value = hashBucket.getValue(keys[i]);
        assertNotNull(value);
        // id 即版本;
        assertEquals(0, value.getId());
        assertArrayEquals(values[i], value.getValue());
        assertEquals(0, hashBucket.getVersion(keys[i]));
    }
}
Also used : MerkleHashBucket(com.jd.blockchain.ledger.merkletree.MerkleHashBucket) Bytes(utils.Bytes) HashEntry(com.jd.blockchain.ledger.merkletree.HashEntry) HashBucketEntry(com.jd.blockchain.ledger.merkletree.HashBucketEntry) TreeOptions(com.jd.blockchain.ledger.merkletree.TreeOptions) BytesKeyValue(com.jd.blockchain.ledger.merkletree.BytesKeyValue) MemoryKVStorage(com.jd.blockchain.storage.service.utils.MemoryKVStorage) MerkleValue(com.jd.blockchain.ledger.merkletree.MerkleValue) Test(org.junit.Test)

Example 4 with MerkleValue

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

the class MerkleSortTreeTest method testCommitAndCancel.

@Test
public void testCommitAndCancel() {
    int count1 = 48;
    byte[][] datas1 = generateRandomData(count1);
    long[] ids1 = generateRandomIDs(count1);
    Set<Long> excludingIds = createIdSet(ids1);
    int count2 = 32;
    byte[][] datas2 = generateRandomData(count2);
    long[] ids2 = generateRandomIDs(count2, excludingIds, true);
    TreeOptions options = createTreeOptions();
    MemoryKVStorage storage = new MemoryKVStorage();
    MerkleSortTree<byte[]> mst = MerkleSortTree.createBytesTree(options, DEFAULT_MKL_KEY_PREFIX, storage);
    long expectedMaxId1 = Arrays.stream(ids1).max().getAsLong();
    assertEquals(0, mst.getCount());
    assertNull(mst.getRootHash());
    assertEquals(-1L, mst.getMaxId());
    addDatas(ids1, datas1, mst);
    // 未提交之前总数不会发生变化;
    assertEquals(0, mst.getCount());
    assertNull(mst.getRootHash());
    // “最大编码”会实时更新;
    assertNotNull(mst.getMaxId());
    assertEquals(expectedMaxId1, mst.getMaxId());
    // 迭代器不包含未提交的数据;预期迭代器为空;
    SkippingIterator<MerkleValue<byte[]>> iter = mst.bytesIterator();
    assertEquals(0, iter.getTotalCount());
    // 提交之后才更新属性;
    mst.commit();
    assertEquals(count1, mst.getCount());
    assertNotNull(mst.getRootHash());
    assertNotNull(mst.getMaxId());
    assertEquals(expectedMaxId1, mst.getMaxId());
    assertDataEquals(mst, ids1, datas1);
    // 预期提交后,迭代器反映出最新提交的数据;
    Map<Long, byte[]> dataMap = new HashMap<Long, byte[]>();
    mapIdValues(ids1, datas1, dataMap);
    iter = mst.iterator();
    long[] sortedIds1 = ids1;
    Arrays.sort(sortedIds1);
    assertIteratorSortedAndEquals(iter, count1, sortedIds1, dataMap);
    // 测试写入数据后回滚操作是否符合预期;
    long expectedMaxId2 = Arrays.stream(ids2).max().getAsLong();
    expectedMaxId2 = Math.max(expectedMaxId1, expectedMaxId2);
    HashDigest rootHash1 = mst.getRootHash();
    // 写入数据,但并不提交;
    addDatas(ids2, datas2, mst);
    // 预期未提交之前,根哈希不会变化;
    assertEquals(rootHash1, mst.getRootHash());
    // 预期未提交之前,总数不会变化;
    assertEquals(count1, mst.getCount());
    // 预期“最大编码”属性是实时变化的;
    assertEquals(expectedMaxId2, mst.getMaxId());
    // 预期未提交之前,预期迭代器不会变化;
    iter = mst.iterator();
    assertIteratorSortedAndEquals(iter, count1, sortedIds1, dataMap);
    // 回滚之后,预期所有的属性恢复到上一次提交的结果;
    mst.cancel();
    // 预期“根哈希”维持上次提交之后的结果;
    assertEquals(rootHash1, mst.getRootHash());
    // 预期“总数”维持上次提交之后的结果;
    assertEquals(count1, mst.getCount());
    // 预期“最大编码”属性恢复到上次提交之后的结果;
    assertEquals(expectedMaxId1, mst.getMaxId());
    // 预期迭代器不会变化,维持上次提交之后的结果;
    iter = mst.iterator();
    assertIteratorSortedAndEquals(iter, count1, sortedIds1, dataMap);
}
Also used : HashMap(java.util.HashMap) TreeOptions(com.jd.blockchain.ledger.merkletree.TreeOptions) HashDigest(com.jd.blockchain.crypto.HashDigest) MemoryKVStorage(com.jd.blockchain.storage.service.utils.MemoryKVStorage) MerkleValue(com.jd.blockchain.ledger.merkletree.MerkleValue) Test(org.junit.Test)

Example 5 with MerkleValue

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

the class MerkleSortTreeTest method testIdConfliction.

/**
 * 测试插入同一个 ID 的冲突表现是否符合预期;
 */
@Test
public void testIdConfliction() {
    TreeOptions options = createTreeOptions();
    MemoryKVStorage storage = new MemoryKVStorage();
    MerkleSortTree<byte[]> mst = MerkleSortTree.createBytesTree(options, DEFAULT_MKL_KEY_PREFIX, storage);
    // 验证空的迭代器;
    SkippingIterator<MerkleValue<byte[]>> iter = mst.bytesIterator();
    assertEquals(0, iter.getTotalCount());
    assertEquals(-1, iter.getCursor());
    assertFalse(iter.hasNext());
    assertNull(iter.next());
    // 加入数据,验证顺序数据插入的生成的迭代器;
    int count = 10;
    byte[][] datas = generateRandomData(count);
    long[] ids = generateSeqenceIDs(0, count);
    addDatasAndCommit(ids, datas, mst);
    ;
    // 预期默认的 MerkleSortedTree 实现下,写入相同 id 的数据会引发移除;
    MerkleTreeKeyExistException keyExistException = null;
    try {
        mst.set(8, datas[0]);
    } catch (MerkleTreeKeyExistException e) {
        keyExistException = e;
    }
    assertNotNull(keyExistException);
}
Also used : TreeOptions(com.jd.blockchain.ledger.merkletree.TreeOptions) MerkleTreeKeyExistException(com.jd.blockchain.ledger.merkletree.MerkleTreeKeyExistException) MemoryKVStorage(com.jd.blockchain.storage.service.utils.MemoryKVStorage) MerkleValue(com.jd.blockchain.ledger.merkletree.MerkleValue) Test(org.junit.Test)

Aggregations

MerkleValue (com.jd.blockchain.ledger.merkletree.MerkleValue)5 TreeOptions (com.jd.blockchain.ledger.merkletree.TreeOptions)5 MemoryKVStorage (com.jd.blockchain.storage.service.utils.MemoryKVStorage)5 Test (org.junit.Test)5 HashMap (java.util.HashMap)2 HashDigest (com.jd.blockchain.crypto.HashDigest)1 BytesConverter (com.jd.blockchain.ledger.merkletree.BytesConverter)1 BytesKeyValue (com.jd.blockchain.ledger.merkletree.BytesKeyValue)1 DefaultDataPolicy (com.jd.blockchain.ledger.merkletree.DefaultDataPolicy)1 HashBucketEntry (com.jd.blockchain.ledger.merkletree.HashBucketEntry)1 HashEntry (com.jd.blockchain.ledger.merkletree.HashEntry)1 MerkleHashBucket (com.jd.blockchain.ledger.merkletree.MerkleHashBucket)1 MerkleTreeKeyExistException (com.jd.blockchain.ledger.merkletree.MerkleTreeKeyExistException)1 ByteArrayInputStream (java.io.ByteArrayInputStream)1 ByteArrayOutputStream (java.io.ByteArrayOutputStream)1 SecureRandom (java.security.SecureRandom)1 Bytes (utils.Bytes)1