throw
und revert()
kompilieren beide zur revert
Operation (opcode 0xfd
). Laut den Dokumenten :
Alternativ zu revert() kann auch das Schlüsselwort throw verwendet werden.
Warum kommt es dann zu folgendem Vertrag
contract test {
function () {
throw;
//revert();
}
}
erzeugt anderen Bytecode, wenn ich revert()
anstelle von throw
im obigen Beispiel verwende? Ich verwende Remix mit Solidity 0.4.13+commit.0fb4cb1a.Emscripten.clang. Dies sind die resultierenden Opcodes:
using throw: PUSH1 0x60 PUSH1 0x40 MSTORE CALLVALUE ISZERO PUSH1 0xE JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST JUMPDEST PUSH1 0x47 DUP1 PUSH1 0x1C PUSH1 0x0 CODECOPY PUSH1 0x0 RETURN STOP PUSH1 0x60 PUSH1 0x40 MSTORE JUMPDEST CALLVALUE ISZERO PUSH1 0xF JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH1 0x19 JUMPDEST PUSH1 0x0 DUP1 REVERT JUMPDEST JUMP JUMPDEST STOP STOP LOG1 PUSH6 0x627A7A723058 KECCAK256 0x4a PUSH32 0x5473469C00A2379987B5AF61DFF50F8FABE3B71589C4D2BBB53073BEB9D10029
using revert(): PUSH1 0x60 PUSH1 0x40 MSTORE CALLVALUE ISZERO PUSH1 0xE JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST JUMPDEST PUSH1 0x47 DUP1 PUSH1 0x1C PUSH1 0x0 CODECOPY PUSH1 0x0 RETURN STOP PUSH1 0x60 PUSH1 0x40 MSTORE JUMPDEST CALLVALUE ISZERO PUSH1 0xF JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH1 0x19 JUMPDEST PUSH1 0x0 DUP1 REVERT JUMPDEST JUMP JUMPDEST STOP STOP LOG1 PUSH6 0x627A7A723058 KECCAK256 0x5f 0xef 0xc4 0xac 0x4c STATICCALL DUP15 TIMESTAMP CODECOPY PUSH10 0x17070269221C62F6F5D4 0xba 0xe1 BALANCE BYTE 0xf7 EQ 0xca SWAP6 SWAP13 0xd0 0x27 0x24 STOP 0x29
Wir sehen, dass die letzten Anweisungen anders sind. Während die Version mit throw
auf endet
0x627A7A723058
KECCAK256
0x4a
PUSH32
0x5473469C00A2379987B5AF61DFF50F8FABE3B71589C4D2BBB53073BEB9D10029
die Version mit revert()
endet auf
0x627A7A723058
KECCAK256
0x5f
0xef
0xc4
0xac
0x4c
STATICCALL
DUP15
TIMESTAMP
CODECOPY
PUSH10
0x17070269221C62F6F5D4
0xba
0xe1
BALANCE
BYTE
0xf7
EQ
0xca
SWAP6
SWAP13
0xd0
0x27
0x24
STOP
0x29
Ich überlasse die genaue Interpretation der OpCodes jemand anderem und weise nur darauf hin, dass es sich um unterschiedliche Anweisungen handelt, sodass unterschiedliche Implementierungen zu erwarten sind.
Beginnend mit Metropolis revert;
wird ungenutztes Gas zurückgegeben, während throw
weiterhin das gesamte verfügbare Gas verbraucht wird. In Bezug auf Vertragsstatusänderungen sind sie gleich – alles wird rückgängig gemacht.
Ich hoffe es hilft.
revert()
und in einen Opcode throw
kompiliert werden sollten . REVERT
Dann würde ich erwarten, dass Metropolis diesen Opcode entsprechend behandelt (mit einer Gasrückerstattung). Ich verstehe nicht, warum dies jetzt oder jemals zu einem anderen kompilierten Code führen würde.revert()
das Gas zurück, nicht den REVERT
Opcode, der sowohl von Solidity als revert()
auch verwendet wird throw
, daher brauchen wir den Unterschied im Bytecode, danke!throw
wird weiterhin alles verfügbare Gas verbraucht? Können wir also schlussfolgern, dass throw
das ungenutzte Gas nicht an den Absender zurückgeschickt wird? @RobHitchensDas revert
wird oft als bezeichnet, cheap throw
da es dem Absender nicht verbrauchtes Gas zurückerstattet.
Wenn Sie am detaillierten Design dieser Funktion interessiert sind, sehen Sie sich bitte die ursprüngliche EIP-140- Diskussion an.
Ende des Bytecodes nach STOP soll nicht ausgeführt werden. Es sind Konstruktorargumente. Was genau macht Solidity damit und was speichert es dort? Nur Gavin kann es wissen. Ich vermute, es ist ein Patch, um alle Ihre Gelder zu haben
Benutzer9402
throw
: github.com/ethereum/solidity/issues/1793 . Es könnte ein Gerüst für die spätere Fehlerbehandlung sein. Interessante Frage!