Ruby Quiz - Challenge #11 - Blockchain Contracts - Disassemble & Assemble Ethereum Virtual Machine (EVM) Opcodes / Bytecodes

Gerald Bauer <[email protected]>
Newsgroups gmane.comp.lang.ruby.general
Message-ID <CAAxEZd8Sxu4Sapyi6NAqA8zFCc8RwLTYQNbgDCayqSk1gPY_kA@mail.gmail.com>
Hello,

  It's Friday. Ruby Quiz time! Join us. Let's keep going with a new
Ruby Quiz [1] every fortnight. Here we go:


  Challenge #11 - Blockchain Contracts - Disassemble & Assemble
Ethereum Virtual Machine (EVM) Opcodes / Bytecodes

Ethereum - the decentralized "world computer" -
lets you store and run your own (contract) code on the blockchain.

Remember
the "magic" sooper-sekret gene mixing operation formula
in the CryptoKitties GeneSciene contract?

You can find the "raw" bytecode encoded as a (hex) string
for the virtual stack machine
in the contract at
`etherscan.io/address/0xf97e0a5b616dffc913e72455fde9ea8bbe946a2b#code` [2].

```
0x60606040526004361061006c5763ffffffff7c0100000000000000000000000000000000000000
0000000000000000006000350416630d9f5aed81146100715780631597ee441461009f57806354c1
5b82146100ee57806361a769001461011557806377a74a201461017e575b600080fd5b341561007c
57600080fd5b61008d6004356024356044356101cd565b60405190815260200160405180910390f3
...
52600019909101906020018161072b57905050905600
```

If you click on "Switch to Opcodes" you
will see an
almost endless stream of to-the-metal Ethereum stack machine
instructions:

```
PUSH1 0x60
PUSH1 0x40
MSTORE
PUSH1 0x04
CALLDATASIZE
LT
PUSH2 0x006c
JUMPI
PUSH4 0xffffffff
PUSH29 0x0100000000000000000000000000000000000000000000000000000000
PUSH1 0x00
CALLDATALOAD
DIV
AND
PUSH4 0x0d9f5aed
DUP2
EQ
PUSH2 0x0071
JUMPI
DUP1
PUSH4 0x1597ee44
EQ
PUSH2 0x009f
JUMPI
DUP1
PUSH4 0x54c15b82
...
```


The challenge:  Code a `disassemble` and an `assemble` method that
pass the RubyQuizTest [3] :-).

For the starter level 1 turn the hex string
into a series of opcodes with the `disassemble` method.

```
def disassemble( hex )
  # ...
end
```

And for the bonus level 2 turn the series of opcodes
back into a hex string with the `assemble` method.

```
def assemble( code )
  # ...
end
```


Start from scratch or, yes, use any library / gem you can find.
To help along the test includes all opcodes / bytecodes (see opcodes.rb [4]).
Use:

```
Ethereum::Opcodes::TABLE[0x60]  #=> :PUSH1
Ethereum::Opcodes::TABLE[0x61]  #=> :PUSH2
Ethereum::Opcodes::TABLE[0x00]  #=> :STOP
```

to lookup the instruction name from the bytecode (e.g. `0x60`, `0x61`,
`0x00`, etc.).
And use:

```
Ethereum::Opcodes::REVERSE_TABLE[:PUSH1]  #=> 0x60
Ethereum::Opcodes::REVERSE_TABLE[:PUSH2]  #=> 0x61
Ethereum::Opcodes::REVERSE_TABLE[:STOP]   #=> 0x00
```

to lookup the bytecode from the instruction name (e.g. `PUSH1`,
`PUSH2`, `STOP`).

Note: In the hex string every byte is a bytecode instruction
with the ONLY exception of `PUSH1`, `PUSH2`, `PUSH3` .. `PUSH32`.
The `PUSH1` instruction places the following 1-byte on the stack
(e.g. disassemble to `PUSH1 0x60`).
The `PUSH2` instruction places the following 2-bytes on the stack
(e.g. disassemble to `PUSH4 0x006c`).
The `PUSH29` instruction places the following 29-bytes on the stack
(e.g. disassemble to `PUSH29
0x0100000000000000000000000000000000000000000000000000000000
`) and so on.

TIP: If interested read more about the Ethereum Virtual Machine (EVM)
and the opcodes / bytcodes in
the (free online) "The Ethereum Virtual Machine" [5] chapter
in the Mastering Ethereum book by Andreas M. Antonopoulos and Gavin Wood.


To qualify for solving the code challenge / puzzle you must pass the test:


```
require 'minitest/autorun'

require_relative './opcodes'


class RubyQuizTest < MiniTest::Test

  def mixgenes_hex
     hex = <<TXT
0x60606040526004361061006c5763ffffffff7c0100000000000000000000000000000000000000
0000000000000000006000350416630d9f5aed81146100715780631597ee441461009f57806354c1
5b82146100ee57806361a769001461011557806377a74a201461017e575b600080fd5b341561007c
57600080fd5b61008d6004356024356044356101cd565b60405190815260200160405180910390f3
5b34156100aa57600080fd5b61008d60046024813581810190830135806020818102016040519081
0160405280939291908181526020018383602002808284375094965061055a95505050505050565b
34156100f957600080fd5b61010161059d565b604051901515815260200160405180910390f35b34
1561012057600080fd5b61012b6004356105a6565b60405160208082528190810183818151815260
200191508051906020019060200280838360005b8381101561016a57808201518382015260200161
0152565b505050509050019250505060405180910390f35b341561018957600080fd5b6101946004
3561061e565b604051808261018080838360005b838110156101ba57808201518382015260200161
01a2565b5050505090500191505060405180910390f35b60008060006101da610709565b6101e261
0709565b6101ea610709565b60008080808080438d90116101fe57600080fd5b8c409a508a151561
022b5760ff8d1660ff194316019c50438d101515610226576101008d039c505b8c409a505b8a8f8f
8f604051808581526020018481526020018381526020018281526020019450505050506040519081
900390209a50600099506102698f6105a6565b98506102748e6105a6565b97506030604051805910
6102855750595b90808252806020026020018201604052509650600093505b600c8410156103ee57
600392505b600183106103e35782846004020195506102c78b60028c610668565b915060028a0199
508160001415610349578886815181106102e457fe5b906020019060200201519450886001870381
5181106102ff57fe5b9060200190602002015189878151811061031557fe5b60ff90921660209283
0290910190910152848960001988018151811061033757fe5b60ff90921660209283029091019091
01525b6103558b60028c610668565b915060028a01995081600014156103d7578786815181106103
7257fe5b90602001906020020151945087600187038151811061038d57fe5b906020019060200201
518887815181106103a357fe5b60ff90921660209283029091019091015284886000198801815181
106103c557fe5b60ff9092166020928302909101909101525b600019909201916102ab565b600190
93019261029d565b600095505b603086101561053e57506000600486061580156104405750878681
51811061041757fe5b9060200190602002015160011689878151811061043057fe5b906020019060
2002015160011614155b15610491576104518b60038c610668565b915060038a01995061048e8987
8151811061046857fe5b9060200190602002015189888151811061047e57fe5b9060200190602002
01518461067e565b90505b60008160ff1611156104c057808787815181106104aa57fe5b60ff9092
16602092830290910190910152610533565b6104cc8b60018c610668565b915060018a0199508160
0014156104ff578886815181106104e957fe5b906020019060200201518787815181106104aa57fe
5b87868151811061050b57fe5b9060200190602002015187878151811061052157fe5b60ff909216
6020928302909101909101525b6001909501946103f3565b6105478761055a565b9f9e5050505050
50505050505050505050565b6000805b60308110156105975760209091029082602f829003815181
1061057d57fe5b9060200190602002015160ff16919091179060010161055e565b50919050565b60
005460ff1681565b6105ae610709565b6105b6610709565b600060306040518059106105c7575059
5b90808252806020026020018201604052509150600090505b6030811015610617576105f2848261
06f1565b8282815181106105fe57fe5b60ff9092166020928302909101909101526001016105df56
5b5092915050565b61062661071b565b61062e61071b565b60005b600c8110156106175761064784
826004026106f1565b8282600c811061065357fe5b60ff9092166020929092020152600101610631
565b600290810a91900a600019018102919091160490565b600083838260ff808316908416111561
0698578691508592505b82820360ff1660011480156106b65750600260ff84160660ff166000145b
156106e75760178360ff1610156106cf575060016106d3565b5060005b8085116106e757600260ff
84160460100193505b5050509392505050565b600061070283600584600502610668565b93925050
50565b60206040519081016040526000815290565b610180604051908101604052600c815b600081
52600019909101906020018161072b57905050905600
TXT

  hex = hex.gsub( /[ \t\n\r]/, '' )  ## remove all whitespaces and
newlines (/r/n)
  hex
end

def mixgenes_code
  code = File.read( './mixgenes.opcodes' )
  code = code.strip   ## note: strip trailing newline
  code
end



def test_mixgenes_level1
  assert_equal mixgenes_code, disassemble( mixgenes_hex )
end

def test_mixgenes_level2
  assert_equal mixgenes_hex,  assemble( mixgenes_code )
end


def test_mixgenes
  assert_equal mixgenes_hex,  assemble( disassemble( mixgenes_hex ))
end

end # class RubyQuizTest
```


Post your code snippets on the "official" Ruby Quiz Channel,
that is, right here.

   Questions? Comments? Welcome too :-).

  Happy opscode hacking and blockchain contract bytecode assembling &
disassembling with Ruby.


[1] https://github.com/planetruby/quiz
[2] https://etherscan.io/address/0xf97e0a5b616dffc913e72455fde9ea8bbe946a2b#code
[3] https://github.com/planetruby/quiz/blob/master/011/test.rb
[4] https://github.com/planetruby/quiz/blob/master/011/opcodes.rb
[5] https://github.com/ethereumbook/ethereumbook/blob/develop/13evm.asciidoc

Unsubscribe: <mailto:[email protected]?subject=unsubscribe>
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk>
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.