Skip to content
This repository was archived by the owner on Jan 5, 2019. It is now read-only.

Commit eb40b00

Browse files
authored
Merge pull request #306 from ewasm/fix-delegatecall
Basic fix for DELEGATECALL and basic support for STATICCALL
2 parents 0bae4c6 + 17f624e commit eb40b00

File tree

8 files changed

+45
-14
lines changed

8 files changed

+45
-14
lines changed

include/evm2wasm.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ enum class opcodeEnum
7474
CALLCODE,
7575
RETURN,
7676
DELEGATECALL,
77+
STATICCALL,
7778
SELFDESTRUCT,
7879
INVALID,
7980
bswap_i32,
@@ -266,6 +267,7 @@ static std::map<int, std::tuple<opcodeEnum, int, int, int>> codes = {
266267
{0xf2, Opcode{opcodeEnum::CALLCODE, 0, 7, 1}},
267268
{0xf3, Opcode{opcodeEnum::RETURN, 0, 2, 0}},
268269
{0xf4, Opcode{opcodeEnum::DELEGATECALL, 0, 6, 1}},
270+
{0xfa, Opcode{opcodeEnum::STATICCALL, 0, 6, 1}},
269271

270272
// "0x70", range - other
271273
{0xff, Opcode{opcodeEnum::SELFDESTRUCT, 0, 1, 0}}};
@@ -313,11 +315,14 @@ static std::map<opcodeEnum, std::vector<opcodeEnum>> depMap = {
313315
opcodeEnum::check_overflow, opcodeEnum::memset, opcodeEnum::callback_32}},
314316
{opcodeEnum::DELEGATECALL, {opcodeEnum::callback, opcodeEnum::memusegas,
315317
opcodeEnum::check_overflow, opcodeEnum::memset,
316-
opcodeEnum::check_overflow_i64}},
318+
opcodeEnum::check_overflow_i64, opcodeEnum::callback_32}},
317319
{opcodeEnum::CALLCODE,
318320
{opcodeEnum::bswap_m256, opcodeEnum::callback, opcodeEnum::memusegas,
319321
opcodeEnum::check_overflow, opcodeEnum::memset, opcodeEnum::callback_32,
320322
opcodeEnum::check_overflow_i64}},
323+
{opcodeEnum::STATICCALL, {opcodeEnum::callback, opcodeEnum::memusegas,
324+
opcodeEnum::check_overflow, opcodeEnum::memset,
325+
opcodeEnum::check_overflow_i64, opcodeEnum::callback_32}},
321326
{opcodeEnum::CREATE, {opcodeEnum::bswap_m256, opcodeEnum::bswap_m160, opcodeEnum::callback_160,
322327
opcodeEnum::memusegas, opcodeEnum::check_overflow}},
323328
{opcodeEnum::RETURN, {opcodeEnum::memusegas, opcodeEnum::check_overflow}},

include/wast-async.h

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -130,8 +130,13 @@ namespace evm2wasm
130130
}
131131
},{
132132
opcodeEnum::DELEGATECALL, {
133-
.wast = ";; generated by ./wasm/generateInterface.js\n(func $DELEGATECALL (param $callback i32)(local $offset0 i32)(local $length0 i32)(local $offset1 i32)(local $length1 i32) (set_local $offset0 (call $check_overflow\n (i64.load (i32.add (get_global $sp) (i32.const -96)))\n (i64.load (i32.add (get_global $sp) (i32.const -88)))\n (i64.load (i32.add (get_global $sp) (i32.const -80)))\n (i64.load (i32.add (get_global $sp) (i32.const -72)))))(set_local $length0 (call $check_overflow\n (i64.load (i32.add (get_global $sp) (i32.const -128)))\n (i64.load (i32.add (get_global $sp) (i32.const -120)))\n (i64.load (i32.add (get_global $sp) (i32.const -112)))\n (i64.load (i32.add (get_global $sp) (i32.const -104)))))\n (call $memusegas (get_local $offset0) (get_local $length0))\n (set_local $offset0 (i32.add (get_global $memstart) (get_local $offset0)))(set_local $offset1 (call $check_overflow\n (i64.load (i32.add (get_global $sp) (i32.const -160)))\n (i64.load (i32.add (get_global $sp) (i32.const -152)))\n (i64.load (i32.add (get_global $sp) (i32.const -144)))\n (i64.load (i32.add (get_global $sp) (i32.const -136)))))(set_local $length1 (call $check_overflow\n (i64.load (i32.add (get_global $sp) (i32.const -192)))\n (i64.load (i32.add (get_global $sp) (i32.const -184)))\n (i64.load (i32.add (get_global $sp) (i32.const -176)))\n (i64.load (i32.add (get_global $sp) (i32.const -168)))))\n (call $memusegas (get_local $offset1) (get_local $length1))\n (set_local $offset1 (i32.add (get_global $memstart) (get_local $offset1))) (i64.store\n (i32.add (get_global $sp) (i32.const -192))\n (i64.extend_u/i32\n (i32.eqz (call $callDelegate(call $check_overflow_i64\n (i64.load (i32.add (get_global $sp) (i32.const 0)))\n (i64.load (i32.add (get_global $sp) (i32.const 8)))\n (i64.load (i32.add (get_global $sp) (i32.const 16)))\n (i64.load (i32.add (get_global $sp) (i32.const 24))))(i32.add (get_global $sp) (i32.const -32))(i32.add (get_global $sp) (i32.const -64))(get_local $offset0)(get_local $length0)(get_local $offset1)(get_local $length1)(get_local $callback)) ;; flip CALL result from EEI to EVM convention (0 -> 1, 1,2,.. -> 1)\n )))\n ;; zero out mem\n (i64.store (i32.add (get_global $sp) (i32.const -168)) (i64.const 0))\n (i64.store (i32.add (get_global $sp) (i32.const -176)) (i64.const 0))\n (i64.store (i32.add (get_global $sp) (i32.const -184)) (i64.const 0)))",
134-
.imports = "(import \"ethereum\" \"callDelegate\" (func $callDelegate (param i64 i32 i32 i32 i32 i32 i32 i32) (result i32)))"
133+
.wast = ";; generated by ./wasm/generateInterface.js\n(func $DELEGATECALL (param $callback i32)(local $offset0 i32)(local $length0 i32) (set_local $offset0 (call $check_overflow\n (i64.load (i32.add (get_global $sp) (i32.const -96)))\n (i64.load (i32.add (get_global $sp) (i32.const -88)))\n (i64.load (i32.add (get_global $sp) (i32.const -80)))\n (i64.load (i32.add (get_global $sp) (i32.const -72)))))(set_local $length0 (call $check_overflow\n (i64.load (i32.add (get_global $sp) (i32.const -128)))\n (i64.load (i32.add (get_global $sp) (i32.const -120)))\n (i64.load (i32.add (get_global $sp) (i32.const -112)))\n (i64.load (i32.add (get_global $sp) (i32.const -104)))))\n (call $memusegas (get_local $offset0) (get_local $length0))\n (set_local $offset0 (i32.add (get_global $memstart) (get_local $offset0))) (i64.store\n (i32.add (get_global $sp) (i32.const -192))\n (i64.extend_u/i32\n (i32.eqz (call $callDelegate(call $check_overflow_i64\n (i64.load (i32.add (get_global $sp) (i32.const 0)))\n (i64.load (i32.add (get_global $sp) (i32.const 8)))\n (i64.load (i32.add (get_global $sp) (i32.const 16)))\n (i64.load (i32.add (get_global $sp) (i32.const 24))))(i32.add (get_global $sp) (i32.const -32))(i32.add (get_global $sp) (i32.const -64))(get_local $offset0)(get_local $length0)(get_local $callback)) ;; flip CALL result from EEI to EVM convention (0 -> 1, 1,2,.. -> 1)\n )))\n ;; zero out mem\n (i64.store (i32.add (get_global $sp) (i32.const -168)) (i64.const 0))\n (i64.store (i32.add (get_global $sp) (i32.const -176)) (i64.const 0))\n (i64.store (i32.add (get_global $sp) (i32.const -184)) (i64.const 0)))",
134+
.imports = "(import \"ethereum\" \"callDelegate\" (func $callDelegate (param i64 i32 i32 i32 i32 i32) (result i32)))"
135+
}
136+
},{
137+
opcodeEnum::STATICCALL, {
138+
.wast = ";; generated by ./wasm/generateInterface.js\n(func $STATICCALL (param $callback i32)(local $offset0 i32)(local $length0 i32) (set_local $offset0 (call $check_overflow\n (i64.load (i32.add (get_global $sp) (i32.const -64)))\n (i64.load (i32.add (get_global $sp) (i32.const -56)))\n (i64.load (i32.add (get_global $sp) (i32.const -48)))\n (i64.load (i32.add (get_global $sp) (i32.const -40)))))(set_local $length0 (call $check_overflow\n (i64.load (i32.add (get_global $sp) (i32.const -96)))\n (i64.load (i32.add (get_global $sp) (i32.const -88)))\n (i64.load (i32.add (get_global $sp) (i32.const -80)))\n (i64.load (i32.add (get_global $sp) (i32.const -72)))))\n (call $memusegas (get_local $offset0) (get_local $length0))\n (set_local $offset0 (i32.add (get_global $memstart) (get_local $offset0))) (i64.store\n (i32.add (get_global $sp) (i32.const -160))\n (i64.extend_u/i32\n (i32.eqz (call $callStatic(call $check_overflow_i64\n (i64.load (i32.add (get_global $sp) (i32.const 0)))\n (i64.load (i32.add (get_global $sp) (i32.const 8)))\n (i64.load (i32.add (get_global $sp) (i32.const 16)))\n (i64.load (i32.add (get_global $sp) (i32.const 24))))(i32.add (get_global $sp) (i32.const -32))(get_local $offset0)(get_local $length0)(get_local $callback)) ;; flip CALL result from EEI to EVM convention (0 -> 1, 1,2,.. -> 1)\n )))\n ;; zero out mem\n (i64.store (i32.add (get_global $sp) (i32.const -136)) (i64.const 0))\n (i64.store (i32.add (get_global $sp) (i32.const -144)) (i64.const 0))\n (i64.store (i32.add (get_global $sp) (i32.const -152)) (i64.const 0)))",
139+
.imports = "(import \"ethereum\" \"callStatic\" (func $callStatic (param i64 i32 i32 i32 i32) (result i32)))"
135140
}
136141
},{
137142
opcodeEnum::SSTORE, {

include/wast.h

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -130,8 +130,13 @@ namespace evm2wasm
130130
}
131131
},{
132132
opcodeEnum::DELEGATECALL, {
133-
.wast = ";; generated by ./wasm/generateInterface.js\n(func $DELEGATECALL (local $offset0 i32)(local $length0 i32)(local $offset1 i32)(local $length1 i32) (set_local $offset0 (call $check_overflow\n (i64.load (i32.add (get_global $sp) (i32.const -96)))\n (i64.load (i32.add (get_global $sp) (i32.const -88)))\n (i64.load (i32.add (get_global $sp) (i32.const -80)))\n (i64.load (i32.add (get_global $sp) (i32.const -72)))))(set_local $length0 (call $check_overflow\n (i64.load (i32.add (get_global $sp) (i32.const -128)))\n (i64.load (i32.add (get_global $sp) (i32.const -120)))\n (i64.load (i32.add (get_global $sp) (i32.const -112)))\n (i64.load (i32.add (get_global $sp) (i32.const -104)))))\n (call $memusegas (get_local $offset0) (get_local $length0))\n (set_local $offset0 (i32.add (get_global $memstart) (get_local $offset0)))(set_local $offset1 (call $check_overflow\n (i64.load (i32.add (get_global $sp) (i32.const -160)))\n (i64.load (i32.add (get_global $sp) (i32.const -152)))\n (i64.load (i32.add (get_global $sp) (i32.const -144)))\n (i64.load (i32.add (get_global $sp) (i32.const -136)))))(set_local $length1 (call $check_overflow\n (i64.load (i32.add (get_global $sp) (i32.const -192)))\n (i64.load (i32.add (get_global $sp) (i32.const -184)))\n (i64.load (i32.add (get_global $sp) (i32.const -176)))\n (i64.load (i32.add (get_global $sp) (i32.const -168)))))\n (call $memusegas (get_local $offset1) (get_local $length1))\n (set_local $offset1 (i32.add (get_global $memstart) (get_local $offset1))) (i64.store\n (i32.add (get_global $sp) (i32.const -192))\n (i64.extend_u/i32\n (i32.eqz (call $callDelegate(call $check_overflow_i64\n (i64.load (i32.add (get_global $sp) (i32.const 0)))\n (i64.load (i32.add (get_global $sp) (i32.const 8)))\n (i64.load (i32.add (get_global $sp) (i32.const 16)))\n (i64.load (i32.add (get_global $sp) (i32.const 24))))(i32.add (get_global $sp) (i32.const -32))(i32.add (get_global $sp) (i32.const -64))(get_local $offset0)(get_local $length0)(get_local $offset1)(get_local $length1)) ;; flip CALL result from EEI to EVM convention (0 -> 1, 1,2,.. -> 1)\n )))\n ;; zero out mem\n (i64.store (i32.add (get_global $sp) (i32.const -168)) (i64.const 0))\n (i64.store (i32.add (get_global $sp) (i32.const -176)) (i64.const 0))\n (i64.store (i32.add (get_global $sp) (i32.const -184)) (i64.const 0)))",
134-
.imports = "(import \"ethereum\" \"callDelegate\" (func $callDelegate (param i64 i32 i32 i32 i32 i32 i32) (result i32)))"
133+
.wast = ";; generated by ./wasm/generateInterface.js\n(func $DELEGATECALL (local $offset0 i32)(local $length0 i32) (set_local $offset0 (call $check_overflow\n (i64.load (i32.add (get_global $sp) (i32.const -96)))\n (i64.load (i32.add (get_global $sp) (i32.const -88)))\n (i64.load (i32.add (get_global $sp) (i32.const -80)))\n (i64.load (i32.add (get_global $sp) (i32.const -72)))))(set_local $length0 (call $check_overflow\n (i64.load (i32.add (get_global $sp) (i32.const -128)))\n (i64.load (i32.add (get_global $sp) (i32.const -120)))\n (i64.load (i32.add (get_global $sp) (i32.const -112)))\n (i64.load (i32.add (get_global $sp) (i32.const -104)))))\n (call $memusegas (get_local $offset0) (get_local $length0))\n (set_local $offset0 (i32.add (get_global $memstart) (get_local $offset0))) (i64.store\n (i32.add (get_global $sp) (i32.const -192))\n (i64.extend_u/i32\n (i32.eqz (call $callDelegate(call $check_overflow_i64\n (i64.load (i32.add (get_global $sp) (i32.const 0)))\n (i64.load (i32.add (get_global $sp) (i32.const 8)))\n (i64.load (i32.add (get_global $sp) (i32.const 16)))\n (i64.load (i32.add (get_global $sp) (i32.const 24))))(i32.add (get_global $sp) (i32.const -32))(i32.add (get_global $sp) (i32.const -64))(get_local $offset0)(get_local $length0)) ;; flip CALL result from EEI to EVM convention (0 -> 1, 1,2,.. -> 1)\n )))\n ;; zero out mem\n (i64.store (i32.add (get_global $sp) (i32.const -168)) (i64.const 0))\n (i64.store (i32.add (get_global $sp) (i32.const -176)) (i64.const 0))\n (i64.store (i32.add (get_global $sp) (i32.const -184)) (i64.const 0)))",
134+
.imports = "(import \"ethereum\" \"callDelegate\" (func $callDelegate (param i64 i32 i32 i32 i32) (result i32)))"
135+
}
136+
},{
137+
opcodeEnum::STATICCALL, {
138+
.wast = ";; generated by ./wasm/generateInterface.js\n(func $STATICCALL (local $offset0 i32)(local $length0 i32) (set_local $offset0 (call $check_overflow\n (i64.load (i32.add (get_global $sp) (i32.const -64)))\n (i64.load (i32.add (get_global $sp) (i32.const -56)))\n (i64.load (i32.add (get_global $sp) (i32.const -48)))\n (i64.load (i32.add (get_global $sp) (i32.const -40)))))(set_local $length0 (call $check_overflow\n (i64.load (i32.add (get_global $sp) (i32.const -96)))\n (i64.load (i32.add (get_global $sp) (i32.const -88)))\n (i64.load (i32.add (get_global $sp) (i32.const -80)))\n (i64.load (i32.add (get_global $sp) (i32.const -72)))))\n (call $memusegas (get_local $offset0) (get_local $length0))\n (set_local $offset0 (i32.add (get_global $memstart) (get_local $offset0))) (i64.store\n (i32.add (get_global $sp) (i32.const -160))\n (i64.extend_u/i32\n (i32.eqz (call $callStatic(call $check_overflow_i64\n (i64.load (i32.add (get_global $sp) (i32.const 0)))\n (i64.load (i32.add (get_global $sp) (i32.const 8)))\n (i64.load (i32.add (get_global $sp) (i32.const 16)))\n (i64.load (i32.add (get_global $sp) (i32.const 24))))(i32.add (get_global $sp) (i32.const -32))(get_local $offset0)(get_local $length0)) ;; flip CALL result from EEI to EVM convention (0 -> 1, 1,2,.. -> 1)\n )))\n ;; zero out mem\n (i64.store (i32.add (get_global $sp) (i32.const -136)) (i64.const 0))\n (i64.store (i32.add (get_global $sp) (i32.const -144)) (i64.const 0))\n (i64.store (i32.add (get_global $sp) (i32.const -152)) (i64.const 0)))",
139+
.imports = "(import \"ethereum\" \"callStatic\" (func $callStatic (param i64 i32 i32 i32) (result i32)))"
135140
}
136141
},{
137142
opcodeEnum::SSTORE, {

index.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,8 @@ const depMap = new Map([
3838
['BLOCKHASH', ['check_overflow', 'callback_256']],
3939
['SHA3', ['memusegas', 'bswap_m256', 'check_overflow', 'keccak']],
4040
['CALL', ['bswap_m256', 'memusegas', 'check_overflow_i64', 'check_overflow', 'memset', 'callback_32']],
41-
['DELEGATECALL', ['callback', 'memusegas', 'check_overflow_i64', 'check_overflow', 'memset']],
41+
['DELEGATECALL', ['callback', 'memusegas', 'check_overflow_i64', 'check_overflow', 'memset', 'callback_32']],
42+
['STATICCALL', ['callback', 'memusegas', 'check_overflow_i64', 'check_overflow', 'memset', 'callback_32']],
4243
['CALLCODE', ['bswap_m256', 'callback', 'memusegas', 'check_overflow_i64', 'check_overflow', 'check_overflow_i64', 'memset', 'callback_32']],
4344
['CREATE', ['bswap_m256', 'bswap_m160', 'callback_160', 'memusegas', 'check_overflow']],
4445
['RETURN', ['memusegas', 'check_overflow']],

opcodes.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,7 @@ const codes = {
147147
0xf2: ['CALLCODE', 0, 7, 1],
148148
0xf3: ['RETURN', 0, 2, 0],
149149
0xf4: ['DELEGATECALL', 0, 6, 1],
150+
0xfa: ['STATICCALL', 0, 6, 1],
150151

151152
// '0x70', range - other
152153
0xff: ['SELFDESTRUCT', 0, 1, 0]

wasm/generateInterface.js

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,13 @@ const interfaceManifest = {
152152
DELEGATECALL: {
153153
name: 'callDelegate',
154154
async: true,
155-
input: ['gasLimit', 'address', 'i128', 'readOffset', 'length', 'writeOffset', 'length'],
155+
input: ['gasLimit', 'address', 'i128', 'readOffset', 'length'],
156+
output: ['i32']
157+
},
158+
STATICCALL: {
159+
name: 'callStatic',
160+
async: true,
161+
input: ['gasLimit', 'address', 'readOffset', 'length'],
156162
output: ['i32']
157163
},
158164
SSTORE: {
@@ -289,7 +295,7 @@ function generateManifest (interfaceManifest, opts) {
289295
locals += `(local $offset${numOfLocals} i32)`
290296
body += `(set_local $offset${numOfLocals} ${checkOverflowStackItem256(spOffset)})`
291297
call += `(get_local $offset${numOfLocals})`
292-
} else if (input === 'length' && (opcode === 'CALL' || opcode === 'CALLCODE')) {
298+
} else if (input === 'length' && (opcode === 'CALL' || opcode === 'CALLCODE' || opcode === 'DELEGATECALL' || opcode === 'STATICCALL')) {
293299
// CALLs in EVM have 7 arguments
294300
// but in ewasm CALLs only have 5 arguments
295301
// so delete the bottom two stack elements, after processing the 5th argument
@@ -309,7 +315,7 @@ function generateManifest (interfaceManifest, opts) {
309315

310316
// delete 7th stack element
311317
spOffset--
312-
} else if (input === 'length' && (opcode !== 'CALL' && opcode !== 'CALLCODE')) {
318+
} else if (input === 'length' && (opcode !== 'CALL' && opcode !== 'CALLCODE' && opcode !== 'DELEGATECALL' && opcode !== 'STATICCALL')) {
313319
locals += `(local $length${numOfLocals} i32)`
314320
body += `(set_local $length${numOfLocals} ${checkOverflowStackItem256(spOffset)})`
315321

@@ -368,7 +374,7 @@ function generateManifest (interfaceManifest, opts) {
368374
call += '(get_local $callback)'
369375
}
370376

371-
if (opcode === 'CALL' || opcode === 'CALLCODE' || opcode === 'DELEGATECALL') {
377+
if (opcode === 'CALL' || opcode === 'CALLCODE' || opcode === 'DELEGATECALL' || opcode === 'STATICCALL') {
372378
call =
373379
`(i64.store
374380
(i32.add (get_global $sp) (i32.const ${spOffset * 32}))

0 commit comments

Comments
 (0)