跨鏈系統構建-basecoin的IBC

basecoin的IBC

一、概述

cosmos網絡中最重要的功能實現是InterBlockchainCommunication(IBC),IBC協議支持不同區塊鏈之間的互操作性。cosmos網絡將IBC作爲一個basecoin插件實現,我們將使用cosmos來跨區塊鏈發送token。

IBC插件定義了一組交易集合作爲AppTx的子類型,要使用這個插件,需要設置AppTx.Name爲“IBC“,同時需要設置data域爲序列化的IBC交易類型。

二、IBC

IBC的目的是使一個區塊鏈能夠作爲另一個區塊鏈的輕客戶端,由於我們使用的是經典的PBFT算法,因此輕客戶端驗證成本低且簡單:因爲需要做的就是檢查最新塊上的驗證者簽名並驗證merkle證明。

在tendermint中,驗證者在處理一個節點之前需要共識,這意味着區塊簽名和區塊狀態根不會包含在當前這個區塊中,而是下一個區塊中,這樣每個區塊包含一個叫做lastcommit的域,包含了前一個區塊的commit,區塊頭還包含一個叫做apphash的域,是merkle的根hash。所以如果我們想驗證高度H的區塊的apphash,我們需要區塊高度H+1的lastcommit中的簽名。

輕客戶端協議不需要下載一個區塊鏈所有的區塊頭,客戶端總是維護最新的區塊頭,只要驗證者沒有變動。如果驗證者有變動,客戶端需要跟蹤這些變動,需要下載每個區塊的頭,因爲簽名有變動。

現在我們可以準確描述出IBC的工作原理,假如我們有兩個鏈chain1和chain2,我們想要從chain1發送一些數據到chain2,大概的工作流程如下:

1. 在chain2上註冊chain1的詳細信息(如chainID,genesis配置)

2. 在chain1上收到一個交易,需要進行IBC,目標地址爲chain2

3. 向chain2同步chain1最新的狀態(區塊頭信息,commit簽名)

4. chain1將IBC數據包發送到chain2,包括在chain1上已經提交的交易的證明,chain2可以驗證該交易因爲其包含了當前的區塊頭和commit

以上每一步都需要一個IBC的交易:

1. IBCRegisterChainTx

type IBCRegisterChainTx struct { BlockchainGenesis }
type BlockchainGenesis struct { ChainID string Genesis string }

IBCRegisterChainTx用於在另一條鏈上註冊當前鏈,包含了需要註冊的鏈的chainID和genesis配置,這個交易僅僅發送一次,多次發送將給出error的response。

2. IBCUpdateChainTx

type IBCUpdateChainTx struct {
  Header tm.Header
  Commit tm.Commit
}

IBCUpdateChainTx用於在另一條鏈上更新當前鏈的狀態,包含了區塊頭和commit的簽名數據,後續會包含驗證者的變動信息,任何人都可以轉發IBCUpdateChainTx,就像發送固定頻率的鏈狀態更新包和驗證者變動包一樣。

3. IBCPacketCreateTx

type IBCPacketCreateTx struct {
  Packet
}

type Packet struct {
  SrcChainID string
  DstChainID string
  Sequence   uint64
  Type string
  Payload    []byte
}

IBCPacketCreateTx用於創建一個跨鏈通信的數據包,包含了源chainID和目標chainID、包類型、和payload。

payload數據格式還沒有定義,可以是任意的字節。

這個IBC交易主要用於以下場景:

chain2在chain1上有一個賬戶,在chain1上使用IBCPacketCreateTx發送資金到這個賬戶,這樣我們可以給chain2證明在chain1鏈上已經有到其賬戶的一個交易,這些資金只能被chain2到chain1的IBC消息解鎖,消息需要指定發送鎖定的資金到chain1的另一個賬戶上。

4. IBCPacketPostTx

type IBCPacketPostTx struct {
  FromChainID     string // The immediate source of the packet, not always Packet.SrcChainID
  FromChainHeight uint64 // The block height in which Packet was committed, to check Proof Packet
  Proof *merkle.IAVLProof
}

IBCPacketPostTx用於從一個鏈發送IBC包到另一個鏈,包含了另一個鏈的交易數據和當前鏈上已經commit的交易的驗證信息。

交易的驗證信息是IAVL樹的一個merkle驗證,IAVL樹是一個平衡二叉搜索樹,包含了節點列表,這些節點通過hash到最後形成一個merkle根hash,這個hash一定和高度H+1的區塊的頭中AppHash匹配。

三、IBC State

我們已經分析了所有的交易類型,接下來看看狀態,每個鏈在merkle樹中存儲了一些IBC狀態,被跟蹤的每條鏈,我們需要存儲:

1. genesis配置

2. 最新的狀態

3. 當前高度的header

我們還需要存儲所有incoming包和outgoing包。

每當一個IBCUpdateChainTx交易被提交,鏈的狀態會被更新,當IBCPacketCreateTx的時候,新的數據包被加入到outgoing,當IBCPacketPostTx的時候,新的數據包被加入到incoming。

四、merkle查詢

basecoin應用程序使用一個單獨的merkle樹,該樹在其所有狀態中共享,包括內置賬戶狀態和所有的插件狀態,所以,使用明確的鍵名和/或hash來確保沒有衝突。

我們可以使用ABCI Query方法來查詢merkle樹,如果我們傳入正確的key,它將返回相應的值,以及證明key和值包含在merkle樹中。

查詢的結果可以用來作爲IBCPacketPostTx的證明。

五、中繼

雖然我們在內部需要所有這些數據包類型以便以安全的方式跟蹤兩條鏈,但對於正常的流程,我們可以運行一箇中繼節點來處理跨鏈交互。

使用中繼的情況下,需要兩個步驟,首先basecoin relay init,必須運行一次從而讓鏈間註冊,確保鏈準備好發送和接收包,然後basecoin relay start,一個守護進程,在每條鏈上輪詢隊列,轉發所有的新消息到對應的鏈。

這個需要中繼能訪問通信的兩條鏈上的資金賬戶,從而支付需要轉發的IBC包。

六、準備

確保安裝了basecoin和basecli,basecoin是創建新的加密貨幣應用程序的框架,它帶有一個默認就啓動的IBC插件。

設置一些環境變量:

[kingnet@pdev3 ~]$ rm -rf ~/.ibcdemo
[kingnet@pdev3 ~]$ export BCHOME1_CLIENT=~/.ibcdemo/chain1/client
[kingnet@pdev3 ~]$ export BCHOME1_SERVER=~/.ibcdemo/chain1/server
[kingnet@pdev3 ~]$ export BCHOME2_CLIENT=~/.ibcdemo/chain2/client
[kingnet@pdev3 ~]$ export BCHOME2_SERVER=~/.ibcdemo/chain2/server
[kingnet@pdev3 ~]$ alias basecli1="basecli --home $BCHOME1_CLIENT"
[kingnet@pdev3 ~]$ alias basecli2="basecli --home $BCHOME2_CLIENT"
[kingnet@pdev3 ~]$ alias basecoin1="basecoin --home $BCHOME1_SERVER"
[kingnet@pdev3 ~]$ alias basecoin2="basecoin --home $BCHOME2_SERVER"
[kingnet@pdev3 ~]$ export CHAINID1="test-chain-1"
[kingnet@pdev3 ~]$ export CHAINID2="test-chain-2"
[kingnet@pdev3 ~]$ export PORT_PREFIX1=1234
[kingnet@pdev3 ~]$ export PORT_PREFIX2=2345
[kingnet@pdev3 ~]$ export RPC_PORT1=${PORT_PREFIX1}7
[kingnet@pdev3 ~]$ export RPC_PORT2=${PORT_PREFIX2}7
[kingnet@pdev3 ~]$

七、安裝第一條鏈

創建test-chian-1鏈上的賬戶:

[kingnet@pdev3 ~]$ basecli1 keys new money
Enter a passphrase:
Repeat the passphrase:
money           5DA404DC686F44E78810E8DE63EBC2D6D440FAF2
**Important** write this seed phrase in a safe place.
It is the only way to recover your account if you ever forget your password.

lesson they festival spider robot put close jaguar work minimum song wish shop measure virus obscure image gossip abstract material rotate castle cluster rigid place balance recipe salt level solution typical bunker hat click toss food female claim empty minute large budget motor crumble maximum recall raven curve vote almost abandon
[kingnet@pdev3 ~]$ basecli1 keys new gotnone
Enter a passphrase:
Repeat the passphrase:
gotnone         D8A5932E4D6FAF6B8C84D2DB6EF2D4FACA40C359
**Important** write this seed phrase in a safe place.
It is the only way to recover your account if you ever forget your password.

drama fiber tomato message sort aim surprise cheap prevent exhaust door veteran video junior film install soldier gorilla artefact foam trigger steak stick cave payment senior arrange palace melt whisper betray absent number fall brain suggest hobby suit assume syrup arrive fence hurt river tent device rebel shift clap amateur abandon
[kingnet@pdev3 ~]$ export MONEY=$(basecli1 keys get money | awk '{print $2}')
[kingnet@pdev3 ~]$ export GOTNONE=$(basecli1 keys get gotnone | awk '{print $2}')
[kingnet@pdev3 ~]$

初始配置配置,給money用戶提供大量初始coin:

[kingnet@pdev3 ~]$ basecoin1 init --chain-id $CHAINID1 $MONEY
[kingnet@pdev3 ~]$

啓動test-chain-1:

[kingnet@pdev3 ~]$ sed -ie "s/4665/$PORT_PREFIX1/" $BCHOME1_SERVER/config.toml
[kingnet@pdev3 ~]$ basecoin1 start &> basecoin1.log &
[2] 193294
[kingnet@pdev3 ~]$

sed命令用於修改配置文件的端口,日誌輸出到basecoin1.log,檢查日誌看是否正確出塊:

[kingnet@pdev3 ~]$ tail -f basecoin1.log
I[05-28|12:19:33.072] Executed block                               module=state height=80 validTxs=0 invalidTxs=0
I[05-28|12:19:33.073] Committed state                              module=state height=80 txs=0 hash=C6D89553EBD974A4F946775CD1D6620BD661A864
I[05-28|12:19:34.059] Executed block                               module=state height=81 validTxs=0 invalidTxs=0
I[05-28|12:19:34.061] Committed state                              module=state height=81 txs=0 hash=C6D89553EBD974A4F946775CD1D6620BD661A864
^C
[kingnet@pdev3 ~]$ 

使用客戶端來驗證test-chain-1已經正確啓動,第一個賬戶有餘額,第二個沒有:

[kingnet@pdev3 ~]$ basecli1 init --node=tcp://localhost:${RPC_PORT1} --genesis=${BCHOME1_SERVER}/genesis.json
Loading validator set from tendermint rpc...
[kingnet@pdev3 ~]$ basecli1 query account $MONEY
{
  "height": 233,
  "data": {
    "pub_key": null,
    "sequence": 0,
    "coins": [
      {
        "denom": "mycoin",
        "amount": 9007199254740992
      }
    ]
  }
}
[kingnet@pdev3 ~]$ basecli1 query account $GOTNONE
ERROR: Account bytes are empty for address D8A5932E4D6FAF6B8C84D2DB6EF2D4FACA40C359
[kingnet@pdev3 ~]$

八、安裝第二條鏈

第二條鏈的安裝基本與第一條相同,主要是需要修改端口,因爲運行在一臺機器上。

爲test-chain-2創建賬戶密鑰:

[kingnet@pdev3 ~]$ basecli2 keys new moremoney
Enter a passphrase:
Repeat the passphrase:
moremoney       3A4F8C378CFAB5E59F39C3F1B90B87B8CB22489B
**Important** write this seed phrase in a safe place.
It is the only way to recover your account if you ever forget your password.

marble vague cricket anger during match that liberty dignity sound ankle best salon fancy will message ketchup fringe tag truly space trial emerge noise about clean tribe spell treat fox coach zone invite noble state bind letter table goddess federal fantasy satoshi exist federal wet neither cloth cliff benefit amateur abandon
[kingnet@pdev3 ~]$ basecli2 keys new broke
Enter a passphrase:
Repeat the passphrase:
broke           A65BE96A51C251537F481096AA3775B55EB0A596
**Important** write this seed phrase in a safe place.
It is the only way to recover your account if you ever forget your password.

raven tiger sadness soup emerge hobby patrol excite torch social end brisk catch keep sphere question actor riot section fold spy security bar senior fog educate nut income solve danger fringe rough blush define slender velvet wrap unfold quality poem attract relief soft sea real stock kitten arrive write advice abandon
[kingnet@pdev3 ~]$ MOREMONEY=$(basecli2 keys get moremoney | awk '{print $2}')
[kingnet@pdev3 ~]$ BROKE=$(basecli2 keys get broke | awk '{print $2}')
[kingnet@pdev3 ~]$

初始配置:

[kingnet@pdev3 ~]$ basecoin2 init --chain-id $CHAINID2 $MOREMONEY
[kingnet@pdev3 ~]$

啓動test-chain-2:

[kingnet@pdev3 ~]$ sed -ie "s/4665/$PORT_PREFIX2/" $BCHOME2_SERVER/config.toml
[kingnet@pdev3 ~]$ basecoin2 start &> basecoin2.log &
[3] 195019
[kingnet@pdev3 ~]$

檢查啓動日誌看是否正確出塊:

[kingnet@pdev3 ~]$ tail -f basecoin2.log
I[05-28|12:28:58.509] Executed block                               module=state height=64 validTxs=0 invalidTxs=0
I[05-28|12:28:58.511] Committed state                              module=state height=64 txs=0 hash=B5EACFA6EA4A1F5A8F88CE4E701CED0F927491C0
I[05-28|12:28:59.488] Executed block                               module=state height=65 validTxs=0 invalidTxs=0
I[05-28|12:28:59.490] Committed state                              module=state height=65 txs=0 hash=B5EACFA6EA4A1F5A8F88CE4E701CED0F927491C0
I[05-28|12:29:00.508] Executed block                               module=state height=66 validTxs=0 invalidTxs=0
I[05-28|12:29:00.510] Committed state                              module=state height=66 txs=0 hash=B5EACFA6EA4A1F5A8F88CE4E701CED0F927491C0
I[05-28|12:29:01.513] Executed block                               module=state height=67 validTxs=0 invalidTxs=0
I[05-28|12:29:01.514] Committed state                              module=state height=67 txs=0 hash=B5EACFA6EA4A1F5A8F88CE4E701CED0F927491C0
I[05-28|12:29:02.499] Executed block                               module=state height=68 validTxs=0 invalidTxs=0
I[05-28|12:29:02.501] Committed state                              module=state height=68 txs=0 hash=B5EACFA6EA4A1F5A8F88CE4E701CED0F927491C0
I[05-28|12:29:03.519] Executed block                               module=state height=69 validTxs=0 invalidTxs=0
I[05-28|12:29:03.520] Committed state                              module=state height=69 txs=0 hash=B5EACFA6EA4A1F5A8F88CE4E701CED0F927491C0
I[05-28|12:29:04.524] Executed block                               module=state height=70 validTxs=0 invalidTxs=0
I[05-28|12:29:04.526] Committed state                              module=state height=70 txs=0 hash=B5EACFA6EA4A1F5A8F88CE4E701CED0F927491C0
^C
[kingnet@pdev3 ~]$

使用客戶端連接test-chain-2來驗證賬戶:

[kingnet@pdev3 ~]$ basecli2 init --node=tcp://localhost:${RPC_PORT2} --genesis=${BCHOME2_SERVER}/genesis.json
Loading validator set from tendermint rpc...
[kingnet@pdev3 ~]$ basecli2 query account $MOREMONEY
{
  "height": 142,
  "data": {
    "pub_key": null,
    "sequence": 0,
    "coins": [
      {
        "denom": "mycoin",
        "amount": 9007199254740992
      }
    ]
  }
}
[kingnet@pdev3 ~]$ basecli2 query account $BROKE
ERROR: Account bytes are empty for address A65BE96A51C251537F481096AA3775B55EB0A596
[kingnet@pdev3 ~]$

九、連接鏈

兩條鏈已經運行,每條鏈有不同的密鑰,接下來啓動一箇中繼將消息從一條鏈轉發到另一條鏈上,從而進行IBC。

中繼賬戶需要一些錢來支付IBC消息,所以在我們開始中繼之前從富裕賬戶轉賬一些資金。

[kingnet@pdev3 ~]$ RELAY_KEY=$BCHOME1_SERVER/key.json
[kingnet@pdev3 ~]$ RELAY_ADDR=$(cat $RELAY_KEY | jq .address | tr -d \")
[kingnet@pdev3 ~]$ basecli1 tx send --amount=100000mycoin --sequence=1 --to=$RELAY_ADDR --name=money
Please enter passphrase for money:
{
  "check_tx": {
    "code": 0,
    "data": "",
    "log": ""
  },
  "deliver_tx": {
    "code": 0,
    "data": "B23167DF11932BEC3C5C2483AC18C8338B72240C",
    "log": ""
  },
  "hash": "2B83744A7A854E64D98E2F7299A27C4D13A971BB",
  "height": 1138
}
[kingnet@pdev3 ~]$ basecli1 query account $RELAY_ADDR
{
  "height": 1160,
  "data": {
    "pub_key": null,
    "sequence": 0,
    "coins": [
      {
        "denom": "mycoin",
        "amount": 100000
      }
    ]
  }
}
[kingnet@pdev3 ~]$ basecli2 tx send --amount=100000mycoin --sequence=1 --to=$RELAY_ADDR --name=moremoney
Please enter passphrase for moremoney:
{
  "check_tx": {
    "code": 0,
    "data": "",
    "log": ""
  },
  "deliver_tx": {
    "code": 0,
    "data": "9905BA121EE6650B277B1D2CDE6E993EF45AA097",
    "log": ""
  },
  "hash": "147AF3D21D67028661BEE9425EA062496C6D2842",
  "height": 646
}
[kingnet@pdev3 ~]$ basecli2 query account $RELAY_ADDR
{
  "height": 659,
  "data": {
    "pub_key": null,
    "sequence": 0,
    "coins": [
      {
        "denom": "mycoin",
        "amount": 100000
      }
    ]
  }
}
[kingnet@pdev3 ~]$

配置中繼:

[kingnet@pdev3 ~]$ basecoin relay init --chain1-id=$CHAINID1 --chain2-id=$CHAINID2 --chain1-addr=tcp://localhost:${RPC_PORT1} --chain2-addr=tcp://localhost:${RPC_PORT2} --genesis1=${BCHOME1_SERVER}/genesis.json --genesis2=${BCHOME2_SERVER}/genesis.json --from=$RELAY_KEY
[kingnet@pdev3 ~]$

啓動中繼:

[kingnet@pdev3 ~]$ basecoin relay start --chain1-id=$CHAINID1 --chain2-id=$CHAINID2 --chain1-addr=tcp://localhost:${RPC_PORT1} --chain2-addr=tcp://localhost:${RPC_PORT2} --from=$RELAY_KEY &> relay.log &
[4] 197724
[kingnet@pdev3 ~]$

兩條鏈已經通過IBC連接,接下來發送一個跨鏈的tx。

十、跨鏈轉賬

[kingnet@pdev3 ~]$ basecli2 query account $BROKE
ERROR: Account bytes are empty for address A65BE96A51C251537F481096AA3775B55EB0A596
[kingnet@pdev3 ~]$ basecli1 tx send --amount=12345mycoin --sequence=2 --to=test-chain-2/$BROKE --name=money
Please enter passphrase for money:
{
  "check_tx": {
    "code": 0,
    "data": "",
    "log": ""
  },
  "deliver_tx": {
    "code": 0,
    "data": "DF5745E4838C4F5B9A8E05D78EDA717B6D925DEC",
    "log": ""
  },
  "hash": "F7EB450C6326D0FC9FFF6F1F72AAB156D919469A",
  "height": 1896
}
[kingnet@pdev3 ~]$ basecli2 query account $BROKE
{
  "height": 1328,
  "data": {
    "pub_key": null,
    "sequence": 0,
    "coins": [
      {
        "denom": "mycoin",
        "amount": 12345
      }
    ]
  }
}
[kingnet@pdev3 ~]$

十一、結論

真可以跨鏈轉賬啊,價值傳輸網就來了!!!!!!





發佈了29 篇原創文章 · 獲贊 8 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章