Ich habe eine folgende Anforderung, die in DAPP erfüllt werden muss.
Notiz:
Der Versuch, eine 3 for-Schleife zu verwenden, scheint dafür kein sehr cleverer Weg zu sein, da dies zu einer kostenintensiven Operation wird. Leider ist dies die einzige Lösung, die mir einfällt, um die obige Bedingung zu erfüllen. Hat jemand Erfahrung damit umzugehen?
// probably only one of mapping or list is needed
address[] public addressList;
mapping (address => bool) public userAddr;
function insertAddress(address[] addressUser) public returns (bool) {
// loop addressUser and check if it is unique
// loop addressUser and check if it exists in mapping
// loop and push addressUser to addressList + insert addressUser to userAddr
return true;
}
Wenn ich Ihre Anforderung sehe, würde ich Folgendes tun:
address[] public addressList;
mapping (address => bool) public userAddr;
function insertAddress(address[] addressUser) public returns (bool) {
// used to check adressUser uniqueness
mapping (address => bool) memory uniq;
for(uint i = 0; i < addressUser.length, i++) {
address addr = addressUser[i];
// check if addressUser is unique
require(uniq[addr] == false);
uniq[addr] = true;
// if addr is not already list
if (userAddr[addr] == false) {
userAddr[addr] = true;
addressList.push(addr);
}
}
return true;
}
Bearbeiten:
Nachdem Sie einen anderen Vertrag gesehen haben, können Sie die Methode hier verwenden und verlangen, dass alle Adressen in aufsteigender Reihenfolge gesendet werden. Es ist wahrscheinlich weniger kostspielig in Bezug auf Benzin, da weniger Speicherzuweisung.
Das würde gehen:
function insertAddress(address[] addressUser) public returns (bool) {
// used to check adressUser uniqueness
address lastAddr = address(0);
for(uint i = 0; i < addressUser.length, i++) {
address addr = addressUser[i];
// check if addressUser is unique
// by forcing all address to be sent
// in increasing order
require(addr > lastAddr);
lastAddr = addr;
// if addr is not already in list
if (userAddr[addr] == false) {
userAddr[addr] = true;
addressList.push(addr);
}
}
return true;
}
Ich habe solche Verträge schon früher erstellt und viele der Probleme gesehen, die Sie haben. Kurz gesagt, diese Operationen, die Sie durchzuführen versuchen, sind teuer . Der beste Weg, dies zu tun, ist es einfach, es effizient zu tun.
Um die Anforderungen zu erfüllen, würde ich die gesamte Funktion in eine Schleife stecken, die über jede übergebene Adresse iteriert. Um es so effizient wie möglich zu machen, können Sie mit einer if
Anweisung prüfen, ob die Adresse bereits existiert. Wenn dies der Fall ist, können Sie einfach zur nächsten Adresse wechseln, ohne weitere Berechnungen an der aktuellen Adresse durchzuführen . Je nachdem, wie Sie Adressen übergeben, kann dies zu enormen Spriteinsparungen führen.
Als Beispiel könnten Sie Folgendes tun:
address[] public addressList;
mapping (address => bool) public userAddr;
function insertAddress(address[] addressUser) public returns (bool)
{
for (uint256 i = 0; i < addressUser.length; i++) {
if (address does not exist) {
push addressUser to addressList
insert addressUser to userAddr
}
}
return true;
}
Das Array muss eindeutig sein. Wenn eine der Array-Adressen bereits vorhanden ist, lehnen Sie den gesamten Vorgang ab und setzen Sie ihn zurück.
Wenn dies der Fall ist, trifft das oben Genannte nicht zu und was Sie ursprünglich hatten, ist der beste Weg, dies zu tun.
Wenn Sie logisch darüber nachdenken, müssen Sie jede Adresse überprüfen, um das Array zu überprüfen. Dies erfordert Opcodes, die jedes Element überprüfen, und Sie können dies nicht umgehen. Nachdem diese Überprüfungen durchgeführt wurden, müssen Sie jedes Element in die Blockchain schreiben, was auch Opcodes für jedes dieser Elemente erfordert. Dieser gesamte Prozess ist rechenintensiv und ist der Grund, warum ein Großteil dieser Logik im Allgemeinen außerhalb der Kette vorgeschlagen wird.
Eine Sache, die Sie tun können, ist, die Hashes der Arrays zu vergleichen (eines, das Sie übermitteln, und eines, das überprüft wird). Sie können die keccack256
von jedem Array nehmen, um einen eindeutigen Hash sicherzustellen. Sie können diesen Hash im Smart Contract speichern und anstelle des gesamten Arrays einen zu prüfenden Hash senden. Auf diese Weise führen Sie jetzt nur eine Prüfung durch, im Gegensatz zu N Prüfungen (N ist die Anzahl der Elemente im Array).
Sie müssen immer noch eine Schleife ausführen, um alle Artikel zum Smart Contract hinzuzufügen, aber jetzt haben Sie effektiv eine Schleife entfernt .
Ein Beispiel wäre:
address[] public addressList;
mapping (address => bool) public userAddr;
mapping (bytes32 => bool) public doesHashExist;
function insertAddress(address[] addressUser) public returns (bool)
{
bytes32 newHash = keccak256(addressUser);
require(!doesHashExist[newHash]);
for (uint256 i = 0; i < addressUser.length; i++) {
push addressUser to addressList
insert addressUser to userAddr
}
}
doesHashExist[newHash] = True;
return true;
}
Sie werden sehen, dass es eine neue Zuordnung gibt, die zum Speichern von Hashes verwendet wird, die im Vertrag vorhanden sind. Die Funktion führt jetzt nur eine einzige Prüfung (sowie einen Hashing) durch, um die Existenz des Arrays zu bestätigen. Schließlich speichert es den Hash.
Vincentsty
Shane Fontaine
Vincentsty
Shane Fontaine
Vincentsty
Shane Fontaine
Vincentsty
Shane Fontaine
Vincentsty
You can take the keccak256 of each array in order to ensure a unique hash.
Ich habe nicht wirklich verstanden, wie dies eine For-Schleife reduzieren wird.keccak256(array[] addressList1) === keccak256(array[] addressList2)
kann nur prüfen, ob zwei Array-Listen gleich sind (in Bezug auf Länge, Wert und Reihenfolge der Werte). Es kann nicht identifiziert werden, ob ein Element eines Arrays in einem anderen Array vorhanden ist, oder ich missverstehe die Implementierung.Shane Fontaine