Search in sources :

Example 1 with MerkleNode

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

the class MerkleSequenceTreeTest method testDataVersionModify.

/**
 * 测试单独修改版本而不变更数据时,是否能够正确地更新 merkle 树;;
 */
@Test
public void testDataVersionModify() {
    CryptoSetting setting = Mockito.mock(CryptoSetting.class);
    when(setting.getHashAlgorithm()).thenReturn(ClassicAlgorithm.SHA256.code());
    when(setting.getAutoVerifyHash()).thenReturn(true);
    // 保存所有写入的数据节点的 SN-Hash 映射表;
    TreeMap<Long, HashDigest> dataNodes = new TreeMap<>();
    MerkleNode nd;
    // 测试从空的树开始,顺序增加数据节点;
    ExistancePolicyKVStorageMap storage = new ExistancePolicyKVStorageMap();
    // 创建空的的树;
    MerkleSequenceTree mkt = new MerkleSequenceTree(setting, keyPrefix, storage);
    long sn = 0;
    // 加入 4097 条数据记录,预期构成以一颗 4 层 16 叉树;
    int count = 4097;
    byte[] dataBuf = new byte[16];
    Random rand = new Random();
    for (int i = 0; i < count; i++) {
        rand.nextBytes(dataBuf);
        nd = mkt.setData(sn, "KEY-" + sn, 0, dataBuf);
        dataNodes.put(sn, nd.getNodeHash());
        sn++;
    }
    mkt.commit();
    byte[] dataOfMaxSnNode = Arrays.copyOf(dataBuf, dataBuf.length);
    // 检查节点数;
    assertEquals(count, mkt.getDataCount());
    // 检查最大序列号的正确性;
    // count-1;
    long expectedMaxSN = 4096;
    long maxSN = mkt.getMaxSn();
    assertEquals(expectedMaxSN, maxSN);
    // 预期扩展到 4 层;
    assertEquals(4, mkt.getLevel());
    // 路径节点 + 数据节点;
    // 预期扩展为 4 层16叉树,由 3 层满16叉树扩展 1 新分支(4个路径节点)而形成;
    long expectedNodes = getMaxPathNodeCount(3) + 4 + 4097;
    assertEquals(expectedNodes, storage.getCount());
    // 仅仅更新最大的 sn 的数据节点的版本(由 0 升级为 1),预期将产生 4 个更新的路径节点和 1 个新的数据节点;
    long currNodes = expectedNodes;
    mkt.setData(maxSN, "KEY-" + maxSN, 1, dataOfMaxSnNode);
    mkt.commit();
    // 验证;
    maxSN = mkt.getMaxSn();
    assertEquals(expectedMaxSN, maxSN);
    // 预期扩展到 4 层;
    assertEquals(4, mkt.getLevel());
    // 路径节点 + 数据节点;
    // 预期将产生 4 个更新的路径节点和 1 个新的数据节点;
    expectedNodes = currNodes + 4 + 1;
    assertEquals(expectedNodes, storage.getCount());
}
Also used : CryptoSetting(com.jd.blockchain.ledger.CryptoSetting) HashDigest(com.jd.blockchain.crypto.HashDigest) Random(java.util.Random) ExistancePolicyKVStorageMap(com.jd.blockchain.storage.service.utils.ExistancePolicyKVStorageMap) MerkleNode(com.jd.blockchain.ledger.MerkleNode) MerkleSequenceTree(com.jd.blockchain.ledger.proof.MerkleSequenceTree) TreeMap(java.util.TreeMap) Test(org.junit.Test)

Example 2 with MerkleNode

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

the class MerkleSequenceTreeTest method testDataModify.

/**
 * 测试以单次提交的方式顺序地插入数据;
 */
@Test
public void testDataModify() {
    CryptoSetting setting = Mockito.mock(CryptoSetting.class);
    when(setting.getHashAlgorithm()).thenReturn(ClassicAlgorithm.SHA256.code());
    when(setting.getAutoVerifyHash()).thenReturn(true);
    // 保存所有写入的数据节点的 SN-Hash 映射表;
    TreeMap<Long, HashDigest> dataNodes = new TreeMap<>();
    MerkleNode nd;
    // 测试从空的树开始,顺序增加数据节点;
    ExistancePolicyKVStorageMap storage = new ExistancePolicyKVStorageMap();
    // 创建空的的树;
    MerkleSequenceTree mkt = new MerkleSequenceTree(setting, keyPrefix, storage);
    long sn = 0;
    // 加入 4097 条数据记录,预期构成以一颗 4 层 16 叉树;
    int count = 4097;
    byte[] dataBuf = new byte[16];
    Random rand = new Random();
    for (int i = 0; i < count; i++) {
        rand.nextBytes(dataBuf);
        nd = mkt.setData(sn, "KEY-" + sn, 0, dataBuf);
        dataNodes.put(sn, nd.getNodeHash());
        sn++;
    }
    mkt.commit();
    // 检查节点数;
    assertEquals(count, mkt.getDataCount());
    // 检查最大序列号的正确性;
    // count-1;
    long expectedMaxSN = 4096;
    long maxSN = mkt.getMaxSn();
    assertEquals(expectedMaxSN, maxSN);
    // 预期扩展到 4 层;
    assertEquals(4, mkt.getLevel());
    // 路径节点 + 数据节点;
    // 预期扩展为 4 层16叉树,由 3 层满16叉树扩展 1 新分支(4个路径节点)而形成;
    long expectedNodes = getMaxPathNodeCount(3) + 4 + 4097;
    assertEquals(expectedNodes, storage.getCount());
    // 覆盖到每一路分支修改数据节点;
    int storageDataCountBefore = storage.getCount();
    // maxSn = 4096;
    int i;
    for (i = 0; i <= maxSN; i += 16) {
        rand.nextBytes(dataBuf);
        sn = i;
        nd = mkt.setData(sn, "KEY-" + sn, 0, dataBuf);
        dataNodes.put(sn, nd.getNodeHash());
    }
    mkt.commit();
    // 检查节点数;
    assertEquals(count, mkt.getDataCount());
    // 检查最大序列号的正确性;
    maxSN = mkt.getMaxSn();
    assertEquals(expectedMaxSN, maxSN);
    // 由于覆盖到每一个分支节点,全部分支节点都重新生成,因此:
    // 新增节点数=修改的数据节点数 + 全部分支节点数;
    long addCounts = i / 16 + getMaxPathNodeCount(3) + 4;
    assertEquals(storageDataCountBefore + addCounts, storage.getCount());
// TODO: 暂时注释掉默克尔证明相关的内容;
// 验证每一个数据节点都产生了存在性证明;
// MerkleProof proof = null;
// for (Long n : dataNodes.keySet()) {
// proof = mkt.getProof(n.longValue());
// assertNotNull(proof);
// HashDigest expHash = dataNodes.get(n);
// assertEquals(expHash.toBase58(), proof.getDataHash().toBase58());
// }
}
Also used : CryptoSetting(com.jd.blockchain.ledger.CryptoSetting) HashDigest(com.jd.blockchain.crypto.HashDigest) Random(java.util.Random) ExistancePolicyKVStorageMap(com.jd.blockchain.storage.service.utils.ExistancePolicyKVStorageMap) MerkleNode(com.jd.blockchain.ledger.MerkleNode) MerkleSequenceTree(com.jd.blockchain.ledger.proof.MerkleSequenceTree) TreeMap(java.util.TreeMap) Test(org.junit.Test)

Example 3 with MerkleNode

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

the class MerkleSequenceTreeTest method testMerkleReload.

/**
 * 测试从存储重新加载 Merkle 树的正确性;
 */
/**
 */
// TODO: 暂时注释掉默克尔证明相关的内容;
// @Test
public void testMerkleReload() {
    CryptoSetting setting = Mockito.mock(CryptoSetting.class);
    when(setting.getHashAlgorithm()).thenReturn(ClassicAlgorithm.SHA256.code());
    when(setting.getAutoVerifyHash()).thenReturn(true);
    // 保存所有写入的数据节点的 SN-Hash 映射表;
    TreeMap<Long, HashDigest> expectedDataNodes = new TreeMap<>();
    MerkleNode nd;
    // 测试从空的树开始,顺序增加数据节点;
    ExistancePolicyKVStorageMap storage = new ExistancePolicyKVStorageMap();
    // 创建空的的树;
    MerkleSequenceTree mkt = new MerkleSequenceTree(setting, keyPrefix, storage);
    long sn = 0;
    // 加入 4097 条数据记录,预期构成以一颗 4 层 16 叉树;
    int count = 4097;
    byte[] dataBuf = new byte[16];
    Random rand = new Random();
    for (int i = 0; i < count; i++) {
        rand.nextBytes(dataBuf);
        nd = mkt.setData(sn, "KEY-" + sn, 0, dataBuf);
        expectedDataNodes.put(sn, nd.getNodeHash());
        sn++;
    }
    mkt.commit();
    // 记录一次提交的根哈希以及部分节点信息,用于后续的加载校验;
    HashDigest r1_rootHash = mkt.getRootHash();
    long r1_dataCount = mkt.getDataCount();
    long r1_maxSN = mkt.getMaxSn();
    long r1_sn1 = r1_maxSN;
    String r1_proof1 = mkt.getProof(r1_sn1).toString();
    long r1_sn2 = 1024;
    String r1_proof2 = mkt.getProof(r1_sn2).toString();
    {
        // 检查节点数;
        assertEquals(count, mkt.getDataCount());
        // 检查最大序列号的正确性;
        long maxSN = mkt.getMaxSn();
        // count-1;
        long expectedMaxSN = 4096;
        assertEquals(expectedMaxSN, maxSN);
        // 预期扩展到 4 层;
        assertEquals(4, mkt.getLevel());
        // 路径节点 + 数据节点;
        // 预期扩展为 4 层16叉树,由 3 层满16叉树扩展 1 新分支(4个路径节点)而形成;
        long expectedNodes = getMaxPathNodeCount(3) + 4 + 4097;
        assertEquals(expectedNodes, storage.getCount());
        // 重新加载,判断数据是否正确;
        MerkleSequenceTree r1_mkt = new MerkleSequenceTree(r1_rootHash, setting, keyPrefix, storage, true);
        {
            // 验证每一个数据节点都产生了存在性证明;
            MerkleProof proof = null;
            HashDigest expectedNodeHash = null;
            MerkleDataNode reallyDataNode = null;
            for (long n = 0; n < maxSN; n++) {
                expectedNodeHash = expectedDataNodes.get(n);
                reallyDataNode = r1_mkt.getData(n);
                assertEquals(expectedNodeHash, reallyDataNode.getNodeHash());
                proof = r1_mkt.getProof(n);
                assertNotNull(proof);
                assertEquals(expectedNodeHash, proof.getDataHash());
            }
        }
    }
    // 覆盖到每一路分支修改数据节点;
    int storageDataCountBefore = storage.getCount();
    // maxSn = 4096;
    long maxSN = mkt.getMaxSn();
    int i;
    for (i = 0; i <= maxSN; i += 16) {
        rand.nextBytes(dataBuf);
        sn = i;
        nd = mkt.setData(sn, "KEY-" + sn, 0, dataBuf);
        expectedDataNodes.put(sn, nd.getNodeHash());
    }
    mkt.commit();
    // 记录一次提交的根哈希以及部分节点信息,用于后续的加载校验;
    HashDigest r2_rootHash = mkt.getRootHash();
    long r2_dataCount = mkt.getDataCount();
    long r2_maxSN = mkt.getMaxSn();
    long r2_sn1 = r1_sn1;
    String r2_proof1 = mkt.getProof(r2_sn1).toString();
    long r2_sn2 = r1_sn2;
    String r2_proof2 = mkt.getProof(r2_sn2).toString();
    {
        // 检查节点数;
        assertEquals(count, mkt.getDataCount());
        assertEquals(r1_dataCount, r2_dataCount);
        // 检查最大序列号的正确性;
        maxSN = mkt.getMaxSn();
        // count-1;
        long expectedMaxSN = 4096;
        assertEquals(expectedMaxSN, maxSN);
        // 由于覆盖到每一个分支节点,全部分支节点都重新生成,因此:
        // 新增节点数=修改的数据节点数 + 全部分支节点数;
        long addCounts = i / 16 + getMaxPathNodeCount(3) + 4;
        assertEquals(storageDataCountBefore + addCounts, storage.getCount());
    }
    // 新插入数据;
    final int NEW_INSERTED_COUNT = 18;
    for (i = 0; i < NEW_INSERTED_COUNT; i++) {
        rand.nextBytes(dataBuf);
        sn = maxSN + 1 + i;
        nd = mkt.setData(sn, "KEY-" + sn, 0, dataBuf);
        expectedDataNodes.put(sn, nd.getNodeHash());
    }
    mkt.commit();
    {
        // 验证每一个数据节点都产生了存在性证明;
        MerkleProof proof = null;
        for (Long n : expectedDataNodes.keySet()) {
            proof = mkt.getProof(n.longValue());
            assertNotNull(proof);
            assertEquals(expectedDataNodes.get(n), proof.getDataHash());
        }
    }
    // 记录一次提交的根哈希以及部分节点信息,用于后续的加载校验;
    HashDigest r3_rootHash = mkt.getRootHash();
    long r3_maxSN = mkt.getMaxSn();
    long r3_sn1 = r2_sn1;
    String r3_proof1 = mkt.getProof(r3_sn1).toString();
    long r3_sn2 = r2_sn2;
    String r3_proof2 = mkt.getProof(r3_sn2).toString();
    long r3_sn3 = 4096 + NEW_INSERTED_COUNT - 5;
    String r3_proof3 = mkt.getProof(r3_sn3).toString();
    {
        // 检查节点数;
        assertEquals(count + NEW_INSERTED_COUNT, mkt.getDataCount());
        // 检查最大序列号的正确性;
        maxSN = mkt.getMaxSn();
        // count-1;
        long expectedMaxSN = 4096 + NEW_INSERTED_COUNT;
        assertEquals(expectedMaxSN, maxSN);
    }
    // --------------------
    // 重新从存储加载生成新的 MerkleTree 实例,验证与初始实例的一致性;
    // 从第 2 轮提交的 Merkle 根哈希加载;
    MerkleSequenceTree r1_mkt = new MerkleSequenceTree(r1_rootHash, setting, keyPrefix, storage, true);
    assertEquals(r1_maxSN, r1_mkt.getMaxSn());
    assertEquals(r1_rootHash, r1_mkt.getRootHash());
    assertEquals(r1_dataCount, r1_mkt.getDataCount());
    assertEquals(r1_proof1, r1_mkt.getProof(r1_sn1).toString());
    assertEquals(r1_proof2, r1_mkt.getProof(r1_sn2).toString());
    // 从第 2 轮提交的 Merkle 根哈希加载;
    // 第 2 轮生成的 Merkle 树是对第 1 轮的数据的全部节点的修改,因此同一个 SN 的节点的证明是不同的;
    MerkleSequenceTree r2_mkt = new MerkleSequenceTree(r2_rootHash, setting, keyPrefix, storage, true);
    assertEquals(r1_maxSN, r2_mkt.getMaxSn());
    assertEquals(r1_dataCount, r2_mkt.getDataCount());
    assertNotEquals(r1_rootHash, r2_mkt.getRootHash());
    assertNotEquals(r1_proof1, r2_mkt.getProof(r1_sn1).toString());
    assertNotEquals(r1_proof2, r2_mkt.getProof(r1_sn2).toString());
    assertEquals(r2_maxSN, r2_mkt.getMaxSn());
    assertEquals(r2_rootHash, r2_mkt.getRootHash());
    assertEquals(r2_dataCount, r2_mkt.getDataCount());
    assertEquals(r2_proof1, r2_mkt.getProof(r2_sn1).toString());
    assertEquals(r2_proof2, r2_mkt.getProof(r2_sn2).toString());
    // 从第 3 轮提交的 Merkle 根哈希加载;
    // 第 3 轮生成的 Merkle 树是在第 2 轮的数据基础上做新增,因此非新增的同一个 SN 的节点的Merkle证明是相同的;
    MerkleSequenceTree r3_mkt = new MerkleSequenceTree(r3_rootHash, setting, keyPrefix, storage, true);
    assertEquals(r2_maxSN + NEW_INSERTED_COUNT, r3_mkt.getMaxSn());
    assertNotEquals(r2_rootHash, r3_mkt.getRootHash());
    assertEquals(r2_dataCount + NEW_INSERTED_COUNT, r3_mkt.getDataCount());
    assertEquals(r3_maxSN, r3_mkt.getMaxSn());
    assertEquals(r3_rootHash, r3_mkt.getRootHash());
    assertEquals(r3_proof1, r3_mkt.getProof(r3_sn1).toString());
    assertEquals(r3_proof2, r3_mkt.getProof(r3_sn2).toString());
    assertEquals(r3_proof3, r3_mkt.getProof(r3_sn3).toString());
    // 验证每一个数据节点都产生了存在性证明;
    {
        MerkleProof proof = null;
        for (Long n : expectedDataNodes.keySet()) {
            proof = r3_mkt.getProof(n.longValue());
            assertNotNull(proof);
            assertEquals(expectedDataNodes.get(n), proof.getDataHash());
        }
    }
}
Also used : MerkleSequenceTree(com.jd.blockchain.ledger.proof.MerkleSequenceTree) MerkleProof(com.jd.blockchain.ledger.MerkleProof) TreeMap(java.util.TreeMap) CryptoSetting(com.jd.blockchain.ledger.CryptoSetting) HashDigest(com.jd.blockchain.crypto.HashDigest) Random(java.util.Random) ExistancePolicyKVStorageMap(com.jd.blockchain.storage.service.utils.ExistancePolicyKVStorageMap) MerkleDataNode(com.jd.blockchain.ledger.MerkleDataNode) MerkleNode(com.jd.blockchain.ledger.MerkleNode)

Example 4 with MerkleNode

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

the class MerkleSequenceTreeTest method testRandomInsert_MultiCommit.

/**
 * 测试以多次提交的方式随机地插入数据;
 */
@Test
public void testRandomInsert_MultiCommit() {
    CryptoSetting setting = Mockito.mock(CryptoSetting.class);
    when(setting.getHashAlgorithm()).thenReturn(ClassicAlgorithm.SHA256.code());
    when(setting.getAutoVerifyHash()).thenReturn(true);
    // 保存所有写入的数据节点的 SN-Hash 映射表;
    TreeMap<Long, HashDigest> dataNodes = new TreeMap<>();
    MerkleNode nd;
    // 测试从空的树开始,顺序增加数据节点;
    ExistancePolicyKVStorageMap kvs1 = new ExistancePolicyKVStorageMap();
    MerkleSequenceTree mkt = new MerkleSequenceTree(setting, keyPrefix, kvs1);
    // 加入 30 条数据记录,分两批各15条分别从序号两端加入,预期构成以一颗 4 层 16 叉树;
    int count = 4097;
    byte[] dataBuf = new byte[16];
    Random rand = new Random();
    long sn = 0;
    for (int i = 0; i < 15; i++) {
        rand.nextBytes(dataBuf);
        nd = mkt.setData(sn, "KEY-" + sn, 0, dataBuf);
        dataNodes.put(sn, nd.getNodeHash());
        sn++;
    }
    sn = count - 1;
    for (int i = 0; i < 15; i++) {
        rand.nextBytes(dataBuf);
        nd = mkt.setData(sn, "KEY-" + sn, 0, dataBuf);
        dataNodes.put(sn, nd.getNodeHash());
        sn--;
    }
    mkt.commit();
    assertEquals(30, mkt.getDataCount());
    // 检查最大序列号的正确性;
    long maxSN = mkt.getMaxSn();
    assertEquals(count - 1, maxSN);
    // 预期扩展到 4 层;
    assertEquals(4, mkt.getLevel());
    // 路径节点 + 数据节点;
    // 预期扩展为 4 层16叉树,共9个路径节点,加30个数据节点;
    long expectedNodes = 9 + 30;
    assertEquals(expectedNodes, kvs1.getCount());
    // ---------------------------------
    // 在 15 - 4081 之间随机插入;
    int randomInterval = 4082 - 15;
    List<Long> snPool = new LinkedList<>();
    for (int i = 0; i < randomInterval; i++) {
        snPool.add(15L + i);
    }
    for (int i = 0; i < randomInterval; i++) {
        int selected = rand.nextInt(snPool.size());
        sn = snPool.remove(selected).longValue();
        rand.nextBytes(dataBuf);
        nd = mkt.setData(sn, "KEY-" + sn, 0, dataBuf);
        dataNodes.put(sn, nd.getNodeHash());
    }
    mkt.commit();
    assertEquals(4097, mkt.getDataCount());
    // 检查最大序列号的正确性;
    maxSN = mkt.getMaxSn();
    assertEquals(count - 1, maxSN);
    // 预期扩展到 4 层;
    assertEquals(4, mkt.getLevel());
    // 路径节点 + 数据节点;
    // 预期扩展为 4 层16叉树,之前的路径节点全部被重新计算哈希, 等同于在3层满16叉树之上加入1条记录,共273路径节点,加上 sn 为 4096
    // 的数据对于 4个路径节点(由于是上次写入的,4个路径节点中本次只更新了根节点);
    expectedNodes = expectedNodes + 273 + 1 + randomInterval;
    assertEquals(expectedNodes, kvs1.getCount());
// TODO: 暂时注释掉默克尔证明相关的内容;
// 验证每一个数据节点都产生了存在性证明;
// MerkleProof proof = null;
// for (Long n : dataNodes.keySet()) {
// proof = mkt.getProof(n.longValue());
// assertNotNull(proof);
// assertEquals(dataNodes.get(n), proof.getDataHash());
// }
}
Also used : MerkleSequenceTree(com.jd.blockchain.ledger.proof.MerkleSequenceTree) TreeMap(java.util.TreeMap) LinkedList(java.util.LinkedList) CryptoSetting(com.jd.blockchain.ledger.CryptoSetting) HashDigest(com.jd.blockchain.crypto.HashDigest) Random(java.util.Random) ExistancePolicyKVStorageMap(com.jd.blockchain.storage.service.utils.ExistancePolicyKVStorageMap) MerkleNode(com.jd.blockchain.ledger.MerkleNode) Test(org.junit.Test)

Example 5 with MerkleNode

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

the class MerkleSequenceTree method getProof.

/**
 * 返回数据的默克尔证明;
 *
 * <p>
 * 如果不存在,则返回 null;
 * <p>
 * 如果 sn 超出范围,则引发 {@link IndexOutOfBoundsException} ;
 *
 * @param sn 数据的序列号;
 * @return 默克尔证明的实例;
 */
public MerkleProof getProof(long sn) {
    MerkleNode[] nodePath = new MerkleNode[root.level + 1];
    MerkleDataNode dataNode = seekPath(sn, nodePath);
    if (dataNode == null) {
        return null;
    }
    for (int i = 0; i < nodePath.length; i++) {
        if (i < nodePath.length - 1) {
            // PathNode will be changed on updating data;
            // So record the path info with the immutable ProofNodeEntry instead;
            PathNode n = (PathNode) nodePath[i];
            ProofNodeEntry p = new ProofNodeEntry();
            p.nodeHash = n.getNodeHash();
            p.level = n.getLevel();
            p.dataCount = n.getDataCount();
            p.startingSN = n.getStartingSN();
            nodePath[i] = p;
        }
    }
    HashDigest[] hashPaths = ArrayUtils.cast(nodePath, HashDigest.class, p -> p.getNodeHash());
    MerkleProofBuilder.create(hashPaths[0]);
    throw new IllegalStateException("Not implemented!");
}
Also used : HashDigest(com.jd.blockchain.crypto.HashDigest) MerkleDataNode(com.jd.blockchain.ledger.MerkleDataNode) MerkleNode(com.jd.blockchain.ledger.MerkleNode)

Aggregations

MerkleNode (com.jd.blockchain.ledger.MerkleNode)6 HashDigest (com.jd.blockchain.crypto.HashDigest)5 CryptoSetting (com.jd.blockchain.ledger.CryptoSetting)4 MerkleSequenceTree (com.jd.blockchain.ledger.proof.MerkleSequenceTree)4 ExistancePolicyKVStorageMap (com.jd.blockchain.storage.service.utils.ExistancePolicyKVStorageMap)4 Random (java.util.Random)4 TreeMap (java.util.TreeMap)4 MerkleDataNode (com.jd.blockchain.ledger.MerkleDataNode)3 Test (org.junit.Test)3 MerkleProof (com.jd.blockchain.ledger.MerkleProof)1 LinkedList (java.util.LinkedList)1