Solidity

在 Solidity 智能合約中儲存和檢索大數據的最佳實踐是什麼?

  • November 25, 2021

假設,我有一個事件創建頁面,在 UI 中有一些表單欄位。而且我有一個智能合約,可以將事件儲存在事件映射或某種結構格式的公共數組中。

struct event{
     bytes32 name;
     uint time;
}

event[] public events;

or

mapping(uint=>event) public events;

我正在送出 UI,數據儲存在契約中。

我有一個列表事件頁面,它將顯示契約中創建的所有事件。

在搜尋了許多論壇後,我得到了一些資訊,有人可以驗證這一點。

方法一:

對於合約中的每次送出或保存,都會呼叫一個事件,並且 UI 具有觀察者並儲存在本地儲存中並顯示在 UI 中。事件數據在這裡可以是映射或數組。

我不想為應用程序提供任何中間儲存,因此每當 UI 刷新時,事件觀察器將接收所有狀態數據並再次更新本地儲存並在 UI 中顯示。

方法二:

對於事件送出,創建新的事件對象並將其推送到事件數組中。

並編寫 get events 方法,迭代事件數組並返回對像中每個鍵的字元串元素列表,然後再次連接和解構 UI 中對像數組中的字元串以與 UI 綁定。

我認為由於迭代,第二種方法的計算量會很高。由於我們正在開發 Dapp,我不想再有任何中間數據庫成為一個集中式系統。

有人可以解釋從智能合約中儲存和檢索數據的各種可能性,這是迄今為止最好的方式。

這對我有很大幫助。提前致謝。

event是一個可靠的關鍵字,可讓您輕鬆檢索契約在 Javascript 前端中生成的數據。就 gas 而言,寫一個事件比寫一個儲存變數(比如你的struct數組)更便宜。然後,您可以.watch針對這些事件並將它們拉入您的 UI。這是推薦的方式。出於性能原因,您可能希望以某種方式記憶體這些事件數據,因為每次重新載入時解析所有塊的效率相當低。

此外,不要嘗試將所有數據放入智能合約中。一個設計良好的 Dapp 的工作就是只包含絕對需要的元素和指向外部結構的指針,但要讓你的儲存層與區塊鏈分開。儲存層可以通過IPFSSwarm實現。

正如 Sebastian 所說,您要謹慎對待要在合約中儲存在區塊鏈上的數據。

話雖如此,儲存數據的 gas 成本將落在交易發行者身上以創建事件。同樣,任何需要迭代此數據的基於“事務”的呼叫都將變得非常昂貴,具體取決於數據量和您需要執行的迭代。

如果一個函式被標記為常量並且不需要修改數據,則可以在不產生 gas 成本的情況下呼叫它,因此迭代事件列表雖然計算成本很高,但如果作為交易執行,則基本上可以自由呼叫。

一個好的做法是添加一個您想要列出的範圍,以便您可以限制每次呼叫所需的處理並在您的 dApp 中分頁結果。

這是一個可以做到這一點的合約範例,它絕不是完整的,但 Remix 中的複制粘貼將用於顯示基本功能:

pragma solidity ^0.4.0;

contract EventManager {

   struct Event {
       bytes32 name;
       uint time;
   }

   uint totalEvents;

   mapping(uint => Event) EventList;

   event EventAdded(address indexed _senderAddress, uint _eventId);

   function addEvent(bytes32 _name, uint _time) returns(uint eventId) {
       eventId = totalEvents++;
       EventList[eventId] = Event(_name, _time);
       EventAdded(msg.sender, eventId);
   }

   function listEvents(uint _start, uint _count) constant returns(uint[] eventIds, bytes32[] eventNames, uint[] eventTimes) {

       uint maxIters = _count;
       if( (_start+_count) > totalEvents) {
           maxIters = totalEvents - _start;
       }

       eventIds = new uint[](maxIters);
       eventNames = new bytes32[](maxIters);
       eventTimes = new uint[](maxIters);

       for(uint i=0;i<maxIters;i++) {
           uint eventId = _start + i;

           Event memory e = EventList[eventId];
           eventIds[i] = eventId;
           eventNames[i] = e.name;
           eventTimes[i] = e.time;
       }
   }
}

引用自:https://ethereum.stackexchange.com/questions/15998