A. 簡要解釋為什麼Rollup系統能將所有交易數據存儲在鏈上?如果交易數據被丟棄且不存儲在任何地方,會出現什麼問題?

B. 看以下Solidity代碼:

pragma solidity ^0.8.0;

contract ERC20 is IERC20 {

mapping(address => uint256) private _balances;

event Transfer(address indexed from, address indexed to, uint256 value);

function _transfer(address sender, address recipient, uint256 amount) {

emit Transfer(sender, recipient, amount);

}}

問1:假設這段代碼部署在兩個合約中:地址為X的合約和地址為Y的合約。下面哪個選項可以讀取合約X中_balance的狀態? 圈出正確的答案。

地址為X的ERC20合約中的transfer()函數代碼地址為Y的ERC20合約中的transfer()函數代碼終端用戶使用etherscan.io

問2:繼續(B)部分,下面哪一個可以讀取調用函數_transfer()時發出的日誌條目Transfer? 圈出正確的答案。

地址為X的ERC20合約中定義的getBalance()函數中的代碼地址為Y的ERC20合約中定義的getBalance()函數中的代碼終端用戶使用etherscan.io

C. 兩個以太坊交易,tx1和tx2,並把它們同時提交到網絡上。交易tx1的maxPriorityFee設置為y, 交易tx2的maxPriorityFee設置為2y。 tx2一定要在tx1之前在鏈上執行嗎? 請進行證明。可以假設tx1和tx2的maxFee都大於baseFee + maxPriorityFee。

D. Alice想從經銷商Bob那裡買一輛車。她發送1個比特幣到Bob的比特幣地址。 Bob會等待一個交易,其中(i)輸入來自Alice的地址,(ii)其中一個輸出是綁定到Bob地址的UTXO,值為1 BTC。只要Bob在比特幣區塊鏈上看到這筆交易,他就把鑰匙給了Alice,然後她把車開走了。這是安全的嗎?Alice可以免費得到那輛車嗎?如果可以,請解釋原因。如果不可以,解釋一下Bob應該做什麼來確保他得到了錢。

F. Alice擁有一輛全新的特斯拉,她現在可以在Compound系統中使用她的車作為抵押嗎?(不賣她的車)如果可以,解釋應該怎麼做。如果不可以,解釋原因。

拜占庭

考慮n個參與方,其中n≥3個,其中一個參與方被指定為發送方。

發送方的一個比特b∈{0,1}。廣播協議是一種協議,其中各方會彼此發送消息,最終每一方輸出一個比特bi,因為i = 1,…, n,或什麼都不輸出。

協議具有一致性,如果有兩個誠實方,如果一方輸出b,另一方輸出b",則b = b"。協議具有有效性,如果發送方是誠實的,誠實的各方的輸出等於輸入發送方的b。協議具有全面性,如果當某個誠實方輸出一個比特時,那麼最終所有誠實方都輸出一個比特。

一個可靠的廣播協議(RBC)是滿足這三個特性的廣播協議。

我們假設存在一個公鑰基礎設施(PKI),這意味著每一方都有一個秘密的簽名密鑰,並且每一方都知道另一方的正確的公開簽名驗證密鑰。

在同步網絡中,考慮以下廣播協議:

步驟0:發送方將其輸入位b (連同其簽名) 發送給所有其他方。然後發送方輸出它的b位並終止。

步驟1:每個非發送方i 將它從發送方聽到的內容反饋給所有其他非發送方(添加了i的簽名) 。如果沒有從發送方那裡聽到任何消息,那麼它在這一步中什麼也不做。類似地,如果發送方的消息是不正常的:例如,如果發送方的簽名是無效的,或者消息不是單個比特,則該方在這一步中不做任何事情。

步驟2:每個非發送方收集它收到的所有信息( 最多有n-1條消息,在步驟0中最多有一條來自發送方,在步驟1中最多有一條來自每個非發送方)。如果有兩個由發送方收到的消息包含一個有效的簽名,但是相反的位(即,在一個簽名的消息中,比特為0,在另一個簽名的消息中,比特為1),那麼發送方是不誠實的,這一方輸出0並進行終止。否則,來自發送方的所有正確簽名的比特都是相同的,並且這一方輸出該比特。如果非發送方沒有收到任何消息,則不輸出任何內容。

問:對於下面的每一個問題,描述攻擊或解釋為什麼沒有攻擊。

如果最多只有一個不誠實方,協議是否具有一致性?如果最多只有一個不誠實方,協議是否有效?如果最多有兩個不誠實方,表明協議沒有一致性。如果最多有兩個不誠實方,協議是否有效?協議是否具有全面性(對於任意數量的不誠實方)?

自動做市商

假設1個ETH值1000個DAI。你是Uniswap V2的流動性提供者,並為DAI/ETH池貢獻5 ETH和5000 DAI。假設1個DAI值1美元,那麼你的出資總額為1萬美元。

幾個月後,1個ETH的價格上升到相當於2000個DAI。在DAI/ETH池穩定下來以適應這個新的匯率後,你決定撤回作為流動性提供者的全部頭寸。假設系統不收費(φ = 1),你將收到多少個ETH和DAI ?如果你一直持有你的5 ETH和5000 DAI,你的資產現在將有1.5萬美金的DAI,比起點多5000個DAI的利潤。在這幾個月裡,作為Uniswap V2的流動性提供者,與“自己拿著”策略相比,你經歷了什麼損失?以美元的絕對值表示損失,假設1 DAI = 1 USD。這被稱為無常損失,儘管在這種情況下,這種損失是相當永久性的。如果你作為Uniswap V2的流動性提供者損失了x美元,其中x是在(2)部分計算的,這些資金去了哪裡?具體來說,誰在這個過程中獲得了x美元?現在讓我們轉向使用Uniswap V2進行交易。假設Bob執行了一個大的交易,使用DAI/ETH池尾了ETH將DAI賣掉。交易完成後,DAI/ETH池中的DAI金額會比之前高,且ETH的金額有點低。因此,DAI/ETH池中的資產比例有點偏離了平衡點。套利者Alice發現了這個機會,並希望在發布一個反方向的交易,這將重新平衡池。她將從該交易中獲利,並希望確保在Bob的交易之後立即執行她的交易。這種策略被稱為 back-running。 Alice該如何實施 back-running策略?說一種方法,使Alice的交易在Bob的交易之後立即執行。假設10個不同的套利者在同一時間執行相同的 back-running策略,以捕獲Bob的交易創造的套利機會。它們都使用了你在(4)部分所描述的相同機制。 10個人當中誰會贏呢?

重入漏洞

在這個問題中,我們將看一個有趣的現實例子。考慮以下在16384個NFT中使用的Solidity代碼片段。通過調用mintNFT()函數,用戶可以一次領取多達20個NFT。可以假設所有的內部變量都被構造函數正確地初始化了(沒有顯示)。

讓我們證明_safeMint根本就不安全(儘管它的名字挺安全的)。

假設已經鑄造了16370個NFT,那麼totalSupply() == 16370。解釋一個惡意合約是如何鑄造超過16384個NFT的。攻擊者可以鑄造NFT的最大數量是多少? 提示:如果在調用地址收到的onERC721Received是惡意的,會發生什麼?注意鑄造循環,並考慮重入漏洞。假設totalSupply()的當前值為16370,為一個惡意的Solidity合約編寫代碼,實現從(1)部分發起的攻擊。你會在前一頁Solidity的代碼中添加或更改哪一行來防止你的攻擊?請注意,單個交易不應該創建超過20個NFT。

比特幣問題

閃電網絡提議的好處是無需向比特幣網絡發布交易就可以執行支付。閃電網絡支付最終會完全取代所有的比特幣交易,使區塊鏈變得不必要嗎?回想一下,比特幣交易有一組輸入地址和一組輸出地址。通常,每個輸入地址簽署整個交易(不包括簽名)來授權支付。這種簽名類型稱為SIGHASH_ALL。相反,假設使用每個輸入地址的密鑰來簽名整個Txin(交易的輸入部分,不包括簽名),而不簽名其他任何內容。也就是說,Txout(交易的輸出部分)沒有簽名(這種簽名類型稱為SIGHASH_NONE)。一旦交易提交給比特幣網絡,礦工可以使用SIGHASH_NONE方法從交易的輸入地址竊取資金嗎?如果可以,解釋如何;如果沒有,解釋原因。如果有人發現了一種方法,在給了一個ECDSA公鑰之後就能偽造ECDSA簽名的任意消息,比特幣會受到怎樣的影響? 假設偽造一個簽名需要30分鐘的計算時間,而且不能加快速度。

Tornado Cash

Tornado Cash合約需要存儲一個大的無效符,從樹中每次都要提取一個無效符。在提款期間,合約需要確定,被提款的的票據的無效符不在已經提款的無效符集合中。如果是這樣的,合約會將這個無效符添加到集合中。 Tornado Cash合約將其完成為一個映射:

mapping(bytes32 => bool) public nullifierHashes;

在提款過程中,合約對所提供的zk-SNARK證據進行驗證,如果有效,合約則:

假設從樹中成功提取了k個。考慮一個正在驗證以太坊交易的礦工。作為k的函數,這個礦工需要分配多少存儲空間來存儲nullifierhash映射? 可以假設Tornado合約除了這個nullifierhash映射之外不需要其他長期存儲。如果我們能將提取的無效符Sk鏈下存儲起來就更好了,比如說儲存在雲的某個地方。 Tornado合約將只存儲對當前無效符設置Sk的一個簡短承諾。當調用提款函數時,用戶將向該函數提供所有當前參數,此外,用戶還將提供

足夠的信息使Tornado合約能夠計算承諾到更新的無效符設置Sk+1:= Sk∪{nf},π的證明被提取的幣的無效符nf不在提交的無效符的集合,即nf 6不屬於Sk。

該合約將驗證π證明,即nf 6不屬於Sk,計算Sk+1的承諾,並用更新後的Sk+1的承諾替換當前對Sk的承諾。有幾種數據結構提供了這些功能,其中Sk的承諾是一個32字節的哈希值,而π的證明只包含2[log2 k]個32字節的哈希值。此外,這個π證明使Tornado Cash能夠計算到Sk+1的短承諾。雖然這種方法將大大減少合約存儲陣列的大小,但只有當它減少調用提款函數所需的gas時,才值得實現。考慮以下的gas成本:calldata(包含函數參數的字符串):每字節16 gas 。寫入存儲陣列的非零條目:5K gas,在存儲陣列中寫入一個零條目:20K gas假設我們只計算上面三個項目所消耗的gas。如果想在當前實現調用提款函數,那麼k是多少的時候,這一改變將節省gas? Tornado cash提供了一個合規工具,可以讓用戶將自己的幣去匿名化:該工俱生成一個文件,將用戶的存款與特定的提款聯繫起來。該文檔可能需要提交給中心化交易所(如Coinbase),然後該交易所才能接受資金。假設n個人將一枚幣存入一個Tornado池,那麼這個池的匿名性設置為n(假設n = 1000)。之後,所有的n個人將他們的幣取出到n個新的以太坊地址中(每個新地址都有一個幣)。觀察者無法判斷哪個新的以太坊地址對應於這n個人中的哪一個,因此匿名集的大小為n。但是,假設有n - 1人使用合規工具並發送結果文檔到Coinbase。這對最後剩下的那些想要私人地址的用戶的隱私意味著什麼?

Source:https://cs251.stanford.edu/