diff --git a/CHANGELOG.md b/CHANGELOG.md index cfbb7f88b7..271a9add39 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,16 +1,41 @@ ## Current ### Features -- [#2366](https://github.com/poanetwork/blockscout/pull/2366) - paginate eth logs + +### Fixes +- [#2425](https://github.com/poanetwork/blockscout/pull/2425) - Force to show address view for checksummed address even if it is not in DB + +### Chore +- [#2402](https://github.com/poanetwork/blockscout/pull/2402) - bump otp version to 22.0 +- [#2450](https://github.com/poanetwork/blockscout/pull/2450) - Fix clearance of logs and node_modules folders in clearing script +- [#2434](https://github.com/poanetwork/blockscout/pull/2434) - get rid of timex warnings + + +## 2.0.2-beta + +### Features +- [#2412](https://github.com/poanetwork/blockscout/pull/2412) - dark theme +- [#2399](https://github.com/poanetwork/blockscout/pull/2399) - decode verified smart contract's logs +- [#2391](https://github.com/poanetwork/blockscout/pull/2391) - Controllers Improvements - [#2379](https://github.com/poanetwork/blockscout/pull/2379) - Disable network selector when is empty +- [#2374](https://github.com/poanetwork/blockscout/pull/2374) - decode constructor arguments for verified smart contracts +- [#2366](https://github.com/poanetwork/blockscout/pull/2366) - paginate eth logs - [#2360](https://github.com/poanetwork/blockscout/pull/2360) - add default evm version to smart contract verification - [#2352](https://github.com/poanetwork/blockscout/pull/2352) - Fetch rewards in parallel with transactions - [#2294](https://github.com/poanetwork/blockscout/pull/2294) - add healthy block period checking endpoint +- [#2324](https://github.com/poanetwork/blockscout/pull/2324) - set timeout for loading message on the main page ### Fixes +- [#2421](https://github.com/poanetwork/blockscout/pull/2421) - Fix hiding of loader for txs on the main page +- [#2420](https://github.com/poanetwork/blockscout/pull/2420) - fetch data from cache in healthy endpoint +- [#2416](https://github.com/poanetwork/blockscout/pull/2416) - Fix "page not found" handling in the router +- [#2413](https://github.com/poanetwork/blockscout/pull/2413) - remove outer tables for decoded data +- [#2410](https://github.com/poanetwork/blockscout/pull/2410) - preload smart contract for logs decoding +- [#2405](https://github.com/poanetwork/blockscout/pull/2405) - added templates for table loader and tile loader - [#2398](https://github.com/poanetwork/blockscout/pull/2398) - show only one decoded candidate -- [#2395](https://github.com/poanetwork/blockscout/pull/2395) - new block loading animation - [#2389](https://github.com/poanetwork/blockscout/pull/2389) - Reduce Lodash lib size (86% of lib methods are not used) +- [#2388](https://github.com/poanetwork/blockscout/pull/2388) - add create2 support to geth's js tracer +- [#2387](https://github.com/poanetwork/blockscout/pull/2387) - fix not existing keys in transaction json rpc - [#2378](https://github.com/poanetwork/blockscout/pull/2378) - Page performance: exclude moment.js localization files except EN, remove unused css - [#2368](https://github.com/poanetwork/blockscout/pull/2368) - add two columns of smart contract info - [#2375](https://github.com/poanetwork/blockscout/pull/2375) - Update created_contract_code_indexed_at on transaction import conflict @@ -28,7 +53,9 @@ - [#2326](https://github.com/poanetwork/blockscout/pull/2326) - fix nested constructor arguments ### Chore -- [#2402](https://github.com/poanetwork/blockscout/pull/2402) - bump otp version to 22.0 +- [#2422](https://github.com/poanetwork/blockscout/pull/2422) - check if address_id is binary in token_transfers_csv endpoint +- [#2418](https://github.com/poanetwork/blockscout/pull/2418) - Remove parentheses in market cap percentage +- [#2401](https://github.com/poanetwork/blockscout/pull/2401) - add ENV vars to manage updating period of average block time and market history cache - [#2363](https://github.com/poanetwork/blockscout/pull/2363) - add parameters example for eth rpc - [#2342](https://github.com/poanetwork/blockscout/pull/2342) - Upgrade Postgres image version in Docker setup - [#2325](https://github.com/poanetwork/blockscout/pull/2325) - Reduce function input to address' hash only where possible diff --git a/apps/block_scout_web/assets/css/app.scss b/apps/block_scout_web/assets/css/app.scss index cf79ee46e8..e91df91740 100644 --- a/apps/block_scout_web/assets/css/app.scss +++ b/apps/block_scout_web/assets/css/app.scss @@ -128,6 +128,7 @@ $fa-font-path: "~@fortawesome/fontawesome-free/webfonts"; @import "components/new_smart_contract"; @import "components/radio_big"; @import "components/btn_no_border"; +@import "theme/dark-theme"; :export { dashboardBannerChartAxisFontColor: $dashboard-banner-chart-axis-font-color; @@ -135,4 +136,6 @@ $fa-font-path: "~@fortawesome/fontawesome-free/webfonts"; dashboardLineColorPrice: $dashboard-line-color-price; primary: $primary; secondary: $secondary; + darkprimary: $dark-primary; + darksecondary: $dark-secondary; } diff --git a/apps/block_scout_web/assets/css/components/_navbar.scss b/apps/block_scout_web/assets/css/components/_navbar.scss index 48c6c50f02..0d892b25ca 100644 --- a/apps/block_scout_web/assets/css/components/_navbar.scss +++ b/apps/block_scout_web/assets/css/components/_navbar.scss @@ -252,4 +252,10 @@ $navbar-logo-width: auto !default; @include media-breakpoint-up(xl) { padding-right: 0; } +} + +.nav-item-networks { + .topnav-nav-link { + transition: none !important; + } } \ No newline at end of file diff --git a/apps/block_scout_web/assets/css/components/_stakes_table.scss b/apps/block_scout_web/assets/css/components/_stakes_table.scss index 79cdc20b38..1831dc4d5b 100644 --- a/apps/block_scout_web/assets/css/components/_stakes_table.scss +++ b/apps/block_scout_web/assets/css/components/_stakes_table.scss @@ -26,6 +26,43 @@ $stakes-table-cell-separation: 25px !default; } } +// Loader +.table-content-loader { + display: inline-block; + height: 24px; + width: 100%; + border-radius: 4px; + background-color: #f5f6fa; + overflow: hidden; + position: relative; + &:before { + width: inherit; + height: inherit; + content: ''; + position: absolute; + background: linear-gradient(to right, #f5f6fa 2%, #eee 18%, #f5f6fa 33%); + animation-duration: 1.7s; + animation-fill-mode: forwards; + animation-iteration-count: infinite; + animation-timing-function: linear; + animation-name: placeholderAnimate; + background-size: 1300px; + } +} + +@keyframes placeholderAnimate { + 0%{ background-position: -650px 0; } + 100% { background-position: 650px 0; } +} + +.table-content-pseudo { + td { + &:last-child { + padding-right: 24px !important; + } + } +} + .stakes-table { min-width: fit-content; width: 100%; diff --git a/apps/block_scout_web/assets/css/components/_tile.scss b/apps/block_scout_web/assets/css/components/_tile.scss index dbfd117875..e621e4fd6d 100644 --- a/apps/block_scout_web/assets/css/components/_tile.scss +++ b/apps/block_scout_web/assets/css/components/_tile.scss @@ -340,6 +340,9 @@ $tile-body-a-color: #5959d8 !default; padding-right: 6px; } } + .tile-type-block { + overflow: hidden; + } .row { @include media-breakpoint-down(lg) { margin-left: -6px; @@ -349,6 +352,52 @@ $tile-body-a-color: #5959d8 !default; } } +// Loader +.tile-type-loading { + background-color: #fff; + padding-top: 30px; + padding-bottom: 28px; +} + +.tile-loader { + display: inline-block; + height: 20px; + width: 100%; + border-radius: 4px; + background-color: #f5f6fa; + overflow: hidden; + position: relative; + &:before { + width: inherit; + height: inherit; + content: ''; + position: absolute; + background: linear-gradient(to right, #f5f6fa 2%, #eee 18%, #f5f6fa 33%); + animation-duration: 1.7s; + animation-fill-mode: forwards; + animation-iteration-count: infinite; + animation-timing-function: linear; + animation-name: tilePlaceholderAnimate; + background-size: 1300px; + } +} + +.tile-label-loader { + height: 14px; + width: 80px; +} + +.tile-address-loader { + & + .tile-address-loader { + margin-top: 6px; + } +} + +@keyframes tilePlaceholderAnimate { + 0%{ background-position: -650px 0; } + 100% { background-position: 650px 0; } +} + // Loading Animation @keyframes playBlockLoadingAnimation { @@ -512,4 +561,4 @@ $cube-quantity: 5; 100% { transform: scale(0); } -} \ No newline at end of file +} diff --git a/apps/block_scout_web/assets/css/theme/_base_variables.scss b/apps/block_scout_web/assets/css/theme/_base_variables.scss index 9f1b82c887..2238327bd4 100644 --- a/apps/block_scout_web/assets/css/theme/_base_variables.scss +++ b/apps/block_scout_web/assets/css/theme/_base_variables.scss @@ -70,7 +70,10 @@ $colors: map-merge( ); $primary: $indigo !default; +$dark-primary: #9b62ff !default; +$dark-primary-alternate: #9b62ff !default; $secondary: #7dd79f !default; +$dark-secondary: #87e1a9 !default; $tertiary: $purple !default; $success: $green !default; $info: $cyan !default; diff --git a/apps/block_scout_web/assets/css/theme/_dai_variables.scss b/apps/block_scout_web/assets/css/theme/_dai_variables.scss index 50cbcfa290..0c09660240 100644 --- a/apps/block_scout_web/assets/css/theme/_dai_variables.scss +++ b/apps/block_scout_web/assets/css/theme/_dai_variables.scss @@ -62,4 +62,9 @@ $card-tab-active: $secondary; // Badges $badge-neutral-color: #20446e; $badge-neutral-background-color: rgba(#20446e, .1); -$api-text-monospace-color: #20446e; \ No newline at end of file +$api-text-monospace-color: #20446e; + +// Dark theme +$dark-primary: #15bba6; +$dark-secondary: #93d7ff; +$dark-primary-alternate: #15bba6; \ No newline at end of file diff --git a/apps/block_scout_web/assets/css/theme/_dark-theme.scss b/apps/block_scout_web/assets/css/theme/_dark-theme.scss new file mode 100644 index 0000000000..e648e01982 --- /dev/null +++ b/apps/block_scout_web/assets/css/theme/_dark-theme.scss @@ -0,0 +1,470 @@ +$body-dark: #1c1d31; // body background +$dark-bg: #22223a; // hero shade +$dark-light-bg: #282945; // pills bg shade +$dark-light: #313355; // tile light top share +$labels-dark: #8a8dba; // header nav, labels + +// Switcher +.dark-mode-changer { + display: inline-flex; + align-items: center; + justify-content: center; + width: 36px; + height: 36px; + background: transparent; + border: none; + cursor: pointer; + margin-right: 5px; + outline: none !important; + box-shadow: none !important; + transition: .2s ease-in; + &:hover { + opacity: .8; + } + svg path { + fill: #828ba0; + } + &--dark { + svg path { + fill: $dark-primary; + } + } +} + +.dark-theme-applied { + color: #fff; + + // navbar + .navbar.navbar-primary { + background-color: $dark-light-bg; + } + .navbar-brand .navbar-logo { + filter: brightness(0) invert(1); + } + .navbar.navbar-primary .navbar-nav .nav-link { + color: $labels-dark; + .nav-link-icon { + svg path { + fill: $labels-dark; + } + } + &.active, &:hover { + .nav-link-icon { + svg path { + fill: $dark-primary; + } + } + &:before { + background-color: $dark-primary; + } + } + } + .navbar.navbar-primary .form-control { + background-color: $dark-bg; + border-color: $dark-bg; + color: #fff; + &::placeholder { + color: $labels-dark; + } + } + .navbar.navbar-primary .navbar-toggler .navbar-toggler-icon { + filter: invert(1); + } + + // footer + .footer { + background: $dark-light-bg; + color: $labels-dark; + } + .footer-social-icon, + .footer-link { + color: $labels-dark; + } + .footer-social-icon:hover, + .footer-link:hover { + color: #fff; + } + .footer-list ul li::before { + background-color: $dark-secondary; + } + + // hero stats + + .layout-container .dashboard-banner-container { + background-image: none; + background-color: $dark-bg; + } + .dashboard-banner-network-plain-container, + .dashboard-banner-network-plain-container::after { + background-color: $dark-light-bg; + } + .dashboard-banner-network-stats-label, + .dashboard-banner-chart-legend .dashboard-banner-chart-legend-label { + color: $labels-dark; + } + .dashboard-banner-chart-legend .dashboard-banner-chart-legend-item:nth-child(1)::before { + background-color: $dark-primary; + } + .dashboard-banner-network-stats-item::before { + background-color: $dark-secondary; + } + .dashboard-banner-chart-legend .dashboard-banner-chart-legend-item:nth-child(2)::before { + background-color: $dark-secondary; + } + + // main container, layout, cards + .layout-container main { + background-color: $body-dark; + } + + .card { + background-color: $dark-light-bg; + box-shadow: 0 0 30px 0 rgba(23, 24, 41, 0.5); + } + + .card-header { + border-bottom-color: darken($labels-dark, 30); + } + + .address-detail-hash-title { + color: #fff; + } + + .card-tabs { + border-bottom-color: darken($labels-dark, 30); + } + + .card-tab { + background-color: transparent; + &:hover:not(.active) { + background-color: rgba($dark-primary, .15); + color: $dark-primary; + } + &.active { + background-color: $dark-primary-alternate; + color: #fff; + } + } + + .card-background-1 { + background-color: $dark-primary-alternate; + } + + // Components + a { + color: $dark-primary; + } + + .tile { + border-top-color: $dark-light; + border-bottom-color: $dark-light; + border-right-color: $dark-light; + background-color: $dark-light; + color: $labels-dark; + &:not([class^="tile tile-type"]) { + border-left-color: $dark-light; + } + &.tile-type-coin-balance { + border-left-color: $dark-light; + } + .tile-title { + color: #fff; + } + .tile-transaction-type-block { + background-color: transparent; + } + } + .tile-bottom-contents { + background-color: $dark-bg; + } + a.tile-title { + color: #fff !important; + } + .tile.tile-type-block .tile-transaction-type-block a { + color: #fff; + } + .fade-up-blocks-chain .tile-type-block-animation { + background-color: $dark-light; + border-top-color: $dark-light; + border-right-color: $dark-light; + border-bottom-color: $dark-light; + } + .fade-up-blocks-chain .tile-type-block-animation:after { + background-color: $dark-light; + } + .cube-animation-title { + color: $labels-dark; + } + .tile .tile-body a, + .tile span[data-address-hash] { color: $dark-primary; } + .fade-up-blocks-chain .tile-type-block-animation .tile-type-line-up { + background-color: $dark-primary; + } + .tile.tile-type-block { + border-left-color: $dark-primary + } + .tile.tile-type-block .tile-status-label { + color: $dark-primary; + } + .tile.tile-type-block .tile-transaction-type-block { + border-right-color: $dark-primary; + border-top-color: $dark-primary; + border-bottom-color: $dark-primary; + } + .tile .progress { + background-color: rgba(#fff, .2); + } + .tile .progress .progress-bar { + background-color: $dark-primary; + } + .tile .tile-title-lg:not([data-balance-change-sign]) { + color: $dark-primary; + } + + // btns + + .btn-line { + background-color: transparent; + border-color: $dark-primary; + color: $dark-primary; + &:hover { + border-color: $dark-primary; + background-color: $dark-primary; + color: #fff; + } + } + + .btn-copy-icon, .btn-qr-icon { + border-color: $dark-primary; + path { + fill: $dark-primary; + } + &:hover { + background-color: $dark-primary; + path { + fill: #fff; + } + } + } + + // pagination + .pagination-container .pagination .page-link { + color: $labels-dark; + border-color: $dark-light; + background-color: $dark-light; + &:not(.no-hover):hover { + color: #fff; + background-color: $dark-primary; + path { + fill: #fff; + } + } + &[disabled] { + color: $labels-dark; + border-color: $dark-light; + background-color: $dark-light; + } + } + + // dropdown + .dropdown-menu { + background-color: $dark-light; + border-left-color: $dark-light; + border-right-color: $dark-light; + border-bottom-color: $dark-light; + } + + .dropdown-item { + color: #fff; + &:hover { + background-color: rgba(#fff, .1); + } + } + .dropdown-item.active { + background-color: $dark-primary; + } + .btn-dropdown-line { + background-color: $dark-light; + border-color: $dark-light; + color: $labels-dark; + } + + // table + .stakes-table-th { + background-color: $dark-light; + color: $labels-dark; + } + .stakes-td { + border-bottom-color: darken($labels-dark, 30); + } + .table th, .table td { + border-top-color: darken($labels-dark, 30); + } + hr { + border-top-color: darken($labels-dark, 30); + } + + // api's + .api-anchors-list { + background-color: $dark-light; + } + .api-doc-list-item { + border-bottom-color: darken($labels-dark, 30); + } + .card-subtitle, + .api-anchors-list-item-title, + .api-doc-list-item-title { + color: #fff; + } + .api-text-monospace { + color: $dark-primary; + } + .api-text-monospace-background { + background-color: rgba($dark-primary, .15); + } + .badge.badge-neutral { + background-color: rgba($dark-primary, .15); + color: $dark-primary; + } + + // download csv button + .download-all-transactions .download-all-transactions-link svg path { + fill: $dark-primary; + } + + //tooltips + .tooltip .arrow:before { + border-top-color: $dark-primary; + border-bottom-color: $dark-primary; + } + .tooltip > .tooltip-inner {background-color: $dark-primary;} + + //network select + .network-selector-overlay { + background-color: rgba($dark-bg, .9); + } + .network-selector { + background-color: $dark-light-bg; + } + .network-selector-title { + color: #fff; + } + .network-selector-text { + color: $labels-dark; + } + .network-selector-close path { + fill: #fff; + } + .network-selector-search-container { + background-color: $dark-light; + } + .network-selector-search-container path { + fill: $labels-dark; + } + .network-selector-search-input { + color: #fff !important; + &::placeholder { + color: $labels-dark; + } + } + .network-selector-tab { + color: $labels-dark; + &:hover, &.active { + color: #fff; + } + &.active { + &:after { + background-color: $dark-primary; + } + } + } + .network-selector-item, + .network-selector-tabs-container { + border-bottom-color: darken($labels-dark, 30); + } + .network-selector-item-title { + color: #fff; + } + .network-selector-item-type { + color: $labels-dark; + } + .radio .radio-icon { + border-color: $labels-dark + } + .network-selector-item-url:hover .network-selector-item-type { + color: #fff; + } + + //coin dropdown + .token-balance-dropdown.dropdown-menu { + border-color: $dark-light !important; + box-shadow: 0 0 30px 0 rgba(23, 24, 41, 0.5) !important; + } + .token-balance-dropdown .dropdown-search-icon path { + fill: $labels-dark; + } + .token-balance-dropdown .dropdown-search-field { + background-color: $dark-light; + border-color: $dark-light; + color: #fff; + &::placeholder { + color: $labels-dark; + } + } + .token-balance-dropdown[aria-labelledby="dropdown-tokens"] .dropdown-items .dropdown-item:hover { + color: #fff !important; + } + .dropdown-header { + color: $labels-dark; + } + .border-bottom { + border-bottom-color: darken($labels-dark, 30) !important; + } + + // coin balance history chart + .chartjs-render-monitor[data-chart="coinBalanceHistoryChart"] { + filter: brightness(0) invert(1) !important; + } + + // logs search + .logs-search-input, .logs-search-btn, .logs-search-btn-cancel { + background-color: $dark-light; + border-color: $dark-light; + color: #fff; + } + + .logs-search-btn { + color: $labels-dark; + } + + .logs-search-btn { + &:hover { + background-color: $dark-primary; + color: #fff; + } + } + + .logs-search-input { + &::placeholder { + color: $labels-dark; + } + } + + // code + pre { + color: #fff; + } + + // info allert + .alert-info { + color: $labels-dark; + background-color: $dark-light; + border-color: $dark-light; + } + + // dark text + .text-dark { + color: #fff; + } + +} \ No newline at end of file diff --git a/apps/block_scout_web/assets/css/theme/_ethereum_classic_variables.scss b/apps/block_scout_web/assets/css/theme/_ethereum_classic_variables.scss index 68feab4dfc..dff677d7cc 100644 --- a/apps/block_scout_web/assets/css/theme/_ethereum_classic_variables.scss +++ b/apps/block_scout_web/assets/css/theme/_ethereum_classic_variables.scss @@ -74,4 +74,9 @@ $card-tab-active: $tertiary; // Badges $badge-neutral-color: $tertiary; $badge-neutral-background-color: rgba($tertiary, .1); -$api-text-monospace-color: $tertiary; \ No newline at end of file +$api-text-monospace-color: $tertiary; + +// Dark theme +$dark-primary: #8588ff; +$dark-secondary: #4ad7a7; +$dark-primary-alternate: #5b5ed8; \ No newline at end of file diff --git a/apps/block_scout_web/assets/css/theme/_ethereum_variables.scss b/apps/block_scout_web/assets/css/theme/_ethereum_variables.scss index 0755d3e4b4..0b5cac0c43 100644 --- a/apps/block_scout_web/assets/css/theme/_ethereum_variables.scss +++ b/apps/block_scout_web/assets/css/theme/_ethereum_variables.scss @@ -56,4 +56,18 @@ $card-tab-active: $secondary; $dashboard-banner-gradient-end ); } +} + +// Dark theme +$dark-primary: #49a2ee; +$dark-secondary: #4ad7a7; +$dark-primary-alternate: #49a2ee; + +.dark-theme-applied { + .dashboard-banner-chart-legend .dashboard-banner-chart-legend-item:nth-child(1)::before { + background-color: $dark-primary !important; + } + .dashboard-banner-chart-legend .dashboard-banner-chart-legend-item:nth-child(2)::before { + background-color: $dark-secondary !important; + } } \ No newline at end of file diff --git a/apps/block_scout_web/assets/css/theme/_goerli_variables.scss b/apps/block_scout_web/assets/css/theme/_goerli_variables.scss index 7900dd4c3b..04f953b477 100644 --- a/apps/block_scout_web/assets/css/theme/_goerli_variables.scss +++ b/apps/block_scout_web/assets/css/theme/_goerli_variables.scss @@ -78,3 +78,8 @@ $card-tab-active: $sub-accent-color; $badge-neutral-color: $sub-accent-color; $badge-neutral-background-color: rgba($sub-accent-color, .1); $api-text-monospace-color: $sub-accent-color; + +// Dark theme +$dark-primary: #e1995a; +$dark-secondary: #aeaeae; +$dark-primary-alternate: #e1995a; \ No newline at end of file diff --git a/apps/block_scout_web/assets/css/theme/_kovan_variables.scss b/apps/block_scout_web/assets/css/theme/_kovan_variables.scss index 351f046726..a4edc629d0 100644 --- a/apps/block_scout_web/assets/css/theme/_kovan_variables.scss +++ b/apps/block_scout_web/assets/css/theme/_kovan_variables.scss @@ -74,4 +74,9 @@ $badge-success-color: #15bba6; $badge-success-background-color: rgba(#15bba6, .1); $badge-neutral-color: $tertiary; $badge-neutral-background-color: rgba($tertiary, .1); -$api-text-monospace-color: $tertiary; \ No newline at end of file +$api-text-monospace-color: $tertiary; + +// Dark theme +$dark-primary: #42e2d7; +$dark-secondary: #1f857f; +$dark-primary-alternate: #1f857f; \ No newline at end of file diff --git a/apps/block_scout_web/assets/css/theme/_lukso_variables.scss b/apps/block_scout_web/assets/css/theme/_lukso_variables.scss index 65f9a73b5f..a7b608bfa8 100644 --- a/apps/block_scout_web/assets/css/theme/_lukso_variables.scss +++ b/apps/block_scout_web/assets/css/theme/_lukso_variables.scss @@ -151,3 +151,20 @@ $dashboard-banner-network-plain-container-height: 150px; $badge-neutral-color: $tertiary; $badge-neutral-background-color: rgba($tertiary, .1); $api-text-monospace-color: $tertiary; + +// Dark theme +$dark-primary: #fdcec4; +$dark-secondary: #a96c55; +$dark-primary-alternate: #a96c55; + +.dark-theme-applied { + .dashboard-banner-network-stats-value { + color: $dark-primary !important; + } + .layout-container .dashboard-banner-container { + background-color: #282945 !important; + } + .dashboard-banner-network-plain-container::after { + box-shadow: none !important; + } +} diff --git a/apps/block_scout_web/assets/css/theme/_neutral_variables.scss b/apps/block_scout_web/assets/css/theme/_neutral_variables.scss index 4033934dd6..120a11c222 100644 --- a/apps/block_scout_web/assets/css/theme/_neutral_variables.scss +++ b/apps/block_scout_web/assets/css/theme/_neutral_variables.scss @@ -71,4 +71,9 @@ $api-text-monospace-color: $primary; .dropdown-items .dropdown-item:hover { color: $primary !important; } -} \ No newline at end of file +} + +// Dark theme +$dark-primary: #9b62ff; +$dark-secondary: #87e1a9; +$dark-primary-alternate: #7e50d0; \ No newline at end of file diff --git a/apps/block_scout_web/assets/css/theme/_poa_variables.scss b/apps/block_scout_web/assets/css/theme/_poa_variables.scss index 4033934dd6..120a11c222 100644 --- a/apps/block_scout_web/assets/css/theme/_poa_variables.scss +++ b/apps/block_scout_web/assets/css/theme/_poa_variables.scss @@ -71,4 +71,9 @@ $api-text-monospace-color: $primary; .dropdown-items .dropdown-item:hover { color: $primary !important; } -} \ No newline at end of file +} + +// Dark theme +$dark-primary: #9b62ff; +$dark-secondary: #87e1a9; +$dark-primary-alternate: #7e50d0; \ No newline at end of file diff --git a/apps/block_scout_web/assets/css/theme/_rinkeby_variables.scss b/apps/block_scout_web/assets/css/theme/_rinkeby_variables.scss index 1e62ea6d69..4fa700c50e 100644 --- a/apps/block_scout_web/assets/css/theme/_rinkeby_variables.scss +++ b/apps/block_scout_web/assets/css/theme/_rinkeby_variables.scss @@ -57,3 +57,8 @@ $card-tab-active: $secondary; ); } } + +// Dark theme +$dark-primary: #38a9f5; +$dark-secondary: #76f1ff; +$dark-primary-alternate: #38a9f5; \ No newline at end of file diff --git a/apps/block_scout_web/assets/css/theme/_ropsten_variables.scss b/apps/block_scout_web/assets/css/theme/_ropsten_variables.scss index 1e62ea6d69..4fa700c50e 100644 --- a/apps/block_scout_web/assets/css/theme/_ropsten_variables.scss +++ b/apps/block_scout_web/assets/css/theme/_ropsten_variables.scss @@ -57,3 +57,8 @@ $card-tab-active: $secondary; ); } } + +// Dark theme +$dark-primary: #38a9f5; +$dark-secondary: #76f1ff; +$dark-primary-alternate: #38a9f5; \ No newline at end of file diff --git a/apps/block_scout_web/assets/css/theme/_rsk_variables.scss b/apps/block_scout_web/assets/css/theme/_rsk_variables.scss index 76029e1a34..d33996a89e 100644 --- a/apps/block_scout_web/assets/css/theme/_rsk_variables.scss +++ b/apps/block_scout_web/assets/css/theme/_rsk_variables.scss @@ -65,3 +65,8 @@ $card-tab-active: $secondary; // Badges $badge-neutral-color: #1a323b; $badge-neutral-background-color: rgba(#1a323b, .1); + +// Dark theme +$dark-primary: #38c5a4; +$dark-secondary: #e39a54; +$dark-primary-alternate: #30ab8d; diff --git a/apps/block_scout_web/assets/css/theme/_sokol_variables.scss b/apps/block_scout_web/assets/css/theme/_sokol_variables.scss index 444cdff178..8d479f397d 100644 --- a/apps/block_scout_web/assets/css/theme/_sokol_variables.scss +++ b/apps/block_scout_web/assets/css/theme/_sokol_variables.scss @@ -72,4 +72,9 @@ $card-tab-active: $sub-accent-color; // Badges $badge-neutral-color: $tertiary; -$badge-neutral-background-color: rgba($tertiary, .1); \ No newline at end of file +$badge-neutral-background-color: rgba($tertiary, .1); + +// Dark theme +$dark-primary: #40bfb2; +$dark-secondary: #25c9ff; +$dark-primary-alternate: #1c9f90; \ No newline at end of file diff --git a/apps/block_scout_web/assets/js/app.js b/apps/block_scout_web/assets/js/app.js index 25de7b2688..89059dd306 100644 --- a/apps/block_scout_web/assets/js/app.js +++ b/apps/block_scout_web/assets/js/app.js @@ -35,6 +35,7 @@ import './pages/favorites' import './pages/network-search' import './pages/layout' import './pages/verification_form' +import './pages/dark-mode-switcher' import './pages/admin/tasks.js' diff --git a/apps/block_scout_web/assets/js/lib/market_history_chart.js b/apps/block_scout_web/assets/js/lib/market_history_chart.js index 615f888d8a..098faac0a8 100644 --- a/apps/block_scout_web/assets/js/lib/market_history_chart.js +++ b/apps/block_scout_web/assets/js/lib/market_history_chart.js @@ -4,6 +4,7 @@ import humps from 'humps' import numeral from 'numeral' import { formatUsdValue } from '../lib/currency' import sassVariables from '../../css/app.scss' +import { showLoader } from '../lib/utils' const config = { type: 'line', @@ -87,6 +88,17 @@ function getMarketCapData (marketHistoryData, availableSupply) { } } +// colors for light and dark theme +var priceLineColor +var mcapLineColor +if (localStorage.getItem('current-color-mode') === 'dark') { + priceLineColor = sassVariables.darkprimary + mcapLineColor = sassVariables.darksecondary +} else { + priceLineColor = sassVariables.dashboardLineColorPrice + mcapLineColor = sassVariables.dashboardLineColorMarket +} + class MarketHistoryChart { constructor (el, availableSupply, marketHistoryData) { this.price = { @@ -95,8 +107,8 @@ class MarketHistoryChart { data: getPriceData(marketHistoryData), fill: false, pointRadius: 0, - backgroundColor: sassVariables.dashboardLineColorPrice, - borderColor: sassVariables.dashboardLineColorPrice, + backgroundColor: priceLineColor, + borderColor: priceLineColor, lineTension: 0 } this.marketCap = { @@ -105,8 +117,8 @@ class MarketHistoryChart { data: getMarketCapData(marketHistoryData, availableSupply), fill: false, pointRadius: 0, - backgroundColor: sassVariables.dashboardLineColorMarket, - borderColor: sassVariables.dashboardLineColorMarket, + backgroundColor: mcapLineColor, + borderColor: mcapLineColor, lineTension: 0 } this.availableSupply = availableSupply @@ -129,6 +141,10 @@ class MarketHistoryChart { export function createMarketHistoryChart (el) { const dataPath = el.dataset.market_history_chart_path const $chartLoading = $('[data-chart-loading-message]') + + const isTimeout = true + const timeoutID = showLoader(isTimeout, $chartLoading) + const $chartError = $('[data-chart-error-message]') const chart = new MarketHistoryChart(el, 0, []) $.getJSON(dataPath, {type: 'JSON'}) @@ -143,6 +159,7 @@ export function createMarketHistoryChart (el) { }) .always(() => { $chartLoading.hide() + clearTimeout(timeoutID) }) return chart } diff --git a/apps/block_scout_web/assets/js/lib/utils.js b/apps/block_scout_web/assets/js/lib/utils.js index e275580812..e00d06ec1b 100644 --- a/apps/block_scout_web/assets/js/lib/utils.js +++ b/apps/block_scout_web/assets/js/lib/utils.js @@ -11,3 +11,16 @@ export function batchChannel (func) { debouncedFunc() } } + +export function showLoader (isTimeout, loader) { + if (isTimeout) { + const timeout = setTimeout(function () { + loader.removeAttr('hidden') + loader.show() + }, 1000) + return timeout + } else { + loader.hide() + return null + } +} diff --git a/apps/block_scout_web/assets/js/pages/chain.js b/apps/block_scout_web/assets/js/pages/chain.js index 154c73e455..df89d92f36 100644 --- a/apps/block_scout_web/assets/js/pages/chain.js +++ b/apps/block_scout_web/assets/js/pages/chain.js @@ -9,7 +9,7 @@ import numeral from 'numeral' import socket from '../socket' import { exchangeRateChannel, formatUsdValue } from '../lib/currency' import { createStore, connectElements } from '../lib/redux_helpers.js' -import { batchChannel } from '../lib/utils' +import { batchChannel, showLoader } from '../lib/utils' import listMorph from '../lib/list_morph' import { createMarketHistoryChart } from '../lib/market_history_chart' @@ -214,11 +214,7 @@ const elements = { }, '[data-selector="chain-block-list"] [data-selector="loading-message"]': { render ($el, state, oldState) { - if (state.blocksLoading) { - $el.show() - } else { - $el.hide() - } + showLoader(state.blocksLoading, $el) } }, '[data-selector="transactions-list"] [data-selector="error-message"]': { @@ -228,7 +224,7 @@ const elements = { }, '[data-selector="transactions-list"] [data-selector="loading-message"]': { render ($el, state, oldState) { - $el.toggle(state.transactionsLoading) + showLoader(state.transactionsLoading, $el) } }, '[data-selector="transactions-list"]': { diff --git a/apps/block_scout_web/assets/js/pages/dark-mode-switcher.js b/apps/block_scout_web/assets/js/pages/dark-mode-switcher.js new file mode 100644 index 0000000000..e9e0bdc524 --- /dev/null +++ b/apps/block_scout_web/assets/js/pages/dark-mode-switcher.js @@ -0,0 +1,11 @@ +import $ from 'jquery' + +$('.dark-mode-changer').click(function () { + if (localStorage.getItem('current-color-mode') === 'dark') { + localStorage.setItem('current-color-mode', 'light') + } else { + localStorage.setItem('current-color-mode', 'dark') + } + // reload each theme switch + document.location.reload(true) +}) diff --git a/apps/block_scout_web/lib/block_scout_web/controllers/address_coin_balance_controller.ex b/apps/block_scout_web/lib/block_scout_web/controllers/address_coin_balance_controller.ex index 33a01959c9..8b39de91a7 100644 --- a/apps/block_scout_web/lib/block_scout_web/controllers/address_coin_balance_controller.ex +++ b/apps/block_scout_web/lib/block_scout_web/controllers/address_coin_balance_controller.ex @@ -16,7 +16,7 @@ defmodule BlockScoutWeb.AddressCoinBalanceController do def index(conn, %{"address_id" => address_hash_string, "type" => "JSON"} = params) do with {:ok, address_hash} <- Chain.string_to_address_hash(address_hash_string), - {:ok, address} <- Chain.hash_to_address(address_hash, [], false) do + :ok <- Chain.check_address_exists(address_hash) do full_options = paging_options(params) coin_balances_plus_one = Chain.address_to_coin_balances(address_hash, full_options) @@ -32,7 +32,7 @@ defmodule BlockScoutWeb.AddressCoinBalanceController do address_coin_balance_path( conn, :index, - address, + address_hash, Map.delete(next_page_params, "type") ) end @@ -52,7 +52,7 @@ defmodule BlockScoutWeb.AddressCoinBalanceController do :error -> unprocessable_entity(conn) - {:error, :not_found} -> + :not_found -> not_found(conn) end end @@ -68,6 +68,12 @@ defmodule BlockScoutWeb.AddressCoinBalanceController do validation_count: validation_count(address_hash), current_path: current_path(conn) ) + else + :error -> + unprocessable_entity(conn) + + {:error, :not_found} -> + not_found(conn) end end end diff --git a/apps/block_scout_web/lib/block_scout_web/controllers/address_contract_controller.ex b/apps/block_scout_web/lib/block_scout_web/controllers/address_contract_controller.ex index bc4df8c4be..5db900b12b 100644 --- a/apps/block_scout_web/lib/block_scout_web/controllers/address_contract_controller.ex +++ b/apps/block_scout_web/lib/block_scout_web/controllers/address_contract_controller.ex @@ -8,8 +8,18 @@ defmodule BlockScoutWeb.AddressContractController do alias Indexer.Fetcher.CoinBalanceOnDemand def index(conn, %{"address_id" => address_hash_string}) do + address_options = [ + necessity_by_association: %{ + :contracts_creation_internal_transaction => :optional, + :names => :optional, + :smart_contract => :optional, + :token => :optional, + :contracts_creation_transaction => :optional + } + ] + with {:ok, address_hash} <- Chain.string_to_address_hash(address_hash_string), - {:ok, address} <- Chain.find_contract_address(address_hash) do + {:ok, address} <- Chain.find_contract_address(address_hash, address_options, true) do render( conn, "index.html", diff --git a/apps/block_scout_web/lib/block_scout_web/controllers/address_logs_controller.ex b/apps/block_scout_web/lib/block_scout_web/controllers/address_logs_controller.ex index e349ecd9ef..d3ea4e5303 100644 --- a/apps/block_scout_web/lib/block_scout_web/controllers/address_logs_controller.ex +++ b/apps/block_scout_web/lib/block_scout_web/controllers/address_logs_controller.ex @@ -16,7 +16,7 @@ defmodule BlockScoutWeb.AddressLogsController do def index(conn, %{"address_id" => address_hash_string, "type" => "JSON"} = params) do with {:ok, address_hash} <- Chain.string_to_address_hash(address_hash_string), - {:ok, address} <- Chain.hash_to_address(address_hash, [], false) do + :ok <- Chain.check_address_exists(address_hash) do logs_plus_one = Chain.address_to_logs(address_hash, paging_options(params)) {results, next_page} = split_list_by_page(logs_plus_one) @@ -26,7 +26,7 @@ defmodule BlockScoutWeb.AddressLogsController do nil next_page_params -> - address_logs_path(conn, :index, address, Map.delete(next_page_params, "type")) + address_logs_path(conn, :index, address_hash, Map.delete(next_page_params, "type")) end items = @@ -74,7 +74,7 @@ defmodule BlockScoutWeb.AddressLogsController do def search_logs(conn, %{"topic" => topic, "address_id" => address_hash_string} = params) do with {:ok, address_hash} <- Chain.string_to_address_hash(address_hash_string), - {:ok, address} <- Chain.hash_to_address(address_hash, [], false) do + :ok <- Chain.check_address_exists(address_hash) do topic = String.trim(topic) formatted_topic = if String.starts_with?(topic, "0x"), do: topic, else: "0x" <> topic @@ -89,7 +89,7 @@ defmodule BlockScoutWeb.AddressLogsController do nil next_page_params -> - address_logs_path(conn, :index, address, Map.delete(next_page_params, "type")) + address_logs_path(conn, :index, address_hash, Map.delete(next_page_params, "type")) end items = @@ -115,4 +115,6 @@ defmodule BlockScoutWeb.AddressLogsController do not_found(conn) end end + + def search_logs(conn, _), do: not_found(conn) end diff --git a/apps/block_scout_web/lib/block_scout_web/controllers/address_read_contract_controller.ex b/apps/block_scout_web/lib/block_scout_web/controllers/address_read_contract_controller.ex index d57aa30807..0849689dce 100644 --- a/apps/block_scout_web/lib/block_scout_web/controllers/address_read_contract_controller.ex +++ b/apps/block_scout_web/lib/block_scout_web/controllers/address_read_contract_controller.ex @@ -15,8 +15,18 @@ defmodule BlockScoutWeb.AddressReadContractController do import BlockScoutWeb.AddressController, only: [transaction_count: 1, validation_count: 1] def index(conn, %{"address_id" => address_hash_string}) do + address_options = [ + necessity_by_association: %{ + :contracts_creation_internal_transaction => :optional, + :names => :optional, + :smart_contract => :optional, + :token => :optional, + :contracts_creation_transaction => :optional + } + ] + with {:ok, address_hash} <- Chain.string_to_address_hash(address_hash_string), - {:ok, address} <- Chain.find_contract_address(address_hash) do + {:ok, address} <- Chain.find_contract_address(address_hash, address_options, true) do render( conn, "index.html", diff --git a/apps/block_scout_web/lib/block_scout_web/controllers/address_transaction_controller.ex b/apps/block_scout_web/lib/block_scout_web/controllers/address_transaction_controller.ex index f6d9b8a30f..47100b972e 100644 --- a/apps/block_scout_web/lib/block_scout_web/controllers/address_transaction_controller.ex +++ b/apps/block_scout_web/lib/block_scout_web/controllers/address_transaction_controller.ex @@ -83,7 +83,11 @@ defmodule BlockScoutWeb.AddressTransactionController do unprocessable_entity(conn) {:error, :not_found} -> - not_found(conn) + with {:ok, _} <- Chain.Hash.Address.validate(address_hash_string) do + json(conn, %{items: [], next_page_path: ""}) + else + {:error, _} -> not_found(conn) + end end end @@ -106,11 +110,28 @@ defmodule BlockScoutWeb.AddressTransactionController do unprocessable_entity(conn) {:error, :not_found} -> - not_found(conn) + {:ok, address_hash} = Chain.string_to_address_hash(address_hash_string) + address = %Chain.Address{hash: address_hash, smart_contract: nil, token: nil} + + with {:ok, _} <- Chain.Hash.Address.validate(address_hash_string) do + render( + conn, + "index.html", + address: address, + coin_balance_status: nil, + exchange_rate: Market.get_exchange_rate(Explorer.coin()) || Token.null(), + filter: params["filter"], + transaction_count: 0, + validation_count: 0, + current_path: current_path(conn) + ) + else + {:error, _} -> not_found(conn) + end end end - def token_transfers_csv(conn, %{"address_id" => address_hash_string}) do + def token_transfers_csv(conn, %{"address_id" => address_hash_string}) when is_binary(address_hash_string) do with {:ok, address_hash} <- Chain.string_to_address_hash(address_hash_string), {:ok, address} <- Chain.hash_to_address(address_hash) do address @@ -130,6 +151,8 @@ defmodule BlockScoutWeb.AddressTransactionController do end end + def token_transfers_csv(conn, _), do: not_found(conn) + def transactions_csv(conn, %{"address_id" => address_hash_string}) do with {:ok, address_hash} <- Chain.string_to_address_hash(address_hash_string), {:ok, address} <- Chain.hash_to_address(address_hash) do @@ -149,4 +172,6 @@ defmodule BlockScoutWeb.AddressTransactionController do not_found(conn) end end + + def transactions_csv(conn, _), do: not_found(conn) end diff --git a/apps/block_scout_web/lib/block_scout_web/controllers/api/rpc/block_controller.ex b/apps/block_scout_web/lib/block_scout_web/controllers/api/rpc/block_controller.ex index 91569a96da..835e19bf3e 100644 --- a/apps/block_scout_web/lib/block_scout_web/controllers/api/rpc/block_controller.ex +++ b/apps/block_scout_web/lib/block_scout_web/controllers/api/rpc/block_controller.ex @@ -8,9 +8,8 @@ defmodule BlockScoutWeb.API.RPC.BlockController do def getblockreward(conn, params) do with {:block_param, {:ok, unsafe_block_number}} <- {:block_param, Map.fetch(params, "blockno")}, {:ok, block_number} <- ChainWeb.param_to_block_number(unsafe_block_number), - block_options = [necessity_by_association: %{transactions: :optional}], - {:ok, block} <- Chain.number_to_block(block_number, block_options) do - reward = Chain.block_reward(block) + {:ok, block} <- Chain.number_to_block(block_number) do + reward = Chain.block_reward(block_number) render(conn, :block_reward, block: block, reward: reward) else diff --git a/apps/block_scout_web/lib/block_scout_web/controllers/api/rpc/transaction_controller.ex b/apps/block_scout_web/lib/block_scout_web/controllers/api/rpc/transaction_controller.ex index 344dbe1037..565ea4b6a5 100644 --- a/apps/block_scout_web/lib/block_scout_web/controllers/api/rpc/transaction_controller.ex +++ b/apps/block_scout_web/lib/block_scout_web/controllers/api/rpc/transaction_controller.ex @@ -10,7 +10,7 @@ defmodule BlockScoutWeb.API.RPC.TransactionController do {:format, {:ok, transaction_hash}} <- to_transaction_hash(txhash_param), {:transaction, {:ok, transaction}} <- transaction_from_hash(transaction_hash), paging_options <- paging_options(params) do - logs = Chain.transaction_to_logs(transaction, paging_options) + logs = Chain.transaction_to_logs(transaction_hash, paging_options) {logs, next_page} = split_list_by_page(logs) render(conn, :gettxinfo, %{ diff --git a/apps/block_scout_web/lib/block_scout_web/controllers/api/v1/decompiled_smart_contract_controller.ex b/apps/block_scout_web/lib/block_scout_web/controllers/api/v1/decompiled_smart_contract_controller.ex index 1eec849380..7b783b9761 100644 --- a/apps/block_scout_web/lib/block_scout_web/controllers/api/v1/decompiled_smart_contract_controller.ex +++ b/apps/block_scout_web/lib/block_scout_web/controllers/api/v1/decompiled_smart_contract_controller.ex @@ -7,8 +7,9 @@ defmodule BlockScoutWeb.API.V1.DecompiledSmartContractController do def create(conn, params) do if auth_token(conn) == actual_token() do with {:ok, hash} <- validate_address_hash(params["address_hash"]), - :ok <- smart_contract_exists?(hash), - :ok <- decompiled_contract_exists?(params["address_hash"], params["decompiler_version"]) do + :ok <- Chain.check_address_exists(hash), + {:contract, :not_found} <- + {:contract, Chain.check_decompiled_contract_exists(params["address_hash"], params["decompiler_version"])} do case Chain.create_decompiled_smart_contract(params) do {:ok, decompiled_smart_contract} -> send_resp(conn, :created, Jason.encode!(decompiled_smart_contract)) @@ -29,7 +30,7 @@ defmodule BlockScoutWeb.API.V1.DecompiledSmartContractController do :not_found -> send_resp(conn, :unprocessable_entity, encode(%{error: "address is not found"})) - :contract_exists -> + {:contract, :ok} -> send_resp( conn, :unprocessable_entity, @@ -41,13 +42,6 @@ defmodule BlockScoutWeb.API.V1.DecompiledSmartContractController do end end - defp smart_contract_exists?(address_hash) do - case Chain.hash_to_address(address_hash) do - {:ok, _address} -> :ok - _ -> :not_found - end - end - defp validate_address_hash(address_hash) do case Address.cast(address_hash) do {:ok, hash} -> {:ok, hash} @@ -55,13 +49,6 @@ defmodule BlockScoutWeb.API.V1.DecompiledSmartContractController do end end - defp decompiled_contract_exists?(address_hash, decompiler_version) do - case Chain.decompiled_code(address_hash, decompiler_version) do - {:ok, _} -> :contract_exists - _ -> :ok - end - end - defp auth_token(conn) do case get_req_header(conn, "auth_token") do [token] -> token diff --git a/apps/block_scout_web/lib/block_scout_web/controllers/api/v1/health_controller.ex b/apps/block_scout_web/lib/block_scout_web/controllers/api/v1/health_controller.ex index 957dc797be..1e65fa75ba 100644 --- a/apps/block_scout_web/lib/block_scout_web/controllers/api/v1/health_controller.ex +++ b/apps/block_scout_web/lib/block_scout_web/controllers/api/v1/health_controller.ex @@ -4,19 +4,22 @@ defmodule BlockScoutWeb.API.V1.HealthController do alias Explorer.Chain def health(conn, _) do - with {:ok, number, timestamp} <- Chain.last_block_status() do - send_resp(conn, :ok, result(number, timestamp)) + with {:ok, number, timestamp} <- Chain.last_db_block_status(), + {:ok, cache_number, cache_timestamp} <- Chain.last_cache_block_status() do + send_resp(conn, :ok, result(number, timestamp, cache_number, cache_timestamp)) else status -> send_resp(conn, :internal_server_error, error(status)) end end - def result(number, timestamp) do + def result(number, timestamp, cache_number, cache_timestamp) do %{ "healthy" => true, "data" => %{ "latest_block_number" => to_string(number), - "latest_block_inserted_at" => to_string(timestamp) + "latest_block_inserted_at" => to_string(timestamp), + "cache_latest_block_number" => to_string(cache_number), + "cache_latest_block_inserted_at" => to_string(cache_timestamp) } } |> Jason.encode!() diff --git a/apps/block_scout_web/lib/block_scout_web/controllers/api/v1/verified_smart_contract_controller.ex b/apps/block_scout_web/lib/block_scout_web/controllers/api/v1/verified_smart_contract_controller.ex index 50334a1a45..8b3d3d71eb 100644 --- a/apps/block_scout_web/lib/block_scout_web/controllers/api/v1/verified_smart_contract_controller.ex +++ b/apps/block_scout_web/lib/block_scout_web/controllers/api/v1/verified_smart_contract_controller.ex @@ -7,8 +7,8 @@ defmodule BlockScoutWeb.API.V1.VerifiedSmartContractController do def create(conn, params) do with {:ok, hash} <- validate_address_hash(params["address_hash"]), - :ok <- smart_contract_exists?(hash), - :ok <- verified_smart_contract_exists?(hash) do + :ok <- Chain.check_address_exists(hash), + {:contract, :not_found} <- {:contract, Chain.check_verified_smart_contract_exists(hash)} do external_libraries = fetch_external_libraries(params) case Publisher.publish(hash, params, external_libraries) do @@ -31,7 +31,7 @@ defmodule BlockScoutWeb.API.V1.VerifiedSmartContractController do :not_found -> send_resp(conn, :unprocessable_entity, encode(%{error: "address is not found"})) - :contract_exists -> + {:contract, :ok} -> send_resp( conn, :unprocessable_entity, @@ -40,13 +40,6 @@ defmodule BlockScoutWeb.API.V1.VerifiedSmartContractController do end end - defp smart_contract_exists?(address_hash) do - case Chain.hash_to_address(address_hash) do - {:ok, _address} -> :ok - _ -> :not_found - end - end - defp validate_address_hash(address_hash) do case Address.cast(address_hash) do {:ok, hash} -> {:ok, hash} @@ -54,14 +47,6 @@ defmodule BlockScoutWeb.API.V1.VerifiedSmartContractController do end end - defp verified_smart_contract_exists?(address_hash) do - if Chain.address_hash_to_smart_contract(address_hash) do - :contract_exists - else - :ok - end - end - defp encode(data) do Jason.encode!(data) end diff --git a/apps/block_scout_web/lib/block_scout_web/controllers/block_transaction_controller.ex b/apps/block_scout_web/lib/block_scout_web/controllers/block_transaction_controller.ex index 15b06f1edd..a1e4cbeb09 100644 --- a/apps/block_scout_web/lib/block_scout_web/controllers/block_transaction_controller.ex +++ b/apps/block_scout_web/lib/block_scout_web/controllers/block_transaction_controller.ex @@ -26,7 +26,7 @@ defmodule BlockScoutWeb.BlockTransactionController do paging_options(params) ) - transactions_plus_one = Chain.block_to_transactions(block, full_options) + transactions_plus_one = Chain.block_to_transactions(block.hash, full_options) {transactions, next_page} = split_list_by_page(transactions_plus_one) @@ -89,7 +89,7 @@ defmodule BlockScoutWeb.BlockTransactionController do :rewards => :optional } ) do - block_transaction_count = Chain.block_to_transaction_count(block) + block_transaction_count = Chain.block_to_transaction_count(block.hash) render( conn, diff --git a/apps/block_scout_web/lib/block_scout_web/controllers/chain_controller.ex b/apps/block_scout_web/lib/block_scout_web/controllers/chain_controller.ex index 40a0fd3bbb..ba5d547cf0 100644 --- a/apps/block_scout_web/lib/block_scout_web/controllers/chain_controller.ex +++ b/apps/block_scout_web/lib/block_scout_web/controllers/chain_controller.ex @@ -2,7 +2,7 @@ defmodule BlockScoutWeb.ChainController do use BlockScoutWeb, :controller alias BlockScoutWeb.ChainView - alias Explorer.{Chain, PagingOptions, Repo} + alias Explorer.{Chain, PagingOptions} alias Explorer.Chain.{Address, Block, Transaction} alias Explorer.Chain.Supply.RSK alias Explorer.Counters.AverageBlockTime @@ -52,6 +52,8 @@ defmodule BlockScoutWeb.ChainController do end end + def search(conn, _), do: not_found(conn) + def token_autocomplete(conn, %{"q" => term}) when is_binary(term) do if term == "" do json(conn, "{}") @@ -72,9 +74,15 @@ defmodule BlockScoutWeb.ChainController do def chain_blocks(conn, _params) do if ajax?(conn) do blocks = - [paging_options: %PagingOptions{page_size: 4}] + [ + paging_options: %PagingOptions{page_size: 4}, + necessity_by_association: %{ + [miner: :names] => :optional, + :transactions => :optional, + :rewards => :optional + } + ] |> Chain.list_blocks() - |> Repo.preload([[miner: :names], :transactions, :rewards]) |> Enum.map(fn block -> %{ chain_block_html: 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 70ec6219f3..ff0a4e67aa 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 @@ -30,10 +30,12 @@ defmodule BlockScoutWeb.SmartContractController do end end + def index(conn, _), do: not_found(conn) + 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), + :ok <- Chain.check_contract_address_exists(address_hash), outputs = Reader.query_function( address_hash, @@ -51,7 +53,7 @@ defmodule BlockScoutWeb.SmartContractController do :error -> unprocessable_entity(conn) - {:error, :not_found} -> + :not_found -> not_found(conn) _ -> diff --git a/apps/block_scout_web/lib/block_scout_web/controllers/transaction_controller.ex b/apps/block_scout_web/lib/block_scout_web/controllers/transaction_controller.ex index 1bedf97c1d..3f849c0e7c 100644 --- a/apps/block_scout_web/lib/block_scout_web/controllers/transaction_controller.ex +++ b/apps/block_scout_web/lib/block_scout_web/controllers/transaction_controller.ex @@ -62,15 +62,15 @@ defmodule BlockScoutWeb.TransactionController do def show(conn, %{"id" => id}) do with {:ok, transaction_hash} <- Chain.string_to_transaction_hash(id), - {:ok, %Chain.Transaction{} = transaction} <- Chain.hash_to_transaction(transaction_hash) do - if Chain.transaction_has_token_transfers?(transaction.hash) do + :ok <- Chain.check_transaction_exists(transaction_hash) do + if Chain.transaction_has_token_transfers?(transaction_hash) do redirect(conn, to: transaction_token_transfer_path(conn, :index, id)) else redirect(conn, to: transaction_internal_transaction_path(conn, :index, id)) end else :error -> conn |> put_status(422) |> render("invalid.html", transaction_hash: id) - {:error, :not_found} -> conn |> put_status(404) |> render("not_found.html", transaction_hash: id) + :not_found -> conn |> put_status(404) |> render("not_found.html", transaction_hash: id) end end end diff --git a/apps/block_scout_web/lib/block_scout_web/controllers/transaction_internal_transaction_controller.ex b/apps/block_scout_web/lib/block_scout_web/controllers/transaction_internal_transaction_controller.ex index 159d144cdd..ca154a0136 100644 --- a/apps/block_scout_web/lib/block_scout_web/controllers/transaction_internal_transaction_controller.ex +++ b/apps/block_scout_web/lib/block_scout_web/controllers/transaction_internal_transaction_controller.ex @@ -10,7 +10,7 @@ defmodule BlockScoutWeb.TransactionInternalTransactionController do def index(conn, %{"transaction_id" => hash_string, "type" => "JSON"} = params) do with {:ok, hash} <- Chain.string_to_transaction_hash(hash_string), - {:ok, transaction} <- Chain.hash_to_transaction(hash) do + :ok <- Chain.check_transaction_exists(hash) do full_options = Keyword.merge( [ @@ -24,7 +24,7 @@ defmodule BlockScoutWeb.TransactionInternalTransactionController do paging_options(params) ) - internal_transactions_plus_one = Chain.transaction_to_internal_transactions(transaction, full_options) + internal_transactions_plus_one = Chain.transaction_to_internal_transactions(hash, full_options) {internal_transactions, next_page} = split_list_by_page(internal_transactions_plus_one) @@ -37,7 +37,7 @@ defmodule BlockScoutWeb.TransactionInternalTransactionController do transaction_internal_transaction_path( conn, :index, - transaction, + hash, Map.delete(next_page_params, "type") ) end @@ -66,7 +66,7 @@ defmodule BlockScoutWeb.TransactionInternalTransactionController do |> put_view(TransactionView) |> render("invalid.html", transaction_hash: hash_string) - {:error, :not_found} -> + :not_found -> conn |> put_status(404) |> put_view(TransactionView) 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 0a87d12493..e076b9ee7b 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 @@ -11,7 +11,9 @@ defmodule BlockScoutWeb.TransactionLogController do def index(conn, %{"transaction_id" => transaction_hash_string, "type" => "JSON"} = params) do with {:ok, transaction_hash} <- Chain.string_to_transaction_hash(transaction_hash_string), {:ok, transaction} <- - Chain.hash_to_transaction(transaction_hash) do + Chain.hash_to_transaction(transaction_hash, + necessity_by_association: %{[to_address: :smart_contract] => :optional} + ) do full_options = Keyword.merge( [ @@ -22,7 +24,7 @@ defmodule BlockScoutWeb.TransactionLogController do paging_options(params) ) - logs_plus_one = Chain.transaction_to_logs(transaction, full_options) + logs_plus_one = Chain.transaction_to_logs(transaction_hash, full_options) {logs, next_page} = split_list_by_page(logs_plus_one) diff --git a/apps/block_scout_web/lib/block_scout_web/controllers/transaction_raw_trace_controller.ex b/apps/block_scout_web/lib/block_scout_web/controllers/transaction_raw_trace_controller.ex index 3d090e8a9b..250a6b4442 100644 --- a/apps/block_scout_web/lib/block_scout_web/controllers/transaction_raw_trace_controller.ex +++ b/apps/block_scout_web/lib/block_scout_web/controllers/transaction_raw_trace_controller.ex @@ -19,7 +19,7 @@ defmodule BlockScoutWeb.TransactionRawTraceController do :token_transfers => :optional } ) do - internal_transactions = Chain.transaction_to_internal_transactions(transaction) + internal_transactions = Chain.transaction_to_internal_transactions(hash) render( conn, diff --git a/apps/block_scout_web/lib/block_scout_web/controllers/transaction_token_transfer_controller.ex b/apps/block_scout_web/lib/block_scout_web/controllers/transaction_token_transfer_controller.ex index cfb215da3e..585a01301f 100644 --- a/apps/block_scout_web/lib/block_scout_web/controllers/transaction_token_transfer_controller.ex +++ b/apps/block_scout_web/lib/block_scout_web/controllers/transaction_token_transfer_controller.ex @@ -10,8 +10,7 @@ defmodule BlockScoutWeb.TransactionTokenTransferController do def index(conn, %{"transaction_id" => hash_string, "type" => "JSON"} = params) do with {:ok, hash} <- Chain.string_to_transaction_hash(hash_string), - {:ok, transaction} <- - Chain.hash_to_transaction(hash) do + :ok <- Chain.check_transaction_exists(hash) do full_options = Keyword.merge( [ @@ -24,7 +23,7 @@ defmodule BlockScoutWeb.TransactionTokenTransferController do paging_options(params) ) - token_transfers_plus_one = Chain.transaction_to_token_transfers(transaction, full_options) + token_transfers_plus_one = Chain.transaction_to_token_transfers(hash, full_options) {token_transfers, next_page} = split_list_by_page(token_transfers_plus_one) @@ -34,7 +33,7 @@ defmodule BlockScoutWeb.TransactionTokenTransferController do nil next_page_params -> - transaction_token_transfer_path(conn, :index, transaction, Map.delete(next_page_params, "type")) + transaction_token_transfer_path(conn, :index, hash, Map.delete(next_page_params, "type")) end items = @@ -62,7 +61,7 @@ defmodule BlockScoutWeb.TransactionTokenTransferController do |> put_view(TransactionView) |> render("invalid.html", transaction_hash: hash_string) - {:error, :not_found} -> + :not_found -> conn |> put_status(404) |> put_view(TransactionView) diff --git a/apps/block_scout_web/lib/block_scout_web/router.ex b/apps/block_scout_web/lib/block_scout_web/router.ex index 4f5a8e1bed..7a1f5b3ed9 100644 --- a/apps/block_scout_web/lib/block_scout_web/router.ex +++ b/apps/block_scout_web/lib/block_scout_web/router.ex @@ -261,6 +261,6 @@ defmodule BlockScoutWeb.Router do get("/api_docs", APIDocsController, :index) get("/eth_rpc_api_docs", APIDocsController, :eth_rpc) - get("/:page", PageNotFoundController, :index) + get("/*path", PageNotFoundController, :index) end end diff --git a/apps/block_scout_web/lib/block_scout_web/templates/address/_tile.html.eex b/apps/block_scout_web/lib/block_scout_web/templates/address/_tile.html.eex index 9680faa2a8..56f1a2bbb2 100644 --- a/apps/block_scout_web/lib/block_scout_web/templates/address/_tile.html.eex +++ b/apps/block_scout_web/lib/block_scout_web/templates/address/_tile.html.eex @@ -21,7 +21,7 @@ <%= if @total_supply do %> - (<%= balance_percentage(@address, @total_supply) %>) + <%= balance_percentage(@address, @total_supply) %> <% end %> diff --git a/apps/block_scout_web/lib/block_scout_web/templates/address/index.html.eex b/apps/block_scout_web/lib/block_scout_web/templates/address/index.html.eex index 3aaab46ad5..c594915d9f 100644 --- a/apps/block_scout_web/lib/block_scout_web/templates/address/index.html.eex +++ b/apps/block_scout_web/lib/block_scout_web/templates/address/index.html.eex @@ -38,7 +38,7 @@ - + <%= render BlockScoutWeb.CommonComponentsView, "_table-loader.html" %> 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 3cb95a5331..04e7c2c036 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 @@ -84,9 +84,11 @@ <%= gettext("Transactions Sent") %> <% end %> - - <%= gettext("Last Balance Update: Block #") %><%= @address.fetched_coin_balance_block_number %> - + <%= if @address.fetched_coin_balance_block_number do %> + + <%= gettext("Last Balance Update: Block #") %><%= @address.fetched_coin_balance_block_number %> + + <% end %> <%= if validator?(@validation_count) do %> diff --git a/apps/block_scout_web/lib/block_scout_web/templates/address_coin_balance/index.html.eex b/apps/block_scout_web/lib/block_scout_web/templates/address_coin_balance/index.html.eex index 6b9459f5b3..2e71dd22ca 100644 --- a/apps/block_scout_web/lib/block_scout_web/templates/address_coin_balance/index.html.eex +++ b/apps/block_scout_web/lib/block_scout_web/templates/address_coin_balance/index.html.eex @@ -40,7 +40,9 @@ -
+
+ <%= render BlockScoutWeb.CommonComponentsView, "_tile-loader.html" %> +
<%= render BlockScoutWeb.CommonComponentsView, "_pagination_container.html", position: "bottom", cur_page_number: "1", show_pagination_limit: true, data_next_page_button: true, data_prev_page_button: true %> 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 340765a97f..e8d6501e02 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 @@ -46,14 +46,18 @@
<%= @address.smart_contract.evm_version %>
<% end %> - <%= if @address.smart_contract.constructor_arguments do %> -
-
<%= gettext "Constructor arguments" %>
-
<%= @address.smart_contract.constructor_arguments %>
-
- <% end %> -
+ <%= if @address.smart_contract.constructor_arguments do %> +
+
+

<%= gettext "Constructor Arguments" %>

+
+
+
<%= raw(format_constructor_arguments(@address.smart_contract)) %>
+              
+
+
+ <% end %>

<%= gettext "Contract source code" %>

@@ -116,7 +120,7 @@

<%= gettext "External libraries" %>

-
<%= format_external_libraries(@address.smart_contract.external_libraries) %>
+              
<%= raw(format_external_libraries(@address.smart_contract.external_libraries)) %>
               
diff --git a/apps/block_scout_web/lib/block_scout_web/templates/address_internal_transaction/index.html.eex b/apps/block_scout_web/lib/block_scout_web/templates/address_internal_transaction/index.html.eex index 3bc2e7fe9b..f18638db0d 100644 --- a/apps/block_scout_web/lib/block_scout_web/templates/address_internal_transaction/index.html.eex +++ b/apps/block_scout_web/lib/block_scout_web/templates/address_internal_transaction/index.html.eex @@ -66,7 +66,9 @@ -
+
+ <%= render BlockScoutWeb.CommonComponentsView, "_tile-loader.html" %> +
<%= render BlockScoutWeb.CommonComponentsView, "_pagination_container.html", position: "bottom", cur_page_number: "1", show_pagination_limit: true, data_next_page_button: true, data_prev_page_button: true %> diff --git a/apps/block_scout_web/lib/block_scout_web/templates/address_logs/_logs.html.eex b/apps/block_scout_web/lib/block_scout_web/templates/address_logs/_logs.html.eex index 1b5cb5c4fd..3fb638b1d9 100644 --- a/apps/block_scout_web/lib/block_scout_web/templates/address_logs/_logs.html.eex +++ b/apps/block_scout_web/lib/block_scout_web/templates/address_logs/_logs.html.eex @@ -11,6 +11,76 @@ ) %> +
<%= gettext "Decoded" %>
+
+ <%= case decode(@log, @log.transaction) do %> + <% {:error, :contract_not_verified} -> %> +
+ <%= gettext "To see decoded input data, the contract must be verified." %> + <%= case @log.transaction do %> + <% %{to_address: %{hash: hash}} -> %> + <%= gettext "Verify the contract " %><%= gettext "here" %> + <% _ -> %> + <%= nil %> + <% end %> +
+ <% {:error, :could_not_decode} -> %> +
+ <%= gettext "Failed to decode log data." %> +
+ <% {:ok, method_id, text, mapping} -> %> + + + + + + + + + +
Method Id0x<%= method_id %>
Call<%= text %>
+
+ " class="table thead-light table-bordered"> + + + + + + + + <%= for {name, type, indexed?, value} <- mapping do %> + + + + + + + + <% end %> +
<%= gettext "Name" %><%= gettext "Type" %><%= gettext "Indexed?" %><%= gettext "Data" %>
+ <%= case BlockScoutWeb.ABIEncodedValueView.copy_text(type, value) do %> + <% :error -> %> + <%= nil %> + <% copy_text -> %> + + + + + + <% end %> + <%= name %><%= type %><%= indexed? %> +
<%= BlockScoutWeb.ABIEncodedValueView.value_html(type, value) %>
+
+
+ <% _ -> %> + <%= nil %> + <% end %>
<%= gettext "Topics" %>
diff --git a/apps/block_scout_web/lib/block_scout_web/templates/address_logs/index.html.eex b/apps/block_scout_web/lib/block_scout_web/templates/address_logs/index.html.eex index 3a44e0cb2d..fabbc7f7d8 100644 --- a/apps/block_scout_web/lib/block_scout_web/templates/address_logs/index.html.eex +++ b/apps/block_scout_web/lib/block_scout_web/templates/address_logs/index.html.eex @@ -27,7 +27,9 @@
-
+
+ <%= render BlockScoutWeb.CommonComponentsView, "_tile-loader.html" %> +
<%= render BlockScoutWeb.CommonComponentsView, "_pagination_container.html", position: "bottom", cur_page_number: "1", show_pagination_limit: true, data_next_page_button: true, data_prev_page_button: true %> diff --git a/apps/block_scout_web/lib/block_scout_web/templates/address_token/index.html.eex b/apps/block_scout_web/lib/block_scout_web/templates/address_token/index.html.eex index 840d9cc1da..8510bdca64 100644 --- a/apps/block_scout_web/lib/block_scout_web/templates/address_token/index.html.eex +++ b/apps/block_scout_web/lib/block_scout_web/templates/address_token/index.html.eex @@ -19,7 +19,9 @@ -
+
+ <%= render BlockScoutWeb.CommonComponentsView, "_tile-loader.html" %> +
diff --git a/apps/block_scout_web/lib/block_scout_web/templates/address_token_transfer/index.html.eex b/apps/block_scout_web/lib/block_scout_web/templates/address_token_transfer/index.html.eex index c2ab502bf0..738d70883d 100644 --- a/apps/block_scout_web/lib/block_scout_web/templates/address_token_transfer/index.html.eex +++ b/apps/block_scout_web/lib/block_scout_web/templates/address_token_transfer/index.html.eex @@ -21,7 +21,9 @@ -
+
+ <%= render BlockScoutWeb.CommonComponentsView, "_tile-loader.html" %> +
<%= render BlockScoutWeb.CommonComponentsView, "_pagination_container.html", position: "bottom", cur_page_number: "1", show_pagination_limit: true, data_next_page_button: true, data_prev_page_button: true %> diff --git a/apps/block_scout_web/lib/block_scout_web/templates/address_transaction/index.html.eex b/apps/block_scout_web/lib/block_scout_web/templates/address_transaction/index.html.eex index c3a4c94129..83c5454627 100644 --- a/apps/block_scout_web/lib/block_scout_web/templates/address_transaction/index.html.eex +++ b/apps/block_scout_web/lib/block_scout_web/templates/address_transaction/index.html.eex @@ -65,7 +65,9 @@
-
+
+ <%= render BlockScoutWeb.CommonComponentsView, "_tile-loader.html" %> +
diff --git a/apps/block_scout_web/lib/block_scout_web/templates/address_validation/index.html.eex b/apps/block_scout_web/lib/block_scout_web/templates/address_validation/index.html.eex index 3f85f03aba..03b37369bc 100644 --- a/apps/block_scout_web/lib/block_scout_web/templates/address_validation/index.html.eex +++ b/apps/block_scout_web/lib/block_scout_web/templates/address_validation/index.html.eex @@ -22,7 +22,9 @@ <%= gettext "Something went wrong, click to reload." %> -
+
+ <%= render BlockScoutWeb.CommonComponentsView, "_tile-loader.html" %> +
<%= render BlockScoutWeb.CommonComponentsView, "_pagination_container.html", position: "bottom", cur_page_number: "1", show_pagination_limit: true, data_next_page_button: true, data_prev_page_button: true %> diff --git a/apps/block_scout_web/lib/block_scout_web/templates/block/index.html.eex b/apps/block_scout_web/lib/block_scout_web/templates/block/index.html.eex index 92b91ce287..dd8a3ed093 100644 --- a/apps/block_scout_web/lib/block_scout_web/templates/block/index.html.eex +++ b/apps/block_scout_web/lib/block_scout_web/templates/block/index.html.eex @@ -11,7 +11,9 @@ <%= render BlockScoutWeb.CommonComponentsView, "_pagination_container.html", position: "top", cur_page_number: "1", show_pagination_limit: true, data_next_page_button: true, data_prev_page_button: true %> -
+
+ <%= render BlockScoutWeb.CommonComponentsView, "_tile-loader.html" %> +
<%= gettext "There are no blocks." %>
diff --git a/apps/block_scout_web/lib/block_scout_web/templates/block_transaction/index.html.eex b/apps/block_scout_web/lib/block_scout_web/templates/block_transaction/index.html.eex index a497ab1b7e..e0847cac86 100644 --- a/apps/block_scout_web/lib/block_scout_web/templates/block_transaction/index.html.eex +++ b/apps/block_scout_web/lib/block_scout_web/templates/block_transaction/index.html.eex @@ -29,7 +29,9 @@
-
+
+ <%= render BlockScoutWeb.CommonComponentsView, "_tile-loader.html" %> +
<%= render BlockScoutWeb.CommonComponentsView, "_pagination_container.html", position: "bottom", cur_page_number: "1", show_pagination_limit: true, data_next_page_button: true, data_prev_page_button: true %> diff --git a/apps/block_scout_web/lib/block_scout_web/templates/chain/_block.html.eex b/apps/block_scout_web/lib/block_scout_web/templates/chain/_block.html.eex index 729df59a3c..706d18ec47 100644 --- a/apps/block_scout_web/lib/block_scout_web/templates/chain/_block.html.eex +++ b/apps/block_scout_web/lib/block_scout_web/templates/chain/_block.html.eex @@ -1,172 +1,5 @@
-
-
- Block Validated, processing... -
-
-
-
- - - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - -
-
-
-
- - - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - -
-
-
-
- - - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - -
-
-
-
-
<%= link( @block, class: "tile-title", diff --git a/apps/block_scout_web/lib/block_scout_web/templates/chain/show.html.eex b/apps/block_scout_web/lib/block_scout_web/templates/chain/show.html.eex index 0c29001697..53b21cb3fa 100644 --- a/apps/block_scout_web/lib/block_scout_web/templates/chain/show.html.eex +++ b/apps/block_scout_web/lib/block_scout_web/templates/chain/show.html.eex @@ -5,7 +5,7 @@
-
+ -
+
+ <%= render BlockScoutWeb.CommonComponentsView, "_tile-loader.html" %> +
<%= render BlockScoutWeb.CommonComponentsView, "_pagination_container.html", position: "bottom", cur_page_number: "1", show_pagination_limit: true, data_next_page_button: true, data_prev_page_button: true %> diff --git a/apps/block_scout_web/lib/block_scout_web/templates/tokens/transfer/index.html.eex b/apps/block_scout_web/lib/block_scout_web/templates/tokens/transfer/index.html.eex index 980cc4b05a..addaa0c359 100644 --- a/apps/block_scout_web/lib/block_scout_web/templates/tokens/transfer/index.html.eex +++ b/apps/block_scout_web/lib/block_scout_web/templates/tokens/transfer/index.html.eex @@ -26,7 +26,9 @@
-
+
+ <%= render BlockScoutWeb.CommonComponentsView, "_tile-loader.html" %> +
<%= render BlockScoutWeb.CommonComponentsView, "_pagination_container.html", position: "bottom", cur_page_number: "1", show_pagination_limit: true, data_next_page_button: true, data_prev_page_button: true %> diff --git a/apps/block_scout_web/lib/block_scout_web/templates/transaction/_decoded_input_body.html.eex b/apps/block_scout_web/lib/block_scout_web/templates/transaction/_decoded_input_body.html.eex index f009eeb2b3..9e68d7e1bd 100644 --- a/apps/block_scout_web/lib/block_scout_web/templates/transaction/_decoded_input_body.html.eex +++ b/apps/block_scout_web/lib/block_scout_web/templates/transaction/_decoded_input_body.html.eex @@ -1,4 +1,5 @@ -" class="table thead-light table-bordered table-responsive transaction-info-table"> +
+
" class="table thead-light table-bordered"> @@ -7,49 +8,52 @@ -
<%= gettext "Method Id" %> 0x<%= @method_id %>Call <%= @text %>
+ +
<%= unless Enum.empty?(@mapping) do %> - " class="table thead-light table-bordered table-responsive"> - - - - - - - <%= for {name, type, value} <- @mapping do %> +
+
<%= gettext "Name" %><%= gettext "Type" %><%= gettext "Data" %>
" class="table thead-light table-bordered"> + + + + + - - - - + - <% end %> -
<%= gettext "Name" %><%= gettext "Type" %><%= gettext "Data" %>
- <%= case BlockScoutWeb.ABIEncodedValueView.copy_text(type, value) do %> - <% :error -> %> - <%= nil %> - <% copy_text -> %> - - - - - - <% end %> - <%= name %><%= type %> - <%= case BlockScoutWeb.ABIEncodedValueView.value_html(type, value) do %> - <% :error -> %> -
- <%= gettext "Error rendering value" %> -
- <% value -> %> -
<%= value %>
+ <%= for {name, type, value} <- @mapping do %> +
+ <%= case BlockScoutWeb.ABIEncodedValueView.copy_text(type, value) do %> + <% :error -> %> + <%= nil %> + <% copy_text -> %> + + + + + <% end %> - -
+ + <%= name %> + <%= type %> + + <%= case BlockScoutWeb.ABIEncodedValueView.value_html(type, value) do %> + <% :error -> %> +
+ <%= gettext "Error rendering value" %> +
+ <% value -> %> +
<%= value %>
+ <% end %> + + + <% end %> + +
<% end %> 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 18928915f2..bce59eb00b 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 @@ -28,7 +28,9 @@
-
+
+ <%= render BlockScoutWeb.CommonComponentsView, "_tile-loader.html" %> +
<%= render BlockScoutWeb.CommonComponentsView, "_pagination_container.html", position: "bottom", cur_page_number: "1", show_pagination_limit: true, data_next_page_button: true, data_prev_page_button: true %> diff --git a/apps/block_scout_web/lib/block_scout_web/templates/transaction_internal_transaction/index.html.eex b/apps/block_scout_web/lib/block_scout_web/templates/transaction_internal_transaction/index.html.eex index e6623b4061..70162a3be8 100644 --- a/apps/block_scout_web/lib/block_scout_web/templates/transaction_internal_transaction/index.html.eex +++ b/apps/block_scout_web/lib/block_scout_web/templates/transaction_internal_transaction/index.html.eex @@ -16,7 +16,9 @@ -
+
+ <%= render BlockScoutWeb.CommonComponentsView, "_tile-loader.html" %> +
<%= render BlockScoutWeb.CommonComponentsView, "_pagination_container.html", position: "bottom", cur_page_number: "1", show_pagination_limit: true, data_next_page_button: true, data_prev_page_button: true %> diff --git a/apps/block_scout_web/lib/block_scout_web/templates/transaction_log/_logs.html.eex b/apps/block_scout_web/lib/block_scout_web/templates/transaction_log/_logs.html.eex index 5a52821601..ff3e46d42a 100644 --- a/apps/block_scout_web/lib/block_scout_web/templates/transaction_log/_logs.html.eex +++ b/apps/block_scout_web/lib/block_scout_web/templates/transaction_log/_logs.html.eex @@ -39,43 +39,45 @@ <%= text %> - " class="table thead-light table-bordered table-responsive"> - - - - - - - - <%= for {name, type, indexed?, value} <- mapping do %> +
+
<%= gettext "Name" %><%= gettext "Type" %><%= gettext "Indexed?" %><%= gettext "Data" %>
" class="table thead-light table-bordered"> - - - - - - - <% end %> -
- <%= case BlockScoutWeb.ABIEncodedValueView.copy_text(type, value) do %> - <% :error -> %> - <%= nil %> - <% copy_text -> %> - - - - - - <% end %> - <%= name %><%= type %><%= indexed? %> -
<%= BlockScoutWeb.ABIEncodedValueView.value_html(type, value) %>
-
+ + <%= gettext "Name" %> + <%= gettext "Type" %> + <%= gettext "Indexed?" %> + <%= gettext "Data" %> + + <%= for {name, type, indexed?, value} <- mapping do %> + + + <%= case BlockScoutWeb.ABIEncodedValueView.copy_text(type, value) do %> + <% :error -> %> + <%= nil %> + <% copy_text -> %> + + + + + + <% end %> + + <%= name %> + <%= type %> + <%= indexed? %> + +
<%= BlockScoutWeb.ABIEncodedValueView.value_html(type, value) %>
+ + + <% end %> + + <% _ -> %> <%= nil %> <% end %> diff --git a/apps/block_scout_web/lib/block_scout_web/templates/transaction_log/index.html.eex b/apps/block_scout_web/lib/block_scout_web/templates/transaction_log/index.html.eex index 3c84e7c4f9..17f480b439 100644 --- a/apps/block_scout_web/lib/block_scout_web/templates/transaction_log/index.html.eex +++ b/apps/block_scout_web/lib/block_scout_web/templates/transaction_log/index.html.eex @@ -19,7 +19,9 @@ -
+
+ <%= render BlockScoutWeb.CommonComponentsView, "_tile-loader.html" %> +
<%= render BlockScoutWeb.CommonComponentsView, "_pagination_container.html", position: "bottom", cur_page_number: "1", show_pagination_limit: true, data_next_page_button: true, data_prev_page_button: true %> diff --git a/apps/block_scout_web/lib/block_scout_web/templates/transaction_token_transfer/index.html.eex b/apps/block_scout_web/lib/block_scout_web/templates/transaction_token_transfer/index.html.eex index d40dedd414..8d356a450a 100644 --- a/apps/block_scout_web/lib/block_scout_web/templates/transaction_token_transfer/index.html.eex +++ b/apps/block_scout_web/lib/block_scout_web/templates/transaction_token_transfer/index.html.eex @@ -18,7 +18,9 @@ -
+
+ <%= render BlockScoutWeb.CommonComponentsView, "_tile-loader.html" %> +
<%= render BlockScoutWeb.CommonComponentsView, "_pagination_container.html", position: "bottom", cur_page_number: "1", show_pagination_limit: true, data_next_page_button: true, data_prev_page_button: true %> diff --git a/apps/block_scout_web/lib/block_scout_web/views/address_contract_view.ex b/apps/block_scout_web/lib/block_scout_web/views/address_contract_view.ex index 5de263f820..57c6e11da7 100644 --- a/apps/block_scout_web/lib/block_scout_web/views/address_contract_view.ex +++ b/apps/block_scout_web/lib/block_scout_web/views/address_contract_view.ex @@ -1,6 +1,7 @@ defmodule BlockScoutWeb.AddressContractView do use BlockScoutWeb, :view + alias ABI.{FunctionSelector, TypeDecoder} alias Explorer.Chain.{Address, Data, InternalTransaction} def render("scripts.html", %{conn: conn}) do @@ -21,9 +22,44 @@ defmodule BlockScoutWeb.AddressContractView do def format_optimization_text(true), do: gettext("true") def format_optimization_text(false), do: gettext("false") + def format_constructor_arguments(contract) do + constructor_abi = Enum.find(contract.abi, fn el -> el["type"] == "constructor" && el["inputs"] != [] end) + + input_types = Enum.map(constructor_abi["inputs"], &FunctionSelector.parse_specification_type/1) + + {_, result} = + contract.constructor_arguments + |> decode_data(input_types) + |> Enum.zip(constructor_abi["inputs"]) + |> Enum.reduce({0, "#{contract.constructor_arguments}\n\n"}, fn {val, %{"type" => type}}, {count, acc} -> + formatted_val = + if is_binary(val) do + Base.encode16(val, case: :lower) + else + val + end + + {count + 1, "#{acc}Arg [#{count}] (#{type}) : #{formatted_val}\n"} + end) + + result + rescue + _ -> contract.constructor_arguments + end + + defp decode_data("0x" <> encoded_data, types) do + decode_data(encoded_data, types) + end + + defp decode_data(encoded_data, types) do + encoded_data + |> Base.decode16!(case: :mixed) + |> TypeDecoder.decode_raw(types) + end + def format_external_libraries(libraries) do Enum.reduce(libraries, "", fn %{name: name, address_hash: address_hash}, acc -> - acc <> name <> " : " <> address_hash <> "\n" + "#{acc}#{name} : #{address_hash} \n" end) end diff --git a/apps/block_scout_web/lib/block_scout_web/views/address_logs_view.ex b/apps/block_scout_web/lib/block_scout_web/views/address_logs_view.ex index 7155e65206..3cdfaf1f9b 100644 --- a/apps/block_scout_web/lib/block_scout_web/views/address_logs_view.ex +++ b/apps/block_scout_web/lib/block_scout_web/views/address_logs_view.ex @@ -1,3 +1,9 @@ defmodule BlockScoutWeb.AddressLogsView do use BlockScoutWeb, :view + + alias Explorer.Chain.Log + + def decode(log, transaction) do + Log.decode(log, transaction) + end end diff --git a/apps/block_scout_web/lib/block_scout_web/views/internal_transaction_view.ex b/apps/block_scout_web/lib/block_scout_web/views/internal_transaction_view.ex index fe12f04302..46252f72ce 100644 --- a/apps/block_scout_web/lib/block_scout_web/views/internal_transaction_view.ex +++ b/apps/block_scout_web/lib/block_scout_web/views/internal_transaction_view.ex @@ -23,6 +23,7 @@ defmodule BlockScoutWeb.InternalTransactionView do def type(%InternalTransaction{type: :call, call_type: :delegatecall}), do: gettext("Delegate Call") def type(%InternalTransaction{type: :call, call_type: :staticcall}), do: gettext("Static Call") def type(%InternalTransaction{type: :create}), do: gettext("Create") + def type(%InternalTransaction{type: :create2}), do: gettext("Create2") def type(%InternalTransaction{type: :selfdestruct}), do: gettext("Self-Destruct") def type(%InternalTransaction{type: :reward}), do: gettext("Reward") end diff --git a/apps/block_scout_web/mix.exs b/apps/block_scout_web/mix.exs index e431d4ecf5..623aba2089 100644 --- a/apps/block_scout_web/mix.exs +++ b/apps/block_scout_web/mix.exs @@ -125,7 +125,7 @@ defmodule BlockScoutWeb.Mixfile do {:spandex_datadog, "~> 0.4.0"}, # `:spandex` tracing of `:phoenix` {:spandex_phoenix, "~> 0.3.1"}, - {:timex, "~> 3.4"}, + {:timex, "~> 3.6"}, {:wallaby, "~> 0.22", only: [:test], runtime: false}, # `:cowboy` `~> 2.0` and Phoenix 1.4 compatibility {:wobserver, "~> 0.2.0", github: "poanetwork/wobserver", branch: "support-https"}, diff --git a/apps/block_scout_web/priv/gettext/default.pot b/apps/block_scout_web/priv/gettext/default.pot index b8e56412a6..e356d87df9 100644 --- a/apps/block_scout_web/priv/gettext/default.pot +++ b/apps/block_scout_web/priv/gettext/default.pot @@ -34,7 +34,7 @@ msgstr "" #, elixir-format #: lib/block_scout_web/templates/block/overview.html.eex:21 -#: lib/block_scout_web/templates/chain/_block.html.eex:178 +#: lib/block_scout_web/templates/chain/_block.html.eex:11 msgid "%{count} Transactions" msgstr "" @@ -62,7 +62,7 @@ msgid "(query)" msgstr "" #, elixir-format -#: lib/block_scout_web/templates/layout/app.html.eex:35 +#: lib/block_scout_web/templates/layout/app.html.eex:40 msgid "- We're indexing this chain right now. Some of the counts may be inaccurate." msgstr "" @@ -87,7 +87,7 @@ msgid "API for the %{subnetwork} - BlockScout" msgstr "" #, elixir-format -#: lib/block_scout_web/templates/layout/_topnav.html.eex:56 +#: lib/block_scout_web/templates/layout/_topnav.html.eex:66 msgid "Accounts" msgstr "" @@ -157,7 +157,7 @@ msgid "Block Height: %{height}" msgstr "" #, elixir-format -#: lib/block_scout_web/templates/layout/app.html.eex:50 +#: lib/block_scout_web/templates/layout/app.html.eex:55 msgid "Block Mined, awaiting import..." msgstr "" @@ -178,19 +178,19 @@ msgstr "" #, elixir-format #: lib/block_scout_web/templates/chain/show.html.eex:87 -#: lib/block_scout_web/templates/layout/_topnav.html.eex:16 -#: lib/block_scout_web/templates/layout/_topnav.html.eex:20 +#: lib/block_scout_web/templates/layout/_topnav.html.eex:26 +#: lib/block_scout_web/templates/layout/_topnav.html.eex:30 msgid "Blocks" msgstr "" #, elixir-format -#: lib/block_scout_web/templates/layout/app.html.eex:49 +#: lib/block_scout_web/templates/layout/app.html.eex:54 msgid "Blocks Indexed" msgstr "" #, elixir-format #: lib/block_scout_web/templates/address/_tabs.html.eex:32 -#: lib/block_scout_web/templates/address/overview.html.eex:95 +#: lib/block_scout_web/templates/address/overview.html.eex:97 #: lib/block_scout_web/templates/address_validation/index.html.eex:13 #: lib/block_scout_web/views/address_view.ex:311 msgid "Blocks Validated" @@ -209,8 +209,8 @@ msgstr "" #, elixir-format #: lib/block_scout_web/templates/address/_validator_metadata_modal.html.eex:37 -#: lib/block_scout_web/templates/address/overview.html.eex:144 -#: lib/block_scout_web/templates/address/overview.html.eex:152 +#: lib/block_scout_web/templates/address/overview.html.eex:146 +#: lib/block_scout_web/templates/address/overview.html.eex:154 #: lib/block_scout_web/templates/tokens/overview/_details.html.eex:107 #: lib/block_scout_web/templates/tokens/overview/_details.html.eex:115 msgid "Close" @@ -258,7 +258,7 @@ msgid "Connection Lost, click to load newer validations" msgstr "" #, elixir-format -#: lib/block_scout_web/templates/address_contract/index.html.eex:71 +#: lib/block_scout_web/templates/address_contract/index.html.eex:75 msgid "Contract ABI" msgstr "" @@ -296,7 +296,7 @@ msgid "Contract name:" msgstr "" #, elixir-format -#: lib/block_scout_web/templates/address_contract/index.html.eex:59 +#: lib/block_scout_web/templates/address_contract/index.html.eex:63 msgid "Contract source code" msgstr "" @@ -319,7 +319,7 @@ msgid "Copy Txn Hash" msgstr "" #, elixir-format -#: lib/block_scout_web/templates/address/overview.html.eex:105 +#: lib/block_scout_web/templates/address/overview.html.eex:107 msgid "Created by" msgstr "" @@ -328,14 +328,6 @@ msgstr "" msgid "Curl" msgstr "" -#, elixir-format -#: lib/block_scout_web/templates/address_logs/_logs.html.eex:44 -#: lib/block_scout_web/templates/transaction/_decoded_input_body.html.eex:18 -#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:48 -#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:113 -msgid "Data" -msgstr "" - #, elixir-format #: lib/block_scout_web/templates/api_docs/_action_tile.html.eex:53 #: lib/block_scout_web/templates/api_docs/_action_tile.html.eex:188 @@ -376,7 +368,7 @@ msgstr "" #, elixir-format #: lib/block_scout_web/templates/address/_balance_card.html.eex:15 #: lib/block_scout_web/templates/internal_transaction/_tile.html.eex:21 -#: lib/block_scout_web/templates/layout/app.html.eex:55 +#: lib/block_scout_web/templates/layout/app.html.eex:60 #: lib/block_scout_web/templates/transaction/_pending_tile.html.eex:20 #: lib/block_scout_web/templates/transaction/_tile.html.eex:30 #: lib/block_scout_web/templates/transaction/overview.html.eex:196 @@ -400,7 +392,7 @@ msgid "Fetching tokens..." msgstr "" #, elixir-format -#: lib/block_scout_web/templates/layout/_topnav.html.eex:26 +#: lib/block_scout_web/templates/layout/_topnav.html.eex:36 msgid "Forked Blocks (Reorgs)" msgstr "" @@ -454,7 +446,7 @@ msgid "IN" msgstr "" #, elixir-format -#: lib/block_scout_web/templates/layout/app.html.eex:51 +#: lib/block_scout_web/templates/layout/app.html.eex:56 msgid "Indexing Tokens" msgstr "" @@ -486,7 +478,7 @@ msgid "Inventory" msgstr "" #, elixir-format -#: lib/block_scout_web/templates/layout/app.html.eex:52 +#: lib/block_scout_web/templates/layout/app.html.eex:57 msgid "Less than" msgstr "" @@ -507,7 +499,7 @@ msgstr "" #, elixir-format #: lib/block_scout_web/templates/chain/show.html.eex:31 -#: lib/block_scout_web/templates/layout/app.html.eex:53 +#: lib/block_scout_web/templates/layout/app.html.eex:58 #: lib/block_scout_web/views/address_view.ex:121 #: lib/block_scout_web/views/address_view.ex:121 msgid "Market Cap" @@ -522,7 +514,7 @@ msgstr "" #, elixir-format #: lib/block_scout_web/templates/block/_tile.html.eex:38 #: lib/block_scout_web/templates/block/overview.html.eex:121 -#: lib/block_scout_web/templates/chain/_block.html.eex:182 +#: lib/block_scout_web/templates/chain/_block.html.eex:15 msgid "Miner" msgstr "" @@ -555,9 +547,10 @@ msgid "Must be set to:" msgstr "" #, elixir-format +#: lib/block_scout_web/templates/address_logs/_logs.html.eex:46 #: lib/block_scout_web/templates/api_docs/_action_tile.html.eex:52 -#: lib/block_scout_web/templates/transaction/_decoded_input_body.html.eex:16 -#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:45 +#: lib/block_scout_web/templates/transaction/_decoded_input_body.html.eex:19 +#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:46 msgid "Name" msgstr "" @@ -604,7 +597,7 @@ msgid "Parent Hash" msgstr "" #, elixir-format -#: lib/block_scout_web/templates/layout/_topnav.html.eex:44 +#: lib/block_scout_web/templates/layout/_topnav.html.eex:54 #: lib/block_scout_web/views/transaction_view.ex:143 #: lib/block_scout_web/views/transaction_view.ex:177 msgid "Pending" @@ -622,13 +615,13 @@ msgstr "" #, elixir-format #: lib/block_scout_web/templates/chain/show.html.eex:24 -#: lib/block_scout_web/templates/layout/app.html.eex:54 +#: lib/block_scout_web/templates/layout/app.html.eex:59 msgid "Price" msgstr "" #, elixir-format #: lib/block_scout_web/templates/address/overview.html.eex:33 -#: lib/block_scout_web/templates/address/overview.html.eex:143 +#: lib/block_scout_web/templates/address/overview.html.eex:145 #: lib/block_scout_web/templates/tokens/overview/_details.html.eex:36 #: lib/block_scout_web/templates/tokens/overview/_details.html.eex:106 msgid "QR Code" @@ -669,8 +662,8 @@ msgstr "" #, elixir-format #: lib/block_scout_web/templates/address_logs/index.html.eex:14 -#: lib/block_scout_web/templates/layout/_topnav.html.eex:102 -#: lib/block_scout_web/templates/layout/_topnav.html.eex:119 +#: lib/block_scout_web/templates/layout/_topnav.html.eex:118 +#: lib/block_scout_web/templates/layout/_topnav.html.eex:135 msgid "Search" msgstr "" @@ -774,7 +767,7 @@ msgid "To" msgstr "" #, elixir-format -#: lib/block_scout_web/templates/layout/_topnav.html.eex:6 +#: lib/block_scout_web/templates/layout/_topnav.html.eex:16 msgid "Toggle navigation" msgstr "" @@ -825,12 +818,6 @@ msgstr "" msgid "Top Accounts - %{subnetwork} Explorer" msgstr "" -#, elixir-format -#: lib/block_scout_web/templates/address_logs/_logs.html.eex:14 -#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:83 -msgid "Topics" -msgstr "" - #, elixir-format #: lib/block_scout_web/templates/block/overview.html.eex:67 msgid "Total Difficulty" @@ -873,7 +860,7 @@ msgstr "" #: lib/block_scout_web/templates/block_transaction/index.html.eex:10 #: lib/block_scout_web/templates/block_transaction/index.html.eex:18 #: lib/block_scout_web/templates/chain/show.html.eex:108 -#: lib/block_scout_web/templates/layout/_topnav.html.eex:35 +#: lib/block_scout_web/templates/layout/_topnav.html.eex:45 #: lib/block_scout_web/views/address_view.ex:305 msgid "Transactions" msgstr "" @@ -900,7 +887,7 @@ msgstr "" #, elixir-format #: lib/block_scout_web/templates/block/overview.html.eex:80 -#: lib/block_scout_web/templates/layout/_topnav.html.eex:23 +#: lib/block_scout_web/templates/layout/_topnav.html.eex:33 msgid "Uncles" msgstr "" @@ -915,7 +902,7 @@ msgid "Used" msgstr "" #, elixir-format -#: lib/block_scout_web/templates/layout/_topnav.html.eex:39 +#: lib/block_scout_web/templates/layout/_topnav.html.eex:49 msgid "Validated" msgstr "" @@ -996,12 +983,12 @@ msgid "Yes" msgstr "" #, elixir-format -#: lib/block_scout_web/templates/address/overview.html.eex:111 +#: lib/block_scout_web/templates/address/overview.html.eex:113 msgid "at" msgstr "" #, elixir-format -#: lib/block_scout_web/views/address_contract_view.ex:22 +#: lib/block_scout_web/views/address_contract_view.ex:23 msgid "false" msgstr "" @@ -1019,7 +1006,7 @@ msgid "string" msgstr "" #, elixir-format -#: lib/block_scout_web/views/address_contract_view.ex:21 +#: lib/block_scout_web/views/address_contract_view.ex:22 msgid "true" msgstr "" @@ -1039,14 +1026,7 @@ msgid "Delegate Call" msgstr "" #, elixir-format -#: lib/block_scout_web/templates/block/_tile.html.eex:47 -#: lib/block_scout_web/templates/chain/_block.html.eex:190 #: lib/block_scout_web/views/internal_transaction_view.ex:27 -msgid "Reward" -msgstr "" - -#, elixir-format -#: lib/block_scout_web/views/internal_transaction_view.ex:26 msgid "Self-Destruct" msgstr "" @@ -1058,7 +1038,6 @@ msgstr "" #, elixir-format #: lib/block_scout_web/templates/address_read_contract/index.html.eex:14 #: lib/block_scout_web/templates/chain/show.html.eex:99 -#: lib/block_scout_web/templates/chain/show.html.eex:125 #: lib/block_scout_web/templates/tokens/read_contract/index.html.eex:21 msgid "Loading..." msgstr "" @@ -1069,22 +1048,17 @@ msgid "Loading...." msgstr "" #, elixir-format -#: lib/block_scout_web/templates/layout/_topnav.html.eex:64 +#: lib/block_scout_web/templates/layout/_topnav.html.eex:74 msgid "APIs" msgstr "" #, elixir-format -#: lib/block_scout_web/templates/layout/_topnav.html.eex:68 +#: lib/block_scout_web/templates/layout/_topnav.html.eex:78 msgid "GraphQL" msgstr "" #, elixir-format -#: lib/block_scout_web/templates/pending_transaction/index.html.eex:32 -msgid "Loading" -msgstr "" - -#, elixir-format -#: lib/block_scout_web/templates/layout/_topnav.html.eex:73 +#: lib/block_scout_web/templates/layout/_topnav.html.eex:83 msgid "RPC" msgstr "" @@ -1134,48 +1108,37 @@ msgid "Static Call" msgstr "" #, elixir-format +#: lib/block_scout_web/templates/address_logs/_logs.html.eex:14 #: lib/block_scout_web/templates/transaction_log/_logs.html.eex:14 msgid "Decoded" msgstr "" #, elixir-format -#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:47 -msgid "Indexed?" -msgstr "" - -#, elixir-format -#: lib/block_scout_web/templates/transaction/_decoded_input_body.html.eex:17 -#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:46 -msgid "Type" -msgstr "" - -#, elixir-format -#: lib/block_scout_web/templates/transaction/_decoded_input_body.html.eex:3 +#: lib/block_scout_web/templates/transaction/_decoded_input_body.html.eex:4 msgid "Method Id" msgstr "" #, elixir-format +#: lib/block_scout_web/templates/address_logs/_logs.html.eex:19 #: lib/block_scout_web/templates/transaction_log/_logs.html.eex:19 msgid "To see decoded input data, the contract must be verified." msgstr "" #, elixir-format -#: lib/block_scout_web/templates/transaction/_decoded_input_body.html.eex:1 -msgid "Transaction Info" -msgstr "" - -#, elixir-format -#: lib/block_scout_web/templates/transaction/_decoded_input_body.html.eex:13 +#: lib/block_scout_web/templates/transaction/_decoded_input_body.html.eex:2 +#: lib/block_scout_web/templates/transaction/_decoded_input_body.html.eex:16 msgid "Transaction Inputs" msgstr "" #, elixir-format +#: lib/block_scout_web/templates/address_logs/_logs.html.eex:22 #: lib/block_scout_web/templates/transaction/_decoded_input.html.eex:11 #: lib/block_scout_web/templates/transaction_log/_logs.html.eex:22 msgid "Verify the contract " msgstr "" #, elixir-format +#: lib/block_scout_web/templates/address_logs/_logs.html.eex:22 #: lib/block_scout_web/templates/transaction/_decoded_input.html.eex:11 #: lib/block_scout_web/templates/transaction_log/_logs.html.eex:22 msgid "here" @@ -1187,26 +1150,10 @@ msgid "Failed to decode input data." msgstr "" #, elixir-format -#: lib/block_scout_web/templates/transaction/_decoded_input_body.html.eex:46 +#: lib/block_scout_web/templates/transaction/_decoded_input_body.html.eex:49 msgid "Error rendering value" msgstr "" -#, elixir-format -#: lib/block_scout_web/templates/transaction/_decoded_input_body.html.eex:28 -#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:58 -msgid "Copy Value" -msgstr "" - -#, elixir-format -#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:29 -msgid "Failed to decode log data." -msgstr "" - -#, elixir-format -#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:42 -msgid "Log Data" -msgstr "" - #, elixir-format #: lib/block_scout_web/templates/address_coin_balance/index.html.eex:34 #: lib/block_scout_web/templates/address_internal_transaction/index.html.eex:61 @@ -1277,7 +1224,7 @@ msgid "There are no pending transactions." msgstr "" #, elixir-format -#: lib/block_scout_web/templates/block/index.html.eex:16 +#: lib/block_scout_web/templates/block/index.html.eex:18 msgid "There are no blocks." msgstr "" @@ -1407,17 +1354,17 @@ msgid "Support" msgstr "" #, elixir-format -#: lib/block_scout_web/templates/address_contract/index.html.eex:73 +#: lib/block_scout_web/templates/address_contract/index.html.eex:77 msgid "Copy ABI" msgstr "" #, elixir-format -#: lib/block_scout_web/templates/address_contract/index.html.eex:89 +#: lib/block_scout_web/templates/address_contract/index.html.eex:93 msgid "Copy Contract Creation Code" msgstr "" #, elixir-format -#: lib/block_scout_web/templates/address_contract/index.html.eex:61 +#: lib/block_scout_web/templates/address_contract/index.html.eex:65 msgid "Copy Source Code" msgstr "" @@ -1432,7 +1379,7 @@ msgid "Contract Libraries" msgstr "" #, elixir-format -#: lib/block_scout_web/templates/address/overview.html.eex:88 +#: lib/block_scout_web/templates/address/overview.html.eex:89 msgid "Last Balance Update: Block #" msgstr "" @@ -1478,13 +1425,13 @@ msgid "Incoming Transactions" msgstr "" #, elixir-format -#: lib/block_scout_web/templates/address/overview.html.eex:119 +#: lib/block_scout_web/templates/address/overview.html.eex:121 msgid "Error: Could not determine contract creator." msgstr "" #, elixir-format -#: lib/block_scout_web/templates/layout/_topnav.html.eex:96 -#: lib/block_scout_web/templates/layout/_topnav.html.eex:100 +#: lib/block_scout_web/templates/layout/_topnav.html.eex:112 +#: lib/block_scout_web/templates/layout/_topnav.html.eex:116 msgid "Search by address, token symbol name, transaction hash, or block number" msgstr "" @@ -1587,27 +1534,27 @@ msgid "Block Details" msgstr "" #, elixir-format -#: lib/block_scout_web/templates/address_contract/index.html.eex:101 +#: lib/block_scout_web/templates/address_contract/index.html.eex:105 msgid "Contract Byte Code" msgstr "" #, elixir-format -#: lib/block_scout_web/templates/address_contract/index.html.eex:87 +#: lib/block_scout_web/templates/address_contract/index.html.eex:91 msgid "Contract Creation Code" msgstr "" #, elixir-format -#: lib/block_scout_web/templates/address_contract/index.html.eex:93 +#: lib/block_scout_web/templates/address_contract/index.html.eex:97 msgid "Contracts that self destruct in their constructors have no contract code published and cannot be verified." msgstr "" #, elixir-format -#: lib/block_scout_web/templates/address_contract/index.html.eex:103 +#: lib/block_scout_web/templates/address_contract/index.html.eex:107 msgid "Copy Contract Byte Code" msgstr "" #, elixir-format -#: lib/block_scout_web/templates/address_contract/index.html.eex:94 +#: lib/block_scout_web/templates/address_contract/index.html.eex:98 msgid "Displaying the init data provided of the creating transaction." msgstr "" @@ -1710,7 +1657,7 @@ msgid "ETH RPC API Documentation" msgstr "" #, elixir-format -#: lib/block_scout_web/templates/layout/_topnav.html.eex:78 +#: lib/block_scout_web/templates/layout/_topnav.html.eex:88 msgid "Eth RPC" msgstr "" @@ -1745,8 +1692,8 @@ msgid "here." msgstr "" #, elixir-format -#: lib/block_scout_web/templates/address_token/index.html.eex:26 -#: lib/block_scout_web/templates/address_transaction/index.html.eex:72 +#: lib/block_scout_web/templates/address_token/index.html.eex:28 +#: lib/block_scout_web/templates/address_transaction/index.html.eex:74 msgid "CSV" msgstr "" @@ -1755,11 +1702,6 @@ msgstr "" msgid "Change Network" msgstr "" -#, elixir-format -#: lib/block_scout_web/templates/address_contract/index.html.eex:51 -msgid "Constructor arguments" -msgstr "" - #, elixir-format #: lib/block_scout_web/views/transaction_view.ex:44 msgid "ERC-20 " @@ -1771,7 +1713,7 @@ msgid "ERC-721 " msgstr "" #, elixir-format -#: lib/block_scout_web/templates/address_contract/index.html.eex:116 +#: lib/block_scout_web/templates/address_contract/index.html.eex:120 msgid "External libraries" msgstr "" @@ -1804,3 +1746,67 @@ msgstr "" #: lib/block_scout_web/templates/address_contract_verification/new.html.eex:4 msgid "Connection Lost" msgstr "" + +#, elixir-format +#: lib/block_scout_web/templates/address_contract/index.html.eex:53 +msgid "Constructor Arguments" +msgstr "" + +#, elixir-format +#: lib/block_scout_web/templates/address_logs/_logs.html.eex:59 +#: lib/block_scout_web/templates/transaction/_decoded_input_body.html.eex:31 +#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:59 +msgid "Copy Value" +msgstr "" + +#, elixir-format +#: lib/block_scout_web/views/internal_transaction_view.ex:26 +msgid "Create2" +msgstr "" + +#, elixir-format +#: lib/block_scout_web/templates/address_logs/_logs.html.eex:49 +#: lib/block_scout_web/templates/address_logs/_logs.html.eex:114 +#: lib/block_scout_web/templates/transaction/_decoded_input_body.html.eex:21 +#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:49 +#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:115 +msgid "Data" +msgstr "" + +#, elixir-format +#: lib/block_scout_web/templates/address_logs/_logs.html.eex:29 +#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:29 +msgid "Failed to decode log data." +msgstr "" + +#, elixir-format +#: lib/block_scout_web/templates/address_logs/_logs.html.eex:48 +#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:48 +msgid "Indexed?" +msgstr "" + +#, elixir-format +#: lib/block_scout_web/templates/address_logs/_logs.html.eex:43 +#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:43 +msgid "Log Data" +msgstr "" + +#, elixir-format +#: lib/block_scout_web/templates/block/_tile.html.eex:47 +#: lib/block_scout_web/templates/chain/_block.html.eex:23 +#: lib/block_scout_web/views/internal_transaction_view.ex:28 +msgid "Reward" +msgstr "" + +#, elixir-format +#: lib/block_scout_web/templates/address_logs/_logs.html.eex:84 +#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:85 +msgid "Topics" +msgstr "" + +#, elixir-format +#: lib/block_scout_web/templates/address_logs/_logs.html.eex:47 +#: lib/block_scout_web/templates/transaction/_decoded_input_body.html.eex:20 +#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:47 +msgid "Type" +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 5333eb95aa..58e159d0bb 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 @@ -62,7 +62,7 @@ msgid "(query)" msgstr "" #, elixir-format -#: lib/block_scout_web/templates/layout/app.html.eex:35 +#: lib/block_scout_web/templates/layout/app.html.eex:40 msgid "- We're indexing this chain right now. Some of the counts may be inaccurate." msgstr "" @@ -87,7 +87,7 @@ msgid "API for the %{subnetwork} - BlockScout" msgstr "" #, elixir-format -#: lib/block_scout_web/templates/layout/_topnav.html.eex:56 +#: lib/block_scout_web/templates/layout/_topnav.html.eex:66 msgid "Accounts" msgstr "" @@ -157,7 +157,7 @@ msgid "Block Height: %{height}" msgstr "" #, elixir-format -#: lib/block_scout_web/templates/layout/app.html.eex:50 +#: lib/block_scout_web/templates/layout/app.html.eex:55 msgid "Block Mined, awaiting import..." msgstr "" @@ -178,19 +178,19 @@ msgstr "" #, elixir-format #: lib/block_scout_web/templates/chain/show.html.eex:87 -#: lib/block_scout_web/templates/layout/_topnav.html.eex:16 -#: lib/block_scout_web/templates/layout/_topnav.html.eex:20 +#: lib/block_scout_web/templates/layout/_topnav.html.eex:26 +#: lib/block_scout_web/templates/layout/_topnav.html.eex:30 msgid "Blocks" msgstr "" #, elixir-format -#: lib/block_scout_web/templates/layout/app.html.eex:49 +#: lib/block_scout_web/templates/layout/app.html.eex:54 msgid "Blocks Indexed" msgstr "" #, elixir-format #: lib/block_scout_web/templates/address/_tabs.html.eex:32 -#: lib/block_scout_web/templates/address/overview.html.eex:95 +#: lib/block_scout_web/templates/address/overview.html.eex:97 #: lib/block_scout_web/templates/address_validation/index.html.eex:13 #: lib/block_scout_web/views/address_view.ex:311 msgid "Blocks Validated" @@ -209,8 +209,8 @@ msgstr "" #, elixir-format #: lib/block_scout_web/templates/address/_validator_metadata_modal.html.eex:37 -#: lib/block_scout_web/templates/address/overview.html.eex:144 -#: lib/block_scout_web/templates/address/overview.html.eex:152 +#: lib/block_scout_web/templates/address/overview.html.eex:146 +#: lib/block_scout_web/templates/address/overview.html.eex:154 #: lib/block_scout_web/templates/tokens/overview/_details.html.eex:107 #: lib/block_scout_web/templates/tokens/overview/_details.html.eex:115 msgid "Close" @@ -258,7 +258,7 @@ msgid "Connection Lost, click to load newer validations" msgstr "" #, elixir-format -#: lib/block_scout_web/templates/address_contract/index.html.eex:71 +#: lib/block_scout_web/templates/address_contract/index.html.eex:75 msgid "Contract ABI" msgstr "" @@ -296,7 +296,7 @@ msgid "Contract name:" msgstr "" #, elixir-format -#: lib/block_scout_web/templates/address_contract/index.html.eex:59 +#: lib/block_scout_web/templates/address_contract/index.html.eex:63 msgid "Contract source code" msgstr "" @@ -319,7 +319,7 @@ msgid "Copy Txn Hash" msgstr "" #, elixir-format -#: lib/block_scout_web/templates/address/overview.html.eex:105 +#: lib/block_scout_web/templates/address/overview.html.eex:107 msgid "Created by" msgstr "" @@ -328,14 +328,6 @@ msgstr "" msgid "Curl" msgstr "" -#, elixir-format -#: lib/block_scout_web/templates/address_logs/_logs.html.eex:44 -#: lib/block_scout_web/templates/transaction/_decoded_input_body.html.eex:18 -#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:48 -#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:113 -msgid "Data" -msgstr "" - #, elixir-format #: lib/block_scout_web/templates/api_docs/_action_tile.html.eex:53 #: lib/block_scout_web/templates/api_docs/_action_tile.html.eex:188 @@ -376,7 +368,7 @@ msgstr "" #, elixir-format #: lib/block_scout_web/templates/address/_balance_card.html.eex:15 #: lib/block_scout_web/templates/internal_transaction/_tile.html.eex:21 -#: lib/block_scout_web/templates/layout/app.html.eex:55 +#: lib/block_scout_web/templates/layout/app.html.eex:60 #: lib/block_scout_web/templates/transaction/_pending_tile.html.eex:20 #: lib/block_scout_web/templates/transaction/_tile.html.eex:30 #: lib/block_scout_web/templates/transaction/overview.html.eex:196 @@ -400,7 +392,7 @@ msgid "Fetching tokens..." msgstr "" #, elixir-format -#: lib/block_scout_web/templates/layout/_topnav.html.eex:26 +#: lib/block_scout_web/templates/layout/_topnav.html.eex:36 msgid "Forked Blocks (Reorgs)" msgstr "" @@ -454,7 +446,7 @@ msgid "IN" msgstr "" #, elixir-format -#: lib/block_scout_web/templates/layout/app.html.eex:51 +#: lib/block_scout_web/templates/layout/app.html.eex:56 msgid "Indexing Tokens" msgstr "" @@ -486,7 +478,7 @@ msgid "Inventory" msgstr "" #, elixir-format -#: lib/block_scout_web/templates/layout/app.html.eex:52 +#: lib/block_scout_web/templates/layout/app.html.eex:57 msgid "Less than" msgstr "" @@ -507,7 +499,7 @@ msgstr "" #, elixir-format #: lib/block_scout_web/templates/chain/show.html.eex:31 -#: lib/block_scout_web/templates/layout/app.html.eex:53 +#: lib/block_scout_web/templates/layout/app.html.eex:58 #: lib/block_scout_web/views/address_view.ex:121 #: lib/block_scout_web/views/address_view.ex:121 msgid "Market Cap" @@ -555,9 +547,10 @@ msgid "Must be set to:" msgstr "" #, elixir-format +#: lib/block_scout_web/templates/address_logs/_logs.html.eex:46 #: lib/block_scout_web/templates/api_docs/_action_tile.html.eex:52 -#: lib/block_scout_web/templates/transaction/_decoded_input_body.html.eex:16 -#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:45 +#: lib/block_scout_web/templates/transaction/_decoded_input_body.html.eex:19 +#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:46 msgid "Name" msgstr "" @@ -604,7 +597,7 @@ msgid "Parent Hash" msgstr "" #, elixir-format -#: lib/block_scout_web/templates/layout/_topnav.html.eex:44 +#: lib/block_scout_web/templates/layout/_topnav.html.eex:54 #: lib/block_scout_web/views/transaction_view.ex:143 #: lib/block_scout_web/views/transaction_view.ex:177 msgid "Pending" @@ -622,13 +615,13 @@ msgstr "" #, elixir-format #: lib/block_scout_web/templates/chain/show.html.eex:24 -#: lib/block_scout_web/templates/layout/app.html.eex:54 +#: lib/block_scout_web/templates/layout/app.html.eex:59 msgid "Price" msgstr "" #, elixir-format #: lib/block_scout_web/templates/address/overview.html.eex:33 -#: lib/block_scout_web/templates/address/overview.html.eex:143 +#: lib/block_scout_web/templates/address/overview.html.eex:145 #: lib/block_scout_web/templates/tokens/overview/_details.html.eex:36 #: lib/block_scout_web/templates/tokens/overview/_details.html.eex:106 msgid "QR Code" @@ -669,8 +662,8 @@ msgstr "" #, elixir-format #: lib/block_scout_web/templates/address_logs/index.html.eex:14 -#: lib/block_scout_web/templates/layout/_topnav.html.eex:102 -#: lib/block_scout_web/templates/layout/_topnav.html.eex:119 +#: lib/block_scout_web/templates/layout/_topnav.html.eex:118 +#: lib/block_scout_web/templates/layout/_topnav.html.eex:135 msgid "Search" msgstr "" @@ -774,7 +767,7 @@ msgid "To" msgstr "" #, elixir-format -#: lib/block_scout_web/templates/layout/_topnav.html.eex:6 +#: lib/block_scout_web/templates/layout/_topnav.html.eex:16 msgid "Toggle navigation" msgstr "" @@ -825,12 +818,6 @@ msgstr "" msgid "Top Accounts - %{subnetwork} Explorer" msgstr "" -#, elixir-format -#: lib/block_scout_web/templates/address_logs/_logs.html.eex:14 -#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:83 -msgid "Topics" -msgstr "" - #, elixir-format #: lib/block_scout_web/templates/block/overview.html.eex:67 msgid "Total Difficulty" @@ -873,7 +860,7 @@ msgstr "" #: lib/block_scout_web/templates/block_transaction/index.html.eex:10 #: lib/block_scout_web/templates/block_transaction/index.html.eex:18 #: lib/block_scout_web/templates/chain/show.html.eex:108 -#: lib/block_scout_web/templates/layout/_topnav.html.eex:35 +#: lib/block_scout_web/templates/layout/_topnav.html.eex:45 #: lib/block_scout_web/views/address_view.ex:305 msgid "Transactions" msgstr "" @@ -900,7 +887,7 @@ msgstr "" #, elixir-format #: lib/block_scout_web/templates/block/overview.html.eex:80 -#: lib/block_scout_web/templates/layout/_topnav.html.eex:23 +#: lib/block_scout_web/templates/layout/_topnav.html.eex:33 msgid "Uncles" msgstr "" @@ -915,7 +902,7 @@ msgid "Used" msgstr "" #, elixir-format -#: lib/block_scout_web/templates/layout/_topnav.html.eex:39 +#: lib/block_scout_web/templates/layout/_topnav.html.eex:49 msgid "Validated" msgstr "" @@ -996,12 +983,12 @@ msgid "Yes" msgstr "" #, elixir-format -#: lib/block_scout_web/templates/address/overview.html.eex:111 +#: lib/block_scout_web/templates/address/overview.html.eex:113 msgid "at" msgstr "" #, elixir-format -#: lib/block_scout_web/views/address_contract_view.ex:22 +#: lib/block_scout_web/views/address_contract_view.ex:23 msgid "false" msgstr "" @@ -1019,7 +1006,7 @@ msgid "string" msgstr "" #, elixir-format -#: lib/block_scout_web/views/address_contract_view.ex:21 +#: lib/block_scout_web/views/address_contract_view.ex:22 msgid "true" msgstr "" @@ -1039,14 +1026,7 @@ msgid "Delegate Call" msgstr "" #, elixir-format -#: lib/block_scout_web/templates/block/_tile.html.eex:47 -#: lib/block_scout_web/templates/chain/_block.html.eex:23 #: lib/block_scout_web/views/internal_transaction_view.ex:27 -msgid "Reward" -msgstr "" - -#, elixir-format -#: lib/block_scout_web/views/internal_transaction_view.ex:26 msgid "Self-Destruct" msgstr "" @@ -1058,7 +1038,6 @@ msgstr "" #, elixir-format #: lib/block_scout_web/templates/address_read_contract/index.html.eex:14 #: lib/block_scout_web/templates/chain/show.html.eex:99 -#: lib/block_scout_web/templates/chain/show.html.eex:125 #: lib/block_scout_web/templates/tokens/read_contract/index.html.eex:21 msgid "Loading..." msgstr "" @@ -1069,22 +1048,17 @@ msgid "Loading...." msgstr "" #, elixir-format -#: lib/block_scout_web/templates/layout/_topnav.html.eex:64 +#: lib/block_scout_web/templates/layout/_topnav.html.eex:74 msgid "APIs" msgstr "" #, elixir-format -#: lib/block_scout_web/templates/layout/_topnav.html.eex:68 +#: lib/block_scout_web/templates/layout/_topnav.html.eex:78 msgid "GraphQL" msgstr "" #, elixir-format -#: lib/block_scout_web/templates/pending_transaction/index.html.eex:32 -msgid "Loading" -msgstr "" - -#, elixir-format -#: lib/block_scout_web/templates/layout/_topnav.html.eex:73 +#: lib/block_scout_web/templates/layout/_topnav.html.eex:83 msgid "RPC" msgstr "" @@ -1134,48 +1108,37 @@ msgid "Static Call" msgstr "" #, elixir-format +#: lib/block_scout_web/templates/address_logs/_logs.html.eex:14 #: lib/block_scout_web/templates/transaction_log/_logs.html.eex:14 msgid "Decoded" msgstr "" #, elixir-format -#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:47 -msgid "Indexed?" -msgstr "" - -#, elixir-format -#: lib/block_scout_web/templates/transaction/_decoded_input_body.html.eex:17 -#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:46 -msgid "Type" -msgstr "" - -#, elixir-format -#: lib/block_scout_web/templates/transaction/_decoded_input_body.html.eex:3 +#: lib/block_scout_web/templates/transaction/_decoded_input_body.html.eex:4 msgid "Method Id" msgstr "" #, elixir-format +#: lib/block_scout_web/templates/address_logs/_logs.html.eex:19 #: lib/block_scout_web/templates/transaction_log/_logs.html.eex:19 msgid "To see decoded input data, the contract must be verified." msgstr "" #, elixir-format -#: lib/block_scout_web/templates/transaction/_decoded_input_body.html.eex:1 -msgid "Transaction Info" -msgstr "" - -#, elixir-format -#: lib/block_scout_web/templates/transaction/_decoded_input_body.html.eex:13 +#: lib/block_scout_web/templates/transaction/_decoded_input_body.html.eex:2 +#: lib/block_scout_web/templates/transaction/_decoded_input_body.html.eex:16 msgid "Transaction Inputs" msgstr "" #, elixir-format +#: lib/block_scout_web/templates/address_logs/_logs.html.eex:22 #: lib/block_scout_web/templates/transaction/_decoded_input.html.eex:11 #: lib/block_scout_web/templates/transaction_log/_logs.html.eex:22 msgid "Verify the contract " msgstr "" #, elixir-format +#: lib/block_scout_web/templates/address_logs/_logs.html.eex:22 #: lib/block_scout_web/templates/transaction/_decoded_input.html.eex:11 #: lib/block_scout_web/templates/transaction_log/_logs.html.eex:22 msgid "here" @@ -1187,25 +1150,10 @@ msgid "Failed to decode input data." msgstr "" #, elixir-format -#: lib/block_scout_web/templates/transaction/_decoded_input_body.html.eex:46 +#: lib/block_scout_web/templates/transaction/_decoded_input_body.html.eex:49 msgid "Error rendering value" msgstr "" - -#, elixir-format -#: lib/block_scout_web/templates/transaction/_decoded_input_body.html.eex:28 -#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:58 -msgid "Copy Value" -msgstr "" - -#, elixir-format -#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:29 -msgid "Failed to decode log data." -msgstr "" - -#, elixir-format -#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:42 -msgid "Log Data" -msgstr "" +"" #, elixir-format #: lib/block_scout_web/templates/address_coin_balance/index.html.eex:34 @@ -1277,7 +1225,7 @@ msgid "There are no pending transactions." msgstr "" #, elixir-format -#: lib/block_scout_web/templates/block/index.html.eex:16 +#: lib/block_scout_web/templates/block/index.html.eex:18 msgid "There are no blocks." msgstr "" @@ -1407,17 +1355,17 @@ msgid "Support" msgstr "" #, elixir-format -#: lib/block_scout_web/templates/address_contract/index.html.eex:73 +#: lib/block_scout_web/templates/address_contract/index.html.eex:77 msgid "Copy ABI" msgstr "" #, elixir-format -#: lib/block_scout_web/templates/address_contract/index.html.eex:89 +#: lib/block_scout_web/templates/address_contract/index.html.eex:93 msgid "Copy Contract Creation Code" msgstr "" #, elixir-format -#: lib/block_scout_web/templates/address_contract/index.html.eex:61 +#: lib/block_scout_web/templates/address_contract/index.html.eex:65 msgid "Copy Source Code" msgstr "" @@ -1432,7 +1380,7 @@ msgid "Contract Libraries" msgstr "" #, elixir-format -#: lib/block_scout_web/templates/address/overview.html.eex:88 +#: lib/block_scout_web/templates/address/overview.html.eex:89 msgid "Last Balance Update: Block #" msgstr "" @@ -1478,13 +1426,13 @@ msgid "Incoming Transactions" msgstr "" #, elixir-format -#: lib/block_scout_web/templates/address/overview.html.eex:119 +#: lib/block_scout_web/templates/address/overview.html.eex:121 msgid "Error: Could not determine contract creator." msgstr "" #, elixir-format -#: lib/block_scout_web/templates/layout/_topnav.html.eex:96 -#: lib/block_scout_web/templates/layout/_topnav.html.eex:100 +#: lib/block_scout_web/templates/layout/_topnav.html.eex:112 +#: lib/block_scout_web/templates/layout/_topnav.html.eex:116 msgid "Search by address, token symbol name, transaction hash, or block number" msgstr "" @@ -1587,27 +1535,27 @@ msgid "Block Details" msgstr "" #, elixir-format -#: lib/block_scout_web/templates/address_contract/index.html.eex:101 +#: lib/block_scout_web/templates/address_contract/index.html.eex:105 msgid "Contract Byte Code" msgstr "" #, elixir-format -#: lib/block_scout_web/templates/address_contract/index.html.eex:87 +#: lib/block_scout_web/templates/address_contract/index.html.eex:91 msgid "Contract Creation Code" msgstr "" #, elixir-format -#: lib/block_scout_web/templates/address_contract/index.html.eex:93 +#: lib/block_scout_web/templates/address_contract/index.html.eex:97 msgid "Contracts that self destruct in their constructors have no contract code published and cannot be verified." msgstr "" #, elixir-format -#: lib/block_scout_web/templates/address_contract/index.html.eex:103 +#: lib/block_scout_web/templates/address_contract/index.html.eex:107 msgid "Copy Contract Byte Code" msgstr "" #, elixir-format -#: lib/block_scout_web/templates/address_contract/index.html.eex:94 +#: lib/block_scout_web/templates/address_contract/index.html.eex:98 msgid "Displaying the init data provided of the creating transaction." msgstr "" @@ -1710,7 +1658,7 @@ msgid "ETH RPC API Documentation" msgstr "" #, elixir-format -#: lib/block_scout_web/templates/layout/_topnav.html.eex:78 +#: lib/block_scout_web/templates/layout/_topnav.html.eex:88 msgid "Eth RPC" msgstr "" @@ -1745,8 +1693,8 @@ msgid "here." msgstr "" #, elixir-format -#: lib/block_scout_web/templates/address_token/index.html.eex:26 -#: lib/block_scout_web/templates/address_transaction/index.html.eex:72 +#: lib/block_scout_web/templates/address_token/index.html.eex:28 +#: lib/block_scout_web/templates/address_transaction/index.html.eex:74 msgid "CSV" msgstr "" @@ -1755,11 +1703,6 @@ msgstr "" msgid "Change Network" msgstr "" -#, elixir-format -#: lib/block_scout_web/templates/address_contract/index.html.eex:51 -msgid "Constructor arguments" -msgstr "" - #, elixir-format #: lib/block_scout_web/views/transaction_view.ex:44 msgid "ERC-20 " @@ -1771,7 +1714,7 @@ msgid "ERC-721 " msgstr "" #, elixir-format -#: lib/block_scout_web/templates/address_contract/index.html.eex:116 +#: lib/block_scout_web/templates/address_contract/index.html.eex:120 msgid "External libraries" msgstr "" @@ -1804,3 +1747,67 @@ msgstr "" #: lib/block_scout_web/templates/address_contract_verification/new.html.eex:4 msgid "Connection Lost" msgstr "" + +#, elixir-format +#: lib/block_scout_web/templates/address_contract/index.html.eex:53 +msgid "Constructor Arguments" +msgstr "" + +#, elixir-format +#: lib/block_scout_web/templates/address_logs/_logs.html.eex:59 +#: lib/block_scout_web/templates/transaction/_decoded_input_body.html.eex:31 +#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:59 +msgid "Copy Value" +msgstr "" + +#, elixir-format +#: lib/block_scout_web/views/internal_transaction_view.ex:26 +msgid "Create2" +msgstr "" + +#, elixir-format +#: lib/block_scout_web/templates/address_logs/_logs.html.eex:49 +#: lib/block_scout_web/templates/address_logs/_logs.html.eex:114 +#: lib/block_scout_web/templates/transaction/_decoded_input_body.html.eex:21 +#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:49 +#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:115 +msgid "Data" +msgstr "" + +#, elixir-format +#: lib/block_scout_web/templates/address_logs/_logs.html.eex:29 +#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:29 +msgid "Failed to decode log data." +msgstr "" + +#, elixir-format +#: lib/block_scout_web/templates/address_logs/_logs.html.eex:48 +#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:48 +msgid "Indexed?" +msgstr "" + +#, elixir-format +#: lib/block_scout_web/templates/address_logs/_logs.html.eex:43 +#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:43 +msgid "Log Data" +msgstr "" + +#, elixir-format +#: lib/block_scout_web/templates/block/_tile.html.eex:47 +#: lib/block_scout_web/templates/chain/_block.html.eex:23 +#: lib/block_scout_web/views/internal_transaction_view.ex:28 +msgid "Reward" +msgstr "" + +#, elixir-format +#: lib/block_scout_web/templates/address_logs/_logs.html.eex:84 +#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:85 +msgid "Topics" +msgstr "" + +#, elixir-format +#: lib/block_scout_web/templates/address_logs/_logs.html.eex:47 +#: lib/block_scout_web/templates/transaction/_decoded_input_body.html.eex:20 +#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:47 +msgid "Type" +msgstr "" diff --git a/apps/block_scout_web/priv/gettext/errors.pot b/apps/block_scout_web/priv/gettext/errors.pot index ca584666e5..cdaaac6299 100644 --- a/apps/block_scout_web/priv/gettext/errors.pot +++ b/apps/block_scout_web/priv/gettext/errors.pot @@ -1,52 +1,52 @@ -## This file is a PO Template file. -## -## `msgid`s here are often extracted from source code. -## Add new translations manually only if they're dynamic -## translations that can't be statically extracted. -## -## Run `mix gettext.extract` to bring this file up to -## date. Leave `msgstr`s empty as changing them here as no -## effect: edit them in PO (`.po`) files instead. -## From Ecto.Changeset.cast/4 +## This file is a PO Template file. +## +## `msgid`s here are often extracted from source code. +## Add new translations manually only if they're dynamic +## translations that can't be statically extracted. +## +## Run `mix gettext.extract` to bring this file up to +## date. Leave `msgstr`s empty as changing them here as no +## effect: edit them in PO (`.po`) files instead. +## From Ecto.Changeset.cast/4 msgid "can't be blank" msgstr "" -## From Ecto.Changeset.unique_constraint/3 +## From Ecto.Changeset.unique_constraint/3 msgid "has already been taken" msgstr "" -## From Ecto.Changeset.put_change/3 +## From Ecto.Changeset.put_change/3 msgid "is invalid" msgstr "" -## From Ecto.Changeset.validate_acceptance/3 +## From Ecto.Changeset.validate_acceptance/3 msgid "must be accepted" msgstr "" -## From Ecto.Changeset.validate_format/3 +## From Ecto.Changeset.validate_format/3 msgid "has invalid format" msgstr "" -## From Ecto.Changeset.validate_subset/3 +## From Ecto.Changeset.validate_subset/3 msgid "has an invalid entry" msgstr "" -## From Ecto.Changeset.validate_exclusion/3 +## From Ecto.Changeset.validate_exclusion/3 msgid "is reserved" msgstr "" -## From Ecto.Changeset.validate_confirmation/3 +## From Ecto.Changeset.validate_confirmation/3 msgid "does not match confirmation" msgstr "" -## From Ecto.Changeset.no_assoc_constraint/3 +## From Ecto.Changeset.no_assoc_constraint/3 msgid "is still associated with this entry" msgstr "" msgid "are still associated with this entry" msgstr "" -## From Ecto.Changeset.validate_length/3 +## From Ecto.Changeset.validate_length/3 msgid "should be %{count} character(s)" msgid_plural "should be %{count} character(s)" msgstr[0] "" @@ -77,7 +77,7 @@ msgid_plural "should have at most %{count} item(s)" msgstr[0] "" msgstr[1] "" -## From Ecto.Changeset.validate_number/3 +## From Ecto.Changeset.validate_number/3 msgid "must be less than %{number}" msgstr "" diff --git a/apps/block_scout_web/test/block_scout_web/controllers/address_transaction_controller_test.exs b/apps/block_scout_web/test/block_scout_web/controllers/address_transaction_controller_test.exs index a29d6b9be6..63a27c7f7b 100644 --- a/apps/block_scout_web/test/block_scout_web/controllers/address_transaction_controller_test.exs +++ b/apps/block_scout_web/test/block_scout_web/controllers/address_transaction_controller_test.exs @@ -13,10 +13,16 @@ defmodule BlockScoutWeb.AddressTransactionControllerTest do assert html_response(conn, 422) end - test "with valid address hash without address", %{conn: conn} do - conn = get(conn, address_transaction_path(conn, :index, "0x8bf38d4764929064f2d4d3a56520a76ab3df415b")) + test "with valid address hash without address in the DB", %{conn: conn} do + conn = + get( + conn, + address_transaction_path(conn, :index, "0x8bf38d4764929064f2d4d3a56520a76ab3df415b", %{"type" => "JSON"}) + ) - assert html_response(conn, 404) + assert json_response(conn, 200) + transaction_tiles = json_response(conn, 200)["items"] + assert transaction_tiles |> length() == 0 end test "returns transactions for the address", %{conn: conn} do diff --git a/apps/block_scout_web/test/block_scout_web/controllers/api/v1/health_controller_test.exs b/apps/block_scout_web/test/block_scout_web/controllers/api/v1/health_controller_test.exs index 41735f685a..19631ff746 100644 --- a/apps/block_scout_web/test/block_scout_web/controllers/api/v1/health_controller_test.exs +++ b/apps/block_scout_web/test/block_scout_web/controllers/api/v1/health_controller_test.exs @@ -1,6 +1,15 @@ defmodule BlockScoutWeb.API.V1.HealthControllerTest do use BlockScoutWeb.ConnCase + alias Explorer.{Chain, PagingOptions} + + setup do + Supervisor.terminate_child(Explorer.Supervisor, {ConCache, Explorer.Chain.Cache.Blocks.cache_name()}) + Supervisor.restart_child(Explorer.Supervisor, {ConCache, Explorer.Chain.Cache.Blocks.cache_name()}) + + :ok + end + describe "GET last_block_status/0" do test "returns error when there are no blocks in db", %{conn: conn} do request = get(conn, api_v1_health_path(conn, :health)) @@ -32,19 +41,50 @@ defmodule BlockScoutWeb.API.V1.HealthControllerTest do end test "returns ok when last block is not stale", %{conn: conn} do - insert(:block, consensus: true, timestamp: DateTime.utc_now()) + block1 = insert(:block, consensus: true, timestamp: DateTime.utc_now(), number: 2) + insert(:block, consensus: true, timestamp: DateTime.utc_now(), number: 1) request = get(conn, api_v1_health_path(conn, :health)) assert request.status == 200 + result = Poison.decode!(request.resp_body) + + assert result["healthy"] == true + assert %{ - "healthy" => true, - "data" => %{ - "latest_block_number" => _, - "latest_block_inserted_at" => _ - } - } = Poison.decode!(request.resp_body) + "latest_block_number" => to_string(block1.number), + "latest_block_inserted_at" => to_string(block1.timestamp), + "cache_latest_block_number" => to_string(block1.number), + "cache_latest_block_inserted_at" => to_string(block1.timestamp) + } == result["data"] end end + + test "return error when cache is stale", %{conn: conn} do + stale_block = insert(:block, consensus: true, timestamp: Timex.shift(DateTime.utc_now(), hours: -50), number: 3) + state_block_hash = stale_block.hash + + assert [%{hash: ^state_block_hash}] = Chain.list_blocks(paging_options: %PagingOptions{page_size: 1}) + + insert(:block, consensus: true, timestamp: DateTime.utc_now(), number: 1) + + assert [%{hash: ^state_block_hash}] = Chain.list_blocks(paging_options: %PagingOptions{page_size: 1}) + + request = get(conn, api_v1_health_path(conn, :health)) + + assert request.status == 500 + + assert %{ + "healthy" => false, + "error_code" => 5001, + "error_title" => "blocks fetching is stuck", + "error_description" => + "There are no new blocks in the DB for the last 5 mins. Check the healthiness of Ethereum archive node or the Blockscout DB instance", + "data" => %{ + "latest_block_number" => _, + "latest_block_inserted_at" => _ + } + } = Poison.decode!(request.resp_body) + end end diff --git a/apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/geth/call.ex b/apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/geth/call.ex index 1555ea6c8f..c83b157324 100644 --- a/apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/geth/call.ex +++ b/apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/geth/call.ex @@ -426,13 +426,14 @@ defmodule EthereumJSONRPC.Geth.Call do "transactionHash" => transaction_hash, "index" => index, "traceAddress" => trace_address, - "type" => "create" = type, + "type" => type, "from" => from_address_hash, "error" => error, "gas" => gas, "init" => init, "value" => value - }) do + }) + when type in ~w(create create2) do %{ block_number: block_number, transaction_index: transaction_index, @@ -454,7 +455,7 @@ defmodule EthereumJSONRPC.Geth.Call do "transactionHash" => transaction_hash, "index" => index, "traceAddress" => trace_address, - "type" => "create", + "type" => type, "from" => from_address_hash, "createdContractAddressHash" => created_contract_address_hash, "gas" => gas, @@ -462,14 +463,15 @@ defmodule EthereumJSONRPC.Geth.Call do "init" => init, "createdContractCode" => created_contract_code, "value" => value - }) do + }) + when type in ~w(create create2) do %{ block_number: block_number, transaction_index: transaction_index, transaction_hash: transaction_hash, index: index, trace_address: trace_address, - type: "create", + type: type, from_address_hash: from_address_hash, gas: gas, gas_used: gas_used, diff --git a/apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/geth/tracer.ex b/apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/geth/tracer.ex index 6545250b4a..cbc43fa71d 100644 --- a/apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/geth/tracer.ex +++ b/apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/geth/tracer.ex @@ -113,6 +113,7 @@ defmodule EthereumJSONRPC.Geth.Tracer do end defp op(%{"op" => "CREATE"} = log, ctx), do: create_op(log, ctx) + defp op(%{"op" => "CREATE2"} = log, ctx), do: create_op(log, ctx, "create2") 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) @@ -155,7 +156,8 @@ defmodule EthereumJSONRPC.Geth.Tracer do defp create_op( %{"stack" => log_stack, "memory" => log_memory}, - %{depth: stack_depth, stack: stack, trace_address: trace_address, calls: calls} = ctx + %{depth: stack_depth, stack: stack, trace_address: trace_address, calls: calls} = ctx, + type \\ "create" ) do [value, input_offset, input_length | _] = Enum.reverse(log_stack) @@ -165,7 +167,7 @@ defmodule EthereumJSONRPC.Geth.Tracer do |> String.slice(quantity_to_integer("0x" <> input_offset) * 2, quantity_to_integer("0x" <> input_length) * 2) call = %{ - "type" => "create", + "type" => type, "from" => nil, "traceAddress" => Enum.reverse(trace_address), "init" => "0x" <> init, diff --git a/apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/transaction.ex b/apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/transaction.ex index f021bfa153..7992c0e63c 100644 --- a/apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/transaction.ex +++ b/apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/transaction.ex @@ -353,4 +353,8 @@ defmodule EthereumJSONRPC.Transaction do _ -> {key, quantity_to_integer(chain_id)} end end + + defp entry_to_elixir(_) do + {nil, nil} + end end diff --git a/apps/ethereum_jsonrpc/mix.exs b/apps/ethereum_jsonrpc/mix.exs index 7c2299c4a8..58dcff8fd5 100644 --- a/apps/ethereum_jsonrpc/mix.exs +++ b/apps/ethereum_jsonrpc/mix.exs @@ -82,7 +82,7 @@ defmodule EthereumJsonrpc.MixProject do # `:spandex` integration with Datadog {:spandex_datadog, "~> 0.4.0"}, # Convert unix timestamps in JSONRPC to DateTimes - {:timex, "~> 3.4"}, + {:timex, "~> 3.6"}, # Encode/decode function names and arguments {:ex_abi, "~> 0.1.18"}, # `:verify_fun` for `Socket.Web.connect` diff --git a/apps/ethereum_jsonrpc/priv/js/ethereum_jsonrpc/geth/debug_traceTransaction/tracer.js b/apps/ethereum_jsonrpc/priv/js/ethereum_jsonrpc/geth/debug_traceTransaction/tracer.js index 15db7d8ff9..5c3c98f871 100644 --- a/apps/ethereum_jsonrpc/priv/js/ethereum_jsonrpc/geth/debug_traceTransaction/tracer.js +++ b/apps/ethereum_jsonrpc/priv/js/ethereum_jsonrpc/geth/debug_traceTransaction/tracer.js @@ -91,6 +91,9 @@ case 'CREATE': this.createOp(log); break; + case 'CREATE2': + this.create2Op(log); + break; case 'SELFDESTRUCT': this.selfDestructOp(log, db); break; @@ -127,7 +130,7 @@ const ret = log.stack.peek(0); if (!ret.equals(0)) { - if (call.type === 'create') { + if (call.type === 'create' || call.type === 'create2') { call.createdContractAddressHash = toHex(toAddress(ret.toString(16))); call.createdContractCode = toHex(db.getCode(toAddress(ret.toString(16)))); } else { @@ -162,6 +165,21 @@ this.callStack.push(call); }, + create2Op(log) { + const inputOffset = log.stack.peek(1).valueOf(); + const inputLength = log.stack.peek(2).valueOf(); + const inputEnd = inputOffset + inputLength; + const stackValue = log.stack.peek(0); + + const call = { + type: 'create2', + from: toHex(log.contract.getAddress()), + init: toHex(log.memory.slice(inputOffset, inputEnd)), + valueBigInt: bigInt(stackValue.toString(10)) + }; + this.callStack.push(call); + }, + selfDestructOp(log, db) { const contractAddress = log.contract.getAddress(); @@ -243,6 +261,9 @@ case 'CREATE': result = this.ctxToCreate(ctx, db); break; + case 'CREATE2': + result = this.ctxToCreate2(ctx, db); + break; } return result; @@ -292,6 +313,22 @@ return result; }, + ctxToCreate2(ctx, db) { + const result = { + type: 'create2', + from: toHex(ctx.from), + init: toHex(ctx.input), + valueBigInt: bigInt(ctx.value.toString(10)), + gasBigInt: bigInt(ctx.gas), + gasUsedBigInt: bigInt(ctx.gasUsed) + }; + + this.putBottomChildCalls(result); + this.putErrorOrCreatedContract(result, ctx, db); + + return result; + }, + putBottomChildCalls(result) { const bottomCall = this.bottomCall(); const bottomChildCalls = bottomCall.calls; @@ -422,4 +459,3 @@ call.gasUsed = '0x' + gasUsedBigInt.toString(16); } } - diff --git a/apps/ethereum_jsonrpc/test/ethereum_jsonrpc/transaction_test.exs b/apps/ethereum_jsonrpc/test/ethereum_jsonrpc/transaction_test.exs index ad7780181d..a8a8fcdfd2 100644 --- a/apps/ethereum_jsonrpc/test/ethereum_jsonrpc/transaction_test.exs +++ b/apps/ethereum_jsonrpc/test/ethereum_jsonrpc/transaction_test.exs @@ -2,4 +2,14 @@ defmodule EthereumJSONRPC.TransactionTest do use ExUnit.Case, async: true doctest EthereumJSONRPC.Transaction + + alias EthereumJSONRPC.Transaction + + describe "to_elixir/1" do + test "skips unsupported keys" do + map = %{"key" => "value", "key1" => "value1"} + + assert %{nil: nil} = Transaction.to_elixir(map) + end + end end diff --git a/apps/explorer/config/config.exs b/apps/explorer/config/config.exs index defd5ae9e5..fed5124a2a 100644 --- a/apps/explorer/config/config.exs +++ b/apps/explorer/config/config.exs @@ -17,7 +17,15 @@ config :explorer, if(System.get_env("UNCLES_IN_AVERAGE_BLOCK_TIME") == "false", do: false, else: true), healthy_blocks_period: System.get_env("HEALTHY_BLOCKS_PERIOD") || :timer.minutes(5) -config :explorer, Explorer.Counters.AverageBlockTime, enabled: true +average_block_period = + case Integer.parse(System.get_env("AVERAGE_BLOCK_CACHE_PERIOD", "")) do + {secs, ""} -> :timer.seconds(secs) + _ -> :timer.minutes(30) + end + +config :explorer, Explorer.Counters.AverageBlockTime, + enabled: true, + period: average_block_period config :explorer, Explorer.Chain.Cache.BlockNumber, enabled: true @@ -106,6 +114,14 @@ config :spandex_ecto, SpandexEcto.EctoLogger, tracer: Explorer.Tracer, otp_app: :explorer +market_history_cache_period = + case Integer.parse(System.get_env("MARKET_HISTORY_CACHE_PERIOD", "")) do + {secs, ""} -> :timer.seconds(secs) + _ -> :timer.hours(6) + end + +config :explorer, Explorer.Market.MarketHistoryCache, period: market_history_cache_period + # Import environment specific config. This must remain at the bottom # of this file so it overrides the configuration defined above. import_config "#{Mix.env()}.exs" diff --git a/apps/explorer/lib/explorer/chain.ex b/apps/explorer/lib/explorer/chain.ex index 17116658bf..c2e480957d 100644 --- a/apps/explorer/lib/explorer/chain.ex +++ b/apps/explorer/lib/explorer/chain.ex @@ -273,7 +273,7 @@ defmodule Explorer.Chain do from(log in Log, inner_join: transaction in assoc(log, :transaction), order_by: [desc: transaction.block_number, desc: transaction.index], - preload: [:transaction], + preload: [:transaction, transaction: [to_address: :smart_contract]], where: transaction.block_number < ^block_number, or_where: transaction.block_number == ^block_number and transaction.index > ^transaction_index, or_where: @@ -364,8 +364,8 @@ defmodule Explorer.Chain do Uncles are not currently accounted for. """ - @spec block_reward(Block.t()) :: Wei.t() - def block_reward(%Block{number: block_number}) do + @spec block_reward(Block.block_number()) :: Wei.t() + def block_reward(block_number) do query = from( block in Block, @@ -415,8 +415,8 @@ defmodule Explorer.Chain do `:key` (a tuple of the lowest/oldest `{index}`) and. Results will be the transactions older than the `index` that are passed. """ - @spec block_to_transactions(Block.t(), [paging_options | necessity_by_association_option]) :: [Transaction.t()] - def block_to_transactions(%Block{hash: block_hash}, options \\ []) when is_list(options) do + @spec block_to_transactions(Hash.Full.t(), [paging_options | necessity_by_association_option]) :: [Transaction.t()] + def block_to_transactions(block_hash, options \\ []) when is_list(options) do necessity_by_association = Keyword.get(options, :necessity_by_association, %{}) options @@ -432,8 +432,8 @@ defmodule Explorer.Chain do @doc """ Counts the number of `t:Explorer.Chain.Transaction.t/0` in the `block`. """ - @spec block_to_transaction_count(Block.t()) :: non_neg_integer() - def block_to_transaction_count(%Block{hash: block_hash}) do + @spec block_to_transaction_count(Hash.Full.t()) :: non_neg_integer() + def block_to_transaction_count(block_hash) do query = from( transaction in Transaction, @@ -843,7 +843,7 @@ defmodule Explorer.Chain do Returns `{:error, :not_found}` if there is no address by that hash present. Returns `{:error, :no_balance}` if there is no balance for that address at that block. """ - @spec get_balance_as_of_block(Hash.Address.t(), integer | :earliest | :latest | :pending) :: + @spec get_balance_as_of_block(Hash.Address.t(), Block.block_number() | :earliest | :latest | :pending) :: {:ok, Wei.t()} | {:error, :no_balance} | {:error, :not_found} def get_balance_as_of_block(address, block) when is_integer(block) do coin_balance_query = @@ -930,33 +930,44 @@ defmodule Explorer.Chain do Repo.all(query) end - @spec find_contract_address(Hash.t()) :: {:ok, Address.t()} | {:error, :not_found} - def find_contract_address(%Hash{byte_count: unquote(Hash.Address.byte_count())} = hash) do + @doc """ + Finds an `t:Explorer.Chain.Address.t/0` that has the provided `t:Explorer.Chain.Address.t/0` `hash` and a contract. + + ## Options + + * `:necessity_by_association` - use to load `t:association/0` as `:required` or `:optional`. If an association is + `:required`, and the `t:Explorer.Chain.Address.t/0` has no associated record for that association, + then the `t:Explorer.Chain.Address.t/0` will not be included in the list. + + Optionally it also accepts a boolean to fetch the `has_decompiled_code?` virtual field or not + + """ + @spec find_contract_address(Hash.Address.t(), [necessity_by_association_option], boolean()) :: + {:ok, Address.t()} | {:error, :not_found} + def find_contract_address( + %Hash{byte_count: unquote(Hash.Address.byte_count())} = hash, + options \\ [], + query_decompiled_code_flag \\ false + ) do + necessity_by_association = Keyword.get(options, :necessity_by_association, %{}) + query = from( address in Address, - preload: [ - :contracts_creation_internal_transaction, - :names, - :smart_contract, - :token, - :contracts_creation_transaction - ], where: address.hash == ^hash and not is_nil(address.contract_code) ) - query_with_decompiled_flag = with_decompiled_code_flag(query, hash) - - address = Repo.one(query_with_decompiled_flag) - - if address do - {:ok, address} - else - {:error, :not_found} + query + |> join_associations(necessity_by_association) + |> with_decompiled_code_flag(hash, query_decompiled_code_flag) + |> Repo.one() + |> case do + nil -> {:error, :not_found} + address -> {:ok, address} end end - @spec find_decompiled_contract_address(Hash.t()) :: {:ok, Address.t()} | {:error, :not_found} + @spec find_decompiled_contract_address(Hash.Address.t()) :: {:ok, Address.t()} | {:error, :not_found} def find_decompiled_contract_address(%Hash{byte_count: unquote(Hash.Address.byte_count())} = hash) do query = from( @@ -1807,7 +1818,7 @@ defmodule Explorer.Chain do Repo.one!(query) end - def last_block_status do + def last_db_block_status do query = from(block in Block, select: {block.number, block.timestamp}, @@ -1816,22 +1827,39 @@ defmodule Explorer.Chain do limit: 1 ) - case Repo.one(query) do - nil -> - {:error, :no_blocks} + query + |> Repo.one() + |> block_status() + end - {number, timestamp} -> - now = DateTime.utc_now() - last_block_period = DateTime.diff(now, timestamp, :millisecond) + def last_cache_block_status do + [ + paging_options: %PagingOptions{page_size: 1} + ] + |> list_blocks() + |> List.last() + |> case do + %{timestamp: timestamp, number: number} -> + block_status({number, timestamp}) - if last_block_period > Application.get_env(:explorer, :healthy_blocks_period) do - {:error, number, timestamp} - else - {:ok, number, timestamp} - end + _ -> + block_status(nil) end end + defp block_status({number, timestamp}) do + now = DateTime.utc_now() + last_block_period = DateTime.diff(now, timestamp, :millisecond) + + if last_block_period > Application.get_env(:explorer, :healthy_blocks_period) do + {:error, number, timestamp} + else + {:ok, number, timestamp} + end + end + + defp block_status(nil), do: {:error, :no_blocks} + @doc """ Calculates the ranges of missing consensus blocks in `range`. @@ -2209,14 +2237,10 @@ defmodule Explorer.Chain do """ - @spec transaction_to_internal_transactions(Transaction.t(), [paging_options | necessity_by_association_option]) :: [ + @spec transaction_to_internal_transactions(Hash.Full.t(), [paging_options | necessity_by_association_option]) :: [ InternalTransaction.t() ] - def transaction_to_internal_transactions( - %Transaction{hash: %Hash{byte_count: unquote(Hash.Full.byte_count())} = hash}, - options \\ [] - ) - when is_list(options) do + def transaction_to_internal_transactions(hash, options \\ []) when is_list(options) do necessity_by_association = Keyword.get(options, :necessity_by_association, %{}) paging_options = Keyword.get(options, :paging_options, @default_paging_options) @@ -2244,12 +2268,8 @@ defmodule Explorer.Chain do the `index` that are passed. """ - @spec transaction_to_logs(Transaction.t(), [paging_options | necessity_by_association_option]) :: [Log.t()] - def transaction_to_logs( - %Transaction{hash: %Hash{byte_count: unquote(Hash.Full.byte_count())} = transaction_hash}, - options \\ [] - ) - when is_list(options) do + @spec transaction_to_logs(Hash.Full.t(), [paging_options | necessity_by_association_option]) :: [Log.t()] + def transaction_to_logs(transaction_hash, options \\ []) when is_list(options) do necessity_by_association = Keyword.get(options, :necessity_by_association, %{}) paging_options = Keyword.get(options, :paging_options, @default_paging_options) @@ -2276,14 +2296,10 @@ defmodule Explorer.Chain do the `index` that are passed. """ - @spec transaction_to_token_transfers(Transaction.t(), [paging_options | necessity_by_association_option]) :: [ + @spec transaction_to_token_transfers(Hash.Full.t(), [paging_options | necessity_by_association_option]) :: [ TokenTransfer.t() ] - def transaction_to_token_transfers( - %Transaction{hash: %Hash{byte_count: unquote(Hash.Full.byte_count())} = transaction_hash}, - options \\ [] - ) - when is_list(options) do + def transaction_to_token_transfers(transaction_hash, options \\ []) when is_list(options) do necessity_by_association = Keyword.get(options, :necessity_by_association, %{}) paging_options = Keyword.get(options, :paging_options, @default_paging_options) @@ -2510,16 +2526,16 @@ defmodule Explorer.Chain do |> repo.insert(on_conflict: :nothing, conflict_target: [:address_hash, :name]) end - @spec address_hash_to_address_with_source_code(%Explorer.Chain.Hash{}) :: %Explorer.Chain.Address{} | nil - def address_hash_to_address_with_source_code(%Explorer.Chain.Hash{} = address_hash) do + @spec address_hash_to_address_with_source_code(Hash.Address.t()) :: Address.t() | nil + def address_hash_to_address_with_source_code(address_hash) do case Repo.get(Address, address_hash) do nil -> nil address -> Repo.preload(address, [:smart_contract, :decompiled_smart_contracts]) end end - @spec address_hash_to_smart_contract(%Explorer.Chain.Hash{}) :: %Explorer.Chain.SmartContract{} | nil - def address_hash_to_smart_contract(%Explorer.Chain.Hash{} = address_hash) do + @spec address_hash_to_smart_contract(Hash.Address.t()) :: SmartContract.t() | nil + def address_hash_to_smart_contract(address_hash) do query = from( smart_contract in SmartContract, @@ -3276,8 +3292,6 @@ defmodule Explorer.Chain do defp staking_pool_filter(query, _), do: query - defp with_decompiled_code_flag(query, hash, use_option \\ true) - defp with_decompiled_code_flag(query, _hash, false), do: query defp with_decompiled_code_flag(query, hash, true) do @@ -3300,4 +3314,203 @@ defmodule Explorer.Chain do |> Base.decode16!(case: :mixed) |> TypeDecoder.decode_raw(types) end + + @doc """ + Checks if an `t:Explorer.Chain.Address.t/0` with the given `hash` exists. + + Returns `:ok` if found + + iex> {:ok, %Explorer.Chain.Address{hash: hash}} = Explorer.Chain.create_address( + ...> %{hash: "0x5aaeb6053f3e94c9b9a09f33669435e7ef1beaed"} + ...> ) + iex> Explorer.Chain.check_address_exists(hash) + :ok + + Returns `:not_found` if not found + + iex> {:ok, hash} = Explorer.Chain.string_to_address_hash("0x5aaeb6053f3e94c9b9a09f33669435e7ef1beaed") + iex> Explorer.Chain.check_address_exists(hash) + :not_found + + """ + @spec check_address_exists(Hash.Address.t()) :: :ok | :not_found + def check_address_exists(address_hash) do + address_hash + |> address_exists?() + |> boolean_to_check_result() + end + + @doc """ + Checks if an `t:Explorer.Chain.Address.t/0` with the given `hash` exists. + + Returns `true` if found + + iex> {:ok, %Explorer.Chain.Address{hash: hash}} = Explorer.Chain.create_address( + ...> %{hash: "0x5aaeb6053f3e94c9b9a09f33669435e7ef1beaed"} + ...> ) + iex> Explorer.Chain.address_exists?(hash) + true + + Returns `false` if not found + + iex> {:ok, hash} = Explorer.Chain.string_to_address_hash("0x5aaeb6053f3e94c9b9a09f33669435e7ef1beaed") + iex> Explorer.Chain.address_exists?(hash) + false + + """ + @spec address_exists?(Hash.Address.t()) :: boolean() + def address_exists?(address_hash) do + query = + from( + address in Address, + where: address.hash == ^address_hash + ) + + Repo.exists?(query) + end + + @doc """ + Checks if it exists an `t:Explorer.Chain.Address.t/0` that has the provided + `t:Explorer.Chain.Address.t/0` `hash` and a contract. + + Returns `:ok` if found and `:not_found` otherwise. + """ + @spec check_contract_address_exists(Hash.Address.t()) :: :ok | :not_found + def check_contract_address_exists(address_hash) do + address_hash + |> contract_address_exists?() + |> boolean_to_check_result() + end + + @doc """ + Checks if it exists an `t:Explorer.Chain.Address.t/0` that has the provided + `t:Explorer.Chain.Address.t/0` `hash` and a contract. + + Returns `true` if found and `false` otherwise. + """ + @spec contract_address_exists?(Hash.Address.t()) :: boolean() + def contract_address_exists?(address_hash) do + query = + from( + address in Address, + where: address.hash == ^address_hash and not is_nil(address.contract_code) + ) + + Repo.exists?(query) + end + + @doc """ + Checks if it exists a `t:Explorer.Chain.DecompiledSmartContract.t/0` for the + `t:Explorer.Chain.Address.t/0` with the provided `hash` and with the provided version. + + Returns `:ok` if found and `:not_found` otherwise. + """ + @spec check_decompiled_contract_exists(Hash.Address.t(), String.t()) :: :ok | :not_found + def check_decompiled_contract_exists(address_hash, version) do + address_hash + |> decompiled_contract_exists?(version) + |> boolean_to_check_result() + end + + @doc """ + Checks if it exists a `t:Explorer.Chain.DecompiledSmartContract.t/0` for the + `t:Explorer.Chain.Address.t/0` with the provided `hash` and with the provided version. + + Returns `true` if found and `false` otherwise. + """ + @spec decompiled_contract_exists?(Hash.Address.t(), String.t()) :: boolean() + def decompiled_contract_exists?(address_hash, version) do + query = + from(contract in DecompiledSmartContract, + where: contract.address_hash == ^address_hash and contract.decompiler_version == ^version + ) + + Repo.exists?(query) + end + + @doc """ + Checks if it exists a verified `t:Explorer.Chain.SmartContract.t/0` for the + `t:Explorer.Chain.Address.t/0` with the provided `hash`. + + Returns `:ok` if found and `:not_found` otherwise. + """ + @spec check_verified_smart_contract_exists(Hash.Address.t()) :: :ok | :not_found + def check_verified_smart_contract_exists(address_hash) do + address_hash + |> verified_smart_contract_exists?() + |> boolean_to_check_result() + end + + @doc """ + Checks if it exists a verified `t:Explorer.Chain.SmartContract.t/0` for the + `t:Explorer.Chain.Address.t/0` with the provided `hash`. + + Returns `true` if found and `false` otherwise. + """ + @spec verified_smart_contract_exists?(Hash.Address.t()) :: boolean() + def verified_smart_contract_exists?(address_hash) do + query = + from( + smart_contract in SmartContract, + where: smart_contract.address_hash == ^address_hash + ) + + Repo.exists?(query) + end + + @doc """ + Checks if a `t:Explorer.Chain.Transaction.t/0` with the given `hash` exists. + + Returns `:ok` if found + + iex> %Transaction{hash: hash} = insert(:transaction) + iex> Explorer.Chain.check_transaction_exists(hash) + :ok + + Returns `:not_found` if not found + + iex> {:ok, hash} = Explorer.Chain.string_to_transaction_hash( + ...> "0x9fc76417374aa880d4449a1f7f31ec597f00b1f6f3dd2d66f4c9c6c445836d8b" + ...> ) + iex> Explorer.Chain.check_transaction_exists(hash) + :not_found + """ + @spec check_transaction_exists(Hash.Full.t()) :: :ok | :not_found + def check_transaction_exists(hash) do + hash + |> transaction_exists?() + |> boolean_to_check_result() + end + + @doc """ + Checks if a `t:Explorer.Chain.Transaction.t/0` with the given `hash` exists. + + Returns `true` if found + + iex> %Transaction{hash: hash} = insert(:transaction) + iex> Explorer.Chain.transaction_exists?(hash) + true + + Returns `false` if not found + + iex> {:ok, hash} = Explorer.Chain.string_to_transaction_hash( + ...> "0x9fc76417374aa880d4449a1f7f31ec597f00b1f6f3dd2d66f4c9c6c445836d8b" + ...> ) + iex> Explorer.Chain.transaction_exists?(hash) + false + """ + @spec transaction_exists?(Hash.Full.t()) :: boolean() + def transaction_exists?(hash) do + query = + from( + transaction in Transaction, + where: transaction.hash == ^hash + ) + + Repo.exists?(query) + end + + defp boolean_to_check_result(true), do: :ok + + defp boolean_to_check_result(false), do: :not_found end diff --git a/apps/explorer/lib/explorer/chain/internal_transaction.ex b/apps/explorer/lib/explorer/chain/internal_transaction.ex index 1231677a57..77f7d15da2 100644 --- a/apps/explorer/lib/explorer/chain/internal_transaction.ex +++ b/apps/explorer/lib/explorer/chain/internal_transaction.ex @@ -392,7 +392,7 @@ defmodule Explorer.Chain.InternalTransaction do @create_required_fields ~w(from_address_hash gas index init trace_address transaction_hash value)a @create_allowed_fields @create_optional_fields ++ @create_required_fields - defp type_changeset(changeset, attrs, :create) do + defp type_changeset(changeset, attrs, type) when type in [:create, :create2] do changeset |> cast(attrs, @create_allowed_fields) |> validate_required(@create_required_fields) @@ -537,7 +537,7 @@ defmodule Explorer.Chain.InternalTransaction do |> put_raw_call_error_or_result(transaction) end - defp internal_transaction_to_raw(%{type: :create} = transaction) do + defp internal_transaction_to_raw(%{type: type} = transaction) when type in [:create, :create2] do %{ from_address_hash: from_address_hash, gas: gas, @@ -549,7 +549,7 @@ defmodule Explorer.Chain.InternalTransaction do action = %{"from" => from_address_hash, "gas" => gas, "init" => init, "value" => value} %{ - "type" => "create", + "type" => Atom.to_string(type), "action" => Action.to_raw(action), "traceAddress" => trace_address } diff --git a/apps/explorer/lib/explorer/chain/internal_transaction/type.ex b/apps/explorer/lib/explorer/chain/internal_transaction/type.ex index 4133dcf45f..0a13587afe 100644 --- a/apps/explorer/lib/explorer/chain/internal_transaction/type.ex +++ b/apps/explorer/lib/explorer/chain/internal_transaction/type.ex @@ -11,7 +11,7 @@ defmodule Explorer.Chain.InternalTransaction.Type do * `:reward` * `:selfdestruct` """ - @type t :: :call | :create | :reward | :selfdestruct + @type t :: :call | :create | :create2 | :reward | :selfdestruct @doc """ Casts `term` to `t:t/0` @@ -22,6 +22,8 @@ defmodule Explorer.Chain.InternalTransaction.Type do {:ok, :call} iex> Explorer.Chain.InternalTransaction.Type.cast(:create) {:ok, :create} + iex> Explorer.Chain.InternalTransaction.Type.cast(:create2) + {:ok, :create2} iex> Explorer.Chain.InternalTransaction.Type.cast(:reward) {:ok, :reward} iex> Explorer.Chain.InternalTransaction.Type.cast(:selfdestruct) @@ -33,6 +35,8 @@ defmodule Explorer.Chain.InternalTransaction.Type do {:ok, :call} iex> Explorer.Chain.InternalTransaction.Type.cast("create") {:ok, :create} + iex> Explorer.Chain.InternalTransaction.Type.cast("create2") + {:ok, :create2} iex> Explorer.Chain.InternalTransaction.Type.cast("reward") {:ok, :reward} iex> Explorer.Chain.InternalTransaction.Type.cast("selfdestruct") @@ -53,9 +57,10 @@ defmodule Explorer.Chain.InternalTransaction.Type do """ @impl Ecto.Type @spec cast(term()) :: {:ok, t()} | :error - def cast(t) when t in ~w(call create selfdestruct reward)a, do: {:ok, t} + def cast(t) when t in ~w(call create create2 selfdestruct reward)a, do: {:ok, t} def cast("call"), do: {:ok, :call} def cast("create"), do: {:ok, :create} + def cast("create2"), do: {:ok, :create2} def cast("reward"), do: {:ok, :reward} def cast("selfdestruct"), do: {:ok, :selfdestruct} def cast(_), do: :error @@ -67,6 +72,8 @@ defmodule Explorer.Chain.InternalTransaction.Type do {:ok, "call"} iex> Explorer.Chain.InternalTransaction.Type.dump(:create) {:ok, "create"} + iex> Explorer.Chain.InternalTransaction.Type.dump(:create2) + {:ok, "create2"} iex> Explorer.Chain.InternalTransaction.Type.dump(:reward) {:ok, "reward"} iex> Explorer.Chain.InternalTransaction.Type.dump(:selfdestruct) @@ -87,6 +94,7 @@ defmodule Explorer.Chain.InternalTransaction.Type do @spec dump(term()) :: {:ok, String.t()} | :error def dump(:call), do: {:ok, "call"} def dump(:create), do: {:ok, "create"} + def dump(:create2), do: {:ok, "create2"} def dump(:reward), do: {:ok, "reward"} def dump(:selfdestruct), do: {:ok, "selfdestruct"} def dump(_), do: :error @@ -98,6 +106,8 @@ defmodule Explorer.Chain.InternalTransaction.Type do {:ok, :call} iex> Explorer.Chain.InternalTransaction.Type.load("create") {:ok, :create} + iex> Explorer.Chain.InternalTransaction.Type.load("create2") + {:ok, :create2} iex> Explorer.Chain.InternalTransaction.Type.load("reward") {:ok, :reward} iex> Explorer.Chain.InternalTransaction.Type.load("selfdestruct") @@ -118,6 +128,7 @@ defmodule Explorer.Chain.InternalTransaction.Type do @spec load(term()) :: {:ok, t()} | :error def load("call"), do: {:ok, :call} def load("create"), do: {:ok, :create} + def load("create2"), do: {:ok, :create2} def load("reward"), do: {:ok, :reward} def load("selfdestruct"), do: {:ok, :selfdestruct} # deprecated diff --git a/apps/explorer/lib/explorer/counters/average_block_time.ex b/apps/explorer/lib/explorer/counters/average_block_time.ex index 233c15f8b3..1065ede2bd 100644 --- a/apps/explorer/lib/explorer/counters/average_block_time.ex +++ b/apps/explorer/lib/explorer/counters/average_block_time.ex @@ -11,7 +11,7 @@ defmodule Explorer.Counters.AverageBlockTime do alias Explorer.Repo alias Timex.Duration - @refresh_period 30 * 60 * 1_000 + @refresh_period Application.get_env(:explorer, __MODULE__)[:period] @doc """ Starts a process to periodically update the counter of the token holders. diff --git a/apps/explorer/lib/explorer/market/market_history_cache.ex b/apps/explorer/lib/explorer/market/market_history_cache.ex index 04b6193716..4ed3d9b7d2 100644 --- a/apps/explorer/lib/explorer/market/market_history_cache.ex +++ b/apps/explorer/lib/explorer/market/market_history_cache.ex @@ -12,7 +12,7 @@ defmodule Explorer.Market.MarketHistoryCache do @last_update_key :last_update @history_key :history # 6 hours - @cache_period 1_000 * 60 * 60 * 6 + @cache_period Application.get_env(:explorer, __MODULE__)[:period] @recent_days 30 def fetch do diff --git a/apps/explorer/lib/explorer/smart_contract/reader.ex b/apps/explorer/lib/explorer/smart_contract/reader.ex index 72b40f55a4..cc3aae5e83 100644 --- a/apps/explorer/lib/explorer/smart_contract/reader.ex +++ b/apps/explorer/lib/explorer/smart_contract/reader.ex @@ -8,7 +8,7 @@ defmodule Explorer.SmartContract.Reader do alias EthereumJSONRPC.Contract alias Explorer.Chain - alias Explorer.Chain.Hash + alias Explorer.Chain.{Hash, SmartContract} @typedoc """ Map of functions to call with the values for the function to be called with. @@ -34,6 +34,8 @@ defmodule Explorer.SmartContract.Reader do @doc """ Queries the contract functions on the blockchain and returns the call results. + Optionally accepts the abi if it has already been fetched. + ## Examples Note that for this example to work the database must be up to date with the @@ -57,14 +59,20 @@ defmodule Explorer.SmartContract.Reader do ) # => %{"sum" => {:error, "Data overflow encoding int, data `abc` cannot fit in 256 bits"}} """ - @spec query_verified_contract(Hash.Address.t(), functions()) :: functions_results() - def query_verified_contract(address_hash, functions) do + @spec query_verified_contract(Hash.Address.t(), functions(), SmartContract.abi() | nil) :: functions_results() + def query_verified_contract(address_hash, functions, mabi \\ nil) do contract_address = Hash.to_string(address_hash) abi = - address_hash - |> Chain.address_hash_to_smart_contract() - |> Map.get(:abi) + case mabi do + nil -> + address_hash + |> Chain.address_hash_to_smart_contract() + |> Map.get(:abi) + + _ -> + mabi + end query_contract(contract_address, abi, functions) end @@ -156,41 +164,41 @@ defmodule Explorer.SmartContract.Reader do """ @spec read_only_functions(Hash.t()) :: [%{}] def read_only_functions(contract_address_hash) do - contract_address_hash - |> Chain.address_hash_to_smart_contract() - |> Map.get(:abi, []) - |> Enum.filter(& &1["constant"]) - |> fetch_current_value_from_blockchain(contract_address_hash, []) - |> Enum.reverse() - end - - def fetch_current_value_from_blockchain( - [%{"inputs" => []} = function | tail], - contract_address_hash, - acc - ) do - values = - fetch_from_blockchain(contract_address_hash, %{ - name: function["name"], - args: function["inputs"], - outputs: function["outputs"] - }) + abi = + contract_address_hash + |> Chain.address_hash_to_smart_contract() + |> Map.get(:abi) - formatted = Map.replace!(function, "outputs", values) + case abi do + nil -> + [] - fetch_current_value_from_blockchain(tail, contract_address_hash, [formatted | acc]) + _ -> + abi + |> Enum.filter(& &1["constant"]) + |> Enum.map(&fetch_current_value_from_blockchain(&1, abi, contract_address_hash)) + end end - def fetch_current_value_from_blockchain([function | tail], contract_address_hash, acc) do - values = link_outputs_and_values(%{}, Map.get(function, "outputs", []), function["name"]) + defp fetch_current_value_from_blockchain(function, abi, contract_address_hash) do + values = + case function do + %{"inputs" => []} -> + name = function["name"] + args = function["inputs"] + outputs = function["outputs"] + + contract_address_hash + |> query_verified_contract(%{name => normalize_args(args)}, abi) + |> link_outputs_and_values(outputs, name) - formatted = Map.replace!(function, "outputs", values) + _ -> + link_outputs_and_values(%{}, Map.get(function, "outputs", []), function["name"]) + end - fetch_current_value_from_blockchain(tail, contract_address_hash, [formatted | acc]) + Map.replace!(function, "outputs", values) end - def fetch_current_value_from_blockchain([], _contract_address_hash, acc), do: acc - @doc """ Fetches the blockchain value of a function that requires arguments. """ @@ -201,23 +209,27 @@ defmodule Explorer.SmartContract.Reader do @spec query_function(Hash.t(), %{name: String.t(), args: [term()]}) :: [%{}] def query_function(contract_address_hash, %{name: name, args: args}) do - function = + abi = contract_address_hash |> Chain.address_hash_to_smart_contract() - |> Map.get(:abi, []) - |> Enum.filter(fn function -> function["name"] == name end) - |> List.first() - - fetch_from_blockchain(contract_address_hash, %{ - name: name, - args: args, - outputs: function["outputs"] - }) - end + |> Map.get(:abi) + + outputs = + case abi do + nil -> + nil + + _ -> + function = + abi + |> Enum.filter(fn function -> function["name"] == name end) + |> List.first() + + function["outputs"] + end - defp fetch_from_blockchain(contract_address_hash, %{name: name, args: args, outputs: outputs}) do contract_address_hash - |> query_verified_contract(%{name => normalize_args(args)}) + |> query_verified_contract(%{name => normalize_args(args)}, abi) |> link_outputs_and_values(outputs, name) end diff --git a/apps/explorer/mix.exs b/apps/explorer/mix.exs index 4956363cc4..b9b887f838 100644 --- a/apps/explorer/mix.exs +++ b/apps/explorer/mix.exs @@ -117,7 +117,7 @@ defmodule Explorer.Mixfile do # Attach `:prometheus_ecto` to `:ecto` {:telemetry, "~> 0.3.0"}, # `Timex.Duration` for `Explorer.Counters.AverageBlockTime.average_block_time/0` - {:timex, "~> 3.4"}, + {:timex, "~> 3.6"}, {:con_cache, "~> 0.13"} ] end diff --git a/apps/explorer/test/explorer/chain_test.exs b/apps/explorer/test/explorer/chain_test.exs index 38e61dee7d..234252dbe4 100644 --- a/apps/explorer/test/explorer/chain_test.exs +++ b/apps/explorer/test/explorer/chain_test.exs @@ -50,21 +50,35 @@ defmodule Explorer.ChainTest do end end - describe "last_block_status/0" do + describe "last_db_block_status/0" do test "return no_blocks errors if db is empty" do - assert {:error, :no_blocks} = Chain.last_block_status() + assert {:error, :no_blocks} = Chain.last_db_block_status() end test "returns {:ok, last_block_period} if block is in healthy period" do insert(:block, consensus: true) - assert {:ok, _, _} = Chain.last_block_status() + assert {:ok, _, _} = Chain.last_db_block_status() end test "return {:ok, last_block_period} if block is not in healthy period" do insert(:block, consensus: true, timestamp: Timex.shift(DateTime.utc_now(), hours: -50)) - assert {:error, _, _} = Chain.last_block_status() + assert {:error, _, _} = Chain.last_db_block_status() + end + end + + describe "last_cache_block_status/0" do + test "returns success if cache is not stale" do + insert(:block, consensus: true) + + assert {:ok, _, _} = Chain.last_cache_block_status() + end + + test "return error if cache is stale" do + insert(:block, consensus: true, timestamp: Timex.shift(DateTime.utc_now(), hours: -50)) + + assert {:error, _, _} = Chain.last_cache_block_status() end end @@ -630,7 +644,7 @@ defmodule Explorer.ChainTest do assert Repo.aggregate(Transaction, :count, :hash) == 0 - assert [] = Chain.block_to_transactions(block) + assert [] = Chain.block_to_transactions(block.hash) end test "with transactions" do @@ -639,7 +653,7 @@ defmodule Explorer.ChainTest do |> insert() |> with_block() - assert [%Transaction{hash: ^transaction_hash}] = Chain.block_to_transactions(block) + assert [%Transaction{hash: ^transaction_hash}] = Chain.block_to_transactions(block.hash) end test "with transactions can be paginated by {index}" do @@ -657,7 +671,7 @@ defmodule Explorer.ChainTest do |> with_block(block) assert second_page_hashes == - block + block.hash |> Chain.block_to_transactions(paging_options: %PagingOptions{key: {index}, page_size: 50}) |> Enum.map(& &1.hash) |> Enum.reverse() @@ -683,7 +697,7 @@ defmodule Explorer.ChainTest do token: token ) - fetched_transaction = List.first(Explorer.Chain.block_to_transactions(block)) + fetched_transaction = List.first(Explorer.Chain.block_to_transactions(block.hash)) assert fetched_transaction.hash == transaction.hash assert length(fetched_transaction.token_transfers) == 2 end @@ -693,7 +707,7 @@ defmodule Explorer.ChainTest do test "without transactions" do block = insert(:block) - assert Chain.block_to_transaction_count(block) == 0 + assert Chain.block_to_transaction_count(block.hash) == 0 end test "with transactions" do @@ -702,7 +716,7 @@ defmodule Explorer.ChainTest do |> insert() |> with_block() - assert Chain.block_to_transaction_count(block) == 1 + assert Chain.block_to_transaction_count(block.hash) == 1 end end @@ -2090,7 +2104,7 @@ defmodule Explorer.ChainTest do test "with transaction without internal transactions" do transaction = insert(:transaction) - assert [] = Chain.transaction_to_internal_transactions(transaction) + assert [] = Chain.transaction_to_internal_transactions(transaction.hash) end test "with transaction with internal transactions returns all internal transactions for a given transaction hash" do @@ -2117,7 +2131,7 @@ defmodule Explorer.ChainTest do transaction_index: transaction.index ) - results = [internal_transaction | _] = Chain.transaction_to_internal_transactions(transaction) + results = [internal_transaction | _] = Chain.transaction_to_internal_transactions(transaction.hash) assert 2 == length(results) @@ -2151,7 +2165,7 @@ defmodule Explorer.ChainTest do to_address: %Ecto.Association.NotLoaded{}, transaction: %Transaction{block: %Ecto.Association.NotLoaded{}} } - ] = Chain.transaction_to_internal_transactions(transaction) + ] = Chain.transaction_to_internal_transactions(transaction.hash) assert [ %InternalTransaction{ @@ -2161,7 +2175,7 @@ defmodule Explorer.ChainTest do } ] = Chain.transaction_to_internal_transactions( - transaction, + transaction.hash, necessity_by_association: %{ :from_address => :optional, :to_address => :optional, @@ -2183,7 +2197,7 @@ defmodule Explorer.ChainTest do transaction_index: transaction.index ) - result = Chain.transaction_to_internal_transactions(transaction) + result = Chain.transaction_to_internal_transactions(transaction.hash) assert Enum.empty?(result) end @@ -2202,7 +2216,7 @@ defmodule Explorer.ChainTest do transaction_index: transaction.index ) - actual = Enum.at(Chain.transaction_to_internal_transactions(transaction), 0) + actual = Enum.at(Chain.transaction_to_internal_transactions(transaction.hash), 0) assert {actual.transaction_hash, actual.index} == {expected.transaction_hash, expected.index} end @@ -2222,7 +2236,7 @@ defmodule Explorer.ChainTest do transaction_index: transaction.index ) - actual = Enum.at(Chain.transaction_to_internal_transactions(transaction), 0) + actual = Enum.at(Chain.transaction_to_internal_transactions(transaction.hash), 0) assert {actual.transaction_hash, actual.index} == {expected.transaction_hash, expected.index} end @@ -2243,7 +2257,7 @@ defmodule Explorer.ChainTest do transaction_index: transaction.index ) - actual = Enum.at(Chain.transaction_to_internal_transactions(transaction), 0) + actual = Enum.at(Chain.transaction_to_internal_transactions(transaction.hash), 0) assert {actual.transaction_hash, actual.index} == {expected.transaction_hash, expected.index} end @@ -2271,7 +2285,7 @@ defmodule Explorer.ChainTest do ) result = - transaction + transaction.hash |> Chain.transaction_to_internal_transactions() |> Enum.map(&{&1.transaction_hash, &1.index}) @@ -2301,17 +2315,17 @@ defmodule Explorer.ChainTest do ) assert [{first_transaction_hash, first_index}, {second_transaction_hash, second_index}] == - transaction + transaction.hash |> Chain.transaction_to_internal_transactions(paging_options: %PagingOptions{key: {-1}, page_size: 2}) |> Enum.map(&{&1.transaction_hash, &1.index}) assert [{first_transaction_hash, first_index}] == - transaction + transaction.hash |> Chain.transaction_to_internal_transactions(paging_options: %PagingOptions{key: {-1}, page_size: 1}) |> Enum.map(&{&1.transaction_hash, &1.index}) assert [{second_transaction_hash, second_index}] == - transaction + transaction.hash |> Chain.transaction_to_internal_transactions(paging_options: %PagingOptions{key: {0}, page_size: 2}) |> Enum.map(&{&1.transaction_hash, &1.index}) end @@ -2321,7 +2335,7 @@ defmodule Explorer.ChainTest do test "without logs" do transaction = insert(:transaction) - assert [] = Chain.transaction_to_logs(transaction) + assert [] = Chain.transaction_to_logs(transaction.hash) end test "with logs" do @@ -2332,7 +2346,7 @@ defmodule Explorer.ChainTest do %Log{transaction_hash: transaction_hash, index: index} = insert(:log, transaction: transaction) - assert [%Log{transaction_hash: ^transaction_hash, index: ^index}] = Chain.transaction_to_logs(transaction) + assert [%Log{transaction_hash: ^transaction_hash, index: ^index}] = Chain.transaction_to_logs(transaction.hash) end test "with logs can be paginated" do @@ -2349,7 +2363,7 @@ defmodule Explorer.ChainTest do |> Enum.map(& &1.index) assert second_page_indexes == - transaction + transaction.hash |> Chain.transaction_to_logs(paging_options: %PagingOptions{key: {log.index}, page_size: 50}) |> Enum.map(& &1.index) end @@ -2364,7 +2378,7 @@ defmodule Explorer.ChainTest do assert [%Log{address: %Address{}, transaction: %Transaction{}}] = Chain.transaction_to_logs( - transaction, + transaction.hash, necessity_by_association: %{ address: :optional, transaction: :optional @@ -2376,7 +2390,7 @@ defmodule Explorer.ChainTest do address: %Ecto.Association.NotLoaded{}, transaction: %Ecto.Association.NotLoaded{} } - ] = Chain.transaction_to_logs(transaction) + ] = Chain.transaction_to_logs(transaction.hash) end end @@ -2384,7 +2398,7 @@ defmodule Explorer.ChainTest do test "without token transfers" do transaction = insert(:transaction) - assert [] = Chain.transaction_to_token_transfers(transaction) + assert [] = Chain.transaction_to_token_transfers(transaction.hash) end test "with token transfers" do @@ -2397,7 +2411,7 @@ defmodule Explorer.ChainTest do insert(:token_transfer, transaction: transaction) assert [%TokenTransfer{transaction_hash: ^transaction_hash, log_index: ^log_index}] = - Chain.transaction_to_token_transfers(transaction) + Chain.transaction_to_token_transfers(transaction.hash) end test "token transfers necessity_by_association loads associations" do @@ -2410,7 +2424,7 @@ defmodule Explorer.ChainTest do assert [%TokenTransfer{token: %Token{}, transaction: %Transaction{}}] = Chain.transaction_to_token_transfers( - transaction, + transaction.hash, necessity_by_association: %{ token: :optional, transaction: :optional @@ -2422,7 +2436,7 @@ defmodule Explorer.ChainTest do token: %Ecto.Association.NotLoaded{}, transaction: %Ecto.Association.NotLoaded{} } - ] = Chain.transaction_to_token_transfers(transaction) + ] = Chain.transaction_to_token_transfers(transaction.hash) end end @@ -2480,7 +2494,17 @@ defmodule Explorer.ChainTest do insert(:address, contract_code: Factory.data("contract_code"), smart_contract: nil, names: []) |> Repo.preload([:contracts_creation_internal_transaction, :contracts_creation_transaction, :token]) - response = Chain.find_contract_address(address.hash) + options = [ + necessity_by_association: %{ + :contracts_creation_internal_transaction => :optional, + :names => :optional, + :smart_contract => :optional, + :token => :optional, + :contracts_creation_transaction => :optional + } + ] + + response = Chain.find_contract_address(address.hash, options, true) assert response == {:ok, address} end @@ -2523,11 +2547,11 @@ defmodule Explorer.ChainTest do |> Decimal.add(Decimal.new(3)) |> Wei.from(:wei) - assert expected == Chain.block_reward(block) + assert expected == Chain.block_reward(block.number) end test "with block without transactions", %{block: block, emission_reward: emission_reward} do - assert emission_reward.reward == Chain.block_reward(block) + assert emission_reward.reward == Chain.block_reward(block.number) end end diff --git a/apps/explorer/test/explorer/smart_contract/reader_test.exs b/apps/explorer/test/explorer/smart_contract/reader_test.exs index ab63b74d1e..82f0a54385 100644 --- a/apps/explorer/test/explorer/smart_contract/reader_test.exs +++ b/apps/explorer/test/explorer/smart_contract/reader_test.exs @@ -102,7 +102,7 @@ defmodule Explorer.SmartContract.ReaderTest do end end - describe "query_verified_contract/2" do + describe "query_verified_contract/3" do test "correctly returns the results of the smart contract functions" do hash = :smart_contract diff --git a/rel/commands/clear_build.sh b/rel/commands/clear_build.sh index 5faca7ffeb..a07a11870e 100755 --- a/rel/commands/clear_build.sh +++ b/rel/commands/clear_build.sh @@ -2,11 +2,13 @@ rm -rf ./_build rm -rf ./deps -rm -rf ./logs/dev -rm -rf ./apps/explorer/node_modules -rm -rf ./apps/block_scout_web/assets/node_modules +logs=$(find . -not -path '*/\.*' -name "logs" -type d) +dev=$(find ${logs} -name "dev") +rm -rf {ls -la ${dev}} + +find . -name "node_modules" -type d -exec rm -rf '{}' + case "$1" in -f) rm -rf ./apps/block_scout_web/priv/static;; -esac \ No newline at end of file +esac