在 Eternal Storage 中儲存複雜數據類型
我一直在閱讀編寫可升級合約的策略。已經多次出現的一種模式是將您的合約業務邏輯與其儲存分離,以便可以在不失去數據的情況下進行升級(在solidity 中編寫可升級合約,可升級的solidity 合約設計)。
在這篇文章中,它說永恆儲存是一種“一種簡單且可擴展的方式來儲存從簡單值到數組和復雜對像類型數據的任何類型的數據”。但是,鑑於下面提供的儲存契約和模擬使用者契約,我很難理解將使用者儲存移動到 EternalStorage 契約的最佳方式,因為它包含數組、映射、結構等內容。任何想法/建議?
pragma solidity ^0.4.24; contract UserRegistry { struct User { address addr; uint points; address[] friendsList; mapping(address => bool) friends; } mapping(address => User) users; mapping(address => mapping(address => uint)) public gamesPlayedTogether; // user address => (friendAddress => games played together) function createUser() public { User memory user = User(msg.sender, 0, new address[](0)); users[msg.sender] = user; } // Various other business logic } contract Storage { mapping(bytes32 => uint256) private uIntStorage; mapping(bytes32 => string) private stringStorage; mapping(bytes32 => address) private addressStorage; mapping(bytes32 => bytes) private bytesStorage; mapping(bytes32 => bool) private boolStorage; mapping(bytes32 => int256) private intStorage; function getAddress(bytes32 _key) public view returns (address) { return addressStorage[_key]; } function getUint(bytes32 _key) public view returns (uint) { return uIntStorage[_key]; } function getString(bytes32 _key) public view returns (string) { return stringStorage[_key]; } function getBytes(bytes32 _key) public view returns (bytes) { return bytesStorage[_key]; } function getBool(bytes32 _key) public view returns (bool) { return boolStorage[_key]; } function getInt(bytes32 _key) public view returns (int) { return intStorage[_key]; } function setAddress(bytes32 _key, address _value) public { addressStorage[_key] = _value; } function setUint(bytes32 _key, uint _value) public { uIntStorage[_key] = _value; } function setString(bytes32 _key, string _value) public { stringStorage[_key] = _value; } function setBytes(bytes32 _key, bytes _value) public { bytesStorage[_key] = _value; } function setBool(bytes32 _key, bool _value) public { boolStorage[_key] = _value; } function setInt(bytes32 _key, int _value) public { intStorage[_key] = _value; } }
我會在模擬客戶端中更改一些細節。它與此處的 Mapped Structs with Index 模式很接近:Solidity是否有解決良好且簡單的儲存模式?.
在您開始之前了解這種參照完整性模式可能會很好:https ://medium.com/@robhitchens/enforcing-referential-integrity-in-ethereum-smart-contracts-a9ab1427ff42 ,然後…
使其無國籍…
將所有內容簡化為帶有鍵的鍵/值對
bytes32
。這是一個為可讀性優化的粗略的最小草圖:contract StatelessUserRegisty { Storage dataStore; constructor() public { dataStore = new Storage(); } function userKey(address userAddr) public pure returns(bytes32 userID) { return keccak256(abi.encodePacked(userAddr)); } function isUser(address userAddr) public view returns(bool isIndeed) { return dataStore.getBool(userKey(userAddr)); } function createUser(address userAddr) public returns(bool success) { require(!isUser(userAddr)); dataStore.setBool(userKey(userAddr),true); return true; } function updateUserPoints(address userAddr, uint userPoints) public returns(bool success) { require(!isUser(userAddr)); dataStore.setUint(userKey(userAddr),userPoints); return true; } }
我逃脫了一點作弊,因為只有 1
bool
和 1uint
。如果有多個uint
變數怎麼辦?繼續扯淡…
bytes32 key1 = keccak256(userAddr, "first"); bytes32 key2 = keccak256(userAddr, "second");
您可以更進一步,添加
row
或添加index
到數組和映射的組合中。在玩過這種模式之後,我開始將這些特定於應用程序的儲存合約視為與應用程序邏輯分開的東西——只是基本的創建、檢索、更新、刪除和引用完整性保證。然後,考慮讓應用程序合約“擁有”一個或多個數據控制器。
ApplicationContract => Data Controller => EternalStorage
數據控制器和/或應用程序合約的有序替換是另一個主題(提示:不要破壞它!)。該設計預計在某些時候可能需要擴展模式。
希望能幫助到你。