2018-02-09 22:48:24 +05:00
|
|
|
var http = require('http');
|
2018-09-27 15:40:46 +05:00
|
|
|
const fs = require('fs-ext');
|
2019-03-16 14:05:45 +05:00
|
|
|
const moment = require('moment');
|
2018-09-27 15:40:46 +05:00
|
|
|
|
2018-02-09 22:48:24 +05:00
|
|
|
var models = require('../models');
|
|
|
|
var rpcConfig = require('../config/config')['rpc'];
|
|
|
|
|
|
|
|
const {username, password, hostname, port} = rpcConfig;
|
|
|
|
|
2019-03-17 00:44:43 +05:00
|
|
|
const keepAliveAgent = new http.Agent({ keepAlive: true });
|
|
|
|
|
|
|
|
|
2019-03-16 23:48:45 +05:00
|
|
|
let sync_sql = '',
|
|
|
|
coolstrs = [];
|
2019-03-16 14:05:45 +05:00
|
|
|
|
2018-02-09 22:48:24 +05:00
|
|
|
function MakeRPCRequest(postData) {
|
|
|
|
return new Promise(function(resolve, reject) {
|
|
|
|
var post_options = {
|
|
|
|
host: hostname,
|
|
|
|
port: port,
|
|
|
|
auth: `${username}:${password}`,
|
|
|
|
path: '/',
|
|
|
|
method: 'POST',
|
2019-03-17 00:44:43 +05:00
|
|
|
agent: keepAliveAgent,
|
2018-02-09 22:48:24 +05:00
|
|
|
headers: {
|
|
|
|
'Content-Type': 'application/x-www-form-urlencoded',
|
|
|
|
'Content-Length': Buffer.byteLength(postData)
|
|
|
|
}
|
|
|
|
};
|
2019-03-16 14:05:45 +05:00
|
|
|
|
2018-02-09 22:48:24 +05:00
|
|
|
var post_req = http.request(post_options, function(res) {
|
|
|
|
res.setEncoding("utf8");
|
|
|
|
let body = "";
|
|
|
|
res.on("data", data => {
|
|
|
|
body += data;
|
|
|
|
});
|
|
|
|
res.on("end", () => {
|
|
|
|
resolve(body);
|
|
|
|
});
|
|
|
|
});
|
2019-03-16 14:05:45 +05:00
|
|
|
|
|
|
|
post_req.on('error', function(err) {
|
|
|
|
if (err.code == 'ECONNREFUSED') {
|
|
|
|
console.log('\x1b[36m%s\x1b[0m', "Couldn't make request to wallet")
|
|
|
|
}
|
|
|
|
reject(err);
|
|
|
|
});
|
|
|
|
|
2018-02-09 22:48:24 +05:00
|
|
|
post_req.write(postData);
|
|
|
|
post_req.end();
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
async function saveTransaction(txid, blockHeight) {
|
|
|
|
const res_tx = await MakeRPCRequest(JSON.stringify({
|
|
|
|
method: 'getrawtransaction',
|
|
|
|
params: [txid, 1],
|
|
|
|
id: 1
|
|
|
|
}));
|
2019-03-16 14:05:45 +05:00
|
|
|
|
2018-02-09 22:48:24 +05:00
|
|
|
const tx = JSON.parse(res_tx)['result'];
|
|
|
|
if (tx === null) {
|
|
|
|
await models.Failure.create({
|
|
|
|
msg: `${txid} fetching failed`,
|
|
|
|
});
|
|
|
|
return;
|
|
|
|
}
|
2019-03-16 14:05:45 +05:00
|
|
|
|
|
|
|
// const transaction = await models.Transaction.create({
|
|
|
|
// txid: tx.txid,
|
|
|
|
// BlockHeight: blockHeight,
|
|
|
|
// });
|
|
|
|
sync_sql += `
|
|
|
|
INSERT INTO Transactions (
|
|
|
|
txid,
|
|
|
|
BlockHeight
|
|
|
|
)
|
|
|
|
VALUES (
|
|
|
|
"${txid}",
|
|
|
|
${blockHeight}
|
|
|
|
);
|
|
|
|
SET @txid = LAST_INSERT_ID();
|
|
|
|
`;
|
2018-02-11 03:36:42 +05:00
|
|
|
|
|
|
|
// Loop over vouts
|
2018-02-09 22:48:24 +05:00
|
|
|
for (var i = 0; i < tx.vout.length; i++) {
|
|
|
|
const vout = tx.vout[i];
|
2018-02-11 03:36:42 +05:00
|
|
|
|
2019-03-16 14:05:45 +05:00
|
|
|
// const m_vout = await models.Vout.create({
|
|
|
|
// n: vout.n,
|
|
|
|
// value: vout.value,
|
|
|
|
// });
|
|
|
|
sync_sql += `
|
|
|
|
INSERT INTO Vouts (n, value)
|
|
|
|
VALUES ("${vout.n}", "${vout.value}");
|
|
|
|
SET @voutid= LAST_INSERT_ID();
|
|
|
|
`;
|
2018-02-11 03:36:42 +05:00
|
|
|
|
|
|
|
// Loop over addresses in vout
|
2018-02-09 22:48:24 +05:00
|
|
|
for (var y = 0; y < vout.scriptPubKey.addresses.length; y++) {
|
|
|
|
const address = vout.scriptPubKey.addresses[y];
|
2019-03-16 14:05:45 +05:00
|
|
|
// let m_address = await models.Address.findOne({
|
|
|
|
// where: {
|
|
|
|
// address,
|
|
|
|
// },
|
|
|
|
// });
|
|
|
|
// if (m_address === null) {
|
|
|
|
// m_address = await models.Address.create({
|
|
|
|
// address,
|
|
|
|
// });
|
|
|
|
// }
|
|
|
|
sync_sql += `
|
2019-03-16 21:09:58 +05:00
|
|
|
INSERT IGNORE INTO Addresses (address) VALUES ("${address}");
|
2019-03-16 14:05:45 +05:00
|
|
|
SET @addrid = (
|
|
|
|
SELECT IF(
|
|
|
|
ROW_COUNT() > 0,
|
|
|
|
LAST_INSERT_ID(),
|
|
|
|
(
|
|
|
|
SELECT id
|
|
|
|
FROM Addresses
|
2019-03-16 21:09:58 +05:00
|
|
|
WHERE address='${address}'
|
2019-03-16 14:05:45 +05:00
|
|
|
)
|
|
|
|
)
|
|
|
|
);
|
|
|
|
`;
|
|
|
|
// await m_vout.addAddresses(m_address);
|
|
|
|
sync_sql += `
|
|
|
|
INSERT INTO AddressVouts (AddressId, VoutId)
|
|
|
|
VALUES (@addrid, @voutid);
|
|
|
|
`;
|
2018-02-09 22:48:24 +05:00
|
|
|
}
|
2019-03-16 14:05:45 +05:00
|
|
|
// await transaction.addVouts(m_vout, {through: {direction: 1}});
|
|
|
|
sync_sql += `
|
|
|
|
INSERT INTO TransactionVouts (TransactionId, VoutId, direction)
|
|
|
|
VALUES (@txid, @voutid, 1);
|
|
|
|
`;
|
2018-02-09 22:48:24 +05:00
|
|
|
}
|
2019-03-16 14:05:45 +05:00
|
|
|
|
|
|
|
// Loop over vins
|
2018-02-09 22:48:24 +05:00
|
|
|
for (var i = 0; i < tx.vin.length; i++) {
|
|
|
|
const vin = tx.vin[i];
|
|
|
|
if (vin.txid) {
|
2019-03-16 14:05:45 +05:00
|
|
|
// const vout = await models.Vout.findAll({
|
|
|
|
// include: {
|
|
|
|
// model: models.Transaction,
|
|
|
|
// where: {
|
|
|
|
// txid: vin.txid,
|
|
|
|
// },
|
|
|
|
// },
|
|
|
|
// where: {
|
|
|
|
// n: vin.vout,
|
|
|
|
// },
|
|
|
|
// });
|
|
|
|
// if (vout) {
|
|
|
|
// await transaction.addVouts(vout[0], { through: { direction: 0, }, });
|
|
|
|
// } else {
|
|
|
|
// throw('Couldnt find vout for VIN');
|
|
|
|
// }
|
|
|
|
sync_sql += `
|
|
|
|
SET @vin = (
|
2019-03-16 21:09:58 +05:00
|
|
|
SELECT Vouts.id
|
2019-03-16 14:05:45 +05:00
|
|
|
FROM Vouts
|
|
|
|
INNER JOIN TransactionVouts
|
|
|
|
ON Vouts.id=TransactionVouts.VoutId
|
|
|
|
INNER JOIN Transactions
|
|
|
|
ON Transactions.id=TransactionVouts.TransactionId
|
|
|
|
WHERE
|
|
|
|
TransactionVouts.direction=1 AND
|
|
|
|
Transactions.txid="${vin.txid}" AND
|
|
|
|
Vouts.n=${vin.vout}
|
|
|
|
);
|
|
|
|
INSERT INTO TransactionVouts (TransactionId, VoutId, direction)
|
|
|
|
VALUES (@txid, @vin, 0);
|
|
|
|
`
|
2018-02-09 22:48:24 +05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
async function syncNextBlock(syncedHeight) {
|
|
|
|
const height = syncedHeight + 1;
|
2019-03-16 14:05:45 +05:00
|
|
|
sync_sql = '';
|
|
|
|
|
2018-02-09 22:48:24 +05:00
|
|
|
const res_hash = await MakeRPCRequest(JSON.stringify({
|
|
|
|
method: 'getblockhash',
|
|
|
|
params: [height],
|
|
|
|
id: 1
|
|
|
|
}));
|
|
|
|
const blockHash = JSON.parse(res_hash)['result'];
|
|
|
|
const res_block = await MakeRPCRequest(JSON.stringify({
|
|
|
|
method: 'getblock',
|
|
|
|
params: [blockHash],
|
|
|
|
id: 1
|
|
|
|
}));
|
|
|
|
const block = JSON.parse(res_block)['result'];
|
2019-03-16 14:05:45 +05:00
|
|
|
|
2019-03-16 23:48:45 +05:00
|
|
|
block.time = moment(block.time*1000).format('YYYY-MM-DD HH:mm:ss');
|
2019-03-16 14:05:45 +05:00
|
|
|
|
|
|
|
// await models.Block.create(block);
|
|
|
|
sync_sql = `
|
|
|
|
SET autocommit = 0;
|
|
|
|
START TRANSACTION;
|
|
|
|
INSERT INTO Block (
|
|
|
|
hash,
|
|
|
|
height,
|
|
|
|
size,
|
|
|
|
version,
|
|
|
|
merkleroot,
|
|
|
|
time,
|
|
|
|
nonce,
|
|
|
|
bits,
|
|
|
|
difficulty,
|
|
|
|
previousblockhash,
|
|
|
|
nextblockhash
|
|
|
|
)
|
|
|
|
VALUES (
|
|
|
|
"${block.hash}",
|
|
|
|
"${block.height}",
|
|
|
|
"${block.size}",
|
|
|
|
"${block.version}",
|
|
|
|
"${block.merkleroot}",
|
|
|
|
"${block.time}",
|
|
|
|
"${block.nonce}",
|
|
|
|
"${block.bits}",
|
|
|
|
"${block.difficulty}",
|
|
|
|
"${block.previousblockhash}",
|
|
|
|
"${block.nextblockhash}"
|
|
|
|
);
|
|
|
|
`
|
2019-03-16 23:48:45 +05:00
|
|
|
coolstrs = []
|
2018-02-09 22:48:24 +05:00
|
|
|
for (var i = 0; i < block.tx.length; i++) {
|
|
|
|
await saveTransaction(block.tx[i], block.height);
|
2019-03-16 23:48:45 +05:00
|
|
|
coolstrs.push(`${block.tx[i]} - ${block.time}`);
|
2018-02-09 22:48:24 +05:00
|
|
|
}
|
2019-03-16 14:05:45 +05:00
|
|
|
|
|
|
|
|
2018-02-09 22:48:24 +05:00
|
|
|
if (block.height > 1) {
|
2019-03-16 14:05:45 +05:00
|
|
|
// await models.Block.update({
|
|
|
|
// nextblockhash: block.hash
|
|
|
|
// },{
|
|
|
|
// where: {
|
|
|
|
// hash: block.previousblockhash
|
|
|
|
// }
|
|
|
|
// });
|
|
|
|
sync_sql += `
|
|
|
|
UPDATE Block
|
|
|
|
SET nextblockhash="${block.previousblockhash}"
|
|
|
|
WHERE nextblockhash="${block.previousblockhash}";
|
|
|
|
`
|
2018-02-09 22:48:24 +05:00
|
|
|
}
|
2019-03-16 14:05:45 +05:00
|
|
|
sync_sql += 'COMMIT;'
|
|
|
|
await models.sequelize.query(sync_sql);
|
2019-03-16 23:48:45 +05:00
|
|
|
|
2018-02-09 22:48:24 +05:00
|
|
|
return height;
|
|
|
|
}
|
|
|
|
|
|
|
|
async function getCurrentHeight() {
|
|
|
|
const result = await MakeRPCRequest(JSON.stringify({
|
|
|
|
method: 'getblockcount',
|
|
|
|
params: [],
|
|
|
|
id: 1
|
|
|
|
}));
|
|
|
|
return JSON.parse(result)['result'];
|
|
|
|
}
|
|
|
|
|
|
|
|
async function getSyncedHeight() {
|
|
|
|
const result = await models.Block.findOne({
|
|
|
|
attributes: ['height'],
|
|
|
|
order: [['height', 'DESC']],
|
|
|
|
limit: 1
|
|
|
|
});
|
2019-03-16 14:05:45 +05:00
|
|
|
|
2018-02-09 22:48:24 +05:00
|
|
|
const height = result ? result.height : -1;
|
|
|
|
return height;
|
|
|
|
}
|
|
|
|
|
2018-09-27 15:40:46 +05:00
|
|
|
async function acquireLock() {
|
|
|
|
let fd = fs.openSync('sync.lock', 'w');
|
|
|
|
try {
|
|
|
|
fs.flockSync(fd, 'exnb');
|
|
|
|
} catch(ex) {
|
|
|
|
if (ex.code === 'EAGAIN') {
|
|
|
|
console.log('Synchronization is already running');
|
|
|
|
} else {
|
|
|
|
console.log('Could\'nt lock file', ex);
|
|
|
|
}
|
|
|
|
throw ex;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-02-09 22:48:24 +05:00
|
|
|
async function syncBlockchain() {
|
|
|
|
|
|
|
|
try {
|
2018-09-27 15:40:46 +05:00
|
|
|
|
|
|
|
await acquireLock();
|
|
|
|
|
|
|
|
let syncedHeight = await getSyncedHeight();
|
|
|
|
console.log('\x1b[36m%s\x1b[0m', 'syncedHeight is', syncedHeight);
|
|
|
|
|
|
|
|
let currentHeight = await getCurrentHeight();
|
2019-03-17 00:17:08 +05:00
|
|
|
console.log('\x1b[34m%s\x1b[0m', 'currentHeight is', currentHeight);
|
2018-09-27 15:40:46 +05:00
|
|
|
|
2018-02-09 22:48:24 +05:00
|
|
|
while (syncedHeight < currentHeight) {
|
|
|
|
syncedHeight = await syncNextBlock(syncedHeight);
|
2019-03-16 23:48:45 +05:00
|
|
|
if (coolstrs) {
|
|
|
|
for(str of coolstrs) {
|
2019-03-17 00:17:08 +05:00
|
|
|
console.log('\x1b[36m%s\x1b[0m', `syncedHeight: ${syncedHeight}/${currentHeight}`, str)
|
2019-03-16 23:48:45 +05:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
console.log('\x1b[36m%s\x1b[0m', 'syncedHeight: ', syncedHeight)
|
|
|
|
}
|
2018-02-09 22:48:24 +05:00
|
|
|
}
|
|
|
|
} catch (e) {
|
2018-09-27 15:40:46 +05:00
|
|
|
console.log(e);
|
2018-09-24 15:35:41 +03:00
|
|
|
} finally {
|
|
|
|
models.sequelize.close().then(() => process.exit(0));
|
2018-02-09 22:48:24 +05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
syncBlockchain();
|