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.blockchainjdchain-root
- 1.1.1-PACK20191209
+ 1.1.2.RELEASEbase
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.blockchainjdchain-root
- 1.1.1-PACK20191209
+ 1.1.2.RELEASEbinary-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.blockchainconsensus
- 1.1.1-PACK20191209
+ 1.1.2.RELEASEconsensus-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.blockchainconsensus
- 1.1.1-PACK20191209
+ 1.1.2.RELEASEconsensus-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.blockchainconsensus
- 1.1.1-PACK20191209
+ 1.1.2.RELEASEconsensus-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.blockchainjdchain-root
- 1.1.1-PACK20191209
+ 1.1.2.RELEASEconsensuspom
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.blockchaincontract
- 1.1.1-PACK20191209
+ 1.1.2.RELEASEcontract-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.blockchaincontract
- 1.1.1-PACK20191209
+ 1.1.2.RELEASEcontract-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.blockchaincontract
- 1.1.1-PACK20191209
+ 1.1.2.RELEASEcontract-maven-pluginmaven-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 @@
contractcom.jd.blockchain
- 1.1.1-PACK20191209
+ 1.1.2.RELEASE4.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.blockchainjdchain-root
- 1.1.1-PACK20191209
+ 1.1.2.RELEASEcontractpom
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.blockchaincrypto
- 1.1.1-PACK20191209
+ 1.1.2.RELEASEcrypto-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.blockchaincrypto
- 1.1.1-PACK20191209
+ 1.1.2.RELEASEcrypto-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.blockchaincrypto
- 1.1.1-PACK20191209
+ 1.1.2.RELEASEcrypto-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 @@
cryptocom.jd.blockchain
- 1.1.1-PACK20191209
+ 1.1.2.RELEASE4.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.blockchaincrypto
- 1.1.1-PACK20191209
+ 1.1.2.RELEASEcrypto-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.blockchainjdchain-root
- 1.1.1-PACK20191209
+ 1.1.2.RELEASEcryptopom
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.blockchaindeployment
- 1.1.1-PACK20191209
+ 1.1.2.RELEASEdeployment-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/scriptsbin
+ unixsrc/main/resources/configconfig
+ unixsrc/main/resources/docsdocs
+ 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.blockchaindeployment
- 1.1.1-PACK20191209
+ 1.1.2.RELEASEdeployment-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/scriptsbin
+ unixsrc/main/resources/configconfig
+ unixsrc/main/resources/docsdocs
+ 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.blockchainjdchain-root
- 1.1.1-PACK20191209
+ 1.1.2.RELEASEdeploymentpom
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.blockchainjdchain-root
- 1.1.1-PACK20191209
+ 1.1.2.RELEASEgateway
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.blockchainledger
- 1.1.1-PACK20191209
+ 1.1.2.RELEASEledger-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 {
*