Storage

乙太坊如何將映射融入儲存?

  • November 27, 2021

可能是一個愚蠢的問題,但乙太坊如何將映射融入儲存?我習慣了數組之類的簡單類型,所以我不明白“Solidity 的映射如何使用整個 256 位可定址記憶體空間”。我猜它很簡單,比如只有非零值佔用空間,但我想知道使用什麼程式碼/算法/概念來實現這一點。謝謝!!!

當您聲明如下合約中的映射時:

contract MappingExample {
   mapping(address => uint256) balances;
}

可變餘額分配給儲存槽 0(因為它是第一個)。但是映射的元素在其他地方。

要計算映射元素的儲存槽或位置,使用以下方法:

slot = keccak256([key, mappingSlot]) // concatenate key and mapping slot

問題是未分配的儲存槽預設值為 0。因此,每個未分配值的鍵都指向一個未分配的儲存槽,EVM 可以直接為其返回值 0。不需要僅僅因為聲明了映射就實際儲存 2^256 - 1 個插槽。

如果您對此感到好奇,您可以在此處查看 go-ethereum 中 SLOAD OPCODE 的實現,它呼叫此處定義的 evm.StateDB.GetState 方法:

func (s *StateDB) GetState(addr common.Address, hash common.Hash) common.Hash {
   stateObject := s.getStateObject(addr)
   if stateObject != nil {
       return stateObject.GetState(s.db, hash)
   }
   return common.Hash{}
}

如您所見,if stateObject == nilthencommon.Hash{}被返回。這是一個歸零的 32 字節數組。基本上,如果地址沒有與之關聯的狀態,則不需要儲存的歸零儲存欄位。

反過來(不是直接)它將呼叫 GetCommittedState defied here。這個方法比較大,這裡就不貼了,如果key不能從狀態trie中恢復,同樣的邏輯會返回預設值0。

因此,稍微改進一下我們的範例:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.10;

contract MappingExample {

   mapping(address => uint256) balances;

   constructor() {
       // Setting balance of an arbitrary address.
       balances[address(0x10)] = 100;
   }

}

您可以讀取餘額

$$ address(0x10) $$使用以下 Web3 程式碼: 從“web3”導入 Web3;

const web3 = new Web3("http://localhost:8545");

// ADDRESS OF OUR CONTRACT (CHANGE IT FOR YOUR OWN)
const contractAddress = "0xd4EC28074b7A66F536D9feCf9b2f81B962215e69";

// STORAGE SLOT OF THE MAPPING
const mappingSlot = '0000000000000000000000000000000000000000000000000000000000000000';

// KEY THAT WE WANT TO READ IN THE MAPPING
const key =         '0000000000000000000000000000000000000000000000000000000000000010';

// COMPUTE THE ACTUAL STORAGE SLOT OF THE VALUE ASSOCIATED WITH THE KEY
const balanceSlot = web3.utils.soliditySha3({t: 'bytes', v: key + mappingSlot});

const balance = await web3.eth.getStorageAt(contractAddress, balanceSlot);
console.log(web3.utils.toNumber(balance));
// DISPLAYS : 100

因為雜湊(解釋為儲存索引)儲存在 EVM 中,任何未知的值都會返回一個 256 位的 0 值,如GetState函式所示,這個 0 值不需要儲存。

本質上,映射中的每個值都映射到某個東西。但並不是所有的值都儲存在合約儲存空間中,只有已經設置好的值。使其成為一個非常有效的結構,不需要每個節點為現有的每個映射分配 2^256 - 1 位。

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