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

Basic fix for DELEGATECALL and basic support for STATICCALL #306

Merged
merged 3 commits into from
Aug 2, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion include/evm2wasm.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ enum class opcodeEnum
CALLCODE,
RETURN,
DELEGATECALL,
STATICCALL,
SELFDESTRUCT,
INVALID,
bswap_i32,
Expand Down Expand Up @@ -266,6 +267,7 @@ static std::map<int, std::tuple<opcodeEnum, int, int, int>> codes = {
{0xf2, Opcode{opcodeEnum::CALLCODE, 0, 7, 1}},
{0xf3, Opcode{opcodeEnum::RETURN, 0, 2, 0}},
{0xf4, Opcode{opcodeEnum::DELEGATECALL, 0, 6, 1}},
{0xfa, Opcode{opcodeEnum::STATICCALL, 0, 6, 1}},

// "0x70", range - other
{0xff, Opcode{opcodeEnum::SELFDESTRUCT, 0, 1, 0}}};
Expand Down Expand Up @@ -313,11 +315,14 @@ static std::map<opcodeEnum, std::vector<opcodeEnum>> depMap = {
opcodeEnum::check_overflow, opcodeEnum::memset, opcodeEnum::callback_32}},
{opcodeEnum::DELEGATECALL, {opcodeEnum::callback, opcodeEnum::memusegas,
opcodeEnum::check_overflow, opcodeEnum::memset,
opcodeEnum::check_overflow_i64}},
opcodeEnum::check_overflow_i64, opcodeEnum::callback_32}},
{opcodeEnum::CALLCODE,
{opcodeEnum::bswap_m256, opcodeEnum::callback, opcodeEnum::memusegas,
opcodeEnum::check_overflow, opcodeEnum::memset, opcodeEnum::callback_32,
opcodeEnum::check_overflow_i64}},
{opcodeEnum::STATICCALL, {opcodeEnum::callback, opcodeEnum::memusegas,
opcodeEnum::check_overflow, opcodeEnum::memset,
opcodeEnum::check_overflow_i64, opcodeEnum::callback_32}},
{opcodeEnum::CREATE, {opcodeEnum::bswap_m256, opcodeEnum::bswap_m160, opcodeEnum::callback_160,
opcodeEnum::memusegas, opcodeEnum::check_overflow}},
{opcodeEnum::RETURN, {opcodeEnum::memusegas, opcodeEnum::check_overflow}},
Expand Down
9 changes: 7 additions & 2 deletions include/wast-async.h
Original file line number Diff line number Diff line change
Expand Up @@ -130,8 +130,13 @@ namespace evm2wasm
}
},{
opcodeEnum::DELEGATECALL, {
.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)))",
.imports = "(import \"ethereum\" \"callDelegate\" (func $callDelegate (param i64 i32 i32 i32 i32 i32 i32 i32) (result i32)))"
.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)))",
.imports = "(import \"ethereum\" \"callDelegate\" (func $callDelegate (param i64 i32 i32 i32 i32 i32) (result i32)))"
}
},{
opcodeEnum::STATICCALL, {
.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)))",
.imports = "(import \"ethereum\" \"callStatic\" (func $callStatic (param i64 i32 i32 i32 i32) (result i32)))"
}
},{
opcodeEnum::SSTORE, {
Expand Down
9 changes: 7 additions & 2 deletions include/wast.h
Original file line number Diff line number Diff line change
Expand Up @@ -130,8 +130,13 @@ namespace evm2wasm
}
},{
opcodeEnum::DELEGATECALL, {
.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)))",
.imports = "(import \"ethereum\" \"callDelegate\" (func $callDelegate (param i64 i32 i32 i32 i32 i32 i32) (result i32)))"
.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)))",
.imports = "(import \"ethereum\" \"callDelegate\" (func $callDelegate (param i64 i32 i32 i32 i32) (result i32)))"
}
},{
opcodeEnum::STATICCALL, {
.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)))",
.imports = "(import \"ethereum\" \"callStatic\" (func $callStatic (param i64 i32 i32 i32) (result i32)))"
}
},{
opcodeEnum::SSTORE, {
Expand Down
3 changes: 2 additions & 1 deletion index.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@ const depMap = new Map([
['BLOCKHASH', ['check_overflow', 'callback_256']],
['SHA3', ['memusegas', 'bswap_m256', 'check_overflow', 'keccak']],
['CALL', ['bswap_m256', 'memusegas', 'check_overflow_i64', 'check_overflow', 'memset', 'callback_32']],
['DELEGATECALL', ['callback', 'memusegas', 'check_overflow_i64', 'check_overflow', 'memset']],
['DELEGATECALL', ['callback', 'memusegas', 'check_overflow_i64', 'check_overflow', 'memset', 'callback_32']],
['STATICCALL', ['callback', 'memusegas', 'check_overflow_i64', 'check_overflow', 'memset', 'callback_32']],
['CALLCODE', ['bswap_m256', 'callback', 'memusegas', 'check_overflow_i64', 'check_overflow', 'check_overflow_i64', 'memset', 'callback_32']],
['CREATE', ['bswap_m256', 'bswap_m160', 'callback_160', 'memusegas', 'check_overflow']],
['RETURN', ['memusegas', 'check_overflow']],
Expand Down
1 change: 1 addition & 0 deletions opcodes.js
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@ const codes = {
0xf2: ['CALLCODE', 0, 7, 1],
0xf3: ['RETURN', 0, 2, 0],
0xf4: ['DELEGATECALL', 0, 6, 1],
0xfa: ['STATICCALL', 0, 6, 1],

// '0x70', range - other
0xff: ['SELFDESTRUCT', 0, 1, 0]
Expand Down
14 changes: 10 additions & 4 deletions wasm/generateInterface.js
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,13 @@ const interfaceManifest = {
DELEGATECALL: {
name: 'callDelegate',
async: true,
input: ['gasLimit', 'address', 'i128', 'readOffset', 'length', 'writeOffset', 'length'],
input: ['gasLimit', 'address', 'i128', 'readOffset', 'length'],
output: ['i32']
},
STATICCALL: {
name: 'callStatic',
async: true,
input: ['gasLimit', 'address', 'readOffset', 'length'],
output: ['i32']
},
SSTORE: {
Expand Down Expand Up @@ -289,7 +295,7 @@ function generateManifest (interfaceManifest, opts) {
locals += `(local $offset${numOfLocals} i32)`
body += `(set_local $offset${numOfLocals} ${checkOverflowStackItem256(spOffset)})`
call += `(get_local $offset${numOfLocals})`
} else if (input === 'length' && (opcode === 'CALL' || opcode === 'CALLCODE')) {
} else if (input === 'length' && (opcode === 'CALL' || opcode === 'CALLCODE' || opcode === 'DELEGATECALL' || opcode === 'STATICCALL')) {
// CALLs in EVM have 7 arguments
// but in ewasm CALLs only have 5 arguments
// so delete the bottom two stack elements, after processing the 5th argument
Expand All @@ -309,7 +315,7 @@ function generateManifest (interfaceManifest, opts) {

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

Expand Down Expand Up @@ -368,7 +374,7 @@ function generateManifest (interfaceManifest, opts) {
call += '(get_local $callback)'
}

if (opcode === 'CALL' || opcode === 'CALLCODE' || opcode === 'DELEGATECALL') {
if (opcode === 'CALL' || opcode === 'CALLCODE' || opcode === 'DELEGATECALL' || opcode === 'STATICCALL') {
call =
`(i64.store
(i32.add (get_global $sp) (i32.const ${spOffset * 32}))
Expand Down
Loading