diff --git a/source/binary-proto/src/main/java/com/jd/blockchain/binaryproto/BinaryProtocol.java b/source/binary-proto/src/main/java/com/jd/blockchain/binaryproto/BinaryProtocol.java index c06c6039..3e4a691a 100644 --- a/source/binary-proto/src/main/java/com/jd/blockchain/binaryproto/BinaryProtocol.java +++ b/source/binary-proto/src/main/java/com/jd/blockchain/binaryproto/BinaryProtocol.java @@ -52,9 +52,17 @@ public class BinaryProtocol { public static T decodeAs(byte[] dataSegment, Class contractType) { + return decodeAs(dataSegment, contractType, true); + } + + public static T decodeAs(byte[] dataSegment, Class contractType, boolean autoRegister) { DataContractEncoder encoder = DataContractContext.ENCODER_LOOKUP.lookup(contractType); if (encoder == null) { - throw new DataContractException("Contract type is not registered! --" + contractType.toString()); + if (autoRegister) { + encoder = DataContractContext.resolve(contractType); + }else { + throw new DataContractException("Contract type is not registered! --" + contractType.toString()); + } } BytesSlice bytes = new BytesSlice(dataSegment, 0, dataSegment.length); return encoder.decode(bytes.getInputStream()); diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/PreparedTx.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/PreparedTx.java index bba464e3..9a413d36 100644 --- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/PreparedTx.java +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/PreparedTx.java @@ -1,16 +1,10 @@ package com.jd.blockchain.transaction; import java.io.IOException; -import java.util.Arrays; -import java.util.Collection; -import java.util.Comparator; - -import org.springframework.cglib.proxy.UndeclaredThrowableException; import com.jd.blockchain.crypto.AsymmetricKeypair; import com.jd.blockchain.crypto.HashDigest; import com.jd.blockchain.ledger.DigitalSignature; -import com.jd.blockchain.ledger.OperationResult; import com.jd.blockchain.ledger.PreparedTransaction; import com.jd.blockchain.ledger.TransactionContent; import com.jd.blockchain.ledger.TransactionRequest; @@ -21,34 +15,17 @@ public class PreparedTx implements PreparedTransaction { private TransactionRequestBuilder txReqBuilder; - private TransactionService txProcessor; - - private OperationResultHandle[] opReturnValueHandlers; - - private TxStateManager stateManager; + private TransactionService txService; /** * 创建一个“就绪交易”对象; * - * @param txReqBuilder 交易请求构建器; - * @param txProcessor 交易处理服务; - * @param opReturnValueHandlerList 操作返回值处理器列表; + * @param txReqBuilder 交易请求构建器; + * @param txService 交易处理服务; */ - public PreparedTx(TxStateManager stateManager, TransactionRequestBuilder txReqBuilder, - TransactionService txProcessor, Collection opReturnValueHandlerList) { - this.stateManager = stateManager; + public PreparedTx(TransactionRequestBuilder txReqBuilder, TransactionService txService) { this.txReqBuilder = txReqBuilder; - this.txProcessor = txProcessor; - - this.opReturnValueHandlers = opReturnValueHandlerList - .toArray(new OperationResultHandle[opReturnValueHandlerList.size()]); - // 按照操作索引升序排列; - Arrays.sort(opReturnValueHandlers, new Comparator() { - @Override - public int compare(OperationResultHandle o1, OperationResultHandle o2) { - return o1.getOperationIndex() - o2.getOperationIndex(); - } - }); + this.txService = txService; } @Override @@ -75,60 +52,14 @@ public class PreparedTx implements PreparedTransaction { @Override public TransactionResponse commit() { - stateManager.commit(); - TransactionResponse txResponse = null; - try { - TransactionRequest txReq = txReqBuilder.buildRequest(); - // 发起交易请求; - txResponse = txProcessor.process(txReq); - - stateManager.complete(); - - } catch (Exception ex) { - stateManager.close(); - handleError(ex); - throw new UndeclaredThrowableException(ex); - } - - if (txResponse != null) { - handleResults(txResponse); - } - - return txResponse; + // 生成请求; + TransactionRequest txReq = txReqBuilder.buildRequest(); + // 发起交易请求; + return txService.process(txReq); } @Override public void close() throws IOException { - if (!stateManager.close()) { - TransactionCancelledExeption error = new TransactionCancelledExeption( - "Prepared transaction has been cancelled!"); - handleError(error); - } - } - - private void handleError(Throwable error) { - for (OperationResultHandle handle : opReturnValueHandlers) { - handle.complete(error); - } - } - - private void handleResults(TransactionResponse txResponse) { - // 解析返回值;正常的情况下,返回结果列表与结果处理器列表中元素对应的操作索引是一致的; - OperationResult[] opResults = txResponse.getOperationResults(); - if (opResults != null && opResults.length > 0) { - if (opResults.length != opReturnValueHandlers.length) { - throw new IllegalStateException(String.format( - "The operation result list of tx doesn't match it's return value handler list! --[TX.Content.Hash=%s][NumOfResults=%s][NumOfHandlers=%s]", - txResponse.getContentHash(), opResults.length, opReturnValueHandlers.length)); - } - for (int i = 0; i < opResults.length; i++) { - if (opResults[i].getIndex() != opReturnValueHandlers[i].getOperationIndex()) { - throw new IllegalStateException( - "The operation indexes of the items in the result list and in the handler list don't match!"); - } - opReturnValueHandlers[i].complete(opResults[i].getResult()); - } - } } } diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/StatefulPreparedTx.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/StatefulPreparedTx.java new file mode 100644 index 00000000..d20ff16d --- /dev/null +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/StatefulPreparedTx.java @@ -0,0 +1,108 @@ +package com.jd.blockchain.transaction; + +import java.io.IOException; +import java.util.Arrays; +import java.util.Collection; +import java.util.Comparator; + +import org.springframework.cglib.proxy.UndeclaredThrowableException; + +import com.jd.blockchain.crypto.AsymmetricKeypair; +import com.jd.blockchain.ledger.DigitalSignature; +import com.jd.blockchain.ledger.OperationResult; +import com.jd.blockchain.ledger.TransactionRequestBuilder; +import com.jd.blockchain.ledger.TransactionResponse; + +class StatefulPreparedTx extends PreparedTx { + + private OperationResultHandle[] opReturnValueHandlers; + + private TxStateManager stateManager; + + /** + * 创建一个“就绪交易”对象; + * + * @param txReqBuilder 交易请求构建器; + * @param txProcessor 交易处理服务; + * @param opReturnValueHandlerList 操作返回值处理器列表; + */ + StatefulPreparedTx(TxStateManager stateManager, TransactionRequestBuilder txReqBuilder, + TransactionService txProcessor, Collection opReturnValueHandlerList) { + super(txReqBuilder, txProcessor); + this.stateManager = stateManager; + + this.opReturnValueHandlers = opReturnValueHandlerList + .toArray(new OperationResultHandle[opReturnValueHandlerList.size()]); + // 按照操作索引升序排列; + Arrays.sort(opReturnValueHandlers, new Comparator() { + @Override + public int compare(OperationResultHandle o1, OperationResultHandle o2) { + return o1.getOperationIndex() - o2.getOperationIndex(); + } + }); + } + + @Override + public DigitalSignature sign(AsymmetricKeypair keyPair) { + DigitalSignature signature = SignatureUtils.sign(getTransactionContent(), keyPair); + addSignature(signature); + return signature; + } + + @Override + public TransactionResponse commit() { + stateManager.commit(); + TransactionResponse txResponse = null; + try { + // 发起交易请求; + txResponse = super.commit(); + + stateManager.complete(); + } catch (Exception ex) { + stateManager.close(); + handleError(ex); + throw new UndeclaredThrowableException(ex); + } + + if (txResponse != null) { + handleResults(txResponse); + } + + return txResponse; + } + + @Override + public void close() throws IOException { + if (!stateManager.close()) { + TransactionCancelledExeption error = new TransactionCancelledExeption( + "Prepared transaction has been cancelled!"); + handleError(error); + } + } + + private void handleError(Throwable error) { + for (OperationResultHandle handle : opReturnValueHandlers) { + handle.complete(error); + } + } + + private void handleResults(TransactionResponse txResponse) { + // 解析返回值;正常的情况下,返回结果列表与结果处理器列表中元素对应的操作索引是一致的; + OperationResult[] opResults = txResponse.getOperationResults(); + if (opResults != null && opResults.length > 0) { + if (opResults.length != opReturnValueHandlers.length) { + throw new IllegalStateException(String.format( + "The operation result list of tx doesn't match it's return value handler list! --[TX.Content.Hash=%s][NumOfResults=%s][NumOfHandlers=%s]", + txResponse.getContentHash(), opResults.length, opReturnValueHandlers.length)); + } + for (int i = 0; i < opResults.length; i++) { + if (opResults[i].getIndex() != opReturnValueHandlers[i].getOperationIndex()) { + throw new IllegalStateException( + "The operation indexes of the items in the result list and in the handler list don't match!"); + } + opReturnValueHandlers[i].complete(opResults[i].getResult()); + } + } + } + +} diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/TxTemplate.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/TxTemplate.java index 01fb8caf..45562a48 100644 --- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/TxTemplate.java +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/TxTemplate.java @@ -32,7 +32,7 @@ public class TxTemplate implements TransactionTemplate { public PreparedTransaction prepare() { stateManager.prepare(); TransactionRequestBuilder txReqBuilder = txBuilder.prepareRequest(); - return new PreparedTx(stateManager, txReqBuilder, txService, txBuilder.getReturnValuehandlers()); + return new StatefulPreparedTx(stateManager, txReqBuilder, txService, txBuilder.getReturnValuehandlers()); } @Override diff --git a/source/sdk/sdk-base/src/main/java/com/jd/blockchain/sdk/BlockchainTransactionService.java b/source/sdk/sdk-base/src/main/java/com/jd/blockchain/sdk/BlockchainTransactionService.java index eff792a3..f7dcf433 100644 --- a/source/sdk/sdk-base/src/main/java/com/jd/blockchain/sdk/BlockchainTransactionService.java +++ b/source/sdk/sdk-base/src/main/java/com/jd/blockchain/sdk/BlockchainTransactionService.java @@ -1,6 +1,8 @@ package com.jd.blockchain.sdk; import com.jd.blockchain.crypto.HashDigest; +import com.jd.blockchain.ledger.PreparedTransaction; +import com.jd.blockchain.ledger.TransactionContent; import com.jd.blockchain.ledger.TransactionTemplate; public interface BlockchainTransactionService { @@ -12,6 +14,14 @@ public interface BlockchainTransactionService { */ TransactionTemplate newTransaction(HashDigest ledgerHash); + /** + * 根据交易内容准备交易实例; + * + * @param content + * @return + */ + PreparedTransaction prepareTransaction(TransactionContent content); + // /** // * 以指定的科目和流水号发起新交易; // * diff --git a/source/sdk/sdk-base/src/main/java/com/jd/blockchain/sdk/proxy/BlockchainServiceProxy.java b/source/sdk/sdk-base/src/main/java/com/jd/blockchain/sdk/proxy/BlockchainServiceProxy.java index 9984cef5..16f047b9 100644 --- a/source/sdk/sdk-base/src/main/java/com/jd/blockchain/sdk/proxy/BlockchainServiceProxy.java +++ b/source/sdk/sdk-base/src/main/java/com/jd/blockchain/sdk/proxy/BlockchainServiceProxy.java @@ -11,6 +11,8 @@ import com.jd.blockchain.ledger.LedgerInfo; import com.jd.blockchain.ledger.LedgerMetadata; import com.jd.blockchain.ledger.LedgerTransaction; import com.jd.blockchain.ledger.ParticipantNode; +import com.jd.blockchain.ledger.PreparedTransaction; +import com.jd.blockchain.ledger.TransactionContent; import com.jd.blockchain.ledger.TransactionState; import com.jd.blockchain.ledger.TransactionTemplate; import com.jd.blockchain.ledger.UserInfo; @@ -19,7 +21,9 @@ import com.jd.blockchain.sdk.BlockchainEventListener; import com.jd.blockchain.sdk.BlockchainService; import com.jd.blockchain.sdk.converters.ClientResolveUtil; import com.jd.blockchain.transaction.BlockchainQueryService; +import com.jd.blockchain.transaction.PreparedTx; import com.jd.blockchain.transaction.TransactionService; +import com.jd.blockchain.transaction.TxRequestBuilder; import com.jd.blockchain.transaction.TxTemplate; public abstract class BlockchainServiceProxy implements BlockchainService { @@ -33,6 +37,12 @@ public abstract class BlockchainServiceProxy implements BlockchainService { public TransactionTemplate newTransaction(HashDigest ledgerHash) { return new TxTemplate(ledgerHash, getTransactionService(ledgerHash)); } + + @Override + public PreparedTransaction prepareTransaction(TransactionContent content) { + TxRequestBuilder txReqBuilder = new TxRequestBuilder(content); + return new PreparedTx(txReqBuilder, getTransactionService(content.getLedgerHash())); + } @Override public BlockchainEventHandle addBlockchainEventListener(int filteredEventTypes, String filteredTxHash, diff --git a/source/sdk/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDKDemo_Tx_Persistance.java b/source/sdk/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDKDemo_Tx_Persistance.java new file mode 100644 index 00000000..0fdca4a3 --- /dev/null +++ b/source/sdk/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDKDemo_Tx_Persistance.java @@ -0,0 +1,96 @@ +/** + * Copyright: Copyright 2016-2020 JD.COM All Right Reserved + * FileName: com.jd.blockchain.sdk.samples.SDKDemo_RegisterUser + * Author: shaozhuguang + * Department: 区块链研发部 + * Date: 2018/10/18 下午2:00 + * Description: 注册用户 + */ +package com.jd.blockchain.sdk.samples; + +import com.jd.blockchain.binaryproto.BinaryProtocol; +import com.jd.blockchain.binaryproto.DataContractRegistry; +import com.jd.blockchain.crypto.AsymmetricKeypair; +import com.jd.blockchain.crypto.HashDigest; +import com.jd.blockchain.crypto.PrivKey; +import com.jd.blockchain.crypto.PubKey; +import com.jd.blockchain.ledger.*; +import com.jd.blockchain.sdk.BlockchainService; +import com.jd.blockchain.sdk.client.GatewayServiceFactory; +import com.jd.blockchain.utils.ConsoleUtils; + +/** + * 注册用户 + * + * @author shaozhuguang + * @create 2018/10/18 + * @since 1.0.0 + */ + +public class SDKDemo_Tx_Persistance { + public static void main(String[] args) { + + String GATEWAY_IPADDR = "127.0.0.1"; + int GATEWAY_PORT = 8081; + if (args != null && args.length == 2) { + GATEWAY_IPADDR = args[0]; + GATEWAY_PORT = Integer.parseInt(args[1]); + } + + // 注册相关class + DataContractRegistry.register(TransactionContent.class); + DataContractRegistry.register(TransactionContentBody.class); + DataContractRegistry.register(TransactionRequest.class); + DataContractRegistry.register(NodeRequest.class); + DataContractRegistry.register(EndpointRequest.class); + DataContractRegistry.register(TransactionResponse.class); + + PrivKey privKey = SDKDemo_Params.privkey1; + PubKey pubKey = SDKDemo_Params.pubKey1; + + BlockchainKeypair CLIENT_CERT = new BlockchainKeypair(SDKDemo_Params.pubKey0, SDKDemo_Params.privkey0); + + boolean SECURE = false; + GatewayServiceFactory gatewayServiceFactory = GatewayServiceFactory.connect(GATEWAY_IPADDR, GATEWAY_PORT, SECURE, + CLIENT_CERT); + BlockchainService blockchainService = gatewayServiceFactory.getBlockchainService(); + + HashDigest[] ledgerHashs = blockchainService.getLedgerHashs(); + // 在本地定义注册账号的 TX; + TransactionTemplate txTemp = blockchainService.newTransaction(ledgerHashs[0]); + + // existed signer + AsymmetricKeypair keyPair = new BlockchainKeypair(pubKey, privKey); + + BlockchainKeypair user = BlockchainKeyGenerator.getInstance().generate(); + + // 注册 + txTemp.users().register(user.getIdentity()); + + // 定义角色权限; + txTemp.security().roles().configure("MANAGER") + .enable(LedgerPermission.REGISTER_USER, LedgerPermission.REGISTER_DATA_ACCOUNT) + .enable(TransactionPermission.CONTRACT_OPERATION); + txTemp.security().authorziations().forUser(user.getIdentity()).authorize("MANAGER"); + + // TX 准备就绪; + PreparedTransaction prepTx = txTemp.prepare(); + + // 序列化交易内容; + byte[] txContentBytes = BinaryProtocol.encode(prepTx.getTransactionContent(), TransactionContent.class); + + // 反序列化交易内容; + TransactionContent txContent = BinaryProtocol.decodeAs(txContentBytes, TransactionContent.class); + + // 根据交易内容重新准备交易; + PreparedTransaction decodedPrepTx = blockchainService.prepareTransaction(txContent); + + // 使用私钥进行签名; + decodedPrepTx.sign(keyPair); + + // 提交交易; + TransactionResponse transactionResponse = decodedPrepTx.commit(); + + ConsoleUtils.info("register user complete, result is [%s]", transactionResponse.isSuccess()); + } +} \ No newline at end of file