Betrachten Sie den folgenden Vertrag, der das Problem veranschaulicht. Hier haben wir ein dynamisches Array von Mappings, add()
das am Ende des Arrays ein frisches neues Mapping hinzufügen, den Wert für Mapping key zurückgeben 0
und diesen Wert in ändern soll true
. remove()
wiederum soll die letzte Zuordnung aus einem Array entfernen.
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--;
}
}
Man kann sich vorstellen, dass das Entfernen eines Mapping-Elements aus einem Array dieses Mapping effektiv löscht und dass das Hinzufügen eines neuen Mappings anstelle des alten ein neues, all key* -> false
, -Element hat. Es stellt sich heraus, dass es nicht stimmt. Dasselbe passiert, wenn Sie versuchen, Elemente auszutauschen, die Mappings enthalten, alles wird außer Mappings ausgetauscht.
Die einzige Lösung, die ich sehe, um damit umzugehen, besteht darin, jeden verwendeten Zuordnungsschlüssel manuell zu löschen / neu zuzuweisen, aber es wird sehr schnell kostspielig in Bezug auf den Gasverbrauch.
Die Fragen, die ich beantworten möchte, sind:
Danke für ihre Aufmerksamkeit!
Um Ihre Frage zu beantworten, lassen Sie mich erklären, wie der EVM-Stack tatsächlich aussieht: An sich ist nur eine Abbildung von einem Schlüssel zu einem Wert, beide 32 Byte lang.
eine solidity map, bildet von sha3(mapId . key) auf einen gegebenen Wert auf dem evm Stack ab. Das ist auch der Grund, warum man nicht durch alle Schlüssel in einer Map iterieren kann, weil sie durch den gesamten evm-Stack "randomisiert" werden.
Ein Solidity-Array bildet sha3(arrayId) + index auf einen Wert ab. Hier können wir iterieren, wenn wir die arrayId kennen, indem wir einfach den Index erhöhen.
(Hier bin ich mir nicht sicher, ob auch die Länge eines Arrays gespeichert wird.)
Das Folgende ist nur Spekulation, da ich mir absolut sicher bin, wie solidity dies löst: Wenn Sie jetzt ein Array von Karten haben, ist das, was Sie tatsächlich tun, mapId = sha3(arrayId) + index. Sie können sie durchlaufen. Wenn Sie jedoch etwas auf einer Karte speichern, gehen Sie wie folgt vor:
sha3((sha3(arrayId) + index) . key ) = value
Aber durch das Entfernen des letzten Elements der Karte verlieren Sie die Array-ID für die Karte, aber da man Karten nicht durchlaufen kann, ohne die Schlüssel zu kennen, bleibt Ihr Wert erhalten.
Multiarrays haben dieses Problem jedoch nicht:
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]`
}
}
Wird die folgende Ausgabe erzeugen:
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
Oleksii Matiiasevych
Dennis
Oleksii Matiiasevych
key => bool
kann manuint[]
als Ersatz eine Sammlung von Stapeln von jeweils 256 bools verwenden. Aber was ist mitkey => uint
oder anderen?