Durch einfaches Senden von Ether an einen Vertrag wird der Code des Vertrags ausgeführt . In Solidity wird dieser Code der so genannten Fallback-Funktion zugeordnet.
Wie viel Arbeit kann in einer Fallback-Funktion erledigt werden?
Die Fallback-Funktion kann so viel berechnen, wie viel Gas sie bekommt.
Es gibt 2 Fälle (im Grunde recipient.send
und recipient.call{value:...}("")
) und Fall 2 hat Auswirkungen auf die Sicherheit und ist ein Schlüsselelement dafür, wie theDAO am 17. Juni 2016 angegriffen und ausgenutzt wurde.
recipient
Die Fallback-Funktion eines Vertrags erhält nur dann einen 2300 -Gas-Zuschuss, wenn sie mit recipient.transfer
oderrecipient.send
aufgerufen wurde . Dies ist dasselbe wie bei einem externen Konto, das recipient
mit bezahlt web3.eth.sendTransaction({to:recipient, gas:21000, ...})
.
Der letzte Teil eines Ethereum-Blogbeitrags erklärt:
Wenn Sie möchten, dass Ihr Vertrag Ether empfängt, müssen Sie seine Fallback-Funktion billig machen. Es kann nur 2300 Gas verwenden, was weder Speicherschreibvorgänge noch Funktionsaufrufe zulässt, die Ether mitsenden. Grundsätzlich sollten Sie innerhalb der Fallback-Funktion nur ein Ereignis protokollieren, damit externe Prozesse darauf reagieren können.
Beispiele für einen externen Prozess sind web3.js-Filter und -Überwachungen.
Hinweis: Seit Dez 2019 recipient.transfer
und recipient.send
werden nicht mehr empfohlen: Ist transfer() nach dem Istanbul-Update noch sicher?
recipient.call{value:...}("")
(und die Verwendung verwandter Funktionen wie .callcode
, .delegatecall
) wird der Fallback-Funktion praktisch[1] so viel Gas geben, wie der Anrufer übrig hat.
Um die gleichen Effekte (2300 Gas Stipendium) und Sicherheit wie in Fall 1 zu erhalten, müssen Anrufer das Gas explizit auf null begrenzen, wenn sie das recipient
by aufrufen:recipient.call{gas: 0, value: ...}("")
(Die DAO begrenzte das Gas nicht und erlitt am 17. Juni 2016 einen Wiedereintrittsangriff . )
Fußnoten
[1] Erklärung, warum eine Fallback-Funktion fast alles, aber nicht alles Gas bekommt. Chriseth (Autor von Solidity) sagte :
Dies ist einer der skurrilen Orte der EVM. Du kannst nicht einfach sagen "mein ganzes Benzin mitschicken", du musst immer eine eindeutige Nummer angeben. Wir haben zwar den GAS-Opcode, der uns die noch verfügbare Gasmenge angibt, aber das Problem ist, dass das Ausführen des Anrufs selbst auch etwas Gas kostet, also müssen wir die Gasmenge, die die Anrufkosten kosten, von dem von GAS bereitgestellten Wert abziehen und Wir müssen auch die Menge an Benzin abziehen, die es kostet, die Subtraktion durchzuführen ...
Константин Ван
recipient.call.gas(2300).value(...)
gleichbedeutend mitrecipient.call.gas(0).value(...)
?eth
Paul Razvan Berg
send
undtransfer
nicht mehr als sicher . Verwenden Siecall{value: amount}("")
stattdessen.eth