| @@ -5,6 +5,7 @@ import com.jd.blockchain.binaryproto.DataContract; | |||
| import com.jd.blockchain.consts.DataCodes; | |||
| import com.jd.blockchain.ledger.*; | |||
| import com.jd.blockchain.utils.Bytes; | |||
| import com.jd.blockchain.utils.IllegalDataException; | |||
| import org.springframework.util.ReflectionUtils; | |||
| import java.math.BigDecimal; | |||
| import java.nio.ByteBuffer; | |||
| @@ -117,7 +118,7 @@ public class ContractSerializeUtils { | |||
| DATA_CONTRACT_MAP.put(DataCodes.CONTRACT_TEXT, CONTRACT_TEXT.class); | |||
| DATA_CONTRACT_MAP.put(DataCodes.CONTRACT_BINARY, CONTRACT_BINARY.class); | |||
| DATA_CONTRACT_MAP.put(DataCodes.CONTRACT_BIG_INT, CONTRACT_BIG_INT.class); | |||
| // DATA_CONTRACT_MAP.put(DataCodes.TX_CONTENT_BODY, TransactionContentBody.class); | |||
| DATA_CONTRACT_MAP.put(DataCodes.CONTRACT_BIZ_CONTENT, ContractBizContent.class); | |||
| return DATA_CONTRACT_MAP; | |||
| } | |||
| @@ -140,8 +141,12 @@ public class ContractSerializeUtils { | |||
| return (CONTRACT_BINARY) () -> (Bytes) object; | |||
| }else if(getDataIntf().get(dataContract.code()).equals(CONTRACT_BIG_INT.class)){ | |||
| return (CONTRACT_BIG_INT) () -> new BigDecimal(object.toString()); | |||
| }else if(getDataIntf().get(dataContract.code()).equals(ContractBizContent.class)){ | |||
| ContractBizContent contractBizContent = (ContractBizContent)object; | |||
| return contractBizContent; | |||
| }else { | |||
| throw new IllegalDataException("cann't get new Object by dataContract and object."); | |||
| } | |||
| return null; | |||
| } | |||
| /** | |||
| @@ -164,6 +169,8 @@ public class ContractSerializeUtils { | |||
| return CONTRACT_TEXT.class; | |||
| }else if(classType.equals(Bytes.class)){ | |||
| return CONTRACT_BINARY.class; | |||
| }else if(classType.equals(BigDecimal.class)){ | |||
| return CONTRACT_BIG_INT.class; | |||
| } | |||
| return null; | |||
| } | |||
| @@ -22,9 +22,16 @@ public interface ContractBizContent { | |||
| HashDigest getLedgerHash(); | |||
| /** | |||
| * 操作列表; | |||
| * 地址; | |||
| * @return | |||
| */ | |||
| @DataField(order = 2, list = true, refContract = true, genericContract = true) | |||
| Operation[] getOperations(); | |||
| @DataField(order = 2, primitiveType = PrimitiveType.TEXT) | |||
| String getAddr(); | |||
| /** | |||
| * 年龄; | |||
| * @return | |||
| */ | |||
| @DataField(order = 3, primitiveType = PrimitiveType.INT32) | |||
| int getAge(); | |||
| } | |||
| @@ -62,7 +62,7 @@ public class GatewayServiceFactory implements BlockchainServiceFactory, Closeabl | |||
| DataContractRegistry.register(CONTRACT_INT64.class); | |||
| DataContractRegistry.register(CONTRACT_TEXT.class); | |||
| DataContractRegistry.register(CONTRACT_BINARY.class); | |||
| // DataContractRegistry.register(CONTRACT_BIG_INT.class); | |||
| DataContractRegistry.register(ContractBizContent.class); | |||
| ByteArrayObjectUtil.init(); | |||
| } | |||
| @@ -4,9 +4,12 @@ import com.jd.blockchain.binaryproto.DataContract; | |||
| import com.jd.blockchain.consts.DataCodes; | |||
| import com.jd.blockchain.contract.Contract; | |||
| import com.jd.blockchain.contract.ContractEvent; | |||
| import com.jd.blockchain.ledger.ContractBizContent; | |||
| import com.jd.blockchain.ledger.TransactionContentBody; | |||
| import com.jd.blockchain.utils.Bytes; | |||
| import java.math.BigDecimal; | |||
| /** | |||
| * 示例:一个“资产管理”智能合约; | |||
| * | |||
| @@ -22,19 +25,16 @@ public interface AssetContract2 { | |||
| * 新发行的资产的持有账户; | |||
| */ | |||
| @ContractEvent(name = "issue-asset-0") | |||
| void issue(@DataContract(code = DataCodes.TX_CONTENT_BODY) TransactionContentBody transactionContentBody, | |||
| @DataContract(code = DataCodes.CONTRACT_TEXT) String assetHolderAddress); | |||
| void issue(ContractBizContent contractBizContent, String assetHolderAddress); | |||
| /** | |||
| * issue asset; | |||
| * @param transactionContentBody | |||
| * @param contractBizContent | |||
| * @param assetHolderAddress | |||
| * @param cashNumber | |||
| */ | |||
| @ContractEvent(name = "issue-asset") | |||
| public void issue(@DataContract(code = DataCodes.TX_CONTENT_BODY) TransactionContentBody transactionContentBody, | |||
| @DataContract(code = DataCodes.CONTRACT_TEXT) String assetHolderAddress, | |||
| @DataContract(code = DataCodes.CONTRACT_INT64) long cashNumber); | |||
| public void issue(ContractBizContent contractBizContent, String assetHolderAddress, long cashNumber); | |||
| /** | |||
| * Bytes can bring the byte[]; | |||
| @@ -49,5 +49,5 @@ public interface AssetContract2 { | |||
| void issue(Byte bytes, String assetHolderAddress, long cashNumber); | |||
| @ContractEvent(name = "issue-asset-4") | |||
| void issue1(byte[] bytes, String assetHolderAddress, long cashNumber); | |||
| void issue(Byte byteObj, String assetHolderAddress, Bytes cashNumber); | |||
| } | |||
| @@ -23,7 +23,9 @@ import org.springframework.core.io.ClassPathResource; | |||
| import java.io.File; | |||
| import java.io.FileInputStream; | |||
| import java.io.IOException; | |||
| import java.math.BigDecimal; | |||
| import static org.junit.Assert.assertEquals; | |||
| import static org.junit.Assert.assertTrue; | |||
| /** | |||
| @@ -64,21 +66,27 @@ public class SDK_Contract_Test { | |||
| /** | |||
| * 演示合约执行的过程; | |||
| */ | |||
| @Test | |||
| // @Test | |||
| public void demoContract1() { | |||
| String dataAddress = registerData4Contract(); | |||
| // 发起交易; | |||
| TransactionTemplate txTemp = bcsrv.newTransaction(ledgerHash); | |||
| String contractAddress = "LdeNhjPGzHcHL6rLcJ7whHxUbn9Tv7qSKRfEA"; | |||
| String contractAddress = "LdeNg8JHFCKABJt6AaRNVCZPgY4ofGPd8MgcR"; | |||
| AssetContract2 assetContract = txTemp.contract(contractAddress, AssetContract2.class); | |||
| TransactionContentBody transactionContentBody = new TransactionContentBody() { | |||
| ContractBizContent contractBizContent = new ContractBizContent() { | |||
| @Override | |||
| public HashDigest getLedgerHash() { | |||
| return new HashDigest(ClassicAlgorithm.SHA256, "zhaogw".getBytes()); | |||
| } | |||
| @Override | |||
| public Operation[] getOperations() { | |||
| return new Operation[0]; | |||
| public String getAddr() { | |||
| return "jinghailu street."; | |||
| } | |||
| @Override | |||
| public int getAge() { | |||
| return 100; | |||
| } | |||
| }; | |||
| // assetContract.issue(transactionContentBody,contractAddress); | |||
| @@ -86,13 +94,19 @@ public class SDK_Contract_Test { | |||
| // assetContract.issue(Bytes.fromString("zhaogw, contract based interface is OK!"),contractAddress,77777); | |||
| // assetContract.issue(Bytes.fromString("zhaogw, contract based interface is OK!"),contractAddress,77777); | |||
| Byte byteObj = Byte.parseByte("127"); | |||
| assetContract.issue(byteObj,contractAddress,321123); | |||
| assetContract.issue(byteObj,dataAddress,321123); | |||
| assetContract.issue(contractBizContent,dataAddress); | |||
| assetContract.issue(Byte.parseByte("126"),dataAddress,Bytes.fromString("100.234")); | |||
| // TX 准备就绪; | |||
| PreparedTransaction prepTx = txTemp.prepare(); | |||
| prepTx.sign(signKeyPair); | |||
| // 提交交易; | |||
| prepTx.commit(); | |||
| TransactionResponse transactionResponse = prepTx.commit(); | |||
| //check; | |||
| KVDataEntry[] dataEntries = bcsrv.getDataEntries(ledgerHash,dataAddress,"total"); | |||
| assertEquals("100",dataEntries[0].getValue().toString()); | |||
| } | |||
| @Test | |||
| @@ -126,6 +140,22 @@ public class SDK_Contract_Test { | |||
| this.setDataInDataAddress(dataAccount.getAddress(),keys,values2,1); | |||
| } | |||
| private String registerData4Contract(){ | |||
| // 在本地定义 TX 模板 | |||
| TransactionTemplate txTemp = bcsrv.newTransaction(ledgerHash); | |||
| BlockchainKeypair dataAccount = BlockchainKeyGenerator.getInstance().generate(); | |||
| txTemp.dataAccounts().register(dataAccount.getIdentity()); | |||
| txTemp.dataAccount(dataAccount.getAddress()).set("total", 200, -1); | |||
| // TX 准备就绪; | |||
| PreparedTransaction prepTx = txTemp.prepare(); | |||
| prepTx.sign(signKeyPair); | |||
| // 提交交易; | |||
| TransactionResponse transactionResponse = prepTx.commit(); | |||
| assertTrue(transactionResponse.isSuccess()); | |||
| return dataAccount.getAddress().toBase58(); | |||
| } | |||
| private void setDataInDataAddress(Bytes dataAddress, String[] keys, String[] values, long version){ | |||
| // 在本地定义 TX 模板 | |||
| TransactionTemplate txTemp = bcsrv.newTransaction(ledgerHash); | |||
| @@ -35,6 +35,7 @@ import java.io.File; | |||
| import java.io.FileInputStream; | |||
| import java.io.IOException; | |||
| import java.io.InputStream; | |||
| import java.math.BigDecimal; | |||
| import java.net.URL; | |||
| import java.util.ArrayList; | |||
| import java.util.Arrays; | |||
| @@ -54,6 +55,7 @@ import static org.junit.Assert.*; | |||
| */ | |||
| public class IntegrationBase { | |||
| public static String KEY_TOTAL = "total"; | |||
| static { | |||
| DataContractRegistry.register(LedgerInitOperation.class); | |||
| @@ -107,6 +109,7 @@ public class IntegrationBase { | |||
| // 定义交易; | |||
| TransactionTemplate txTpl = blockchainService.newTransaction(ledgerHash); | |||
| txTpl.dataAccounts().register(dataAccount.getIdentity()); | |||
| txTpl.dataAccount(dataAccount.getAddress()).set("total", 200, -1); | |||
| // 签名; | |||
| PreparedTransaction ptx = txTpl.prepare(); | |||
| @@ -440,6 +443,8 @@ public class IntegrationBase { | |||
| static HashDigest txContentHash; | |||
| public static LedgerBlock testSDK_Contract(AsymmetricKeypair adminKey, HashDigest ledgerHash, | |||
| BlockchainService blockchainService,LedgerRepository ledgerRepository) { | |||
| KeyPairResponse keyPairResponse = testSDK_RegisterDataAccount(adminKey,ledgerHash,blockchainService); | |||
| System.out.println("adminKey="+ AddressEncoding.generateAddress(adminKey.getPubKey())); | |||
| BlockchainKeypair userKey = BlockchainKeyGenerator.getInstance().generate(); | |||
| System.out.println("userKey="+userKey.getAddress()); | |||
| @@ -458,32 +463,34 @@ public class IntegrationBase { | |||
| TransactionResponse txResp = ptx.commit(); | |||
| assertTrue(txResp.isSuccess()); | |||
| // 验证结果; | |||
| txResp.getContentHash(); | |||
| // 验证结果hash;请求的hash=相应的内容hash; | |||
| assertEquals(ptx.getHash(),txResp.getContentHash()); | |||
| LedgerBlock block = ledgerRepository.getBlock(txResp.getBlockHeight()); | |||
| byte[] contractCodeInDb = ledgerRepository.getContractAccountSet(block).getContract(contractDeployKey.getAddress()) | |||
| .getChainCode(); | |||
| assertArrayEquals(contractCode, contractCodeInDb); | |||
| txContentHash = ptx.getHash(); | |||
| // execute the contract; | |||
| testContractExe(adminKey, ledgerHash, userKey, blockchainService, ledgerRepository, AssetContract.class); | |||
| testContractExe(adminKey, ledgerHash, keyPairResponse.keyPair, blockchainService, ledgerRepository); | |||
| return block; | |||
| } | |||
| private static <T> void testContractExe(AsymmetricKeypair adminKey, HashDigest ledgerHash, BlockchainKeypair userKey, | |||
| BlockchainService blockchainService,LedgerRepository ledgerRepository,Class<T> contractIntf) { | |||
| private static <T> void testContractExe(AsymmetricKeypair adminKey, HashDigest ledgerHash, BlockchainKeypair dataKey, | |||
| BlockchainService blockchainService,LedgerRepository ledgerRepository) { | |||
| LedgerInfo ledgerInfo = blockchainService.getLedger(ledgerHash); | |||
| LedgerBlock previousBlock = blockchainService.getBlock(ledgerHash, ledgerInfo.getLatestBlockHeight() - 1); | |||
| // 定义交易; | |||
| TransactionTemplate txTpl = blockchainService.newTransaction(ledgerHash); | |||
| Byte byteObj = Byte.parseByte("127"); | |||
| Byte byteObj = Byte.parseByte("123"); | |||
| // txTpl.contract(contractDeployKey.getAddress(),AssetContract2.class).issue(byteObj, | |||
| // contractDeployKey.getAddress().toBase58(),321123); | |||
| txTpl.contract(contractDeployKey.getAddress(),AssetContract2.class).issue(byteObj, | |||
| contractDeployKey.getAddress().toBase58(),321123); | |||
| dataKey.getAddress().toBase58(),Bytes.fromString("123321")); | |||
| // txTpl.contract(contractDeployKey.getAddress(),AssetContract2.class).issue(byteObj,dataKey.getAddress().toBase58(),123456); | |||
| // 签名; | |||
| PreparedTransaction ptx = txTpl.prepare(); | |||
| @@ -493,8 +500,11 @@ public class IntegrationBase { | |||
| TransactionResponse txResp = ptx.commit(); | |||
| // 验证结果; | |||
| txResp.getContentHash(); | |||
| Assert.assertTrue(txResp.isSuccess()); | |||
| assertEquals(ptx.getHash(),txResp.getContentHash()); | |||
| LedgerBlock block = ledgerRepository.getBlock(txResp.getBlockHeight()); | |||
| KVDataEntry[] kvDataEntries = ledgerRepository.getDataAccountSet(block).getDataAccount(dataKey.getAddress()).getDataEntries(0,1); | |||
| assertEquals("100",kvDataEntries[0].getValue().toString()); | |||
| } | |||
| /** | |||
| @@ -1,12 +1,12 @@ | |||
| package test.com.jd.blockchain.intgr.contract; | |||
| import com.jd.blockchain.binaryproto.DataContract; | |||
| import com.jd.blockchain.consts.DataCodes; | |||
| import com.jd.blockchain.contract.Contract; | |||
| import com.jd.blockchain.contract.ContractEvent; | |||
| import com.jd.blockchain.ledger.TransactionContentBody; | |||
| import com.jd.blockchain.ledger.ContractBizContent; | |||
| import com.jd.blockchain.utils.Bytes; | |||
| import java.math.BigDecimal; | |||
| /** | |||
| * 示例:一个“资产管理”智能合约; | |||
| * | |||
| @@ -22,32 +22,23 @@ public interface AssetContract2 { | |||
| * 新发行的资产的持有账户; | |||
| */ | |||
| @ContractEvent(name = "issue-asset-0") | |||
| void issue(@DataContract(code = DataCodes.TX_CONTENT_BODY) TransactionContentBody transactionContentBody, | |||
| @DataContract(code = DataCodes.CONTRACT_TEXT) String assetHolderAddress); | |||
| void issue(ContractBizContent contractBizContent, String assetHolderAddress); | |||
| /** | |||
| * issue asset; | |||
| * @param transactionContentBody | |||
| * 发行资产; | |||
| * 新发行的资产数量; | |||
| * @param assetHolderAddress | |||
| * @param cashNumber | |||
| * 新发行的资产的持有账户; | |||
| */ | |||
| @ContractEvent(name = "issue-asset") | |||
| public void issue(@DataContract(code = DataCodes.TX_CONTENT_BODY) TransactionContentBody transactionContentBody, | |||
| @DataContract(code = DataCodes.CONTRACT_TEXT) String assetHolderAddress, | |||
| @DataContract(code = DataCodes.CONTRACT_INT64) long cashNumber); | |||
| void issue(ContractBizContent contractBizContent, String assetHolderAddress, long cashNumber); | |||
| /** | |||
| * Bytes can bring the byte[]; | |||
| * @param bytes | |||
| * @param assetHolderAddress | |||
| * @param cashNumber | |||
| */ | |||
| @ContractEvent(name = "issue-asset-2") | |||
| void issue(Bytes bytes, String assetHolderAddress, long cashNumber); | |||
| @ContractEvent(name = "issue-asset-3") | |||
| void issue(Byte bytes, String assetHolderAddress, long cashNumber); | |||
| @ContractEvent(name = "issue-asset-3") | |||
| void issue(Byte byteObj, String assetHolderAddress, long cashNumber); | |||
| @ContractEvent(name = "issue-asset-4") | |||
| void issue1(byte[] bytes, String assetHolderAddress, long cashNumber); | |||
| void issue(Byte byteObj, String assetHolderAddress, Bytes cashNumber); | |||
| } | |||