java json 转map_Java对接Omni/USDT教程「OmniTool.Java」
OmniTool.Java開發(fā)包適用于為Java應用快速增加對Omni/USDT數(shù)字資產(chǎn)的支持能力,即支持使用自有Omni節(jié)點的應用場景,也支持基于第三方API服務和離線裸交易的輕量級部署場景。官方下載地址:http://sc.hubwiz.com/codebag/omni-java-lib/。
1、開發(fā)包概述
OmniTool.Java開發(fā)包主要包含以下特性:
- 完善的Bitcoin/Omni Layer RPC API封裝
- 支持利用自有節(jié)點或第三方服務獲取指定地址的比特幣utxo集合
- 支持離線生成Omni代幣或比特幣轉(zhuǎn)賬裸交易
- 支持利用自有節(jié)點或第三方服務廣播裸交易
OmniTool.Java支持本地部署的Omnicored節(jié)點,也支持第三方服務提供的開放API,要增加新的第三方服務也非常簡單,只需要參考代碼實現(xiàn)如下接口:
- IUtxoCollector:Utxo采集器
- IBroadcaster:裸交易廣播器
OmniTool.Java軟件包當前版本1.0.0,主要類/接口及關(guān)系如下圖所示:
OmniTool.Java軟件包主要代碼文件清單請訪問官網(wǎng):http://sc.hubwiz.com/codebag/omni-java-lib/
2、RpcClient類使用說明
RpcClient類封裝了比特幣以及Omni Layer的RPC API接口協(xié)議。創(chuàng)建RpcClient對象時,需要傳入包含有效身份信息的節(jié)點RPC URL。例如,假設(shè)安裝在本機的omnicored節(jié)點軟件接入主網(wǎng),其配置如下:
- rpcuser:user
- rpcpassword:123456
- rpcport:8332
那么可以使用如下的代碼來實例化RpcClient:
import omnitool.RpcClient;RpcClient client = new RpcClient( "http://user:123456@127.0.0.1:8332" /*節(jié)點RPC API的URL*/ );使用RpcClient的call()方法可以調(diào)用Bitcoin層和omni層的所有RPC API。例如,使用listunspent調(diào)用來獲取本地節(jié)點中指定地址的utxo:
//import java.util.Map;Map[] unspents = client.call( Map[].class, /*返回結(jié)果類型*/ "listunspent", /*RPC API名稱*/ 6, /*最小確認數(shù)*/ 999999, /*最大確認數(shù)*/ new String[]{"mgnucj8nYqdrPFh2JfZSB1NmUThUGnmsqe"} /*地址清單*/ );for(Object unspent: unspents) { System.out.printf("txid: %s",(String)unspent.get("txid"));}call()方法的返回結(jié)果對應于RPC API的JSON響應中的result字段,其類型取決于我們傳入的第一個參數(shù)。
call()方法的第一個參數(shù)聲明方法返回的結(jié)果類型的Class對象,方法會將RPC API的JSON響應中的result字段解碼為該參數(shù)指定的類型。通常我們都可以使用Map或Map[]來對應JSON響應中的result字段的內(nèi)容,例如上例所示。這種處理方式可以適應不斷變化中的RPC API,但從結(jié)果中提取數(shù)據(jù)時,不得不小心處理類型轉(zhuǎn)換的問題。
call()方法的第二個參數(shù)聲明要調(diào)用的RPC API方法名,從第三個參數(shù)開始的其他參數(shù)則表示所指定的RPC API方法的參數(shù)。
2.1 定義自己的結(jié)果類
可選地,也可以自己定義一個類來簡化從call()方法的返回結(jié)果中提取數(shù)據(jù)的難度。例如,對于上面的示例,我們可以定義一個Unspent類來描述listupsent響應中的JSON對象(不需要定義所有的字段,按自己的需求選擇):
class Unspent{ public String txid; public long vout; public String account; public String scriptPubKey; public double amount; public long confirmations;}那么我們可以按如下的方式調(diào)用RpcClient:
Unspent[] unspents = client.call( Unspent[].class, /*返回結(jié)果類型*/ "listunspent", /*RPC API方法名*/ 6, /*最小確認數(shù)*/ 999999, /*最大確認數(shù)*/ new String[]{"mgnucj8nYqdrPFh2JfZSB1NmUThUGnmsqe"} /*地址清單*/ );for(Object unspent: unspents) { System.out.printf("txid: %s",unspent.txid); System.out.printf("vout: %d",unspent.vout); System.out.printf("amount:%f",unspent.amount);}顯然,定義自己的結(jié)果類可以將RPC API的JSON響應直接反序列化到指定的類型,對于操作復雜響應結(jié)果會很有幫助。但比特幣和Omni層的RPC API不僅在動態(tài)演化中,而且有些JSON響應的結(jié)構(gòu)本身就是動態(tài)的,因此往往還需要結(jié)合使用前面更通用的Map或Map[]類型。
2.2 Omni層RPC API
OmniCore節(jié)點在比特幣原有的RPC接口之外,擴充了額外的接口用來操作Omni層的數(shù)據(jù),這些擴展的RPC接口采用omni_前綴以區(qū)隔于Bitcoin的原有RPC接口。
例如,獲取某個地址的USDT代幣余額需要使用Omni層的omni_getbalance調(diào)用,下面的代碼獲取地址1EXoDusjGwvnjZUyKkxZ4UHEf77z6A5S4P的USDT(資產(chǎn)ID:31)余額:
Map[] balances = client.call( Map[].class, /*返回結(jié)果類型*/ "omni_getbalance" /*Omni RPC API方法名*/ "1EXoDusjGwvnjZUyKkxZ4UHEf77z6A5S4P", /*賬戶地址*/ 31 /*Omni資產(chǎn)ID:USDT=31*/);for(Map b:balances){ System.out.printf("balance: %s",(String)b.balance);}類似的,可以使用omni_send調(diào)用來執(zhí)行簡單的USDT轉(zhuǎn)賬。例如,下面的代碼從地址3M9qvHKtgARhqcMtM5cRT9VaiDJ5PSfQGY向地址37FaKponF7zqoMLUjEiko25pDiuVH5YLEa轉(zhuǎn)入100.0個USDT代幣:
String txid = client.call( String.class, /*返回結(jié)果類型*/ "omni_send", /*RPC API方法名*/ "3M9qvHKtgARhqcMtM5cRT9VaiDJ5PSfQGY", /*代幣轉(zhuǎn)出地址*/ "37FaKponF7zqoMLUjEiko25pDiuVH5YLEa", /*代幣轉(zhuǎn)入地址*/ 31, /*代幣ID:USDT*/ "100.00" /*轉(zhuǎn)移的代幣數(shù)量*/);System.out.printf("tx hash => %s",txid);開發(fā)包中的demo/RpcClientDemo.java示例代碼使用RpcClient完整演示了在Omni層的代幣發(fā)行與轉(zhuǎn)賬功能,如果你計劃搭建自己的Omni Core節(jié)點,相信這個示例會有很大幫助。
3、ToolKit類使用說明
如果不愿意搭建自己的Omni Core節(jié)點,而是希望基于第三方API為自己的Java應用增加對Omni Layer/USDT的支持,那么最簡單的方法是使用離線交易的入口類ToolKit。
ToolKit類的主要作用是創(chuàng)建并廣播Omni代幣或比特幣轉(zhuǎn)賬裸交易,它的基本使用步驟如下:
- 創(chuàng)建一個ToolKit實例
- 使用AddKey()方法將必要的私鑰加入該ToolKit實例,例如轉(zhuǎn)出地址的私鑰,因為ToolKit需要利用私鑰對裸交易進行簽名
- 使用SendOmnicoin()方法生成并廣播Omni代幣轉(zhuǎn)賬裸交易,或者使用SendBitcoin()方法生成并廣播比特幣轉(zhuǎn)賬裸交易
3.1 Omni/USDT代幣轉(zhuǎn)賬
使用ToolKit實現(xiàn)的Omni/USDT代幣轉(zhuǎn)賬示例代碼如下,說明見注釋:
import omnitool.*;String network = "main"; ToolKit kit = new ToolKit( network, /*接入的網(wǎng)絡(luò)*/ new KeyStoreMemory(), /*使用內(nèi)存密鑰庫*/ 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; /*私鑰對應的地址作為發(fā)起賬號*/String to = "1GxX5tQR1C.....x2zbdj4mMuDcWR"; /*接收地址*/ String txid = kit.sendOmnicoin( from, /*發(fā)送方地址,私鑰必須已經(jīng)加入錢包*/ to, /*接收方地址*/ 31, /*轉(zhuǎn)賬代幣ID,USDT=31*/ 10000 /*轉(zhuǎn)賬代幣數(shù)量,調(diào)整為最小單位計量的整數(shù)*/ null, /*比特幣手續(xù)費支付地址,私鑰必須已加入ToolKit*/ 546, /*向接收方發(fā)送的流通比特幣,單位:satoshi*/ 1000, /*交易手續(xù)費,單位:satoshi*/ true /*是否廣播*/);System.out.printf("txid => %s",txid); /*打印交易哈希*/注意:
- ToolKit實例利用錢包中的私鑰生成地址列表,并利用這些地址從第三方服務獲取utxo信息。 因此需要錢包中 的私鑰對應地址在鏈上有utxo存在,ToolKit對象才能夠成功構(gòu)造并簽名裸交易。
- 轉(zhuǎn)賬目標地址應當與創(chuàng)建Toolkit對象時指定的網(wǎng)絡(luò)一致,例如主網(wǎng)的p2pkh地址,前綴應當為1。
3.2 指定Omni交易的手續(xù)費支付地址
在Omni協(xié)議層不需要支付交易手續(xù)費,但是Omni交易所嵌入的比特幣交易依然需要支付手續(xù)費。當sendOmnicoin()方法的手續(xù)費支付地址設(shè)置為null時,將使用發(fā)送方地址支付比特幣交易手續(xù)費。當你的Java應用需要實現(xiàn)多賬戶歸集功能時,使用統(tǒng)一的手續(xù)費支付地址會更容易管理一些。
例如,下面的代碼使用地址35stX1w6LKHj7hGHz6GVNzXZCdUhAeqDb6支付Omni交易的手續(xù)費:
String txid = kit.sendOmnicoin( from, /*發(fā)送方地址,私鑰必須已加入ToolKit*/ to, /*接收方地址*/ 31, /*轉(zhuǎn)賬OMNI代幣ID,31:USDT*/ 10000, /*轉(zhuǎn)賬OMNI代幣數(shù)量,已調(diào)整至最小單位*/ "35stX1w6LKH...CdUhAeqDb6" /*交易手續(xù)費支付地址,私鑰必須已加入ToolKit*/ 546, /*向接收方發(fā)送的流通比特幣,單位:satoshi*/ 1000, /*交易手續(xù)費,單位:satoshi*/ true /*是否廣播*/ );注意:
- 即使指定了余額充足的手續(xù)費支付地址,Omni交易的發(fā)送方依然必須有微量的比特幣 余額(546 SATOSHI),因為Omni協(xié)議需要交易發(fā)送方至少有一個可用UTXO。
- 手續(xù)費支付地址同時也是找零地址,多余的比特幣將返回至該地址
3.3 指定Omni交易的比特幣轉(zhuǎn)賬數(shù)量
由于Omni交易要求發(fā)送方必須有可用的UTXO,因此為了便于接收Omni代幣的地址可以繼續(xù)流通所持有的Omni代幣,sendOmnicoin()方法需要至少向接收方地址轉(zhuǎn)入546 SATOSHI的比特幣,可以在調(diào)用該方法時修改這個默認數(shù)值。
例如,下面的代碼轉(zhuǎn)入接收方1000個SATOSHI:
String txid = kit.SendOmnicoin( from, /*發(fā)送方地址,私鑰必須已加入ToolKit*/ to, /*接收方地址*/ 31, /*轉(zhuǎn)賬OMNI代幣ID,31:USDT*/ 10000, /*轉(zhuǎn)賬OMNI代幣數(shù)量,已調(diào)整至最小單位*/ fundAddr: "35stX1w6LKH...CdUhAeqDb6" /*交易手續(xù)費支付地址,私鑰必須已加入ToolKit*/ 1000, /*向接收方發(fā)送的流通比特幣,單位:satoshi*/ 1000, /*交易手續(xù)費,單位:satoshi*/ true /*是否廣播*/ );3.4 指定Omni交易的手續(xù)費
sendOmnicoin()方法可以設(shè)置交易手續(xù)費,例如設(shè)置為3000 SATOSHI:
String txid = kit.SendOmnicoin( from, /*發(fā)送方地址,私鑰必須已加入ToolKit*/ to, /*接收方地址*/ 31, /*轉(zhuǎn)賬OMNI代幣ID,31:USDT*/ 10000, /*轉(zhuǎn)賬OMNI代幣數(shù)量*/ fundAddr: "35stX1w6LKH...CdUhAeqDb6" /*交易手續(xù)費支付地址,私鑰必須已加入ToolKit*/ 1000, /*向接收方發(fā)送的流通比特幣,單位:satoshi*/ 3000, /*交易手續(xù)費,單位:SATOSHI*/ true /*是否廣播*/ );3.5 僅生成Omni裸交易但不廣播
有時可能只需要生成Omni轉(zhuǎn)賬裸交易但并不需要廣播出去,可以將sendOmnicoin()方法的最后一個參數(shù)設(shè)置為false來取消廣播,這時將返回生成的裸交易。例如:
String rawtx = kit.SendOmnicoin( from, /*發(fā)送方地址,私鑰必須已加入ToolKit*/ to, /*接收方地址*/ 31, /*轉(zhuǎn)賬OMNI代幣ID,31:USDT*/ 10000, /*轉(zhuǎn)賬OMNI代幣數(shù)量,已調(diào)整至最小單位*/ fundAddr: "35stX1w6LKH...CdUhAeqDb6" /*交易手續(xù)費支付地址,私鑰必須已加入ToolKit*/ 1000, /*向接收方發(fā)送的流通比特幣,單位:satoshi*/ 3000, /*交易手續(xù)費,單位:SATOSHI*/ false /*是否廣播*/ );System.out.println(rawtx); /*打印裸交易內(nèi)容*/3.6 比特幣轉(zhuǎn)賬
OmniTool.Java也支持比特幣轉(zhuǎn)賬裸交易的生成與廣播。
例如,下面的代碼從ToolKit的某個地址向其他地址轉(zhuǎn)10000 SATOSHI:
String privHex = "4aec8e45106....00d5c5a05b"; /*私鑰:16進制字符串*/ kit.addKey(privHex); /*將私鑰加入ToolKit*/String from = kit.getKeyStore() .getByKey(privHex).address; /*私鑰對應的地址作為發(fā)起賬號*/String to = "1GxX5tQR1C.....x2zbdj4mMuDcWR"; /*接收地址*/ String txid = kit.sendBitcoin( from, /*發(fā)送方地址*/ to, /*接收方地址*/ 10000, /*轉(zhuǎn)賬比特幣數(shù)量,單位:SATOSHI*/ 1500, /*手續(xù)費,單位:SATOSHI*/ null, /*找零地址*/ true /*是否廣播*/ );當找零地址設(shè)置為null時,SendBitcoin()方法使用發(fā)送方地址作為找零地址。下面的代碼創(chuàng)建一個新地址接收找零:
String changeAddr = kit.newAddress(); /*創(chuàng)建新地址*/String txid = kit.sendBitcoin( from, /*發(fā)送方地址*/ to, /*接收方地址*/ 10000, /*轉(zhuǎn)賬比特幣數(shù)量,單位:SATOSHI*/ 1500, /*手續(xù)費,單位:SATOSHI*/ changeAddr, /*找零地址*/ true /*是否廣播*/ );類似的,當只需要生成裸交易而不希望廣播時,可以設(shè)置最后一個參數(shù)為false。
4、UTXO采集器
OmniTool.Java使用接口UtxoCollector來約定UTXO的采集功能。該接口的實現(xiàn)需要支持獲取指定地址的候選UTXO集合,可指定多個地址。
接口方法:
UtxoBag collect(String[] addresses); /*提取并返回候選UTXO集合*/參數(shù)addresses用來聲明要收集UTXO的地址清單。
當前實現(xiàn)類:
- UtxoCollectorSmartbit:基于云端第三方API實現(xiàn)的Utxo采集器
- UtxoCollectorRpc:基于omnicored節(jié)點RPC API實現(xiàn)的Utxo采集器
例如,下面的代碼使用UtxoCollectorSmartbit獲取測試鏈某個指定地址的UTXO:
UtxoCollector collector = new UtxoCollectorSmartbit( "main" /*主鏈*/ );String[] addresses = new String[]{"1C3TZ...brS2xHM"};UtxoBag collected = collector.Collect( addresses /*地址清單*/ );5、UTXO選擇器
OmniTool.Java使用接口UtxoSelector來約定UTXO的篩選策略。該接口的實現(xiàn)需要根據(jù)目標金額從候選UTXO中選擇可用UTXO,并返回新的UtxoBag實例。
接口方法:
UtxoBag select(long target,UtxoBag collected); /*選擇可消費UTXO,返回UtxoBag對象*/參數(shù)target聲明要達成的最低金額目標,單位:SATOSHI。
參數(shù)collected是候選的utxo集合,通常是UtxoCollector的collect()調(diào)用返回的結(jié)果。
當前實現(xiàn)類:
- UtxoSelectorDefault:選擇不少于6個確認的未消費UTXO
例如下面的代碼使用UtxoSelectorDefault實例從候選UTXO中刪選出至少100000 SATOSHI的UTXO:
//collected表示候選UTXO集合,來自Utxo采集器的collect()調(diào)用結(jié)果UtxoSelector selector = new UtxoSelectorDefault();UtxoBag selected = selector.select( 100000, /*最低目標金額*/ collected /*候選UTXO集合*/ );System.out.printf("total:%d":selected.getTotal()); /*打印輸出選中utxo總額*/考慮到UTXO的不可分割性,篩選出的若干UTXO的總和,有可能超過目標金額。可以使用UtxoBag實例的getTotal()方法查看集合中的UTXO總額,如上。
6、裸交易廣播器
OmniTool.Java使用Broadcaster接口約定裸交易廣播的功能規(guī)格。該接口的實現(xiàn)應當將裸交易廣播到Omni/Btc網(wǎng)絡(luò)中。
接口方法:
String broadcast(String rawtx); /*廣播裸交易*/參數(shù)rawtx用來聲明要廣播的裸交易,類型為16進制字符串。
當前實現(xiàn)類:
- BroadcasterSmartbit
- BroadcasterRpc
例如,下面的代碼使用BroadcasterSmartbit將裸交易碼流廣播到Omni/Btc網(wǎng)絡(luò)中:
Broadcaster broadcaster = new BroadcasterSmartbit( "testnet" /*測試鏈*/ );String txid = broadcaster.broadcast( "01000000011da9283b4...59f58488ac00000000" /*裸交易*/ );7、密鑰存儲接口
OmniTool.Java使用KeyStore約定密鑰存儲的功能規(guī)格。
接口方法:
bool add(KeyStoreItem item); /*存入密鑰*/KeyStoreItem[] list(); /*瀏覽全部密鑰*/KeyStoreItem getByKey(); /*查詢指定16進制私鑰對應的密鑰信息*/ KeyStoreItem getByWif(); /*查詢指定WIF格式私鑰對應的密鑰信息*/KeyStoreItem getByAddress(); /*查詢指定地址對應的密鑰信息*/KeyStoreItem getByScript(); /*查詢指定公鑰腳本對應的密鑰信息*/KeyStore當前實現(xiàn)類有兩個:
- KeyStoreMemory:基于內(nèi)存字典實現(xiàn),沒有持久化能力,適合調(diào)試
- KeyStoreSql:基于Sql數(shù)據(jù)庫實現(xiàn),適合作為生產(chǎn)環(huán)境密鑰存儲的參考實現(xiàn)
密鑰存儲實例的主要功能就是為ToolKit提供密鑰存儲和查詢能力。下面的代碼使用KeyStoreSql來啟動ToolKit,生成幾個不同類型的地址,導入16進制私鑰和WIF私鑰,然后進行查詢:
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",item.key); System.out.printf("wif => %s",item.wif); System.out.printf("address => %s",item.address); System.out.printf("script => %s",item.script);} KeyStoreItem item = kit.getByAddress(addr1); /*查詢指定地址的密鑰記錄*/System.out.printf("key => %s",item.key);下載地址:Omni/USDT Java開發(fā)包 - 匯智網(wǎng)
總結(jié)
以上是生活随笔為你收集整理的java json 转map_Java对接Omni/USDT教程「OmniTool.Java」的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: arraylist删除指定元素_面试官:
- 下一篇: tms570 can 接收大量数据_CA