DASP智慧合約Top10漏洞

FLy_鵬程萬里發表於2018-08-24

該專案是NCC集團的一項舉措。這是一個開放的合作專案,致力於發現安全社群內的智慧合約漏洞。

GitHub地址 https://github.com/CryptoServices/dasp


在瞭解智慧合約Top10之前,我們簡單說一下,OWASP Top10。
OWASP: Open Web Application Security Project


這個專案會公開十大web應用程式安全風險
2017年版下載地址http://www.owasp.org.cn/owasp-project/OWASPTop102017v1.3.pdf

類似的,我們有了智慧合約Top10漏洞。以下是國外原創,翻譯過來的,翻譯可能不準確,還請理解。


1.重入

也被稱為或與空競爭,遞迴呼叫漏洞,未知呼叫等。

這種漏洞在很多時候被很多不同的人忽略:審閱者傾向於一次一個地審查函式,並且假定保護子例程的呼叫將安全並按預期執行。————菲爾戴安

重入攻擊介紹

  • 重入攻擊,可能是最著名的以太坊漏洞,

  • 第一次被發現時,每個人都感到驚訝。

  • 它在數百萬美元的搶劫案中首次亮相,導致了以太坊的分叉。

  • 當初始執行完成之前,外部合同呼叫被允許對呼叫合同進行新的呼叫時,就會發生重新進入。

  • 對於函式來說,這意味著合同狀態可能會在執行過程中因為呼叫不可信合同或使用具有外部地址的低階函式而發生變化。


損失:估計為350萬ETH(當時約為5000萬美元)

攻擊發現時間表

2016/6/5——Christian Reitwiessner發現了一個堅定的反模式
https://blog.ethereum.org/2016/06/10/smart-contract-security/


2016/6/9——更多以太坊攻擊:Race-To-Empty是真正的交易(vessenes.com)
http://vessenes.com/more-ethereum-attacks-race-to-empty-is-the-real-deal/


2016/6/12——在以太坊智慧合約’遞迴呼叫’錯誤發現(blog.slock.it)之後,沒有DAO資金面臨風險。
https://blog.slock.it/no-dao-funds-at-risk-following-the-ethereum-smart-contract-recursive-call-bug-discovery-29f482d348b


2016/6/17——我認為TheDAO現在正在流失(reddit.com)
https://www.reddit.com/r/ethereum/comments/4oi2ta/i_think_thedao_is_getting_drained_right_now/


2016/8/24——DAO的歷史和經驗教訓(blog.sock.it)
https://blog.slock.it/the-history-of-the-dao-and-lessons-learned-d06740f8cfa5

真實世界影響

DAO
https://en.wikipedia.org/wiki/The_DAO_(organization)

示例

  • 一個聰明的合約跟蹤一些外部地址的平衡,並允許使用者通過其公共資金檢索withdraw()功能。

  • 一個惡意的智慧合約使用withdraw()函式檢索其全部餘額。

  • 在更新惡意合約的餘額之前,受害者合約執行call.value(amount)() 低階別函式將乙太網傳送給惡意合約。

  • 該惡意合約有一個支付fallback()接受資金的功能,然後回撥到受害者合約的withdraw()功能。

  • 第二次執行會觸發資金轉移:請記住,惡意合約的餘額尚未從首次提款中更新。結果, 惡意合約第二次成功退出了全部餘額。

程式碼示例

以下函式包含易受重入攻擊影響的函式。當低階別call()函式向msg.sender地址傳送ether時,它變得易受攻擊; 如果地址是智慧合約,則付款將觸發其備用功能以及剩餘的交易gas:

function withdraw(uint _amount) {
    require(balances[msg.sender] >= _amount);
    msg.sender.call.value(_amount)();
    balances[msg.sender] -= _amount;
}

其他資源

DAO智慧合約
https://etherscan.io/address/0xbb9bc244d798123fde783fcc1c72d3bb8c189413#code

分析DAO的利用
http://hackingdistributed.com/2016/06/18/analysis-of-the-dao-exploit/

簡單的DAO程式碼示例
http://blockchain.unica.it/projects/ethereum-survey/attacks.html#simpledao

重入程式碼示例
https://github.com/trailofbits/not-so-smart-contracts/tree/master/reentrancy

有人試圖利用我們的智慧合約中的一個缺陷,盜取它的一切
https://blog.citymayor.co/posts/how-someone-tried-to-exploit-a-flaw-in-our-smart-contract-and-steal-all-of-its-ether/


2.訪問控制

通過呼叫initWallet函式,可以將Parity Wallet庫合約變為常規多sig錢包併成為它的所有者。


  • 訪問控制問題在所有程式中都很常見,而不僅僅是智慧合約。

  • 事實上,這是OWASP排名前10位的第5位。人們通常通過其公共或外部功能訪問合約的功能。

  • 儘管不安全的可視性設定會給攻擊者直接訪問合約的私有價值或邏輯的方式,但訪問控制旁路有時更加微妙。

  • 這些漏洞可能發生在合約使用已棄用tx.origin的驗證呼叫者時,長時間處理大型授權邏輯require並delegatecall在代理庫或代理合約中魯莽使用。

損失:估計為150,000 ETH(當時約3000萬美元)

真實世界影響

奇偶校驗錯誤1
http://paritytech.io/the-multi-sig-hack-a-postmortem/

奇偶校驗錯誤2
http://paritytech.io/a-postmortem-on-the-parity-multi-sig-library-self-destruct/

Rubixi
https://blog.ethereum.org/2016/06/19/thinking-smart-contract-security/

示例

一個聰明的合約指定它初始化它作為合約的地址。這是授予特殊特權的常見模式,例如提取合約能力。
不幸的是,初始化函式可以被任何人呼叫,即使它已經被呼叫。允許任何人成為合約者並獲得資金。

程式碼示例

在下面的例子中,契約的初始化函式將函式的呼叫者設定為它的所有者。然而,邏輯與合約的建構函式分離,並且不記錄它已經被呼叫的事實。

function initContract() public {
    owner = msg.sender;
}

在Parity multi-sig錢包中,這個初始化函式與錢包本身分離並在“庫”合約。使用者需要通過呼叫庫的函式來初始化自己的錢包delegateCall。不幸的是,在我們的例子中,函式沒有檢查錢包是否已經被初始化。更糟糕的是,由於圖書館是一個聰明的合約,任何人都可以自行初始化圖書館並要求銷燬。

其他資源

修復Parity多訊號錢包bug 1
https://github.com/paritytech/parity/pull/6103/files

奇偶校驗安全警報2
http://paritytech.io/security-alert-2/

在奇偶錢包multi-sig hack上
https://blog.zeppelin.solutions/on-the-parity-wallet-multisig-hack-405a8c12e8f7

不受保護的功能
https://github.com/trailofbits/not-so-smart-contracts/tree/master/unprotected_function

Rubixi的智慧合約
https://etherscan.io/address/0xe82719202e5965Cf5D9B6673B7503a3b92DE20be#code


3.算數問題

這個問題,我們之前的文章有提到,也就是比較經典的溢位。

也被稱為整數溢位和整數下溢。

溢位情況會導致不正確的結果,特別是如果可能性未被預期,可能會影響程式的可靠性和安全性。———Jules Dourlens

溢位簡介

  • 整數溢位和下溢不是一類新的漏洞,但它們在智慧合約中尤其危險

  • 其中無符號整數很普遍,大多數開發人員習慣於簡單int型別(通常是有符號整數)

  • 如果發生溢位,許多良性程式碼路徑成為盜竊或拒絕服務的載體。

真實世界影響

DAO
http://blockchain.unica.it/projects/ethereum-survey/attacks.html

BatchOverflow(多個令牌)
https://peckshield.com/2018/04/22/batchOverflow/

ProxyOverflow(多個令牌)
https://peckshield.com/2018/04/25/proxyOverflow/

示例

  • 一個聰明的合約的withdraw()功能,您可以為您的餘額仍是手術後積極檢索,只要捐贈合約醚。

  • 一個攻擊者試圖收回比他或她的當前餘額多。

  • 該withdraw()功能檢查的結果總是正數,允許攻擊者退出超過允許。

  • 由此產生的餘額下降,併成為比它應該更大的數量級。

程式碼示例

最直接的例子是一個不檢查整數下溢的函式,允許您撤銷無限量的標記:

function withdraw(uint _amount) {
    require(balances[msg.sender] - _amount > 0);
    msg.sender.transfer(_amount);
    balances[msg.sender] -= _amount;
}

第二個例子(在無益的Solidity編碼競賽期間被發現https://github.com/Arachnid/uscc/tree/master/submissions-2017/doughoyte)
是由於陣列的長度由無符號整數表示的事實促成的錯誤的錯誤:

function popArrayOfThings() {
    require(arrayOfThings.length >= 0);
    arrayOfThings.length--; 
}

第三個例子是第一個例子的變體,其中兩個無符號整數的算術結果是一個無符號整數:

function votes(uint postId, uint upvote, uint downvotes) {
    if (upvote - downvote < 0) {
        deletePost(postId)
    }
}

第四個示例提供了即將棄用的var關鍵字。由於var將自身改變為包含指定值所需的最小型別,因此它將成為uint8保持值0.如果迴圈的迭代次數超過255次,它將永遠達不到該數字,並且在執行執行時停止出gas:

for (var i = 0; i < somethingLarge; i ++) {
    // ...
}

其他資源

SafeMath防止溢位
https://ethereumdev.io/safemath-protect-overflows/

整數溢位程式碼示例
https://github.com/trailofbits/not-so-smart-contracts/tree/master/integer_overflow


4.未檢查返回值的低階別呼叫

也稱為或與無聲失敗傳送, 未經檢查傳送。

應儘可能避免使用低階別“呼叫”。如果返回值處理不當,它可能會導致意外的行為。——Remix

其中的密實度的更深層次的特點是低階別的功能call(),callcode(),delegatecall()和send()。他們在計算錯誤方面的行為與其他Solidity函式完全不同,因為他們不會傳播(或冒泡),並且不會導致當前執行的全部回覆。相反,他們會返回一個布林值設定為false,並且程式碼將繼續執行。這可能會讓開發人員感到意外,如果未檢查到這種低階別呼叫的返回值,則可能導致失敗開啟和其他不想要的結果。請記住,傳送可能會失敗!

真實世界影響

以太之王——https://www.kingoftheether.com/postmortem.html
Etherpot——https://www.dasp.co/

程式碼示例

  • 下面的程式碼是一個當忘記檢查返回值時會出錯的例子send()。

  • 如果呼叫用於將ether傳送給不接受它們的智慧合約(例如,因為它沒有應付回退功能)

  • 則EVM將用其替換其返回值false。

  • 由於在我們的例子中沒有檢查返回值,因此函式對合約狀態的更改不會被恢復,並且etherLeft變數最終會跟蹤一個不正確的值:

function withdraw(uint256 _amount) public {
    require(balances[msg.sender] >= _amount);
    balances[msg.sender] -= _amount;
    etherLeft -= _amount;
    msg.sender.send(_amount);
}

其他資源

未經檢查的外部電話
https://github.com/trailofbits/not-so-smart-contracts/tree/master/unchecked_external_call

掃描“未經檢查 - 傳送”錯誤的現場以太坊合約
http://hackingdistributed.com/2016/06/16/scanning-live-ethereum-contracts-for-bugs/


5.拒絕服務

包括達到氣量上限,意外丟擲,意外殺死,訪問控制違規

I accidentally killed it. ————devops199 on the Parity multi-sig wallet


  • 在以太坊的世界中,拒絕服務是致命的:

  • 儘管其他型別的應用程式最終可以恢復,但智慧合約可以通過其中一種攻擊永遠離線。

  • 許多方面導致拒絕服務,包括在作為交易接受方時惡意行為

  • 人為地增加計算功能所需的gas,濫用訪問控制訪問智慧合約的私人元件

  • 利用混淆和疏忽,…這類攻擊包括許多不同的變體,並可能在未來幾年看到很多發展。

損失:估計為514,874 ETH(當時約3億美元)

真實世界影響

政府
https://www.reddit.com/r/ethereum/comments/4ghzhv/governmentals_1100_eth_jackpot_payout_is_stuck/

奇偶校驗多訊號錢包
http://paritytech.io/a-postmortem-on-the-parity-multi-sig-library-self-destruct/

示例

  • 一個拍賣合約允許它的使用者出價不同的資產。

  • 為了投標,使用者必須bid(uint object)用期望的以太數來呼叫函式。

  • 拍賣合約將把以太儲存在第三方儲存中,直到物件的所有者接受投標或初始投標人取消。

  • 這意味著拍賣合約必須在其餘額中保留未解決出價的全部價值。

  • 該拍賣合約還包括一個withdraw(uint amount)功能,它允許管理員從合約獲取資金。

  • 隨著函式傳送amount到硬編碼地址,開發人員決定公開該函式。

  • 一個攻擊者看到了潛在的攻擊和呼叫功能,指揮所有的合約的資金為其管理員。

  • 這破壞了託管承諾並阻止了所有未決出價。

  • 雖然管理員可能會將託管的錢退還給合約,但攻擊者可以通過簡單地撤回資金繼續進行攻擊。

程式碼示例

在下面的例子中(受以太王的啟發http://blockchain.unica.it/projects/ethereum-survey/attacks.html#kotet)
遊戲合約的功能可以讓你成為總統,如果你公開賄賂前一個。不幸的是,如果前總統是一個聰明的合約,並導致支付逆轉,權力的轉移將失敗,惡意智慧合約將永遠保持總統。聽起來像是對我的獨裁:

function becomePresident() payable {
    require(msg.value >= price); // must pay the price to become president
    president.transfer(price);   // we pay the previous president
    president = msg.sender;      // we crown the new president
    price = price * 2;           // we double the price to become president
}

在第二個例子中,呼叫者可以決定下一個函式呼叫將獎勵誰。由於for迴圈中有昂貴的指令,攻擊者可能會引入太大的數字來迭代(由於以太坊中的氣體阻塞限制),這將有效地阻止函式的功能。

function selectNextWinners(uint256 _largestWinner) {
    for(uint256 i = 0; i < largestWinner, i++) {
        // heavy code
    }
    largestWinner = _largestWinner;
}

其他資源

奇偶Multisig被黑客入侵。再次
https://medium.com/chain-cloud-company-blog/parity-multisig-hack-again-b46771eaa838

關於Parity multi-sig錢包漏洞和Cappasity令牌眾包的宣告
https://blog.artoken.io/statement-on-the-parity-multi-sig-wallet-vulnerability-and-the-cappasity-artoken-crowdsale-b3a3fed2d567


6.錯誤隨機
也被稱為沒有什麼是祕密的

合約對block.number年齡沒有足夠的驗證,導致400個ETH輸給一個未知的玩家,他在等待256個街區之前揭示了可預測的中獎號碼。—————阿森尼羅托夫


  • 以太坊的隨機性很難找到。

  • 雖然Solidity提供的功能和變數可以訪問明顯難以預測的值

  • 但它們通常要麼比看起來更公開,要麼受到礦工影響。

  • 由於這些隨機性的來源在一定程度上是可預測的,所以惡意使用者通常可以複製它並依靠其不可預知性來攻擊該功能。

損失:超過400 ETH

真實世界影響

SmartBillions彩票
https://www.reddit.com/r/ethereum/comments/74d3dc/smartbillions_lottery_contract_just_got_hacked/

TheRun
https://medium.com/@hrishiolickel/why-smart-contracts-fail-undiscovered-bugs-and-what-we-can-do-about-them-119aa2843007

示例

  1. 甲智慧合約使用塊號作為隨機有遊戲用的源。

  2. 攻擊者建立一個惡意合約來檢查當前的塊號碼是否是贏家。如果是這樣,它就稱為第一個智慧合約以獲勝; 由於該呼叫將是同一交易的一部分,因此兩個合約中的塊編號將保持不變。

  3. 攻擊者只需要呼叫她的惡意合同,直到獲勝。

程式碼示例

在第一個例子中,a private seed與iteration數字和keccak256雜湊函式結合使用來確定主叫方是否獲勝。Eventhough的seed是private,它必須是通過交易在某個時間點設定,並因此在blockchain可見。

uint256 private seed;

function play() public payable {
    require(msg.value >= 1 ether);
    iteration++;
    uint randomNumber = uint(keccak256(seed + iteration));
    if (randomNumber % 2 == 0) {
        msg.sender.transfer(this.balance);
    }
}
  • 在這第二個例子中,block.blockhash正被用來生成一個隨機數。

  • 如果將該雜湊值blockNumber設定為當前值block.number(出於顯而易見的原因)並且因此設定為,則該雜湊值未知0。

  • 在blockNumber過去設定為超過256個塊的情況下,它將始終為零。

  • 最後,如果它被設定為一個以前的不太舊的區塊號碼,另一個智慧合約可以訪問相同的號碼並將遊戲合約作為同一交易的一部分進行呼叫。

function play() public payable {
    require(msg.value >= 1 ether);
    if (block.blockhash(blockNumber) % 2 == 0) {
        msg.sender.transfer(this.balance);
    }
}

其他資源

在以太坊智慧合約中預測隨機數
https://blog.positive.com/predicting-random-numbers-in-ethereum-smart-contracts-e5358c6b8620

在以太坊隨機
https://blog.otlw.co/random-in-ethereum-50eefd09d33e


7.前臺執行

也被稱為檢查時間與使用時間(TOCTOU),競爭條件,事務順序依賴性(TOD)

事實證明,只需要150行左右的Python就可以獲得一個正常執行的演算法。————Ivan Bogatyy

  • 由於礦工總是通過代表外部擁有地址(EOA)的程式碼獲得gas費用

  • 因此使用者可以指定更高的費用以便更快地開展交易。

  • 由於以太坊區塊鏈是公開的,每個人都可以看到其他人未決交易的內容。

  • 這意味著,如果某個使用者正在揭示拼圖或其他有價值的祕密的解決方案,惡意使用者可以竊取解決方案並以較高的費用複製其交易,以搶佔原始解決方案。

  • 如果智慧合約的開發者不小心,這種情況會導致實際的和毀滅性的前端攻擊。

真實世界影響

Bancor
https://hackernoon.com/front-running-bancor-in-150-lines-of-python-with-ethereum-api-d5e2bfd0d798

ERC-20
https://docs.google.com/document/d/1YLPtQxZu1UAvO9cZ1O2RPXBbT0mooh4DYKjA_jp-RLM/

TheRun
https://www.dasp.co/

示例

  1. 一個聰明的合約釋出的RSA號(N = prime1 x prime2)。

  2. 對其submitSolution()公共功能的呼叫與權利prime1並prime2獎勵來電者。

  3. Alice成功地將RSA編號考慮在內,並提交解決方案。

  4. 有人在網路上看到Alice的交易(包含解決方案)等待被開採,並以較高的gas價格提交。

  5. 由於支付更高的費用,第二筆交易首先被礦工收回。該攻擊者贏得獎金。

其他資源

在以太坊智慧合約中預測隨機數
https://blog.positive.com/predicting-random-numbers-in-ethereum-smart-contracts-e5358c6b8620

虛擬和解的前衛,悲痛和危險
https://blog.0xproject.com/front-running-griefing-and-the-perils-of-virtual-settlement-part-1-8554ab283e97

Frontrunning Bancor
https://www.youtube.com/watch?v=RL2nE3huNiI


8.時間操縱

也被稱為時間戳依賴

如果一位礦工持有合約的股份,他可以通過為他正在挖掘的礦區選擇合適的時間戳來獲得優勢。———-Nicola Atzei,Massimo Bartoletti和Tiziana Cimoli

  • 從鎖定令牌銷售到在特定時間為遊戲解鎖資金,合約有時需要依賴當前時間。

  • 這通常通過Solidity中的block.timestamp別名或其別名完成now。

  • 但是,這個價值從哪裡來?來自礦工!

  • 由於交易的礦工在報告採礦發生的時間方面具有迴旋餘地

  • 所以良好的智慧合約將避免強烈依賴所宣傳的時間。

  • 請注意,block.timestamp有時(錯誤)也會在隨機數的生成中使用,如#6所述。壞隨機性。

真實世界影響

政府
http://blockchain.unica.it/projects/ethereum-survey/attacks.html#governmental

示例

  1. 一場比賽在今天午夜付出了第一名球員。

  2. 惡意的礦工包括他或她試圖贏得比賽並將時間戳設定為午夜。

  3. 在午夜之前,礦工最終挖掘該塊。當前的實時時間“足夠接近”到午夜(當前為該塊設定的時間戳),網路上的其他節點決定接受該塊。

程式碼示例

以下功能只接受特定日期之後的呼叫。由於礦工可以影響他們區塊的時間戳(在一定程度上),他們可以嘗試挖掘一個包含他們交易的區塊,並在未來設定一個區塊時間戳。如果足夠接近,它將在網路上被接受,交易將在任何其他玩家試圖贏得比賽之前給予礦工以太:

function play() public {
    require(now > 1521763200 && neverPlayed == true);
    neverPlayed = false;
    msg.sender.transfer(1500 ether);
}

其他資源

對以太坊智慧合約的攻擊調查
https://eprint.iacr.org/2016/1007

在以太坊智慧合約中預測隨機數
https://blog.positive.com/predicting-random-numbers-in-ethereum-smart-contracts-e5358c6b8620

讓智慧合約變得更聰明
https://blog.acolyer.org/2017/02/23/making-smart-contracts-smarter/


9短地址攻擊

也被稱為或涉及非連鎖問題,客戶端漏洞

為令牌傳輸準備資料的服務假定使用者將輸入20位元組長的地址,但實際上並未檢查地址的長度。—-PawełBylica

  • 短地址攻擊是EVM本身接受不正確填充引數的副作用。

  • 攻擊者可以通過使用專門製作的地址來利用這一點,使編碼錯誤的客戶端在將它們包含在事務中之前不正確地對引數進行編碼。

  • 這是EVM問題還是客戶問題?是否應該在智慧合約中修復?

  • 儘管每個人都有不同的觀點,但事實是,這個問題可能會直接影響很多乙太網。

  • 雖然這個漏洞還沒有被大規模利用,但它很好地證明了客戶和以太坊區塊鏈之間的互動帶來的問題。

  • 其他脫鏈問題存在:重要的是以太坊生態系統對特定的javascript前端,瀏覽器外掛和公共節點的深度信任。

  • 臭名昭著的鏈外利用被用於Coindash ICO的黑客在他們的網頁上修改了公司的以太坊地址,誘騙參與者將ethers傳送到攻擊者的地址。

發現時間表

真實世界影響

未知交換(s)
https://blog.golemproject.net/how-to-find-10m-by-just-reading-blockchain-6ae9d39fcd95

示例

  1. 交易所API具有交易功能,可以接收收件人地址和金額。

  2. 然後,API transfer(address _to, uint256 _amount)使用填充引數與智慧合約函式進行互動:它將12位零位元組的地址(預期的20位元組長度)預先設定為32位元組長

  3. Bob(0x3bdde1e9fbaef2579dd63e2abbf0be445ab93f00)要求Alice轉讓他20個代幣。他惡意地將她的地址截斷以消除尾隨的零。

  4. Alice使用交換API和Bob(0x3bdde1e9fbaef2579dd63e2abbf0be445ab93f)的較短的19位元組地址。

  5. API用12個零位元組填充地址,使其成為31個位元組而不是32個位元組。有效地竊取以下_amount引數中的一個位元組。

  6. 最終,執行智慧合約程式碼的EVM將會注意到資料未被正確填充,並會在_amount引數末尾新增丟失的位元組。有效地傳輸256倍以上的令牌。

其他資源

ERC20短地址攻擊說明
http://vessenes.com/the-erc20-short-address-attack-explained/

分析ERC20短地址攻擊
https://ericrafaloff.com/analyzing-the-erc20-short-address-attack/

智慧合約短地址攻擊緩解失敗
https://blog.coinfabrik.com/smart-contract-short-address-attack-mitigation-failure/

從標記中刪除短地址攻擊檢查
https://github.com/OpenZeppelin/zeppelin-solidity/issues/261


10.未知的未知物

我們相信更多的安全審計或更多的測試將沒有什麼區別。主要問題是評審人員不知道要尋找什麼。———Christoph Jentzsch

  • 以太坊仍處於起步階段。

  • 用於開發智慧合約的主要語言Solidity尚未達到穩定版本

  • 而生態系統的工具仍處於試驗階段。

  • 一些最具破壞性的智慧合約漏洞使每個人都感到驚訝

  • 並且沒有理由相信不會有另一個同樣出乎意料或同樣具有破壞性的漏洞。

  • 只要投資者決定將大量資金用於複雜而輕微審計的程式碼

  • 我們將繼續看到新發現導致可怕後果。

  • 正式驗證智慧合約的方法尚不成熟,但它們似乎具有很好的前景,可以作為擺脫今天不穩定現狀的方式。

  • 隨著新型別的漏洞不斷被發現,開發人員需要繼續努力

  • 並且需要開發新工具來在壞人之前找到它們。

  • 這個Top10可能會迅速發展,直到智慧合約開發達到穩定和成熟的狀態。

相關文章