* redesigned sync, so no external node is needed

+ allow only once instance of the wallet
+ store txhash and use it as single ID for transactions
This commit is contained in:
Taegus
2018-12-24 21:44:41 +01:00
parent 7d6ba1c1f8
commit 82e988a723
7 changed files with 136 additions and 124 deletions

108
main.js
View File

@@ -1,68 +1,76 @@
// Modules to control application life and create native browser window // Modules to control application life and create native browser window
const {app, ipcMain, BrowserWindow} = require('electron'); const {app, ipcMain, BrowserWindow} = require('electron');
const singleInstance = require('single-instance');
const path = require('path'); const path = require('path');
const fs = require('fs'); const fs = require('fs');
// Keep a global reference of the window object, if you don't, the window will var locker = new singleInstance('Ether1DesktopWallet');
// be closed automatically when the JavaScript object is garbage collected.
let mainWindow
function createWindow () { locker.lock().then(function() {
// Create the browser window. // Keep a global reference of the window object, if you don't, the window will
mainWindow = new BrowserWindow({ // be closed automatically when the JavaScript object is garbage collected.
width: 1200, let mainWindow
height: 800,
minWidth: 1100,
minHeight: 700,
backgroundColor: "#000000"
});
// and load the index.html of the app. function createWindow () {
mainWindow.loadFile('index.html'); // Create the browser window.
EthoGeth.startGeth(); mainWindow = new BrowserWindow({
width: 1200,
height: 800,
minWidth: 1100,
minHeight: 700,
backgroundColor: "#000000"
});
// Open the DevTools. // and load the index.html of the app.
// mainWindow.webContents.openDevTools() mainWindow.loadFile('index.html');
EthoGeth.startGeth();
// Emitted when the window is closed. // Open the DevTools.
mainWindow.on('closed', function () { // mainWindow.webContents.openDevTools()
// Dereference the window object, usually you would store windows
// in an array if your app supports multi windows, this is the time // Emitted when the window is closed.
// when you should delete the corresponding element. mainWindow.on('closed', function () {
mainWindow = null // Dereference the window object, usually you would store windows
// in an array if your app supports multi windows, this is the time
// when you should delete the corresponding element.
mainWindow = null
})
}
// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
app.on('ready', createWindow)
// Quit when all windows are closed.
app.on('window-all-closed', function () {
// On OS X it is common for applications and their menu bar
// to stay active until the user quits explicitly with Cmd + Q
if (process.platform !== 'darwin') {
EthoGeth.stopGeth();
app.quit();
}
}) })
}
// This method will be called when Electron has finished app.on('activate', function () {
// initialization and is ready to create browser windows. // On OS X it's common to re-create a window in the app when the
// Some APIs can only be used after this event occurs. // dock icon is clicked and there are no other windows open.
app.on('ready', createWindow) if (mainWindow === null) {
createWindow()
}
})
// Quit when all windows are closed. // In this file you can include the rest of your app's specific main process
app.on('window-all-closed', function () { // code. You can also put them in separate files and require them here.
// On OS X it is common for applications and their menu bar // listen for request to get template
// to stay active until the user quits explicitly with Cmd + Q ipcMain.on('getTemplateContent', (event, arg) => {
if (process.platform !== 'darwin') { event.returnValue = fs.readFileSync(path.join(app.getAppPath(), "assets/templates/") + arg, 'utf8');
EthoGeth.stopGeth(); });
app.quit()
}
}) })
.catch(function(err) {
app.on('activate', function () { app.quit();
// On OS X it's common to re-create a window in the app when the
// dock icon is clicked and there are no other windows open.
if (mainWindow === null) {
createWindow()
}
}) })
// In this file you can include the rest of your app's specific main process
// code. You can also put them in separate files and require them here.
// listen for request to get template
ipcMain.on('getTemplateContent', (event, arg) => {
event.returnValue = fs.readFileSync(path.join(app.getAppPath(), "assets/templates/") + arg, 'utf8');
});
require('./modules/geth.js'); require('./modules/geth.js');
require('./modules/accounts.js'); require('./modules/accounts.js');
require('./modules/database.js'); require('./modules/database.js');

View File

@@ -14,7 +14,7 @@ db.ensureIndex({ fieldName: 'block' }, function (err) {
}); });
ipcMain.on('storeTransaction', (event, arg) => { ipcMain.on('storeTransaction', (event, arg) => {
db.update({ block: arg.block, fromaddr: arg.fromaddr, toaddr: arg.toaddr }, arg, { upsert: true }, function (err, numReplaced, upsert) { db.update({ txhash: arg.txhash }, arg, { upsert: true }, function (err, numReplaced, upsert) {
// do nothing for now // do nothing for now
}); });
}); });
@@ -29,8 +29,7 @@ ipcMain.on('getTransactions', (event, arg) => {
docs[i].timestamp, docs[i].timestamp,
docs[i].fromaddr, docs[i].fromaddr,
docs[i].toaddr, docs[i].toaddr,
docs[i].value, docs[i].value
docs[i].confirmed || 1
]); ]);
} }

View File

@@ -53,8 +53,8 @@ class Geth {
this.gethProcess.stdout.on('data', function(data) { this.gethProcess.stdout.on('data', function(data) {
EthoGeth._writeLog(data.toString() + '\n'); EthoGeth._writeLog(data.toString() + '\n');
}); });
} catch (e) { } catch (err) {
dialog.showErrorBox("Error starting application", e); dialog.showErrorBox("Error starting application", err.message);
app.quit(); app.quit();
} }
} }

View File

@@ -21,14 +21,14 @@
"win": { "win": {
"icon": "build/icon.png", "icon": "build/icon.png",
"target": "7z", "target": "7z",
"artifactName": "Windows-${productName}-${version}.${ext}", "artifactName": "Windows-${productName}-${version}.${ext}",
"extraResources": [ "extraResources": [
"bin/win/*" "bin/win/*"
] ]
}, },
"linux": { "linux": {
"target": "tar.gz", "target": "tar.gz",
"artifactName": "Linux-${productName}-${version}.${ext}", "artifactName": "Linux-${productName}-${version}.${ext}",
"extraResources": [ "extraResources": [
"bin/linux/*" "bin/linux/*"
] ]
@@ -47,7 +47,8 @@
"app-root-path": "^2.1.0", "app-root-path": "^2.1.0",
"electron-storage": "^1.0.7", "electron-storage": "^1.0.7",
"handlebars": "^4.0.12", "handlebars": "^4.0.12",
"nedb": "^1.8.0" "nedb": "^1.8.0",
"single-instance": "0.0.1"
}, },
"devDependencies": { "devDependencies": {
"electron": "^3.0.12", "electron": "^3.0.12",

View File

@@ -145,16 +145,14 @@ $(document).on("render_send", function() {
EthoMainGUI.showGeneralError(error); EthoMainGUI.showGeneralError(error);
}, },
function(transaction) { function(transaction) {
/*
ipcRenderer.send('storeTransaction', { ipcRenderer.send('storeTransaction', {
block: element.block, block: element.block.toString(),
fromaddr: element.fromaddr, txhash: element.hash.toLowerCase(),
fromaddr: element.fromaddr.toLowerCase(),
timestamp: element.timestamp, timestamp: element.timestamp,
toaddr: element.toaddr, toaddr: element.toaddr.toLowerCase(),
value: element.value, value: element.value
confirmed: "1",
}); });
*/
} }
); );
} }

View File

@@ -28,7 +28,7 @@ SyncProgress = new ProgressBar.Line('#syncProgress',
}); });
// set initial value for the progress text // set initial value for the progress text
SyncProgress.setText("initializing, please wait..."); SyncProgress.setText("Waiting for blockchain, please wait...");
var peerCountInterval = setInterval(function() var peerCountInterval = setInterval(function()
{ {
@@ -39,61 +39,67 @@ var peerCountInterval = setInterval(function()
function StartSyncProcess() { function StartSyncProcess() {
var alreadyCatchedUp = false; var alreadyCatchedUp = false;
var nodeSyncInterval = null;
function keepTheNodeInSync(interval) { var subscription = web3Local.eth.subscribe('syncing', function(error, sync){
var nodeSyncInterval = setInterval(function() if (!error) {
{ if (!sync) {
web3Local.eth.isSyncing(function(error, sync) if (nodeSyncInterval) {
clearInterval(nodeSyncInterval);
}
nodeSyncInterval = setInterval(function()
{
web3Local.eth.getBlock("latest", function(error, localBlock) {
if (localBlock.number > 0) {
if (!EthoTransactions.getIsSyncing()) {
SyncProgress.animate(1);
SyncProgress.setText(vsprintf('%d/%d (100%%)', [localBlock.number, localBlock.number]));
}
if (alreadyCatchedUp == false)
{
// clear the repeat interval and render wallets
$(document).trigger("onNewAccountTransaction");
alreadyCatchedUp = true;
// sync all the transactions to the current block
EthoTransactions.syncTransactionsForAllAddresses(localBlock.number);
$(document).trigger("onSyncInterval");
}
}
});
}, 10000);
}
}
}).on("data", function(sync){
if ((sync) && (sync.HighestBlock > 0)) {
SyncProgress.animate(sync.CurrentBlock / sync.HighestBlock);
SyncProgress.setText(vsprintf('%d/%d (%d%%)', [sync.CurrentBlock, sync.HighestBlock, Math.round(sync.CurrentBlock / sync.HighestBlock * 100)]));
}
}).on("changed", function(isSyncing){
if(isSyncing) {
nodeSyncInterval = setInterval(function()
{ {
if(!error) { web3Local.eth.isSyncing(function(error, sync){
if(sync == true) { if ((!error) && (sync)) {
console.log("start the sync");
} else if(sync) {
SyncProgress.animate(sync.currentBlock / sync.highestBlock); SyncProgress.animate(sync.currentBlock / sync.highestBlock);
SyncProgress.setText(vsprintf('%d/%d (%d%%)', [sync.currentBlock, sync.highestBlock, Math.round(sync.currentBlock / sync.highestBlock * 100)])); SyncProgress.setText(vsprintf('%d/%d (%d%%)', [sync.currentBlock, sync.highestBlock, Math.round(sync.currentBlock / sync.highestBlock * 100)]));
} else {
web3Local.eth.getBlock("latest", function(error, localBlock) {
if (localBlock.number > 0) {
web3Remote.eth.getBlock("latest", function(error, remoteBlock) {
if (!EthoTransactions.getIsSyncing()) {
SyncProgress.animate(localBlock.number / remoteBlock.number);
SyncProgress.setText(vsprintf('%d/%d (%d%%)', [localBlock.number, remoteBlock.number, Math.round(localBlock.number / remoteBlock.number * 100)]));
}
if (remoteBlock.number == localBlock.number) {
if (alreadyCatchedUp == false)
{
// clear the repeat interval and render wallets
$(document).trigger("onNewAccountTransaction");
clearInterval(nodeSyncInterval);
alreadyCatchedUp = true;
// sync all the transactions to the current block
EthoTransactions.syncTransactionsForAllAddresses(localBlock.number);
$(document).trigger("onSyncInterval");
// restart with less intensity
keepTheNodeInSync(10000);
}
}
});
}
});
} }
} });
}); }, 2000);
}, interval); } else {
} if (nodeSyncInterval) {
clearInterval(nodeSyncInterval);
// initial fast syncing }
keepTheNodeInSync(2000); }
});
} }
var InitWeb3 = setInterval(function() var InitWeb3 = setInterval(function()
{ {
try { try {
web3Local = new Web3(new Web3.providers.WebsocketProvider('ws://localhost:8546')); web3Local = new Web3(new Web3.providers.WebsocketProvider('ws://localhost:8546'));
web3Remote = new Web3(new Web3.providers.HttpProvider("https://rpc.ether1.org"));
web3Local.eth.net.isListening(function(error, success) { web3Local.eth.net.isListening(function(error, success) {
if (!error) { if (!error) {

View File

@@ -36,13 +36,12 @@ class Transactions {
$.getJSON("https://richlist.ether1.org/transactions_list.php" + params, function( result ) { $.getJSON("https://richlist.ether1.org/transactions_list.php" + params, function( result ) {
result.data.forEach(element => { result.data.forEach(element => {
ipcRenderer.send('storeTransaction', { ipcRenderer.send('storeTransaction', {
block: element.block, block: element.block.toString(),
txhash: element.hash, txhash: element.txhash.toLowerCase(),
fromaddr: element.fromaddr, fromaddr: element.fromaddr.toLowerCase(),
timestamp: element.timestamp, timestamp: element.timestamp,
toaddr: element.toaddr, toaddr: element.toaddr.toLowerCase(),
value: element.value, value: element.value
confirmed: "1"
}); });
}); });
@@ -149,11 +148,12 @@ class Transactions {
}, },
{ {
"targets": 6, "targets": 6,
"defaultContent": "",
"render": function ( data, type, row ) { "render": function ( data, type, row ) {
if (data == 0) { if (row[1]) {
return '<i class="fas fa-question"></i>';
} else if (data == 1) {
return '<i class="fas fa-check"></i>'; return '<i class="fas fa-check"></i>';
} else if (data == 1) {
return '<i class="fas fa-question"></i>';
} }
} }
} }
@@ -196,11 +196,11 @@ $(document).on("onSyncInterval", function() {
if ((EthoWallets.getAddressExists(element.from)) || (EthoWallets.getAddressExists(element.to))) { if ((EthoWallets.getAddressExists(element.from)) || (EthoWallets.getAddressExists(element.to))) {
var Transaction = { var Transaction = {
block: element.blockNumber.toString(), block: element.blockNumber.toString(),
txhash: element.hash.toLowerCase(),
fromaddr: element.from.toLowerCase(), fromaddr: element.from.toLowerCase(),
timestamp: moment().format('YYYY-MM-DD HH:mm:ss'), timestamp: moment().format('YYYY-MM-DD HH:mm:ss'),
toaddr: element.to.toLowerCase(), toaddr: element.to.toLowerCase(),
value: Number(element.value).toExponential(5).toString().replace('+',''), value: Number(element.value).toExponential(5).toString().replace('+','')
confirmed: "0",
} }
// store transaction and notify about new transactions // store transaction and notify about new transactions