為了實現(xiàn)兩條EOSIO體系區(qū)塊鏈間token的跨鏈轉(zhuǎn)移,首先需要解決兩個難題,1.輕客戶端如何實現(xiàn),2.如何確保跨鏈交易的完整性和可靠性, 如何防止雙花和重放攻擊。下文均以EOS主網(wǎng)和BOS主網(wǎng)為例進行說明,但本文檔適用于任何兩條EOSIO體系的區(qū)塊鏈。
?
一、術(shù)語
BOSIBC:是指BOSCORE技術(shù)團隊開發(fā)的IBC合約及插件。
二、關(guān)鍵概念及數(shù)據(jù)結(jié)構(gòu)
· Simple Payment Verification (SPV)
簡單支付驗證技術(shù)最早在中本聰?shù)?a href="http://www.tjjbhg.com/tags/比特幣/" target="_blank">比特幣白皮書中提出Bitcoin,用于驗證一筆交易存在于區(qū)塊鏈中。 SPV client存儲著連續(xù)的區(qū)塊頭,但沒有區(qū)塊體,因此只需占用很小的存儲空間。當獲得一筆交易和這筆交易的Merkle path后,可以驗證這筆交易是否 存在于區(qū)塊鏈上。
· Lightwight client (lwc)
輕客戶端,即SPV client,即由區(qū)塊頭組成的一條輕量的鏈。
· Merkle path 默克爾路徑。為驗證一筆交易是否存在于某個區(qū)塊中,只需要提供交易原始數(shù)據(jù)和交易在所在區(qū)塊的merkle path,而無需提供整個區(qū)塊體,通過計算merkle path并和區(qū)塊頭中 記錄的merkle root對比,若相等,則說明此交易存在于此區(qū)塊中。merkle path也被稱為merkle branch。
· Block Producer Schedule
BP Schedule是基于DPOS機制的EOSIO體系公鏈用于決定生產(chǎn)區(qū)塊權(quán)利的技術(shù),新的BP Schedule是由上一批BP Schedule包含的Block Producers認證通過后生效 以此確保嚴格的BP權(quán)利交接,在輕客戶端中跟隨對應(yīng)主網(wǎng)的BP Schedule是IBC系統(tǒng)邏輯的一項核心技術(shù)。
· forkdb
EOSIO節(jié)點在運行時,有兩個底層的db用于存儲區(qū)塊信息,一個是blog即block log,用于存儲不可逆區(qū)塊,一個是forkdb,用于存儲可逆區(qū)塊。 forkdb存儲的是當前區(qū)塊鏈最頂端的一部分區(qū)塊信息,一個區(qū)塊首先要被forkdb接受才能最終進入不可逆區(qū)塊,IBC系統(tǒng)在合約實現(xiàn)的輕客戶端主要參考了forkdb的邏輯。
三、輕客戶端
為了解決跨鏈問題,首先要解決的是輕客戶端如何實現(xiàn)的問題。
1. 輕客戶端運行在哪里合理,合約中還是合約外,例如插件中;
2. 若運行在合約中,是實時同步對方鏈的全部區(qū)塊頭數(shù)據(jù),還是根據(jù)需要同步一部分區(qū)塊數(shù)據(jù)來驗證交易,因為如果同步全部區(qū)塊數(shù)據(jù)會消耗兩條鏈大量cpu資源。
3. 若運行在合約中,如何確保輕客戶端的可信性,如何防止惡意攻擊,如何做到完全去中心化,不依賴對任何中繼節(jié)點的信任;
3.1 輕客戶端是否運行在合約中
比特幣的輕客戶端最早是運行在單個節(jié)點上(如個人電腦或去中心化比特幣手機錢包),用于驗證交易是否存,并查看交易所在區(qū)塊深度。
IBC和去中心化錢包對輕客戶端的需求是不同的,去中心化錢包一般運行在個人的手機App上,為用戶個人提供交易驗證服務(wù),而IBC系統(tǒng)需要的輕客戶端 要對所有人公開可查可信,從這個角度看,一個能夠獲得大眾信任的輕客戶端只能運行在合約中,因為只有合約的數(shù)據(jù)是全局一致不可篡改的, 運行在合約外則無法實現(xiàn)一個可信的輕客戶端,因此BOSIBC將輕客戶端運行在合約中。
3.2 是否同步全量區(qū)塊頭信息
在比特幣和以太坊的輕客戶端中,會尋找一個起點和后續(xù)的一些驗證點,輕客戶端會同步起點后的全量的區(qū)塊頭信息。比特幣每年產(chǎn)生的所有區(qū)塊的區(qū)塊頭體積僅有4Mb, 按現(xiàn)在移動設(shè)備的存儲能力,是完全可以容納的,并且同步這些區(qū)塊頭也不會消耗移動設(shè)備大量計算資源。然而EOSIO的情況卻很不同, EOSIO每0.5秒一個區(qū)塊,實際測試可知,每添加一個區(qū)塊頭到合約中需要消耗0.5毫秒cpu,每刪除一個區(qū)塊頭需要0.2毫秒,因此每處理一個區(qū)塊頭需要0.7ms的cpu。 假設(shè)要同步對方EOSIO公鏈的全量區(qū)塊頭信息,按現(xiàn)在每個區(qū)塊總的cpu時間200ms計算,也就是需要一條鏈全部計算的0.7ms / 200ms = 0.35%才能實時全量同步 另一條鏈的所有區(qū)塊頭, 按實際全網(wǎng)抵押總量為4億token計算,如果再cpu繁忙時保證IBC系統(tǒng)正常工作,需要為push區(qū)塊信息的賬戶抵押 4億 * 0.35% = 140萬token,這是個很大的數(shù)目。又因為EOSIO倡導多側(cè)鏈的生態(tài),假設(shè)未來有多條側(cè)鏈和EOSIO主網(wǎng)實現(xiàn)跨鏈,并且側(cè)鏈與側(cè)鏈間 也實現(xiàn)了一對多的跨鏈,按1對10計算,每條鏈需要維護10個輕客戶端,則只為了維護這些輕客戶端就需要消耗3.5%的單條鏈全網(wǎng)cpu,這個比例實在是太高了, 因此需要尋找更合理的方案。
設(shè)計跨鏈通信的過程是一種尋找可信證據(jù)的過程,有沒有一種方案即不需要同步全量區(qū)塊信息,又可以保證輕客戶端的可信性,EOSIO底層已經(jīng)為實現(xiàn)這一目的有所準備。 我們先假設(shè),如果BP schedule自始至終不會變化,那么任何時候,當ibc.chain合約中獲得一連串的簽名驗證通過的區(qū)塊頭,比如第n ~ n+336個, 并且有2/3以上的活躍bp在出塊,就可以確信第n個區(qū)塊已經(jīng)是不可逆的,可以用于驗證跨鏈交易。 然后,就是需要考慮有BP schedule更換的情況了,當出現(xiàn)BP schedule更換時,不在接受交易驗證,直到更換完成,處理BP更換時相對復雜的過程,后續(xù)會更詳細介紹, 因此使用這個方案就可以大大降低需要同步的區(qū)塊頭數(shù)量,只有在BP列表更換或有跨鏈交易時才需要同步區(qū)塊。
為了實現(xiàn)這一目的,在ibc.chain中引入了概念section,一個section記錄的是一段連續(xù)的區(qū)塊頭信息,section結(jié)構(gòu)不存儲具體的區(qū)塊頭信息,而是記錄這一段 區(qū)塊頭的第一個區(qū)塊編號(first)和最后一個區(qū)塊編號(last),具體區(qū)塊頭信息在chaindb中存儲,每個section都有一個valid值,在沒有bp schedule更替的時候, 只要有2/3的活躍BP在出塊,并且last - first 》 lib_depth則認為first ~ last - lib_depth的區(qū)塊是不可逆的,可以用于驗證跨鏈交易, 當遇到BP schedule 更替,section的valid變?yōu)閒alse,不再接受交易驗證,直到schedule更替完成,valid重新變?yōu)閠rue之后,繼續(xù)驗證跨鏈交易。
3.3 如何確保輕客戶端的可信性
3.3.1 forkdb
1.一個新的區(qū)塊是如何追加到forkdb的
一個運行的nodeos節(jié)點維護著兩個底層數(shù)據(jù)結(jié)構(gòu)blog 和forkdb, blog用于存儲不可逆的區(qū)塊信息,其存儲的數(shù)據(jù)是序列化的signed_block,forkdb用于存儲可逆區(qū)塊信息,其存儲的數(shù)據(jù)是block_state, block_state比signed_block包含更多區(qū)塊相關(guān)信息。一個區(qū)塊首先要被追加到forkdb,才可能最終變?yōu)椴豢赡鎱^(qū)塊而移除forkdb進入blog, 一個區(qū)塊的block_state信息是如何獲得的呢,并非生產(chǎn)區(qū)塊的BP將所生產(chǎn)區(qū)塊的block_state通過p2p網(wǎng)絡(luò)傳遞給其他bp和全節(jié)點,p2p網(wǎng)絡(luò) 只傳遞signed_block, 當一個節(jié)點通過p2p網(wǎng)絡(luò)接收到一個signed_block后,它會使用此signed_block構(gòu)建block_state并驗證簽名 相關(guān)函數(shù), 其中需要說明的幾個關(guān)鍵點是,1.blockroot_merkle,2.get_scheduled_producer(),3.verify_signee()。
blockroot_merkle
EOSIO在block_state::block_header_state結(jié)構(gòu)中維護了一個blockroot_merkle的incremental_merkle數(shù)據(jù),incremental_merkle實際是 一個完整的merkle樹的活躍節(jié)點,使用incremental_merkle只需維護極少的活躍節(jié)點信息即可不斷累加并獲得merkle_root,是block_state 中使用的一個關(guān)鍵技術(shù)。BOSIBC的ibc.chain合約同樣使用了此數(shù)據(jù)結(jié)構(gòu)。
blockroot_merkle從創(chuàng)世區(qū)塊id不斷累加,但是signed_block和blog中并沒有這個數(shù)據(jù),只有forkdb的每個block_state中記錄著當前block的 blockroot_merkle,并且此值被用于計算區(qū)塊簽名。
get_scheduled_producer()
此函數(shù)根據(jù)一個區(qū)塊的header.timestamp計算出應(yīng)該生成此區(qū)塊的producer_key(見block_header_state::next()),為后續(xù)驗證簽名做準備。
驗證簽名相關(guān)函數(shù)如下
digest_type block_header_state::sig_digest()const {
auto header_bmroot = digest_type::hash( std::make_pair( header.digest(), blockroot_merkle.get_root() ) );
return digest_type::hash( std::make_pair(header_bmroot, pending_schedule_hash) );
}
public_key_type block_header_state::signee()const {
return fc::crypto::public_key( header.producer_signature, sig_digest(), true );
}
void block_header_state::verify_signee( const public_key_type& signee )const {
EOS_ASSERT( block_signing_key == signee, wrong_signing_key, “block not signed by expected key”,
(“block_signing_key”, block_signing_key)( “signee”, signee ) );
}
驗證簽名的第一步是獲得區(qū)塊摘要,即sig_digest(),此函數(shù)中用到了header.digest(),blockroot_merkle.get_root()和pending_schedule_hash; 第二步是獲得簽名公鑰,即signee(),通過區(qū)塊的producer_signature和sig_digest()計算BP公鑰; 第三步是驗證公鑰是否正確,即verify_signee(),此函數(shù)在block_header_state::next()被調(diào)用;驗證通過后,一個區(qū)塊被追加的forkdb中的分支中。
所以在forkdb中每添加一個區(qū)塊都經(jīng)過了非常嚴格全面的效驗,核心是包括blockroot_merkle,get_scheduled_producer()和verify_signee(), 在ibc.chain合約完全繼承了forkdb嚴格的效驗。
2.forkdb如何處理分叉
當添加一個新的區(qū)塊導致fordb的head.id和controller_impl的head.id不同時,則重新選擇分支。 源碼參考eosio::chain::controller_impl的push_block()和maybe_switch_forks();
3.LIB如何確定
EOSIO目前使用的共識方式是dpos,當構(gòu)造一個區(qū)塊的block_header_state時會設(shè)定required_confs,此值為當前活躍BP數(shù)量的2/3+1, 在21個BP的情況下,required_confs為15。每個區(qū)塊頭中都有header.confirmed,用于對前面的區(qū)塊進行確認,每個區(qū)塊得到一個確認, 其required_confs會減1,當某個區(qū)塊的required_confs減少到零時,此區(qū)塊會被最新區(qū)塊(即forkdb的head)提名為dpos_proposed_irreversible_blocknum, 當某個區(qū)塊獲得了2/3的BP提名后,其變?yōu)椴豢赡鎱^(qū)塊,即進入LIB。由于確認的信息是在header中傳遞的,因此一個區(qū)塊從產(chǎn)生到進入LIB總共需要 兩個2/3輪,也就是 12 *( 14 * 2 ) = 336才會進入LIB,考錄到BP每次都是連續(xù)出12個區(qū)塊,只有第一個區(qū)塊的header.confirmed為非零, 因此當一個BP開始出塊時,只有第一個區(qū)塊會提升LIB,因此實際head和LIB的差距在325至336之間,但是在有BP丟塊的情況下,head和LIB的差距可能出現(xiàn)小于 325至336。
4.BP列表是如何更換的
在pow的區(qū)塊鏈中,比如比特幣和以太坊,是選擇算力累加最大的分叉作為主鏈,一個區(qū)塊只有包含一定的算力才有可能被認可,最終變?yōu)椴豢赡妗?而在以dpos為共識算法的EOS中,區(qū)塊被認可的標記是BP簽名,因此BP列表在EOSIO中具有至關(guān)重要的地位。IBC的輕客戶端同樣需要維護BP列表和BP列表的更換, 因此需要透徹分析BP列表的更換邏輯。
第一步,在系統(tǒng)合約eosio.system的onblock()函數(shù)中,系統(tǒng)會每分鐘一次嘗試更新bp列表update_elected_producers( timestamp ),此函數(shù)最終調(diào)用 wasm接口set_proposed_producers(),通過一系列檢查后,會將新的schedule和當前區(qū)塊編號存到global_property_object對象中。
第二部,當此區(qū)塊變?yōu)椴豢赡嬷螅瑫诋斍暗膒ending區(qū)塊中設(shè)置新的名單header.new_producers,并重置global_property_object對象,當前 pending區(qū)塊編號會被記錄到pending_schedule_lib_num,此時在nodeos日志中可以看到新的名單;具體邏輯參考controller::start_block() // Promote proposed schedule to pending schedule.。 也就是說新的名單從proposed schedule變?yōu)閜ending schedule大約需要經(jīng)歷325至336個區(qū)塊。從這里開始, 后面區(qū)塊block_header_state的pending_schedule.version會比active_schedule.version大1.
第三步,當pending_schedule_lib_num變?yōu)椴豢赡婧螅琣ctive_schedule會被pending schedule替換,整個的BP更換過程完成。 從pending schedule出現(xiàn)到其變?yōu)閍ctive_schedule同樣需要經(jīng)歷約325至336區(qū)塊。
IBC系統(tǒng)的輕客戶端同樣需要繼承forkdb的這些邏輯,才能實現(xiàn)可信的輕客戶端。然而,輕客戶端是在合約中實現(xiàn),需要充分考慮合約的特性和限制, 因此在實現(xiàn)細節(jié)上,需要做諸多調(diào)整。
3.3.2 eosio::table(“chaindb”), ibc.chain合約中的forkdb
1.輕客戶端(lwc)的LIB如何確定
有兩種方案,一種是完全按forkdb的邏輯,維護一整套confirm_count和confirmations等block_header_state相關(guān)信息,每添加一個區(qū)塊 計算一次LIB,這樣做的優(yōu)點是可以準確獲得實時LIB值,然而對于輕客戶端來說,其關(guān)心的是區(qū)塊已經(jīng)不可逆,而并非實時的精確LIB值。有沒有更簡單的方案呢, 根據(jù)上述的邏輯,如果有活躍的2/3以上的BP在出塊,并且某個區(qū)塊的深度超過336,則此區(qū)塊一定是不可逆的,可以用于驗證跨鏈交易;使用這種方案, 可以簡化合約中forkdb的復雜度。
ibc.chain合約中表global的lib_depth是一個深度值,當在一段連續(xù)的區(qū)塊頭中,某個區(qū)塊頭的深度超過此值時,則認為不可逆,可以用于驗證交易了。 此值應(yīng)該設(shè)置多少合適呢,可以設(shè)置成336,當輕客戶端檢查到有2/3以上的BP在出塊,則認為深度超過了336的區(qū)塊是不可逆的。然而在合約中添加和刪除區(qū)塊頭 是非常耗cpu的,實際測試可知,每添加一個區(qū)塊頭需要消耗0.5毫秒cpu,每刪除一個區(qū)塊頭需要0.2毫秒,因此每個區(qū)塊頭需要0.7ms的cpu。 是否會出現(xiàn)主網(wǎng)巨大波動,導致沒有進lib的區(qū)塊全部回滾呢,這是有可能的,實際也發(fā)生過,因此要必須確保一筆跨鏈交易所在區(qū)塊進入lib,再開始處理。 插件在此時可以起到一定的作用,在BOSCORE技術(shù)團隊研發(fā)的ibc_plugin中,設(shè)置了參數(shù),只處理一定深度內(nèi)的跨鏈交易,這樣,插件中的深度和合約中的深度相加 超過336即可。這只是BOSIBC初期的做法,目的是避免消耗大量cpu,后續(xù)可能會考慮將合約中的深度設(shè)置為336,從而完全不依賴中繼的深度,然而無論是插件 還是合約中增加深度值,都會直接延長跨鏈交易到賬時間,從而影響用戶體驗,因此需要根據(jù)實際情況確定一個合理的值,從而即保證足夠安全又不失良好的用戶體驗。
2.表chaindb
表chaindb是ibc.chain合約中的forkdb,ibc.chain合約中沒有blog結(jié)構(gòu),和eosio中forkdb使用的block_header_state不同,chaindb進行了大量精簡,只保留了 block_num、block_id、header、active_schedule、pending_schedule、blockroot_merkle、block_signing_key7個數(shù)據(jù),又因為 bp schedule需要占用大量空間,因此在另外的表prodsches中存儲實際schedule信息,在chaindb中用id引用,以節(jié)省內(nèi)存占用和wasm cpu消耗。
3.輕客戶端的創(chuàng)世區(qū)塊
輕客戶端需要一個可信的起點,此起點是輕客戶端的創(chuàng)世區(qū)塊頭,后面所有區(qū)塊頭的驗證都是基于創(chuàng)世區(qū)塊頭的信息。 創(chuàng)世區(qū)塊頭需要block_header_state中的blockroot_merkle,active_schedule和header信息,才能驗證區(qū)塊簽名。 源碼為chain::chaininit(),最重要一個限制是,創(chuàng)世區(qū)塊頭的pending_schedule必須和active_schedule相同,因為其不同意味著 此區(qū)塊是bp列表更替過程中的一個區(qū)塊,如果使用更替過程中的區(qū)塊,需要同步后續(xù)的區(qū)塊,直到active_schedule被pending_schedule替換, 增加了復雜度,因此這樣的區(qū)塊不適合作為創(chuàng)世區(qū)塊。
4.輕客戶端是如何添加新區(qū)塊的
輕客戶端添加header的方式和和eosio的forkdb非常類似。源碼見ibc.chain的chain::pushheader()。 第一步,通過區(qū)塊編號驗證是否能夠連接到最新的section 第二部,是否需要處理分叉,刪除舊數(shù)據(jù)。在ibc.chainz中不會同時保存多個分支,而是以后者替代前者的方式實現(xiàn)對分叉的處理。 第三步,通過區(qū)塊id驗證是否能夠連接到最新的section 第四部,構(gòu)造block_header_state,并驗證BP簽名
其中最核心的是構(gòu)造block_header_state,在這個過程中處理的BP schedule的更換,確保有2/3以上活躍BP(見section_type::add())。
5. Section Section是chaindb的核心概念和創(chuàng)新,意思是一段連續(xù)的區(qū)塊頭,Section的管理也是最ibc.chain的核心的邏輯。 使用section的目的是降低cpu消耗,只有在BP schedule有變化或有跨鏈交易時才需要同步一部分區(qū)塊頭。 任何section的起始區(qū)塊不能是 bp schedule 更換過程中的區(qū)塊,也就是說,任何一個section的起始區(qū)塊的pending_schedule.version必須等于 active_schedule.version,并且一個section的起始區(qū)塊頭的active_schedule必須和前一個section最后區(qū)塊的active_schedule相同, 這樣就保證了在任意兩個section之間一定不存在BP schedule的更換,每一此BP schedule更換的完整過程必須在某個section中完成,從而確保 section數(shù)據(jù)的可信性。
四、跨鏈交易
1. 跨鏈交易三部曲
一筆跨鏈交易分為三個過程,下面以將EOS從EOS主網(wǎng)跨鏈轉(zhuǎn)賬到BOS主網(wǎng)為例說明,首先用戶在EOS主網(wǎng)發(fā)起一筆跨鏈交易orig_trx,在EOS側(cè)ibc.token合約的 origtrx表中會記錄此交易信息,當這筆交易所在區(qū)塊進入lib后,EOS側(cè)IBC中繼(relay_eos)將此交易和交易相關(guān)信息(區(qū)塊信息及Merkle路徑) 傳遞到BOS側(cè)中繼(relay_bos);relay_bos構(gòu)造cash交易并調(diào)用BOS側(cè)ibc.token合約的cash接口,如果調(diào)用成功, cash函數(shù)中會給目標用戶發(fā)行對應(yīng)的token;等cash交易所在的區(qū)塊進入lib后,relay_bos會將cash_trx和此交易相關(guān)信息(區(qū)塊信息及Merkle路徑) 傳遞到relay_eos,relay_eos構(gòu)造cashconfirm交易并調(diào)用EOS側(cè)ibc.token合約的cashconfirm接口,cashconfirm會刪除EOS側(cè)ibc.token合約 中對orig_trx的記錄,至此一筆完整的跨鏈交易完成。
2. 跨鏈失敗的交易
跨鏈交易是可能失敗的,比如指定的賬戶在對方鏈上不存在,或者由于網(wǎng)絡(luò)環(huán)境惡劣,導致調(diào)用cash接口失敗,未能成功跨鏈的交易會被回滾,即原路退還用戶的資產(chǎn), 然而現(xiàn)在的IBC系統(tǒng)是交易驅(qū)動的,失敗的IBC交易需要等到有成功的IBC交易完成后才會被回滾。(注:后續(xù)版本升級會讓失敗的交易盡快回滾)
3. 如何防止replay攻擊,即雙花攻擊
防止雙花攻擊分為兩個階段:
1,一筆成功的跨鏈交易只能執(zhí)行一次cash,否則會造成重復cash。
2,對于每一個cash交易,必須將其相關(guān)信息傳回原鏈執(zhí)行cashconfirm,以消除合約中記錄的原始交易信息,否則會出現(xiàn)即在目的鏈上給用戶發(fā)行了token, 又將原鏈的token退還給了用戶。
cash函數(shù)是ibc.token的核心邏輯,ibc.token合約中記錄著最近執(zhí)行cash的原始交易id,即orig_trx_id,并且新的cash的orig_trx的區(qū)塊編號必須 大于或等于所有orig_trx所在的區(qū)塊編號,也就是說必須按原始交易在原鏈按區(qū)塊的順序進行cash,(執(zhí)行cash時,原鏈某個區(qū)塊內(nèi)的跨鏈交易順序是無關(guān)緊要的) ,再結(jié)合trx_id檢查,可以確保一筆跨鏈交易只能執(zhí)行一次cash。
同樣,cashconfirm接口會檢查cash交易的編號seq_num,此編號必須逐一遞增,以確保所有在目的鏈上的cash交易都會刪除在原鏈上的原始交易記錄, 從而確保不會出現(xiàn)雙花的情況。
五、插件
插件的作用分為兩部分:1,輕客戶端同步;2,跨鏈交易傳遞。
核心邏輯請參考ibc_plugin_impl::ibc_core_checker()
ibc_plugin主要參考了net_plugin的框架。
六、問答
問:IBC合約的多個action中用到了relay的權(quán)限,那么,本IBC系統(tǒng)是否依賴對中繼的信任。
答:目前出于安全以及快速功能迭代的考量,特意添加了中繼權(quán)限,隨著功能逐漸完善 BOS IBC 方案會支持多中繼機制,以避免單點風險。
驗證relay權(quán)限處于兩種考慮:1,ibc.chain合約使用了section的機制,現(xiàn)在的邏輯不允許為舊的section添加區(qū)塊,也不允許在一個section前面 添加區(qū)塊頭,如果任何人都可以調(diào)用pushsection接口,假設(shè)應(yīng)該push的區(qū)塊范圍是1000-1300,故意搗亂的人可能會搶先push 1100-1300, 從而導致1000-1100無法被push,進而導致一些跨鏈交易無法成功,(注,此問題會在后續(xù)版本中考慮優(yōu)化);2,考慮到IBC系統(tǒng)承載著 大量用戶資產(chǎn),并且本系統(tǒng)還未經(jīng)過長期市場考驗,因此增加了relay權(quán)限,以降低安全風險。
七、升級計劃
1. 兼容pbft
2. 以更優(yōu)雅的方式支持多條側(cè)鏈&EOS主鏈互相跨鏈
3. 支持token以外其他類型數(shù)據(jù)的跨鏈
評論