From 721ae9ecaa59ea4365c34051b4da2b4f7351c505 Mon Sep 17 00:00:00 2001 From: Ryan Arthur Date: Mon, 24 Sep 2018 15:07:13 -0400 Subject: [PATCH 01/34] Add favicon assets --- .../assets/static/android-chrome-192x192.png | Bin 0 -> 17833 bytes .../assets/static/android-chrome-512x512.png | Bin 0 -> 43379 bytes .../assets/static/apple-touch-icon.png | Bin 0 -> 16647 bytes .../assets/static/browserconfig.xml | 9 ++++ .../assets/static/favicon-16x16.png | Bin 0 -> 20045 bytes .../assets/static/favicon-32x32.png | Bin 0 -> 20670 bytes .../block_scout_web/assets/static/favicon.ico | Bin 1258 -> 15086 bytes .../assets/static/mstile-150x150.png | Bin 0 -> 10352 bytes .../assets/static/safari-pinned-tab.svg | 39 ++++++++++++++++++ .../assets/static/site.webmanifest | 19 +++++++++ .../templates/layout/app.html.eex | 10 +++++ 11 files changed, 77 insertions(+) create mode 100644 apps/block_scout_web/assets/static/android-chrome-192x192.png create mode 100644 apps/block_scout_web/assets/static/android-chrome-512x512.png create mode 100644 apps/block_scout_web/assets/static/apple-touch-icon.png create mode 100644 apps/block_scout_web/assets/static/browserconfig.xml create mode 100644 apps/block_scout_web/assets/static/favicon-16x16.png create mode 100644 apps/block_scout_web/assets/static/favicon-32x32.png create mode 100644 apps/block_scout_web/assets/static/mstile-150x150.png create mode 100644 apps/block_scout_web/assets/static/safari-pinned-tab.svg create mode 100644 apps/block_scout_web/assets/static/site.webmanifest diff --git a/apps/block_scout_web/assets/static/android-chrome-192x192.png b/apps/block_scout_web/assets/static/android-chrome-192x192.png new file mode 100644 index 0000000000000000000000000000000000000000..5a5c2814492dae6990b726940faefce5a33a8a8a GIT binary patch literal 17833 zcmcdxgLfrQu)eW2ys>Rt8{4+Cv2AX$v27=tjW@P!+uqnWe)+xkKfE)idwP1NXL{;X z*Y{ObM<^*sBEsXs0{{R-X(=(4uXE3T1s3|NR@tzH0RX-cSc!@%S(%yw08$YtX)tQ4 z(pbaCDdgnj4MLE`AzNZJb0xnp%T=K8NZ`nmQP6@TS7yYamVzUp=>F20=pqnDA-4ae ze(cIGEUb)z!lT|M2Xo!5$-e4hyLz9>;q&--O5t$;D8(Ix4{HC02CNqHOUp?CTufA0 zlkQ=OuV(-+J@Nf1k?%!C{a_6RXWJL=^4JI$nVtO0g0G(yR<|G(Mt~Iifm&{I7UDAs zpoLD8eiR~b2Jzi|{%#;XLWyD~RVXNa@-VylhX+p?Esq{55UW2p8$1v`r9Ytmzujf(hoPAk)`tOL+MZ5sfFEae1#WgIveG5 znS3SMslACeL5JbbrgQq$8GQ3vWvIj%Y_G}N*VGIkr3LN5UE#tA^@vV<4T4vsCyyY; zh{!(7zMyjnz2`Il0+2km5BW=&GticHJo<^~2T`mT3+7PKC{%EZn3=yC`Dg^rL>y-L zU($Y`#+0lev&y+mUOWLc~6P_YI?|yXU?TsS)e=D_J(ve(2#YYLr^i zu;awR5srR~*dW_eC5CjbOmc1soVZr_kn<7Y0MA@vMl~MHtg%CC_7jn*9a*Yh$fvtE z5I>W>Ye~DP{gtRR7^e`zaiVK5EyR(BOy%DyQChdroh#S{-7Reu34K?S8+V9*vI*$$ zFjX^5Ma8OG_h%5}*9s9Ef#cYg6T|!f7~6RGabf?1gT^NYI}JoWhxsl_hKBK-)H4$!UFg>Ysemmv!&kUum#=4@Y}1&a`A+P{`(_p)VphP(7- zrgDJTgqS56TdpC4l0NY*J`Jv=Hkf{eocNo;b1iKv^lbd2gBPqKoLz`y2wsSLA3;1I zw}*RIkoGNAp8GrsaKUVIZRA$Itr?~(vdHKOxI}yqz2JsehIs^OX+;QLBG|YDZ8>;c zY+I!vmQ(V@E8oKYC0czM=H}4lNZVz(UF%vdUr6EAgR^Nl9$wYjUL5+lTuVe&H@G5v zj_;1v9>`(*5Ewx)j9ZI&{yRHtJBBLK!_=|~J2Y1=U6LDpU+HY-aOSgrBfIyRBJvpd z7Q}XYK!ijm$*)Q(hjqa6zH2>c@mG9fwkTZzDb^7qrRIIC!$#uuoNs}0hxC=i%HN5i9$Hv-cLx9U8!%0A;rX};jjrLp(EhM=roc` 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 literal 0 HcmV?d00001 diff --git a/apps/block_scout_web/assets/static/android-chrome-512x512.png b/apps/block_scout_web/assets/static/android-chrome-512x512.png new file mode 100644 index 0000000000000000000000000000000000000000..0b4840d41a70e2172db279d360330b26f3aa5261 GIT binary patch literal 43379 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∾jnSvWs;wdSb3Q>Y{bQ#u>`gd*vIB8( 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 literal 0 HcmV?d00001 diff --git a/apps/block_scout_web/assets/static/browserconfig.xml b/apps/block_scout_web/assets/static/browserconfig.xml new file mode 100644 index 0000000000..b3930d0f04 --- /dev/null +++ b/apps/block_scout_web/assets/static/browserconfig.xml @@ -0,0 +1,9 @@ + + + + + + #da532c + + + diff --git a/apps/block_scout_web/assets/static/favicon-16x16.png b/apps/block_scout_web/assets/static/favicon-16x16.png new file mode 100644 index 0000000000000000000000000000000000000000..fd59e524be74d111e8f9992924916642ca190ce4 GIT binary patch literal 20045 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%0DfZ)qmOxn{XK+|!UW&=&vV%&$=a#CdvEX); z#btE?QyI#U7S9 zi-69_nI&@yJY`!D(a4b{IH{=k1JaahCGS_KHT0Tay0HSCwu6ie8x$31FVE1RG4?mz zvmXwWT3bwf8G2tWy}qIJ;W-pYQDgLS(#O0KlPK74N)`!CWlFE`@^3|bdY$AG(UDq| zQ?$K^>Xjb(X3h76Uah2p!;bi#A9ZBPIu_@M_FLVv%~*dAhgO*hkaMmhwi;+(O02h6 ztR(%il@U>~Hpt}mts}!WKyNG+?0$P_>PEsLg|SYrD=9V={Z*^bhIE%rmsumOzOL56W8&;T`H=0Fb2Fvy!^&a&Kj3gj7R%{{DW#jDnjJ8 zb2o;og^yg)#(A1r3ag6aJk^SjwcMuY%#{)1J?_&5u8>W_TEh2*raSf|IE54)^R6*# zZiz0w;*=)Ne3vVgFnMpYXkOiRkJYVHn=mdnj&vQb{4`L}jbeZXm<^VnJT5#kXIA9} zKTDzpB9scl`m5S*Y<-1zwKRi1J>pN^bKhvevP1hSQI`)XyJK@mS@_tJ0dLlyduPf; cW~2enW>CSlk>u60{}{x|+|Dd-t<8 literal 0 HcmV?d00001 diff --git a/apps/block_scout_web/assets/static/favicon.ico b/apps/block_scout_web/assets/static/favicon.ico index 73de524aaadcf60fbe9d32881db0aa86b58b5cb9..293b5abbc70d22ee62ef7118046b33137c337872 100644 GIT binary patch literal 15086 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 diff --git a/apps/block_scout_web/assets/static/mstile-150x150.png b/apps/block_scout_web/assets/static/mstile-150x150.png new file mode 100644 index 0000000000000000000000000000000000000000..f9a6b5a8dd8c671d370782c16574f489793ba598 GIT binary patch literal 10352 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 rKfZ>{P5 + + + +Created by potrace 1.11, written by Peter Selinger 2001-2013 + + + + + diff --git a/apps/block_scout_web/assets/static/site.webmanifest b/apps/block_scout_web/assets/static/site.webmanifest new file mode 100644 index 0000000000..b20abb7cbb --- /dev/null +++ b/apps/block_scout_web/assets/static/site.webmanifest @@ -0,0 +1,19 @@ +{ + "name": "", + "short_name": "", + "icons": [ + { + "src": "/android-chrome-192x192.png", + "sizes": "192x192", + "type": "image/png" + }, + { + "src": "/android-chrome-512x512.png", + "sizes": "512x512", + "type": "image/png" + } + ], + "theme_color": "#ffffff", + "background_color": "#ffffff", + "display": "standalone" +} diff --git a/apps/block_scout_web/lib/block_scout_web/templates/layout/app.html.eex b/apps/block_scout_web/lib/block_scout_web/templates/layout/app.html.eex index a2cea8f5da..3a1f9d0376 100644 --- a/apps/block_scout_web/lib/block_scout_web/templates/layout/app.html.eex +++ b/apps/block_scout_web/lib/block_scout_web/templates/layout/app.html.eex @@ -6,6 +6,16 @@ <%= gettext "BlockScout" %> "> + + "> + "> + "> + "> + " color="#5bbad5"> + "> + + "> + From 779bdfbacfb6c135ef784fac1cd992a537bf2e27 Mon Sep 17 00:00:00 2001 From: Ryan Arthur Date: Mon, 24 Sep 2018 15:08:22 -0400 Subject: [PATCH 02/34] Internationalization --- apps/block_scout_web/priv/gettext/default.pot | 6 +++--- .../priv/gettext/en/LC_MESSAGES/default.po | 14 +++++++++++--- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/apps/block_scout_web/priv/gettext/default.pot b/apps/block_scout_web/priv/gettext/default.pot index 56b387527f..3f899ab3e5 100644 --- a/apps/block_scout_web/priv/gettext/default.pot +++ b/apps/block_scout_web/priv/gettext/default.pot @@ -408,13 +408,13 @@ msgid "Avg Block Time" msgstr "" #: lib/block_scout_web/templates/chain/show.html.eex:17 -#: lib/block_scout_web/templates/layout/app.html.eex:24 +#: lib/block_scout_web/templates/layout/app.html.eex:34 #: lib/block_scout_web/views/address_view.ex:99 msgid "Market Cap" msgstr "" #: lib/block_scout_web/templates/chain/show.html.eex:10 -#: lib/block_scout_web/templates/layout/app.html.eex:25 +#: lib/block_scout_web/templates/layout/app.html.eex:35 msgid "Price" msgstr "" @@ -1059,7 +1059,7 @@ msgid "View Less Transfers" msgstr "" #, elixir-format -#: lib/block_scout_web/templates/layout/app.html.eex:23 +#: lib/block_scout_web/templates/layout/app.html.eex:33 msgid "Less than" msgstr "" diff --git a/apps/block_scout_web/priv/gettext/en/LC_MESSAGES/default.po b/apps/block_scout_web/priv/gettext/en/LC_MESSAGES/default.po index a69de3ddfb..867b2f7dc3 100644 --- a/apps/block_scout_web/priv/gettext/en/LC_MESSAGES/default.po +++ b/apps/block_scout_web/priv/gettext/en/LC_MESSAGES/default.po @@ -420,13 +420,13 @@ msgid "Avg Block Time" msgstr "" #: lib/block_scout_web/templates/chain/show.html.eex:17 -#: lib/block_scout_web/templates/layout/app.html.eex:24 +#: lib/block_scout_web/templates/layout/app.html.eex:34 #: lib/block_scout_web/views/address_view.ex:99 msgid "Market Cap" msgstr "" #: lib/block_scout_web/templates/chain/show.html.eex:10 -#: lib/block_scout_web/templates/layout/app.html.eex:25 +#: lib/block_scout_web/templates/layout/app.html.eex:35 msgid "Price" msgstr "" @@ -570,6 +570,14 @@ msgstr "Yes" msgid "Last Updated In Block" msgstr "" +#: lib/block_scout_web/templates/smart_contract/_functions.html.eex:49 +msgid "WEI" +msgstr "" + +#: lib/block_scout_web/templates/smart_contract/_functions.html.eex:50 +msgid "ETH" +msgstr "" + #, elixir-format #: #: lib/block_scout_web/templates/transaction_internal_transaction/index.html.eex:77 @@ -1063,7 +1071,7 @@ msgid "View Less Transfers" msgstr "" #, elixir-format -#: lib/block_scout_web/templates/layout/app.html.eex:23 +#: lib/block_scout_web/templates/layout/app.html.eex:33 msgid "Less than" msgstr "" From 8853ccf0a48f5f6fa115917f5a8994cbff2273e3 Mon Sep 17 00:00:00 2001 From: jimmay5469 Date: Tue, 25 Sep 2018 14:49:59 -0400 Subject: [PATCH 03/34] Upgrade node.js and bootstrap.js --- .tool-versions | 2 +- apps/block_scout_web/assets/package-lock.json | 6 +++--- apps/block_scout_web/assets/package.json | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.tool-versions b/.tool-versions index 2f81e457af..bf2689b13f 100644 --- a/.tool-versions +++ b/.tool-versions @@ -1,3 +1,3 @@ elixir 1.7.1 erlang 21.0.4 -nodejs 10.5.0 +nodejs 10.11.0 diff --git a/apps/block_scout_web/assets/package-lock.json b/apps/block_scout_web/assets/package-lock.json index 6f0ffa5568..83b0b292fd 100644 --- a/apps/block_scout_web/assets/package-lock.json +++ b/apps/block_scout_web/assets/package-lock.json @@ -1481,9 +1481,9 @@ "dev": true }, "bootstrap": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-4.1.1.tgz", - "integrity": "sha512-SpiDSOcbg4J/PjVSt4ny5eY6j74VbVSjROY4Fb/WIUXBV9cnb5luyR4KnPvNoXuGnBK1T+nJIWqRsvU3yP8Mcg==" + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-4.1.3.tgz", + "integrity": "sha512-rDFIzgXcof0jDyjNosjv4Sno77X4KuPeFxG2XZZv1/Kc8DRVGVADdoQyyOVDwPqL36DDmtCQbrpMCqvpPLJQ0w==" }, "brace-expansion": { "version": "1.1.11", diff --git a/apps/block_scout_web/assets/package.json b/apps/block_scout_web/assets/package.json index f363ff1246..a3c05cba5a 100644 --- a/apps/block_scout_web/assets/package.json +++ b/apps/block_scout_web/assets/package.json @@ -21,7 +21,7 @@ "dependencies": { "@fortawesome/fontawesome-free": "^5.1.0-4", "bignumber.js": "^7.2.1", - "bootstrap": "^4.1.0", + "bootstrap": "^4.1.3", "chart.js": "^2.7.2", "clipboard": "^2.0.1", "humps": "^2.0.1", From e06ad3da1c8a96acae3603df8e60761ecb992138 Mon Sep 17 00:00:00 2001 From: jimmay5469 Date: Tue, 25 Sep 2018 15:41:48 -0400 Subject: [PATCH 04/34] Use valid element ID to get token collapse working again --- .../block_scout_web/templates/transaction/_tile.html.eex | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/block_scout_web/lib/block_scout_web/templates/transaction/_tile.html.eex b/apps/block_scout_web/lib/block_scout_web/templates/transaction/_tile.html.eex index 778824848f..fb5b733494 100644 --- a/apps/block_scout_web/lib/block_scout_web/templates/transaction/_tile.html.eex +++ b/apps/block_scout_web/lib/block_scout_web/templates/transaction/_tile.html.eex @@ -51,7 +51,7 @@
<% [first_token_transfer | remaining_token_transfers]= @transaction.token_transfers %> <%= render "_token_transfer.html", address: assigns[:current_address], token_transfer: first_token_transfer %> -
+
<%= for token_transfer <- remaining_token_transfers do %> <%= render "_token_transfer.html", address: assigns[:current_address], token_transfer: token_transfer %> <% end %> @@ -60,8 +60,8 @@ <%= if Enum.any?(remaining_token_transfers) do %>
- <%= link gettext("View More Transfers"), to: "##{@transaction.hash}", "data-toggle": "collapse", "data-selector": "token-transfer-open", "data-test": "token_transfers_expansion" %> - <%= link gettext("View Less Transfers"), class: "d-none", to: "##{@transaction.hash}", "data-toggle": "collapse", "data-selector": "token-transfer-close" %> + <%= link gettext("View More Transfers"), to: "#transaction-#{@transaction.hash}", "data-toggle": "collapse", "data-selector": "token-transfer-open", "data-test": "token_transfers_expansion" %> + <%= link gettext("View Less Transfers"), class: "d-none", to: "#transaction-#{@transaction.hash}", "data-toggle": "collapse", "data-selector": "token-transfer-close" %>
<% end %> From 94621979f69907372fd9257ab8e0ca281bf137c8 Mon Sep 17 00:00:00 2001 From: Ryan Arthur Date: Tue, 25 Sep 2018 15:50:13 -0400 Subject: [PATCH 05/34] Move the contract Craeted by (address) at (transaction) info to its own line --- .../templates/address/overview.html.eex | 32 +++++++++---------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/apps/block_scout_web/lib/block_scout_web/templates/address/overview.html.eex b/apps/block_scout_web/lib/block_scout_web/templates/address/overview.html.eex index aef2b60213..ef8b5cd66c 100644 --- a/apps/block_scout_web/lib/block_scout_web/templates/address/overview.html.eex +++ b/apps/block_scout_web/lib/block_scout_web/templates/address/overview.html.eex @@ -32,24 +32,24 @@ <%= link(token_title(@address.token), to: token_path(@conn, :show, @address.hash), "data-test": "token_hash_link" ) %> <% end %> - <%= if contract?(@address) do %> - - <%= gettext "Contract created by" %> - <%= link( - trimmed_hash(@address.contracts_creation_internal_transaction.from_address_hash), - to: address_path(@conn, :show, @address.contracts_creation_internal_transaction.from_address_hash) - ) %> +
+ <%= if contract?(@address) do %> + + <%= gettext "Created by" %> + <%= link( + trimmed_hash(@address.contracts_creation_internal_transaction.from_address_hash), + to: address_path(@conn, :show, @address.contracts_creation_internal_transaction.from_address_hash) + ) %> - <%= gettext "at" %> + <%= gettext "at" %> - <%= link( - trimmed_hash(@address.contracts_creation_internal_transaction.transaction_hash), - to: transaction_path(@conn, :show, @address.contracts_creation_internal_transaction.transaction_hash), - "data-test": "transaction_hash_link" - ) %> - - <% end %> -
+ <%= link( + trimmed_hash(@address.contracts_creation_internal_transaction.transaction_hash), + to: transaction_path(@conn, :show, @address.contracts_creation_internal_transaction.transaction_hash), + "data-test": "transaction_hash_link" + ) %> + + <% end %>
From 8fb8e3938d5dfc6797864614938224f7eeff4431 Mon Sep 17 00:00:00 2001 From: Ryan Arthur Date: Tue, 25 Sep 2018 15:55:26 -0400 Subject: [PATCH 06/34] Internationalization --- apps/block_scout_web/priv/gettext/default.pot | 12 ++++++------ .../priv/gettext/en/LC_MESSAGES/default.po | 12 ++++++------ 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/apps/block_scout_web/priv/gettext/default.pot b/apps/block_scout_web/priv/gettext/default.pot index 1db4c0cfb7..9b78620c4e 100644 --- a/apps/block_scout_web/priv/gettext/default.pot +++ b/apps/block_scout_web/priv/gettext/default.pot @@ -667,12 +667,7 @@ msgid "Contract Call" msgstr "" #, elixir-format -#: lib/block_scout_web/templates/address/overview.html.eex:37 -msgid "Contract created by" -msgstr "" - -#, elixir-format -#: lib/block_scout_web/templates/address/overview.html.eex:43 +#: lib/block_scout_web/templates/address/overview.html.eex:44 msgid "at" msgstr "" @@ -1260,3 +1255,8 @@ msgstr "" #: lib/block_scout_web/templates/transaction/overview.html.eex:23 msgid "This transaction is pending confirmation." msgstr "" + +#, elixir-format +#: lib/block_scout_web/templates/address/overview.html.eex:38 +msgid "Created by" +msgstr "" diff --git a/apps/block_scout_web/priv/gettext/en/LC_MESSAGES/default.po b/apps/block_scout_web/priv/gettext/en/LC_MESSAGES/default.po index cacf084173..1e66cbbba2 100644 --- a/apps/block_scout_web/priv/gettext/en/LC_MESSAGES/default.po +++ b/apps/block_scout_web/priv/gettext/en/LC_MESSAGES/default.po @@ -679,12 +679,7 @@ msgid "Contract Call" msgstr "" #, elixir-format -#: lib/block_scout_web/templates/address/overview.html.eex:37 -msgid "Contract created by" -msgstr "" - -#, elixir-format -#: lib/block_scout_web/templates/address/overview.html.eex:43 +#: lib/block_scout_web/templates/address/overview.html.eex:44 msgid "at" msgstr "" @@ -1272,3 +1267,8 @@ msgstr "" #: lib/block_scout_web/templates/transaction/overview.html.eex:23 msgid "This transaction is pending confirmation." msgstr "" + +#, elixir-format +#: lib/block_scout_web/templates/address/overview.html.eex:38 +msgid "Created by" +msgstr "" From 428e674667c0b3eda080933f31aeb0a193796a63 Mon Sep 17 00:00:00 2001 From: Lucas Narciso Date: Tue, 25 Sep 2018 17:28:07 -0300 Subject: [PATCH 07/34] Handle more errors types at Smart Contract Reader Errors may pop up that do not comply with the current expect API: they may not include a :message key in its formation. When they did not, the exception handler was throwing an exception. --- .../lib/explorer/smart_contract/reader.ex | 12 ++++++++++-- .../explorer/smart_contract/reader_test.exs | 18 ++++++++++++++++++ 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/apps/explorer/lib/explorer/smart_contract/reader.ex b/apps/explorer/lib/explorer/smart_contract/reader.ex index 523b2bca8b..efdf7360cd 100644 --- a/apps/explorer/lib/explorer/smart_contract/reader.ex +++ b/apps/explorer/lib/explorer/smart_contract/reader.ex @@ -114,7 +114,7 @@ defmodule Explorer.SmartContract.Reader do |> decode_results(abi, functions) rescue error -> - format_error(functions, error.message) + format_error(functions, error) end defp decode_results({:ok, results}, abi, functions), do: Encoder.decode_abi_results(results, abi, functions) @@ -123,7 +123,7 @@ defmodule Explorer.SmartContract.Reader do format_error(functions, "Bad Gateway") end - defp format_error(functions, message) do + defp format_error(functions, message) when is_binary(message) do functions |> Enum.map(fn {function_name, _args} -> %{function_name => {:error, message}} @@ -131,6 +131,14 @@ defmodule Explorer.SmartContract.Reader do |> List.first() end + defp format_error(functions, %{message: error_message}) do + format_error(functions, error_message) + end + + defp format_error(functions, error) do + format_error(functions, Exception.message(error)) + end + @doc """ Given the encoded data that references a function and its arguments in the blockchain, as well as the contract address, returns what EthereumJSONRPC.execute_contract_functions expects. """ diff --git a/apps/explorer/test/explorer/smart_contract/reader_test.exs b/apps/explorer/test/explorer/smart_contract/reader_test.exs index 77f0874c08..5452c10e2d 100644 --- a/apps/explorer/test/explorer/smart_contract/reader_test.exs +++ b/apps/explorer/test/explorer/smart_contract/reader_test.exs @@ -82,6 +82,24 @@ defmodule Explorer.SmartContract.ReaderTest do assert %{"get" => {:error, "Bad Gateway"}} = response end + + test "handles other types of errors" do + smart_contract = build(:smart_contract) + contract_address_hash = Hash.to_string(smart_contract.address_hash) + abi = smart_contract.abi + + expect( + EthereumJSONRPC.Mox, + :json_rpc, + fn [%{id: _, method: _, params: [%{data: _, to: _}]}], _options -> + raise FunctionClauseError + end + ) + + response = Reader.query_contract(contract_address_hash, abi, %{"get" => []}) + + assert %{"get" => {:error, "no function clause matches"}} = response + end end describe "query_verified_contract/2" do From 8e3d80a6dbc91a7fec8a773a0e443a1eeb52ed26 Mon Sep 17 00:00:00 2001 From: Sebastian Abondano Date: Tue, 25 Sep 2018 19:23:35 -0400 Subject: [PATCH 08/34] Realtime indexer waits half a second before fetch Why: * For Sokol, on staging, we noticed many errors like this one: ``` 00:45:05.627 application=indexer [error] realtime indexer failed to validate for block 4668478: [%{code: -32602, data: %{"blockNumber" => "0x473C3E", "hash" => "0x532e069e200be3e372da9680872826bb08caef91"}, message: "Unknown block number"}, %{code: -32602, data: %{"blockNumber" => "0x473C3E", "hash" => "0x95426f2bc716022fcf1def006dbc4bb81f5b5164"}, message: "Unknown block number"}, %{code: -32602, data: %{"blockNumber" => "0x473C3E", "hash" => "0xe797a1da01eb0f951e0e400f9343de9d17a06bac"}, message: "Unknown block number"}]. Block will be retried by catchup indexer. ``` * Issue link: https://github.com/poanetwork/blockscout/issues/808 This change addresses the need by: * Editing `Indexer.Block.Realtime.Fetcher.fetch_and_import_block/2` for it to wait half a second before starting to fetch and import. The rationale here is that we're hoping that half a second will be enough for Parity to sync and not return an "Unknown block number" error. --- apps/indexer/lib/indexer/block/realtime/fetcher.ex | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/indexer/lib/indexer/block/realtime/fetcher.ex b/apps/indexer/lib/indexer/block/realtime/fetcher.ex index f55a298a69..297d5eeb23 100644 --- a/apps/indexer/lib/indexer/block/realtime/fetcher.ex +++ b/apps/indexer/lib/indexer/block/realtime/fetcher.ex @@ -124,6 +124,9 @@ defmodule Indexer.Block.Realtime.Fetcher do end def fetch_and_import_block(block_number_to_fetch, block_fetcher) do + # Wait half a second to give Parity/Geth time to sync. + :timer.sleep(500) + case fetch_and_import_range(block_fetcher, block_number_to_fetch..block_number_to_fetch) do {:ok, {_inserted, _next}} -> Logger.debug(fn -> From 5af15639b99afea63a399d421f72692feae58b0f Mon Sep 17 00:00:00 2001 From: Alex Garibay Date: Wed, 26 Sep 2018 11:59:58 -0500 Subject: [PATCH 09/34] Preload created contract address for transaction logs (#812) Transactions that create a contract address rely on the field to be preloaded. --- .../controllers/transaction_log_controller.ex | 1 + .../controllers/transaction_log_controller_test.exs | 12 ++++++++++++ 2 files changed, 13 insertions(+) diff --git a/apps/block_scout_web/lib/block_scout_web/controllers/transaction_log_controller.ex b/apps/block_scout_web/lib/block_scout_web/controllers/transaction_log_controller.ex index 421c0c38de..be3567f47c 100644 --- a/apps/block_scout_web/lib/block_scout_web/controllers/transaction_log_controller.ex +++ b/apps/block_scout_web/lib/block_scout_web/controllers/transaction_log_controller.ex @@ -13,6 +13,7 @@ defmodule BlockScoutWeb.TransactionLogController do transaction_hash, necessity_by_association: %{ :block => :optional, + [created_contract_address: :names] => :optional, [from_address: :names] => :required, [to_address: :names] => :optional, :token_transfers => :optional diff --git a/apps/block_scout_web/test/block_scout_web/controllers/transaction_log_controller_test.exs b/apps/block_scout_web/test/block_scout_web/controllers/transaction_log_controller_test.exs index eb1550fd5a..c84525219f 100644 --- a/apps/block_scout_web/test/block_scout_web/controllers/transaction_log_controller_test.exs +++ b/apps/block_scout_web/test/block_scout_web/controllers/transaction_log_controller_test.exs @@ -119,4 +119,16 @@ defmodule BlockScoutWeb.TransactionLogControllerTest do assert %Token{} = conn.assigns.exchange_rate end + + test "loads for transcations that created a contract", %{conn: conn} do + contract_address = insert(:contract_address) + + transaction = + :transaction + |> insert(to_address: nil) + |> with_contract_creation(contract_address) + + conn = get(conn, transaction_log_path(conn, :index, transaction)) + assert html_response(conn, 200) + end end From 8467348a790f3ed5dc6de2a0186b08724f47b366 Mon Sep 17 00:00:00 2001 From: Stamates Date: Thu, 20 Sep 2018 15:27:22 -0400 Subject: [PATCH 10/34] Remove collated pending transactions --- .../assets/js/pages/transaction.js | 45 +++++++++++++++++++ .../channels/transaction_channel.ex | 1 + .../pending_transaction/index.html.eex | 33 +++----------- .../transaction/_pending_tile.html.eex | 24 ++++++++++ .../features/viewing_transactions_test.exs | 12 +++++ 5 files changed, 88 insertions(+), 27 deletions(-) create mode 100644 apps/block_scout_web/lib/block_scout_web/templates/transaction/_pending_tile.html.eex diff --git a/apps/block_scout_web/assets/js/pages/transaction.js b/apps/block_scout_web/assets/js/pages/transaction.js index 6598e33659..6f14e3e082 100644 --- a/apps/block_scout_web/assets/js/pages/transaction.js +++ b/apps/block_scout_web/assets/js/pages/transaction.js @@ -14,6 +14,7 @@ export const initialState = { blockNumber: null, channelDisconnected: false, confirmations: null, + pendingTransactionHashes: [], newTransactions: [], transactionCount: null } @@ -24,6 +25,7 @@ export function reducer (state = initialState, action) { return Object.assign({}, state, { beyondPageOne: action.beyondPageOne, blockNumber: parseInt(action.blockNumber, 10), + pendingTransactionHashes: action.pendingTransactionHashes || [], transactionCount: numeral(action.transactionCount).value() }) } @@ -40,6 +42,16 @@ export function reducer (state = initialState, action) { }) } else return state } + case 'RECEIVED_NEW_TRANSACTION': { + if (state.pendingTransactionHashes.includes(action.msg.transactionHash)) { + const index = state.pendingTransactionHashes.indexOf(action.msg.transactionHash) + return Object.assign({}, state, { + pendingTransactionHashes: state.pendingTransactionHashes.splice(index, 1), + transactionCount: state.transactionCount - 1, + newTransactions: [action.msg.transactionHash] + }) + } else return state + } case 'RECEIVED_NEW_TRANSACTION_BATCH': { if (state.channelDisconnected || state.beyondPageOne) return state @@ -137,3 +149,36 @@ if ($transactionListPage.length) { } }) } + +const $transactionPendingListPage = $('[data-page="transaction-pending-list"]') +if ($transactionPendingListPage.length) { + initRedux(reducer, { + main (store) { + const pendingState = store.dispatch({ + type: 'PAGE_LOAD', + transactionCount: $('[data-selector="transaction-pending-count"]').text(), + pendingTransactionHashes: $('[data-transaction-hash]').map((index, el) => + el.attributes['data-transaction-hash'].nodeValue + ).toArray(), + beyondPageOne: !!humps.camelizeKeys(URI(window.location).query(true)).index + }) + if (!pendingState.beyondPageOne) { + const transactionsChannel = socket.channel(`transactions:new_transaction`) + transactionsChannel.join() + transactionsChannel.onError(() => store.dispatch({ type: 'CHANNEL_DISCONNECTED' })) + transactionsChannel.on('new_transaction', (msg) => + store.dispatch({ type: 'RECEIVED_NEW_TRANSACTION', msg: humps.camelizeKeys(msg) }) + ) + } + }, + render (state, oldState) { + const $transactionsPendingList = $('[data-selector="transactions-pending-list"]') + const $transactionPendingCount = $('[data-selector="transaction-pending-count"]') + + if (oldState.transactionCount !== state.transactionCount) $transactionPendingCount.empty().append(numeral(state.transactionCount).format()) + if (oldState.pendingTransactionHashes !== state.pendingTransactionHashes && state.newTransactions.length > 0) { + $('[data-transaction-hash="'+ state.newTransactions[0] + '"]').remove() + } + } + }) +} diff --git a/apps/block_scout_web/lib/block_scout_web/channels/transaction_channel.ex b/apps/block_scout_web/lib/block_scout_web/channels/transaction_channel.ex index 1887c90ffd..fcd8193a47 100644 --- a/apps/block_scout_web/lib/block_scout_web/channels/transaction_channel.ex +++ b/apps/block_scout_web/lib/block_scout_web/channels/transaction_channel.ex @@ -28,6 +28,7 @@ defmodule BlockScoutWeb.TransactionChannel do ) push(socket, "new_transaction", %{ + transaction_hash: Explorer.Chain.Hash.to_string(transaction.hash), transaction_html: rendered_transaction }) diff --git a/apps/block_scout_web/lib/block_scout_web/templates/pending_transaction/index.html.eex b/apps/block_scout_web/lib/block_scout_web/templates/pending_transaction/index.html.eex index 7a37f3d93b..5957b4197a 100644 --- a/apps/block_scout_web/lib/block_scout_web/templates/pending_transaction/index.html.eex +++ b/apps/block_scout_web/lib/block_scout_web/templates/pending_transaction/index.html.eex @@ -1,4 +1,4 @@ -
+
@@ -46,33 +46,12 @@

<%= gettext "Transactions" %>

<%= gettext("Showing %{count} Pending Transactions", count: @pending_transaction_count) %>

- <%= for transaction <- @transactions do %> -
-
-
- <%= BlockScoutWeb.TransactionView.transaction_display_type(transaction) %> -
<%= BlockScoutWeb.TransactionView.formatted_status(transaction) %>
-
-
- <%= render BlockScoutWeb.TransactionView, "_link.html", transaction_hash: transaction.hash %> - - <%= render BlockScoutWeb.AddressView, "_link.html", address: transaction.from_address, contract: BlockScoutWeb.AddressView.contract?(transaction.from_address) %> - → - <%= if transaction.to_address_hash do %> - <%= render BlockScoutWeb.AddressView, "_link.html", address: transaction.to_address, contract: BlockScoutWeb.AddressView.contract?(transaction.to_address) %> - <% else %> - <%= gettext("Contract Address Pending") %> - <% end %> - - - <%= BlockScoutWeb.TransactionView.value(transaction, include_label: false) %> <%= gettext "Ether" %> - <%= BlockScoutWeb.TransactionView.formatted_fee(transaction, denomination: :ether, include_label: false) %> <%= gettext "TX Fee" %> - + + <%= for transaction <- @transactions do %> + <%= render BlockScoutWeb.TransactionView, "_pending_tile.html", transaction: transaction %> + <% end %> + -
-
-
- <% end %> <%= if @next_page_params do %> <%= link( gettext("Older"), diff --git a/apps/block_scout_web/lib/block_scout_web/templates/transaction/_pending_tile.html.eex b/apps/block_scout_web/lib/block_scout_web/templates/transaction/_pending_tile.html.eex new file mode 100644 index 0000000000..d13b6dc403 --- /dev/null +++ b/apps/block_scout_web/lib/block_scout_web/templates/transaction/_pending_tile.html.eex @@ -0,0 +1,24 @@ +
+
+
+ <%= BlockScoutWeb.TransactionView.transaction_display_type(@transaction) %> +
<%= BlockScoutWeb.TransactionView.formatted_status(@transaction) %>
+
+
+ <%= render BlockScoutWeb.TransactionView, "_link.html", transaction_hash: @transaction.hash %> + + <%= render BlockScoutWeb.AddressView, "_link.html", address: @transaction.from_address, contract: BlockScoutWeb.AddressView.contract?(@transaction.from_address) %> + → + <%= if @transaction.to_address_hash do %> + <%= render BlockScoutWeb.AddressView, "_link.html", address: @transaction.to_address, contract: BlockScoutWeb.AddressView.contract?(@transaction.to_address) %> + <% else %> + <%= gettext("Contract Address Pending") %> + <% end %> + + + <%= BlockScoutWeb.TransactionView.value(@transaction, include_label: false) %> <%= gettext "Ether" %> + <%= BlockScoutWeb.TransactionView.formatted_fee(@transaction, denomination: :ether, include_label: false) %> <%= gettext "TX Fee" %> + +
+
+
diff --git a/apps/block_scout_web/test/block_scout_web/features/viewing_transactions_test.exs b/apps/block_scout_web/test/block_scout_web/features/viewing_transactions_test.exs index f2b522808c..79f5215b8f 100644 --- a/apps/block_scout_web/test/block_scout_web/features/viewing_transactions_test.exs +++ b/apps/block_scout_web/test/block_scout_web/features/viewing_transactions_test.exs @@ -83,6 +83,18 @@ defmodule BlockScoutWeb.ViewingTransactionsTest do |> assert_has(TransactionListPage.transaction_status(pending_contract)) end + test "live remove collated pending transaction", %{pending: pending, session: session} do + session + |> TransactionListPage.visit_page() + |> TransactionListPage.click_pending() + |> assert_has(TransactionListPage.transaction(pending)) + + transaction = with_block(pending) + Notifier.handle_event({:chain_event, :transactions, [transaction.hash]}) + + refute_has(session, TransactionListPage.transaction(pending)) + end + test "contract creation is shown for to_address on list page", %{session: session} do contract_address = insert(:contract_address) From ff5d4d0163a3330308c3ef1bbfe89501712e1ed0 Mon Sep 17 00:00:00 2001 From: Stamates Date: Thu, 20 Sep 2018 21:27:28 -0400 Subject: [PATCH 11/34] Wireup live update of pending transactions --- .../assets/__tests__/pages/transaction.js | 201 ++++++++++++++++++ .../assets/js/pages/transaction.js | 124 ++++++++--- .../channels/transaction_channel.ex | 27 ++- .../lib/block_scout_web/notifier.ex | 10 +- .../pending_transaction/index.html.eex | 17 +- .../templates/transaction/index.html.eex | 6 +- .../channels/transaction_channel_test.exs | 17 ++ .../features/viewing_transactions_test.exs | 11 + apps/explorer/lib/explorer/chain/import.ex | 2 +- .../indexer/pending_transaction/fetcher.ex | 1 + 10 files changed, 373 insertions(+), 43 deletions(-) diff --git a/apps/block_scout_web/assets/__tests__/pages/transaction.js b/apps/block_scout_web/assets/__tests__/pages/transaction.js index 20da637dae..eae08fa44c 100644 --- a/apps/block_scout_web/assets/__tests__/pages/transaction.js +++ b/apps/block_scout_web/assets/__tests__/pages/transaction.js @@ -13,6 +13,207 @@ test('RECEIVED_NEW_BLOCK', () => { expect(output.confirmations).toBe(4) }) +describe('RECEIVED_NEW_PENDING_TRANSACTION_BATCH', () => { + test('single transaction', () => { + const state = initialState + const action = { + type: 'RECEIVED_NEW_PENDING_TRANSACTION_BATCH', + msgs: [{ + transactionHash: '0x00', + transactionHtml: 'test' + }] + } + const output = reducer(state, action) + + expect(output.newPendingTransactions).toEqual(['test']) + expect(output.pendingTransactionHashes.length).toEqual(1) + expect(output.pendingTransactionHashes[0]).toEqual('0x00') + expect(output.batchCountAccumulator).toEqual(0) + expect(output.transactionCount).toEqual(1) + }) + test('large batch of transactions', () => { + const state = initialState + const action = { + type: 'RECEIVED_NEW_PENDING_TRANSACTION_BATCH', + msgs: [{ + transactionHash: '0x01', + transactionHtml: 'test 1' + },{ + transactionHash: '0x02', + transactionHtml: 'test 2' + },{ + transactionHash: '0x03', + transactionHtml: 'test 3' + },{ + transactionHash: '0x04', + transactionHtml: 'test 4' + },{ + transactionHash: '0x05', + transactionHtml: 'test 5' + },{ + transactionHash: '0x06', + transactionHtml: 'test 6' + },{ + transactionHash: '0x07', + transactionHtml: 'test 7' + },{ + transactionHash: '0x08', + transactionHtml: 'test 8' + },{ + transactionHash: '0x09', + transactionHtml: 'test 9' + },{ + transactionHash: '0x10', + transactionHtml: 'test 10' + },{ + transactionHash: '0x11', + transactionHtml: 'test 11' + }] + } + const output = reducer(state, action) + + expect(output.newPendingTransactions).toEqual([]) + expect(output.pendingTransactionHashes).toEqual([]) + expect(output.batchCountAccumulator).toEqual(11) + expect(output.transactionCount).toEqual(11) + }) + test('single transaction after single transaction', () => { + const state = Object.assign({}, initialState, { + newPendingTransactions: ['test 1'], + pendingTransactionHashes: ['0x01'], + transactionCount: 1 + }) + const action = { + type: 'RECEIVED_NEW_PENDING_TRANSACTION_BATCH', + msgs: [{ + transactionHash: '0x02', + transactionHtml: 'test 2' + }] + } + const output = reducer(state, action) + + expect(output.newPendingTransactions).toEqual(['test 1', 'test 2']) + expect(output.pendingTransactionHashes).toEqual(['0x01', '0x02']) + expect(output.batchCountAccumulator).toEqual(0) + expect(output.transactionCount).toEqual(2) + }) + test('single transaction after large batch of transactions', () => { + const state = Object.assign({}, initialState, { + newTransactions: [], + batchCountAccumulator: 11 + }) + const action = { + type: 'RECEIVED_NEW_PENDING_TRANSACTION_BATCH', + msgs: [{ + transactionHash: '0x12', + transactionHtml: 'test 12' + }] + } + const output = reducer(state, action) + + expect(output.newPendingTransactions).toEqual([]) + expect(output.pendingTransactionHashes).toEqual([]) + expect(output.batchCountAccumulator).toEqual(12) + }) + test('large batch of transactions after large batch of transactions', () => { + const state = Object.assign({}, initialState, { + newPendingTransactions: [], + batchCountAccumulator: 11 + }) + const action = { + type: 'RECEIVED_NEW_PENDING_TRANSACTION_BATCH', + msgs: [{ + transactionHash: '0x12', + transactionHtml: 'test 12' + },{ + transactionHash: '0x13', + transactionHtml: 'test 13' + },{ + transactionHash: '0x14', + transactionHtml: 'test 14' + },{ + transactionHash: '0x15', + transactionHtml: 'test 15' + },{ + transactionHash: '0x16', + transactionHtml: 'test 16' + },{ + transactionHash: '0x17', + transactionHtml: 'test 17' + },{ + transactionHash: '0x18', + transactionHtml: 'test 18' + },{ + transactionHash: '0x19', + transactionHtml: 'test 19' + },{ + transactionHash: '0x20', + transactionHtml: 'test 20' + },{ + transactionHash: '0x21', + transactionHtml: 'test 21' + },{ + transactionHash: '0x22', + transactionHtml: 'test 22' + }] + } + const output = reducer(state, action) + + expect(output.newPendingTransactions).toEqual([]) + expect(output.pendingTransactionHashes).toEqual([]) + expect(output.batchCountAccumulator).toEqual(22) + }) + test('after disconnection', () => { + const state = Object.assign({}, initialState, { + channelDisconnected: true + }) + const action = { + type: 'RECEIVED_NEW_PENDING_TRANSACTION_BATCH', + msgs: [{ + transactionHash: '0x00', + transactionHtml: 'test' + }] + } + const output = reducer(state, action) + + expect(output.newPendingTransactions).toEqual([]) + expect(output.pendingTransactionHashes).toEqual([]) + expect(output.batchCountAccumulator).toEqual(0) + }) + test('on page 2+', () => { + const state = Object.assign({}, initialState, { + beyondPageOne: true + }) + const action = { + type: 'RECEIVED_NEW_PENDING_TRANSACTION_BATCH', + msgs: [{ + transactionHash: '0x00', + transactionHtml: 'test' + }] + } + const output = reducer(state, action) + + expect(output.newPendingTransactions).toEqual([]) + expect(output.pendingTransactionHashes).toEqual([]) + expect(output.batchCountAccumulator).toEqual(0) + }) +}) + +test('RECEIVED_NEW_TRANSACTION', () => { + const state = { ...initialState, pendingTransactionHashes: ['0x00'], transactionCount: 2 } + const action = { + type: 'RECEIVED_NEW_TRANSACTION', + msg: { + transactionHash: '0x00' + } + } + const output = reducer(state, action) + + expect(output.transactionCount).toBe(1) + expect(output.pendingTransactionHashes).toEqual([]) + expect(output.newTransactions).toEqual(['0x00']) +}) + describe('RECEIVED_NEW_TRANSACTION_BATCH', () => { test('single transaction', () => { const state = initialState diff --git a/apps/block_scout_web/assets/js/pages/transaction.js b/apps/block_scout_web/assets/js/pages/transaction.js index 6f14e3e082..efe4897ff5 100644 --- a/apps/block_scout_web/assets/js/pages/transaction.js +++ b/apps/block_scout_web/assets/js/pages/transaction.js @@ -14,8 +14,9 @@ export const initialState = { blockNumber: null, channelDisconnected: false, confirmations: null, - pendingTransactionHashes: [], + newPendingTransactions: [], newTransactions: [], + pendingTransactionHashes: [], transactionCount: null } @@ -45,13 +46,36 @@ export function reducer (state = initialState, action) { case 'RECEIVED_NEW_TRANSACTION': { if (state.pendingTransactionHashes.includes(action.msg.transactionHash)) { const index = state.pendingTransactionHashes.indexOf(action.msg.transactionHash) + state.pendingTransactionHashes.splice(index, 1) return Object.assign({}, state, { - pendingTransactionHashes: state.pendingTransactionHashes.splice(index, 1), + pendingTransactionHashes: state.pendingTransactionHashes, transactionCount: state.transactionCount - 1, newTransactions: [action.msg.transactionHash] }) } else return state } + case 'RECEIVED_NEW_PENDING_TRANSACTION_BATCH': { + if (state.channelDisconnected || state.beyondPageOne) return state + + if (!state.batchCountAccumulator && action.msgs.length < BATCH_THRESHOLD) { + return Object.assign({}, state, { + newPendingTransactions: [ + ...state.newPendingTransactions, + ...action.msgs.map(({transactionHtml}) => transactionHtml) + ], + pendingTransactionHashes: [ + ...state.pendingTransactionHashes, + ...action.msgs.map(({transactionHash}) => transactionHash) + ], + transactionCount: state.transactionCount + action.msgs.length + }) + } else { + return Object.assign({}, state, { + batchCountAccumulator: state.batchCountAccumulator + action.msgs.length, + transactionCount: state.transactionCount + action.msgs.length + }) + } + } case 'RECEIVED_NEW_TRANSACTION_BATCH': { if (state.channelDisconnected || state.beyondPageOne) return state @@ -103,21 +127,30 @@ if ($transactionDetailsPage.length) { }) } -const $transactionListPage = $('[data-page="transaction-list"]') -if ($transactionListPage.length) { +const $transactionPendingListPage = $('[data-page="transaction-pending-list"]') +if ($transactionPendingListPage.length) { initRedux(reducer, { main (store) { - const state = store.dispatch({ + const pendingState = store.dispatch({ type: 'PAGE_LOAD', - transactionCount: $('[data-selector="transaction-count"]').text(), + transactionCount: $('[data-selector="transaction-pending-count"]').text(), + pendingTransactionHashes: $('[data-transaction-hash]').map((index, el) => + el.attributes['data-transaction-hash'].nodeValue + ).toArray(), beyondPageOne: !!humps.camelizeKeys(URI(window.location).query(true)).index }) - if (!state.beyondPageOne) { - const transactionsChannel = socket.channel(`transactions:new_transaction`) - transactionsChannel.join() - transactionsChannel.onError(() => store.dispatch({ type: 'CHANNEL_DISCONNECTED' })) - transactionsChannel.on('new_transaction', batchChannel((msgs) => - store.dispatch({ type: 'RECEIVED_NEW_TRANSACTION_BATCH', msgs: humps.camelizeKeys(msgs) })) + const transactionsChannel = socket.channel(`transactions:new_transaction`) + transactionsChannel.join() + transactionsChannel.onError(() => store.dispatch({ type: 'CHANNEL_DISCONNECTED' })) + transactionsChannel.on('new_transaction', (msg) => + store.dispatch({ type: 'RECEIVED_NEW_TRANSACTION', msg: humps.camelizeKeys(msg) }) + ) + if (!pendingState.beyondPageOne) { + const pendingTransactionsChannel = socket.channel(`transactions:new_pending_transaction`) + pendingTransactionsChannel.join() + pendingTransactionsChannel.onError(() => store.dispatch({ type: 'CHANNEL_DISCONNECTED' })) + pendingTransactionsChannel.on('new_pending_transaction', batchChannel((msgs) => + store.dispatch({ type: 'RECEIVED_NEW_PENDING_TRANSACTION_BATCH', msgs: humps.camelizeKeys(msgs) })) ) } }, @@ -125,24 +158,31 @@ if ($transactionListPage.length) { const $channelBatching = $('[data-selector="channel-batching-message"]') const $channelBatchingCount = $('[data-selector="channel-batching-count"]') const $channelDisconnected = $('[data-selector="channel-disconnected-message"]') - const $transactionsList = $('[data-selector="transactions-list"]') - const $transactionCount = $('[data-selector="transaction-count"]') + const $pendingTransactionsList = $('[data-selector="transactions-pending-list"]') + const $pendingTransactionsCount = $('[data-selector="transaction-pending-count"]') if (state.channelDisconnected) $channelDisconnected.show() - if (oldState.transactionCount !== state.transactionCount) $transactionCount.empty().append(numeral(state.transactionCount).format()) + if (oldState.transactionCount !== state.transactionCount) { + $pendingTransactionsCount.empty().append(numeral(state.transactionCount).format()) + } + if (oldState.pendingTransactionHashes !== state.pendingTransactionHashes && state.newTransactions.length > 0) { + $('[data-transaction-hash="' + state.newTransactions[0] + '"]').remove() + } if (state.batchCountAccumulator) { $channelBatching.show() $channelBatchingCount[0].innerHTML = numeral(state.batchCountAccumulator).format() } else { $channelBatching.hide() } - if (oldState.newTransactions !== state.newTransactions) { - const newTransactionsToInsert = state.newTransactions.slice(oldState.newTransactions.length) - $transactionsList + if (oldState.newPendingTransactions !== state.newPendingTransactions) { + const newTransactionsToInsert = state.newPendingTransactions.slice(oldState.newPendingTransactions.length) + $pendingTransactionsList .children() - .slice($transactionsList.children().length - newTransactionsToInsert.length, $transactionsList.children().length) + .slice($pendingTransactionsList.children().length - newTransactionsToInsert.length, + $pendingTransactionsList.children().length + ) .remove() - prependWithClingBottom($transactionsList, newTransactionsToInsert.reverse().join('')) + prependWithClingBottom($pendingTransactionsList, newTransactionsToInsert.reverse().join('')) updateAllAges() } @@ -150,34 +190,48 @@ if ($transactionListPage.length) { }) } -const $transactionPendingListPage = $('[data-page="transaction-pending-list"]') -if ($transactionPendingListPage.length) { +const $transactionListPage = $('[data-page="transaction-list"]') +if ($transactionListPage.length) { initRedux(reducer, { main (store) { - const pendingState = store.dispatch({ + const state = store.dispatch({ type: 'PAGE_LOAD', - transactionCount: $('[data-selector="transaction-pending-count"]').text(), - pendingTransactionHashes: $('[data-transaction-hash]').map((index, el) => - el.attributes['data-transaction-hash'].nodeValue - ).toArray(), + transactionCount: $('[data-selector="transaction-count"]').text(), beyondPageOne: !!humps.camelizeKeys(URI(window.location).query(true)).index }) - if (!pendingState.beyondPageOne) { + if (!state.beyondPageOne) { const transactionsChannel = socket.channel(`transactions:new_transaction`) transactionsChannel.join() transactionsChannel.onError(() => store.dispatch({ type: 'CHANNEL_DISCONNECTED' })) - transactionsChannel.on('new_transaction', (msg) => - store.dispatch({ type: 'RECEIVED_NEW_TRANSACTION', msg: humps.camelizeKeys(msg) }) + transactionsChannel.on('new_transaction', batchChannel((msgs) => + store.dispatch({ type: 'RECEIVED_NEW_TRANSACTION_BATCH', msgs: humps.camelizeKeys(msgs) })) ) } }, render (state, oldState) { - const $transactionsPendingList = $('[data-selector="transactions-pending-list"]') - const $transactionPendingCount = $('[data-selector="transaction-pending-count"]') + const $channelBatching = $('[data-selector="channel-batching-message"]') + const $channelBatchingCount = $('[data-selector="channel-batching-count"]') + const $channelDisconnected = $('[data-selector="channel-disconnected-message"]') + const $transactionsList = $('[data-selector="transactions-list"]') + const $transactionCount = $('[data-selector="transaction-count"]') - if (oldState.transactionCount !== state.transactionCount) $transactionPendingCount.empty().append(numeral(state.transactionCount).format()) - if (oldState.pendingTransactionHashes !== state.pendingTransactionHashes && state.newTransactions.length > 0) { - $('[data-transaction-hash="'+ state.newTransactions[0] + '"]').remove() + if (state.channelDisconnected) $channelDisconnected.show() + if (oldState.transactionCount !== state.transactionCount) $transactionCount.empty().append(numeral(state.transactionCount).format()) + if (state.batchCountAccumulator) { + $channelBatching.show() + $channelBatchingCount[0].innerHTML = numeral(state.batchCountAccumulator).format() + } else { + $channelBatching.hide() + } + if (oldState.newTransactions !== state.newTransactions) { + const newTransactionsToInsert = state.newTransactions.slice(oldState.newTransactions.length) + $transactionsList + .children() + .slice($transactionsList.children().length - newTransactionsToInsert.length, $transactionsList.children().length) + .remove() + prependWithClingBottom($transactionsList, newTransactionsToInsert.reverse().join('')) + + updateAllAges() } } }) diff --git a/apps/block_scout_web/lib/block_scout_web/channels/transaction_channel.ex b/apps/block_scout_web/lib/block_scout_web/channels/transaction_channel.ex index fcd8193a47..1080bde074 100644 --- a/apps/block_scout_web/lib/block_scout_web/channels/transaction_channel.ex +++ b/apps/block_scout_web/lib/block_scout_web/channels/transaction_channel.ex @@ -5,18 +5,41 @@ defmodule BlockScoutWeb.TransactionChannel do use BlockScoutWeb, :channel alias BlockScoutWeb.TransactionView + alias Explorer.Chain.Hash alias Phoenix.View - intercept(["new_transaction"]) + intercept(["new_pending_transaction", "new_transaction"]) def join("transactions:new_transaction", _params, socket) do {:ok, %{}, socket} end + def join("transactions:new_pending_transaction", _params, socket) do + {:ok, %{}, socket} + end + def join("transactions:" <> _transaction_hash, _params, socket) do {:ok, %{}, socket} end + def handle_out("new_pending_transaction", %{transaction: transaction}, socket) do + Gettext.put_locale(BlockScoutWeb.Gettext, socket.assigns.locale) + + rendered_transaction = + View.render_to_string( + TransactionView, + "_pending_tile.html", + transaction: transaction + ) + + push(socket, "new_pending_transaction", %{ + transaction_hash: Hash.to_string(transaction.hash), + transaction_html: rendered_transaction + }) + + {:noreply, socket} + end + def handle_out("new_transaction", %{transaction: transaction}, socket) do Gettext.put_locale(BlockScoutWeb.Gettext, socket.assigns.locale) @@ -28,7 +51,7 @@ defmodule BlockScoutWeb.TransactionChannel do ) push(socket, "new_transaction", %{ - transaction_hash: Explorer.Chain.Hash.to_string(transaction.hash), + transaction_hash: Hash.to_string(transaction.hash), transaction_html: rendered_transaction }) diff --git a/apps/block_scout_web/lib/block_scout_web/notifier.ex b/apps/block_scout_web/lib/block_scout_web/notifier.ex index 023adfb87a..a67012b75e 100644 --- a/apps/block_scout_web/lib/block_scout_web/notifier.ex +++ b/apps/block_scout_web/lib/block_scout_web/notifier.ex @@ -4,7 +4,7 @@ defmodule BlockScoutWeb.Notifier do """ alias Explorer.{Chain, Market, Repo} - alias Explorer.Chain.{Address, InternalTransaction} + alias Explorer.Chain.{Address, InternalTransaction, Transaction} alias Explorer.ExchangeRates.Token alias BlockScoutWeb.Endpoint @@ -49,7 +49,7 @@ defmodule BlockScoutWeb.Notifier do transaction_hashes |> Chain.hashes_to_transactions( necessity_by_association: %{ - :block => :required, + :block => :optional, [created_contract_address: :names] => :optional, [from_address: :names] => :optional, [to_address: :names] => :optional, @@ -93,6 +93,12 @@ defmodule BlockScoutWeb.Notifier do end end + defp broadcast_transaction(%Transaction{block_number: nil} = pending) do + Endpoint.broadcast("transactions:new_pending_transaction", "new_pending_transaction", %{ + transaction: pending + }) + end + defp broadcast_transaction(transaction) do Endpoint.broadcast("transactions:new_transaction", "new_transaction", %{ transaction: transaction diff --git a/apps/block_scout_web/lib/block_scout_web/templates/pending_transaction/index.html.eex b/apps/block_scout_web/lib/block_scout_web/templates/pending_transaction/index.html.eex index 5957b4197a..b79f06f0d1 100644 --- a/apps/block_scout_web/lib/block_scout_web/templates/pending_transaction/index.html.eex +++ b/apps/block_scout_web/lib/block_scout_web/templates/pending_transaction/index.html.eex @@ -43,9 +43,22 @@
+ +

<%= gettext "Transactions" %>

-

<%= gettext("Showing %{count} Pending Transactions", count: @pending_transaction_count) %>

- +

+ <%= gettext("Showing") %> + <%= Cldr.Number.to_string!(@pending_transaction_count, format: "#,###") %> + <%= gettext("Pending Transactions") %> +

<%= for transaction <- @transactions do %> <%= render BlockScoutWeb.TransactionView, "_pending_tile.html", transaction: transaction %> diff --git a/apps/block_scout_web/lib/block_scout_web/templates/transaction/index.html.eex b/apps/block_scout_web/lib/block_scout_web/templates/transaction/index.html.eex index 0d82093f03..6ed329392e 100644 --- a/apps/block_scout_web/lib/block_scout_web/templates/transaction/index.html.eex +++ b/apps/block_scout_web/lib/block_scout_web/templates/transaction/index.html.eex @@ -54,7 +54,11 @@

<%= gettext "Transactions" %>

-

<%= gettext("Showing") %> <%= Cldr.Number.to_string!(@transaction_estimated_count, format: "#,###") %> <%= gettext("Validated Transactions") %>

+

+ <%= gettext("Showing") %> + <%= Cldr.Number.to_string!(@transaction_estimated_count, format: "#,###") %> + <%= gettext("Validated Transactions") %> +

<%= for transaction <- @transactions do %> <%= render BlockScoutWeb.TransactionView, "_tile.html", transaction: transaction %> diff --git a/apps/block_scout_web/test/block_scout_web/channels/transaction_channel_test.exs b/apps/block_scout_web/test/block_scout_web/channels/transaction_channel_test.exs index 69ba3a6493..3335b859d6 100644 --- a/apps/block_scout_web/test/block_scout_web/channels/transaction_channel_test.exs +++ b/apps/block_scout_web/test/block_scout_web/channels/transaction_channel_test.exs @@ -22,4 +22,21 @@ defmodule BlockScoutWeb.TransactionChannelTest do assert false, "Expected message received nothing." end end + + test "subscribed user is notified of new_pending_transaction event" do + topic = "transactions:new_pending_transaction" + @endpoint.subscribe(topic) + + pending = insert(:transaction) + + Notifier.handle_event({:chain_event, :transactions, [pending.hash]}) + + receive do + %Phoenix.Socket.Broadcast{topic: ^topic, event: "new_pending_transaction", payload: payload} -> + assert payload.transaction.hash == pending.hash + after + 5_000 -> + assert false, "Expected message received nothing." + end + end end diff --git a/apps/block_scout_web/test/block_scout_web/features/viewing_transactions_test.exs b/apps/block_scout_web/test/block_scout_web/features/viewing_transactions_test.exs index 79f5215b8f..58d6e6bbd1 100644 --- a/apps/block_scout_web/test/block_scout_web/features/viewing_transactions_test.exs +++ b/apps/block_scout_web/test/block_scout_web/features/viewing_transactions_test.exs @@ -83,6 +83,17 @@ defmodule BlockScoutWeb.ViewingTransactionsTest do |> assert_has(TransactionListPage.transaction_status(pending_contract)) end + test "live update pending transaction", %{session: session} do + session + |> TransactionListPage.visit_page() + |> TransactionListPage.click_pending() + + pending = insert(:transaction) + Notifier.handle_event({:chain_event, :transactions, [pending.hash]}) + + assert_has(session, TransactionListPage.transaction(pending)) + end + test "live remove collated pending transaction", %{pending: pending, session: session} do session |> TransactionListPage.visit_page() diff --git a/apps/explorer/lib/explorer/chain/import.ex b/apps/explorer/lib/explorer/chain/import.ex index c9cb68a0b0..e23a9ab2a6 100644 --- a/apps/explorer/lib/explorer/chain/import.ex +++ b/apps/explorer/lib/explorer/chain/import.ex @@ -165,7 +165,7 @@ defmodule Explorer.Chain.Import do * `:blocks` * `:params` - `list` of params for `Explorer.Chain.Block.changeset/2`. * `:timeout` - the timeout for inserting all blocks. Defaults to `#{@insert_blocks_timeout}` milliseconds. - * `:broacast` - Boolean flag indicating whether or not to broadcast the event. + * `:broadcast` - Boolean flag indicating whether or not to broadcast the event. * `:internal_transactions` * `:params` - `list` of params for `Explorer.Chain.InternalTransaction.changeset/2`. * `:timeout` - the timeout for inserting all internal transactions. Defaults to diff --git a/apps/indexer/lib/indexer/pending_transaction/fetcher.ex b/apps/indexer/lib/indexer/pending_transaction/fetcher.ex index 7d27c1606a..bfb9f46d3c 100644 --- a/apps/indexer/lib/indexer/pending_transaction/fetcher.ex +++ b/apps/indexer/lib/indexer/pending_transaction/fetcher.ex @@ -110,6 +110,7 @@ defmodule Indexer.PendingTransaction.Fetcher do {:ok, _} = Chain.import(%{ addresses: %{params: addresses_params}, + broadcast: true, transactions: %{params: transactions_params, on_conflict: :nothing} }) From 0e08a549d5506c19167015624589cb493cdcf438 Mon Sep 17 00:00:00 2001 From: Stamates Date: Fri, 21 Sep 2018 10:21:18 -0400 Subject: [PATCH 12/34] Improve coveralls coverage and remove unused functions. --- .../controllers/smart_contract_controller.ex | 1 + .../templates/address_contract/index.html.eex | 16 +++--- .../views/address_contract_view.ex | 5 -- .../block_scout_web/views/transaction_view.ex | 4 -- .../address_contract_controller_test.exs | 8 +-- .../smart_contract_controller_test.exs | 56 ++++++++++++++++--- .../views/error_helpers_test.exs | 38 ++++++++----- .../views/layout_view_test.exs | 6 ++ .../views/transaction_view_test.exs | 2 +- 9 files changed, 94 insertions(+), 42 deletions(-) diff --git a/apps/block_scout_web/lib/block_scout_web/controllers/smart_contract_controller.ex b/apps/block_scout_web/lib/block_scout_web/controllers/smart_contract_controller.ex index b9398ca056..70ec6219f3 100644 --- a/apps/block_scout_web/lib/block_scout_web/controllers/smart_contract_controller.ex +++ b/apps/block_scout_web/lib/block_scout_web/controllers/smart_contract_controller.ex @@ -33,6 +33,7 @@ defmodule BlockScoutWeb.SmartContractController do def show(conn, params) do with true <- ajax?(conn), {:ok, address_hash} <- Chain.string_to_address_hash(params["id"]), + {:ok, _address} <- Chain.find_contract_address(address_hash), outputs = Reader.query_function( address_hash, diff --git a/apps/block_scout_web/lib/block_scout_web/templates/address_contract/index.html.eex b/apps/block_scout_web/lib/block_scout_web/templates/address_contract/index.html.eex index 1a62b895f5..f8378f477d 100644 --- a/apps/block_scout_web/lib/block_scout_web/templates/address_contract/index.html.eex +++ b/apps/block_scout_web/lib/block_scout_web/templates/address_contract/index.html.eex @@ -35,12 +35,12 @@ class: "nav-link active") do %> <%= gettext("Code") %> - <%= if smart_contract_verified?(@address) do %> + <%= if BlockScoutWeb.AddressView.smart_contract_verified?(@address) do %> <% end %> <% end %> - <%= if smart_contract_with_read_only_functions?(@address) do %> + <%= if BlockScoutWeb.AddressView.smart_contract_with_read_only_functions?(@address) do %> @@ -25,7 +25,7 @@ <%= link( gettext("Transactions"), class: "dropdown-item active", - to: block_transaction_path(@conn, :index, @conn.params["block_id"]) + to: block_transaction_path(@conn, :index, @conn.params["block_hash_or_number"]) ) %> diff --git a/apps/block_scout_web/test/block_scout_web/controllers/block_transaction_controller_test.exs b/apps/block_scout_web/test/block_scout_web/controllers/block_transaction_controller_test.exs index 10e3cbfb20..0c1c41c70c 100644 --- a/apps/block_scout_web/test/block_scout_web/controllers/block_transaction_controller_test.exs +++ b/apps/block_scout_web/test/block_scout_web/controllers/block_transaction_controller_test.exs @@ -35,6 +35,50 @@ defmodule BlockScoutWeb.BlockTransactionControllerTest do assert 2 == Enum.count(conn.assigns.transactions) end + test "does not return transactions for non-consensus block number", %{conn: conn} do + block = insert(:block, consensus: false) + + :transaction + |> insert() + |> with_block(block) + + conn = get(conn, block_transaction_path(conn, :index, block.number)) + + assert html_response(conn, 404) + end + + test "returns transactions for consensus block hash", %{conn: conn} do + block = insert(:block, consensus: true) + + :transaction + |> insert() + |> with_block(block) + + conn = get(conn, block_transaction_path(conn, :index, block.hash)) + + assert html_response(conn, 200) + assert Enum.count(conn.assigns.transactions) == 1 + end + + test "returns transactions for non-consensus block hash", %{conn: conn} do + block = insert(:block, consensus: false) + + :transaction + |> insert() + |> with_block(block) + + conn = get(conn, block_transaction_path(conn, :index, block.hash)) + + assert html_response(conn, 200) + assert Enum.count(conn.assigns.transactions) == 1 + end + + test "does not return transactions for invalid block hash", %{conn: conn} do + conn = get(conn, block_transaction_path(conn, :index, "0x0")) + + assert html_response(conn, 404) + end + test "does not return unrelated transactions", %{conn: conn} do insert(:transaction) block = insert(:block) diff --git a/apps/explorer/lib/explorer/chain.ex b/apps/explorer/lib/explorer/chain.ex index acb65edb12..88b4db01ed 100644 --- a/apps/explorer/lib/explorer/chain.ex +++ b/apps/explorer/lib/explorer/chain.ex @@ -605,11 +605,20 @@ defmodule Explorer.Chain do iex> Explorer.Chain.hash_to_block(hash) {:error, :not_found} + ## Options + + * `:necessity_by_association` - use to load `t:association/0` as `:required` or `:optional`. If an association is + `:required`, and the `t:Explorer.Chain.Block.t/0` has no associated record for that association, then the + `t:Explorer.Chain.Block.t/0` will not be included in the page `entries`. + """ - @spec hash_to_block(Hash.Full.t()) :: {:ok, Block.t()} | {:error, :not_found} - def hash_to_block(%Hash{byte_count: unquote(Hash.Full.byte_count())} = hash) do + @spec hash_to_block(Hash.Full.t(), [necessity_by_association_option]) :: {:ok, Block.t()} | {:error, :not_found} + def hash_to_block(%Hash{byte_count: unquote(Hash.Full.byte_count())} = hash, options \\ []) when is_list(options) do + necessity_by_association = Keyword.get(options, :necessity_by_association, %{}) + Block |> where(hash: ^hash) + |> join_associations(necessity_by_association) |> Repo.one() |> case do nil ->