@@ -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> |
@@ -63,7 +63,7 @@ | |||
<scope>test</scope> | |||
</dependency> | |||
</dependencies> | |||
</dependencies> | |||
<build> | |||
<plugins> | |||
@@ -78,42 +78,32 @@ | |||
</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-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>--> | |||
<!--<!–<arg>-verbose</arg>–>--> | |||
<!--<!–<arg>-Xlint:unchecked</arg>–>--> | |||
<!--<!–<arg>-Xlint:deprecation</arg>–>--> | |||
<!--<!–<arg>-bootclasspath</arg>–>--> | |||
<!--<!–<arg>${env.JAVA_HOME}/jre/lib/rt.jar</arg>–>--> | |||
<!--<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> --> | |||
<!--<!–<arg>-verbose</arg>–> --> | |||
<!--<!–<arg>-Xlint:unchecked</arg>–> --> | |||
<!--<!–<arg>-Xlint:deprecation</arg>–> --> | |||
<!--<!–<arg>-bootclasspath</arg>–> --> | |||
<!--<!–<arg>${env.JAVA_HOME}/jre/lib/rt.jar</arg>–> --> | |||
<!--<arg>-extdirs</arg> --> | |||
<!--<arg>${project.basedir}/../contract/contract-libs;$JAVA_HOME/jre/lib/ext</arg> --> | |||
<!--</compilerArgs> --> | |||
<!--</configuration> --> | |||
<!--</plugin> --> | |||
<!--</plugins> --> | |||
<!--</build> --> | |||
</project> |
@@ -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(); | |||
/** | |||
* 开始新事务;<br> | |||
* | |||
@@ -32,7 +47,8 @@ public interface LedgerEditor { | |||
* 或者全部回滚(通过方法 {@link LedgerTransactionContext#rollback()}),以此实现原子性写入; | |||
* <p> | |||
* | |||
* 每一次事务性的账本写入操作在提交后,都会记录该事务相关的系统全局快照,以交易对象 {@link LedgerTransaction} 进行保存;<p> | |||
* 每一次事务性的账本写入操作在提交后,都会记录该事务相关的系统全局快照,以交易对象 {@link LedgerTransaction} 进行保存; | |||
* <p> | |||
* | |||
* 注:方法不解析、不执行交易中的操作; | |||
* | |||
@@ -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); | |||
@@ -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:验证交易签名; | |||
@@ -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<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 { | |||
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; | |||
} | |||
@@ -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(); | |||
@@ -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(); | |||
} | |||
} |
@@ -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); | |||
@@ -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(); | |||
} | |||
@@ -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(); | |||
@@ -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()); | |||
@@ -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) { | |||
@@ -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<OperationResultHandle> getReturnValuehandlers() { | |||
return opFactory.getReturnValuetHandlers(); | |||
@@ -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 | |||
@@ -8,11 +8,11 @@ | |||
<artifactId>spring-boot-starter-parent</artifactId> | |||
<version>2.0.6.RELEASE</version> | |||
</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> | |||
<artifactId>jdchain-root</artifactId> | |||
@@ -92,6 +92,11 @@ | |||
<artifactId>mockito-core</artifactId> | |||
<scope>test</scope> | |||
</dependency> | |||
<dependency> | |||
<groupId>org.springframework.boot</groupId> | |||
<artifactId>spring-boot-starter-log4j2</artifactId> | |||
<scope>test</scope> | |||
</dependency> | |||
</dependencies> | |||
<dependencyManagement> | |||
@@ -446,22 +451,22 @@ | |||
</execution> | |||
</executions> | |||
</plugin> | |||
<!--<!– 生成sources源码包的插件 –>--> | |||
<!--<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>--> | |||
<!--<!– 生成sources源码包的插件 –> --> | |||
<!--<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> | |||
</pluginManagement> | |||
@@ -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; | |||
} | |||