使用Java SDK实现离线签名

2025-05-29 0 36

严格来说,tx-signer并不属于sdk,它是bytomd中构建交易、对交易签名两大模块的java实现版。因此,若想用tx-signer对交易进行离线签名,需要由你在本地保管好自己的私钥。

如果你的目的是完全脱离于bytomd全节点,可能需要自己做更多额外的工作。比如,在构建交易时,需要花费若干个utxo(unspent transaction output)作为交易的输入,如果没有全节点则需要自身来维护utxo。当使用tx-signer构建完成一笔交易并签名后,若没有全节点的帮助,也需要自己实现p2p网络协议将交易广播到其他节点。

本文不会对以上技术细节进行讨论,而是利用bytomd全节点查询可用的utxo构建交易,对交易进行签名并序列化后,同样使用bytomd提交交易。

准备工作

将maven依赖引入到你的项目中

获取sdk源码

?

1
git clone https://github.com/bytom/bytom-java-sdk.git

打包成jar包并安装到本地的maven仓库

?

1
$ mvn clean install -dskiptests

在项目的pom文件中添加依赖。其中,第一个依赖是bytomd api的封装,可用于查询可用的utxo以及提交交易;第二个依赖用于构建交易以及对交易进行离线签名

?

1

2

3

4

5

6

7

8

9

10

11
<dependency>

<groupid>io.bytom</groupid>

<artifactid>java-sdk</artifactid>

<version>1.0.0</version>

</dependency>

<dependency>

<groupid>io.bytom</groupid>

<artifactid>tx-signer</artifactid>

<version>1.0.0</version>

</dependency>

构建交易

普通交易

查询可用的utxo

在本文中,以下将全部使用全节点来查询可用的utxo,你也可以构建一套自己的utxo维护方案。

?

1

2

3

4
client client = client.generateclient();

unspentoutput.querybuilder builder = new unspentoutput.querybuilder();

builder.accountalias = "bytom";

list<unspentoutput> outputs = builder.list(client);

利用sdk只需要四行代码就能查询可用的utxo(sdk具体文档详见java-sdk documentation)。在querybuilder中可以指定是否为未确认的utxo(默认false),也可以通过from和count来进行分页查询(默认查询所有)。
假设在当前账户下查询得到这样一个utxo:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16
{

"account_alias": "bytom",

"id": "ffdc59d0478277298de4afa458dfa7623c051a46b7a84939fb8227083411b156",

"asset_id": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",

"asset_alias": "btm",

"amount": 41250000000,

"account_id": "0g1r52o1g0a02",

"address": "sm1qxls6ajp6fejc0j5kp8jwt2nj3kmsqazfumrkrr",

"control_program_index": 1,

"program": "001437e1aec83a4e6587ca9609e4e5aa728db7007449",

"source_id": "2d3a5d920833778cc7c65d7c96fe5f3c4a1a61aa086ee093f44a0522dd499a34",

"source_pos": 0,

"valid_height": 4767,

"change": false,

"derive_rule": 0

}

构建交易

现在需要往0014c832e1579b4f96dc12dcfff39e8fe69a62d3f516这个control program转100个btm。代码如下:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27
string btmassetid = "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff";

// 下面的字段与utxo中的字段一一对应

spendinput input = new spendinput();

input.setassetid(btmassetid);

input.setamount(41250000000l);

input.setprogram("001437e1aec83a4e6587ca9609e4e5aa728db7007449");

input.setsourceposition(0);

input.setsourceid("2d3a5d920833778cc7c65d7c96fe5f3c4a1a61aa086ee093f44a0522dd499a34");

input.setchange(false);

input.setcontrolprogramindex(1);

// 选择使用bip32还是bip44来派生地址,默认bip44

input.setbipprotocol(bipprotocol.bip44);

// 账户对应的密钥索引

input.setkeyindex(1);

// 自身本地保管的私钥,用于对交易进行签名

input.setrootprivatekey("4864bae85cf38bfbb347684abdbc01e311a24f99e2c7fe94f3c071d9c83d8a5a349722316972e382c339b79b7e1d83a565c6b3e7cf46847733a47044ae493257");

transaction tx = new transaction.builder()

.addinput(input)

// 加入需要转入的output

.addoutput(new output(btmassetid, 10000000000l, "0014c832e1579b4f96dc12dcfff39e8fe69a62d3f516"))

// 剩余的btm用于找零

.addoutput(new output(btmassetid, 31250000000l, "0014bb8a039726df1b649738e9973db14a4b4fd4becf"))

.settimerange(0)

.build();

string rawtransaction = tx.rawtransaction();

对交易调用build方法后,自动会对交易进行本地的验证和签名操作。注意,在本地只是做简单的字段验证,本地验证通过并不代表交易合法。最后对交易调用rawtransaction方法返回交易序列化后的字符串。

提交交易

本文利用bytomd全节点来提交交易:

?

1

2

3
hashmap<string, object> body = new hashmap<>();

body.put("raw_transaction", "070100010160015e4b5cb973f5bef4eadde4c89b92ee73312b940e84164da0594149554cc8a2adeaffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80c480c1240201160014cb9f2391bafe2bc1159b2c4c8a0f17ba1b4dd94e6302401cb779288be890a28c5209036da1a27d9fe74a51c38e0a10db4817bcf4fd05f68580239eea7dcabf19f144c77bf13d3674b5139aa51a99ba58118386c190af0e20bcbe020b05e1b7d0825953d92bf47897be08cd7751a37adb95d6a2e5224f55ab02013dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80b095e42001160014a82f02bc37bc5ed87d5f9fca02f8a6a7d89cdd5c000149ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80d293ad03012200200824e931fb806bd77fdcd291aad3bd0a4493443a4120062bd659e64a3e0bac6600");

transaction.submitresponse response = client.request("submit-transaction", body, transaction.submitresponse.class);

交易提交成功后,response返回交易id。

发行资产交易

查询可用的utxo

发行资产时,需要使用btm作为手续费,因此第一步同样需要查询当前账户下可用的utxo,由于上面已经提到,这里不再赘述。

查询需要发行的资产信息

例如,需要发行的资产id为7b38dc897329a288ea31031724f5c55bcafec80468a546955023380af2faad14

?

1

2

3
asset.querybuilder builder = new asset.querybuilder();

builder.setid("7b38dc897329a288ea31031724f5c55bcafec80468a546955023380af2faad14");

list<asset> assets = builder.list(client);

假设查询得到的资产信息如下:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20
{

"type": "asset",

"xpubs": [

"5ff7f79f0fd4eb9ccb17191b0a1ac9bed5b4a03320a06d2ff8170dd51f9ad9089c4038ec7280b5eb6745ef3d36284e67f5cf2ed2a0177d462d24abf53c0399ed"

],

"quorum": 1,

"key_index": 3,

"derive_rule": 0,

"id": "7b38dc897329a288ea31031724f5c55bcafec80468a546955023380af2faad14",

"alias": "棒棒鸡",

"vm_version": 1,

"issue_program": "ae20db11f9dfa39c9e66421c530fe027218edd3d5b1cd98f24c826f4d9c0cd131a475151ad",

"raw_definition_byte": "7b0a202022646563696d616c73223a20382c0a2020226465736372697074696f6e223a207b7d2c0a2020226e616d65223a2022222c0a20202273796d626f6c223a2022220a7d",

"definition": {

"decimals": 8,

"description": {},

"name": "",

"symbol": ""

}

}

构建交易

现在需要发行1000个棒棒鸡资产:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31
issuanceinput issuanceinput = new issuanceinput();

issuanceinput.setassetid("7b38dc897329a288ea31031724f5c55bcafec80468a546955023380af2faad14");

issuanceinput.setamount(100000000000l);

// issue program

issuanceinput.setprogram("ae20db11f9dfa39c9e66421c530fe027218edd3d5b1cd98f24c826f4d9c0cd131a475151ad");

// 可以不指定,不指定时将随机生成一个

issuanceinput.setnonce("ac9d5a527f5ab00a");

issuanceinput.setkeyindex(5);

// raw definition byte

issuanceinput.setrawassetdefinition("7b0a202022646563696d616c73223a20382c0a2020226465736372697074696f6e223a207b7d2c0a2020226e616d65223a2022222c0a20202273796d626f6c223a2022220a7d");

// 该资产对应的私钥

issuanceinput.setrootprivatekey("4864bae85cf38bfbb347684abdbc01e311a24f99e2c7fe94f3c071d9c83d8a5a349722316972e382c339b79b7e1d83a565c6b3e7cf46847733a47044ae493257");

// 创建一个spend input作为手续费,假设当前有一个100btm的utxo,并且使用1btm作为手续费,则后续还要创建99btm的找零地址

spendinput feeinput = new spendinput(btmassetid, 10000000000l, "0014cb9f2391bafe2bc1159b2c4c8a0f17ba1b4dd94e");

feeinput.setkeyindex(1);

feeinput.setchange(true);

feeinput.setsourceid("4b5cb973f5bef4eadde4c89b92ee73312b940e84164da0594149554cc8a2adea");

feeinput.setsourceposition(2);

feeinput.setcontrolprogramindex(457);

feeinput.setrootprivatekey("4864bae85cf38bfbb347684abdbc01e311a24f99e2c7fe94f3c071d9c83d8a5a349722316972e382c339b79b7e1d83a565c6b3e7cf46847733a47044ae493257");

transaction tx = new transaction.builder()

.addinput(issuanceinput)

.addinput(feeinput)

// 该output用于接收发行的资产

.addoutput(new output("7b38dc897329a288ea31031724f5c55bcafec80468a546955023380af2faad14", 100000000000l, "001437e1aec83a4e6587ca9609e4e5aa728db7007449"))

// 找零

.addoutput(new output(btmassetid, 9800000000l, "00148be1104e04734e5edaba5eea2e85793896b77c56"))

.settimerange(0)

.build();

提交交易

提交交易的方式与普通交易一致。

销毁资产交易

销毁资产跟发行资产类似,同样需要btm作为手续费。

查询可用的utxo

查询方式与普通交易一致。

构建交易

这里以销毁一个btm为例,假设查询得到一个100btm的utxo:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21
// 查询得到一个100btm的utxo作为输入

spendinput input = new spendinput(btmassetid, 10000000000l, "0014f1dc52048f439ac7fd74f8106a21da78f00de48f");

input.setrootprivatekey(rootkey);

input.setchange(true);

input.setkeyindex(1);

input.setcontrolprogramindex(41);

input.setsourceid("0b2cff11d1d056d95237a5f2d06059e5395e86f60e69c1e8201ea624911c0c65");

input.setsourceposition(0);

// 销毁资产时,可添加一段附加的文本

string arbitrary = "77656c636f6d65efbc8ce6aca2e8bf8ee69da5e588b0e58e9fe5ad90e4b896e7958c";

// 销毁99个btm,剩余1个btm作为手续费

output output = output.newretireoutput(btmassetid, 9900000000l, arbitrary);

transaction transaction = new transaction.builder()

.addinput(input)

.addoutput(output)

.settimerange(2000000)

.build();

string rawtransaction = transaction.rawtransaction();

提交交易

提交交易的方式与普通交易一致。

bytom java sdk:https://github.com/bytom/bytom-java-sdk/

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持快网idc。

原文链接:https://segmentfault.com/a/1190000018674925

收藏 (0) 打赏

感谢您的支持,我会继续努力的!

打开微信/支付宝扫一扫,即可进行扫码打赏哦,分享从这里开始,精彩与您同在
点赞 (0)

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。

快网idc优惠网 建站教程 使用Java SDK实现离线签名 https://www.kuaiidc.com/109297.html

相关文章

发表评论
暂无评论