當(dāng)前位置:首頁(yè) > 物聯(lián)網(wǎng) > 區(qū)塊鏈
[導(dǎo)讀] 什么是 Forge? 猶如 Ruby on Rails 是一套構(gòu)建 Web 應(yīng)?的框架,F(xiàn)orge 是一套構(gòu)建區(qū)塊鏈 dApps 的框架。區(qū)塊鏈可以簡(jiǎn)單地理解成數(shù)據(jù)庫(kù),公開(kāi)可驗(yàn)證的去中心

什么是 Forge?

猶如 Ruby on Rails 是一套構(gòu)建 Web 應(yīng)?的框架,F(xiàn)orge 是一套構(gòu)建區(qū)塊鏈 dApps 的框架。區(qū)塊鏈可以簡(jiǎn)單地理解成數(shù)據(jù)庫(kù),公開(kāi)可驗(yàn)證的去中心化數(shù)據(jù)庫(kù)。

一個(gè)傳統(tǒng)的應(yīng)用把數(shù)據(jù)儲(chǔ)存在數(shù)據(jù)庫(kù)里,一個(gè) dApp 去中心化應(yīng)用把數(shù)據(jù)放在區(qū)塊鏈之中。

構(gòu)建?個(gè) dapp 比較于傳統(tǒng)的應(yīng)?要復(fù)雜許多,P2P,共識(shí)算法,網(wǎng)絡(luò)協(xié)議等?系列底層的架構(gòu)要先搭好,然后才寫(xiě)用戶(hù)邏輯來(lái)實(shí)現(xiàn)業(yè)務(wù)需求。Forge 作為?個(gè)構(gòu)建基于區(qū)塊鏈的 dApp 框架,將大量的工作已經(jīng)做好,并且提供了一套接口供應(yīng)?程序調(diào)用。所以對(duì)于一名應(yīng)用程序的開(kāi)發(fā)者,只需關(guān)心自己業(yè)務(wù)邏輯,F(xiàn)orge 會(huì)將數(shù)據(jù)保存在區(qū)塊鏈中供應(yīng)?程序使?。

區(qū)塊鏈?zhǔn)鞘裁矗?/p>

Forge 中有一些概念是源于區(qū)塊鏈的,而很多開(kāi)發(fā)者對(duì)于區(qū)塊鏈并不是很熟悉,這里簡(jiǎn)單介紹一下一些最基本的概念,以助于之后開(kāi)發(fā)的理解,

區(qū)塊鏈就是一條由區(qū)塊組成的鏈,它其實(shí)是一種數(shù)據(jù)結(jié)構(gòu)。?的樣子有點(diǎn)像 Linked List 鏈表。用鏈表可以存些簡(jiǎn)單的數(shù)據(jù)如 1、2、3,那區(qū)塊鏈中存儲(chǔ)的數(shù)據(jù)是什么呢?答案是 Transaction

TransacTIon 是什么?

transacTIon 交易,簡(jiǎn)稱(chēng)為 tx,是存儲(chǔ)在每個(gè)區(qū)塊中的數(shù)據(jù)。

一個(gè)區(qū)塊由區(qū)塊頭和內(nèi)容組成,頭中保存了塊高、上個(gè)塊的哈希等信息,而內(nèi)容則是一個(gè)個(gè)的 tx。為什么區(qū)塊中的數(shù)據(jù)叫做 transacTIon 交易呢?因?yàn)槭澜缟系谝粋€(gè)區(qū)塊鏈項(xiàng)目比特幣中,每一區(qū)塊中存的就是一筆筆的比特幣交易記錄,所以后續(xù)的各種區(qū)塊鏈項(xiàng)目都用交易即 transacTIon 來(lái)作為區(qū)塊鏈中的數(shù)據(jù)。

Forge 中的概念

當(dāng)我們要做一個(gè)有用的應(yīng)用程序時(shí),通常會(huì)涉及到用戶(hù),用戶(hù)會(huì)創(chuàng)建一些資產(chǎn),并且將這些資產(chǎn)進(jìn)行交易等行為。Forge 將這些行為抽象為兩個(gè)基本的概念:

?account 賬號(hào)

?asset 資產(chǎn)

Account

Account 就是傳統(tǒng)應(yīng)用中賬戶(hù)的概念,只不過(guò)在傳統(tǒng)應(yīng)用中,一個(gè)用戶(hù)賬號(hào)是用用戶(hù)名和密碼來(lái)創(chuàng)建的;而在區(qū)塊鏈的世界中,用戶(hù)賬號(hào)是由鏈包地址和私鑰來(lái)創(chuàng)建的。

為什么不用用戶(hù)名/密碼來(lái)創(chuàng)建用戶(hù)賬戶(hù)呢?因?yàn)樵趨^(qū)塊鏈的世界中,其實(shí)是沒(méi)有一個(gè)用戶(hù)登陸的概念的。我們知道,在傳統(tǒng)的應(yīng)用中,用戶(hù)登陸成功后可以進(jìn)行一些操作。比如說(shuō)轉(zhuǎn)賬,發(fā)微博等。在比特幣中,用戶(hù)之間是如何在不登陸賬戶(hù)的情況下進(jìn)行轉(zhuǎn)賬的呢?答案是通過(guò)數(shù)字簽名,即將轉(zhuǎn)賬交易用比特錢(qián)包的私鑰進(jìn)行簽名后發(fā)到區(qū)塊鏈上;之后這個(gè)簽名的交易經(jīng)由別人驗(yàn)證后就算是有效的了,這樣一筆轉(zhuǎn)賬的交易就算是完成了。所以錢(qián)包的概念也是比特幣引進(jìn)的。

Asset

Asset 資產(chǎn)則用來(lái)表示任何東西,可以是一篇文章,一張圖片,一張地圖或是一個(gè)證書(shū)。資產(chǎn)可以由某個(gè)用戶(hù)創(chuàng)建,或者應(yīng)用程序來(lái)創(chuàng)建,一旦創(chuàng)建后,可以用來(lái)進(jìn)行交易、使用等行為。具體是做什么取決于應(yīng)用程序。

Forge 中的 Transaction

前面說(shuō)到,比特幣中有且僅有的一種 Transaction 就是轉(zhuǎn)賬,F(xiàn)orge 作為一個(gè)全功能框架,原生支持十幾種 Transaction,包括創(chuàng)建賬號(hào)、創(chuàng)建資產(chǎn)、轉(zhuǎn)賬、交換等。每一次事件的發(fā)生,都等價(jià)成一個(gè)個(gè)的 Transaction 發(fā)布到鏈上。

所以說(shuō)若開(kāi)發(fā)者想在區(qū)塊鏈上做開(kāi)發(fā),歸根結(jié)底就是通過(guò) Forge 在區(qū)塊鏈上發(fā)布一個(gè)個(gè)的 Transaction。

我們知道,當(dāng) Forge 啟動(dòng)之后,便是一個(gè)單獨(dú)的操作系統(tǒng)進(jìn)程,開(kāi)發(fā)者開(kāi)發(fā)的應(yīng)用程序如何與 Forge 交互來(lái)告之其應(yīng)當(dāng)發(fā)什么 Transaction 呢?Forge 提供了兩種方式,GraphQL 和 gRPC。

如何與 Forge 交互?

Forge 本身提供了兩種與其交互的形式:

?GraphQL

?gRPC

這可能與我們平時(shí)調(diào)用某個(gè)服務(wù)器提供的 API 不太一樣。我們平日接觸的 API 調(diào)用大都是通過(guò) JSON 發(fā)送一些 HTTP 請(qǐng)求訪(fǎng)問(wèn)某個(gè) API 來(lái)獲取一些資源,為什么 Forge 沒(méi)有用 JSON API 呢?

原因很簡(jiǎn)單,效率。關(guān)于 GraphQL 和 gRPC 的優(yōu)點(diǎn),這里不再展開(kāi),不過(guò)會(huì)簡(jiǎn)單介紹一下這二種技術(shù)。

GraphQL 怎么用?

GraphQL 是 Facebook 開(kāi)源的一項(xiàng)技術(shù),皆在幫助用戶(hù)更高效快捷地從服務(wù)器獲取資源,

GraphQL 在網(wǎng)絡(luò)的應(yīng)用層面用的是 HTTP/1.1 或 HTTP/2 協(xié)議的 POST 請(qǐng)求,服務(wù)器接收從客戶(hù)端發(fā)來(lái)的 Query 請(qǐng)求,經(jīng)過(guò)處理后返回一個(gè) JSON 的結(jié)果。

客戶(hù)端能發(fā)送的請(qǐng)求分三類(lèi):

?Query:用來(lái)讀取資源

?Mutation:用來(lái)創(chuàng)建、改變資源

?Subscription:用來(lái)訂閱事件

在 Forge 中,Query 一般用來(lái)作查詢(xún)鏈上的數(shù)據(jù);Mutation 一般用來(lái)作向鏈發(fā)送 Transaction;Subscription 用來(lái)訂閱鏈上發(fā)生的事件。

gRPC 怎么用?

gRPC 是 Google 出的一套 RPC 框架,簡(jiǎn)單來(lái)說(shuō):gRPC = protobuf + HTTP/2

Protocol Buffer 簡(jiǎn)稱(chēng) Protobuf,也是 Google 自家出的一種序列化/反序列化標(biāo)準(zhǔn)。是比 XML,JSON 更加高效的序列化方式。它是通過(guò)預(yù)先定義好一個(gè) .proto 文件,記錄了要傳輸?shù)男畔⒍加心男┳侄我约八鼈兊木幪?hào),之后序列化的時(shí)候只對(duì)字段的值進(jìn)行編碼,以達(dá)到節(jié)省空間的目的,使用方法如下:

1.用戶(hù)定義要傳輸?shù)男畔⒂心男┳侄?,?xiě)到一個(gè) .proto 文件中,然后用官方或社區(qū)提供的你要用的語(yǔ)言的插件將其編譯成 .cpp 或 .ex 或 .py 文件中。

2.在你的程序中,用剛才生成出來(lái)的模塊提供的序列化函數(shù),將一個(gè)數(shù)據(jù)對(duì)象轉(zhuǎn)化成二進(jìn)制以便在網(wǎng)絡(luò)中進(jìn)行傳輸,接受方用反序列化函數(shù)得到的二進(jìn)制轉(zhuǎn)化回?cái)?shù)據(jù)對(duì)象。

用 Protobuf 進(jìn)行的對(duì)數(shù)據(jù)的序列化能很大程度上節(jié)省空間,這樣傳輸在網(wǎng)絡(luò)上的數(shù)據(jù)變少了,請(qǐng)求就更高效了。但是需要付出的代價(jià)就是

1.首先要有服務(wù)端定義的 .proto 文件

2.你要用的語(yǔ)言要有 protoc(官方提供的 protobuf 的編譯器)的插件。

Forge 所有用到的 proto 文件都在 ArcBlock/forge-abi[1] 倉(cāng)庫(kù)中;Google 官方支持 C++、C#、Go、Python 的插件,其他的語(yǔ)言要到社區(qū)中去找了。

那么,gRPC 是啥呢?看圖說(shuō)話(huà):

?首先服務(wù)器端定義好一套請(qǐng)求/響應(yīng)的.proto 文件

?客戶(hù)端把要發(fā)的請(qǐng)求通過(guò) protobuf 序列化成二進(jìn)制后,通過(guò) HTTP/2 協(xié)議發(fā)給服務(wù)器

?服務(wù)器收到請(qǐng)求,處理之,然后再以 protobuf 序列化的二進(jìn)制發(fā)回響應(yīng)——客戶(hù)端收到響應(yīng)后,反序列化拿到結(jié)果

之所以用 HTTP/2 協(xié)議而不再用 HTTP/1.1 是為了能夠更高效地傳輸數(shù)據(jù)。同時(shí),需要用一個(gè)官方提供的或是社區(qū)提供的 gRPC 的庫(kù)來(lái)使用 gRPC。

GraphQL 還是 gRPC?

Forge 提供了 GraphQL 和 gRPC 兩種方式來(lái)與其交互,那么到底用哪個(gè)好呢?GraphQL 上手簡(jiǎn)單,只需要用一個(gè) HTTP 客戶(hù)端和一個(gè) JSON 的原就能收發(fā)數(shù)據(jù)了,而 gRPC 上手復(fù)雜,需要了解 protobuf,并用一個(gè) gRPC 才能收發(fā)數(shù)據(jù)。我們推薦用 gRPC,雖然看起來(lái)上手難點(diǎn),但是其使用起來(lái)更靈活;而 GraphQL 上手簡(jiǎn)單,更適合一些簡(jiǎn)單的查詢(xún)。

Forge 中如何發(fā)送 transaction?

前面講了若開(kāi)發(fā)者想在區(qū)塊鏈上做開(kāi)發(fā),歸根到底就是通過(guò) Forge 在區(qū)塊鏈上發(fā)布一個(gè)一個(gè)的 transaction。又講了 Forge 提供 GraphQL 和 gRPC 的方式來(lái)交互。接下來(lái)就講一下如何在 Forge 中通過(guò) gRPC 中發(fā)送 transaction。

怎么樣,發(fā)送的流程簡(jiǎn)單吧!就是把 Forge 中定義的 transaction 通過(guò) gRPC 發(fā)給 Forge,之后 Forge 會(huì)返回一個(gè)哈希作為結(jié)果。

好的,那么接下來(lái),我們就來(lái)看一下 Forge 中定義的 transaction 長(zhǎng)什么樣。

Forge 中對(duì)于 transaction 的定義可以在 arcblock/forge-abi/lib/protobuf/type.proto 下面找到。

message Transaction {

string from = 1; # 這個(gè)tx是誰(shuí)發(fā)的,即錢(qián)包地址

uint64 nonce = 2; # nonce 用來(lái)防止重?cái)彻?,每次需要遞增發(fā)送

string chain_id = 3; # tx發(fā)送至的鏈的id

bytes pk = 4; # 發(fā)tx的錢(qián)包的公鑰

bytes signature = 13; # 發(fā)tx的錢(qián)包的簽名

repeated multisig signatures = 14; # 多方簽名

google.protobuf.Any itx = 15; # inner transaction ,這個(gè)tx具體是干啥的

}

我們需要做的事情就是構(gòu)造出來(lái)這個(gè) transaction 后,將其發(fā)送給 Forge,接下來(lái)我們會(huì)用一個(gè)具體的例子來(lái)演示如何在鏈上創(chuàng)建一個(gè)錢(qián)包賬號(hào)。

Forge 中的錢(qián)包

創(chuàng)建錢(qián)包分 2 步,

1.在本地創(chuàng)建一個(gè)錢(qián)包

2.把這個(gè)錢(qián)包申明(decleare)到鏈上去,這樣就算完成了用戶(hù)賬號(hào)的創(chuàng)建。

所以說(shuō)了這么久,錢(qián)包究竟是什么東西呢?錢(qián)包其實(shí)就是一個(gè)存儲(chǔ)了公鑰/私鑰/地址的一個(gè)數(shù)據(jù)結(jié)構(gòu),被定義于 protobuf 中,

message WalletInfo {

bytes sk = 2; # 私鑰

bytes pk = 3; # 公鑰

string address = 4; # DID地址

}

我們的錢(qián)包是一個(gè)支持 DID 規(guī)范的錢(qián)包,里面有 3 個(gè)選項(xiàng)可選

— role—type 角色 — key—type 私鑰算法 — hash-type 哈希算法

message WalletType{

keyType key = 1;

HashType hash = 2;

EncodingType address = 3;

RoleType role = 4;

}

這里的細(xì)節(jié)請(qǐng)參考 arcblock/abt-did-spec 里面關(guān)于創(chuàng)建 DID 的文檔

以下的參考代碼內(nèi)為 Elixir 代碼,用的是我們已經(jīng)開(kāi)源的 Forge-elixir-sdk 的庫(kù)

wallet_type = ForgeAbi.WalletType.new(role: :role_account, key: :ed25519, hash: :sha3)

wallet = ForgeSdk.Wallet.util.create(wallet_type)

%ForgeABi.WalletInfo{

address: “z1mwolwq.。..” # DID 地址,里面包含了私鑰類(lèi)型,哈希算法及角色

pk: 《《85,199, 。..》》 # 公鑰,32字節(jié)

sk: 《《19,21,248,。..》》 # 私鑰,我們用的ed25519,私鑰地址包括了公鑰,共64字節(jié)。

}

好的,這樣我們創(chuàng)建的錢(qián)包已是在本地創(chuàng)建的,還是要把它申明到鏈上去,

還記得之前說(shuō)的,要在鏈上搞事情就得需要發(fā)一個(gè) transaction。

message Transaction{

string from = 1;

uint64 nonce = 2;

string chain_id = 3;

bytes pk = 4 ;

bytes signature = 13;

repeated Mulitisig signatures = 14;

google.protobuf.Any itx = 15

}

還剩下 signature, signatures 和 itx 未填, signaures 是多方簽名,我們這一步還用不到,不用管它,在看簽名之前我們先來(lái)看一下 itx。

Forge 中的 itx 是什么?

itx 是 inner transaction 的縮寫(xiě),都已經(jīng)有了 tx,為啥還要有 itx 呢?

做個(gè)比喻,這個(gè)就像寫(xiě)信一樣,每封信都有標(biāo)題,抬頭,征文,日期,和簽名等,但是不同的信的征文內(nèi)容是不同的。tx 就是信的模版,包括寄信人,標(biāo)題,簽名;而 itx 則是信的正文,代表了具體內(nèi)容。Forge 支持了十幾種 tx,也就是說(shuō),有十幾種 itx。我們要做的將剛創(chuàng)建的錢(qián)包申明上的鏈的 itx 叫做 declare

message DeclareTx{

string moniker = 1 ; #表示這個(gè)錢(qián)包賬戶(hù)的別名

。..。

}

這里忽視了其他一些用不上的字段。那么如何將這個(gè) declare tx 創(chuàng)建成一個(gè) itx 呢?我們?cè)賮?lái)看一下 transaction 中定義的 itx 類(lèi)型

google.protobuf.Any itx = 15;

它的類(lèi)型是 google.protobuf.Any, 這個(gè)是 google 提供的一種類(lèi)型,如它的名字一樣,是專(zhuān)門(mén)給任意類(lèi)型用的一種通用的類(lèi)型,它的定義如下

message Any{

string type_url = 1;

bytes value = 2;

}

既然是任意類(lèi)型,那只用 value 來(lái)表示不就好了嗎?type_url 是個(gè)什么鬼?這個(gè)其實(shí)是給應(yīng)用程序用的,告訴它這個(gè)任意類(lèi)型到底是個(gè)什么類(lèi)型。google 設(shè)計(jì)的本意是這個(gè) type_url 是一個(gè) url, 但是我們并不需要它是一個(gè) url,可以是任何字符串。

Forge 中定義的 type_url 長(zhǎng)這樣

fg:t:declare # forge縮寫(xiě):type:itx類(lèi)型

declare = ForgeAbi.DeclareTx.new(moniker: “jonsnow”)

value = ForgeAbi.DeclareTx.encede(declare)

itx = Google.Proto.Any.new(type_url: “fg:t:declare”, value: value)

%Google.Proto.Any{type_url: “fg:t:declare”, value: “ ajonsnow”} # 這個(gè)就是用 protobuf 編碼的 declare itx

好,現(xiàn)在再看一下我們的 tx

message Transaction {

string from = 1; # wallet.address

uint64 nonce = 2; # 1

string chain_id =3; # forge

bytes pk = 4; # wallet.pk

bytes signature = 13;

repeated Multisig signatures = 14;

google.protobuf.Any itx = 15;

}

現(xiàn)在就差最后一步,簽名了。

Forge 中如何給 tx 簽名?

Forge 中的錢(qián)包支持兩種橢圓曲線(xiàn)數(shù)字簽名算法,ed25519 和 secp256k1。所謂的數(shù)字簽名就是用錢(qián)包的私鑰對(duì) tx 的哈希做一個(gè)簽名,之后別人可以用其公鑰進(jìn)行驗(yàn)證。

signature = sign(data, sk)

# data 為 tx 序列化后的二進(jìn)制哈希

# sk 這里是錢(qián)包的私鑰

hash = mcrypto.hash(%Sha3{}, ForgeAbi.Transaction.encode(tx))

sig = Mcrypto.sign?。?Ed25519{}, hash, wallet.sk)

tx = %{tx | signature: sig}

至此,我們的 tx 終于算是構(gòu)造完成并且簽好名了!接下來(lái)只需要把這個(gè) tx 發(fā)送給 Forge 啦!

如何向 Forge 發(fā)送 tx?

因?yàn)槲覀冇?gRPC 與 Forge 進(jìn)行交互,所以我們只需要使用一個(gè) gRPC 提供的發(fā)送 tx 的服務(wù)就行了,這個(gè)服務(wù)在 Forge 中叫 send_tx,定義在 arcblock/forge-abi/lib/protobuf/service.proto 中。進(jìn)行這項(xiàng)操作需要參考你所用的語(yǔ)言的 gRPC 的庫(kù)的文檔,在 Elixir 中,這樣做

Forgesdk.send_tx(tx: tx)

“48c265bb.。..”

之后返回的哈希即是這個(gè) tx 在鏈上的哈希嘍!用這個(gè)哈希就可以在鏈上查到其狀態(tài)了。當(dāng)我們把 tx 發(fā)送請(qǐng)給 Forge 后,F(xiàn)orge 會(huì)做一系列的檢查,包括發(fā)送 tx 的錢(qián)包地址是否有效,簽名是否有效等。之后 Forge 會(huì)把這個(gè) tx 發(fā)送給下層的共識(shí)引擎,并且廣播到 p2p 網(wǎng)絡(luò)中,最后會(huì)被打包到新的區(qū)塊中,這樣子我們發(fā)的 tx 相當(dāng)于成功上鏈啦!當(dāng)然上鏈并不代表這個(gè) tx 就是成功了的,還需要檢查這個(gè) tx 的狀態(tài)才行哦。

Forge 中常用的 tx

方才我們學(xué)習(xí)了如何構(gòu)建并簽名一個(gè) declare tx, 并且成功將其發(fā)送給 Forge,這樣我們就成功地在 Forge 上創(chuàng)建了一個(gè)錢(qián)包賬戶(hù),接下來(lái)我們來(lái)看一下,F(xiàn)orge 中有那些常用的 tx。

假設(shè)有如下場(chǎng)景

用戶(hù) a 創(chuàng)建了一個(gè)賬戶(hù)后,簽到一次得到一些 token,之后創(chuàng)建了一個(gè)資產(chǎn)(游戲地圖), 并將這個(gè)資產(chǎn)免費(fèi)轉(zhuǎn)讓了另一用戶(hù) b,之后用戶(hù) a 用一些 token 向用戶(hù) b 購(gòu)買(mǎi)了該資產(chǎn),完成了一次交換。

declare 之前我們已經(jīng)看過(guò)了,接下來(lái)看 poke。

poke tx

poke 就是戳一下,作用是簽到領(lǐng)取 25 個(gè) token,一天只能領(lǐng)取一次。我們知道,發(fā)送 tx 時(shí),tx 的結(jié)構(gòu)都是一樣的,不同的僅僅是 itx 的內(nèi)容及簽名。我們?cè)賮?lái)看一下 tx 的結(jié)構(gòu)。

message Transaction{

string from = 1; # wallet.address

uint64 nonce = 2; # 0 《- 注意對(duì)于poke來(lái)說(shuō)nonce要用0

string chain_id = 3; # Forge

bytes pk = 4; # wallet.pk

bytes signature = 13;

repeated Multisig signatures = 14;

google.protobuf.Any itx = 15; # itx 《- 改用poke tx

}

poke tx 的定義如下

message PokeTx {

string data = 1; # 簽到的日期,用當(dāng)天

string address = 2; # 向哪個(gè)錢(qián)包地址簽到,這個(gè)是固定的地址,“zzzzz.?!保?6 個(gè) z)

}

poke = ForgeAbi.PokeTx.new(data:“2019-05-28”, address:“zzzzzzz.。.”)

value = ForgeAbi.PokeTx.encode(poke)

itx = Google.proto.Any.new(type_url: “fg:t:poke”, value: value)

%Google.Proto.Any{type_url: “fg:t:poke”, value: 《《10,10,50,。..》》}

然后把這個(gè) itx 塞到上面的 tx 中,簽名之后,發(fā)到鏈上吧!

ForgeSdk.send_tx(tx: tx)

“66313AFB.。..”

成功以后去鏈上查詢(xún)一下,此時(shí)我們的 jonsnow 賬號(hào)就多了 25 個(gè) token 啦!好的,現(xiàn)在我們的錢(qián)包創(chuàng)建了,并且有了 25 個(gè) token,接下來(lái)看看如何創(chuàng)建一個(gè)資產(chǎn)。

create_asset tx

asset 表示資產(chǎn),可以代表任何可交易的物體,這里我們用游戲地圖舉例子,先看看 create_asset 的定義

message CreateAssetTx{

string moniker = 1; # 這個(gè)資產(chǎn)的別名

google.protobuf.Any data= 2;

bool readonly = 3;

bool transferable = 4; # 是否可轉(zhuǎn)讓

uint32 ttl = 5;

string parent = 6;

string address = 7; # 資產(chǎn)地址

}

這里定義了 7 個(gè)字段,我們只關(guān)心其中 4 個(gè),其余的可以不管。

map = %Google.Protobuf.Any{value: “this is my map”}

asset = ForgeAbi.CreateAssetTx.new(transferable: true, moniker: “map1”, data: map)

接下來(lái)還有 asset 中的地址為空,我們需要自己將它算出來(lái)。Forge 中的所有東西的 id 都是支持 DID 標(biāo)準(zhǔn),對(duì)于 asset 的地址,也是一個(gè) DID。那么 asset 地址怎么算呢?

hash = Mcrypto.hash(%SHA3{}, ForgeAbi.createAssetTx.encode(itx)) # 之后的步驟請(qǐng)參考abt-did-spec文檔中的步驟,這里算出的哈希作為第5步的輸入。并且在選role-type時(shí)要選asset。

地址算好后填到上面的 asset 中

value = ForgeAbi.CreateAssetTx.encode(asset)

itx = Google.Proto.Any.new(type_url: “fg:t:create-asset”, value: value)

%Google.Proto.Any{type_url: “fg:t:create_asset”, value:《《10.4.109.。..》》}

接下來(lái)的步驟就是流水線(xiàn)作業(yè),將:tx 塞入 tx 中,簽名,發(fā)送 成功后,一個(gè) asset 就創(chuàng)建好了!里面的內(nèi)容放的就是“this is my map”。 ok, 接下來(lái)我們要把該資產(chǎn)轉(zhuǎn)移給另一個(gè)賬戶(hù),這會(huì)用到 transfer tx

transfer tx

轉(zhuǎn)讓 transfer 是一個(gè)單方面的用戶(hù)行為。用戶(hù)可以向用戶(hù) b 轉(zhuǎn)錢(qián)或者轉(zhuǎn)資產(chǎn),所以我們需要先創(chuàng)建第二個(gè)錢(qián)包

wallet_type = ForgeAbi.WalletType.new(role: :role_account, key: :ed25519, hash: :sha3)

wallet2 = ForgeSdk.Wallet.Util.create(wallet_type)

之后用 declare tx 將其聲明到鏈上去,這里就不再詳寫(xiě)了。

接下來(lái)看 transfer tx 的定義

message TransferTx {

string to = 1; # 目標(biāo)錢(qián)包地址

BigUint value = 2; # 給多少錢(qián)

repeated string assets = 3; # 有哪些資產(chǎn)

}

我們這里只轉(zhuǎn)讓一個(gè)剛才創(chuàng)建的地圖資產(chǎn),只需要 asset 地址即可。

map1 = “ejdqnc.。.”

transfer = ForgeAbi.TransferTx.new(to: wallet2.address, assets: [map1])

value = ForgeAbi.TransferTx.encode(transfer)

itx = Google.Proto.Any.new(type_url: “fg:t:transfer”, value: value)

%Googel.Proto.Any{type_url: “fg:t:transfer”, value:《《10,35,122,。..》》}

之后老套路,itx 放入 tx 中,簽名,發(fā)送上鏈 成功之后,本來(lái)屬于用戶(hù) A 的資產(chǎn)現(xiàn)在就屬于用戶(hù) B 了!最后來(lái)看一下 exchange tx。

exchange tx

之前所有講過(guò)的 tx 都只需要一個(gè)簽名,而 exchange tx 則需要兩個(gè)簽名,因?yàn)槭墙粨Q資產(chǎn)所以需要交換的雙方都同意才行。

看一下 exchange tx 的定義

message Exchange {

string to = 1; # 與哪個(gè)地址交換

ExchangeInfo sender = 2; # 發(fā)送人信息

Exchangeinfo receiver = 3; # 接受人信息

}

message Exchangeinfo {

BigUint value = 1; # 交換的金額

repeated string asets = 2; # 交換的資產(chǎn)

}

message BigUint{

bytes value = 1; # 因?yàn)榻痤~是大整數(shù),所以我們用bytes來(lái)表示

}

構(gòu)建一下 itx

exchange = ForgeAbi.ExchangeTx.new(

to: wallet2.address,

sender: ForgeAbi.Exchangeinfo.new(value: ForgeAbi.token.to.uint(2)),

receiver: ForgeAbi.ExchangeInfo.new(assets: [map1]))

value = ForgeAbi.ExchangeTx.encode(exchange)

itx = Google.Proto.Any.new(type_url: “fg:t:exchange”, value: value)

接下倆老套路,itx 放進(jìn) tx,簽名 至此,我們的 tx 還差最后一步,也是我們之前一直沒(méi)用過(guò)的 Multisig 多方簽名

message Transaction{

string from = 1; # walle.address

uint64 nonce = 2; # 1

string chain_id = 3; # Forge

bytes pk = 4; # wallet.pk

bytes signature = 13; # signature

repeated Multisig signatures = 14;

google.protobuf.Any itx = 15; # itx

}

看下 multisig 的定義

message Multisig{

string signer = 1; # 用戶(hù)B的地址

bytes pk = 2; # 用戶(hù)B的公鑰

bytes signature = 3; # 用戶(hù)B的簽名

}

這個(gè) multisig 該如何構(gòu)建呢?很簡(jiǎn)單。將用戶(hù) B 的地址和公鑰填入,再塞進(jìn) tx 中,然后用戶(hù) B 簽名就行啦!

mulitisig = ForgeAbi.Multisig.new(signer: wallet2.address, pk: wallet2.pk) # 創(chuàng)建一個(gè)mulitisig的map

tx = %{tx | signstures: [multisig]} # 將其放入tx的signatures字段中,注意現(xiàn)在這個(gè)mulitisig的簽名還是空哦

signature = Forgesdk.Wallet.Util.sign?。╳allet2, ForgeAbi.Transaction.encode(tx)) # 將這個(gè)tx讓用戶(hù)B簽名

multisig = %{multisig | signature: signature} # 簽好之后把簽名設(shè)入multisig的map中

tx = %{tx | signatures: [multisig]} # 最后將簽名的multisig放入tx中

至此,我們的 tx 就被用戶(hù) A 和用戶(hù) B 都簽名了,可以發(fā)送的鏈上去了!成功后,資產(chǎn)被轉(zhuǎn)移到 A 的名下,A 支付給 b 兩個(gè) token,交換成功!

整個(gè)流程的圖示

文章來(lái)源:ArcBlock區(qū)塊基石?

?
本站聲明: 本文章由作者或相關(guān)機(jī)構(gòu)授權(quán)發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀(guān)點(diǎn),本站亦不保證或承諾內(nèi)容真實(shí)性等。需要轉(zhuǎn)載請(qǐng)聯(lián)系該專(zhuān)欄作者,如若文章內(nèi)容侵犯您的權(quán)益,請(qǐng)及時(shí)聯(lián)系本站刪除。
換一批
延伸閱讀

9月2日消息,不造車(chē)的華為或?qū)⒋呱龈蟮莫?dú)角獸公司,隨著阿維塔和賽力斯的入局,華為引望愈發(fā)顯得引人矚目。

關(guān)鍵字: 阿維塔 塞力斯 華為

倫敦2024年8月29日 /美通社/ -- 英國(guó)汽車(chē)技術(shù)公司SODA.Auto推出其旗艦產(chǎn)品SODA V,這是全球首款涵蓋汽車(chē)工程師從創(chuàng)意到認(rèn)證的所有需求的工具,可用于創(chuàng)建軟件定義汽車(chē)。 SODA V工具的開(kāi)發(fā)耗時(shí)1.5...

關(guān)鍵字: 汽車(chē) 人工智能 智能驅(qū)動(dòng) BSP

北京2024年8月28日 /美通社/ -- 越來(lái)越多用戶(hù)希望企業(yè)業(yè)務(wù)能7×24不間斷運(yùn)行,同時(shí)企業(yè)卻面臨越來(lái)越多業(yè)務(wù)中斷的風(fēng)險(xiǎn),如企業(yè)系統(tǒng)復(fù)雜性的增加,頻繁的功能更新和發(fā)布等。如何確保業(yè)務(wù)連續(xù)性,提升韌性,成...

關(guān)鍵字: 亞馬遜 解密 控制平面 BSP

8月30日消息,據(jù)媒體報(bào)道,騰訊和網(wǎng)易近期正在縮減他們對(duì)日本游戲市場(chǎng)的投資。

關(guān)鍵字: 騰訊 編碼器 CPU

8月28日消息,今天上午,2024中國(guó)國(guó)際大數(shù)據(jù)產(chǎn)業(yè)博覽會(huì)開(kāi)幕式在貴陽(yáng)舉行,華為董事、質(zhì)量流程IT總裁陶景文發(fā)表了演講。

關(guān)鍵字: 華為 12nm EDA 半導(dǎo)體

8月28日消息,在2024中國(guó)國(guó)際大數(shù)據(jù)產(chǎn)業(yè)博覽會(huì)上,華為常務(wù)董事、華為云CEO張平安發(fā)表演講稱(chēng),數(shù)字世界的話(huà)語(yǔ)權(quán)最終是由生態(tài)的繁榮決定的。

關(guān)鍵字: 華為 12nm 手機(jī) 衛(wèi)星通信

要點(diǎn): 有效應(yīng)對(duì)環(huán)境變化,經(jīng)營(yíng)業(yè)績(jī)穩(wěn)中有升 落實(shí)提質(zhì)增效舉措,毛利潤(rùn)率延續(xù)升勢(shì) 戰(zhàn)略布局成效顯著,戰(zhàn)新業(yè)務(wù)引領(lǐng)增長(zhǎng) 以科技創(chuàng)新為引領(lǐng),提升企業(yè)核心競(jìng)爭(zhēng)力 堅(jiān)持高質(zhì)量發(fā)展策略,塑強(qiáng)核心競(jìng)爭(zhēng)優(yōu)勢(shì)...

關(guān)鍵字: 通信 BSP 電信運(yùn)營(yíng)商 數(shù)字經(jīng)濟(jì)

北京2024年8月27日 /美通社/ -- 8月21日,由中央廣播電視總臺(tái)與中國(guó)電影電視技術(shù)學(xué)會(huì)聯(lián)合牽頭組建的NVI技術(shù)創(chuàng)新聯(lián)盟在BIRTV2024超高清全產(chǎn)業(yè)鏈發(fā)展研討會(huì)上宣布正式成立。 活動(dòng)現(xiàn)場(chǎng) NVI技術(shù)創(chuàng)新聯(lián)...

關(guān)鍵字: VI 傳輸協(xié)議 音頻 BSP

北京2024年8月27日 /美通社/ -- 在8月23日舉辦的2024年長(zhǎng)三角生態(tài)綠色一體化發(fā)展示范區(qū)聯(lián)合招商會(huì)上,軟通動(dòng)力信息技術(shù)(集團(tuán))股份有限公司(以下簡(jiǎn)稱(chēng)"軟通動(dòng)力")與長(zhǎng)三角投資(上海)有限...

關(guān)鍵字: BSP 信息技術(shù)
關(guān)閉
關(guān)閉