1. 功能介绍
本文档详细说明BubiChain Java SDK常用接口文档, 使开发者更方便地操作和查询BubiChain区块链。
2. 准备工作
2.1. 环境要求
JDK要求8或更高版本。
3. 安装
需要以下两步来完成,下面以4.1.1版本为例说明。
首先在Maven的配置文件中添加 BubiChain 的以下远程仓库
<repository>
<id>releases</id>
<url>http://maven.bubidev.cn/content/repositories/releases/</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
在pom.xml的配置文件中添加相应版本的依赖包
<dependency>
<groupId>cn.bubi.sdk</groupId>
<artifactId>bubichain-sdk</artifactId>
<version>4.1.1</version>
</dependency>
调用SDK的接口getInstance
来生成SDK实例,如下:
String url = "http://seed1-node.bubi.cn";
SDK sdk = SDK.getInstance(url);
调用Keypair.generator
接口生成账户,具体调用如下:
Keypair keypair = Keypair.generator();
System.out.println(keypair.getPrivateKey());
System.out.println(keypair.getPublicKey());
System.out.println(keypair.getAddress());
至此,链信息以及账户信息准备完成,接下来就可以进行更加深入的操作了。
4. 使用说明
如何使用sdk发送交易,分为以下几步。
4.1. 实例化SDK
String url = "http://seed1-node.bubi.cn";
SDK sdk = SDK.getInstance(url);
4.2. 获取账户nonce值
nonce
用于防止重放攻击并确保交易顺序。每个账户都有一个与之相关的nonce
值,表示该账户已发送的交易数量。每发送一笔交易,nonce
值会递增1。这意味着每笔交易都有一个唯一的nonce
值,从而避免同一交易被多次执行。还可以确保交易按照特定的顺序被处理。调用如下:
// 初始化请求参数
String senderAddress = "adxSa4oENoQCc66JRouZu1rKu4RWjgS69YD4S";
AccountGetNonceRequest getNonceRequest = new AccountGetNonceRequest();
getNonceRequest.setAddress(senderAddress);
// 调用getNonce接口
AccountGetNonceResponse getNonceResponse = sdk.getAccountService().getNonce(getNonceRequest);
// 赋值nonce
if (getNonceResponse.getErrorCode() == 0) {
AccountGetNonceResult result = getNonceResponse.getResult();
System.out.println("nonce: " + result.getNonce());
}
else {
System.out.println("error" + getNonceResponse.getErrorDesc());
}
4.3. 构建操作
操作是指在交易中做的动作,详细信息请参阅SDK接口/操作结构,例如,转移Gas操作,接口调用如下:
String senderAddress = "adxSa4oENoQCc66JRouZu1rKu4RWjgS69YD4S";
String destAddress = "adxSgTxU1awVzNUeR8xcnd3K75XKU8ziNHcWW";
Long eaAmount = ToBaseUnit.ToUGas("10.9");
GasSendOperation operation = new GasSendOperation();
operation.setSourceAddress(senderAddress);
operation.setDestAddress(destAddress);
operation.setAmount(eaAmount);
4.4. 序列化交易
该接口用于序列化交易,并生成交易Blob串,便于网络传输。其中nonce和operation是上面接口得到的,调用如下:
// 初始化变量
String senderAddress = "adxSa4oENoQCc66JRouZu1rKu4RWjgS69YD4S";
Long gasPrice = 1000L;
Long feeLimit = ToBaseUnit.ToUGas("0.01");
// 初始化请求参数
TransactionBuildBlobRequest buildBlobRequest = new TransactionBuildBlobRequest();
buildBlobRequest.setSourceAddress(senderAddress);
buildBlobRequest.setNonce(nonce + 1);
buildBlobRequest.setFeeLimit(feeLimit);
buildBlobRequest.setGasPrice(gasPrice);
buildBlobRequest.addOperation(operation);
// 调用buildBlob接口
TransactionBuildBlobResponse buildBlobResponse = sdk.getTransactionService().buildBlob(buildBlobRequest);
if (buildBlobResponse.getErrorCode() == 0) {
TransactionBuildBlobResult result = buildBlobResponse.getResult();
System.out.println("txHash: " + result.getHash() + ", blob: " + result.getTransactionBlob());
} else {
System.out.println("error: " + buildBlobResponse.getErrorDesc());
}
4.5. 签名交易
该接口用于交易发起者使用其账户私钥对交易进行签名。其中transactionBlob是上面接口得到的,调用如下:
// 初始化请求参数
String senderPrivateKey = "privbwAQyE2vWwzt9NuC8vecqpZm7DS8kfiMPsKPcrTatUkmkxkVhfaf";
String []signerPrivateKeyArr = {senderPrivateKey};
TransactionSignRequest signRequest = new TransactionSignRequest();
signRequest.setBlob(transactionBlob);
for (int i = 0; i < signerPrivateKeyArr.length; i++) {
signRequest.addPrivateKey(signerPrivateKeyArr[i]);
}
// 调用sign接口
TransactionSignResponse signResponse = sdk.getTransactionService().sign(signRequest);
if (signResponse.getErrorCode() == 0) {
TransactionSignResult result = signResponse.getResult();
System.out.println(JSON.toJSONString(result, true));
} else {
System.out.println("error: " + signResponse.getErrorDesc());
}
4.6. 提交交易
该接口用于向BubiChain区块链发送交易请求,触发交易的执行。其中transactionBlob和signResult是上面接口得到的,调用如下:
// 初始化请求参数
TransactionSubmitRequest submitRequest = new TransactionSubmitRequest();
submitRequest.setTransactionBlob(transactionBlob);
submitRequest.setSignatures(signResult.getSignatures());
// 调用submit接口
TransactionSubmitResponse response = sdk.getTransactionService().submit(submitRequest);
if (0 == response.getErrorCode()) {
System.out.println("交易广播成功,hash=" + response.getResult().getHash());
} else {
System.out.println("error: " + response.getErrorDesc());
}
4.7. 查询交易结果
根据提交交易获取到的返回值hash字段进行查询。
public void getTransactionInfo() {
TransactionGetInfoRequest request = new TransactionGetInfoRequest();
request.setHash("0d67997af3777b977deb648082c8288b4ba46b09d910d016f0942bcd853ad518");
TransactionGetInfoResponse response = sdk.getTransactionService().getInfo(request);
if (response.getErrorCode() == 0) {
System.out.println(JSON.toJSONString(response.getResult(), true));
} else {
System.out.println("error: " + response.getErrorDesc());
}
}
5. SDK接口
5.1. 交易服务
交易服务提供交易相关的接口,目前有5个接口:buildBlob、evaluateFee、sign、submit、getInfo。
- buildBlob
接口说明
该接口用于序列化交易,生成交易Blob串,便于网络传输
调用方法
TransactionBuildBlobResponse buildBlob(TransactionBuildBlobRequest);
请求参数
参数 | 类型 | 描述 |
---|---|---|
sourceAddress | String | 必填,发起该操作的源账户地址 |
nonce | Long | 必填,待发起的交易序列号,函数里+1,大小限制[1, Long.MAX_VALUE] |
gasPrice | Long | 必填,交易费用单价,按字节收费,单位UGas,1 Gas = 10^8 UGas,大小限制[1000, Long.MAX_VALUE] |
feeLimit | Long | 必填,交易要求的最低的手续费,单位UGas,1 Gas = 10^8 UGas,大小限制[1, Long.MAX_VALUE] |
operation | BaseOperation[] | 必填,待提交的操作列表,不能为空 |
ceilLedgerSeq | long | 选填,距离当前区块高度指定差值的区块内执行的限制,当区块超出当时区块高度与所设差值的和后,交易执行失败。必须大于等于0,是0时不限制 |
metadata | String | 选填,备注 |
响应数据
字段名称 | 类型 | 描述 |
---|---|---|
transactionBlob | String | Transaction序列化后的16进制字符串 |
hash | String | 交易hash |
示例
// 初始化变量
String senderAddresss = "adxSYQ8iMyZ7Dkj1oX1kjGMV55WXvoPKcLEK3";
String destAddress = "adxSgTxU1awVzNUeR8xcnd3K75XKU8ziNHcWW";
Long eaAmount = ToBaseUnit.ToUGas("10.9");
Long gasPrice = 1000L;
Long feeLimit = ToBaseUnit.ToUGas("0.01");
Long nonce = 1L;
// 构建sendGas操作
GasSendOperation operation = new GasSendOperation();
operation.setSourceAddress(senderAddresss);
operation.setDestAddress(destAddress);
operation.setAmount(eaAmount);
// 初始化请求参数
TransactionBuildBlobRequest request = new TransactionBuildBlobRequest();
request.setSourceAddress(senderAddresss);
request.setNonce(nonce);
request.setFeeLimit(feeLimit);
request.setGasPrice(gasPrice);
request.addOperation(operation);
// 调用buildBlob接口
String transactionBlob = null;
TransactionBuildBlobResponse response = sdk.getTransactionService().buildBlob(request);
if (response.getErrorCode() == 0) {
TransactionBuildBlobResult result = response.getResult();
System.out.println(JSON.toJSONString(result, true));
} else {
System.out.println("error: " + response.getErrorDesc());
}
- evaluateFee
接口说明
该接口实现交易的费用评估。
调用方法
TransactionEvaluateFeeResponse evaluateFee (TransactionEvaluateFeeRequest);
请求参数
参数 | 类型 | 描述 |
---|---|---|
sourceAddress | String | 必填,发起该操作的源账户地址 |
nonce | Long | 必填,待发起的交易序列号,大小限制[1, Long.MAX_VALUE] |
operation | BaseOperation[] | 必填,待提交的操作列表,不能为空 |
signtureNumber | Integer | 选填,待签名者的数量,默认是1,大小限制[1, Integer.MAX_VALUE] |
ceilLedgerSeq | Long | 选填,距离当前区块高度指定差值的区块内执行的限制,当区块超出当时区块高度与所设差值的和后,交易执行失败。必须大于等于0,是0时不限制 |
metadata | String | 选填,备注 |
响应数据
参数 | 类型 | 描述 |
---|---|---|
txs | TestTx[] | 评估交易集 |
示例
// 初始化变量
String senderAddresss = "adxSa4oENoQCc66JRouZu1rKu4RWjgS69YD4S";
String destAddress = "adxSYQ8iMyZ7Dkj1oX1kjGMV55WXvoPKcLEK3";
Long eaAmount = ToBaseUnit.ToUGas("10.9");
Long gasPrice = 1000L;
Long feeLimit = ToBaseUnit.ToUGas("0.01");
Long nonce = 51L;
// 构建sendGas操作
GasSendOperation gasSendOperation = new GasSendOperation();
gasSendOperation.setSourceAddress(senderAddresss);
gasSendOperation.setDestAddress(destAddress);
gasSendOperation.setAmount(eaAmount);
// 初始化评估交易请求参数
TransactionEvaluateFeeRequest request = new TransactionEvaluateFeeRequest();
request.addOperation(gasSendOperation);
request.setSourceAddress(senderAddresss);
request.setNonce(nonce);
request.setSignatureNumber(1);
request.setMetadata(HexFormat.byteToHex("evaluate fees".getBytes()));
// 调用evaluateFee接口
TransactionEvaluateFeeResponse response = sdk.getTransactionService().evaluateFee(request);
if (response.getErrorCode() == 0) {
TransactionEvaluateFeeResult result = response.getResult();
System.out.println(JSON.toJSONString(result, true));
} else {
System.out.println("error: " + response.getErrorDesc());
}
- sign
接口说明
该接口用于实现交易的签名
调用方法
TransactionSignResponse sign(TransactionSignRequest);
请求参数
参数 | 类型 | 描述 |
---|---|---|
blob | String | 必填,待签名的交易Blob |
privateKeys | String[] | 必填,私钥列表 |
响应数据
参数 | 类型 | 描述 |
---|---|---|
signatures | Signature[] | 签名后的数据列表 |
示例
// 初始化请求参数
String issuePrivateKey = "privbwAQyE2vWwzt9NuC8vecqpZm7DS8kfiMPsKPcrTatUkmkxkVhfaf";
String []signerPrivateKeyArr = {issuePrivateKey};
String transactionBlob = "0A246275516E6E5545425245773268423670574847507A77616E5837643238786B364B566370102118C0843D20E8073A56080712246275516E6E5545425245773268423670574847507A77616E5837643238786B364B566370522C0A24627551426A4A443142534A376E7A41627A6454656E416870466A6D7852564545746D78481080A9E08704";
TransactionSignRequest request = new TransactionSignRequest();
request.setBlob(transactionBlob);
for (int i = 0; i < signerPrivateKeyArr.length; i++) {
request.addPrivateKey(signerPrivateKeyArr[i]);
}
TransactionSignResponse response = sdk.getTransactionService().sign(request);
if(0 == response.getErrorCode()){
System.out.println(JSON.toJSONString(response.getResult(), true));
}else{
System.out.println("error: " + response.getErrorDesc());
}
- submit
接口说明
该接口用于实现交易的提交。
调用方法
TransactionSubmitResponse submit(TransactionSubmitRequest);
请求参数
参数 | 类型 | 描述 |
---|---|---|
blob | String | 必填,交易blob |
signature | Signature[] | 必填,签名列表 |
响应数据
参数 | 类型 | 描述 |
---|---|---|
hash | String | 交易hash |
示例
// 初始化请求参数
String transactionBlob = "0A246275516E6E5545425245773268423670574847507A77616E5837643238786B364B566370102118C0843D20E8073A56080712246275516E6E5545425245773268423670574847507A77616E5837643238786B364B566370522C0A24627551426A4A443142534A376E7A41627A6454656E416870466A6D7852564545746D78481080A9E08704";
Signature signature = new Signature();
signature.setSignData("D2B5E3045F2C1B7D363D4F58C1858C30ABBBB0F41E4B2E18AF680553CA9C3689078E215C097086E47A4393BCA715C7A5D2C180D8750F35C6798944F79CC5000A");
signature.setPublicKey("b0011765082a9352e04678ef38d38046dc01306edef676547456c0c23e270aaed7ffe9e31477");
TransactionSubmitRequest request = new TransactionSubmitRequest();
request.setTransactionBlob(transactionBlob);
request.addSignature(signature);
// 调用submit接口
TransactionSubmitResponse response = sdk.getTransactionService().submit(request);
if (0 == response.getErrorCode()) { // 交易提交成功
System.out.println(JSON.toJSONString(response.getResult(), true));
} else{
System.out.println("error: " + response.getErrorDesc());
}
- getInfo
接口说明
该接口用于实现根据交易hash查询交易。
调用方法
TransactionGetInfoResponse getInfo (TransactionGetInfoRequest);
请求参数
参数 | 类型 | 描述 |
---|---|---|
hash | String | 交易hash |
响应数据
参数 | 类型 | 描述 |
---|---|---|
totalCount | Long | 返回的总交易数 |
transactions | TransactionHistory[] | 交易内容 |
示例
// 初始化请求参数
String txHash = "1653f54fbba1134f7e35acee49592a7c29384da10f2f629c9a214f6e54747705";
TransactionGetInfoRequest request = new TransactionGetInfoRequest();
request.setHash(txHash);
// 调用getInfo接口
TransactionGetInfoResponse response = sdk.getTransactionService().getInfo(request);
if (response.getErrorCode() == 0) {
System.out.println(JSON.toJSONString(response.getResult(), true));
} else {
System.out.println("error: " + response.getErrorDesc());
}
5.2. 操作结构
操作是指在交易在要做的事情,在构建操作之前,需要构建操作。目前操作有10种,分别是 AccountActivateOperation、AccountSetMetadataOperation、 AccountSetPrivilegeOperation、 AssetIssueOperation、 AssetSendOperation、 GasSendOperation、 ContractCreateOperation、 ContractInvokeByAssetOperation、 ContractInvokeByGasOperation、 LogCreateOperation。
BaseOperation
BaseOperation是buildBlob接口中所有操作的基类。
成员变量 | 类型 | 描述 |
---|---|---|
sourceAddress | String | 选填,操作源账户地址 |
metadata | String | 选填,备注 |
- AccountActivateOperation
功能
该操作用于激活账户。AccountActivateOperation继承于BaseOperation。
费用
FeeLimit目前固定是0.01 Gas。
成员
成员变量 | 类型 | 描述 |
---|---|---|
sourceAddress | String | 选填,操作源账户地址 |
destAddress | String | 必填,目标账户地址 |
initBalance | Long | 必填,初始化资产,单位UGas,1 Gas = 10^8 UGas, 大小(0, Long.MAX_VALUE] |
metadata | String | 选填,备注 |
-
AccountSetMetadataOperation
功能
该操作用于设置账户metadata。AccountSetMetadataOperation继承于BaseOperation。
费用
FeeLimit目前固定是0.01 Gas。
成员
成员变量 | 类型 | 描述 |
---|---|---|
sourceAddress | String | 选填,操作源账户地址 |
key | String | 必填,metadata的关键词,长度限制[1, 1024] |
value | String | 必填,metadata的内容,长度限制[0, 256000] |
version | Long | 选填,metadata的版本 |
deleteFlag | Boolean | 选填,是否删除metadata |
metadata | String | 选填,备注 |
-
AccountSetPrivilegeOperation
功能
该操作用于设置账户权限。AccountSetPrivilegeOperation继承于BaseOperation。
费用
feeLimit目前固定是0.01 Gas。
成员
成员变量 | 类型 | 描述 |
---|---|---|
sourceAddress | String | 选填,操作源账户地址 |
masterWeight | String | 选填,账户自身权重,大小限制[0, (Integer.MAX_VALUE * 2L + 1)] |
signers | Signer[] | 选填,签名者权重列表 |
txThreshold | String | 选填,交易门限,大小限制[0, Long.MAX_VALUE] |
typeThreshold | TypeThreshold[] | 选填,指定类型交易门限 |
metadata | String | 选填,备注 |
-
AssetIssueOperation
功能
该操作用于发行资产。AssetIssueOperation继承于BaseOperation。
费用
FeeLimit目前固定是50.01 Gas。
成员
成员变量 | 类型 | 描述 |
---|---|---|
sourceAddress | String | 选填,操作源账户地址 |
code | String | 必填,资产编码,长度限制[1, 64] |
assetAmount | Long | 必填,资产发行数量,大小限制[0, Long.MAX_VALUE] |
metadata | String | 选填,备注 |
-
AssetSendOperation
注意:若目标账户未激活,必须先调用激活账户操作。
功能
该操作用于转移资产。AssetSendOperation继承于BaseOperation。
费用
FeeLimit目前固定是0.01 Gas。
成员
成员变量 | 类型 | 描述 |
---|---|---|
sourceAddress | String | 选填,操作源账户地址 |
destAddress | String | 必填,目标账户地址 |
code | String | 必填,资产编码,长度限制[1, 64] |
issuer | String | 必填,资产发行账户地址 |
assetAmount | Long | 必填,资产数量,大小限制[0, Long.MAX_VALUE] |
metadata | String | 选填,备注 |
-
GasSendOperation
注意:若目标账户未激活,该操作也可使目标账户激活。
功能
该操作用于转移Gas。GasSendOperation继承于BaseOperation。
费用
FeeLimit目前固定是0.01 Gas。
成员
成员变量 | 类型 | 描述 |
---|---|---|
sourceAddress | String | 选填,操作源账户地址 |
destAddress | String | 必填,目标账户地址 |
gasAmount | Long | 必填,资产发行数量,大小限制[0, Long.MAX_VALUE] |
metadata | String | 选填,备注 |
-
ContractCreateOperation
功能
该操作用于创建合约。ContractCreateOperation继承于BaseOperation。
费用
FeeLimit目前固定是10.01 Gas。
成员
成员变量 | 类型 | 描述 |
---|---|---|
sourceAddress | String | 选填,操作源账户地址 |
initBalance | Long | 必填,给合约账户的初始化资产,单位UGas,1 Gas = 10^8 UGas, 大小限制[1, Long.MAX_VALUE] |
type | Integer | 选填,合约的语种,默认是0 |
payload | String | 必填,对应语种的合约代码 |
initInput | String | 选填,合约代码中init方法的入参 |
metadata | String | 选填,备注 |
-
ContractInvokeByAssetOperation
注意:若合约账户不存在,必须先创建合约账户。
功能
该操作用于转移资产并触发合约。ContractInvokeByAssetOperation继承于BaseOperation。
费用
FeeLimit要根据合约中执行交易来做添加手续费,首先发起交易手续费目前是0.01Gas,然后合约中的交易也需要交易发起者添加相应交易的手续费。
成员
成员变量 | 类型 | 描述 |
---|---|---|
sourceAddress | String | 选填,操作源账户地址 |
contractAddress | String | 必填,合约账户地址 |
code | String | 选填,资产编码,长度限制[0, 64];当为空时,仅触发合约; |
issuer | String | 选填,资产发行账户地址,当null时,仅触发合约 |
assetAmount | Long | 选填,资产数量,大小限制[0, Long.MAX_VALUE],当是0时,仅触发合约 |
input | String | 选填,待触发的合约的main()入参 |
metadata | String | 选填,备注 |
-
ContractInvokeByGasOperation
注意:若目标账户非合约账户且未激活,该操作也可使目标账户激活。
功能
该操作用于转移Gas并触发合约。ContractInvokeByGasOperation继承于BaseOperation。
费用
FeeLimit要根据合约中执行交易来做添加手续费,首先发起交易手续费目前是0.01Gas,然后合约中的交易也需要交易发起者添加相应交易的手续费。
成员
成员变量 | 类型 | 描述 |
---|---|---|
sourceAddress | String | 选填,操作源账户地址 |
contractAddress | String | 必填,合约账户地址 |
gasAmount | Long | 选填,资产发行数量,大小限制[0, Long.MAX_VALUE],当0时仅触发合约 |
input | String | 选填,待触发的合约的main()入参 |
metadata | String | 选填,备注 |
-
LogCreateOperation
功能
该操作用于记录日志。LogCreateOperation继承于BaseOperation。
费用
FeeLimit目前固定是0.01 Gas。
成员
成员变量 | 类型 | 描述 |
---|---|---|
sourceAddress | String | 选填,操作源账户地址 |
topic | String | 必填,日志主题,长度限制[1, 128] |
datas | List | 必填,日志内容,每个字符串长度限制[1, 1024] |
metadata | String | 选填,备注 |
5.3. 账户服务
账户服务提供账户相关的接口,包括6个接口: checkValid、getInfo、getNonce、getBalance、getAssets、getMetadata。
-
checkValid
接口说明
该接口用于检查区块链账户地址的有效性
调用方法
AccounCheckValidResponse checkValid(AccountCheckValidRequest)
请求参数
参数 | 类型 | 描述 |
---|---|---|
address | String | 必填,待检查的区块链账户地址 |
响应数据
参数 | 类型 | 描述 |
---|---|---|
isValid | Boolean | 是否有效 |
示例
// 初始化请求参数
String address = "adxSdV6qWfyhJAmzrPbv3btsPPT6aFrqBku3C";
AccountCheckValidRequest request = new AccountCheckValidRequest();
request.setAddress(address);
// 调用checkValid
AccountCheckValidResponse response = sdk.getAccountService().checkValid(request);
if(0 == response.getErrorCode()) {
System.out.println(response.getResult().isValid());
} else {
System.out.println("error: " + response.getErrorDesc());
}
-
getInfo-Account
接口说明
该接口用于获取指定的账户信息
调用方法
AccountGetInfoResponse GetInfo(AccountGetInfoRequest);
请求参数
参数 | 类型 | 描述 |
---|---|---|
address | String | 必填,待检查的区块链账户地址 |
响应数据
参数 | 类型 | 描述 |
---|---|---|
address | String | 账户地址 |
balance | Long | 账户余额,单位UGas,1 Gas = 10^8 UGas, 必须大于0 |
nonce | Long | 账户交易序列号,必须大于0 |
priv | Priv | 账户权限 |
示例
// 初始化请求参数
String accountAddress = "adxSdV6qWfyhJAmzrPbv3btsPPT6aFrqBku3C";
AccountGetInfoRequest request = new AccountGetInfoRequest();
request.setAddress(accountAddress);
// 调用getInfo接口
AccountGetInfoResponse response = sdk.getAccountService().getInfo(request);
if (response.getErrorCode() == 0) {
AccountGetInfoResult result = response.getResult();
System.out.println("账户信息: \n" + JSON.toJSONString(result, true));
} else {
System.out.println("error: " + response.getErrorDesc());
}
-
getNonce
接口说明
该接口用于获取指定账户的nonce值
调用方法
AccountGetNonceResponse getNonce(AccountGetNonceRequest);
请求参数
参数 | 类型 | 描述 |
---|---|---|
address | String | 必填,待查询的区块链账户地址 |
响应数据
参数 | 类型 | 描述 |
---|---|---|
nonce | Long | 账户交易序列号 |
示例
// 初始化请求参数
String accountAddress = "adxSk9MTT6aGoMxjAxuEGt1agRvWWnng25RF2";
AccountGetNonceRequest request = new AccountGetNonceRequest();
request.setAddress(accountAddress);
// 调用getNonce接口
AccountGetNonceResponse response = sdk.getAccountService().getNonce(request);
if(0 == response.getErrorCode()){
System.out.println("账户nonce:" + response.getResult().getNonce());
} else {
System.out.println("error: " + response.getErrorDesc());
}
-
getBalance
接口说明
该接口用于获取指定账户的Gas的余额
调用方法
AccountGetBalanceResponse getBalance(AccountGetBalanceRequest);
请求参数
参数 | 类型 | 描述 |
---|---|---|
address | String | 必填,待查询的区块链账户地址 |
响应数据
参数 | 类型 | 描述 |
---|---|---|
balance | Long | Gas的余额,单位UGas,1 Gas = 10^8 UGas |
示例
// 初始化请求参数
String accountAddress = "adxSk9MTT6aGoMxjAxuEGt1agRvWWnng25RF2";
AccountGetBalanceRequest request = new AccountGetBalanceRequest();
request.setAddress(accountAddress);
// 调用getBalance接口
AccountGetBalanceResponse response = sdk.getAccountService().getBalance(request);
if(0 == response.getErrorCode()){
AccountGetBalanceResult result = response.getResult();
System.out.println("Gas余额:" + ToBaseUnit.ToUGas(result.getBalance().toString()) + " Gas");
} else {
System.out.println("error: " + response.getErrorDesc());
}
-
getAssets
接口说明
该接口用于获取指定账户的所有资产信息
调用方法
AccountGetAssets getAssets(AccountGetAssetsRequest);
请求参数
参数 | 类型 | 描述 |
---|---|---|
address | String | 必填,待查询的账户地址 |
响应数据
参数 | 类型 | 描述 |
---|---|---|
asset | AssetInfo[] | 账户资产 |
示例
// 初始化请求参数
AccountGetAssetsRequest request = new AccountGetAssetsRequest();
request.setAddress("adxSmZHjDopQam2y5ntvHhGk4XEkiXc9MnFWZ");
// 调用getAssets接口
AccountGetAssetsResponse response = sdk.getAccountService().getAssets(request);
if (response.getErrorCode() == 0) {
AccountGetAssetsResult result = response.getResult();
System.out.println(JSON.toJSONString(result, true));
} else {
System.out.println("error: " + response.getErrorDesc());
}
-
getMetadata
接口说明
该接口用于获取指定账户的metadata信息
调用方法
AccountGetMetadataResponse getMetadata(AccountGetMetadataRequest);
请求参数
参数 | 类型 | 描述 |
---|---|---|
address | String | 必填,待查询的账户地址 |
key | String | 选填,metadata关键字,长度限制[1, 1024] |
响应数据
参数 | 类型 | 描述 |
---|---|---|
metadata | MetadataInfo | 账户 |
示例
// 初始化请求参数
String accountAddress = "adxSmZHjDopQam2y5ntvHhGk4XEkiXc9MnFWZ";
AccountGetMetadataRequest request = new AccountGetMetadataRequest();
request.setAddress(accountAddress);
request.setKey("20180704");
// 调用getMetadata接口
AccountGetMetadataResponse response = sdk.getAccountService().getMetadata(request);
if (response.getErrorCode() == 0) {
AccountGetMetadataResult result = response.getResult();
System.out.println(JSON.toJSONString(result, true));
} else {
System.out.println("error: " + response.getErrorDesc());
}
5.4. 资产服务
账户服务提供资产相关的接口,目前有1个接口:getInfo
-
getInfo-Asset
接口说明
该接口用于获取指定账户的指定资产信息
调用方法
AssetGetInfoResponse getInfo(AssetGetInfoRequest);
请求参数
参数 | 类型 | 描述 |
---|---|---|
address | String | 必填,待查询的账户地址 |
code | String | 必填,资产编码,长度限制[1, 64] |
issuer | String | 必填,资产发行账户地址 |
响应数据
参数 | 类型 | 描述 |
---|---|---|
asset | AssetInfo[] | 账户资产 |
示例
// 初始化请求参数
AssetGetInfoRequest request = new AssetGetInfoRequest();
request.setAddress("adxSmZHjDopQam2y5ntvHhGk4XEkiXc9MnFWZ");
request.setIssuer("adxSdV6qWfyhJAmzrPbv3btsPPT6aFrqBku3C");
request.setCode("HNC");
// 调用getInfo消息
AssetGetInfoResponse response = sdk.getAssetService().getInfo(request);
if (response.getErrorCode() == 0) {
AssetGetInfoResult result = response.getResult();
System.out.println(JSON.toJSONString(result, true));
} else {
System.out.println("error: " + response.getErrorDesc());
}
5.5. 合约服务
合约服务提供合约相关的接口,目前有4个接口:checkValid、getInfo、getAddress、call
-
checkValid-Contract
接口说明
该接口用于检测合约账户的有效性
调用方法
ContractCheckValidResponse checkValid(ContractCheckValidRequest)
请求参数
参数 | 类型 | 描述 |
---|---|---|
contractAddress | String | 待检测的合约账户地址 |
响应数据
参数 | 类型 | 描述 |
---|---|---|
isValid | Boolean | 是否有效 |
示例
// 初始化请求参数
ContractCheckValidRequest request = new ContractCheckValidRequest();
request.setContractAddress("adxSYQ8iMyZ7Dkj1oX1kjGMV55WXvoPKcLEK3");
// 调用checkValid接口
ContractCheckValidResponse response = sdk.getContractService().checkValid(request);
if (response.getErrorCode() == 0) {
ContractCheckValidResult result = response.getResult();
System.out.println(result.getValid());
} else {
System.out.println("error: " + response.getErrorDesc());
}
-
getInfo-Contract
接口说明
该接口用于查询合约代码
调用方法
ContractGetInfoResponse getInfo (ContractGetInfoRequest);
请求参数
参数 | 类型 | 描述 |
---|---|---|
contractAddress | String | 待查询的合约账户地址 |
响应数据
参数 | 类型 | 描述 |
---|---|---|
contract | ContractInfo | 合约信息 |
示例
// 初始化请求参数
ContractGetInfoRequest request = new ContractGetInfoRequest();
request.setContractAddress("adxSYQ8iMyZ7Dkj1oX1kjGMV55WXvoPKcLEK3");
// 调用getInfo接口
ContractGetInfoResponse response = sdk.getContractService().getInfo(request);
if (response.getErrorCode() == 0) {
System.out.println(JSON.toJSONString(response.getResult(), true));
} else {
System.out.println("error: " + response.getErrorDesc());
}
-
getAddress
接口说明
该接口用于查询合约地址
调用方法
ContractGetAddressResponse getInfo (ContractGetAddressRequest);
请求参数
参数 | 类型 | 描述 |
---|---|---|
hash | String | 创建合约交易的hash |
响应数据
参数 | 类型 | 描述 |
---|---|---|
contractAddressList | List | 合约地址列表 |
示例
// 初始化请求参数
ContractGetAddressRequest request = new ContractGetAddressRequest();
request.setHash("44246c5ba1b8b835a5cbc29bdc9454cdb9a9d049870e41227f2dcfbcf7a07689");
// 调用getAddress接口
ContractGetAddressResponse response = sdk.getContractService().getAddress(request);
if (response.getErrorCode() == 0) {
System.out.println(JSON.toJSONString(response.getResult(), true));
} else {
System.out.println("error: " + response.getErrorDesc());
}
-
call
接口说明
该接口用于调试合约代码
调用方法
ContractCallesponse call(ContractCallRequest);
请求参数
参数 | 类型 | 描述 |
---|---|---|
sourceAddress | String | 选填,合约触发账户地址 |
contractAddress | String | 选填,合约账户地址,与code不能同时为空 |
code | String | 选填,合约代码,与contractAddress不能同时为空,长度限制[1, 64] |
input | String | 选填,合约入参 |
contractBalance | String | 选填,赋予合约的初始 Gas 余额, 单位UGas,1 Gas = 10^8 UGas, 大小限制[1, Long.MAX_VALUE] |
optType | Integer | 必填,0: 调用合约的读写接口 init, 1: 调用合约的读写接口 main, 2 :调用只读接口 query |
feeLimit | Long | 交易要求的最低手续费, 大小限制[1, Long.MAX_VALUE] |
gasPrice | Long | 交易费用单价,按字节收费,大小限制[1000, Long.MAX_VALUE] |
响应数据
参数 | 类型 | 描述 |
---|---|---|
logs | JSONObject | 日志信息 |
queryRets | JSONArray | 查询结果集 |
stat | ContractStat | 合约资源占用信息 |
txs | TransactionEnvs[] | 交易集 |
示例
// 初始化请求参数
ContractCallRequest request = new ContractCallRequest();
request.setCode("\"use strict\";log(undefined);function query() { getBalance(thisAddress); }");
request.setFeeLimit(1000000000L);
request.setOptType(2);
// 调用call接口
ContractCallResponse response = sdk.getContractService().call(request);
if (response.getErrorCode() == 0) {
ContractCallResult result = response.getResult();
System.out.println(JSON.toJSONString(result, true));
} else {
System.out.println("error: " + response.getErrorDesc());
}
5.6. 区块服务
区块服务主要是区块相关的接口,目前有11个接口:getNumber、checkStatus、getTransactions、getInfo、getLatestInfo、getValidators、getLatestValidators、getReward、getLatestReward、getFees、getLatestFees。
-
getNumber
接口说明
该接口用于查询最新的区块高度。
调用方法
BlockGetNumberResponse getNumber();
响应数据
参数 | 类型 | 描述 |
---|---|---|
blockNumber | Long | 最新的区块高度,对应底层字段seq |
示例
// 调用getNumber接口
BlockGetNumberResponse response = sdk.getBlockService().getNumber();
if(0 == response.getErrorCode()){
System.out.println(JSON.toJSONString(response.getResult(), true));
}else{
System.out.println("error: " + response.getErrorDesc());
}
-
checkStatus
接口说明
该接口用于检查本地节点区块是否同步完成。
调用方法
BlockCheckStatusResponse checkStatus();
响应数据
参数 | 类型 | 描述 |
---|---|---|
isSynchronous | Boolean | 区块是否同步 |
示例
// 调用checkStatus
BlockCheckStatusResponse response = sdk.getBlockService().checkStatus();
if(0 == response.getErrorCode()){
System.out.println(JSON.toJSONString(response.getResult(), true));
}else{
System.out.println("error: " + response.getErrorDesc());
}
-
getTransactions
接口说明
该接口用于查询指定区块高度下的所有交易。
调用方法
BlockGetTransactionsResponse getTransactions(BlockGetTransactionsRequest);
请求参数
参数 | 类型 | 描述 |
---|---|---|
blockNumber | Long | 必填,待查询的区块高度,必须大于0 |
响应数据
参数 | 类型 | 描述 |
---|---|---|
totalCount | Long | 返回的总交易数 |
transactions | TransactionHistory[] | 交易内容 |
示例
// 初始化请求参数
Long blockNumber = 617247L;// 第617247区块
BlockGetTransactionsRequest request = new BlockGetTransactionsRequest();
request.setBlockNumber(blockNumber);
// 调用getTransactions接口
BlockGetTransactionsResponse response = sdk.getBlockService().getTransactions(request);
if(0 == response.getErrorCode()){
System.out.println(JSON.toJSONString(response.getResult(), true));
}else{
System.out.println("error: " + response.getErrorDesc());
}
-
getInfo-Block
接口说明
该接口用于获取区块信息。
调用方法
BlockGetInfoResponse getInfo(BlockGetInfoRequest);
请求参数
参数 | 类型 | 描述 |
---|---|---|
blockNumber | Long | 必填,待查询的区块高度 |
响应数据
参数 | 类型 | 描述 |
---|---|---|
closeTime | Long | 区块关闭时间 |
number | Long | 区块高度 |
txCount | Long | 交易总量 |
version | String | 区块版本 |
示例
// 初始化请求参数
BlockGetInfoRequest request = new BlockGetInfoRequest();
request.setBlockNumber(629743L);
// 调用getInfo接口
BlockGetInfoResponse response = sdk.getBlockService().getInfo(request);
if (response.getErrorCode() == 0) {
BlockGetInfoResult result = response.getResult();
System.out.println(JSON.toJSONString(result, true));
} else {
System.out.println("error: " + response.getErrorDesc());
}
-
getLatestInfo
接口说明
该接口用于获取最新区块信息。
调用方法
BlockGetLatestInfoResponse getLatestInfo();
响应数据
参数 | 类型 | 描述 |
---|---|---|
closeTime | Long | 区块关闭时间 |
number | Long | 区块高度,对应底层字段seq |
txCount | Long | 交易总量 |
version | String | 区块版本 |
示例
// 调用getLatestInfo接口
BlockGetLatestInfoResponse response = sdk.getBlockService().getLatestInfo();
if (response.getErrorCode() == 0) {
BlockGetLatestInfoResult result = response.getResult();
System.out.println(JSON.toJSONString(result, true));
} else {
System.out.println("error: " + response.getErrorDesc());
}
-
getValidators
接口说明
该接口用于获取指定区块中所有验证节点数。
调用方法
BlockGetValidatorsResponse getValidators(BlockGetValidatorsRequest);
请求参数
参数 | 类型 | 描述 |
---|---|---|
blockNumber | Long | 必填,待查询的区块高度,必须大于0 |
响应数据
参数 | 类型 | 描述 |
---|---|---|
validators | ValidatorInfo[] | 验证节点列表 |
示例
// 初始化请求参数
BlockGetValidatorsRequest request = new BlockGetValidatorsRequest();
request.setBlockNumber(629743L);
// 调用getValidators接口
BlockGetValidatorsResponse response = sdk.getBlockService().getValidators(request);
if (response.getErrorCode() == 0) {
BlockGetValidatorsResult result = response.getResult();
System.out.println(JSON.toJSONString(result, true));
} else {
System.out.println("error: " + response.getErrorDesc());
}
-
getLatestValidators
接口说明
该接口用于获取最新区块中所有验证节点数。
调用方法
BlockGetLatestValidatorsResponse getLatestValidators();
响应数据
参数 | 类型 | 描述 |
---|---|---|
validators | ValidatorInfo[] | 验证节点列表 |
示例
// 调用getLatestValidators接口
BlockGetLatestValidatorsResponse response = sdk.getBlockService().getLatestValidators();
if (response.getErrorCode() == 0) {
BlockGetLatestValidatorsResult result = response.getResult();
System.out.println(JSON.toJSONString(result, true));
} else {
System.out.println("error: " + response.getErrorDesc());
}
-
getReward
接口说明
该接口用于获取指定区块中的区块奖励和验证节点奖励。
调用方法
BlockGetRewardResponse getReward(BlockGetRewardRequest);
请求参数
参数 | 类型 | 描述 |
---|---|---|
blockNumber | Long | 必填,待查询的区块高度,必须大于0 |
响应数据
参数 | 类型 | 描述 |
---|---|---|
blockReward | Long | 区块奖励数 |
validatorsReward | ValidatorReward[] | 验证节点奖励情况 |
示例
// 初始化请求参数
BlockGetRewardRequest request = new BlockGetRewardRequest();
request.setBlockNumber(629743L);
// 调用getReward接口
BlockGetRewardResponse response = sdk.getBlockService().getReward(request);
if (response.getErrorCode() == 0) {
BlockGetRewardResult result = response.getResult();
System.out.println(JSON.toJSONString(result, true));
} else {
System.out.println("error: " + response.getErrorDesc());
}
-
getLatestReward
接口说明
获取最新区块中的区块奖励和验证节点奖励。
调用方法
BlockGetLatestRewardResponse getLatestReward();
响应数据
参数 | 类型 | 描述 |
---|---|---|
blockReward | Long | 区块奖励数 |
validatorsReward | ValidatorReward[] | 验证节点奖励情况 |
示例
// 调用getLatestReward接口
BlockGetLatestRewardResponse response = sdk.getBlockService().getLatestReward();
if (response.getErrorCode() == 0) {
BlockGetLatestRewardResult result = response.getResult();
System.out.println(JSON.toJSONString(result, true));
} else {
System.out.println("error: " + response.getErrorDesc());
}
-
getFees
接口说明
获取指定区块中的账户最低资产限制和费用单价,按字节收费。
调用方法
BlockGetFeesResponse getFees(BlockGetFeesRequest);
请求参数
参数 | 类型 | 描述 |
---|---|---|
blockNumber | Long | 必填,待查询的区块高度,必须大于0 |
响应数据
参数 | 类型 | 描述 |
---|---|---|
fees | Fees | 费用 |
示例
// 初始化请求参数
BlockGetFeesRequest request = new BlockGetFeesRequest();
request.setBlockNumber(629743L);
// 调用getFees接口
BlockGetFeesResponse response = sdk.getBlockService().getFees(request);
if (response.getErrorCode() == 0) {
System.out.println(JSON.toJSONString(response.getResult(), true));
} else {
System.out.println("error: " + response.getErrorDesc());
}
-
getLatestFees
接口说明
该接口用于获取最新区块中的账户最低资产限制和费用单价,按字节收费。
调用方法
BlockGetLatestFeesResponse getLatestFees();
响应数据
参数 | 类型 | 描述 |
---|---|---|
fees | Fees | 费用 |
示例
// 调用getLatestFees接口
BlockGetLatestFeesResponse response = sdk.getBlockService().getLatestFees();
if (response.getErrorCode() == 0) {
System.out.println(JSON.toJSONString(response.getResult(), true));
} else {
System.out.println("error: " + response.getErrorDesc());
}
6. 场景示例代码
6.1. 生成账户
package cn.bubi.sdk.example;
import com.alibaba.fastjson.JSON;
import cn.bubi.SDK;
import cn.bubi.common.ToBaseUnit;
import cn.bubi.crypto.Keypair;
import cn.bubi.model.request.TransactionBuildBlobRequest;
import cn.bubi.model.request.TransactionSignRequest;
import cn.bubi.model.request.TransactionSubmitRequest;
import cn.bubi.model.request.operation.AccountActivateOperation;
import cn.bubi.model.request.operation.BaseOperation;
import cn.bubi.model.response.TransactionBuildBlobResponse;
import cn.bubi.model.response.TransactionSignResponse;
import cn.bubi.model.response.TransactionSubmitResponse;
import cn.bubi.model.response.result.TransactionBuildBlobResult;
import org.testng.annotations.Test;
import java.util.ArrayList;
import java.util.List;
public class BatchCreateBuchainAccountDemo {
SDK sdk = SDK.getInstance("http://node.bubidev.cn");
/**
* 批量创建账户
*
* 注意:一次最多100个创建账户的操作,该操作是原子性的。每个初始化账户推荐给0.02Gas,交易费用100个操作的情况下建议feeLimist为0.1Gas
*/
@Test
public void createBuchainAccount(){
// 推荐人账户地址
String refereeAddress = "adxSYvndiFG4zpbLGugX3j93fDn9nWZfWp8Gd";
// 推荐人账户私钥
String refereePrivateKey = "privbw1Uup9Qif12uysm9LyCby3HC5s6m7FMBzU4Ac64NVZ2tvB4f8wB";
// 推荐人账户nonce
// TODO 需要查询当前推荐人的nonce值
Long refereeNonce = null;
AccountGetNonceRequest getNonceRequest = new AccountGetNonceRequest();
getNonceRequest.setAddress(refereeAddress);
// 调用getNonce接口
AccountGetNonceResponse getNonceResponse = sdk.getAccountService().getNonce(getNonceRequest);
// 赋值nonce
if (getNonceResponse.getErrorCode() == 0) {
AccountGetNonceResult result = getNonceResponse.getResult();
refereeNonce = result.getNonce()+1;
}
// The fixed write 1000L, the unit is UGas
Long gasPrice = 1000L;
// Set up the maximum cost 0.01Gas
Long feeLimit = ToBaseUnit.ToUGas("0.1");
// 每个账户初始化0.02Gas
Long initBalance = ToBaseUnit.ToUGas("0.02");
List<AccountActivateOperation> accountActivateOperationList = new ArrayList<AccountActivateOperation>();
Keypair keypair;
// 注意:交易里最多100个操作
for (int i = 0; i < 100; i++) {
keypair = Keypair.generator();
AccountActivateOperation operation = new AccountActivateOperation();
operation.setSourceAddress(refereeAddress);
operation.setDestAddress(keypair.getAddress());
operation.setInitBalance(initBalance);
accountActivateOperationList.add(operation);
System.out.println("第" + i + " " + JSON.toJSONString(keypair));
}
// 提交交易(广播交易),生成的hash,需要通过hash再次查询交易来确认最终状态。
String hash = submitTransaction(refereePrivateKey,refereeAddress,accountActivateOperationList,refereeNonce, gasPrice, feeLimit, "");
if(hash != null){
System.out.println("tx hash:" + hash);
}else{
System.out.println("操作失败");
}
}
/**
* @param submiterPrivateKey The account private key to start transaction
* @param submiterAddresss The account address to start transaction
* @param operations operations
* @param submiterNonce initiation account's Nonce
* @param gasPrice Gas price
* @param feeLimit fee limit
* @return java.lang.String transaction hash
*/
private String submitTransaction(String submiterPrivateKey, String submiterAddresss, List<AccountActivateOperation> operations, Long submiterNonce, Long gasPrice, Long feeLimit, String transMetadata) {
// 1. Build transaction
TransactionBuildBlobRequest transactionBuildBlobRequest = new TransactionBuildBlobRequest();
transactionBuildBlobRequest.setSourceAddress(submiterAddresss);
transactionBuildBlobRequest.setNonce(submiterNonce);
transactionBuildBlobRequest.setFeeLimit(feeLimit);
transactionBuildBlobRequest.setGasPrice(gasPrice);
for (BaseOperation opt: operations
) {
transactionBuildBlobRequest.addOperation(opt);
}
transactionBuildBlobRequest.setMetadata(transMetadata);
// 2. Build transaction BLob
String transactionBlob;
TransactionBuildBlobResponse transactionBuildBlobResponse = sdk.getTransactionService().buildBlob(transactionBuildBlobRequest);
if (transactionBuildBlobResponse.getErrorCode() != 0) {
System.out.println("error: " + transactionBuildBlobResponse.getErrorDesc());
return null;
}
TransactionBuildBlobResult transactionBuildBlobResult = transactionBuildBlobResponse.getResult();
transactionBlob = transactionBuildBlobResult.getTransactionBlob();
// 3. Sign transaction BLob
String[] signerPrivateKeyArr = {submiterPrivateKey};
TransactionSignRequest transactionSignRequest = new TransactionSignRequest();
transactionSignRequest.setBlob(transactionBlob);
for (String s : signerPrivateKeyArr) {
transactionSignRequest.addPrivateKey(s);
}
TransactionSignResponse transactionSignResponse = sdk.getTransactionService().sign(transactionSignRequest);
if (transactionSignResponse.getErrorCode() != 0) {
System.out.println("error: " + transactionSignResponse.getErrorDesc());
return null;
}
// 4. Broadcast transaction
String Hash = null;
TransactionSubmitRequest transactionSubmitRequest = new TransactionSubmitRequest();
transactionSubmitRequest.setTransactionBlob(transactionBlob);
transactionSubmitRequest.setSignatures(transactionSignResponse.getResult().getSignatures());
TransactionSubmitResponse transactionSubmitResponse = sdk.getTransactionService().submit(transactionSubmitRequest);
if (0 == transactionSubmitResponse.getErrorCode()) {
Hash = transactionSubmitResponse.getResult().getHash();
} else {
System.out.println(JSON.toJSONString(transactionSubmitResponse, true));
}
return Hash;
}
}
6.2. 激活账户
public void activateAccount() {
// The account private key to activate a new account
String activatePrivateKey = "privbyQCRp7DLqKtRFCqKQJr81TurTqG6UKXMMtGAmPG3abcM9XHjWvq";
Long initBalance = ToBaseUnit.ToUGas("1000");
// The fixed write 1000L, the unit is UGas
Long gasPrice = 1000L;
// Set up the maximum cost 0.01Gas
Long feeLimit = ToBaseUnit.ToUGas("0.01");
// Transaction initiation account's nonce + 1
Long nonce = 8L;
// Generate a new account to be activated
Keypair keypair = Keypair.generator();
System.out.println(JSON.toJSONString(keypair, true));
String destAccount = keypair.getAddress();
// 1. Get the account address to send this transaction
String activateAddresss = getAddressByPrivateKey(activatePrivateKey);
// 2. Build activateAccount
AccountActivateOperation operation = new AccountActivateOperation();
operation.setSourceAddress(activateAddresss);
operation.setDestAddress(destAccount);
operation.setInitBalance(initBalance);
operation.setMetadata("activate account");
String[] signerPrivateKeyArr = {activatePrivateKey};
// Record txhash for subsequent confirmation of the real result of the transaction.
// After recommending five blocks, call again through txhash `Get the transaction information
// from the transaction Hash'(see example: getTxByHash ()) to confirm the final result of the transaction
String txHash = submitTransaction(signerPrivateKeyArr, activateAddresss, operation, nonce, gasPrice, feeLimit);
if (txHash != null) {
System.out.println("hash: " + txHash);
}
}
6.3. 部署合约
import com.alibaba.fastjson.JSONObject;
import cn.bubi.SDK;
import cn.bubi.common.ToBaseUnit;
import cn.bubi.model.request.*;
import cn.bubi.model.request.operation.BaseOperation;
import cn.bubi.model.request.operation.ContractCreateOperation;
import cn.bubi.model.response.*;
import cn.bubi.model.response.result.data.Signature;
import cn.bubi.model.response.result.data.TransactionHistory;
import org.junit.Test;
/**
* @Author riven
*/
public class CreateContractDemo {
public SDK sdk = SDK.getInstance("http://192.168.6.123:19333");
public String accountAddress = "adxSYmvoQXGc831Swotbah5udGZWoqQjSZpmY";
public String privateKey = "privbtacCSANUxPn8sXU358Wz3HfXArvmcy7aT9SDdrbPEkYJVGpinUG";
public String contract = "'use strict';\n function _saveObj(key, value){\n Chain.store(key, JSON.stringify(value));\n }\n function queryData(params) {\n let hash= params.hash;\n let data = JSON.parse(Chain.load(hash));\n Utils.assert(data !== false, '10000,The data hashnot existed');\n return data;\n }\n function store(params){\n Utils.assert(params.hash!== undefined, '10003,The hashparams error');\n let hash= params.hash;\n let data = JSON.parse(Chain.load(hash));\n Utils.assert(data === false, '10001,The data hashis already existed');\n let dataJson = {};\n dataJson = params.data;\n Chain.store(hash,JSON.stringify(dataJson));\n }\n function init(input){\n return;\n }\n function main(input_str){\n let input = JSON.parse(input_str);\n if(input.method === 'store'){\n store(input.params);\n }\n else{\n throw '<Main interface passes an invalid operation type>';\n }\n }\n function query(input_str){\n let input = JSON.parse(input_str);\n let object ={};\n if(input.method === 'queryData'){\n object = queryData(input.params);\n }\n else{\n throw '<unidentified operation type>';\n }\n return JSON.stringify(object);\n }";
@Test
public void createContract() {
BaseOperation[] baseOperations = buildOperations();
long accountNonce = getAccountNonce();
System.out.println("accountNonce:"+accountNonce);
String transactionBlob = seralizeTransaction(accountNonce, baseOperations);
Signature[] signatures = signTransaction(transactionBlob);
String hash = submitTransaction(transactionBlob, signatures);
System.out.println("hash:"+hash);
int errorCode = checkTransactionStatus(hash);
System.out.println("errorCode:"+errorCode);
}
public long getAccountNonce() {
long nonce = 0;
// Init request
AccountGetNonceRequest request = new AccountGetNonceRequest();
request.setAddress(accountAddress);
// Call getNonce
AccountGetNonceResponse response = sdk.getAccountService().getNonce(request);
if (0 == response.getErrorCode()) {
nonce = response.getResult().getNonce();
} else {
System.out.println("error: " + response.getErrorDesc());
}
return nonce;
}
public BaseOperation[] buildOperations() {
// The account address to issue apt1.0 token
String createContractAddress = accountAddress;
// Contract account initialization Gas,the unit is UGas,and 1 Gas = 10^8 UGas
Long initBalance = ToBaseUnit.ToUGas("0.01");
// The token name
String name = "Contract Global";
// The token code
String symbol = "CGO";
// The token total supply, which includes the dicimals.
// If decimals is 8 and you want to issue 10 tokens now, the nowSupply must be 10 * 10 ^ 8, like below.
String totalSupply = "1000000000";
// The token decimals
Integer decimals = 8;
// Contract code
String payload = contract;
// Init initInput
JSONObject initInput = new JSONObject();
JSONObject params = new JSONObject();
params.put("name", name);
params.put("symbol", symbol);
params.put("decimals", decimals);
params.put("totalSupply", totalSupply);
initInput.put("params", params);
// Build create contract operation
ContractCreateOperation contractCreateOperation = new ContractCreateOperation();
contractCreateOperation.setSourceAddress(createContractAddress);
contractCreateOperation.setInitBalance(initBalance);
contractCreateOperation.setPayload(payload);
contractCreateOperation.setInitInput(initInput.toJSONString());
contractCreateOperation.setMetadata("create ctp 1.0 contract");
return new BaseOperation[]{ contractCreateOperation };
}
public String seralizeTransaction(Long nonce, BaseOperation[] operations) {
String transactionBlob = null;
// The account address to create contract and issue ctp 1.0 token
String senderAddresss = accountAddress;
// The gasPrice is fixed at 1000L, the unit is UGas
Long gasPrice = 1000L;
// Set up the maximum cost 10.08Gas
Long feeLimit = ToBaseUnit.ToUGas("10.08");
// Nonce should add 1
nonce += 1;
// Build transaction Blob
TransactionBuildBlobRequest transactionBuildBlobRequest = new TransactionBuildBlobRequest();
transactionBuildBlobRequest.setSourceAddress(senderAddresss);
transactionBuildBlobRequest.setNonce(nonce);
transactionBuildBlobRequest.setFeeLimit(feeLimit);
transactionBuildBlobRequest.setGasPrice(gasPrice);
for (BaseOperation operation : operations) {
transactionBuildBlobRequest.addOperation(operation);
}
TransactionBuildBlobResponse transactionBuildBlobResponse = sdk.getTransactionService().buildBlob(transactionBuildBlobRequest);
if (transactionBuildBlobResponse.getErrorCode() == 0) {
transactionBlob = transactionBuildBlobResponse. getResult().getTransactionBlob();
} else {
System.out.println("error: " + transactionBuildBlobResponse.getErrorDesc());
}
return transactionBlob;
}
public Signature[] signTransaction(String transactionBlob) {
Signature[] signatures = null;
// The account private key to issue atp1.0 token
String senderPrivateKey = privateKey;
// Sign transaction BLob
TransactionSignRequest transactionSignRequest = new TransactionSignRequest();
transactionSignRequest.setBlob(transactionBlob);
transactionSignRequest.addPrivateKey(senderPrivateKey);
TransactionSignResponse transactionSignResponse = sdk.getTransactionService().sign(transactionSignRequest);
if (transactionSignResponse.getErrorCode() == 0) {
signatures = transactionSignResponse.getResult().getSignatures();
} else {
System.out.println("error: " + transactionSignResponse.getErrorDesc());
}
return signatures;
}
public String submitTransaction(String transactionBlob, Signature[] signatures) {
String hash = null;
// Submit transaction
TransactionSubmitRequest transactionSubmitRequest = new TransactionSubmitRequest();
transactionSubmitRequest.setTransactionBlob(transactionBlob);
transactionSubmitRequest.setSignatures(signatures);
TransactionSubmitResponse transactionSubmitResponse = sdk.getTransactionService().submit(transactionSubmitRequest);
if (0 == transactionSubmitResponse.getErrorCode()) {
hash = transactionSubmitResponse.getResult().getHash();
} else {
System.out.println("error: " + transactionSubmitResponse.getErrorDesc());
}
return hash ;
}
public int checkTransactionStatus(String txHash) {
// Init request
TransactionGetInfoRequest request = new TransactionGetInfoRequest();
request.setHash(txHash);
// Call getInfo
TransactionGetInfoResponse response = sdk.getTransactionService().getInfo(request);
int errorCode = response.getErrorCode();
if (errorCode == 0){
TransactionHistory transactionHistory = response.getResult().getTransactions()[0];
errorCode = transactionHistory.getErrorCode();
}
return errorCode;
}
}
6.4. 调用合约
package cn.bubi.sdk.example;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import cn.bubi.SDK;
import cn.bubi.common.ToBaseUnit;
import cn.bubi.encryption.key.PrivateKey;
import cn.bubi.model.request.*;
import cn.bubi.model.request.operation.BaseOperation;
import cn.bubi.model.request.operation.ContractCreateOperation;
import cn.bubi.model.request.operation.ContractInvokeByAssetOperation;
import cn.bubi.model.request.operation.ContractInvokeByGasOperation;
import cn.bubi.model.response.*;
import cn.bubi.model.response.result.ContractCallResult;
import cn.bubi.model.response.result.ContractCheckValidResult;
import cn.bubi.model.response.result.TransactionBuildBlobResult;
import org.testng.annotations.Test;
/**
* @Author riven
*/
public class ContractDemo {
SDK sdk = SDK.getInstance("http://node.bubidev.cn");
/**
* Check whether the contract is valid
*/
@Test
public void checkContractValid() {
// Init request
ContractCheckValidRequest request = new ContractCheckValidRequest();
request.setContractAddress("adxSqKcX8wGCMKhzNUBoDWfbeQaMhfnGdtyG2");
// Call checkValid
ContractCheckValidResponse response = sdk.getContractService().checkValid(request);
if (response.getErrorCode() == 0) {
ContractCheckValidResult result = response.getResult();
System.out.println(result.getValid());
} else {
System.out.println("error: " + response.getErrorDesc());
}
}
/**
* Get contract info
*/
@Test
public void getContractInfo() {
// Init request
ContractGetInfoRequest request = new ContractGetInfoRequest();
request.setContractAddress("adxSqKcX8wGCMKhzNUBoDWfbeQaMhfnGdtyG2");
// Call getInfo
ContractGetInfoResponse response = sdk.getContractService().getInfo(request);
if (response.getErrorCode() == 0) {
System.out.println(JSON.toJSONString(response.getResult(), true));
} else {
System.out.println("error: " + response.getErrorDesc());
}
}
/**
* Get contract address
*/
@Test
public void getContractAddress() {
// Init request
String hash = "44246c5ba1b8b835a5cbc29bdc9454cdb9a9d049870e41227f2dcfbcf7a07689";
ContractGetAddressRequest request = new ContractGetAddressRequest();
request.setHash(hash);
// Call getAddress
ContractGetAddressResponse response = sdk.getContractService().getAddress(request);
if (response.getErrorCode() == 0) {
System.out.println(JSON.toJSONString(response.getResult(), true));
} else {
System.out.println("error: " + response.getErrorDesc());
}
}
/**
* call contract
*/
@Test
public void callContract() {
// Init variable
// Contract address
String contractAddress = "adxSqKcX8wGCMKhzNUBoDWfbeQaMhfnGdtyG2";
// Spender address
String spender = "adxSYvndiFG4zpbLGugX3j93fDn9nWZfWp8Gd";
// Amount
String amount = "1000000";
// Init input
JSONObject input = new JSONObject();
input.put("method", "approve");
JSONObject params = new JSONObject();
params.put("spender", spender);
params.put("value", amount);
input.put("params", params);
// Init request
ContractCallRequest request = new ContractCallRequest();
request.setContractAddress(contractAddress);
request.setFeeLimit(1000000000L);
request.setOptType(1);
request.setInput(input.toJSONString());
// Call call
ContractCallResponse response = sdk.getContractService().call(request);
if (response.getErrorCode() == 0) {
ContractCallResult result = response.getResult();
System.out.println(JSON.toJSONString(result, true));
} else {
System.out.println("error: " + response.getErrorDesc());
}
}
/**
* 创建合约
*/
@Test
public void createContract() {
// The account private key to create contract
String createPrivateKey = "privbUdwf6xV1d5Jvkcakuz8T8nfFn4U7d5s55VUbwmi79DPxqNWSD1n";
// Contract account initialization Gas,the unit is UGas,and 1 Gas = 10^8 UGas
Long initBalance = 100000000L;//ToBaseUnit.ToUGas("0.1");
// Contract code
String payload = "\n \"use strict\";\n function init(bar)\n {\n /*init whatever you want*/\n return;\n }\n \n function main(input)\n {\n let para = JSON.parse(input);\n if (para.do_foo)\n {\n let x = {\n 'hello' : 'world'\n };\n }\n }\n \n function query(input)\n { \n return input;\n }\n ";
// The fixed write 1000L ,the unit is UGas
Long gasPrice = 1000L;
// Set up the maximum cost 10.01Gas
Long feeLimit = 1015076000L;//ToBaseUnit.ToUGas("10.01");
// Transaction initiation account's Nonce + 1
Long nonce = 18L;
// Contract init function entry
String initInput = "";
// 1. Get the account address to send this transaction
String createAddresss = getAddressByPrivateKey(createPrivateKey);
// 2. Build activateAccount operation
ContractCreateOperation operation = new ContractCreateOperation();
operation.setSourceAddress(createAddresss);
operation.setInitBalance(initBalance);
operation.setPayload(payload);
operation.setInitInput(initInput);
operation.setMetadata("create contract");
// Record txhash for subsequent confirmation of the real result of the transaction.
// After recommending five blocks, call again through txhash `Get the transaction information
// from the transaction Hash'(see example: getTxByHash ()) to confirm the final result of the transaction
String txHash = submitTransaction(createPrivateKey, createAddresss, operation, nonce, gasPrice, feeLimit);
if (txHash != null) {
System.out.println("hash: " + txHash);
}
}
/**
* Send asset and trigger contract
*/
@Test
public void invokeContractByAsset() {
// Init variable
// The account private key to invoke contract
String invokePrivateKey = "privby8cFTi4ugxc95qJMF5PvCz6PvQAxhUXAZoqFENUKRE19tM1Vbii";
// The account to receive the assets
String destAddress = "adxScpCtbeLP2KGRaCkbtrmz8iB5mu6DQcW3r";
// The asset code to be sent
String assetCode = "TST";
// The account address to issue asset
String assetIssuer = "adxSYvndiFG4zpbLGugX3j93fDn9nWZfWp8Gd";
// 0 means that the contract is only triggered
Long amount = 0L;
// The fixed write 1000L, the unit is UGas
Long gasPrice = 1000L;
// Set up the maximum cost 0.01Gas
Long feeLimit = ToBaseUnit.ToUGas("0.01");
// Transaction initiation account's Nonce + 1
Long nonce = 57L;
// Contract main function entry
String input = "";
// 1. Get the account address to send this transaction
String invokeAddresss = getAddressByPrivateKey(invokePrivateKey);
// 2. Build sendAsset operation
ContractInvokeByAssetOperation operation = new ContractInvokeByAssetOperation();
operation.setSourceAddress(invokeAddresss);
operation.setContractAddress(destAddress);
operation.setCode(assetCode);
operation.setIssuer(assetIssuer);
operation.setAssetAmount(amount);
operation.setInput(input);
operation.setMetadata("send token");
// Record txhash for subsequent confirmation of the real result of the transaction.
// After recommending five blocks, call again through txhash `Get the transaction information
// from the transaction Hash'(see example: getTxByHash ()) to confirm the final result of the transaction
String txHash = submitTransaction(invokePrivateKey, invokeAddresss, operation, nonce, gasPrice, feeLimit);
if (txHash != null) {
System.out.println("hash: " + txHash);
}
}
/**
* Send Gas and trigger contract
*/
@Test
public void invokeContractByGas() {
// Init variable
// The account private key to invoke contract
String invokePrivateKey = "privby8cFTi4ugxc95qJMF5PvCz6PvQAxhUXAZoqFENUKRE19tM1Vbii";
// The account to receive the Gas
String destAddress = "adxSqKcX8wGCMKhzNUBoDWfbeQaMhfnGdtyG2";
// 0 means that the contract is only triggered
Long amount = 0L;
// The fixed write 1000L, the unit is UGas
Long gasPrice = 1000L;
// Set up the maximum cost 0.01Gas
Long feeLimit = ToBaseUnit.ToUGas("0.01");
// Transaction initiation account's Nonce + 1
Long nonce = 58L;
// Contract main function entry
String input = "";
// 1. Get the account address to send this transaction
String invokeAddresss = getAddressByPrivateKey(invokePrivateKey);
// 2. Build sendAsset operation
ContractInvokeByGasOperation operation = new ContractInvokeByGasOperation();
operation.setSourceAddress(invokeAddresss);
operation.setContractAddress(destAddress);
operation.setBuAmount(amount);
operation.setInput(input);
// Record txhash for subsequent confirmation of the real result of the transaction.
// After recommending five blocks, call again through txhash `Get the transaction information
// from the transaction Hash'(see example: getTxByHash ()) to confirm the final result of the transaction
String txHash = submitTransaction(invokePrivateKey, invokeAddresss, operation, nonce, gasPrice, feeLimit);
if (txHash != null) {
System.out.println("hash: " + txHash);
}
}
/**
* @param senderPrivateKey The account private key to start transaction
* @param senderAddresss The account address to start transaction
* @param operation operation
* @param senderNonce Transaction initiation account's Nonce
* @param gasPrice Gas price
* @param feeLimit fee limit
* @return java.lang.String transaction hash
* @author riven
*/
private String submitTransaction(String senderPrivateKey, String senderAddresss, BaseOperation operation, Long senderNonce, Long gasPrice, Long feeLimit) {
// 3. Build transaction
TransactionBuildBlobRequest transactionBuildBlobRequest = new TransactionBuildBlobRequest();
transactionBuildBlobRequest.setSourceAddress(senderAddresss);
transactionBuildBlobRequest.setNonce(senderNonce);
transactionBuildBlobRequest.setFeeLimit(feeLimit);
transactionBuildBlobRequest.setGasPrice(gasPrice);
transactionBuildBlobRequest.addOperation(operation);
// transactionBuildBlobRequest.setMetadata("abc");
// 4. Build transaction BLob
String transactionBlob;
TransactionBuildBlobResponse transactionBuildBlobResponse = sdk.getTransactionService().buildBlob(transactionBuildBlobRequest);
if (transactionBuildBlobResponse.getErrorCode() != 0) {
System.out.println("error: " + transactionBuildBlobResponse.getErrorDesc());
return null;
}
TransactionBuildBlobResult transactionBuildBlobResult = transactionBuildBlobResponse.getResult();
String txHash = transactionBuildBlobResult.getHash();
transactionBlob = transactionBuildBlobResult.getTransactionBlob();
// 5. Sign transaction BLob
String[] signerPrivateKeyArr = {senderPrivateKey};
TransactionSignRequest transactionSignRequest = new TransactionSignRequest();
transactionSignRequest.setBlob(transactionBlob);
for (String s : signerPrivateKeyArr) {
transactionSignRequest.addPrivateKey(s);
}
TransactionSignResponse transactionSignResponse = sdk.getTransactionService().sign(transactionSignRequest);
if (transactionSignResponse.getErrorCode() != 0) {
System.out.println("error: " + transactionSignResponse.getErrorDesc());
return null;
}
// 6. Broadcast
TransactionSubmitRequest transactionSubmitRequest = new TransactionSubmitRequest();
transactionSubmitRequest.setTransactionBlob(transactionBlob);
transactionSubmitRequest.setSignatures(transactionSignResponse.getResult().getSignatures());
TransactionSubmitResponse transactionSubmitResponse = sdk.getTransactionService().submit(transactionSubmitRequest);
if (0 == transactionSubmitResponse.getErrorCode()) {
System.out.println("Success,hash=" + transactionSubmitResponse.getResult().getHash());
} else {
System.out.println("Failure,hash=" + transactionSubmitResponse.getResult().getHash() + "");
System.out.println(JSON.toJSONString(transactionSubmitResponse, true));
}
return txHash;
}
/**
* @param privatekey private key
* @return java.lang.String Account address
* @author riven
*/
private String getAddressByPrivateKey(String privatekey) {
String publicKey = PrivateKey.getEncPublicKey(privatekey);
return PrivateKey.getEncAddress(publicKey);
}
}
6.5. 交易
package cn.bubi.sdk.example;
import com.alibaba.fastjson.JSON;
import cn.bubi.SDK;
import cn.bubi.common.ToBaseUnit;
import cn.bubi.model.request.AccountGetNonceRequest;
import cn.bubi.model.request.TransactionBuildBlobRequest;
import cn.bubi.model.request.TransactionSignRequest;
import cn.bubi.model.request.TransactionSubmitRequest;
import cn.bubi.model.request.operation.GasSendOperation;
import cn.bubi.model.response.AccountGetNonceResponse;
import cn.bubi.model.response.TransactionBuildBlobResponse;
import cn.bubi.model.response.TransactionSignResponse;
import cn.bubi.model.response.TransactionSubmitResponse;
import cn.bubi.model.response.result.AccountGetNonceResult;
import cn.bubi.model.response.result.TransactionBuildBlobResult;
import cn.bubi.model.response.result.TransactionSignResult;
import org.testng.annotations.Test;
/**
* @Author riven
*/
public class submitTransactionDemo {
SDK sdk = SDK.getInstance("http://node.bubidev.cn");
/*
* Get account nonce to start transaction
*/
@Test
public void getAccountNonce() {
// Init request
String senderAddress = "adxSYvndiFG4zpbLGugX3j93fDn9nWZfWp8Gd";
AccountGetNonceRequest getNonceRequest = new AccountGetNonceRequest();
getNonceRequest.setAddress(senderAddress);
// Call getNonce
AccountGetNonceResponse getNonceResponse = sdk.getAccountService().getNonce(getNonceRequest);
// Get nonce
if (getNonceResponse.getErrorCode() == 0) {
AccountGetNonceResult result = getNonceResponse.getResult();
System.out.println("nonce: " + result.getNonce());
} else {
System.out.println("error" + getNonceResponse.getErrorDesc());
}
}
/*
* Build operation
*/
@Test
public void buildOperation() {
String senderAddress = "adxSYvndiFG4zpbLGugX3j93fDn9nWZfWp8Gd";
String destAddress = "adxScpCtbeLP2KGRaCkbtrmz8iB5mu6DQcW3r";
Long amount = ToBaseUnit.ToUGas("10.9");
GasSendOperation operation = new GasSendOperation();
operation.setSourceAddress(senderAddress);
operation.setDestAddress(destAddress);
operation.setAmount(amount);
System.out.println(JSON.toJSONString(operation, true));
}
/*
* Build transaction blob
*/
@Test
public void buildTransactionBlob() {
// Get the nonce above getAccountNonce interface
String senderAddress = "adxSYvndiFG4zpbLGugX3j93fDn9nWZfWp8Gd";
AccountGetNonceRequest getNonceRequest = new AccountGetNonceRequest();
getNonceRequest.setAddress(senderAddress);
AccountGetNonceResponse getNonceResponse = sdk.getAccountService().getNonce(getNonceRequest);
Long nonce;
if (getNonceResponse.getErrorCode() == 0) {
AccountGetNonceResult result = getNonceResponse.getResult();
nonce = result.getNonce();
} else {
System.out.println("error" + getNonceResponse.getErrorDesc());
return;
}
// Get the operation above buildOperation interface
String destAddress = "adxScpCtbeLP2KGRaCkbtrmz8iB5mu6DQcW3r";
Long amount = ToBaseUnit.ToUGas("10.9");
GasSendOperation operation = new GasSendOperation();
operation.setSourceAddress(senderAddress);
operation.setDestAddress(destAddress);
operation.setAmount(amount);
// Init variable
Long gasPrice = 1000L;
Long feeLimit = ToBaseUnit.ToUGas("0.01");
// Init request
TransactionBuildBlobRequest buildBlobRequest = new TransactionBuildBlobRequest();
buildBlobRequest.setSourceAddress(senderAddress);
buildBlobRequest.setNonce(nonce + 1);
buildBlobRequest.setFeeLimit(feeLimit);
buildBlobRequest.setGasPrice(gasPrice);
buildBlobRequest.addOperation(operation);
// Build buildBlob
TransactionBuildBlobResponse buildBlobResponse = sdk.getTransactionService().buildBlob(buildBlobRequest);
if (buildBlobResponse.getErrorCode() == 0) {
TransactionBuildBlobResult result = buildBlobResponse.getResult();
System.out.println("txHash: " + result.getHash() + ", blob: " + result.getTransactionBlob());
} else {
System.out.println("error: " + buildBlobResponse.getErrorDesc());
}
}
/*
* Sign transaction
*/
@Test
public void signTransaction() {
// Get the nonce above getAccountNonce interface
String senderAddress = "adxSYvndiFG4zpbLGugX3j93fDn9nWZfWp8Gd";
AccountGetNonceRequest getNonceRequest = new AccountGetNonceRequest();
getNonceRequest.setAddress(senderAddress);
AccountGetNonceResponse getNonceResponse = sdk.getAccountService().getNonce(getNonceRequest);
Long nonce;
if (getNonceResponse.getErrorCode() == 0) {
AccountGetNonceResult result = getNonceResponse.getResult();
nonce = result.getNonce();
} else {
System.out.println("error" + getNonceResponse.getErrorDesc());
return;
}
// Get the operation above buildOperation interface
String destAddress = "adxScpCtbeLP2KGRaCkbtrmz8iB5mu6DQcW3r";
Long amount = ToBaseUnit.ToUGas("10.9");
GasSendOperation operation = new GasSendOperation();
operation.setSourceAddress(senderAddress);
operation.setDestAddress(destAddress);
operation.setAmount(amount);
// Get the transaction blob above buildTransactionBlob interface
Long gasPrice = 1000L;
Long feeLimit = ToBaseUnit.ToUGas("0.01");
TransactionBuildBlobRequest buildBlobRequest = new TransactionBuildBlobRequest();
buildBlobRequest.setSourceAddress(senderAddress);
buildBlobRequest.setNonce(nonce + 1);
buildBlobRequest.setFeeLimit(feeLimit);
buildBlobRequest.setGasPrice(gasPrice);
buildBlobRequest.addOperation(operation);
String transactionBlob;
TransactionBuildBlobResponse buildBlobResponse = sdk.getTransactionService().buildBlob(buildBlobRequest);
if (buildBlobResponse.getErrorCode() == 0) {
TransactionBuildBlobResult result = buildBlobResponse.getResult();
transactionBlob = result.getTransactionBlob();
} else {
System.out.println("error: " + buildBlobResponse.getErrorDesc());
return;
}
// Init request
String senderPrivateKey = "privbyQCRp7DLqKtRFCqKQJr81TurTqG6UKXMMtGAmPG3abcM9XHjWvq";
String[] signerPrivateKeyArr = {senderPrivateKey};
TransactionSignRequest signRequest = new TransactionSignRequest();
signRequest.setBlob(transactionBlob);
for (String s : signerPrivateKeyArr) {
signRequest.addPrivateKey(s);
}
// Call sign
TransactionSignResponse signResponse = sdk.getTransactionService().sign(signRequest);
if (signResponse.getErrorCode() == 0) {
TransactionSignResult result = signResponse.getResult();
System.out.println(JSON.toJSONString(result, true));
} else {
System.out.println("error: " + signResponse.getErrorDesc());
}
}
/*
* Broadcast transaction
*/
@Test
public void broadcastTransaction() {
// Get the nonce above getAccountNonce interface
String senderAddress = "adxSYvndiFG4zpbLGugX3j93fDn9nWZfWp8Gd";
AccountGetNonceRequest getNonceRequest = new AccountGetNonceRequest();
getNonceRequest.setAddress(senderAddress);
AccountGetNonceResponse getNonceResponse = sdk.getAccountService().getNonce(getNonceRequest);
Long nonce;
if (getNonceResponse.getErrorCode() == 0) {
AccountGetNonceResult result = getNonceResponse.getResult();
nonce = result.getNonce();
} else {
System.out.println("error" + getNonceResponse.getErrorDesc());
return;
}
// Get the operation above buildOperation interface
String destAddress = "adxScpCtbeLP2KGRaCkbtrmz8iB5mu6DQcW3r";
Long amount = ToBaseUnit.ToUGas("10.9");
GasSendOperation operation = new GasSendOperation();
operation.setSourceAddress(senderAddress);
operation.setDestAddress(destAddress);
operation.setAmount(amount);
// Get the transaction blob above buildTransactionBlob interface
Long gasPrice = 1000L;
Long feeLimit = ToBaseUnit.ToUGas("0.01");
TransactionBuildBlobRequest buildBlobRequest = new TransactionBuildBlobRequest();
buildBlobRequest.setSourceAddress(senderAddress);
buildBlobRequest.setNonce(nonce + 1);
buildBlobRequest.setFeeLimit(feeLimit);
buildBlobRequest.setGasPrice(gasPrice);
buildBlobRequest.addOperation(operation);
String transactionBlob;
TransactionBuildBlobResponse buildBlobResponse = sdk.getTransactionService().buildBlob(buildBlobRequest);
if (buildBlobResponse.getErrorCode() == 0) {
TransactionBuildBlobResult result = buildBlobResponse.getResult();
transactionBlob = result.getTransactionBlob();
} else {
System.out.println("error: " + buildBlobResponse.getErrorDesc());
return;
}
// Get sign result above signTransaction interface
String senderPrivateKey = "privbyQCRp7DLqKtRFCqKQJr81TurTqG6UKXMMtGAmPG3abcM9XHjWvq";
String[] signerPrivateKeyArr = {senderPrivateKey};
TransactionSignRequest signRequest = new TransactionSignRequest();
signRequest.setBlob(transactionBlob);
for (String s : signerPrivateKeyArr) {
signRequest.addPrivateKey(s);
}
TransactionSignResult signResult;
TransactionSignResponse signResponse = sdk.getTransactionService().sign(signRequest);
if (signResponse.getErrorCode() == 0) {
signResult = signResponse.getResult();
} else {
System.out.println("error: " + signResponse.getErrorDesc());
return;
}
// Init request
TransactionSubmitRequest submitRequest = new TransactionSubmitRequest();
submitRequest.setTransactionBlob(transactionBlob);
submitRequest.setSignatures(signResult.getSignatures());
// Call submit
TransactionSubmitResponse response = sdk.getTransactionService().submit(submitRequest);
if (0 == response.getErrorCode()) {
System.out.println("Success,hash=" + response.getResult().getHash());
} else {
System.out.println("error: " + response.getErrorDesc());
}
}
}
6.6. 交易查询
public int checkTransactionStatus(String txHash) {
// Init request
TransactionGetInfoRequest request = new TransactionGetInfoRequest();
request.setHash(txHash);
// Call getInfo
TransactionGetInfoResponse response = sdk.getTransactionService().getInfo(request);
int errorCode = response.getErrorCode();
if (errorCode == 0){
TransactionHistory transactionHistory = response.getResult().getTransactions()[0];
errorCode = transactionHistory.getErrorCode();
}
return errorCode;
}
7. 错误码
异常 | 错误码 | 描述 |
---|---|---|
ACCOUNT_CREATE_ERROR | 11001 | Failed to create the account |
INVALID_SOURCGasDDRESS_ERROR | 11002 | Invalid sourceAddress |
INVALID_DESTADDRESS_ERROR | 11003 | Invalid destAddress |
INVALID_INITBALANCE_ERROR | 11004 | InitBalance must be between 1 and Long.MAX_VALUE |
SOURCGasDDRESS_EQUAL_DESTADDRESS_ERROR | 11005 | SourceAddress cannot be equal to destAddress |
INVALID_ADDRESS_ERROR | 11006 | Invalid address |
CONNECTNETWORK_ERROR | 11007 | Failed to connect to the network |
INVALID_ISSUE_AMOUNT_ERROR | 11008 | Amount of the token to be issued must be between 1 and Long.MAX_VALUE |
NO_ASSET_ERROR | 11009 | The account does not have the asset |
NO_METADATA_ERROR | 11010 | The account does not have the metadata |
INVALID_DATAKEY_ERROR | 11011 | The length of key must be between 1 and 1024 |
INVALID_DATAVALUE_ERROR | 11012 | The length of value must be between 0 and 256000 |
INVALID_DATAVERSION_ERROR | 11013 | The version must be equal to or greater than 0 |
INVALID_MASTERWEIGHT_ERROR | 11015 | MasterWeight must be between 0 and (Integer.MAX_VALUE * 2L + 1) |
INVALID_SIGNER_ADDRESS_ERROR | 11016 | Invalid signer address |
INVALID_SIGNER_WEIGHT_ERROR | 11017 | Signer weight must be between 0 and (Integer.MAX_VALUE * 2L + 1) |
INVALID_TX_THRESHOLD_ERROR | 11018 | TxThreshold must be between 0 and Long.MAX_VALUE |
INVALID_OPERATION_TYPE_ERROR | 11019 | Operation type must be between 1 and 100 |
INVALID_TYPE_THRESHOLD_ERROR | 11020 | TypeThreshold must be between 0 and Long.MAX_VALUE |
INVALID_ASSET_CODE_ERROR | 11023 | The length of key must be between 1 and 64 |
INVALID_ASSET_AMOUNT_ERROR | 11024 | AssetAmount must be between 0 and Long.MAX_VALUE |
INVALID_GAS_AMOUNT_ERROR | 11026 | GasAmount must be between 0 and Long.MAX_VALUE |
INVALID_ISSUER_ADDRESS_ERROR | 11027 | Invalid issuer address |
NO_SUCH_TOKEN_ERROR | 11030 | No such token |
INVALID_TOKEN_NAME_ERROR | 11031 | The length of token name must be between 1 and 1024 |
INVALID_TOKEN_SIMBOL_ERROR | 11032 | The length of symbol must be between 1 and 1024 |
INVALID_TOKEN_DECIMALS_ERROR | 11033 | Decimals must be between 0 and 8 |
INVALID_TOKEN_TOTALSUPPLY_ERROR | 11034 | TotalSupply must be between 1 and Long.MAX_VALUE |
INVALID_TOKENOWNER_ERRPR | 11035 | Invalid token owner |
INVALID_CONTRACTADDRESS_ERROR | 11037 | Invalid contract address |
CONTRACTADDRESS_NOT_CONTRACTACCOUNT_ERROR | 11038 | contractAddress is not a contract account |
INVALID_TOKEN_AMOUNT_ERROR | 11039 | TokenAmount must be between 1 and Long.MAX_VALUE |
SOURCGasDDRESS_EQUAL_CONTRACTADDRESS_ERROR | 11040 | SourceAddress cannot be equal to contractAddress |
INVALID_FROMADDRESS_ERROR | 11041 | Invalid fromAddress |
FROMADDRESS_EQUAL_DESTADDRESS_ERROR | 11042 | FromAddress cannot be equal to destAddress |
INVALID_SPENDER_ERROR | 11043 | Invalid spender |
PAYLOAD_EMPTY_ERROR | 11044 | Payload cannot be empty |
INVALID_LOG_TOPIC_ERROR | 11045 | The length of a log topic must be between 1 and 128 |
INVALID_LOG_DATA_ERROR | 11046 | The length of one piece of log data must be between 1 and1024 |
INVALID_CONTRACT_TYPE_ERROR | 11047 | Invalid contract type |
INVALID_NONCE_ERROR | 11048 | Nonce must be between 1 and Long.MAX_VALUE |
INVALID_GASPRICE_ERROR | 11049 | GasPrice must be between 1000 and Long.MAX_VALUE |
INVALID_FEELIMIT_ERROR | 11050 | FeeLimit must be between 1 and Long.MAX_VALUE |
OPERATIONS_EMPTY_ERROR | 11051 | Operations cannot be empty |
INVALID_CEILLEDGERSEQ_ERROR | 11052 | CeilLedgerSeq must be equal to or greater than 0 |
OPERATIONS_ONE_ERROR | 11053 | One of the operations cannot be resolved |
INVALID_SIGNATURENUMBER_ERROR | 11054 | SignagureNumber must be between 1 and Integer.MAX_VALUE |
INVALID_HASH_ERROR | 11055 | Invalid transaction hash |
INVALID_BLOB_ERROR | 11056 | Invalid blob |
PRIVATEKEY_NULL_ERROR | 11057 | PrivateKeys cannot be empty |
PRIVATEKEY_ONE_ERROR | 11058 | One of privateKeys is invalid |
SIGNDATA_NULL_ERROR | 11059 | SignData cannot be empty |
INVALID_BLOCKNUMBER_ERROR | 11060 | BlockNumber must be bigger than 0 |
PUBLICKEY_NULL_ERROR | 11061 | PublicKey cannot be empty |
URL_EMPTY_ERROR | 11062 | Url cannot be empty |
CONTRACTADDRESS_CODE_BOTH_NULL_ERROR | 11063 | ContractAddress and code cannot be empty at the same time |
INVALID_OPTTYPE_ERROR | 11064 | OptType must be between 0 and 2 |
GET_ALLOWANCE_ERROR | 11065 | Failed to get allowance |
GET_TOKEN_INFO_ERROR | 11066 | Failed to get token info |
SIGNATURE_EMPTY_ERROR | 11067 | The signatures cannot be empty |
REQUEST_NULL_ERROR | 12001 | Request parameter cannot be null |
CONNECTN_BLOCKCHAIN_ERROR | 19999 | Failed to connect to the blockchain |
SYSTEM_ERROR | 20000 | System error |
8. 常见问题
待收集