Browse Source

Jade to Pug, added Vout Ns, refactored database/pages, port in config, clean dependencies

stuff
xcps 7 years ago
parent
commit
887c852b55
  1. 2
      app.js
  2. 43
      bin/createUserAndDb.js
  3. 41
      bin/initdb.js
  4. 23
      bin/syncBlockchain.js
  5. 3
      bin/www
  6. 3
      config/config.json.example
  7. 10
      models/transaction.js
  8. 8
      models/vout.js
  9. 3
      package.json
  10. 46
      routes/address.js
  11. 2
      routes/block.js
  12. 49
      routes/transaction.js
  13. 0
      views/404.pug
  14. 15
      views/address.jade
  15. 21
      views/address.pug
  16. 6
      views/block.pug
  17. 0
      views/error.pug
  18. 2
      views/index.pug
  19. 0
      views/layout.pug
  20. 37
      views/transaction.jade
  21. 54
      views/transaction.pug

2
app.js

@ -16,7 +16,7 @@ var app = express();
// view engine setup // view engine setup
app.set('views', path.join(__dirname, 'views')); app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade'); app.set('view engine', 'pug');
// uncomment after placing your favicon in /public // uncomment after placing your favicon in /public
app.use(favicon(path.join(__dirname, 'public', 'favicon.ico'))); app.use(favicon(path.join(__dirname, 'public', 'favicon.ico')));

43
bin/createUserAndDb.js

@ -0,0 +1,43 @@
#!/usr/bin/env node
var exec = require('child_process').exec;
var models = require('../models');
var env = require('../config/config.json')['env'] || 'development';
var config = require(__dirname + '/../config/config.json')['database'][env];
if (process.argv.length < 4) {
console.log('Provide root user name and password for mysql');
process.exit(0);
}
const dropUserDB = `mysql -u${process.argv[2]} -p${process.argv[3]} -e "drop database ${config.database};drop user ${config.username}"`
const createdb = `mysql -u${process.argv[2]} -p${process.argv[3]} -e "create database ${config.database}"`;
const createUser = `mysql -u${process.argv[2]} -p${process.argv[3]} -e "create user ${config.username} identified by '${config.password}'"`;
const grantAccess = `mysql -u${process.argv[2]} -p${process.argv[3]} -e "grant all on ${config.database}.* to ${config.username}"`;
exec(dropUserDB, function(err,stdout,stderr) {
console.log(stdout);
exec(createdb, function(err,stdout,stderr) {
if (err) {
console.log(err);
process.exit(0);
} else {
console.log(stdout);
exec(createUser, function(err, stdout, stderr) {
if (err) {
console.log(err);
process.exit(0);
} else {
console.log(stdout);
exec(grantAccess, function(err, stdout, stderr) {
if (err) {
console.log(err);
} else {
console.log(`\nUSER (${config.username}) AND DATABASE (${config.database}) CREATED SUCCESSFULLY`);
console.log(stdout);
}
});
}
});
}
});
});

41
bin/initdb.js

@ -1,51 +1,12 @@
#!/usr/bin/env node #!/usr/bin/env node
var exec = require('child_process').exec;
var models = require('../models'); var models = require('../models');
var env = require('../config/config.json')['env'] || 'development';
var config = require(__dirname + '/../config/config.json')['database'][env];
if (process.argv.length < 4) {
console.log('Provide root user name and password for mysql');
process.exit(0);
}
const dropUserDB = `mysql -u${process.argv[2]} -p${process.argv[3]} -e "drop database ${config.database};drop user ${config.username}"`
const createdb = `mysql -u${process.argv[2]} -p${process.argv[3]} -e "create database ${config.database}"`;
const createUser = `mysql -u${process.argv[2]} -p${process.argv[3]} -e "create user ${config.username} identified by '${config.password}'"`;
const grantAccess = `mysql -u${process.argv[2]} -p${process.argv[3]} -e "grant all on ${config.database}.* to ${config.username}"`;
exec(dropUserDB, function(err,stdout,stderr) {
console.log(stdout);
exec(createdb, function(err,stdout,stderr) {
if (err) {
console.log(err);
process.exit(0);
} else {
console.log(stdout);
exec(createUser, function(err, stdout, stderr) {
if (err) {
console.log(err);
process.exit(0);
} else {
console.log(stdout);
exec(grantAccess, function(err, stdout, stderr) {
if (err) {
console.log(err);
} else {
console.log(stdout);
models.sequelize.sync({force: true}) models.sequelize.sync({force: true})
.then(() => { .then(() => {
console.log(`\nUSER (${config.username}) AND DATABASE (${config.database}) CREATED SUCCESSFULLY`); console.log('Tables created');
process.exit(0); process.exit(0);
}) })
.catch((err) => { .catch((err) => {
console.log(err); console.log(err);
process.exit(0); process.exit(0);
}); });
}
});
}
});
}
});
});

23
bin/syncBlockchain.js

@ -39,7 +39,6 @@ async function saveTransaction(txid, blockHeight) {
id: 1 id: 1
})); }));
const tx = JSON.parse(res_tx)['result']; const tx = JSON.parse(res_tx)['result'];
// console.log('tx:', tx);
if (tx === null) { if (tx === null) {
await models.Failure.create({ await models.Failure.create({
msg: `${txid} fetching failed`, msg: `${txid} fetching failed`,
@ -50,11 +49,17 @@ async function saveTransaction(txid, blockHeight) {
txid: tx.txid, txid: tx.txid,
BlockHeight: blockHeight, BlockHeight: blockHeight,
}); });
// Loop over vouts
for (var i = 0; i < tx.vout.length; i++) { for (var i = 0; i < tx.vout.length; i++) {
const vout = tx.vout[i]; const vout = tx.vout[i];
const m_vout = await models.Vout.create({ const m_vout = await models.Vout.create({
n: vout.n,
value: vout.value, value: vout.value,
}); });
// Loop over addresses in vout
for (var y = 0; y < vout.scriptPubKey.addresses.length; y++) { for (var y = 0; y < vout.scriptPubKey.addresses.length; y++) {
const address = vout.scriptPubKey.addresses[y]; const address = vout.scriptPubKey.addresses[y];
let m_address = await models.Address.findOne({ let m_address = await models.Address.findOne({
@ -69,18 +74,26 @@ async function saveTransaction(txid, blockHeight) {
} }
await m_vout.addAddresses(m_address); await m_vout.addAddresses(m_address);
} }
await transaction.addVouts(m_vout); await transaction.addVouts(m_vout, {through: {direction: 1}});
} }
for (var i = 0; i < tx.vin.length; i++) { for (var i = 0; i < tx.vin.length; i++) {
const vin = tx.vin[i]; const vin = tx.vin[i];
if (vin.txid) { if (vin.txid) {
const trans = await models.Transaction.findOne({ const vout = await models.Vout.findAll({
include: {
model: models.Transaction,
where: { where: {
txid: vin.txid, txid: vin.txid,
}, },
},
where: {
n: vin.vout,
},
}); });
if (trans) { if (vout) {
await transaction.addTxtx(trans); await transaction.addVouts(vout, { through: { direction: 0, }, });
} else {
throw('Couldnt find vout for VIN');
} }
} }
} }

3
bin/www

@ -8,12 +8,13 @@ var app = require('../app');
var debug = require('debug')('gostexplr:server'); var debug = require('debug')('gostexplr:server');
var http = require('http'); var http = require('http');
var models = require('../models'); var models = require('../models');
var config = require('../config/config.json');
/** /**
* Get port from environment and store in Express. * Get port from environment and store in Express.
*/ */
var port = normalizePort(process.env.PORT || '3000'); var port = config['port'] || '3000';
app.set('port', port); app.set('port', port);
/** /**

3
config/config.json.example

@ -30,5 +30,6 @@
"hostname": "127.0.0.1", "hostname": "127.0.0.1",
"port": 9376 "port": 9376
}, },
"env": "production" "env": "production",
"port": 3000
} }

10
models/transaction.js

@ -11,21 +11,21 @@ module.exports = (sequelize, DataTypes) => {
}], }],
}); });
const TxToTx = sequelize.define('TxToTx', {}, { const TransactionVouts = sequelize.define('TransactionVouts', {
'direction': DataTypes.TINYINT(1),
}, {
timestamps: false, timestamps: false,
}); });
Transaction.belongsToMany(Transaction, { through: TxToTx, as: 'txtx' });
Transaction.associate = function (models) { Transaction.associate = function (models) {
models.Transaction.belongsTo(models.Block, { models.Transaction.belongsTo(models.Block, {
onDelete: "CASCADE", onDelete: "CASCADE",
foreignKey: { foreignKey: {
allowNull: false allowNull: false
} },
}); });
models.Transaction.hasMany(models.Vout); models.Transaction.belongsToMany(models.Vout, { through: 'TransactionVouts' });
}; };
return Transaction; return Transaction;

8
models/vout.js

@ -2,19 +2,15 @@
module.exports = (sequelize, DataTypes) => { module.exports = (sequelize, DataTypes) => {
const Vout = sequelize.define('Vout', { const Vout = sequelize.define('Vout', {
n: DataTypes.MEDIUMINT.UNSIGNED,
value: DataTypes.DECIMAL(16, 8), value: DataTypes.DECIMAL(16, 8),
}, { }, {
timestamps: false, timestamps: false,
}); });
Vout.associate = function (models) { Vout.associate = function (models) {
models.Vout.belongsTo(models.Transaction, {
onDelete: "CASCADE",
foreignKey: {
allowNull: false
}
});
models.Vout.belongsToMany(models.Address, { through: 'AddressVout' }); models.Vout.belongsToMany(models.Address, { through: 'AddressVout' });
models.Vout.belongsToMany(models.Transaction, { through: 'TransactionVouts' });
}; };
return Vout; return Vout;

3
package.json

@ -6,6 +6,7 @@
"scripts": { "scripts": {
"start": "node ./bin/www", "start": "node ./bin/www",
"initdb": "node ./bin/initdb.js", "initdb": "node ./bin/initdb.js",
"createUserAndDb": "node ./bin/createUserAndDb.js",
"syncBlockchain": "node ./bin/syncBlockchain.js", "syncBlockchain": "node ./bin/syncBlockchain.js",
"addN": "node ./bin/addNToVouts.js" "addN": "node ./bin/addNToVouts.js"
}, },
@ -22,10 +23,10 @@
"debug": "~2.6.9", "debug": "~2.6.9",
"express": "~4.15.5", "express": "~4.15.5",
"forever": "^0.15.3", "forever": "^0.15.3",
"jade": "~1.11.0",
"morgan": "~1.9.0", "morgan": "~1.9.0",
"mysql": "^2.15.0", "mysql": "^2.15.0",
"mysql2": "^1.5.1", "mysql2": "^1.5.1",
"pug": "^2.0.0-rc.4",
"sequelize": "^4.32.2", "sequelize": "^4.32.2",
"sequelize-cli": "^3.2.0", "sequelize-cli": "^3.2.0",
"serve-favicon": "~2.4.5" "serve-favicon": "~2.4.5"

46
routes/address.js

@ -5,36 +5,38 @@ var router = express.Router();
/* GET home page. */ /* GET home page. */
router.get('/:address/:offset*?', async function(req, res, next) { router.get('/:address/:offset*?', async function(req, res, next) {
const addrss = encodeURI(req.params.address); const safe_address = encodeURI(req.params.address);
const limit = 30;
const paramPage = parseInt(req.params.offset); const address = await models.Address.findOne({
const page = isNaN(paramPage) || paramPage < 1 ? 1 : paramPage; where: {
const offset = 30 * (page - 1); address: safe_address,
const txes = await models.sequelize.query(` },
SELECT txid include: {
FROM Transactions as t model: models.Vout,
LEFT JOIN Vouts as v include: {
ON v.TransactionId=t.id model: models.Transaction,
LEFT JOIN AddressVouts as av include: {
ON v.id=av.VoutId model: models.Vout,
LEFT JOIN Addresses as a },
ON a.id=av.AddressId },
WHERE a.address='${addrss}' },
LIMIT ${limit} });
OFFSET ${offset};
`);
if (txes === null) { if (address === null) {
res.status(404).render('404'); res.status(404).render('404');
return; return;
} }
const limit = 30;
const paramPage = parseInt(req.params.offset);
const page = isNaN(paramPage) || paramPage < 1 ? 1 : paramPage;
const offset = 30 * (page - 1);
const nextpage = txes[0].length === 30 ? page + 1 : null; const nextpage = address.Vouts.length === 30 ? page + 1 : null;
const prevpage = page > 1 ? page - 1 : null; const prevpage = page > 1 ? page - 1 : null;
console.log(address.toJSON());
res.render('address', { res.render('address', {
address: addrss, address: address.toJSON(),
txes: txes[0],
nextpage, nextpage,
prevpage, prevpage,
}); });

2
routes/block.js

@ -13,10 +13,12 @@ router.get('/:hash', async function(req, res, next) {
model: models.Transaction, model: models.Transaction,
}, },
}); });
if (blockInstance === null) { if (blockInstance === null) {
res.status(404).render('404'); res.status(404).render('404');
return; return;
} }
const lastBlock = await models.Block.findOne({ const lastBlock = await models.Block.findOne({
attributes: [ attributes: [
[models.sequelize.fn('MAX', models.sequelize.col('height')), 'maxheight'] [models.sequelize.fn('MAX', models.sequelize.col('height')), 'maxheight']

49
routes/transaction.js

@ -15,27 +15,34 @@ router.get('/:txid', async function(req, res, next) {
model: models.Block, model: models.Block,
},{ },{
model: models.Vout, model: models.Vout,
include: { include: [
{
model: models.Address, model: models.Address,
}
}, { }, {
model: models.Transaction, model: models.Transaction,
as: 'txtx', include: {
}], model: models.Vout,
},
}
],
},],
}); });
if (transaction === null) { if (transaction === null) {
res.status(404).render('404'); res.status(404).render('404');
return; return;
} }
const vouts = [];
transaction.Vouts.forEach((vout) => { // const vouts = [];
vout.Addresses.forEach((address) => { // transaction.Vouts.forEach((vout) => {
vouts.push({ // vout.Addresses.forEach((address) => {
address: address.address, // vouts.push({
value: vout.value, // address: address.address,
}); // value: vout.value,
}); // });
}); // });
// });
const lastBlock = await models.Block.findOne({ const lastBlock = await models.Block.findOne({
attributes: [ attributes: [
[models.sequelize.fn('MAX', models.sequelize.col('height')), 'maxheight'] [models.sequelize.fn('MAX', models.sequelize.col('height')), 'maxheight']
@ -43,10 +50,20 @@ router.get('/:txid', async function(req, res, next) {
raw: true, raw: true,
}); });
const confirmations = lastBlock.maxheight - transaction.Block.height + 1; const confirmations = lastBlock.maxheight - transaction.Block.height + 1;
transaction.blockTime = transaction.Block.time.toUTCString();
const txJson = transaction.toJSON();
// txJson.vins = txJson.Vouts.filter({TransactionVouts: {direction: 0}});
// txJson.vouts txJson.Vouts.filter({TransactionVouts: {direction: 1}});
const txTemplate = Object.assign(txJson, {
vins: txJson.Vouts.filter((vout) => vout.TransactionVouts.direction === 0),
vouts: txJson.Vouts.filter((vout) => vout.TransactionVouts.direction === 1),
});
txTemplate.blockTime = transaction.Block.time.toUTCString();
res.render('transaction', { res.render('transaction', {
transaction, transaction: txTemplate,
vouts, // vouts,
confirmations, confirmations,
}); });
}); });

0
views/404.jade → views/404.pug

15
views/address.jade

@ -1,15 +0,0 @@
extends layout
block content
h3 Address
div= address
h3 Transactions
each val in txes
div
a(href='/transaction/#{val.txid}/') #{val.txid}
div.pagination
if prevpage
a(href='/address/#{address}/#{prevpage}/', style='float:left') Back
if nextpage
a(href='/address/#{address}/#{nextpage}/', style='float:right') Next

21
views/address.pug

@ -0,0 +1,21 @@
extends layout
block content
h3 Address
div= address.address
h3 Transactions
table
each vout in address.Vouts
tr
if vout.Transactions[0].TransactionVouts.direction == 1
td OUT
else
td IN
td
a(href=`/transaction/${vout.Transactions[0].txid}/`) #{vout.Transactions[0].txid}
div.pagination
if prevpage
a(href=`/address/#{address}/${prevpage}/`, style='float:left') Back
if nextpage
a(href=`/address/${address}/${nextpage}/`, style='float:right') Next

6
views/block.jade → views/block.pug

@ -9,13 +9,13 @@ block content
tr tr
td.capitalize #{key} td.capitalize #{key}
td td
a(href='/block/#{block.nextblockhash}/') #{block.nextblockhash} a(href=`/block/${block.nextblockhash}/`) #{block.nextblockhash}
-continue -continue
if (key === 'previousblockhash') if (key === 'previousblockhash')
tr tr
td.capitalize #{key} td.capitalize #{key}
td td
a(href='/block/#{block.previousblockhash}/') #{block.previousblockhash} a(href=`/block/${block.previousblockhash}/`) #{block.previousblockhash}
-continue -continue
if (key === 'Transactions') if (key === 'Transactions')
-continue -continue
@ -26,5 +26,5 @@ block content
h3 Transactions h3 Transactions
each tx in block.Transactions each tx in block.Transactions
div div
a(href='/transaction/#{tx.txid}/') #{tx.txid} a(href=`/transaction/${tx.txid}/`) #{tx.txid}

0
views/error.jade → views/error.pug

2
views/index.jade → views/index.pug

@ -8,4 +8,4 @@ block content
tr tr
td #{block.height} td #{block.height}
td td
a(href='/block/#{block.hash}/') #{block.hash} a(href='/block/' + block.hash + '/') #{block.hash}

0
views/layout.jade → views/layout.pug

37
views/transaction.jade

@ -1,37 +0,0 @@
extends layout
block content
h3 Transaction
table
tr
td Hash
td #{transaction.txid}
tr
td Block
td
a(href='/block/#{transaction.Block.hash}/') #{transaction.Block.hash}
tr
td Block time
td #{transaction.blockTime}
tr
td Confirmations
td #{confirmations}
h3 In
if transaction.txtx.length
table
each val in transaction.txtx
tr
td
a(href='/transaction/#{val.txid}/') #{val.txid}
else
div Mined
h3 Out
table
each val in vouts
tr
td
a(href='/address/#{val.address}/') #{val.address}
td #{val.value}

54
views/transaction.pug

@ -0,0 +1,54 @@
extends layout
block content
h3 Transaction
table
tr
td Hash
td #{transaction.txid}
tr
td Block
td
a(href=`/block/${transaction.Block.hash}/`) #{transaction.Block.hash}
tr
td Block time
td #{transaction.blockTime}
tr
td Confirmations
td #{confirmations}
h3 In
if transaction.vins.length
table
tr
th Address
th Value
th Transaction
each vin in transaction.vins
tr
td
a(href=`/address/${vin.Addresses[0].address}/`) #{vin.Addresses[0].address}
td #{vin.value}
td
a(href=`/transaction/${vin.Transactions[0].txid}/`) #{vin.Transactions[0].txid}
else
div Mined
h3 Out
table
tr
th Address
th Value
th Transaction
each vout in transaction.vouts
each address in vout.Addresses
tr
td
a(href=`/address/${address.address}/`) #{address.address}
td #{vout.value}
td
if vout.Transactions[0].TransactionVouts.direction == 0
a(href=`/transaction/${vout.Transactions[0].txid}/`) #{vout.Transactions[0].txid}
else
span No yet
Loading…
Cancel
Save