diff --git a/source/base/pom.xml b/source/base/pom.xml index f1daa601..ca3f56cf 100644 --- a/source/base/pom.xml +++ b/source/base/pom.xml @@ -5,7 +5,7 @@ com.jd.blockchain jdchain-root - 1.1.1-PACK20191209 + 1.1.2.RELEASE base diff --git a/source/base/src/main/java/com/jd/blockchain/consts/DataCodes.java b/source/base/src/main/java/com/jd/blockchain/consts/DataCodes.java index e3e2506c..cd1da3d5 100644 --- a/source/base/src/main/java/com/jd/blockchain/consts/DataCodes.java +++ b/source/base/src/main/java/com/jd/blockchain/consts/DataCodes.java @@ -121,12 +121,16 @@ public interface DataCodes { public static final int ACCOUNT_HEADER = 0x710; - public static final int USER = 0x800; + public static final int USER_ACCOUNT_HEADER = 0x800; + + public static final int USER_INFO = 0x801; public static final int DATA = 0x900; // contract related; - public static final int CONTRACT = 0xA00; + public static final int CONTRACT_ACCOUNT_HEADER = 0xA00; + + public static final int CONTRACT_INFO = 0xA01; // ...0xA19 public static final int HASH = 0xB00; diff --git a/source/binary-proto/pom.xml b/source/binary-proto/pom.xml index 08f1a013..50c1debc 100644 --- a/source/binary-proto/pom.xml +++ b/source/binary-proto/pom.xml @@ -5,7 +5,7 @@ com.jd.blockchain jdchain-root - 1.1.1-PACK20191209 + 1.1.2.RELEASE binary-proto diff --git a/source/binary-proto/src/main/java/com/jd/blockchain/binaryproto/impl/DynamicDataContract.java b/source/binary-proto/src/main/java/com/jd/blockchain/binaryproto/impl/DynamicDataContract.java index aaa8780b..58b94e25 100644 --- a/source/binary-proto/src/main/java/com/jd/blockchain/binaryproto/impl/DynamicDataContract.java +++ b/source/binary-proto/src/main/java/com/jd/blockchain/binaryproto/impl/DynamicDataContract.java @@ -21,8 +21,6 @@ class DynamicDataContract implements InvocationHandler { private DataContractEncoderImpl contractEncoder; -// private BytesSlice contractBytes; - // 字段的数据片段列表,首个是 HeaderSlice,其次是按字段顺序排列的数据片段; private BytesSlices[] dataSlices; diff --git a/source/consensus/consensus-bftsmart/pom.xml b/source/consensus/consensus-bftsmart/pom.xml index 88f22e5f..3a21c5e4 100644 --- a/source/consensus/consensus-bftsmart/pom.xml +++ b/source/consensus/consensus-bftsmart/pom.xml @@ -5,7 +5,7 @@ com.jd.blockchain consensus - 1.1.1-PACK20191209 + 1.1.2.RELEASE consensus-bftsmart diff --git a/source/consensus/consensus-bftsmart/src/main/java/com/jd/blockchain/consensus/bftsmart/service/BftsmartNodeServer.java b/source/consensus/consensus-bftsmart/src/main/java/com/jd/blockchain/consensus/bftsmart/service/BftsmartNodeServer.java index 297ccebe..61a6a619 100644 --- a/source/consensus/consensus-bftsmart/src/main/java/com/jd/blockchain/consensus/bftsmart/service/BftsmartNodeServer.java +++ b/source/consensus/consensus-bftsmart/src/main/java/com/jd/blockchain/consensus/bftsmart/service/BftsmartNodeServer.java @@ -10,6 +10,7 @@ import bftsmart.consensus.app.BatchAppResultImpl; import bftsmart.tom.*; import com.jd.blockchain.binaryproto.BinaryProtocol; import com.jd.blockchain.consensus.service.*; +import com.jd.blockchain.crypto.HashDigest; import com.jd.blockchain.ledger.*; import com.jd.blockchain.transaction.TxResponseMessage; import com.jd.blockchain.utils.serialize.binary.BinarySerializeUtils; @@ -354,141 +355,97 @@ public class BftsmartNodeServer extends DefaultRecoverable implements NodeServer // }); } - /** - * - * Used by consensus write phase, pre compute new block hash - * - */ -// public BatchAppResultImpl preComputeAppHash(byte[][] commands) { -// String batchId = messageHandle.beginBatch(realmName); -// List> asyncFutureLinkedList = new ArrayList<>(commands.length); -// List responseLinkedList = new ArrayList<>(); -// try { -// int msgId = 0; -// for (byte[] txContent : commands) { -// AsyncFuture asyncFuture = messageHandle.processOrdered(msgId++, txContent, realmName, batchId); -// asyncFutureLinkedList.add(asyncFuture); -// } -// StateSnapshot stateSnapshot = messageHandle.completeBatch(realmName, batchId); -// byte[] blockHashBytes = stateSnapshot.getSnapshot(); -// -// for (int i = 0; i< asyncFutureLinkedList.size(); i++) { -// responseLinkedList.add(asyncFutureLinkedList.get(i).get()); -// } -// -// -// return new BatchAppResultImpl(responseLinkedList, blockHashBytes, batchId); -// -// } catch (Exception e) { -// // todo 需要处理应答码 404 -// LOGGER.error("Error occurred while processing ordered messages! --" + e.getMessage(), e); -// messageHandle.rollbackBatch(realmName, batchId, TransactionState.IGNORED_BY_CONSENSUS_PHASE_PRECOMPUTE_ROLLBACK.CODE); -// } -// -// return null; -// } - /** * Used by consensus write phase, pre compute new block hash */ public BatchAppResultImpl preComputeAppHash(byte[][] commands) { - String batchId = messageHandle.beginBatch(realmName); + List> asyncFutureLinkedList = new ArrayList<>(commands.length); List responseLinkedList = new ArrayList<>(); - BatchAppResultImpl result; + StateSnapshot newStateSnapshot = null; + StateSnapshot preStateSnapshot = null; + StateSnapshot genisStateSnapshot = null; + BatchAppResultImpl result = null; + String batchId = null; + int msgId = 0; + try { - int msgId = 0; - boolean isOK = true; - TransactionState transactionState = TransactionState.IGNORED_BY_BLOCK_FULL_ROLLBACK; + batchId = messageHandle.beginBatch(realmName); + genisStateSnapshot = messageHandle.getGenisStateSnapshot(realmName); + preStateSnapshot = messageHandle.getStateSnapshot(realmName); + + if (preStateSnapshot == null) { + throw new IllegalStateException("Pre block state snapshot is null!"); + } for (int i = 0; i < commands.length; i++) { byte[] txContent = commands[i]; - try { - AsyncFuture asyncFuture = messageHandle.processOrdered(msgId++, txContent, realmName, batchId); - asyncFutureLinkedList.add(asyncFuture); - } catch (BlockRollbackException e) { - LOGGER.error("Error occurred while processing ordered messages! --" + e.getMessage(), e); - isOK = false; - // TODO: handle the BlockRollbackException in detail; - if (e instanceof DataVersionConflictException) { - transactionState = TransactionState.DATA_VERSION_CONFLICT; - } - break; - } + AsyncFuture asyncFuture = messageHandle.processOrdered(msgId++, txContent, realmName, batchId); + asyncFutureLinkedList.add(asyncFuture); } + newStateSnapshot = messageHandle.completeBatch(realmName, batchId); - if (isOK) { - StateSnapshot stateSnapshot = messageHandle.completeBatch(realmName, batchId); - byte[] blockHashBytes = stateSnapshot.getSnapshot(); - - for (int i = 0; i < asyncFutureLinkedList.size(); i++) { - responseLinkedList.add(asyncFutureLinkedList.get(i).get()); - } - - result = new BatchAppResultImpl(responseLinkedList, blockHashBytes, batchId); - result.setErrorCode((byte) 0); - - return result; - } else { - - for (int i = 0; i < commands.length; i++) { - responseLinkedList.add(createAppResponse(commands[i],transactionState)); - } - - Random random = new Random(); - byte[] rand = new byte[4]; - random.nextBytes(rand); + for (int i = 0; i < asyncFutureLinkedList.size(); i++) { + responseLinkedList.add(asyncFutureLinkedList.get(i).get()); + } - result = new BatchAppResultImpl(responseLinkedList, rand, batchId); - result.setErrorCode((byte) 1); + result = new BatchAppResultImpl(responseLinkedList, newStateSnapshot.getSnapshot(), batchId, genisStateSnapshot.getSnapshot()); + result.setErrorCode((byte) 0); - return result; + } catch (Exception e) { + LOGGER.error("Error occurred while pre compute app! --" + e.getMessage(), e); + for (int i = 0; i < commands.length; i++) { + responseLinkedList.add(createAppResponse(commands[i],TransactionState.IGNORED_BY_BLOCK_FULL_ROLLBACK)); } - } catch (Exception e) { - LOGGER.error("Error occurred while genearte batch app result! --" + e.getMessage(), e); - throw e; + result = new BatchAppResultImpl(responseLinkedList,preStateSnapshot.getSnapshot(), batchId, genisStateSnapshot.getSnapshot()); + result.setErrorCode((byte) 1); } + + return result; } - public byte[] createAppResponse(byte[] command, TransactionState transactionState) { + // Block full rollback responses, generated in pre compute phase, due to tx exception + private byte[] createAppResponse(byte[] command, TransactionState transactionState) { TransactionRequest txRequest = BinaryProtocol.decode(command); TxResponseMessage resp = new TxResponseMessage(txRequest.getTransactionContent().getHash()); -// resp.setExecutionState(TransactionState.IGNORED_BY_BLOCK_FULL_ROLLBACK); + resp.setExecutionState(transactionState); return BinaryProtocol.encode(resp, TransactionResponse.class); } - /** - * - * Consensus write phase will terminate, new block hash values are inconsistent, update batch messages execute state - * - */ - public List updateAppResponses(List asyncResponseLinkedList) { + public List updateAppResponses(List asyncResponseLinkedList, byte[] commonHash, boolean isConsistent) { List updatedResponses = new ArrayList<>(); + TxResponseMessage resp = null; for(int i = 0; i < asyncResponseLinkedList.size(); i++) { TransactionResponse txResponse = BinaryProtocol.decode(asyncResponseLinkedList.get(i)); - TxResponseMessage resp = new TxResponseMessage(txResponse.getContentHash()); - resp.setExecutionState(TransactionState.IGNORED_BY_CONSENSUS_PHASE_PRECOMPUTE_ROLLBACK); + if (isConsistent) { + resp = new TxResponseMessage(txResponse.getContentHash()); + } + else { + resp = new TxResponseMessage(new HashDigest(commonHash)); + } + resp.setExecutionState(TransactionState.IGNORED_BY_BLOCK_FULL_ROLLBACK); updatedResponses.add(BinaryProtocol.encode(resp, TransactionResponse.class)); - } - - return updatedResponses; } - + return updatedResponses; +} /** * * Decision has been made at the consensus stage, commit block * */ public void preComputeAppCommit(String batchId) { - - messageHandle.commitBatch(realmName, batchId); - + try { + messageHandle.commitBatch(realmName, batchId); + } catch (BlockRollbackException e) { + LOGGER.error("Error occurred while pre compute commit --" + e.getMessage(), e); + throw e; + } } /** @@ -497,7 +454,7 @@ public class BftsmartNodeServer extends DefaultRecoverable implements NodeServer * */ public void preComputeAppRollback(String batchId) { - messageHandle.rollbackBatch(realmName, batchId, TransactionState.IGNORED_BY_CONSENSUS_PHASE_PRECOMPUTE_ROLLBACK.CODE); + messageHandle.rollbackBatch(realmName, batchId, TransactionState.IGNORED_BY_BLOCK_FULL_ROLLBACK.CODE); LOGGER.debug("Rollback of operations that cause inconsistencies in the ledger"); } diff --git a/source/consensus/consensus-framework/pom.xml b/source/consensus/consensus-framework/pom.xml index b2ee168a..9409e169 100644 --- a/source/consensus/consensus-framework/pom.xml +++ b/source/consensus/consensus-framework/pom.xml @@ -5,7 +5,7 @@ com.jd.blockchain consensus - 1.1.1-PACK20191209 + 1.1.2.RELEASE consensus-framework diff --git a/source/consensus/consensus-framework/src/main/java/com/jd/blockchain/consensus/ConsensusProviders.java b/source/consensus/consensus-framework/src/main/java/com/jd/blockchain/consensus/ConsensusProviders.java index c1b8c58c..58853099 100644 --- a/source/consensus/consensus-framework/src/main/java/com/jd/blockchain/consensus/ConsensusProviders.java +++ b/source/consensus/consensus-framework/src/main/java/com/jd/blockchain/consensus/ConsensusProviders.java @@ -19,7 +19,8 @@ public class ConsensusProviders { provider = providers.get(className); if (provider == null) { provider = loadProvider(ConsensusProvider.class, className); - providers.put(className, provider); +// providers.put(className, provider); + registerProvider(provider); } } } diff --git a/source/consensus/consensus-framework/src/main/java/com/jd/blockchain/consensus/service/MessageHandle.java b/source/consensus/consensus-framework/src/main/java/com/jd/blockchain/consensus/service/MessageHandle.java index 4e0e1b89..e864d2d0 100644 --- a/source/consensus/consensus-framework/src/main/java/com/jd/blockchain/consensus/service/MessageHandle.java +++ b/source/consensus/consensus-framework/src/main/java/com/jd/blockchain/consensus/service/MessageHandle.java @@ -59,4 +59,19 @@ public interface MessageHandle { */ AsyncFuture processUnordered(byte[] message); + /** + * 获得当前最新区块的状态快照 + * + * @param realmName + * @return 最新区块的状态快照 + */ + StateSnapshot getStateSnapshot(String realmName); + + /** + * 获得创世区块的状态快照 + * @param realmName + * @return 创世区块的状态快照 + */ + StateSnapshot getGenisStateSnapshot(String realmName); + } diff --git a/source/consensus/consensus-mq/pom.xml b/source/consensus/consensus-mq/pom.xml index 0479b332..c1b13078 100644 --- a/source/consensus/consensus-mq/pom.xml +++ b/source/consensus/consensus-mq/pom.xml @@ -5,7 +5,7 @@ com.jd.blockchain consensus - 1.1.1-PACK20191209 + 1.1.2.RELEASE consensus-mq diff --git a/source/consensus/pom.xml b/source/consensus/pom.xml index 2d335393..c5ad1d10 100644 --- a/source/consensus/pom.xml +++ b/source/consensus/pom.xml @@ -5,7 +5,7 @@ com.jd.blockchain jdchain-root - 1.1.1-PACK20191209 + 1.1.2.RELEASE consensus pom diff --git a/source/contract/contract-framework/pom.xml b/source/contract/contract-framework/pom.xml index 82cabef7..cf934009 100644 --- a/source/contract/contract-framework/pom.xml +++ b/source/contract/contract-framework/pom.xml @@ -5,7 +5,7 @@ com.jd.blockchain contract - 1.1.1-PACK20191209 + 1.1.2.RELEASE contract-framework diff --git a/source/contract/contract-jvm/pom.xml b/source/contract/contract-jvm/pom.xml index aeedac36..19501b8b 100644 --- a/source/contract/contract-jvm/pom.xml +++ b/source/contract/contract-jvm/pom.xml @@ -5,7 +5,7 @@ com.jd.blockchain contract - 1.1.1-PACK20191209 + 1.1.2.RELEASE contract-jvm diff --git a/source/contract/contract-maven-plugin/pom.xml b/source/contract/contract-maven-plugin/pom.xml index 62a40ec5..91c815b7 100644 --- a/source/contract/contract-maven-plugin/pom.xml +++ b/source/contract/contract-maven-plugin/pom.xml @@ -5,7 +5,7 @@ com.jd.blockchain contract - 1.1.1-PACK20191209 + 1.1.2.RELEASE contract-maven-plugin maven-plugin diff --git a/source/contract/contract-samples/pom.xml b/source/contract/contract-samples/pom.xml index 68b351fe..15ac70d8 100644 --- a/source/contract/contract-samples/pom.xml +++ b/source/contract/contract-samples/pom.xml @@ -5,7 +5,7 @@ contract com.jd.blockchain - 1.1.1-PACK20191209 + 1.1.2.RELEASE 4.0.0 diff --git a/source/contract/contract-samples/src/main/java/com/jd/blockchain/contract/ReadContractImpl.java b/source/contract/contract-samples/src/main/java/com/jd/blockchain/contract/ReadContractImpl.java index e3d720a5..2f6e0610 100644 --- a/source/contract/contract-samples/src/main/java/com/jd/blockchain/contract/ReadContractImpl.java +++ b/source/contract/contract-samples/src/main/java/com/jd/blockchain/contract/ReadContractImpl.java @@ -1,7 +1,7 @@ package com.jd.blockchain.contract; import com.jd.blockchain.crypto.HashDigest; -import com.jd.blockchain.ledger.KVDataEntry; +import com.jd.blockchain.ledger.TypedKVEntry; @Contract public class ReadContractImpl implements EventProcessingAware, ReadContract { @@ -24,7 +24,7 @@ public class ReadContractImpl implements EventProcessingAware, ReadContract { @Override @ContractEvent(name = "read-key") public String read(String address, String key) { - KVDataEntry[] kvDataEntries = eventContext.getLedger().getDataEntries(ledgerHash, address, key); + TypedKVEntry[] kvDataEntries = eventContext.getLedger().getDataEntries(ledgerHash, address, key); if (kvDataEntries != null && kvDataEntries.length == 1) { return kvDataEntries[0].getValue().toString(); @@ -35,7 +35,7 @@ public class ReadContractImpl implements EventProcessingAware, ReadContract { @Override @ContractEvent(name = "version-key") public Long readVersion(String address, String key) { - KVDataEntry[] kvDataEntries = eventContext.getLedger().getDataEntries(ledgerHash, address, key); + TypedKVEntry[] kvDataEntries = eventContext.getLedger().getDataEntries(ledgerHash, address, key); if (kvDataEntries != null && kvDataEntries.length == 1) { return kvDataEntries[0].getVersion(); diff --git a/source/contract/contract-samples/src/main/java/com/jd/blockchain/contract/TransferContractImpl.java b/source/contract/contract-samples/src/main/java/com/jd/blockchain/contract/TransferContractImpl.java index c312dd4f..d29ee281 100644 --- a/source/contract/contract-samples/src/main/java/com/jd/blockchain/contract/TransferContractImpl.java +++ b/source/contract/contract-samples/src/main/java/com/jd/blockchain/contract/TransferContractImpl.java @@ -2,7 +2,7 @@ package com.jd.blockchain.contract; import com.alibaba.fastjson.JSON; import com.jd.blockchain.crypto.HashDigest; -import com.jd.blockchain.ledger.KVDataEntry; +import com.jd.blockchain.ledger.TypedKVEntry; import com.jd.blockchain.ledger.KVDataVO; import com.jd.blockchain.ledger.KVInfoVO; @@ -14,7 +14,7 @@ public class TransferContractImpl implements EventProcessingAware, TransferContr @Override public String create(String address, String account, long money) { - KVDataEntry[] kvDataEntries = eventContext.getLedger().getDataEntries(ledgerHash, address, account); + TypedKVEntry[] kvDataEntries = eventContext.getLedger().getDataEntries(ledgerHash, address, account); // 肯定有返回值,但若不存在则返回version=-1 if (kvDataEntries != null && kvDataEntries.length > 0) { long currVersion = kvDataEntries[0].getVersion(); @@ -32,13 +32,13 @@ public class TransferContractImpl implements EventProcessingAware, TransferContr @Override public String transfer(String address, String from, String to, long money) { // 首先查询余额 - KVDataEntry[] kvDataEntries = eventContext.getLedger().getDataEntries(ledgerHash, address, from, to); + TypedKVEntry[] kvDataEntries = eventContext.getLedger().getDataEntries(ledgerHash, address, from, to); if (kvDataEntries == null || kvDataEntries.length != 2) { throw new IllegalStateException(String.format("%s -> %s - %s may be not created !!!", address, from, to)); } else { // 判断from账号中钱数量是否足够 long fromMoney = 0L, toMoney = 0L, fromVersion = 0L, toVersion = 0L; - for (KVDataEntry kvDataEntry : kvDataEntries) { + for (TypedKVEntry kvDataEntry : kvDataEntries) { if (kvDataEntry.getKey().equals(from)) { fromMoney = (long) kvDataEntry.getValue(); fromVersion = kvDataEntry.getVersion(); @@ -62,7 +62,7 @@ public class TransferContractImpl implements EventProcessingAware, TransferContr @Override public long read(String address, String account) { - KVDataEntry[] kvDataEntries = eventContext.getLedger().getDataEntries(ledgerHash, address, account); + TypedKVEntry[] kvDataEntries = eventContext.getLedger().getDataEntries(ledgerHash, address, account); if (kvDataEntries == null || kvDataEntries.length == 0) { return -1; } @@ -71,7 +71,7 @@ public class TransferContractImpl implements EventProcessingAware, TransferContr @Override public String readAll(String address, String account) { - KVDataEntry[] kvDataEntries = eventContext.getLedger().getDataEntries(ledgerHash, address, account); + TypedKVEntry[] kvDataEntries = eventContext.getLedger().getDataEntries(ledgerHash, address, account); // 获取最新的版本号 if (kvDataEntries == null || kvDataEntries.length == 0) { return ""; @@ -91,7 +91,7 @@ public class TransferContractImpl implements EventProcessingAware, TransferContr KVInfoVO kvInfoVO = new KVInfoVO(kvDataVOS); - KVDataEntry[] allEntries = eventContext.getLedger().getDataEntries(ledgerHash, address, kvInfoVO); + TypedKVEntry[] allEntries = eventContext.getLedger().getDataEntries(ledgerHash, address, kvInfoVO); return JSON.toJSONString(allEntries); } diff --git a/source/contract/pom.xml b/source/contract/pom.xml index a05f4661..d88eb189 100644 --- a/source/contract/pom.xml +++ b/source/contract/pom.xml @@ -4,7 +4,7 @@ com.jd.blockchain jdchain-root - 1.1.1-PACK20191209 + 1.1.2.RELEASE contract pom diff --git a/source/crypto/crypto-adv/pom.xml b/source/crypto/crypto-adv/pom.xml index 6c6a9536..4841494b 100644 --- a/source/crypto/crypto-adv/pom.xml +++ b/source/crypto/crypto-adv/pom.xml @@ -5,7 +5,7 @@ com.jd.blockchain crypto - 1.1.1-PACK20191209 + 1.1.2.RELEASE crypto-adv diff --git a/source/crypto/crypto-classic/pom.xml b/source/crypto/crypto-classic/pom.xml index bba14fc0..1b15926b 100644 --- a/source/crypto/crypto-classic/pom.xml +++ b/source/crypto/crypto-classic/pom.xml @@ -5,7 +5,7 @@ com.jd.blockchain crypto - 1.1.1-PACK20191209 + 1.1.2.RELEASE crypto-classic diff --git a/source/crypto/crypto-classic/src/main/java/com/jd/blockchain/crypto/service/classic/RIPEMD160HashFunction.java b/source/crypto/crypto-classic/src/main/java/com/jd/blockchain/crypto/service/classic/RIPEMD160HashFunction.java index 47172e87..bddbc99b 100644 --- a/source/crypto/crypto-classic/src/main/java/com/jd/blockchain/crypto/service/classic/RIPEMD160HashFunction.java +++ b/source/crypto/crypto-classic/src/main/java/com/jd/blockchain/crypto/service/classic/RIPEMD160HashFunction.java @@ -5,12 +5,10 @@ import static com.jd.blockchain.crypto.CryptoBytes.ALGORYTHM_CODE_SIZE; import java.util.Arrays; import com.jd.blockchain.crypto.CryptoAlgorithm; -import com.jd.blockchain.crypto.CryptoBytes; import com.jd.blockchain.crypto.CryptoException; import com.jd.blockchain.crypto.HashDigest; import com.jd.blockchain.crypto.HashFunction; import com.jd.blockchain.crypto.utils.classic.RIPEMD160Utils; -import com.jd.blockchain.utils.security.RipeMD160Utils; public class RIPEMD160HashFunction implements HashFunction { @@ -19,7 +17,7 @@ public class RIPEMD160HashFunction implements HashFunction { private static final int DIGEST_BYTES = 160 / 8; private static final int DIGEST_LENGTH = ALGORYTHM_CODE_SIZE + DIGEST_BYTES; - + RIPEMD160HashFunction() { } @@ -30,7 +28,6 @@ public class RIPEMD160HashFunction implements HashFunction { @Override public HashDigest hash(byte[] data) { - if (data == null) { throw new CryptoException("data is null!"); } @@ -39,6 +36,16 @@ public class RIPEMD160HashFunction implements HashFunction { return new HashDigest(RIPEMD160, digestBytes); } + @Override + public HashDigest hash(byte[] data, int offset, int len) { + if (data == null) { + throw new CryptoException("data is null!"); + } + + byte[] digestBytes = RIPEMD160Utils.hash(data, offset, len); + return new HashDigest(RIPEMD160, digestBytes); + } + @Override public boolean verify(HashDigest digest, byte[] data) { HashDigest hashDigest = hash(data); @@ -59,5 +66,5 @@ public class RIPEMD160HashFunction implements HashFunction { throw new CryptoException("digestBytes is invalid!"); } } - + } diff --git a/source/crypto/crypto-classic/src/main/java/com/jd/blockchain/crypto/service/classic/SHA256HashFunction.java b/source/crypto/crypto-classic/src/main/java/com/jd/blockchain/crypto/service/classic/SHA256HashFunction.java index 7ba4ec6a..307a85e1 100644 --- a/source/crypto/crypto-classic/src/main/java/com/jd/blockchain/crypto/service/classic/SHA256HashFunction.java +++ b/source/crypto/crypto-classic/src/main/java/com/jd/blockchain/crypto/service/classic/SHA256HashFunction.java @@ -5,12 +5,10 @@ import static com.jd.blockchain.crypto.CryptoBytes.ALGORYTHM_CODE_SIZE; import java.util.Arrays; import com.jd.blockchain.crypto.CryptoAlgorithm; -import com.jd.blockchain.crypto.CryptoBytes; import com.jd.blockchain.crypto.CryptoException; import com.jd.blockchain.crypto.HashDigest; import com.jd.blockchain.crypto.HashFunction; import com.jd.blockchain.crypto.utils.classic.SHA256Utils; -import com.jd.blockchain.utils.security.ShaUtils; public class SHA256HashFunction implements HashFunction { @@ -30,7 +28,6 @@ public class SHA256HashFunction implements HashFunction { @Override public HashDigest hash(byte[] data) { - if (data == null) { throw new CryptoException("data is null!"); } @@ -38,6 +35,16 @@ public class SHA256HashFunction implements HashFunction { byte[] digestBytes = SHA256Utils.hash(data); return new HashDigest(SHA256, digestBytes); } + + @Override + public HashDigest hash(byte[] data, int offset, int len) { + if (data == null) { + throw new CryptoException("data is null!"); + } + + byte[] digestBytes = SHA256Utils.hash(data, offset, len); + return new HashDigest(SHA256, digestBytes); + } @Override public boolean verify(HashDigest digest, byte[] data) { diff --git a/source/crypto/crypto-classic/src/main/java/com/jd/blockchain/crypto/utils/classic/RIPEMD160Utils.java b/source/crypto/crypto-classic/src/main/java/com/jd/blockchain/crypto/utils/classic/RIPEMD160Utils.java index 05b11a6a..0ce73eab 100644 --- a/source/crypto/crypto-classic/src/main/java/com/jd/blockchain/crypto/utils/classic/RIPEMD160Utils.java +++ b/source/crypto/crypto-classic/src/main/java/com/jd/blockchain/crypto/utils/classic/RIPEMD160Utils.java @@ -10,16 +10,26 @@ import org.bouncycastle.crypto.digests.RIPEMD160Digest; */ public class RIPEMD160Utils { - // The length of RIPEMD160 output is 20 bytes - private static final int RIPEMD160DIGEST_LENGTH = 160 / 8; + // The length of RIPEMD160 output is 20 bytes + public static final int RIPEMD160DIGEST_LENGTH = 160 / 8; - public static byte[] hash(byte[] data){ + public static byte[] hash(byte[] data) { - byte[] result = new byte[RIPEMD160DIGEST_LENGTH]; - RIPEMD160Digest ripemd160Digest = new RIPEMD160Digest(); + byte[] result = new byte[RIPEMD160DIGEST_LENGTH]; + RIPEMD160Digest ripemd160Digest = new RIPEMD160Digest(); - ripemd160Digest.update(data,0,data.length); - ripemd160Digest.doFinal(result,0); - return result; - } + ripemd160Digest.update(data, 0, data.length); + ripemd160Digest.doFinal(result, 0); + return result; + } + + public static byte[] hash(byte[] data, int offset, int len) { + + byte[] result = new byte[RIPEMD160DIGEST_LENGTH]; + RIPEMD160Digest ripemd160Digest = new RIPEMD160Digest(); + + ripemd160Digest.update(data, offset, len); + ripemd160Digest.doFinal(result, 0); + return result; + } } diff --git a/source/crypto/crypto-classic/src/main/java/com/jd/blockchain/crypto/utils/classic/SHA256Utils.java b/source/crypto/crypto-classic/src/main/java/com/jd/blockchain/crypto/utils/classic/SHA256Utils.java index a4a6523e..017a2b7a 100644 --- a/source/crypto/crypto-classic/src/main/java/com/jd/blockchain/crypto/utils/classic/SHA256Utils.java +++ b/source/crypto/crypto-classic/src/main/java/com/jd/blockchain/crypto/utils/classic/SHA256Utils.java @@ -11,7 +11,7 @@ import org.bouncycastle.crypto.digests.SHA256Digest; public class SHA256Utils { // The length of SHA256 output is 32 bytes - private static final int SHA256DIGEST_LENGTH = 256 / 8; + public static final int SHA256DIGEST_LENGTH = 256 / 8; public static byte[] hash(byte[] data){ @@ -22,4 +22,14 @@ public class SHA256Utils { sha256Digest.doFinal(result,0); return result; } + + public static byte[] hash(byte[] data, int offset, int len){ + + byte[] result = new byte[SHA256DIGEST_LENGTH]; + SHA256Digest sha256Digest = new SHA256Digest(); + + sha256Digest.update(data, offset, len); + sha256Digest.doFinal(result,0); + return result; + } } diff --git a/source/crypto/crypto-framework/pom.xml b/source/crypto/crypto-framework/pom.xml index 8b3fe207..b720b24a 100644 --- a/source/crypto/crypto-framework/pom.xml +++ b/source/crypto/crypto-framework/pom.xml @@ -5,7 +5,7 @@ com.jd.blockchain crypto - 1.1.1-PACK20191209 + 1.1.2.RELEASE crypto-framework diff --git a/source/crypto/crypto-framework/src/main/java/com/jd/blockchain/crypto/HashFunction.java b/source/crypto/crypto-framework/src/main/java/com/jd/blockchain/crypto/HashFunction.java index 8a1069de..26afa778 100644 --- a/source/crypto/crypto-framework/src/main/java/com/jd/blockchain/crypto/HashFunction.java +++ b/source/crypto/crypto-framework/src/main/java/com/jd/blockchain/crypto/HashFunction.java @@ -10,6 +10,14 @@ public interface HashFunction extends CryptoFunction { */ HashDigest hash(byte[] data); + /** + * 计算指定数据的 hash; + * + * @param data + * @return + */ + HashDigest hash(byte[] data, int offset, int len); + /** * 校验 hash 摘要与指定的数据是否匹配; diff --git a/source/crypto/crypto-pki/pom.xml b/source/crypto/crypto-pki/pom.xml index 0b5b3b94..f4633b41 100644 --- a/source/crypto/crypto-pki/pom.xml +++ b/source/crypto/crypto-pki/pom.xml @@ -5,7 +5,7 @@ crypto com.jd.blockchain - 1.1.1-PACK20191209 + 1.1.2.RELEASE 4.0.0 diff --git a/source/crypto/crypto-sm/pom.xml b/source/crypto/crypto-sm/pom.xml index f0dd548f..9aa68f29 100644 --- a/source/crypto/crypto-sm/pom.xml +++ b/source/crypto/crypto-sm/pom.xml @@ -5,7 +5,7 @@ com.jd.blockchain crypto - 1.1.1-PACK20191209 + 1.1.2.RELEASE crypto-sm diff --git a/source/crypto/crypto-sm/src/main/java/com/jd/blockchain/crypto/service/sm/SM3HashFunction.java b/source/crypto/crypto-sm/src/main/java/com/jd/blockchain/crypto/service/sm/SM3HashFunction.java index 85fb943c..79893ae5 100644 --- a/source/crypto/crypto-sm/src/main/java/com/jd/blockchain/crypto/service/sm/SM3HashFunction.java +++ b/source/crypto/crypto-sm/src/main/java/com/jd/blockchain/crypto/service/sm/SM3HashFunction.java @@ -16,7 +16,7 @@ public class SM3HashFunction implements HashFunction { private static final int DIGEST_BYTES = 256 / 8; private static final int DIGEST_LENGTH = CryptoBytes.ALGORYTHM_CODE_SIZE + DIGEST_BYTES; - + SM3HashFunction() { } @@ -27,7 +27,6 @@ public class SM3HashFunction implements HashFunction { @Override public HashDigest hash(byte[] data) { - if (data == null) { throw new CryptoException("data is null!"); } @@ -36,6 +35,16 @@ public class SM3HashFunction implements HashFunction { return new HashDigest(SM3, digestBytes); } + @Override + public HashDigest hash(byte[] data, int offset, int len) { + if (data == null) { + throw new CryptoException("data is null!"); + } + + byte[] digestBytes = SM3Utils.hash(data, offset, len); + return new HashDigest(SM3, digestBytes); + } + @Override public boolean verify(HashDigest digest, byte[] data) { HashDigest hashDigest = hash(data); diff --git a/source/crypto/crypto-sm/src/main/java/com/jd/blockchain/crypto/utils/sm/SM3Utils.java b/source/crypto/crypto-sm/src/main/java/com/jd/blockchain/crypto/utils/sm/SM3Utils.java index 6272a990..282a403c 100644 --- a/source/crypto/crypto-sm/src/main/java/com/jd/blockchain/crypto/utils/sm/SM3Utils.java +++ b/source/crypto/crypto-sm/src/main/java/com/jd/blockchain/crypto/utils/sm/SM3Utils.java @@ -4,19 +4,30 @@ import org.bouncycastle.crypto.digests.SM3Digest; public class SM3Utils { - // The length of sm3 output is 32 bytes - private static final int SM3DIGEST_LENGTH = 32; + // The length of sm3 output is 32 bytes + public static final int SM3DIGEST_LENGTH = 32; - public static byte[] hash(byte[] data) { + public static byte[] hash(byte[] data) { - byte[] result = new byte[SM3DIGEST_LENGTH]; + byte[] result = new byte[SM3DIGEST_LENGTH]; - SM3Digest sm3digest = new SM3Digest(); + SM3Digest sm3digest = new SM3Digest(); - sm3digest.update(data, 0, data.length); - sm3digest.doFinal(result, 0); + sm3digest.update(data, 0, data.length); + sm3digest.doFinal(result, 0); - return result; - } -} + return result; + } + + public static byte[] hash(byte[] data, int offset, int len) { + + byte[] result = new byte[SM3DIGEST_LENGTH]; + SM3Digest sm3digest = new SM3Digest(); + + sm3digest.update(data, offset, len); + sm3digest.doFinal(result, 0); + + return result; + } +} diff --git a/source/crypto/pom.xml b/source/crypto/pom.xml index ac3ef3ca..f9774b54 100644 --- a/source/crypto/pom.xml +++ b/source/crypto/pom.xml @@ -5,7 +5,7 @@ com.jd.blockchain jdchain-root - 1.1.1-PACK20191209 + 1.1.2.RELEASE crypto pom diff --git a/source/deployment/deployment-autotest/src/test/java/com/jd/blockchain/AppTest.java b/source/deployment/deployment-autotest/src/test/java/com/jd/blockchain/AppTest.java deleted file mode 100644 index 941b907f..00000000 --- a/source/deployment/deployment-autotest/src/test/java/com/jd/blockchain/AppTest.java +++ /dev/null @@ -1,20 +0,0 @@ -package com.jd.blockchain; - -import static org.junit.Assert.assertTrue; - -import org.junit.Test; - -/** - * Unit test for simple App. - */ -public class AppTest -{ - /** - * Rigorous Test :-) - */ - @Test - public void shouldAnswerWithTrue() - { - assertTrue( true ); - } -} diff --git a/source/deployment/deployment-gateway/pom.xml b/source/deployment/deployment-gateway/pom.xml index 029c2fd1..ea4f9310 100644 --- a/source/deployment/deployment-gateway/pom.xml +++ b/source/deployment/deployment-gateway/pom.xml @@ -5,7 +5,7 @@ com.jd.blockchain deployment - 1.1.1-PACK20191209 + 1.1.2.RELEASE deployment-gateway @@ -66,6 +66,28 @@ + + + + net.nicoulaj.maven.plugins + checksum-maven-plugin + 1.8 + + + + artifacts + + + + + + SHA-256 + + ${project.basedir}/target/deployment-peer-${project.version}.zip + true + ${project.basedir}/target/SHA-256.xml + + \ No newline at end of file diff --git a/source/deployment/deployment-gateway/src/main/resources/assembly.xml b/source/deployment/deployment-gateway/src/main/resources/assembly.xml index 39811c14..861990d0 100644 --- a/source/deployment/deployment-gateway/src/main/resources/assembly.xml +++ b/source/deployment/deployment-gateway/src/main/resources/assembly.xml @@ -12,14 +12,17 @@ src/main/resources/scripts bin + unix src/main/resources/config config + unix src/main/resources/docs docs + unix diff --git a/source/deployment/deployment-gateway/src/main/resources/config/gateway.conf b/source/deployment/deployment-gateway/src/main/resources/config/gateway.conf index 7d4915d5..b0bcb4af 100644 --- a/source/deployment/deployment-gateway/src/main/resources/config/gateway.conf +++ b/source/deployment/deployment-gateway/src/main/resources/config/gateway.conf @@ -20,7 +20,7 @@ peer.providers=com.jd.blockchain.consensus.bftsmart.BftsmartConsensusProvider #若该值不配置或配置不正确,则浏览器模糊查询部分无法正常显示 #数据检索服务模块(Argus)需单独部署,若不部署其他功能仍可正常使用 data.retrieval.url=http://127.0.0.1:10001 -schema.retrieval.url=http://192.168.151.40:8082 +schema.retrieval.url=http://127.0.0.1:8082 #默认公钥的内容(Base58编码数据); keys.default.pubkey= diff --git a/source/deployment/deployment-gateway/src/main/resources/docs/api_doc_cn_1.4.MD b/source/deployment/deployment-gateway/src/main/resources/docs/api_doc_cn_1.4.MD index 7ff79c96..017b97d2 100644 --- a/source/deployment/deployment-gateway/src/main/resources/docs/api_doc_cn_1.4.MD +++ b/source/deployment/deployment-gateway/src/main/resources/docs/api_doc_cn_1.4.MD @@ -1768,7 +1768,7 @@ KVInfoVO对应格式如下: KVInfoVO说明: + 1)支持多个Key作为入参; - + + 2)每个Key支持多个version; @@ -1808,6 +1808,57 @@ http://localhost/ledgers/657TQAw6ssVoeKniWGwbovk7njvCTvikPambM9eBv6ezs/accounts/ |type|value类型| |value|值| +### 6.9 查询某数据账户键数量 +``` +GET /ledgers/{ledger}/accounts/address/{address}/keys/count/search?keyword={keyword} +``` +#### 参数 +请求类型 | 名称 | 是否必需 | 说明 | 数据类型 +--- | --- | --- | --- | --- +path | ledger | 是 | 所要搜索的账本,需要完整的账本哈希 | string +path | address | 是 | 所要搜索的数据账户地址,需要完整的数据账户地址 | string +query | keyword | 否 | 键的部分字符,空表示全部 | string + +#### 请求实例 +``` +http://localhost/ledgers/657TQAw6ssVoeKniWGwbovk7njvCTvikPambM9eBv6ezs/accounts/address/5Sm4gWXrNpDWW9Boi4xZCzZMHboRvEDm29Fa/keys/count/search?keyword=j +``` +#### 返回实例 +``` +{ "data": 66, "success": true } +``` +说明 + +名称 | 说明 +--- | --- +data | 条件查询键总数 + +### 6.10 查询某数据账户键 +``` +GET /ledgers/{ledger}/accounts/address/{address}/keys/search?keyword={keyword}&fromIndex={start_index}&count={count} +``` +#### 参数 +请求类型 | 名称 | 是否必需 | 说明 | 数据类型 +--- | --- | --- | --- | --- +path | ledger | 是 | 所要搜索的账本,需要完整的账本哈希 | string +path | address | 是 | 所要搜索的数据账户地址,需要完整的数据账户地址 | string +query | keyword | 否 | 键的部分字符,空表示全部 | string +query | start_index | 否 | 查询数据账户对应Key的起始序号,默认为0 | 数字 +query | count | 否 | 查询返回数据账户对应Key的数量,默认最大返回值为100,小于0或大于100均返回最大可返回结果集 | 数字 + +#### 请求实例 +``` +http://localhost/ledgers/657TQAw6ssVoeKniWGwbovk7njvCTvikPambM9eBv6ezs/accounts/address/5Sm4gWXrNpDWW9Boi4xZCzZMHboRvEDm29Fa/keys/search?keyword=j&fromIndex=0&count=-1 +``` +#### 返回实例 +``` +{ "data": [ { "key": "jd" }, { "key": "jdchain" }], "success": true } +``` +说明 + +名称 | 说明 +--- | --- +key | 键 ## 7 搜索 diff --git a/source/deployment/deployment-gateway/src/main/resources/scripts/startup.sh b/source/deployment/deployment-gateway/src/main/resources/scripts/startup.sh index 915c33f3..62272d19 100644 --- a/source/deployment/deployment-gateway/src/main/resources/scripts/startup.sh +++ b/source/deployment/deployment-gateway/src/main/resources/scripts/startup.sh @@ -2,8 +2,18 @@ HOME=$(cd `dirname $0`;cd ../; pwd) GATEWAY=$(ls $HOME/lib | grep deployment-gateway-) +PROC_INFO=$HOME/lib/$GATEWAY" -c "$HOME/config/gateway.conf +#echo $PROC_INFO +#get PID +PID=`ps -ef | grep "$PROC_INFO" | grep -v grep | awk '{print $2}'` +#echo $PID +if [[ ! -z $PID ]] +then + echo "process already exists,please check... If necessary, you should kill the process first." + exit +fi if [ ! -n "$GATEWAY" ]; then echo "GateWay Is Null !!!" else - nohup java -jar -server -Djdchain.log=$HOME $HOME/lib/$GATEWAY -c $HOME/config/gateway.conf $* >$HOME/bin/gw.out 2>&1 & + nohup java -jar -server -Djdchain.log=$HOME $PROC_INFO $* >$HOME/bin/gw.out 2>&1 & fi \ No newline at end of file diff --git a/source/deployment/deployment-peer/pom.xml b/source/deployment/deployment-peer/pom.xml index 25c9879c..266e5855 100644 --- a/source/deployment/deployment-peer/pom.xml +++ b/source/deployment/deployment-peer/pom.xml @@ -5,7 +5,7 @@ com.jd.blockchain deployment - 1.1.1-PACK20191209 + 1.1.2.RELEASE deployment-peer @@ -101,6 +101,28 @@ + + + net.nicoulaj.maven.plugins + checksum-maven-plugin + 1.8 + + + + artifacts + + + + + + SHA-256 + + ${project.basedir}/target/deployment-peer-${project.version}.zip + true + ${project.basedir}/target/SHA-256.xml + + + \ No newline at end of file diff --git a/source/deployment/deployment-peer/src/main/resources/assembly.xml b/source/deployment/deployment-peer/src/main/resources/assembly.xml index 881c0aef..37aa494c 100644 --- a/source/deployment/deployment-peer/src/main/resources/assembly.xml +++ b/source/deployment/deployment-peer/src/main/resources/assembly.xml @@ -12,14 +12,17 @@ src/main/resources/scripts bin + unix src/main/resources/config config + unix src/main/resources/docs docs + unix diff --git a/source/deployment/deployment-peer/src/main/resources/config/init/ledger.init b/source/deployment/deployment-peer/src/main/resources/config/init/ledger.init index e84f24f5..8f06ac57 100644 --- a/source/deployment/deployment-peer/src/main/resources/config/init/ledger.init +++ b/source/deployment/deployment-peer/src/main/resources/config/init/ledger.init @@ -87,7 +87,7 @@ cons_parti.0.consensus.host=127.0.0.1 #第0个参与方的共识服务的端口; cons_parti.0.consensus.port=8900 #第0个参与方的共识服务是否开启安全连接; -cons_parti.0.consensus.secure=true +cons_parti.0.consensus.secure=false #第0个参与方的账本初始服务的主机; cons_parti.0.initializer.host=127.0.0.1 diff --git a/source/deployment/deployment-peer/src/main/resources/scripts/manager-startup.sh b/source/deployment/deployment-peer/src/main/resources/scripts/manager-startup.sh index 790dfdfd..e630da5f 100644 --- a/source/deployment/deployment-peer/src/main/resources/scripts/manager-startup.sh +++ b/source/deployment/deployment-peer/src/main/resources/scripts/manager-startup.sh @@ -2,8 +2,18 @@ HOME=$(cd `dirname $0`;cd ../; pwd) UMP=$(ls $HOME/manager | grep manager-booter-) +PROC_INFO=$HOME/manager/$UMP" -home "$HOME" -p 8000" +#echo $PROC_INFO +#get PID +PID=`ps -ef | grep "$PROC_INFO" | grep -v grep | awk '{print $2}'` +#echo $PID +if [[ ! -z $PID ]] +then + echo "process already exists,please check... If necessary, you should kill the process first." + exit +fi if [ ! -n "UMP" ]; then echo "JDChain Manager Is Null !!!" else - nohup java -jar -server -Djdchain.log=$HOME $HOME/manager/$UMP -home $HOME -p 8000 $* >$HOME/bin/jump.out 2>&1 & + nohup java -jar -server -Djdchain.log=$HOME $PROC_INFO $* >$HOME/bin/jump.out 2>&1 & fi \ No newline at end of file diff --git a/source/deployment/deployment-peer/src/main/resources/scripts/peer-startup.sh b/source/deployment/deployment-peer/src/main/resources/scripts/peer-startup.sh index bbdf3aa7..407b30ea 100644 --- a/source/deployment/deployment-peer/src/main/resources/scripts/peer-startup.sh +++ b/source/deployment/deployment-peer/src/main/resources/scripts/peer-startup.sh @@ -2,8 +2,18 @@ HOME=$(cd `dirname $0`;cd ../; pwd) PEER=$(ls $HOME/system | grep deployment-peer-) +PROC_INFO=$HOME/system/$PEER" -home="$HOME" -c "$HOME/config/ledger-binding.conf" -p 7080" +#echo $PROC_INFO +#get PID +PID=`ps -ef | grep "$PROC_INFO" | grep -v grep | awk '{print $2}'` +#echo $PID +if [[ ! -z $PID ]] +then + echo "process already exists,please check... If necessary, you should kill the process first." + exit +fi if [ ! -n "$PEER" ]; then echo "Peer Is Null !!!" else - nohup java -jar -server -Xmx2g -Xms2g -Djdchain.log=$HOME $HOME/system/$PEER -home=$HOME -c $HOME/config/ledger-binding.conf -p 7080 $* >$HOME/bin/peer.out 2>&1 & + nohup java -jar -server -Xmx1g -Xms1g -Djdchain.log=$HOME $PROC_INFO $* >$HOME/bin/peer.out 2>&1 & fi \ No newline at end of file diff --git a/source/deployment/pom.xml b/source/deployment/pom.xml index e67a8ef0..fef74936 100644 --- a/source/deployment/pom.xml +++ b/source/deployment/pom.xml @@ -5,7 +5,7 @@ com.jd.blockchain jdchain-root - 1.1.1-PACK20191209 + 1.1.2.RELEASE deployment pom diff --git a/source/gateway/pom.xml b/source/gateway/pom.xml index 875cd46b..e7632327 100644 --- a/source/gateway/pom.xml +++ b/source/gateway/pom.xml @@ -5,7 +5,7 @@ com.jd.blockchain jdchain-root - 1.1.1-PACK20191209 + 1.1.2.RELEASE gateway diff --git a/source/gateway/src/main/java/com/jd/blockchain/gateway/web/BlockBrowserController.java b/source/gateway/src/main/java/com/jd/blockchain/gateway/web/BlockBrowserController.java index 2b480825..97780f62 100644 --- a/source/gateway/src/main/java/com/jd/blockchain/gateway/web/BlockBrowserController.java +++ b/source/gateway/src/main/java/com/jd/blockchain/gateway/web/BlockBrowserController.java @@ -5,9 +5,6 @@ import java.util.List; import javax.servlet.http.HttpServletRequest; -import com.jd.blockchain.gateway.service.GatewayQueryService; -import com.jd.blockchain.sdk.LedgerBaseSettings; -import com.jd.blockchain.utils.decompiler.utils.DecompilerUtils; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.PathVariable; @@ -23,9 +20,9 @@ import com.jd.blockchain.crypto.KeyGenUtils; import com.jd.blockchain.crypto.PubKey; import com.jd.blockchain.gateway.PeerService; import com.jd.blockchain.gateway.service.DataRetrievalService; -import com.jd.blockchain.ledger.AccountHeader; +import com.jd.blockchain.gateway.service.GatewayQueryService; +import com.jd.blockchain.ledger.BlockchainIdentity; import com.jd.blockchain.ledger.ContractInfo; -import com.jd.blockchain.ledger.KVDataEntry; import com.jd.blockchain.ledger.KVInfoVO; import com.jd.blockchain.ledger.LedgerAdminInfo; import com.jd.blockchain.ledger.LedgerBlock; @@ -34,11 +31,14 @@ import com.jd.blockchain.ledger.LedgerMetadata; import com.jd.blockchain.ledger.LedgerTransaction; import com.jd.blockchain.ledger.ParticipantNode; import com.jd.blockchain.ledger.TransactionState; +import com.jd.blockchain.ledger.TypedKVEntry; import com.jd.blockchain.ledger.UserInfo; import com.jd.blockchain.sdk.BlockchainExtendQueryService; import com.jd.blockchain.sdk.ContractSettings; +import com.jd.blockchain.sdk.LedgerBaseSettings; import com.jd.blockchain.utils.BaseConstant; import com.jd.blockchain.utils.ConsoleUtils; +import com.jd.blockchain.utils.decompiler.utils.DecompilerUtils; @RestController @RequestMapping(path = "/") @@ -252,7 +252,7 @@ public class BlockBrowserController implements BlockchainExtendQueryService { @RequestMapping(method = RequestMethod.GET, path = "ledgers/{ledgerHash}/accounts/address/{address}") @Override - public AccountHeader getDataAccount(@PathVariable(name = "ledgerHash") HashDigest ledgerHash, + public BlockchainIdentity getDataAccount(@PathVariable(name = "ledgerHash") HashDigest ledgerHash, @PathVariable(name = "address") String address) { return peerService.getQueryService().getDataAccount(ledgerHash, address); @@ -261,7 +261,7 @@ public class BlockBrowserController implements BlockchainExtendQueryService { @RequestMapping(method = { RequestMethod.GET, RequestMethod.POST }, path = "ledgers/{ledgerHash}/accounts/{address}/entries") @Override - public KVDataEntry[] getDataEntries(@PathVariable("ledgerHash") HashDigest ledgerHash, + public TypedKVEntry[] getDataEntries(@PathVariable("ledgerHash") HashDigest ledgerHash, @PathVariable("address") String address, @RequestParam("keys") String... keys) { return peerService.getQueryService().getDataEntries(ledgerHash, address, keys); } @@ -269,7 +269,7 @@ public class BlockBrowserController implements BlockchainExtendQueryService { @RequestMapping(method = { RequestMethod.GET, RequestMethod.POST }, path = "ledgers/{ledgerHash}/accounts/{address}/entries-version") @Override - public KVDataEntry[] getDataEntries(@PathVariable("ledgerHash") HashDigest ledgerHash, + public TypedKVEntry[] getDataEntries(@PathVariable("ledgerHash") HashDigest ledgerHash, @PathVariable("address") String address, @RequestBody KVInfoVO kvInfoVO) { return peerService.getQueryService().getDataEntries(ledgerHash, address, kvInfoVO); } @@ -277,7 +277,7 @@ public class BlockBrowserController implements BlockchainExtendQueryService { @RequestMapping(method = { RequestMethod.GET, RequestMethod.POST }, path = "ledgers/{ledgerHash}/accounts/address/{address}/entries") @Override - public KVDataEntry[] getDataEntries(@PathVariable("ledgerHash") HashDigest ledgerHash, + public TypedKVEntry[] getDataEntries(@PathVariable("ledgerHash") HashDigest ledgerHash, @PathVariable("address") String address, @RequestParam(name = "fromIndex", required = false, defaultValue = "0") int fromIndex, @RequestParam(name = "count", required = false, defaultValue = "-1") int count) { @@ -594,7 +594,7 @@ public class BlockBrowserController implements BlockchainExtendQueryService { */ @RequestMapping(method = RequestMethod.GET, path = "ledgers/{ledgerHash}/users") @Override - public AccountHeader[] getUsers(@PathVariable(name = "ledgerHash") HashDigest ledgerHash, + public BlockchainIdentity[] getUsers(@PathVariable(name = "ledgerHash") HashDigest ledgerHash, @RequestParam(name = "fromIndex", required = false, defaultValue = "0") int fromIndex, @RequestParam(name = "count", required = false, defaultValue = "-1") int count) { return revertAccountHeader(peerService.getQueryService().getUsers(ledgerHash, fromIndex, count)); @@ -602,7 +602,7 @@ public class BlockBrowserController implements BlockchainExtendQueryService { @RequestMapping(method = RequestMethod.GET, path = "ledgers/{ledgerHash}/accounts") @Override - public AccountHeader[] getDataAccounts(@PathVariable(name = "ledgerHash") HashDigest ledgerHash, + public BlockchainIdentity[] getDataAccounts(@PathVariable(name = "ledgerHash") HashDigest ledgerHash, @RequestParam(name = "fromIndex", required = false, defaultValue = "0") int fromIndex, @RequestParam(name = "count", required = false, defaultValue = "-1") int count) { return revertAccountHeader(peerService.getQueryService().getDataAccounts(ledgerHash, fromIndex, count)); @@ -610,18 +610,18 @@ public class BlockBrowserController implements BlockchainExtendQueryService { @RequestMapping(method = RequestMethod.GET, path = "ledgers/{ledgerHash}/contracts") @Override - public AccountHeader[] getContractAccounts(@PathVariable(name = "ledgerHash") HashDigest ledgerHash, + public BlockchainIdentity[] getContractAccounts(@PathVariable(name = "ledgerHash") HashDigest ledgerHash, @RequestParam(name = "fromIndex", required = false, defaultValue = "0") int fromIndex, @RequestParam(name = "count", required = false, defaultValue = "-1") int count) { return revertAccountHeader(peerService.getQueryService().getContractAccounts(ledgerHash, fromIndex, count)); } /** - * reverse the AccountHeader[] content; the latest record show first; + * reverse the BlockchainIdentity[] content; the latest record show first; * @return */ - private AccountHeader[] revertAccountHeader(AccountHeader[] accountHeaders){ - AccountHeader[] accounts = new AccountHeader[accountHeaders.length]; + private BlockchainIdentity[] revertAccountHeader(BlockchainIdentity[] accountHeaders){ + BlockchainIdentity[] accounts = new BlockchainIdentity[accountHeaders.length]; if(accountHeaders!=null && accountHeaders.length>0){ for (int i = 0; i < accountHeaders.length; i++) { accounts[accountHeaders.length-1-i] = accountHeaders[i]; diff --git a/source/ledger/ledger-core/pom.xml b/source/ledger/ledger-core/pom.xml index 57983885..cbbfd67b 100644 --- a/source/ledger/ledger-core/pom.xml +++ b/source/ledger/ledger-core/pom.xml @@ -5,7 +5,7 @@ com.jd.blockchain ledger - 1.1.1-PACK20191209 + 1.1.2.RELEASE ledger-core diff --git a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/AccountAccessPolicy.java b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/AccountAccessPolicy.java index 2e025bf2..3ffa5536 100644 --- a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/AccountAccessPolicy.java +++ b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/AccountAccessPolicy.java @@ -2,7 +2,7 @@ package com.jd.blockchain.ledger.core; import com.jd.blockchain.crypto.PubKey; -import com.jd.blockchain.ledger.AccountHeader; +import com.jd.blockchain.ledger.BlockchainIdentity; import com.jd.blockchain.utils.Bytes; /** @@ -19,7 +19,7 @@ public interface AccountAccessPolicy { * @param account * @return Return true if it satisfies this policy, or false if it doesn't; */ - boolean checkDataWriting(AccountHeader account); + boolean checkDataWriting(BlockchainIdentity account); boolean checkRegistering(Bytes address, PubKey pubKey); diff --git a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/AccountDecorator.java b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/AccountDecorator.java new file mode 100644 index 00000000..399631ce --- /dev/null +++ b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/AccountDecorator.java @@ -0,0 +1,45 @@ +package com.jd.blockchain.ledger.core; + +import com.jd.blockchain.crypto.HashDigest; +import com.jd.blockchain.ledger.Account; +import com.jd.blockchain.ledger.BlockchainIdentity; +import com.jd.blockchain.ledger.HashProof; +import com.jd.blockchain.ledger.MerkleSnapshot; +import com.jd.blockchain.ledger.TypedValue; +import com.jd.blockchain.utils.Bytes; +import com.jd.blockchain.utils.Dataset; + +public class AccountDecorator implements Account, HashProvable, MerkleSnapshot{ + + private CompositeAccount mklAccount; + + public AccountDecorator(CompositeAccount mklAccount) { + this.mklAccount = mklAccount; + } + + protected Dataset getHeaders() { + return mklAccount.getHeaders(); + } + + + @Override + public HashDigest getRootHash() { + return mklAccount.getRootHash(); + } + + @Override + public HashProof getProof(Bytes key) { + return mklAccount.getProof(key); + } + + @Override + public BlockchainIdentity getID() { + return mklAccount.getID(); + } + + @Override + public Dataset getDataset() { + return mklAccount.getDataset(); + } + +} diff --git a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/AccountQuery.java b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/AccountQuery.java index 8f1f3cb0..23afd3fd 100644 --- a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/AccountQuery.java +++ b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/AccountQuery.java @@ -1,12 +1,11 @@ package com.jd.blockchain.ledger.core; -import com.jd.blockchain.ledger.AccountHeader; +import com.jd.blockchain.ledger.BlockchainIdentity; +import com.jd.blockchain.ledger.MerkleProof; import com.jd.blockchain.utils.Bytes; public interface AccountQuery extends MerkleProvable { - - AccountHeader[] getHeaders(int fromIndex, int count); - + /** * 返回总数; * @@ -14,7 +13,15 @@ public interface AccountQuery extends MerkleProvable { */ long getTotal(); + BlockchainIdentity[] getHeaders(int fromIndex, int count); + boolean contains(Bytes address); + + /** + * get proof of specified account; + */ + @Override + MerkleProof getProof(Bytes address); /** * 返回账户实例; diff --git a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/CompositeAccount.java b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/CompositeAccount.java new file mode 100644 index 00000000..5630917e --- /dev/null +++ b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/CompositeAccount.java @@ -0,0 +1,12 @@ +package com.jd.blockchain.ledger.core; + +import com.jd.blockchain.ledger.Account; +import com.jd.blockchain.ledger.MerkleSnapshot; +import com.jd.blockchain.ledger.TypedValue; +import com.jd.blockchain.utils.Dataset; + +public interface CompositeAccount extends Account, MerkleSnapshot, HashProvable{ + + Dataset getHeaders(); + +} diff --git a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/ContractAccount.java b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/ContractAccount.java index 69dfac2c..19c76463 100644 --- a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/ContractAccount.java +++ b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/ContractAccount.java @@ -1,81 +1,72 @@ package com.jd.blockchain.ledger.core; -import com.jd.blockchain.crypto.HashDigest; import com.jd.blockchain.crypto.PubKey; -import com.jd.blockchain.ledger.BytesData; import com.jd.blockchain.ledger.BytesValue; import com.jd.blockchain.ledger.ContractInfo; -import com.jd.blockchain.ledger.MerkleProof; +import com.jd.blockchain.ledger.TypedValue; import com.jd.blockchain.utils.Bytes; -public class ContractAccount implements ContractInfo { +public class ContractAccount extends AccountDecorator implements ContractInfo { - private static final Bytes CONTRACT_INFO_PREFIX = Bytes.fromString("INFO" + LedgerConsts.KEY_SEPERATOR); + private static final String CONTRACT_INFO_PREFIX = "INFO" + LedgerConsts.KEY_SEPERATOR; - private static final Bytes CHAIN_CODE_KEY = Bytes.fromString("CHAIN-CODE"); + private static final String CHAIN_CODE_KEY = "CHAIN-CODE"; - private MerkleAccount accBase; - - public ContractAccount(MerkleAccount accBase) { - this.accBase = accBase; + public ContractAccount(CompositeAccount mklAccount) { + super(mklAccount); } @Override public Bytes getAddress() { - return accBase.getAddress(); + return getID().getAddress(); } @Override public PubKey getPubKey() { - return accBase.getPubKey(); - } - - @Override - public HashDigest getRootHash() { - return accBase.getRootHash(); + return getID().getPubKey(); } - public MerkleProof getChaincodeProof() { - return accBase.getProof(CHAIN_CODE_KEY); - } - - public MerkleProof getPropertyProof(Bytes key) { - return accBase.getProof(encodePropertyKey(key)); - } +// public MerkleProof getChaincodeProof() { +// return getHeaders().getProof(CHAIN_CODE_KEY); +// } +// +// public MerkleProof getPropertyProof(Bytes key) { +// return getHeaders().getProof(encodePropertyKey(key)); +// } public long setChaincode(byte[] chaincode, long version) { - BytesValue bytesValue = BytesData.fromBytes(chaincode); - return accBase.setBytes(CHAIN_CODE_KEY, bytesValue, version); + TypedValue bytesValue = TypedValue.fromBytes(chaincode); + return getHeaders().setValue(CHAIN_CODE_KEY, bytesValue, version); } public byte[] getChainCode() { - return accBase.getBytes(CHAIN_CODE_KEY).getValue().toBytes(); + return getHeaders().getValue(CHAIN_CODE_KEY).getBytes().toBytes(); } public byte[] getChainCode(long version) { - return accBase.getBytes(CHAIN_CODE_KEY, version).getValue().toBytes(); + return getHeaders().getValue(CHAIN_CODE_KEY, version).getBytes().toBytes(); } public long getChaincodeVersion() { - return accBase.getVersion(CHAIN_CODE_KEY); + return getHeaders().getVersion(CHAIN_CODE_KEY); } - public long setProperty(Bytes key, String value, long version) { - BytesValue bytesValue = BytesData.fromText(value); - return accBase.setBytes(encodePropertyKey(key), bytesValue, version); + public long setProperty(String key, String value, long version) { + TypedValue bytesValue = TypedValue.fromText(value); + return getHeaders().setValue(encodePropertyKey(key), bytesValue, version); } - public String getProperty(Bytes key) { - BytesValue bytesValue = accBase.getBytes(encodePropertyKey(key)); - return BytesData.toText(bytesValue); + public String getProperty(String key) { + BytesValue bytesValue = getHeaders().getValue(encodePropertyKey(key)); + return TypedValue.wrap(bytesValue).stringValue(); } - public String getProperty(Bytes key, long version) { - BytesValue bytesValue = accBase.getBytes(encodePropertyKey(key), version); - return BytesData.toText(bytesValue); + public String getProperty(String key, long version) { + BytesValue bytesValue = getHeaders().getValue(encodePropertyKey(key), version); + return TypedValue.wrap(bytesValue).stringValue(); } - private Bytes encodePropertyKey(Bytes key) { + private String encodePropertyKey(String key) { return CONTRACT_INFO_PREFIX.concat(key); } diff --git a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/ContractAccountSet.java b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/ContractAccountSet.java index 5f4c7855..c4ee0408 100644 --- a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/ContractAccountSet.java +++ b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/ContractAccountSet.java @@ -2,7 +2,7 @@ package com.jd.blockchain.ledger.core; import com.jd.blockchain.crypto.HashDigest; import com.jd.blockchain.crypto.PubKey; -import com.jd.blockchain.ledger.AccountHeader; +import com.jd.blockchain.ledger.BlockchainIdentity; import com.jd.blockchain.ledger.CryptoSetting; import com.jd.blockchain.ledger.DigitalSignature; import com.jd.blockchain.ledger.MerkleProof; @@ -17,17 +17,18 @@ public class ContractAccountSet implements Transactional, ContractAccountQuery { public ContractAccountSet(CryptoSetting cryptoSetting, String prefix, ExPolicyKVStorage exStorage, VersioningKVStorage verStorage, AccountAccessPolicy accessPolicy) { - accountSet = new MerkleAccountSet(cryptoSetting, prefix, exStorage, verStorage, accessPolicy); + accountSet = new MerkleAccountSet(cryptoSetting, Bytes.fromString(prefix), exStorage, verStorage, accessPolicy); } public ContractAccountSet(HashDigest dataRootHash, CryptoSetting cryptoSetting, String prefix, ExPolicyKVStorage exStorage, VersioningKVStorage verStorage, boolean readonly, AccountAccessPolicy accessPolicy) { - accountSet = new MerkleAccountSet(dataRootHash, cryptoSetting, prefix, exStorage, verStorage, readonly, accessPolicy); + accountSet = new MerkleAccountSet(dataRootHash, cryptoSetting, Bytes.fromString(prefix), exStorage, verStorage, + readonly, accessPolicy); } @Override - public AccountHeader[] getHeaders(int fromIndex, int count) { + public BlockchainIdentity[] getHeaders(int fromIndex, int count) { return accountSet.getHeaders(fromIndex, count); } @@ -66,7 +67,7 @@ public class ContractAccountSet implements Transactional, ContractAccountQuery { @Override public ContractAccount getAccount(Bytes address) { - MerkleAccount accBase = accountSet.getAccount(address); + CompositeAccount accBase = accountSet.getAccount(address); return new ContractAccount(accBase); } @@ -77,7 +78,7 @@ public class ContractAccountSet implements Transactional, ContractAccountQuery { @Override public ContractAccount getAccount(Bytes address, long version) { - MerkleAccount accBase = accountSet.getAccount(address, version); + CompositeAccount accBase = accountSet.getAccount(address, version); return new ContractAccount(accBase); } @@ -92,7 +93,7 @@ public class ContractAccountSet implements Transactional, ContractAccountQuery { */ public ContractAccount deploy(Bytes address, PubKey pubKey, DigitalSignature addressSignature, byte[] chaincode) { // TODO: 校验和记录合约地址签名; - MerkleAccount accBase = accountSet.register(address, pubKey); + CompositeAccount accBase = accountSet.register(address, pubKey); ContractAccount contractAcc = new ContractAccount(accBase); contractAcc.setChaincode(chaincode, -1); return contractAcc; @@ -107,7 +108,7 @@ public class ContractAccountSet implements Transactional, ContractAccountQuery { * @return 返回链码的新版本号; */ public long update(Bytes address, byte[] chaincode, long version) { - MerkleAccount accBase = accountSet.getAccount(address); + CompositeAccount accBase = accountSet.getAccount(address); ContractAccount contractAcc = new ContractAccount(accBase); return contractAcc.setChaincode(chaincode, version); } diff --git a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/DataAccount.java b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/DataAccount.java index afaab416..4814cdf6 100644 --- a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/DataAccount.java +++ b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/DataAccount.java @@ -1,268 +1,234 @@ package com.jd.blockchain.ledger.core; -import com.jd.blockchain.binaryproto.BinaryProtocol; -import com.jd.blockchain.crypto.HashDigest; -import com.jd.blockchain.crypto.PubKey; -import com.jd.blockchain.ledger.AccountHeader; -import com.jd.blockchain.ledger.BytesData; -import com.jd.blockchain.ledger.BytesValue; -import com.jd.blockchain.ledger.KVDataEntry; -import com.jd.blockchain.ledger.KVDataObject; -import com.jd.blockchain.ledger.MerkleProof; -import com.jd.blockchain.utils.Bytes; - -public class DataAccount implements AccountHeader, MerkleProvable { - - private MerkleAccount baseAccount; - - public DataAccount(MerkleAccount accBase) { - this.baseAccount = accBase; - } - - @Override - public Bytes getAddress() { - return baseAccount.getAddress(); - } - - @Override - public PubKey getPubKey() { - return baseAccount.getPubKey(); - } - - @Override - public HashDigest getRootHash() { - return baseAccount.getRootHash(); - } - - /** - * 返回指定数据的存在性证明; - */ - @Override - public MerkleProof getProof(Bytes key) { - return baseAccount.getProof(key); - } +public class DataAccount extends AccountDecorator { + + public DataAccount(CompositeAccount mklAccount) { + super(mklAccount); + } + +// /** +// * Create or update the value associated the specified key if the version +// * checking is passed.
+// * +// * The value of the key will be updated only if it's latest version equals the +// * specified version argument.
+// * If the key doesn't exist, the version checking will be ignored, and key will +// * be created with a new sequence number as id.
+// * It also could specify the version argument to -1 to ignore the version +// * checking. +// *

+// * If updating is performed, the version of the key increase by 1.
+// * If creating is performed, the version of the key initialize by 0.
+// * +// * @param key The key of data; +// * @param value The value of data; +// * @param version The expected version of the key. +// * @return The new version of the key.
+// * If the key is new created success, then return 0;
+// * If the key is updated success, then return the new version;
+// * If this operation fail by version checking or other reason, then +// * return -1; +// */ +// public long setBytes(Bytes key, BytesValue value, long version) { +// return super.getDataset().setValue(key, value, version); +// } + +// +// /** +// * Create or update the value associated the specified key if the version +// * checking is passed.
+// * +// * The value of the key will be updated only if it's latest version equals the +// * specified version argument.
+// * If the key doesn't exist, the version checking will be ignored, and key will +// * be created with a new sequence number as id.
+// * It also could specify the version argument to -1 to ignore the version +// * checking. +// *

+// * If updating is performed, the version of the key increase by 1.
+// * If creating is performed, the version of the key initialize by 0.
+// * +// * @param key The key of data; +// * @param value The value of data; +// * @param version The expected version of the key. +// * @return The new version of the key.
+// * If the key is new created success, then return 0;
+// * If the key is updated success, then return the new version;
+// * If this operation fail by version checking or other reason, then +// * return -1; +// */ +// public long setBytes(Bytes key, String value, long version) { +// BytesValue bytesValue = TypedValue.fromText(value); +// return baseAccount.setValue(key, bytesValue, version); +// } +// +// /** +// * Create or update the value associated the specified key if the version +// * checking is passed.
+// * +// * The value of the key will be updated only if it's latest version equals the +// * specified version argument.
+// * If the key doesn't exist, the version checking will be ignored, and key will +// * be created with a new sequence number as id.
+// * It also could specify the version argument to -1 to ignore the version +// * checking. +// *

+// * If updating is performed, the version of the key increase by 1.
+// * If creating is performed, the version of the key initialize by 0.
+// * +// * @param key The key of data; +// * @param value The value of data; +// * @param version The expected version of the key. +// * @return The new version of the key.
+// * If the key is new created success, then return 0;
+// * If the key is updated success, then return the new version;
+// * If this operation fail by version checking or other reason, then +// * return -1; +// */ +// public long setBytes(Bytes key, byte[] value, long version) { +// BytesValue bytesValue = TypedValue.fromBytes(value); +// return baseAccount.setValue(key, bytesValue, version); +// } +// +// /** +// * Return the latest version entry associated the specified key; If the key +// * doesn't exist, then return -1; +// * +// * @param key +// * @return +// */ +// public long getDataVersion(String key) { +// return baseAccount.getVersion(Bytes.fromString(key)); +// } +// +// /** +// * Return the latest version entry associated the specified key; If the key +// * doesn't exist, then return -1; +// * +// * @param key +// * @return +// */ +// public long getDataVersion(Bytes key) { +// return baseAccount.getVersion(key); +// } +// +// /** +// * return the latest version's value; +// * +// * @param key +// * @return return null if not exist; +// */ +// public BytesValue getBytes(String key) { +// return baseAccount.getValue(Bytes.fromString(key)); +// } +// +// /** +// * return the latest version's value; +// * +// * @param key +// * @return return null if not exist; +// */ +// public BytesValue getBytes(Bytes key) { +// return baseAccount.getValue(key); +// } +// +// /** +// * return the specified version's value; +// * +// * @param key +// * @param version +// * @return return null if not exist; +// */ +// public BytesValue getBytes(String key, long version) { +// return baseAccount.getValue(Bytes.fromString(key), version); +// } +// +// /** +// * return the specified version's value; +// * +// * @param key +// * @param version +// * @return return null if not exist; +// */ +// public BytesValue getBytes(Bytes key, long version) { +// return baseAccount.getValue(key, version); +// } - - /** - * Create or update the value associated the specified key if the version - * checking is passed.
- * - * The value of the key will be updated only if it's latest version equals the - * specified version argument.
- * If the key doesn't exist, the version checking will be ignored, and key will - * be created with a new sequence number as id.
- * It also could specify the version argument to -1 to ignore the version - * checking. - *

- * If updating is performed, the version of the key increase by 1.
- * If creating is performed, the version of the key initialize by 0.
- * - * @param key The key of data; - * @param value The value of data; - * @param version The expected version of the key. - * @return The new version of the key.
- * If the key is new created success, then return 0;
- * If the key is updated success, then return the new version;
- * If this operation fail by version checking or other reason, then - * return -1; - */ - public long setBytes(Bytes key, BytesValue value, long version) { - return baseAccount.setBytes(key, value, version); - } - - /** - * Create or update the value associated the specified key if the version - * checking is passed.
- * - * The value of the key will be updated only if it's latest version equals the - * specified version argument.
- * If the key doesn't exist, the version checking will be ignored, and key will - * be created with a new sequence number as id.
- * It also could specify the version argument to -1 to ignore the version - * checking. - *

- * If updating is performed, the version of the key increase by 1.
- * If creating is performed, the version of the key initialize by 0.
- * - * @param key The key of data; - * @param value The value of data; - * @param version The expected version of the key. - * @return The new version of the key.
- * If the key is new created success, then return 0;
- * If the key is updated success, then return the new version;
- * If this operation fail by version checking or other reason, then - * return -1; - */ - public long setBytes(Bytes key, String value, long version) { - BytesValue bytesValue = BytesData.fromText(value); - return baseAccount.setBytes(key, bytesValue, version); - } - - /** - * Create or update the value associated the specified key if the version - * checking is passed.
- * - * The value of the key will be updated only if it's latest version equals the - * specified version argument.
- * If the key doesn't exist, the version checking will be ignored, and key will - * be created with a new sequence number as id.
- * It also could specify the version argument to -1 to ignore the version - * checking. - *

- * If updating is performed, the version of the key increase by 1.
- * If creating is performed, the version of the key initialize by 0.
- * - * @param key The key of data; - * @param value The value of data; - * @param version The expected version of the key. - * @return The new version of the key.
- * If the key is new created success, then return 0;
- * If the key is updated success, then return the new version;
- * If this operation fail by version checking or other reason, then - * return -1; - */ - public long setBytes(Bytes key, byte[] value, long version) { - BytesValue bytesValue = BytesData.fromBytes(value); - return baseAccount.setBytes(key, bytesValue, version); - } - - /** - * Return the latest version entry associated the specified key; If the key - * doesn't exist, then return -1; - * - * @param key - * @return - */ - public long getDataVersion(String key) { - return baseAccount.getVersion(Bytes.fromString(key)); - } - - /** - * Return the latest version entry associated the specified key; If the key - * doesn't exist, then return -1; - * - * @param key - * @return - */ - public long getDataVersion(Bytes key) { - return baseAccount.getVersion(key); - } - - /** - * return the latest version's value; - * - * @param key - * @return return null if not exist; - */ - public BytesValue getBytes(String key) { - return baseAccount.getBytes(Bytes.fromString(key)); - } - - /** - * return the latest version's value; - * - * @param key - * @return return null if not exist; - */ - public BytesValue getBytes(Bytes key) { - return baseAccount.getBytes(key); - } - - /** - * return the specified version's value; - * - * @param key - * @param version - * @return return null if not exist; - */ - public BytesValue getBytes(String key, long version) { - return baseAccount.getBytes(Bytes.fromString(key), version); - } - - /** - * return the specified version's value; - * - * @param key - * @param version - * @return return null if not exist; - */ - public BytesValue getBytes(Bytes key, long version) { - return baseAccount.getBytes(key, version); - } - /** - * @param key - * @param version - * @return - */ - public KVDataEntry getDataEntry(String key, long version) { - return getDataEntry(Bytes.fromString(key), version); - } - /** - * @param key - * @param version - * @return - */ - public KVDataEntry getDataEntry(Bytes key, long version) { - BytesValue value = baseAccount.getBytes(key, version); - if (value == null) { - return new KVDataObject(key.toUTF8String(), -1, null); - }else { - return new KVDataObject(key.toUTF8String(), version, value); - } - } - - /** - * return the specified index's KVDataEntry; - * - * @param fromIndex - * @param count - * @return return null if not exist; - */ - - public KVDataEntry[] getDataEntries(int fromIndex, int count) { - if (count == 0 || getDataEntriesTotalCount() == 0) { - return null; - } - - if (count == -1 || count > getDataEntriesTotalCount()) { - fromIndex = 0; - count = (int)getDataEntriesTotalCount(); - } - - if (fromIndex < 0 || fromIndex > getDataEntriesTotalCount() - 1) { - fromIndex = 0; - } - - KVDataEntry[] kvDataEntries = new KVDataEntry[count]; - byte[] value; - String key; - long ver; - for (int i = 0; i < count; i++) { - value = baseAccount.dataset.getValuesAtIndex(fromIndex); - key = baseAccount.dataset.getKeyAtIndex(fromIndex); - ver = baseAccount.dataset.getVersion(key); - BytesValue decodeData = BinaryProtocol.decode(value); - kvDataEntries[i] = new KVDataObject(key, ver, decodeData); - fromIndex++; - } - - return kvDataEntries; - } - - /** - * return the dataAccount's kv total count; - * - * @param - * @param - * @return return total count; - */ - public long getDataEntriesTotalCount() { - if(baseAccount == null){ - return 0; - } - return baseAccount.dataset.getDataCount(); - } +// /** +// * @param key +// * @param version +// * @return +// */ +// public KVDataEntry getDataEntry(String key, long version) { +// return getDataEntry(Bytes.fromString(key), version); +// } +// +// /** +// * @param key +// * @param version +// * @return +// */ +// public KVDataEntry getDataEntry(Bytes key, long version) { +// BytesValue value = baseAccount.getValue(key, version); +// if (value == null) { +// return new KVDataObject(key.toUTF8String(), -1, null); +// }else { +// return new KVDataObject(key.toUTF8String(), version, value); +// } +// } +// +// /** +// * return the specified index's KVDataEntry; +// * +// * @param fromIndex +// * @param count +// * @return return null if not exist; +// */ +// +// public KVDataEntry[] getDataEntries(int fromIndex, int count) { +// if (count == 0 || getDataEntriesTotalCount() == 0) { +// return null; +// } +// +// if (count == -1 || count > getDataEntriesTotalCount()) { +// fromIndex = 0; +// count = (int)getDataEntriesTotalCount(); +// } +// +// if (fromIndex < 0 || fromIndex > getDataEntriesTotalCount() - 1) { +// fromIndex = 0; +// } +// +// KVDataEntry[] kvDataEntries = new KVDataEntry[count]; +// byte[] value; +// String key; +// long ver; +// for (int i = 0; i < count; i++) { +// value = baseAccount.dataset.getValuesAtIndex(fromIndex); +// key = baseAccount.dataset.getKeyAtIndex(fromIndex); +// ver = baseAccount.dataset.getVersion(key); +// BytesValue decodeData = BinaryProtocol.decode(value); +// kvDataEntries[i] = new KVDataObject(key, ver, decodeData); +// fromIndex++; +// } +// +// return kvDataEntries; +// } +// +// /** +// * return the dataAccount's kv total count; +// * +// * @param +// * @param +// * @return return total count; +// */ +// public long getDataEntriesTotalCount() { +// if(baseAccount == null){ +// return 0; +// } +// return baseAccount.dataset.getDataCount(); +// } } \ No newline at end of file diff --git a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/DataAccountSet.java b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/DataAccountSet.java index f693211b..0f849c1d 100644 --- a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/DataAccountSet.java +++ b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/DataAccountSet.java @@ -2,7 +2,7 @@ package com.jd.blockchain.ledger.core; import com.jd.blockchain.crypto.HashDigest; import com.jd.blockchain.crypto.PubKey; -import com.jd.blockchain.ledger.AccountHeader; +import com.jd.blockchain.ledger.BlockchainIdentity; import com.jd.blockchain.ledger.CryptoSetting; import com.jd.blockchain.ledger.DigitalSignature; import com.jd.blockchain.ledger.MerkleProof; @@ -17,17 +17,18 @@ public class DataAccountSet implements Transactional, DataAccountQuery { public DataAccountSet(CryptoSetting cryptoSetting, String prefix, ExPolicyKVStorage exStorage, VersioningKVStorage verStorage, AccountAccessPolicy accessPolicy) { - accountSet = new MerkleAccountSet(cryptoSetting, prefix, exStorage, verStorage, accessPolicy); + accountSet = new MerkleAccountSet(cryptoSetting, Bytes.fromString(prefix), exStorage, verStorage, accessPolicy); } public DataAccountSet(HashDigest dataRootHash, CryptoSetting cryptoSetting, String prefix, ExPolicyKVStorage exStorage, VersioningKVStorage verStorage, boolean readonly, AccountAccessPolicy accessPolicy) { - accountSet = new MerkleAccountSet(dataRootHash, cryptoSetting, prefix, exStorage, verStorage, readonly, accessPolicy); + accountSet = new MerkleAccountSet(dataRootHash, cryptoSetting, Bytes.fromString(prefix), exStorage, verStorage, + readonly, accessPolicy); } @Override - public AccountHeader[] getHeaders(int fromIndex, int count) { + public BlockchainIdentity[] getHeaders(int fromIndex, int count) { return accountSet.getHeaders(fromIndex, count); } @@ -64,7 +65,7 @@ public class DataAccountSet implements Transactional, DataAccountQuery { public DataAccount register(Bytes address, PubKey pubKey, DigitalSignature addressSignature) { // TODO: 未实现对地址签名的校验和记录; - MerkleAccount accBase = accountSet.register(address, pubKey); + CompositeAccount accBase = accountSet.register(address, pubKey); return new DataAccount(accBase); } @@ -82,7 +83,7 @@ public class DataAccountSet implements Transactional, DataAccountQuery { */ @Override public DataAccount getAccount(Bytes address) { - MerkleAccount accBase = accountSet.getAccount(address); + CompositeAccount accBase = accountSet.getAccount(address); if (accBase == null) { return null; } @@ -91,7 +92,7 @@ public class DataAccountSet implements Transactional, DataAccountQuery { @Override public DataAccount getAccount(Bytes address, long version) { - MerkleAccount accBase = accountSet.getAccount(address, version); + CompositeAccount accBase = accountSet.getAccount(address, version); return new DataAccount(accBase); } diff --git a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/EmptyAccountSet.java b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/EmptyAccountSet.java index 879bf702..8cfdd7fc 100644 --- a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/EmptyAccountSet.java +++ b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/EmptyAccountSet.java @@ -1,13 +1,13 @@ package com.jd.blockchain.ledger.core; import com.jd.blockchain.crypto.HashDigest; -import com.jd.blockchain.ledger.AccountHeader; +import com.jd.blockchain.ledger.BlockchainIdentity; import com.jd.blockchain.ledger.MerkleProof; import com.jd.blockchain.utils.Bytes; public class EmptyAccountSet implements AccountQuery { - private static final AccountHeader[] EMPTY = {}; + private static final BlockchainIdentity[] EMPTY = {}; @Override public HashDigest getRootHash() { @@ -20,7 +20,7 @@ public class EmptyAccountSet implements AccountQuery { } @Override - public AccountHeader[] getHeaders(int fromIndex, int count) { + public BlockchainIdentity[] getHeaders(int fromIndex, int count) { return EMPTY; } diff --git a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/GenericAccountSet.java b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/GenericAccountSet.java new file mode 100644 index 00000000..372163e1 --- /dev/null +++ b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/GenericAccountSet.java @@ -0,0 +1,92 @@ +//package com.jd.blockchain.ledger.core; +// +//import com.jd.blockchain.crypto.HashDigest; +//import com.jd.blockchain.ledger.AccountHeader; +//import com.jd.blockchain.ledger.CryptoSetting; +//import com.jd.blockchain.ledger.MerkleProof; +//import com.jd.blockchain.storage.service.ExPolicyKVStorage; +//import com.jd.blockchain.storage.service.VersioningKVStorage; +//import com.jd.blockchain.utils.Bytes; +//import com.jd.blockchain.utils.Transactional; +// +//public class GenericAccountSet> implements AccountQuery, Transactional { +// +// private Class headerType; +// +// private MerkleAccountSet merkleAccountSet; +// +// public GenericAccountSet(Class headerType, CryptoSetting cryptoSetting, String keyPrefix, ExPolicyKVStorage exStorage, +// VersioningKVStorage verStorage, AccountAccessPolicy accessPolicy) { +// this(headerType, null, cryptoSetting, keyPrefix, exStorage, verStorage, false, accessPolicy); +// } +// +// public GenericAccountSet(Class headerType, HashDigest rootHash, CryptoSetting cryptoSetting, String keyPrefix, +// ExPolicyKVStorage exStorage, VersioningKVStorage verStorage, boolean readonly, +// AccountAccessPolicy accessPolicy) { +// this.headerType = headerType; +// this.merkleAccountSet = new MerkleAccountSet(rootHash, cryptoSetting, keyPrefix, exStorage, verStorage, readonly, accessPolicy); +// } +// +// @Override +// public MerkleProof getProof(Bytes address) { +// return merkleAccountSet.getProof(address); +// } +// +// @Override +// public HashDigest getRootHash() { +// return merkleAccountSet.getRootHash(); +// } +// +// @Override +// public boolean isUpdated() { +// return merkleAccountSet.isUpdated(); +// } +// +// @Override +// public void commit() { +// merkleAccountSet.commit(); +// } +// +// @Override +// public void cancel() { +// merkleAccountSet.cancel(); +// } +// +// @Override +// public H[] getHeaders(int fromIndex, int count) { +// merkleAccountSet.getHeaders(fromIndex, count) +// return null; +// } +// +// @Override +// public long getTotal() { +// // TODO Auto-generated method stub +// return 0; +// } +// +// @Override +// public boolean contains(Bytes address) { +// // TODO Auto-generated method stub +// return false; +// } +// +// @Override +// public T getAccount(String address) { +// // TODO Auto-generated method stub +// return null; +// } +// +// @Override +// public T getAccount(Bytes address) { +// // TODO Auto-generated method stub +// return null; +// } +// +// @Override +// public T getAccount(Bytes address, long version) { +// // TODO Auto-generated method stub +// return null; +// } +// +// +//} diff --git a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/HashDigestList.java b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/HashDigestList.java new file mode 100644 index 00000000..e2a74de7 --- /dev/null +++ b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/HashDigestList.java @@ -0,0 +1,42 @@ +package com.jd.blockchain.ledger.core; + +import java.util.ArrayList; +import java.util.List; + +import com.jd.blockchain.crypto.HashDigest; +import com.jd.blockchain.ledger.HashProof; + +/** + * + * @author huanghaiquan + * + */ +public class HashDigestList implements HashProof { + + private List proofs = new ArrayList(); + + public HashDigestList() { + } + + public HashDigestList(HashProof proof) { + concat(proof); + } + + public void concat(HashProof proof) { + int levels = proof.getLevels(); + for (int i = levels; i > -1; i--) { + proofs.add(proof.getHash(i)); + } + } + + @Override + public int getLevels() { + return proofs.size(); + } + + @Override + public HashDigest getHash(int level) { + return proofs.get(level); + } + +} diff --git a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/HashProvable.java b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/HashProvable.java new file mode 100644 index 00000000..88da19ae --- /dev/null +++ b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/HashProvable.java @@ -0,0 +1,10 @@ +package com.jd.blockchain.ledger.core; + +import com.jd.blockchain.ledger.HashProof; +import com.jd.blockchain.utils.Bytes; + +public interface HashProvable { + + HashProof getProof(Bytes key); + +} diff --git a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/LedgerQueryService.java b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/LedgerQueryService.java index 41e70138..c377a56a 100644 --- a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/LedgerQueryService.java +++ b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/LedgerQueryService.java @@ -5,11 +5,12 @@ import java.util.List; import com.jd.blockchain.contract.ContractException; import com.jd.blockchain.crypto.HashDigest; -import com.jd.blockchain.ledger.AccountHeader; +import com.jd.blockchain.ledger.BlockchainIdentity; import com.jd.blockchain.ledger.BytesValue; import com.jd.blockchain.ledger.ContractInfo; -import com.jd.blockchain.ledger.KVDataEntry; -import com.jd.blockchain.ledger.KVDataObject; +import com.jd.blockchain.ledger.TypedKVEntry; +import com.jd.blockchain.ledger.TypedValue; +import com.jd.blockchain.ledger.TypedKVData; import com.jd.blockchain.ledger.KVDataVO; import com.jd.blockchain.ledger.KVInfoVO; import com.jd.blockchain.ledger.LedgerAdminInfo; @@ -22,22 +23,25 @@ import com.jd.blockchain.ledger.ParticipantNode; import com.jd.blockchain.ledger.TransactionState; import com.jd.blockchain.ledger.UserInfo; import com.jd.blockchain.transaction.BlockchainQueryService; +import com.jd.blockchain.utils.ArrayUtils; import com.jd.blockchain.utils.Bytes; +import com.jd.blockchain.utils.DataEntry; +import com.jd.blockchain.utils.DataIterator; import com.jd.blockchain.utils.QueryUtil; public class LedgerQueryService implements BlockchainQueryService { - private static final KVDataEntry[] EMPTY_ENTRIES = new KVDataEntry[0]; - + private static final TypedKVEntry[] EMPTY_ENTRIES = new TypedKVEntry[0]; + private HashDigest[] ledgerHashs; private LedgerQuery ledger; public LedgerQueryService(LedgerQuery ledger) { this.ledger = ledger; - this.ledgerHashs = new HashDigest[] {ledger.getHash()}; + this.ledgerHashs = new HashDigest[] { ledger.getHash() }; } - + private void checkLedgerHash(HashDigest ledgerHash) { if (!ledgerHashs[0].equals(ledgerHash)) { throw new LedgerException("Unsupport cross chain query!"); @@ -58,7 +62,7 @@ public class LedgerQueryService implements BlockchainQueryService { ledgerInfo.setLatestBlockHeight(ledger.getLatestBlockHeight()); return ledgerInfo; } - + @Override public LedgerAdminInfo getLedgerAdminInfo(HashDigest ledgerHash) { checkLedgerHash(ledgerHash); @@ -270,15 +274,15 @@ public class LedgerQueryService implements BlockchainQueryService { } @Override - public AccountHeader getDataAccount(HashDigest ledgerHash, String address) { + public BlockchainIdentity getDataAccount(HashDigest ledgerHash, String address) { checkLedgerHash(ledgerHash); LedgerBlock block = ledger.getLatestBlock(); DataAccountQuery dataAccountSet = ledger.getDataAccountSet(block); - return dataAccountSet.getAccount(Bytes.fromBase58(address)); + return dataAccountSet.getAccount(Bytes.fromBase58(address)).getID(); } @Override - public KVDataEntry[] getDataEntries(HashDigest ledgerHash, String address, String... keys) { + public TypedKVEntry[] getDataEntries(HashDigest ledgerHash, String address, String... keys) { if (keys == null || keys.length == 0) { return EMPTY_ENTRIES; } @@ -287,25 +291,26 @@ public class LedgerQueryService implements BlockchainQueryService { DataAccountQuery dataAccountSet = ledger.getDataAccountSet(block); DataAccount dataAccount = dataAccountSet.getAccount(Bytes.fromBase58(address)); - KVDataEntry[] entries = new KVDataEntry[keys.length]; + + TypedKVEntry[] entries = new TypedKVEntry[keys.length]; long ver; for (int i = 0; i < entries.length; i++) { final String currKey = keys[i]; - ver = dataAccount == null ? -1 : dataAccount.getDataVersion(Bytes.fromString(currKey)); + ver = dataAccount == null ? -1 : dataAccount.getDataset().getVersion(currKey); if (ver < 0) { - entries[i] = new KVDataObject(currKey, -1, null); + entries[i] = new TypedKVData(currKey, -1, null); } else { - BytesValue value = dataAccount.getBytes(Bytes.fromString(currKey), ver); - entries[i] = new KVDataObject(currKey, ver, value); + BytesValue value = dataAccount.getDataset().getValue(currKey, ver); + entries[i] = new TypedKVData(currKey, ver, value); } } return entries; } - public KVDataEntry[] getDataEntries(HashDigest ledgerHash, String address, KVInfoVO kvInfoVO) { + public TypedKVEntry[] getDataEntries(HashDigest ledgerHash, String address, KVInfoVO kvInfoVO) { // parse kvInfoVO; List keyList = new ArrayList<>(); List versionList = new ArrayList<>(); @@ -335,22 +340,22 @@ public class LedgerQueryService implements BlockchainQueryService { DataAccountQuery dataAccountSet = ledger.getDataAccountSet(block); DataAccount dataAccount = dataAccountSet.getAccount(Bytes.fromBase58(address)); - KVDataEntry[] entries = new KVDataEntry[keys.length]; + TypedKVEntry[] entries = new TypedKVEntry[keys.length]; long ver = -1; for (int i = 0; i < entries.length; i++) { // ver = dataAccount.getDataVersion(Bytes.fromString(keys[i])); // dataAccount.getBytes(Bytes.fromString(keys[i]),1); ver = versions[i]; if (ver < 0) { - entries[i] = new KVDataObject(keys[i], -1, null); + entries[i] = new TypedKVData(keys[i], -1, null); } else { - if (dataAccount.getDataEntriesTotalCount() == 0 - || dataAccount.getBytes(Bytes.fromString(keys[i]), ver) == null) { + if (dataAccount.getDataset().getDataCount() == 0 + || dataAccount.getDataset().getValue(keys[i], ver) == null) { // is the address is not exist; the result is null; - entries[i] = new KVDataObject(keys[i], -1, null); + entries[i] = new TypedKVData(keys[i], -1, null); } else { - BytesValue value = dataAccount.getBytes(Bytes.fromString(keys[i]), ver); - entries[i] = new KVDataObject(keys[i], ver, value); + BytesValue value = dataAccount.getDataset().getValue(keys[i], ver); + entries[i] = new TypedKVData(keys[i], ver, value); } } } @@ -359,14 +364,22 @@ public class LedgerQueryService implements BlockchainQueryService { } @Override - public KVDataEntry[] getDataEntries(HashDigest ledgerHash, String address, int fromIndex, int count) { + public TypedKVEntry[] getDataEntries(HashDigest ledgerHash, String address, int fromIndex, int count) { checkLedgerHash(ledgerHash); LedgerBlock block = ledger.getLatestBlock(); DataAccountQuery dataAccountSet = ledger.getDataAccountSet(block); DataAccount dataAccount = dataAccountSet.getAccount(Bytes.fromBase58(address)); - int pages[] = QueryUtil.calFromIndexAndCount(fromIndex, count, (int) dataAccount.getDataEntriesTotalCount()); - return dataAccount.getDataEntries(pages[0], pages[1]); +// int pages[] = QueryUtil.calFromIndexAndCount(fromIndex, count, (int) dataAccount.getDataset().getDataCount()); +// return dataAccount.getDataset().getDataEntry(key, version).getDataEntries(pages[0], pages[1]); + + DataIterator iterator = dataAccount.getDataset().iterator(); + iterator.skip(fromIndex); + DataEntry[] dataEntries = iterator.next(count); + + TypedKVEntry[] typedKVEntries = ArrayUtils.castTo(dataEntries, TypedKVEntry.class, + e -> e == null ? null : new TypedKVData(e.getKey(), e.getVersion(), e.getValue())); + return typedKVEntries; } @Override @@ -376,7 +389,7 @@ public class LedgerQueryService implements BlockchainQueryService { DataAccountQuery dataAccountSet = ledger.getDataAccountSet(block); DataAccount dataAccount = dataAccountSet.getAccount(Bytes.fromBase58(address)); - return dataAccount.getDataEntriesTotalCount(); + return dataAccount.getDataset().getDataCount(); } @Override @@ -388,7 +401,7 @@ public class LedgerQueryService implements BlockchainQueryService { } @Override - public AccountHeader[] getUsers(HashDigest ledgerHash, int fromIndex, int count) { + public BlockchainIdentity[] getUsers(HashDigest ledgerHash, int fromIndex, int count) { checkLedgerHash(ledgerHash); LedgerBlock block = ledger.getLatestBlock(); UserAccountQuery userAccountSet = ledger.getUserAccountSet(block); @@ -397,7 +410,7 @@ public class LedgerQueryService implements BlockchainQueryService { } @Override - public AccountHeader[] getDataAccounts(HashDigest ledgerHash, int fromIndex, int count) { + public BlockchainIdentity[] getDataAccounts(HashDigest ledgerHash, int fromIndex, int count) { checkLedgerHash(ledgerHash); LedgerBlock block = ledger.getLatestBlock(); DataAccountQuery dataAccountSet = ledger.getDataAccountSet(block); @@ -406,7 +419,7 @@ public class LedgerQueryService implements BlockchainQueryService { } @Override - public AccountHeader[] getContractAccounts(HashDigest ledgerHash, int fromIndex, int count) { + public BlockchainIdentity[] getContractAccounts(HashDigest ledgerHash, int fromIndex, int count) { checkLedgerHash(ledgerHash); LedgerBlock block = ledger.getLatestBlock(); ContractAccountQuery contractAccountSet = ledger.getContractAccountSet(block); diff --git a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/LedgerRepositoryImpl.java b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/LedgerRepositoryImpl.java index 9734f880..49e7ebba 100644 --- a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/LedgerRepositoryImpl.java +++ b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/LedgerRepositoryImpl.java @@ -374,6 +374,10 @@ class LedgerRepositoryImpl implements LedgerRepository { return new LedgerDataset(adminDataset, userAccountSet, dataAccountSet, contractAccountSet, true); } + public synchronized void resetNextBlockEditor() { + this.nextBlockEditor = null; + } + @Override public synchronized LedgerEditor createNextBlock() { if (closed) { diff --git a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/LedgerTransactionalEditor.java b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/LedgerTransactionalEditor.java index ea7bb7ed..15954e4f 100644 --- a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/LedgerTransactionalEditor.java +++ b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/LedgerTransactionalEditor.java @@ -355,7 +355,11 @@ public class LedgerTransactionalEditor implements LedgerEditor { throw new IllegalStateException("The current block is not ready yet!"); } - baseStorage.flush(); + try { + baseStorage.flush(); + } catch (Exception e) { + throw new BlockRollbackException(e.getMessage(), e); + } committed = true; } diff --git a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/MerkleAccount.java b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/MerkleAccount.java index 49ef5753..38a65e31 100644 --- a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/MerkleAccount.java +++ b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/MerkleAccount.java @@ -3,15 +3,21 @@ package com.jd.blockchain.ledger.core; import com.jd.blockchain.binaryproto.BinaryProtocol; import com.jd.blockchain.crypto.HashDigest; import com.jd.blockchain.crypto.PubKey; -import com.jd.blockchain.ledger.AccountHeader; import com.jd.blockchain.ledger.BlockchainIdentity; -import com.jd.blockchain.ledger.BlockchainIdentityData; import com.jd.blockchain.ledger.BytesValue; import com.jd.blockchain.ledger.CryptoSetting; +import com.jd.blockchain.ledger.HashProof; +import com.jd.blockchain.ledger.LedgerException; import com.jd.blockchain.ledger.MerkleProof; +import com.jd.blockchain.ledger.MerkleSnapshot; +import com.jd.blockchain.ledger.TypedValue; import com.jd.blockchain.storage.service.ExPolicyKVStorage; import com.jd.blockchain.storage.service.VersioningKVStorage; import com.jd.blockchain.utils.Bytes; +import com.jd.blockchain.utils.Dataset; +import com.jd.blockchain.utils.DatasetHelper; +import com.jd.blockchain.utils.DatasetHelper.DataChangedListener; +import com.jd.blockchain.utils.DatasetHelper.TypeMapper; import com.jd.blockchain.utils.Transactional; /** @@ -20,94 +26,166 @@ import com.jd.blockchain.utils.Transactional; * @author huanghaiquan * */ -public class MerkleAccount implements AccountHeader, MerkleProvable, Transactional { +public class MerkleAccount implements CompositeAccount, HashProvable, MerkleSnapshot, Transactional { - private BlockchainIdentity bcid; + private static final Bytes HEADER_PREFIX = Bytes.fromString("HD/"); + private static final Bytes DATA_PREFIX = Bytes.fromString("DT/"); - protected MerkleDataSet dataset; + private static final Bytes KEY_HEADER_ROOT = Bytes.fromString("HEADER"); + + private static final Bytes KEY_DATA_ROOT = Bytes.fromString("DATA"); + + private static final String KEY_PUBKEY = "PUBKEY"; + + private BlockchainIdentity accountID; + + private MerkleDataSet rootDataset; + + private MerkleDataSet headerDataset; + + private MerkleDataSet dataDataset; + + private Dataset typedHeader; + + private Dataset typedData; + +// private long version; /** - * Create a new Account with the specified address and pubkey;
+ * Create a new Account with the specified identity(address and pubkey);
* * At the same time, a empty merkle dataset is also created for this account, * which is used for storing data of this account.
- * - * Note that, the blockchain identity of the account is not stored in the - * account's merkle dataset, but is stored by the outer invoker; * - * @param address - * @param pubKey + * This new account will be writable.
+ * + * @param accountID Identity of this new account; + * @param cryptoSetting Settings about crypto operations; + * @param keyPrefix Prefix of all keys in this account's dataset; + * @param exStorage The base storage for existance operation; + * @param verStorage The base storage for versioning operation; */ - public MerkleAccount(Bytes address, PubKey pubKey, CryptoSetting cryptoSetting, String keyPrefix, + public MerkleAccount(BlockchainIdentity accountID, CryptoSetting cryptoSetting, Bytes keyPrefix, ExPolicyKVStorage exStorage, VersioningKVStorage verStorage) { - this(address, pubKey, null, cryptoSetting, keyPrefix, exStorage, verStorage, false); + // 初始化数据集; + initializeDatasets(null, cryptoSetting, keyPrefix, exStorage, verStorage, false); + + initPubKey(accountID.getPubKey()); + this.accountID = accountID; } /** - * Create a new Account with the specified address and pubkey;
+ * Create a account instance with the specified address and root hash; load it's + * merkle dataset from the specified root hash. This merkle dateset is used for + * storing data of this account.
* - * At the same time, a empty merkle dataset is also created for this account, - * which is used for storing data of this account.
- * - * Note that, the blockchain identity of the account is not stored in the - * account's merkle dataset, but is stored by the outer invoker; - * - * @param bcid - * @param cryptoSetting - * @param exStorage - * @param verStorage - * @param accessPolicy + * @param address Address of this account; + * @param rootHash Merkle root hash of this account; It can not be null; + * @param cryptoSetting Settings about crypto operations; + * @param keyPrefix Prefix of all keys in this account's dataset; + * @param exStorage The base storage for existance operation; + * @param verStorage The base storage for versioning operation; + * @param readonly Readonly about this account's dataset; */ - public MerkleAccount(BlockchainIdentity bcid, CryptoSetting cryptoSetting, String keyPrefix, - ExPolicyKVStorage exStorage, VersioningKVStorage verStorage) { - this(bcid, null, cryptoSetting, keyPrefix, exStorage, verStorage, false); + public MerkleAccount(Bytes address, HashDigest rootHash, CryptoSetting cryptoSetting, Bytes keyPrefix, + ExPolicyKVStorage exStorage, VersioningKVStorage verStorage, boolean readonly) { + if (rootHash == null) { + throw new IllegalArgumentException("Specified a null root hash for account[" + address.toBase58() + "]!"); + } + + // 初始化数据集; + initializeDatasets(rootHash, cryptoSetting, keyPrefix, exStorage, verStorage, readonly); + + // 初始化账户的身份; + PubKey pubKey = loadPubKey(); + this.accountID = new AccountID(address, pubKey); } - /** - * Create a account instance with the specified address and pubkey and load it's - * merkle dataset from the specified root hash. This merkle dateset is used for storing data - * of this account.
- * - * @param address - * @param pubKey - * @param dataRootHash merkle root hash of account's data; if set to a null value, - * an empty merkle dataset is created; - * @param cryptoSetting - * @param exStorage - * @param verStorage - * @param readonly - * @param accessPolicy - */ - public MerkleAccount(Bytes address, PubKey pubKey, HashDigest dataRootHash, CryptoSetting cryptoSetting, - String keyPrefix, ExPolicyKVStorage exStorage, VersioningKVStorage verStorage, boolean readonly) { - this(new BlockchainIdentityData(address, pubKey), dataRootHash, cryptoSetting, keyPrefix, exStorage, verStorage, + private void initializeDatasets(HashDigest rootHash, CryptoSetting cryptoSetting, Bytes keyPrefix, + ExPolicyKVStorage exStorage, VersioningKVStorage verStorage, boolean readonly) { + // 加载“根数据集” + this.rootDataset = new MerkleDataSet(rootHash, cryptoSetting, keyPrefix, exStorage, verStorage, readonly); + + // 初始化数据修改监听器; + DataChangedListener dataChangedListener = new DataChangedListener() { + @Override + public void onChanged(String key, TypedValue value, long expectedVersion, long newVersion) { + onUpdated(key, value, expectedVersion, newVersion); + } + }; + + TypeMapper valueMapper = new TypeMapper() { + + @Override + public byte[] encode(TypedValue t2) { + return BinaryProtocol.encode(t2, BytesValue.class); + } + + @Override + public TypedValue decode(byte[] t1) { + BytesValue v = BinaryProtocol.decodeAs(t1, BytesValue.class); + return TypedValue.wrap(v); + } + }; + + // 加载“头数据集”; + HashDigest headerRoot = loadHeaderRoot(); + Bytes headerPrefix = keyPrefix.concat(HEADER_PREFIX); + this.headerDataset = new MerkleDataSet(headerRoot, cryptoSetting, headerPrefix, exStorage, verStorage, readonly); + this.typedHeader = DatasetHelper.listen(DatasetHelper.map(headerDataset, valueMapper), dataChangedListener); + + // 加载“主数据集” + HashDigest dataRoot = loadDataRoot(); + Bytes dataPrefix = keyPrefix.concat(DATA_PREFIX); + this.dataDataset = new MerkleDataSet(dataRoot, cryptoSetting, dataPrefix, exStorage, verStorage, readonly); + this.typedData = DatasetHelper.listen(DatasetHelper.map(dataDataset, valueMapper), dataChangedListener); } - public MerkleAccount(BlockchainIdentity bcid, HashDigest dataRootHash, CryptoSetting cryptoSetting, String keyPrefix, - ExPolicyKVStorage exStorage, VersioningKVStorage verStorage, boolean readonly) { - this.bcid = bcid; - this.dataset = new MerkleDataSet(dataRootHash, cryptoSetting, keyPrefix, exStorage, verStorage, readonly); + private HashDigest loadHeaderRoot() { + byte[] hashBytes = rootDataset.getValue(KEY_HEADER_ROOT); + if (hashBytes == null) { + return null; + } + return new HashDigest(hashBytes); + } + + private HashDigest loadDataRoot() { + byte[] hashBytes = rootDataset.getValue(KEY_DATA_ROOT); + if (hashBytes == null) { + return null; + } + return new HashDigest(hashBytes); + } + + private long getHeaderRootVersion() { + return rootDataset.getVersion(KEY_HEADER_ROOT); + } + + private long getDataRootVersion() { + return rootDataset.getVersion(KEY_DATA_ROOT); } - /* - * (non-Javadoc) - * - * @see com.jd.blockchain.ledger.core.AccountDataSet#getAddress() - */ - @Override public Bytes getAddress() { - return bcid.getAddress(); + return accountID.getAddress(); } - /* - * (non-Javadoc) - * - * @see com.jd.blockchain.ledger.core.AccountDataSet#getPubKey() - */ - @Override public PubKey getPubKey() { - return bcid.getPubKey(); + return accountID.getPubKey(); + } + + @Override + public BlockchainIdentity getID() { + return accountID; + } + + public Dataset getHeaders() { + return typedHeader; + } + + @Override + public Dataset getDataset() { + return typedData; } /* @@ -117,12 +195,22 @@ public class MerkleAccount implements AccountHeader, MerkleProvable, Transaction */ @Override public HashDigest getRootHash() { - return dataset.getRootHash(); + return rootDataset.getRootHash(); } @Override - public MerkleProof getProof(Bytes key) { - return dataset.getProof(key); + public HashProof getProof(Bytes key) { + MerkleProof dataProof = dataDataset.getProof(key); + if (dataProof == null) { + return null; + } + MerkleProof rootProof = rootDataset.getProof(KEY_DATA_ROOT); + if (rootProof == null) { + return null; + } + HashDigestList proof = new HashDigestList(rootProof); + proof.concat(dataProof); + return proof; } /** @@ -131,90 +219,298 @@ public class MerkleAccount implements AccountHeader, MerkleProvable, Transaction * @return */ public boolean isReadonly() { - return dataset.isReadonly(); + return dataDataset.isReadonly() || headerDataset.isReadonly(); } /** - * Create or update the value associated the specified key if the version - * checking is passed.
- * - * The value of the key will be updated only if it's latest version equals the - * specified version argument.
- * If the key doesn't exist, the version checking will be ignored, and key will - * be created with a new sequence number as id.
- * It also could specify the version argument to -1 to ignore the version - * checking. - *

- * If updating is performed, the version of the key increase by 1.
- * If creating is performed, the version of the key initialize by 0.
+ * 初始化账户的公钥; * - * @param key The key of data; - * @param value The value of data; - * @param version The expected version of the key. - * @return The new version of the key.
- * If the key is new created success, then return 0;
- * If the key is updated success, then return the new version;
- * If this operation fail by version checking or other reason, then - * return -1; + * @param pubKey */ - public long setBytes(Bytes key, BytesValue value, long version) { - byte[] bytesValue = BinaryProtocol.encode(value, BytesValue.class); - return dataset.setValue(key, bytesValue, version); + private void initPubKey(PubKey pubKey) { + long v = typedHeader.setValue(KEY_PUBKEY, TypedValue.fromPubKey(pubKey), -1); + if (v < 0) { + throw new LedgerException("PubKey storage conflict!"); + } } /** - * Return the latest version entry associated the specified key; If the key - * doesn't exist, then return -1; + * 加载公钥; * - * @param key * @return */ - public long getVersion(Bytes key) { - return dataset.getVersion(key); + private PubKey loadPubKey() { + TypedValue value = typedHeader.getValue(KEY_PUBKEY); + if (value == null) { + return null; + } + return value.pubKeyValue(); } /** - * return the latest version's value; + * 当写入新值时触发此方法; * * @param key - * @return return null if not exist; + * @param value + * @param newVersion */ - public BytesValue getBytes(Bytes key) { - byte[] bytesValue = dataset.getValue(key); - if (bytesValue == null) { - return null; - } - return BinaryProtocol.decodeAs(bytesValue, BytesValue.class); + protected void onUpdated(String key, TypedValue value, long expectedVersion, long newVersion) { } /** - * Return the specified version's value; + * 当账户数据提交后触发此方法;
* - * @param key - * @param version - * @return return null if not exist; + * 此方法默认会返回新的账户版本号,等于当前版本号加 1 ; + * + * @param previousRootHash 提交前的根哈希;如果是新账户的首次提交,则为 null; + * @param newRootHash 新的根哈希; */ - public BytesValue getBytes(Bytes key, long version) { - byte[] bytesValue = dataset.getValue(key, version); - if (bytesValue == null) { - return null; - } - return BinaryProtocol.decodeAs(bytesValue, BytesValue.class); + protected void onCommited(HashDigest previousRootHash, HashDigest newRootHash) { } @Override public boolean isUpdated() { - return dataset.isUpdated(); + return headerDataset.isUpdated() || dataDataset.isUpdated() || rootDataset.isUpdated(); } @Override public void commit() { - dataset.commit(); + if (headerDataset.isUpdated()) { + headerDataset.commit(); + long version = getHeaderRootVersion(); + rootDataset.setValue(KEY_HEADER_ROOT, headerDataset.getRootHash().toBytes(), version); + } + if (dataDataset.isUpdated()) { + long version = getDataRootVersion(); + dataDataset.commit(); + rootDataset.setValue(KEY_DATA_ROOT, dataDataset.getRootHash().toBytes(), version); + } + + if (rootDataset.isUpdated()) { + HashDigest previousRootHash = rootDataset.getRootHash(); + rootDataset.commit(); + onCommited(previousRootHash, rootDataset.getRootHash()); + } } @Override public void cancel() { - dataset.cancel(); + headerDataset.cancel(); + dataDataset.cancel(); + rootDataset.cancel(); + } + + // ---------------------- + + private class AccountID implements BlockchainIdentity { + + private Bytes address; + + private PubKey pubKey; + + public AccountID(Bytes address, PubKey pubKey) { + this.address = address; + this.pubKey = pubKey; + } + + @Override + public Bytes getAddress() { + return address; + } + + @Override + public PubKey getPubKey() { + return pubKey; + } + } +// private static class MerkleDatasetAdapter implements Dataset { +// +// private static DataChangedListener NULL_LISTENER = new DataChangedListener() { +// @Override +// public void onChanged(Bytes key, BytesValue value, long newVersion) { +// } +// }; +// +// private DataChangedListener changedListener; +// +// private MerkleDataSet dataset; +// +// public MerkleDataSet getDataset() { +// return dataset; +// } +// +// @SuppressWarnings("unused") +// public MerkleDatasetAdapter(MerkleDataSet dataset) { +// this(dataset, NULL_LISTENER); +// } +// +// public MerkleDatasetAdapter(MerkleDataSet dataset, DataChangedListener listener) { +// this.dataset = dataset; +// this.changedListener = listener == null ? NULL_LISTENER : listener; +// } +// +// @Override +// public DataEntry getDataEntry(String key) { +// return new VersioningKVEntryWraper(dataset.getDataEntry(Bytes.fromString(key))); +// } +// +// @Override +// public DataEntry getDataEntry(String key, long version) { +// return new VersioningKVEntryWraper(dataset.getDataEntry(Bytes.fromString(key), version)); +// } +// +// /** +// * Create or update the value associated the specified key if the version +// * checking is passed.
+// * +// * The value of the key will be updated only if it's latest version equals the +// * specified version argument.
+// * If the key doesn't exist, the version checking will be ignored, and key will +// * be created with a new sequence number as id.
+// * It also could specify the version argument to -1 to ignore the version +// * checking. +// *

+// * If updating is performed, the version of the key increase by 1.
+// * If creating is performed, the version of the key initialize by 0.
+// * +// * @param key The key of data; +// * @param value The value of data; +// * @param version The expected version of the key. +// * @return The new version of the key.
+// * If the key is new created success, then return 0;
+// * If the key is updated success, then return the new version;
+// * If this operation fail by version checking or other reason, then +// * return -1; +// */ +// @Override +// public long setValue(Bytes key, BytesValue value, long version) { +// byte[] bytesValue = BinaryProtocol.encode(value, BytesValue.class); +// long v = dataset.setValue(key, bytesValue, version); +// if (v > -1) { +// changedListener.onChanged(key, value, v); +// } +// return v; +// } +// +// /** +// * Return the latest version entry associated the specified key; If the key +// * doesn't exist, then return -1; +// * +// * @param key +// * @return +// */ +// @Override +// public long getVersion(Bytes key) { +// return dataset.getVersion(key); +// } +// +// /** +// * return the latest version's value; +// * +// * @param key +// * @return return null if not exist; +// */ +// @Override +// public BytesValue getValue(Bytes key) { +// byte[] bytesValue = dataset.getValue(key); +// if (bytesValue == null) { +// return null; +// } +// return BinaryProtocol.decodeAs(bytesValue, BytesValue.class); +// } +// +// /** +// * Return the specified version's value; +// * +// * @param key +// * @param version +// * @return return null if not exist; +// */ +// @Override +// public BytesValue getValue(Bytes key, long version) { +// byte[] bytesValue = dataset.getValue(key, version); +// if (bytesValue == null) { +// return null; +// } +// return BinaryProtocol.decodeAs(bytesValue, BytesValue.class); +// } +// +// @Override +// public long getDataCount() { +// return dataset.getDataCount(); +// } +// +// @Override +// public long setValue(String key, BytesValue value, long version) { +// byte[] bytesValue = BinaryProtocol.encode(value, BytesValue.class); +// return dataset.setValue(key, bytesValue, version); +// } +// +// @Override +// public BytesValue getValue(String key, long version) { +// byte[] bytesValue = dataset.getValue(key, version); +// if (bytesValue == null) { +// return null; +// } +// return BinaryProtocol.decodeAs(bytesValue, BytesValue.class); +// } +// +// @Override +// public BytesValue getValue(String key) { +// byte[] bytesValue = dataset.getValue(key); +// if (bytesValue == null) { +// return null; +// } +// return BinaryProtocol.decodeAs(bytesValue, BytesValue.class); +// } +// +// @Override +// public long getVersion(String key) { +// return dataset.getVersion(key); +// } +// +// @Override +// public DataEntry getDataEntry(String key) { +// return new VersioningKVEntryWraper(dataset.getDataEntry(key)); +// } +// +// @Override +// public DataEntry getDataEntry(String key, long version) { +// return new VersioningKVEntryWraper(dataset.getDataEntry(key, version)); +// } +// } + +// private static interface DataChangedListener { +// +// void onChanged(Bytes key, BytesValue value, long newVersion); +// +// } + +// private static class VersioningKVEntryWraper implements DataEntry { +// +// private DataEntry kv; +// +// public VersioningKVEntryWraper(DataEntry kv) { +// this.kv = kv; +// } +// +// @Override +// public String getKey() { +// return kv.getKey().toUTF8String(); +// } +// +// @Override +// public long getVersion() { +// return kv.getVersion(); +// } +// +// @Override +// public BytesValue getValue() { +// return BinaryProtocol.decodeAs(kv.getValue(), BytesValue.class); +// } +// +// } + } \ No newline at end of file diff --git a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/MerkleAccountHeader.java b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/MerkleAccountHeader.java new file mode 100644 index 00000000..94faeb6a --- /dev/null +++ b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/MerkleAccountHeader.java @@ -0,0 +1,12 @@ +//package com.jd.blockchain.ledger.core; +// +//import com.jd.blockchain.binaryproto.DataField; +//import com.jd.blockchain.ledger.BlockchainIdentity; +//import com.jd.blockchain.ledger.MerkleSnapshot; +// +//public interface MerkleAccountHeader extends MerkleSnapshot { +// +// @DataField(order = 1, refContract = true) +// BlockchainIdentity getID(); +// +//} diff --git a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/MerkleAccountSet.java b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/MerkleAccountSet.java index d3e507ba..8f46e235 100644 --- a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/MerkleAccountSet.java +++ b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/MerkleAccountSet.java @@ -3,31 +3,35 @@ package com.jd.blockchain.ledger.core; import java.util.HashMap; import java.util.Map; -import com.jd.blockchain.binaryproto.BinaryProtocol; import com.jd.blockchain.binaryproto.DataContractRegistry; import com.jd.blockchain.crypto.AddressEncoding; import com.jd.blockchain.crypto.HashDigest; import com.jd.blockchain.crypto.PubKey; -import com.jd.blockchain.ledger.AccountHeader; -import com.jd.blockchain.ledger.BytesValue; +import com.jd.blockchain.ledger.BlockchainIdentity; +import com.jd.blockchain.ledger.BlockchainIdentityData; import com.jd.blockchain.ledger.CryptoSetting; import com.jd.blockchain.ledger.LedgerException; import com.jd.blockchain.ledger.MerkleProof; import com.jd.blockchain.ledger.MerkleSnapshot; +import com.jd.blockchain.ledger.TypedValue; import com.jd.blockchain.storage.service.ExPolicyKVStorage; import com.jd.blockchain.storage.service.VersioningKVStorage; import com.jd.blockchain.utils.Bytes; +import com.jd.blockchain.utils.DataEntry; import com.jd.blockchain.utils.Transactional; -public class MerkleAccountSet implements Transactional, MerkleProvable, AccountQuery { +public class MerkleAccountSet implements Transactional, MerkleProvable, AccountQuery { static { DataContractRegistry.register(MerkleSnapshot.class); - DataContractRegistry.register(AccountHeader.class); + DataContractRegistry.register(BlockchainIdentity.class); } - private final String keyPrefix; + private final Bytes keyPrefix; + /** + * 账户根哈希的数据集; + */ private MerkleDataSet merkleDataset; /** @@ -36,7 +40,7 @@ public class MerkleAccountSet implements Transactional, MerkleProvable, AccountQ * */ // TODO:未考虑大数据量时,由于缺少过期策略,会导致内存溢出的问题; - private Map latestAccountsCache = new HashMap<>(); + private Map latestAccountsCache = new HashMap<>(); private ExPolicyKVStorage baseExStorage; @@ -44,7 +48,7 @@ public class MerkleAccountSet implements Transactional, MerkleProvable, AccountQ private CryptoSetting cryptoSetting; - private boolean updated; + private volatile boolean updated; private AccountAccessPolicy accessPolicy; @@ -56,12 +60,12 @@ public class MerkleAccountSet implements Transactional, MerkleProvable, AccountQ merkleDataset.setReadonly(); } - public MerkleAccountSet(CryptoSetting cryptoSetting, String keyPrefix, ExPolicyKVStorage exStorage, + public MerkleAccountSet(CryptoSetting cryptoSetting, Bytes keyPrefix, ExPolicyKVStorage exStorage, VersioningKVStorage verStorage, AccountAccessPolicy accessPolicy) { this(null, cryptoSetting, keyPrefix, exStorage, verStorage, false, accessPolicy); } - public MerkleAccountSet(HashDigest rootHash, CryptoSetting cryptoSetting, String keyPrefix, + public MerkleAccountSet(HashDigest rootHash, CryptoSetting cryptoSetting, Bytes keyPrefix, ExPolicyKVStorage exStorage, VersioningKVStorage verStorage, boolean readonly, AccountAccessPolicy accessPolicy) { this.keyPrefix = keyPrefix; @@ -70,6 +74,7 @@ public class MerkleAccountSet implements Transactional, MerkleProvable, AccountQ this.baseVerStorage = verStorage; this.merkleDataset = new MerkleDataSet(rootHash, cryptoSetting, keyPrefix, this.baseExStorage, this.baseVerStorage, readonly); + this.accessPolicy = accessPolicy; } @@ -83,29 +88,17 @@ public class MerkleAccountSet implements Transactional, MerkleProvable, AccountQ return merkleDataset.getProof(key); } - public AccountHeader[] getHeaders(int fromIndex, int count) { - byte[][] results = merkleDataset.getLatestValues(fromIndex, count); - AccountHeader[] accounts = new AccountHeader[results.length]; + @Override + public BlockchainIdentity[] getHeaders(int fromIndex, int count) { + DataEntry[] results = merkleDataset.getLatestDataEntries(fromIndex, count); + BlockchainIdentity[] ids = new BlockchainIdentity[results.length]; for (int i = 0; i < results.length; i++) { - accounts[i] = deserialize(results[i]); + InnerMerkleAccount account = createAccount(results[i].getKey(), new HashDigest(results[i].getValue()), + results[i].getVersion(), true); + ids[i] = account.getID(); } - return accounts; - } - - // private VersioningAccount deserialize(byte[] txBytes) { - //// return BinaryEncodingUtils.decode(txBytes, null, Account.class); - // AccountHeaderData accInfo = BinaryEncodingUtils.decode(txBytes); - //// return new BaseAccount(accInfo.getAddress(), accInfo.getPubKey(), null, - // cryptoSetting, - //// baseExStorage, baseVerStorage, true, accessPolicy); - // return new VersioningAccount(accInfo.getAddress(), accInfo.getPubKey(), - // accInfo.getRootHash(), cryptoSetting, - // keyPrefix, baseExStorage, baseVerStorage, true, accessPolicy, accInfo.); - // } - - private AccountHeader deserialize(byte[] txBytes) { - return BinaryProtocol.decode(txBytes); + return ids; } /** @@ -118,7 +111,7 @@ public class MerkleAccountSet implements Transactional, MerkleProvable, AccountQ } @Override - public MerkleAccount getAccount(String address) { + public CompositeAccount getAccount(String address) { return getAccount(Bytes.fromBase58(address)); } @@ -128,7 +121,8 @@ public class MerkleAccountSet implements Transactional, MerkleProvable, AccountQ * @param address * @return */ - public MerkleAccount getAccount(Bytes address) { + @Override + public CompositeAccount getAccount(Bytes address) { return this.getAccount(address, -1); } @@ -142,25 +136,30 @@ public class MerkleAccountSet implements Transactional, MerkleProvable, AccountQ * @return */ public boolean contains(Bytes address) { - long latestVersion = getVersion(address); + InnerMerkleAccount acc = latestAccountsCache.get(address); + if (acc != null) { + // 无论是新注册未提交的,还是缓存已提交的账户实例,都认为是存在; + return true; + } + long latestVersion = merkleDataset.getVersion(address); return latestVersion > -1; } /** * 返回指定账户的版本;
* 如果账户已经注册,则返回该账户的最新版本,值大于等于 0;
- * 如果账户不存在,则返回 -1;
- * 如果指定的账户已经注册(通过 {@link #register(String, PubKey)} 方法),但尚未提交(通过 - * {@link #commit()} 方法),此方法对该账户仍然返回 0; + * 如果账户不存在,则返回 -1;
+ * 如果账户已经注册(通过 {@link #register(String, PubKey)} 方法),但尚未提交(通过 {@link #commit()} + * 方法),则返回 -1;
* * @param address * @return */ public long getVersion(Bytes address) { - InnerVersioningAccount acc = latestAccountsCache.get(address); + InnerMerkleAccount acc = latestAccountsCache.get(address); if (acc != null) { // 已注册尚未提交,也返回 -1; - return acc.version == -1 ? 0 : acc.version; + return acc.getVersion(); } return merkleDataset.getVersion(address); @@ -175,12 +174,12 @@ public class MerkleAccountSet implements Transactional, MerkleProvable, AccountQ * @param version 账户版本;如果指定为 -1,则返回最新版本; * @return */ - public MerkleAccount getAccount(Bytes address, long version) { + public CompositeAccount getAccount(Bytes address, long version) { version = version < 0 ? -1 : version; - InnerVersioningAccount acc = latestAccountsCache.get(address); + InnerMerkleAccount acc = latestAccountsCache.get(address); if (acc != null && version == -1) { return acc; - } else if (acc != null && acc.version == version) { + } else if (acc != null && acc.getVersion() == version) { return acc; } @@ -194,7 +193,7 @@ public class MerkleAccountSet implements Transactional, MerkleProvable, AccountQ } // 如果是不存在的,或者刚刚新增未提交的账户,则前面一步查询到的 latestVersion 小于 0, 代码不会执行到此; - if (acc != null && acc.version != latestVersion) { + if (acc != null && acc.getVersion() != latestVersion) { // 当执行到此处时,并且缓冲列表中缓存了最新的版本, // 如果当前缓存的最新账户的版本和刚刚从存储中检索得到的最新版本不一致,可能存在外部的并发更新,这超出了系统设计的逻辑; @@ -205,21 +204,15 @@ public class MerkleAccountSet implements Transactional, MerkleProvable, AccountQ } // Now, be sure that "acc == null", so get account from storage; - - byte[] bytes = merkleDataset.getValue(address, version); - if (bytes == null) { - return null; - } - // Set readonly for the old version account; boolean readonly = (version > -1 && version < latestVersion) || isReadonly(); - - // String prefix = address.concat(LedgerConsts.KEY_SEPERATOR); - // ExPolicyKVStorage ss = PrefixAppender.prefix(prefix, baseExStorage); - // VersioningKVStorage vs = PrefixAppender.prefix(prefix, baseVerStorage); - // BaseAccount accDS = deserialize(bytes, cryptoSetting, ss, vs, readonly); - String prefix = keyPrefix + address; - acc = deserialize(bytes, cryptoSetting, prefix, baseExStorage, baseVerStorage, readonly, latestVersion); + + long qVersion = version == -1 ? latestVersion : version; + // load account from storage; + acc = loadAccount(address, readonly, qVersion); + if (acc == null) { + return null; + } if (!readonly) { // cache the latest version witch enable reading and writing; // readonly version of account not necessary to be cached; @@ -228,6 +221,10 @@ public class MerkleAccountSet implements Transactional, MerkleProvable, AccountQ return acc; } + public CompositeAccount register(Bytes address, PubKey pubKey) { + return register(new BlockchainIdentityData(address, pubKey)); + } + /** * 注册一个新账户;
* @@ -239,16 +236,18 @@ public class MerkleAccountSet implements Transactional, MerkleProvable, AccountQ * @param pubKey 公钥; * @return 注册成功的账户对象; */ - public MerkleAccount register(Bytes address, PubKey pubKey) { + public CompositeAccount register(BlockchainIdentity accountId) { if (isReadonly()) { throw new IllegalArgumentException("This AccountSet is readonly!"); } + Bytes address = accountId.getAddress(); + PubKey pubKey = accountId.getPubKey(); verifyAddressEncoding(address, pubKey); - InnerVersioningAccount cachedAcc = latestAccountsCache.get(address); + InnerMerkleAccount cachedAcc = latestAccountsCache.get(address); if (cachedAcc != null) { - if (cachedAcc.version < 0) { + if (cachedAcc.getVersion() < 0) { // 同一个新账户已经注册,但尚未提交,所以重复注册不会引起任何变化; return cachedAcc; } @@ -264,17 +263,8 @@ public class MerkleAccountSet implements Transactional, MerkleProvable, AccountQ throw new LedgerException("Account Registering was rejected for the access policy!"); } - // String prefix = address.concat(LedgerConsts.KEY_SEPERATOR); - // ExPolicyKVStorage accExStorage = PrefixAppender.prefix(prefix, - // baseExStorage); - // VersioningKVStorage accVerStorage = PrefixAppender.prefix(prefix, - // baseVerStorage); - // BaseAccount accDS = createInstance(address, pubKey, cryptoSetting, - // accExStorage, accVerStorage); - - String prefix = keyPrefix + address; - InnerVersioningAccount acc = createInstance(address, pubKey, cryptoSetting, prefix, baseExStorage, baseVerStorage, - -1); + Bytes prefix = keyPrefix.concat(address); + InnerMerkleAccount acc = createInstance(accountId, cryptoSetting, prefix); latestAccountsCache.put(address, acc); updated = true; @@ -288,20 +278,50 @@ public class MerkleAccountSet implements Transactional, MerkleProvable, AccountQ } } - private InnerVersioningAccount createInstance(Bytes address, PubKey pubKey, CryptoSetting cryptoSetting, - String keyPrefix, ExPolicyKVStorage exStorage, VersioningKVStorage verStorage, long version) { - return new InnerVersioningAccount(address, pubKey, cryptoSetting, keyPrefix, exStorage, verStorage, version); + private InnerMerkleAccount createInstance(BlockchainIdentity header, CryptoSetting cryptoSetting, Bytes keyPrefix) { + return new InnerMerkleAccount(header, cryptoSetting, keyPrefix, baseExStorage, baseVerStorage); + } + + /** + * 加载指定版本的账户; + * + * @param address 账户地址; + * @param readonly 是否只读; + * @param version 账户的版本;大于等于 0 ; + * @return + */ + private InnerMerkleAccount loadAccount(Bytes address, boolean readonly, long version) { + byte[] rootHashBytes = merkleDataset.getValue(address, version); + if (rootHashBytes == null) { + return null; + } + HashDigest rootHash = new HashDigest(rootHashBytes); + + return createAccount(address, rootHash, version, readonly); } - private InnerVersioningAccount deserialize(byte[] bytes, CryptoSetting cryptoSetting, String keyPrefix, - ExPolicyKVStorage exStorage, VersioningKVStorage verStorage, boolean readonly, long version) { - AccountHeader accInfo = BinaryProtocol.decode(bytes); - return new InnerVersioningAccount(accInfo.getAddress(), accInfo.getPubKey(), accInfo.getRootHash(), cryptoSetting, - keyPrefix, exStorage, verStorage, readonly, version); + private InnerMerkleAccount createAccount(Bytes address, HashDigest rootHash, long version, boolean readonly) { + // prefix; + Bytes prefix = keyPrefix.concat(address); + + return new InnerMerkleAccount(address, version, rootHash, cryptoSetting, prefix, baseExStorage, baseVerStorage, + readonly); } - private byte[] serialize(AccountHeader account) { - return BinaryProtocol.encode(account, AccountHeader.class); + // TODO:优化:区块链身份(地址+公钥)与其Merkle树根哈希分开独立存储; + // 不必作为一个整块,避免状态数据写入时频繁重写公钥,尤其某些算法的公钥可能很大; + + /** + * 保存账户的根哈希,返回账户的新版本; + * + * @param account + * @return + */ + private long saveAccount(InnerMerkleAccount account) { + // 提交更改,更新哈希; + account.commit(); + + return account.getVersion(); } @Override @@ -315,17 +335,10 @@ public class MerkleAccountSet implements Transactional, MerkleProvable, AccountQ return; } try { - for (InnerVersioningAccount acc : latestAccountsCache.values()) { + for (InnerMerkleAccount acc : latestAccountsCache.values()) { // updated or new created; - if (acc.isUpdated() || acc.version < 0) { - // 提交更改,更新哈希; - acc.commit(); - byte[] value = serialize(acc); - long ver = merkleDataset.setValue(acc.getAddress(), value, acc.version); - if (ver < 0) { - // Update fail; - throw new LedgerException("Account updating fail! --[Address=" + acc.getAddress() + "]"); - } + if (acc.isUpdated() || acc.getVersion() < 0) { + saveAccount(acc); } } merkleDataset.commit(); @@ -343,7 +356,7 @@ public class MerkleAccountSet implements Transactional, MerkleProvable, AccountQ Bytes[] addresses = new Bytes[latestAccountsCache.size()]; latestAccountsCache.keySet().toArray(addresses); for (Bytes address : addresses) { - InnerVersioningAccount acc = latestAccountsCache.remove(address); + InnerMerkleAccount acc = latestAccountsCache.remove(address); // cancel; if (acc.isUpdated()) { acc.cancel(); @@ -352,107 +365,46 @@ public class MerkleAccountSet implements Transactional, MerkleProvable, AccountQ updated = false; } - public static class AccountHeaderData implements AccountHeader { - - private Bytes address; - private PubKey pubKey; - private HashDigest rootHash; - - public AccountHeaderData(Bytes address, PubKey pubKey, HashDigest rootHash) { - this.address = address; - this.pubKey = pubKey; - this.rootHash = rootHash; - } - - @Override - public Bytes getAddress() { - return address; - } + /** + * 内部实现的账户,监听和同步账户数据的变更; + * + * @author huanghaiquan + * + */ + private class InnerMerkleAccount extends MerkleAccount { - @Override - public PubKey getPubKey() { - return pubKey; - } + private long version; - @Override - public HashDigest getRootHash() { - return rootHash; + public InnerMerkleAccount(BlockchainIdentity accountID, CryptoSetting cryptoSetting, Bytes keyPrefix, + ExPolicyKVStorage exStorage, VersioningKVStorage verStorage) { + super(accountID, cryptoSetting, keyPrefix, exStorage, verStorage); + this.version = -1; } - } - - private class InnerVersioningAccount extends MerkleAccount { - - // private final BaseAccount account; - - private final long version; - - // public VersioningAccount(BaseAccount account, long version) { - // this.account = account; - // this.version = version; - // } - - public InnerVersioningAccount(Bytes address, PubKey pubKey, HashDigest rootHash, CryptoSetting cryptoSetting, - String keyPrefix, ExPolicyKVStorage exStorage, VersioningKVStorage verStorage, boolean readonly, - long version) { - super(address, pubKey, rootHash, cryptoSetting, keyPrefix, exStorage, verStorage, readonly); + public InnerMerkleAccount(Bytes address, long version, HashDigest dataRootHash, CryptoSetting cryptoSetting, + Bytes keyPrefix, ExPolicyKVStorage exStorage, VersioningKVStorage verStorage, boolean readonly) { + super(address, dataRootHash, cryptoSetting, keyPrefix, exStorage, verStorage, readonly); this.version = version; } - public InnerVersioningAccount(Bytes address, PubKey pubKey, CryptoSetting cryptoSetting, String keyPrefix, - ExPolicyKVStorage exStorage, VersioningKVStorage verStorage, long version) { - super(address, pubKey, cryptoSetting, keyPrefix, exStorage, verStorage); - this.version = version; + @Override + protected void onUpdated(String key, TypedValue value, long expectedVersion, long newVersion) { + updated = true; } - // @Override - // public Bytes getAddress() { - // return account.getAddress(); - // } - // - // @Override - // public PubKey getPubKey() { - // return account.getPubKey(); - // } - // - // @Override - // public HashDigest getRootHash() { - // return account.getRootHash(); - // } - // - // @Override - // public MerkleProof getProof(Bytes key) { - // return account.getProof(key); - // } - // - // @Override - // public boolean isReadonly() { - // return account.isReadonly(); - // } - @Override - public long setBytes(Bytes key, BytesValue value, long version) { - long v = super.setBytes(key, value, version); - if (v > -1) { - updated = true; + protected void onCommited(HashDigest previousRootHash, HashDigest newRootHash) { + long newVersion = merkleDataset.setValue(this.getAddress(), newRootHash.toBytes(), version); + if (newVersion < 0) { + // Update fail; + throw new LedgerException("Account updating fail! --[Address=" + this.getAddress() + "]"); } - return v; + this.version = newVersion; } - // @Override - // public long getKeyVersion(Bytes key) { - // return account.getKeyVersion(key); - // } - // - // @Override - // public byte[] getBytes(Bytes key) { - // return account.getBytes(key); - // } - // - // @Override - // public byte[] getBytes(Bytes key, long version) { - // return account.getBytes(key, version); - // } + public long getVersion() { + return version; + } } diff --git a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/MerkleDataCluster.java b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/MerkleDataCluster.java new file mode 100644 index 00000000..41339c58 --- /dev/null +++ b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/MerkleDataCluster.java @@ -0,0 +1,74 @@ +package com.jd.blockchain.ledger.core; + +import java.util.Map; + +import com.jd.blockchain.crypto.HashDigest; +import com.jd.blockchain.ledger.CryptoSetting; +import com.jd.blockchain.ledger.MerkleSnapshot; +import com.jd.blockchain.storage.service.ExPolicyKVStorage; +import com.jd.blockchain.storage.service.VersioningKVStorage; +import com.jd.blockchain.utils.Bytes; +import com.jd.blockchain.utils.Transactional; + +public class MerkleDataCluster implements Transactional, MerkleSnapshot { + + private boolean readonly; + + private MerkleDataSet rootDS; + + private Map partitions; + + /** + * Create an empty readable {@link MerkleDataCluster} instance; + */ + public MerkleDataCluster(CryptoSetting setting, Bytes keyPrefix, ExPolicyKVStorage exPolicyStorage, + VersioningKVStorage versioningStorage) { + this(null, setting, keyPrefix, exPolicyStorage, versioningStorage, false); + } + + /** + * Create an {@link MerkleDataCluster} instance; + * + * @param rootHash root hash of this {@link MerkleDataCluster} instance; + * @param readonly whether read only; + */ + public MerkleDataCluster(HashDigest rootHash, CryptoSetting setting, Bytes keyPrefix, + ExPolicyKVStorage exPolicyStorage, VersioningKVStorage versioningStorage, boolean readonly) { + this.rootDS = new MerkleDataSet(rootHash, setting, keyPrefix, exPolicyStorage, versioningStorage, readonly); + } + + @Override + public HashDigest getRootHash() { + return rootDS.getRootHash(); + } + + @Override + public boolean isUpdated() { + return rootDS.isUpdated(); + } + +// public VersioningMap getPartition(Bytes name) { +// return getPartition(name, false); +// } +// +// public VersioningMap getPartition(Bytes name, boolean create) { +// +// } +// +// public VersioningMap createPartition(Bytes name) { +// +// } + + @Override + public void commit() { + // TODO Auto-generated method stub + + } + + @Override + public void cancel() { + // TODO Auto-generated method stub + + } + +} diff --git a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/MerkleDataEntry.java b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/MerkleDataEntry.java index 3dd99df0..15de35b5 100644 --- a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/MerkleDataEntry.java +++ b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/MerkleDataEntry.java @@ -1,11 +1,12 @@ package com.jd.blockchain.ledger.core; import com.jd.blockchain.ledger.MerkleProof; -import com.jd.blockchain.storage.service.VersioningKVEntry; +import com.jd.blockchain.utils.Bytes; +import com.jd.blockchain.utils.DataEntry; public interface MerkleDataEntry { - VersioningKVEntry getData(); + DataEntry getData(); MerkleProof getProof(); } diff --git a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/MerkleDataNodeEncoder.java b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/MerkleDataNodeEncoder.java new file mode 100644 index 00000000..1b4cb0f7 --- /dev/null +++ b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/MerkleDataNodeEncoder.java @@ -0,0 +1,14 @@ +package com.jd.blockchain.ledger.core; + +import com.jd.blockchain.ledger.core.MerkleTree.DataNode; +import com.jd.blockchain.utils.Bytes; + +public interface MerkleDataNodeEncoder { + + byte getFormatVersion(); + + DataNode create(short hashAlgorithm, long sn, Bytes key, long version, byte[] hashedData); + + DataNode resolve(byte[] bytes); + +} diff --git a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/MerkleDataNodeEncoder_V0.java b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/MerkleDataNodeEncoder_V0.java new file mode 100644 index 00000000..aa47aa6f --- /dev/null +++ b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/MerkleDataNodeEncoder_V0.java @@ -0,0 +1,128 @@ +package com.jd.blockchain.ledger.core; + +import com.jd.blockchain.crypto.Crypto; +import com.jd.blockchain.crypto.HashDigest; +import com.jd.blockchain.crypto.HashFunction; +import com.jd.blockchain.ledger.core.MerkleTree.DataNode; +import com.jd.blockchain.utils.Bytes; +import com.jd.blockchain.utils.io.BytesUtils; +import com.jd.blockchain.utils.io.NumberMask; + +/** + * The first version of the DataNode binary sequence encoder, which's version + * number is 0. + * + *

+ * This version of DataNode binary sequence is composed of sn(8 bytes), + * key(variable size), version(8 bytes) and node hash(32 bytes for SHA256); + * + *

+ * In this version, the node hash is computed from bytes sequence composing of + * sn, key, version and original value of the key; + * + *

+ * For the purpose of upgrading the version of DataNode binary format, we use + * the first byte of the binary sequence as the tag to identify the version of + * DataNode binary format, and reduce the maximum value of the valid range of SN + * to 2^56.
+ * Other versions of the implementation also follow the above rules, the version + * of the data node binary format is marked from 0, incremented by 1. + * + * @author huanghaiquan + * + */ +class MerkleDataNodeEncoder_V0 implements MerkleDataNodeEncoder { + + @Override + public byte getFormatVersion() { + return 0; + } + + @Override + public DataNode resolve(byte[] bytes) { + if (bytes[0] != getFormatVersion()) { + throw new IllegalArgumentException("Unsupported version of data node bytes sequence[" + bytes[0] + "]! "); + } + + // resolve SN; + byte[] snBytes = new byte[8]; + snBytes[0] = 0x0; + System.arraycopy(bytes, 1, snBytes, 1, 7); + long sn = BytesUtils.toLong(snBytes); + + // skip bytes of SN; + int 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[] nodeHashBytes = new byte[hashSize]; + System.arraycopy(bytes, offset, nodeHashBytes, 0, hashSize); + offset += hashSize; + HashDigest nodeHash = new HashDigest(nodeHashBytes); + return new DataNode(nodeHash, sn, key, version, null, bytes); + } + + @Deprecated + @Override + public DataNode create(short hashAlgorithm, long sn, Bytes key, long version, byte[] value) { + // Header is composed of sn, key and version; + // So the size of header is: 8 + "mask of key size" + "key bytes" + 8; + int keySize = key.size(); + int maskSize = NumberMask.SHORT.getMaskLength(keySize); + + int headerSize = 8 + maskSize + keySize + 8; + byte[] headerBytes = new byte[headerSize]; + + int offset = 0; + // write sn; + offset += BytesUtils.toBytes(sn, headerBytes, 0); + + // write the size of key bytes; + NumberMask.SHORT.writeMask(keySize, headerBytes, offset); + offset += maskSize; + + // write the key bytes; + offset += key.copyTo(headerBytes, offset, keySize); + + // version; + offset += BytesUtils.toBytes(version, headerBytes, offset); + + // compute node hash from the combination of header and data value; + byte[] dataBytes = BytesUtils.concat(headerBytes, value); + + HashFunction hashFunc = Crypto.getHashFunction(hashAlgorithm); + HashDigest dataNodeHash = hashFunc.hash(dataBytes); + + // build bytes of data node, which is composed of sn, key, version and node + // hash; + int hashMaskSize = NumberMask.TINY.getMaskLength(dataNodeHash.size()); + int dataNodeSize = headerSize + hashMaskSize + dataNodeHash.size(); + byte[] nodeBytes = new byte[dataNodeSize]; + + offset = 0; + System.arraycopy(headerBytes, 0, nodeBytes, offset, headerSize); + offset += headerSize; + NumberMask.TINY.writeMask(dataNodeHash.size(), nodeBytes, offset); + offset += hashMaskSize; + System.arraycopy(dataNodeHash.toBytes(), 0, nodeBytes, offset, dataNodeHash.size()); + + // No data hash has been computed and record in this old version of + // implementation; + return new DataNode(dataNodeHash, sn, key, version, null, nodeBytes); + } +} diff --git a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/MerkleDataNodeEncoder_V1.java b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/MerkleDataNodeEncoder_V1.java new file mode 100644 index 00000000..929e7e40 --- /dev/null +++ b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/MerkleDataNodeEncoder_V1.java @@ -0,0 +1,200 @@ +package com.jd.blockchain.ledger.core; + +import com.jd.blockchain.crypto.Crypto; +import com.jd.blockchain.crypto.HashDigest; +import com.jd.blockchain.crypto.HashFunction; +import com.jd.blockchain.ledger.core.MerkleTree.DataNode; +import com.jd.blockchain.utils.Bytes; +import com.jd.blockchain.utils.io.BytesUtils; +import com.jd.blockchain.utils.io.NumberMask; + +/** + * The second version of the DataNode binary sequence encoder, which's version + * number is 1. + * + *

+ * This version of DataNode binary sequence is composed of sn(8 bytes), + * key(variable size), version(8 bytes), hash of original value the key, and + * node hash; + * + *

+ * In this version, the node hash is computed from bytes sequence composing of + * sn, key, version , hash of original value of the key; + * + *

+ * For the purpose of upgrading the version of DataNode binary format, we use + * the first byte of the binary sequence as the tag to identify the version of + * DataNode binary format, and reduce the maximum value of the valid range of SN + * to 2^56.
+ * Other versions of the implementation also follow the above rules, the version + * of the data node binary format is marked from 0, incremented by 1. + * + * @author huanghaiquan + * + */ +class MerkleDataNodeEncoder_V1 implements MerkleDataNodeEncoder { + + @Override + public byte getFormatVersion() { + return 1; + } + + /** + * Parse DataNode from it's bytes sequence; + *

+ * the bytes sequence is: sn + key + version + data_hash; + * + * @param bytes + * @return + */ + @Override + public DataNode resolve(byte[] bytes) { + if (bytes[0] != getFormatVersion()) { + throw new IllegalArgumentException("Unsupported version of data node bytes sequence[" + bytes[0] + "]! "); + } + + // resolve SN; + byte[] snBytes = new byte[8]; + snBytes[0] = 0x0; + System.arraycopy(bytes, 1, snBytes, 1, 7); + long sn = BytesUtils.toLong(snBytes); + + // skip bytes of SN; + int offset = 8; + + // resolve key of data; + // First, resolve the number mask of the key size; + // Second, read the key bytes; + 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; + Bytes key = new Bytes(keyBytes); + + // Resolve version of key; + long version = BytesUtils.toLong(bytes, offset); + offset += 8; + + // resovle data hash; + int dataHashSize = NumberMask.TINY.resolveMaskedNumber(bytes, offset); + offset += NumberMask.TINY.getMaskLength(dataHashSize); + byte[] dataHashBytes = new byte[dataHashSize]; + System.arraycopy(bytes, offset, dataHashBytes, 0, dataHashSize); + offset += dataHashSize; + HashDigest dataHash = new HashDigest(dataHashBytes); + + // resovle node hash; + int nodeHashSize = NumberMask.TINY.resolveMaskedNumber(bytes, offset); + offset += NumberMask.TINY.getMaskLength(nodeHashSize); + byte[] nodeHashBytes = new byte[nodeHashSize]; + System.arraycopy(bytes, offset, nodeHashBytes, 0, nodeHashSize); + offset += nodeHashSize; + HashDigest nodeHash = new HashDigest(nodeHashBytes); + + return new DataNode(nodeHash, sn, key, version, dataHash, bytes); + } + + public DataNode newDataNode(short hashAlgorithm, long sn, Bytes key, long version, HashDigest dataHash) { + HashFunction hashFunc = Crypto.getHashFunction(hashAlgorithm); + return create(hashFunc, sn, key, version, dataHash); + } + + @Override + public DataNode create(short hashAlgorithm, long sn, Bytes key, long version, byte[] data) { + HashFunction hashFunc = Crypto.getHashFunction(hashAlgorithm); + HashDigest dataHash = hashFunc.hash(data); + + return create(hashFunc, sn, key, version, dataHash); + } + + /** + * Data node's bytes sequence is composited by header( reference: + * {@link #buildKeyHeaderBytes(long, Bytes, long)} ) and data hash; + * + *

+ * In general, the bytes sequence is: sn + key + version + data_hash + + * node_hash; + * + * @param hashFunc + * @param sn + * @param key + * @param version + * @param dataHash + * @return + */ + private DataNode create(HashFunction hashFunc, long sn, Bytes key, long version, HashDigest dataHash) { + byte[] headerBytes = buildKeyHeaderBytes(sn, key, version); + int headerSize = headerBytes.length; + + // 单独对头部和数据进行哈希,以便在提供 Merkle 证明时能够不必传递原始数据即可进行哈希验证; + HashDigest headerHash = hashFunc.hash(headerBytes); + byte[] dataHashBytes = BytesUtils.concat(headerHash.getRawDigest(), dataHash.getRawDigest()); + + HashDigest dataNodeHash = hashFunc.hash(dataHashBytes); + + int dataHashSize = dataHash.size(); + int nodeHashSize = dataNodeHash.size(); + int dataHashMaskSize = NumberMask.TINY.getMaskLength(dataHashSize); + int nodeHashMaskSize = NumberMask.TINY.getMaskLength(nodeHashSize); + int nodeSize = headerSize + dataHashMaskSize + dataHashSize + nodeHashMaskSize + nodeHashSize; + byte[] nodeBytes = new byte[nodeSize]; + + // write header; + int offset = 0; + System.arraycopy(headerBytes, 0, nodeBytes, offset, headerSize); + offset += headerSize; + + // write data hash; + NumberMask.TINY.writeMask(dataHashSize, nodeBytes, offset); + offset += dataHashMaskSize; + System.arraycopy(dataHash.toBytes(), 0, nodeBytes, offset, dataHashSize); + offset += dataHashSize; + + // write node hash; + NumberMask.TINY.writeMask(nodeHashSize, nodeBytes, offset); + offset += nodeHashMaskSize; + System.arraycopy(dataNodeHash.toBytes(), 0, nodeBytes, offset, nodeHashSize); + + // set format version; + nodeBytes[0] = getFormatVersion(); + + return new DataNode(dataNodeHash, sn, key, version, dataHash, nodeBytes); + } + + /** + * Header is composited by sn + key + version; Bytes sequence: sn_size(8) + + * number_mask_of_key_size + key_bytes + version_size(8); + * + * @param sn + * @param key + * @param version + * @return + */ + private static byte[] buildKeyHeaderBytes(long sn, Bytes key, long version) { + int keySize = key.size(); + int maskSize = NumberMask.SHORT.getMaskLength(keySize); + + // Size Of header = sn + key + version; + // sn_size(8) + mask_size + key_size + version_size(8); + int headerSize = 8 + maskSize + keySize + 8; + byte[] headerBytes = new byte[headerSize]; + + // write bytes of sn; + int offset = 0; + offset += BytesUtils.toBytes(sn, headerBytes, 0); + + // write bytes of key mask; + NumberMask.SHORT.writeMask(keySize, headerBytes, offset); + offset += maskSize; + + // write bytes of key; + offset += key.copyTo(headerBytes, offset, keySize); + + // write bytes of version; + offset += BytesUtils.toBytes(version, headerBytes, offset); + + return headerBytes; + } + +} diff --git a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/MerkleDataSet.java b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/MerkleDataSet.java index 16927b97..80217efe 100644 --- a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/MerkleDataSet.java +++ b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/MerkleDataSet.java @@ -7,11 +7,14 @@ import com.jd.blockchain.ledger.MerkleDataNode; import com.jd.blockchain.ledger.MerkleProof; import com.jd.blockchain.storage.service.ExPolicyKVStorage; import com.jd.blockchain.storage.service.ExPolicyKVStorage.ExPolicy; -import com.jd.blockchain.storage.service.VersioningKVEntry; import com.jd.blockchain.storage.service.VersioningKVStorage; import com.jd.blockchain.storage.service.utils.BufferedKVStorage; import com.jd.blockchain.storage.service.utils.VersioningKVData; +import com.jd.blockchain.utils.ArrayUtils; import com.jd.blockchain.utils.Bytes; +import com.jd.blockchain.utils.DataEntry; +import com.jd.blockchain.utils.DataIterator; +import com.jd.blockchain.utils.Dataset; import com.jd.blockchain.utils.Transactional; import com.jd.blockchain.utils.io.BytesUtils; @@ -23,23 +26,24 @@ import com.jd.blockchain.utils.io.BytesUtils; * @author huanghaiquan * */ -public class MerkleDataSet implements Transactional, MerkleProvable { +public class MerkleDataSet implements Transactional, MerkleProvable, Dataset { /** * 4 MB MaxSize of value; */ public static final int MAX_SIZE_OF_VALUE = 4 * 1024 * 1024; - public static final String ORIG_KEY_SEPERATOR = LedgerConsts.KEY_SEPERATOR; - - public static final String SN_PREFIX = "SN" + ORIG_KEY_SEPERATOR; - public static final String DATA_PREFIX = "KV" + ORIG_KEY_SEPERATOR; - public static final String MERKLE_TREE_PREFIX = "MKL" + ORIG_KEY_SEPERATOR; + public static final Bytes SN_PREFIX = Bytes.fromString("SN" + LedgerConsts.KEY_SEPERATOR); + public static final Bytes DATA_PREFIX = Bytes.fromString("KV" + LedgerConsts.KEY_SEPERATOR); + public static final Bytes MERKLE_TREE_PREFIX = Bytes.fromString("MKL" + LedgerConsts.KEY_SEPERATOR); private final Bytes snKeyPrefix; private final Bytes dataKeyPrefix; private final Bytes merkleKeyPrefix; + @SuppressWarnings("unchecked") + private static final DataEntry[] EMPTY_ENTRIES = new DataEntry[0]; + private BufferedKVStorage bufferedStorage; private VersioningKVStorage valueStorage; @@ -71,6 +75,18 @@ public class MerkleDataSet implements Transactional, MerkleProvable { */ public MerkleDataSet(CryptoSetting setting, String keyPrefix, ExPolicyKVStorage exPolicyStorage, VersioningKVStorage versioningStorage) { + this(setting, Bytes.fromString(keyPrefix), exPolicyStorage, versioningStorage); + } + + /** + * 创建一个新的 MerkleDataSet; + * + * @param setting 密码设置; + * @param exPolicyStorage 默克尔树的存储; + * @param versioningStorage 数据的存储; + */ + public MerkleDataSet(CryptoSetting setting, Bytes keyPrefix, ExPolicyKVStorage exPolicyStorage, + VersioningKVStorage versioningStorage) { // 缓冲对KV的写入; this.bufferedStorage = new BufferedKVStorage(exPolicyStorage, versioningStorage, false); @@ -79,15 +95,15 @@ public class MerkleDataSet implements Transactional, MerkleProvable { // bufferedStorage); // this.snStorage = PrefixAppender.prefix(SN_PREFIX, (ExPolicyKVStorage) // bufferedStorage); - snKeyPrefix = Bytes.fromString(keyPrefix + SN_PREFIX); - dataKeyPrefix = Bytes.fromString(keyPrefix + DATA_PREFIX); + snKeyPrefix = keyPrefix.concat(SN_PREFIX); + dataKeyPrefix = keyPrefix.concat(DATA_PREFIX); this.valueStorage = bufferedStorage; this.snStorage = bufferedStorage; // MerkleTree 本身是可缓冲的; // ExPolicyKVStorage merkleTreeStorage = // PrefixAppender.prefix(MERKLE_TREE_PREFIX, exPolicyStorage); - merkleKeyPrefix = Bytes.fromString(keyPrefix + MERKLE_TREE_PREFIX); + merkleKeyPrefix = keyPrefix.concat(MERKLE_TREE_PREFIX); ExPolicyKVStorage merkleTreeStorage = exPolicyStorage; this.merkleTree = new MerkleTree(setting, merkleKeyPrefix, merkleTreeStorage); this.snGenerator = new MerkleSequenceSNGenerator(merkleTree); @@ -104,17 +120,33 @@ public class MerkleDataSet implements Transactional, MerkleProvable { */ public MerkleDataSet(HashDigest merkleRootHash, CryptoSetting setting, String keyPrefix, ExPolicyKVStorage exPolicyStorage, VersioningKVStorage versioningStorage, boolean readonly) { + this(merkleRootHash, setting, Bytes.fromString(keyPrefix), exPolicyStorage, versioningStorage, readonly); + } + + /** + * 从指定的 Merkle 根构建的 MerkleDataSet; + * + * @param dataStorage + * @param defaultMerkleHashAlgorithm + * @param verifyMerkleHashOnLoad + * @param merkleTreeStorage + * @param snGenerator + */ + public MerkleDataSet(HashDigest merkleRootHash, CryptoSetting setting, Bytes keyPrefix, + ExPolicyKVStorage exPolicyStorage, VersioningKVStorage versioningStorage, boolean readonly) { // 缓冲对KV的写入; this.bufferedStorage = new BufferedKVStorage(exPolicyStorage, versioningStorage, false); // 把存储数据值、SN、Merkle节点的 key 分别加入独立的前缀,避免针对 key 的注入攻击; - snKeyPrefix = Bytes.fromString(keyPrefix + SN_PREFIX); - dataKeyPrefix = Bytes.fromString(keyPrefix + DATA_PREFIX); +// snKeyPrefix = Bytes.fromString(keyPrefix + SN_PREFIX); +// dataKeyPrefix = Bytes.fromString(keyPrefix + DATA_PREFIX); + snKeyPrefix = keyPrefix.concat(SN_PREFIX); + dataKeyPrefix = keyPrefix.concat(DATA_PREFIX); this.valueStorage = bufferedStorage; this.snStorage = bufferedStorage; // MerkleTree 本身是可缓冲的; - merkleKeyPrefix = Bytes.fromString(keyPrefix + MERKLE_TREE_PREFIX); + merkleKeyPrefix = keyPrefix.concat(MERKLE_TREE_PREFIX); ExPolicyKVStorage merkleTreeStorage = exPolicyStorage; this.merkleTree = new MerkleTree(merkleRootHash, setting, merkleKeyPrefix, merkleTreeStorage, readonly); @@ -130,15 +162,21 @@ public class MerkleDataSet implements Transactional, MerkleProvable { this.readonly = true; } + @Override public long getDataCount() { return merkleTree.getDataCount(); } + /** + * 返回理论上允许的最大数据索引; + * + * @return + */ public long getMaxIndex() { return merkleTree.getMaxSn(); } - public byte[][] getLatestValues(int fromIndex, int count) { + public byte[][] getLatestValues(long fromIndex, int count) { if (count > LedgerConsts.MAX_LIST_COUNT) { throw new IllegalArgumentException("Count exceed the upper limit[" + LedgerConsts.MAX_LIST_COUNT + "]!"); } @@ -154,24 +192,41 @@ public class MerkleDataSet implements Transactional, MerkleProvable { return values; } - public VersioningKVEntry[] getLatestDataEntries(int fromIndex, int count) { + public DataEntry[] getLatestDataEntries(long fromIndex, int count) { if (count > LedgerConsts.MAX_LIST_COUNT) { throw new IllegalArgumentException("Count exceed the upper limit[" + LedgerConsts.MAX_LIST_COUNT + "]!"); } if (fromIndex < 0 || (fromIndex + count) > merkleTree.getDataCount()) { throw new IllegalArgumentException("Index out of bound!"); } - VersioningKVEntry[] values = new VersioningKVEntry[count]; + if (count == 0) { + return EMPTY_ENTRIES; + } + @SuppressWarnings("unchecked") + DataEntry[] values = new DataEntry[count]; byte[] bytesValue; for (int i = 0; i < count; i++) { MerkleDataNode dataNode = merkleTree.getData(fromIndex + i); Bytes dataKey = encodeDataKey(dataNode.getKey()); bytesValue = valueStorage.get(dataKey, dataNode.getVersion()); - values[i] = new VersioningKVData(dataNode.getKey(), dataNode.getVersion(), bytesValue); + values[i] = new VersioningKVData(dataNode.getKey(), dataNode.getVersion(), bytesValue); } return values; } + public DataEntry getLatestDataEntry(long index) { + if (index < 0 || index + 1 > merkleTree.getDataCount()) { + throw new IllegalArgumentException("Index out of bound!"); + } + byte[] bytesValue; + MerkleDataNode dataNode = merkleTree.getData(index); + Bytes dataKey = encodeDataKey(dataNode.getKey()); + bytesValue = valueStorage.get(dataKey, dataNode.getVersion()); + DataEntry entry = new VersioningKVData(dataNode.getKey(), dataNode.getVersion(), + bytesValue); + return entry; + } + /** * get the data at the specific index; * @@ -192,32 +247,34 @@ public class MerkleDataSet implements Transactional, MerkleProvable { */ public String getKeyAtIndex(int fromIndex) { MerkleDataNode dataNode = merkleTree.getData(fromIndex); - return dataNode.getKey().toUTF8String(); - } - - /** - * Create or update the value associated the specified key if the version - * checking is passed.
- * - * The value of the key will be updated only if it's latest version equals the - * specified version argument.
- * If the key doesn't exist, it will be created when the version arg was -1. - *

- * If updating is performed, the version of the key increase by 1.
- * If creating is performed, the version of the key initialize by 0.
- * - * @param key The key of data; - * @param value The value of data; - * @param version The expected latest version of the key. - * @return The new version of the key.
- * If the key is new created success, then return 0;
- * If the key is updated success, then return the new version;
- * If this operation fail by version checking or other reason, then - * return -1; - */ - public long setValue(String key, byte[] value, long version) { - return setValue(Bytes.fromString(key), value, version); - } + // TODO: 未去掉前缀; + return dataNode.getKey().toUTF8String(); + } + +// /** +// * Create or update the value associated the specified key if the version +// * checking is passed.
+// * +// * The value of the key will be updated only if it's latest version equals the +// * specified version argument.
+// * If the key doesn't exist, it will be created when the version arg was -1. +// *

+// * If updating is performed, the version of the key increase by 1.
+// * If creating is performed, the version of the key initialize by 0.
+// * +// * @param key The key of data; +// * @param value The value of data; +// * @param version The expected latest version of the key. +// * @return The new version of the key.
+// * If the key is new created success, then return 0;
+// * If the key is updated success, then return the new version;
+// * If this operation fail by version checking or other reason, then +// * return -1; +// */ +// @Override +// public long setValue(String key, byte[] value, long version) { +// return setValue(Bytes.fromString(key), value, version); +// } /** * Create or update the value associated the specified key if the version @@ -239,6 +296,7 @@ public class MerkleDataSet implements Transactional, MerkleProvable { * If this operation fail by version checking or other reason, then * return -1; */ + @Override public long setValue(Bytes key, byte[] value, long version) { if (readonly) { throw new IllegalArgumentException("This merkle dataset is readonly!"); @@ -336,18 +394,19 @@ public class MerkleDataSet implements Transactional, MerkleProvable { return mdn.getVersion(); } - /** - * Return the specified version's value;
- * - * If the key with the specified version doesn't exist, then return null;
- * If the version is specified to -1, then return the latest version's value; - * - * @param key - * @param version - */ - public byte[] getValue(String key, long version) { - return getValue(Bytes.fromString(key), version); - } +// /** +// * Return the specified version's value;
+// * +// * If the key with the specified version doesn't exist, then return null;
+// * If the version is specified to -1, then return the latest version's value; +// * +// * @param key +// * @param version +// */ +// @Override +// public byte[] getValue(String key, long version) { +// return getValue(Bytes.fromString(key), version); +// } /** * Return the specified version's value;
@@ -358,6 +417,7 @@ public class MerkleDataSet implements Transactional, MerkleProvable { * @param key * @param version */ + @Override public byte[] getValue(Bytes key, long version) { long latestVersion = getMerkleVersion(key); if (latestVersion < 0 || version > latestVersion) { @@ -370,15 +430,16 @@ public class MerkleDataSet implements Transactional, MerkleProvable { return valueStorage.get(dataKey, version); } - /** - * Return the latest version's value; - * - * @param key - * @return return null if not exist; - */ - public byte[] getValue(String key) { - return getValue(Bytes.fromString(key)); - } +// /** +// * Return the latest version's value; +// * +// * @param key +// * @return return null if not exist; +// */ +// @Override +// public byte[] getValue(String key) { +// return getValue(Bytes.fromString(key)); +// } /** * Return the latest version's value; @@ -386,6 +447,7 @@ public class MerkleDataSet implements Transactional, MerkleProvable { * @param key * @return return null if not exist; */ + @Override public byte[] getValue(Bytes key) { long latestVersion = getMerkleVersion(key); if (latestVersion < 0) { @@ -395,16 +457,17 @@ public class MerkleDataSet implements Transactional, MerkleProvable { return valueStorage.get(dataKey, latestVersion); } - /** - * Return the latest version entry associated the specified key; If the key - * doesn't exist, then return -1; - * - * @param key - * @return - */ - public long getVersion(String key) { - return getMerkleVersion(Bytes.fromString(key)); - } +// /** +// * Return the latest version entry associated the specified key; If the key +// * doesn't exist, then return -1; +// * +// * @param key +// * @return +// */ +// @Override +// public long getVersion(String key) { +// return getMerkleVersion(Bytes.fromString(key)); +// } /** * Return the latest version entry associated the specified key; If the key @@ -413,33 +476,46 @@ public class MerkleDataSet implements Transactional, MerkleProvable { * @param key * @return */ + @Override public long getVersion(Bytes key) { return getMerkleVersion(key); } - public VersioningKVEntry getDataEntry(String key) { - return getDataEntry(Bytes.fromString(key)); - } +// @Override +// public VersioningKVEntry getDataEntry(String key) { +// return getDataEntry(key, -1); +// } /** * * @param key * @return Null if the key doesn't exist! */ - public VersioningKVEntry getDataEntry(Bytes key) { - long latestVersion = getMerkleVersion(key); - if (latestVersion < 0) { - return null; - } - Bytes dataKey = encodeDataKey(key); - byte[] value = valueStorage.get(dataKey, latestVersion); - if (value == null) { - return null; - } - return new VersioningKVData(key, latestVersion, value); - } + @Override + public DataEntry getDataEntry(Bytes key) { + return getDataEntry(key, -1); + } + +// @Override +// public VersioningKVEntry getDataEntry(String key, long version) { +// Bytes keyBytes = Bytes.fromString(key); +// long latestVersion = getMerkleVersion(keyBytes); +// if (latestVersion < 0 || version > latestVersion) { +// // key not exist, or the specified version is out of the latest version indexed +// // by the current merkletree; +// return null; +// } +// version = version < 0 ? latestVersion : version; +// Bytes dataKey = encodeDataKey(keyBytes); +// byte[] value = valueStorage.get(dataKey, version); +// if (value == null) { +// return null; +// } +// return new VersioningKVData(key, version, value); +// } - public VersioningKVEntry getDataEntry(Bytes key, long version) { + @Override + public DataEntry getDataEntry(Bytes key, long version) { long latestVersion = getMerkleVersion(key); if (latestVersion < 0 || version > latestVersion) { // key not exist, or the specified version is out of the latest version indexed @@ -452,11 +528,21 @@ public class MerkleDataSet implements Transactional, MerkleProvable { if (value == null) { return null; } - return new VersioningKVData(key, version, value); + return new VersioningKVData(key, version, value); + } + + @Override + public DataIterator iterator() { + return new AscDataInterator(getDataCount()); + } + + @Override + public DataIterator iteratorDesc() { + return new DescDataInterator(getDataCount()); } public MerkleDataEntry getMerkleEntry(Bytes key, long version) { - VersioningKVEntry dataEntry = getDataEntry(key, version); + DataEntry dataEntry = getDataEntry(key, version); if (dataEntry == null) { return null; } @@ -465,7 +551,7 @@ public class MerkleDataSet implements Transactional, MerkleProvable { } public MerkleDataEntry getMerkleEntry(Bytes key) { - VersioningKVEntry dataEntry = getDataEntry(key); + DataEntry dataEntry = getDataEntry(key); if (dataEntry == null) { return null; } @@ -492,23 +578,23 @@ public class MerkleDataSet implements Transactional, MerkleProvable { } /** - * A wrapper for {@link VersioningKVEntry} and {@link MerkleProof}; + * A wrapper for {@link DataEntry} and {@link MerkleProof}; * * @author huanghaiquan * */ private static class MerkleDataEntryWrapper implements MerkleDataEntry { - private VersioningKVEntry data; + private DataEntry data; private MerkleProof proof; - public MerkleDataEntryWrapper(VersioningKVEntry data, MerkleProof proof) { + public MerkleDataEntryWrapper(DataEntry data, MerkleProof proof) { this.data = data; this.proof = proof; } @Override - public VersioningKVEntry getData() { + public DataEntry getData() { return data; } @@ -536,4 +622,119 @@ public class MerkleDataSet implements Transactional, MerkleProvable { merkleTree.cancel(); snGenerator = new MerkleSequenceSNGenerator(merkleTree); } + + // ---------------------------------------------------------- + + private class AscDataInterator implements DataIterator { + + private final long total; + + private long cursor = 0; + + public AscDataInterator(long total) { + this.total = total; + } + + @Override + public void skip(long count) { + cursor = nextCursor(count); + } + + private long nextCursor(long skippingCount) { + long c = cursor + skippingCount; + return c > total ? total : c; + } + + @Override + public DataEntry next() { + if (hasNext()) { + DataEntry entry = getLatestDataEntry(cursor); + cursor = nextCursor(1); + return entry; + } + return null; + } + + @Override + public DataEntry[] next(int count) { + if (hasNext()) { + long from = cursor; + long nextCursor = nextCursor(count); + long c = nextCursor - cursor; + if (c > LedgerConsts.MAX_LIST_COUNT) { + throw new IllegalArgumentException( + "Count exceed the upper limit[" + LedgerConsts.MAX_LIST_COUNT + "]!"); + } + DataEntry[] entries = getLatestDataEntries(from, (int) c); + cursor = nextCursor; + return entries; + } + return EMPTY_ENTRIES; + } + + @Override + public boolean hasNext() { + return cursor < total; + } + + } + + private class DescDataInterator implements DataIterator { + + private final long total; + + private long cursor; + + public DescDataInterator(long total) { + this.total = total; + this.cursor = total - 1; + } + + @Override + public void skip(long count) { + cursor = nextCursor(count); + } + + private long nextCursor(long skippingCount) { + long c = cursor - skippingCount; + return c < 0 ? -1 : c; + } + + @Override + public DataEntry next() { + if (hasNext()) { + DataEntry entry = getLatestDataEntry(cursor); + cursor = nextCursor(1); + return entry; + } + return null; + } + + @Override + public DataEntry[] next(int count) { + if (hasNext()) { + long nextCursor = nextCursor(count); + long from = nextCursor + 1; + long c = cursor - nextCursor; + if (c > LedgerConsts.MAX_LIST_COUNT) { + throw new IllegalArgumentException( + "Count exceed the upper limit[" + LedgerConsts.MAX_LIST_COUNT + "]!"); + } + DataEntry[] entries = getLatestDataEntries(from, (int) c); + // reverse; + ArrayUtils.reverse(entries); + + cursor = nextCursor; + return entries; + } + return EMPTY_ENTRIES; + } + + @Override + public boolean hasNext() { + return cursor < total; + } + + } + } \ No newline at end of file diff --git a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/MerkleTree.java b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/MerkleTree.java index d86facba..b34cf9fe 100644 --- a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/MerkleTree.java +++ b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/MerkleTree.java @@ -52,8 +52,9 @@ public class MerkleTree implements Transactional { public static final int TREE_DEGREE = 16; - public static final int MAX_LEVEL = 15; + public static final int MAX_LEVEL = 14; + // 正好是 2 的 56 次方(7字节),将 SN 8个字节中的首个字节预留作为 DataNode 的编码格式版本标记; public static final long MAX_DATACOUNT = power(TREE_DEGREE, MAX_LEVEL); public static final long MAX_SN = MAX_DATACOUNT - 1; @@ -147,14 +148,10 @@ public class MerkleTree implements Transactional { /** * 创建 Merkle 树; * - * @param rootHash - * 节点的根Hash; 如果指定为 null,则实际上创建一个空的 Merkle Tree; - * @param verifyOnLoad - * 从外部存储加载节点时是否校验节点的哈希; - * @param kvStorage - * 保存 Merkle 节点的存储服务; - * @param readonly - * 是否只读; + * @param rootHash 节点的根Hash; 如果指定为 null,则实际上创建一个空的 Merkle Tree; + * @param verifyOnLoad 从外部存储加载节点时是否校验节点的哈希; + * @param kvStorage 保存 Merkle 节点的存储服务; + * @param readonly 是否只读; */ public MerkleTree(HashDigest rootHash, CryptoSetting setting, String keyPrefix, ExPolicyKVStorage kvStorage, boolean readonly) { @@ -164,14 +161,10 @@ public class MerkleTree implements Transactional { /** * 创建 Merkle 树; * - * @param rootHash - * 节点的根Hash; 如果指定为 null,则实际上创建一个空的 Merkle Tree; - * @param verifyOnLoad - * 从外部存储加载节点时是否校验节点的哈希; - * @param kvStorage - * 保存 Merkle 节点的存储服务; - * @param readonly - * 是否只读; + * @param rootHash 节点的根Hash; 如果指定为 null,则实际上创建一个空的 Merkle Tree; + * @param verifyOnLoad 从外部存储加载节点时是否校验节点的哈希; + * @param kvStorage 保存 Merkle 节点的存储服务; + * @param readonly 是否只读; */ public MerkleTree(HashDigest rootHash, CryptoSetting setting, Bytes keyPrefix, ExPolicyKVStorage kvStorage, boolean readonly) { @@ -205,8 +198,7 @@ public class MerkleTree implements Transactional { *

* 如果 sn 超出范围,则引发 {@link IndexOutOfBoundsException} ; * - * @param sn - * 数据的序列号; + * @param sn 数据的序列号; * @return 默克尔证明的实例; */ public MerkleProof getProof(long sn) { @@ -242,13 +234,10 @@ public class MerkleTree implements Transactional { * 注:默克尔树只保存指定数据的哈希以及关联的键,而不会保存数据原文,因此调用者需要自己处理对数据的存储;
* 此外,哈希计算是把键和数据内容拼接一起进行计算的; * - * @param sn - * 与此数据唯一相关的序列号;sn 必须大于等于 0 ; - * @param key - * 与此数据唯一相关的键; + * @param sn 与此数据唯一相关的序列号;sn 必须大于等于 0 ; + * @param key 与此数据唯一相关的键; * @param version - * @param hashedData - * 要参与哈希计算的数据内容;注:此参数值并不会被默克尔树保存; + * @param hashedData 要参与哈希计算的数据内容;注:此参数值并不会被默克尔树保存; * @return */ public MerkleDataNode setData(long sn, String key, long version, byte[] hashedData) { @@ -266,13 +255,10 @@ public class MerkleTree implements Transactional { * 注:默克尔树只保存指定数据的哈希以及关联的键,而不会保存数据原文,因此调用者需要自己处理对数据的存储;
* 此外,哈希计算是把键和数据内容拼接一起进行计算的; * - * @param sn - * 与此数据唯一相关的序列号;sn 必须大于等于 0 ; - * @param key - * 与此数据唯一相关的键; + * @param sn 与此数据唯一相关的序列号;sn 必须大于等于 0 ; + * @param key 与此数据唯一相关的键; * @param version - * @param hashedData - * 要参与哈希计算的数据内容;注:此参数值并不会被默克尔树保存; + * @param hashedData 要参与哈希计算的数据内容;注:此参数值并不会被默克尔树保存; * @return */ public MerkleDataNode setData(long sn, Bytes key, long version, byte[] hashedData) { @@ -285,7 +271,8 @@ public class MerkleTree implements Transactional { if (sn > MAX_SN) { throw new IllegalArgumentException("The sn is great than MAX[" + MAX_SN + "]!"); } - DataNode dataNode = DataNode.newDataNode(setting.getHashAlgorithm(), sn, key, version, hashedData); + DataNode dataNode = MerkleTreeEncoder.LATEST_DATANODE_ENCODER.create(setting.getHashAlgorithm(), sn, key, + version, hashedData); updatedDataNodes.put(sn, dataNode); return dataNode; } @@ -591,10 +578,8 @@ public class MerkleTree implements Transactional { /** * 重新计算所有子节点以及自身的哈希,并返回新加入的数据节点的数量; * - * @param pathNode - * 需要重新计算 hash 的路径节点; - * @param updatedNodes - * 用于记录已更新节点的列表; + * @param pathNode 需要重新计算 hash 的路径节点; + * @param updatedNodes 用于记录已更新节点的列表; * @return */ @SuppressWarnings("unused") @@ -732,12 +717,10 @@ public class MerkleTree implements Transactional { * * 如果 sn 超出范围,则引发 {@link IndexOutOfBoundsException} ; * - * @param sn - * 数据节点的序列号; - * @param path - * 用于记录节点路径的列表,长度必须大于等于当前默克尔树的总的层级(即 path.length 大于等于 root.level + - * 1);
- * 如果参数为 null,则不记录; + * @param sn 数据节点的序列号; + * @param path 用于记录节点路径的列表,长度必须大于等于当前默克尔树的总的层级(即 path.length 大于等于 root.level + + * 1);
+ * 如果参数为 null,则不记录; * @return 序列号对应的数据节点;
* 如果不存在,则返回 null,注意,此时指定的路径参数 path 依然写入了查找过程的路径; */ @@ -844,7 +827,8 @@ public class MerkleTree implements Transactional { if (bytes == null || bytes.length == 0) { return null; } - DataNode dataNode = DataNode.parse(bytes); + + DataNode dataNode = MerkleTreeEncoder.resolve(bytes); if (verify && !hashBytes.equals(dataNode.nodeHash)) { String keyStr = hashBytes.toBase58(); String actualHashStr = dataNode.nodeHash.toBase58(); @@ -861,8 +845,7 @@ public class MerkleTree implements Transactional { * 注:此方法不处理溢出;调用者需要自行规避; * * @param value - * @param x - * 大于等于 0 的整数; + * @param x 大于等于 0 的整数; * @return */ private static long power(long value, int x) { @@ -1140,14 +1123,10 @@ public class MerkleTree implements Transactional { /** * 创建一个路径节点; * - * @param hashAlgorithm - * 生成节点采用的哈希算法; - * @param startingSN - * 路径节点表示的子树的起始序列号; - * @param level - * 路径节点的层级深度;路径节点的深度从 1 开始往上递增(数据节点作为树的深度为 0); - * @param dataCount - * 路径节点表示的子树所包含的数据节点的数量; + * @param hashAlgorithm 生成节点采用的哈希算法; + * @param startingSN 路径节点表示的子树的起始序列号; + * @param level 路径节点的层级深度;路径节点的深度从 1 开始往上递增(数据节点作为树的深度为 0); + * @param dataCount 路径节点表示的子树所包含的数据节点的数量; */ private PathNode(CryptoAlgorithm hashAlgorithm, long startingSN, int level, long dataCount) { this(hashAlgorithm, startingSN, level, dataCount, new HashDigest[TREE_DEGREE], null); @@ -1338,10 +1317,8 @@ public class MerkleTree implements Transactional { /** * 从指定的字节数组反序列化节点; * - * @param bytes - * 字节数组;合法的输入应等同于 {@link #toBytes()} 方法的输出; - * @param checkHash - * 是否重新计算并校验节点的哈希; + * @param bytes 字节数组;合法的输入应等同于 {@link #toBytes()} 方法的输出; + * @param checkHash 是否重新计算并校验节点的哈希; * @return */ private static PathNode parse(byte[] bytes, boolean checkHash) { @@ -1429,7 +1406,7 @@ public class MerkleTree implements Transactional { * @author huanghaiquan * */ - private static class DataNode extends AbstractMerkleNode implements MerkleDataNode { + static class DataNode extends AbstractMerkleNode implements MerkleDataNode { private long sn; @@ -1437,64 +1414,17 @@ public class MerkleTree implements Transactional { private long version; - private byte[] dataNodeBytes; + private byte[] nodeBytes; + + private HashDigest valueHash; - private DataNode(long sn, Bytes key, long version, HashDigest dataHash, byte[] dataBytes) { + DataNode(HashDigest nodeHash, long sn, Bytes key, long version, HashDigest valueHash, byte[] nodeBytes) { this.sn = sn; this.key = key; this.version = version; - this.nodeHash = dataHash; - this.dataNodeBytes = dataBytes; - } - - @SuppressWarnings("unused") - private static DataNode newDataNode(CryptoAlgorithm hashAlgorithm, long sn, Bytes key, long version, - byte[] hashedData) { - return newDataNode(hashAlgorithm.code(), sn, key, version, hashedData); - } - - private static DataNode 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 DataNode(sn, key, version, dataHash, dataNodeBytes); + this.nodeHash = nodeHash; + this.valueHash = valueHash; + this.nodeBytes = nodeBytes; } @Override @@ -1547,6 +1477,11 @@ public class MerkleTree implements Transactional { return version; } + @Override + public HashDigest getValueHash() { + return valueHash; + } + @Override public byte[] toBytes() { // ByteArrayOutputStream out = new ByteArrayOutputStream(); @@ -1574,38 +1509,7 @@ public class MerkleTree implements Transactional { // // System.arraycopy(nodeHash.toBytes(), 0, totalBytes, offset, hashSize); - return dataNodeBytes; - } - - private static DataNode 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 DataNode(sn, key, version, dataHash, bytes); + return nodeBytes; } @Override diff --git a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/MerkleTreeEncoder.java b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/MerkleTreeEncoder.java new file mode 100644 index 00000000..a02ba65a --- /dev/null +++ b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/MerkleTreeEncoder.java @@ -0,0 +1,31 @@ +package com.jd.blockchain.ledger.core; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +import com.jd.blockchain.ledger.core.MerkleTree.DataNode; + +class MerkleTreeEncoder { + + static final MerkleDataNodeEncoder LATEST_DATANODE_ENCODER = new MerkleDataNodeEncoder_V1(); + + static final MerkleDataNodeEncoder V0_DATANODE_ENCODER = new MerkleDataNodeEncoder_V0(); + + static final List DATANODE_ENCODERS = Collections + .unmodifiableList(Arrays.asList(LATEST_DATANODE_ENCODER, V0_DATANODE_ENCODER)); + + /** + * @param bytes + * @return + */ + static DataNode resolve(byte[] bytes) { + for (MerkleDataNodeEncoder encoder : MerkleTreeEncoder.DATANODE_ENCODERS) { + if (encoder.getFormatVersion() == bytes[0]) { + return encoder.resolve(bytes); + } + } + + throw new IllegalStateException("Unsupported version of DataNode bytes sequence[" + bytes[0] + "]!"); + } +} diff --git a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/OpeningAccessPolicy.java b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/OpeningAccessPolicy.java index 6628aad3..8efd1d10 100644 --- a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/OpeningAccessPolicy.java +++ b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/OpeningAccessPolicy.java @@ -1,7 +1,7 @@ package com.jd.blockchain.ledger.core; import com.jd.blockchain.crypto.PubKey; -import com.jd.blockchain.ledger.AccountHeader; +import com.jd.blockchain.ledger.BlockchainIdentity; import com.jd.blockchain.utils.Bytes; /** @@ -15,7 +15,7 @@ import com.jd.blockchain.utils.Bytes; public class OpeningAccessPolicy implements AccountAccessPolicy { @Override - public boolean checkDataWriting(AccountHeader account) { + public boolean checkDataWriting(BlockchainIdentity account) { return true; } diff --git a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/ParticipantDataset.java b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/ParticipantDataset.java index dbc077a8..bd629b8a 100644 --- a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/ParticipantDataset.java +++ b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/ParticipantDataset.java @@ -28,7 +28,7 @@ public class ParticipantDataset implements Transactional, MerkleProvable, Partic public ParticipantDataset(HashDigest merkleRootHash, CryptoSetting cryptoSetting, String prefix, ExPolicyKVStorage exPolicyStorage, VersioningKVStorage verStorage, boolean readonly) { - dataset = new MerkleDataSet(merkleRootHash, cryptoSetting, prefix, exPolicyStorage, verStorage, readonly); + dataset = new MerkleDataSet(merkleRootHash, cryptoSetting, Bytes.fromString(prefix), exPolicyStorage, verStorage, readonly); } @Override diff --git a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/RolePrivilegeDataset.java b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/RolePrivilegeDataset.java index 14673435..220b519c 100644 --- a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/RolePrivilegeDataset.java +++ b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/RolePrivilegeDataset.java @@ -14,10 +14,10 @@ import com.jd.blockchain.ledger.RolePrivileges; import com.jd.blockchain.ledger.TransactionPermission; import com.jd.blockchain.ledger.TransactionPrivilege; import com.jd.blockchain.storage.service.ExPolicyKVStorage; -import com.jd.blockchain.storage.service.VersioningKVEntry; import com.jd.blockchain.storage.service.VersioningKVStorage; import com.jd.blockchain.utils.Bytes; import com.jd.blockchain.utils.Transactional; +import com.jd.blockchain.utils.DataEntry; public class RolePrivilegeDataset implements Transactional, MerkleProvable, RolePrivilegeSettings { @@ -30,7 +30,8 @@ public class RolePrivilegeDataset implements Transactional, MerkleProvable, Role public RolePrivilegeDataset(HashDigest merkleRootHash, CryptoSetting cryptoSetting, String prefix, ExPolicyKVStorage exPolicyStorage, VersioningKVStorage verStorage, boolean readonly) { - dataset = new MerkleDataSet(merkleRootHash, cryptoSetting, prefix, exPolicyStorage, verStorage, readonly); + dataset = new MerkleDataSet(merkleRootHash, cryptoSetting, Bytes.fromString(prefix), exPolicyStorage, + verStorage, readonly); } @Override @@ -255,7 +256,7 @@ public class RolePrivilegeDataset implements Transactional, MerkleProvable, Role public RolePrivileges getRolePrivilege(String roleName) { // 只返回最新版本; Bytes key = encodeKey(roleName); - VersioningKVEntry kv = dataset.getDataEntry(key); + DataEntry kv = dataset.getDataEntry(key); if (kv == null) { return null; } @@ -265,7 +266,7 @@ public class RolePrivilegeDataset implements Transactional, MerkleProvable, Role @Override public RolePrivileges[] getRolePrivileges(int index, int count) { - VersioningKVEntry[] kvEntries = dataset.getLatestDataEntries(index, count); + DataEntry[] kvEntries = dataset.getLatestDataEntries(index, count); RolePrivileges[] pns = new RolePrivileges[kvEntries.length]; PrivilegeSet privilege; for (int i = 0; i < pns.length; i++) { diff --git a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/SecurityContext.java b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/SecurityContext.java index d3ad83ba..2fde0054 100644 --- a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/SecurityContext.java +++ b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/SecurityContext.java @@ -1,12 +1,5 @@ package com.jd.blockchain.ledger.core; -import java.util.Set; - -import com.jd.blockchain.ledger.BlockchainIdentity; -import com.jd.blockchain.ledger.LedgerPermission; -import com.jd.blockchain.ledger.LedgerSecurityException; -import com.jd.blockchain.ledger.TransactionPermission; - public class SecurityContext { private static ThreadLocal policyHolder = new ThreadLocal(); diff --git a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/TransactionBatchProcessor.java b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/TransactionBatchProcessor.java index 3d2ebed9..e2f42050 100644 --- a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/TransactionBatchProcessor.java +++ b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/TransactionBatchProcessor.java @@ -39,6 +39,18 @@ public class TransactionBatchProcessor implements TransactionBatchProcess { private TransactionBatchResult batchResult; + public byte[] getPrevLatestBlockHash() { + return ledger.getLatestBlockHash().toBytes(); + } + + public byte[] getGenisBlockHash() { + return ledger.getBlockHash(0).toBytes(); + } + + public long getPreLatestBlockHeight() { + return ledger.getLatestBlockHeight(); + } + public HashDigest getLedgerHash() { return ledger.getHash(); } @@ -273,9 +285,6 @@ public class TransactionBatchProcessor implements TransactionBatchProcess { // rollback all the block; // TODO: handle the BlockRollbackException in detail; result = TransactionState.IGNORED_BY_BLOCK_FULL_ROLLBACK; - if (e instanceof DataVersionConflictException) { - result = TransactionState.DATA_VERSION_CONFLICT; - } txCtx.rollback(); LOGGER.error( String.format("Transaction was rolled back! --[BlockHeight=%s][RequestHash=%s][TxHash=%s] --%s", @@ -295,6 +304,8 @@ public class TransactionBatchProcessor implements TransactionBatchProcess { result = TransactionState.CONTRACT_DOES_NOT_EXIST; } else if (e instanceof ParticipantDoesNotExistException) { result = TransactionState.PARTICIPANT_DOES_NOT_EXIST; + } else if (e instanceof DataVersionConflictException) { + result = TransactionState.DATA_VERSION_CONFLICT; } txCtx.discardAndCommit(result, operationResults); LOGGER.error(String.format( diff --git a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/TransactionEngineImpl.java b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/TransactionEngineImpl.java index 2d0fb55a..e684ff4d 100644 --- a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/TransactionEngineImpl.java +++ b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/TransactionEngineImpl.java @@ -48,6 +48,16 @@ public class TransactionEngineImpl implements TransactionEngine { return batchs.get(ledgerHash); } + public void freeBatch(HashDigest ledgerHash) { + finishBatch(ledgerHash); + } + + public void resetNewBlockEditor(HashDigest ledgerHash) { + + LedgerRepository ledgerRepo = ledgerService.getLedger(ledgerHash); + ((LedgerRepositoryImpl)ledgerRepo).resetNextBlockEditor(); + } + private void finishBatch(HashDigest ledgerHash) { batchs.remove(ledgerHash); } diff --git a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/TransactionSet.java b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/TransactionSet.java index 28c6bff4..fe336005 100644 --- a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/TransactionSet.java +++ b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/TransactionSet.java @@ -88,7 +88,8 @@ public class TransactionSet implements Transactional, TransactionQuery { public TransactionSet(HashDigest txRootHash, CryptoSetting setting, String keyPrefix, ExPolicyKVStorage merkleTreeStorage, VersioningKVStorage dataStorage, boolean readonly) { this.txStatePrefix = Bytes.fromString(keyPrefix + TX_STATE_PREFIX); - this.txSet = new MerkleDataSet(txRootHash, setting, keyPrefix, merkleTreeStorage, dataStorage, readonly); + this.txSet = new MerkleDataSet(txRootHash, setting, Bytes.fromString(keyPrefix), merkleTreeStorage, dataStorage, + readonly); } /** diff --git a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/UserAccount.java b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/UserAccount.java index 49743f90..87696e86 100644 --- a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/UserAccount.java +++ b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/UserAccount.java @@ -1,9 +1,9 @@ package com.jd.blockchain.ledger.core; -import com.jd.blockchain.crypto.HashDigest; import com.jd.blockchain.crypto.PubKey; import com.jd.blockchain.ledger.BytesValue; -import com.jd.blockchain.ledger.BytesData; +import com.jd.blockchain.ledger.LedgerException; +import com.jd.blockchain.ledger.TypedValue; import com.jd.blockchain.ledger.UserInfo; import com.jd.blockchain.utils.Bytes; @@ -13,72 +13,73 @@ import com.jd.blockchain.utils.Bytes; * @author huanghaiquan * */ -public class UserAccount implements UserInfo { +public class UserAccount extends AccountDecorator implements UserInfo { // implements UserInfo { - private static final Bytes USER_INFO_PREFIX = Bytes.fromString("PROP" + LedgerConsts.KEY_SEPERATOR); + private static final String USER_INFO_PREFIX = "PROP" + LedgerConsts.KEY_SEPERATOR; - private static final Bytes DATA_PUB_KEY = Bytes.fromString("DATA-PUBKEY"); + private static final String DATA_PUB_KEY = "DATA-PUBKEY"; - private MerkleAccount baseAccount; + public UserAccount(CompositeAccount baseAccount) { + super(baseAccount); + } + + private PubKey dataPubKey; + @Override public Bytes getAddress() { - return baseAccount.getAddress(); + return getID().getAddress(); } @Override public PubKey getPubKey() { - return baseAccount.getPubKey(); + return getID().getPubKey(); } - + @Override - public HashDigest getRootHash() { - return baseAccount.getRootHash(); - } - - public UserAccount(MerkleAccount baseAccount) { - this.baseAccount = baseAccount; - } - public PubKey getDataPubKey() { - BytesValue pkBytes = baseAccount.getBytes(DATA_PUB_KEY); - if (pkBytes == null) { - return null; + if (dataPubKey == null) { + BytesValue pkBytes = getHeaders().getValue(DATA_PUB_KEY); + if (pkBytes == null) { + return null; + } + dataPubKey = new PubKey(pkBytes.getBytes().toBytes()); } - return new PubKey(pkBytes.getValue().toBytes()); + return dataPubKey; } - public long setDataPubKey(PubKey pubKey) { - byte[] pkBytes = pubKey.toBytes(); - return baseAccount.setBytes(DATA_PUB_KEY, BytesData.fromBytes(pkBytes), -1); + public void setDataPubKey(PubKey pubKey) { + long version = getHeaders().getVersion(DATA_PUB_KEY); + setDataPubKey(pubKey, version); } - public long setDataPubKey(PubKey pubKey, long version) { - byte[] pkBytes = pubKey.toBytes(); - return baseAccount.setBytes(DATA_PUB_KEY, BytesData.fromBytes(pkBytes), version); + public void setDataPubKey(PubKey pubKey, long version) { + TypedValue value = TypedValue.fromPubKey(dataPubKey); + long newVersion = getHeaders().setValue(DATA_PUB_KEY, value, version); + if (newVersion > -1) { + dataPubKey = pubKey; + } else { + throw new LedgerException("Data public key was updated failed!"); + } } public long setProperty(String key, String value, long version) { - return setProperty(Bytes.fromString(key), value, version); + return getHeaders().setValue(encodePropertyKey(key), TypedValue.fromText(value), version); } - public long setProperty(Bytes key, String value, long version) { - return baseAccount.setBytes(encodePropertyKey(key), BytesData.fromText(value), version); + public String getProperty(String key) { + BytesValue value = getHeaders().getValue(encodePropertyKey(key)); + return value == null ? null : value.getBytes().toUTF8String(); } - public String getProperty(Bytes key) { - BytesValue value = baseAccount.getBytes(encodePropertyKey(key)); - return value == null ? null : value.getValue().toUTF8String(); + public String getProperty(String key, long version) { + BytesValue value = getHeaders().getValue(encodePropertyKey(key), version); + return value == null ? null : value.getBytes().toUTF8String(); } - public String getProperty(Bytes key, long version) { - BytesValue value = baseAccount.getBytes(encodePropertyKey(key), version); - return value == null ? null : value.getValue().toUTF8String(); + private String encodePropertyKey(String key) { + return USER_INFO_PREFIX+key; } - private Bytes encodePropertyKey(Bytes key) { - // return key.concatTo(USER_INFO_PREFIX); - return USER_INFO_PREFIX.concat(key); - } } \ No newline at end of file diff --git a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/UserAccountSet.java b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/UserAccountSet.java index a2e25356..bc71711d 100644 --- a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/UserAccountSet.java +++ b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/UserAccountSet.java @@ -2,7 +2,7 @@ package com.jd.blockchain.ledger.core; import com.jd.blockchain.crypto.HashDigest; import com.jd.blockchain.crypto.PubKey; -import com.jd.blockchain.ledger.AccountHeader; +import com.jd.blockchain.ledger.BlockchainIdentity; import com.jd.blockchain.ledger.CryptoSetting; import com.jd.blockchain.ledger.LedgerException; import com.jd.blockchain.ledger.MerkleProof; @@ -21,19 +21,20 @@ public class UserAccountSet implements Transactional, UserAccountQuery { public UserAccountSet(CryptoSetting cryptoSetting, String keyPrefix, ExPolicyKVStorage simpleStorage, VersioningKVStorage versioningStorage, AccountAccessPolicy accessPolicy) { - accountSet = new MerkleAccountSet(cryptoSetting, keyPrefix, simpleStorage, versioningStorage, accessPolicy); + accountSet = new MerkleAccountSet(cryptoSetting, Bytes.fromString(keyPrefix), simpleStorage, versioningStorage, + accessPolicy); } public UserAccountSet(HashDigest dataRootHash, CryptoSetting cryptoSetting, String keyPrefix, ExPolicyKVStorage exStorage, VersioningKVStorage verStorage, boolean readonly, AccountAccessPolicy accessPolicy) { - accountSet = new MerkleAccountSet(dataRootHash, cryptoSetting, keyPrefix, exStorage, verStorage, readonly, - accessPolicy); + accountSet = new MerkleAccountSet(dataRootHash, cryptoSetting, Bytes.fromString(keyPrefix), exStorage, + verStorage, readonly, accessPolicy); } @Override - public AccountHeader[] getHeaders(int fromIndex, int count) { - return accountSet.getHeaders(fromIndex,count); + public BlockchainIdentity[] getHeaders(int fromIndex, int count) { + return accountSet.getHeaders(fromIndex, count); } /** @@ -49,7 +50,7 @@ public class UserAccountSet implements Transactional, UserAccountQuery { public boolean isReadonly() { return accountSet.isReadonly(); } - + void setReadonly() { accountSet.setReadonly(); } @@ -63,7 +64,7 @@ public class UserAccountSet implements Transactional, UserAccountQuery { public MerkleProof getProof(Bytes key) { return accountSet.getProof(key); } - + @Override public UserAccount getAccount(String address) { return getAccount(Bytes.fromBase58(address)); @@ -71,7 +72,7 @@ public class UserAccountSet implements Transactional, UserAccountQuery { @Override public UserAccount getAccount(Bytes address) { - MerkleAccount baseAccount = accountSet.getAccount(address); + CompositeAccount baseAccount = accountSet.getAccount(address); return new UserAccount(baseAccount); } @@ -82,7 +83,7 @@ public class UserAccountSet implements Transactional, UserAccountQuery { @Override public UserAccount getAccount(Bytes address, long version) { - MerkleAccount baseAccount = accountSet.getAccount(address, version); + CompositeAccount baseAccount = accountSet.getAccount(address, version); return new UserAccount(baseAccount); } @@ -93,14 +94,12 @@ public class UserAccountSet implements Transactional, UserAccountQuery { * * 如果指定的地址和公钥不匹配,则会引发 {@link LedgerException} 异常; * - * @param address - * 区块链地址; - * @param pubKey - * 公钥; + * @param address 区块链地址; + * @param pubKey 公钥; * @return 注册成功的用户对象; */ public UserAccount register(Bytes address, PubKey pubKey) { - MerkleAccount baseAccount = accountSet.register(address, pubKey); + CompositeAccount baseAccount = accountSet.register(address, pubKey); return new UserAccount(baseAccount); } diff --git a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/UserRoleDataset.java b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/UserRoleDataset.java index 25ecd85a..8aa45ebc 100644 --- a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/UserRoleDataset.java +++ b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/UserRoleDataset.java @@ -13,10 +13,10 @@ import com.jd.blockchain.ledger.RolesPolicy; import com.jd.blockchain.ledger.UserRoles; import com.jd.blockchain.ledger.UserAuthorizationSettings; import com.jd.blockchain.storage.service.ExPolicyKVStorage; -import com.jd.blockchain.storage.service.VersioningKVEntry; import com.jd.blockchain.storage.service.VersioningKVStorage; import com.jd.blockchain.utils.Bytes; import com.jd.blockchain.utils.Transactional; +import com.jd.blockchain.utils.DataEntry; /** * User-Role authorization data set; @@ -35,7 +35,7 @@ public class UserRoleDataset implements Transactional, MerkleProvable, UserAutho public UserRoleDataset(HashDigest merkleRootHash, CryptoSetting cryptoSetting, String prefix, ExPolicyKVStorage exPolicyStorage, VersioningKVStorage verStorage, boolean readonly) { - dataset = new MerkleDataSet(merkleRootHash, cryptoSetting, prefix, exPolicyStorage, verStorage, readonly); + dataset = new MerkleDataSet(merkleRootHash, cryptoSetting, Bytes.fromString(prefix), exPolicyStorage, verStorage, readonly); } @Override @@ -168,7 +168,7 @@ public class UserRoleDataset implements Transactional, MerkleProvable, UserAutho @Override public UserRoles getUserRoles(Bytes userAddress) { // 只返回最新版本; - VersioningKVEntry kv = dataset.getDataEntry(userAddress); + DataEntry kv = dataset.getDataEntry(userAddress); if (kv == null) { return null; } @@ -178,7 +178,7 @@ public class UserRoleDataset implements Transactional, MerkleProvable, UserAutho @Override public UserRoles[] getUserRoles() { - VersioningKVEntry[] kvEntries = dataset.getLatestDataEntries(0, (int) dataset.getDataCount()); + DataEntry[] kvEntries = dataset.getLatestDataEntries(0, (int) dataset.getDataCount()); UserRoles[] pns = new UserRoles[kvEntries.length]; RoleSet roleset; for (int i = 0; i < pns.length; i++) { diff --git a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/handles/ContractLedgerContext.java b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/handles/ContractLedgerContext.java index 0d0d3c3d..fe3f9826 100644 --- a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/handles/ContractLedgerContext.java +++ b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/handles/ContractLedgerContext.java @@ -5,7 +5,24 @@ import java.util.List; import com.jd.blockchain.contract.LedgerContext; import com.jd.blockchain.crypto.HashDigest; -import com.jd.blockchain.ledger.*; +import com.jd.blockchain.ledger.BlockchainIdentity; +import com.jd.blockchain.ledger.BytesValue; +import com.jd.blockchain.ledger.ContractInfo; +import com.jd.blockchain.ledger.DataAccountKVSetOperation; +import com.jd.blockchain.ledger.DataAccountRegisterOperation; +import com.jd.blockchain.ledger.TypedKVEntry; +import com.jd.blockchain.ledger.KVInfoVO; +import com.jd.blockchain.ledger.LedgerAdminInfo; +import com.jd.blockchain.ledger.LedgerBlock; +import com.jd.blockchain.ledger.LedgerInfo; +import com.jd.blockchain.ledger.LedgerMetadata; +import com.jd.blockchain.ledger.LedgerTransaction; +import com.jd.blockchain.ledger.Operation; +import com.jd.blockchain.ledger.ParticipantNode; +import com.jd.blockchain.ledger.TransactionState; +import com.jd.blockchain.ledger.TypedValue; +import com.jd.blockchain.ledger.UserInfo; +import com.jd.blockchain.ledger.UserRegisterOperation; import com.jd.blockchain.ledger.core.OperationHandleContext; import com.jd.blockchain.transaction.BlockchainQueryService; import com.jd.blockchain.transaction.DataAccountKVSetOperationBuilder; @@ -150,22 +167,22 @@ public class ContractLedgerContext implements LedgerContext { } @Override - public AccountHeader getDataAccount(HashDigest ledgerHash, String address) { + public BlockchainIdentity getDataAccount(HashDigest ledgerHash, String address) { return innerQueryService.getDataAccount(ledgerHash, address); } @Override - public KVDataEntry[] getDataEntries(HashDigest ledgerHash, String address, String... keys) { + public TypedKVEntry[] getDataEntries(HashDigest ledgerHash, String address, String... keys) { return innerQueryService.getDataEntries(ledgerHash, address, keys); } @Override - public KVDataEntry[] getDataEntries(HashDigest ledgerHash, String address, KVInfoVO kvInfoVO) { + public TypedKVEntry[] getDataEntries(HashDigest ledgerHash, String address, KVInfoVO kvInfoVO) { return innerQueryService.getDataEntries(ledgerHash, address, kvInfoVO); } @Override - public KVDataEntry[] getDataEntries(HashDigest ledgerHash, String address, int fromIndex, int count) { + public TypedKVEntry[] getDataEntries(HashDigest ledgerHash, String address, int fromIndex, int count) { return innerQueryService.getDataEntries(ledgerHash, address, fromIndex, count); } @@ -182,17 +199,17 @@ public class ContractLedgerContext implements LedgerContext { // ---------------------------user()---------------------------- @Override - public AccountHeader[] getUsers(HashDigest ledgerHash, int fromIndex, int count) { + public BlockchainIdentity[] getUsers(HashDigest ledgerHash, int fromIndex, int count) { return innerQueryService.getUsers(ledgerHash, fromIndex, count); } @Override - public AccountHeader[] getDataAccounts(HashDigest ledgerHash, int fromIndex, int count) { + public BlockchainIdentity[] getDataAccounts(HashDigest ledgerHash, int fromIndex, int count) { return innerQueryService.getDataAccounts(ledgerHash, fromIndex, count); } @Override - public AccountHeader[] getContractAccounts(HashDigest ledgerHash, int fromIndex, int count) { + public BlockchainIdentity[] getContractAccounts(HashDigest ledgerHash, int fromIndex, int count) { return innerQueryService.getContractAccounts(ledgerHash, fromIndex, count); } @@ -268,7 +285,7 @@ public class ContractLedgerContext implements LedgerContext { @Override public DataAccountKVSetOperationBuilder setText(String key, String value, long expVersion) { - BytesValue bytesValue = BytesData.fromText(value); + BytesValue bytesValue = TypedValue.fromText(value); this.op = new SingleKVSetOpTemplate(key, bytesValue, expVersion); handle(op); return this; @@ -276,7 +293,7 @@ public class ContractLedgerContext implements LedgerContext { @Override public DataAccountKVSetOperationBuilder setBytes(String key, Bytes value, long expVersion) { - BytesValue bytesValue = BytesData.fromBytes(value); + BytesValue bytesValue = TypedValue.fromBytes(value); this.op = new SingleKVSetOpTemplate(key, bytesValue, expVersion); handle(op); return this; @@ -284,7 +301,7 @@ public class ContractLedgerContext implements LedgerContext { @Override public DataAccountKVSetOperationBuilder setInt64(String key, long value, long expVersion) { - BytesValue bytesValue = BytesData.fromInt64(value); + BytesValue bytesValue = TypedValue.fromInt64(value); this.op = new SingleKVSetOpTemplate(key, bytesValue, expVersion); handle(op); return this; @@ -301,7 +318,7 @@ public class ContractLedgerContext implements LedgerContext { @Override public DataAccountKVSetOperationBuilder setJSON(String key, String value, long expVersion) { - BytesValue bytesValue = BytesData.fromJSON(value); + BytesValue bytesValue = TypedValue.fromJSON(value); this.op = new SingleKVSetOpTemplate(key, bytesValue, expVersion); handle(op); return this; @@ -309,7 +326,7 @@ public class ContractLedgerContext implements LedgerContext { @Override public DataAccountKVSetOperationBuilder setXML(String key, String value, long expVersion) { - BytesValue bytesValue = BytesData.fromXML(value); + BytesValue bytesValue = TypedValue.fromXML(value); this.op = new SingleKVSetOpTemplate(key, bytesValue, expVersion); handle(op); return this; @@ -317,7 +334,7 @@ public class ContractLedgerContext implements LedgerContext { @Override public DataAccountKVSetOperationBuilder setBytes(String key, byte[] value, long expVersion) { - BytesValue bytesValue = BytesData.fromBytes(value); + BytesValue bytesValue = TypedValue.fromBytes(value); this.op = new SingleKVSetOpTemplate(key, bytesValue, expVersion); handle(op); return this; @@ -325,7 +342,7 @@ public class ContractLedgerContext implements LedgerContext { @Override public DataAccountKVSetOperationBuilder setImage(String key, byte[] value, long expVersion) { - BytesValue bytesValue = BytesData.fromImage(value); + BytesValue bytesValue = TypedValue.fromImage(value); this.op = new SingleKVSetOpTemplate(key, bytesValue, expVersion); handle(op); return this; @@ -333,7 +350,7 @@ public class ContractLedgerContext implements LedgerContext { @Override public DataAccountKVSetOperationBuilder setTimestamp(String key, long value, long expVersion) { - BytesValue bytesValue = BytesData.fromTimestamp(value); + BytesValue bytesValue = TypedValue.fromTimestamp(value); this.op = new SingleKVSetOpTemplate(key, bytesValue, expVersion); handle(op); return this; diff --git a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/handles/DataAccountKVSetOperationHandle.java b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/handles/DataAccountKVSetOperationHandle.java index 0f9fdb2b..dfab3f1c 100644 --- a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/handles/DataAccountKVSetOperationHandle.java +++ b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/handles/DataAccountKVSetOperationHandle.java @@ -5,6 +5,7 @@ import com.jd.blockchain.ledger.DataAccountKVSetOperation; import com.jd.blockchain.ledger.DataAccountKVSetOperation.KVWriteEntry; import com.jd.blockchain.ledger.DataVersionConflictException; import com.jd.blockchain.ledger.LedgerPermission; +import com.jd.blockchain.ledger.TypedValue; import com.jd.blockchain.ledger.core.DataAccount; import com.jd.blockchain.ledger.core.LedgerDataset; import com.jd.blockchain.ledger.core.LedgerQuery; @@ -37,7 +38,7 @@ public class DataAccountKVSetOperationHandle extends AbstractLedgerOperationHand KVWriteEntry[] writeSet = kvWriteOp.getWriteSet(); long v = -1L; for (KVWriteEntry kvw : writeSet) { - v = account.setBytes(Bytes.fromString(kvw.getKey()), kvw.getValue(), kvw.getExpectedVersion()); + v = account.getDataset().setValue(kvw.getKey(), TypedValue.wrap(kvw.getValue()), kvw.getExpectedVersion()); if (v < 0) { throw new DataVersionConflictException(); } 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 new file mode 100644 index 00000000..d8757e0e --- /dev/null +++ b/source/ledger/ledger-core/src/test/java/com/jd/blockchain/ledger/core/MerkleDataNodeEncoderTest.java @@ -0,0 +1,153 @@ +package com.jd.blockchain.ledger.core; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; + +import java.util.Random; + +import org.junit.Test; + +import com.jd.blockchain.crypto.Crypto; +import com.jd.blockchain.crypto.HashDigest; +import com.jd.blockchain.crypto.HashFunction; +import com.jd.blockchain.crypto.service.classic.ClassicAlgorithm; +import com.jd.blockchain.ledger.core.MerkleTree.DataNode; +import com.jd.blockchain.utils.Bytes; + +public class MerkleDataNodeEncoderTest { + + @Test + public void testEnocoderV0() { + + + 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; + 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(key, nodeV0.getKey()); + + byte[] nodeBytes = nodeV0.toBytes(); + + DataNode nodeV0_reversed = encoderV0.resolve(nodeBytes); + assertNull(nodeV0_reversed.getValueHash()); + + assertEquals(nodeV0.getNodeHash(), nodeV0_reversed.getNodeHash()); + assertEquals(encoderV0.getFormatVersion(), nodeBytes[0]); + + assertEquals(sn, nodeV0_reversed.getSN()); + assertEquals(version, nodeV0_reversed.getVersion()); + assertEquals(key, nodeV0_reversed.getKey()); + } + + @Test + public void testEnocoderV1() { + 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; + 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(key, node.getKey()); + + byte[] nodeBytes = node.toBytes(); + + DataNode node_reversed = encoderV1.resolve(nodeBytes); + + assertEquals(dataHash, node_reversed.getValueHash()); + assertEquals(node.getNodeHash(), node_reversed.getNodeHash()); + assertEquals(encoderV1.getFormatVersion(), nodeBytes[0]); + + assertEquals(sn, node_reversed.getSN()); + assertEquals(version, node_reversed.getVersion()); + 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 diff --git a/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/TxTestContractImpl.java b/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/TxTestContractImpl.java index 60ee6864..a0bf65be 100644 --- a/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/TxTestContractImpl.java +++ b/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/TxTestContractImpl.java @@ -3,7 +3,7 @@ package test.com.jd.blockchain.ledger; import com.jd.blockchain.contract.ContractEventContext; import com.jd.blockchain.contract.ContractLifecycleAware; import com.jd.blockchain.contract.EventProcessingAware; -import com.jd.blockchain.ledger.KVDataEntry; +import com.jd.blockchain.ledger.TypedKVEntry; import com.jd.blockchain.utils.Bytes; public class TxTestContractImpl implements TxTestContract, ContractLifecycleAware, EventProcessingAware { @@ -16,7 +16,7 @@ public class TxTestContractImpl implements TxTestContract, ContractLifecycleAwar @Override public boolean testReadable() { - KVDataEntry v1 = eventContext.getLedger().getDataEntries(eventContext.getCurrentLedgerHash(), + TypedKVEntry v1 = eventContext.getLedger().getDataEntries(eventContext.getCurrentLedgerHash(), dataAddress.toBase58(), KEY)[0]; String text1 = (String) v1.getValue(); System.out.printf("k1=%s, version=%s \r\n", text1, v1.getVersion()); @@ -26,7 +26,7 @@ public class TxTestContractImpl implements TxTestContract, ContractLifecycleAwar System.out.printf("new value = %s\r\n", newValue); eventContext.getLedger().dataAccount(dataAddress).setText(KEY, newValue, v1.getVersion()); - KVDataEntry v2 = eventContext.getLedger().getDataEntries(eventContext.getCurrentLedgerHash(), + TypedKVEntry v2 = eventContext.getLedger().getDataEntries(eventContext.getCurrentLedgerHash(), dataAddress.toBase58(), KEY)[0]; System.out.printf("---- read new value ----\r\nk1=%s, version=%s \r\n", v2.getValue(), v2.getVersion()); diff --git a/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/core/AccountSetTest.java b/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/core/AccountSetTest.java index 812a8758..99bd2076 100644 --- a/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/core/AccountSetTest.java +++ b/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/core/AccountSetTest.java @@ -14,11 +14,12 @@ import com.jd.blockchain.crypto.service.classic.ClassicCryptoService; import com.jd.blockchain.crypto.service.sm.SMCryptoService; import com.jd.blockchain.ledger.BlockchainKeyGenerator; import com.jd.blockchain.ledger.BlockchainKeypair; -import com.jd.blockchain.ledger.core.MerkleAccountSet; -import com.jd.blockchain.ledger.core.MerkleAccount; +import com.jd.blockchain.ledger.core.CompositeAccount; import com.jd.blockchain.ledger.core.CryptoConfig; +import com.jd.blockchain.ledger.core.MerkleAccountSet; import com.jd.blockchain.ledger.core.OpeningAccessPolicy; import com.jd.blockchain.storage.service.utils.MemoryKVStorage; +import com.jd.blockchain.utils.Bytes; public class AccountSetTest { @@ -43,12 +44,13 @@ public class AccountSetTest { cryptoConf.setHashAlgorithm(ClassicAlgorithm.SHA256); String keyPrefix = ""; - MerkleAccountSet accset = new MerkleAccountSet(cryptoConf, keyPrefix, storage, storage, accessPolicy); + MerkleAccountSet accset = new MerkleAccountSet(cryptoConf, Bytes.fromString(keyPrefix), storage, storage, accessPolicy); BlockchainKeypair userKey = BlockchainKeyGenerator.getInstance().generate(); accset.register(userKey.getAddress(), userKey.getPubKey()); - - MerkleAccount userAcc = accset.getAccount(userKey.getAddress()); + + //尚未提交之前,可以检索到账户的存在,但版本仍然标记为 -1; + CompositeAccount userAcc = accset.getAccount(userKey.getAddress()); assertNotNull(userAcc); assertTrue(accset.contains(userKey.getAddress())); @@ -56,13 +58,13 @@ public class AccountSetTest { HashDigest rootHash = accset.getRootHash(); assertNotNull(rootHash); - MerkleAccountSet reloadAccSet = new MerkleAccountSet(rootHash, cryptoConf, keyPrefix, storage, storage, true, accessPolicy); - MerkleAccount reloadUserAcc = reloadAccSet.getAccount(userKey.getAddress()); + MerkleAccountSet reloadAccSet = new MerkleAccountSet(rootHash, cryptoConf, Bytes.fromString(keyPrefix), storage, storage, true, accessPolicy); + CompositeAccount reloadUserAcc = reloadAccSet.getAccount(userKey.getAddress()); assertNotNull(reloadUserAcc); assertTrue(reloadAccSet.contains(userKey.getAddress())); - assertEquals(userAcc.getAddress(), reloadUserAcc.getAddress()); - assertEquals(userAcc.getPubKey(), reloadUserAcc.getPubKey()); + assertEquals(userAcc.getID().getAddress(), reloadUserAcc.getID().getAddress()); + assertEquals(userAcc.getID().getPubKey(), reloadUserAcc.getID().getPubKey()); } } diff --git a/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/core/BaseAccountTest.java b/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/core/BaseAccountTest.java index 51c8232b..9d55b19e 100644 --- a/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/core/BaseAccountTest.java +++ b/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/core/BaseAccountTest.java @@ -2,6 +2,7 @@ package test.com.jd.blockchain.ledger.core; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; import org.junit.Test; @@ -12,9 +13,9 @@ import com.jd.blockchain.crypto.service.classic.ClassicCryptoService; import com.jd.blockchain.crypto.service.sm.SMCryptoService; import com.jd.blockchain.ledger.BlockchainKeyGenerator; import com.jd.blockchain.ledger.BlockchainKeypair; -import com.jd.blockchain.ledger.BytesData; -import com.jd.blockchain.ledger.core.MerkleAccount; +import com.jd.blockchain.ledger.TypedValue; import com.jd.blockchain.ledger.core.CryptoConfig; +import com.jd.blockchain.ledger.core.MerkleAccount; import com.jd.blockchain.storage.service.utils.MemoryKVStorage; import com.jd.blockchain.utils.Bytes; @@ -48,38 +49,39 @@ public class BaseAccountTest { BlockchainKeypair bck = BlockchainKeyGenerator.getInstance().generate(); // 新建账户; - MerkleAccount baseAccount = new MerkleAccount(bck.getIdentity(), cryptoConf, keyPrefix, testStorage, testStorage); - assertFalse(baseAccount.isUpdated());// 空的账户; + MerkleAccount baseAccount = new MerkleAccount(bck.getIdentity(), cryptoConf, Bytes.fromString(keyPrefix), + testStorage, testStorage); + assertTrue(baseAccount.isUpdated());//初始化新账户时,先写入PubKey; assertFalse(baseAccount.isReadonly()); // 在空白状态下写入数据; - long v = baseAccount.setBytes(Bytes.fromString("A"), BytesData.fromText("VALUE_A"), 0); + long v = baseAccount.getDataset().setValue("A", TypedValue.fromText("VALUE_A"), 0); // 预期失败; assertEquals(-1, v); - v = baseAccount.setBytes(Bytes.fromString("A"), BytesData.fromText("VALUE_A"), 1); + v = baseAccount.getDataset().setValue("A", TypedValue.fromText("VALUE_A"), 1); // 预期失败; assertEquals(-1, v); - v = baseAccount.setBytes(Bytes.fromString("A"), BytesData.fromText("VALUE_A"), -1); + v = baseAccount.getDataset().setValue("A", TypedValue.fromText("VALUE_A"), -1); // 预期成功; assertEquals(0, v); - v = baseAccount.setBytes(Bytes.fromString("A"), BytesData.fromText("VALUE_A-1"), -1); + v = baseAccount.getDataset().setValue("A", TypedValue.fromText("VALUE_A-1"), -1); // 已经存在版本,指定版本号-1,预期导致失败; assertEquals(-1, v); baseAccount.commit(); v = 0; for (int i = 0; i < 10; i++) { - long s = baseAccount.setBytes(Bytes.fromString("A"), BytesData.fromText("VALUE_A_" + i), v); + long s = baseAccount.getDataset().setValue("A", TypedValue.fromText("VALUE_A_" + i), v); baseAccount.commit(); // 预期成功; assertEquals(v + 1, s); v++; } - v = baseAccount.setBytes(Bytes.fromString("A"), BytesData.fromText("VALUE_A_" + v), v + 1); + v = baseAccount.getDataset().setValue("A", TypedValue.fromText("VALUE_A_" + v), v + 1); // 预期成功; assertEquals(-1, v); diff --git a/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/core/BlockFullRollBackTest.java b/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/core/BlockFullRollBackTest.java new file mode 100644 index 00000000..6c8009f9 --- /dev/null +++ b/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/core/BlockFullRollBackTest.java @@ -0,0 +1,188 @@ +package test.com.jd.blockchain.ledger.core; + +import com.jd.blockchain.binaryproto.DataContractRegistry; +import com.jd.blockchain.crypto.HashDigest; +import com.jd.blockchain.ledger.*; +import com.jd.blockchain.ledger.core.*; +import com.jd.blockchain.storage.service.utils.MemoryKVStorage; +import org.junit.Test; +import org.mockito.Mockito; + +import static org.junit.Assert.*; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyLong; +import static org.mockito.Mockito.doCallRealMethod; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.when; + +public class BlockFullRollBackTest { + + static { + DataContractRegistry.register(TransactionContent.class); + DataContractRegistry.register(TransactionContentBody.class); + DataContractRegistry.register(TransactionRequest.class); + DataContractRegistry.register(NodeRequest.class); + DataContractRegistry.register(EndpointRequest.class); + DataContractRegistry.register(TransactionResponse.class); + DataContractRegistry.register(UserRegisterOperation.class); + DataContractRegistry.register(DataAccountRegisterOperation.class); + } + + private static final String LEDGER_KEY_PREFIX = "LDG://"; + + private HashDigest ledgerHash = null; + + private BlockchainKeypair parti0 = BlockchainKeyGenerator.getInstance().generate(); + private BlockchainKeypair parti1 = BlockchainKeyGenerator.getInstance().generate(); + private BlockchainKeypair parti2 = BlockchainKeyGenerator.getInstance().generate(); + private BlockchainKeypair parti3 = BlockchainKeyGenerator.getInstance().generate(); + + private BlockchainKeypair[] participants = { parti0, parti1, parti2, parti3 }; + + + @Test + public void testBlockFullkRollBack() { + + final MemoryKVStorage STORAGE = new MemoryKVStorage(); + + final MemoryKVStorage STORAGE_Mock = Mockito.spy(STORAGE); + + // 初始化账本到指定的存储库; + ledgerHash = initLedger(STORAGE_Mock, parti0, parti1, parti2, parti3); + + System.out.println("---------- Ledger init OK !!! ----------"); + + // 加载账本; + LedgerManager ledgerManager = new LedgerManager(); + + LedgerRepository ledgerRepo = ledgerManager.register(ledgerHash, STORAGE_Mock); + + // 构造存储错误,并产生区块回滚 + doThrow(BlockRollbackException.class).when(STORAGE_Mock).set(any(), any(), anyLong()); + + LedgerEditor newBlockEditor = ledgerRepo.createNextBlock(); + + OperationHandleRegisteration opReg = new DefaultOperationHandleRegisteration(); + LedgerSecurityManager securityManager = getSecurityManager(); + TransactionBatchProcessor txbatchProcessor = new TransactionBatchProcessor(securityManager, newBlockEditor, + ledgerRepo, opReg); + + // 注册新用户; + BlockchainKeypair userKeypair = BlockchainKeyGenerator.getInstance().generate(); + TransactionRequest transactionRequest = LedgerTestUtils.createTxRequest_UserReg(userKeypair, ledgerHash, + parti0, parti0); + TransactionResponse txResp = txbatchProcessor.schedule(transactionRequest); + + LedgerBlock newBlock = newBlockEditor.prepare(); + try { + newBlockEditor.commit(); + } catch (BlockRollbackException e) { + newBlockEditor.cancel(); + } + + // 验证正确性; + ledgerManager = new LedgerManager(); + ledgerRepo = ledgerManager.register(ledgerHash, STORAGE_Mock); + LedgerBlock latestBlock = ledgerRepo.getLatestBlock(); + assertEquals(ledgerRepo.getBlockHash(0), latestBlock.getHash()); + assertEquals(0, latestBlock.getHeight()); + + LedgerDataQuery ledgerDS = ledgerRepo.getLedgerData(latestBlock); + boolean existUser = ledgerDS.getUserAccountSet().contains(userKeypair.getAddress()); + + assertFalse(existUser); + + doCallRealMethod().when(STORAGE_Mock).set(any(), any(), anyLong()); + + //区块正常提交 + // 生成新区块; + LedgerEditor newBlockEditor1 = ledgerRepo.createNextBlock(); + + OperationHandleRegisteration opReg1 = new DefaultOperationHandleRegisteration(); + LedgerSecurityManager securityManager1 = getSecurityManager(); + TransactionBatchProcessor txbatchProcessor1 = new TransactionBatchProcessor(securityManager1, newBlockEditor1, + ledgerRepo, opReg1); + + // 注册新用户; + BlockchainKeypair userKeypair1 = BlockchainKeyGenerator.getInstance().generate(); + TransactionRequest transactionRequest1 = LedgerTestUtils.createTxRequest_UserReg(userKeypair1, ledgerHash, + parti0, parti0); + TransactionResponse txResp1 = txbatchProcessor1.schedule(transactionRequest1); + + LedgerBlock newBlock1 = newBlockEditor1.prepare(); + + try { + newBlockEditor1.commit(); + } catch (BlockRollbackException e) { + newBlockEditor1.cancel(); + } + + ledgerManager = new LedgerManager(); + ledgerRepo = ledgerManager.register(ledgerHash, STORAGE_Mock); + LedgerBlock latestBlock1 = ledgerRepo.getLatestBlock(); + assertEquals(newBlock1.getHash(), latestBlock1.getHash()); + assertEquals(1, latestBlock1.getHeight()); + + LedgerDataQuery ledgerDS1 = ledgerRepo.getLedgerData(latestBlock1); + boolean existUser1 = ledgerDS1.getUserAccountSet().contains(userKeypair1.getAddress()); + + assertTrue(existUser1); + + } + + private static LedgerSecurityManager getSecurityManager() { + LedgerSecurityManager securityManager = Mockito.mock(LedgerSecurityManager.class); + + SecurityPolicy securityPolicy = Mockito.mock(SecurityPolicy.class); + when(securityPolicy.isEndpointEnable(any(LedgerPermission.class), any())).thenReturn(true); + when(securityPolicy.isEndpointEnable(any(TransactionPermission.class), any())).thenReturn(true); + when(securityPolicy.isNodeEnable(any(LedgerPermission.class), any())).thenReturn(true); + when(securityPolicy.isNodeEnable(any(TransactionPermission.class), any())).thenReturn(true); + + when(securityManager.createSecurityPolicy(any(), any())).thenReturn(securityPolicy); + + return securityManager; + } + + private HashDigest initLedger(MemoryKVStorage storage, BlockchainKeypair... partiKeys) { + // 创建初始化配置; + LedgerInitSetting initSetting = LedgerTestUtils.createLedgerInitSetting(partiKeys); + + // 创建账本; + LedgerEditor ldgEdt = LedgerTransactionalEditor.createEditor(initSetting, LEDGER_KEY_PREFIX, storage, storage); + + TransactionRequest genesisTxReq = LedgerTestUtils.createLedgerInitTxRequest(partiKeys); + LedgerTransactionContext genisisTxCtx = ldgEdt.newTransaction(genesisTxReq); + LedgerDataset ldgDS = genisisTxCtx.getDataset(); + + for (int i = 0; i < partiKeys.length; i++) { + UserAccount userAccount = ldgDS.getUserAccountSet().register(partiKeys[i].getAddress(), + partiKeys[i].getPubKey()); + userAccount.setProperty("Name", "参与方-" + i, -1); + userAccount.setProperty("Share", "" + (10 + i), -1); + } + + LedgerTransaction tx = genisisTxCtx.commit(TransactionState.SUCCESS); + + assertEquals(genesisTxReq.getTransactionContent().getHash(), tx.getTransactionContent().getHash()); + assertEquals(0, tx.getBlockHeight()); + + LedgerBlock block = ldgEdt.prepare(); + + assertEquals(0, block.getHeight()); + assertNotNull(block.getHash()); + assertNull(block.getPreviousHash()); + + // 创世区块的账本哈希为 null; + assertNull(block.getLedgerHash()); + assertNotNull(block.getHash()); + + // 提交数据,写入存储; + ldgEdt.commit(); + + HashDigest ledgerHash = block.getHash(); + return ledgerHash; + } +} diff --git a/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/core/ContractInvokingTest.java b/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/core/ContractInvokingTest.java index 3232c385..de1d224f 100644 --- a/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/core/ContractInvokingTest.java +++ b/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/core/ContractInvokingTest.java @@ -16,14 +16,35 @@ import static org.mockito.Mockito.when; import java.io.InputStream; import java.util.Random; -import com.jd.blockchain.utils.io.BytesUtils; -import com.jd.blockchain.ledger.*; import org.junit.Test; import org.mockito.Mockito; import com.jd.blockchain.binaryproto.BinaryProtocol; import com.jd.blockchain.binaryproto.DataContractRegistry; import com.jd.blockchain.crypto.HashDigest; +import com.jd.blockchain.ledger.BlockchainKeyGenerator; +import com.jd.blockchain.ledger.BlockchainKeypair; +import com.jd.blockchain.ledger.BytesValue; +import com.jd.blockchain.ledger.DataAccountRegisterOperation; +import com.jd.blockchain.ledger.EndpointRequest; +import com.jd.blockchain.ledger.LedgerBlock; +import com.jd.blockchain.ledger.LedgerInitSetting; +import com.jd.blockchain.ledger.LedgerPermission; +import com.jd.blockchain.ledger.LedgerTransaction; +import com.jd.blockchain.ledger.NodeRequest; +import com.jd.blockchain.ledger.OperationResult; +import com.jd.blockchain.ledger.ParticipantNode; +import com.jd.blockchain.ledger.ParticipantRegisterOperation; +import com.jd.blockchain.ledger.ParticipantStateUpdateOperation; +import com.jd.blockchain.ledger.TransactionContent; +import com.jd.blockchain.ledger.TransactionContentBody; +import com.jd.blockchain.ledger.TransactionPermission; +import com.jd.blockchain.ledger.TransactionRequest; +import com.jd.blockchain.ledger.TransactionRequestBuilder; +import com.jd.blockchain.ledger.TransactionResponse; +import com.jd.blockchain.ledger.TransactionState; +import com.jd.blockchain.ledger.TypedValue; +import com.jd.blockchain.ledger.UserRegisterOperation; import com.jd.blockchain.ledger.core.DefaultOperationHandleRegisteration; import com.jd.blockchain.ledger.core.LedgerDataQuery; import com.jd.blockchain.ledger.core.LedgerDataset; @@ -43,6 +64,8 @@ import com.jd.blockchain.storage.service.utils.MemoryKVStorage; import com.jd.blockchain.transaction.BooleanValueHolder; import com.jd.blockchain.transaction.TxBuilder; import com.jd.blockchain.utils.Bytes; +import com.jd.blockchain.utils.DataEntry; +import com.jd.blockchain.utils.io.BytesUtils; import test.com.jd.blockchain.ledger.TxTestContract; import test.com.jd.blockchain.ledger.TxTestContractImpl; @@ -132,7 +155,7 @@ public class ContractInvokingTest { assertEquals(1, opResults.length); assertEquals(0, opResults[0].getIndex()); - byte[] expectedRetnBytes = BinaryProtocol.encode(BytesData.fromInt64(issueAmount), BytesValue.class); + byte[] expectedRetnBytes = BinaryProtocol.encode(TypedValue.fromInt64(issueAmount), BytesValue.class); byte[] reallyRetnBytes = BinaryProtocol.encode(opResults[0].getResult(), BytesValue.class); assertArrayEquals(expectedRetnBytes, reallyRetnBytes); @@ -218,9 +241,9 @@ public class ContractInvokingTest { TransactionBatchResultHandle txResultHandle = txbatchProcessor.prepare(); txResultHandle.commit(); - BytesValue latestValue = ledgerRepo.getDataAccountSet().getAccount(kpDataAccount.getAddress()).getBytes(key, + BytesValue latestValue = ledgerRepo.getDataAccountSet().getAccount(kpDataAccount.getAddress()).getDataset().getValue(key, -1); - System.out.printf("latest value=[%s] %s \r\n", latestValue.getType(), latestValue.getValue().toUTF8String()); + System.out.printf("latest value=[%s] %s \r\n", latestValue.getType(), latestValue.getBytes().toUTF8String()); boolean readable = readableHolder.get(); assertTrue(readable); @@ -278,14 +301,14 @@ public class ContractInvokingTest { } }); // 预期数据都能够正常写入; - KVDataEntry kv1 = ledgerRepo.getDataAccountSet().getAccount(kpDataAccount.getAddress()).getDataEntry("K1", + DataEntry kv1 = ledgerRepo.getDataAccountSet().getAccount(kpDataAccount.getAddress()).getDataset().getDataEntry("K1", 0); - KVDataEntry kv2 = ledgerRepo.getDataAccountSet().getAccount(kpDataAccount.getAddress()).getDataEntry("K2", + DataEntry kv2 = ledgerRepo.getDataAccountSet().getAccount(kpDataAccount.getAddress()).getDataset().getDataEntry("K2", 0); assertEquals(0, kv1.getVersion()); assertEquals(0, kv2.getVersion()); - assertEquals("V1-0", kv1.getValue()); - assertEquals("V2-0", kv2.getValue()); + assertEquals("V1-0", kv1.getValue().stringValue()); + assertEquals("V2-0", kv2.getValue().stringValue()); // 构建基于接口调用合约的交易请求,用于测试合约调用; buildBlock(ledgerRepo, ledgerManager, opReg, new TxDefinitor() { @@ -299,12 +322,12 @@ public class ContractInvokingTest { } }); // 预期数据都能够正常写入; - kv1 = ledgerRepo.getDataAccountSet().getAccount(kpDataAccount.getAddress()).getDataEntry("K1", 1); - kv2 = ledgerRepo.getDataAccountSet().getAccount(kpDataAccount.getAddress()).getDataEntry("K2", 1); + kv1 = ledgerRepo.getDataAccountSet().getAccount(kpDataAccount.getAddress()).getDataset().getDataEntry("K1", 1); + kv2 = ledgerRepo.getDataAccountSet().getAccount(kpDataAccount.getAddress()).getDataset().getDataEntry("K2", 1); assertEquals(1, kv1.getVersion()); assertEquals(1, kv2.getVersion()); - assertEquals("V1-1", kv1.getValue()); - assertEquals("V2-1", kv2.getValue()); + assertEquals("V1-1", kv1.getValue().stringValue()); + assertEquals("V2-1", kv2.getValue().stringValue()); // 构建基于接口调用合约的交易请求,用于测试合约调用; buildBlock(ledgerRepo, ledgerManager, opReg, new TxDefinitor() { @@ -314,16 +337,17 @@ public class ContractInvokingTest { contractProxy.testRollbackWhileVersionConfliction(kpDataAccount.getAddress().toBase58(), "K1", "V1-2", 1); contractProxy.testRollbackWhileVersionConfliction(kpDataAccount.getAddress().toBase58(), "K2", "V2-2", - 0); + 0);//预期会回滚; } }); - // 预期数据都能够正常写入; - kv1 = ledgerRepo.getDataAccountSet().getAccount(kpDataAccount.getAddress()).getDataEntry("K1", 1); + // 预期数据回滚,账本没有发生变更; + kv1 = ledgerRepo.getDataAccountSet().getAccount(kpDataAccount.getAddress()).getDataset().getDataEntry("K1", 1); assertEquals(1, kv1.getVersion()); - assertEquals("V1-1", kv1.getValue()); - kv1 = ledgerRepo.getDataAccountSet().getAccount(kpDataAccount.getAddress()).getDataEntry("K1", 2); - assertEquals(-1, kv1.getVersion()); - assertEquals(null, kv1.getValue()); + assertEquals("V1-1", kv1.getValue().stringValue()); + kv1 = ledgerRepo.getDataAccountSet().getAccount(kpDataAccount.getAddress()).getDataset().getDataEntry("K1", 2); + assertNull(kv1); + kv2 = ledgerRepo.getDataAccountSet().getAccount(kpDataAccount.getAddress()).getDataset().getDataEntry("K2", 1); + assertEquals(1, kv2.getVersion()); } diff --git a/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/core/LedgerAccountTest.java b/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/core/LedgerAccountTest.java index a50cd41e..53e9eb4d 100644 --- a/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/core/LedgerAccountTest.java +++ b/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/core/LedgerAccountTest.java @@ -1,22 +1,12 @@ package test.com.jd.blockchain.ledger.core; -import static org.junit.Assert.assertEquals; - import java.util.Random; import org.junit.Before; -import org.junit.Test; -import com.jd.blockchain.binaryproto.BinaryProtocol; import com.jd.blockchain.binaryproto.DataContractRegistry; -import com.jd.blockchain.crypto.HashDigest; -import com.jd.blockchain.crypto.PubKey; -import com.jd.blockchain.crypto.service.classic.ClassicAlgorithm; -import com.jd.blockchain.crypto.service.sm.SMAlgorithm; -import com.jd.blockchain.ledger.AccountHeader; +import com.jd.blockchain.ledger.BlockchainIdentity; import com.jd.blockchain.ledger.UserInfo; -import com.jd.blockchain.ledger.core.MerkleAccountSet; -import com.jd.blockchain.utils.Bytes; /** * Created by zhangshuang3 on 2018/9/3. @@ -35,27 +25,27 @@ public class LedgerAccountTest { rand.nextBytes(seed); rand.nextBytes(settingValue); rand.nextBytes(rawDigestBytes); - DataContractRegistry.register(AccountHeader.class); + DataContractRegistry.register(BlockchainIdentity.class); DataContractRegistry.register(UserInfo.class); } - @Test - public void testSerialize_AccountHeader() { - String address = "xxxxxxxxxxxx"; - PubKey pubKey = new PubKey(SMAlgorithm.SM2, rawDigestBytes); - HashDigest hashDigest = new HashDigest(ClassicAlgorithm.SHA256, rawDigestBytes); - MerkleAccountSet.AccountHeaderData accountHeaderData = new MerkleAccountSet.AccountHeaderData(Bytes.fromString(address), - pubKey, hashDigest); - - // encode and decode - byte[] encodeBytes = BinaryProtocol.encode(accountHeaderData, AccountHeader.class); - AccountHeader deAccountHeaderData = BinaryProtocol.decode(encodeBytes); - - // verify start - assertEquals(accountHeaderData.getAddress(), deAccountHeaderData.getAddress()); - assertEquals(accountHeaderData.getPubKey(), deAccountHeaderData.getPubKey()); - assertEquals(accountHeaderData.getRootHash(), deAccountHeaderData.getRootHash()); - - } +// @Test +// public void testSerialize_AccountHeader() { +// String address = "xxxxxxxxxxxx"; +// PubKey pubKey = new PubKey(SMAlgorithm.SM2, rawDigestBytes); +// HashDigest hashDigest = new HashDigest(ClassicAlgorithm.SHA256, rawDigestBytes); +// MerkleAccountSet.AccountHeaderData accountHeaderData = new MerkleAccountSet.AccountHeaderData(Bytes.fromString(address), +// pubKey, hashDigest); +// +// // encode and decode +// byte[] encodeBytes = BinaryProtocol.encode(accountHeaderData, AccountHeader.class); +// AccountHeader deAccountHeaderData = BinaryProtocol.decode(encodeBytes); +// +// // verify start +// assertEquals(accountHeaderData.getAddress(), deAccountHeaderData.getAddress()); +// assertEquals(accountHeaderData.getPubKey(), deAccountHeaderData.getPubKey()); +// assertEquals(accountHeaderData.getRootHash(), deAccountHeaderData.getRootHash()); + +// } } diff --git a/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/core/LedgerEditorTest.java b/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/core/LedgerEditorTest.java index 97979205..78f04762 100644 --- a/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/core/LedgerEditorTest.java +++ b/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/core/LedgerEditorTest.java @@ -8,12 +8,9 @@ import org.junit.Before; import org.junit.Test; import com.jd.blockchain.binaryproto.DataContractRegistry; -import com.jd.blockchain.crypto.AddressEncoding; import com.jd.blockchain.crypto.AsymmetricKeypair; import com.jd.blockchain.crypto.Crypto; -import com.jd.blockchain.crypto.CryptoProvider; import com.jd.blockchain.crypto.SignatureFunction; -import com.jd.blockchain.crypto.service.classic.ClassicAlgorithm; import com.jd.blockchain.crypto.service.classic.ClassicCryptoService; import com.jd.blockchain.crypto.service.sm.SMCryptoService; import com.jd.blockchain.ledger.BlockchainKeyGenerator; @@ -25,7 +22,7 @@ import com.jd.blockchain.ledger.LedgerInitSetting; import com.jd.blockchain.ledger.LedgerTransaction; import com.jd.blockchain.ledger.TransactionRequest; import com.jd.blockchain.ledger.TransactionState; -import com.jd.blockchain.ledger.core.CryptoConfig; +import com.jd.blockchain.ledger.TypedValue; import com.jd.blockchain.ledger.core.DataAccount; import com.jd.blockchain.ledger.core.LedgerDataset; import com.jd.blockchain.ledger.core.LedgerEditor; @@ -33,11 +30,6 @@ import com.jd.blockchain.ledger.core.LedgerTransactionContext; import com.jd.blockchain.ledger.core.LedgerTransactionalEditor; import com.jd.blockchain.ledger.core.UserAccount; import com.jd.blockchain.storage.service.utils.MemoryKVStorage; -import com.jd.blockchain.transaction.ConsensusParticipantData; -import com.jd.blockchain.transaction.LedgerInitData; -import com.jd.blockchain.utils.Bytes; -import com.jd.blockchain.utils.io.BytesUtils; -import com.jd.blockchain.utils.net.NetworkAddress; public class LedgerEditorTest { @@ -102,7 +94,7 @@ public class LedgerEditorTest { DataAccount dataAccount = ldgDS.getDataAccountSet().register(dataKP.getAddress(), dataKP.getPubKey(), null); - dataAccount.setBytes(Bytes.fromString("A"), "abc", -1); + dataAccount.getDataset().setValue("A", TypedValue.fromText("abc"), -1); LedgerTransaction tx = genisisTxCtx.commit(TransactionState.SUCCESS); LedgerBlock block = ldgEdt.prepare(); @@ -115,9 +107,9 @@ public class LedgerEditorTest { assertEquals(0, block.getHeight()); // 验证数据读写的一致性; - BytesValue bytes = dataAccount.getBytes("A"); + BytesValue bytes = dataAccount.getDataset().getValue("A"); assertEquals(DataType.TEXT, bytes.getType()); - String textValue = bytes.getValue().toUTF8String(); + String textValue = bytes.getBytes().toUTF8String(); assertEquals("abc", textValue); } diff --git a/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/core/LedgerTestUtils.java b/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/core/LedgerTestUtils.java index d3595755..a9c8a683 100644 --- a/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/core/LedgerTestUtils.java +++ b/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/core/LedgerTestUtils.java @@ -44,12 +44,18 @@ public class LedgerTestUtils { partiKeys[1] = BlockchainKeyGenerator.getInstance().generate(); return createLedgerInitSetting(partiKeys); } - - public static LedgerInitSetting createLedgerInitSetting(BlockchainKeypair[] partiKeys) { + + public static CryptoProvider[] getContextProviders() { CryptoProvider[] supportedProviders = new CryptoProvider[SUPPORTED_PROVIDERS.length]; for (int i = 0; i < SUPPORTED_PROVIDERS.length; i++) { supportedProviders[i] = Crypto.getProvider(SUPPORTED_PROVIDERS[i]); } + + return supportedProviders; + } + + public static LedgerInitSetting createLedgerInitSetting(BlockchainKeypair[] partiKeys) { + CryptoProvider[] supportedProviders =getContextProviders(); CryptoConfig defCryptoSetting = new CryptoConfig(); defCryptoSetting.setSupportedProviders(supportedProviders); diff --git a/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/core/MerkleAccountSetTest.java b/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/core/MerkleAccountSetTest.java new file mode 100644 index 00000000..f3bb67da --- /dev/null +++ b/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/core/MerkleAccountSetTest.java @@ -0,0 +1,58 @@ +package test.com.jd.blockchain.ledger.core; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +import org.junit.Test; + +import com.jd.blockchain.crypto.Crypto; +import com.jd.blockchain.ledger.BlockchainKeyGenerator; +import com.jd.blockchain.ledger.BlockchainKeypair; +import com.jd.blockchain.ledger.TypedValue; +import com.jd.blockchain.ledger.core.CompositeAccount; +import com.jd.blockchain.ledger.core.CryptoConfig; +import com.jd.blockchain.ledger.core.MerkleAccountSet; +import com.jd.blockchain.ledger.core.OpeningAccessPolicy; +import com.jd.blockchain.storage.service.utils.MemoryKVStorage; +import com.jd.blockchain.utils.Bytes; + +public class MerkleAccountSetTest { + + @Test + public void testRegister() { + final OpeningAccessPolicy POLICY = new OpeningAccessPolicy(); + + final MemoryKVStorage STORAGE = new MemoryKVStorage(); + + Bytes KEY_PREFIX = Bytes.fromString("/ACCOUNT"); + + CryptoConfig cryptoConfig = new CryptoConfig(); + cryptoConfig.setSupportedProviders(LedgerTestUtils.getContextProviders()); + cryptoConfig.setAutoVerifyHash(true); + cryptoConfig.setHashAlgorithm(Crypto.getAlgorithm("SHA256")); + + MerkleAccountSet accountset = new MerkleAccountSet(cryptoConfig, KEY_PREFIX, STORAGE, STORAGE, POLICY); + + BlockchainKeypair key1 = BlockchainKeyGenerator.getInstance().generate(); + accountset.register(key1.getIdentity()); + + accountset.commit(); + + CompositeAccount acc1 = accountset.getAccount(key1.getAddress()); + assertNotNull(acc1); + assertEquals(0, accountset.getVersion(key1.getAddress())); + + acc1.getDataset().setValue("K1", TypedValue.fromText("V0"), -1); + + TypedValue v1 = acc1.getDataset().getValue("K1"); + assertNotNull(v1); + assertEquals(0, acc1.getDataset().getVersion("K1")); + + accountset.commit(); + + v1 = acc1.getDataset().getValue("K1"); + assertNotNull(v1); + assertEquals(0, acc1.getDataset().getVersion("K1")); + } + +} diff --git a/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/core/MerkleDataSetTest.java b/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/core/MerkleDataSetTest.java index a90806d6..a8ab595b 100644 --- a/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/core/MerkleDataSetTest.java +++ b/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/core/MerkleDataSetTest.java @@ -23,9 +23,11 @@ import com.jd.blockchain.crypto.service.sm.SMCryptoService; import com.jd.blockchain.ledger.MerkleProof; import com.jd.blockchain.ledger.core.CryptoConfig; import com.jd.blockchain.ledger.core.MerkleDataSet; -import com.jd.blockchain.storage.service.VersioningKVEntry; import com.jd.blockchain.storage.service.utils.MemoryKVStorage; import com.jd.blockchain.utils.Bytes; +import com.jd.blockchain.utils.DataEntry; +import com.jd.blockchain.utils.Dataset; +import com.jd.blockchain.utils.DatasetHelper; import com.jd.blockchain.utils.io.BytesUtils; public class MerkleDataSetTest { @@ -53,9 +55,9 @@ public class MerkleDataSetTest { MemoryKVStorage storage = new MemoryKVStorage(); MerkleDataSet mds = new MerkleDataSet(cryptoConfig, keyPrefix, storage, storage); - mds.setValue("A", "A".getBytes(), -1); - mds.setValue("B", "B".getBytes(), -1); - mds.setValue("C", "C".getBytes(), -1); + mds.setValue(Bytes.fromString("A"), "A".getBytes(), -1); + mds.setValue(Bytes.fromString("B"), "B".getBytes(), -1); + mds.setValue(Bytes.fromString("C"), "C".getBytes(), -1); mds.commit(); @@ -85,22 +87,23 @@ public class MerkleDataSetTest { MemoryKVStorage storage = new MemoryKVStorage(); MerkleDataSet mds = new MerkleDataSet(cryptoConfig, keyPrefix, storage, storage); - mds.setValue("A", "A".getBytes(), -1); - mds.setValue("B", "B".getBytes(), -1); - mds.setValue("C", "C".getBytes(), -1); + Dataset ds = DatasetHelper.map(mds); + ds.setValue("A", "A".getBytes(), -1); + ds.setValue("B", "B".getBytes(), -1); + ds.setValue("C", "C".getBytes(), -1); mds.commit(); - byte[] va = mds.getValue("A"); + byte[] va = ds.getValue("A"); assertNotNull(va); assertEquals("A", new String(va)); - byte[] vc = mds.getValue("C"); - VersioningKVEntry ventry = mds.getDataEntry("C"); + byte[] vc = ds.getValue("C"); + DataEntry ventry = ds.getDataEntry("C"); assertNotNull(vc); assertNotNull(ventry); assertEquals("C", new String(vc)); - assertEquals("C", ventry.getKey().toUTF8String()); + assertEquals("C", ventry.getKey()); HashDigest root1 = mds.getRootHash(); @@ -111,8 +114,8 @@ public class MerkleDataSetTest { int expStorageCount = 10; assertEquals(expStorageCount, storage.getStorageCount()); - mds.setValue("B", "B".getBytes(), 0); - mds.setValue("C", "C".getBytes(), 0); + ds.setValue("B", "B".getBytes(), 0); + ds.setValue("C", "C".getBytes(), 0); mds.commit(); HashDigest root2 = mds.getRootHash(); assertNotEquals(root1, root2); @@ -122,7 +125,7 @@ public class MerkleDataSetTest { expStorageCount = expStorageCount + 3; assertEquals(expStorageCount, storage.getStorageCount()); - mds.setValue("D", "DValue".getBytes(), -1); + ds.setValue("D", "DValue".getBytes(), -1); mds.commit(); HashDigest root3 = mds.getRootHash(); assertNotEquals(root2, root3); @@ -135,31 +138,31 @@ public class MerkleDataSetTest { assertEquals(expStorageCount, storage.getStorageCount()); // Check rollback function: Add some keys, and then rollback; - long v = mds.setValue("E", "E-values".getBytes(), -1); + long v = ds.setValue("E", "E-values".getBytes(), -1); assertEquals(v, 0); - String expEValue = new String(mds.getValue("E")); + String expEValue = new String(ds.getValue("E")); assertEquals(expEValue, "E-values"); - v = mds.setValue("F", "F-values".getBytes(), -1); + v = ds.setValue("F", "F-values".getBytes(), -1); assertEquals(v, 0); - String expFValue = new String(mds.getValue("F")); + String expFValue = new String(ds.getValue("F")); assertEquals(expFValue, "F-values"); - v = mds.setValue("E", "E-values-1".getBytes(), 0); + v = ds.setValue("E", "E-values-1".getBytes(), 0); assertEquals(v, 1); - expEValue = new String(mds.getValue("E")); + expEValue = new String(ds.getValue("E")); assertEquals(expEValue, "E-values-1"); mds.cancel(); - byte[] bv = mds.getValue("E"); + byte[] bv = ds.getValue("E"); assertNull(bv); - bv = mds.getValue("F"); + bv = ds.getValue("F"); assertNull(bv); - v = mds.getVersion("E"); + v = ds.getVersion("E"); assertEquals(-1, v); - v = mds.getVersion("F"); + v = ds.getVersion("F"); assertEquals(-1, v); // Expect that states has been recover; @@ -194,10 +197,11 @@ public class MerkleDataSetTest { MemoryKVStorage storage = new MemoryKVStorage(); MerkleDataSet mds = new MerkleDataSet(cryptoConfig, keyPrefix, storage, storage); + Dataset ds = DatasetHelper.map(mds); // 初始的时候没有任何数据,总是返回 null; - VersioningKVEntry verKVEntry = mds.getDataEntry("NULL_KEY"); - byte[] vbytes = mds.getValue("NULL_KEY"); + DataEntry verKVEntry = ds.getDataEntry("NULL_KEY"); + byte[] vbytes = ds.getValue("NULL_KEY"); assertNull(verKVEntry); assertNull(vbytes); @@ -217,7 +221,7 @@ public class MerkleDataSetTest { for (int i = 0; i < count; i++) { key = "data" + i; rand.nextBytes(data); - v = mds.setValue(key, data, -1); + v = ds.setValue(key, data, -1); dataVersions.put(key, v); dataValues.put(key + "_" + v, data); assertEquals(v, 0); @@ -237,7 +241,7 @@ public class MerkleDataSetTest { KeySnapshot ks = new KeySnapshot(); ks.proof = proof; - ks.maxVersion = mds.getVersion(key); + ks.maxVersion = ds.getVersion(key); snapshot.put(key, ks); } @@ -271,7 +275,7 @@ public class MerkleDataSetTest { key = "data" + i; rand.nextBytes(data); expVer = dataVersions.get(key); - v = mds.setValue(key, data, expVer); + v = ds.setValue(key, data, expVer); assertEquals(v, expVer + 1); @@ -300,7 +304,7 @@ public class MerkleDataSetTest { KeySnapshot ks = new KeySnapshot(); ks.proof = proof; - ks.maxVersion = mds.getVersion(key); + ks.maxVersion = ds.getVersion(key); snapshot.put(key, ks); } history.put(rootHash, snapshot); @@ -316,6 +320,7 @@ public class MerkleDataSetTest { MerkleDataSet mdsReload = new MerkleDataSet(hisRootHash, cryptoConfig, keyPrefix, storage, storage, true); + Dataset dsReload = DatasetHelper.map(mdsReload); assertEquals(hisRootHash, mdsReload.getRootHash()); // verify every keys; @@ -323,7 +328,7 @@ public class MerkleDataSetTest { key = "data" + i; // 最新版本一致; long expLatestVersion = snapshot.get(key).maxVersion; - long actualLatestVersion = mdsReload.getVersion(key); + long actualLatestVersion = dsReload.getVersion(key); assertEquals(expLatestVersion, actualLatestVersion); // 数据证明一致; @@ -339,7 +344,7 @@ public class MerkleDataSetTest { for (long j = 0; j < actualLatestVersion; j++) { String keyver = key + "_" + j; byte[] expValue = dataValues.get(keyver); - byte[] actualValue = mdsReload.getValue(key, j); + byte[] actualValue = dsReload.getValue(key, j); assertTrue(BytesUtils.equals(expValue, actualValue)); } } @@ -365,10 +370,11 @@ public class MerkleDataSetTest { MemoryKVStorage storage = new MemoryKVStorage(); MerkleDataSet mds = new MerkleDataSet(cryptoConfig, keyPrefix, storage, storage); + Dataset ds = DatasetHelper.map(mds); // 初始的时候没有任何数据,总是返回 null; - VersioningKVEntry verKVEntry = mds.getDataEntry("NULL_KEY"); - byte[] vbytes = mds.getValue("NULL_KEY"); + DataEntry verKVEntry = ds.getDataEntry("NULL_KEY"); + byte[] vbytes = ds.getValue("NULL_KEY"); assertNull(verKVEntry); assertNull(vbytes); @@ -388,7 +394,7 @@ public class MerkleDataSetTest { MerkleProof proof; for (int i = 0; i < count; i++) { key = "data" + i; - v = mds.setValue(key, data, -1); + v = ds.setValue(key, data, -1); dataVersions.put(key, v); // dataValues.put(key + "_" + v, data); assertEquals(v, 0); @@ -408,7 +414,7 @@ public class MerkleDataSetTest { KeySnapshot ks = new KeySnapshot(); ks.proof = proof; - ks.maxVersion = mds.getVersion(key); + ks.maxVersion = ds.getVersion(key); snapshot.put(key, ks); } @@ -418,6 +424,7 @@ public class MerkleDataSetTest { // verify; { MerkleDataSet mdsReload = new MerkleDataSet(rootHash, cryptoConfig, keyPrefix, storage, storage, true); + Dataset dsReload = DatasetHelper.map(mdsReload); // verify every keys; Map snapshot = history.get(rootHash); MerkleProof expProof; @@ -429,7 +436,7 @@ public class MerkleDataSetTest { expProof = snapshot.get(key).proof; assertEquals(expProof.toString(), proof.toString()); - byte[] value = mdsReload.getValue(key); + byte[] value = dsReload.getValue(key); assertTrue(BytesUtils.equals(data, value)); } } diff --git a/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/core/MerkleTreeTest.java b/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/core/MerkleTreeTest.java index afe8e435..ee3a7509 100644 --- a/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/core/MerkleTreeTest.java +++ b/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/core/MerkleTreeTest.java @@ -556,6 +556,9 @@ public class MerkleTreeTest { /** * 测试从存储重新加载 Merkle 树的正确性; */ + /** + * + */ @Test public void testMerkleReload() { CryptoSetting setting = Mockito.mock(CryptoSetting.class); @@ -563,7 +566,7 @@ public class MerkleTreeTest { when(setting.getAutoVerifyHash()).thenReturn(true); // 保存所有写入的数据节点的 SN-Hash 映射表; - TreeMap dataNodes = new TreeMap<>(); + TreeMap expectedDataNodes = new TreeMap<>(); MerkleNode nd; // 测试从空的树开始,顺序增加数据节点; @@ -580,7 +583,7 @@ public class MerkleTreeTest { for (int i = 0; i < count; i++) { rand.nextBytes(dataBuf); nd = mkt.setData(sn, "KEY-" + sn, 0, dataBuf); - dataNodes.put(sn, nd.getNodeHash()); + expectedDataNodes.put(sn, nd.getNodeHash()); sn++; } mkt.commit(); @@ -610,6 +613,24 @@ public class MerkleTreeTest { // 预期扩展为 4 层16叉树,由 3 层满16叉树扩展 1 新分支(4个路径节点)而形成; long expectedNodes = getMaxPathNodeCount(3) + 4 + 4097; assertEquals(expectedNodes, storage.getCount()); + + //重新加载,判断数据是否正确; + MerkleTree r1_mkt = new MerkleTree(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.getHash(0)); + } + } } // 覆盖到每一路分支修改数据节点; @@ -621,7 +642,7 @@ public class MerkleTreeTest { rand.nextBytes(dataBuf); sn = i; nd = mkt.setData(sn, "KEY-" + sn, 0, dataBuf); - dataNodes.put(sn, nd.getNodeHash()); + expectedDataNodes.put(sn, nd.getNodeHash()); } mkt.commit(); @@ -658,16 +679,18 @@ public class MerkleTreeTest { rand.nextBytes(dataBuf); sn = maxSN + 1 + i; nd = mkt.setData(sn, "KEY-" + sn, 0, dataBuf); - dataNodes.put(sn, nd.getNodeHash()); + expectedDataNodes.put(sn, nd.getNodeHash()); } mkt.commit(); - // 验证每一个数据节点都产生了存在性证明; - MerkleProof proof = null; - for (Long n : dataNodes.keySet()) { - proof = mkt.getProof(n.longValue()); - assertNotNull(proof); - assertEquals(dataNodes.get(n), proof.getHash(0)); + { + // 验证每一个数据节点都产生了存在性证明; + MerkleProof proof = null; + for (Long n : expectedDataNodes.keySet()) { + proof = mkt.getProof(n.longValue()); + assertNotNull(proof); + assertEquals(expectedDataNodes.get(n), proof.getHash(0)); + } } // 记录一次提交的根哈希以及部分节点信息,用于后续的加载校验; @@ -700,6 +723,7 @@ public class MerkleTreeTest { assertEquals(r1_proof1, r1_mkt.getProof(r1_sn1).toString()); assertEquals(r1_proof2, r1_mkt.getProof(r1_sn2).toString()); + // 从第 2 轮提交的 Merkle 根哈希加载; // 第 2 轮生成的 Merkle 树是对第 1 轮的数据的全部节点的修改,因此同一个 SN 的节点的证明是不同的; MerkleTree r2_mkt = new MerkleTree(r2_rootHash, setting, keyPrefix, storage, true); @@ -730,13 +754,16 @@ public class MerkleTreeTest { assertEquals(r3_proof3, r3_mkt.getProof(r3_sn3).toString()); // 验证每一个数据节点都产生了存在性证明; - for (Long n : dataNodes.keySet()) { - proof = r3_mkt.getProof(n.longValue()); - assertNotNull(proof); - assertEquals(dataNodes.get(n), proof.getHash(0)); + { + MerkleProof proof = null; + for (Long n : expectedDataNodes.keySet()) { + proof = r3_mkt.getProof(n.longValue()); + assertNotNull(proof); + assertEquals(expectedDataNodes.get(n), proof.getHash(0)); + } } } - + @SuppressWarnings("unused") private static int getLevel(long dataCount) { if (dataCount < 0) { @@ -772,8 +799,7 @@ public class MerkleTreeTest { * 注:此方法不处理溢出;调用者需要自行规避; * * @param value - * @param x - * 大于等于 0 的整数; + * @param x 大于等于 0 的整数; * @return */ private static long power(long value, int x) { diff --git a/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/core/TransactionBatchProcessorTest.java b/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/core/TransactionBatchProcessorTest.java index 06bf987d..a0e554e1 100644 --- a/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/core/TransactionBatchProcessorTest.java +++ b/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/core/TransactionBatchProcessorTest.java @@ -332,24 +332,25 @@ public class TransactionBatchProcessorTest { newBlock = newBlockEditor.prepare(); newBlockEditor.commit(); - BytesValue v1_0 = ledgerRepo.getDataAccountSet().getAccount(dataAccountKeypair.getAddress()).getBytes("K1", + BytesValue v1_0 = ledgerRepo.getDataAccountSet().getAccount(dataAccountKeypair.getAddress()).getDataset().getValue("K1", 0); - BytesValue v1_1 = ledgerRepo.getDataAccountSet().getAccount(dataAccountKeypair.getAddress()).getBytes("K1", + BytesValue v1_1 = ledgerRepo.getDataAccountSet().getAccount(dataAccountKeypair.getAddress()).getDataset().getValue("K1", 1); - BytesValue v2 = ledgerRepo.getDataAccountSet().getAccount(dataAccountKeypair.getAddress()).getBytes("K2", + BytesValue v2 = ledgerRepo.getDataAccountSet().getAccount(dataAccountKeypair.getAddress()).getDataset().getValue("K2", 0); - BytesValue v3 = ledgerRepo.getDataAccountSet().getAccount(dataAccountKeypair.getAddress()).getBytes("K3", + BytesValue v3 = ledgerRepo.getDataAccountSet().getAccount(dataAccountKeypair.getAddress()).getDataset().getValue("K3", 0); + assertNotNull(v1_0); assertNotNull(v1_1); assertNotNull(v2); assertNotNull(v3); - assertEquals("V-1-1", v1_0.getValue().toUTF8String()); - assertEquals("V-1-2", v1_1.getValue().toUTF8String()); - assertEquals("V-2-1", v2.getValue().toUTF8String()); - assertEquals("V-3-1", v3.getValue().toUTF8String()); + assertEquals("V-1-1", v1_0.getBytes().toUTF8String()); + assertEquals("V-1-2", v1_1.getBytes().toUTF8String()); + assertEquals("V-2-1", v2.getBytes().toUTF8String()); + assertEquals("V-3-1", v3.getBytes().toUTF8String()); // 提交多笔数据写入的交易,包含存在数据版本冲突的交易,验证交易是否正确回滚; // 先写一笔正确的交易; k3 的版本将变为 1 ; @@ -371,27 +372,27 @@ public class TransactionBatchProcessorTest { } catch (DataVersionConflictException e) { versionConflictionException = e; } - assertNotNull(versionConflictionException); +// assertNotNull(versionConflictionException); newBlock = newBlockEditor.prepare(); newBlockEditor.commit(); - BytesValue v1 = ledgerRepo.getDataAccountSet().getAccount(dataAccountKeypair.getAddress()).getBytes("K1"); - v3 = ledgerRepo.getDataAccountSet().getAccount(dataAccountKeypair.getAddress()).getBytes("K3"); + BytesValue v1 = ledgerRepo.getDataAccountSet().getAccount(dataAccountKeypair.getAddress()).getDataset().getValue("K1"); + v3 = ledgerRepo.getDataAccountSet().getAccount(dataAccountKeypair.getAddress()).getDataset().getValue("K3"); // k1 的版本仍然为1,没有更新; long k1_version = ledgerRepo.getDataAccountSet().getAccount(dataAccountKeypair.getAddress()) - .getDataVersion("K1"); + .getDataset().getVersion("K1"); assertEquals(1, k1_version); long k3_version = ledgerRepo.getDataAccountSet().getAccount(dataAccountKeypair.getAddress()) - .getDataVersion("K3"); + .getDataset().getVersion("K3"); assertEquals(1, k3_version); assertNotNull(v1); assertNotNull(v3); - assertEquals("V-1-2", v1.getValue().toUTF8String()); - assertEquals("V-3-2", v3.getValue().toUTF8String()); + assertEquals("V-1-2", v1.getBytes().toUTF8String()); + assertEquals("V-3-2", v3.getBytes().toUTF8String()); // // 验证正确性; // ledgerManager = new LedgerManager(); diff --git a/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/core/TransactionSetTest.java b/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/core/TransactionSetTest.java index cd5ebc9f..63ee3e64 100644 --- a/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/core/TransactionSetTest.java +++ b/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/core/TransactionSetTest.java @@ -164,8 +164,8 @@ public class TransactionSetTest { for (int i = 0; i < acutualKVWriteSet.length; i++) { assertEquals(expKVWriteSet[i].getKey(), acutualKVWriteSet[i].getKey()); assertEquals(expKVWriteSet[i].getExpectedVersion(), acutualKVWriteSet[i].getExpectedVersion()); - assertTrue(BytesUtils.equals(expKVWriteSet[i].getValue().getValue().toBytes(), - acutualKVWriteSet[i].getValue().getValue().toBytes())); + assertTrue(BytesUtils.equals(expKVWriteSet[i].getValue().getBytes().toBytes(), + acutualKVWriteSet[i].getValue().getBytes().toBytes())); } ContractCodeDeployOperation actualContractDplOp = (ContractCodeDeployOperation) actualOperations[3]; diff --git a/source/ledger/ledger-model/pom.xml b/source/ledger/ledger-model/pom.xml index c23fd17e..90b5a759 100644 --- a/source/ledger/ledger-model/pom.xml +++ b/source/ledger/ledger-model/pom.xml @@ -6,7 +6,7 @@ com.jd.blockchain ledger - 1.1.1-PACK20191209 + 1.1.2.RELEASE ledger-model diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/Account.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/Account.java new file mode 100644 index 00000000..28694160 --- /dev/null +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/Account.java @@ -0,0 +1,11 @@ +package com.jd.blockchain.ledger; + +import com.jd.blockchain.utils.Dataset; + +public interface Account { + + BlockchainIdentity getID(); + + Dataset getDataset(); + +} diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/AccountHeader.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/AccountHeader.java index 16f2794b..fcc530de 100644 --- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/AccountHeader.java +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/AccountHeader.java @@ -1,20 +1,20 @@ -package com.jd.blockchain.ledger; - -import com.jd.blockchain.binaryproto.DataContract; -import com.jd.blockchain.binaryproto.DataField; -import com.jd.blockchain.binaryproto.PrimitiveType; -import com.jd.blockchain.consts.DataCodes; -import com.jd.blockchain.crypto.PubKey; -import com.jd.blockchain.utils.Bytes; - -@DataContract(code= DataCodes.ACCOUNT_HEADER) -public interface AccountHeader extends MerkleSnapshot{ - - @DataField(order=1, primitiveType = PrimitiveType.BYTES) - Bytes getAddress(); - - @DataField(order=2, primitiveType = PrimitiveType.BYTES) - PubKey getPubKey(); - - -} +//package com.jd.blockchain.ledger; +// +//import com.jd.blockchain.binaryproto.DataContract; +//import com.jd.blockchain.binaryproto.DataField; +//import com.jd.blockchain.binaryproto.PrimitiveType; +//import com.jd.blockchain.consts.DataCodes; +//import com.jd.blockchain.crypto.PubKey; +//import com.jd.blockchain.utils.Bytes; +// +//@Deprecated +//@DataContract(code= DataCodes.ACCOUNT_HEADER) +//public interface AccountHeader { //extends MerkleSnapshot{ +// +// @DataField(order = 1, primitiveType = PrimitiveType.BYTES) +// Bytes getAddress(); +// +// @DataField(order = 2, primitiveType=PrimitiveType.BYTES) +// PubKey getPubKey(); +// +//} diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/BytesData.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/BytesData.java deleted file mode 100644 index ca4e9cb0..00000000 --- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/BytesData.java +++ /dev/null @@ -1,118 +0,0 @@ -package com.jd.blockchain.ledger; - -import com.jd.blockchain.utils.Bytes; -import com.jd.blockchain.utils.io.BytesUtils; - -/** - * - * @author huanghaiquan - * - */ -public class BytesData implements BytesValue { - DataType type; - Bytes value; - - private BytesData(DataType type, byte[] bytes) { - this.type = type; - this.value = new Bytes(bytes); - } - - private BytesData(DataType type, Bytes bytes) { - this.type = type; - this.value = bytes; - } - - public static BytesValue fromType(DataType type, byte[] value) { - return new BytesData(type, value); - } - - public static BytesValue fromBytes(byte[] value) { - return new BytesData(DataType.BYTES, value); - } - - public static BytesValue fromBytes(Bytes value) { - return new BytesData(DataType.BYTES, value); - } - - public static BytesValue fromImage(byte[] value) { - return new BytesData(DataType.IMG, value); - } - - public static BytesValue fromImage(Bytes value) { - return new BytesData(DataType.IMG, value); - } - - /** - * 以 UTF-8 编码从字符串转换为字节数组值; - * - * @param value - * @return - */ - public static BytesValue fromText(String value) { - return new BytesData(DataType.TEXT, BytesUtils.toBytes(value)); - } - - /** - * 以 UTF-8 编码把字节数组值转换为字符串; - * - * @param bytesValue - * @return - */ - public static String toText(BytesValue bytesValue) { - if (bytesValue == null) { - return null; - } - if (bytesValue.getType() != DataType.TEXT) { - throw new ValueTypeCastException("The expected value type is " + DataType.TEXT.toString() - + ", but it is actually " + bytesValue.getType().toString() + "!"); - } - return bytesValue.getValue().toUTF8String(); - } - - public static BytesValue fromJSON(String value) { - return new BytesData(DataType.JSON, BytesUtils.toBytes(value)); - } - - public static BytesValue fromXML(String value) { - return new BytesData(DataType.XML, BytesUtils.toBytes(value)); - } - - public static BytesValue fromInt32(int value) { - return new BytesData(DataType.INT32, BytesUtils.toBytes(value)); - } - - public static BytesValue fromInt64(long value) { - return new BytesData(DataType.INT64, BytesUtils.toBytes(value)); - } - - public static BytesValue fromInt16(short value) { - return new BytesData(DataType.INT16, BytesUtils.toBytes(value)); - } - - public static BytesValue fromInt8(byte value) { - return new BytesData(DataType.INT8, BytesUtils.toBytes(value)); - } - - public static BytesValue fromTimestamp(long value) { - return new BytesData(DataType.TIMESTAMP, BytesUtils.toBytes(value)); - } - - public static BytesValue fromBoolean(boolean value) { - return new BytesData(DataType.BOOLEAN, BytesUtils.toBytes(value)); - } - - @Override - public DataType getType() { - return this.type; - } - - public void setType(DataType type) { - this.type = type; - } - - @Override - public Bytes getValue() { - return this.value; - } - -} diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/BytesDataList.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/BytesDataList.java index f7aef959..a7541a41 100644 --- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/BytesDataList.java +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/BytesDataList.java @@ -14,18 +14,18 @@ public class BytesDataList implements BytesValueList { } public static BytesValueList singleText(String value) { - return new BytesDataList(BytesData.fromText(value)); + return new BytesDataList(TypedValue.fromText(value)); } public static BytesValueList singleLong(long value) { - return new BytesDataList(BytesData.fromInt64(value)); + return new BytesDataList(TypedValue.fromInt64(value)); } public static BytesValueList singleInt(int value) { - return new BytesDataList(BytesData.fromInt32(value)); + return new BytesDataList(TypedValue.fromInt32(value)); } public static BytesValueList singleBoolean(boolean value) { - return new BytesDataList(BytesData.fromBoolean(value)); + return new BytesDataList(TypedValue.fromBoolean(value)); } } diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/BytesValue.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/BytesValue.java index 6e7b9b46..47d4ad16 100644 --- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/BytesValue.java +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/BytesValue.java @@ -29,6 +29,6 @@ public interface BytesValue { * @return */ @DataField(order = 1, primitiveType = PrimitiveType.BYTES) - Bytes getValue(); + Bytes getBytes(); } diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/BytesValueEncoding.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/BytesValueEncoding.java index baee5868..6579f1c4 100644 --- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/BytesValueEncoding.java +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/BytesValueEncoding.java @@ -68,7 +68,7 @@ public class BytesValueEncoding { } // 将对象序列化 byte[] serialBytes = BinaryProtocol.encode(value, type); - return BytesData.fromType(DataType.DATA_CONTRACT, serialBytes); + return TypedValue.fromType(DataType.DATA_CONTRACT, serialBytes); } BytesValueResolver bytesValueResolver = CLASS_RESOLVER_MAP.get(type); if (bytesValueResolver == null) { diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/ContractInfo.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/ContractInfo.java index cb1da5c4..047e3c51 100644 --- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/ContractInfo.java +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/ContractInfo.java @@ -5,9 +5,10 @@ import com.jd.blockchain.binaryproto.DataField; import com.jd.blockchain.binaryproto.PrimitiveType; import com.jd.blockchain.consts.DataCodes; -@DataContract(code= DataCodes.CONTRACT) -public interface ContractInfo extends AccountHeader { +@DataContract(code= DataCodes.CONTRACT_ACCOUNT_HEADER) +public interface ContractInfo extends BlockchainIdentity, MerkleSnapshot { @DataField(order=4, primitiveType= PrimitiveType.BYTES) byte[] getChainCode(); + } diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/DataType.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/DataType.java index 1cb8fce3..6395bcc2 100644 --- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/DataType.java +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/DataType.java @@ -106,6 +106,20 @@ public enum DataType { * DataContract 数据; */ DATA_CONTRACT((byte) (BaseType.EXT | 0x01)); + + + + public static final boolean BOOLEAN_DEFAULT_VALUE = false; + + public static final byte INT8_DEFAULT_VALUE = 0; + + public static final short INT16_DEFAULT_VALUE = 0; + + public static final int INT32_DEFAULT_VALUE = 0; + + public static final long INT64_DEFAULT_VALUE = 0; + + @EnumField(type = PrimitiveType.INT8) public final byte CODE; @@ -114,6 +128,51 @@ public enum DataType { this.CODE = code; } + /** + * 是否表示“文本类型”或“文本衍生类型”; + * + * @return + */ + public boolean isText() { + return BaseType.TEXT == (BaseType.TEXT & CODE); + } + + /** + * 是否表示“字节类型”或“字节衍生类型”; + * + * @return + */ + public boolean isBytes() { + return BaseType.BYTES == (BaseType.BYTES & CODE); + } + + /** + * 是否表示“整数类型”或“整数衍生类型”; + * + * @return + */ + public boolean isInteger() { + return BaseType.INTEGER == (BaseType.INTEGER & CODE); + } + + /** + * 是否表示“布尔类型”; + * + * @return + */ + public boolean isBoolean() { + return BaseType.BOOLEAN == (BaseType.BOOLEAN & CODE); + } + + /** + * 是否表示“扩展类型”; + * + * @return + */ + public boolean isExt() { + return BaseType.EXT == (BaseType.EXT & CODE); + } + public static DataType valueOf(byte code) { for (DataType dataType : DataType.values()) { if (dataType.CODE == code) { diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/DataVersionConflictException.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/DataVersionConflictException.java index 8af67d01..9831c0cc 100644 --- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/DataVersionConflictException.java +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/DataVersionConflictException.java @@ -1,6 +1,6 @@ package com.jd.blockchain.ledger; -public class DataVersionConflictException extends BlockRollbackException { +public class DataVersionConflictException extends LedgerException { private static final long serialVersionUID = 3583192000738807503L; diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/HashProof.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/HashProof.java new file mode 100644 index 00000000..4b2dd9c5 --- /dev/null +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/HashProof.java @@ -0,0 +1,44 @@ +package com.jd.blockchain.ledger; + +import com.jd.blockchain.crypto.HashDigest; + +public interface HashProof { + /** + * 最大层级数;
+ * 叶子节点(即数据节点)的层级为 0,数据节点之上的每一级父节点的层级加 1, 最大层级便是根节点的层级; + * + * @return + * + * @see MerkleTree#getLevel() + */ + int getLevels(); + + /** + * 返回证明中指定层级的节点的哈希; + *

+ * + * @param level + * 参数值为 0 返回的是数据节点的哈希;
+ * 参数值为 {@link #getLevels()} 返回的是根节点的哈希; + * @return + */ + HashDigest getHash(int level); + + /** + * 返回根节点的哈希; + * + * @return + */ + default HashDigest getRootHash() { + return getHash(getLevels()); + } + + /** + * 返回数据节点的哈希; + * + * @return + */ + default HashDigest getDataHash() { + return getHash(0); + } +} diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/KVDataObject.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/KVDataObject.java deleted file mode 100644 index 1e8247ee..00000000 --- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/KVDataObject.java +++ /dev/null @@ -1,616 +0,0 @@ -package com.jd.blockchain.ledger; - -import java.math.BigInteger; -import java.util.Date; - -import com.jd.blockchain.binaryproto.PrimitiveType; -import com.jd.blockchain.utils.Bytes; -import com.jd.blockchain.utils.io.ByteArray; -import com.jd.blockchain.utils.io.BytesUtils; - -/** - * KV数据项; - * - *

- * - * {@link KVDataObject} 被设计为只读对象; - * - * @author huanghaiquan - * - */ -public class KVDataObject implements KVDataEntry { - - private String key; - - private long version; - - private BytesValue bytesValue; - - public KVDataObject(String key, long version, BytesValue bytesValue) { - this.key = key; - this.version = version < 0 ? -1 : version; - this.bytesValue = bytesValue; - } - - /* - * (non-Javadoc) - * - * @see com.jd.blockchain.ledger.KVDataEntry#getKey() - */ - @Override - public String getKey() { - return key; - } - - /* - * (non-Javadoc) - * - * @see com.jd.blockchain.ledger.KVDataEntry#getVersion() - */ - @Override - public long getVersion() { - return version; - } - - /* - * (non-Javadoc) - * - * @see com.jd.blockchain.ledger.KVDataEntry#getType() - */ - @Override - public DataType getType() { - return bytesValue == null ? DataType.NIL : bytesValue.getType(); - } - - @Override - public Object getValue() { - if (bytesValue == null) { - return null; - } - - switch (getType()) { - case NIL: - return null; - case TEXT: - return bytesValue.getValue().toUTF8String(); - case BYTES: - return ByteArray.toHex(bytesValue.getValue().toBytes()); - case INT64: - return BytesUtils.toLong(bytesValue.getValue().toBytes()); - case JSON: - return bytesValue.getValue().toUTF8String(); - case XML: - return bytesValue.getValue().toUTF8String(); - - default: - throw new IllegalStateException("Unsupported value type[" + getType() + "] to resolve!"); - } - } - - /** - * 是否为空值; - *

- * - * 仅当数据类型 {@link #getType()} 为 {@link PrimitiveType#NIL} 时返回 true,其它情况返回 false; - *

- * - * @return - */ - public boolean isNil() { - return bytesValue == null || DataType.NIL == bytesValue.getType(); - } - - /** - * 字节数组形式的原始内容; - * - * @return - */ - Bytes bytesArray() { - return bytesValue.getValue(); - } - - /** - * 返回 8 位整数值; - *

- * - * 仅当数据类型 {@link #getType()} 为 {@link PrimitiveType#INT8} 有效; - *

- * - * 无效类型将引发 {@link IllegalStateException} 异常; - * - * @return - */ - public byte tinyValue() { - if (DataType.INT8 == getType()) { - return bytesValue.getValue().toBytes()[0]; - } - throw new IllegalStateException(String.format("Expected type [%s], but [%s]", DataType.INT8, getType())); - } - - /** - * 返回 16 位整数值; - *

- * - * 仅当数据类型 {@link #getType()} 为 {@link PrimitiveType#INT16} 有效; - *

- * - * 无效类型将引发 {@link IllegalStateException} 异常; - * - * @return - */ - public short shortValue() { - if (DataType.INT16 == getType()) { - return BytesUtils.toShort(bytesValue.getValue().toBytes(), 0); - } - throw new IllegalStateException(String.format("Expected type [%s], but [%s]", DataType.INT16, getType())); - } - - /** - * 返回 32 位整数值; - *

- * - * 仅当数据类型 {@link #getType()} 为 {@link PrimitiveType#INT32} 有效; - *

- * - * 无效类型将引发 {@link IllegalStateException} 异常; - * - * @return - */ - public int intValue() { - if (DataType.INT32 == getType()) { - return BytesUtils.toInt(bytesValue.getValue().toBytes(), 0); - } - throw new IllegalStateException(String.format("Expected type [%s], but [%s]", DataType.INT32, getType())); - } - - /** - * 返回 64 位整数值; - *

- * - * 仅当数据类型 {@link #getType()} 为 {@link PrimitiveType#INT64} 有效; - *

- * - * 无效类型将引发 {@link IllegalStateException} 异常; - * - * @return - */ - public long longValue() { - if (DataType.INT64 == getType()) { - return BytesUtils.toLong(bytesValue.getValue().toBytes(), 0); - } - throw new IllegalStateException(String.format("Expected type [%s], but [%s]", DataType.INT64, getType())); - - } - - /** - * 返回大整数值; - *

- * - * 仅当数据类型 {@link #getType()} 为 {@link PrimitiveType#BIG_INT} 有效; - *

- * - * 无效类型将引发 {@link IllegalStateException} 异常; - * - * @return - */ - public BigInteger bigIntValue() { - if (DataType.BIG_INT == getType()) { - return new BigInteger(bytesValue.getValue().toBytes()); - } - throw new IllegalStateException( - String.format("Expected type [%s], but [%s]", DataType.BIG_INT, getType())); - } - - /** - * 返回布尔值; - *

- * - * 仅当数据类型 {@link #getType()} 为 {@link PrimitiveType#BIG_INT} 有效; - *

- * - * 无效类型将引发 {@link IllegalStateException} 异常; - * - * @return - */ - public boolean boolValue() { - if (DataType.BOOLEAN == getType()) { - return BytesUtils.toBoolean(bytesValue.getValue().toBytes()[0]); - } - throw new IllegalStateException( - String.format("Expected type [%s], but [%s]", DataType.BOOLEAN, getType())); - } - - /** - * 返回日期时间值; - *

- * - * 仅当数据类型 {@link #getType()} 为 {@link PrimitiveType#TIMESTAMP} 有效; - *

- * - * 无效类型将引发 {@link IllegalStateException} 异常; - * - * @return - */ - public Date datetimeValue() { - if (DataType.TIMESTAMP == getType()) { - long ts = BytesUtils.toLong(bytesValue.getValue().toBytes()); - return new Date(ts); - } - throw new IllegalStateException( - String.format("Expected type [%s], but [%s]", DataType.TIMESTAMP, getType())); - } - - /** - * 返回大整数值; - *

- * - * 仅当数据类型 {@link #getType()} 为 {@link PrimitiveType#TEXT} / - * {@link PrimitiveType#JSON} / {@link PrimitiveType#XML} 有效; - *

- * - * 无效类型将引发 {@link IllegalStateException} 异常; - * - * @return - */ - public String stringValue() { - DataType type = getType(); - if (DataType.TEXT == type || DataType.JSON == type || DataType.XML == type) { - return bytesValue.getValue().toUTF8String(); - } - throw new IllegalStateException(String.format("Expected type [%s] or [%s] or [%s] , but [%s]", - PrimitiveType.TEXT, DataType.JSON, DataType.XML, type)); - } - -// // ---------------- -// public KVDataEntry nextVersionNil() { -// return nilState(key, version + 1); -// } -// -// public KVDataEntry nextVersionBoolean(boolean value) { -// return booleanState(key, version + 1, value); -// } -// -// public KVDataEntry nextVersionTiny(byte value) { -// return tinyState(key, version + 1, value); -// } -// -// public KVDataEntry nextVersionShort(short value) { -// return shortState(key, version + 1, value); -// } -// -// public KVDataEntry nextVersionInt(int value) { -// return intState(key, version + 1, value); -// } -// -// public KVDataEntry nextVersionLong(long value) { -// return longState(key, version + 1, value); -// } -// -// public KVDataEntry nextVersionDatetime(Date value) { -// return datetimeState(key, version + 1, value); -// } -// -// public KVDataEntry nextVersionJson(String value) { -// return jsonState(key, version + 1, value); -// } -// -// public KVDataEntry nextVersionXml(String value) { -// return xmlState(key, version + 1, value); -// } -// -// public KVDataEntry nextVersionBigInt(BigInteger value) { -// return bigIntState(key, version + 1, value); -// } -// -// public KVDataEntry nextVersionText(boolean encrypted, String value) { -// return textState(key, version + 1, encrypted, value); -// } -// -// public KVDataEntry nextVersionBytes(boolean encrypted, byte[] value) { -// return bytesState(key, version + 1, encrypted, value); -// } -// -// public KVDataEntry nextVersionImage(boolean encrypted, byte[] value) { -// return imageState(key, version + 1, encrypted, value); -// } -// -// public KVDataEntry nextVersionVideo(boolean encrypted, byte[] value) { -// return videoState(key, version + 1, encrypted, value); -// } -// -// public KVDataEntry nextVersionLocation(boolean encrypted, byte[] value) { -// return locationState(key, version + 1, encrypted, value); -// } -// // ---------------- -// -// public KVDataEntry newNil() { -// return nilState(key, version); -// } -// -// public KVDataEntry newBoolean(boolean value) { -// return booleanState(key, version, value); -// } -// -// public KVDataEntry newTiny(byte value) { -// return tinyState(key, version, value); -// } -// -// public KVDataEntry newShort(short value) { -// return shortState(key, version, value); -// } -// -// public KVDataEntry newInt(int value) { -// return intState(key, version, value); -// } -// -// public KVDataObject newLong(long value) { -// return longState(key, version, value); -// } -// -// public KVDataEntry newDatetime(Date value) { -// return datetimeState(key, version, value); -// } -// -// public KVDataEntry newJson(String value) { -// return jsonState(key, version, value); -// } -// -// public KVDataEntry newXml(String value) { -// return xmlState(key, version, value); -// } -// -// public KVDataEntry newBigInt(BigInteger value) { -// return bigIntState(key, version, value); -// } -// -// public KVDataEntry newText(boolean encrypted, String value) { -// return textState(key, version, encrypted, value); -// } -// -// public KVDataEntry newBytes(boolean encrypted, byte[] value) { -// return bytesState(key, version, encrypted, value); -// } -// -// public KVDataEntry newImage(boolean encrypted, byte[] value) { -// return imageState(key, version, encrypted, value); -// } -// -// public KVDataEntry newVideo(boolean encrypted, byte[] value) { -// return videoState(key, version, encrypted, value); -// } -// -// public KVDataEntry newLocation(boolean encrypted, byte[] value) { -// return locationState(key, version, encrypted, value); -// } -// -// // ---------------- -// -// public KVDataEntry newNil(long version) { -// return nilState(key, version); -// } -// -// public KVDataEntry newBoolean(long version, boolean value) { -// return booleanState(key, version, value); -// } -// -// public KVDataEntry newTiny(long version, byte value) { -// return tinyState(key, version, value); -// } -// -// public KVDataEntry newShort(long version, short value) { -// return shortState(key, version, value); -// } -// -// public KVDataEntry newInt(long version, int value) { -// return intState(key, version, value); -// } -// -// public KVDataEntry newLong(long version, long value) { -// return longState(key, version, value); -// } -// -// public KVDataEntry newDatetime(long version, Date value) { -// return datetimeState(key, version, value); -// } -// -// public KVDataEntry newJson(long version, String value) { -// return jsonState(key, version, value); -// } -// -// public KVDataEntry newXml(long version, String value) { -// return xmlState(key, version, value); -// } -// -// public KVDataEntry newBigInt(long version, BigInteger value) { -// return bigIntState(key, version, value); -// } -// -// public KVDataEntry newText(long version, boolean encrypted, String value) { -// return textState(key, version, encrypted, value); -// } -// -// public KVDataEntry newBytes(long version, boolean encrypted, byte[] value) { -// return bytesState(key, version, encrypted, value); -// } -// -// public KVDataEntry newImage(long version, boolean encrypted, byte[] value) { -// return imageState(key, version, encrypted, value); -// } -// -// public KVDataEntry newVideo(long version, boolean encrypted, byte[] value) { -// return videoState(key, version, encrypted, value); -// } -// -// public KVDataEntry newLocation(long version, boolean encrypted, byte[] value) { -// return locationState(key, version, encrypted, value); -// } -// -// // ---------------- -// -// public static KVDataEntry booleanState(String key, boolean value) { -// return booleanState(key, -1, value); -// } -// -// public static KVDataEntry tinyState(String key, byte value) { -// return tinyState(key, -1, value); -// } -// -// public static KVDataEntry shortState(String key, short value) { -// return shortState(key, -1, value); -// } -// -// public static KVDataEntry intState(String key, int value) { -// return intState(key, -1, value); -// } -// -// public static KVDataEntry longState(String key, long value) { -// return longState(key, -1, value); -// } -// -// public static KVDataEntry datetimeState(String key, Date value) { -// return datetimeState(key, -1, value); -// } -// -// public static KVDataEntry jsonState(String key, String value) { -// return jsonState(key, -1, value); -// } -// -// public static KVDataEntry xmlState(String key, String value) { -// return xmlState(key, -1, value); -// } -// -// public static KVDataEntry bigIntState(String key, BigInteger value) { -// return bigIntState(key, -1, value); -// } -// -// public static KVDataObject textState(String key, String value) { -// return textState(key, -1, false, value); -// } -// -// public static KVDataEntry bytesState(String key, byte[] value) { -// return bytesState(key, -1, false, value); -// } -// -// public static KVDataEntry imageState(String key, byte[] value) { -// return imageState(key, -1, false, value); -// } -// -// public static KVDataEntry videoState(String key, byte[] value) { -// return videoState(key, -1, false, value); -// } -// -// public static KVDataEntry locationState(String key, byte[] value) { -// return locationState(key, -1, false, value); -// } -// -// // ---------------- -// -// public static KVDataEntry textState(String key, boolean encrypted, String value) { -// return textState(key, -1, encrypted, value); -// } -// -// public static KVDataEntry bytesState(String key, boolean encrypted, byte[] value) { -// return bytesState(key, -1, encrypted, value); -// } -// -// public static KVDataEntry imageState(String key, boolean encrypted, byte[] value) { -// return imageState(key, -1, encrypted, value); -// } -// -// public static KVDataEntry videoState(String key, boolean encrypted, byte[] value) { -// return videoState(key, -1, encrypted, value); -// } -// -// public static KVDataEntry locationState(String key, boolean encrypted, byte[] value) { -// return locationState(key, -1, encrypted, value); -// } -// -// // ---------------------- -// -// public static KVDataEntry nilState(String key) { -// return new KVDataObject(key, ValueType.NIL, -1, false, BytesUtils.EMPTY_BYTES); -// } -// -// public static KVDataEntry nilState(String key, long version) { -// return new KVDataObject(key, ValueType.NIL, version, false, BytesUtils.EMPTY_BYTES); -// } -// -// public static KVDataEntry booleanState(String key, long version, boolean value) { -// byte[] v = { value ? (byte) 1 : (byte) 0 }; -// return new KVDataObject(key, ValueType.BOOLEAN, version, false, v); -// } -// -// public static KVDataEntry tinyState(String key, long version, byte value) { -// byte[] v = { value }; -// return new KVDataObject(key, ValueType.INT8, version, false, v); -// } -// -// public static KVDataEntry shortState(String key, long version, short value) { -// byte[] v = BytesUtils.toBytes(value); -// return new KVDataObject(key, ValueType.INT16, version, false, v); -// } -// -// public static KVDataEntry intState(String key, long version, int value) { -// byte[] v = BytesUtils.toBytes(value); -// return new KVDataObject(key, ValueType.INT32, version, false, v); -// } -// -// public static KVDataObject longState(String key, long version, long value) { -// byte[] v = BytesUtils.toBytes(value); -// return new KVDataObject(key, ValueType.INT64, version, false, v); -// } -// -// public static KVDataEntry datetimeState(String key, long version, Date value) { -// byte[] v = BytesUtils.toBytes(value.getTime()); -// return new KVDataObject(key, ValueType.DATETIME, version, false, v); -// } -// -// public static KVDataObject textState(String key, long version, boolean encrypted, String value) { -// try { -// byte[] v = value.getBytes("UTF-8"); -// return new KVDataObject(key, ValueType.TEXT, version, encrypted, v); -// } catch (UnsupportedEncodingException e) { -// throw new IllegalStateException(e.getMessage(), e); -// } -// } -// -// public static KVDataEntry jsonState(String key, long version, String value) { -// try { -// byte[] v = value.getBytes("UTF-8"); -// return new KVDataObject(key, ValueType.JSON, version, false, v); -// } catch (UnsupportedEncodingException e) { -// throw new IllegalStateException(e.getMessage(), e); -// } -// } -// -// public static KVDataEntry xmlState(String key, long version, String value) { -// try { -// byte[] v = value.getBytes("UTF-8"); -// return new KVDataObject(key, ValueType.XML, version, false, v); -// } catch (UnsupportedEncodingException e) { -// throw new IllegalStateException(e.getMessage(), e); -// } -// } -// -// public static KVDataEntry bigIntState(String key, long version, BigInteger value) { -// byte[] v = value.toByteArray(); -// return new KVDataObject(key, ValueType.BIG_INT, version, false, v); -// } -// -// public static KVDataEntry bytesState(String key, long version, boolean encrypted, byte[] value) { -// return new KVDataObject(key, ValueType.BYTES, version, encrypted, value); -// } -// -// public static KVDataEntry imageState(String key, long version, boolean encrypted, byte[] value) { -// return new KVDataObject(key, ValueType.IMG, version, encrypted, value); -// } -// -// public static KVDataEntry videoState(String key, long version, boolean encrypted, byte[] value) { -// return new KVDataObject(key, ValueType.VIDEO, version, encrypted, value); -// } -// -// public static KVDataEntry locationState(String key, long version, boolean encrypted, byte[] value) { -// return new KVDataObject(key, ValueType.LOCATION, version, encrypted, value); -// } - -} \ No newline at end of file diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/MerkleDataNode.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/MerkleDataNode.java index c2014877..43e9d32f 100644 --- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/MerkleDataNode.java +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/MerkleDataNode.java @@ -1,5 +1,6 @@ package com.jd.blockchain.ledger; +import com.jd.blockchain.crypto.HashDigest; import com.jd.blockchain.utils.Bytes; public interface MerkleDataNode extends MerkleNode { @@ -9,5 +10,7 @@ public interface MerkleDataNode extends MerkleNode { Bytes getKey(); long getVersion(); + + HashDigest getValueHash(); } \ No newline at end of file diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/MerkleProof.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/MerkleProof.java index 1463f736..75721f7f 100644 --- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/MerkleProof.java +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/MerkleProof.java @@ -1,8 +1,6 @@ package com.jd.blockchain.ledger; -import com.jd.blockchain.crypto.HashDigest; - -public interface MerkleProof { +public interface MerkleProof extends HashProof { /** * 所证明的数据节点的序列号; @@ -11,62 +9,46 @@ public interface MerkleProof { */ long getSN(); - /** - * 最大层级数;
- * 叶子节点(即数据节点)的层级为 0,数据节点之上的每一级父节点的层级加 1, 最大层级便是根节点的层级; - * - * @return - * - * @see MerkleTree#getLevel() - */ - int getLevels(); - - /** - * 返回证明中指定层级的节点的哈希; - *

- * - * @param level - * 参数值为 0 返回的是数据节点的哈希;
- * 参数值为 {@link #getLevels()} 返回的是根节点的哈希; - * @return - */ - HashDigest getHash(int level); - - MerkleNode getNode(int level); - // /** -// * 返回证明中指定层级的数据起始序号; +// * 最大层级数;
+// * 叶子节点(即数据节点)的层级为 0,数据节点之上的每一级父节点的层级加 1, 最大层级便是根节点的层级; // * -// * @param level // * @return +// * +// * @see MerkleTree#getLevel() // */ -// long getStartingSN(int level); - +// int getLevels(); +// // /** -// * 返回证明中指定层级的数据记录总数; +// * 返回证明中指定层级的节点的哈希; +// *

// * // * @param level +// * 参数值为 0 返回的是数据节点的哈希;
+// * 参数值为 {@link #getLevels()} 返回的是根节点的哈希; // * @return // */ -// long getDataCount(int level); +// HashDigest getHash(int level); - /** - * 返回根节点的哈希; - * - * @return - */ - default HashDigest getRootHash() { - return getHash(getLevels()); - } + MerkleNode getNode(int level); /** - * 返回数据节点的哈希; - * - * @return - */ - default HashDigest getDataHash() { - return getHash(0); - } +// * 返回根节点的哈希; +// * +// * @return +// */ +// default HashDigest getRootHash() { +// return getHash(getLevels()); +// } +// +// /** +// * 返回数据节点的哈希; +// * +// * @return +// */ +// default HashDigest getDataHash() { +// return getHash(0); +// } default MerkleDataNode getDataNode() { return (MerkleDataNode)getNode(0); diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/TypedKVData.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/TypedKVData.java new file mode 100644 index 00000000..dd06de98 --- /dev/null +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/TypedKVData.java @@ -0,0 +1,78 @@ +package com.jd.blockchain.ledger; + +/** + * 强类型的“键-值”数据对象; + * + *

+ * + * {@link TypedKVData} 被设计为只读对象; + * + * @author huanghaiquan + * + */ +public class TypedKVData implements TypedKVEntry { + + private String key; + + private long version; + + private DataType type; + + private Object value; + + public TypedKVData(String key, long version, DataType type, Object value) { + this.key = key; + this.version = version; + this.type = type; + this.value = value; + } + + public TypedKVData(String key, long version, BytesValue bytesValue) { + this.key = key; + this.version = version; + TypedValue typedValue; + if (bytesValue != null && bytesValue instanceof TypedValue) { + typedValue = (TypedValue) bytesValue; + } else { + typedValue = TypedValue.wrap(bytesValue); + } + this.type = typedValue.getType(); + this.value = typedValue.getValue(); + } + + /* + * (non-Javadoc) + * + * @see com.jd.blockchain.ledger.KVDataEntry#getKey() + */ + @Override + public String getKey() { + return key; + } + + /* + * (non-Javadoc) + * + * @see com.jd.blockchain.ledger.KVDataEntry#getVersion() + */ + @Override + public long getVersion() { + return version; + } + + /* + * (non-Javadoc) + * + * @see com.jd.blockchain.ledger.KVDataEntry#getType() + */ + @Override + public DataType getType() { + return type; + } + + @Override + public Object getValue() { + return value; + } + +} \ No newline at end of file diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/KVDataEntry.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/TypedKVEntry.java similarity index 57% rename from source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/KVDataEntry.java rename to source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/TypedKVEntry.java index 396cc36d..54165c61 100644 --- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/KVDataEntry.java +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/TypedKVEntry.java @@ -1,6 +1,6 @@ package com.jd.blockchain.ledger; -public interface KVDataEntry { +public interface TypedKVEntry { /** * 键名; @@ -33,4 +33,12 @@ public interface KVDataEntry { */ Object getValue(); + default long longValue() { + if (getType() == DataType.INT64) { + Object value = getValue(); + return value == null ? 0 : (long) value; + } + throw new IllegalStateException(String.format("Expected type [%s], but [%s]", DataType.INT64, getType())); + } + } \ No newline at end of file diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/TypedValue.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/TypedValue.java new file mode 100644 index 00000000..65dbd298 --- /dev/null +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/TypedValue.java @@ -0,0 +1,454 @@ +package com.jd.blockchain.ledger; + +import java.math.BigInteger; +import java.util.Date; + +import com.jd.blockchain.binaryproto.PrimitiveType; +import com.jd.blockchain.crypto.HashDigest; +import com.jd.blockchain.crypto.PubKey; +import com.jd.blockchain.crypto.SignatureDigest; +import com.jd.blockchain.utils.Bytes; +import com.jd.blockchain.utils.io.BytesUtils; + +/** + * + * @author huanghaiquan + * + */ +public class TypedValue implements BytesValue { + + public static final BytesValue NIL = new TypedValue(); + + private DataType type; + private Bytes value; + + private TypedValue(DataType type, byte[] bytes) { + this.type = type; + this.value = new Bytes(bytes); + } + + private TypedValue(DataType type, Bytes bytes) { + this.type = type; + this.value = bytes; + } + + private TypedValue(BytesValue bytesValue) { + if (bytesValue == null) { + this.type = DataType.NIL; + } else { + this.type = bytesValue.getType(); + this.value = bytesValue.getBytes(); + } + } + + private TypedValue() { + this.type = DataType.NIL; + } + + @Override + public DataType getType() { + return this.type; + } + + @Override + public Bytes getBytes() { + return this.value; + } + + public Object getValue() { + if (isNil()) { + return null; + } + switch (type) { + case BOOLEAN: + return toBoolean(); + case INT8: + return toInt8(); + case INT16: + return toInt16(); + case INT32: + return toInt32(); + case INT64: + return toInt64(); + case BIG_INT: + return toBigInteger(); + case TIMESTAMP: + return toDatetime(); + case TEXT: + case JSON: + case XML: + return toText(); + + case BYTES: + case VIDEO: + case IMG: + case LOCATION: + case ENCRYPTED_DATA: + return toBytesArray(); + + case HASH_DIGEST: + return toHashDegist(); + case PUB_KEY: + return toPubKey(); + case SIGNATURE_DIGEST: + return toSignatureDigest(); + + case DATA_CONTRACT: + return toBytesArray(); + default: + throw new IllegalStateException(String.format("Type [%s] has not be supported!", type)); + } + } + + /** + * 是否为空值; + *

+ * + * 仅当数据类型 {@link #getType()} 为 {@link PrimitiveType#NIL} 时返回 true,其它情况返回 false; + *

+ * + * @return + */ + public boolean isNil() { + return value == null || DataType.NIL == type; + } + + /** + * 返回 8 位整数值; + *

+ * + * 仅当数据类型 {@link #getType()} 为 {@link PrimitiveType#INT8} 有效; + *

+ * + * 无效类型将引发 {@link IllegalStateException} 异常; + * + * @return + */ + public byte tinyValue() { + if (isNil()) { + return DataType.INT8_DEFAULT_VALUE; + } + if (DataType.INT8 == getType()) { + return toInt8(); + } + throw new IllegalStateException(String.format("Type [%s] cannot be convert to Int8!", type)); + } + + private byte toInt8() { + return value.toBytes()[0]; + } + + /** + * 返回 16 位整数值; + *

+ * + * 仅当数据类型 {@link #getType()} 为 {@link PrimitiveType#INT16} 有效; + *

+ * + * 无效类型将引发 {@link IllegalStateException} 异常; + * + * @return + */ + public short shortValue() { + if (isNil()) { + return DataType.INT16_DEFAULT_VALUE; + } + if (DataType.INT16 == getType()) { + return toInt16(); + } + throw new IllegalStateException(String.format("Type [%s] cannot be convert to Int16!", type)); + } + + private short toInt16() { + return BytesUtils.toShort(value.toBytes(), 0); + } + + /** + * 返回 32 位整数值; + *

+ * + * 仅当数据类型 {@link #getType()} 为 {@link PrimitiveType#INT32} 有效; + *

+ * + * 无效类型将引发 {@link IllegalStateException} 异常; + * + * @return + */ + public int intValue() { + if (isNil()) { + return DataType.INT32_DEFAULT_VALUE; + } + if (DataType.INT32 == getType()) { + return toInt32(); + } + throw new IllegalStateException(String.format("Type [%s] cannot be convert to Int32!", type)); + } + + private int toInt32() { + return BytesUtils.toInt(value.toBytes(), 0); + } + + /** + * 返回 64 位整数值; + *

+ * + * 仅当数据类型 {@link #getType()} 为 {@link PrimitiveType#INT64} 有效; + *

+ * + * 无效类型将引发 {@link IllegalStateException} 异常; + * + * @return + */ + public long longValue() { + if (isNil()) { + return DataType.INT64_DEFAULT_VALUE; + } + if (DataType.INT64 == type) { + return toInt64(); + } + throw new IllegalStateException(String.format("Type [%s] cannot be convert to Int64!", type)); + + } + + private long toInt64() { + return BytesUtils.toLong(value.toBytes(), 0); + } + + /** + * 返回大整数值; + *

+ * + * 仅当数据类型 {@link #getType()} 为 {@link PrimitiveType#BIG_INT} 有效; + *

+ * + * 无效类型将引发 {@link IllegalStateException} 异常; + * + * @return + */ + public BigInteger bigIntValue() { + if (isNil()) { + return null; + } + if (DataType.BIG_INT == type) { + return toBigInteger(); + } + throw new IllegalStateException(String.format("Type [%s] cannot be convert to BigInteger!", type)); + } + + private BigInteger toBigInteger() { + return new BigInteger(value.toBytes()); + } + + /** + * 返回布尔值; + *

+ * + * 仅当数据类型 {@link #getType()} 为 {@link PrimitiveType#BIG_INT} 有效; + *

+ * + * 无效类型将引发 {@link IllegalStateException} 异常; + * + * @return + */ + public boolean boolValue() { + if (isNil()) { + return DataType.BOOLEAN_DEFAULT_VALUE; + } + if (DataType.BOOLEAN == type) { + return toBoolean(); + } + throw new IllegalStateException(String.format("Type [%s] cannot be convert to boolean!", type)); + } + + private boolean toBoolean() { + return BytesUtils.toBoolean(value.toBytes()[0]); + } + + /** + * 返回日期时间值; + *

+ * + * 仅当数据类型 {@link #getType()} 为 {@link PrimitiveType#TIMESTAMP} 有效; + *

+ * + * 无效类型将引发 {@link IllegalStateException} 异常; + * + * @return + */ + public Date datetimeValue() { + if (isNil()) { + return null; + } + if (DataType.TIMESTAMP == type) { + return toDatetime(); + } + throw new IllegalStateException(String.format("Type [%s] cannot be convert to datetime!", type)); + } + + private Date toDatetime() { + long ts = BytesUtils.toLong(value.toBytes()); + return new Date(ts); + } + + /** + * 返回文本值; + *

+ * + * 仅当数据类型 {@link #getType()} 为“文本类型”或“文本衍生类型”时有效; + *

+ * + * 无效类型将引发 {@link IllegalStateException} 异常; + * + * @return + */ + public String stringValue() { + if (isNil()) { + return null; + } + if (type.isText()) { + return toText(); + } + throw new IllegalStateException(String.format("Type [%s] cannot be convert to text!", type)); + } + + private String toText() { + return value.toUTF8String(); + } + + /** + * 返回字节数组的值; + *

+ * + * 仅当数据类型 {@link #getType()} 为“字节类型”或“字节衍生类型”时有效; + *

+ * + * 无效类型将引发 {@link IllegalStateException} 异常; + * + * @return + */ + public byte[] bytesValue() { + if (isNil()) { + return null; + } + if (type.isBytes()) { + return toBytesArray(); + } + throw new IllegalStateException(String.format("Type [%s] cannot be convert to bytes!", type)); + } + + private byte[] toBytesArray() { + return value.toBytes(); + } + + public HashDigest hashDigestValue() { + if (isNil()) { + return null; + } + if (DataType.HASH_DIGEST == type) { + return toHashDegist(); + } + throw new IllegalStateException(String.format("Type [%s] cannot be convert to hash digest!", type)); + } + + private HashDigest toHashDegist() { + return new HashDigest(toBytesArray()); + } + + public PubKey pubKeyValue() { + if (isNil()) { + return null; + } + if (DataType.PUB_KEY == type) { + return toPubKey(); + } + throw new IllegalStateException(String.format("Type [%s] cannot be convert to pub key!", type)); + } + + private PubKey toPubKey() { + return new PubKey(toBytesArray()); + } + + public SignatureDigest signatureDigestValue() { + if (isNil()) { + return null; + } + if (DataType.SIGNATURE_DIGEST == type) { + return toSignatureDigest(); + } + throw new IllegalStateException(String.format("Type [%s] cannot be convert to signature digest!", type)); + } + + private SignatureDigest toSignatureDigest() { + return new SignatureDigest(toBytesArray()); + } + + public static TypedValue wrap(BytesValue value) { + return new TypedValue(value); + } + + public static TypedValue fromType(DataType type, byte[] value) { + return new TypedValue(type, value); + } + + public static TypedValue fromBytes(byte[] value) { + return new TypedValue(DataType.BYTES, value); + } + + public static TypedValue fromBytes(Bytes value) { + return new TypedValue(DataType.BYTES, value); + } + + public static TypedValue fromImage(byte[] value) { + return new TypedValue(DataType.IMG, value); + } + + public static TypedValue fromImage(Bytes value) { + return new TypedValue(DataType.IMG, value); + } + + /** + * 以 UTF-8 编码从字符串转换为字节数组值; + * + * @param value + * @return + */ + public static TypedValue fromText(String value) { + return new TypedValue(DataType.TEXT, BytesUtils.toBytes(value)); + } + + public static TypedValue fromJSON(String value) { + return new TypedValue(DataType.JSON, BytesUtils.toBytes(value)); + } + + public static TypedValue fromXML(String value) { + return new TypedValue(DataType.XML, BytesUtils.toBytes(value)); + } + + public static TypedValue fromInt32(int value) { + return new TypedValue(DataType.INT32, BytesUtils.toBytes(value)); + } + + public static TypedValue fromInt64(long value) { + return new TypedValue(DataType.INT64, BytesUtils.toBytes(value)); + } + + public static TypedValue fromInt16(short value) { + return new TypedValue(DataType.INT16, BytesUtils.toBytes(value)); + } + + public static TypedValue fromInt8(byte value) { + return new TypedValue(DataType.INT8, BytesUtils.toBytes(value)); + } + + public static TypedValue fromTimestamp(long value) { + return new TypedValue(DataType.TIMESTAMP, BytesUtils.toBytes(value)); + } + + public static TypedValue fromBoolean(boolean value) { + return new TypedValue(DataType.BOOLEAN, BytesUtils.toBytes(value)); + } + + public static TypedValue fromPubKey(PubKey pubKey) { + return new TypedValue(DataType.PUB_KEY, pubKey.toBytes()); + } +} diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/TypedValue_.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/TypedValue_.java new file mode 100644 index 00000000..145344b5 --- /dev/null +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/TypedValue_.java @@ -0,0 +1,472 @@ +//package com.jd.blockchain.ledger; +// +//import java.math.BigInteger; +//import java.util.Date; +// +//import com.jd.blockchain.binaryproto.PrimitiveType; +//import com.jd.blockchain.crypto.HashDigest; +//import com.jd.blockchain.crypto.PubKey; +//import com.jd.blockchain.crypto.SignatureDigest; +//import com.jd.blockchain.utils.Bytes; +//import com.jd.blockchain.utils.io.BytesUtils; +// +//public class TypedValue_ { +// +// private BytesValue bytesValue; +// +// public TypedValue_(BytesValue bytesValue) { +// this.bytesValue = bytesValue; +// } +// +// public DataType getType() { +// return bytesValue == null ? DataType.NIL : bytesValue.getType(); +// } +// +// public Object getValue() { +// if (isNil()) { +// return null; +// } +// switch (bytesValue.getType()) { +// case BOOLEAN: +// return toBoolean(); +// case INT8: +// return toInt8(); +// case INT16: +// return toInt16(); +// case INT32: +// return toInt32(); +// case INT64: +// return toInt64(); +// case BIG_INT: +// return toBigInteger(); +// case TIMESTAMP: +// return toDatetime(); +// case TEXT: +// case JSON: +// case XML: +// return toText(); +// +// case BYTES: +// case VIDEO: +// case IMG: +// case LOCATION: +// case ENCRYPTED_DATA: +// return toBytesArray(); +// +// case HASH_DIGEST: +// return toHashDegist(); +// case PUB_KEY: +// return toPubKey(); +// case SIGNATURE_DIGEST: +// return toSignatureDigest(); +// +// case DATA_CONTRACT: +// return toBytesArray(); +// default: +// throw new IllegalStateException(String.format("Type [%s] has not be supported!", bytesValue.getType())); +// } +// } +// +// /** +// * 是否为空值; +// *

+// * +// * 仅当数据类型 {@link #getType()} 为 {@link PrimitiveType#NIL} 时返回 true,其它情况返回 false; +// *

+// * +// * @return +// */ +// public boolean isNil() { +// return bytesValue == null || DataType.NIL == bytesValue.getType(); +// } +// +// /** +// * 返回 8 位整数值; +// *

+// * +// * 仅当数据类型 {@link #getType()} 为 {@link PrimitiveType#INT8} 有效; +// *

+// * +// * 无效类型将引发 {@link IllegalStateException} 异常; +// * +// * @return +// */ +// public byte tinyValue() { +// if (isNil()) { +// return DataType.INT8_DEFAULT_VALUE; +// } +// if (DataType.INT8 == getType()) { +// return toInt8(); +// } +// throw new IllegalStateException(String.format("Type [%s] cannot be convert to Int8!", bytesValue.getType())); +// } +// +// private byte toInt8() { +// return bytesValue.getValue().toBytes()[0]; +// } +// +// /** +// * 返回 16 位整数值; +// *

+// * +// * 仅当数据类型 {@link #getType()} 为 {@link PrimitiveType#INT16} 有效; +// *

+// * +// * 无效类型将引发 {@link IllegalStateException} 异常; +// * +// * @return +// */ +// public short shortValue() { +// if (isNil()) { +// return DataType.INT16_DEFAULT_VALUE; +// } +// if (DataType.INT16 == getType()) { +// return toInt16(); +// } +// throw new IllegalStateException(String.format("Type [%s] cannot be convert to Int16!", bytesValue.getType())); +// } +// +// private short toInt16() { +// return BytesUtils.toShort(bytesValue.getValue().toBytes(), 0); +// } +// +// /** +// * 返回 32 位整数值; +// *

+// * +// * 仅当数据类型 {@link #getType()} 为 {@link PrimitiveType#INT32} 有效; +// *

+// * +// * 无效类型将引发 {@link IllegalStateException} 异常; +// * +// * @return +// */ +// public int intValue() { +// if (isNil()) { +// return DataType.INT32_DEFAULT_VALUE; +// } +// if (DataType.INT32 == getType()) { +// return toInt32(); +// } +// throw new IllegalStateException(String.format("Type [%s] cannot be convert to Int32!", bytesValue.getType())); +// } +// +// private int toInt32() { +// return BytesUtils.toInt(bytesValue.getValue().toBytes(), 0); +// } +// +// /** +// * 返回 64 位整数值; +// *

+// * +// * 仅当数据类型 {@link #getType()} 为 {@link PrimitiveType#INT64} 有效; +// *

+// * +// * 无效类型将引发 {@link IllegalStateException} 异常; +// * +// * @return +// */ +// public long longValue() { +// if (isNil()) { +// return DataType.INT64_DEFAULT_VALUE; +// } +// if (DataType.INT64 == bytesValue.getType()) { +// return toInt64(); +// } +// throw new IllegalStateException(String.format("Type [%s] cannot be convert to Int64!", bytesValue.getType())); +// +// } +// +// private long toInt64() { +// return BytesUtils.toLong(bytesValue.getValue().toBytes(), 0); +// } +// +// /** +// * 返回大整数值; +// *

+// * +// * 仅当数据类型 {@link #getType()} 为 {@link PrimitiveType#BIG_INT} 有效; +// *

+// * +// * 无效类型将引发 {@link IllegalStateException} 异常; +// * +// * @return +// */ +// public BigInteger bigIntValue() { +// if (isNil()) { +// return null; +// } +// if (DataType.BIG_INT == bytesValue.getType()) { +// return toBigInteger(); +// } +// throw new IllegalStateException( +// String.format("Type [%s] cannot be convert to BigInteger!", bytesValue.getType())); +// } +// +// private BigInteger toBigInteger() { +// return new BigInteger(bytesValue.getValue().toBytes()); +// } +// +// /** +// * 返回布尔值; +// *

+// * +// * 仅当数据类型 {@link #getType()} 为 {@link PrimitiveType#BIG_INT} 有效; +// *

+// * +// * 无效类型将引发 {@link IllegalStateException} 异常; +// * +// * @return +// */ +// public boolean boolValue() { +// if (isNil()) { +// return DataType.BOOLEAN_DEFAULT_VALUE; +// } +// if (DataType.BOOLEAN == bytesValue.getType()) { +// return toBoolean(); +// } +// throw new IllegalStateException(String.format("Type [%s] cannot be convert to boolean!", bytesValue.getType())); +// } +// +// private boolean toBoolean() { +// return BytesUtils.toBoolean(bytesValue.getValue().toBytes()[0]); +// } +// +// /** +// * 返回日期时间值; +// *

+// * +// * 仅当数据类型 {@link #getType()} 为 {@link PrimitiveType#TIMESTAMP} 有效; +// *

+// * +// * 无效类型将引发 {@link IllegalStateException} 异常; +// * +// * @return +// */ +// public Date datetimeValue() { +// if (isNil()) { +// return null; +// } +// if (DataType.TIMESTAMP == bytesValue.getType()) { +// return toDatetime(); +// } +// throw new IllegalStateException( +// String.format("Type [%s] cannot be convert to datetime!", bytesValue.getType())); +// } +// +// private Date toDatetime() { +// long ts = BytesUtils.toLong(bytesValue.getValue().toBytes()); +// return new Date(ts); +// } +// +// /** +// * 返回文本值; +// *

+// * +// * 仅当数据类型 {@link #getType()} 为“文本类型”或“文本衍生类型”时有效; +// *

+// * +// * 无效类型将引发 {@link IllegalStateException} 异常; +// * +// * @return +// */ +// public String stringValue() { +// if (isNil()) { +// return null; +// } +// DataType type = bytesValue.getType(); +// if (type.isText()) { +// return toText(); +// } +// throw new IllegalStateException(String.format("Type [%s] cannot be convert to text!", type)); +// } +// +// private String toText() { +// return bytesValue.getValue().toUTF8String(); +// } +// +// /** +// * 返回字节数组的值; +// *

+// * +// * 仅当数据类型 {@link #getType()} 为“字节类型”或“字节衍生类型”时有效; +// *

+// * +// * 无效类型将引发 {@link IllegalStateException} 异常; +// * +// * @return +// */ +// public byte[] bytesValue() { +// if (isNil()) { +// return null; +// } +// DataType type = bytesValue.getType(); +// if (type.isBytes()) { +// return toBytesArray(); +// } +// throw new IllegalStateException(String.format("Type [%s] cannot be convert to bytes!", type)); +// } +// +// private byte[] toBytesArray() { +// return bytesValue.getValue().toBytes(); +// } +// +// public HashDigest hashDigestValue() { +// if (isNil()) { +// return null; +// } +// if (DataType.HASH_DIGEST == bytesValue.getType()) { +// return toHashDegist(); +// } +// throw new IllegalStateException( +// String.format("Type [%s] cannot be convert to hash digest!", bytesValue.getType())); +// } +// +// private HashDigest toHashDegist() { +// return new HashDigest(toBytesArray()); +// } +// +// public PubKey pubKeyValue() { +// if (isNil()) { +// return null; +// } +// if (DataType.PUB_KEY == bytesValue.getType()) { +// return toPubKey(); +// } +// throw new IllegalStateException(String.format("Type [%s] cannot be convert to pub key!", bytesValue.getType())); +// } +// +// private PubKey toPubKey() { +// return new PubKey(toBytesArray()); +// } +// +// public SignatureDigest signatureDigestValue() { +// if (isNil()) { +// return null; +// } +// if (DataType.SIGNATURE_DIGEST == bytesValue.getType()) { +// return toSignatureDigest(); +// } +// throw new IllegalStateException( +// String.format("Type [%s] cannot be convert to signature digest!", bytesValue.getType())); +// } +// +// private SignatureDigest toSignatureDigest() { +// return new SignatureDigest(toBytesArray()); +// } +// +// public BytesValue convertToBytesValue() { +// return bytesValue == null ? TypedBytesValue.NIL : bytesValue; +// } +// +// public static TypedBytesValue fromText(String key, String value, long version) { +// BytesValue bytesValue = TypedBytesValue.fromText(value); +// return new TypedBytesValue(bytesValue); +// } +// +// public static TypedBytesValue fromBoolean(String key, boolean value, long version) { +// BytesValue bytesValue = TypedBytesValue.fromBoolean(value); +// return new TypedBytesValue(bytesValue); +// } +// +// public static TypedBytesValue fromInt8(String key, byte value, long version) { +// BytesValue bytesValue = TypedBytesValue.fromInt8(value); +// return new TypedBytesValue(bytesValue); +// } +// +// public static TypedBytesValue fromInt16(String key, short value, long version) { +// BytesValue bytesValue = TypedBytesValue.fromInt16(value); +// return new TypedBytesValue(bytesValue); +// } +// +// public static TypedBytesValue fromInt32(String key, int value, long version) { +// BytesValue bytesValue = TypedBytesValue.fromInt32(value); +// return new TypedBytesValue(bytesValue); +// } +// +// public static TypedBytesValue fromInt64(String key, long value, long version) { +// BytesValue bytesValue = TypedBytesValue.fromInt64(value); +// return new TypedBytesValue(bytesValue); +// } +// +// public static TypedBytesValue fromBytes(String key, byte[] value, long version) { +// BytesValue bytesValue = TypedBytesValue.fromBytes(value); +// return new TypedBytesValue(bytesValue); +// } +// +// public static TypedBytesValue fromTimestamp(String key, long value, long version) { +// BytesValue bytesValue = TypedBytesValue.fromTimestamp(value); +// return new TypedBytesValue(bytesValue); +// } +// +// public static TypedBytesValue fromJSON(String key, String value, long version) { +// BytesValue bytesValue = TypedBytesValue.fromJSON(value); +// return new TypedBytesValue(bytesValue); +// } +// +// public static TypedBytesValue fromXML(String key, String value, long version) { +// BytesValue bytesValue = TypedBytesValue.fromXML(value); +// return new TypedBytesValue(bytesValue); +// } +// +// public static TypedBytesValue fromImage(String key, byte[] value, long version) { +// BytesValue bytesValue = TypedBytesValue.fromImage(value); +// return new TypedBytesValue(bytesValue); +// } +// +// public static TypedBytesValue fromText(Bytes key, String value, long version) { +// BytesValue bytesValue = TypedBytesValue.fromText(value); +// return new TypedBytesValue(bytesValue); +// } +// +// public static TypedBytesValue fromBoolean(Bytes key, boolean value, long version) { +// BytesValue bytesValue = TypedBytesValue.fromBoolean(value); +// return new TypedBytesValue(bytesValue); +// } +// +// public static TypedBytesValue fromInt8(Bytes key, byte value, long version) { +// BytesValue bytesValue = TypedBytesValue.fromInt8(value); +// return new TypedBytesValue(bytesValue); +// } +// +// public static TypedBytesValue fromInt16(Bytes key, short value, long version) { +// BytesValue bytesValue = TypedBytesValue.fromInt16(value); +// return new TypedBytesValue(bytesValue); +// } +// +// public static TypedBytesValue fromInt32(Bytes key, int value, long version) { +// BytesValue bytesValue = TypedBytesValue.fromInt32(value); +// return new TypedBytesValue(bytesValue); +// } +// +// public static TypedBytesValue fromInt64(Bytes key, long value, long version) { +// BytesValue bytesValue = TypedBytesValue.fromInt64(value); +// return new TypedBytesValue(bytesValue); +// } +// +// public static TypedBytesValue fromBytes(Bytes key, byte[] value, long version) { +// BytesValue bytesValue = TypedBytesValue.fromBytes(value); +// return new TypedBytesValue(bytesValue); +// } +// +// public static TypedBytesValue fromTimestamp(Bytes key, long value, long version) { +// BytesValue bytesValue = TypedBytesValue.fromTimestamp(value); +// return new TypedBytesValue(bytesValue); +// } +// +// public static TypedBytesValue fromJSON(Bytes key, String value, long version) { +// BytesValue bytesValue = TypedBytesValue.fromJSON(value); +// return new TypedBytesValue(bytesValue); +// } +// +// public static TypedBytesValue fromXML(Bytes key, String value, long version) { +// BytesValue bytesValue = TypedBytesValue.fromXML(value); +// return new TypedBytesValue(bytesValue); +// } +// +// public static TypedBytesValue fromImage(Bytes key, byte[] value, long version) { +// BytesValue bytesValue = TypedBytesValue.fromImage(value); +// return new TypedBytesValue(bytesValue); +// } +// +//} diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/UserAccountHeader.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/UserAccountHeader.java new file mode 100644 index 00000000..8fc0e7a5 --- /dev/null +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/UserAccountHeader.java @@ -0,0 +1,12 @@ +package com.jd.blockchain.ledger; + +import com.jd.blockchain.binaryproto.DataContract; +import com.jd.blockchain.consts.DataCodes; +import com.jd.blockchain.crypto.PubKey; + +@DataContract(code= DataCodes.USER_ACCOUNT_HEADER) +public interface UserAccountHeader extends BlockchainIdentity { + + PubKey getDataPubKey(); + +} diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/UserInfo.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/UserInfo.java index 48759b9f..c7b14d1a 100644 --- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/UserInfo.java +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/UserInfo.java @@ -2,11 +2,8 @@ package com.jd.blockchain.ledger; import com.jd.blockchain.binaryproto.DataContract; import com.jd.blockchain.consts.DataCodes; -import com.jd.blockchain.crypto.PubKey; -@DataContract(code= DataCodes.USER) -public interface UserInfo extends AccountHeader { - - PubKey getDataPubKey(); - +@DataContract(code = DataCodes.USER_INFO) +public interface UserInfo extends UserAccountHeader { + } diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/resolver/AbstractBytesValueResolver.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/resolver/AbstractBytesValueResolver.java index 995d5522..d6ee0b98 100644 --- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/resolver/AbstractBytesValueResolver.java +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/resolver/AbstractBytesValueResolver.java @@ -47,7 +47,7 @@ public abstract class AbstractBytesValueResolver implements BytesValueResolver { if (!isSupport(dataType)) { throw new IllegalStateException(String.format("Un-support encode DataType[%s] Object !!!", dataType.name())); } - return decode(value.getValue()); + return decode(value.getBytes()); } protected abstract Object decode(Bytes value); diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/resolver/BooleanToBytesValueResolver.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/resolver/BooleanToBytesValueResolver.java index 0664fdb9..69285395 100644 --- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/resolver/BooleanToBytesValueResolver.java +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/resolver/BooleanToBytesValueResolver.java @@ -1,6 +1,6 @@ package com.jd.blockchain.ledger.resolver; -import com.jd.blockchain.ledger.BytesData; +import com.jd.blockchain.ledger.TypedValue; import com.jd.blockchain.ledger.BytesValue; import com.jd.blockchain.ledger.DataType; import com.jd.blockchain.utils.Bytes; @@ -21,7 +21,7 @@ public class BooleanToBytesValueResolver extends AbstractBytesValueResolver { if (!isSupport(type)) { throw new IllegalStateException(String.format("Un-support encode Class[%s] Object !!!", type.getName())); } - return BytesData.fromBoolean((boolean) value); + return TypedValue.fromBoolean((boolean) value); } @Override diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/resolver/BytesToBytesValueResolver.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/resolver/BytesToBytesValueResolver.java index f4871515..fe71eee7 100644 --- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/resolver/BytesToBytesValueResolver.java +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/resolver/BytesToBytesValueResolver.java @@ -1,6 +1,6 @@ package com.jd.blockchain.ledger.resolver; -import com.jd.blockchain.ledger.BytesData; +import com.jd.blockchain.ledger.TypedValue; import com.jd.blockchain.ledger.BytesValue; import com.jd.blockchain.ledger.DataType; import com.jd.blockchain.utils.Bytes; @@ -21,9 +21,9 @@ public class BytesToBytesValueResolver extends AbstractBytesValueResolver { throw new IllegalStateException(String.format("Un-support encode Class[%s] Object !!!", type.getName())); } if (type.equals(byte[].class)) { - return BytesData.fromBytes((byte[]) value); + return TypedValue.fromBytes((byte[]) value); } - return BytesData.fromBytes((Bytes) value); + return TypedValue.fromBytes((Bytes) value); } @Override diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/resolver/IntegerToBytesValueResolver.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/resolver/IntegerToBytesValueResolver.java index a8400f02..075d1f76 100644 --- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/resolver/IntegerToBytesValueResolver.java +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/resolver/IntegerToBytesValueResolver.java @@ -1,6 +1,6 @@ package com.jd.blockchain.ledger.resolver; -import com.jd.blockchain.ledger.BytesData; +import com.jd.blockchain.ledger.TypedValue; import com.jd.blockchain.ledger.BytesValue; import com.jd.blockchain.ledger.DataType; import com.jd.blockchain.utils.Bytes; @@ -21,7 +21,7 @@ public class IntegerToBytesValueResolver extends AbstractBytesValueResolver { if (!isSupport(type)) { throw new IllegalStateException(String.format("Un-support encode Class[%s] Object !!!", type.getName())); } - return BytesData.fromInt32((int) value); + return TypedValue.fromInt32((int) value); } @Override diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/resolver/LongToBytesValueResolver.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/resolver/LongToBytesValueResolver.java index fa11bcf4..ce6dbaf9 100644 --- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/resolver/LongToBytesValueResolver.java +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/resolver/LongToBytesValueResolver.java @@ -1,6 +1,6 @@ package com.jd.blockchain.ledger.resolver; -import com.jd.blockchain.ledger.BytesData; +import com.jd.blockchain.ledger.TypedValue; import com.jd.blockchain.ledger.BytesValue; import com.jd.blockchain.ledger.DataType; import com.jd.blockchain.utils.Bytes; @@ -21,7 +21,7 @@ public class LongToBytesValueResolver extends AbstractBytesValueResolver { if (!isSupport(type)) { throw new IllegalStateException(String.format("Un-support encode Class[%s] Object !!!", type.getName())); } - return BytesData.fromInt64((long)value); + return TypedValue.fromInt64((long)value); } @Override diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/resolver/ShortToBytesValueResolver.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/resolver/ShortToBytesValueResolver.java index b8eea38c..ddbed5fb 100644 --- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/resolver/ShortToBytesValueResolver.java +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/resolver/ShortToBytesValueResolver.java @@ -1,6 +1,6 @@ package com.jd.blockchain.ledger.resolver; -import com.jd.blockchain.ledger.BytesData; +import com.jd.blockchain.ledger.TypedValue; import com.jd.blockchain.ledger.BytesValue; import com.jd.blockchain.ledger.DataType; import com.jd.blockchain.utils.Bytes; @@ -21,7 +21,7 @@ public class ShortToBytesValueResolver extends AbstractBytesValueResolver { if (!isSupport(type)) { throw new IllegalStateException(String.format("Un-support encode Class[%s] Object !!!", type.getName())); } - return BytesData.fromInt16((short)value); + return TypedValue.fromInt16((short)value); } @Override diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/resolver/StringToBytesValueResolver.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/resolver/StringToBytesValueResolver.java index dca8e5d1..0f08442e 100644 --- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/resolver/StringToBytesValueResolver.java +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/resolver/StringToBytesValueResolver.java @@ -1,6 +1,6 @@ package com.jd.blockchain.ledger.resolver; -import com.jd.blockchain.ledger.BytesData; +import com.jd.blockchain.ledger.TypedValue; import com.jd.blockchain.ledger.BytesValue; import com.jd.blockchain.ledger.DataType; import com.jd.blockchain.utils.Bytes; @@ -26,10 +26,10 @@ public class StringToBytesValueResolver extends AbstractBytesValueResolver { // 类型判断 String valString = (String)value; if (JSONSerializeUtils.isJSON(valString)) { - return BytesData.fromJSON(valString); + return TypedValue.fromJSON(valString); } // 暂不处理XML格式 - return BytesData.fromText(valString); + return TypedValue.fromText(valString); } @Override diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/BlockchainQueryService.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/BlockchainQueryService.java index 9710b50d..f63a7f2a 100644 --- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/BlockchainQueryService.java +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/BlockchainQueryService.java @@ -3,9 +3,9 @@ package com.jd.blockchain.transaction; import org.springframework.cglib.core.Block; import com.jd.blockchain.crypto.HashDigest; -import com.jd.blockchain.ledger.AccountHeader; +import com.jd.blockchain.ledger.BlockchainIdentity; import com.jd.blockchain.ledger.ContractInfo; -import com.jd.blockchain.ledger.KVDataEntry; +import com.jd.blockchain.ledger.TypedKVEntry; import com.jd.blockchain.ledger.KVInfoVO; import com.jd.blockchain.ledger.LedgerAdminInfo; import com.jd.blockchain.ledger.LedgerBlock; @@ -250,7 +250,7 @@ public interface BlockchainQueryService { * @param address * @return */ - AccountHeader getDataAccount(HashDigest ledgerHash, String address); + BlockchainIdentity getDataAccount(HashDigest ledgerHash, String address); /** * 返回数据账户中指定的键的最新值;
@@ -264,9 +264,9 @@ public interface BlockchainQueryService { * @param keys * @return */ - KVDataEntry[] getDataEntries(HashDigest ledgerHash, String address, String... keys); + TypedKVEntry[] getDataEntries(HashDigest ledgerHash, String address, String... keys); - KVDataEntry[] getDataEntries(HashDigest ledgerHash, String address, KVInfoVO kvInfoVO); + TypedKVEntry[] getDataEntries(HashDigest ledgerHash, String address, KVInfoVO kvInfoVO); /** * 返回指定数据账户中KV数据的总数;
@@ -287,7 +287,7 @@ public interface BlockchainQueryService { * 如果参数值为 -1,则返回全部的记录;
* @return */ - KVDataEntry[] getDataEntries(HashDigest ledgerHash, String address, int fromIndex, int count); + TypedKVEntry[] getDataEntries(HashDigest ledgerHash, String address, int fromIndex, int count); /** * 返回合约账户信息; @@ -306,7 +306,7 @@ public interface BlockchainQueryService { * @param count * @return */ - AccountHeader[] getUsers(HashDigest ledgerHash, int fromIndex, int count); + BlockchainIdentity[] getUsers(HashDigest ledgerHash, int fromIndex, int count); /** * get data accounts by ledgerHash and its range; @@ -316,7 +316,7 @@ public interface BlockchainQueryService { * @param count * @return */ - AccountHeader[] getDataAccounts(HashDigest ledgerHash, int fromIndex, int count); + BlockchainIdentity[] getDataAccounts(HashDigest ledgerHash, int fromIndex, int count); /** * get contract accounts by ledgerHash and its range; @@ -326,5 +326,5 @@ public interface BlockchainQueryService { * @param count * @return */ - AccountHeader[] getContractAccounts(HashDigest ledgerHash, int fromIndex, int count); + BlockchainIdentity[] getContractAccounts(HashDigest ledgerHash, int fromIndex, int count); } diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/DataAccountKVSetOperationBuilderImpl.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/DataAccountKVSetOperationBuilderImpl.java index b2ccef13..cec540c9 100644 --- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/DataAccountKVSetOperationBuilderImpl.java +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/DataAccountKVSetOperationBuilderImpl.java @@ -1,7 +1,7 @@ package com.jd.blockchain.transaction; import com.jd.blockchain.ledger.BytesValue; -import com.jd.blockchain.ledger.BytesData; +import com.jd.blockchain.ledger.TypedValue; import com.jd.blockchain.ledger.DataAccountKVSetOperation; import com.jd.blockchain.utils.Bytes; @@ -26,14 +26,14 @@ public class DataAccountKVSetOperationBuilderImpl implements DataAccountKVSetOpe @Override public DataAccountKVSetOperationBuilder setBytes(String key, byte[] value, long expVersion) { - BytesValue bytesValue = BytesData.fromBytes(value); + BytesValue bytesValue = TypedValue.fromBytes(value); operation.set(key, bytesValue, expVersion); return this; } @Override public DataAccountKVSetOperationBuilder setImage(String key, byte[] value, long expVersion) { - BytesValue bytesValue = BytesData.fromImage(value); + BytesValue bytesValue = TypedValue.fromImage(value); operation.set(key, bytesValue, expVersion); return this; } @@ -45,42 +45,42 @@ public class DataAccountKVSetOperationBuilderImpl implements DataAccountKVSetOpe @Override public DataAccountKVSetOperationBuilder setText(String key, String value, long expVersion) { - BytesValue bytesValue = BytesData.fromText(value); + BytesValue bytesValue = TypedValue.fromText(value); operation.set(key, bytesValue, expVersion); return this; } @Override public DataAccountKVSetOperationBuilder setBytes(String key, Bytes value, long expVersion) { - BytesValue bytesValue = BytesData.fromBytes(value); + BytesValue bytesValue = TypedValue.fromBytes(value); operation.set(key, bytesValue, expVersion); return this; } @Override public DataAccountKVSetOperationBuilder setInt64(String key, long value, long expVersion) { - BytesValue bytesValue = BytesData.fromInt64(value); + BytesValue bytesValue = TypedValue.fromInt64(value); operation.set(key, bytesValue, expVersion); return this; } @Override public DataAccountKVSetOperationBuilder setJSON(String key, String value, long expVersion) { - BytesValue bytesValue = BytesData.fromJSON(value); + BytesValue bytesValue = TypedValue.fromJSON(value); operation.set(key, bytesValue, expVersion); return this; } @Override public DataAccountKVSetOperationBuilder setXML(String key, String value, long expVersion) { - BytesValue bytesValue = BytesData.fromXML(value); + BytesValue bytesValue = TypedValue.fromXML(value); operation.set(key, bytesValue, expVersion); return this; } @Override public DataAccountKVSetOperationBuilder setTimestamp(String key, long value, long expVersion) { - BytesValue bytesValue = BytesData.fromTimestamp(value); + BytesValue bytesValue = TypedValue.fromTimestamp(value); operation.set(key, bytesValue, expVersion); return this; } diff --git a/source/ledger/ledger-model/src/test/java/test/com/jd/blockchain/ledger/BytesToBytesValueResolverTest.java b/source/ledger/ledger-model/src/test/java/test/com/jd/blockchain/ledger/BytesToBytesValueResolverTest.java index 3635743c..2dfa0dbd 100644 --- a/source/ledger/ledger-model/src/test/java/test/com/jd/blockchain/ledger/BytesToBytesValueResolverTest.java +++ b/source/ledger/ledger-model/src/test/java/test/com/jd/blockchain/ledger/BytesToBytesValueResolverTest.java @@ -26,7 +26,7 @@ public class BytesToBytesValueResolverTest { assertEquals(bytesValue.getType(), DataType.BYTES); - assertEquals(bytesObj, bytesValue.getValue()); + assertEquals(bytesObj, bytesValue.getBytes()); Bytes resolveBytesObj = (Bytes)resolver.decode(bytesValue); diff --git a/source/ledger/ledger-model/src/test/java/test/com/jd/blockchain/ledger/BytesValueEncodingTest.java b/source/ledger/ledger-model/src/test/java/test/com/jd/blockchain/ledger/BytesValueEncodingTest.java index e5b624c9..f572a831 100644 --- a/source/ledger/ledger-model/src/test/java/test/com/jd/blockchain/ledger/BytesValueEncodingTest.java +++ b/source/ledger/ledger-model/src/test/java/test/com/jd/blockchain/ledger/BytesValueEncodingTest.java @@ -28,9 +28,9 @@ public class BytesValueEncodingTest { BytesValue longBytesVal2 = BytesValueEncoding.encodeSingle(longVal, long.class); BytesValue longBytesVal3 = BytesValueEncoding.encodeSingle(longVal, Long.class); - assertEquals(longBytesVal1.getValue(), longBytesVal2.getValue()); + assertEquals(longBytesVal1.getBytes(), longBytesVal2.getBytes()); assertEquals(longBytesVal1.getType(), longBytesVal2.getType()); - assertEquals(longBytesVal2.getValue(), longBytesVal3.getValue()); + assertEquals(longBytesVal2.getBytes(), longBytesVal3.getBytes()); assertEquals(longBytesVal2.getType(), longBytesVal3.getType()); long resolveLongVal1 = (long)BytesValueEncoding.decode(longBytesVal1); diff --git a/source/ledger/ledger-model/src/test/java/test/com/jd/blockchain/ledger/ContractEventSendOpTemplateTest.java b/source/ledger/ledger-model/src/test/java/test/com/jd/blockchain/ledger/ContractEventSendOpTemplateTest.java index d010ae6f..506d86d4 100644 --- a/source/ledger/ledger-model/src/test/java/test/com/jd/blockchain/ledger/ContractEventSendOpTemplateTest.java +++ b/source/ledger/ledger-model/src/test/java/test/com/jd/blockchain/ledger/ContractEventSendOpTemplateTest.java @@ -16,7 +16,7 @@ import org.junit.Test; import com.jd.blockchain.binaryproto.BinaryProtocol; import com.jd.blockchain.binaryproto.DataContractRegistry; -import com.jd.blockchain.ledger.BytesData; +import com.jd.blockchain.ledger.TypedValue; import com.jd.blockchain.ledger.BytesDataList; import com.jd.blockchain.ledger.BytesValueList; import com.jd.blockchain.ledger.ContractEventSendOperation; @@ -41,7 +41,7 @@ public class ContractEventSendOpTemplateTest { DataContractRegistry.register(ContractEventSendOperation.class); DataContractRegistry.register(Operation.class); String contractAddress = "zhangsan-address", event = "zhangsan-event"; - BytesValueList args = new BytesDataList(BytesData.fromText("zhangsan-args")); + BytesValueList args = new BytesDataList(TypedValue.fromText("zhangsan-args")); data = new ContractEventSendOpTemplate(Bytes.fromString(contractAddress), event, args); } diff --git a/source/ledger/ledger-model/src/test/java/test/com/jd/blockchain/ledger/DataAccountKVSetOpTemplateTest.java b/source/ledger/ledger-model/src/test/java/test/com/jd/blockchain/ledger/DataAccountKVSetOpTemplateTest.java index d8b33048..6c1d4f57 100644 --- a/source/ledger/ledger-model/src/test/java/test/com/jd/blockchain/ledger/DataAccountKVSetOpTemplateTest.java +++ b/source/ledger/ledger-model/src/test/java/test/com/jd/blockchain/ledger/DataAccountKVSetOpTemplateTest.java @@ -16,7 +16,7 @@ import org.junit.Test; import com.jd.blockchain.binaryproto.BinaryProtocol; import com.jd.blockchain.binaryproto.DataContractRegistry; -import com.jd.blockchain.ledger.BytesData; +import com.jd.blockchain.ledger.TypedValue; import com.jd.blockchain.ledger.DataAccountKVSetOperation; import com.jd.blockchain.ledger.Operation; import com.jd.blockchain.transaction.DataAccountKVSetOpTemplate; @@ -41,11 +41,11 @@ public class DataAccountKVSetOpTemplateTest { String accountAddress = "zhangsandhakhdkah"; data = new DataAccountKVSetOpTemplate(Bytes.fromString(accountAddress)); KVData kvData1 = - new KVData("test1", BytesData.fromText("zhangsan"), 9999L); + new KVData("test1", TypedValue.fromText("zhangsan"), 9999L); KVData kvData2 = - new KVData("test2", BytesData.fromText("lisi"), 9990L); + new KVData("test2", TypedValue.fromText("lisi"), 9990L); KVData kvData3 = - new KVData("test3", BytesData.fromText("wangwu"), 1990L); + new KVData("test3", TypedValue.fromText("wangwu"), 1990L); data.set(kvData1); data.set(kvData2); data.set(kvData3); @@ -63,7 +63,7 @@ public class DataAccountKVSetOpTemplateTest { assertEquals(dataKv.length, resolvedKv.length); for (int i = 0; i < dataKv.length; i++) { assertEquals(dataKv[i].getKey(), resolvedKv[i].getKey()); - assertArrayEquals(dataKv[i].getValue().getValue().toBytes(), resolvedKv[i].getValue().getValue().toBytes()); + assertArrayEquals(dataKv[i].getValue().getBytes().toBytes(), resolvedKv[i].getValue().getBytes().toBytes()); assertEquals(dataKv[i].getValue().getType().CODE, resolvedKv[i].getValue().getType().CODE); assertEquals(dataKv[i].getExpectedVersion(), resolvedKv[i].getExpectedVersion()); diff --git a/source/ledger/ledger-model/src/test/java/test/com/jd/blockchain/ledger/IntegerToBytesValueResolverTest.java b/source/ledger/ledger-model/src/test/java/test/com/jd/blockchain/ledger/IntegerToBytesValueResolverTest.java index 8e39aa85..dd9d4632 100644 --- a/source/ledger/ledger-model/src/test/java/test/com/jd/blockchain/ledger/IntegerToBytesValueResolverTest.java +++ b/source/ledger/ledger-model/src/test/java/test/com/jd/blockchain/ledger/IntegerToBytesValueResolverTest.java @@ -22,13 +22,13 @@ public class IntegerToBytesValueResolverTest { BytesValue intBytesValue2 = resolver.encode(intVal, Integer.class); - assertEquals(intBytesValue.getValue(), intBytesValue1.getValue()); + assertEquals(intBytesValue.getBytes(), intBytesValue1.getBytes()); - assertEquals(intBytesValue.getValue(), intBytesValue2.getValue()); + assertEquals(intBytesValue.getBytes(), intBytesValue2.getBytes()); Bytes intBytes = Bytes.fromInt(intVal); - assertEquals(intBytes, intBytesValue.getValue()); + assertEquals(intBytes, intBytesValue.getBytes()); assertEquals(intBytesValue.getType(), DataType.INT32); diff --git a/source/ledger/ledger-model/src/test/java/test/com/jd/blockchain/ledger/KVDataTest.java b/source/ledger/ledger-model/src/test/java/test/com/jd/blockchain/ledger/KVDataTest.java index d1a6fcb9..3d54f16c 100644 --- a/source/ledger/ledger-model/src/test/java/test/com/jd/blockchain/ledger/KVDataTest.java +++ b/source/ledger/ledger-model/src/test/java/test/com/jd/blockchain/ledger/KVDataTest.java @@ -16,7 +16,7 @@ import org.junit.Test; import com.jd.blockchain.binaryproto.BinaryProtocol; import com.jd.blockchain.binaryproto.DataContractRegistry; -import com.jd.blockchain.ledger.BytesData; +import com.jd.blockchain.ledger.TypedValue; import com.jd.blockchain.ledger.DataAccountKVSetOperation; import com.jd.blockchain.transaction.DataAccountKVSetOpTemplate; import com.jd.blockchain.transaction.KVData; @@ -38,7 +38,7 @@ public class KVDataTest { byte[] value = "test-value".getBytes(); long expectedVersion = 9999L; - kvData = new KVData(key, BytesData.fromBytes(value), expectedVersion); + kvData = new KVData(key, TypedValue.fromBytes(value), expectedVersion); } @Test @@ -48,7 +48,7 @@ public class KVDataTest { System.out.println("------Assert start ------"); assertEquals(resolvedKvData.getKey(), kvData.getKey()); assertEquals(resolvedKvData.getExpectedVersion(), kvData.getExpectedVersion()); - assertArrayEquals(resolvedKvData.getValue().getValue().toBytes(), kvData.getValue().getValue().toBytes()); + assertArrayEquals(resolvedKvData.getValue().getBytes().toBytes(), kvData.getValue().getBytes().toBytes()); System.out.println("------Assert OK ------"); } } \ No newline at end of file diff --git a/source/ledger/ledger-model/src/test/java/test/com/jd/blockchain/ledger/LongToBytesValueResolverTest.java b/source/ledger/ledger-model/src/test/java/test/com/jd/blockchain/ledger/LongToBytesValueResolverTest.java index 899a6415..b4d20b4c 100644 --- a/source/ledger/ledger-model/src/test/java/test/com/jd/blockchain/ledger/LongToBytesValueResolverTest.java +++ b/source/ledger/ledger-model/src/test/java/test/com/jd/blockchain/ledger/LongToBytesValueResolverTest.java @@ -23,13 +23,13 @@ public class LongToBytesValueResolverTest { BytesValue longBytesValue2 = resolver.encode(longVal, Long.class); - assertEquals(longBytesValue.getValue(), longBytesValue1.getValue()); + assertEquals(longBytesValue.getBytes(), longBytesValue1.getBytes()); - assertEquals(longBytesValue.getValue(), longBytesValue2.getValue()); + assertEquals(longBytesValue.getBytes(), longBytesValue2.getBytes()); Bytes longBytes = Bytes.fromLong(longVal); - assertEquals(longBytes, longBytesValue.getValue()); + assertEquals(longBytes, longBytesValue.getBytes()); assertEquals(longBytesValue.getType(), DataType.INT64); diff --git a/source/ledger/ledger-model/src/test/java/test/com/jd/blockchain/ledger/ShortToBytesValueResolverTest.java b/source/ledger/ledger-model/src/test/java/test/com/jd/blockchain/ledger/ShortToBytesValueResolverTest.java index b35cedd7..2e8e46be 100644 --- a/source/ledger/ledger-model/src/test/java/test/com/jd/blockchain/ledger/ShortToBytesValueResolverTest.java +++ b/source/ledger/ledger-model/src/test/java/test/com/jd/blockchain/ledger/ShortToBytesValueResolverTest.java @@ -21,7 +21,7 @@ public class ShortToBytesValueResolverTest { Bytes shortBytes = new Bytes(BytesUtils.toBytes(shortVal)); - assertEquals(shortBytes, shortBytesValue.getValue()); + assertEquals(shortBytes, shortBytesValue.getBytes()); assertEquals(shortBytesValue.getType(), DataType.INT16); diff --git a/source/ledger/ledger-model/src/test/java/test/com/jd/blockchain/ledger/StringToBytesValueResolverTest.java b/source/ledger/ledger-model/src/test/java/test/com/jd/blockchain/ledger/StringToBytesValueResolverTest.java index 17dd0c04..544f06bb 100644 --- a/source/ledger/ledger-model/src/test/java/test/com/jd/blockchain/ledger/StringToBytesValueResolverTest.java +++ b/source/ledger/ledger-model/src/test/java/test/com/jd/blockchain/ledger/StringToBytesValueResolverTest.java @@ -20,7 +20,7 @@ public class StringToBytesValueResolverTest { BytesValue textBytesValue = resolver.encode(textVal); - assertEquals(Bytes.fromString(textVal), textBytesValue.getValue()); + assertEquals(Bytes.fromString(textVal), textBytesValue.getBytes()); assertEquals(textBytesValue.getType(), DataType.TEXT); @@ -43,7 +43,7 @@ public class StringToBytesValueResolverTest { Person person = new Person("zhangsan", 80); String personJson = JSON.toJSONString(person); BytesValue textBytesValue = resolver.encode(personJson); - assertEquals(Bytes.fromString(personJson), textBytesValue.getValue()); + assertEquals(Bytes.fromString(personJson), textBytesValue.getBytes()); assertEquals(textBytesValue.getType(), DataType.JSON); } diff --git a/source/ledger/ledger-model/src/test/java/test/com/jd/blockchain/ledger/TxContentBlobTest.java b/source/ledger/ledger-model/src/test/java/test/com/jd/blockchain/ledger/TxContentBlobTest.java index 0404ee38..c8d8c313 100644 --- a/source/ledger/ledger-model/src/test/java/test/com/jd/blockchain/ledger/TxContentBlobTest.java +++ b/source/ledger/ledger-model/src/test/java/test/com/jd/blockchain/ledger/TxContentBlobTest.java @@ -77,8 +77,8 @@ public class TxContentBlobTest { for (int j = 0; j < dataKv.length; j++) { assertEquals(dataKv[i].getKey(), resolvedKv[i].getKey()); assertEquals(dataKv[i].getExpectedVersion(), resolvedKv[i].getExpectedVersion()); - assertArrayEquals(dataKv[i].getValue().getValue().toBytes(), - resolvedKv[i].getValue().getValue().toBytes()); + assertArrayEquals(dataKv[i].getValue().getBytes().toBytes(), + resolvedKv[i].getValue().getBytes().toBytes()); } } } @@ -108,8 +108,8 @@ public class TxContentBlobTest { for (int j = 0; j < dataKv.length; j++) { assertEquals(dataKv[i].getKey(), resolvedKv[i].getKey()); assertEquals(dataKv[i].getExpectedVersion(), resolvedKv[i].getExpectedVersion()); - assertArrayEquals(dataKv[i].getValue().getValue().toBytes(), - resolvedKv[i].getValue().getValue().toBytes()); + assertArrayEquals(dataKv[i].getValue().getBytes().toBytes(), + resolvedKv[i].getValue().getBytes().toBytes()); } } } diff --git a/source/ledger/ledger-rpc/pom.xml b/source/ledger/ledger-rpc/pom.xml index 34a7aae5..57a8cf9f 100644 --- a/source/ledger/ledger-rpc/pom.xml +++ b/source/ledger/ledger-rpc/pom.xml @@ -5,7 +5,7 @@ com.jd.blockchain ledger - 1.1.1-PACK20191209 + 1.1.2.RELEASE ledger-rpc diff --git a/source/ledger/pom.xml b/source/ledger/pom.xml index 89a6c6db..d5049b8c 100644 --- a/source/ledger/pom.xml +++ b/source/ledger/pom.xml @@ -5,7 +5,7 @@ com.jd.blockchain jdchain-root - 1.1.1-PACK20191209 + 1.1.2.RELEASE ledger pom diff --git a/source/manager/manager-booter/pom.xml b/source/manager/manager-booter/pom.xml index ea1e7729..e4764486 100644 --- a/source/manager/manager-booter/pom.xml +++ b/source/manager/manager-booter/pom.xml @@ -5,7 +5,7 @@ manager com.jd.blockchain - 1.1.1-PACK20191209 + 1.1.2.RELEASE 4.0.0 diff --git a/source/manager/manager-booter/src/main/resources/application.properties b/source/manager/manager-booter/src/main/resources/application.properties index c64be53e..a8959472 100644 --- a/source/manager/manager-booter/src/main/resources/application.properties +++ b/source/manager/manager-booter/src/main/resources/application.properties @@ -4,5 +4,5 @@ spring.mvc.favicon.enabled=false logging.config=classpath:log4j2-jump.xml -retrieval.schemaUrl=http://192.168.151.40:8082 -retrieval.taskUrl=http://192.168.151.40:10005 \ No newline at end of file +schema.retrieval.url=http://127.0.0.1:8082 +task.retrieval.url=http://127.0.0.1:10005 \ No newline at end of file diff --git a/source/manager/manager-booter/src/main/resources/config.properties b/source/manager/manager-booter/src/main/resources/config.properties index ac5a026f..bc4e3dc2 100644 --- a/source/manager/manager-booter/src/main/resources/config.properties +++ b/source/manager/manager-booter/src/main/resources/config.properties @@ -7,5 +7,5 @@ server.port=8080 # 本地数据库存储位置 db.url=rocksdb://#project#/jumpdb -schema.retrieval.url=http://192.168.151.40:8082 -task.retrieval.url=http://192.168.151.40:10005 \ No newline at end of file +schema.retrieval.url=http://127.0.0.1:8082 +task.retrieval.url=http://127.0.0.1:10005 \ No newline at end of file diff --git a/source/manager/manager-model/pom.xml b/source/manager/manager-model/pom.xml index 0b7f63b0..fd35f6d9 100644 --- a/source/manager/manager-model/pom.xml +++ b/source/manager/manager-model/pom.xml @@ -5,7 +5,7 @@ manager com.jd.blockchain - 1.1.1-PACK20191209 + 1.1.2.RELEASE 4.0.0 @@ -65,6 +65,7 @@ org.rocksdb rocksdbjni + ${rocksdb.version} diff --git a/source/manager/manager-model/src/main/java/com/jd/blockchain/ump/model/UmpConstant.java b/source/manager/manager-model/src/main/java/com/jd/blockchain/ump/model/UmpConstant.java index 216a1e85..7903620c 100644 --- a/source/manager/manager-model/src/main/java/com/jd/blockchain/ump/model/UmpConstant.java +++ b/source/manager/manager-model/src/main/java/com/jd/blockchain/ump/model/UmpConstant.java @@ -16,7 +16,7 @@ public class UmpConstant { public static final String PRIVATE_KEY_SUFFIX = ".priv"; - public static final String PUBLIC_KEY_SUFFIX = ".priv"; + public static final String PUBLIC_KEY_SUFFIX = ".pub"; public static final String PWD_SUFFIX = ".pwd"; @@ -134,6 +134,6 @@ public class UmpConstant { public static final String ALL_LEDGER="all_ledger"; public static final String DELIMETER_MINUS = "-"; public static final String SCHEMA_PREFIX = "schema_"; - public static final String SCHEMA_RETRIEVAL_URL = "retrieval.schemaUrl"; - public static final String TASK_RETRIEVAL_URL = "retrieval.taskUrl"; + public static final String SCHEMA_RETRIEVAL_URL = "schema.retrieval.url"; + public static final String TASK_RETRIEVAL_URL = "task.retrieval.url"; } diff --git a/source/manager/manager-service/pom.xml b/source/manager/manager-service/pom.xml index 357b6b41..4ea9f334 100644 --- a/source/manager/manager-service/pom.xml +++ b/source/manager/manager-service/pom.xml @@ -5,7 +5,7 @@ manager com.jd.blockchain - 1.1.1-PACK20191209 + 1.1.2.RELEASE 4.0.0 diff --git a/source/manager/manager-web/pom.xml b/source/manager/manager-web/pom.xml index e646bbfb..0ec34f4a 100644 --- a/source/manager/manager-web/pom.xml +++ b/source/manager/manager-web/pom.xml @@ -5,7 +5,7 @@ manager com.jd.blockchain - 1.1.1-PACK20191209 + 1.1.2.RELEASE 4.0.0 diff --git a/source/manager/pom.xml b/source/manager/pom.xml index 587d5b41..a59378a9 100644 --- a/source/manager/pom.xml +++ b/source/manager/pom.xml @@ -11,7 +11,7 @@ com.jd.blockchain jdchain-root - 1.1.1-PACK20191209 + 1.1.2.RELEASE manager pom diff --git a/source/peer/pom.xml b/source/peer/pom.xml index bbc7a063..23a08185 100644 --- a/source/peer/pom.xml +++ b/source/peer/pom.xml @@ -5,7 +5,7 @@ com.jd.blockchain jdchain-root - 1.1.1-PACK20191209 + 1.1.2.RELEASE peer diff --git a/source/peer/src/main/java/com/jd/blockchain/peer/PeerServerBooter.java b/source/peer/src/main/java/com/jd/blockchain/peer/PeerServerBooter.java index 056753fe..b7892879 100644 --- a/source/peer/src/main/java/com/jd/blockchain/peer/PeerServerBooter.java +++ b/source/peer/src/main/java/com/jd/blockchain/peer/PeerServerBooter.java @@ -169,7 +169,9 @@ public class PeerServerBooter { app.addInitializers((ApplicationContextInitializer) applicationContext -> { ConfigurableListableBeanFactory beanFactory = applicationContext.getBeanFactory(); for (Object bean : externalBeans) { - beanFactory.registerSingleton(bean.toString(), bean); + if (bean != null) { + beanFactory.registerSingleton(bean.toString(), bean); + } } }); } diff --git a/source/peer/src/main/java/com/jd/blockchain/peer/consensus/ConsensusMessageDispatcher.java b/source/peer/src/main/java/com/jd/blockchain/peer/consensus/ConsensusMessageDispatcher.java index 7a3ba62f..6b8967f6 100644 --- a/source/peer/src/main/java/com/jd/blockchain/peer/consensus/ConsensusMessageDispatcher.java +++ b/source/peer/src/main/java/com/jd/blockchain/peer/consensus/ConsensusMessageDispatcher.java @@ -6,6 +6,8 @@ import com.jd.blockchain.ledger.OperationResult; import com.jd.blockchain.ledger.TransactionRequest; import com.jd.blockchain.ledger.TransactionResponse; import com.jd.blockchain.ledger.TransactionState; +import com.jd.blockchain.ledger.core.TransactionBatchProcessor; +import com.jd.blockchain.ledger.core.TransactionEngineImpl; import com.jd.blockchain.service.TransactionBatchProcess; import com.jd.blockchain.service.TransactionBatchResultHandle; import com.jd.blockchain.service.TransactionEngine; @@ -19,6 +21,7 @@ import com.jd.blockchain.consensus.service.MessageHandle; import com.jd.blockchain.consensus.service.StateSnapshot; import com.jd.blockchain.crypto.HashDigest; +import javax.swing.plaf.nimbus.State; import java.util.HashMap; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; @@ -61,6 +64,26 @@ public class ConsensusMessageDispatcher implements MessageHandle { return realmProcessor.newBatchId(); } + @Override + public StateSnapshot getStateSnapshot(String realmName) { + RealmProcessor realmProcessor = realmProcessorMap.get(realmName); + if (realmProcessor == null) { + throw new IllegalArgumentException("RealmName is not init!"); + } + + return realmProcessor.getStateSnapshot(); + + } + + @Override + public StateSnapshot getGenisStateSnapshot(String realmName) { + RealmProcessor realmProcessor = realmProcessorMap.get(realmName); + if (realmProcessor == null) { + throw new IllegalArgumentException("RealmName is not init!"); + } + return realmProcessor.getGenisStateSnapshot(); + } + @Override public AsyncFuture processOrdered(int messageId, byte[] message, String realmName, String batchId) { // TODO 要求messageId在同一个批次不重复,但目前暂不验证 @@ -191,6 +214,14 @@ public class ConsensusMessageDispatcher implements MessageHandle { return currBatchId; } + public StateSnapshot getStateSnapshot() { + return new BlockStateSnapshot(((TransactionBatchProcessor)getTxBatchProcess()).getPreLatestBlockHeight(), ((TransactionBatchProcessor)getTxBatchProcess()).getPrevLatestBlockHash()); + } + + public StateSnapshot getGenisStateSnapshot() { + return new BlockStateSnapshot(0, ((TransactionBatchProcessor)getTxBatchProcess()).getGenisBlockHash()); + } + public AsyncFuture schedule(TransactionRequest txRequest) { CompletableAsyncFuture asyncTxResult = new CompletableAsyncFuture<>(); TransactionResponse resp = getTxBatchProcess().schedule(txRequest); @@ -236,6 +267,7 @@ public class ConsensusMessageDispatcher implements MessageHandle { currBatchId = null; txResponseMap = null; txBatchProcess = null; + batchResultHandle =null; } finally { realmLock.unlock(); } @@ -244,10 +276,15 @@ public class ConsensusMessageDispatcher implements MessageHandle { public void rollback(int reasonCode) { realmLock.lock(); try { - batchResultHandle.cancel(TransactionState.valueOf((byte)reasonCode)); + if (batchResultHandle != null) { + batchResultHandle.cancel(TransactionState.valueOf((byte)reasonCode)); + } currBatchId = null; txResponseMap = null; txBatchProcess = null; + batchResultHandle = null; + ((TransactionEngineImpl) (txEngine)).freeBatch(ledgerHash); + ((TransactionEngineImpl) (txEngine)).resetNewBlockEditor(ledgerHash); } finally { realmLock.unlock(); } diff --git a/source/peer/src/main/java/com/jd/blockchain/peer/ledger/LedgerConfigurer.java b/source/peer/src/main/java/com/jd/blockchain/peer/ledger/LedgerConfigurer.java index f6c8bcb9..5c5c8b7e 100644 --- a/source/peer/src/main/java/com/jd/blockchain/peer/ledger/LedgerConfigurer.java +++ b/source/peer/src/main/java/com/jd/blockchain/peer/ledger/LedgerConfigurer.java @@ -1,5 +1,6 @@ package com.jd.blockchain.peer.ledger; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -12,6 +13,7 @@ import com.jd.blockchain.service.TransactionEngine; @Configuration public class LedgerConfigurer { + @ConditionalOnMissingBean @Bean public LedgerManager ledgerManager() { return new LedgerManager(); diff --git a/source/peer/src/main/java/com/jd/blockchain/peer/web/LedgerQueryController.java b/source/peer/src/main/java/com/jd/blockchain/peer/web/LedgerQueryController.java index 741594ce..41ce1458 100644 --- a/source/peer/src/main/java/com/jd/blockchain/peer/web/LedgerQueryController.java +++ b/source/peer/src/main/java/com/jd/blockchain/peer/web/LedgerQueryController.java @@ -3,7 +3,6 @@ package com.jd.blockchain.peer.web; import java.util.ArrayList; import java.util.List; -import com.jd.blockchain.ledger.*; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestBody; @@ -14,6 +13,22 @@ import org.springframework.web.bind.annotation.RestController; import com.jd.blockchain.contract.ContractException; import com.jd.blockchain.crypto.HashDigest; +import com.jd.blockchain.ledger.BlockchainIdentity; +import com.jd.blockchain.ledger.BytesValue; +import com.jd.blockchain.ledger.ContractInfo; +import com.jd.blockchain.ledger.KVDataVO; +import com.jd.blockchain.ledger.KVInfoVO; +import com.jd.blockchain.ledger.LedgerAdminInfo; +import com.jd.blockchain.ledger.LedgerBlock; +import com.jd.blockchain.ledger.LedgerInfo; +import com.jd.blockchain.ledger.LedgerMetadata; +import com.jd.blockchain.ledger.LedgerTransaction; +import com.jd.blockchain.ledger.ParticipantNode; +import com.jd.blockchain.ledger.TransactionState; +import com.jd.blockchain.ledger.TypedKVData; +import com.jd.blockchain.ledger.TypedKVEntry; +import com.jd.blockchain.ledger.TypedValue; +import com.jd.blockchain.ledger.UserInfo; import com.jd.blockchain.ledger.core.ContractAccountQuery; import com.jd.blockchain.ledger.core.DataAccount; import com.jd.blockchain.ledger.core.DataAccountQuery; @@ -23,7 +38,10 @@ import com.jd.blockchain.ledger.core.ParticipantCertData; import com.jd.blockchain.ledger.core.TransactionQuery; import com.jd.blockchain.ledger.core.UserAccountQuery; import com.jd.blockchain.transaction.BlockchainQueryService; +import com.jd.blockchain.utils.ArrayUtils; import com.jd.blockchain.utils.Bytes; +import com.jd.blockchain.utils.DataEntry; +import com.jd.blockchain.utils.DataIterator; import com.jd.blockchain.utils.QueryUtil; @RestController @@ -72,7 +90,7 @@ public class LedgerQueryController implements BlockchainQueryService { } return null; } - + @RequestMapping(method = RequestMethod.GET, path = "ledgers/{ledgerHash}/admininfo") @Override public LedgerAdminInfo getLedgerAdminInfo(@PathVariable(name = "ledgerHash") HashDigest ledgerHash) { @@ -326,18 +344,18 @@ public class LedgerQueryController implements BlockchainQueryService { @RequestMapping(method = RequestMethod.GET, path = "ledgers/{ledgerHash}/accounts/address/{address}") @Override - public AccountHeader getDataAccount(@PathVariable(name = "ledgerHash") HashDigest ledgerHash, + public BlockchainIdentity getDataAccount(@PathVariable(name = "ledgerHash") HashDigest ledgerHash, @PathVariable(name = "address") String address) { LedgerQuery ledger = ledgerService.getLedger(ledgerHash); LedgerBlock block = ledger.getLatestBlock(); DataAccountQuery dataAccountSet = ledger.getDataAccountSet(block); - return dataAccountSet.getAccount(Bytes.fromBase58(address)); + return dataAccountSet.getAccount(Bytes.fromBase58(address)).getID(); } @RequestMapping(method = { RequestMethod.GET, RequestMethod.POST }, path = "ledgers/{ledgerHash}/accounts/{address}/entries") @Override - public KVDataEntry[] getDataEntries(@PathVariable(name = "ledgerHash") HashDigest ledgerHash, + public TypedKVEntry[] getDataEntries(@PathVariable(name = "ledgerHash") HashDigest ledgerHash, @PathVariable(name = "address") String address, @RequestParam("keys") String... keys) { if (keys == null || keys.length == 0) { return null; @@ -347,15 +365,15 @@ public class LedgerQueryController implements BlockchainQueryService { DataAccountQuery dataAccountSet = ledger.getDataAccountSet(block); DataAccount dataAccount = dataAccountSet.getAccount(Bytes.fromBase58(address)); - KVDataEntry[] entries = new KVDataEntry[keys.length]; + TypedKVEntry[] entries = new TypedKVEntry[keys.length]; long ver; for (int i = 0; i < entries.length; i++) { - ver = dataAccount.getDataVersion(Bytes.fromString(keys[i])); + ver = dataAccount.getDataset().getVersion(keys[i]); if (ver < 0) { - entries[i] = new KVDataObject(keys[i], -1, null); + entries[i] = new TypedKVData(keys[i], -1, null); } else { - BytesValue value = dataAccount.getBytes(Bytes.fromString(keys[i]), ver); - entries[i] = new KVDataObject(keys[i], ver, value); + BytesValue value = dataAccount.getDataset().getValue(keys[i], ver); + entries[i] = new TypedKVData(keys[i], ver, value); } } @@ -365,7 +383,7 @@ public class LedgerQueryController implements BlockchainQueryService { @RequestMapping(method = { RequestMethod.GET, RequestMethod.POST }, path = "ledgers/{ledgerHash}/accounts/{address}/entries-version") @Override - public KVDataEntry[] getDataEntries(@PathVariable(name = "ledgerHash") HashDigest ledgerHash, + public TypedKVEntry[] getDataEntries(@PathVariable(name = "ledgerHash") HashDigest ledgerHash, @PathVariable(name = "address") String address, @RequestBody KVInfoVO kvInfoVO) { // parse kvInfoVO; List keyList = new ArrayList<>(); @@ -396,21 +414,21 @@ public class LedgerQueryController implements BlockchainQueryService { DataAccountQuery dataAccountSet = ledger.getDataAccountSet(block); DataAccount dataAccount = dataAccountSet.getAccount(Bytes.fromBase58(address)); - KVDataEntry[] entries = new KVDataEntry[keys.length]; + TypedKVEntry[] entries = new TypedKVEntry[keys.length]; long ver = -1; for (int i = 0; i < entries.length; i++) { // ver = dataAccount.getDataVersion(Bytes.fromString(keys[i])); ver = versions[i]; if (ver < 0) { - entries[i] = new KVDataObject(keys[i], -1, null); + entries[i] = new TypedKVData(keys[i], -1, null); } else { - if (dataAccount.getDataEntriesTotalCount() == 0 - || dataAccount.getBytes(Bytes.fromString(keys[i]), ver) == null) { + if (dataAccount.getDataset().getDataCount() == 0 + || dataAccount.getDataset().getValue(keys[i], ver) == null) { // is the address is not exist; the result is null; - entries[i] = new KVDataObject(keys[i], -1, null); + entries[i] = new TypedKVData(keys[i], -1, null); } else { - BytesValue value = dataAccount.getBytes(Bytes.fromString(keys[i]), ver); - entries[i] = new KVDataObject(keys[i], ver, value); + BytesValue value = dataAccount.getDataset().getValue(keys[i], ver); + entries[i] = new TypedKVData(keys[i], ver, value); } } } @@ -421,7 +439,7 @@ public class LedgerQueryController implements BlockchainQueryService { @RequestMapping(method = { RequestMethod.GET, RequestMethod.POST }, path = "ledgers/{ledgerHash}/accounts/address/{address}/entries") @Override - public KVDataEntry[] getDataEntries(@PathVariable(name = "ledgerHash") HashDigest ledgerHash, + public TypedKVEntry[] getDataEntries(@PathVariable(name = "ledgerHash") HashDigest ledgerHash, @PathVariable(name = "address") String address, @RequestParam(name = "fromIndex", required = false, defaultValue = "0") int fromIndex, @RequestParam(name = "count", required = false, defaultValue = "-1") int count) { @@ -431,27 +449,33 @@ public class LedgerQueryController implements BlockchainQueryService { DataAccountQuery dataAccountSet = ledger.getDataAccountSet(block); DataAccount dataAccount = dataAccountSet.getAccount(Bytes.fromBase58(address)); - int pages[] = QueryUtil.calFromIndexAndCount(fromIndex, count, (int) dataAccount.getDataEntriesTotalCount()); - return dataAccount.getDataEntries(pages[0], pages[1]); +// int pages[] = QueryUtil.calFromIndexAndCount(fromIndex, count, (int) dataAccount.getDataset().getDataCount()); +// return dataAccount.getDataEntries(pages[0], pages[1]); + + DataIterator iterator = dataAccount.getDataset().iterator(); + iterator.skip(fromIndex); + DataEntry[] dataEntries = iterator.next(count); + TypedKVEntry[] typedKVEntries = ArrayUtils.castTo(dataEntries, TypedKVEntry.class, + e -> e == null ? null : new TypedKVData(e.getKey(), e.getVersion(), e.getValue())); + return typedKVEntries; } @RequestMapping(method = RequestMethod.GET, path = "ledgers/{ledgerHash}/accounts/address/{address}/entries/count") @Override public long getDataEntriesTotalCount(@PathVariable(name = "ledgerHash") HashDigest ledgerHash, @PathVariable(name = "address") String address) { - LedgerQuery ledger = ledgerService.getLedger(ledgerHash); LedgerBlock block = ledger.getLatestBlock(); DataAccountQuery dataAccountSet = ledger.getDataAccountSet(block); DataAccount dataAccount = dataAccountSet.getAccount(Bytes.fromBase58(address)); - return dataAccount.getDataEntriesTotalCount(); + return dataAccount.getDataset().getDataCount(); } @RequestMapping(method = RequestMethod.GET, path = "ledgers/{ledgerHash}/contracts/address/{address}") @Override public ContractInfo getContract(@PathVariable(name = "ledgerHash") HashDigest ledgerHash, - @PathVariable(name = "address") String address) { + @PathVariable(name = "address") String address) { LedgerQuery ledger = ledgerService.getLedger(ledgerHash); LedgerBlock block = ledger.getLatestBlock(); ContractAccountQuery contractAccountSet = ledger.getContractAccountSet(block); @@ -468,7 +492,7 @@ public class LedgerQueryController implements BlockchainQueryService { */ @RequestMapping(method = RequestMethod.GET, path = "ledgers/{ledgerHash}/users") @Override - public AccountHeader[] getUsers(@PathVariable(name = "ledgerHash") HashDigest ledgerHash, + public BlockchainIdentity[] getUsers(@PathVariable(name = "ledgerHash") HashDigest ledgerHash, @RequestParam(name = "fromIndex", required = false, defaultValue = "0") int fromIndex, @RequestParam(name = "count", required = false, defaultValue = "-1") int count) { LedgerQuery ledger = ledgerService.getLedger(ledgerHash); @@ -488,7 +512,7 @@ public class LedgerQueryController implements BlockchainQueryService { */ @RequestMapping(method = RequestMethod.GET, path = "ledgers/{ledgerHash}/accounts") @Override - public AccountHeader[] getDataAccounts(@PathVariable(name = "ledgerHash") HashDigest ledgerHash, + public BlockchainIdentity[] getDataAccounts(@PathVariable(name = "ledgerHash") HashDigest ledgerHash, @RequestParam(name = "fromIndex", required = false, defaultValue = "0") int fromIndex, @RequestParam(name = "count", required = false, defaultValue = "-1") int count) { LedgerQuery ledger = ledgerService.getLedger(ledgerHash); @@ -500,7 +524,7 @@ public class LedgerQueryController implements BlockchainQueryService { @RequestMapping(method = RequestMethod.GET, path = "ledgers/{ledgerHash}/contracts") @Override - public AccountHeader[] getContractAccounts(@PathVariable(name = "ledgerHash") HashDigest ledgerHash, + public BlockchainIdentity[] getContractAccounts(@PathVariable(name = "ledgerHash") HashDigest ledgerHash, @RequestParam(name = "fromIndex", required = false, defaultValue = "0") int fromIndex, @RequestParam(name = "count", required = false, defaultValue = "-1") int count) { LedgerQuery ledger = ledgerService.getLedger(ledgerHash); diff --git a/source/pom.xml b/source/pom.xml index 8ef54310..ecc0e3ca 100644 --- a/source/pom.xml +++ b/source/pom.xml @@ -11,7 +11,7 @@ com.jd.blockchain jdchain-root - 1.1.1-PACK20191209 + 1.1.2.RELEASE pom jdchain @@ -35,9 +35,9 @@ - 0.3.0.RELEASE - 1.1.0.RELEASE - 1.1.0.RELEASE + 0.4.0.RELEASE + 1.1.2.RELEASE + 1.1.2.RELEASE 2.4 3.3.0 1.2.2 @@ -67,7 +67,7 @@ 3.3.6 3.0.1 2.9.0 - 5.15.10 + 6.3.6 3.4.6 3.5.12 3.5.3 @@ -515,7 +515,63 @@ -Xdoclint:none + + + + sonatype-oss-release + + + + org.apache.maven.plugins + maven-source-plugin + 2.1.2 + + + attach-sources + + jar-no-fork + + + + + + org.apache.maven.plugins + maven-javadoc-plugin + 2.7 + + + attach-javadocs + + jar + + + + + + org.apache.maven.plugins + maven-gpg-plugin + 1.1 + + + sign-artifacts + verify + + sign + + + + + + + + + + sonatype-nexus-staging + Nexus Release Repository + https://oss.sonatype.org/service/local/staging/deploy/maven2/ + + diff --git a/source/runtime/pom.xml b/source/runtime/pom.xml index e777b18a..e78338ce 100644 --- a/source/runtime/pom.xml +++ b/source/runtime/pom.xml @@ -5,7 +5,7 @@ com.jd.blockchain jdchain-root - 1.1.1-PACK20191209 + 1.1.2.RELEASE runtime pom diff --git a/source/runtime/runtime-context/pom.xml b/source/runtime/runtime-context/pom.xml index ce2465c5..33a72651 100644 --- a/source/runtime/runtime-context/pom.xml +++ b/source/runtime/runtime-context/pom.xml @@ -5,7 +5,7 @@ com.jd.blockchain runtime - 1.1.1-PACK20191209 + 1.1.2.RELEASE runtime-context diff --git a/source/runtime/runtime-modular-booter/pom.xml b/source/runtime/runtime-modular-booter/pom.xml index 38fc0a24..d641b32a 100644 --- a/source/runtime/runtime-modular-booter/pom.xml +++ b/source/runtime/runtime-modular-booter/pom.xml @@ -5,7 +5,7 @@ com.jd.blockchain runtime - 1.1.1-PACK20191209 + 1.1.2.RELEASE runtime-modular-booter \ No newline at end of file diff --git a/source/runtime/runtime-modular/pom.xml b/source/runtime/runtime-modular/pom.xml index 7c3a9ac0..fc54d0ef 100644 --- a/source/runtime/runtime-modular/pom.xml +++ b/source/runtime/runtime-modular/pom.xml @@ -5,7 +5,7 @@ com.jd.blockchain runtime - 1.1.1-PACK20191209 + 1.1.2.RELEASE runtime-modular diff --git a/source/sdk/pom.xml b/source/sdk/pom.xml index 137a8696..c4037224 100644 --- a/source/sdk/pom.xml +++ b/source/sdk/pom.xml @@ -4,7 +4,7 @@ com.jd.blockchain jdchain-root - 1.1.1-PACK20191209 + 1.1.2.RELEASE sdk pom diff --git a/source/sdk/sdk-base/pom.xml b/source/sdk/sdk-base/pom.xml index bb4ec273..6ce41769 100644 --- a/source/sdk/sdk-base/pom.xml +++ b/source/sdk/sdk-base/pom.xml @@ -4,7 +4,7 @@ com.jd.blockchain sdk - 1.1.1-PACK20191209 + 1.1.2.RELEASE sdk-base diff --git a/source/sdk/sdk-base/src/main/java/com/jd/blockchain/sdk/converters/ClientResolveUtil.java b/source/sdk/sdk-base/src/main/java/com/jd/blockchain/sdk/converters/ClientResolveUtil.java index e4aea5a0..46bb8d12 100644 --- a/source/sdk/sdk-base/src/main/java/com/jd/blockchain/sdk/converters/ClientResolveUtil.java +++ b/source/sdk/sdk-base/src/main/java/com/jd/blockchain/sdk/converters/ClientResolveUtil.java @@ -39,14 +39,14 @@ import com.jd.blockchain.utils.io.BytesUtils; public class ClientResolveUtil { - public static KVDataEntry[] read(KVDataEntry[] kvDataEntries) { + public static TypedKVEntry[] read(TypedKVEntry[] kvDataEntries) { if (kvDataEntries == null || kvDataEntries.length == 0) { return kvDataEntries; } - KVDataEntry[] resolveKvDataEntries = new KVDataEntry[kvDataEntries.length]; + TypedKVEntry[] resolveKvDataEntries = new TypedKVEntry[kvDataEntries.length]; // kvDataEntries是代理对象,需要处理 for (int i = 0; i < kvDataEntries.length; i++) { - KVDataEntry kvDataEntry = kvDataEntries[i]; + TypedKVEntry kvDataEntry = kvDataEntries[i]; String key = kvDataEntry.getKey(); long version = kvDataEntry.getVersion(); DataType dataType = kvDataEntry.getType(); @@ -108,7 +108,7 @@ public class ClientResolveUtil { public static Object readValueByBytesValue(BytesValue bytesValue) { DataType dataType = bytesValue.getType(); - Bytes saveVal = bytesValue.getValue(); + Bytes saveVal = bytesValue.getBytes(); Object showVal; switch (dataType) { case BYTES: @@ -147,11 +147,11 @@ public class ClientResolveUtil { long expectedVersion = currWriteSetObj.getLong("expectedVersion"); JSONObject valueObj = currWriteSetObj.getJSONObject("value"); String typeStr = valueObj.getString("type"); - // Base58Utils.decode(valueObj.getJSONObject("value").getString("value")) - String realValBase58 = valueObj.getJSONObject("value").getString("value"); + // Base58Utils.decode(valueObj.getJSONObject("bytes").getString("value")) + String realValBase58 = valueObj.getJSONObject("bytes").getString("value"); String key = currWriteSetObj.getString("key"); DataType dataType = DataType.valueOf(typeStr); - BytesValue bytesValue = BytesData.fromType(dataType, Base58Utils.decode(realValBase58)); + BytesValue bytesValue = TypedValue.fromType(dataType, Base58Utils.decode(realValBase58)); KVData kvData = new KVData(key, bytesValue, expectedVersion); kvOperation.set(kvData); } @@ -200,7 +200,7 @@ public class ClientResolveUtil { JSONObject pubKeyObj = currConsensusParticipant.getJSONObject("pubKey"); String pubKeyBase58 = pubKeyObj.getString("value"); // 生成ParticipantNode对象 - ParticipantCertData participantCertData = new ParticipantCertData(id, address, name, new PubKey(Bytes.fromBase58(pubKeyBase58).toBytes())); + ParticipantCertData participantCertData = new ParticipantCertData(id, address, name, new PubKey(Bytes.fromBase58(pubKeyBase58).toBytes()), null); participantNodes[i] = participantCertData; } ledgerInitSettingData.setConsensusParticipants(participantNodes); @@ -294,11 +294,12 @@ public class ClientResolveUtil { this.pubKey = participantNode.getPubKey(); } - public ParticipantCertData(int id, Bytes address, String name, PubKey pubKey) { + public ParticipantCertData(int id, Bytes address, String name, PubKey pubKey, ParticipantNodeState participantNodeState) { this.id = id; this.address = address; this.name = name; this.pubKey = pubKey; + this.participantNodeState = participantNodeState; } @@ -329,7 +330,7 @@ public class ClientResolveUtil { } - public static class KvData implements KVDataEntry { + public static class KvData implements TypedKVEntry { private String key; diff --git a/source/sdk/sdk-base/src/main/java/com/jd/blockchain/sdk/proxy/BlockchainServiceProxy.java b/source/sdk/sdk-base/src/main/java/com/jd/blockchain/sdk/proxy/BlockchainServiceProxy.java index ff1c9176..9984cef5 100644 --- a/source/sdk/sdk-base/src/main/java/com/jd/blockchain/sdk/proxy/BlockchainServiceProxy.java +++ b/source/sdk/sdk-base/src/main/java/com/jd/blockchain/sdk/proxy/BlockchainServiceProxy.java @@ -1,9 +1,9 @@ package com.jd.blockchain.sdk.proxy; import com.jd.blockchain.crypto.HashDigest; -import com.jd.blockchain.ledger.AccountHeader; +import com.jd.blockchain.ledger.BlockchainIdentity; import com.jd.blockchain.ledger.ContractInfo; -import com.jd.blockchain.ledger.KVDataEntry; +import com.jd.blockchain.ledger.TypedKVEntry; import com.jd.blockchain.ledger.KVInfoVO; import com.jd.blockchain.ledger.LedgerAdminInfo; import com.jd.blockchain.ledger.LedgerBlock; @@ -156,25 +156,25 @@ public abstract class BlockchainServiceProxy implements BlockchainService { } @Override - public AccountHeader getDataAccount(HashDigest ledgerHash, String address) { + public BlockchainIdentity getDataAccount(HashDigest ledgerHash, String address) { return getQueryService(ledgerHash).getDataAccount(ledgerHash, address); } @Override - public KVDataEntry[] getDataEntries(HashDigest ledgerHash, String address, String... keys) { - KVDataEntry[] kvDataEntries = getQueryService(ledgerHash).getDataEntries(ledgerHash, address, keys); + public TypedKVEntry[] getDataEntries(HashDigest ledgerHash, String address, String... keys) { + TypedKVEntry[] kvDataEntries = getQueryService(ledgerHash).getDataEntries(ledgerHash, address, keys); return ClientResolveUtil.read(kvDataEntries); } @Override - public KVDataEntry[] getDataEntries(HashDigest ledgerHash, String address, KVInfoVO kvInfoVO) { - KVDataEntry[] kvDataEntries = getQueryService(ledgerHash).getDataEntries(ledgerHash, address, kvInfoVO); + public TypedKVEntry[] getDataEntries(HashDigest ledgerHash, String address, KVInfoVO kvInfoVO) { + TypedKVEntry[] kvDataEntries = getQueryService(ledgerHash).getDataEntries(ledgerHash, address, kvInfoVO); return ClientResolveUtil.read(kvDataEntries); } @Override - public KVDataEntry[] getDataEntries(HashDigest ledgerHash, String address, int fromIndex, int count) { - KVDataEntry[] kvDataEntries = getQueryService(ledgerHash).getDataEntries(ledgerHash, address, fromIndex, count); + public TypedKVEntry[] getDataEntries(HashDigest ledgerHash, String address, int fromIndex, int count) { + TypedKVEntry[] kvDataEntries = getQueryService(ledgerHash).getDataEntries(ledgerHash, address, fromIndex, count); return ClientResolveUtil.read(kvDataEntries); } @@ -189,17 +189,17 @@ public abstract class BlockchainServiceProxy implements BlockchainService { } @Override - public AccountHeader[] getUsers(HashDigest ledgerHash, int fromIndex, int count) { + public BlockchainIdentity[] getUsers(HashDigest ledgerHash, int fromIndex, int count) { return getQueryService(ledgerHash).getUsers(ledgerHash, fromIndex, count); } @Override - public AccountHeader[] getDataAccounts(HashDigest ledgerHash, int fromIndex, int count) { + public BlockchainIdentity[] getDataAccounts(HashDigest ledgerHash, int fromIndex, int count) { return getQueryService(ledgerHash).getDataAccounts(ledgerHash, fromIndex, count); } @Override - public AccountHeader[] getContractAccounts(HashDigest ledgerHash, int fromIndex, int count) { + public BlockchainIdentity[] getContractAccounts(HashDigest ledgerHash, int fromIndex, int count) { return getQueryService(ledgerHash).getContractAccounts(ledgerHash, fromIndex, count); } } diff --git a/source/sdk/sdk-base/src/main/java/com/jd/blockchain/sdk/proxy/HttpBlockchainQueryService.java b/source/sdk/sdk-base/src/main/java/com/jd/blockchain/sdk/proxy/HttpBlockchainQueryService.java index ccd5ceec..d13fa436 100644 --- a/source/sdk/sdk-base/src/main/java/com/jd/blockchain/sdk/proxy/HttpBlockchainQueryService.java +++ b/source/sdk/sdk-base/src/main/java/com/jd/blockchain/sdk/proxy/HttpBlockchainQueryService.java @@ -487,7 +487,7 @@ public interface HttpBlockchainQueryService extends BlockchainExtendQueryService */ @HttpAction(method=HttpMethod.GET, path="ledgers/{ledgerHash}/accounts/address/{address}") @Override - AccountHeader getDataAccount(@PathParam(name="ledgerHash", converter=HashDigestToStringConverter.class) HashDigest ledgerHash, + BlockchainIdentity getDataAccount(@PathParam(name="ledgerHash", converter=HashDigestToStringConverter.class) HashDigest ledgerHash, @PathParam(name="address") String address); /** @@ -504,13 +504,13 @@ public interface HttpBlockchainQueryService extends BlockchainExtendQueryService */ @HttpAction(method=HttpMethod.POST, path="ledgers/{ledgerHash}/accounts/{address}/entries") @Override - KVDataEntry[] getDataEntries(@PathParam(name="ledgerHash", converter=HashDigestToStringConverter.class) HashDigest ledgerHash, + TypedKVEntry[] getDataEntries(@PathParam(name="ledgerHash", converter=HashDigestToStringConverter.class) HashDigest ledgerHash, @PathParam(name="address") String address, @RequestParam(name="keys", array = true) String... keys); @HttpAction(method=HttpMethod.POST, path="ledgers/{ledgerHash}/accounts/{address}/entries-version") @Override - KVDataEntry[] getDataEntries(@PathParam(name="ledgerHash", converter=HashDigestToStringConverter.class) HashDigest ledgerHash, + TypedKVEntry[] getDataEntries(@PathParam(name="ledgerHash", converter=HashDigestToStringConverter.class) HashDigest ledgerHash, @PathParam(name="address") String address, @RequestBody KVInfoVO kvInfoVO); @@ -531,7 +531,7 @@ public interface HttpBlockchainQueryService extends BlockchainExtendQueryService */ @HttpAction(method = HttpMethod.POST, path = "ledgers/{ledgerHash}/accounts/address/{address}/entries") @Override - KVDataEntry[] getDataEntries(@PathParam(name = "ledgerHash") HashDigest ledgerHash, + TypedKVEntry[] getDataEntries(@PathParam(name = "ledgerHash") HashDigest ledgerHash, @PathParam(name = "address") String address, @RequestParam(name = "fromIndex", required = false) int fromIndex, @RequestParam(name = "count", required = false) int count); @@ -569,7 +569,7 @@ public interface HttpBlockchainQueryService extends BlockchainExtendQueryService */ @HttpAction(method = HttpMethod.GET, path = "ledgers/{ledgerHash}/users") @Override - AccountHeader[] getUsers(@PathParam(name="ledgerHash", converter=HashDigestToStringConverter.class) HashDigest ledgerHash, + BlockchainIdentity[] getUsers(@PathParam(name="ledgerHash", converter=HashDigestToStringConverter.class) HashDigest ledgerHash, @RequestParam(name="fromIndex", required = false) int fromIndex, @RequestParam(name="count", required = false) int count); @@ -582,7 +582,7 @@ public interface HttpBlockchainQueryService extends BlockchainExtendQueryService */ @HttpAction(method = HttpMethod.GET, path = "ledgers/{ledgerHash}/accounts") @Override - AccountHeader[] getDataAccounts(@PathParam(name="ledgerHash", converter=HashDigestToStringConverter.class) HashDigest ledgerHash, + BlockchainIdentity[] getDataAccounts(@PathParam(name="ledgerHash", converter=HashDigestToStringConverter.class) HashDigest ledgerHash, @RequestParam(name="fromIndex", required = false) int fromIndex, @RequestParam(name="count", required = false) int count); @@ -595,7 +595,7 @@ public interface HttpBlockchainQueryService extends BlockchainExtendQueryService */ @HttpAction(method = HttpMethod.GET, path = "ledgers/{ledgerHash}/contracts") @Override - AccountHeader[] getContractAccounts(@PathParam(name="ledgerHash", converter=HashDigestToStringConverter.class) HashDigest ledgerHash, + BlockchainIdentity[] getContractAccounts(@PathParam(name="ledgerHash", converter=HashDigestToStringConverter.class) HashDigest ledgerHash, @RequestParam(name="fromIndex", required = false) int fromIndex, @RequestParam(name="count", required = false) int count); diff --git a/source/sdk/sdk-base/src/main/java/com/jd/blockchain/sdk/service/NodeSigningAppender.java b/source/sdk/sdk-base/src/main/java/com/jd/blockchain/sdk/service/NodeSigningAppender.java index 52f576e4..0014c28a 100644 --- a/source/sdk/sdk-base/src/main/java/com/jd/blockchain/sdk/service/NodeSigningAppender.java +++ b/source/sdk/sdk-base/src/main/java/com/jd/blockchain/sdk/service/NodeSigningAppender.java @@ -8,13 +8,10 @@ import com.jd.blockchain.crypto.AsymmetricKeypair; import com.jd.blockchain.crypto.Crypto; import com.jd.blockchain.crypto.HashDigest; import com.jd.blockchain.crypto.HashFunction; -import com.jd.blockchain.crypto.SignatureDigest; -import com.jd.blockchain.crypto.SignatureFunction; import com.jd.blockchain.ledger.DigitalSignature; import com.jd.blockchain.ledger.NodeRequest; import com.jd.blockchain.ledger.TransactionRequest; import com.jd.blockchain.ledger.TransactionResponse; -import com.jd.blockchain.transaction.DigitalSignatureBlob; import com.jd.blockchain.transaction.SignatureUtils; import com.jd.blockchain.transaction.TransactionService; import com.jd.blockchain.transaction.TxRequestMessage; diff --git a/source/sdk/sdk-client/pom.xml b/source/sdk/sdk-client/pom.xml index f92d6a67..e2e995f4 100644 --- a/source/sdk/sdk-client/pom.xml +++ b/source/sdk/sdk-client/pom.xml @@ -4,7 +4,7 @@ com.jd.blockchain sdk - 1.1.1-PACK20191209 + 1.1.2.RELEASE sdk-client diff --git a/source/sdk/sdk-client/src/main/java/com/jd/blockchain/sdk/client/GatewayServiceFactory.java b/source/sdk/sdk-client/src/main/java/com/jd/blockchain/sdk/client/GatewayServiceFactory.java index 79a329af..1d50d1d7 100644 --- a/source/sdk/sdk-client/src/main/java/com/jd/blockchain/sdk/client/GatewayServiceFactory.java +++ b/source/sdk/sdk-client/src/main/java/com/jd/blockchain/sdk/client/GatewayServiceFactory.java @@ -71,7 +71,6 @@ public class GatewayServiceFactory implements BlockchainServiceFactory, Closeabl ByteArrayObjectUtil.init(); } - protected GatewayServiceFactory(ServiceEndpoint gatewayEndpoint, BlockchainKeypair userKey) { httpConnectionManager = new ServiceConnectionManager(); this.userKey = userKey; @@ -80,7 +79,7 @@ public class GatewayServiceFactory implements BlockchainServiceFactory, Closeabl TransactionService txProcSrv = createConsensusService(gatewayEndpoint); this.blockchainService = new GatewayBlockchainServiceProxy(txProcSrv, queryService); } - + @Override public BlockchainService getBlockchainService() { return blockchainService; @@ -107,19 +106,49 @@ public class GatewayServiceFactory implements BlockchainServiceFactory, Closeabl // factory.setMaxConnections(100); // return factory; // } - + + /** + * 连接网关节点; + * + * @param gatewayAddress 网关节点的网络地址; + * @return 网关服务工厂的实例; + */ public static GatewayServiceFactory connect(NetworkAddress gatewayAddress) { return connect(gatewayAddress.getHost(), gatewayAddress.getPort(), gatewayAddress.isSecure(), null); } + /** + * 网关服务工厂的实例; + * + * @param gatewayAddress 网关节点的网络地址; + * @param userKey 自动交易签名的用户密钥;可选参数,如果不为 null,则在提交交易时,自动以参数指定的密钥签署交易; + * @return 网关服务工厂的实例; + */ public static GatewayServiceFactory connect(NetworkAddress gatewayAddress, BlockchainKeypair userKey) { return connect(gatewayAddress.getHost(), gatewayAddress.getPort(), gatewayAddress.isSecure(), userKey); } - + + /** + * 连接网关节点; + * + * @param gatewayHost 网关节点的地址; + * @param gatewayPort 网关节点的端口; + * @param secure 是否采用安全的通讯协议(HTTPS); + * @return 网关服务工厂的实例; + */ public static GatewayServiceFactory connect(String gatewayHost, int gatewayPort, boolean secure) { return connect(gatewayHost, gatewayPort, secure, null); } + /** + * 连接网关节点; + * + * @param gatewayHost 网关节点的地址; + * @param gatewayPort 网关节点的端口; + * @param secure 是否采用安全的通讯协议(HTTPS); + * @param userKey 自动交易签名的用户密钥;可选参数,如果不为 null,则在提交交易时,自动以参数指定的密钥签署交易; + * @return 网关服务工厂的实例; + */ public static GatewayServiceFactory connect(String gatewayHost, int gatewayPort, boolean secure, BlockchainKeypair userKey) { // if (userKey == null) { @@ -128,8 +157,8 @@ public class GatewayServiceFactory implements BlockchainServiceFactory, Closeabl ServiceEndpoint gatewayEndpoint = new ServiceEndpoint(gatewayHost, gatewayPort, secure); GatewayServiceFactory factory = new GatewayServiceFactory(gatewayEndpoint, userKey); factory.setMaxConnections(100); - //TODO: 未实现网关对用户的认证; - //TODO: 未实现加载不同账本的密码算法配置; + // TODO: 未实现网关对用户的认证; + // TODO: 未实现加载不同账本的密码算法配置; return factory; } @@ -171,7 +200,7 @@ public class GatewayServiceFactory implements BlockchainServiceFactory, Closeabl @Override public TransactionResponse process(TransactionRequest txRequest) { TxRequestMessage reqMsg = (TxRequestMessage) txRequest; - //TODO: 未实现按不同的账本的密码参数配置,采用不同的哈希算法和签名算法; + // TODO: 未实现按不同的账本的密码参数配置,采用不同的哈希算法和签名算法; if (!reqMsg.containsEndpointSignature(userKey.getAddress())) { // TODO: 优化上下文对此 TransactionContent 的多次序列化带来的额外性能开销; DigitalSignature signature = SignatureUtils.sign(txRequest.getTransactionContent(), userKey); diff --git a/source/sdk/sdk-samples/pom.xml b/source/sdk/sdk-samples/pom.xml index 5bbecd22..ece0c958 100644 --- a/source/sdk/sdk-samples/pom.xml +++ b/source/sdk/sdk-samples/pom.xml @@ -5,7 +5,7 @@ com.jd.blockchain sdk - 1.1.1-PACK20191209 + 1.1.2.RELEASE sdk-samples diff --git a/source/sdk/sdk-samples/src/main/java/com/jd/blockchain/contract/samples/AssetContractImpl.java b/source/sdk/sdk-samples/src/main/java/com/jd/blockchain/contract/samples/AssetContractImpl.java index d662378d..1782d985 100644 --- a/source/sdk/sdk-samples/src/main/java/com/jd/blockchain/contract/samples/AssetContractImpl.java +++ b/source/sdk/sdk-samples/src/main/java/com/jd/blockchain/contract/samples/AssetContractImpl.java @@ -9,8 +9,8 @@ import com.jd.blockchain.contract.ContractException; import com.jd.blockchain.contract.EventProcessingAware; import com.jd.blockchain.crypto.HashDigest; import com.jd.blockchain.ledger.BlockchainIdentity; -import com.jd.blockchain.ledger.KVDataEntry; -import com.jd.blockchain.ledger.KVDataObject; +import com.jd.blockchain.ledger.TypedKVEntry; +import com.jd.blockchain.ledger.TypedKVData; import com.jd.blockchain.utils.Bytes; /** @@ -47,16 +47,16 @@ public class AssetContractImpl implements EventProcessingAware, AssetContract { } // 查询当前值; - KVDataEntry[] kvEntries = eventContext.getLedger().getDataEntries(currentLedgerHash(), ASSET_ADDRESS, KEY_TOTAL, + TypedKVEntry[] kvEntries = eventContext.getLedger().getDataEntries(currentLedgerHash(), ASSET_ADDRESS, KEY_TOTAL, assetHolderAddress); // 计算资产的发行总数; - KVDataObject currTotal = (KVDataObject) kvEntries[0]; + TypedKVData currTotal = (TypedKVData) kvEntries[0]; long newTotal = currTotal.longValue() + amount; eventContext.getLedger().dataAccount(ASSET_ADDRESS).setInt64(KEY_TOTAL, newTotal, currTotal.getVersion()); // 分配到持有者账户; - KVDataObject holderAmount = (KVDataObject) kvEntries[1]; + TypedKVData holderAmount = (TypedKVData) kvEntries[1]; long newHodlerAmount = holderAmount.longValue() + amount; eventContext.getLedger().dataAccount(ASSET_ADDRESS) .setInt64(assetHolderAddress, newHodlerAmount, holderAmount.getVersion()).setText("K2", "info2", -1) @@ -77,10 +77,10 @@ public class AssetContractImpl implements EventProcessingAware, AssetContract { checkSignerPermission(fromAddress); // 查询现有的余额; - KVDataEntry[] origBalances = eventContext.getLedger().getDataEntries(currentLedgerHash(), ASSET_ADDRESS, + TypedKVEntry[] origBalances = eventContext.getLedger().getDataEntries(currentLedgerHash(), ASSET_ADDRESS, fromAddress, toAddress); - KVDataEntry fromBalanceKV = origBalances[0]; - KVDataEntry toBalanceKV = origBalances[1]; + TypedKVEntry fromBalanceKV = origBalances[0]; + TypedKVEntry toBalanceKV = origBalances[1]; long fromBalance = fromBalanceKV.getVersion() == -1 ? 0 : (long) fromBalanceKV.getValue(); long toBalance = toBalanceKV.getVersion() == -1 ? 0 : (long) toBalanceKV.getValue(); diff --git a/source/sdk/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDKDemo_Query.java b/source/sdk/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDKDemo_Query.java index 3205fd73..a3e44d95 100644 --- a/source/sdk/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDKDemo_Query.java +++ b/source/sdk/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDKDemo_Query.java @@ -4,7 +4,7 @@ import com.jd.blockchain.crypto.Crypto; import com.jd.blockchain.crypto.HashDigest; import com.jd.blockchain.ledger.BlockchainKeyGenerator; import com.jd.blockchain.ledger.BlockchainKeypair; -import com.jd.blockchain.ledger.KVDataEntry; +import com.jd.blockchain.ledger.TypedKVEntry; import com.jd.blockchain.ledger.LedgerBlock; import com.jd.blockchain.ledger.LedgerTransaction; import com.jd.blockchain.ledger.Transaction; @@ -67,7 +67,7 @@ public class SDKDemo_Query { // 获取数据; String commerceAccount = "GGhhreGeasdfasfUUfehf9932lkae99ds66jf=="; String[] objKeys = new String[] { "x001", "x002" }; - KVDataEntry[] kvData = service.getDataEntries(LEDGER_HASH, commerceAccount, objKeys); + TypedKVEntry[] kvData = service.getDataEntries(LEDGER_HASH, commerceAccount, objKeys); long payloadVersion = kvData[0].getVersion(); diff --git a/source/sdk/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDK_Contract_Demo.java b/source/sdk/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDK_Contract_Demo.java index 9d43b199..caae0d6d 100644 --- a/source/sdk/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDK_Contract_Demo.java +++ b/source/sdk/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDK_Contract_Demo.java @@ -6,7 +6,7 @@ import static com.jd.blockchain.transaction.ContractReturnValue.decode; import com.jd.blockchain.contract.TransferContract; import com.jd.blockchain.ledger.BlockchainKeyGenerator; import com.jd.blockchain.ledger.BlockchainKeypair; -import com.jd.blockchain.ledger.KVDataEntry; +import com.jd.blockchain.ledger.TypedKVEntry; import com.jd.blockchain.ledger.PreparedTransaction; import com.jd.blockchain.ledger.TransactionResponse; import com.jd.blockchain.ledger.TransactionTemplate; @@ -106,11 +106,11 @@ public class SDK_Contract_Demo extends SDK_Base_Demo { } private long readByKvOperation(String address, String account) { - KVDataEntry[] kvDataEntries = blockchainService.getDataEntries(ledgerHash, address, account); + TypedKVEntry[] kvDataEntries = blockchainService.getDataEntries(ledgerHash, address, account); if (kvDataEntries == null || kvDataEntries.length == 0) { throw new IllegalStateException(String.format("Ledger %s Service inner Error !!!", ledgerHash.toBase58())); } - KVDataEntry kvDataEntry = kvDataEntries[0]; + TypedKVEntry kvDataEntry = kvDataEntries[0]; if (kvDataEntry.getVersion() == -1) { return 0L; } diff --git a/source/sdk/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDK_Contract_Random_Demo.java b/source/sdk/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDK_Contract_Random_Demo.java index c73a7f91..868f3269 100644 --- a/source/sdk/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDK_Contract_Random_Demo.java +++ b/source/sdk/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDK_Contract_Random_Demo.java @@ -79,11 +79,11 @@ public class SDK_Contract_Random_Demo extends SDK_Base_Demo { } private long readByKvOperation(String address, String account) { - KVDataEntry[] kvDataEntries = blockchainService.getDataEntries(ledgerHash, address, account); + TypedKVEntry[] kvDataEntries = blockchainService.getDataEntries(ledgerHash, address, account); if (kvDataEntries == null || kvDataEntries.length == 0) { throw new IllegalStateException(String.format("Ledger %s Service inner Error !!!", ledgerHash.toBase58())); } - KVDataEntry kvDataEntry = kvDataEntries[0]; + TypedKVEntry kvDataEntry = kvDataEntries[0]; if (kvDataEntry.getVersion() == -1) { return 0L; } diff --git a/source/sdk/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDK_InsertData_Demo.java b/source/sdk/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDK_InsertData_Demo.java index 3a89c7a6..d90b5233 100644 --- a/source/sdk/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDK_InsertData_Demo.java +++ b/source/sdk/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDK_InsertData_Demo.java @@ -107,9 +107,9 @@ public class SDK_InsertData_Demo extends SDK_Base_Demo { // KVDataEntry[] kvData = blockchainService.getDataEntries(ledgerHash, commerceAccount, objKeys); // 获取数据账户下所有的KV列表 - KVDataEntry[] kvData = blockchainService.getDataEntries(ledgerHash, commerceAccount, 0, 100); + TypedKVEntry[] kvData = blockchainService.getDataEntries(ledgerHash, commerceAccount, 0, 100); if (kvData != null && kvData.length > 0) { - for (KVDataEntry kvDatum : kvData) { + for (TypedKVEntry kvDatum : kvData) { System.out.println("kvData.key=" + kvDatum.getKey()); System.out.println("kvData.version=" + kvDatum.getVersion()); System.out.println("kvData.type=" + kvDatum.getType()); diff --git a/source/sdk/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_GateWay_Query_Test_.java b/source/sdk/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_GateWay_Query_Test_.java index 3851d6a7..3d291811 100644 --- a/source/sdk/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_GateWay_Query_Test_.java +++ b/source/sdk/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_GateWay_Query_Test_.java @@ -19,12 +19,12 @@ import com.jd.blockchain.crypto.HashFunction; import com.jd.blockchain.crypto.PubKey; import com.jd.blockchain.crypto.SignatureDigest; import com.jd.blockchain.crypto.SignatureFunction; -import com.jd.blockchain.ledger.AccountHeader; +import com.jd.blockchain.ledger.BlockchainIdentity; import com.jd.blockchain.ledger.BlockchainKeyGenerator; import com.jd.blockchain.ledger.BlockchainKeypair; import com.jd.blockchain.ledger.DigitalSignature; import com.jd.blockchain.ledger.EndpointRequest; -import com.jd.blockchain.ledger.KVDataEntry; +import com.jd.blockchain.ledger.TypedKVEntry; import com.jd.blockchain.ledger.LedgerBlock; import com.jd.blockchain.ledger.LedgerInfo; import com.jd.blockchain.ledger.LedgerTransaction; @@ -98,7 +98,7 @@ public class SDK_GateWay_Query_Test_ { System.out.println("contractCount=" + count); count = service.getContractCount(ledgerHash, hashDigest); System.out.println("contractCount=" + count); - AccountHeader contract = service.getContract(ledgerHash, "12345678"); + BlockchainIdentity contract = service.getContract(ledgerHash, "12345678"); System.out.println(contract); LedgerBlock block = service.getBlock(ledgerHash, hashDigest); @@ -109,7 +109,7 @@ public class SDK_GateWay_Query_Test_ { count = service.getDataAccountCount(ledgerHash, hashDigest); System.out.println("dataAccountCount=" + count); - AccountHeader dataAccount = service.getDataAccount(ledgerHash, "1245633"); + BlockchainIdentity dataAccount = service.getDataAccount(ledgerHash, "1245633"); System.out.println(dataAccount.getAddress()); count = service.getTransactionCount(ledgerHash, hashDigest); @@ -149,8 +149,8 @@ public class SDK_GateWay_Query_Test_ { String commerceAccount = "GGhhreGeasdfasfUUfehf9932lkae99ds66jf=="; String[] objKeys = new String[] { "x001", "x002" }; - KVDataEntry[] kvData = service.getDataEntries(ledgerHash, commerceAccount, objKeys); - for (KVDataEntry kvDatum : kvData) { + TypedKVEntry[] kvData = service.getDataEntries(ledgerHash, commerceAccount, objKeys); + for (TypedKVEntry kvDatum : kvData) { System.out.println("kvData.key=" + kvDatum.getKey()); System.out.println("kvData.version=" + kvDatum.getVersion()); System.out.println("kvData.value=" + kvDatum.getValue()); diff --git a/source/storage/pom.xml b/source/storage/pom.xml index 14576a85..7e432edd 100644 --- a/source/storage/pom.xml +++ b/source/storage/pom.xml @@ -3,7 +3,7 @@ com.jd.blockchain jdchain-root - 1.1.1-PACK20191209 + 1.1.2.RELEASE storage pom diff --git a/source/storage/storage-composite/pom.xml b/source/storage/storage-composite/pom.xml index e46b466c..176a447e 100644 --- a/source/storage/storage-composite/pom.xml +++ b/source/storage/storage-composite/pom.xml @@ -4,7 +4,7 @@ com.jd.blockchain storage - 1.1.1-PACK20191209 + 1.1.2.RELEASE storage-composite @@ -56,7 +56,7 @@ \ No newline at end of file diff --git a/source/storage/storage-rocksdb/src/main/java/com/jd/blockchain/storage/service/impl/rocksdb/RocksDBConnectionFactory.java b/source/storage/storage-rocksdb/src/main/java/com/jd/blockchain/storage/service/impl/rocksdb/RocksDBConnectionFactory.java index 46165c47..eb5b09f2 100644 --- a/source/storage/storage-rocksdb/src/main/java/com/jd/blockchain/storage/service/impl/rocksdb/RocksDBConnectionFactory.java +++ b/source/storage/storage-rocksdb/src/main/java/com/jd/blockchain/storage/service/impl/rocksdb/RocksDBConnectionFactory.java @@ -26,7 +26,7 @@ public class RocksDBConnectionFactory implements DbConnectionFactory { public static final String URI_SCHEME = "rocksdb"; public static final Pattern URI_PATTER = Pattern - .compile("^\\w+\\://(/)?\\w+(/.*)*$"); + .compile("^\\w+\\://(/)?\\w+(\\:)?([/\\\\].*)*$"); private Map connections = new ConcurrentHashMap<>(); @@ -40,7 +40,7 @@ public class RocksDBConnectionFactory implements DbConnectionFactory { if (!URI_PATTER.matcher(dbConnectionString).matches()) { throw new IllegalArgumentException("Illegal format of rocksdb connection string!"); } - URI dbUri = URI.create(dbConnectionString); + URI dbUri = URI.create(dbConnectionString.replace("\\", "/")); if (!support(dbUri.getScheme())) { throw new IllegalArgumentException( String.format("Not supported db connection string with scheme \"%s\"!", dbUri.getScheme())); @@ -49,9 +49,6 @@ public class RocksDBConnectionFactory implements DbConnectionFactory { String uriHead = dbPrefix(); int beginIndex = dbConnectionString.indexOf(uriHead); String dbPath = dbConnectionString.substring(beginIndex + uriHead.length()); - if (!dbPath.startsWith(File.separator)) { - dbPath = File.separator + dbPath; - } RocksDBConnection conn = connections.get(dbPath); if (conn != null) { diff --git a/source/storage/storage-rocksdb/src/main/java/com/jd/blockchain/storage/service/impl/rocksdb/RocksDBVersioningStorage.java b/source/storage/storage-rocksdb/src/main/java/com/jd/blockchain/storage/service/impl/rocksdb/RocksDBVersioningStorage.java index 978fd8c5..98c47325 100644 --- a/source/storage/storage-rocksdb/src/main/java/com/jd/blockchain/storage/service/impl/rocksdb/RocksDBVersioningStorage.java +++ b/source/storage/storage-rocksdb/src/main/java/com/jd/blockchain/storage/service/impl/rocksdb/RocksDBVersioningStorage.java @@ -7,9 +7,9 @@ import java.util.concurrent.locks.ReentrantLock; import org.apache.commons.collections4.map.LRUMap; import org.rocksdb.*; -import com.jd.blockchain.storage.service.VersioningKVEntry; import com.jd.blockchain.storage.service.VersioningKVStorage; import com.jd.blockchain.utils.Bytes; +import com.jd.blockchain.utils.DataEntry; import com.jd.blockchain.utils.io.BytesUtils; /** @@ -127,7 +127,7 @@ public class RocksDBVersioningStorage implements VersioningKVStorage { } @Override - public VersioningKVEntry getEntry(Bytes key, long version) { + public DataEntry getEntry(Bytes key, long version) { byte[] value = get(key, version); if (value == null) { return null; @@ -226,7 +226,7 @@ public class RocksDBVersioningStorage implements VersioningKVStorage { } } - private static class VersioningKVData implements VersioningKVEntry { + private static class VersioningKVData implements DataEntry { private Bytes key; diff --git a/source/storage/storage-rocksdb/src/test/java/test/com/jd/blockchain/storage/service/impl/rocksdb/RocksDBStorageTest.java b/source/storage/storage-rocksdb/src/test/java/test/com/jd/blockchain/storage/service/impl/rocksdb/RocksDBStorageTest.java index c930d961..d33b809f 100644 --- a/source/storage/storage-rocksdb/src/test/java/test/com/jd/blockchain/storage/service/impl/rocksdb/RocksDBStorageTest.java +++ b/source/storage/storage-rocksdb/src/test/java/test/com/jd/blockchain/storage/service/impl/rocksdb/RocksDBStorageTest.java @@ -1,5 +1,6 @@ package test.com.jd.blockchain.storage.service.impl.rocksdb; +import static com.jd.blockchain.storage.service.impl.rocksdb.RocksDBConnectionFactory.URI_PATTER; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; @@ -7,6 +8,8 @@ import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import java.io.File; +import java.util.HashMap; +import java.util.Map; import org.junit.Test; @@ -133,4 +136,18 @@ public class RocksDBStorageTest { return dbURI; } + @Test + // test rocksDB uri patter + public void testRocksDBUriPatter() { + Map cases = new HashMap<>(); + cases.put("rocksdb:///home/peer0/rocksdb", true); + cases.put("rocksdb://D:\\home\\rocksdb", true); + cases.put("rocksdb://\\home\\rocksdb", false); + cases.put("rocksdb://:\\home\\rocksdb", false); + cases.put("rocksdb://D:\\home\\", true); + cases.put("rocksdb:///home/peer0/", true); + for(Map.Entry entity : cases.entrySet()) { + assertEquals(URI_PATTER.matcher(entity.getKey()).matches(), entity.getValue()); + } + } } diff --git a/source/storage/storage-service/pom.xml b/source/storage/storage-service/pom.xml index cf17ec5d..5e50de10 100644 --- a/source/storage/storage-service/pom.xml +++ b/source/storage/storage-service/pom.xml @@ -5,7 +5,7 @@ com.jd.blockchain storage - 1.1.1-PACK20191209 + 1.1.2.RELEASE storage-service diff --git a/source/storage/storage-service/src/main/java/com/jd/blockchain/storage/service/VersioningKVEntry.java b/source/storage/storage-service/src/main/java/com/jd/blockchain/storage/service/VersioningKVEntry.java deleted file mode 100644 index a18f6740..00000000 --- a/source/storage/storage-service/src/main/java/com/jd/blockchain/storage/service/VersioningKVEntry.java +++ /dev/null @@ -1,20 +0,0 @@ -package com.jd.blockchain.storage.service; - -import com.jd.blockchain.utils.Bytes; - -/** - * 版本化的键值数据项; - * - * @author huanghaiquan - * - */ -public interface VersioningKVEntry { - -// String getKey(); - Bytes getKey(); - - long getVersion(); - - byte[] getValue(); - -} \ No newline at end of file diff --git a/source/storage/storage-service/src/main/java/com/jd/blockchain/storage/service/VersioningKVStorage.java b/source/storage/storage-service/src/main/java/com/jd/blockchain/storage/service/VersioningKVStorage.java index 711606d3..980cc32c 100644 --- a/source/storage/storage-service/src/main/java/com/jd/blockchain/storage/service/VersioningKVStorage.java +++ b/source/storage/storage-service/src/main/java/com/jd/blockchain/storage/service/VersioningKVStorage.java @@ -1,6 +1,7 @@ package com.jd.blockchain.storage.service; import com.jd.blockchain.utils.Bytes; +import com.jd.blockchain.utils.DataEntry; /** * Versioning Key-Value Storage @@ -40,7 +41,7 @@ public interface VersioningKVStorage extends BatchStorageService { * @param version * @return */ - VersioningKVEntry getEntry(Bytes key, long version); + DataEntry getEntry(Bytes key, long version); /** * Return the specified verson's value;
diff --git a/source/storage/storage-service/src/main/java/com/jd/blockchain/storage/service/utils/BufferedKVStorage.java b/source/storage/storage-service/src/main/java/com/jd/blockchain/storage/service/utils/BufferedKVStorage.java index 7b292248..b038a87e 100644 --- a/source/storage/storage-service/src/main/java/com/jd/blockchain/storage/service/utils/BufferedKVStorage.java +++ b/source/storage/storage-service/src/main/java/com/jd/blockchain/storage/service/utils/BufferedKVStorage.java @@ -7,10 +7,10 @@ import java.util.concurrent.ForkJoinTask; import java.util.concurrent.RecursiveTask; import com.jd.blockchain.storage.service.ExPolicyKVStorage; -import com.jd.blockchain.storage.service.VersioningKVEntry; import com.jd.blockchain.storage.service.VersioningKVStorage; import com.jd.blockchain.utils.Bytes; import com.jd.blockchain.utils.Transactional; +import com.jd.blockchain.utils.DataEntry; /** * {@link BufferedKVStorage} 缓冲写入的KV存储;
@@ -77,9 +77,9 @@ public class BufferedKVStorage implements VersioningKVStorage, ExPolicyKVStorage } return ws.getLatestVersion(); } - + @Override - public VersioningKVEntry getEntry(Bytes key, long version) { + public DataEntry getEntry(Bytes key, long version) { VersioningWritingSet ws = versioningCache.get(key); if (ws == null) { return origVersioningStorage.getEntry(key, version); @@ -484,7 +484,7 @@ public class BufferedKVStorage implements VersioningKVStorage, ExPolicyKVStorage return startingVersion; } - public VersioningKVEntry getEntry(long version) { + public DataEntry getEntry(long version) { byte[] value = get(version); if (value == null) { return null; @@ -505,7 +505,7 @@ public class BufferedKVStorage implements VersioningKVStorage, ExPolicyKVStorage } } - private static class VersioningKVData implements VersioningKVEntry { + private static class VersioningKVData implements DataEntry { private Bytes key; diff --git a/source/storage/storage-service/src/main/java/com/jd/blockchain/storage/service/utils/MemoryKVStorage.java b/source/storage/storage-service/src/main/java/com/jd/blockchain/storage/service/utils/MemoryKVStorage.java index 0c2192a3..a0f36c0d 100644 --- a/source/storage/storage-service/src/main/java/com/jd/blockchain/storage/service/utils/MemoryKVStorage.java +++ b/source/storage/storage-service/src/main/java/com/jd/blockchain/storage/service/utils/MemoryKVStorage.java @@ -5,9 +5,9 @@ import java.util.Set; import com.jd.blockchain.storage.service.ExPolicyKVStorage; import com.jd.blockchain.storage.service.KVStorageService; -import com.jd.blockchain.storage.service.VersioningKVEntry; import com.jd.blockchain.storage.service.VersioningKVStorage; import com.jd.blockchain.utils.Bytes; +import com.jd.blockchain.utils.DataEntry; import com.jd.blockchain.utils.io.BytesMap; public class MemoryKVStorage implements ExPolicyKVStorage, VersioningKVStorage, KVStorageService, BytesMap { @@ -21,7 +21,7 @@ public class MemoryKVStorage implements ExPolicyKVStorage, VersioningKVStorage, } @Override - public VersioningKVEntry getEntry(Bytes key, long version) { + public DataEntry getEntry(Bytes key, long version) { return verStorage.getEntry(key, version); } diff --git a/source/storage/storage-service/src/main/java/com/jd/blockchain/storage/service/utils/VersioningKVData.java b/source/storage/storage-service/src/main/java/com/jd/blockchain/storage/service/utils/VersioningKVData.java index 684c75fe..73816055 100644 --- a/source/storage/storage-service/src/main/java/com/jd/blockchain/storage/service/utils/VersioningKVData.java +++ b/source/storage/storage-service/src/main/java/com/jd/blockchain/storage/service/utils/VersioningKVData.java @@ -1,24 +1,23 @@ package com.jd.blockchain.storage.service.utils; -import com.jd.blockchain.storage.service.VersioningKVEntry; -import com.jd.blockchain.utils.Bytes; +import com.jd.blockchain.utils.DataEntry; -public class VersioningKVData implements VersioningKVEntry { +public class VersioningKVData implements DataEntry { - private Bytes key; + private K key; private long version; - private byte[] value; + private V value; - public VersioningKVData(Bytes key, long version, byte[] value) { + public VersioningKVData(K key, long version, V value) { this.key = key; this.version = version; this.value = value; } @Override - public Bytes getKey() { + public K getKey() { return key; } @@ -28,7 +27,7 @@ public class VersioningKVData implements VersioningKVEntry { } @Override - public byte[] getValue() { + public V getValue() { return value; } diff --git a/source/storage/storage-service/src/main/java/com/jd/blockchain/storage/service/utils/VersioningKVStorageMap.java b/source/storage/storage-service/src/main/java/com/jd/blockchain/storage/service/utils/VersioningKVStorageMap.java index 3c4855e3..1c6b8def 100644 --- a/source/storage/storage-service/src/main/java/com/jd/blockchain/storage/service/utils/VersioningKVStorageMap.java +++ b/source/storage/storage-service/src/main/java/com/jd/blockchain/storage/service/utils/VersioningKVStorageMap.java @@ -5,9 +5,9 @@ import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; -import com.jd.blockchain.storage.service.VersioningKVEntry; import com.jd.blockchain.storage.service.VersioningKVStorage; import com.jd.blockchain.utils.Bytes; +import com.jd.blockchain.utils.DataEntry; import com.jd.blockchain.utils.io.BytesMap; public class VersioningKVStorageMap implements VersioningKVStorage, BytesMap { @@ -42,7 +42,7 @@ public class VersioningKVStorageMap implements VersioningKVStorage, BytesMap com.jd.blockchain jdchain-root - 1.1.1-PACK20191209 + 1.1.2.RELEASE test pom diff --git a/source/test/test-consensus-client/pom.xml b/source/test/test-consensus-client/pom.xml index 0b2e086e..78bc7c75 100644 --- a/source/test/test-consensus-client/pom.xml +++ b/source/test/test-consensus-client/pom.xml @@ -5,7 +5,7 @@ com.jd.blockchain test - 1.1.1-PACK20191209 + 1.1.2.RELEASE test-consensus-client diff --git a/source/test/test-consensus-node/pom.xml b/source/test/test-consensus-node/pom.xml index a5ee769f..af98ce14 100644 --- a/source/test/test-consensus-node/pom.xml +++ b/source/test/test-consensus-node/pom.xml @@ -5,7 +5,7 @@ com.jd.blockchain test - 1.1.1-PACK20191209 + 1.1.2.RELEASE test-consensus-node @@ -38,7 +38,7 @@ com.jd.blockchain consensus-bftsmart - 1.1.1-PACK20191209 + 1.1.2.RELEASE org.springframework.boot diff --git a/source/test/test-integration/pom.xml b/source/test/test-integration/pom.xml index 8a1fde17..3f0b7650 100644 --- a/source/test/test-integration/pom.xml +++ b/source/test/test-integration/pom.xml @@ -5,7 +5,7 @@ com.jd.blockchain test - 1.1.1-PACK20191209 + 1.1.2.RELEASE test-integration @@ -58,6 +58,11 @@ ${project.version} + + org.mockito + mockito-core + + diff --git a/source/test/test-integration/src/main/java/test/com/jd/blockchain/intgr/IntegratedContext.java b/source/test/test-integration/src/main/java/test/com/jd/blockchain/intgr/IntegratedContext.java index 7a3bed53..f77158bd 100644 --- a/source/test/test-integration/src/main/java/test/com/jd/blockchain/intgr/IntegratedContext.java +++ b/source/test/test-integration/src/main/java/test/com/jd/blockchain/intgr/IntegratedContext.java @@ -6,12 +6,16 @@ import java.util.Map; import com.jd.blockchain.consensus.ConsensusSettings; import com.jd.blockchain.crypto.AsymmetricKeypair; +import com.jd.blockchain.crypto.HashDigest; import com.jd.blockchain.ledger.core.LedgerManager; +import com.jd.blockchain.storage.service.DbConnectionFactory; import com.jd.blockchain.storage.service.impl.composite.CompositeConnectionFactory; import com.jd.blockchain.tools.initializer.LedgerBindingConfig; public class IntegratedContext { + private HashDigest ledgerHash; + private Map nodes = new HashMap<>(); public int[] getNodeIds() { @@ -25,6 +29,14 @@ public class IntegratedContext { return ids; } + public HashDigest getLedgerHash() { + return ledgerHash; + } + + public void setLedgerHash(HashDigest ledgerHash) { + this.ledgerHash = ledgerHash; + } + public Node getNode(int id) { return nodes.get(id); } @@ -44,7 +56,7 @@ public class IntegratedContext { private LedgerManager ledgerManager; - private CompositeConnectionFactory storageDB; + private DbConnectionFactory storageDB; private LedgerBindingConfig bindingConfig; @@ -60,7 +72,7 @@ public class IntegratedContext { return ledgerManager; } - public CompositeConnectionFactory getStorageDB() { + public DbConnectionFactory getStorageDB() { return storageDB; } @@ -84,7 +96,7 @@ public class IntegratedContext { this.ledgerManager = ledgerManager; } - public void setStorageDB(CompositeConnectionFactory storageDB) { + public void setStorageDB(DbConnectionFactory storageDB) { this.storageDB = storageDB; } diff --git a/source/test/test-integration/src/main/java/test/com/jd/blockchain/intgr/IntegrationTest.java b/source/test/test-integration/src/main/java/test/com/jd/blockchain/intgr/IntegrationTest.java index 70ca67b7..8324af7c 100644 --- a/source/test/test-integration/src/main/java/test/com/jd/blockchain/intgr/IntegrationTest.java +++ b/source/test/test-integration/src/main/java/test/com/jd/blockchain/intgr/IntegrationTest.java @@ -7,7 +7,21 @@ import java.io.InputStream; import java.util.Properties; import java.util.Random; import java.util.concurrent.CountDownLatch; - +import java.util.concurrent.atomic.AtomicBoolean; + +import com.jd.blockchain.consensus.bftsmart.BftsmartConsensusProvider; +import com.jd.blockchain.consensus.bftsmart.service.BftsmartNodeServer; +import com.jd.blockchain.consensus.bftsmart.service.BftsmartServerSettings; +import com.jd.blockchain.consensus.service.*; +import com.jd.blockchain.ledger.*; +import com.jd.blockchain.ledger.core.*; +import com.jd.blockchain.peer.consensus.ConsensusMessageDispatcher; +import com.jd.blockchain.peer.consensus.LedgerStateManager; +import com.jd.blockchain.storage.service.impl.composite.CompositeConnectionFactory; +import com.jd.blockchain.utils.concurrent.ThreadInvoker; +import org.mockito.Mockito; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.stubbing.Answer; import org.springframework.core.io.ClassPathResource; import com.jd.blockchain.consensus.ConsensusProvider; @@ -21,24 +35,6 @@ import com.jd.blockchain.crypto.KeyGenUtils; import com.jd.blockchain.crypto.PrivKey; import com.jd.blockchain.crypto.PubKey; import com.jd.blockchain.gateway.GatewayConfigProperties.KeyPairConfig; -import com.jd.blockchain.ledger.AccountHeader; -import com.jd.blockchain.ledger.BlockchainKeyGenerator; -import com.jd.blockchain.ledger.BlockchainKeypair; -import com.jd.blockchain.ledger.BytesValue; -import com.jd.blockchain.ledger.DataAccountKVSetOperation; -import com.jd.blockchain.ledger.KVDataEntry; -import com.jd.blockchain.ledger.LedgerBlock; -import com.jd.blockchain.ledger.LedgerInfo; -import com.jd.blockchain.ledger.LedgerInitProperties; -import com.jd.blockchain.ledger.ParticipantNode; -import com.jd.blockchain.ledger.PreparedTransaction; -import com.jd.blockchain.ledger.TransactionResponse; -import com.jd.blockchain.ledger.TransactionTemplate; -import com.jd.blockchain.ledger.UserInfo; -import com.jd.blockchain.ledger.core.DataAccountQuery; -import com.jd.blockchain.ledger.core.LedgerManage; -import com.jd.blockchain.ledger.core.LedgerManager; -import com.jd.blockchain.ledger.core.LedgerQuery; import com.jd.blockchain.sdk.BlockchainService; import com.jd.blockchain.sdk.client.GatewayServiceFactory; import com.jd.blockchain.storage.service.KVStorageService; @@ -54,6 +50,9 @@ import test.com.jd.blockchain.intgr.IntegratedContext.Node; import test.com.jd.blockchain.intgr.perf.LedgerInitializeWebTest; import test.com.jd.blockchain.intgr.perf.Utils; +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.doAnswer; + public class IntegrationTest { // 合约测试使用的初始化数据; BlockchainKeypair contractDataKey = BlockchainKeyGenerator.getInstance().generate(); @@ -73,37 +72,52 @@ public class IntegrationTest { private static String memDbConnString = LedgerInitConsensusConfig.memConnectionStrings[0]; - // private static final MQConnectionConfig mqConnConfig = new - // MQConnectionConfig(); - // static { - // mqConnConfig.setServer(MQ_SERVER); - // mqConnConfig.setTopic(MQ_TOPIC); - // } + private static AtomicBoolean isTestTurnOn = new AtomicBoolean(false); + + public static final String PASSWORD = "abc"; + + public static final String PUB_KEYS = "3snPdw7i7Pb3B5AxpSXy6YVruvftugNQ7rB7k2KWukhBwKQhFBFagT"; + public static final String PRIV_KEYS = "177gjtSgSdUF3LwRFGhzbpZZxmXXChsnwbuuLCG1V9KYfVuuxLwXGmZCp5FGUvsenhwBQLV"; + public static void main_(String[] args) { // init ledgers of all nodes ; IntegratedContext context = initLedgers(); + Node node0 = context.getNode(0); Node node1 = context.getNode(1); Node node2 = context.getNode(2); Node node3 = context.getNode(3); + LedgerManager ledgerManagerMock0 = Mockito.spy(node0.getLedgerManager()); + LedgerManager ledgerManagerMock1 = Mockito.spy(node1.getLedgerManager()); + LedgerManager ledgerManagerMock2 = Mockito.spy(node2.getLedgerManager()); + LedgerManager ledgerManagerMock3 = Mockito.spy(node3.getLedgerManager()); + + node0.setLedgerManager(ledgerManagerMock0); + node1.setLedgerManager(ledgerManagerMock1); + node2.setLedgerManager(ledgerManagerMock2); + node3.setLedgerManager(ledgerManagerMock3); + + //todo +// mockNodeServer(context); + NetworkAddress peerSrvAddr0 = new NetworkAddress("127.0.0.1", 10200); - PeerTestRunner peer0 = new PeerTestRunner(peerSrvAddr0, node0.getBindingConfig(), node0.getStorageDB()); + PeerTestRunner peer0 = new PeerTestRunner(peerSrvAddr0, node0.getBindingConfig(), node0.getStorageDB(), node0.getLedgerManager()); NetworkAddress peerSrvAddr1 = new NetworkAddress("127.0.0.1", 10210); - PeerTestRunner peer1 = new PeerTestRunner(peerSrvAddr1, node1.getBindingConfig(), node1.getStorageDB()); + PeerTestRunner peer1 = new PeerTestRunner(peerSrvAddr1, node1.getBindingConfig(), node1.getStorageDB(), node1.getLedgerManager()); NetworkAddress peerSrvAddr2 = new NetworkAddress("127.0.0.1", 10220); - PeerTestRunner peer2 = new PeerTestRunner(peerSrvAddr2, node2.getBindingConfig(), node2.getStorageDB()); + PeerTestRunner peer2 = new PeerTestRunner(peerSrvAddr2, node2.getBindingConfig(), node2.getStorageDB(), node2.getLedgerManager()); NetworkAddress peerSrvAddr3 = new NetworkAddress("127.0.0.1", 10230); - PeerTestRunner peer3 = new PeerTestRunner(peerSrvAddr3, node3.getBindingConfig(), node3.getStorageDB()); + PeerTestRunner peer3 = new PeerTestRunner(peerSrvAddr3, node3.getBindingConfig(), node3.getStorageDB(), node3.getLedgerManager()); - AsyncCallback peerStarting0 = peer0.start(); - AsyncCallback peerStarting1 = peer1.start(); - AsyncCallback peerStarting2 = peer2.start(); - AsyncCallback peerStarting3 = peer3.start(); + ThreadInvoker.AsyncCallback peerStarting0 = peer0.start(); + ThreadInvoker.AsyncCallback peerStarting1 = peer1.start(); + ThreadInvoker.AsyncCallback peerStarting2 = peer2.start(); + ThreadInvoker.AsyncCallback peerStarting3 = peer3.start(); peerStarting0.waitReturn(); peerStarting1.waitReturn(); @@ -116,38 +130,96 @@ public class IntegrationTest { gwkey0.setPubKeyValue(LedgerInitializeWebTest.PUB_KEYS[0]); gwkey0.setPrivKeyValue(LedgerInitializeWebTest.PRIV_KEYS[0]); gwkey0.setPrivKeyPassword(encodedBase58Pwd); - // GatewayTestRunner gateway0 = new GatewayTestRunner("127.0.0.1", 10300, - // gwkey0, peerSrvAddr0); - GatewayTestRunner gateway0 = new GatewayTestRunner("127.0.0.1", 10300, gwkey0, peerSrvAddr0); - // KeyPairConfig gwkey1 = new KeyPairConfig(); - // gwkey1.setPubKeyValue(LedgerInitializeWebTest.PUB_KEYS[1]); - // gwkey1.setPrivKeyValue(LedgerInitializeWebTest.PRIV_KEYS[1]); - // gwkey1.setPrivKeyPassword(encodedBase58Pwd); - // GatewayTestRunner gateway1 = new GatewayTestRunner("127.0.0.1", 10310, - // gwkey1, peerSrvAddr1); + GatewayTestRunner gateway0 = new GatewayTestRunner("127.0.0.1", 10300, gwkey0, peerSrvAddr0, LedgerInitConsensusConfig.bftsmartProvider, null); - AsyncCallback gwStarting0 = gateway0.start(); - // AsyncCallback gwStarting1 = gateway1.start(); + ThreadInvoker.AsyncCallback gwStarting0 = gateway0.start(); gwStarting0.waitReturn(); - // gwStarting1.waitReturn(); // 执行测试用例之前,校验每个节点的一致性; - // testConsistencyAmongNodes(context); +// testConsistencyAmongNodes(context); + + testStorageErrorBlockRollbackSdk(gateway0, context); + + testConsensusFirstTimeoutSdk(gateway0, context); + + testConsensusSecondTimeoutSdk(gateway0, context); + + //todo +// testBlockHashInconsistentSdk(gateway0, context); + + testTransactionRollbackSdk(gateway0, context); + + testInvalidUserSignerSdk(gateway0, context); testSDK(gateway0, context); + System.out.println("------IntegrationTest Ok--------"); + // 执行测试用例之后,校验每个节点的一致性; - // testConsistencyAmongNodes(context); +// testConsistencyAmongNodes(context); } + //todo +// private static void mockNodeServer(IntegratedContext context) { +// +// Bytes nodeAddress0 = AddressEncoding.generateAddress(context.getNode(0).getPartiKeyPair().getPubKey()); +// Bytes nodeAddress1 = AddressEncoding.generateAddress(context.getNode(1).getPartiKeyPair().getPubKey()); +// Bytes nodeAddress2 = AddressEncoding.generateAddress(context.getNode(2).getPartiKeyPair().getPubKey()); +// Bytes nodeAddress3 = AddressEncoding.generateAddress(context.getNode(3).getPartiKeyPair().getPubKey()); +// +// BftsmartConsensusProvider bftsmartProvider0 = new BftsmartConsensusProvider(); +// BftsmartConsensusProvider mockedBftsmartProvider0 = Mockito.spy(bftsmartProvider0); +// +// BftsmartConsensusProvider bftsmartProvider1 = new BftsmartConsensusProvider(); +// BftsmartConsensusProvider mockedBftsmartProvider1 = Mockito.spy(bftsmartProvider1); +// +// BftsmartConsensusProvider bftsmartProvider2 = new BftsmartConsensusProvider(); +// BftsmartConsensusProvider mockedBftsmartProvider2 = Mockito.spy(bftsmartProvider2); +// +// BftsmartConsensusProvider bftsmartProvider3 = new BftsmartConsensusProvider(); +// BftsmartConsensusProvider mockedBftsmartProvider3 = Mockito.spy(bftsmartProvider3); +// +// doAnswer(new Answer() { +// @Override +// public BftsmartNodeServer answer(InvocationOnMock invocation) throws Throwable { +// BftsmartServerSettings serverSettings =(BftsmartServerSettings) invocation.getArguments()[0]; +// +// MessageHandle messageHandle = new ConsensusMessageDispatcher(); +// // mock spy messageHandle +// MessageHandle mockedMessageHandle = Mockito.spy(messageHandle); +// +// StateMachineReplicate stateMachineReplicate = new LedgerStateManager(); +// +// if(nodeAddress0.equals(serverSettings.getReplicaSettings().getAddress())){ +// doAnswer(new Answer() { +// @Override +// public Object answer(InvocationOnMock invocation) throws Throwable { +// +// if (isTestTurnOn.get()) { +// Random random = new Random(); +// byte[] msg = new byte[4]; +// random.nextBytes(msg); +// invocation.getArguments()[0] = msg; +// } +// return invocation.callRealMethod(); +// } +// }).when(mockedMessageHandle).processOrdered(any(), any(), any(), any()); +// } +// +// return new BftsmartNodeServer(serverSettings, mockedMessageHandle, stateMachineReplicate); +// } +// }).when(mockedBftsmartProvider0).getServerFactory().setupServer(any(), any(), any()); +// +// ConsensusProviders.registerProvider(mockedBftsmartProvider0); +// } /** * 检查所有节点之间的账本是否一致; * * @param context */ - private void testConsistencyAmongNodes(IntegratedContext context) { + private static void testConsistencyAmongNodes(IntegratedContext context) { int[] ids = context.getNodeIds(); Node[] nodes = new Node[ids.length]; LedgerQuery[] ledgers = new LedgerQuery[ids.length]; @@ -164,6 +236,180 @@ public class IntegrationTest { } } + private static void testConsensusFirstTimeoutSdk(GatewayTestRunner gateway, IntegratedContext context) { + + AtomicBoolean isTestTurnOn = new AtomicBoolean(true); + + Node node0 = context.getNode(0); + Node node1 = context.getNode(1); + + LedgerManager ledgerManagerMock0 = node0.getLedgerManager(); + LedgerManager ledgerManagerMock1 = node1.getLedgerManager(); + + doAnswer(new Answer() { + @Override + public LedgerRepository answer(InvocationOnMock invocation) throws Throwable { + if (isTestTurnOn.get()) { + Thread.sleep(5000); + } + return (LedgerRepository)invocation.callRealMethod(); + } + }).when(ledgerManagerMock0).getLedger(any()); + + doAnswer(new Answer() { + @Override + public LedgerRepository answer(InvocationOnMock invocation) throws Throwable { + if (isTestTurnOn.get()) { + Thread.sleep(5000); + } + return (LedgerRepository)invocation.callRealMethod(); + } + }).when(ledgerManagerMock1).getLedger(any()); + + testSDK(gateway, context); + + isTestTurnOn.set(false); + } + + private static void testConsensusSecondTimeoutSdk(GatewayTestRunner gateway, IntegratedContext context) { + AtomicBoolean isTestTurnOn = new AtomicBoolean(true); + + Node node0 = context.getNode(0); + Node node1 = context.getNode(1); + + LedgerManager ledgerManagerMock0 = node0.getLedgerManager(); + LedgerManager ledgerManagerMock1 = node1.getLedgerManager(); + + doAnswer(new Answer() { + @Override + public LedgerRepository answer(InvocationOnMock invocation) throws Throwable { + if (isTestTurnOn.get()) { + Thread.sleep(10000); + } + return (LedgerRepository)invocation.callRealMethod(); + } + }).when(ledgerManagerMock0).getLedger(any()); + + doAnswer(new Answer() { + @Override + public LedgerRepository answer(InvocationOnMock invocation) throws Throwable { + if (isTestTurnOn.get()) { + Thread.sleep(10000); + } + return (LedgerRepository)invocation.callRealMethod(); + } + }).when(ledgerManagerMock1).getLedger(any()); + + testSDK(gateway, context); + + isTestTurnOn.set(false); + } + + //todo +// private static void testBlockHashInconsistentSdk(GatewayTestRunner gateway, IntegratedContext context) { +// isTestTurnOn.set(true); +// testSDK(gateway, context); +// isTestTurnOn.set(false); +// +// } + + private static void testStorageErrorBlockRollbackSdk(GatewayTestRunner gateway, IntegratedContext context) { + + ((TestDbFactory)context.getNode(0).getStorageDB()).setErrorSetTurnOn(true); + ((TestDbFactory)context.getNode(1).getStorageDB()).setErrorSetTurnOn(true); + ((TestDbFactory)context.getNode(2).getStorageDB()).setErrorSetTurnOn(true); + ((TestDbFactory)context.getNode(3).getStorageDB()).setErrorSetTurnOn(true); + + testSDK(gateway, context); + + ((TestDbFactory)context.getNode(0).getStorageDB()).setErrorSetTurnOn(false); + ((TestDbFactory)context.getNode(1).getStorageDB()).setErrorSetTurnOn(false); + ((TestDbFactory)context.getNode(2).getStorageDB()).setErrorSetTurnOn(false); + ((TestDbFactory)context.getNode(3).getStorageDB()).setErrorSetTurnOn(false); + + } + + private static void testTransactionRollbackSdk(GatewayTestRunner gateway, IntegratedContext context) { + + // 连接网关; + GatewayServiceFactory gwsrvFact = GatewayServiceFactory.connect(gateway.getServiceAddress()); + BlockchainService bcsrv = gwsrvFact.getBlockchainService(); + + HashDigest[] ledgerHashs = bcsrv.getLedgerHashs(); + + AsymmetricKeypair adminKey = context.getNode(0).getPartiKeyPair(); + + // 注册用户,并验证最终写入; + BlockchainKeypair dataAccount = BlockchainKeyGenerator.getInstance().generate(); + + // 定义交易; + TransactionTemplate txTpl = bcsrv.newTransaction(ledgerHashs[0]); + txTpl.dataAccounts().register(dataAccount.getIdentity()); + + String dataKey = "jd_code"; + String dataVal = "www.jd.com"; + + // Construct error kv version + txTpl.dataAccount(dataAccount.getAddress()).setText(dataKey, dataVal, 1); + + PreparedTransaction prepTx = txTpl.prepare(); + + prepTx.sign(adminKey); + + // 提交并等待共识返回; + TransactionResponse txResp = prepTx.commit(); + + // 验证结果; + Node node0 = context.getNode(0); + LedgerManage ledgerManager = new LedgerManager(); + + KVStorageService storageService = node0.getStorageDB().connect(memDbConnString).getStorageService(); + + LedgerQuery ledgerOfNode0 = ledgerManager.register(ledgerHashs[0], storageService); + + + } + + private static void testInvalidUserSignerSdk(GatewayTestRunner gateway, IntegratedContext context) { + // 连接网关; + GatewayServiceFactory gwsrvFact = GatewayServiceFactory.connect(gateway.getServiceAddress()); + BlockchainService bcsrv = gwsrvFact.getBlockchainService(); + + HashDigest[] ledgerHashs = bcsrv.getLedgerHashs(); + + //Invalid signer + PrivKey privKey = KeyGenUtils.decodePrivKeyWithRawPassword(PRIV_KEYS, PASSWORD); + PubKey pubKey = KeyGenUtils.decodePubKey(PUB_KEYS); + + AsymmetricKeypair asymmetricKeypair = new AsymmetricKeypair(pubKey, privKey); + + // 注册用户,并验证最终写入; + BlockchainKeypair user = BlockchainKeyGenerator.getInstance().generate(); + + // 定义交易; + TransactionTemplate txTpl = bcsrv.newTransaction(ledgerHashs[0]); + txTpl.users().register(user.getIdentity()); + + // 签名; + PreparedTransaction ptx = txTpl.prepare(); + + HashDigest transactionHash = ptx.getHash(); + + ptx.sign(asymmetricKeypair); + + // 提交并等待共识返回; + TransactionResponse txResp = ptx.commit(); + + // 验证结果; + Node node0 = context.getNode(0); + LedgerManage ledgerManager = new LedgerManager(); + + KVStorageService storageService = node0.getStorageDB().connect(memDbConnString).getStorageService(); + + LedgerQuery ledgerOfNode0 = ledgerManager.register(ledgerHashs[0], storageService); + + } + private static void testSDK(GatewayTestRunner gateway, IntegratedContext context) { // 连接网关; GatewayServiceFactory gwsrvFact = GatewayServiceFactory.connect(gateway.getServiceAddress()); @@ -216,8 +462,8 @@ public class IntegrationTest { ledgerOfNode0.retrieveLatestBlock(); // 更新内存 // 先验证应答 - KVDataEntry[] kvDataEntries = blockchainService.getDataEntries(ledgerHash, dataAccountAddress, dataKey); - for (KVDataEntry kvDataEntry : kvDataEntries) { + TypedKVEntry[] kvDataEntries = blockchainService.getDataEntries(ledgerHash, dataAccountAddress, dataKey); + for (TypedKVEntry kvDataEntry : kvDataEntries) { String valHexText = (String) kvDataEntry.getValue(); byte[] valBytes = HexUtils.decode(valHexText); String valText = new String(valBytes); @@ -420,22 +666,22 @@ public class IntegrationTest { UserInfo userInfo = blockchainService.getUser(ledgerHash, userAddress.toString()); // getDataAccount - AccountHeader accountHeader = blockchainService.getDataAccount(ledgerHash, dataAddress.toString()); + BlockchainIdentity accountHeader = blockchainService.getDataAccount(ledgerHash, dataAddress.toString()); // getDataEntries return; } - public static ConsensusProvider getConsensusProvider() { - return ConsensusProviders.getProvider("com.jd.blockchain.consensus.bftsmart.BftsmartConsensusProvider"); + public static ConsensusProvider getConsensusProvider(String providerName) { + return ConsensusProviders.getProvider(providerName); } private static IntegratedContext initLedgers() { Prompter consolePrompter = new PresetAnswerPrompter("N"); // new ConsolePrompter(); LedgerInitProperties initSetting = loadInitSetting_integration(); - Properties props = LedgerInitializeWebTest.loadConsensusSetting(); - ConsensusProvider csProvider = getConsensusProvider(); + Properties props = LedgerInitializeWebTest.loadConsensusSetting(LedgerInitConsensusConfig.bftsmartConfig.getConfigPath()); + ConsensusProvider csProvider = getConsensusProvider(LedgerInitConsensusConfig.bftsmartConfig.getProvider()); ConsensusSettings csProps = csProvider.getSettingsFactory() .getConsensusSettingsBuilder() .createSettings(props, Utils.loadParticipantNodes()); @@ -465,29 +711,39 @@ public class IntegrationTest { CountDownLatch quitLatch = new CountDownLatch(4); + TestDbFactory dbFactory0 = new TestDbFactory(new CompositeConnectionFactory()); + dbFactory0.setErrorSetTurnOn(false); DBConnectionConfig testDb0 = new DBConnectionConfig(); testDb0.setConnectionUri("memory://local/0"); LedgerBindingConfig bindingConfig0 = new LedgerBindingConfig(); AsyncCallback callback0 = nodeCtx0.startInitCommand(privkey0, encodedPassword, initSetting, csProps, - csProvider, testDb0, consolePrompter, bindingConfig0, quitLatch); + csProvider, testDb0, consolePrompter, bindingConfig0, quitLatch, dbFactory0); + + TestDbFactory dbFactory1 = new TestDbFactory(new CompositeConnectionFactory()); + dbFactory1.setErrorSetTurnOn(false); DBConnectionConfig testDb1 = new DBConnectionConfig(); testDb1.setConnectionUri("memory://local/1"); LedgerBindingConfig bindingConfig1 = new LedgerBindingConfig(); AsyncCallback callback1 = nodeCtx1.startInitCommand(privkey1, encodedPassword, initSetting, csProps, - csProvider, testDb1, consolePrompter, bindingConfig1, quitLatch); + csProvider, testDb1, consolePrompter, bindingConfig1, quitLatch, dbFactory1); + + TestDbFactory dbFactory2 = new TestDbFactory(new CompositeConnectionFactory()); + dbFactory2.setErrorSetTurnOn(false); DBConnectionConfig testDb2 = new DBConnectionConfig(); testDb2.setConnectionUri("memory://local/2"); LedgerBindingConfig bindingConfig2 = new LedgerBindingConfig(); AsyncCallback callback2 = nodeCtx2.startInitCommand(privkey2, encodedPassword, initSetting, csProps, - csProvider, testDb2, consolePrompter, bindingConfig2, quitLatch); + csProvider, testDb2, consolePrompter, bindingConfig2, quitLatch, dbFactory2); + TestDbFactory dbFactory3 = new TestDbFactory(new CompositeConnectionFactory()); + dbFactory3.setErrorSetTurnOn(false); DBConnectionConfig testDb3 = new DBConnectionConfig(); testDb3.setConnectionUri("memory://local/3"); LedgerBindingConfig bindingConfig3 = new LedgerBindingConfig(); AsyncCallback callback3 = nodeCtx3.startInitCommand(privkey3, encodedPassword, initSetting, csProps, - csProvider, testDb3, consolePrompter, bindingConfig3, quitLatch); + csProvider, testDb3, consolePrompter, bindingConfig3, quitLatch, dbFactory3); HashDigest ledgerHash0 = callback0.waitReturn(); HashDigest ledgerHash1 = callback1.waitReturn(); @@ -501,6 +757,8 @@ public class IntegrationTest { IntegratedContext context = new IntegratedContext(); + context.setLedgerHash(ledgerHash0); + Node node0 = new Node(0); node0.setConsensusSettings(csProps); node0.setLedgerManager(nodeCtx0.getLedgerManager()); @@ -542,7 +800,7 @@ public class IntegrationTest { } public static LedgerInitProperties loadInitSetting_integration() { - ClassPathResource ledgerInitSettingResource = new ClassPathResource("ledger_init_test_integration.init"); + ClassPathResource ledgerInitSettingResource = new ClassPathResource("ledger_init_test_web2.init"); try (InputStream in = ledgerInitSettingResource.getInputStream()) { LedgerInitProperties setting = LedgerInitProperties.resolve(in); return setting; @@ -660,9 +918,9 @@ public class IntegrationTest { LedgerQuery ledgerOfNode0 = node0.getLedgerManager().getLedger(ledgerHash); LedgerBlock block = ledgerOfNode0.getBlock(txResp.getBlockHeight()); BytesValue val1InDb = ledgerOfNode0.getDataAccountSet(block).getAccount(contractDataKey.getAddress()) - .getBytes("A"); + .getDataset().getValue("A"); BytesValue val2InDb = ledgerOfNode0.getDataAccountSet(block).getAccount(contractDataKey.getAddress()) - .getBytes(KEY_TOTAL); + .getDataset().getValue(KEY_TOTAL); } /** diff --git a/source/test/test-integration/src/main/java/test/com/jd/blockchain/intgr/PeerTestRunner.java b/source/test/test-integration/src/main/java/test/com/jd/blockchain/intgr/PeerTestRunner.java index c2c552ed..0a0722f0 100644 --- a/source/test/test-integration/src/main/java/test/com/jd/blockchain/intgr/PeerTestRunner.java +++ b/source/test/test-integration/src/main/java/test/com/jd/blockchain/intgr/PeerTestRunner.java @@ -1,5 +1,6 @@ package test.com.jd.blockchain.intgr; +import com.jd.blockchain.ledger.core.LedgerManager; import com.jd.blockchain.peer.PeerServerBooter; import com.jd.blockchain.storage.service.DbConnectionFactory; import com.jd.blockchain.tools.initializer.LedgerBindingConfig; @@ -28,18 +29,18 @@ public class PeerTestRunner { } public PeerTestRunner(NetworkAddress serviceAddress, LedgerBindingConfig ledgerBindingConfig) { - this(serviceAddress, ledgerBindingConfig, null); + this(serviceAddress, ledgerBindingConfig, null, null); } public PeerTestRunner(NetworkAddress serviceAddress, LedgerBindingConfig ledgerBindingConfig, - DbConnectionFactory dbConnectionFactory) { + DbConnectionFactory dbConnectionFactory, LedgerManager ledgerManager) { this.serviceAddress = serviceAddress; this.ledgerBindingConfig = ledgerBindingConfig; if (dbConnectionFactory == null) { this.peerServer = new PeerServerBooter(ledgerBindingConfig, serviceAddress.getHost(), serviceAddress.getPort(),null); }else { this.peerServer = new PeerServerBooter(ledgerBindingConfig, serviceAddress.getHost(), serviceAddress.getPort(),null, - dbConnectionFactory); + dbConnectionFactory, ledgerManager); } } diff --git a/source/test/test-integration/src/main/java/test/com/jd/blockchain/intgr/TestDbFactory.java b/source/test/test-integration/src/main/java/test/com/jd/blockchain/intgr/TestDbFactory.java new file mode 100644 index 00000000..0b9c7ed6 --- /dev/null +++ b/source/test/test-integration/src/main/java/test/com/jd/blockchain/intgr/TestDbFactory.java @@ -0,0 +1,140 @@ +package test.com.jd.blockchain.intgr; + +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyLong; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.when; + +import java.util.concurrent.atomic.AtomicBoolean; + +import com.jd.blockchain.storage.service.*; +import com.jd.blockchain.storage.service.utils.MemoryKVStorage; +import org.mockito.Mockito; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.stubbing.Answer; + +public class TestDbFactory implements DbConnectionFactory{ + + private DbConnectionFactory innerDbFactory; + + private AtomicBoolean errorSetTurnOn = new AtomicBoolean(false); + + public TestDbFactory(DbConnectionFactory innerDbFactory) { + this.innerDbFactory = innerDbFactory; + } + + + Answer exKVStorageMockedAnswer = new Answer() { + + @Override + public ExPolicyKVStorage answer(InvocationOnMock invocation) throws Throwable { + + ExPolicyKVStorage reallyExKVStorage = (ExPolicyKVStorage) invocation.callRealMethod(); + + ExPolicyKVStorage mockExKVStorage = Mockito.spy(reallyExKVStorage); + + //按条件开关触发异常; + doAnswer(new Answer() { + + @Override + public Boolean answer(InvocationOnMock invocation) throws Throwable { + if (isErrorSetTurnOn()) { + return false; + } + return (Boolean) invocation.callRealMethod(); + } + }).when(mockExKVStorage).set(any(), any(), any()); + + return mockExKVStorage; + } + }; + + Answer verKVStorageMockedAnswer = new Answer() { + + @Override + public VersioningKVStorage answer(InvocationOnMock invocation) throws Throwable { + + VersioningKVStorage reallyVerKVStorage = (VersioningKVStorage) invocation.callRealMethod(); + + VersioningKVStorage mockVerKVStorage = Mockito.spy(reallyVerKVStorage); + + //按条件开关触发异常; + doAnswer(new Answer() { + + @Override + public Long answer(InvocationOnMock invocation) throws Throwable { + if (isErrorSetTurnOn()) { + return (long)(-1); + } + return (Long) invocation.callRealMethod(); + } + }).when(mockVerKVStorage).set(any(), any(), anyLong()); + + return mockVerKVStorage; + } + }; + + Answer storageMockedAnswer = new Answer() { + + @Override + public KVStorageService answer(InvocationOnMock invocation) throws Throwable { + + KVStorageService reallyStorage = (KVStorageService) invocation.callRealMethod(); + + TestMemoryKVStorage testMemoryKVStorage = new TestMemoryKVStorage((MemoryKVStorage)reallyStorage); + + KVStorageService mockedStorage = Mockito.spy(testMemoryKVStorage); + + doAnswer(exKVStorageMockedAnswer).when(mockedStorage).getExPolicyKVStorage(); + + doAnswer(verKVStorageMockedAnswer).when(mockedStorage).getVersioningKVStorage(); + + return mockedStorage; + } + + }; + + + @Override + public String dbPrefix() { + return innerDbFactory.dbPrefix(); + } + + @Override + public boolean support(String scheme) { + return innerDbFactory.support(scheme); + } + + @Override + public DbConnection connect(String dbConnectionString) { + + DbConnection reallyDbConn = innerDbFactory.connect(dbConnectionString); + + DbConnection mockDbConn = Mockito.spy(reallyDbConn); + + when(mockDbConn.getStorageService()).then(storageMockedAnswer); + return mockDbConn; + } + + @Override + public DbConnection connect(String dbConnectionString, String password) { + return connect(dbConnectionString); + } + + @Override + public void close() { + innerDbFactory.close(); + + } + + public boolean isErrorSetTurnOn() { + return errorSetTurnOn.get(); + } + + public void setErrorSetTurnOn(boolean errorSetTurnOn) { + this.errorSetTurnOn.set(errorSetTurnOn);; + } + + + +} diff --git a/source/test/test-integration/src/main/java/test/com/jd/blockchain/intgr/TestMemoryKVStorage.java b/source/test/test-integration/src/main/java/test/com/jd/blockchain/intgr/TestMemoryKVStorage.java new file mode 100644 index 00000000..15e99f60 --- /dev/null +++ b/source/test/test-integration/src/main/java/test/com/jd/blockchain/intgr/TestMemoryKVStorage.java @@ -0,0 +1,24 @@ +package test.com.jd.blockchain.intgr; + +import com.jd.blockchain.storage.service.ExPolicyKVStorage; +import com.jd.blockchain.storage.service.VersioningKVStorage; +import com.jd.blockchain.storage.service.utils.MemoryKVStorage; + +public class TestMemoryKVStorage extends MemoryKVStorage { + + private MemoryKVStorage memoryKVStorage; + + public TestMemoryKVStorage(MemoryKVStorage memoryKVStorage) { + this.memoryKVStorage = memoryKVStorage; + } + + @Override + public ExPolicyKVStorage getExPolicyKVStorage() { + return memoryKVStorage; + } + + @Override + public VersioningKVStorage getVersioningKVStorage() { + return memoryKVStorage; + } +} diff --git a/source/test/test-integration/src/main/java/test/com/jd/blockchain/intgr/consensus/ConsensusTest.java b/source/test/test-integration/src/main/java/test/com/jd/blockchain/intgr/consensus/ConsensusTest.java index 7c959bc3..e91d804e 100644 --- a/source/test/test-integration/src/main/java/test/com/jd/blockchain/intgr/consensus/ConsensusTest.java +++ b/source/test/test-integration/src/main/java/test/com/jd/blockchain/intgr/consensus/ConsensusTest.java @@ -69,16 +69,16 @@ public class ConsensusTest { Node node3 = context.getNode(3); NetworkAddress peerSrvAddr0 = new NetworkAddress("127.0.0.1", 10200); - PeerTestRunner peer0 = new PeerTestRunner(peerSrvAddr0, node0.getBindingConfig(), node0.getStorageDB()); + PeerTestRunner peer0 = new PeerTestRunner(peerSrvAddr0, node0.getBindingConfig(), node0.getStorageDB(), null); NetworkAddress peerSrvAddr1 = new NetworkAddress("127.0.0.1", 10210); - PeerTestRunner peer1 = new PeerTestRunner(peerSrvAddr1, node1.getBindingConfig(), node1.getStorageDB()); + PeerTestRunner peer1 = new PeerTestRunner(peerSrvAddr1, node1.getBindingConfig(), node1.getStorageDB(), null); NetworkAddress peerSrvAddr2 = new NetworkAddress("127.0.0.1", 10220); - PeerTestRunner peer2 = new PeerTestRunner(peerSrvAddr2, node2.getBindingConfig(), node2.getStorageDB()); + PeerTestRunner peer2 = new PeerTestRunner(peerSrvAddr2, node2.getBindingConfig(), node2.getStorageDB(), null); NetworkAddress peerSrvAddr3 = new NetworkAddress("127.0.0.1", 10230); - PeerTestRunner peer3 = new PeerTestRunner(peerSrvAddr3, node3.getBindingConfig(), node3.getStorageDB()); + PeerTestRunner peer3 = new PeerTestRunner(peerSrvAddr3, node3.getBindingConfig(), node3.getStorageDB(), null); AsyncCallback peerStarting0 = peer0.start(); AsyncCallback peerStarting1 = peer1.start(); diff --git a/source/test/test-integration/src/main/java/test/com/jd/blockchain/intgr/perf/GlobalPerformanceTest.java b/source/test/test-integration/src/main/java/test/com/jd/blockchain/intgr/perf/GlobalPerformanceTest.java index 7f23a276..a7ef9fae 100644 --- a/source/test/test-integration/src/main/java/test/com/jd/blockchain/intgr/perf/GlobalPerformanceTest.java +++ b/source/test/test-integration/src/main/java/test/com/jd/blockchain/intgr/perf/GlobalPerformanceTest.java @@ -67,16 +67,16 @@ public class GlobalPerformanceTest { Node node3 = context.getNode(3); NetworkAddress peerSrvAddr0 = new NetworkAddress("127.0.0.1", 10200); - PeerTestRunner peer0 = new PeerTestRunner(peerSrvAddr0, node0.getBindingConfig(), node0.getStorageDB()); + PeerTestRunner peer0 = new PeerTestRunner(peerSrvAddr0, node0.getBindingConfig(), node0.getStorageDB(), null); NetworkAddress peerSrvAddr1 = new NetworkAddress("127.0.0.1", 10210); - PeerTestRunner peer1 = new PeerTestRunner(peerSrvAddr1, node1.getBindingConfig(), node1.getStorageDB()); + PeerTestRunner peer1 = new PeerTestRunner(peerSrvAddr1, node1.getBindingConfig(), node1.getStorageDB(), null); NetworkAddress peerSrvAddr2 = new NetworkAddress("127.0.0.1", 10220); - PeerTestRunner peer2 = new PeerTestRunner(peerSrvAddr2, node2.getBindingConfig(), node2.getStorageDB()); + PeerTestRunner peer2 = new PeerTestRunner(peerSrvAddr2, node2.getBindingConfig(), node2.getStorageDB(), null); NetworkAddress peerSrvAddr3 = new NetworkAddress("127.0.0.1", 10230); - PeerTestRunner peer3 = new PeerTestRunner(peerSrvAddr3, node3.getBindingConfig(), node3.getStorageDB()); + PeerTestRunner peer3 = new PeerTestRunner(peerSrvAddr3, node3.getBindingConfig(), node3.getStorageDB(), null); AsyncCallback peerStarting0 = peer0.start(); AsyncCallback peerStarting1 = peer1.start(); diff --git a/source/test/test-integration/src/main/java/test/com/jd/blockchain/intgr/perf/LedgerInitializeTest.java b/source/test/test-integration/src/main/java/test/com/jd/blockchain/intgr/perf/LedgerInitializeTest.java index 36ef321f..71efc4e5 100644 --- a/source/test/test-integration/src/main/java/test/com/jd/blockchain/intgr/perf/LedgerInitializeTest.java +++ b/source/test/test-integration/src/main/java/test/com/jd/blockchain/intgr/perf/LedgerInitializeTest.java @@ -48,16 +48,17 @@ public class LedgerInitializeTest { public static final String PASSWORD = "abc"; - public static final String[] PUB_KEYS = { "endPsK36koyFr1D245Sa9j83vt6pZUdFBJoJRB3xAsWM6cwhRbna", - "endPsK36sC5JdPCDPDAXUwZtS3sxEmqEhFcC4whayAsTTh8Z6eoZ", - "endPsK36jEG281HMHeh6oSqzqLkT95DTnCM6REDURjdb2c67uR3R", - "endPsK36nse1dck4uF19zPvAMijCV336Y3zWdgb4rQG8QoRj5ktR" }; + public static final String[] PUB_KEYS = { "3snPdw7i7PjVKiTH2VnXZu5H8QmNaSXpnk4ei533jFpuifyjS5zzH9", + "3snPdw7i7PajLB35tEau1kmixc6ZrjLXgxwKbkv5bHhP7nT5dhD9eX", + "3snPdw7i7PZi6TStiyc6mzjprnNhgs2atSGNS8wPYzhbKaUWGFJt7x", + "3snPdw7i7PifPuRX7fu3jBjsb3rJRfDe9GtbDfvFJaJ4V4hHXQfhwk" }; + public static final String[] PRIV_KEYS = { - "177gjsj5PHeCpbAtJE7qnbmhuZMHAEKuMsd45zHkv8F8AWBvTBbff8yRKdCyT3kwrmAjSnY", - "177gjw9u84WtuCsK8u2WeH4nWqzgEoJWY7jJF9AU6XwLHSosrcNX3H6SSBsfvR53HgX7KR2", - "177gk2FpjufgEon92mf2oRRFXDBZkRy8SkFci7Jxc5pApZEJz3oeCoxieWatDD3Xg7i1QEN", - "177gjvv7qvfCAXroFezSn23UFXLVLFofKS3y6DXkJ2DwVWS4LcRNtxRgiqWmQEeWNz4KQ3J" }; + "177gjzHTznYdPgWqZrH43W3yp37onm74wYXT4v9FukpCHBrhRysBBZh7Pzdo5AMRyQGJD7x", + "177gju9p5zrNdHJVEQnEEKF4ZjDDYmAXyfG84V5RPGVc5xFfmtwnHA7j51nyNLUFffzz5UT", + "177gjtwLgmSx5v1hFb46ijh7L9kdbKUpJYqdKVf9afiEmAuLgo8Rck9yu5UuUcHknWJuWaF", + "177gk1pudweTq5zgJTh8y3ENCTwtSFsKyX7YnpuKPo7rKgCkCBXVXh5z2syaTCPEMbuWRns" }; private Map serviceRegisterMap = new ConcurrentHashMap<>(); diff --git a/source/test/test-integration/src/main/java/test/com/jd/blockchain/intgr/perf/LedgerInitializeWebTest.java b/source/test/test-integration/src/main/java/test/com/jd/blockchain/intgr/perf/LedgerInitializeWebTest.java index 8ee650cc..b687d8f6 100644 --- a/source/test/test-integration/src/main/java/test/com/jd/blockchain/intgr/perf/LedgerInitializeWebTest.java +++ b/source/test/test-integration/src/main/java/test/com/jd/blockchain/intgr/perf/LedgerInitializeWebTest.java @@ -5,6 +5,11 @@ import java.io.InputStream; import java.util.Properties; import java.util.concurrent.CountDownLatch; +import com.jd.blockchain.ledger.core.*; +import com.jd.blockchain.storage.service.DbConnectionFactory; +import org.mockito.Mockito; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.stubbing.Answer; import org.springframework.boot.SpringApplication; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.core.io.ClassPathResource; @@ -27,12 +32,6 @@ import com.jd.blockchain.ledger.LedgerInitProperties; import com.jd.blockchain.ledger.Operation; import com.jd.blockchain.ledger.TransactionContent; import com.jd.blockchain.ledger.UserRegisterOperation; -import com.jd.blockchain.ledger.core.LedgerInitDecision; -import com.jd.blockchain.ledger.core.LedgerInitProposal; -import com.jd.blockchain.ledger.core.LedgerManager; -import com.jd.blockchain.ledger.core.LedgerQuery; -import com.jd.blockchain.ledger.core.UserAccount; -import com.jd.blockchain.ledger.core.UserAccountQuery; import com.jd.blockchain.storage.service.DbConnection; import com.jd.blockchain.storage.service.impl.composite.CompositeConnectionFactory; //import com.jd.blockchain.storage.service.utils.MemoryBasedDb; @@ -52,6 +51,7 @@ import com.jd.blockchain.utils.io.BytesUtils; import com.jd.blockchain.utils.io.FileUtils; import com.jd.blockchain.utils.net.NetworkAddress; +import test.com.jd.blockchain.intgr.LedgerInitConsensusConfig; import test.com.jd.blockchain.intgr.PresetAnswerPrompter; public class LedgerInitializeWebTest { @@ -73,7 +73,7 @@ public class LedgerInitializeWebTest { // 加载初始化配置; LedgerInitProperties initSetting = loadInitSetting_1(); // 加载共识配置; - Properties props = loadConsensusSetting(); + Properties props = loadConsensusSetting(LedgerInitConsensusConfig.bftsmartConfig.getConfigPath()); // ConsensusProperties csProps = new ConsensusProperties(props); ConsensusProvider csProvider = getConsensusProvider(); ConsensusSettings csProps = csProvider.getSettingsFactory() @@ -242,7 +242,7 @@ public class LedgerInitializeWebTest { Prompter consolePrompter = new PresetAnswerPrompter("N"); // new ConsolePrompter(); LedgerInitProperties initSetting = loadInitSetting_2(); - Properties props = loadConsensusSetting(); + Properties props = loadConsensusSetting(LedgerInitConsensusConfig.bftsmartConfig.getConfigPath()); // ConsensusProperties csProps = new ConsensusProperties(props); ConsensusProvider csProvider = getConsensusProvider(); ConsensusSettings csProps = csProvider.getSettingsFactory() @@ -340,8 +340,8 @@ public class LedgerInitializeWebTest { } } - public static Properties loadConsensusSetting() { - ClassPathResource ledgerInitSettingResource = new ClassPathResource("bftsmart.config"); + public static Properties loadConsensusSetting(String configPath) { + ClassPathResource ledgerInitSettingResource = new ClassPathResource(configPath); try (InputStream in = ledgerInitSettingResource.getInputStream()) { return FileUtils.readProperties(in); } catch (IOException e) { @@ -365,7 +365,7 @@ public class LedgerInitializeWebTest { private volatile LedgerManager ledgerManager; - private volatile CompositeConnectionFactory db; + private volatile DbConnectionFactory db; private int id; @@ -401,9 +401,14 @@ public class LedgerInitializeWebTest { // dbConnConfig.getPassword()); DbConnection conn = db.connect(dbConnConfig.getUri()); LedgerQuery ledgerRepo = ledgerManager.register(ledgerHash, conn.getStorageService()); + return ledgerRepo; } + public LedgerRepository ledgerRepository(HashDigest ledgerHash) { + return ledgerManager.getLedger(ledgerHash); + } + public SignatureDigest createPermissionRequestSignature(int requesterId, PrivKey privKey) { return controller.signPermissionRequest(requesterId, privKey); } @@ -429,21 +434,14 @@ public class LedgerInitializeWebTest { return invoker.start(); } - // public AsyncCallback startInitCommand(PrivKey privKey, String - // base58Pwd, LedgerInitProperties ledgerSetting, ConsensusSettings csProps, - // DBConnectionConfig dbConnConfig, - // Prompter prompter, LedgerBindingConfig conf, CountDownLatch quitLatch) { - // return startInitCommand(privKey, base58Pwd, ledgerSetting, csProps, - // dbConnConfig, prompter, conf, quitLatch); - // } public AsyncCallback startInitCommand(PrivKey privKey, String base58Pwd, - LedgerInitProperties ledgerSetting, ConsensusSettings csProps, ConsensusProvider csProvider, - DBConnectionConfig dbConnConfig, Prompter prompter, LedgerBindingConfig conf, - CountDownLatch quitLatch) { - this.db = new CompositeConnectionFactory(); + LedgerInitProperties ledgerSetting, ConsensusSettings csProps, ConsensusProvider csProvider, + DBConnectionConfig dbConnConfig, Prompter prompter, LedgerBindingConfig conf, + CountDownLatch quitLatch, DbConnectionFactory db) { this.dbConnConfig = dbConnConfig; // this.mqConnConfig = mqConnConfig; + this.db = db; ThreadInvoker invoker = new ThreadInvoker() { @Override @@ -451,7 +449,11 @@ public class LedgerInitializeWebTest { LedgerInitCommand initCmd = new LedgerInitCommand(); HashDigest ledgerHash = initCmd.startInit(id, privKey, base58Pwd, ledgerSetting, dbConnConfig, prompter, conf, db); - NodeWebContext.this.ledgerManager = initCmd.getLedgerManager(); + + LedgerManager lm = initCmd.getLedgerManager(); + + NodeWebContext.this.ledgerManager = lm; + quitLatch.countDown(); return ledgerHash; } @@ -460,6 +462,7 @@ public class LedgerInitializeWebTest { return invoker.start(); } + public LedgerInitProposal preparePermision(PrivKey privKey, LedgerInitConfiguration initConfig) { return controller.prepareLocalPermission(id, privKey, initConfig); } @@ -517,7 +520,7 @@ public class LedgerInitializeWebTest { // return ctx.getBean(LedgerManager.class); } - public CompositeConnectionFactory getStorageDB() { + public DbConnectionFactory getStorageDB() { return db; } } diff --git a/source/test/test-integration/src/main/resources/bftsmart.config b/source/test/test-integration/src/main/resources/bftsmart.config index df811663..80ed0f6a 100644 --- a/source/test/test-integration/src/main/resources/bftsmart.config +++ b/source/test/test-integration/src/main/resources/bftsmart.config @@ -14,58 +14,36 @@ # limitations under the License. -############################################ -###### Consensus Commit Block Parameters: transaction count ###### -############################################ -system.block.txsize=15 - -############################################ -###### Consensus Commit Block Parameters: delay time ###### -############################################ -system.block.maxdelay=500 - ############################################ ###### Consensus Participant0 ###### ############################################ -system.server.0.pubkey=3snPdw7i7PapsDoW185c3kfK6p8s6SwiJAdEUzgnfeuUox12nxgzXu system.server.0.network.host=127.0.0.1 - system.server.0.network.port=8910 - system.server.0.network.secure=false ############################################ ###### #Consensus Participant1 ###### ############################################ -system.server.1.pubkey=3snPdw7i7Ph1SYLQt9uqVEqiuvNXjxCdGvEdN6otJsg5rbr7Aze7kf system.server.1.network.host=127.0.0.1 - system.server.1.network.port=8920 - system.server.1.network.secure=false ############################################ ###### #Consensus Participant2 ###### ############################################ -system.server.2.pubkey=3snPdw7i7PezptA6dNBkotPjmKEbTkY8fmusLBnfj8Cf7eFwhWDwKr system.server.2.network.host=127.0.0.1 - system.server.2.network.port=8930 - system.server.2.network.secure=false ############################################ ###### Consensus Participant3 ###### ############################################ -system.server.3.pubkey=3snPdw7i7PerZYfRzEB61SAN9tFK4yHm9wUSRtkLSSGXHkQRbB5PkS system.server.3.network.host=127.0.0.1 - system.server.3.network.port=8940 - system.server.3.network.secure=false ############################################ @@ -94,7 +72,7 @@ system.servers.num = 4 #system.servers.f = 1 #Timeout to asking for a client request -system.totalordermulticast.timeout = 2000 +system.totalordermulticast.timeout = 5000 #Maximum batch size (in number of messages) @@ -174,5 +152,4 @@ system.ttp.id = 7002 system.bft = true #Custom View Storage; -#view.storage.handler=bftsmart.reconfiguration.views.DefaultViewStorage - +#view.storage.handler=bftsmart.reconfiguration.views.DefaultViewStorage \ No newline at end of file diff --git a/source/test/test-integration/src/main/resources/ledger_init_test_web2.init b/source/test/test-integration/src/main/resources/ledger_init_test_web2.init index 00fc9da1..5be0e69d 100644 --- a/source/test/test-integration/src/main/resources/ledger_init_test_web2.init +++ b/source/test/test-integration/src/main/resources/ledger_init_test_web2.init @@ -2,7 +2,10 @@ ledger.seed=932dfe23-fe23232f-283f32fa-dd32aa76-8322ca2f-56236cda-7136b322-cb323ffe #账本的描述名称;此属性不参与共识,仅仅在当前参与方的本地节点用于描述用途; -ledger.name= +ledger.name==myledger + +#声明的账本创建时间;格式为 “yyyy-MM-dd HH:mm:ss.SSSZ”,表示”年-月-日 时:分:秒:毫秒时区“;例如:“2019-08-01 14:26:58.069+0800”,其中,+0800 表示时区是东8区 +created-time=2019-08-01 14:26:58.069+0800 #共识服务提供者;必须; consensus.service-provider=com.jd.blockchain.consensus.bftsmart.BftsmartConsensusProvider diff --git a/source/test/test-integration/src/test/java/test/com/jd/blockchain/intgr/IntegrationBase.java b/source/test/test-integration/src/test/java/test/com/jd/blockchain/intgr/IntegrationBase.java index 9c3b3320..a109e456 100644 --- a/source/test/test-integration/src/test/java/test/com/jd/blockchain/intgr/IntegrationBase.java +++ b/source/test/test-integration/src/test/java/test/com/jd/blockchain/intgr/IntegrationBase.java @@ -103,6 +103,36 @@ public class IntegrationBase { return keyPairResponse; } + public static KeyPairResponse testSDK_BlockFullRollBack(AsymmetricKeypair adminKey, HashDigest ledgerHash, + BlockchainService blockchainService) { + + BlockchainKeypair user = BlockchainKeyGenerator.getInstance().generate(); + + TransactionTemplate txTpl = blockchainService.newTransaction(ledgerHash); + + //Register user account + txTpl.users().register(user.getIdentity()); + + PreparedTransaction prepTx = txTpl.prepare(); + + HashDigest transactionHash = prepTx.getHash(); + + prepTx.sign(adminKey); + + //Commit transaction + TransactionResponse transactionResponse = prepTx.commit(); + + //The whole block will rollback, due to storage error + assertEquals(transactionResponse.getExecutionState().CODE, TransactionState.IGNORED_BY_BLOCK_FULL_ROLLBACK.CODE); + + KeyPairResponse keyPairResponse = new KeyPairResponse(); + keyPairResponse.keyPair = user; + keyPairResponse.txResp = transactionResponse; + keyPairResponse.txHash = transactionHash; + return keyPairResponse; + } + + public static KeyPairResponse testSDK_RegisterDataAccount(AsymmetricKeypair adminKey, HashDigest ledgerHash, BlockchainService blockchainService) { // 注册数据账户,并验证最终写入; @@ -286,8 +316,8 @@ public class IntegrationBase { assertEquals(txResp.getContentHash(), transactionHash); assertEquals(txResp.getBlockHash(), ledgerRepository.getLatestBlockHash()); - KVDataEntry[] kvDataEntries = blockchainService.getDataEntries(ledgerHash, daAddress, dataKey); - for (KVDataEntry kvDataEntry : kvDataEntries) { + TypedKVEntry[] kvDataEntries = blockchainService.getDataEntries(ledgerHash, daAddress, dataKey); + for (TypedKVEntry kvDataEntry : kvDataEntries) { assertEquals(dataKey, kvDataEntry.getKey()); String valHexText = (String) kvDataEntry.getValue(); assertEquals(dataVal, valHexText); diff --git a/source/test/test-integration/src/test/java/test/com/jd/blockchain/intgr/IntegrationBaseTest.java b/source/test/test-integration/src/test/java/test/com/jd/blockchain/intgr/IntegrationBaseTest.java index d28a2b45..4d9cf522 100644 --- a/source/test/test-integration/src/test/java/test/com/jd/blockchain/intgr/IntegrationBaseTest.java +++ b/source/test/test-integration/src/test/java/test/com/jd/blockchain/intgr/IntegrationBaseTest.java @@ -47,16 +47,16 @@ public class IntegrationBaseTest { Node node3 = context.getNode(3); NetworkAddress peerSrvAddr0 = new NetworkAddress("127.0.0.1", 13200); - PeerTestRunner peer0 = new PeerTestRunner(peerSrvAddr0, node0.getBindingConfig(), node0.getStorageDB()); + PeerTestRunner peer0 = new PeerTestRunner(peerSrvAddr0, node0.getBindingConfig(), node0.getStorageDB(), null); NetworkAddress peerSrvAddr1 = new NetworkAddress("127.0.0.1", 13210); - PeerTestRunner peer1 = new PeerTestRunner(peerSrvAddr1, node1.getBindingConfig(), node1.getStorageDB()); + PeerTestRunner peer1 = new PeerTestRunner(peerSrvAddr1, node1.getBindingConfig(), node1.getStorageDB(), null); NetworkAddress peerSrvAddr2 = new NetworkAddress("127.0.0.1", 13220); - PeerTestRunner peer2 = new PeerTestRunner(peerSrvAddr2, node2.getBindingConfig(), node2.getStorageDB()); + PeerTestRunner peer2 = new PeerTestRunner(peerSrvAddr2, node2.getBindingConfig(), node2.getStorageDB(), null); NetworkAddress peerSrvAddr3 = new NetworkAddress("127.0.0.1", 13230); - PeerTestRunner peer3 = new PeerTestRunner(peerSrvAddr3, node3.getBindingConfig(), node3.getStorageDB()); + PeerTestRunner peer3 = new PeerTestRunner(peerSrvAddr3, node3.getBindingConfig(), node3.getStorageDB(), null); AsyncCallback peerStarting0 = peer0.start(); AsyncCallback peerStarting1 = peer1.start(); diff --git a/source/test/test-integration/src/test/java/test/com/jd/blockchain/intgr/IntegrationTest2.java b/source/test/test-integration/src/test/java/test/com/jd/blockchain/intgr/IntegrationTest2.java index 683ed91f..3512d6b0 100644 --- a/source/test/test-integration/src/test/java/test/com/jd/blockchain/intgr/IntegrationTest2.java +++ b/source/test/test-integration/src/test/java/test/com/jd/blockchain/intgr/IntegrationTest2.java @@ -64,16 +64,16 @@ public class IntegrationTest2 { Node node3 = context.getNode(3); NetworkAddress peerSrvAddr0 = new NetworkAddress("127.0.0.1", 13200); - PeerTestRunner peer0 = new PeerTestRunner(peerSrvAddr0, node0.getBindingConfig(), node0.getStorageDB()); + PeerTestRunner peer0 = new PeerTestRunner(peerSrvAddr0, node0.getBindingConfig(), node0.getStorageDB(), null); NetworkAddress peerSrvAddr1 = new NetworkAddress("127.0.0.1", 13210); - PeerTestRunner peer1 = new PeerTestRunner(peerSrvAddr1, node1.getBindingConfig(), node1.getStorageDB()); + PeerTestRunner peer1 = new PeerTestRunner(peerSrvAddr1, node1.getBindingConfig(), node1.getStorageDB(), null); NetworkAddress peerSrvAddr2 = new NetworkAddress("127.0.0.1", 13220); - PeerTestRunner peer2 = new PeerTestRunner(peerSrvAddr2, node2.getBindingConfig(), node2.getStorageDB()); + PeerTestRunner peer2 = new PeerTestRunner(peerSrvAddr2, node2.getBindingConfig(), node2.getStorageDB(), null); NetworkAddress peerSrvAddr3 = new NetworkAddress("127.0.0.1", 13230); - PeerTestRunner peer3 = new PeerTestRunner(peerSrvAddr3, node3.getBindingConfig(), node3.getStorageDB()); + PeerTestRunner peer3 = new PeerTestRunner(peerSrvAddr3, node3.getBindingConfig(), node3.getStorageDB(), null); AsyncCallback peerStarting0 = peer0.start(); AsyncCallback peerStarting1 = peer1.start(); diff --git a/source/test/test-integration/src/test/java/test/com/jd/blockchain/intgr/IntegrationTestAll4Redis.java b/source/test/test-integration/src/test/java/test/com/jd/blockchain/intgr/IntegrationTestAll4Redis.java index 50ccb64c..6c8c762c 100644 --- a/source/test/test-integration/src/test/java/test/com/jd/blockchain/intgr/IntegrationTestAll4Redis.java +++ b/source/test/test-integration/src/test/java/test/com/jd/blockchain/intgr/IntegrationTestAll4Redis.java @@ -1,8 +1,39 @@ package test.com.jd.blockchain.intgr; -import com.jd.blockchain.crypto.*; +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.Random; + +import org.junit.Test; +import org.springframework.core.io.ClassPathResource; + +import com.jd.blockchain.crypto.AddressEncoding; +import com.jd.blockchain.crypto.AsymmetricKeypair; +import com.jd.blockchain.crypto.Crypto; +import com.jd.blockchain.crypto.HashDigest; +import com.jd.blockchain.crypto.KeyGenUtils; +import com.jd.blockchain.crypto.PrivKey; +import com.jd.blockchain.crypto.PubKey; import com.jd.blockchain.gateway.GatewayConfigProperties.KeyPairConfig; -import com.jd.blockchain.ledger.*; +import com.jd.blockchain.ledger.BlockchainKeyGenerator; +import com.jd.blockchain.ledger.BlockchainKeypair; +import com.jd.blockchain.ledger.BytesValue; +import com.jd.blockchain.ledger.DataAccountKVSetOperation; +import com.jd.blockchain.ledger.TypedKVEntry; +import com.jd.blockchain.ledger.LedgerBlock; +import com.jd.blockchain.ledger.LedgerInfo; +import com.jd.blockchain.ledger.LedgerInitProperties; +import com.jd.blockchain.ledger.PreparedTransaction; +import com.jd.blockchain.ledger.TransactionResponse; +import com.jd.blockchain.ledger.TransactionState; +import com.jd.blockchain.ledger.TransactionTemplate; import com.jd.blockchain.ledger.core.DataAccount; import com.jd.blockchain.ledger.core.DataAccountQuery; import com.jd.blockchain.ledger.core.LedgerManage; @@ -17,19 +48,10 @@ import com.jd.blockchain.utils.Bytes; import com.jd.blockchain.utils.codec.HexUtils; import com.jd.blockchain.utils.concurrent.ThreadInvoker.AsyncCallback; import com.jd.blockchain.utils.net.NetworkAddress; -import org.junit.Test; -import org.springframework.core.io.ClassPathResource; + import test.com.jd.blockchain.intgr.contract.AssetContract; import test.com.jd.blockchain.intgr.initializer.LedgerInitializeWeb4SingleStepsTest; -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.util.Random; - -import static org.junit.Assert.*; - public class IntegrationTestAll4Redis { public static final String PASSWORD = "abc"; @@ -214,21 +236,21 @@ public class IntegrationTestAll4Redis { assertEquals(ledgerRepository.retrieveLatestBlockHeight(), txResp.getBlockHeight()); assertEquals("Value_A_0", ledgerRepository.getDataAccountSet(ledgerRepository.retrieveLatestBlock()) - .getAccount(dataKey.getAddress()).getBytes("A").getValue().toUTF8String()); + .getAccount(dataKey.getAddress()).getDataset().getValue("A").getBytes().toUTF8String()); assertEquals("Value_B_0", ledgerRepository.getDataAccountSet(ledgerRepository.retrieveLatestBlock()) - .getAccount(dataKey.getAddress()).getBytes("B").getValue().toUTF8String()); + .getAccount(dataKey.getAddress()).getDataset().getValue("B").getBytes().toUTF8String()); assertEquals("Value_C_0", ledgerRepository.getDataAccountSet(ledgerRepository.retrieveLatestBlock()) - .getAccount(dataKey.getAddress()).getBytes("C").getValue().toUTF8String()); + .getAccount(dataKey.getAddress()).getDataset().getValue("C").getBytes().toUTF8String()); assertEquals("Value_D_0", ledgerRepository.getDataAccountSet(ledgerRepository.retrieveLatestBlock()) - .getAccount(dataKey.getAddress()).getBytes("D").getValue().toUTF8String()); + .getAccount(dataKey.getAddress()).getDataset().getValue("D").getBytes().toUTF8String()); assertEquals(0, ledgerRepository.getDataAccountSet(ledgerRepository.retrieveLatestBlock()) - .getAccount(dataKey.getAddress()).getDataVersion("A")); + .getAccount(dataKey.getAddress()).getDataset().getVersion("A")); assertEquals(0, ledgerRepository.getDataAccountSet(ledgerRepository.retrieveLatestBlock()) - .getAccount(dataKey.getAddress()).getDataVersion("B")); + .getAccount(dataKey.getAddress()).getDataset().getVersion("B")); assertEquals(0, ledgerRepository.getDataAccountSet(ledgerRepository.retrieveLatestBlock()) - .getAccount(dataKey.getAddress()).getDataVersion("C")); + .getAccount(dataKey.getAddress()).getDataset().getVersion("C")); assertEquals(0, ledgerRepository.getDataAccountSet(ledgerRepository.retrieveLatestBlock()) - .getAccount(dataKey.getAddress()).getDataVersion("D")); + .getAccount(dataKey.getAddress()).getDataset().getVersion("D")); return; } @@ -280,9 +302,9 @@ public class IntegrationTestAll4Redis { assertEquals(txResp.getContentHash(), prepTx.getHash()); assertEquals(txResp.getBlockHash(), ledgerRepository.getLatestBlockHash()); - KVDataEntry[] kvDataEntries = blockchainService.getDataEntries(ledgerHash, dataAccountAddress.toString(), + TypedKVEntry[] kvDataEntries = blockchainService.getDataEntries(ledgerHash, dataAccountAddress.toString(), dataKey); - for (KVDataEntry kvDataEntry : kvDataEntries) { + for (TypedKVEntry kvDataEntry : kvDataEntries) { assertEquals(dataKey, kvDataEntry.getKey()); String valHexText = (String) kvDataEntry.getValue(); byte[] valBytes = HexUtils.decode(valHexText); @@ -449,9 +471,9 @@ public class IntegrationTestAll4Redis { AsymmetricKeypair key = Crypto.getSignatureFunction("ED25519").generateKeypair(); PubKey pubKey = key.getPubKey(); Bytes dataAddress = AddressEncoding.generateAddress(pubKey); - assertEquals(dataAddress, dataAccountSet.getAccount(dataAddress).getAddress()); + assertEquals(dataAddress, dataAccountSet.getAccount(dataAddress).getID().getAddress()); assertEquals("hello", - dataAccountSet.getAccount(dataAddress).getBytes(KEY_TOTAL, -1).getValue().toUTF8String()); + dataAccountSet.getAccount(dataAddress).getDataset().getValue(KEY_TOTAL, -1).getBytes().toUTF8String()); // 验证userAccount,从合约内部赋值,然后外部验证;内部定义动态key,外部不便于得到,临时屏蔽; // UserAccountSet userAccountSet = @@ -479,11 +501,11 @@ public class IntegrationTestAll4Redis { // 验证结果; LedgerBlock block = ledgerRepository.getBlock(txResp.getBlockHeight()); BytesValue val1InDb = ledgerRepository.getDataAccountSet(block).getAccount(contractDataKey.getAddress()) - .getBytes("A"); + .getDataset().getValue("A"); BytesValue val2InDb = ledgerRepository.getDataAccountSet(block).getAccount(contractDataKey.getAddress()) - .getBytes(KEY_TOTAL); - assertEquals("Value_A_0", val1InDb.getValue().toUTF8String()); - assertEquals("total value,dataAccount", val2InDb.getValue().toUTF8String()); + .getDataset().getValue(KEY_TOTAL); + assertEquals("Value_A_0", val1InDb.getBytes().toUTF8String()); + assertEquals("total value,dataAccount", val2InDb.getBytes().toUTF8String()); } /** diff --git a/source/test/test-integration/src/test/java/test/com/jd/blockchain/intgr/IntegrationTestDataAccount.java b/source/test/test-integration/src/test/java/test/com/jd/blockchain/intgr/IntegrationTestDataAccount.java index c6361d89..c62ee9c4 100644 --- a/source/test/test-integration/src/test/java/test/com/jd/blockchain/intgr/IntegrationTestDataAccount.java +++ b/source/test/test-integration/src/test/java/test/com/jd/blockchain/intgr/IntegrationTestDataAccount.java @@ -23,7 +23,7 @@ import com.jd.blockchain.gateway.GatewayConfigProperties.KeyPairConfig; import com.jd.blockchain.ledger.BlockchainKeyGenerator; import com.jd.blockchain.ledger.BlockchainKeypair; import com.jd.blockchain.ledger.DataAccountKVSetOperation; -import com.jd.blockchain.ledger.KVDataEntry; +import com.jd.blockchain.ledger.TypedKVEntry; import com.jd.blockchain.ledger.LedgerBlock; import com.jd.blockchain.ledger.LedgerInitProperties; import com.jd.blockchain.ledger.PreparedTransaction; @@ -78,16 +78,16 @@ public class IntegrationTestDataAccount { Node node3 = context.getNode(3); NetworkAddress peerSrvAddr0 = new NetworkAddress("127.0.0.1", 14200); - PeerTestRunner peer0 = new PeerTestRunner(peerSrvAddr0, node0.getBindingConfig(), node0.getStorageDB()); + PeerTestRunner peer0 = new PeerTestRunner(peerSrvAddr0, node0.getBindingConfig(), node0.getStorageDB(), null); NetworkAddress peerSrvAddr1 = new NetworkAddress("127.0.0.1", 14210); - PeerTestRunner peer1 = new PeerTestRunner(peerSrvAddr1, node1.getBindingConfig(), node1.getStorageDB()); + PeerTestRunner peer1 = new PeerTestRunner(peerSrvAddr1, node1.getBindingConfig(), node1.getStorageDB(), null); NetworkAddress peerSrvAddr2 = new NetworkAddress("127.0.0.1", 14220); - PeerTestRunner peer2 = new PeerTestRunner(peerSrvAddr2, node2.getBindingConfig(), node2.getStorageDB()); + PeerTestRunner peer2 = new PeerTestRunner(peerSrvAddr2, node2.getBindingConfig(), node2.getStorageDB(), null); NetworkAddress peerSrvAddr3 = new NetworkAddress("127.0.0.1", 14230); - PeerTestRunner peer3 = new PeerTestRunner(peerSrvAddr3, node3.getBindingConfig(), node3.getStorageDB()); + PeerTestRunner peer3 = new PeerTestRunner(peerSrvAddr3, node3.getBindingConfig(), node3.getStorageDB(), null); AsyncCallback peerStarting0 = peer0.start(); AsyncCallback peerStarting1 = peer1.start(); @@ -214,7 +214,7 @@ public class IntegrationTestDataAccount { e.printStackTrace(); } - KVDataEntry[] kvDataEntries = blockchainService.getDataEntries(ledgerHashs[0], dataAddr.toBase58(), "A", "B", + TypedKVEntry[] kvDataEntries = blockchainService.getDataEntries(ledgerHashs[0], dataAddr.toBase58(), "A", "B", "C", "D"); for (int i = 0; i < kvDataEntries.length; i++) { Object result = kvDataEntries[i].getValue(); diff --git a/source/test/test-integration/src/test/java/test/com/jd/blockchain/intgr/initializer/LedgerInitializeWeb4Nodes.java b/source/test/test-integration/src/test/java/test/com/jd/blockchain/intgr/initializer/LedgerInitializeWeb4Nodes.java index ec77fbee..1ccf994c 100644 --- a/source/test/test-integration/src/test/java/test/com/jd/blockchain/intgr/initializer/LedgerInitializeWeb4Nodes.java +++ b/source/test/test-integration/src/test/java/test/com/jd/blockchain/intgr/initializer/LedgerInitializeWeb4Nodes.java @@ -53,6 +53,7 @@ public class LedgerInitializeWeb4Nodes { System.setProperty("peer.log", path); System.setProperty("init.log", path); System.setProperty("gateway.log", path); + System.setProperty("jdchain.log", path); } catch (Exception e) { e.printStackTrace(); } diff --git a/source/test/test-ledger/pom.xml b/source/test/test-ledger/pom.xml index 57061dfc..5c001f85 100644 --- a/source/test/test-ledger/pom.xml +++ b/source/test/test-ledger/pom.xml @@ -5,7 +5,7 @@ com.jd.blockchain test - 1.1.1-PACK20191209 + 1.1.2.RELEASE test-ledger diff --git a/source/test/test-ledger/src/main/java/test/perf/com/jd/blockchain/ledger/MerkleDatasetPerformanceTester.java b/source/test/test-ledger/src/main/java/test/perf/com/jd/blockchain/ledger/MerkleDatasetPerformanceTester.java index 7b5faffb..a71efcee 100644 --- a/source/test/test-ledger/src/main/java/test/perf/com/jd/blockchain/ledger/MerkleDatasetPerformanceTester.java +++ b/source/test/test-ledger/src/main/java/test/perf/com/jd/blockchain/ledger/MerkleDatasetPerformanceTester.java @@ -14,6 +14,7 @@ import com.jd.blockchain.storage.service.ExPolicyKVStorage; import com.jd.blockchain.storage.service.VersioningKVStorage; import com.jd.blockchain.storage.service.impl.redis.RedisConnectionFactory; import com.jd.blockchain.storage.service.utils.MemoryKVStorage; +import com.jd.blockchain.utils.Bytes; public class MerkleDatasetPerformanceTester { @@ -156,12 +157,12 @@ public class MerkleDatasetPerformanceTester { for (int i = 0; i < round; i++) { for (int j = 0; j < batchCount; j++) { key = "data_" + startTs + "_" + randomId + "_" + (i * batchCount + j); - long v = mds.getVersion(key); - mds.setValue(key, data, v); + long v = mds.getVersion(Bytes.fromString(key)); + mds.setValue(Bytes.fromString(key), data, v); } mds.commit(); rootHash = mds.getRootHash(); - mds = new MerkleDataSet(rootHash, cryptoConfig, MKL_KEY_PREFIX, exStorage, verStorage, false); + mds = new MerkleDataSet(rootHash, cryptoConfig, Bytes.fromString(MKL_KEY_PREFIX), exStorage, verStorage, false); } long elapsedTs = System.currentTimeMillis() - startTs; diff --git a/source/tools/pom.xml b/source/tools/pom.xml index cd499634..1671c46f 100644 --- a/source/tools/pom.xml +++ b/source/tools/pom.xml @@ -5,7 +5,7 @@ com.jd.blockchain jdchain-root - 1.1.1-PACK20191209 + 1.1.2.RELEASE tools pom diff --git a/source/tools/tools-initializer-booter/pom.xml b/source/tools/tools-initializer-booter/pom.xml index 0c5e8764..4c012f35 100644 --- a/source/tools/tools-initializer-booter/pom.xml +++ b/source/tools/tools-initializer-booter/pom.xml @@ -5,7 +5,7 @@ com.jd.blockchain tools - 1.1.1-PACK20191209 + 1.1.2.RELEASE tools-initializer-booter diff --git a/source/tools/tools-initializer/pom.xml b/source/tools/tools-initializer/pom.xml index ca737d61..b97c7890 100644 --- a/source/tools/tools-initializer/pom.xml +++ b/source/tools/tools-initializer/pom.xml @@ -5,7 +5,7 @@ com.jd.blockchain tools - 1.1.1-PACK20191209 + 1.1.2.RELEASE tools-initializer diff --git a/source/tools/tools-keygen-booter/pom.xml b/source/tools/tools-keygen-booter/pom.xml index 7c967b10..edfe4824 100644 --- a/source/tools/tools-keygen-booter/pom.xml +++ b/source/tools/tools-keygen-booter/pom.xml @@ -5,7 +5,7 @@ com.jd.blockchain tools - 1.1.1-PACK20191209 + 1.1.2.RELEASE tools-keygen-booter diff --git a/source/tools/tools-keygen/pom.xml b/source/tools/tools-keygen/pom.xml index a4d0efbd..5ed95354 100644 --- a/source/tools/tools-keygen/pom.xml +++ b/source/tools/tools-keygen/pom.xml @@ -5,7 +5,7 @@ com.jd.blockchain tools - 1.1.1-PACK20191209 + 1.1.2.RELEASE tools-keygen diff --git a/source/utils/pom.xml b/source/utils/pom.xml index 3952a27b..a9233b6d 100644 --- a/source/utils/pom.xml +++ b/source/utils/pom.xml @@ -4,7 +4,7 @@ com.jd.blockchain jdchain-root - 1.1.1-PACK20191209 + 1.1.2.RELEASE utils pom diff --git a/source/utils/utils-common/pom.xml b/source/utils/utils-common/pom.xml index 2957e06f..04fec308 100644 --- a/source/utils/utils-common/pom.xml +++ b/source/utils/utils-common/pom.xml @@ -4,7 +4,7 @@ com.jd.blockchain utils - 1.1.1-PACK20191209 + 1.1.2.RELEASE utils-common diff --git a/source/utils/utils-common/src/main/java/com/jd/blockchain/utils/ArrayUtils.java b/source/utils/utils-common/src/main/java/com/jd/blockchain/utils/ArrayUtils.java index 79773915..cea92cbc 100644 --- a/source/utils/utils-common/src/main/java/com/jd/blockchain/utils/ArrayUtils.java +++ b/source/utils/utils-common/src/main/java/com/jd/blockchain/utils/ArrayUtils.java @@ -9,17 +9,29 @@ import java.util.*; */ public abstract class ArrayUtils { private ArrayUtils() { - + } - + + public static R[] castTo(T[] objs, Class clazz, CastFunction cf) { + if (objs == null) { + return null; + } + @SuppressWarnings("unchecked") + R[] array = (R[]) Array.newInstance(clazz, objs.length); + for (int i = 0; i < objs.length; i++) { + array[i] = cf.cast(objs[i]); + } + return array; + } + public static T[] singleton(T obj, Class clazz) { @SuppressWarnings("unchecked") T[] array = (T[]) Array.newInstance(clazz, 1); array[0] = obj; return array; } - - public static T[] toArray(Iterator itr, Class clazz){ + + public static T[] toArray(Iterator itr, Class clazz) { List lst = new LinkedList(); while (itr.hasNext()) { T t = (T) itr.next(); @@ -30,19 +42,19 @@ public abstract class ArrayUtils { lst.toArray(array); return array; } - - public static T[] toArray(Collection collection, Class clazz){ + + public static T[] toArray(Collection collection, Class clazz) { @SuppressWarnings("unchecked") T[] array = (T[]) Array.newInstance(clazz, collection.size()); collection.toArray(array); return array; } - - public static List asList(T[] array){ + + public static List asList(T[] array) { return asList(array, 0, array.length); } - - public static Set asSet(T[] array){ + + public static Set asSet(T[] array) { if (array == null || array.length == 0) { return Collections.emptySet(); } @@ -52,8 +64,8 @@ public abstract class ArrayUtils { } return set; } - - public static SortedSet asSortedSet(T[] array){ + + public static SortedSet asSortedSet(T[] array) { if (array == null || array.length == 0) { return Collections.emptySortedSet(); } @@ -63,12 +75,12 @@ public abstract class ArrayUtils { } return set; } - - public static List asList(T[] array, int fromIndex){ + + public static List asList(T[] array, int fromIndex) { return asList(array, fromIndex, array.length); } - - public static List asList(T[] array, int fromIndex, int toIndex){ + + public static List asList(T[] array, int fromIndex, int toIndex) { if (toIndex < fromIndex) { throw new IllegalArgumentException("The toIndex less than fromIndex!"); } @@ -78,10 +90,33 @@ public abstract class ArrayUtils { if (toIndex > array.length) { throw new IllegalArgumentException("The toIndex great than the length of array!"); } - + if (fromIndex == toIndex) { return Collections.emptyList(); } return new ReadonlyArrayListWrapper(array, fromIndex, toIndex); } + + public static interface CastFunction { + public R cast(T data); + } + + /** + * Reverse all elements of the specified array;
+ * + * @param + * @param array + */ + public static void reverse(T[] array) { + if (array == null || array.length < 2) { + return; + } + + T t; + for (int i = 0, j = array.length - 1; i < j; i++, j--) { + t = array[i]; + array[i] = array[j]; + array[j] = t; + } + } } diff --git a/source/utils/utils-common/src/main/java/com/jd/blockchain/utils/BaseConstant.java b/source/utils/utils-common/src/main/java/com/jd/blockchain/utils/BaseConstant.java index 4548dbad..890748e5 100644 --- a/source/utils/utils-common/src/main/java/com/jd/blockchain/utils/BaseConstant.java +++ b/source/utils/utils-common/src/main/java/com/jd/blockchain/utils/BaseConstant.java @@ -1,7 +1,5 @@ package com.jd.blockchain.utils; -import java.io.File; - /** * * @author zhaogw diff --git a/source/utils/utils-common/src/main/java/com/jd/blockchain/utils/DataEntry.java b/source/utils/utils-common/src/main/java/com/jd/blockchain/utils/DataEntry.java new file mode 100644 index 00000000..b02fa524 --- /dev/null +++ b/source/utils/utils-common/src/main/java/com/jd/blockchain/utils/DataEntry.java @@ -0,0 +1,17 @@ +package com.jd.blockchain.utils; + +/** + * Versioning Key-Value data entry; + * + * @author huanghaiquan + * + */ +public interface DataEntry { + + public K getKey(); + + public long getVersion(); + + public V getValue(); + +} \ No newline at end of file diff --git a/source/utils/utils-common/src/main/java/com/jd/blockchain/utils/DataIterator.java b/source/utils/utils-common/src/main/java/com/jd/blockchain/utils/DataIterator.java new file mode 100644 index 00000000..13a8a0d0 --- /dev/null +++ b/source/utils/utils-common/src/main/java/com/jd/blockchain/utils/DataIterator.java @@ -0,0 +1,21 @@ +package com.jd.blockchain.utils; + +/** + * 数据迭代器; + * + * @author huanghaiquan + * + * @param + * @param + */ +public interface DataIterator { + + void skip(long count); + + DataEntry next(); + + DataEntry[] next(int count); + + boolean hasNext(); + +} diff --git a/source/utils/utils-common/src/main/java/com/jd/blockchain/utils/DataTypeUtils.java b/source/utils/utils-common/src/main/java/com/jd/blockchain/utils/DataTypeUtils.java deleted file mode 100644 index 05952868..00000000 --- a/source/utils/utils-common/src/main/java/com/jd/blockchain/utils/DataTypeUtils.java +++ /dev/null @@ -1,34 +0,0 @@ -package com.jd.blockchain.utils; - -import java.lang.reflect.Type; -import java.util.HashMap; -import java.util.Map; - -import org.springframework.util.TypeUtils; - -public abstract class DataTypeUtils { - - private static Map, Class> wrapperTypes = new HashMap, Class>(); - - static{ - wrapperTypes.put(long.class, Long.class); - wrapperTypes.put(int.class, Integer.class); - wrapperTypes.put(char.class, Character.class); - wrapperTypes.put(byte.class, Byte.class); - wrapperTypes.put(boolean.class, Boolean.class); - } - - public static boolean isAssignable(Type lhsType, Type rhsType) { - boolean assignable = TypeUtils.isAssignable(lhsType, rhsType); - if (assignable) { - return true; - } - if (lhsType instanceof Class) { - Class lhsClass = (Class) lhsType; - - } - - return false; - } - -} diff --git a/source/utils/utils-common/src/main/java/com/jd/blockchain/utils/Dataset.java b/source/utils/utils-common/src/main/java/com/jd/blockchain/utils/Dataset.java new file mode 100644 index 00000000..2a82bd19 --- /dev/null +++ b/source/utils/utils-common/src/main/java/com/jd/blockchain/utils/Dataset.java @@ -0,0 +1,101 @@ +package com.jd.blockchain.utils; + +/** + * Key-Value data set; + * + * @author huanghaiquan + * + * @param + * @param + */ +public interface Dataset { + + /** + * Total count of data entries; + * + * @return + */ + long getDataCount(); + + /** + * Create or update the value associated the specified key if the version + * checking is passed.
+ * + * The value of the key will be updated only if it's latest version equals the + * specified version argument.
+ * If the key doesn't exist, it will be created when the version arg was -1. + *

+ * If updating is performed, the version of the key increase by 1.
+ * If creating is performed, the version of the key initialize by 0.
+ * + * @param key The key of data; + * @param value The value of data; + * @param version The expected latest version of the key. + * @return The new version of the key.
+ * If the key is new created success, then return 0;
+ * If the key is updated success, then return the new version;
+ * If this operation fail by version checking or other reason, then + * return -1; + */ + long setValue(K key, V value, long version); + + /** + * Return the specified version's value;
+ * + * If the key with the specified version doesn't exist, then return null;
+ * If the version is specified to -1, then return the latest version's value; + * + * @param key + * @param version + */ + V getValue(K key, long version); + + /** + * Return the value of the latest version; + * + * @param key + * @return return null if not exist; + */ + V getValue(K key); + + /** + * Return the latest version number of the specified key; + * + * @param key + * @return The version number of the specified key; If the key doesn't exist, + * then return -1; + */ + long getVersion(K key); + + /** + * Return the data entry with the specified key; + * + * @param key + * @return Null if the key doesn't exist! + */ + DataEntry getDataEntry(K key); + + /** + * Return the data entry with the specified key and version; + * + * @param key + * @param version + * @return Null if the key doesn't exist! + */ + DataEntry getDataEntry(K key, long version); + + /** + * Ascending iterator; + * + * @return + */ + DataIterator iterator(); + + /** + * Descending iterator; + * + * @return + */ + DataIterator iteratorDesc(); + +} \ No newline at end of file diff --git a/source/utils/utils-common/src/main/java/com/jd/blockchain/utils/DatasetHelper.java b/source/utils/utils-common/src/main/java/com/jd/blockchain/utils/DatasetHelper.java new file mode 100644 index 00000000..acbdce51 --- /dev/null +++ b/source/utils/utils-common/src/main/java/com/jd/blockchain/utils/DatasetHelper.java @@ -0,0 +1,382 @@ +package com.jd.blockchain.utils; + +/** + * Helper for {@link Dataset}; + * + * @author huanghaiquan + * + */ +public class DatasetHelper { + + public static final TypeMapper UTF8_STRING_BYTES_MAPPER = new TypeMapper() { + + @Override + public Bytes encode(String t2) { + return Bytes.fromString(t2); + } + + @Override + public String decode(Bytes t1) { + return t1.toUTF8String(); + } + }; + + public static final TypeMapper BYTES_UTF8_STRING_MAPPER = new TypeMapper() { + + @Override + public String encode(Bytes t1) { + return t1.toUTF8String(); + } + + @Override + public Bytes decode(String t2) { + return Bytes.fromString(t2); + } + }; + + /** + * 适配两个不同类型参数的数据集; + * + * @param 适配输入的 键 类型; + * @param 适配输出的 键 类型; + * @param 适配输入的 值 类型; + * @param 适配输出的 值 类型; + * @param dataset 数据集; + * @param keyMapper 键的映射配置; + * @param valueMapper 值的映射配置; + * @return + */ + public static Dataset map(Dataset dataset) { + return new TypeAdapter(dataset, UTF8_STRING_BYTES_MAPPER, new EmptyMapper()); + } + + /** + * 适配两个不同类型参数的数据集; + * + * @param 适配输入的 键 类型; + * @param 适配输出的 键 类型; + * @param 适配输入的 值 类型; + * @param 适配输出的 值 类型; + * @param dataset 数据集; + * @param keyMapper 键的映射配置; + * @param valueMapper 值的映射配置; + * @return + */ + public static Dataset map(Dataset dataset, TypeMapper valueMapper) { + return new TypeAdapter(dataset, UTF8_STRING_BYTES_MAPPER, valueMapper); + } + + /** + * 适配两个不同类型参数的数据集; + * + * @param 适配输入的 键 类型; + * @param 适配输出的 键 类型; + * @param 适配输入的 值 类型; + * @param 适配输出的 值 类型; + * @param dataset 数据集; + * @param keyMapper 键的映射配置; + * @param valueMapper 值的映射配置; + * @return + */ + public static Dataset map(Dataset dataset, TypeMapper keyMapper, + TypeMapper valueMapper) { + return new TypeAdapter(dataset, keyMapper, valueMapper); + } + + /** + * 监听对数据集的变更; + * + * @param 键 类型; + * @param 值 类型; + * @param dataset 要监听的数据集; + * @param listener 要植入的监听器; + * @return 植入监听器的数据集实例; + */ + public static Dataset listen(Dataset dataset, DataChangedListener listener) { + return new DatasetUpdatingMonitor(dataset, listener); + } + + /** + * 数据修改监听器; + * + * @author huanghaiquan + * + * @param + * @param + */ + public static interface DataChangedListener { + + void onChanged(K key, V value, long expectedVersion, long newVersion); + + } + + /** + * 类型映射接口; + * + * @author huanghaiquan + * + * @param + * @param + */ + public static interface TypeMapper { + + T1 encode(T2 t2); + + T2 decode(T1 t1); + + } + + private static class EmptyMapper implements TypeMapper { + + @Override + public T encode(T t) { + return t; + } + + @Override + public T decode(T t) { + return t; + } + + } + + private static class DatasetUpdatingMonitor implements Dataset { + + private Dataset dataset; + + private DataChangedListener listener; + + public DatasetUpdatingMonitor(Dataset dataset, DataChangedListener listener) { + this.dataset = dataset; + this.listener = listener; + } + + @Override + public long getDataCount() { + return dataset.getDataCount(); + } + + @Override + public long setValue(K key, V value, long version) { + long newVersion = dataset.setValue(key, value, version); + if (newVersion > -1) { + listener.onChanged(key, value, version, newVersion); + } + return newVersion; + } + + @Override + public V getValue(K key, long version) { + return dataset.getValue(key, version); + } + + @Override + public V getValue(K key) { + return dataset.getValue(key); + } + + @Override + public long getVersion(K key) { + return dataset.getVersion(key); + } + + @Override + public DataEntry getDataEntry(K key) { + return dataset.getDataEntry(key); + } + + @Override + public DataEntry getDataEntry(K key, long version) { + return dataset.getDataEntry(key, version); + } + + @Override + public DataIterator iterator() { + return dataset.iterator(); + } + + @Override + public DataIterator iteratorDesc() { + return dataset.iteratorDesc(); + } + + } + + /** + * 类型适配器; + * + * @author huanghaiquan + * + * @param + * @param + * @param + * @param + */ + private static class TypeAdapter implements Dataset { + private Dataset dataset; + private TypeMapper keyMapper; + private TypeMapper valueMapper; + + public TypeAdapter(Dataset dataset, TypeMapper keyMapper, TypeMapper valueMapper) { + this.dataset = dataset; + this.keyMapper = keyMapper; + this.valueMapper = valueMapper; + } + + @Override + public long getDataCount() { + return dataset.getDataCount(); + } + + @Override + public long setValue(K2 key, V2 value, long version) { + K1 key1 = keyMapper.encode(key); + V1 value1 = valueMapper.encode(value); + return dataset.setValue(key1, value1, version); + } + + @Override + public V2 getValue(K2 key, long version) { + K1 k = keyMapper.encode(key); + V1 v = dataset.getValue(k, version); + if (v == null) { + return null; + } + return valueMapper.decode(v); + } + + @Override + public V2 getValue(K2 key) { + K1 k = keyMapper.encode(key); + V1 v = dataset.getValue(k); + if (v == null) { + return null; + } + return valueMapper.decode(v); + } + + @Override + public long getVersion(K2 key) { + K1 k = keyMapper.encode(key); + return dataset.getVersion(k); + } + + @Override + public DataEntry getDataEntry(K2 key) { + K1 k = keyMapper.encode(key); + DataEntry entry = dataset.getDataEntry(k); + if (entry == null) { + return null; + } + V2 v = valueMapper.decode(entry.getValue()); + return new KeyValueEntry(key, v, entry.getVersion()); + } + + @Override + public DataEntry getDataEntry(K2 key, long version) { + K1 k = keyMapper.encode(key); + DataEntry entry = dataset.getDataEntry(k, version); + if (entry == null) { + return null; + } + V2 v = valueMapper.decode(entry.getValue()); + return new KeyValueEntry(key, v, entry.getVersion()); + } + + @Override + public DataIterator iterator() { + DataIterator it = dataset.iterator(); + return new DataIteratorAdapter(it, keyMapper, valueMapper); + } + + @Override + public DataIterator iteratorDesc() { + DataIterator it = dataset.iteratorDesc(); + return new DataIteratorAdapter(it, keyMapper, valueMapper); + } + + } + + private static class DataIteratorAdapter implements DataIterator { + + private DataIterator iterator; + + private TypeMapper keyMapper; + private TypeMapper valueMapper; + + public DataIteratorAdapter(DataIterator iterator, TypeMapper keyMapper, + TypeMapper valueMapper) { + this.iterator = iterator; + this.keyMapper = keyMapper; + this.valueMapper = valueMapper; + } + + @Override + public void skip(long count) { + iterator.skip(count); + } + + @Override + public DataEntry next() { + DataEntry entry = iterator.next(); + return cast(entry); + } + + private DataEntry cast(DataEntry entry) { + if (entry == null) { + return null; + } + + K2 k = keyMapper.decode(entry.getKey()); + V2 v = valueMapper.decode(entry.getValue()); + return new KeyValueEntry(k, v, entry.getVersion()); + } + + @SuppressWarnings("unchecked") + @Override + public DataEntry[] next(int count) { + DataEntry[] entries = iterator.next(count); + if (entries == null) { + return null; + } + if (entries.length == 0) { + return (DataEntry[]) entries; + } + return ArrayUtils.castTo(entries, DataEntry.class, e -> cast(e)); + } + + @Override + public boolean hasNext() { + return iterator.hasNext(); + } + + } + + private static class KeyValueEntry implements DataEntry { + + private K key; + + private V value; + + private long version; + + public KeyValueEntry(K key, V value, long version) { + this.key = key; + this.value = value; + this.version = version; + } + + public K getKey() { + return key; + } + + public long getVersion() { + return version; + } + + public V getValue() { + return value; + } + + } +} diff --git a/source/utils/utils-http/pom.xml b/source/utils/utils-http/pom.xml index 61871c46..5f6236f4 100644 --- a/source/utils/utils-http/pom.xml +++ b/source/utils/utils-http/pom.xml @@ -4,7 +4,7 @@ com.jd.blockchain utils - 1.1.1-PACK20191209 + 1.1.2.RELEASE diff --git a/source/utils/utils-serialize/pom.xml b/source/utils/utils-serialize/pom.xml index 5e514438..acdd4ed2 100644 --- a/source/utils/utils-serialize/pom.xml +++ b/source/utils/utils-serialize/pom.xml @@ -4,7 +4,7 @@ com.jd.blockchain utils - 1.1.1-PACK20191209 + 1.1.2.RELEASE utils-serialize diff --git a/source/utils/utils-test/pom.xml b/source/utils/utils-test/pom.xml index 39d93ed6..0fce0b58 100644 --- a/source/utils/utils-test/pom.xml +++ b/source/utils/utils-test/pom.xml @@ -4,7 +4,7 @@ com.jd.blockchain utils - 1.1.1-PACK20191209 + 1.1.2.RELEASE utils-test diff --git a/source/utils/utils-web-server/pom.xml b/source/utils/utils-web-server/pom.xml index 7120f2ea..109fd82e 100644 --- a/source/utils/utils-web-server/pom.xml +++ b/source/utils/utils-web-server/pom.xml @@ -4,7 +4,7 @@ com.jd.blockchain utils - 1.1.1-PACK20191209 + 1.1.2.RELEASE utils-web-server diff --git a/source/utils/utils-web/pom.xml b/source/utils/utils-web/pom.xml index 23e0fac4..b635dfb0 100644 --- a/source/utils/utils-web/pom.xml +++ b/source/utils/utils-web/pom.xml @@ -4,7 +4,7 @@ com.jd.blockchain utils - 1.1.1-PACK20191209 + 1.1.2.RELEASE utils-web