Merge branch 'master' into ab-check-if-contract-has-arguments

pull/1898/head
Ayrat Badykov 6 years ago committed by GitHub
commit 65246b4bb6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 1
      CHANGELOG.md
  2. 238
      apps/block_scout_web/lib/block_scout_web/views/address_decompiled_contract_view.ex
  3. 4
      apps/block_scout_web/test/block_scout_web/views/address_decompiled_contract_view_test.exs

@ -21,6 +21,7 @@
- [#1869](https://github.com/poanetwork/blockscout/pull/1869) - Fix output and gas extraction in JS tracer for Geth
- [#1868](https://github.com/poanetwork/blockscout/pull/1868) - fix: logs list endpoint performance
- [#1822](https://github.com/poanetwork/blockscout/pull/1822) - Fix style breaks in decompiled contract code view
- [#1885](https://github.com/poanetwork/blockscout/pull/1885) - highlight reserved words in decompiled code
- [#1896](https://github.com/poanetwork/blockscout/pull/1896) - re-query tokens in top nav automplete
- [#1881](https://github.com/poanetwork/blockscout/pull/1881) - fix: store solc versions locally for performance
- [#1898](https://github.com/poanetwork/blockscout/pull/1898) - check if the constructor has arguments before verifying constructor arguments

@ -2,51 +2,231 @@ defmodule BlockScoutWeb.AddressDecompiledContractView do
use BlockScoutWeb, :view
@colors %{
"\e[95m" => "136, 0, 0",
"\e[95m" => "",
# red
"\e[91m" => "236, 89, 58",
"\e[91m" => "",
# gray
"\e[38;5;8m" => "111, 110, 111",
"\e[38;5;8m" => "<span style=\"color:rgb(111, 110, 111)\">",
# green
"\e[32m" => "57, 115, 0",
"\e[32m" => "",
# yellowgreen
"\e[93m" => "57, 115, 0",
"\e[93m" => "",
# yellow
"\e[92m" => "119, 232, 81",
"\e[92m" => "",
# red
"\e[94m" => "136, 0, 0"
"\e[94m" => ""
}
@comment_start "#"
@reserved_words_types [
"var",
"bool",
"string",
"int",
"uint",
"int8",
"uint8",
"int16",
"uint16",
"int24",
"uint24",
"int32",
"uint32",
"int40",
"uint40",
"int48",
"uint48",
"int56",
"uint56",
"int64",
"uint64",
"int72",
"uint72",
"int80",
"uint80",
"int88",
"uint88",
"int96",
"uint96",
"int104",
"uint104",
"int112",
"uint112",
"int120",
"uint120",
"int128",
"uint128",
"int136",
"uint136",
"int144",
"uint144",
"int152",
"uint152",
"int160",
"uint160",
"int168",
"uint168",
"int176",
"uint176",
"int184",
"uint184",
"int192",
"uint192",
"int200",
"uint200",
"int208",
"uint208",
"int216",
"uint216",
"int224",
"uint224",
"int232",
"uint232",
"int240",
"uint240",
"int248",
"uint248",
"int256",
"uint256",
"byte",
"bytes",
"bytes1",
"bytes2",
"bytes3",
"bytes4",
"bytes5",
"bytes6",
"bytes7",
"bytes8",
"bytes9",
"bytes10",
"bytes11",
"bytes12",
"bytes13",
"bytes14",
"bytes15",
"bytes16",
"bytes17",
"bytes18",
"bytes19",
"bytes20",
"bytes21",
"bytes22",
"bytes23",
"bytes24",
"bytes25",
"bytes26",
"bytes27",
"bytes28",
"bytes29",
"bytes30",
"bytes31",
"bytes32",
"true",
"false",
"enum",
"struct",
"mapping",
"address"
]
@reserved_words_keywords [
"def",
"require",
"revert",
"return",
"assembly",
"memory",
"mem"
]
@modifiers [
"payable",
"public",
"view",
"pure",
"returns",
"internal"
]
@reserved_words @reserved_words_keywords ++ @reserved_words_types
@reserved_words_regexp ([@comment_start | @reserved_words] ++ @modifiers)
|> Enum.reduce("", fn el, acc -> acc <> "|" <> el end)
|> Regex.compile!()
def highlight_decompiled_code(code) do
{_, result} =
@colors
|> Enum.reduce(code, fn {symbol, rgb}, acc ->
String.replace(acc, symbol, "<span style=\"color:rgb(#{rgb})\">")
String.replace(acc, symbol, rgb)
end)
|> String.replace("\e[1m", "<span style=\"font-weight:bold\">")
|> String.replace("»", "&raquo;")
|> String.replace("\e[0m", "</span>")
|> String.split(~r/\<span style=.*?\)"\>|\<\/span\>/, include_captures: true, trim: true)
|> Enum.reduce({"", []}, fn part, {style, acc} ->
new_style =
cond do
String.contains?(part, "<span style") -> part
part == "</span>" -> ""
true -> style
end
new_part = new_part(part, new_style)
{new_style, [new_part | acc]}
end)
|> add_styles_to_every_line()
result
|> Enum.reduce("", fn part, acc ->
part <> acc
end)
|> add_styles_to_reserved_words()
|> add_line_numbers()
end
defp add_styles_to_every_line(lines) do
lines
|> Enum.reduce({"", []}, fn part, {style, acc} ->
new_style =
cond do
String.contains?(part, "<span style") -> part
part == "</span>" -> ""
true -> style
end
new_part = new_part(part, new_style)
{new_style, [new_part | acc]}
end)
end
defp add_styles_to_reserved_words(code) do
code
|> String.split("\n")
|> Enum.map(fn line ->
add_styles_to_line(line)
end)
|> Enum.reduce("", fn el, acc ->
acc <> el <> "\n"
end)
end
defp add_styles_to_line(line) do
parts =
line
|> String.split(@reserved_words_regexp,
include_captures: true
)
comment_position = Enum.find_index(parts, fn part -> part == "#" end)
parts
|> Enum.with_index()
|> Enum.map(fn {el, index} ->
cond do
!(is_nil(comment_position) || comment_position > index) -> el
el in @reserved_words -> "<span class=\"hljs-keyword\">" <> el <> "</span>"
el in @modifiers -> "<span class=\"hljs-title\">" <> el <> "</span>"
true -> el
end
end)
|> Enum.reduce("", fn el, acc ->
acc <> el
end)
end
def sort_contracts_by_version(decompiled_contracts) do
decompiled_contracts
|> Enum.sort_by(& &1.decompiler_version)
@ -76,18 +256,12 @@ defmodule BlockScoutWeb.AddressDecompiledContractView do
part
true ->
result =
part
|> String.split("\n")
|> Enum.reduce("", fn p, a ->
a <> new_style <> p <> "</span>\n"
end)
if String.ends_with?(part, "\n") do
result
else
String.slice(result, 0..-2)
end
part
|> String.split("\n")
|> Enum.reduce("", fn p, a ->
a <> new_style <> p <> "</span>\n"
end)
|> String.slice(0..-2)
end
end
end

@ -56,7 +56,7 @@ defmodule BlockScoutWeb.AddressDecompiledContractViewTest do
result = AddressDecompiledContractView.highlight_decompiled_code(code)
assert result ==
"<code> <span style=\"color:rgb(111, 110, 111)\">#</span></code>\n<code><span style=\"color:rgb(111, 110, 111)\"> # eveem.org 6 Feb 2019</span></code>\n<code><span style=\"color:rgb(111, 110, 111)\"> # Decompiled source of </span>0x00Bd9e214FAb74d6fC21bf1aF34261765f57e875<span style=\"color:rgb(111, 110, 111)\"></span></code>\n<code><span style=\"color:rgb(111, 110, 111)\"> #</span></code>\n<code><span style=\"color:rgb(111, 110, 111)\"> # Let's make the world open source</span></code>\n<code><span style=\"color:rgb(111, 110, 111)\"> # </span></code>\n<code> <span style=\"color:rgb(111, 110, 111)\">#</span></code>\n<code><span style=\"color:rgb(111, 110, 111)\"> # I failed with these:</span></code>\n<code><span style=\"color:rgb(111, 110, 111)\"> </span><span style=\"color:rgb(111, 110, 111)\"># - </span><span style=\"color:rgb(236, 89, 58)\">unknowne77c646d(?)</span><span style=\"color:rgb(111, 110, 111)\"></span></code>\n<code><span style=\"color:rgb(111, 110, 111)\"> </span><span style=\"color:rgb(111, 110, 111)\"># - </span><span style=\"color:rgb(236, 89, 58)\">transferFromWithData(address _from, address _to, uint256 _value, bytes _data)</span><span style=\"color:rgb(111, 110, 111)\"></span></code>\n<code><span style=\"color:rgb(111, 110, 111)\"> # All the rest is below.</span></code>\n<code><span style=\"color:rgb(111, 110, 111)\"> #</span></code>\n<code></code>\n<code></code>\n<code> <span style=\"color:rgb(111, 110, 111)\"># Storage definitions and getters</span></code>\n<code></code>\n<code> <span style=\"color:rgb(57, 115, 0)\">def</span> storage:</code>\n<code> <span style=\"color:rgb(57, 115, 0)\">allowance</span> is uint256 => uint256 <span style=\"color:rgb(111, 110, 111)\"># mask(256, 0) at storage #2</span></code>\n<code> <span style=\"color:rgb(57, 115, 0)\">stor4</span> is uint256 => uint8 <span style=\"color:rgb(111, 110, 111)\"># mask(8, 0) at storage #4</span></code>\n<code></code>\n<code> <span style=\"color:rgb(136, 0, 0)\">def </span>allowance(address <span style=\"color:rgb(57, 115, 0)\">_owner</span>, address <span style=\"color:rgb(57, 115, 0)\">_spender</span>) <span style=\"color:rgb(136, 0, 0)\">payable</span>: 64</code>\n<code> return <span style=\"color:rgb(57, 115, 0)\">allowance</span><span style=\"color:rgb(57, 115, 0)\">[</span>sha3(((320 - 1)<span style=\"font-weight:bold\"> and </span>(320 - 1)<span style=\"font-weight:bold\"> and </span><span style=\"color:rgb(57, 115, 0)\">_owner</span>), 1), ((320 - 1)<span style=\"font-weight:bold\"> and </span><span style=\"color:rgb(57, 115, 0)\">_spender</span><span style=\"font-weight:bold\"> and </span>(320 - 1))<span style=\"color:rgb(57, 115, 0)\">]</span></code>\n<code></code>\n<code></code>\n<code> <span style=\"color:rgb(111, 110, 111)\">#</span></code>\n<code><span style=\"color:rgb(111, 110, 111)\"> # Regular functions - see Tutorial for understanding quirks of the code</span></code>\n<code><span style=\"color:rgb(111, 110, 111)\"> #</span></code>\n<code></code>\n<code></code>\n<code> <span style=\"color:rgb(111, 110, 111)\"># folder failed in this function - may be terribly long, sorry</span></code>\n<code> <span style=\"color:rgb(136, 0, 0)\">def </span>unknownc47d033b(?) <span style=\"color:rgb(136, 0, 0)\">payable</span>: not cd[4]:</code>\n<code> revert</code>\n<code> else:</code>\n<code> <span style=\"color:rgb(136, 0, 0)\">mem[</span>0<span style=\"color:rgb(136, 0, 0)\">]</span>cd[4]</code>\n<code> <span style=\"color:rgb(136, 0, 0)\">mem[</span>32<span style=\"color:rgb(136, 0, 0)\">]</span> = 4</code>\n<code> <span style=\"color:rgb(136, 0, 0)\">mem[</span>96<span style=\"color:rgb(136, 0, 0)\">]</span> = bool(<span style=\"color:rgb(57, 115, 0)\">stor4</span><span style=\"color:rgb(57, 115, 0)\">[</span>((320 - 1)<span style=\"font-weight:bold\"> and </span>(320 - 1)<span style=\"font-weight:bold\"> and </span>cd[4])<span style=\"color:rgb(57, 115, 0)\">]</span>)</code>\n<code> return bool(<span style=\"color:rgb(57, 115, 0)\">stor4</span><span style=\"color:rgb(57, 115, 0)\">[</span>((320 - 1)<span style=\"font-weight:bold\"> and </span>(320 - 1)<span style=\"font-weight:bold\"> and </span>cd[4])<span style=\"color:rgb(57, 115, 0)\">]</span>)</code>\n<code></code>\n<code> <span style=\"color:rgb(136, 0, 0)\">def </span>_fallback() <span style=\"color:rgb(136, 0, 0)\">payable</span>: <span style=\"color:rgb(111, 110, 111)\"># default function</span></code>\n<code> revert</code>\n<code></code>\n"
"<code> <span style=\"color:rgb(111, 110, 111)\">#</span></code>\n<code><span style=\"color:rgb(111, 110, 111)\"> # eveem.org 6 Feb 2019</span></code>\n<code><span style=\"color:rgb(111, 110, 111)\"> # Decompiled source of </span>0x00Bd9e214FAb74d6fC21bf1aF34261765f57e875<span style=\"color:rgb(111, 110, 111)\"></span></code>\n<code><span style=\"color:rgb(111, 110, 111)\"> #</span></code>\n<code><span style=\"color:rgb(111, 110, 111)\"> # Let's make the world open source</span></code>\n<code><span style=\"color:rgb(111, 110, 111)\"> # </span></code>\n<code> <span style=\"color:rgb(111, 110, 111)\">#</span></code>\n<code><span style=\"color:rgb(111, 110, 111)\"> # I failed with these:</span></code>\n<code><span style=\"color:rgb(111, 110, 111)\"> </span><span style=\"color:rgb(111, 110, 111)\"># - </span>unknowne77c646d(?)<span style=\"color:rgb(111, 110, 111)\"></span></code>\n<code><span style=\"color:rgb(111, 110, 111)\"> </span><span style=\"color:rgb(111, 110, 111)\"># - </span>transferFromWithData(address _from, address _to, uint256 _value, bytes _data)<span style=\"color:rgb(111, 110, 111)\"></span></code>\n<code><span style=\"color:rgb(111, 110, 111)\"> # All the rest is below.</span></code>\n<code><span style=\"color:rgb(111, 110, 111)\"> #</span></code>\n<code></code>\n<code></code>\n<code> <span style=\"color:rgb(111, 110, 111)\"># Storage definitions and getters</span></code>\n<code></code>\n<code> <span class=\"hljs-keyword\">def</span> storage:</code>\n<code> allowance is <span class=\"hljs-keyword\">uint</span>256 => <span class=\"hljs-keyword\">uint</span>256 <span style=\"color:rgb(111, 110, 111)\"># mask(256, 0) at storage #2</span></code>\n<code> stor4 is <span class=\"hljs-keyword\">uint</span>256 => <span class=\"hljs-keyword\">uint</span>8 <span style=\"color:rgb(111, 110, 111)\"># mask(8, 0) at storage #4</span></code>\n<code></code>\n<code> <span class=\"hljs-keyword\">def</span> allowance(<span class=\"hljs-keyword\">address</span> _owner, <span class=\"hljs-keyword\">address</span> _spender) <span class=\"hljs-title\">payable</span>: 64</code>\n<code> <span class=\"hljs-keyword\">return</span> allowance[_owner_spender(320 - 1))]</code>\n<code></code>\n<code></code>\n<code> <span style=\"color:rgb(111, 110, 111)\">#</span></code>\n<code><span style=\"color:rgb(111, 110, 111)\"> # Regular functions - see Tutorial for understanding quirks of the code</span></code>\n<code><span style=\"color:rgb(111, 110, 111)\"> #</span></code>\n<code></code>\n<code></code>\n<code> <span style=\"color:rgb(111, 110, 111)\"># folder failed in this function - may be terribly long, sorry</span></code>\n<code> <span class=\"hljs-keyword\">def</span> unknownc47d033b(?) <span class=\"hljs-title\">payable</span>: not cd[4]:</code>\n<code> <span class=\"hljs-keyword\">revert</span></code>\n<code> else:</code>\n<code> <span class=\"hljs-keyword\">mem</span>[0]cd[4]</code>\n<code> <span class=\"hljs-keyword\">mem</span>[32] = 4</code>\n<code> <span class=\"hljs-keyword\">mem</span>[96] = <span class=\"hljs-keyword\">bool</span>(stor4[cd[4])])</code>\n<code> <span class=\"hljs-keyword\">return</span> <span class=\"hljs-keyword\">bool</span>(stor4[cd[4])])</code>\n<code></code>\n<code> <span class=\"hljs-keyword\">def</span> _fallback() <span class=\"hljs-title\">payable</span>: <span style=\"color:rgb(111, 110, 111)\"># default function</span></code>\n<code> <span class=\"hljs-keyword\">revert</span></code>\n<code></code>\n<code></code>\n"
end
test "adds style span to every line" do
@ -70,7 +70,7 @@ defmodule BlockScoutWeb.AddressDecompiledContractViewTest do
"""
assert AddressDecompiledContractView.highlight_decompiled_code(code) ==
"<code> <span style=\"color:rgb(111, 110, 111)\">#</span></code>\n<code><span style=\"color:rgb(111, 110, 111)\"> # eveem.org 6 Feb 2019</span></code>\n<code><span style=\"color:rgb(111, 110, 111)\"> # Decompiled source of </span>0x00Bd9e214FAb74d6fC21bf1aF34261765f57e875<span style=\"color:rgb(111, 110, 111)\"></span></code>\n<code><span style=\"color:rgb(111, 110, 111)\"> #</span></code>\n<code><span style=\"color:rgb(111, 110, 111)\"> # Let's make the world open source</span></code>\n<code><span style=\"color:rgb(111, 110, 111)\"> # </span></code>\n<code></code>\n"
"<code> <span style=\"color:rgb(111, 110, 111)\">#</span></code>\n<code><span style=\"color:rgb(111, 110, 111)\"> # eveem.org 6 Feb 2019</span></code>\n<code><span style=\"color:rgb(111, 110, 111)\"> # Decompiled source of </span>0x00Bd9e214FAb74d6fC21bf1aF34261765f57e875<span style=\"color:rgb(111, 110, 111)\"></span></code>\n<code><span style=\"color:rgb(111, 110, 111)\"> #</span></code>\n<code><span style=\"color:rgb(111, 110, 111)\"> # Let's make the world open source</span></code>\n<code><span style=\"color:rgb(111, 110, 111)\"> # </span></code>\n<code></code>\n<code></code>\n"
end
end

Loading…
Cancel
Save