Browse Source

Fixed the bug where abnormal transaction processing was not reported;

tags/1.0.1
huanghaiquan 5 years ago
parent
commit
bcbe8ae214
17 changed files with 550 additions and 126 deletions
  1. +62
    -0
      source/base/src/main/resources/log4j2.xml
  2. +28
    -38
      source/ledger/ledger-core/pom.xml
  3. +17
    -1
      source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/LedgerEditor.java
  4. +12
    -2
      source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/LedgerRepositoryImpl.java
  5. +40
    -6
      source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/LedgerTransactionalEditor.java
  6. +126
    -19
      source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/TransactionBatchProcessor.java
  7. +1
    -1
      source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/ContractInvokingTest.java
  8. +13
    -5
      source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/LedgerEditerTest.java
  9. +9
    -2
      source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/LedgerManagerTest.java
  10. +51
    -12
      source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/LedgerTestUtils.java
  11. +131
    -8
      source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/TransactionBatchProcessorTest.java
  12. +1
    -2
      source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/TransactionSetTest.java
  13. +10
    -5
      source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/TransactionState.java
  14. +12
    -2
      source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/TxBuilder.java
  15. +8
    -2
      source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/TxRequestBuilder.java
  16. +26
    -21
      source/pom.xml
  17. +3
    -0
      source/utils/utils-common/src/main/java/com/jd/blockchain/utils/io/BytesUtils.java

+ 62
- 0
source/base/src/main/resources/log4j2.xml View File

@@ -0,0 +1,62 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--日志级别以及优先级排序: OFF > FATAL > ERROR > WARN > INFO > DEBUG > TRACE > ALL -->
<!--Configuration后面的status,这个用于设置log4j2自身内部的信息输出,可以不设置,当设置成trace时,你会看到log4j2内部各种详细输出-->
<!--monitorInterval:Log4j能够自动检测修改配置 文件和重新配置本身,设置间隔秒数-->
<configuration status="WARN" monitorInterval="60">
<!--先定义所有的appender-->
<appenders>
<!--这个输出控制台的配置-->
<console name="Console" target="SYSTEM_OUT">
<!--控制台只输出level及以上级别的信息(onMatch),其他的直接拒绝(onMismatch)-->
<ThresholdFilter level="trace" onMatch="ACCEPT" onMismatch="DENY"/>
<!--输出日志的格式-->
<PatternLayout pattern="%d{HH:mm:ss.SSS} %-5level %class{36} %L %M - %msg%xEx%n"/>
</console>
<!--文件会打印出所有信息,这个log每次运行程序会自动清空,由append属性决定,适合临时测试用-->
<File name="log" fileName="../logs/test.log" append="false">
<PatternLayout pattern="%d{HH:mm:ss.SSS} %-5level %class{36} %L %M - %msg%xEx%n"/>
</File>
<!-- 这个会打印出所有的info及以下级别的信息,每次大小超过size,则这size大小的日志会自动存入按年份-月份建立的文件夹下面并进行压缩,作为存档-->
<RollingFile name="PeerRollingInfo" fileName="../logs/peer.out.info.log"
filePattern="../logs/$${date:yyyy-MM}/peer.out.info-%d{yyyy-MM-dd}-%i.log">
<!--控制台只输出level及以上级别的信息(onMatch),其他的直接拒绝(onMismatch)-->
<ThresholdFilter level="info" onMatch="ACCEPT" onMismatch="DENY"/>
<PatternLayout pattern="[%d{HH:mm:ss:SSS}] [%p] - %l - %m%n"/>
<Policies>
<TimeBasedTriggeringPolicy/>
<SizeBasedTriggeringPolicy size="100 MB"/>
</Policies>
</RollingFile>
<RollingFile name="PeerRollingWarn" fileName="../logs/peer.out.warn.log"
filePattern="../logs/$${date:yyyy-MM}/peer.out.warn-%d{yyyy-MM-dd}-%i.log">
<ThresholdFilter level="warn" onMatch="ACCEPT" onMismatch="DENY"/>
<PatternLayout pattern="[%d{HH:mm:ss:SSS}] [%p] - %l - %m%n"/>
<Policies>
<TimeBasedTriggeringPolicy/>
<SizeBasedTriggeringPolicy size="100 MB"/>
</Policies>
<!-- DefaultRolloverStrategy属性如不设置,则默认为最多同一文件夹下7个文件,这里设置了20 -->
<DefaultRolloverStrategy max="20"/>
</RollingFile>
<RollingFile name="PeerRollingError" fileName="../logs/peer.out.error.log"
filePattern="../logs/$${date:yyyy-MM}/peer.out.error-%d{yyyy-MM-dd}-%i.log">
<ThresholdFilter level="error" onMatch="ACCEPT" onMismatch="DENY"/>
<PatternLayout pattern="[%d{HH:mm:ss:SSS}] [%p] - %l - %m%n"/>
<Policies>
<TimeBasedTriggeringPolicy/>
<SizeBasedTriggeringPolicy size="100 MB"/>
</Policies>
</RollingFile>
</appenders>
<!--然后定义logger,只有定义了logger并引入的appender,appender才会生效-->
<loggers>
<!--过滤掉spring的一些DEBUG信息-->
<logger name="org.springframework" level="INFO"></logger>
<root level="all">
<appender-ref ref="Console"/>
<appender-ref ref="PeerRollingInfo"/>
<appender-ref ref="PeerRollingWarn"/>
<appender-ref ref="PeerRollingError"/>
</root>
</loggers>
</configuration>

+ 28
- 38
source/ledger/ledger-core/pom.xml View File

@@ -63,7 +63,7 @@
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>


</dependencies>
</dependencies>


<build> <build>
<plugins> <plugins>
@@ -78,42 +78,32 @@
</plugins> </plugins>
</build> </build>


<!--<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.5</version>
<configuration>
<excludes>
<exclude>**/TransactionBatchProcessorTest.java</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>-->
<!--<build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId> <version>2.5</version> <configuration>
<excludes> <exclude>**/TransactionBatchProcessorTest.java</exclude> </excludes>
</configuration> </plugin> </plugins> </build> -->


<!--<build>-->
<!--<plugins>-->
<!--<plugin>-->
<!--<groupId>org.apache.maven.plugins</groupId>-->
<!--<artifactId>maven-compiler-plugin</artifactId>-->
<!--<version>3.1</version>-->
<!--<configuration>-->
<!--<source>1.8</source>-->
<!--<target>1.8</target>-->
<!--<encoding>UTF-8</encoding>-->
<!--<compilerArgs>-->
<!--&lt;!&ndash;<arg>-verbose</arg>&ndash;&gt;-->
<!--&lt;!&ndash;<arg>-Xlint:unchecked</arg>&ndash;&gt;-->
<!--&lt;!&ndash;<arg>-Xlint:deprecation</arg>&ndash;&gt;-->
<!--&lt;!&ndash;<arg>-bootclasspath</arg>&ndash;&gt;-->
<!--&lt;!&ndash;<arg>${env.JAVA_HOME}/jre/lib/rt.jar</arg>&ndash;&gt;-->
<!--<arg>-extdirs</arg>-->
<!--<arg>${project.basedir}/../contract/contract-libs;$JAVA_HOME/jre/lib/ext</arg>-->
<!--</compilerArgs>-->
<!--</configuration>-->
<!--</plugin>-->
<!--</plugins>-->
<!--</build>-->
<!--<build> -->
<!--<plugins> -->
<!--<plugin> -->
<!--<groupId>org.apache.maven.plugins</groupId> -->
<!--<artifactId>maven-compiler-plugin</artifactId> -->
<!--<version>3.1</version> -->
<!--<configuration> -->
<!--<source>1.8</source> -->
<!--<target>1.8</target> -->
<!--<encoding>UTF-8</encoding> -->
<!--<compilerArgs> -->
<!--&lt;!&ndash;<arg>-verbose</arg>&ndash;&gt; -->
<!--&lt;!&ndash;<arg>-Xlint:unchecked</arg>&ndash;&gt; -->
<!--&lt;!&ndash;<arg>-Xlint:deprecation</arg>&ndash;&gt; -->
<!--&lt;!&ndash;<arg>-bootclasspath</arg>&ndash;&gt; -->
<!--&lt;!&ndash;<arg>${env.JAVA_HOME}/jre/lib/rt.jar</arg>&ndash;&gt; -->
<!--<arg>-extdirs</arg> -->
<!--<arg>${project.basedir}/../contract/contract-libs;$JAVA_HOME/jre/lib/ext</arg> -->
<!--</compilerArgs> -->
<!--</configuration> -->
<!--</plugin> -->
<!--</plugins> -->
<!--</build> -->
</project> </project>

+ 17
- 1
source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/LedgerEditor.java View File

@@ -1,5 +1,6 @@
package com.jd.blockchain.ledger.core; package com.jd.blockchain.ledger.core;


import com.jd.blockchain.crypto.HashDigest;
import com.jd.blockchain.ledger.LedgerBlock; import com.jd.blockchain.ledger.LedgerBlock;
import com.jd.blockchain.ledger.LedgerException; import com.jd.blockchain.ledger.LedgerException;
import com.jd.blockchain.ledger.LedgerTransaction; import com.jd.blockchain.ledger.LedgerTransaction;
@@ -18,6 +19,20 @@ import com.jd.blockchain.ledger.TransactionRequest;
*/ */
public interface LedgerEditor { public interface LedgerEditor {


/**
* 账本Hash;
*
* @return
*/
HashDigest getLedgerHash();

/**
* 新区块的高度;
*
* @return
*/
long getBlockHeight();

/** /**
* 开始新事务;<br> * 开始新事务;<br>
* *
@@ -32,7 +47,8 @@ public interface LedgerEditor {
* 或者全部回滚(通过方法 {@link LedgerTransactionContext#rollback()}),以此实现原子性写入; * 或者全部回滚(通过方法 {@link LedgerTransactionContext#rollback()}),以此实现原子性写入;
* <p> * <p>
* *
* 每一次事务性的账本写入操作在提交后,都会记录该事务相关的系统全局快照,以交易对象 {@link LedgerTransaction} 进行保存;<p>
* 每一次事务性的账本写入操作在提交后,都会记录该事务相关的系统全局快照,以交易对象 {@link LedgerTransaction} 进行保存;
* <p>
* *
* 注:方法不解析、不执行交易中的操作; * 注:方法不解析、不执行交易中的操作;
* *


+ 12
- 2
source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/LedgerRepositoryImpl.java View File

@@ -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."); "A new block is in process, cann't create another one until it finish by committing or canceling.");
} }
LedgerBlock previousBlock = getLatestBlock(); LedgerBlock previousBlock = getLatestBlock();
LedgerTransactionalEditor editor = LedgerTransactionalEditor.createEditor(
LedgerTransactionalEditor editor = LedgerTransactionalEditor.createEditor(ledgerHash,
getAdminInfo().getMetadata().getSetting(), previousBlock, keyPrefix, exPolicyStorage, getAdminInfo().getMetadata().getSetting(), previousBlock, keyPrefix, exPolicyStorage,
versioningStorage); versioningStorage);
NewBlockCommittingMonitor committingMonitor = new NewBlockCommittingMonitor(editor, this); NewBlockCommittingMonitor committingMonitor = new NewBlockCommittingMonitor(editor, this);
@@ -479,7 +479,7 @@ public class LedgerRepositoryImpl implements LedgerRepository {
} }


static TransactionSet newTransactionSet(LedgerSetting ledgerSetting, String keyPrefix, static TransactionSet newTransactionSet(LedgerSetting ledgerSetting, String keyPrefix,
ExPolicyKVStorage ledgerExStorage, VersioningKVStorage ledgerVerStorage) {
ExPolicyKVStorage ledgerExStorage, VersioningKVStorage ledgerVerStorage) {
// TransactionSet transactionSet = new // TransactionSet transactionSet = new
// TransactionSet(ledgerSetting.getCryptoSetting(), // TransactionSet(ledgerSetting.getCryptoSetting(),
// PrefixAppender.prefix(TRANSACTION_SET_PREFIX, ledgerExStorage), // PrefixAppender.prefix(TRANSACTION_SET_PREFIX, ledgerExStorage),
@@ -576,6 +576,16 @@ public class LedgerRepositoryImpl implements LedgerRepository {
this.ledgerRepo = ledgerRepo; this.ledgerRepo = ledgerRepo;
} }


@Override
public HashDigest getLedgerHash() {
return editor.getLedgerHash();
}

@Override
public long getBlockHeight() {
return editor.getBlockHeight();
}

@Override @Override
public LedgerTransactionContext newTransaction(TransactionRequest txRequest) { public LedgerTransactionContext newTransaction(TransactionRequest txRequest) {
return editor.newTransaction(txRequest); return editor.newTransaction(txRequest);


+ 40
- 6
source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/LedgerTransactionalEditor.java View File

@@ -26,6 +26,11 @@ public class LedgerTransactionalEditor implements LedgerEditor {
System.out.println("------ [[ parallel-dbwrite=" + PARALLEL_DB_WRITE + " ]] ------"); System.out.println("------ [[ parallel-dbwrite=" + PARALLEL_DB_WRITE + " ]] ------");
} }


/**
* 账本Hash,创世区块的编辑器则返回 null;
*/
private HashDigest ledgerHash;

private final String ledgerKeyPrefix; private final String ledgerKeyPrefix;


private CryptoSetting cryptoSetting; private CryptoSetting cryptoSetting;
@@ -49,8 +54,9 @@ public class LedgerTransactionalEditor implements LedgerEditor {


private LedgerDataContext newTxCtx; private LedgerDataContext newTxCtx;


private LedgerTransactionalEditor(CryptoSetting cryptoSetting, LedgerBlockData newlyBlock,
private LedgerTransactionalEditor(HashDigest ledgerHash, CryptoSetting cryptoSetting, LedgerBlockData newlyBlock,
StagedSnapshot startingPoint, String ledgerKeyPrefix, BufferedKVStorage bufferedStorage) { StagedSnapshot startingPoint, String ledgerKeyPrefix, BufferedKVStorage bufferedStorage) {
this.ledgerHash = ledgerHash;
this.ledgerKeyPrefix = ledgerKeyPrefix; this.ledgerKeyPrefix = ledgerKeyPrefix;
this.cryptoSetting = cryptoSetting; this.cryptoSetting = cryptoSetting;
this.newlyBlock = newlyBlock; this.newlyBlock = newlyBlock;
@@ -59,8 +65,9 @@ public class LedgerTransactionalEditor implements LedgerEditor {
this.stagedSnapshots.push(startingPoint); 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; // new block;
LedgerBlockData currBlock = new LedgerBlockData(previousBlock.getHeight() + 1, previousBlock.getLedgerHash(), LedgerBlockData currBlock = new LedgerBlockData(previousBlock.getHeight() + 1, previousBlock.getLedgerHash(),
previousBlock.getHash()); previousBlock.getHash());
@@ -71,7 +78,7 @@ public class LedgerTransactionalEditor implements LedgerEditor {
StagedSnapshot startingPoint = new TxSnapshot(previousBlock, previousBlock.getTransactionSetHash()); StagedSnapshot startingPoint = new TxSnapshot(previousBlock, previousBlock.getTransactionSetHash());


// instantiate editor; // instantiate editor;
return new LedgerTransactionalEditor(ledgerSetting.getCryptoSetting(), currBlock, startingPoint,
return new LedgerTransactionalEditor(ledgerHash, ledgerSetting.getCryptoSetting(), currBlock, startingPoint,
ledgerKeyPrefix, txStagedStorage); ledgerKeyPrefix, txStagedStorage);
} }


@@ -81,7 +88,7 @@ public class LedgerTransactionalEditor implements LedgerEditor {
StagedSnapshot startingPoint = new GenesisSnapshot(initSetting); StagedSnapshot startingPoint = new GenesisSnapshot(initSetting);
// init storage; // init storage;
BufferedKVStorage txStagedStorage = new BufferedKVStorage(ledgerExStorage, ledgerVerStorage, false); BufferedKVStorage txStagedStorage = new BufferedKVStorage(ledgerExStorage, ledgerVerStorage, false);
return new LedgerTransactionalEditor(initSetting.getCryptoSetting(), genesisBlock, startingPoint,
return new LedgerTransactionalEditor(null, initSetting.getCryptoSetting(), genesisBlock, startingPoint,
ledgerKeyPrefix, txStagedStorage); ledgerKeyPrefix, txStagedStorage);
} }


@@ -102,12 +109,39 @@ public class LedgerTransactionalEditor implements LedgerEditor {
// return lastTxCtx.getDataSet(); // return lastTxCtx.getDataSet();
// } // }


public LedgerBlock getNewlyBlock() {
LedgerBlock getNewlyBlock() {
return newlyBlock; 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 @Override
public LedgerTransactionContext newTransaction(TransactionRequest txRequest) { 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(); checkState();
// TODO:验证交易签名; // TODO:验证交易签名;




+ 126
- 19
source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/TransactionBatchProcessor.java View File

@@ -9,11 +9,13 @@ import org.slf4j.LoggerFactory;


import com.jd.blockchain.crypto.HashDigest; import com.jd.blockchain.crypto.HashDigest;
import com.jd.blockchain.ledger.BytesValue; import com.jd.blockchain.ledger.BytesValue;
import com.jd.blockchain.ledger.DigitalSignature;
import com.jd.blockchain.ledger.LedgerBlock; import com.jd.blockchain.ledger.LedgerBlock;
import com.jd.blockchain.ledger.LedgerException; import com.jd.blockchain.ledger.LedgerException;
import com.jd.blockchain.ledger.Operation; import com.jd.blockchain.ledger.Operation;
import com.jd.blockchain.ledger.OperationResult; import com.jd.blockchain.ledger.OperationResult;
import com.jd.blockchain.ledger.OperationResultData; import com.jd.blockchain.ledger.OperationResultData;
import com.jd.blockchain.ledger.TransactionContent;
import com.jd.blockchain.ledger.TransactionRequest; import com.jd.blockchain.ledger.TransactionRequest;
import com.jd.blockchain.ledger.TransactionResponse; import com.jd.blockchain.ledger.TransactionResponse;
import com.jd.blockchain.ledger.TransactionState; 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.TransactionBatchProcess;
import com.jd.blockchain.service.TransactionBatchResult; import com.jd.blockchain.service.TransactionBatchResult;
import com.jd.blockchain.service.TransactionBatchResultHandle; 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; import com.jd.blockchain.utils.Bytes;


public class TransactionBatchProcessor implements TransactionBatchProcess { public class TransactionBatchProcessor implements TransactionBatchProcess {
@@ -50,12 +55,9 @@ public class TransactionBatchProcessor implements TransactionBatchProcess {
private TransactionBatchResult batchResult; private TransactionBatchResult batchResult;


/** /**
* @param newBlockEditor
* 新区块的数据编辑器;
* @param previousBlockDataset
* 新区块的前一个区块的数据集;即未提交新区块之前的经过共识的账本最新数据集;
* @param opHandles
* 操作处理对象注册表;
* @param newBlockEditor 新区块的数据编辑器;
* @param previousBlockDataset 新区块的前一个区块的数据集;即未提交新区块之前的经过共识的账本最新数据集;
* @param opHandles 操作处理对象注册表;
*/ */
public TransactionBatchProcessor(LedgerEditor newBlockEditor, LedgerDataSet previousBlockDataset, public TransactionBatchProcessor(LedgerEditor newBlockEditor, LedgerDataSet previousBlockDataset,
OperationHandleRegisteration opHandles, LedgerService ledgerService) { OperationHandleRegisteration opHandles, LedgerService ledgerService) {
@@ -65,6 +67,18 @@ public class TransactionBatchProcessor implements TransactionBatchProcess {
this.ledgerService = ledgerService; 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) * (non-Javadoc)
* *
@@ -74,14 +88,61 @@ public class TransactionBatchProcessor implements TransactionBatchProcess {
*/ */
@Override @Override
public TransactionResponse schedule(TransactionRequest request) { 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<OperationResult> 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;
}
}


/**
* 处理交易;<br>
*
* 此方法会处理所有的异常,以不同结果的 {@link TransactionResponse} 返回;
*
* @param request
* @param txCtx
* @return
*/
private TransactionResponse handleTx(TransactionRequest request, LedgerTransactionContext txCtx) {
TransactionState result;
List<OperationResult> operationResults = new ArrayList<>();
try { try {

LedgerDataSet dataset = txCtx.getDataSet(); LedgerDataSet dataset = txCtx.getDataSet();
TransactionRequestContext reqCtx = new TransactionRequestContextImpl(request); TransactionRequestContext reqCtx = new TransactionRequestContextImpl(request);
// TODO: 验证签名者的有效性; // TODO: 验证签名者的有效性;
@@ -101,7 +162,8 @@ public class TransactionBatchProcessor implements TransactionBatchProcess {
OperationHandleContext handleContext = new OperationHandleContext() { OperationHandleContext handleContext = new OperationHandleContext() {
@Override @Override
public void handle(Operation operation) { 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()); OperationHandle hdl = opHandles.getHandle(operation.getClass());
hdl.process(operation, dataset, reqCtx, previousBlockDataset, this, ledgerService); hdl.process(operation, dataset, reqCtx, previousBlockDataset, this, ledgerService);
} }
@@ -110,7 +172,8 @@ public class TransactionBatchProcessor implements TransactionBatchProcess {
int opIndex = 0; int opIndex = 0;
for (Operation op : ops) { for (Operation op : ops) {
opHandle = opHandles.getHandle(op.getClass()); 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) { if (opResult != null) {
operationResults.add(new OperationResultData(opIndex, opResult)); operationResults.add(new OperationResultData(opIndex, opResult));
} }
@@ -119,19 +182,22 @@ public class TransactionBatchProcessor implements TransactionBatchProcess {


// 提交交易(事务); // 提交交易(事务);
result = TransactionState.SUCCESS; result = TransactionState.SUCCESS;

txCtx.commit(result, operationResults); txCtx.commit(result, operationResults);
} catch (LedgerException e) { } catch (LedgerException e) {
// TODO: 识别更详细的异常类型以及执行对应的处理; // TODO: 识别更详细的异常类型以及执行对应的处理;
result = TransactionState.LEDGER_ERROR; result = TransactionState.LEDGER_ERROR;
txCtx.discardAndCommit(TransactionState.LEDGER_ERROR, operationResults); 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) { } catch (Exception e) {
result = TransactionState.SYSTEM_ERROR; result = TransactionState.SYSTEM_ERROR;
txCtx.discardAndCommit(TransactionState.SYSTEM_ERROR, operationResults); 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); TxResponseHandle resp = new TxResponseHandle(request, result);


@@ -139,9 +205,50 @@ public class TransactionBatchProcessor implements TransactionBatchProcess {
OperationResult[] operationResultArray = new OperationResult[operationResults.size()]; OperationResult[] operationResultArray = new OperationResult[operationResults.size()];
resp.setOperationResults(operationResults.toArray(operationResultArray)); 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; return resp;
} }




+ 1
- 1
source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/ContractInvokingTest.java View File

@@ -184,7 +184,7 @@ public class ContractInvokingTest {
// 创建账本; // 创建账本;
LedgerEditor ldgEdt = LedgerTransactionalEditor.createEditor(initSetting, LEDGER_KEY_PREFIX, storage, storage); 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); LedgerTransactionContext genisisTxCtx = ldgEdt.newTransaction(genesisTxReq);
LedgerDataSet ldgDS = genisisTxCtx.getDataSet(); LedgerDataSet ldgDS = genisisTxCtx.getDataSet();




+ 13
- 5
source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/LedgerEditerTest.java View File

@@ -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.ClassicAlgorithm;
import com.jd.blockchain.crypto.service.classic.ClassicCryptoService; import com.jd.blockchain.crypto.service.classic.ClassicCryptoService;
import com.jd.blockchain.crypto.service.sm.SMCryptoService; 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.BlockchainKeypair;
import com.jd.blockchain.ledger.BytesValue; import com.jd.blockchain.ledger.BytesValue;
import com.jd.blockchain.ledger.DataType; import com.jd.blockchain.ledger.DataType;
@@ -52,6 +53,13 @@ public class LedgerEditerTest {
private static final String LEDGER_KEY_PREFIX = "LDG://"; private static final String LEDGER_KEY_PREFIX = "LDG://";
private SignatureFunction signatureFunction; 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); 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); LedgerTransactionContext txCtx = ldgEdt.newTransaction(genesisTxReq);


@@ -86,7 +94,7 @@ public class LedgerEditerTest {
@Test @Test
public void testWriteDataAccoutKvOp() { public void testWriteDataAccoutKvOp() {
LedgerEditor ldgEdt = createLedgerInitEditor(); LedgerEditor ldgEdt = createLedgerInitEditor();
LedgerTransactionContext genisisTxCtx = createGenisisTx(ldgEdt);
LedgerTransactionContext genisisTxCtx = createGenisisTx(ldgEdt, participants);
LedgerDataSet ldgDS = genisisTxCtx.getDataSet(); LedgerDataSet ldgDS = genisisTxCtx.getDataSet();


AsymmetricKeypair cryptoKeyPair = signatureFunction.generateKeypair(); AsymmetricKeypair cryptoKeyPair = signatureFunction.generateKeypair();
@@ -119,7 +127,7 @@ public class LedgerEditerTest {
@Test @Test
public void testGennesisBlockCreation() { public void testGennesisBlockCreation() {
LedgerEditor ldgEdt = createLedgerInitEditor(); LedgerEditor ldgEdt = createLedgerInitEditor();
LedgerTransactionContext genisisTxCtx = createGenisisTx(ldgEdt);
LedgerTransactionContext genisisTxCtx = createGenisisTx(ldgEdt, participants);
LedgerDataSet ldgDS = genisisTxCtx.getDataSet(); LedgerDataSet ldgDS = genisisTxCtx.getDataSet();


AsymmetricKeypair cryptoKeyPair = signatureFunction.generateKeypair(); AsymmetricKeypair cryptoKeyPair = signatureFunction.generateKeypair();
@@ -146,5 +154,5 @@ public class LedgerEditerTest {
ldgEdt.commit(); ldgEdt.commit();


} }
} }

+ 9
- 2
source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/LedgerManagerTest.java View File

@@ -63,6 +63,13 @@ public class LedgerManagerTest {
public static final String[] SUPPORTED_PROVIDERS = { ClassicCryptoService.class.getName(), public static final String[] SUPPORTED_PROVIDERS = { ClassicCryptoService.class.getName(),
SMCryptoService.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; private SignatureFunction signatureFunction;


@Before @Before
@@ -83,13 +90,13 @@ public class LedgerManagerTest {
LedgerEditor ldgEdt = ledgerManager.newLedger(initSetting, storage); LedgerEditor ldgEdt = ledgerManager.newLedger(initSetting, storage);


// 创建一个模拟的创世交易; // 创建一个模拟的创世交易;
TransactionRequest genesisTxReq = LedgerTestUtils.createTxRequest_UserReg(null);
TransactionRequest genesisTxReq = LedgerTestUtils.createLedgerInitTxRequest(participants);


// 记录交易,注册用户; // 记录交易,注册用户;
LedgerTransactionContext txCtx = ldgEdt.newTransaction(genesisTxReq); LedgerTransactionContext txCtx = ldgEdt.newTransaction(genesisTxReq);
LedgerDataSet ldgDS = txCtx.getDataSet(); LedgerDataSet ldgDS = txCtx.getDataSet();
BlockchainKeypair userKP = BlockchainKeyGenerator.getInstance().generate(); BlockchainKeypair userKP = BlockchainKeyGenerator.getInstance().generate();
UserAccount userAccount = ldgDS.getUserAccountSet().register(userKP.getAddress(), userKP.getPubKey()); UserAccount userAccount = ldgDS.getUserAccountSet().register(userKP.getAddress(), userKP.getPubKey());
userAccount.setProperty("Name", "孙悟空", -1); userAccount.setProperty("Name", "孙悟空", -1);
userAccount.setProperty("Age", "10000", -1); userAccount.setProperty("Age", "10000", -1);


+ 51
- 12
source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/LedgerTestUtils.java View File

@@ -38,10 +38,10 @@ public class LedgerTestUtils {


private static Random rand = new Random(); 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() { public static LedgerInitSetting createLedgerInitSetting() {
BlockchainKeypair[] partiKeys = new BlockchainKeypair[2]; BlockchainKeypair[] partiKeys = new BlockchainKeypair[2];
@@ -81,22 +81,61 @@ public class LedgerTestUtils {
return initSetting; 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 txBuilder = new TxBuilder(ledgerHash);


txBuilder.users().register(userKeypair.getIdentity()); txBuilder.users().register(userKeypair.getIdentity());


TransactionRequestBuilder txReqBuilder = txBuilder.prepareRequest(); 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(); return txReqBuilder.buildRequest();
} }




+ 131
- 8
source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/TransactionBatchProcessorTest.java View File

@@ -1,6 +1,7 @@
package test.com.jd.blockchain.ledger; package test.com.jd.blockchain.ledger;


import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull; import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
@@ -54,19 +55,22 @@ public class TransactionBatchProcessorTest {
private BlockchainKeypair parti2 = BlockchainKeyGenerator.getInstance().generate(); private BlockchainKeypair parti2 = BlockchainKeyGenerator.getInstance().generate();
private BlockchainKeypair parti3 = BlockchainKeyGenerator.getInstance().generate(); private BlockchainKeypair parti3 = BlockchainKeyGenerator.getInstance().generate();


private BlockchainKeypair[] participants = { parti0, parti1, parti2, parti3 };

private TransactionRequest transactionRequest; private TransactionRequest transactionRequest;


// 采用基于内存的 Storage;
private MemoryKVStorage storage = new MemoryKVStorage();
// TODO: 验证无效签名会被拒绝;


@Test @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(); LedgerManager ledgerManager = new LedgerManager();
LedgerRepository ledgerRepo = ledgerManager.register(ledgerHash, storage);
LedgerRepository ledgerRepo = ledgerManager.register(ledgerHash, STORAGE);


// 验证参与方账户的存在; // 验证参与方账户的存在;
LedgerDataSet previousBlockDataset = ledgerRepo.getDataSet(ledgerRepo.getLatestBlock()); LedgerDataSet previousBlockDataset = ledgerRepo.getDataSet(ledgerRepo.getLatestBlock());
@@ -85,18 +89,137 @@ public class TransactionBatchProcessorTest {
// 注册新用户; // 注册新用户;
BlockchainKeypair userKeypair = BlockchainKeyGenerator.getInstance().generate(); BlockchainKeypair userKeypair = BlockchainKeyGenerator.getInstance().generate();
transactionRequest = LedgerTestUtils.createTxRequest_UserReg(ledgerHash, userKeypair, parti0); 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(); LedgerBlock newBlock = newBlockEditor.prepare();
newBlockEditor.commit(); newBlockEditor.commit();


assertEquals(TransactionState.SUCCESS, txResp1.getExecutionState());
assertEquals(TransactionState.LEDGER_ERROR, txResp2.getExecutionState());
assertEquals(TransactionState.SUCCESS, txResp3.getExecutionState());

// 验证正确性; // 验证正确性;
ledgerManager = new LedgerManager(); ledgerManager = new LedgerManager();
ledgerRepo = ledgerManager.register(ledgerHash, storage);
ledgerRepo = ledgerManager.register(ledgerHash, STORAGE);


LedgerBlock latestBlock = ledgerRepo.getLatestBlock(); LedgerBlock latestBlock = ledgerRepo.getLatestBlock();
assertEquals(newBlock.getHash(), latestBlock.getHash()); assertEquals(newBlock.getHash(), latestBlock.getHash());
assertEquals(1, newBlock.getHeight()); 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) { private HashDigest initLedger(MemoryKVStorage storage, BlockchainKeypair... partiKeys) {
@@ -106,7 +229,7 @@ public class TransactionBatchProcessorTest {
// 创建账本; // 创建账本;
LedgerEditor ldgEdt = LedgerTransactionalEditor.createEditor(initSetting, LEDGER_KEY_PREFIX, storage, storage); 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); LedgerTransactionContext genisisTxCtx = ldgEdt.newTransaction(genesisTxReq);
LedgerDataSet ldgDS = genisisTxCtx.getDataSet(); LedgerDataSet ldgDS = genisisTxCtx.getDataSet();




+ 1
- 2
source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/TransactionSetTest.java View File

@@ -102,8 +102,7 @@ public class TransactionSetTest {
txSnapshot.setContractAccountSetHash(contractAccountSetHash); txSnapshot.setContractAccountSetHash(contractAccountSetHash);


long blockHeight = 8922L; 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); txset.add(tx);


assertTrue(txset.isUpdated()); assertTrue(txset.isUpdated());


+ 10
- 5
source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/TransactionState.java View File

@@ -11,7 +11,7 @@ import com.jd.blockchain.consts.DataCodes;
* @author huanghaiquan * @author huanghaiquan
* *
*/ */
@EnumContract(code= DataCodes.ENUM_TYPE_TRANSACTION_STATE)
@EnumContract(code = DataCodes.ENUM_TYPE_TRANSACTION_STATE)
public enum TransactionState { public enum TransactionState {
/** /**
@@ -23,16 +23,21 @@ public enum TransactionState {
* 共识错误; * 共识错误;
*/ */
CONSENSUS_ERROR((byte) 1), CONSENSUS_ERROR((byte) 1),
/** /**
* 账本错误; * 账本错误;
*/ */
LEDGER_ERROR((byte) 2), 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); TIMEOUT((byte) 0x81);
@EnumField(type= PrimitiveType.INT8)
@EnumField(type = PrimitiveType.INT8)
public final byte CODE; public final byte CODE;
private TransactionState(byte code) { private TransactionState(byte code) {


+ 12
- 2
source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/TxBuilder.java View File

@@ -55,12 +55,22 @@ public class TxBuilder implements TransactionBuilder {
txContent.addOperations(opFactory.getOperations()); txContent.addOperations(opFactory.getOperations());
txContent.setTime(time); 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); txContent.setHash(contentHash);


return txContent; 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<OperationResultHandle> getReturnValuehandlers() { public Collection<OperationResultHandle> getReturnValuehandlers() {
return opFactory.getReturnValuetHandlers(); return opFactory.getReturnValuetHandlers();


+ 8
- 2
source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/TxRequestBuilder.java View File

@@ -75,8 +75,14 @@ public class TxRequestBuilder implements TransactionRequestBuilder {
} }
public static boolean verifySignature(TransactionContent txContent, SignatureDigest signDigest, PubKey pubKey) { 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 @Override


+ 26
- 21
source/pom.xml View File

@@ -8,11 +8,11 @@
<artifactId>spring-boot-starter-parent</artifactId> <artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.6.RELEASE</version> <version>2.0.6.RELEASE</version>
</parent> </parent>
<!--<parent>-->
<!--<groupId>org.sonatype.oss</groupId>-->
<!--<artifactId>oss-parent</artifactId>-->
<!--<version>7</version>-->
<!--</parent>-->
<!--<parent> -->
<!--<groupId>org.sonatype.oss</groupId> -->
<!--<artifactId>oss-parent</artifactId> -->
<!--<version>7</version> -->
<!--</parent> -->


<groupId>com.jd.blockchain</groupId> <groupId>com.jd.blockchain</groupId>
<artifactId>jdchain-root</artifactId> <artifactId>jdchain-root</artifactId>
@@ -92,6 +92,11 @@
<artifactId>mockito-core</artifactId> <artifactId>mockito-core</artifactId>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
<scope>test</scope>
</dependency>
</dependencies> </dependencies>


<dependencyManagement> <dependencyManagement>
@@ -446,22 +451,22 @@
</execution> </execution>
</executions> </executions>
</plugin> </plugin>
<!--&lt;!&ndash; 生成sources源码包的插件 &ndash;&gt;-->
<!--<plugin>-->
<!--<artifactId>maven-source-plugin</artifactId>-->
<!--<version>2.4</version>-->
<!--<configuration>-->
<!--<attach>true</attach>-->
<!--</configuration>-->
<!--<executions>-->
<!--<execution>-->
<!--<phase>package</phase>-->
<!--<goals>-->
<!--<goal>jar-no-fork</goal>-->
<!--</goals>-->
<!--</execution>-->
<!--</executions>-->
<!--</plugin>-->
<!--&lt;!&ndash; 生成sources源码包的插件 &ndash;&gt; -->
<!--<plugin> -->
<!--<artifactId>maven-source-plugin</artifactId> -->
<!--<version>2.4</version> -->
<!--<configuration> -->
<!--<attach>true</attach> -->
<!--</configuration> -->
<!--<executions> -->
<!--<execution> -->
<!--<phase>package</phase> -->
<!--<goals> -->
<!--<goal>jar-no-fork</goal> -->
<!--</goals> -->
<!--</execution> -->
<!--</executions> -->
<!--</plugin> -->
</plugins> </plugins>
</pluginManagement> </pluginManagement>




+ 3
- 0
source/utils/utils-common/src/main/java/com/jd/blockchain/utils/io/BytesUtils.java View File

@@ -46,6 +46,9 @@ public class BytesUtils {
if (bytes1 == bytes2) { if (bytes1 == bytes2) {
return true; return true;
} }
if (bytes1 == null || bytes2 == null) {
return false;
}
if (bytes1.length != bytes2.length) { if (bytes1.length != bytes2.length) {
return false; return false;
} }


Loading…
Cancel
Save