Home

Awesome

HAssembly-evm

EVM (Ethereum virtual machine) Assembly on Haskell DSL

This is a bytecode generator from EVM assembly on Haskell DSL.

Warning:

Feature:

Limitation:

Run

Command:

GHC:

Stack:

Cabal:

Example:

$ runghc -isrc app/Main.hs
601060200100

Code example

Basic:

main :: IO ()
main = putStrLn $ codegen prog1

prog1 :: EvmAsm
prog1 = do
    push1 0x10
    push1 0x20
    add

Composable:

prog2 :: EvmAsm
prog2 = do
    prog2a
    prog2b

prog2a = do
    push1 0x40
    mload

prog2b = do
    push1 0x20
    add

Pseudo instruction and built-in function:

prog3 :: EvmAsm
prog3 = do
    push1 0x60
    push1 0x40
    mstore
    _jump "target2"            -- symbol jump

    push1 (_progSize prog4)    -- program size
    _pushlabel "top1"          -- push label
    _dest "target2"            -- jump target


prog4 :: EvmAsm
prog4 = do
    _label "top1"              -- label
    _push 0x11234456788        -- multi length push
    _raw 0x7                   -- raw byte
    _raw 0x8

Using host language (Haskell):

prog5 = do
    if isBizantinum          -- if expression on Haskell
        then prog_header1
        else prog_header2
    push1 0x60
    push1 0x40
    mstore

User defined functions and syntax:

Example1:

shiftL nbit = do    -- user defined function
    push1 nbit
    push1 2
    exp
    mul

prog6 = do
    mload
    shiftL 16    -- using
    push1 0x1
    add

    string "OK" >> log1

Example2: (examples/userSyntax.hs)

prog7 = do
    let num1 = const 0x10      -- let syntax
    let num2 = const 0x20
    let factor1 = ptr 0x05     -- memory type
    let user1   = key 0x100    -- storage type

    add2(num1, num2)           -- functional syntax
    add2(ref factor1, num1)
    add
    add2(value user1, const 3)
    memory(factor1) <== mul    -- assignment syntax

    storage(user1) <== mul2(num2, (add2(const 4, ref factor1)))

Example3: (examples/userFlow.hs)

prog8 = do
    _if (iszero) (do -- then
          push1 0x01
          push1 0x02
          add
      ) (do -- else
          push1 0x01
          push1 0x02
          sub
      )

Execute bytecode

If you need to execute a generated bytecode, please use the evm command of go-ethereum project or some tools.

Execute bytecode by evm command:

$ evm --code "601060200100" --debug run

Disasemble bytecode by evm command:

$ evm disasm sample.bytecode

Listing and pretty printing

Simple listing:

Use pprList function:

main :: IO ()
main = putStrLn $ pprList prog1   -- using `pprList`

prog1 :: EvmAsm
prog1 = do ...

Output example:

$ runghc -isrc examples/pprList.hs
000000: push1 0x10
000002: push1 0x20
000004: add
000005: stop

Under implementation ...

Pretty-print for Solidity:

$ runghc -isrc examples/PprSol.hs
{
    0x10
    0x20
    add
    stop
    pop
}

Stack hight checking:

$ runghc -isrc examples/StackCheck.hs
Final stack-hight: 0

See also