在乙太坊上定位儲存數據的成本/效率
根據對這個問題的回答,可以通過 3 種方式在乙太坊上儲存 IPFS 雜湊:
- 將其儲存為字元串
- 將其儲存為結構
- 將其儲存在事件日誌中
從最貴到最便宜的順序排列。
現在,假設我想繼續儲存多個雜湊值
$$ t0 - t1 $$使用一種指定的方法,在時間 t1 之後在區塊鏈上定位這些散列的成本是多少? 例如,考慮一個場景,學生將他們的家庭作業的 IPFS 雜湊上傳到區塊鏈,而實際數據存在於 IPFS 上。在送出截止日期之後,我想追踪在該時間範圍內送出的人。
有人可以比較所有三種方法來查找這些雜湊嗎?
TL; 博士;
事件比契約狀態便宜得多。Bytes32 可能是最好的選擇,不管有沒有結構。對於一小部分案例,僅事件是可能的。
將其儲存為字元串
這是一種浪費,因為字元串是可變長度的,因此需要兩個字,一個用於長度,一個用於有效負載。由於 IPFS 雜湊總是 32 字節,因此介面和儲存中的這種成本都是不必要的。
將其儲存為結構
A
struct
是一個容器,您可以在其中儲存其他定義的類型,實際上是創建一個複合類型。按照措辭,此選項無效。將其儲存在事件日誌中
事件儲存比狀態儲存便宜得多,但需要注意的是,儲存在事件中的值無法被合約訪問。在這種情況下,這可能是可以接受的。
未提及
bytes32
是一種固定大小的類型,可以很好地映射到 IPFS(沒有前導Qm
)以及乙太坊的自然字長和最小的可定址儲存槽。這使得它看起來非常適合 IPFS 雜湊,無論是儲存在合約狀態還是事件日誌中。實際上,您最終可能會創建一個
struct
包含有關文件的元數據。struct Doc { bytes32 IPFShash; // other stuff }
即使是合約中最基本的邏輯(這是一份已知文件嗎?)也需要一些狀態儲存。組織通常要求多一點。因此,一般來說,雖然應盡一切努力將其保持在最低限度,但可能需要一些契約儲存。
並且,如果遵循最佳實踐,還可以為重要的狀態更改發出事件。事件日誌和發射器看起來像:
event LogNewDoc(address sender, bytes hash, ...);
後來,當事情發生時:
emit LogNewDoc(msg.sender, ipfsHash, ...);
有一種無狀態模式可能適用於合約永遠不會檢查雜湊並且您希望客戶端快速獲取相關事件的情況。
您在合約中維護一個
uint
指向包含有趣事件的最新塊的 a。在事件內,另一個指針指向之前的事件。這意味著客戶端不需要探索整個鏈來檢索事件,並且最近的事件最先到達。契約狀態需要覆蓋uint
目前為 5,000 的 a,因為它不會0
持續很長時間。希望能幫助到你。
細化
超級簡單的例子。客戶端檢查
latestEvent()
然後偵聽該塊只是為了獲取它然後關閉偵聽器。日誌中的麵包屑提示在哪裡查找較早的事件。pragma solidity 0.5.1; contract EventChain { // one of these for each chain you want conveniently accessible from client software uint public latestEvent; event LogChainedEvent(address sender, uint previousEvent); function logData() public { emit LogChainedEvent(msg.sender, latestEvent); latestEvent++; } }
通過這種方法,可以想像以一種方便數據訪問的方式組織事件鏈。例如,您可以根據主題的某種標識符跟踪版本歷史記錄(IPFS 雜湊每次更改)。
考慮:
mapping(bytes32 => uint) public latestVersion; // topic => events (ipfsHash)