Рассмотрим следующий контракт, который иллюстрирует проблему. Здесь у нас есть динамический массив сопоставлений, 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--;
}
}
Можно подумать, что удаление элемента сопоставления из массива эффективно очищает это сопоставление, и что добавление нового сопоставления вместо старого будет иметь новый key* -> false
элемент all . Оказывается, это неправда. То же самое произойдет, если вы попытаетесь поменять местами элементы, внутри которых есть сопоставления, все будет заменено, кроме сопоставлений.
Единственное решение, которое я вижу, чтобы справиться с этим, - это вручную удалить / переназначить каждый используемый ключ сопоставления, но это очень быстро становится дорогостоящим с точки зрения использования газа.
Вопросы, на которые я ищу ответы:
Спасибо за внимание!
Чтобы ответить на ваш вопрос, позвольте мне объяснить, как на самом деле выглядит стек EVM: сам по себе это просто карта от ключа до значения, оба длиной 32 байта.
карта солидности, сопоставляется с sha3(mapId .key) с заданным значением в стеке evm. Это также причина, по которой невозможно перебрать все ключи на карте, потому что они «рандомизированы» по всему стеку evm.
массив солидности сопоставляется с sha3(arrayId) + index со значением. Здесь мы можем выполнить итерацию, если мы знаем идентификатор массива, просто увеличив индекс.
(Здесь я не совсем уверен, сохраняется ли длина массива.)
Нижеследующее является просто предположением, поскольку я полностью уверен, как солидность решает эту проблему: если у вас теперь есть массив карт, то, что вы на самом деле делаете, это mapId = sha3(arrayId) + index. Вы можете перебирать их. Однако, если вы сохраняете что-то на карту, вы делаете следующее:
sha3((sha3(arrayId) + index) . key ) = value
Но, удалив последний элемент карты, вы потеряете идентификатор массива для карты, но поскольку нельзя перебирать карты, не зная ключей, ваше значение сохраняется.
Однако у мультимассивов нет этой проблемы:
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
Алексей Матиясевич
Денис
Алексей Матиясевич
key => bool
можно использоватьuint[]
набор пакетов по 256 логических значений в каждом. А как жеkey => uint
другие?