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

Gerald Bauer wrote:

Challenge #11 - Blockchain Contracts - Disassemble & Assemble Ethereum

Virtual Machine (EVM) Opcodes / Bytecodes

$ ruby -v lib/011.rb
ruby 2.6.0p0 (2018-12-25 revision 66547) [x86_64-linux]
Run options: --seed 51739
# Running:
...
Finished in 0.009713s, 308.8672 runs/s, 308.8672 assertions/s.
3 runs, 3 assertions, 0 failures, 0 errors, 0 skips

$ cat lib/011.rb
# frozen_string_literal: true
require_relative '../011/test.rb'

class RubyQuizTest
  @@op2hex = Ethereum::Opcodes::TABLE
             .transform_values{|v| v.to_s.freeze}

  @@hex2op = Ethereum::Opcodes::TABLE.invert
             .transform_values{|v| v.to_s(16).rjust(2, '0').freeze}

  def disassemble(hex)
    n = 0
    hex.chars.each_slice(2).map{|a,b|
      if n == 0
        c = "#{a}#{b}".to_i(16)
        t = (0x60..0x7f).include?(c) ? "#{n = c - 0x5f; ' 0x'}" : ''
        "\r\n#{@@op2hex[c]}#{t}"
      else
        n -= 1
        "#{a}#{b}"
      end
    }.join[8..]
  end

  def assemble(code)
    code.scan(/^(\w+)(?: 0x(\w+))?\r?$/).map{|a,b|
      "#{@@hex2op[a.intern]}#{b}"
    }.join.prepend('0x')
  end
end

Dir.chdir("#{__dir__}/../011")
RubyQuizTest.new('fjc')

Hello,

    Wow. Great to see high-speed Ethereum opscode / bytecode assemble
and disassemble versions in ruby.
Thanks again for keeping the ruby quiz going.

   For reference here's the test answer from my humble self:

def disassemble( hex ) # returns (code) text with opcodes
  hex = hex[2..-1] if hex.start_with?( '0x' ) # cut off leading 0x

  bytes = [hex].pack('H*').bytes # convert (hex) string to bytearray

  lines = []
  while bytes.size > 0
    opcode = bytes.shift

    ins = Ethereum::Opcodes::TABLE[opcode]
    if ins =~ /^PUSH([0-9]+)$/
      num = $1.to_i
      args_hex = num.times.map { '%02x' % bytes.shift }.join
      lines << "#{ins} 0x#{args_hex}"
    else
      lines << "#{ins}"
    end
  end
  lines.join( "\n" )
end

def assemble( code ) # returns (hex) string
  hex = '0x'

  words = code.split
  words.each do |word|
    if word =~ /^0x/
      hex << word[2..-1]
    else # assume instruction / opcode mnemonic
      opcode = Ethereum::Opcodes::REVERSE_TABLE[word.to_sym]
      hex << ('%02x' % opcode)
    end
  end
  hex

end

  Anyone else? You're (more than) welcome to post your code snippets /
version :-).

  Cheers. Prost.

PS: Find the collected code snippets / solutions [1] at the ruby quiz repo.

[1] https://github.com/planetruby/quiz/blob/master/011/solution.rb