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

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

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

准备工作

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

获取SDK源码

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

打包成JAR包并安装到本地的Maven仓库

$ mvn clean install -DskipTests

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

io.bytom

java-sdk

1.0.0

io.bytom

tx-signer

1.0.0

构建交易

普通交易

查询可用的utxo

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

Client client = Client.generateClient();

UnspentOutput.QueryBuilder builder = new UnspentOutput.QueryBuilder();

builder.accountAlias = "bytom";

List outputs = builder.list(client);

利用SDK只需要四行代码就能查询可用的utxo(SDK具体文档详见java-sdk documentation)。在QueryBuilder中可以指定是否为未确认的utxo(默认false),也可以通过from和count来进行分页查询(默认查询所有)。

假设在当前账户下查询得到这样一个utxo:

{

"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。代码如下:

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全节点来提交交易:

HashMap 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

Asset.QueryBuilder builder = new Asset.QueryBuilder();

builder.setId("7b38dc897329a288ea31031724f5c55bcafec80468a546955023380af2faad14");

List assets = builder.list(client);

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

{

"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个棒棒鸡资产:

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:

// 查询得到一个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();

提交交易

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

java工程打包时进行签名_使用Java SDK实现离线签名相关推荐

  1. java文件打包成jar文件_将java文件打包成jar包步骤

    将mypackage包中的FrameDemo.java文件打包成可执行成jar包 步骤1:先将程序中所有类打包成一个包 编译mypackage包FrameDemo.java文件,将类文件存入D盘Jar ...

  2. java编写代码时易出错_写Java程序最容易犯的错误有哪些呢?

    1.Duplicated Code 代码重复几乎是最常见的异味了.他也是Refactoring的主要目标之一.代码重复往往来自于copy-and-paste的编程风格.与他相对应OAOO是一个好系统的 ...

  3. Java工程打包部署到linux服务器整个过程

    本次分享是Java工程打包部署到linux服务器整个过程,包括在服务器上jar包启停的一些经验分享. 操作环境 下面是对已经完成的Java工程打包上传,启停步骤分享. 1.在项目工程中使用Maven的 ...

  4. maven 打包时缺少文件_(三)Java资源文件和路径相关扫盲

    本来打算接着上文直接写登录功能的,顺便介绍下SpringSecurity,但是SpringSecurity和Spring以及SpirngBoot是如何衔接的又是个较为复杂的事情.看了下SpringBo ...

  5. ue4 设置打包名称_[UE4]工程打包时添加自定义文件 - 纳金网

    Project Settings -> packaging -> Packaging选项中,有多个设置项来设置打包时要排除或者包含的文件夹,比如:设置哪些目录不参与cook,以及哪些目录在 ...

  6. maven 打包时缺少文件_解决Intellij Idea下使用Maven项目打包时部分文件缺失问题

    问题 Idea被越来越多的java开发者青睐,特别是丰富的插件极大方便了开发者.Idea虽然没有Eclipse的繁琐配置,但也会出现一些问题.问题如下: 一.在进行Maven项目打包的时候,会发现有的 ...

  7. java工程如何跑起来的_你编写的Java代码是咋跑起来的?

    如果你是一名 Java 开发人员,你肯定指定 Java 代码有很多种不同的运行方式.比如说可以在开发工具(IDEA.Eclipse等)中运行,可以双击执行 jar 文件运行,也可以在命令行中运行,甚至 ...

  8. java个性签名_【转】哲理个性签名大全_300条qq哲理个性签名

    吵架好像抓痒,越抓越痒. 女人的聪明在于能欣赏男人的聪明. 生活是灯,工作是油,若要灯亮,就得加油! 若要优美的嘴唇,要讲亲切的话;若要可爱的眼睛,要看到别人的好处;若要苗条的身体,把你的食物分给饥饿 ...

  9. java web开源项目源码_适合Java新手的开源项目集合——在 GitHub 学编程

    作者:HelloGitHub-老荀 当今互联网份额最大的编程语言是哪一个?是 Java!这两年一直有听说 Java 要不行了.在走下坡路了.没错,Java 的确在走下坡路,未来的事情的确不好说,但是瘦 ...

最新文章

  1. Java 的序列化和反序列化,你该知道得更多
  2. Python基础教程:赋值、深拷贝与浅拷贝(内存地址)
  3. vim + cscope + kscope
  4. 旋转数组—leetcode189
  5. c语言两个变量相乘出现乱码,C语言,矩阵的乘法运算程序,输出一堆乱码,求大神看看哪里错了。。...
  6. 将本地源代码程序推送远程Github仓库
  7. linux故障排查书籍,Linux系统故障排查和修复技巧.docx
  8. JAVA设计模式初探之组合模式
  9. selenium常见面试题
  10. 关于CodeReview
  11. NV12图像格式叠加(水印原理演示)
  12. 一个简单的鼠标钩子程序
  13. windows无法格式化u盘_U盘修复无法格式化的解决方法
  14. 对比UltraCompare和Beyond Compare我这么选,你会怎么选?
  15. ASPECT RATIO
  16. 魔兽争霸无法在这个计算机,win10系统魔兽争霸按F1无法选中自己的英雄的图文办法...
  17. 如何建立异地容灾备份体系
  18. 教你如何用Unity和Cardboard把3D游戏做成VR游戏
  19. matlab solve 解的范围,matlab怎么解方程,如何规定解的范围?
  20. Java调试大法,来了~

热门文章

  1. 1行代码搞定Latex公式编写,这个4.6M的Python小插件,堪称论文必备神器
  2. 看完发现RNN原来是这样,机器学习人门贴送上
  3. golang的临时对象池sync.Pool
  4. 卷积神经网络(CNN)实现CIFAR100类别分类
  5. 线性回归之梯度下降法介绍
  6. 爬虫之selenium标签页的切换
  7. CveService.java
  8. 已知子网掩码如何计算IP地址中的主机位
  9. 为什么机器学习项目非常难管理?
  10. 常用特征工程方法总结