Skip to content

Commit a7d5ff3

Browse files
authored
Fix revert reason encoding (#3420)
1 parent 60e9892 commit a7d5ff3

File tree

3 files changed

+49
-19
lines changed

3 files changed

+49
-19
lines changed

execution_chain/evm/evm_errors.nim

Lines changed: 31 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,8 @@ import
1414
std/tables,
1515
results,
1616
stint,
17-
stew/[assign2, byteutils],
18-
eth/common/hashes,
19-
web3/encoding
17+
stew/byteutils,
18+
eth/common/hashes
2019

2120
export
2221
results
@@ -101,20 +100,42 @@ const panicReasons = {
101100
0x51: "uninitialized function",
102101
}.toTable
103102

103+
func decodeU256(input: openArray[byte]): Opt[UInt256] =
104+
if input.len < 32:
105+
return Opt.none(UInt256)
106+
Opt.some(UInt256.fromBytesBE(input.toOpenArray(0, 31)))
107+
108+
func decodeString(input: openArray[byte]): Opt[string] =
109+
let
110+
offset256 = ?decodeU256(input)
111+
offset = offset256.truncate(int)
112+
113+
if offset >= input.len:
114+
return Opt.none(string)
115+
116+
let
117+
len256 = ?decodeU256(input.toOpenArray(offset, input.len-1))
118+
len = len256.truncate(int)
119+
dataOffset = offset + 32
120+
121+
if dataOffset + len >= input.len:
122+
return Opt.none(string)
123+
124+
ok(string.fromBytes(input.toOpenArray(dataOffset, dataOffset + len - 1)))
125+
104126
# UnpackRevert resolves the abi-encoded revert reason. According to the solidity
105127
# spec https://solidity.readthedocs.io/en/latest/control-structures.html#revert,
106128
# the provided revert reason is abi-encoded as if it were a call to function
107129
# `Error(string)` or `Panic(uint256)`.
108-
proc unpackRevertReason*(data: openArray[byte], reason: var string) =
130+
proc unpackRevertReason*(data: openArray[byte]): Opt[string] =
109131
if data.len() < 4:
110-
reason = ""
111-
return
132+
return Opt.none(string)
112133

113134
let selector = data[0..3]
114135

115136
if selector == revertSelector:
116-
discard decode(data.toOpenArray(4, data.len() - 1), 0, 0, reason)
137+
return decodeString(data.toOpenArray(4, data.len() - 1))
117138
elif selector == panicSelector:
118-
var reasonCode: UInt256
119-
discard decode(data.toOpenArray(4, data.len() - 1), 0, 0, reasonCode)
120-
assign(reason, panicReasons.getOrDefault(reasonCode.truncate(int)))
139+
let reasonCode = decodeU256(data.toOpenArray(4, data.len() - 1)).valueOr:
140+
return Opt.none(string)
141+
return ok(panicReasons.getOrDefault(reasonCode.truncate(int)))

execution_chain/evm/interpreter/op_handlers/oph_sysops.nim

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -64,13 +64,12 @@ proc revertOp(cpt: VmCpt): EvmResultVoid =
6464

6565
cpt.memory.extend(pos, len)
6666
assign(cpt.output, cpt.memory.read(pos, len))
67-
68-
var revertReason: string
69-
unpackRevertReason(cpt.output, revertReason)
67+
68+
let revertReason = unpackRevertReason(cpt.output)
7069

7170
let revertMsg =
72-
if revertReason.len() > 0:
73-
"execution reverted: " & revertReason
71+
if revertReason.isSome:
72+
"execution reverted: " & revertReason.value
7473
else:
7574
"execution reverted"
7675

tests/test_evm_errors.nim

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,23 @@ suite "EVM errors tests":
1414
test "unpack revert reason data":
1515
let data = "0x08c379a000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000018556e69737761705632526f757465723a20455850495245440000000000000000"
1616

17-
var revertReason: string
18-
unpackRevertReason(data.hexToSeqByte(), revertReason)
17+
let revertReason = unpackRevertReason(data.hexToSeqByte()).expect("something")
1918
check revertReason == "UniswapV2Router: EXPIRED"
2019

20+
test "unpack revert reason data missing bytes":
21+
let data = "0x08c379a0000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000018556e69737761705632526f757465723a20455850495245440000000000000000"
22+
23+
let revertReason = unpackRevertReason(data.hexToSeqByte())
24+
check revertReason == Opt.none(string)
25+
2126
test "unpack panic reason data":
2227
let data = "0x4e487b710000000000000000000000000000000000000000000000000000000000000032"
2328

24-
var revertReason: string
25-
unpackRevertReason(data.hexToSeqByte(), revertReason)
29+
var revertReason = unpackRevertReason(data.hexToSeqByte()).expect("something")
2630
check revertReason == "out-of-bounds access of an array or bytesN"
31+
32+
test "unpack panic reason data missing byte":
33+
let data = "0x4e487b7100000000000000000000000000000000000000000000000000000000000032"
34+
35+
var revertReason = unpackRevertReason(data.hexToSeqByte())
36+
check revertReason == Opt.none(string)

0 commit comments

Comments
 (0)