diff --git a/source/base/src/main/resources/log4j2.xml b/source/base/src/main/resources/log4j2.xml
new file mode 100644
index 00000000..c889aa69
--- /dev/null
+++ b/source/base/src/main/resources/log4j2.xml
@@ -0,0 +1,62 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/source/ledger/ledger-core/pom.xml b/source/ledger/ledger-core/pom.xml
index 34497874..f246b6d2 100644
--- a/source/ledger/ledger-core/pom.xml
+++ b/source/ledger/ledger-core/pom.xml
@@ -63,7 +63,7 @@
test
-
+
@@ -78,42 +78,32 @@
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/LedgerEditor.java b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/LedgerEditor.java
index efa3e750..ced98b45 100644
--- a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/LedgerEditor.java
+++ b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/LedgerEditor.java
@@ -1,5 +1,6 @@
package com.jd.blockchain.ledger.core;
+import com.jd.blockchain.crypto.HashDigest;
import com.jd.blockchain.ledger.LedgerBlock;
import com.jd.blockchain.ledger.LedgerException;
import com.jd.blockchain.ledger.LedgerTransaction;
@@ -18,6 +19,20 @@ import com.jd.blockchain.ledger.TransactionRequest;
*/
public interface LedgerEditor {
+ /**
+ * 账本Hash;
+ *
+ * @return
+ */
+ HashDigest getLedgerHash();
+
+ /**
+ * 新区块的高度;
+ *
+ * @return
+ */
+ long getBlockHeight();
+
/**
* 开始新事务;
*
@@ -32,7 +47,8 @@ public interface LedgerEditor {
* 或者全部回滚(通过方法 {@link LedgerTransactionContext#rollback()}),以此实现原子性写入;
*
*
- * 每一次事务性的账本写入操作在提交后,都会记录该事务相关的系统全局快照,以交易对象 {@link LedgerTransaction} 进行保存;
+ * 每一次事务性的账本写入操作在提交后,都会记录该事务相关的系统全局快照,以交易对象 {@link LedgerTransaction} 进行保存;
+ *
*
* 注:方法不解析、不执行交易中的操作;
*
diff --git a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/LedgerRepositoryImpl.java b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/LedgerRepositoryImpl.java
index 69e3223f..7b9b4a9a 100644
--- a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/LedgerRepositoryImpl.java
+++ b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/LedgerRepositoryImpl.java
@@ -401,7 +401,7 @@ public class LedgerRepositoryImpl implements LedgerRepository {
"A new block is in process, cann't create another one until it finish by committing or canceling.");
}
LedgerBlock previousBlock = getLatestBlock();
- LedgerTransactionalEditor editor = LedgerTransactionalEditor.createEditor(
+ LedgerTransactionalEditor editor = LedgerTransactionalEditor.createEditor(ledgerHash,
getAdminInfo().getMetadata().getSetting(), previousBlock, keyPrefix, exPolicyStorage,
versioningStorage);
NewBlockCommittingMonitor committingMonitor = new NewBlockCommittingMonitor(editor, this);
@@ -479,7 +479,7 @@ public class LedgerRepositoryImpl implements LedgerRepository {
}
static TransactionSet newTransactionSet(LedgerSetting ledgerSetting, String keyPrefix,
- ExPolicyKVStorage ledgerExStorage, VersioningKVStorage ledgerVerStorage) {
+ ExPolicyKVStorage ledgerExStorage, VersioningKVStorage ledgerVerStorage) {
// TransactionSet transactionSet = new
// TransactionSet(ledgerSetting.getCryptoSetting(),
// PrefixAppender.prefix(TRANSACTION_SET_PREFIX, ledgerExStorage),
@@ -576,6 +576,16 @@ public class LedgerRepositoryImpl implements LedgerRepository {
this.ledgerRepo = ledgerRepo;
}
+ @Override
+ public HashDigest getLedgerHash() {
+ return editor.getLedgerHash();
+ }
+
+ @Override
+ public long getBlockHeight() {
+ return editor.getBlockHeight();
+ }
+
@Override
public LedgerTransactionContext newTransaction(TransactionRequest txRequest) {
return editor.newTransaction(txRequest);
diff --git a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/LedgerTransactionalEditor.java b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/LedgerTransactionalEditor.java
index d939c865..a84d7692 100644
--- a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/LedgerTransactionalEditor.java
+++ b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/LedgerTransactionalEditor.java
@@ -26,6 +26,11 @@ public class LedgerTransactionalEditor implements LedgerEditor {
System.out.println("------ [[ parallel-dbwrite=" + PARALLEL_DB_WRITE + " ]] ------");
}
+ /**
+ * 账本Hash,创世区块的编辑器则返回 null;
+ */
+ private HashDigest ledgerHash;
+
private final String ledgerKeyPrefix;
private CryptoSetting cryptoSetting;
@@ -49,8 +54,9 @@ public class LedgerTransactionalEditor implements LedgerEditor {
private LedgerDataContext newTxCtx;
- private LedgerTransactionalEditor(CryptoSetting cryptoSetting, LedgerBlockData newlyBlock,
+ private LedgerTransactionalEditor(HashDigest ledgerHash, CryptoSetting cryptoSetting, LedgerBlockData newlyBlock,
StagedSnapshot startingPoint, String ledgerKeyPrefix, BufferedKVStorage bufferedStorage) {
+ this.ledgerHash = ledgerHash;
this.ledgerKeyPrefix = ledgerKeyPrefix;
this.cryptoSetting = cryptoSetting;
this.newlyBlock = newlyBlock;
@@ -59,8 +65,9 @@ public class LedgerTransactionalEditor implements LedgerEditor {
this.stagedSnapshots.push(startingPoint);
}
- public static LedgerTransactionalEditor createEditor(LedgerSetting ledgerSetting, LedgerBlock previousBlock,
- String ledgerKeyPrefix, ExPolicyKVStorage ledgerExStorage, VersioningKVStorage ledgerVerStorage) {
+ public static LedgerTransactionalEditor createEditor(HashDigest ledgerHash, LedgerSetting ledgerSetting,
+ LedgerBlock previousBlock, String ledgerKeyPrefix, ExPolicyKVStorage ledgerExStorage,
+ VersioningKVStorage ledgerVerStorage) {
// new block;
LedgerBlockData currBlock = new LedgerBlockData(previousBlock.getHeight() + 1, previousBlock.getLedgerHash(),
previousBlock.getHash());
@@ -71,7 +78,7 @@ public class LedgerTransactionalEditor implements LedgerEditor {
StagedSnapshot startingPoint = new TxSnapshot(previousBlock, previousBlock.getTransactionSetHash());
// instantiate editor;
- return new LedgerTransactionalEditor(ledgerSetting.getCryptoSetting(), currBlock, startingPoint,
+ return new LedgerTransactionalEditor(ledgerHash, ledgerSetting.getCryptoSetting(), currBlock, startingPoint,
ledgerKeyPrefix, txStagedStorage);
}
@@ -81,7 +88,7 @@ public class LedgerTransactionalEditor implements LedgerEditor {
StagedSnapshot startingPoint = new GenesisSnapshot(initSetting);
// init storage;
BufferedKVStorage txStagedStorage = new BufferedKVStorage(ledgerExStorage, ledgerVerStorage, false);
- return new LedgerTransactionalEditor(initSetting.getCryptoSetting(), genesisBlock, startingPoint,
+ return new LedgerTransactionalEditor(null, initSetting.getCryptoSetting(), genesisBlock, startingPoint,
ledgerKeyPrefix, txStagedStorage);
}
@@ -102,12 +109,39 @@ public class LedgerTransactionalEditor implements LedgerEditor {
// return lastTxCtx.getDataSet();
// }
- public LedgerBlock getNewlyBlock() {
+ LedgerBlock getNewlyBlock() {
return newlyBlock;
}
+ @Override
+ public long getBlockHeight() {
+ return newlyBlock.getHeight();
+ }
+
+ @Override
+ public HashDigest getLedgerHash() {
+ return ledgerHash;
+ }
+
+ private boolean isRequestedLedger(TransactionRequest txRequest) {
+ HashDigest reqLedgerHash = txRequest.getTransactionContent().getLedgerHash();
+ if (ledgerHash == reqLedgerHash) {
+ return true;
+ }
+ if (ledgerHash == null || reqLedgerHash == null) {
+ return false;
+ }
+ return ledgerHash.equals(reqLedgerHash);
+ }
+
@Override
public LedgerTransactionContext newTransaction(TransactionRequest txRequest) {
+ // 验证账本是否;
+ if (!isRequestedLedger(txRequest)) {
+ throw new LedgerException("This ledger is not the target ledger of transaction request["
+ + txRequest.getTransactionContent().getHash() + "]!");
+ }
+
checkState();
// TODO:验证交易签名;
diff --git a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/TransactionBatchProcessor.java b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/TransactionBatchProcessor.java
index b4795c01..b14b3678 100644
--- a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/TransactionBatchProcessor.java
+++ b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/TransactionBatchProcessor.java
@@ -9,11 +9,13 @@ import org.slf4j.LoggerFactory;
import com.jd.blockchain.crypto.HashDigest;
import com.jd.blockchain.ledger.BytesValue;
+import com.jd.blockchain.ledger.DigitalSignature;
import com.jd.blockchain.ledger.LedgerBlock;
import com.jd.blockchain.ledger.LedgerException;
import com.jd.blockchain.ledger.Operation;
import com.jd.blockchain.ledger.OperationResult;
import com.jd.blockchain.ledger.OperationResultData;
+import com.jd.blockchain.ledger.TransactionContent;
import com.jd.blockchain.ledger.TransactionRequest;
import com.jd.blockchain.ledger.TransactionResponse;
import com.jd.blockchain.ledger.TransactionState;
@@ -26,6 +28,9 @@ import com.jd.blockchain.ledger.core.TransactionRequestContext;
import com.jd.blockchain.service.TransactionBatchProcess;
import com.jd.blockchain.service.TransactionBatchResult;
import com.jd.blockchain.service.TransactionBatchResultHandle;
+import com.jd.blockchain.transaction.TxBuilder;
+import com.jd.blockchain.transaction.TxRequestBuilder;
+import com.jd.blockchain.transaction.TxResponseMessage;
import com.jd.blockchain.utils.Bytes;
public class TransactionBatchProcessor implements TransactionBatchProcess {
@@ -50,12 +55,9 @@ public class TransactionBatchProcessor implements TransactionBatchProcess {
private TransactionBatchResult batchResult;
/**
- * @param newBlockEditor
- * 新区块的数据编辑器;
- * @param previousBlockDataset
- * 新区块的前一个区块的数据集;即未提交新区块之前的经过共识的账本最新数据集;
- * @param opHandles
- * 操作处理对象注册表;
+ * @param newBlockEditor 新区块的数据编辑器;
+ * @param previousBlockDataset 新区块的前一个区块的数据集;即未提交新区块之前的经过共识的账本最新数据集;
+ * @param opHandles 操作处理对象注册表;
*/
public TransactionBatchProcessor(LedgerEditor newBlockEditor, LedgerDataSet previousBlockDataset,
OperationHandleRegisteration opHandles, LedgerService ledgerService) {
@@ -65,6 +67,18 @@ public class TransactionBatchProcessor implements TransactionBatchProcess {
this.ledgerService = ledgerService;
}
+ private boolean isRequestedLedger(TransactionRequest txRequest) {
+ HashDigest currLedgerHash = newBlockEditor.getLedgerHash();
+ HashDigest reqLedgerHash = txRequest.getTransactionContent().getLedgerHash();
+ if (currLedgerHash == reqLedgerHash) {
+ return true;
+ }
+ if (currLedgerHash == null || reqLedgerHash == null) {
+ return false;
+ }
+ return currLedgerHash.equals(reqLedgerHash);
+ }
+
/*
* (non-Javadoc)
*
@@ -74,14 +88,61 @@ public class TransactionBatchProcessor implements TransactionBatchProcess {
*/
@Override
public TransactionResponse schedule(TransactionRequest request) {
- // 此调用将会验证交易签名,验签失败将会抛出异常,同时,不记录签名错误的交易到链上;
- LedgerTransactionContext txCtx = newBlockEditor.newTransaction(request);
- TransactionState result;
+ TransactionResponse resp;
+ try {
+ if (!isRequestedLedger(request)) {
+ // 抛弃不属于当前账本的交易请求;
+ resp = discard(request, TransactionState.DISCARD_BY_WRONG_LEDGER);
+ responseList.add(resp);
+ return resp;
+ }
+ if (!verifyTxContent(request)) {
+ // 抛弃哈希和签名校验失败的交易请求;
+ resp = discard(request, TransactionState.DISCARD_BY_WRONG_CONTENT_SIGNATURE);
+ responseList.add(resp);
+ return resp;
+ }
- List operationResults = new ArrayList<>();
+ LOGGER.debug("Start handling transaction... --[BlockHeight=%s][RequestHash=%s][TxHash=%s]",
+ newBlockEditor.getBlockHeight(), request.getHash(), request.getTransactionContent().getHash());
+ // 创建交易上下文;
+ // 此调用将会验证交易签名,验签失败将会抛出异常,同时,不记录签名错误的交易到链上;
+ LedgerTransactionContext txCtx = newBlockEditor.newTransaction(request);
+
+ // 处理交易;
+ resp = handleTx(request, txCtx);
+
+ LOGGER.debug("Complete handling transaction. --[BlockHeight=%s][RequestHash=%s][TxHash=%s]",
+ newBlockEditor.getBlockHeight(), request.getHash(), request.getTransactionContent().getHash());
+
+ responseList.add(resp);
+ return resp;
+ } catch (Exception e) {
+ // 抛弃发生处理异常的交易请求;
+ resp = discard(request, TransactionState.SYSTEM_ERROR);
+ LOGGER.error(String.format(
+ "Discard transaction rollback caused by the system exception! --[BlockHeight=%s][RequestHash=%s][TxHash=%s] --%s",
+ newBlockEditor.getBlockHeight(), request.getHash(), request.getTransactionContent().getHash(),
+ e.getMessage()), e);
+
+ responseList.add(resp);
+ return resp;
+ }
+ }
+ /**
+ * 处理交易;
+ *
+ * 此方法会处理所有的异常,以不同结果的 {@link TransactionResponse} 返回;
+ *
+ * @param request
+ * @param txCtx
+ * @return
+ */
+ private TransactionResponse handleTx(TransactionRequest request, LedgerTransactionContext txCtx) {
+ TransactionState result;
+ List operationResults = new ArrayList<>();
try {
-
LedgerDataSet dataset = txCtx.getDataSet();
TransactionRequestContext reqCtx = new TransactionRequestContextImpl(request);
// TODO: 验证签名者的有效性;
@@ -101,7 +162,8 @@ public class TransactionBatchProcessor implements TransactionBatchProcess {
OperationHandleContext handleContext = new OperationHandleContext() {
@Override
public void handle(Operation operation) {
- //assert; Instance of operation are one of User related operations or DataAccount related operations;
+ // assert; Instance of operation are one of User related operations or
+ // DataAccount related operations;
OperationHandle hdl = opHandles.getHandle(operation.getClass());
hdl.process(operation, dataset, reqCtx, previousBlockDataset, this, ledgerService);
}
@@ -110,7 +172,8 @@ public class TransactionBatchProcessor implements TransactionBatchProcess {
int opIndex = 0;
for (Operation op : ops) {
opHandle = opHandles.getHandle(op.getClass());
- BytesValue opResult = opHandle.process(op, dataset, reqCtx, previousBlockDataset, handleContext, ledgerService);
+ BytesValue opResult = opHandle.process(op, dataset, reqCtx, previousBlockDataset, handleContext,
+ ledgerService);
if (opResult != null) {
operationResults.add(new OperationResultData(opIndex, opResult));
}
@@ -119,19 +182,22 @@ public class TransactionBatchProcessor implements TransactionBatchProcess {
// 提交交易(事务);
result = TransactionState.SUCCESS;
-
txCtx.commit(result, operationResults);
} catch (LedgerException e) {
// TODO: 识别更详细的异常类型以及执行对应的处理;
result = TransactionState.LEDGER_ERROR;
txCtx.discardAndCommit(TransactionState.LEDGER_ERROR, operationResults);
- LOGGER.warn(String.format("Transaction rollback caused by the ledger exception! --[TxHash=%s] --%s",
- request.getHash().toBase58(), e.getMessage()), e);
+ LOGGER.error(String.format(
+ "Transaction rollback caused by the ledger exception! --[BlockHeight=%s][RequestHash=%s][TxHash=%s] --%s",
+ newBlockEditor.getBlockHeight(), request.getHash(), request.getTransactionContent().getHash(),
+ e.getMessage()), e);
} catch (Exception e) {
result = TransactionState.SYSTEM_ERROR;
txCtx.discardAndCommit(TransactionState.SYSTEM_ERROR, operationResults);
- LOGGER.warn(String.format("Transaction rollback caused by the system exception! --[TxHash=%s] --%s",
- request.getHash().toBase58(), e.getMessage()), e);
+ LOGGER.error(String.format(
+ "Transaction rollback caused by the system exception! --[BlockHeight=%s][RequestHash=%s][TxHash=%s] --%s",
+ newBlockEditor.getBlockHeight(), request.getHash(), request.getTransactionContent().getHash(),
+ e.getMessage()), e);
}
TxResponseHandle resp = new TxResponseHandle(request, result);
@@ -139,9 +205,50 @@ public class TransactionBatchProcessor implements TransactionBatchProcess {
OperationResult[] operationResultArray = new OperationResult[operationResults.size()];
resp.setOperationResults(operationResults.toArray(operationResultArray));
}
+ return resp;
+ }
- responseList.add(resp);
+ private boolean verifyTxContent(TransactionRequest request) {
+ TransactionContent txContent = request.getTransactionContent();
+ if (!TxBuilder.verifyTxContentHash(txContent, txContent.getHash())) {
+ return false;
+ }
+ DigitalSignature[] endpointSignatures = request.getEndpointSignatures();
+ if (endpointSignatures != null) {
+ for (DigitalSignature signature : endpointSignatures) {
+ if (!TxRequestBuilder.verifyHashSignature(txContent.getHash(), signature.getDigest(),
+ signature.getPubKey())) {
+ return false;
+ }
+ }
+ }
+ DigitalSignature[] nodeSignatures = request.getNodeSignatures();
+ if (nodeSignatures != null) {
+ for (DigitalSignature signature : nodeSignatures) {
+ if (!TxRequestBuilder.verifyHashSignature(txContent.getHash(), signature.getDigest(),
+ signature.getPubKey())) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+ /**
+ * 直接丢弃交易;
+ *
+ * @param request
+ * @param txState
+ * @return 丢弃交易的回复;只包含原始请求中的交易内容哈希和交易被丢弃的原因,而不包含区块信息;
+ */
+ private TransactionResponse discard(TransactionRequest request, TransactionState txState) {
+ // 丢弃交易的回复;只返回请求的交易内容哈希和交易被丢弃的原因,
+ TxResponseMessage resp = new TxResponseMessage(request.getTransactionContent().getHash());
+ resp.setExecutionState(txState);
+
+ LOGGER.error("Discard transaction request! --[BlockHeight=%s][RequestHash=%s][TxHash=%s][ResponseState=%s]",
+ newBlockEditor.getBlockHeight(), request.getHash(), request.getTransactionContent().getHash(),
+ resp.getExecutionState());
return resp;
}
diff --git a/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/ContractInvokingTest.java b/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/ContractInvokingTest.java
index eab81350..daffa40b 100644
--- a/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/ContractInvokingTest.java
+++ b/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/ContractInvokingTest.java
@@ -184,7 +184,7 @@ public class ContractInvokingTest {
// 创建账本;
LedgerEditor ldgEdt = LedgerTransactionalEditor.createEditor(initSetting, LEDGER_KEY_PREFIX, storage, storage);
- TransactionRequest genesisTxReq = LedgerTestUtils.createTxRequest_UserReg(null);
+ TransactionRequest genesisTxReq = LedgerTestUtils.createLedgerInitTxRequest(partiKeys);
LedgerTransactionContext genisisTxCtx = ldgEdt.newTransaction(genesisTxReq);
LedgerDataSet ldgDS = genisisTxCtx.getDataSet();
diff --git a/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/LedgerEditerTest.java b/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/LedgerEditerTest.java
index c7f3d6e6..dfab92c9 100644
--- a/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/LedgerEditerTest.java
+++ b/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/LedgerEditerTest.java
@@ -16,6 +16,7 @@ import com.jd.blockchain.crypto.SignatureFunction;
import com.jd.blockchain.crypto.service.classic.ClassicAlgorithm;
import com.jd.blockchain.crypto.service.classic.ClassicCryptoService;
import com.jd.blockchain.crypto.service.sm.SMCryptoService;
+import com.jd.blockchain.ledger.BlockchainKeyGenerator;
import com.jd.blockchain.ledger.BlockchainKeypair;
import com.jd.blockchain.ledger.BytesValue;
import com.jd.blockchain.ledger.DataType;
@@ -52,6 +53,13 @@ public class LedgerEditerTest {
private static final String LEDGER_KEY_PREFIX = "LDG://";
private SignatureFunction signatureFunction;
+ private BlockchainKeypair parti0 = BlockchainKeyGenerator.getInstance().generate();
+ private BlockchainKeypair parti1 = BlockchainKeyGenerator.getInstance().generate();
+ private BlockchainKeypair parti2 = BlockchainKeyGenerator.getInstance().generate();
+ private BlockchainKeypair parti3 = BlockchainKeyGenerator.getInstance().generate();
+
+ private BlockchainKeypair[] participants = { parti0, parti1, parti2, parti3 };
+
/**
* 初始化一个;
*/
@@ -74,8 +82,8 @@ public class LedgerEditerTest {
return LedgerTransactionalEditor.createEditor(initSetting, LEDGER_KEY_PREFIX, storage, storage);
}
- private LedgerTransactionContext createGenisisTx(LedgerEditor ldgEdt) {
- TransactionRequest genesisTxReq = LedgerTestUtils.createTxRequest_UserReg(null);
+ private LedgerTransactionContext createGenisisTx(LedgerEditor ldgEdt, BlockchainKeypair[] partis) {
+ TransactionRequest genesisTxReq = LedgerTestUtils.createLedgerInitTxRequest(partis);
LedgerTransactionContext txCtx = ldgEdt.newTransaction(genesisTxReq);
@@ -86,7 +94,7 @@ public class LedgerEditerTest {
@Test
public void testWriteDataAccoutKvOp() {
LedgerEditor ldgEdt = createLedgerInitEditor();
- LedgerTransactionContext genisisTxCtx = createGenisisTx(ldgEdt);
+ LedgerTransactionContext genisisTxCtx = createGenisisTx(ldgEdt, participants);
LedgerDataSet ldgDS = genisisTxCtx.getDataSet();
AsymmetricKeypair cryptoKeyPair = signatureFunction.generateKeypair();
@@ -119,7 +127,7 @@ public class LedgerEditerTest {
@Test
public void testGennesisBlockCreation() {
LedgerEditor ldgEdt = createLedgerInitEditor();
- LedgerTransactionContext genisisTxCtx = createGenisisTx(ldgEdt);
+ LedgerTransactionContext genisisTxCtx = createGenisisTx(ldgEdt, participants);
LedgerDataSet ldgDS = genisisTxCtx.getDataSet();
AsymmetricKeypair cryptoKeyPair = signatureFunction.generateKeypair();
@@ -146,5 +154,5 @@ public class LedgerEditerTest {
ldgEdt.commit();
}
-
+
}
diff --git a/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/LedgerManagerTest.java b/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/LedgerManagerTest.java
index 9639602c..73e4a8c1 100644
--- a/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/LedgerManagerTest.java
+++ b/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/LedgerManagerTest.java
@@ -63,6 +63,13 @@ public class LedgerManagerTest {
public static final String[] SUPPORTED_PROVIDERS = { ClassicCryptoService.class.getName(),
SMCryptoService.class.getName() };
+ private BlockchainKeypair parti0 = BlockchainKeyGenerator.getInstance().generate();
+ private BlockchainKeypair parti1 = BlockchainKeyGenerator.getInstance().generate();
+ private BlockchainKeypair parti2 = BlockchainKeyGenerator.getInstance().generate();
+ private BlockchainKeypair parti3 = BlockchainKeyGenerator.getInstance().generate();
+
+ private BlockchainKeypair[] participants = { parti0, parti1, parti2, parti3 };
+
private SignatureFunction signatureFunction;
@Before
@@ -83,13 +90,13 @@ public class LedgerManagerTest {
LedgerEditor ldgEdt = ledgerManager.newLedger(initSetting, storage);
// 创建一个模拟的创世交易;
- TransactionRequest genesisTxReq = LedgerTestUtils.createTxRequest_UserReg(null);
+ TransactionRequest genesisTxReq = LedgerTestUtils.createLedgerInitTxRequest(participants);
// 记录交易,注册用户;
LedgerTransactionContext txCtx = ldgEdt.newTransaction(genesisTxReq);
LedgerDataSet ldgDS = txCtx.getDataSet();
BlockchainKeypair userKP = BlockchainKeyGenerator.getInstance().generate();
-
+
UserAccount userAccount = ldgDS.getUserAccountSet().register(userKP.getAddress(), userKP.getPubKey());
userAccount.setProperty("Name", "孙悟空", -1);
userAccount.setProperty("Age", "10000", -1);
diff --git a/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/LedgerTestUtils.java b/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/LedgerTestUtils.java
index 3a631ad3..ca405b35 100644
--- a/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/LedgerTestUtils.java
+++ b/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/LedgerTestUtils.java
@@ -38,10 +38,10 @@ public class LedgerTestUtils {
private static Random rand = new Random();
- public static TransactionRequest createTxRequest_UserReg(HashDigest ledgerHash) {
- BlockchainKeypair key = BlockchainKeyGenerator.getInstance().generate(ED25519);
- return createTxRequest_UserReg(ledgerHash, key);
- }
+// public static TransactionRequest createTxRequest_UserReg(HashDigest ledgerHash) {
+// BlockchainKeypair key = BlockchainKeyGenerator.getInstance().generate(ED25519);
+// return createTxRequest_UserReg(ledgerHash, key);
+// }
public static LedgerInitSetting createLedgerInitSetting() {
BlockchainKeypair[] partiKeys = new BlockchainKeypair[2];
@@ -81,22 +81,61 @@ public class LedgerTestUtils {
return initSetting;
}
- public static TransactionRequest createTxRequest_UserReg(HashDigest ledgerHash, BlockchainKeypair userKeypair) {
- return createTxRequest_UserReg(ledgerHash, userKeypair, null);
+// public static TransactionRequest createTxRequest_UserReg(BlockchainKeypair userKeypair, HashDigest ledgerHash, BlockchainKeypair... partiKeys) {
+// return createTxRequest_UserReg(userKeypair, ledgerHash, null, null);
+// }
+
+ public static TransactionRequest createLedgerInitTxRequest(BlockchainKeypair... participants) {
+ TxBuilder txBuilder = new TxBuilder(null);
+
+ for (BlockchainKeypair parti : participants) {
+ txBuilder.users().register(parti.getIdentity());
+ }
+
+ TransactionRequestBuilder txReqBuilder = txBuilder.prepareRequest();
+ for (BlockchainKeypair parti : participants) {
+ txReqBuilder.signAsNode(parti);
+ }
+
+ return txReqBuilder.buildRequest();
+ }
+
+ public static TransactionRequest createTxRequest_UserReg(HashDigest ledgerHash,
+ BlockchainKeypair nodeKeypair, BlockchainKeypair... signers) {
+ return createTxRequest_UserReg(BlockchainKeyGenerator.getInstance().generate(), ledgerHash, nodeKeypair,
+ signers);
}
- public static TransactionRequest createTxRequest_UserReg(HashDigest ledgerHash, BlockchainKeypair userKeypair,
- BlockchainKeypair gatewayKeypair) {
+ public static TransactionRequest createTxRequest_UserReg(BlockchainKeypair userKeypair, HashDigest ledgerHash,
+ BlockchainKeypair nodeKeypair, BlockchainKeypair... signers) {
TxBuilder txBuilder = new TxBuilder(ledgerHash);
txBuilder.users().register(userKeypair.getIdentity());
TransactionRequestBuilder txReqBuilder = txBuilder.prepareRequest();
- txReqBuilder.signAsEndpoint(userKeypair);
- if (gatewayKeypair != null) {
- txReqBuilder.signAsNode(gatewayKeypair);
+ txReqBuilder.signAsEndpoint(nodeKeypair);
+ if (nodeKeypair != null) {
+ txReqBuilder.signAsNode(nodeKeypair);
}
-
+
+ return txReqBuilder.buildRequest();
+ }
+
+ public static TransactionRequest createTxRequest_MultiOPs_WithError(HashDigest ledgerHash,
+ BlockchainKeypair userKeypair, BlockchainKeypair nodeKeypair) {
+ TxBuilder txBuilder = new TxBuilder(ledgerHash);
+
+ txBuilder.users().register(userKeypair.getIdentity());
+
+ BlockchainKeypair testKey = BlockchainKeyGenerator.getInstance().generate();
+ txBuilder.dataAccount(testKey.getAddress()).setBytes("AA", "Value".getBytes(), 1);
+
+ TransactionRequestBuilder txReqBuilder = txBuilder.prepareRequest();
+ txReqBuilder.signAsEndpoint(nodeKeypair);
+ if (nodeKeypair != null) {
+ txReqBuilder.signAsNode(nodeKeypair);
+ }
+
return txReqBuilder.buildRequest();
}
diff --git a/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/TransactionBatchProcessorTest.java b/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/TransactionBatchProcessorTest.java
index 72c8a848..1172b3c4 100644
--- a/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/TransactionBatchProcessorTest.java
+++ b/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/TransactionBatchProcessorTest.java
@@ -1,6 +1,7 @@
package test.com.jd.blockchain.ledger;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
@@ -54,19 +55,22 @@ public class TransactionBatchProcessorTest {
private BlockchainKeypair parti2 = BlockchainKeyGenerator.getInstance().generate();
private BlockchainKeypair parti3 = BlockchainKeyGenerator.getInstance().generate();
+ private BlockchainKeypair[] participants = { parti0, parti1, parti2, parti3 };
+
private TransactionRequest transactionRequest;
- // 采用基于内存的 Storage;
- private MemoryKVStorage storage = new MemoryKVStorage();
+ // TODO: 验证无效签名会被拒绝;
@Test
- public void testTxReqProcess() {
+ public void testSingleTxProcess() {
+ final MemoryKVStorage STORAGE = new MemoryKVStorage();
+
// 初始化账本到指定的存储库;
- ledgerHash = initLedger(storage, parti0, parti1, parti2, parti3);
+ ledgerHash = initLedger(STORAGE, parti0, parti1, parti2, parti3);
// 加载账本;
LedgerManager ledgerManager = new LedgerManager();
- LedgerRepository ledgerRepo = ledgerManager.register(ledgerHash, storage);
+ LedgerRepository ledgerRepo = ledgerManager.register(ledgerHash, STORAGE);
// 验证参与方账户的存在;
LedgerDataSet previousBlockDataset = ledgerRepo.getDataSet(ledgerRepo.getLatestBlock());
@@ -85,18 +89,137 @@ public class TransactionBatchProcessorTest {
// 注册新用户;
BlockchainKeypair userKeypair = BlockchainKeyGenerator.getInstance().generate();
transactionRequest = LedgerTestUtils.createTxRequest_UserReg(ledgerHash, userKeypair, parti0);
- txbatchProcessor.schedule(transactionRequest);
+ TransactionResponse txResp = txbatchProcessor.schedule(transactionRequest);
+
+ LedgerBlock newBlock = newBlockEditor.prepare();
+ newBlockEditor.commit();
+
+ // 验证正确性;
+ ledgerManager = new LedgerManager();
+ ledgerRepo = ledgerManager.register(ledgerHash, STORAGE);
+
+ LedgerBlock latestBlock = ledgerRepo.getLatestBlock();
+ assertEquals(newBlock.getHash(), latestBlock.getHash());
+ assertEquals(1, newBlock.getHeight());
+
+ assertEquals(TransactionState.SUCCESS, txResp.getExecutionState());
+ }
+
+ @Test
+ public void testMultiTxsProcess() {
+ final MemoryKVStorage STORAGE = new MemoryKVStorage();
+
+ // 初始化账本到指定的存储库;
+ ledgerHash = initLedger(STORAGE, parti0, parti1, parti2, parti3);
+
+ // 加载账本;
+ LedgerManager ledgerManager = new LedgerManager();
+ LedgerRepository ledgerRepo = ledgerManager.register(ledgerHash, STORAGE);
+
+ // 验证参与方账户的存在;
+ LedgerDataSet previousBlockDataset = ledgerRepo.getDataSet(ledgerRepo.getLatestBlock());
+ UserAccount user0 = previousBlockDataset.getUserAccountSet().getUser(parti0.getAddress());
+ assertNotNull(user0);
+ boolean partiRegistered = previousBlockDataset.getUserAccountSet().contains(parti0.getAddress());
+ assertTrue(partiRegistered);
+
+ // 生成新区块;
+ LedgerEditor newBlockEditor = ledgerRepo.createNextBlock();
+
+ OperationHandleRegisteration opReg = new DefaultOperationHandleRegisteration();
+ TransactionBatchProcessor txbatchProcessor = new TransactionBatchProcessor(newBlockEditor, previousBlockDataset,
+ opReg, ledgerManager);
+
+ // 注册新用户;
+ BlockchainKeypair userKeypair1 = BlockchainKeyGenerator.getInstance().generate();
+ transactionRequest = LedgerTestUtils.createTxRequest_UserReg(ledgerHash, userKeypair1, parti0);
+ TransactionResponse txResp1 = txbatchProcessor.schedule(transactionRequest);
+
+// BlockchainKeypair userKeypair2 = BlockchainKeyGenerator.getInstance().generate();
+// transactionRequest = LedgerTestUtils.createTxRequest_UserReg(ledgerHash, userKeypair2, parti0);
+// TransactionResponse txResp2 = txbatchProcessor.schedule(transactionRequest);
+
+ LedgerBlock newBlock = newBlockEditor.prepare();
+ newBlockEditor.commit();
+
+ assertEquals(TransactionState.SUCCESS, txResp1.getExecutionState());
+// assertEquals(TransactionState.SUCCESS, txResp2.getExecutionState());
+
+ // 验证正确性;
+ ledgerManager = new LedgerManager();
+ ledgerRepo = ledgerManager.register(ledgerHash, STORAGE);
+
+ LedgerBlock latestBlock = ledgerRepo.getLatestBlock();
+ assertEquals(newBlock.getHash(), latestBlock.getHash());
+ assertEquals(1, newBlock.getHeight());
+
+ LedgerDataSet ledgerDS = ledgerRepo.getDataSet(latestBlock);
+ boolean existUser1 = ledgerDS.getUserAccountSet().contains(userKeypair1.getAddress());
+// boolean existUser2 = ledgerDS.getUserAccountSet().contains(userKeypair2.getAddress());
+ assertTrue(existUser1);
+// assertTrue(existUser2);
+ }
+
+ @Test
+ public void testTxRollback() {
+ final MemoryKVStorage STORAGE = new MemoryKVStorage();
+
+ // 初始化账本到指定的存储库;
+ ledgerHash = initLedger(STORAGE, parti0, parti1, parti2, parti3);
+
+ // 加载账本;
+ LedgerManager ledgerManager = new LedgerManager();
+ LedgerRepository ledgerRepo = ledgerManager.register(ledgerHash, STORAGE);
+
+ // 验证参与方账户的存在;
+ LedgerDataSet previousBlockDataset = ledgerRepo.getDataSet(ledgerRepo.getLatestBlock());
+ UserAccount user0 = previousBlockDataset.getUserAccountSet().getUser(parti0.getAddress());
+ assertNotNull(user0);
+ boolean partiRegistered = previousBlockDataset.getUserAccountSet().contains(parti0.getAddress());
+ assertTrue(partiRegistered);
+
+ // 生成新区块;
+ LedgerEditor newBlockEditor = ledgerRepo.createNextBlock();
+
+ OperationHandleRegisteration opReg = new DefaultOperationHandleRegisteration();
+ TransactionBatchProcessor txbatchProcessor = new TransactionBatchProcessor(newBlockEditor, previousBlockDataset,
+ opReg, ledgerManager);
+
+ // 注册新用户;
+ BlockchainKeypair userKeypair1 = BlockchainKeyGenerator.getInstance().generate();
+ transactionRequest = LedgerTestUtils.createTxRequest_UserReg(ledgerHash, userKeypair1, parti0);
+ TransactionResponse txResp1 = txbatchProcessor.schedule(transactionRequest);
+
+ BlockchainKeypair userKeypair2 = BlockchainKeyGenerator.getInstance().generate();
+ transactionRequest = LedgerTestUtils.createTxRequest_MultiOPs_WithError(ledgerHash, userKeypair2, parti0);
+ TransactionResponse txResp2 = txbatchProcessor.schedule(transactionRequest);
+
+ BlockchainKeypair userKeypair3 = BlockchainKeyGenerator.getInstance().generate();
+ transactionRequest = LedgerTestUtils.createTxRequest_UserReg(ledgerHash, userKeypair3, parti0);
+ TransactionResponse txResp3 = txbatchProcessor.schedule(transactionRequest);
LedgerBlock newBlock = newBlockEditor.prepare();
newBlockEditor.commit();
+ assertEquals(TransactionState.SUCCESS, txResp1.getExecutionState());
+ assertEquals(TransactionState.LEDGER_ERROR, txResp2.getExecutionState());
+ assertEquals(TransactionState.SUCCESS, txResp3.getExecutionState());
+
// 验证正确性;
ledgerManager = new LedgerManager();
- ledgerRepo = ledgerManager.register(ledgerHash, storage);
+ ledgerRepo = ledgerManager.register(ledgerHash, STORAGE);
LedgerBlock latestBlock = ledgerRepo.getLatestBlock();
assertEquals(newBlock.getHash(), latestBlock.getHash());
assertEquals(1, newBlock.getHeight());
+
+ LedgerDataSet ledgerDS = ledgerRepo.getDataSet(latestBlock);
+ boolean existUser1 = ledgerDS.getUserAccountSet().contains(userKeypair1.getAddress());
+ boolean existUser2 = ledgerDS.getUserAccountSet().contains(userKeypair2.getAddress());
+ boolean existUser3 = ledgerDS.getUserAccountSet().contains(userKeypair3.getAddress());
+ assertTrue(existUser1);
+ assertFalse(existUser2);
+ assertTrue(existUser3);
}
private HashDigest initLedger(MemoryKVStorage storage, BlockchainKeypair... partiKeys) {
@@ -106,7 +229,7 @@ public class TransactionBatchProcessorTest {
// 创建账本;
LedgerEditor ldgEdt = LedgerTransactionalEditor.createEditor(initSetting, LEDGER_KEY_PREFIX, storage, storage);
- TransactionRequest genesisTxReq = LedgerTestUtils.createTxRequest_UserReg(null);
+ TransactionRequest genesisTxReq = LedgerTestUtils.createLedgerInitTxRequest(partiKeys);
LedgerTransactionContext genisisTxCtx = ldgEdt.newTransaction(genesisTxReq);
LedgerDataSet ldgDS = genisisTxCtx.getDataSet();
diff --git a/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/TransactionSetTest.java b/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/TransactionSetTest.java
index a4b719a7..f023a987 100644
--- a/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/TransactionSetTest.java
+++ b/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/TransactionSetTest.java
@@ -102,8 +102,7 @@ public class TransactionSetTest {
txSnapshot.setContractAccountSetHash(contractAccountSetHash);
long blockHeight = 8922L;
- LedgerTransactionData tx = new LedgerTransactionData(blockHeight, txReq, TransactionState.SUCCESS, txSnapshot,
- null);
+ LedgerTransactionData tx = new LedgerTransactionData(blockHeight, txReq, TransactionState.SUCCESS, txSnapshot);
txset.add(tx);
assertTrue(txset.isUpdated());
diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/TransactionState.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/TransactionState.java
index e89d41b6..9d9b1691 100644
--- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/TransactionState.java
+++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/TransactionState.java
@@ -11,7 +11,7 @@ import com.jd.blockchain.consts.DataCodes;
* @author huanghaiquan
*
*/
-@EnumContract(code= DataCodes.ENUM_TYPE_TRANSACTION_STATE)
+@EnumContract(code = DataCodes.ENUM_TYPE_TRANSACTION_STATE)
public enum TransactionState {
/**
@@ -23,16 +23,21 @@ public enum TransactionState {
* 共识错误;
*/
CONSENSUS_ERROR((byte) 1),
-
+
/**
* 账本错误;
*/
LEDGER_ERROR((byte) 2),
/**
- * 数据序列更新错误;
+ * 由于在错误的账本上执行交易而被丢弃;
+ */
+ DISCARD_BY_WRONG_LEDGER((byte) 3),
+
+ /**
+ * 由于交易内容的验签失败而丢弃;
*/
- DATA_SEQUENCE_UPDATE_ERROR((byte) 3),
+ DISCARD_BY_WRONG_CONTENT_SIGNATURE((byte) 4),
/**
* 系统错误;
@@ -44,7 +49,7 @@ public enum TransactionState {
*/
TIMEOUT((byte) 0x81);
- @EnumField(type= PrimitiveType.INT8)
+ @EnumField(type = PrimitiveType.INT8)
public final byte CODE;
private TransactionState(byte code) {
diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/TxBuilder.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/TxBuilder.java
index 35e09d78..1ff23a2f 100644
--- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/TxBuilder.java
+++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/TxBuilder.java
@@ -55,12 +55,22 @@ public class TxBuilder implements TransactionBuilder {
txContent.addOperations(opFactory.getOperations());
txContent.setTime(time);
- byte[] contentBodyBytes = BinaryProtocol.encode(txContent, TransactionContentBody.class);
- HashDigest contentHash = Crypto.getHashFunction(DEFAULT_HASH_ALGORITHM).hash(contentBodyBytes);
+ HashDigest contentHash = computeTxContentHash(txContent);
txContent.setHash(contentHash);
return txContent;
}
+
+ public static HashDigest computeTxContentHash(TransactionContent txContent) {
+ byte[] contentBodyBytes = BinaryProtocol.encode(txContent, TransactionContentBody.class);
+ HashDigest contentHash = Crypto.getHashFunction(DEFAULT_HASH_ALGORITHM).hash(contentBodyBytes);
+ return contentHash;
+ }
+
+ public static boolean verifyTxContentHash(TransactionContent txContent, HashDigest verifiedHash) {
+ HashDigest hash = computeTxContentHash(txContent);
+ return hash.equals(verifiedHash);
+ }
public Collection getReturnValuehandlers() {
return opFactory.getReturnValuetHandlers();
diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/TxRequestBuilder.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/TxRequestBuilder.java
index 7d6701a5..87326bb1 100644
--- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/TxRequestBuilder.java
+++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/TxRequestBuilder.java
@@ -75,8 +75,14 @@ public class TxRequestBuilder implements TransactionRequestBuilder {
}
public static boolean verifySignature(TransactionContent txContent, SignatureDigest signDigest, PubKey pubKey) {
- return Crypto.getSignatureFunction(pubKey.getAlgorithm()).verify(signDigest, pubKey,
- txContent.getHash().toBytes());
+ if (!TxBuilder.verifyTxContentHash(txContent, txContent.getHash())) {
+ return false;
+ }
+ return verifyHashSignature(txContent.getHash(), signDigest, pubKey);
+ }
+
+ public static boolean verifyHashSignature(HashDigest hash, SignatureDigest signDigest, PubKey pubKey) {
+ return Crypto.getSignatureFunction(pubKey.getAlgorithm()).verify(signDigest, pubKey, hash.toBytes());
}
@Override
diff --git a/source/pom.xml b/source/pom.xml
index f2a8ac32..4dca787c 100644
--- a/source/pom.xml
+++ b/source/pom.xml
@@ -8,11 +8,11 @@
spring-boot-starter-parent
2.0.6.RELEASE
-
-
-
-
-
+
+
+
+
+
com.jd.blockchain
jdchain-root
@@ -92,6 +92,11 @@
mockito-core
test
+
+ org.springframework.boot
+ spring-boot-starter-log4j2
+ test
+
@@ -446,22 +451,22 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/source/utils/utils-common/src/main/java/com/jd/blockchain/utils/io/BytesUtils.java b/source/utils/utils-common/src/main/java/com/jd/blockchain/utils/io/BytesUtils.java
index 93520e0e..3f0a7256 100644
--- a/source/utils/utils-common/src/main/java/com/jd/blockchain/utils/io/BytesUtils.java
+++ b/source/utils/utils-common/src/main/java/com/jd/blockchain/utils/io/BytesUtils.java
@@ -46,6 +46,9 @@ public class BytesUtils {
if (bytes1 == bytes2) {
return true;
}
+ if (bytes1 == null || bytes2 == null) {
+ return false;
+ }
if (bytes1.length != bytes2.length) {
return false;
}