Include solc-js as a dependency

It executes the solc-js compiler instead of the C version in the app.

Even though it's not the more appropriated way to compile solidity
`solc-js` will allows us compiling all versions from the beginning.
pull/288/head
Igor Florian 7 years ago
parent 2066427b29
commit a94ad57fd2
  1. 14
      .circleci/config.yml
  2. 1
      .gitignore
  3. 5
      README.md
  4. 102
      apps/explorer/lib/explorer/smart_contract/solidity/code_compiler.ex
  5. 46
      apps/explorer/lib/explorer/smart_contract/verifier.ex
  6. 18
      apps/explorer/package.json
  7. 14
      apps/explorer/priv/compile_solc.js
  8. 3
      apps/explorer/priv/solc.bash
  9. 18
      apps/explorer/test/explorer/smart_contract/solidity/code_compiler_test.exs

@ -40,6 +40,20 @@ jobs:
- v6-npm-install-{{ .Branch }} - v6-npm-install-{{ .Branch }}
- v6-npm-install - v6-npm-install
- run:
command: npm install
working_directory: "apps/explorer"
- save_cache:
key: v3-npm-install-{{ .Branch }}-{{ checksum "apps/explorer/package-lock.json" }}
paths: "apps/explorer/node_modules"
- save_cache:
key: v3-npm-install-{{ .Branch }}
paths: "apps/explorer/node_modules"
- save_cache:
key: v3-npm-install
paths: "apps/explorer/node_modules"
- run: - run:
command: npm install command: npm install
working_directory: "apps/explorer_web/assets" working_directory: "apps/explorer_web/assets"

1
.gitignore vendored

@ -15,6 +15,7 @@ npm-debug.log
# Static artifacts # Static artifacts
/apps/explorer_web/assets/node_modules /apps/explorer_web/assets/node_modules
/apps/explorer/node_modules
# Since we are building assets from assets/, # Since we are building assets from assets/,
# we ignore priv/static. You may want to comment # we ignore priv/static. You may want to comment

@ -26,7 +26,9 @@ To get POA Explorer up and running locally:
* Set up some default configuration with: `cp apps/explorer_web/config/dev.secret.exs.example apps/explorer_web/config/dev.secret.exs` * Set up some default configuration with: `cp apps/explorer_web/config/dev.secret.exs.example apps/explorer_web/config/dev.secret.exs`
* Install dependencies with `mix do deps.get, local.rebar, deps.compile, compile` * Install dependencies with `mix do deps.get, local.rebar, deps.compile, compile`
* Create and migrate your database with `mix ecto.create && mix ecto.migrate` * Create and migrate your database with `mix ecto.create && mix ecto.migrate`
* Install Node.js dependencies with `cd apps/explorer_web/assets && npm install; cd -` * Install Node.js dependencies with:
* `cd apps/explorer_web/assets && npm install; cd -`
* `cd apps/explorer && npm install; cd -`
* Start Phoenix with `mix phx.server` * Start Phoenix with `mix phx.server`
Now you can visit [`localhost:4000`](http://localhost:4000) from your browser. Now you can visit [`localhost:4000`](http://localhost:4000) from your browser.
@ -60,7 +62,6 @@ Configure your local CCMenu with the following url: [`https://circleci.com/gh/po
#### Prerequisites #### Prerequisites
* PhantomJS (for wallaby) * PhantomJS (for wallaby)
* `Solidity` - http://solidity.readthedocs.io/en/v0.4.24/installing-solidity.html
#### Running the tests #### Running the tests

@ -10,68 +10,60 @@ defmodule Explorer.SmartContract.Solidity.CodeCompiler do
## Examples ## Examples
iex(1)> Explorer.SmartContract.Solidity.CodeCompiler.run("SimpleStorage", "pragma solidity ^0.4.23; contract SimpleStorage {uint storedData; function set(uint x) public {storedData = x; } function get() public constant returns (uint) {return storedData; } }", false) iex(1)> Explorer.SmartContract.Solidity.CodeCompiler.run("SimpleStorage", "pragma solidity ^0.4.23; contract SimpleStorage {uint storedData; function set(uint x) public {storedData = x; } function get() public constant returns (uint) {return storedData; } }", false)
%{ {:ok, %{
"contracts" => %{ "abi" => [
"SimpleStorage" => %{ %{
"SimpleStorage" => %{ "constant" => false,
"abi" => [ "inputs" => [%{"name" => "x", "type" => "uint256"}],
%{ "name" => "set",
"constant" => false, "outputs" => [],
"inputs" => [%{"name" => "x", "type" => "uint256"}], "payable" => false,
"name" => "set", "stateMutability" => "nonpayable",
"outputs" => [], "type" => "function"
"payable" => false, },
"stateMutability" => "nonpayable", %{
"type" => "function" "constant" => true,
}, "inputs" => [],
%{ "name" => "get",
"constant" => true, "outputs" => [%{"name" => "", "type" => "uint256"}],
"inputs" => [], "payable" => false,
"name" => "get", "stateMutability" => "view",
"outputs" => [%{"name" => "", "type" => "uint256"}], "type" => "function"
"payable" => false,
"stateMutability" => "view",
"type" => "function"
}
],
"evm" => %{
"bytecode" => %{
"linkReferences" => %{},
"object" => "608060405234801561001057600080fd5b5060df8061001f6000396000f3006080604052600436106049576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806360fe47b114604e5780636d4ce63c146078575b600080fd5b348015605957600080fd5b5060766004803603810190808035906020019092919050505060a0565b005b348015608357600080fd5b50608a60aa565b6040518082815260200191505060405180910390f35b8060008190555050565b600080549050905600a165627a7a72305820017172d01c000255d5c74c0efce764adf7c4ae444d7f7e2ed852f6fb9b73df5d0029",
"opcodes" => "PUSH1 0x80 PUSH1 0x40 MSTORE CALLVALUE DUP1 ISZERO PUSH2 0x10 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH1 0xDF DUP1 PUSH2 0x1F PUSH1 0x0 CODECOPY PUSH1 0x0 RETURN STOP PUSH1 0x80 PUSH1 0x40 MSTORE PUSH1 0x4 CALLDATASIZE LT PUSH1 0x49 JUMPI PUSH1 0x0 CALLDATALOAD PUSH29 0x100000000000000000000000000000000000000000000000000000000 SWAP1 DIV PUSH4 0xFFFFFFFF AND DUP1 PUSH4 0x60FE47B1 EQ PUSH1 0x4E JUMPI DUP1 PUSH4 0x6D4CE63C EQ PUSH1 0x78 JUMPI JUMPDEST PUSH1 0x0 DUP1 REVERT JUMPDEST CALLVALUE DUP1 ISZERO PUSH1 0x59 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH1 0x76 PUSH1 0x4 DUP1 CALLDATASIZE SUB DUP2 ADD SWAP1 DUP1 DUP1 CALLDATALOAD SWAP1 PUSH1 0x20 ADD SWAP1 SWAP3 SWAP2 SWAP1 POP POP POP PUSH1 0xA0 JUMP JUMPDEST STOP JUMPDEST CALLVALUE DUP1 ISZERO PUSH1 0x83 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH1 0x8A PUSH1 0xAA JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 DUP3 DUP2 MSTORE PUSH1 0x20 ADD SWAP2 POP POP PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 RETURN JUMPDEST DUP1 PUSH1 0x0 DUP2 SWAP1 SSTORE POP POP JUMP JUMPDEST PUSH1 0x0 DUP1 SLOAD SWAP1 POP SWAP1 JUMP STOP LOG1 PUSH6 0x627A7A723058 KECCAK256 ADD PUSH18 0x72D01C000255D5C74C0EFCE764ADF7C4AE44 0x4d PUSH32 0x7E2ED852F6FB9B73DF5D00290000000000000000000000000000000000000000 ",
"sourceMap" => "25:157:0:-;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;25:157:0;;;;;;;"
},
"deployedBytecode" => %{
"linkReferences" => %{},
"object" => "6080604052600436106049576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806360fe47b114604e5780636d4ce63c146078575b600080fd5b348015605957600080fd5b5060766004803603810190808035906020019092919050505060a0565b005b348015608357600080fd5b50608a60aa565b6040518082815260200191505060405180910390f35b8060008190555050565b600080549050905600a165627a7a72305820017172d01c000255d5c74c0efce764adf7c4ae444d7f7e2ed852f6fb9b73df5d0029",
"opcodes" => "PUSH1 0x80 PUSH1 0x40 MSTORE PUSH1 0x4 CALLDATASIZE LT PUSH1 0x49 JUMPI PUSH1 0x0 CALLDATALOAD PUSH29 0x100000000000000000000000000000000000000000000000000000000 SWAP1 DIV PUSH4 0xFFFFFFFF AND DUP1 PUSH4 0x60FE47B1 EQ PUSH1 0x4E JUMPI DUP1 PUSH4 0x6D4CE63C EQ PUSH1 0x78 JUMPI JUMPDEST PUSH1 0x0 DUP1 REVERT JUMPDEST CALLVALUE DUP1 ISZERO PUSH1 0x59 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH1 0x76 PUSH1 0x4 DUP1 CALLDATASIZE SUB DUP2 ADD SWAP1 DUP1 DUP1 CALLDATALOAD SWAP1 PUSH1 0x20 ADD SWAP1 SWAP3 SWAP2 SWAP1 POP POP POP PUSH1 0xA0 JUMP JUMPDEST STOP JUMPDEST CALLVALUE DUP1 ISZERO PUSH1 0x83 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH1 0x8A PUSH1 0xAA JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 DUP3 DUP2 MSTORE PUSH1 0x20 ADD SWAP2 POP POP PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 RETURN JUMPDEST DUP1 PUSH1 0x0 DUP2 SWAP1 SSTORE POP POP JUMP JUMPDEST PUSH1 0x0 DUP1 SLOAD SWAP1 POP SWAP1 JUMP STOP LOG1 PUSH6 0x627A7A723058 KECCAK256 ADD PUSH18 0x72D01C000255D5C74C0EFCE764ADF7C4AE44 0x4d PUSH32 0x7E2ED852F6FB9B73DF5D00290000000000000000000000000000000000000000 ",
"sourceMap" => "25:157:0:-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;66:46;;8:9:-1;5:2;;;30:1;27;20:12;5:2;66:46:0;;;;;;;;;;;;;;;;;;;;;;;;;;113:67;;8:9:-1;5:2;;;30:1;27;20:12;5:2;113:67:0;;;;;;;;;;;;;;;;;;;;;;;66:46;108:1;95:10;:14;;;;66:46;:::o;113:67::-;153:4;167:10;;160:17;;113:67;:::o"
},
"gasEstimates" => %{
"creation" => %{
"codeDepositCost" => "44600",
"executionCost" => "93",
"totalCost" => "44693"
},
"external" => %{"get()" => "424", "set(uint256)" => "20205"}
}
},
"metadata" => "{\"compiler\":{\"version\":\"0.4.24+commit.e67f0147\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"constant\":false,\"inputs\":[{\"name\":\"x\",\"type\":\"uint256\"}],\"name\":\"set\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"get\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"methods\":{}},\"userdoc\":{\"methods\":{}}},\"settings\":{\"compilationTarget\":{\"SimpleStorage\":\"SimpleStorage\"},\"evmVersion\":\"byzantium\",\"libraries\":{},\"optimizer\":{\"enabled\":false,\"runs\":200},\"remappings\":[]},\"sources\":{\"SimpleStorage\":{\"keccak256\":\"0x3f5ecc4c6077dffdfc98d9781295205833bf0558bc2a0c86fc3d5f246808ba34\",\"urls\":[\"bzzr://60d588b13340f26a038f51934f9b8c3cf3928372bc4358848a86960040a3a8e2\"]}},\"version\":1}"
} }
} ],
}, "bytecode" => "608060405234801561001057600080fd5b5060df8061001f6000396000f3006080604052600436106049576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806360fe47b114604e5780636d4ce63c146078575b600080fd5b348015605957600080fd5b5060766004803603810190808035906020019092919050505060a0565b005b348015608357600080fd5b50608a60aa565b6040518082815260200191505060405180910390f35b8060008190555050565b600080549050905600a165627a7a72305820017172d01c000255d5c74c0efce764adf7c4ae444d7f7e2ed852f6fb9b73df5d0029",
"sources" => %{"SimpleStorage" => %{"id" => 0}} "name" => "SimpleStorage"
} }}
""" """
def run(name, code, optimization) do def run(name, code, optimization) do
{response, _status} = {response, _status} =
System.cmd( System.cmd(
Application.app_dir(:explorer, "priv/solc.bash"), "node",
[generate_settings(name, code, optimization)] [
Application.app_dir(:explorer, "priv/compile_solc.js"),
generate_settings(name, code, optimization),
"v0.4.24+commit.e67f0147"
]
) )
Jason.decode!(response) case Jason.decode!(response) do
%{
"contracts" => %{
^name => %{
^name => %{
"abi" => abi,
"evm" => %{
"bytecode" => %{"object" => bytecode}
}
}
}
}
} ->
{:ok, %{"abi" => abi, "bytecode" => bytecode, "name" => name}}
_ ->
{:error, :compilation}
end
end end
@doc """ @doc """

@ -19,24 +19,23 @@ defmodule Explorer.SmartContract.Verifier do
"optimization" => optimization "optimization" => optimization
}) do }) do
solc_output = CodeCompiler.run(name, contract_source_code, optimization) solc_output = CodeCompiler.run(name, contract_source_code, optimization)
compare_bytecodes(solc_output, address_hash)
end
defp compare_bytecodes(compilation_error = {:error, _}, _), do: compilation_error
case solc_output do defp compare_bytecodes({:ok, %{"abi" => abi, "bytecode" => bytecode}}, address_hash) do
%{ generated_bytecode = extract_bytecode(bytecode)
"contracts" => %{
^name => %{
^name => %{
"abi" => abi,
"evm" => %{
"bytecode" => %{"object" => bytecode}
}
}
}
}
} ->
compare_bytecodes(address_hash, abi, bytecode)
_ -> "0x" <> blockchain_bytecode =
{:error, :compilation} address_hash
|> Chain.smart_contract_bytecode()
|> extract_bytecode
if generated_bytecode == blockchain_bytecode do
{:ok, %{abi: abi}}
else
{:error, :generated_bytecode}
end end
end end
@ -56,19 +55,4 @@ defmodule Explorer.SmartContract.Verifier do
bytecode bytecode
end end
defp compare_bytecodes(address_hash, abi, bytecode) do
generated_bytecode = extract_bytecode(bytecode)
"0x" <> blockchain_bytecode =
address_hash
|> Chain.smart_contract_bytecode()
|> extract_bytecode
if generated_bytecode == blockchain_bytecode do
{:ok, %{abi: abi}}
else
{:error, :generated_bytecode}
end
end
end end

@ -0,0 +1,18 @@
{
"repository": {
"type": "git",
"url": "git+https://github.com/poanetwork/poa-explorer.git"
},
"private": true,
"name": "poa-explorer",
"author": "POA Network",
"license": "GPL-3.0",
"engines": {
"node": "9.x",
"npm": "5.x"
},
"scripts": {},
"dependencies": {
"solc-js": "^0.4.20-browser.1"
}
}

@ -0,0 +1,14 @@
#!/usr/bin/env node
const solc = require('solc-js');
var sourceCode = process.argv[2];
var version = process.argv[3];
var compiled_code = solc.loadRemoteVersion(version, function (err, solcSnapshot) {
if (err) {
console.log(JSON.stringify(err));
} else {
console.log(solcSnapshot.compileStandardWrapper(sourceCode));
}
});

@ -1,3 +0,0 @@
#!/bin/bash
echo "$1" | solc --standard-json

@ -28,18 +28,12 @@ defmodule Explorer.SmartContract.Solidity.CodeCompilerTest do
response = CodeCompiler.run(name, code, optimization) response = CodeCompiler.run(name, code, optimization)
assert %{ assert {:ok,
"contracts" => %{ %{
^name => %{ "abi" => _,
^name => %{ "bytecode" => _,
"abi" => _, "name" => _
"evm" => %{ }} = response
"bytecode" => %{"object" => _}
}
}
}
}
} = response
end end
end end

Loading…
Cancel
Save