Module: Ethereum::Tester::SolidityWrapper

Defined in:
lib/ethereum/tester/solidity_wrapper.rb

Defined Under Namespace

Classes: CompileError

Class Method Summary collapse

Class Method Details

.combined(code) ⇒ Object



41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
# File 'lib/ethereum/tester/solidity_wrapper.rb', line 41

def combined(code)
  out = Tempfile.new 'solc_output_'

  pipe = IO.popen([solc_path, '--add-std', '--optimize', '--combined-json', 'abi,bin,devdoc,userdoc'], 'w', [:out, :err] => out)
  pipe.write code
  pipe.close_write
  raise CompileError, 'compilation failed' unless $?.success?

  out.rewind
  contracts = JSON.parse(out.read)['contracts']

  contracts.each do |name, data|
    data['abi'] = JSON.parse data['abi']
    data['devdoc'] = JSON.parse data['devdoc']
    data['userdoc'] = JSON.parse data['userdoc']
  end

  names = contract_names code
  raise AssertError unless names.size <= contracts.size

  names.map {|n| [n, contracts[n]] }
ensure
  out.close
end

.compile(code, contract_name = '') ⇒ Object

Returns binary of last contract in code.



69
70
71
72
73
74
75
76
77
78
# File 'lib/ethereum/tester/solidity_wrapper.rb', line 69

def compile(code, contract_name='')
  sorted_contracts = combined code
  if contract_name.true?
    idx = sorted_contracts.map(&:first).index(contract_name)
  else
    idx = -1
  end

  Utils.decode_hex sorted_contracts[idx][1]['bin']
end

.compile_rich(code) ⇒ Object

Full format as returned by jsonrpc.



102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
# File 'lib/ethereum/tester/solidity_wrapper.rb', line 102

def compile_rich(code)
  combined(code).map do |(name, contract)|
    [
      name,
      {
        'code' => "0x#{contract['bin']}",
        'info' => {
          'abiDefinition' => contract['abi'],
          'compilerVersion' => compiler_version,
          'developerDoc' => contract['devdoc'],
          'language' => 'Solidity',
          'languageVersion' => '0',
          'source' => code,
          'userDoc' => contract['userdoc']
        }
      }
    ]
  end.to_h
end

.compiler_versionObject



94
95
96
97
# File 'lib/ethereum/tester/solidity_wrapper.rb', line 94

def compiler_version
  output = `#{solc_path} --version`.strip
  output =~ /^Version: ([0-9a-z.-]+)\// ? $1 : nil
end

.contract_names(code) ⇒ Object



29
30
31
32
33
34
35
36
37
38
39
# File 'lib/ethereum/tester/solidity_wrapper.rb', line 29

def contract_names(code)
  names = []

  split_contracts(code).each do |contract|
    keyword, name, _ = contract.split(/\s+/, 3)
    raise AssertError, 'keyword must be contract' unless keyword == 'contract' && !name.empty?
    names.push name
  end

  names
end

.mk_full_signature(code, contract_name = '') ⇒ Object

Returns signature of last contract in code.



83
84
85
86
87
88
89
90
91
92
# File 'lib/ethereum/tester/solidity_wrapper.rb', line 83

def mk_full_signature(code, contract_name='')
  sorted_contracts = combined code
  if contract_name.true?
    idx = sorted_contracts.map(&:first).index(contract_name)
  else
    idx = -1
  end

  sorted_contracts[idx][1]['abi']
end

.solc_pathObject



122
123
124
# File 'lib/ethereum/tester/solidity_wrapper.rb', line 122

def solc_path
  @solc_path ||= which('solc')
end

.solc_path=(v) ⇒ Object



126
127
128
# File 'lib/ethereum/tester/solidity_wrapper.rb', line 126

def solc_path=(v)
  @solc_path = v
end

.split_contracts(code) ⇒ Object



11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# File 'lib/ethereum/tester/solidity_wrapper.rb', line 11

def split_contracts(code)
  contracts = []
  contract = nil

  code.split("\n").each do |line|
    if line =~ /\Acontract /
      contracts.push(contract.join("\n")) if contract
      contract = [line]
    elsif contract
      contract.push line
    end
  end

  contracts.push(contract.join("\n")) if contract

  contracts
end

.which(cmd) ⇒ Object



130
131
132
133
134
135
136
137
138
139
# File 'lib/ethereum/tester/solidity_wrapper.rb', line 130

def which(cmd)
  exts = ENV['PATHEXT'] ? ENV['PATHEXT'].split(';') : ['']
  ENV['PATH'].split(File::PATH_SEPARATOR).each do |path|
    exts.each { |ext|
      exe = File.join(path, "#{cmd}#{ext}")
      return exe if File.executable?(exe) && !File.directory?(exe)
    }
  end
  return nil
end