Merge branch 'master' into ab-paginate-addresses

pull/1812/head
Victor Baranov 6 years ago committed by GitHub
commit 3c6c0dd6a4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 4
      CHANGELOG.md
  2. 2
      apps/block_scout_web/assets/css/_code.scss
  3. 53
      apps/block_scout_web/assets/css/theme/_ethereum_variables.scss
  4. 41
      apps/block_scout_web/assets/static/images/ethereum_logo.svg
  5. 61
      apps/block_scout_web/lib/block_scout_web/views/address_decompiled_contract_view.ex
  6. 16
      apps/block_scout_web/test/block_scout_web/views/address_decompiled_contract_view_test.exs
  7. 88
      apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/geth.ex
  8. 36
      apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/geth/call.ex
  9. 282
      apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/geth/tracer.ex

@ -3,9 +3,11 @@
### Features ### Features
- [#1812](https://github.com/poanetwork/blockscout/pull/1812) - add pagination to addresses page - [#1812](https://github.com/poanetwork/blockscout/pull/1812) - add pagination to addresses page
- [#1874](https://github.com/poanetwork/blockscout/pull/1874) - add changes to ethereum theme and ethereum logo
- [#1815](https://github.com/poanetwork/blockscout/pull/1815) - able to search without prefix "0x" - [#1815](https://github.com/poanetwork/blockscout/pull/1815) - able to search without prefix "0x"
- [#1813](https://github.com/poanetwork/blockscout/pull/1813) - add total blocks counter to the main page - [#1813](https://github.com/poanetwork/blockscout/pull/1813) - add total blocks counter to the main page
- [#1806](https://github.com/poanetwork/blockscout/pull/1806) - verify contracts with a post request - [#1806](https://github.com/poanetwork/blockscout/pull/1806) - verify contracts with a post request
- [#1857](https://github.com/poanetwork/blockscout/pull/1857) - Re-implement Geth JS internal transaction tracer in Elixir
- [#1859](https://github.com/poanetwork/blockscout/pull/1859) - feat: show raw transaction traces - [#1859](https://github.com/poanetwork/blockscout/pull/1859) - feat: show raw transaction traces
### Fixes ### Fixes
@ -17,6 +19,7 @@
- [#1849](https://github.com/poanetwork/blockscout/pull/1849) - Improve chains menu - [#1849](https://github.com/poanetwork/blockscout/pull/1849) - Improve chains menu
- [#1869](https://github.com/poanetwork/blockscout/pull/1869) - Fix output and gas extraction in JS tracer for Geth - [#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 - [#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
### Chore ### Chore
@ -199,3 +202,4 @@
- [https://github.com/poanetwork/blockscout/pull/1532](https://github.com/poanetwork/blockscout/pull/1532) - Upgrade elixir to 1.8.1 - [https://github.com/poanetwork/blockscout/pull/1532](https://github.com/poanetwork/blockscout/pull/1532) - Upgrade elixir to 1.8.1
- [https://github.com/poanetwork/blockscout/pull/1553](https://github.com/poanetwork/blockscout/pull/1553) - Dockerfile: remove 1.7.1 version pin FROM bitwalker/alpine-elixir-phoenix - [https://github.com/poanetwork/blockscout/pull/1553](https://github.com/poanetwork/blockscout/pull/1553) - Dockerfile: remove 1.7.1 version pin FROM bitwalker/alpine-elixir-phoenix
- [https://github.com/poanetwork/blockscout/pull/1465](https://github.com/poanetwork/blockscout/pull/1465) - Resolve lodash security alert - [https://github.com/poanetwork/blockscout/pull/1465](https://github.com/poanetwork/blockscout/pull/1465) - Resolve lodash security alert

@ -14,7 +14,7 @@ pre {
.pre-decompiled code::before { .pre-decompiled code::before {
content: counter(line); content: counter(line);
display: inline-block; display: inline-block;
width: flex; width: 3em;
border-right: 1px solid #ddd; border-right: 1px solid #ddd;
padding: 0 .5em; padding: 0 .5em;
margin-right: .5em; margin-right: .5em;

@ -1,3 +1,50 @@
$primary: #16465b; // general
$secondary: #5ab3ff; $primary: #153550;
$tertiary: #77a4c5; $secondary: #49a2ee;
$tertiary: #4ad7a7;
$additional-font: #89cae6;
// footer
$footer-background-color: $primary;
$footer-title-color: #fff;
$footer-text-color: #89cae6;
$footer-item-disc-color: $secondary;
.footer-logo { filter: brightness(0) invert(1); }
// dashboard
$dashboard-line-color-price: $tertiary; // price left border
$dashboard-banner-chart-legend-value-color: $additional-font; // chart labels
$dashboard-stats-item-value-color: $additional-font; // stat values
$dashboard-stats-item-border-color: $secondary; // stat border
$dashboard-banner-gradient-start: $primary; // gradient begin
$dashboard-banner-gradient-end: lighten($primary, 5); // gradient end
$dashboard-banner-network-plain-container-background-color: #1c476c; // stats bg
// navigation
.navbar { box-shadow: 0px 0px 30px 0px rgba(21, 53, 80, 0.12); } // header shadow
$header-icon-border-color-hover: $secondary; // top border on hover
$header-icon-color-hover: $secondary; // nav icon on hover
.dropdown-item:hover, .dropdown-item:focus { background-color: $secondary !important; } // dropdown item on hover
// buttons
$btn-line-bg: #fff; // button bg
$btn-line-color: $secondary; // button border and font color && hover bg color
$btn-copy-color: $secondary; // btn copy
$btn-qr-color: $secondary; // btn qr-code
//links & tile
.tile a { color: $secondary !important; } // links color for badges
.tile-type-block {
border-left: 4px solid $secondary;
} // tab active bg
// card
$card-background-1: $secondary;
$card-tab-active: $secondary;

@ -1,40 +1 @@
<?xml version="1.0" encoding="utf-8"?> <svg data-name="-e-eth_logo_top" xmlns="http://www.w3.org/2000/svg" width="106.094" height="30"><g data-name="1" fill-rule="evenodd"><path data-name="Фигура 1" d="M9 11.2l-9 4.4L9 0v11.2z" fill="#828083"/><path data-name="Фигура 1 копия" d="M9 10.783L0 15.2l9 5.215v-9.632z" fill="#353336"/><path data-name="Фигура 1 копия 2" d="M9 22.568l-9-5.78L9 30v-7.432z" fill="#848285"/><path data-name="Фигура 1 копия 3" d="M9 11.2l9 4.4L9 0v11.2z" fill="#2f2d30"/><path data-name="Фигура 1 копия 3" d="M9 10.783l9 4.412-9 5.215v-9.627z" fill="#121212"/><path data-name="Фигура 1 копия 3" d="M9 22.568l9-5.78L9 30v-7.432z" fill="#302e31"/></g><path d="M29.675 13.329a4.417 4.417 0 0 0 .012 5.856 3.867 3.867 0 0 0 6.084-.5.332.332 0 0 0-.289-.5.351.351 0 0 0-.289.165 3.239 3.239 0 0 1-2.77 1.395 2.9 2.9 0 0 1-2.168-.922 3.555 3.555 0 0 1-1.012-2.2h6.719a.309.309 0 0 0 .361-.338 4.287 4.287 0 0 0-1.116-2.943 3.683 3.683 0 0 0-5.532-.013zm.58.377a2.994 2.994 0 0 1 4.336 0 3.6 3.6 0 0 1 1.012 2.215h-6.36a3.6 3.6 0 0 1 1.012-2.215zm11.2-4.046a.336.336 0 1 0-.672 0v2.613h-1.728a.35.35 0 0 0 0 .7h1.728v7.01a.336.336 0 0 0 .672 0v-7.01h1.8a.35.35 0 0 0 0-.7h-1.8V9.66zm5.664 4.173V5.889a.336.336 0 1 0-.672 0v14.04a.336.336 0 0 0 .672 0v-3.492a3.921 3.921 0 0 1 .6-2.512 2.52 2.52 0 0 1 2.222-1.124 2.113 2.113 0 0 1 1.792.909 3.075 3.075 0 0 1 .621 1.962v4.258a.336.336 0 0 0 .672 0v-4.273a3.766 3.766 0 0 0-.816-2.448 2.755 2.755 0 0 0-2.28-1.1 3.047 3.047 0 0 0-2.808 1.728zm10.08-.5a4.417 4.417 0 0 0 .012 5.856 3.867 3.867 0 0 0 6.084-.5.332.332 0 0 0-.289-.5.35.35 0 0 0-.289.165 3.24 3.24 0 0 1-2.771 1.395 2.9 2.9 0 0 1-2.167-.922 3.549 3.549 0 0 1-1.012-2.2h6.719a.309.309 0 0 0 .361-.338 4.287 4.287 0 0 0-1.116-2.943 3.683 3.683 0 0 0-5.531-.017zm.58.377a2.994 2.994 0 0 1 4.336 0 3.6 3.6 0 0 1 1.012 2.215h-6.36a3.592 3.592 0 0 1 1.016-2.219zm11.108-.888a4.025 4.025 0 0 0-1.176 1.255V12.6a.336.336 0 0 0-.672 0v7.3a.336.336 0 0 0 .672 0v-3.2a4.148 4.148 0 0 1 .7-2.464 2.951 2.951 0 0 1 2.16-1.292.329.329 0 0 0 .312-.359.3.3 0 0 0-.36-.311 2.919 2.919 0 0 0-1.632.545zm5.16.511a4.417 4.417 0 0 0 .012 5.856 3.867 3.867 0 0 0 6.084-.5.332.332 0 0 0-.289-.5.353.353 0 0 0-.29.165 3.237 3.237 0 0 1-2.77 1.395 2.9 2.9 0 0 1-2.167-.922 3.549 3.549 0 0 1-1.012-2.2h6.719a.309.309 0 0 0 .361-.338 4.287 4.287 0 0 0-1.116-2.943 3.683 3.683 0 0 0-5.528-.017zm.58.377a2.994 2.994 0 0 1 4.336 0 3.6 3.6 0 0 1 1.012 2.215h-6.36a3.592 3.592 0 0 1 1.016-2.219zm15.044-1.1v2.736q0 4.44-2.785 4.44a2.144 2.144 0 0 1-1.823-.912 3.159 3.159 0 0 1-.6-1.968v-4.3a.336.336 0 1 0-.672 0v4.308a3.779 3.779 0 0 0 .817 2.455 2.747 2.747 0 0 0 2.279 1.107 2.983 2.983 0 0 0 2.785-1.9v1.392a.336.336 0 1 0 .672 0V12.61a.336.336 0 1 0-.672 0zm10.295 1.632a2.8 2.8 0 0 0-2.856-2.136 3.052 3.052 0 0 0-2.808 1.7V12.6a.336.336 0 0 0-.672 0v7.33a.336.336 0 0 0 .672 0v-3.4a4.571 4.571 0 0 1 .6-2.679 2.529 2.529 0 0 1 2.208-1.053 2.146 2.146 0 0 1 1.8.885 3.067 3.067 0 0 1 .624 1.962v4.285a.336.336 0 0 0 .672 0v-3.3a5.018 5.018 0 0 1 .624-2.56 2.4 2.4 0 0 1 2.16-1.268 2.106 2.106 0 0 1 1.8.885 3.067 3.067 0 0 1 .624 1.962v4.281a.336.336 0 0 0 .672 0v-4.3a3.84 3.84 0 0 0-.84-2.484 2.746 2.746 0 0 0-2.256-1.044 3.142 3.142 0 0 0-3.024 2.136z" fill="#1b1635" fill-rule="evenodd"/></svg>
<!-- Generator: Adobe Illustrator 22.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 532.5 106" style="enable-background:new 0 0 532.5 106;" xml:space="preserve">
<style type="text/css">
.st0{fill:#FFFFFF;}
</style>
<title>ethereum-logo</title>
<g>
<path class="st0" d="M121.6,73.1c-2.9,0-5.6-0.7-7.9-2.2c-2.4-1.4-4.2-3.4-5.5-6c-1.3-2.6-2-5.5-2-8.6v-1.4c0-3.3,0.6-6.3,1.9-8.9
c1.3-2.6,3.1-4.7,5.3-6.2s4.8-2.3,7.4-2.3c4.2,0,7.5,1.4,9.9,4.3c2.4,2.8,3.7,6.7,3.7,11.7v2.1H110v0.7c0,3.9,1.1,7.1,3.3,9.7
c2.2,2.6,5,3.9,8.4,3.9c2,0,3.8-0.4,5.4-1.1c1.6-0.7,3-1.9,4.2-3.6l2.4,1.8C131,71,126.9,73.1,121.6,73.1z M120.9,40.7
c-2.9,0-5.3,1-7.2,3.1c-2,2.1-3.1,4.9-3.6,8.4h20.6v-0.4c-0.1-3.3-1-6-2.8-8.1C126.1,41.7,123.8,40.7,120.9,40.7z"/>
<path class="st0" d="M164.6,29.3v8.8h7.1v3.1h-7.1v22.9c0,1.9,0.3,3.3,1,4.3c0.7,0.9,1.8,1.4,3.4,1.4c0.6,0,1.7-0.1,3.1-0.3
l0.2,3.1c-1,0.4-2.3,0.5-4.1,0.5c-2.6,0-4.5-0.8-5.7-2.3c-1.2-1.5-1.8-3.7-1.8-6.7V41.2h-6.3v-3.1h6.3v-8.8H164.6z"/>
<path class="st0" d="M200.2,43.9c1.2-2.1,2.8-3.6,4.8-4.8c1.9-1.1,4.1-1.7,6.4-1.7c3.7,0,6.4,1,8.2,3.1c1.8,2.1,2.7,5.2,2.7,9.3
v22.5h-3.8V49.9c0-3.1-0.7-5.4-2-6.9c-1.3-1.5-3.3-2.3-6.1-2.3c-2.3,0-4.4,0.7-6.2,2.2c-1.8,1.5-3.1,3.5-4,6v23.5h-3.8V23.7h3.8
V43.9z"/>
<path class="st0" d="M262.3,73.1c-2.9,0-5.6-0.7-7.9-2.2c-2.4-1.4-4.2-3.4-5.5-6c-1.3-2.6-2-5.5-2-8.6v-1.4c0-3.3,0.6-6.3,1.9-8.9
c1.3-2.6,3.1-4.7,5.3-6.2s4.8-2.3,7.4-2.3c4.2,0,7.5,1.4,9.9,4.3c2.4,2.8,3.7,6.7,3.7,11.7v2.1h-24.5v0.7c0,3.9,1.1,7.1,3.3,9.7
c2.2,2.6,5,3.9,8.4,3.9c2,0,3.8-0.4,5.4-1.1c1.6-0.7,3-1.9,4.2-3.6l2.4,1.8C271.6,71,267.6,73.1,262.3,73.1z M261.6,40.7
c-2.9,0-5.3,1-7.2,3.1c-2,2.1-3.1,4.9-3.6,8.4h20.6v-0.4c-0.1-3.3-1-6-2.8-8.1C266.8,41.7,264.4,40.7,261.6,40.7z"/>
<path class="st0" d="M315.2,41.3c-0.8-0.1-1.7-0.2-2.6-0.2c-2.4,0-4.4,0.7-6,2s-2.8,3.2-3.5,5.8v23.6h-3.8V38.1h3.7l0.1,5.5
c2-4.1,5.2-6.1,9.7-6.1c1.1,0,1.9,0.1,2.5,0.4L315.2,41.3z"/>
<path class="st0" d="M350.8,73.1c-2.9,0-5.6-0.7-7.9-2.2c-2.4-1.4-4.2-3.4-5.5-6c-1.3-2.6-2-5.5-2-8.6v-1.4c0-3.3,0.6-6.3,1.9-8.9
c1.3-2.6,3.1-4.7,5.3-6.2s4.8-2.3,7.4-2.3c4.2,0,7.5,1.4,9.9,4.3c2.4,2.8,3.7,6.7,3.7,11.7v2.1h-24.5v0.7c0,3.9,1.1,7.1,3.3,9.7
c2.2,2.6,5,3.9,8.4,3.9c2,0,3.8-0.4,5.4-1.1c1.6-0.7,3-1.9,4.2-3.6l2.4,1.8C360.1,71,356.1,73.1,350.8,73.1z M350.1,40.7
c-2.9,0-5.3,1-7.2,3.1s-3.1,4.9-3.6,8.4h20.6v-0.4c-0.1-3.3-1-6-2.8-8.1C355.3,41.7,353,40.7,350.1,40.7z"/>
<path class="st0" d="M410,68.1c-2.3,3.3-5.9,5-10.9,5c-3.7,0-6.4-1.1-8.3-3.2s-2.9-5.3-2.9-9.4V38.1h3.8v21.9
c0,6.5,2.6,9.8,7.9,9.8c5.5,0,9-2.3,10.4-6.8V38.1h3.8v34.3H410L410,68.1z"/>
<path class="st0" d="M443.9,38.1l0.1,5.6c1.3-2.1,2.9-3.6,4.8-4.7c1.9-1,4-1.6,6.3-1.6c5.4,0,8.9,2.2,10.3,6.7
c1.2-2.1,2.9-3.8,4.9-4.9c2.1-1.2,4.3-1.7,6.8-1.7c7.4,0,11.1,4,11.3,12.1v22.9h-3.8V49.8c0-3.1-0.7-5.3-2-6.8
c-1.3-1.5-3.4-2.2-6.4-2.2c-2.7,0-5,0.9-6.9,2.7c-1.9,1.7-2.9,3.8-3.1,6.3v22.7h-3.8V49.5c0-2.9-0.7-5.1-2.1-6.6
c-1.4-1.4-3.5-2.2-6.3-2.2c-2.4,0-4.4,0.7-6.2,2c-1.7,1.4-3,3.4-3.8,6.1v23.5h-3.8V38.1H443.9z"/>
</g>
<path class="st0" d="M57.5,17.7l21.7,36c-7,4.2-13.9,8.3-20.9,12.3c-0.6,0.2-1.3,0.2-1.8-0.1c-6.9-4-13.7-8-20.7-12.2
C43.1,41.7,50.2,29.8,57.5,17.7z"/>
<path class="st0" d="M78.1,58.9L57.2,88.3L36.3,58.9l0.4-0.4c1.7,1,3.4,2,5.1,3c4.5,2.6,9,5.2,13.4,7.9c1.2,0.9,2.9,1,4.1,0
c5.4-3.3,10.9-6.5,16.4-9.7c0.7-0.4,1.4-0.8,2.2-1.2L78.1,58.9z"/>
</svg>

Before

Width:  |  Height:  |  Size: 3.5 KiB

After

Width:  |  Height:  |  Size: 3.2 KiB

@ -18,13 +18,32 @@ defmodule BlockScoutWeb.AddressDecompiledContractView do
} }
def highlight_decompiled_code(code) do def highlight_decompiled_code(code) do
@colors {_, result} =
|> Enum.reduce(code, fn {symbol, rgb}, acc -> @colors
String.replace(acc, symbol, "<span style=\"color:rgb(#{rgb})\">") |> Enum.reduce(code, fn {symbol, rgb}, acc ->
String.replace(acc, symbol, "<span style=\"color:rgb(#{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)
result
|> Enum.reduce("", fn part, acc ->
part <> acc
end) end)
|> String.replace("\e[1m", "<span style=\"font-weight:bold\">")
|> String.replace("»", "&raquo;")
|> String.replace("\e[0m", "</span>")
|> add_line_numbers() |> add_line_numbers()
end end
@ -41,4 +60,34 @@ defmodule BlockScoutWeb.AddressDecompiledContractView do
acc <> "<code>#{line}</code>\n" acc <> "<code>#{line}</code>\n"
end) end)
end end
defp new_part(part, new_style) do
cond do
part == "" ->
""
part == "</span>" ->
""
part == new_style ->
""
new_style == "" ->
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
end
end
end end

@ -56,7 +56,21 @@ defmodule BlockScoutWeb.AddressDecompiledContractViewTest do
result = AddressDecompiledContractView.highlight_decompiled_code(code) result = AddressDecompiledContractView.highlight_decompiled_code(code)
assert result == assert result ==
"<code> <span style=\"color:rgb(111, 110, 111)\">#</code>\n<code> # eveem.org 6 Feb 2019</code>\n<code> # Decompiled source of </span>0x00Bd9e214FAb74d6fC21bf1aF34261765f57e875<span style=\"color:rgb(111, 110, 111)\"></code>\n<code> #</code>\n<code> # Let's make the world open source</code>\n<code> # </span></code>\n<code> <span style=\"color:rgb(111, 110, 111)\">#</code>\n<code> # I failed with these:</code>\n<code> </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)\"></code>\n<code> </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)\"></code>\n<code> # All the rest is below.</code>\n<code> #</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>: <span style=\"color:rgb(111, 110, 111)\"></span></code>\n<code> require (calldata.size - 4)<span style=\"font-weight:bold\"> >= </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)\">#</code>\n<code> # Regular functions - see Tutorial for understanding quirks of the code</code>\n<code> #</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>: <span style=\"color:rgb(111, 110, 111)\"></span></code>\n<code> if (calldata.size - 4)<span style=\"font-weight:bold\"> < </span>32:</code>\n<code> revert</code>\n<code> else:</code>\n<code> if not (320 - 1)<span style=\"font-weight:bold\"> or </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> = (320 - 1)<span style=\"font-weight:bold\"> and </span>(320 - 1)<span style=\"font-weight:bold\"> and </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><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"
end
test "adds style span to every line" do
code = """
#
# eveem.org 6 Feb 2019
# Decompiled source of 0x00Bd9e214FAb74d6fC21bf1aF34261765f57e875
#
# Let's make the world open source
# 
"""
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"
end end
end end

@ -3,9 +3,10 @@ defmodule EthereumJSONRPC.Geth do
Ethereum JSONRPC methods that are only supported by [Geth](https://github.com/ethereum/go-ethereum/wiki/geth). Ethereum JSONRPC methods that are only supported by [Geth](https://github.com/ethereum/go-ethereum/wiki/geth).
""" """
import EthereumJSONRPC, only: [id_to_params: 1, json_rpc: 2, request: 1] import EthereumJSONRPC, only: [id_to_params: 1, integer_to_quantity: 1, json_rpc: 2, request: 1]
alias EthereumJSONRPC.Geth.Calls alias EthereumJSONRPC.{FetchedBalance, FetchedCode}
alias EthereumJSONRPC.Geth.{Calls, Tracer}
@behaviour EthereumJSONRPC.Variant @behaviour EthereumJSONRPC.Variant
@ -28,7 +29,11 @@ defmodule EthereumJSONRPC.Geth do
id_to_params id_to_params
|> debug_trace_transaction_requests() |> debug_trace_transaction_requests()
|> json_rpc(json_rpc_named_arguments) do |> json_rpc(json_rpc_named_arguments) do
debug_trace_transaction_responses_to_internal_transactions_params(responses, id_to_params) debug_trace_transaction_responses_to_internal_transactions_params(
responses,
id_to_params,
json_rpc_named_arguments
)
end end
end end
@ -62,13 +67,88 @@ defmodule EthereumJSONRPC.Geth do
request(%{id: id, method: "debug_traceTransaction", params: [hash_data, %{tracer: @tracer}]}) request(%{id: id, method: "debug_traceTransaction", params: [hash_data, %{tracer: @tracer}]})
end end
defp debug_trace_transaction_responses_to_internal_transactions_params(responses, id_to_params) defp debug_trace_transaction_responses_to_internal_transactions_params(
[%{result: %{"structLogs" => _}} | _] = responses,
id_to_params,
json_rpc_named_arguments
)
when is_map(id_to_params) do
with {:ok, receipts} <-
id_to_params
|> Enum.map(fn {id, %{hash_data: hash_data}} ->
request(%{id: id, method: "eth_getTransactionReceipt", params: [hash_data]})
end)
|> json_rpc(json_rpc_named_arguments),
{:ok, txs} <-
id_to_params
|> Enum.map(fn {id, %{hash_data: hash_data}} ->
request(%{id: id, method: "eth_getTransactionByHash", params: [hash_data]})
end)
|> json_rpc(json_rpc_named_arguments) do
receipts_map = Enum.into(receipts, %{}, fn %{id: id, result: receipt} -> {id, receipt} end)
txs_map = Enum.into(txs, %{}, fn %{id: id, result: tx} -> {id, tx} end)
responses
|> Enum.map(fn %{id: id, result: %{"structLogs" => _} = result} ->
debug_trace_transaction_response_to_internal_transactions_params(
%{id: id, result: Tracer.replay(result, Map.fetch!(receipts_map, id), Map.fetch!(txs_map, id))},
id_to_params
)
end)
|> reduce_internal_transactions_params()
|> fetch_missing_data(json_rpc_named_arguments)
end
end
defp debug_trace_transaction_responses_to_internal_transactions_params(
responses,
id_to_params,
_json_rpc_named_arguments
)
when is_list(responses) and is_map(id_to_params) do when is_list(responses) and is_map(id_to_params) do
responses responses
|> Enum.map(&debug_trace_transaction_response_to_internal_transactions_params(&1, id_to_params)) |> Enum.map(&debug_trace_transaction_response_to_internal_transactions_params(&1, id_to_params))
|> reduce_internal_transactions_params() |> reduce_internal_transactions_params()
end end
defp fetch_missing_data({:ok, transactions}, json_rpc_named_arguments) when is_list(transactions) do
id_to_params = id_to_params(transactions)
with {:ok, responses} <-
id_to_params
|> Enum.map(fn
{id, %{created_contract_address_hash: address, block_number: block_number}} ->
FetchedCode.request(%{id: id, block_quantity: integer_to_quantity(block_number), address: address})
{id, %{type: "selfdestruct", from: hash_data, block_number: block_number}} ->
FetchedBalance.request(%{id: id, block_quantity: integer_to_quantity(block_number), hash_data: hash_data})
_ ->
nil
end)
|> Enum.reject(&is_nil/1)
|> json_rpc(json_rpc_named_arguments) do
results = Enum.into(responses, %{}, fn %{id: id, result: result} -> {id, result} end)
transactions =
id_to_params
|> Enum.map(fn
{id, %{created_contract_address_hash: _} = transaction} ->
%{transaction | created_contract_code: Map.fetch!(results, id)}
{id, %{type: "selfdestruct"} = transaction} ->
%{transaction | value: Map.fetch!(results, id)}
{_, transaction} ->
transaction
end)
{:ok, transactions}
end
end
defp fetch_missing_data(result, _json_rpc_named_arguments), do: result
defp debug_trace_transaction_response_to_internal_transactions_params(%{id: id, result: calls}, id_to_params) defp debug_trace_transaction_response_to_internal_transactions_params(%{id: id, result: calls}, id_to_params)
when is_map(id_to_params) do when is_map(id_to_params) do
%{block_number: block_number, hash_data: transaction_hash, transaction_index: transaction_index} = %{block_number: block_number, hash_data: transaction_hash, transaction_index: transaction_index} =

@ -328,9 +328,8 @@ defmodule EthereumJSONRPC.Geth.Call do
"from" => from_address_hash, "from" => from_address_hash,
"to" => to_address_hash, "to" => to_address_hash,
"gas" => gas, "gas" => gas,
"gasUsed" => gas_used,
"input" => input, "input" => input,
"output" => output, "error" => error,
"value" => value "value" => value
}) })
when call_type in ~w(call callcode delegatecall) do when call_type in ~w(call callcode delegatecall) do
@ -345,9 +344,8 @@ defmodule EthereumJSONRPC.Geth.Call do
from_address_hash: from_address_hash, from_address_hash: from_address_hash,
to_address_hash: to_address_hash, to_address_hash: to_address_hash,
gas: gas, gas: gas,
gas_used: gas_used,
input: input, input: input,
output: output, error: error,
value: value value: value
} }
end end
@ -363,8 +361,9 @@ defmodule EthereumJSONRPC.Geth.Call do
"from" => from_address_hash, "from" => from_address_hash,
"to" => to_address_hash, "to" => to_address_hash,
"gas" => gas, "gas" => gas,
"gasUsed" => gas_used,
"input" => input, "input" => input,
"error" => error, "output" => output,
"value" => value "value" => value
}) })
when call_type in ~w(call callcode delegatecall) do when call_type in ~w(call callcode delegatecall) do
@ -379,8 +378,9 @@ defmodule EthereumJSONRPC.Geth.Call do
from_address_hash: from_address_hash, from_address_hash: from_address_hash,
to_address_hash: to_address_hash, to_address_hash: to_address_hash,
gas: gas, gas: gas,
gas_used: gas_used,
input: input, input: input,
error: error, output: output,
value: value value: value
} }
end end
@ -425,13 +425,11 @@ defmodule EthereumJSONRPC.Geth.Call do
"transactionHash" => transaction_hash, "transactionHash" => transaction_hash,
"index" => index, "index" => index,
"traceAddress" => trace_address, "traceAddress" => trace_address,
"type" => "create", "type" => "create" = type,
"from" => from_address_hash, "from" => from_address_hash,
"createdContractAddressHash" => created_contract_address_hash, "error" => error,
"gas" => gas, "gas" => gas,
"gasUsed" => gas_used,
"init" => init, "init" => init,
"createdContractCode" => created_contract_code,
"value" => value "value" => value
}) do }) do
%{ %{
@ -440,13 +438,11 @@ defmodule EthereumJSONRPC.Geth.Call do
transaction_hash: transaction_hash, transaction_hash: transaction_hash,
index: index, index: index,
trace_address: trace_address, trace_address: trace_address,
type: "create", type: type,
from_address_hash: from_address_hash, from_address_hash: from_address_hash,
gas: gas, gas: gas,
gas_used: gas_used, error: error,
created_contract_address_hash: created_contract_address_hash,
init: init, init: init,
created_contract_code: created_contract_code,
value: value value: value
} }
end end
@ -457,11 +453,13 @@ defmodule EthereumJSONRPC.Geth.Call do
"transactionHash" => transaction_hash, "transactionHash" => transaction_hash,
"index" => index, "index" => index,
"traceAddress" => trace_address, "traceAddress" => trace_address,
"type" => "create" = type, "type" => "create",
"from" => from_address_hash, "from" => from_address_hash,
"error" => error, "createdContractAddressHash" => created_contract_address_hash,
"gas" => gas, "gas" => gas,
"gasUsed" => gas_used,
"init" => init, "init" => init,
"createdContractCode" => created_contract_code,
"value" => value "value" => value
}) do }) do
%{ %{
@ -470,11 +468,13 @@ defmodule EthereumJSONRPC.Geth.Call do
transaction_hash: transaction_hash, transaction_hash: transaction_hash,
index: index, index: index,
trace_address: trace_address, trace_address: trace_address,
type: type, type: "create",
from_address_hash: from_address_hash, from_address_hash: from_address_hash,
gas: gas, gas: gas,
error: error, gas_used: gas_used,
created_contract_address_hash: created_contract_address_hash,
init: init, init: init,
created_contract_code: created_contract_code,
value: value value: value
} }
end end

@ -0,0 +1,282 @@
defmodule EthereumJSONRPC.Geth.Tracer do
@moduledoc """
Elixir implementation of a custom tracer (`priv/js/ethereum_jsonrpc/geth/debug_traceTransaction/tracer.js`)
for variants that don't support specifying tracer in [debug_traceTransaction](https://github.com/ethereum/go-ethereum/wiki/Management-APIs#debug_tracetransaction) calls.
"""
import EthereumJSONRPC, only: [integer_to_quantity: 1, quantity_to_integer: 1]
def replay(%{"structLogs" => logs} = result, receipt, tx) when is_list(logs) do
%{"contractAddress" => contract_address} = receipt
%{"from" => from, "to" => to, "value" => value, "input" => input} = tx
top =
to
|> if do
%{
"type" => "call",
"callType" => "call",
"to" => to,
"input" => input,
"output" => Map.get(result, "return", "0x" <> Map.get(result, "returnValue", ""))
}
else
%{
"type" => "create",
"init" => input,
"createdContractAddressHash" => contract_address,
"createdContractCode" => "0x"
}
end
|> Map.merge(%{
"from" => from,
"traceAddress" => [],
"value" => value,
"gas" => 0,
"gasUsed" => 0
})
ctx = %{
depth: 1,
stack: [top],
trace_address: [0],
calls: [[]]
}
logs
|> Enum.reduce(ctx, &step/2)
|> finalize()
end
defp step(%{"error" => _}, %{stack: [%{"error" => _} | _]} = ctx), do: ctx
defp step(
%{"error" => _} = log,
%{
depth: stack_depth,
stack: [call | stack],
trace_address: [_, trace_index | trace_address],
calls: [subsubcalls, subcalls | calls]
} = ctx
) do
call = process_return(log, Map.put(call, "error", "error"))
subsubcalls =
subsubcalls
|> Enum.reverse()
|> Enum.map(fn
subcalls when is_list(subcalls) -> subcalls
subcall when is_map(subcall) -> %{subcall | "from" => call["createdContractAddressHash"] || call["to"]}
end)
%{
ctx
| depth: stack_depth - 1,
stack: stack,
trace_address: [trace_index + 1 | trace_address],
calls: [[subsubcalls, call | subcalls] | calls]
}
end
defp step(
%{"depth" => log_depth} = log,
%{
depth: stack_depth,
stack: [call | stack],
trace_address: [_, trace_index | trace_address],
calls: [subsubcalls, subcalls | calls]
} = ctx
)
when log_depth == stack_depth - 1 do
call = process_return(log, call)
subsubcalls =
subsubcalls
|> Enum.reverse()
|> Enum.map(fn
subcalls when is_list(subcalls) -> subcalls
subcall when is_map(subcall) -> %{subcall | "from" => call["createdContractAddressHash"] || call["to"]}
end)
step(log, %{
ctx
| depth: stack_depth - 1,
stack: stack,
trace_address: [trace_index + 1 | trace_address],
calls: [[subsubcalls, call | subcalls] | calls]
})
end
defp step(%{"gas" => log_gas, "gasCost" => log_gas_cost} = log, %{stack: [%{"gas" => call_gas} = call | stack]} = ctx) do
gas = max(call_gas, log_gas)
op(log, %{ctx | stack: [%{call | "gas" => gas, "gasUsed" => gas - log_gas - log_gas_cost} | stack]})
end
defp op(%{"op" => "CREATE"} = log, ctx), do: create_op(log, ctx)
defp op(%{"op" => "SELFDESTRUCT"} = log, ctx), do: self_destruct_op(log, ctx)
defp op(%{"op" => "CALL"} = log, ctx), do: call_op(log, "call", ctx)
defp op(%{"op" => "CALLCODE"} = log, ctx), do: call_op(log, "callcode", ctx)
defp op(%{"op" => "DELEGATECALL"} = log, ctx), do: call_op(log, "delegatecall", ctx)
defp op(%{"op" => "STATICCALL"} = log, ctx), do: call_op(log, "staticcall", ctx)
defp op(%{"op" => "REVERT"}, ctx), do: revert_op(ctx)
defp op(_, ctx), do: ctx
defp process_return(%{"stack" => log_stack}, %{"type" => "create"} = call) do
[ret | _] = Enum.reverse(log_stack)
case quantity_to_integer(ret) do
0 -> Map.put(call, "error", call["error"] || "internal failure")
_ -> %{call | "createdContractAddressHash" => "0x" <> String.slice(ret, 24, 40)}
end
end
defp process_return(
%{"stack" => log_stack, "memory" => log_memory},
%{"outputOffset" => out_off, "outputLength" => out_len} = call
) do
[ret | _] = Enum.reverse(log_stack)
ret
|> quantity_to_integer()
|> case do
0 ->
Map.put(call, "error", call["error"] || "internal failure")
_ ->
output =
log_memory
|> IO.iodata_to_binary()
|> String.slice(out_off, out_len)
%{call | "output" => "0x" <> output}
end
|> Map.drop(["outputOffset", "outputLength"])
end
defp create_op(
%{"stack" => log_stack, "memory" => log_memory},
%{depth: stack_depth, stack: stack, trace_address: trace_address, calls: calls} = ctx
) do
[value, input_offset, input_length | _] = Enum.reverse(log_stack)
init =
log_memory
|> IO.iodata_to_binary()
|> String.slice(quantity_to_integer("0x" <> input_offset) * 2, quantity_to_integer("0x" <> input_length) * 2)
call = %{
"type" => "create",
"from" => nil,
"traceAddress" => Enum.reverse(trace_address),
"init" => "0x" <> init,
"gas" => 0,
"gasUsed" => 0,
"value" => "0x" <> value,
"createdContractAddressHash" => nil,
"createdContractCode" => "0x"
}
%{
ctx
| depth: stack_depth + 1,
stack: [call | stack],
trace_address: [0 | trace_address],
calls: [[] | calls]
}
end
defp self_destruct_op(
%{"stack" => log_stack, "gas" => log_gas, "gasCost" => log_gas_cost},
%{trace_address: [trace_index | trace_address], calls: [subcalls | calls]} = ctx
) do
[to | _] = Enum.reverse(log_stack)
if quantity_to_integer(to) in 1..8 do
ctx
else
call = %{
"type" => "selfdestruct",
"from" => nil,
"to" => "0x" <> String.slice(to, 24, 40),
"traceAddress" => Enum.reverse([trace_index | trace_address]),
"gas" => log_gas,
"gasUsed" => log_gas_cost,
"value" => "0x0"
}
%{ctx | trace_address: [trace_index + 1 | trace_address], calls: [[call | subcalls] | calls]}
end
end
defp call_op(
%{"stack" => log_stack, "memory" => log_memory},
call_type,
%{
depth: stack_depth,
stack: [%{"value" => parent_value} = parent | stack],
trace_address: trace_address,
calls: calls
} = ctx
) do
[_, to | log_stack] = Enum.reverse(log_stack)
{value, [input_offset, input_length, output_offset, output_length | _]} =
case call_type do
"delegatecall" ->
{parent_value, log_stack}
"staticcall" ->
{"0x0", log_stack}
_ ->
[value | rest] = log_stack
{"0x" <> value, rest}
end
input =
log_memory
|> IO.iodata_to_binary()
|> String.slice(quantity_to_integer("0x" <> input_offset) * 2, quantity_to_integer("0x" <> input_length) * 2)
call = %{
"type" => "call",
"callType" => call_type,
"from" => nil,
"to" => "0x" <> String.slice(to, 24, 40),
"traceAddress" => Enum.reverse(trace_address),
"input" => "0x" <> input,
"output" => "0x",
"outputOffset" => quantity_to_integer("0x" <> output_offset) * 2,
"outputLength" => quantity_to_integer("0x" <> output_length) * 2,
"gas" => 0,
"gasUsed" => 0,
"value" => value
}
%{
ctx
| depth: stack_depth + 1,
stack: [call, parent | stack],
trace_address: [0 | trace_address],
calls: [[] | calls]
}
end
defp revert_op(%{stack: [last | stack]} = ctx) do
%{ctx | stack: [Map.put(last, "error", "execution reverted") | stack]}
end
defp finalize(%{stack: [top], calls: [calls]}) do
calls =
Enum.map(calls, fn
subcalls when is_list(subcalls) -> subcalls
subcall when is_map(subcall) -> %{subcall | "from" => top["createdContractAddressHash"] || top["to"]}
end)
[top | Enum.reverse(calls)]
|> List.flatten()
|> Enum.map(fn %{"gas" => gas, "gasUsed" => gas_used} = call ->
%{call | "gas" => integer_to_quantity(gas), "gasUsed" => integer_to_quantity(gas_used)}
end)
end
end
Loading…
Cancel
Save