Solidity

使用映射作為臨時 KeyValue 實例是否方便?

  • April 1, 2016

考慮以下說明問題的契約。這裡我們有一個動態映射數組,add()意在向數組末尾添加一個新的映射,返回映射鍵的值並將該值0更改為true. remove()反過來意味著從數組中刪除最後一個映射。

contract ClearMapping {
   mapping(uint => bool)[] state;

   // 1. add -> false
   // 2. remove
   // 3. add -> true
   function add() returns (bool) {
       uint pos = state.length++;
       bool curr = state[pos][0];
       state[pos][0] = true;
       return curr;
   }

   function remove() {
       state.length--;
   }
}

可以認為從數組中刪除映射元素有效地清除了該映射,並且添加一個新映射代替舊映射將有一個新的 allkey* -> false元素。事實證明這不是真的。如果您嘗試交換內部具有映射的元素,也會發生同樣的事情,除了映射之外的所有內容都將被交換。

我看到的唯一解決方案是手動刪除/重新分配每個使用的映射鍵,但它在氣體使用方面變得非常昂貴。

我要回答的問題是:

  1. 這是 EVM/Solidity 中的錯誤嗎?
  2. 是否有一種方便/有效的方法來清除/交換映射?
  3. 我不應該將映射用作臨時 KeyValue 實例嗎?

感謝關注!

為了回答你的問題,讓我解釋一下 EVM 堆棧的實際樣子:它本身只是一個從鍵到值的映射,都是 32 字節長。

一個可靠映射,從 sha3(mapId . key) 映射到 evm 堆棧上的給定值。這也是無法遍歷映射中所有鍵的原因,因為它們在整個 evm 堆棧中是“隨機化的”。

一個solidity數組從sha3(arrayId)+索引映射到一個值。如果我們只通過增加索引來知道arrayId,我們就可以在這裡進行迭代。

(這裡我不確定是否也保存了數組的長度。)

以下只是推測,因為我完全確定solidity如何解決這個問題:如果您現在有一個地圖數組,那麼您實際上要做的是mapId = sha3(arrayId)+ index。您可以遍歷它們。但是,如果您將某些內容保存到地圖中,請執行以下操作:

sha3((sha3(arrayId) + index) . key ) = value

但是通過刪除映射的最後一個元素,您會失去映射的數組 id,但是因為在不知道鍵的情況下無法遍歷映射,因此您的值會被保留。

但是,多數組沒有這個問題:

import "dapple/test.sol";

contract A is Test {
 uint[][] multiarray;

 function testMultiArray() {
   //@log multiarray length: `uint multiarray.length`
   //@log incrementing multiarray
   multiarray.length++;
   //@log multiarray length: `uint multiarray.length`
   //@log multiarray[0] length: `uint multiarray[0].length`
   //@log incrementing multiarray[0]
   multiarray[0].length++;
   multiarray[0].length++;
   //@log multiarray[0][0]: `uint multiarray[0][0]`
   //@log set value to 1
   multiarray[0][0] = 1;
   multiarray[0][1] = 1;
   //@log multiarray[0] length: `uint multiarray[0].length`
   //@log multiarray[0][0]: `uint multiarray[0][0]`
   //@log multiarray[0][1]: `uint multiarray[0][1]`
   //@log decrementing multiarray
   multiarray.length--;
   //@log multiarray[0] length: `uint multiarray.length`
   //@log incrementing multiarray
   multiarray.length++;
   //@log multiarray[0] length: `uint multiarray[0].length`
   multiarray[0].length++;
   multiarray[0].length++;
   //@log multiarray[0][0]: `uint multiarray[0][0]`
   //@log multiarray[0][1]: `uint multiarray[0][1]`
 }
}

將產生以下輸出:

 test multi array
 LOG:  multiarray length: 0
 LOG:  incrementing multiarray
 LOG:  multiarray length: 1
 LOG:  multiarray[0] length: 0
 LOG:  incrementing multiarray[0]
 LOG:  multiarray[0][0]: 0
 LOG:  set value to 1
 LOG:  multiarray[0] length: 2
 LOG:  multiarray[0][0]: 1
 LOG:  multiarray[0][1]: 1
 LOG:  decrementing multiarray
 LOG:  multiarray[0] length: 0
 LOG:  incrementing multiarray
 LOG:  multiarray[0] length: 0
 LOG:  multiarray[0][0]: 0
 LOG:  multiarray[0][1]: 0

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