Arweave Client
概述
goar client 实现了所有的 Arweave http 接口调用,开发者可以利用 goar client 方便的调用这些接口,获取到 Arweave 网络的基本信息,交易信息。
使用
安装
go get github.com/everFinance/goar
创建 goar client 实例
package main
import (
"github.com/everFinance/goar"
"time"
)
func main() {
arUrl := "https://arweave.net"
proxyUrl := "http://127.0.0.1:portNum"
cli := goar.NewClient(arUrl, proxyUrl)
}
说明:
arUrl
: Arweave 网关或者节点地址,通过调用网关或节点的接口就能获取到 Arweave 网络的所有相关信息,本例中我们填入的是 Arweave 官方提供的网关地址。proxyUrl
: 为可选参数,可以不传入,在网络情况不佳的时候可以设置该参数。cli
: 创建的 client 实例,通过调用该实例的方法可以获取到 Arweave 网络的各种信息。- 接下来介绍 client 中的方法时,我们默认已经创建了 cli 这个实例。
获取 Arweave 网络信息
info, err := cli.GetInfo()
if err != nil {
panic(err)
}
fmt.Println(info)
返回值:
{
"network": "arweave.N.1",
"version": 5,
"release": 52,
"height": 1003310,
"current": "WurQMcQD_f_YPDHi8fP7ClNebdLJTMCqU_50msl1jO47zVblGKfFjL5gazw-Tgu2",
"blocks": 1003311,
"peers": 25545,
"queue_length": 0,
"node_state_latency": 0
}
该方法返回的是 Arweave 网络的基本信息。包括版本号,区块高度,节点数量等。
获取全部节点
peers, err := cli.GetPeers()
if err != nil {
panic(err)
}
fmt.Println(peers)
返回值:
[
"198.54.132.54:55252",
"223.204.22.110:1984",
"207.53.233.64:1984",
"131.239.134.6:1984",
...............,
"176.9.24.56:1984",
"161.35.15.191:1984",
"157.230.2.154:1984",
"5.9.18.85:1984",
]
该方法将返回当前 Arweave 节点的 ip:protNum
。
获取交易元数据
arId := "sUfG7jvu7PBQptlSIxtl6t5zD9LBMxv66_uVAlBk8dU"
tx, err := cli.GetTransactionByID(arId)
if err != nil {
panic(err)
}
fmt.Println(tx)
返回值:
{
"format": 2,
"id": "sUfG7jvu7PBQptlSIxtl6t5zD9LBMxv66_uVAlBk8dU",
"last_tx": "qs7DSGzs55TDuu2J3rLjH2zv0CxikbWO8Cv6CopOoNUfskQ3vvwmu2muyBjAx-Gi",
"owner": "ybuxOeQh6PUQnz1t8h4-sZ1WMLWbq2r8xLaRgAofKimabNKUFW37UpaNXpLu-NCoPutYksFbh46RutWB3mxZaBFRwaWPHHg9qsvqUMrnQjmIAUom_Mkhewp-0o3SXl0PhaIlwLuUzJpQYBe2alZtnDSWLfEp6BP7is5th6KNeEq7_xGEPMSyxP6y6emEiYGAqpcnueM0NdDBcyjUmlmOrU4z-NHL_hBrSWvtD5hcuuaLvZPH9UCocWXyBBZ1gNnGsGEYBFu2bF_R6Ex3g_iY0MmdT0E52MldtkiiUQ9gFSffyUgf_WLyFDKtEkvytP2nqmyPuhouK2vehAcSsWVEdrw4469ccB-iiY4T5ACTRW9xnPGSiefcHjdS7DdnAxxL9PBl0dZPoJDR203Jwvamk7ekdquXBoVCvoxkER1bro7z5MHP9tRxT5VY_oqi9_O1cUGvZQ9gSlUedlsxbDClKhKpsGvJvOA8ecCuZszZLFJKpqkmkcHzJdlqcneVd4Kcnszb2Fw621r61VU8cXyF3mhk_7tRpmJM75wzSissCBq08eBaLeOhzYiNlA0rJFOBNT6uRASbPaPpF7WfvA5gRcHinPEdOdKXeQtS58-Z8TkD_kYYsL2G7-2pjeh1q9gdaCeff0OHwsLstFHTxgtjrZgi5PWk35_4sdEQalzTwYs",
"tags": [
{
"name": "Q29udGVudC1UeXBl",
"value": "aW1hZ2UvcG5n"
}
],
"target": "",
"quantity": "0",
"data": "",
"data_size": "324218",
"data_tree": [],
"data_root": "vwuJoWSU5UFmarPmtWNfXk8ccsb92LMfy8bHpSAjXIc",
"reward": "106343596",
"signature": "W1FIZlGnAHm3-gfEf7a3fNfI_MORpvqn6VpLn37A-TCGV98p5HlQ8BI7lLBpLkBaO7Pd6ol3k_ZCW36-FPREJtBAGiQsv9CZRDmR6ABKqR1Ib1vJF7qFTNAc3XNWfO03xdVvuQWgi9Vsjtrr0rGv15Fpt4GCiNXwLRhnaeIg6kknNvbpQRkTR_9siGk4WL3ci5dfR-T1Vq6ihAicI2wPtE23mVKMHooAPxRGXPX4X7FIxomFYQ7k5vXaFkO3JTfvuVb2kPq4P-xgtqBbkB_oPYyu0PGQgBngnXggu9E3YxsZsxWrzPcyvzFH1dl1h684EGk6Prberte3c2n0Mez8Ee9YYBPN-oF5FpA0de6YHj1GkO50PpUmSeEYivW5HPNhIAagjrmAez1yQ6FPivKIjrz3FKy9qe-ZhU44RT5kireF585ARDiYInIa5RTbhmf0JV8xA1aICrapjoYSoM5Ghyooa4XhN9I1n6qoaUhOUw3mXxDIHYHf9wPyJdZ-bu43LMXjT4NgWlqX09MdfbhG4eQOvJwEONkqYTWpSegR5ZP06aqELiegZnFeVsGgD6O1QWcoiDYxaIbwdDwoQzxv2ij0Lk8LNOzScQGLQatNam7ncY3Zf2Uvg7m4ps1FSsWJyjU5t4uy7UAj5XCUrjHUaDeoistMi0nqOc-Yk5mpvWQ"
}
一笔 Arweave 原生交易如上所示,下面将对交易信息进行说明:
format
:交易格式,目前 Arweave 交易的 format 都是 2。id
:该笔交易的 hash 值。last_tx
:一个锚点 - 防止重放攻击。一般是最后 50 个区块之一的哈希值,也可以是发送钱包的最后一个传出交易 ID。如果这是来自钱包的第一笔交易,则可以使用空字符串。owner
:RSA 公钥。tags
:交易的一些自定义标签,例如上例的 tags 为{”name”:”ContentType”, “value”:”img/png”}
,但是展示出来的是经过 base64Url 编码后的值,所以你需要经过解码才能看到真实值。target
:转账地址,如果只是发送数据到 Arweave 上,该值可以为空。quantity
:转账金额,单位是 winston, 1 AR = 10^12 winston。data
:交易数据,获取交易元数据时该字段为空。data_size
:交易数据的 size, 单位是 byte。data_root
:交易数据的默克尔根 hash。reward
:该笔交易的矿工费。signature
:交易签名。
获取交易状态
arId := "sUfG7jvu7PBQptlSIxtl6t5zD9LBMxv66_uVAlBk8dU"
status, err := cli.GetTransactionStatus(arId)
if err != nil {
panic(err)
}
fmt.Println(status)
返回值:
{
"block_height": 1003308,
"block_indep_hash": "jmvPK-uRUQH93Xx6D4LrAktVEkYCo_3kytFlgo0hMpV0dNWx0AWKzmQ2OlRwLPqc",
"number_of_confirmations": 40
}
该方法将返回交易的区块高度,区块哈希以及确认的节点数量。
获取交易 Tags
arId := "sUfG7jvu7PBQptlSIxtl6t5zD9LBMxv66_uVAlBk8dU"
tags, err := cli.GetTransactionTags(arId)
if err != nil {
panic(err)
}
fmt.Println(tags)
返回值:
[{Content-Type image/png}]
前面在获取交易元数据时,我们获取到的交易 Tags 是经过编码的,在此处我们获取到的 Tags 是经过解码的可供阅读的 Tags。
获取交易数据
extension := "png"
arId := "sUfG7jvu7PBQptlSIxtl6t5zD9LBMxv66_uVAlBk8dU"
data, err := cli.GetTransactionData(arId, extension)
if err != nil {
panic(err)
}
fmt.Println(data)
返回值:交易数据。
说明:
extension
为可选字段,例如 png,txt 等。- 如果交易数据大于 12M,goar 会通过 chunks 的方式来高效的获取数据。
获取交易价格
target := "An AR addr or nil"
txData := "txData"
data, err := cli.GetTransactionPrice([]byte(txData), &target)
if err != nil {
panic(err)
}
fmt.Println(data)
返回值:该笔交易需支付的 AR (单位是 winston),支付的费用的主要用途是永存上传的 data。
说明:
txData
是该笔 AR 交易所携带的数据,可以通过 file IO 来读取数据。target
是转账地址,如果只是发送数据到 Arweave 该值为 nil。
获取 tx_anchor
anthor, err := cli.GetTransactionAnchor()
if err != nil {
panic(err)
}
fmt.Println(anthor)
返回值:
nE7kAIYYzIZ_4_xbxidX_WmzntSuGsnc-MMmf6tmeYVdT0b-i5X5pVGB95MIg3bw
说明:
tx_anchor
主要用来构造交易时填充last_tx
字段,该值一般为最近 50 个区块之一的哈希值,可以用来判断 AR 交易是否过期,用于防止重放攻击。
提交 AR 交易
tx := <AR Tx>
body, statusCode, err := cli.SubmitTransaction(tx)
说明:
该方法主要是供其他模块(该模块会组装 AR 交易)调用,一般不会直接 New 一个客户端实例来调用此方法。
提交 Chunk
chunk := <AR data chunk>
body, statusCode, err := tt.Client.SubmitChunks(chunk) // always body is errMsg
说明:
同提交 AR 交易一样,该方法也是由其他模块(该模块会将 data 分成一个个 chunk)调用。
条件查询
qry := `{
transactions(ids: ["G-1t0Lqysin897HC3IV8xu_Mr884B-Mo5YEnlhUH54k"]) {
edges {
node {
id
block {
id
timestamp
}
}
}
}
}`
res, err := cli.GraphQL(qry)
if err != nil {
panic(err)
}
fmt.Println(string(res))
返回值:
{
"transactions":{
"edges":[
{
"node":{
"block":{
"id":"_W3jArV87Kzuf_VXHzgOgtivmtHTt26QD5jbwH9DPuxfa7KvTaWykeup_UKMv1zZ",
"timestamp":1600878676
},
"id":"G-1t0Lqysin897HC3IV8xu_Mr884B-Mo5YEnlhUH54k"
}
}
]
}
}
说明:
qry
为查询条件,在本例中,我们查询的是指定 ArIds 对应的区块哈希和时间戳,更多的查询实例可以参考 graphQL。
获取余额
addr := "NVkSolD-1AJcJ0BMfEASJjIuak3Y6CvDJZ4XOIUbU9g"
bal, err := cli.GetWalletBalance(addr)
if err != nil {
panic(err)
}
fmt.Println(bal)
返回值:229.422694029987
说明:
addr
:Arweave 地址。bal
: 账户余额,以 AR 为单位。
获取最后一笔交易
addr := "NVkSolD-1AJcJ0BMfEASJjIuak3Y6CvDJZ4XOIUbU9g"
txId, err := cli.GetLastTransactionID(addr)
if err != nil {
panic(err)
}
fmt.Println(txId)
返回值:AR 交易的 id。
说明:获取指定地址的最后一笔 AR 交易 id。
通过区块哈希获取区块信息
id := "rEPeabLpDO_2y6tsNVvwHRjJNYYHgVz9oqyLhXM-3QjUzTtePPy1sOIpmnn57OY0"
block, err := cli.GetBlockByID(id)
if err != nil {
panic(err)
}
fmt.Println(block)
通过区块高度获取区块信息
height := 510788
block, err := cli.GetBlockByHeight(height)
if err != nil {
panic(err)
}
fmt.Println(block)
返回值:
{
"nonce": "gyms_ZAPH3conbCKIRm8JuODAtp8NlD3aBaLdCsp--I",
"previous_block": "u1dfjcN3yH37oRN96CfUvVf7V0w7zoQ233JNgMXS_XWZhXTsibwCprbXcvp5G3io",
"timestamp": 1597905785,
"last_retarget": 1597904281,
"diff": "115792089225334907412622155393890012047568246338521059128782635418398016667648",
"height": 510788,
"hash": "_____9BbiDatEnH3djvX0-NhBGA28NEWnjDIWLCkiB8",
"indep_hash": "rEPeabLpDO_2y6tsNVvwHRjJNYYHgVz9oqyLhXM-3QjUzTtePPy1sOIpmnn57OY0",
"txs": [
"-NR_WOHN7feR53D5Sco-U8uQtw_1x5jENmcp0N-EOhk",
.......................
"2ZSx2Ast1AmBYKBotKHvdh3BnZq9vLxnwmd9M49UQDI",
],
"tx_root": "L-f7g24O5lHA5onKbmFmRbyKZ0R_dXboW7AZmPBo2iI",
"tx_tree": [],
"wallet_list": "ZekJxJrqTWIUkAxkYZt_yxS1Yvyp_9p1Y0VMrZlIMFz0dvXamtOaZNgr8ZLkFHN7",
"reward_addr": "V12aL_AA2IiL3ltx44e4TTVQXuEaSdgy3qswrToFcJc",
"tags": [],
"reward_pool": 5119213831149206,
"weave_size": 1160387834901,
"block_size": 50468816,
"cumulative_diff": "469151620099952",
"hash_list_merkle": "Vrd5HYeH1O3XVCkFqWrBRcZgX8A_ItyUwdpNgrh5PYF-tChDUqXj2rMoh7khJEJg",
"poa": {
"option": "1",
"tx_path": "-JFwjXN41_SRo8PFA6W1p-hk_hpFBRZZDGTT24Z5hg202t7EcuyZV9u02Wsv_82VO6YCCm6iReJO_I51X0m0PAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMlStkRI-8YKz8VmNSwYEYMH2YL-Pjney2JX31ACcb6bwrPjIjg2BdHYXe9-FUsLhlA7xVTsA7Qsyux3qWv2amP0LZgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAShVGoMskgWgBd-tBILt01zNBb-zRJmG66T6_byUU7vM5LSfvB70FgAtCPFMy7-XkRHIkAX8b-o-HB-iOAE5RFxzBEQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOhMKikwMvPZvB3Khu29C51mNhl1wcj-ZGMCriJ6Xw3khoX4UsGGdPv5N6lsUAtLofG7Ard5GS1HrSidKG47JucgQdQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAShPSTbG2LFU-qJ57Hl-ADcGPFV1PyR6ePNg5B9L2kYFZ_JgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEoT0g",
"data_path": "hrxipQs9CNZOuUnxZn3uYHr2oIGUKYhyKny9rDdttmrbpOzVkObe7bpVeAG0U62w1h-ixPFGse9BMz294MTKXwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAjS-HxbUwp9VESWe2tOi5CZj1Jg52kS_pJ9PIzGx4Q6IWxcmyQBaIWtZ3X2izltsBIf-oEMoAX3TV6Rd9pWmQiAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAeOxWCbG1qLKw41g-KBLEC0g6Xfo58MC88OqHBhpJEvph4kbJT5vSt6nkjRYp2NaHr-xFdW_DgbxW3NuEKiOs8QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAS2pyAEkkplSfU4ciSdbMUexYmGoK_kv_CoYKQbdk8PAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAA",
"chunk": "PCFET0NUWVBFIGh0bWw-PGh0bWwgbGFuZz0iZW4tVVMiIHByZWZpeD0ib2c6IGh0dHA6Ly9vZ3AubWUvbnMjIiBzdHlsZT0idHJhbnNmb3JtOiBub25lOyI-PGhlYWQ-PG1ldGEgY2hhcnNldD0iVVRGLTgiPjxtZXRhIGh0dHAtZXF1aXY9IlgtVUEtQ29tcGF0aWJsZSIgY29udGVudD0iSUU9......"
}
}
获取交易具体字段
field := "data.png"
data, err := cli.GetTransactionField("sUfG7jvu7PBQptlSIxtl6t5zD9LBMxv66_uVAlBk8dU", field)
if err != nil {
panic(err)
}
fmt.Println(data)
返回值: 该笔交易的数据。
说明:
field
字段可以接受的参数为:id, last_tx, owner, tags, target, quantity, data, data_root, data_size, reward, signature,以及 data.{extension}。