前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Omni Layer USDT区块链开发包简介【OmniTool.Java】

Omni Layer USDT区块链开发包简介【OmniTool.Java】

作者头像
用户1408045
发布2019-12-01 13:42:06
1.8K0
发布2019-12-01 13:42:06
举报
文章被收录于专栏:汇智网教程

OmniTool.Java开发包适用于为Java应用快速增加对Omni/USDT数字资产的支持能力,即支持使用自有Omni节点的应用场景,也支持基于第三方API服务和离线裸交易的轻量级部署场景。官方下载地址:http://sc.hubwiz.com/codebag/omni-java-lib/

1、开发包概述

OmniTool.Java开发包主要包含以下特性:

  • 完善的Bitcoin/Omni Layer RPC API封装
  • 支持利用自有节点或第三方服务获取指定地址的比特币utxo集合
  • 支持离线生成Omni代币或比特币转账裸交易
  • 支持利用自有节点或第三方服务广播裸交易

OmniTool.Java支持本地部署的Omnicored节点,也支持第三方服务提供的开放API,要增加新的第三方服务也非常简单,只需要参考代码实现如下接口:

  • IUtxoCollector:Utxo采集器
  • IBroadcaster:裸交易广播器

OmniTool.Java软件包当前版本1.0.0,主要类/接口及关系如下图所示:

OmniTool.Java软件包主要代码文件清单请访问官网:http://sc.hubwiz.com/codebag/omni-java-lib/

2、RpcClient类使用说明

RpcClient类封装了比特币以及Omni Layer的RPC API接口协议。创建RpcClient对象时,需要传入包含有效身份信息的节点RPC URL。例如,假设安装在本机的omnicored节点软件接入主网,其配置如下:

  • rpcuser:user
  • rpcpassword:123456
  • rpcport:8332

那么可以使用如下的代码来实例化RpcClient:

代码语言:javascript
复制
import omnitool.RpcClient;

RpcClient client = new RpcClient(
    "http://user:123456@127.0.0.1:8332"       /*节点RPC API的URL*/
  );

使用RpcClient的call()方法可以调用Bitcoin层和omni层的所有RPC API。例如,使用listunspent调用来获取本地节点中指定地址的utxo:

代码语言:javascript
复制
//import java.util.Map;

Map[] unspents = client.call(
  Map[].class,                              /*返回结果类型*/
  "listunspent",                            /*RPC API名称*/
  6,                                        /*最小确认数*/
  999999,                                   /*最大确认数*/
  new String[]{"mgnucj8nYqdrPFh2JfZSB1NmUThUGnmsqe"}    /*地址清单*/  
);
for(Object unspent: unspents) {
  System.out.printf("txid: %s\n",(String)unspent.get("txid"));
}

call()方法的返回结果对应于RPC API的JSON响应中的result字段,其类型取决于我们传入的第一个参数。

call()方法的第一个参数声明方法返回的结果类型的Class对象,方法会将RPC API的JSON响应中的result字段解码为该参数指定的类型。通常我们都可以使用MapMap[]来对应JSON响应中的result字段的内容,例如上例所示。这种处理方式可以适应不断变化中的RPC API,但从结果中提取数据时,不得不小心处理类型转换的问题。

call()方法的第二个参数声明要调用的RPC API方法名,从第三个参数开始的其他参数则表示所指定的RPC API方法的参数。

2.1 定义自己的结果类

可选地,也可以自己定义一个类来简化从call()方法的返回结果中提取数据的难度。例如,对于上面的示例,我们可以定义一个Unspent类来描述listupsent响应中的JSON对象(不需要定义所有的字段,按自己的需求选择):

代码语言:javascript
复制
class Unspent{
  public String txid;
  public long vout;
  public String account;
  public String scriptPubKey;
  public double amount;
  public long confirmations;
}

那么我们可以按如下的方式调用RpcClient:

代码语言:javascript
复制
Unspent[] unspents = client.call(
  Unspent[].class,                          /*返回结果类型*/
  "listunspent",                            /*RPC API方法名*/
  6,                                        /*最小确认数*/
  999999,                                   /*最大确认数*/
  new String[]{"mgnucj8nYqdrPFh2JfZSB1NmUThUGnmsqe"}    /*地址清单*/  
);
for(Object unspent: unspents) {
  System.out.printf("txid: %s\n",unspent.txid);
  System.out.printf("vout: %d\n",unspent.vout);
  System.out.printf("amount:%f\n",unspent.amount);
}

显然,定义自己的结果类可以将RPC API的JSON响应直接反序列化到指定的类型,对于操作复杂响应结果会很有帮助。但比特币和Omni层的RPC API不仅在动态演化中,而且有些JSON响应的结构本身就是动态的,因此往往还需要结合使用前面更通用的MapMap[]类型。

2.2 Omni层RPC API

OmniCore节点在比特币原有的RPC接口之外,扩充了额外的接口用来操作Omni层的数据,这些扩展的RPC接口采用omni_前缀以区隔于Bitcoin的原有RPC接口。

例如,获取某个地址的USDT代币余额需要使用Omni层的omni_getbalance调用,下面的代码获取地址1EXoDusjGwvnjZUyKkxZ4UHEf77z6A5S4P的USDT(资产ID:31)余额:

代码语言:javascript
复制
Map[] balances = client.call(
  Map[].class,                                /*返回结果类型*/
  "omni_getbalance"                           /*Omni RPC API方法名*/
  "1EXoDusjGwvnjZUyKkxZ4UHEf77z6A5S4P",       /*账户地址*/
  31                                          /*Omni资产ID:USDT=31*/
);
for(Map b:balances){
  System.out.printf("balance: %s\n",(String)b.balance);
}

类似的,可以使用omni_send调用来执行简单的USDT转账。例如,下面的代码从地址3M9qvHKtgARhqcMtM5cRT9VaiDJ5PSfQGY向地址37FaKponF7zqoMLUjEiko25pDiuVH5YLEa转入100.0个USDT代币:

代码语言:javascript
复制
String txid = client.call(
  String.class,                               /*返回结果类型*/
  "omni_send",                                /*RPC API方法名*/
  "3M9qvHKtgARhqcMtM5cRT9VaiDJ5PSfQGY",       /*代币转出地址*/
  "37FaKponF7zqoMLUjEiko25pDiuVH5YLEa",       /*代币转入地址*/
  31,                                         /*代币ID:USDT*/
  "100.00"                                    /*转移的代币数量*/
);
System.out.printf("tx hash => %s\n",txid);

开发包中的demo/RpcClientDemo.java示例代码使用RpcClient完整演示了在Omni层的代币发行与转账功能,如果你计划搭建自己的Omni Core节点,相信这个示例会有很大帮助。

3、ToolKit类使用说明

如果不愿意搭建自己的Omni Core节点,而是希望基于第三方API为自己的Java应用增加对Omni Layer/USDT的支持,那么最简单的方法是使用离线交易的入口类ToolKit

ToolKit类的主要作用是创建并广播Omni代币或比特币转账裸交易,它的基本使用步骤如下:

  • 创建一个ToolKit实例
  • 使用AddKey()方法将必要的私钥加入该ToolKit实例,例如转出地址的私钥,因为ToolKit需要利用私钥对裸交易进行签名
  • 使用SendOmnicoin()方法生成并广播Omni代币转账裸交易,或者使用SendBitcoin()方法生成并广播比特币转账裸交易
3.1 Omni/USDT代币转账

使用ToolKit实现的Omni/USDT代币转账示例代码如下,说明见注释:

代码语言:javascript
复制
import omnitool.*;

String network = "main";                         
ToolKit kit = new ToolKit(
  network,                                      /*接入的网络*/
  new KeyStoreMemory(),                         /*使用内存密钥库*/
  new UtxoCollectorSmartbit(network),           /*使用云端Utxo采集器*/
  new UtxoSelectorDefault(),                    /*使用默认策略Utxo选择器*/
  new BroadcasterSmartbit(network)              /*使用云端裸交易广播器*/
);
String privHex = "4aec8e45106....00d5c5a05b";   /*私钥:16进制字符串*/            
kit.addKey(privHex);                            /*将私钥加入ToolKit*/

String from = kit.getKeyStore()
                 .getByKey(privHex).address;    /*私钥对应的地址作为发起账号*/
String to = "1GxX5tQR1C.....x2zbdj4mMuDcWR";    /*接收地址*/                    

String txid = kit.sendOmnicoin(
  from,                                         /*发送方地址,私钥必须已经加入钱包*/
  to,                                           /*接收方地址*/
  31,                                           /*转账代币ID,USDT=31*/
  10000                                         /*转账代币数量,调整为最小单位计量的整数*/
  null,                                         /*比特币手续费支付地址,私钥必须已加入ToolKit*/  
  546,                                          /*向接收方发送的流通比特币,单位:satoshi*/
  1000,                                         /*交易手续费,单位:satoshi*/ 
  true                                          /*是否广播*/
);

System.out.printf("txid => %s\n",txid);         /*打印交易哈希*/  

注意:

  • ToolKit实例利用钱包中的私钥生成地址列表,并利用这些地址从第三方服务获取utxo信息。 因此需要钱包中 的私钥对应地址在链上有utxo存在,ToolKit对象才能够成功构造并签名裸交易。
  • 转账目标地址应当与创建Toolkit对象时指定的网络一致,例如主网的p2pkh地址,前缀应当为1
3.2 指定Omni交易的手续费支付地址

在Omni协议层不需要支付交易手续费,但是Omni交易所嵌入的比特币交易依然需要支付手续费。当sendOmnicoin()方法的手续费支付地址设置为null时,将使用发送方地址支付比特币交易手续费。当你的Java应用需要实现多账户归集功能时,使用统一的手续费支付地址会更容易管理一些。

例如,下面的代码使用地址35stX1w6LKHj7hGHz6GVNzXZCdUhAeqDb6支付Omni交易的手续费:

代码语言:javascript
复制
String txid = kit.sendOmnicoin(
    from,                                     /*发送方地址,私钥必须已加入ToolKit*/
    to,                                       /*接收方地址*/
    31,                                       /*转账OMNI代币ID,31:USDT*/
    10000,                                    /*转账OMNI代币数量,已调整至最小单位*/
    "35stX1w6LKH...CdUhAeqDb6"                /*交易手续费支付地址,私钥必须已加入ToolKit*/
    546,                                      /*向接收方发送的流通比特币,单位:satoshi*/
    1000,                                     /*交易手续费,单位:satoshi*/ 
    true                                      /*是否广播*/
  );

注意:

  • 即使指定了余额充足的手续费支付地址,Omni交易的发送方依然必须有微量的比特币 余额(546 SATOSHI),因为Omni协议需要交易发送方至少有一个可用UTXO。
  • 手续费支付地址同时也是找零地址,多余的比特币将返回至该地址
3.3 指定Omni交易的比特币转账数量

由于Omni交易要求发送方必须有可用的UTXO,因此为了便于接收Omni代币的地址可以继续流通所持有的Omni代币,sendOmnicoin()方法需要至少向接收方地址转入546 SATOSHI的比特币,可以在调用该方法时修改这个默认数值。

例如,下面的代码转入接收方1000个SATOSHI:

代码语言:javascript
复制
String txid = kit.SendOmnicoin(
    from,                                     /*发送方地址,私钥必须已加入ToolKit*/
    to,                                       /*接收方地址*/
    31,                                       /*转账OMNI代币ID,31:USDT*/
    10000,                                    /*转账OMNI代币数量,已调整至最小单位*/
    fundAddr: "35stX1w6LKH...CdUhAeqDb6"      /*交易手续费支付地址,私钥必须已加入ToolKit*/
    1000,                                     /*向接收方发送的流通比特币,单位:satoshi*/
    1000,                                     /*交易手续费,单位:satoshi*/ 
    true                                      /*是否广播*/
  );
3.4 指定Omni交易的手续费

sendOmnicoin()方法可以设置交易手续费,例如设置为3000 SATOSHI

代码语言:javascript
复制
String txid = kit.SendOmnicoin(
    from,                                     /*发送方地址,私钥必须已加入ToolKit*/
    to,                                       /*接收方地址*/
    31,                                       /*转账OMNI代币ID,31:USDT*/
    10000,                                    /*转账OMNI代币数量*/
    fundAddr: "35stX1w6LKH...CdUhAeqDb6"      /*交易手续费支付地址,私钥必须已加入ToolKit*/
    1000,                                     /*向接收方发送的流通比特币,单位:satoshi*/
    3000,                                     /*交易手续费,单位:SATOSHI*/
    true                                      /*是否广播*/
  );
3.5 仅生成Omni裸交易但不广播

有时可能只需要生成Omni转账裸交易但并不需要广播出去,可以将sendOmnicoin()方法的最后一个参数设置为false来取消广播,这时将返回生成的裸交易。例如:

代码语言:javascript
复制
String rawtx = kit.SendOmnicoin(
    from,                                     /*发送方地址,私钥必须已加入ToolKit*/
    to,                                       /*接收方地址*/
    31,                                       /*转账OMNI代币ID,31:USDT*/
    10000,                                    /*转账OMNI代币数量,已调整至最小单位*/
    fundAddr: "35stX1w6LKH...CdUhAeqDb6"      /*交易手续费支付地址,私钥必须已加入ToolKit*/
    1000,                                     /*向接收方发送的流通比特币,单位:satoshi*/
    3000,                                     /*交易手续费,单位:SATOSHI*/
    false                                     /*是否广播*/
  );
System.out.println(rawtx);                    /*打印裸交易内容*/
3.6 比特币转账

OmniTool.Java也支持比特币转账裸交易的生成与广播。

例如,下面的代码从ToolKit的某个地址向其他地址转10000 SATOSHI

代码语言:javascript
复制
String privHex = "4aec8e45106....00d5c5a05b";     /*私钥:16进制字符串*/            
kit.addKey(privHex);                              /*将私钥加入ToolKit*/

String from = kit.getKeyStore()
                 .getByKey(privHex).address;      /*私钥对应的地址作为发起账号*/
String to = "1GxX5tQR1C.....x2zbdj4mMuDcWR";      /*接收地址*/                    

String txid = kit.sendBitcoin(
    from,                                         /*发送方地址*/
    to,                                           /*接收方地址*/
    10000,                                        /*转账比特币数量,单位:SATOSHI*/
    1500,                                         /*手续费,单位:SATOSHI*/
    null,                                         /*找零地址*/
    true                                          /*是否广播*/
  );                       

当找零地址设置为null时,SendBitcoin()方法使用发送方地址作为找零地址。下面的代码创建一个新地址接收找零:

代码语言:javascript
复制
String changeAddr = kit.newAddress();             /*创建新地址*/
String txid = kit.sendBitcoin(
    from,                                         /*发送方地址*/
    to,                                           /*接收方地址*/
    10000,                                        /*转账比特币数量,单位:SATOSHI*/
    1500,                                         /*手续费,单位:SATOSHI*/
    changeAddr,                                   /*找零地址*/
    true                                          /*是否广播*/
  );                       

类似的,当只需要生成裸交易而不希望广播时,可以设置最后一个参数为false

4、UTXO采集器

OmniTool.Java使用接口UtxoCollector来约定UTXO的采集功能。该接口的实现需要支持获取指定地址的候选UTXO集合,可指定多个地址。

接口方法:

代码语言:javascript
复制
UtxoBag collect(String[] addresses);               /*提取并返回候选UTXO集合*/

参数addresses用来声明要收集UTXO的地址清单。

当前实现类:

  • UtxoCollectorSmartbit:基于云端第三方API实现的Utxo采集器
  • UtxoCollectorRpc:基于omnicored节点RPC API实现的Utxo采集器

例如,下面的代码使用UtxoCollectorSmartbit获取测试链某个指定地址的UTXO:

代码语言:javascript
复制
UtxoCollector collector = new UtxoCollectorSmartbit(
    "main"                                          /*主链*/
  );
String[] addresses = new String[]{"1C3TZ...brS2xHM"};
UtxoBag collected = collector.Collect(
    addresses                                       /*地址清单*/
  );

5、UTXO选择器

OmniTool.Java使用接口UtxoSelector来约定UTXO的筛选策略。该接口的实现需要根据目标金额从候选UTXO中选择可用UTXO,并返回新的UtxoBag实例。

接口方法:

代码语言:javascript
复制
UtxoBag select(long target,UtxoBag collected);       /*选择可消费UTXO,返回UtxoBag对象*/

参数target声明要达成的最低金额目标,单位:SATOSHI。

参数collected是候选的utxo集合,通常是UtxoCollector的collect()调用返回的结果。

当前实现类:

  • UtxoSelectorDefault:选择不少于6个确认的未消费UTXO

例如下面的代码使用UtxoSelectorDefault实例从候选UTXO中删选出至少100000 SATOSHI的UTXO:

代码语言:javascript
复制
//collected表示候选UTXO集合,来自Utxo采集器的collect()调用结果

UtxoSelector selector = new UtxoSelectorDefault();
UtxoBag selected = selector.select(
    100000,                                           /*最低目标金额*/
    collected                                         /*候选UTXO集合*/
  );
System.out.printf("total:%d\n":selected.getTotal());  /*打印输出选中utxo总额*/

考虑到UTXO的不可分割性,筛选出的若干UTXO的总和,有可能超过目标金额。可以使用UtxoBag实例的getTotal()方法查看集合中的UTXO总额,如上。

6、裸交易广播器

OmniTool.Java使用Broadcaster接口约定裸交易广播的功能规格。该接口的实现应当将裸交易广播到Omni/Btc网络中。

接口方法:

代码语言:javascript
复制
String broadcast(String rawtx);                     /*广播裸交易*/

参数rawtx用来声明要广播的裸交易,类型为16进制字符串。

当前实现类:

  • BroadcasterSmartbit
  • BroadcasterRpc

例如,下面的代码使用BroadcasterSmartbit将裸交易码流广播到Omni/Btc网络中:

代码语言:javascript
复制
Broadcaster broadcaster = new BroadcasterSmartbit(
    "testnet"                                       /*测试链*/
  );
String txid = broadcaster.broadcast(
    "01000000011da9283b4...59f58488ac00000000"      /*裸交易*/
  );

7、密钥存储接口

OmniTool.Java使用KeyStore约定密钥存储的功能规格。

接口方法:

代码语言:javascript
复制
bool add(KeyStoreItem item);                        /*存入密钥*/
KeyStoreItem[] list();                              /*浏览全部密钥*/
KeyStoreItem getByKey();                            /*查询指定16进制私钥对应的密钥信息*/  
KeyStoreItem getByWif();                            /*查询指定WIF格式私钥对应的密钥信息*/
KeyStoreItem getByAddress();                        /*查询指定地址对应的密钥信息*/
KeyStoreItem getByScript();                         /*查询指定公钥脚本对应的密钥信息*/

KeyStore当前实现类有两个:

  • KeyStoreMemory:基于内存字典实现,没有持久化能力,适合调试
  • KeyStoreSql:基于Sql数据库实现,适合作为生产环境密钥存储的参考实现

密钥存储实例的主要功能就是为ToolKit提供密钥存储和查询能力。下面的代码使用KeyStoreSql来启动ToolKit,生成几个不同类型的地址,导入16进制私钥和WIF私钥,然后进行查询:

代码语言:javascript
复制
ToolKit kit = new ToolKit(
    "testnet",
    new KeyStoreSqlite("testnet.wallet"),
    null,null,null
  );

String addr1 = kit.newAddress("SEGWIT-P2SH");         /*生成隔离见证p2sh地址*/
String addr2 = kit.newAddress("SEGWIT");              /*生成隔离见证地址*/
String addr3 = kit.newAddress("P2PKH");               /*生成P2PKH地址,默认选项*/
String addr4 = kit.addKey(                            /*导入16进制私钥*/
    "4aec8e45106....00d5c5a05b",
    "SEGWIT-P2SH"                                     /*使用该私钥的SEGWIT-P2SH地址*/  
  );  
String addr5 = kit.addWif(                            /*导入WIF格式的私钥*/
    "cNJFgo1driF...SkdcF6JXXwHMm"                                         
  );                                                  /*默认使用私钥的P2PKH地址*/
  
KeyStoreItem[] items = kit.list();                    /*返回全部密钥记录*/
for(KeyStoreItem item:items)
{
  System.out.printf("key => %s\n",item.key);
  System.out.printf("wif => %s\n",item.wif);
  System.out.printf("address => %s\n",item.address);
  System.out.printf("script => %s\n",item.script);
}  
  
KeyStoreItem item = kit.getByAddress(addr1);          /*查询指定地址的密钥记录*/
System.out.printf("key => %s\n",item.key);  

下载地址:Omni/USDT Java开发包 - 汇智网

(adsbygoogle = window.adsbygoogle || []).push({});

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1、开发包概述
  • 2、RpcClient类使用说明
    • 2.1 定义自己的结果类
      • 2.2 Omni层RPC API
      • 3、ToolKit类使用说明
        • 3.1 Omni/USDT代币转账
          • 3.2 指定Omni交易的手续费支付地址
            • 3.3 指定Omni交易的比特币转账数量
              • 3.4 指定Omni交易的手续费
                • 3.5 仅生成Omni裸交易但不广播
                  • 3.6 比特币转账
                  • 4、UTXO采集器
                  • 5、UTXO选择器
                  • 6、裸交易广播器
                  • 7、密钥存储接口
                  相关产品与服务
                  区块链
                  云链聚未来,协同无边界。腾讯云区块链作为中国领先的区块链服务平台和技术提供商,致力于构建技术、数据、价值、产业互联互通的区块链基础设施,引领区块链底层技术及行业应用创新,助力传统产业转型升级,推动实体经济与数字经济深度融合。
                  领券
                  问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档