Skip to content

Commit 4d9bb0f

Browse files
authored
Merge pull request #848 from FISCO-BCOS/feature-3.6.0
<feat>(transaction): impl transaction manager, add gas provider. (#847)
2 parents be9c323 + d79ce90 commit 4d9bb0f

15 files changed

+1227
-475
lines changed

build.gradle

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,11 @@ ext {
2020
commonsIOVersion = '2.11.0'
2121
commonsLang3Version = '3.12.0'
2222
toml4jVersion = "0.7.2"
23-
bcprovJDK15onVersion = '1.69'
23+
bcprovJDK18onVersion = '1.75'
2424
webankJavaCryptoVersion = "1.0.3"
2525
junitVersion = '4.13.2'
2626
commonsCollections4Version = "4.4"
27-
bcosSdkJniVersion = "3.5.0"
27+
bcosSdkJniVersion = "3.6.0-SNAPSHOT"
2828
slf4jApiVerison = '1.7.36'
2929
mockitoVersion = '4.8.0'
3030
gsonVersion = '2.10.1'
@@ -40,7 +40,7 @@ allprojects {
4040
apply plugin: 'maven-publish'
4141
apply plugin: 'idea'
4242
apply plugin: 'eclipse'
43-
43+
4444
apply plugin: 'java'
4545
apply plugin: 'java-library'
4646
apply plugin: 'jacoco'
@@ -125,13 +125,13 @@ googleJavaFormat {
125125
}
126126

127127
dependencies {
128-
api("org.fisco-bcos:fisco-bcos-tars-sdk" + ":${tarsSDKVersion}")
129-
api("org.fisco-bcos:bcos-sdk-jni:${bcosSdkJniVersion}") {
130-
exclude group : "org.slf4j"
131-
exclude group : "com.fasterxml.jackson.core"
128+
api("org.fisco-bcos:fisco-bcos-tars-sdk" + ":${tarsSDKVersion}")
129+
api("org.fisco-bcos:bcos-sdk-jni:${bcosSdkJniVersion}") {
130+
exclude group: "org.slf4j"
131+
exclude group: "com.fasterxml.jackson.core"
132132
}
133133

134-
api("org.bouncycastle:bcprov-jdk15on:${bcprovJDK15onVersion}")
134+
api("org.bouncycastle:bcprov-jdk18on:${bcprovJDK18onVersion}")
135135
api("com.google.code.gson:gson:${gsonVersion}")
136136
api("org.apache.commons:commons-lang3:${commonsLang3Version}")
137137
api("com.fasterxml.jackson.core:jackson-databind:${jacksonVersion}")
@@ -177,10 +177,12 @@ javadoc {
177177
}
178178

179179
task copyHooks(type: Copy) {
180-
from("hooks") {
181-
include "**"
180+
if (!file(".git/hooks/pre-commit").exists()) {
181+
from("hooks") {
182+
include "**"
183+
}
184+
into ".git/hooks"
182185
}
183-
into ".git/hooks"
184186
}
185187

186188
task sourcesJar(type: Jar) {
@@ -265,7 +267,7 @@ publishing {
265267

266268
jar {
267269
// destinationDir file('dist/apps')
268-
archiveFileName="fisco-bcos-" + project.name + '-' + project.version + '.jar'
270+
archiveFileName = "fisco-bcos-" + project.name + '-' + project.version + '.jar'
269271
exclude '**/*.xml'
270272
exclude '**/*.properties'
271273

Lines changed: 270 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,270 @@
1+
package org.fisco.bcos.sdk.v3.test.transaction.demo;
2+
3+
import java.io.IOException;
4+
import java.util.ArrayList;
5+
import java.util.Collections;
6+
import java.util.List;
7+
import java.util.concurrent.CompletableFuture;
8+
import java.util.concurrent.ExecutionException;
9+
import java.util.concurrent.TimeUnit;
10+
import java.util.concurrent.TimeoutException;
11+
import org.fisco.bcos.sdk.jni.common.JniException;
12+
import org.fisco.bcos.sdk.jni.utilities.tx.TransactionBuilderJniObj;
13+
import org.fisco.bcos.sdk.v3.BcosSDK;
14+
import org.fisco.bcos.sdk.v3.client.Client;
15+
import org.fisco.bcos.sdk.v3.codec.ContractCodecException;
16+
import org.fisco.bcos.sdk.v3.model.ConstantConfig;
17+
import org.fisco.bcos.sdk.v3.model.TransactionReceipt;
18+
import org.fisco.bcos.sdk.v3.model.callback.TransactionCallback;
19+
import org.fisco.bcos.sdk.v3.transaction.codec.decode.TransactionDecoderService;
20+
import org.fisco.bcos.sdk.v3.transaction.manager.AssembleTransactionWithRemoteSignProcessor;
21+
import org.fisco.bcos.sdk.v3.transaction.manager.TransactionProcessorFactory;
22+
import org.fisco.bcos.sdk.v3.transaction.model.dto.CallResponse;
23+
import org.fisco.bcos.sdk.v3.transaction.model.dto.TransactionResponse;
24+
import org.fisco.bcos.sdk.v3.transaction.model.exception.NoSuchTransactionFileException;
25+
import org.fisco.bcos.sdk.v3.transaction.model.exception.TransactionBaseException;
26+
import org.fisco.bcos.sdk.v3.transaction.signer.RemoteSignProviderInterface;
27+
import org.fisco.bcos.sdk.v3.utils.Hex;
28+
29+
public class AssembleTransactionWithRemoteSignProcessorSample {
30+
private static final String configFile =
31+
"src/integration-test/resources/" + ConstantConfig.CONFIG_FILE_NAME;
32+
33+
// 合约ABI文件目录
34+
private static final String abiFile = "src/integration-test/resources/abi/";
35+
// 合约BIN文件目录
36+
private static final String binFile = "src/integration-test/resources/bin/";
37+
// prepare sdk, read from the config file
38+
private final BcosSDK sdk;
39+
private final Client client;
40+
// mock remote sign service
41+
private final RemoteSignProviderInterface remoteSignProviderMock;
42+
private final String abi;
43+
44+
private final AssembleTransactionWithRemoteSignProcessor
45+
assembleTransactionWithRemoteSignProcessor;
46+
47+
public AssembleTransactionWithRemoteSignProcessorSample()
48+
throws IOException, NoSuchTransactionFileException {
49+
// create sdk by config file
50+
sdk = BcosSDK.build(configFile);
51+
client = this.sdk.getClient("group0");
52+
// RemoteSignProviderMock 为mock服务,可以改为调用远程签名服务
53+
remoteSignProviderMock = new RemoteSignProviderMock(this.client.getCryptoSuite());
54+
// build processor
55+
assembleTransactionWithRemoteSignProcessor =
56+
TransactionProcessorFactory.createAssembleTransactionWithRemoteSignProcessor(
57+
this.client,
58+
this.client.getCryptoSuite().getCryptoKeyPair(),
59+
abiFile,
60+
binFile,
61+
this.remoteSignProviderMock);
62+
// 从contract loader内获取ABI字符串,也可以直接从外部传入
63+
abi =
64+
assembleTransactionWithRemoteSignProcessor
65+
.getContractLoader()
66+
.getABIByContractName("HelloWorld");
67+
}
68+
69+
public String deployContract()
70+
throws NoSuchTransactionFileException, ContractCodecException, JniException,
71+
ExecutionException, InterruptedException, TimeoutException {
72+
73+
// 从contract loader内获取ABI字符串,也可以直接从外部传入
74+
String abi =
75+
assembleTransactionWithRemoteSignProcessor
76+
.getContractLoader()
77+
.getABIByContractName("HelloWorld");
78+
// 从contract loader内获取BIN字符串,也可以直接从外部传入
79+
String bin =
80+
assembleTransactionWithRemoteSignProcessor
81+
.getContractLoader()
82+
.getBinaryByContractName("HelloWorld");
83+
84+
/// 1. 准备部署交易参数
85+
List<Object> params = new ArrayList<>(Collections.singletonList("test"));
86+
// 部署合约需要bin、abi、构造参数
87+
/// 2. 构造交易体结构
88+
// 构造交易结构,long是指针类型,使用完后需要主动释放
89+
long transactionData =
90+
assembleTransactionWithRemoteSignProcessor.getRawTransactionForConstructor(
91+
abi, bin, params);
92+
93+
try {
94+
95+
/// 3. 使用交易体计算交易哈希
96+
// 返回交易哈希,十六进制字符串
97+
String rawTxHash =
98+
TransactionBuilderJniObj.calcTransactionDataHash(
99+
client.getCryptoSuite().cryptoTypeConfig, transactionData);
100+
101+
/// 4. 请求远程签名服务对交易哈希进行签名
102+
CompletableFuture<TransactionReceipt> receiptCompletableFuture =
103+
new CompletableFuture<>();
104+
105+
// 发起远程签名请求, 对bytes签名
106+
remoteSignProviderMock.requestForSignAsync(
107+
Hex.decode(rawTxHash),
108+
this.client.getCryptoSuite().cryptoTypeConfig,
109+
signatureResult -> {
110+
111+
/// 5. 获取到签名之后,拼装完整交易,并获取编码后的交易
112+
String signedTransaction = null;
113+
try {
114+
signedTransaction =
115+
TransactionBuilderJniObj.createSignedTransaction(
116+
transactionData,
117+
Hex.toHexString(signatureResult.encode()),
118+
rawTxHash,
119+
0);
120+
} catch (JniException e) {
121+
throw new RuntimeException(e);
122+
}
123+
124+
/// 6. 将编码后的交易发送到链上
125+
assembleTransactionWithRemoteSignProcessor.sendTransactionAsync(
126+
signedTransaction,
127+
new TransactionCallback() {
128+
@Override
129+
public void onResponse(TransactionReceipt receipt) {
130+
receiptCompletableFuture.complete(receipt);
131+
}
132+
});
133+
return 0;
134+
});
135+
136+
TransactionReceipt transactionReceipt =
137+
receiptCompletableFuture.get(10000, TimeUnit.MILLISECONDS);
138+
139+
String contractAddress = transactionReceipt.getContractAddress();
140+
if (transactionReceipt.isStatusOK()) {
141+
System.out.println("部署合约成功,合约地址:" + contractAddress);
142+
}
143+
144+
return contractAddress;
145+
} finally {
146+
TransactionBuilderJniObj.destroyTransactionData(transactionData);
147+
}
148+
}
149+
150+
public TransactionResponse sendTransaction(String address, List<Object> params)
151+
throws JniException, ContractCodecException, ExecutionException, InterruptedException,
152+
TimeoutException {
153+
154+
// 1. 准备交易参数
155+
// 2. 构造交易体
156+
long transactionData =
157+
assembleTransactionWithRemoteSignProcessor.getRawTransaction(
158+
address, abi, "set", params);
159+
160+
try {
161+
162+
/// 3. 使用交易体计算交易哈希
163+
// 返回交易哈希,十六进制字符串
164+
String rawTxHash =
165+
TransactionBuilderJniObj.calcTransactionDataHash(
166+
client.getCryptoSuite().cryptoTypeConfig, transactionData);
167+
168+
/// 4. 请求远程签名服务对交易哈希进行签名
169+
CompletableFuture<TransactionReceipt> receiptCompletableFuture =
170+
new CompletableFuture<>();
171+
172+
// 发起远程签名请求, 对bytes签名
173+
remoteSignProviderMock.requestForSignAsync(
174+
Hex.decode(rawTxHash),
175+
this.client.getCryptoSuite().cryptoTypeConfig,
176+
signatureResult -> {
177+
178+
/// 5. 获取到签名之后,拼装完整交易,并获取编码后的交易
179+
String signedTransaction = null;
180+
try {
181+
signedTransaction =
182+
TransactionBuilderJniObj.createSignedTransaction(
183+
transactionData,
184+
Hex.toHexString(signatureResult.encode()),
185+
rawTxHash,
186+
0);
187+
} catch (JniException e) {
188+
throw new RuntimeException(e);
189+
}
190+
191+
/// 6. 将编码后的交易发送到链上
192+
assembleTransactionWithRemoteSignProcessor.sendTransactionAsync(
193+
signedTransaction,
194+
new TransactionCallback() {
195+
@Override
196+
public void onResponse(TransactionReceipt receipt) {
197+
receiptCompletableFuture.complete(receipt);
198+
}
199+
});
200+
return 0;
201+
});
202+
203+
/// 5. 收到交易回执
204+
TransactionReceipt transactionReceipt =
205+
receiptCompletableFuture.get(10000, TimeUnit.MILLISECONDS);
206+
207+
/// 6. 解析交易回执
208+
TransactionDecoderService transactionDecoderService =
209+
new TransactionDecoderService(client.getCryptoSuite(), client.isWASM());
210+
211+
if (transactionReceipt.isStatusOK()) {
212+
/// 7. 如果回执中存在事件
213+
/// Map<String, List<List<Object>>> stringListMap =
214+
// transactionDecoderService.decodeEvents(abi, transactionReceipt.getLogEntries());
215+
/// 8. 如果合约有返回值
216+
// TransactionResponse transactionResponse =
217+
// transactionDecoderService.decodeReceiptWithValues(abi, "set",
218+
// transactionReceipt);
219+
/// 9. 如果合约无返回值
220+
TransactionResponse transactionResponse =
221+
transactionDecoderService.decodeReceiptWithoutValues(
222+
abi, transactionReceipt);
223+
return transactionResponse;
224+
} else {
225+
String revertMessage =
226+
transactionDecoderService.decodeRevertMessage(
227+
transactionReceipt.getOutput());
228+
System.out.println("交易回滚,回滚信息:" + revertMessage);
229+
return null;
230+
}
231+
232+
} finally {
233+
TransactionBuilderJniObj.destroyTransactionData(transactionData);
234+
}
235+
}
236+
237+
String callContract(String address) throws TransactionBaseException, ContractCodecException {
238+
// get 方法没有参数
239+
List<Object> params = new ArrayList<>();
240+
CallResponse callResponse =
241+
assembleTransactionWithRemoteSignProcessor.sendCall(
242+
"", address, abi, "get", params);
243+
List<Object> callResponseReturnObject = callResponse.getReturnObject();
244+
return (String) callResponseReturnObject.get(0);
245+
}
246+
247+
public static void main(String[] args)
248+
throws TransactionBaseException, IOException, JniException, ContractCodecException,
249+
ExecutionException, InterruptedException, TimeoutException {
250+
251+
AssembleTransactionWithRemoteSignProcessorSample
252+
assembleTransactionWithRemoteSignProcessorSample =
253+
new AssembleTransactionWithRemoteSignProcessorSample();
254+
255+
// 部署合约
256+
String address = assembleTransactionWithRemoteSignProcessorSample.deployContract();
257+
258+
String param = "test";
259+
TransactionResponse transactionResponse =
260+
assembleTransactionWithRemoteSignProcessorSample.sendTransaction(
261+
address, Collections.singletonList(param));
262+
263+
if (transactionResponse.getTransactionReceipt().isStatusOK()) {
264+
265+
String result = assembleTransactionWithRemoteSignProcessorSample.callContract(address);
266+
assert param.equals(result);
267+
System.out.println("调用合约结束。");
268+
}
269+
}
270+
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
package org.fisco.bcos.sdk.v3.test.transaction.demo;
2+
3+
import org.fisco.bcos.sdk.jni.common.JniException;
4+
import org.fisco.bcos.sdk.v3.crypto.signature.SignatureResult;
5+
import org.fisco.bcos.sdk.v3.model.TransactionReceipt;
6+
import org.fisco.bcos.sdk.v3.transaction.manager.AssembleTransactionWithRemoteSignProcessor;
7+
import org.fisco.bcos.sdk.v3.transaction.signer.RemoteSignCallbackInterface;
8+
import org.fisco.bcos.sdk.v3.transaction.tools.JsonUtils;
9+
10+
public class RemoteSignCallbackMock implements RemoteSignCallbackInterface {
11+
12+
protected AssembleTransactionWithRemoteSignProcessor assembleTransactionWithRemoteSignProcessor;
13+
protected long transactionData;
14+
protected int txAttribute;
15+
16+
public RemoteSignCallbackMock(
17+
AssembleTransactionWithRemoteSignProcessor assembleTransactionWithRemoteSignProcessor,
18+
long transactionData,
19+
int txAttribute) {
20+
this.assembleTransactionWithRemoteSignProcessor =
21+
assembleTransactionWithRemoteSignProcessor;
22+
this.transactionData = transactionData;
23+
this.txAttribute = txAttribute;
24+
}
25+
26+
/**
27+
* 签名结果回调的实现
28+
*
29+
* @param signatureStr 签名服务回调返回的签名结果串
30+
* @return *
31+
*/
32+
@Override
33+
public int handleSignedTransaction(SignatureResult signatureStr) {
34+
System.out.println(System.currentTimeMillis() + " SignatureResult: " + signatureStr);
35+
// send the transaction after sign it
36+
TransactionReceipt tr = null;
37+
try {
38+
tr =
39+
assembleTransactionWithRemoteSignProcessor.encodeAndPush(
40+
transactionData, signatureStr.convertToString(), this.txAttribute);
41+
} catch (JniException e) {
42+
e.printStackTrace();
43+
}
44+
System.out.println(
45+
"handleSignedTransaction transactionReceipt is: " + JsonUtils.toJson(tr));
46+
return 0;
47+
}
48+
}

0 commit comments

Comments
 (0)