From 081126bb7398d9cb6904e96a1e54c69429d7802a Mon Sep 17 00:00:00 2001 From: ArtemKo7v Date: Mon, 26 Dec 2016 18:21:07 +0700 Subject: [PATCH 0001/1583] Error handling --- js/ethplorer.js | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/js/ethplorer.js b/js/ethplorer.js index bcff0437..ebcef8f2 100644 --- a/js/ethplorer.js +++ b/js/ethplorer.js @@ -308,6 +308,17 @@ Ethplorer = { }else{ titleAdd += 'Operation'; $('.token-operation-type').text('Operation'); + if(oTx.receipt && oTx.receipt.logs && oTx.receipt.logs.length){ + for(var i=0; i Date: Tue, 27 Dec 2016 23:42:14 +0700 Subject: [PATCH 0002/1583] Do cache unknown transactions --- service/lib/ethplorer.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/service/lib/ethplorer.php b/service/lib/ethplorer.php index 04e4df17..b200f258 100644 --- a/service/lib/ethplorer.php +++ b/service/lib/ethplorer.php @@ -224,7 +224,9 @@ public function getTransactionDetails($hash){ } } } - $this->oCache->save($cache, $result); + if($result['tx']){ + $this->oCache->save($cache, $result); + } } if(is_array($result) && is_array($result['tx'])){ $result['tx']['confirmations'] = $this->oCache->get('lastBlock') - $result['tx']['blockNumber'] + 1; From 261117edf259adacfc9a4b029de399a20691826c Mon Sep 17 00:00:00 2001 From: ArtemKo7v Date: Thu, 5 Jan 2017 20:52:07 +0700 Subject: [PATCH 0003/1583] Significant changes --- .htaccess | 6 +- README.md | 2 +- cfg/config.ethplorer.sample.js | 22 -- css/ethplorer.css | 81 +++++- index.html | 401 ---------------------------- index.php | 470 +++++++++++++++++++++++++++++++++ js/ethplorer.js | 87 ++++-- service/lib/ethplorer.php | 37 ++- 8 files changed, 627 insertions(+), 479 deletions(-) delete mode 100644 cfg/config.ethplorer.sample.js delete mode 100644 index.html create mode 100644 index.php diff --git a/.htaccess b/.htaccess index cb7910d3..f62a608f 100644 --- a/.htaccess +++ b/.htaccess @@ -6,15 +6,15 @@ RewriteRule ^api/(.*) api/index.php [L,QSA] RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d -RewriteRule ^tx/(.*) index.html [L,QSA] +RewriteRule ^tx/(.*) index.php [L,QSA] RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d -RewriteRule ^address/(.*) index.html [L,QSA] +RewriteRule ^address/(.*) index.php [L,QSA] RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d -RewriteRule ^search/(.*) index.html [L,QSA] +RewriteRule ^search/(.*) index.php [L,QSA] RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d diff --git a/README.md b/README.md index 6a9d8f44..c85f59b2 100644 --- a/README.md +++ b/README.md @@ -23,4 +23,4 @@ Make sure your web server supports .htaccess and mod_rewrite. # Configure -Copy cfg/config.ethplorer.sample.js to cfg/config.ethplorer.js and specify service addresses. +Copy service/config.sample.php to service/config.php and specify service addresses. diff --git a/cfg/config.ethplorer.sample.js b/cfg/config.ethplorer.sample.js deleted file mode 100644 index 805e1e7a..00000000 --- a/cfg/config.ethplorer.sample.js +++ /dev/null @@ -1,22 +0,0 @@ -/*! - * Copyright 2016 Everex https://everex.io - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -Ethplorer.Config = { - testnet: false, - phpService: "/service/service.php", - ga: '', - updateLink: '' -}; \ No newline at end of file diff --git a/css/ethplorer.css b/css/ethplorer.css index c8bc071a..39214a18 100644 --- a/css/ethplorer.css +++ b/css/ethplorer.css @@ -32,7 +32,7 @@ body { .content-page h3 { padding-left: 20px; padding-top: 12px; - margin-bottom: 0; + margin-bottom: 0; } .content-page .block { @@ -43,40 +43,40 @@ body { } .content-page .block-header { - padding-bottom: 10px; - background-color:white; - border-top-left-radius: 8px; - border-top-right-radius: 8px; + padding-bottom: 10px; + background-color:white; + border-top-left-radius: 8px; + border-top-right-radius: 8px; } .content-page table td { color: white; border: 0 !important; - min-width: 120px; + min-width: 120px; } .content-page table td:first-child { - padding: 8px 8px 8px 28px; + padding: 8px 8px 8px 28px; } tr.even { - background: #0f0f0f; + background: #0f0f0f; } tr.odd { - background: #1a1a1a; + background: #1a1a1a; } .content-page tr.blue { - background-color: #1396e2 !important; + background-color: #1396e2 !important; } .content-page tr.green { - background-color: #27ae60 !important; + background-color: #27ae60 !important; } .content-page tr.red { - background-color: #c0392b !important; + background-color: #c0392b !important; } .block h3 { @@ -143,6 +143,16 @@ a { text-decoration: underline; } +.nav-tabs { + margin-top: 10px; +} + +.nav-tabs li a { + text-decoration: none; + border-radius: 8px 8px 0 0; +} + + a.local-link, a.local-link:visited, a.local-link:hover { color: white; } @@ -276,9 +286,46 @@ a.dashed { } #ethplorer-path { + display: none; + padding: 16px; overflow: hidden; text-overflow: ellipsis; max-width: 100vw; + background-color: white; + border-radius: 8px; + text-align: center; + font-size: 22px; + margin-top: 10px; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis +} + +.arrow-in { + color: #00ff00; +} +.arrow-in:before { + content: '↑'; +} +.arrow-out { + color: #ff0000; +} +.arrow-out:before { + content: '↓'; +} + +.block-header.clickable.closed { + background: black; + color: white; +} + +.block-header.clickable h3 { + display: inline-block; + border-bottom: 1px dashed; + padding: 0px; + margin-left: 20px; + margin-top: 12px; + cursor: pointer; } .hash-from-to { @@ -363,6 +410,9 @@ a.dashed { } @media screen and (max-width: 991px) { + #ethplorer-path { + font-size: 18px; + } .address-token { display: none; } @@ -407,7 +457,9 @@ a.dashed { #address-token-transfers td { font-size: 11px; } - + #ethplorer-path { + font-size: 14px; + } td.list-field { overflow: hidden; max-width: 34vw; @@ -451,6 +503,9 @@ a.token-update { } @media screen and (max-width: 767px) { + #ethplorer-path { + font-size: 16px; + } .multiop tr td:nth-child(3), .multiop tr td:nth-child(4) diff --git a/index.html b/index.html deleted file mode 100644 index bbb12bff..00000000 --- a/index.html +++ /dev/null @@ -1,401 +0,0 @@ - - - - Ethplorer - - - - - - - - - - - - - - - - - - - - -
- -
-
-
-
-
-
search in progress...
-
- -
-

-

-
- -
- -
-
-
-

Internal operations

-
- -
-
-
- -
-
- - - - - - - - - - - - - - - - - - - - - - - - - - -
URL
SHA256 Hash
Filename
Filesize
Data
Short Link
-
-
- - -
-
-

Transaction details

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Tx
Date
Message
Block - ( confirmations) -
From
To
Creates
Value
Gas Limit
Gas Used
Gas Price
TX Fee
Nonce
Parsed Data -

-                                
Input Data - ASCII -

-                                
Status
-
-
-
- -
-
-
-

Information

- - - - - - - - - - - - - - - - - - - - - -
Creator
Balance
Transactions
Transactions
-
-
-
-
-

Token Balances

-
-
-
-

Token Information

- - - - - - - - - - - - - - - - - - - - -
Symbol
Decimals
Owner
Total Supply
-
-
- - -
-
-

Token Issuances

-
-
- * all dates are displayed for timezone -
- -
-
-
-
-
- - - -
- - - - - - - - diff --git a/index.php b/index.php new file mode 100644 index 00000000..ae343fb4 --- /dev/null +++ b/index.php @@ -0,0 +1,470 @@ +isValidTransactionHash($rParts[2])){ + $header = "Transaction hash: " . $rParts[2]; + $error = FALSE; + } + if(('address' === $rParts[1]) && $es->isValidAddress($rParts[2])){ + $header = "Address: " . $rParts[2]; + $error = FALSE; + } + if(('token' === $rParts[1]) && $es->isValidAddress($rParts[2])){ + $header = "Token address: " . $rParts[2]; + $error = FALSE; + } +} +if($error){ + // @todo: normal error message + die('Invalid request'); +} + +?> + + + Ethplorer<?php if($header){ echo ": " . $header; } ?> + + + + + + + + + + + + + + + + + + + + +
+ +
+
+
+ +
+
+
search in progress...
+
+ +
+

+

+
+ +
+
+

+
+
+ +
+ + +
+ +
+
+
+
+

Internal operations

+
+ +
+
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
URL
SHA256 Hash
Filename
Filesize
Data
Short Link
+
+
+ + +
+ + +
+
+
+

Transaction details

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ +
+
+
+

Information

+ + + + + + + + + + + + + + + + + + + + + +
Creator
Balance
Transactions
Transactions
+
+
+
+
+

Token Balances

+
+
+
+

Token Information

+ + + + + + + + + + + + + + + + + + + + +
Symbol
Decimals
Owner
Total Supply
+
+
+ + + +
+
+

Token Issuances

+
+
+ * all dates are displayed for timezone +
+ +
+
+
+
+
+ + + +
+ + + + + + + + diff --git a/js/ethplorer.js b/js/ethplorer.js index ebcef8f2..9d3f6448 100644 --- a/js/ethplorer.js +++ b/js/ethplorer.js @@ -15,6 +15,7 @@ */ Ethplorer = { + service: "/service/service.php", init: function(){ BigNumber.config({ ERRORS: false }); Ethplorer.route(); @@ -28,6 +29,34 @@ Ethplorer = { $(this).addClass('active'); } }); + $(document).on('click', '.block-header.clickable h3', function(){ + var el = $(this).parent('.clickable'); + var oid = el.attr('data-opens'); + if(el.hasClass('closed')){ + localStorage[oid] = 'open'; + el.removeClass('closed'); + $('#' + oid).show(); + }else{ + localStorage[oid] = 'closed'; + el.addClass('closed'); + $('#' + oid).hide(); + } + }); + if(localStorage){ + $('.block-header.clickable').each(function(){ + var el = $(this); + var oid = el.attr('data-opens'); + if('undefined' !== typeof(localStorage[oid])){ + if('open' === localStorage[oid]){ + el.removeClass('closed'); + $('#' + oid).show(); + }else{ + el.addClass('closed'); + $('#' + oid).hide(); + } + } + }); + } }, route: function(){ var pathData = Ethplorer.Utils.parsePath(); @@ -66,12 +95,11 @@ Ethplorer = { Ethplorer.error('Invalid transaction hash'); return; } - $.getJSON(Ethplorer.Config.phpService, {data: txHash}, function(_txHash){ + $.getJSON(Ethplorer.service, {data: txHash}, function(_txHash){ return function(data){ Ethplorer.showTxDetails(_txHash, data); } }(txHash)); - }, knownContracts: [], @@ -100,6 +128,13 @@ Ethplorer = { if(oOperation.type == 'Mint'){ oOperation.type = 'Issuance'; } + + if('undefined' !== typeof(oOperation.value)){ + oOperation.value = Ethplorer.Utils.toBig(oOperation.value).div(Math.pow(10, oToken.decimals)); + oOperation.value = Ethplorer.Utils.formatNum(oOperation.value, true, oToken.decimals, true); + oOperation.value = oToken.symbol ? (oOperation.value + ' ' + oToken.symbol) : oOperation.value; + } + titleAdd += oOperation.type; $('.token-operation-type').text(oOperation['type']); Ethplorer.fillValues('transfer', txData, ['operation', 'operation.from', 'operation.to', 'operation.value']); @@ -115,7 +150,8 @@ Ethplorer = { showTxDetails: function(txHash, txData){ - $('#ethplorer-path').html('Transaction hash ' + txHash); + // $('#ethplorer-path').html('

Transaction hash: ' + txHash + '

'); + $('#ethplorer-path').show(); $('.list-field').empty(); $('#transaction-tx-hash').html(Ethplorer.Utils.getEtherscanLink(txHash)); @@ -238,6 +274,7 @@ Ethplorer = { if('undefined' !== typeof(op.value)){ op.value = Ethplorer.Utils.toBig(op.value).div(Math.pow(10, opToken.decimals)); op.value = Ethplorer.Utils.formatNum(op.value, true, opToken.decimals, true); + op.value = opToken.symbol ? (op.value + ' ' + opToken.symbol) : op.value; op.symbol = opToken.symbol; } var opParties = ''; @@ -262,7 +299,8 @@ Ethplorer = { '' + '' ); - row.click(function(_tx, _op){ + row[0].operation = op; + row.click(function(_tx){ return function(){ if($(this).hasClass('selectable')){ $(this).removeClass('selectable'); @@ -272,15 +310,15 @@ Ethplorer = { $('.token-related').animate({opacity:0.1}, 250, function(){ $('.token-related').animate({opacity:1}, 250); }); - setTimeout(function(__tx, __op){ + setTimeout(function(__tx, _op){ return function(){ - Ethplorer.showOpDetails(__tx, __op); + Ethplorer.showOpDetails(__tx, _op); }; - }(_tx, _op), 250); - document.location.hash = ('undefined' !== typeof(_op.priority)) ? _op.priority : _op.index; + }(_tx, this.operation), 250); + document.location.hash = ('undefined' !== typeof(this.operation.priority)) ? this.operation.priority : this.operation.index; } }; - }(oTx, op)); + }(oTx)); $('.multiop table').append(row); } } @@ -333,6 +371,7 @@ Ethplorer = { Ethplorer.fillValues('transfer', txData, ['tx', 'tx.timestamp']); } + document.title = 'Ethplorer'; document.title += (': ' + (titleAdd ? (titleAdd + ' -') : '')); document.title += (' hash ' + txHash); @@ -340,12 +379,12 @@ Ethplorer = { if(hash && hash.length){ var idx = parseInt(hash); var el = $('[data-op-idx=' + idx + ']'); - if(el.length){ + if(el.length && ('undefined' !== typeof(el[0].operation))){ $('.multiop .blue').addClass('selectable'); $('.multiop .blue').removeClass('blue'); el.addClass('blue'); el.removeClass('selectable'); - Ethplorer.showOpDetails(txData.tx, txData.operations[idx]); + Ethplorer.showOpDetails(txData.tx, el[0].operation); } } @@ -365,7 +404,7 @@ Ethplorer = { Ethplorer.error('Invalid address format'); return; } - $.getJSON(Ethplorer.Config.phpService, {data: address}, function(_address){ + $.getJSON(Ethplorer.service, {data: address}, function(_address){ return function(data){ Ethplorer.showAddressDetails(_address, data); } @@ -378,7 +417,8 @@ Ethplorer = { $('.address-type').text(data.isContract ? 'Contract' : 'Address'); $('#address-issuances').hide(); var tp = data.isContract ? 'Contract address ' : 'Address '; - $('#ethplorer-path').html('' + tp + ' ' + address); + // $('#ethplorer-path').html('' + tp + ' ' + address); + $('#ethplorer-path').show(); data.address = address; data.balance = parseFloat(data.balance) * 1e+18; Ethplorer.fillValues('address', data, ['address', 'balance']); @@ -527,18 +567,24 @@ Ethplorer = { var date = Ethplorer.Utils.ts2date(tx.timestamp, false); var value = Ethplorer.Utils.formatNum(qty, true, txToken.decimals ? txToken.decimals : 18, 2) + ' ' + txToken.symbol; var token = Ethplorer.Utils.getEthplorerLink(tx.contract, txToken.name, false); - tdDate.html(Ethplorer.Utils.getEthplorerLink(tx.transactionHash, date, false)); + var from = tx.from ? ((tx.from !== address) ? Ethplorer.Utils.getEthplorerLink(tx.from) : address) : false; + var to = tx.to ? ((tx.to !== address) ? Ethplorer.Utils.getEthplorerLink(tx.to) : address) : false; + var arrow = ''; + if(from && (tx.from === address)){ + value = '-' + value; + arrow = ''; + }else if(to && (tx.to === address)){ + arrow = ''; + } + tdDate.html(Ethplorer.Utils.getEthplorerLink(tx.transactionHash, date, false) + (arrow ? (' ' + arrow) : '')); divData.html( - 'Date: ' + date + '
' + + 'Date: ' + date + (arrow ? (' ' + arrow) : '') + '
' + (!data.token ? ('Token: ' + token + '
') : '') + 'Value: ' + value + '
' + 'Tx: ' + Ethplorer.Utils.getEthplorerLink(tx.transactionHash) + '
' + - (tx.from ? ( - 'From: ' + Ethplorer.Utils.getEthplorerLink(tx.from) + '
' + - 'To: ' + Ethplorer.Utils.getEthplorerLink(tx.to) - ) : ('Address: ' + Ethplorer.Utils.getEthplorerLink(tx.address))) + (from ? ('From: ' + from + '
To: ' + to) : ('Address: ' + address)) ); - if(!tx.from && tx.address){ + if(!from && tx.address){ value = (tx.type && ('burn' === tx.type)) ? '-' + value + '
Burn' : /*'+' + */value + '
Issuance'; } tdQty.html(value); @@ -561,6 +607,7 @@ Ethplorer = { } } + document.title = 'Ethplorer'; document.title += (': ' + (titleAdd ? (titleAdd + ' -') : '')); document.title += ((data.isContract ? ' Ethereum contract ' : ' Ethereum address ') + address); diff --git a/service/lib/ethplorer.php b/service/lib/ethplorer.php index b200f258..39355993 100644 --- a/service/lib/ethplorer.php +++ b/service/lib/ethplorer.php @@ -67,29 +67,28 @@ protected function __construct(array $aConfig){ ); $this->oCache = new evxCache($this->aSettings['cacheDir']); - if(!isset($this->aSettings['mongo'])){ - throw new Exception("Mongo configuration not found"); - } if(!isset($this->aSettings['ethereum'])){ throw new Exception("Ethereum configuration not found"); } - if(class_exists("MongoClient")){ - $oMongo = new MongoClient($this->aSettings['mongo']['server']); - $oDB = $oMongo->{$this->aSettings['mongo']['dbName']}; - $this->dbs = array( - 'transactions' => $oDB->{"everex.eth.transactions"}, - 'blocks' => $oDB->{"everex.eth.blocks"}, - 'contracts' => $oDB->{"everex.eth.contracts"}, - 'tokens' => $oDB->{"everex.erc20.contracts"}, - 'operations' => $oDB->{"everex.erc20.operations"}, - 'balances' => $oDB->{"everex.erc20.balances"} - ); - }else{ - throw new Exception("MongoClient class not found, php_mongo extension required"); + if(isset($this->aSettings['mongo']) && (FALSE !== $this->aSettings['mongo'])){ + if(class_exists("MongoClient")){ + $oMongo = new MongoClient($this->aSettings['mongo']['server']); + $oDB = $oMongo->{$this->aSettings['mongo']['dbName']}; + $this->dbs = array( + 'transactions' => $oDB->{"everex.eth.transactions"}, + 'blocks' => $oDB->{"everex.eth.blocks"}, + 'contracts' => $oDB->{"everex.eth.contracts"}, + 'tokens' => $oDB->{"everex.erc20.contracts"}, + 'operations' => $oDB->{"everex.erc20.operations"}, + 'balances' => $oDB->{"everex.erc20.balances"} + ); + // Get last block + $lastblock = $this->getLastBlock(); + $this->oCache->store('lastBlock', $lastblock); + }else{ + throw new Exception("MongoClient class not found, php_mongo extension required"); + } } - // Get last block - $lastblock = $this->getLastBlock(); - $this->oCache->store('lastBlock', $lastblock); } /** From a30f725a4c6a068f6c69761cdd93659e83cc238d Mon Sep 17 00:00:00 2001 From: ArtemKo7v Date: Fri, 6 Jan 2017 16:29:42 +0700 Subject: [PATCH 0004/1583] CSS and layout updates --- css/ethplorer.css | 75 +++++++++++++++++++++++++---------------------- index.php | 24 ++++++++++++--- js/ethplorer.js | 56 +++++++++++++++-------------------- 3 files changed, 84 insertions(+), 71 deletions(-) diff --git a/css/ethplorer.css b/css/ethplorer.css index 39214a18..f1c96614 100644 --- a/css/ethplorer.css +++ b/css/ethplorer.css @@ -181,7 +181,8 @@ a.local-link, a.local-link:visited, a.local-link:hover { td.list-field { white-space: nowrap; overflow: hidden; - max-width: 26vw; + max-width: 1px; + width: 80%; text-overflow: ellipsis; } @@ -301,31 +302,12 @@ a.dashed { text-overflow: ellipsis } -.arrow-in { - color: #00ff00; -} -.arrow-in:before { - content: '↑'; -} -.arrow-out { - color: #ff0000; -} -.arrow-out:before { - content: '↓'; +.incoming { + color: #4f9450 !important; } -.block-header.clickable.closed { - background: black; - color: white; -} - -.block-header.clickable h3 { - display: inline-block; - border-bottom: 1px dashed; - padding: 0px; - margin-left: 20px; - margin-top: 12px; - cursor: pointer; +.outgoing { + color: #900 !important; } .hash-from-to { @@ -345,6 +327,37 @@ a.dashed { color: white; } +#address-issuances tr td:last-child { + min-width: 150px; +} + +.tx-details-link { + font-size: 22px; + color: white !important; + cursor: pointer; + border-bottom: 1px dashed white; +} + +.tx-details-link, +.tx-details-link:hover, +.tx-details-link:visited, +.tx-details-link:active { + text-decoration: none; +} + +.tx-details-link.closed { + display: none; +} + +.tx-details-close { + top: 24px; + position: absolute; + right: 32px; + font-size: 30px; + color: #444; + cursor: pointer; +} + .total-in-out-small { font-size: 0.8em; opacity: 0.4; @@ -410,6 +423,7 @@ a.dashed { } @media screen and (max-width: 991px) { + .tx-details-link, #ethplorer-path { font-size: 18px; } @@ -422,12 +436,6 @@ a.dashed { } @media screen and (min-width: 400px) and (max-width: 991px) { - td.list-field { - overflow: hidden; - max-width: 44vw; - text-overflow: ellipsis; - } - .hash-from-to { max-width: 38vw; } @@ -457,14 +465,10 @@ a.dashed { #address-token-transfers td { font-size: 11px; } + .tx-details-link, #ethplorer-path { font-size: 14px; } - td.list-field { - overflow: hidden; - max-width: 34vw; - text-overflow: ellipsis; - } .table tr td:first-child { padding-left: 8px; } @@ -503,6 +507,7 @@ a.token-update { } @media screen and (max-width: 767px) { + .tx-details-link, #ethplorer-path { font-size: 16px; } diff --git a/index.php b/index.php index ae343fb4..5d0715c8 100644 --- a/index.php +++ b/index.php @@ -102,9 +102,11 @@
-
+
+

+
@@ -160,6 +162,9 @@
+
-
+