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