Code Monkey home page Code Monkey logo

cl-evasm's Introduction

Intro

This is EVM assembly implemented as a Common Lisp embedded language.

What it means is that this package provides macro that allows the user to write evm assembly code with simple syntax while having full general purpose language (Common Lisp) available to augment asm code writing with arbitrary code.

See "Advanced, meta evaluation" what is possible with this approach that is impossible with other assemblies.

The goal of this code is to

  1. Show how one can possibly implement simple and powerful assembly. (it's only ~200 lines of code, where 90 is just instruction enumeration)
  2. Introduce real macros as a useful feature that implementors of evm asm may consider
  3. I really needed asm and I actually use it.

Rules

Rules for asm writing.

We use asm, asm-hex, asm-oct macros to transform evm assembly DSL to list of assembly mnemonics, mnemonict->octets function is used to transform the output of asm into hex bytecode.

Literals and mnemonics

Basic

Numbers and hex strings are translated to push instruction of appropriate size.

(asm 16) ;; =>  '((push 1 16))
(asm-hex 16) ;; =>  "6010"
(asm "0xaabb") ;; => '((PUSH 2 43707))))'

For each evm opcode there is a mnemonic defined in src/assembly.lisp.

  • Most mnemonics are just symbols from evm spec.: add pop
  • Some mnemonics are lists of repetitive symbols from spec. (push 1 #xff) (dup 11) (swap 5) (log 1)
  • There are special mnemonics
    1. (verbatim #xaabbccff) - sequence of bytes that represent a sequence of arbitrary instructions
    2. (push-label 'symbol'), (label 'symbol) - symbolic labels of some place in bytecode. label will resolve to jumpdest and push-label will resolve to push of label position to stack.
(asm 1 2 add) ;; > '((push 1 1) (push 1 2) add)'
(asm 2 2 add 4 eq
     (push-label 'ok) jumpi
     0 0 revert
     (label 'ok)) ;; adds 2 and 2 and if its not 4 we revert, if its 4 we jump over revert

Arbitrary evaluation

If asm sees a form that is not literal or mnemonic it evaluates is, evaluation should return valid input to asm macro.

;; here (+ 2 3) will be evaluated and result is pushed 
(asm (+ 2 3)) ;; -> '((push 1 5))

;; imagine we have function that calcuates selector for function
;; (selector "Transfer()") ;; -> "0xaabbccdd" (not correct btw)
(asm (selector "Transfer()") eq) ;; compares top of the stack to selector of transfer

This functionality can be used to replace huff macros as a lisp functions

(defun compare-to-n (n)
  (asm n eq))
  
(asm 4 (compare-to-n 4)) ;; when executed will yield 1 at the top of the stack
(asm 5 (compare-to-n 4)) ;; when executed will yield 0 at the top of the stack

We can emulate static memory allocation or free storage pointer with this.

(let* ((free-memory-slot -32)
       (allocated-memory-slot-1 (incf free-memory-slot 32)) ;; its 0
       (allocated-memory-slot-2 (incf free-memory-slot 32))) ;; its 32
  (asm allocated-memory-slot-1 mload 
       allocated-memory-slot-2 mload add)) ;; adds memory slots at 0 and 32 to each other

Advanced, meta evaluation

This class features are not available in any evm assembly implementation out there, and it's where embedding into lisp shines.

Imagine we would like to implement a feature like that:

  1. We have operation hide
  2. Hide takes any valid assembly code and transforms it to code that does not see a value that is on top of the stack.
  3. In other words, hide hides top of the stack from the code inside!

Usage:

(asm 1 2 3
     (hide add)) ;; will push 1 2 3 to the top of the stack 
	                     ;; add inside hide will not see 3 and will add 1 and 2. 

I will not implement hide, but this is trivial code transformation left as an exercise to the reader.

Possible implementation - hide will be common lisp macro (or function, but syntax would be (hide (asm ...)) instead of (hide ...)). Hide will take asm instructions and transform them in a way that code inside will never see hidden value (e.g. (swap n), (dup n) will be replaced with (swap (+ n 1)) (swap (+ n 1))).

Other uses of meta evaluation

(meta evaluation is basically macros but not like huff macros which are just functions in lisp terms)

  1. if,then,else - can be used instead of arbitrary jumps and labels.
  2. Loops. Loop can be a macro that takes code inside loop (body), adds loop counter logic around and hides loop counter data from body.

See Factor language for inspiration of useful stack utilities, especially combinators

cl-evasm's People

Contributors

dvush avatar

Watchers

 avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.