diff --git a/source/ledger/ledger-core/src/test/java/com/jd/blockchain/ledger/core/MerkleDataNodeEncoderTest.java b/source/ledger/ledger-core/src/test/java/com/jd/blockchain/ledger/core/MerkleDataNodeEncoderTest.java index 558ddc95..d8757e0e 100644 --- a/source/ledger/ledger-core/src/test/java/com/jd/blockchain/ledger/core/MerkleDataNodeEncoderTest.java +++ b/source/ledger/ledger-core/src/test/java/com/jd/blockchain/ledger/core/MerkleDataNodeEncoderTest.java @@ -18,26 +18,39 @@ public class MerkleDataNodeEncoderTest { @Test public void testEnocoderV0() { - MerkleDataNodeEncoder encoderV0 = new MerkleDataNodeEncoder_V0(); + Random rand = new Random(); byte[] data = new byte[512]; - byte[] key = new byte[256]; + byte[] keyBytes = new byte[256]; rand.nextBytes(data); - rand.nextBytes(key); + rand.nextBytes(keyBytes); + Bytes key = new Bytes(keyBytes); long sn = 1024; long version = 1; - - DataNode nodeV0 = encoderV0.create(ClassicAlgorithm.SHA256.code(), sn, new Bytes(key), version, data); + doTestV0(sn, version, key, data); + + sn = 0; + version = 1000; + doTestV0(sn, version, key, data); + + sn = (1 << 56) -1; + version = 1000; + doTestV0(sn, version, key, data); + } + + private void doTestV0(long sn, long version, Bytes key, byte[] data) { + MerkleDataNodeEncoder encoderV0 = new MerkleDataNodeEncoder_V0(); + DataNode nodeV0 = encoderV0.create(ClassicAlgorithm.SHA256.code(), sn, key, version, data); assertNull(nodeV0.getValueHash()); assertEquals(sn, nodeV0.getSN()); assertEquals(version, nodeV0.getVersion()); - assertEquals(new Bytes(key), nodeV0.getKey()); + assertEquals(key, nodeV0.getKey()); byte[] nodeBytes = nodeV0.toBytes(); @@ -47,37 +60,47 @@ public class MerkleDataNodeEncoderTest { assertEquals(nodeV0.getNodeHash(), nodeV0_reversed.getNodeHash()); assertEquals(encoderV0.getFormatVersion(), nodeBytes[0]); - assertEquals(sn, nodeV0_reversed.getSN()); assertEquals(version, nodeV0_reversed.getVersion()); - assertEquals(new Bytes(key), nodeV0_reversed.getKey()); + assertEquals(key, nodeV0_reversed.getKey()); } @Test public void testEnocoderV1() { - MerkleDataNodeEncoder encoderV1 = new MerkleDataNodeEncoder_V1(); - Random rand = new Random(); byte[] data = new byte[512]; - byte[] key = new byte[256]; + byte[] keyBytes = new byte[256]; rand.nextBytes(data); - rand.nextBytes(key); - - HashFunction hashFunc = Crypto.getHashFunction(ClassicAlgorithm.SHA256); - HashDigest dataHash = hashFunc.hash(data); + rand.nextBytes(keyBytes); + Bytes key = new Bytes(keyBytes); long sn = 1024; long version = 1; - - DataNode node = encoderV1.create(ClassicAlgorithm.SHA256.code(), sn, new Bytes(key), version, data); + doTestV1(sn, version, key, data); + + sn = 0; + version = 10088; + doTestV1(sn, version, key, data); + + sn = (1 << 56) -1; + version = 1000; + doTestV1(sn, version, key, data); + } + + private void doTestV1(long sn, long version, Bytes key, byte[] data) { + HashFunction hashFunc = Crypto.getHashFunction(ClassicAlgorithm.SHA256); + HashDigest dataHash = hashFunc.hash(data); + + MerkleDataNodeEncoder encoderV1 = new MerkleDataNodeEncoder_V1(); + DataNode node = encoderV1.create(ClassicAlgorithm.SHA256.code(), sn, key, version, data); assertEquals(dataHash, node.getValueHash()); assertEquals(sn, node.getSN()); assertEquals(version, node.getVersion()); - assertEquals(new Bytes(key), node.getKey()); + assertEquals(key, node.getKey()); byte[] nodeBytes = node.toBytes(); @@ -89,8 +112,42 @@ public class MerkleDataNodeEncoderTest { assertEquals(sn, node_reversed.getSN()); assertEquals(version, node_reversed.getVersion()); - assertEquals(new Bytes(key), node_reversed.getKey()); - + assertEquals(key, node_reversed.getKey()); } + @Test + public void testCompatibility() { + Random rand = new Random(); + + byte[] data = new byte[512]; + byte[] keyBytes = new byte[256]; + + rand.nextBytes(data); + rand.nextBytes(keyBytes); + + Bytes key = new Bytes(keyBytes); + + long sn = 1024; + long version = 1; + + + PreviousDataNode pdataNode = PreviousDataNode.newDataNode(ClassicAlgorithm.SHA256.code(), sn, key, version, + data); + + MerkleDataNodeEncoder encoderV0 = new MerkleDataNodeEncoder_V0(); + DataNode dataNode = encoderV0.create(ClassicAlgorithm.SHA256.code(), sn, key, version, data); + + assertEquals(pdataNode.getNodeHash(), dataNode.getNodeHash()); + assertEquals(pdataNode.getSN(), dataNode.getSN()); + assertEquals(pdataNode.getVersion(), dataNode.getVersion()); + assertEquals(pdataNode.getKey(), dataNode.getKey()); + + DataNode dataNode_reversed = encoderV0.resolve(pdataNode.toBytes()); + + assertNull(dataNode_reversed.getValueHash()); + assertEquals(pdataNode.getNodeHash(), dataNode_reversed.getNodeHash()); + assertEquals(pdataNode.getSN(), dataNode_reversed.getSN()); + assertEquals(pdataNode.getVersion(), dataNode_reversed.getVersion()); + assertEquals(pdataNode.getKey(), dataNode_reversed.getKey()); + } } diff --git a/source/ledger/ledger-core/src/test/java/com/jd/blockchain/ledger/core/PreviousDataNode.java b/source/ledger/ledger-core/src/test/java/com/jd/blockchain/ledger/core/PreviousDataNode.java new file mode 100644 index 00000000..49f0039c --- /dev/null +++ b/source/ledger/ledger-core/src/test/java/com/jd/blockchain/ledger/core/PreviousDataNode.java @@ -0,0 +1,191 @@ +package com.jd.blockchain.ledger.core; + +import com.jd.blockchain.crypto.Crypto; +import com.jd.blockchain.crypto.CryptoAlgorithm; +import com.jd.blockchain.crypto.HashDigest; +import com.jd.blockchain.crypto.HashFunction; +import com.jd.blockchain.utils.Bytes; +import com.jd.blockchain.utils.io.BytesUtils; +import com.jd.blockchain.utils.io.NumberMask; + + + +/** + * A copy of previous version of com.jd.blockchain.ledger.core.MerkleTree.DataNode; + * + * @author huanghaiquan + * + */ +public class PreviousDataNode { + + private HashDigest nodeHash; + + private long sn; + + private Bytes key; + + private long version; + + private byte[] dataNodeBytes; + + private PreviousDataNode(long sn, Bytes key, long version, HashDigest dataHash, byte[] dataBytes) { + this.sn = sn; + this.key = key; + this.version = version; + this.nodeHash = dataHash; + this.dataNodeBytes = dataBytes; + } + + static PreviousDataNode newDataNode(CryptoAlgorithm hashAlgorithm, long sn, Bytes key, long version, + byte[] hashedData) { + return newDataNode(hashAlgorithm.code(), sn, key, version, hashedData); + } + + static PreviousDataNode newDataNode(short hashAlgorithm, long sn, Bytes key, long version, byte[] hashedData) { + // byte[] keyStrBytes = BytesUtils.toBytes(key); + // int maskSize = NumberMask.SHORT.getMaskLength(keyStrBytes.length); + int keySize = key.size(); + int maskSize = NumberMask.SHORT.getMaskLength(keySize); + + // int bodySize = 8 + maskSize + keyStrBytes.length + 8;// sn + key + version; + int bodySize = 8 + maskSize + keySize + 8;// sn + key + version; + byte[] bodyBytes = new byte[bodySize]; + + int offset = 0; + offset += BytesUtils.toBytes(sn, bodyBytes, 0); + + // NumberMask.SHORT.writeMask(keyStrBytes.length, bodyBytes, offset); + NumberMask.SHORT.writeMask(keySize, bodyBytes, offset); + offset += maskSize; + + // System.arraycopy(keyStrBytes, 0, bodyBytes, offset, keyStrBytes.length); + // System.arraycopy(keyStrBytes, 0, bodyBytes, offset, keyStrBytes.length); + // offset += keyStrBytes.length; + offset += key.copyTo(bodyBytes, offset, keySize); + + // TODO: version; + offset += BytesUtils.toBytes(version, bodyBytes, offset); + + byte[] dataBytes = BytesUtils.concat(bodyBytes, hashedData); + + HashFunction hashFunc = Crypto.getHashFunction(hashAlgorithm); + HashDigest dataHash = hashFunc.hash(dataBytes); + + int hashMaskSize = NumberMask.TINY.getMaskLength(dataHash.size()); + int dataNodeSize = bodySize + hashMaskSize + dataHash.size(); + byte[] dataNodeBytes = new byte[dataNodeSize]; + + offset = 0; + System.arraycopy(bodyBytes, 0, dataNodeBytes, offset, bodySize); + offset += bodySize; + NumberMask.TINY.writeMask(dataHash.size(), dataNodeBytes, offset); + offset += hashMaskSize; + System.arraycopy(dataHash.toBytes(), 0, dataNodeBytes, offset, dataHash.size()); + + return new PreviousDataNode(sn, key, version, dataHash, dataNodeBytes); + } + + public HashDigest getNodeHash() { + return nodeHash; + } + + protected long getStartingSN() { + return sn; + } + + protected long getDataCount() { + return 1; + } + + /* + * (non-Javadoc) + * + * @see com.jd.blockchain.ledger.core.MerkleDataNode#getLevel() + */ + public int getLevel() { + return 0; + } + + /* + * (non-Javadoc) + * + * @see com.jd.blockchain.ledger.core.MerkleDataNode#getSN() + */ + public long getSN() { + return sn; + } + + /* + * (non-Javadoc) + * + * @see com.jd.blockchain.ledger.core.MerkleDataNode#getKey() + */ + public Bytes getKey() { + return key; + } + + /* + * (non-Javadoc) + * + * @see com.jd.blockchain.ledger.core.MerkleDataNode#getVersion() + */ + public long getVersion() { + return version; + } + + public byte[] toBytes() { + return dataNodeBytes; + } + + static PreviousDataNode parse(byte[] bytes) { + // InputStream in = new ByteArrayInputStream(bytes); + + int offset = 0; + long sn = BytesUtils.toLong(bytes, offset); + offset += 8; + + // byte[] keyBytes = BytesEncoding.read(NumberMask.SHORT, in); + // String key = BytesUtils.toString(keyBytes); + int keySize = NumberMask.SHORT.resolveMaskedNumber(bytes, offset); + offset += NumberMask.SHORT.getMaskLength(keySize); + byte[] keyBytes = new byte[keySize]; + System.arraycopy(bytes, offset, keyBytes, 0, keySize); + offset += keySize; + // String key = BytesUtils.toString(keyBytes); + Bytes key = new Bytes(keyBytes); + + // long version = BytesUtils.readLong(in); + long version = BytesUtils.toLong(bytes, offset); + offset += 8; + + // byte[] dataHashBytes = BytesEncoding.read(NumberMask.SHORT, in); + int hashSize = NumberMask.TINY.resolveMaskedNumber(bytes, offset); + offset += NumberMask.TINY.getMaskLength(hashSize); + byte[] dataHashBytes = new byte[hashSize]; + System.arraycopy(bytes, offset, dataHashBytes, 0, hashSize); + offset += hashSize; + HashDigest dataHash = new HashDigest(dataHashBytes); + return new PreviousDataNode(sn, key, version, dataHash, bytes); + } + + @Override + public int hashCode() { + return nodeHash.hashCode(); + } + + @Override + public boolean equals(Object obj) { + if (obj == null) { + return false; + } + if (obj == this) { + return true; + } + if (obj instanceof PreviousDataNode) { + PreviousDataNode node1 = (PreviousDataNode) obj; + return this.nodeHash.equals(node1.nodeHash); + } + return false; + } + +} \ No newline at end of file