From fd277bc674ab6ed30ae906465d6cda3f14ff3c69 Mon Sep 17 00:00:00 2001 From: joeuhren <46763106+joeuhren@users.noreply.github.com> Date: Thu, 19 Nov 2020 21:37:42 -0700 Subject: [PATCH] Full address history with DataTables ajax loading --- app.js | 36 ++++++++ lib/database.js | 130 +++++++++++++++++++++-------- models/addresstx.js | 10 +++ routes/index.js | 74 +++++++--------- scripts/sync.js | 85 ++++++++++--------- views/address.pug | 24 ++---- views/includes/address_history.pug | 93 +++++++++++++-------- 7 files changed, 276 insertions(+), 176 deletions(-) create mode 100644 models/addresstx.js diff --git a/app.js b/app.js index 83e88f5..394ac41 100644 --- a/app.js +++ b/app.js @@ -132,6 +132,42 @@ app.use('/ext/getbasicstats', function(req,res){ }); }); +app.use('/ext/getaddresstxsajax', function(req,res){ + if(req.query.length > settings.txcount){ + req.query.length = settings.txcount; + } + db.get_address_txs_ajax(req.query.address, req.query.start, req.query.length,function(txs, count){ + var data = []; + for(i=0; i settings.txcount ) { - tx_array.shift(); - } - Address.updateOne({a_id:hash}, { - txs: tx_array, - received: received, - sent: sent, - balance: received - sent - }, function() { - return cb(); - }); - } else { - if (type == tx_array[index].type) { - return cb(); //duplicate + //Considering no duplicate + var tx_array = []; + var received = address.received; + var sent = address.sent; + if (type == 'vin') { + sent = sent + amount; + } else { + received = received + amount; + } + + tx_array.push({addresses: txid, type: type}); + + Address.updateOne({a_id:hash}, { + received: received, + sent: sent, + balance: received - sent + }, function() { + + var newAddressTx = new AddressTx({ + a_id: hash, + addresses: txid, + type: type + }); + newAddressTx.save(function(err) { + if (err) { + return cb(err); } else { - Address.updateOne({a_id:hash}, { - txs: tx_array, - received: received, - sent: sent, - balance: received - sent - }, function() { - return cb(); - }); + //console.log('address saved: %s', hash); + //console.log(newAddress); + return cb(); } - } + }); + return cb(); }); } } else { @@ -103,14 +100,12 @@ function update_address(hash, txid, amount, type, cb) { if (type == 'vin') { var newAddress = new Address({ a_id: hash, - txs: [ {addresses: txid, type: 'vin'} ], sent: amount, balance: amount, }); } else { var newAddress = new Address({ a_id: hash, - txs: [ {addresses: txid, type: 'vout'} ], received: amount, balance: amount, }); @@ -122,6 +117,21 @@ function update_address(hash, txid, amount, type, cb) { } else { //console.log('address saved: %s', hash); //console.log(newAddress); + + var newAddressTx = new AddressTx({ + a_id: hash, + addresses: txid, + type: type + }); + newAddressTx.save(function(err) { + if (err) { + return cb(err); + } else { + //console.log('address saved: %s', hash); + //console.log(newAddress); + return cb(); + } + }); return cb(); } }); @@ -394,6 +404,52 @@ module.exports = { }); }, + get_address_txs_ajax: function(hash, start, length, cb) { + var totalCount = 0; + Address.findOne({a_id: hash}, function(err, addressTotalTxs) { + + if(err) { + return cb(err); + } else { + AddressTx.find({a_id: hash}).count({}, function(err, count){ + if(err) { + return cb(err); + } else { + totalCount = count; + AddressTx.find({a_id: hash}).sort({_id: 'desc'}).skip(Number(start)).limit(Number(length)).exec(function (err, address) { + if (err) { + return cb(err); + } else { + //console.log(address); + var txs = []; + var count = address.length; + var hashes = address; + + var txs = []; + + lib.syncLoop(count, function (loop) { + var i = loop.iteration(); + find_tx(hashes[i].addresses, function (tx) { + if (tx) { + txs.push(tx); + loop.next(); + } else { + txs.push("1. Not found"); + loop.next(); + } + }) + }, function () { + return cb(txs, totalCount); + }); + } + }); + } + }); + + } + }); + }, + create_market: function(coin, exchange, market, cb) { var newMarkets = new Markets({ market: market, diff --git a/models/addresstx.js b/models/addresstx.js new file mode 100644 index 0000000..178a1dd --- /dev/null +++ b/models/addresstx.js @@ -0,0 +1,10 @@ +var mongoose = require('mongoose') + , Schema = mongoose.Schema; + +var AddressTXSchema = new Schema({ + a_id: { type: String, index: true}, + addresses: { type: String, lowercase: true}, + type: { type: String } +}, {id: false}); + +module.exports = mongoose.model('AddressTx', AddressTXSchema); diff --git a/routes/index.js b/routes/index.js index 53fc15f..a72158f 100644 --- a/routes/index.js +++ b/routes/index.js @@ -1,10 +1,10 @@ var express = require('express') - , router = express.Router() - , settings = require('../lib/settings') - , locale = require('../lib/locale') - , db = require('../lib/database') - , lib = require('../lib/explorer') - , qr = require('qr-image'); + , router = express.Router() + , settings = require('../lib/settings') + , locale = require('../lib/locale') + , db = require('../lib/database') + , lib = require('../lib/explorer') + , qr = require('qr-image'); function route_get_block(res, blockhash) { lib.get_block(blockhash, function (block) { @@ -96,25 +96,7 @@ function route_get_address(res, hash, count) { db.get_address(hash, false, function(address) { if (address) { var txs = []; - var hashes = address.txs.reverse(); - if (address.txs.length < count) { - count = address.txs.length; - } - lib.syncLoop(count, function (loop) { - var i = loop.iteration(); - db.get_tx(hashes[i].addresses, function(tx) { - if (tx) { - txs.push(tx); - loop.next(); - } else { - loop.next(); - } - }); - }, function(){ - - res.render('address', { active: 'address', address: address, txs: txs}); - }); - + res.render('address', { active: 'address', address: address, txs: txs}); } else { route_get_index(res, hash + ' not found'); } @@ -192,22 +174,22 @@ router.get('/network', function(req, res) { router.get('/reward', function(req, res){ //db.get_stats(settings.coin, function (stats) { - console.log(stats); - db.get_heavy(settings.coin, function (heavy) { - //heavy = heavy; - var votes = heavy.votes; - votes.sort(function (a,b) { - if (a.count < b.count) { - return -1; - } else if (a.count > b.count) { - return 1; - } else { - return 0; - } - }); - - res.render('reward', { active: 'reward', stats: stats, heavy: heavy, votes: heavy.votes }); + console.log(stats); + db.get_heavy(settings.coin, function (heavy) { + //heavy = heavy; + var votes = heavy.votes; + votes.sort(function (a,b) { + if (a.count < b.count) { + return -1; + } else if (a.count > b.count) { + return 1; + } else { + return 0; + } }); + + res.render('reward', { active: 'reward', stats: stats, heavy: heavy, votes: heavy.votes }); + }); //}); }); @@ -281,12 +263,12 @@ router.get('/ext/summary', function(req, res) { lib.get_difficulty(function(difficulty) { difficultyHybrid = '' if (difficulty['proof-of-work']) { - if (settings.index.difficulty == 'Hybrid') { - difficultyHybrid = 'POS: ' + difficulty['proof-of-stake']; - difficulty = 'POW: ' + difficulty['proof-of-work']; - } else if (settings.index.difficulty == 'POW') { - difficulty = difficulty['proof-of-work']; - } else { + if (settings.index.difficulty == 'Hybrid') { + difficultyHybrid = 'POS: ' + difficulty['proof-of-stake']; + difficulty = 'POW: ' + difficulty['proof-of-work']; + } else if (settings.index.difficulty == 'POW') { + difficulty = difficulty['proof-of-work']; + } else { difficulty = difficulty['proof-of-stake']; } } diff --git a/scripts/sync.js b/scripts/sync.js index bcf2ac3..7560ad7 100644 --- a/scripts/sync.js +++ b/scripts/sync.js @@ -1,11 +1,12 @@ var mongoose = require('mongoose') - , db = require('../lib/database') - , Tx = require('../models/tx') - , Address = require('../models/address') - , Richlist = require('../models/richlist') - , Stats = require('../models/stats') - , settings = require('../lib/settings') - , fs = require('fs'); + , db = require('../lib/database') + , Tx = require('../models/tx') + , Address = require('../models/address') + , AddressTx = require('../models/addresstx') + , Richlist = require('../models/richlist') + , Stats = require('../models/stats') + , settings = require('../lib/settings') + , fs = require('fs'); var mode = 'update'; var database = 'index'; @@ -23,10 +24,10 @@ function usage() { console.log('check checks index for (and adds) any missing transactions/addresses'); console.log('reindex Clears index then resyncs from genesis to current block'); console.log(''); - console.log('notes:'); + console.log('notes:'); console.log('* \'current block\' is the latest created block when script is executed.'); console.log('* The market database only supports (& defaults to) reindex mode.'); - console.log('* If check mode finds missing data(ignoring new data since last sync),'); + console.log('* If check mode finds missing data(ignoring new data since last sync),'); console.log(' index_timeout in settings.json is set too low.') console.log(''); process.exit(0); @@ -39,17 +40,17 @@ if (process.argv[2] == 'index') { } else { switch(process.argv[3]) { - case 'update': - mode = 'update'; - break; - case 'check': - mode = 'check'; - break; - case 'reindex': - mode = 'reindex'; - break; - default: - usage(); + case 'update': + mode = 'update'; + break; + case 'check': + mode = 'check'; + break; + case 'reindex': + mode = 'reindex'; + break; + default: + usage(); } } } else if (process.argv[2] == 'market'){ @@ -87,7 +88,7 @@ function remove_lock(cb) { }); } else { return cb(); - } + } } function is_locked(cb) { @@ -102,7 +103,7 @@ function is_locked(cb) { }); } else { return cb(); - } + } } function exit() { @@ -140,34 +141,36 @@ is_locked(function (exists) { db.get_stats(settings.coin, function(stats){ if (settings.heavy == true) { db.update_heavy(settings.coin, stats.count, 20, function(){ - + }); } if (mode == 'reindex') { - Tx.remove({}, function(err) { - Address.remove({}, function(err2) { - Richlist.updateOne({coin: settings.coin}, { - received: [], - balance: [], - }, function(err3) { - Stats.updateOne({coin: settings.coin}, { - last: 0, - }, function() { - console.log('index cleared (reindex)'); - }); - db.update_tx_db(settings.coin, 1, stats.count, settings.update_timeout, function(){ - db.update_richlist('received', function(){ - db.update_richlist('balance', function(){ - db.get_stats(settings.coin, function(nstats){ - console.log('reindex complete (block: %s)', nstats.last); - exit(); + Tx.remove({}, function(err) { + Address.remove({}, function(err2) { + AddressTx.remove({}, function(err3) { + Richlist.updateOne({coin: settings.coin}, { + received: [], + balance: [], + }, function(err3) { + Stats.updateOne({coin: settings.coin}, { + last: 0, + }, function() { + console.log('index cleared (reindex)'); + }); + db.update_tx_db(settings.coin, 1, stats.count, settings.update_timeout, function(){ + db.update_richlist('received', function(){ + db.update_richlist('balance', function(){ + db.get_stats(settings.coin, function(nstats){ + console.log('reindex complete (block: %s)', nstats.last); + exit(); + }); }); }); }); }); }); }); - }); + }); } else if (mode == 'check') { db.update_tx_db(settings.coin, 1, stats.count, settings.check_timeout, function(){ db.get_stats(settings.coin, function(nstats){ diff --git a/views/address.pug b/views/address.pug index b717763..f4d8a57 100644 --- a/views/address.pug +++ b/views/address.pug @@ -4,25 +4,25 @@ block content - var balance = (address.received - address.sent) / 100000000; - var sent = address.sent /100000000 - var received = address.received / 100000000 - img.qrcode.pull-right.hidden-xs(src='/qr/' + address.a_id) + img.qrcode.pull-right.hidden-xs(src='/qr/' + address.a_id) .col-xs-12.col-md-10.col-md-offset-1 .panel.panel-default.panel-address-summary - .panel-heading(style='position:relative;') + .panel-heading(style='position:relative;') strong #{address.a_id} if settings.labels[address.a_id] - if settings.labels[address.a_id].type + if settings.labels[address.a_id].type label(class='label label-' + settings.labels[address.a_id].type + ' pull-right hidden-xs', style='margin-left:15px;') =settings.labels[address.a_id].label if settings.labels[address.a_id].url a(href=settings.labels[address.a_id].url, target='_blank') span.fa.fa-question-circle(style='margin-left:5px;') else - label.label.label-default.pull-right.hidden-xs(style='margin-left:15px;') + label.label.label-default.pull-right.hidden-xs(style='margin-left:15px;') =settings.labels[address.a_id].label if settings.labels[address.a_id].url a(href=settings.labels[address.a_id].url, target='_blank') span.fa.fa-question-circle(style='margin-left:5px;') - table.table.table-bordered.table-striped.summary-table + table.table.table-bordered.table-striped.summary-table thead tr if settings.show_sent_received == true @@ -31,23 +31,17 @@ block content if settings.show_sent_received == true th #{settings.locale.total_received} (#{settings.symbol}) th #{settings.locale.rl_balance} (#{settings.symbol}) - tbody + tbody tr - if settings.show_sent_received == true + if settings.show_sent_received == true td #{sent.toFixed(8)} if address.a_id !== 'coinbase' if settings.show_sent_received == true td #{received.toFixed(8)} td #{balance.toFixed(8)} - .panel.panel-default.hidden-xs - .panel-heading - strong #{settings.locale.ex_latest_transactions} - table.table.table-bordered.table-striped.history-table - include ./includes/address_history.pug - .panel.panel-default.hidden-lg.hidden-md + .panel.panel-default .panel-heading strong #{settings.locale.ex_latest_transactions} table.table.table-bordered.table-striped include ./includes/address_history.pug - .footer-padding - \ No newline at end of file + .footer-padding \ No newline at end of file diff --git a/views/includes/address_history.pug b/views/includes/address_history.pug index bc264b2..c76ab3c 100644 --- a/views/includes/address_history.pug +++ b/views/includes/address_history.pug @@ -1,38 +1,57 @@ -thead - tr - th #{settings.locale.timestamp} - th #{settings.locale.tx_hash} - th #{settings.locale.mkt_amount} (#{settings.symbol}) -tbody - each tx in txs - - var time = format_unixtime(tx.timestamp) +script. + var hashAddress = "#{address.a_id}"; + $(document).ready(function () { + var rtable = $('#address-txs').dataTable({ + autoWidth: true, + searching: false, + ordering: false, + responsive: true, + lengthChange: true, + processing: true, + serverSide: true, + ajax: { + "url": '/ext/getaddresstxsajax', + "data": { + "address": hashAddress + } + }, + rowCallback: function (row, data, index) { + var timestamp = data[0]; //variables for better readability + var txhash = data[1]; //variables for better readability + var out = data[2]; //variables for better readability + var vin = data[3]; //variables for better readability + + $("td:eq(0)", row).html(timestamp); + $("td:eq(1)", row).html('' + txhash + ''); + + var amount = 0; + + if(out > 0 && vin > 0) { + amount = (out - vin) / 100000000 + if (amount < 0) { + amount = amount * -1 + $("td:eq(2)", row).html("-" + amount.toFixed(8)).addClass("info"); + } else if (amount > 0) { + ammount = amount.toFixed(8); + $("td:eq(2)", row).html("+" + amount).addClass("info"); + } else { + $("td:eq(2)", row).html(amount.toFixed(8)).addClass("info"); + } + }else if(out > 0) { + amount = out / 100000000; + $("td:eq(2)", row).html("+" + amount.toFixed(8)).addClass("success"); + }else{ + amount = vin / 100000000; + $("td:eq(2)", row).html("-" + amount.toFixed(8)).addClass("danger"); + } + + }, + }); + }); +table#address-txs.table.table-bordered.table-striped + thead tr - td #{time} - td - a(href='/tx/' + tx.txid) #{tx.txid} - - var out = 0 - - var vin = 0 - each r in tx.vout - if r.addresses == address.a_id - - out = r.amount - each s in tx.vin - if s.addresses == address.a_id - - vin = s.amount - if out > 0 && vin > 0 - td.info - - var amount = (out - vin) / 100000000 - if amount < 0 - - amount = amount * -1 - | - #{amount.toFixed(8)} - else if amount > 0 - | + #{amount.toFixed(8)} - else - | #{amount.toFixed(8)} - else if out > 0 - td.success - - var amount = out / 100000000 - | + #{amount.toFixed(8)} - else - td.danger - - var amount = vin / 100000000 - | - #{amount.toFixed(8)} \ No newline at end of file + th.hidden-xs #{settings.locale.timestamp} + th.hidden-xs #{settings.locale.tx_hash} + th #{settings.locale.mkt_amount} (#{settings.symbol}) + tbody \ No newline at end of file