Commit 78e59de1 authored by Eriksson Monteiro's avatar Eriksson Monteiro

update millix node

parent 681cdb22
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
<br> <br>
<a href="#"><img src="https://github.com/millix/millix-wallet/blob/master/app/icon.png?raw=true" alt="millix node" width="200"></a> <a href="#"><img src="https://github.com/millix/millix-wallet/blob/master/app/icon.png?raw=true" alt="millix node" width="200"></a>
<br> <br>
millix node <small>v1.10.1</small> millix node <small>v1.10.6</small>
<br> <br>
</h1> </h1>
......
...@@ -13,8 +13,7 @@ class _OBexeX0f0MsnL1S3 extends Endpoint { ...@@ -13,8 +13,7 @@ class _OBexeX0f0MsnL1S3 extends Endpoint {
} }
/** /**
* get the active wallet in the node * gets the active wallet in the node
* in the node
* @param app * @param app
* @param req * @param req
* @param res * @param res
......
...@@ -27,8 +27,16 @@ class _Xim7SaikcsHICvfQ extends Endpoint { ...@@ -27,8 +27,16 @@ class _Xim7SaikcsHICvfQ extends Endpoint {
}); });
} }
try { try {
const {address: addressBase, identifier: addressKeyIdentifier} = this.addressRepository.getAddressComponent(address); const {
res.send({is_valid: walletUtils.isValidAddress(addressBase) && walletUtils.isValidAddress(addressKeyIdentifier)}); address : addressBase,
identifier: addressKeyIdentifier, version: addressVersion
} = this.addressRepository.getAddressComponent(address);
res.send({
is_valid : walletUtils.isValidAddress(addressBase) && walletUtils.isValidAddress(addressKeyIdentifier),
address_base : addressBase,
address_version : addressVersion,
address_key_identifier: addressKeyIdentifier
});
} }
catch (e) { catch (e) {
res.send({ res.send({
......
import Endpoint from '../endpoint';
import wallet from '../../core/wallet/wallet';
import _ from 'lodash';
import services from '../../core/services/services';
/**
* api end_session
*/
class _pIQZEKY4T9vttBUk extends Endpoint {
constructor() {
super('pIQZEKY4T9vttBUk');
}
/**
* ends the active wallet session in the node
* @param app
* @param req
* @param res
* @returns {*}
*/
handler(app, req, res) {
if (!wallet.initialized || _.isEmpty(wallet.getActiveWallets())) {
return res.send({
api_status : 'fail',
api_message: 'wallet not loaded'
});
}
services.stop();
return res.send({
address_key_identifier: wallet.defaultKeyIdentifier,
locked : true
});
}
}
export default new _pIQZEKY4T9vttBUk();
import Endpoint from '../endpoint';
import database from '../../database/database';
/**
* api list_transaction_history
*/
class _w9UTTA7NXnEDUXhe extends Endpoint {
constructor() {
super('w9UTTA7NXnEDUXhe');
}
/**
* list transaction history for a given wallet
* @param app
* @param req (p0: address_key_identifier<require>)
* @param res
* @returns {*}
*/
handler(app, req, res) {
let addressKeyIdentifier;
if (req.method === 'GET') {
if (!req.query.p0) {
return res.status(400).send({
api_status : 'fail',
api_message: 'p0<address_key_identifier> is required'
});
}
else {
addressKeyIdentifier = req.query.p0;
}
}
else {
if (!req.body.p0) {
return res.status(400).send({
api_status : 'fail',
api_message: 'p0<address_key_identifier> is required'
});
}
else {
addressKeyIdentifier = req.body.p0;
}
}
return database.applyShards((shardID) => {
return database.getRepository('transaction', shardID)
.getTransactionsByAddressKeyIdentifier(addressKeyIdentifier);
}, 'transaction_date desc').then(transactions => {
res.send(transactions);
}).catch(e => res.send({
api_status : 'fail',
api_message: `unexpected generic api error: (${e})`
}));
}
}
export default new _w9UTTA7NXnEDUXhe();
...@@ -422,6 +422,24 @@ ...@@ -422,6 +422,24 @@
"version_released": "1.10.2", "version_released": "1.10.2",
"permission": "{\"require_identity\": true, \"private\": true}", "permission": "{\"require_identity\": true, \"private\": true}",
"enable": true "enable": true
},
{
"id": "w9UTTA7NXnEDUXhe",
"name": "list_transaction_history",
"description": "list transaction history for a given wallet",
"method": "GET",
"version_released": "1.10.6",
"permission": "{\"require_identity\": true, \"private\": false}",
"enable": true
},
{
"id": "pIQZEKY4T9vttBUk",
"name": "end_session",
"description": "ends the active wallet session in the node",
"method": "GET",
"version_released": "1.10.6",
"permission": "{\"require_identity\": true, \"private\": true}",
"enable": true
} }
] ]
} }
...@@ -734,7 +734,7 @@ export const TRANSACTION_INPUT_MAX = 128; ...@@ -734,7 +734,7 @@ export const TRANSACTION_INPUT_MAX = 128;
export const TRANSACTION_OUTPUT_MAX = 128; export const TRANSACTION_OUTPUT_MAX = 128;
export const TRANSACTION_PARENT_MAX = 16; export const TRANSACTION_PARENT_MAX = 16;
export const TRANSACTION_SIGNATURE_MAX = 128; export const TRANSACTION_SIGNATURE_MAX = 128;
export const TRANSACTION_PROGRESSIVE_SYNC_TIMESPAN = 3600; export const TRANSACTION_PROGRESSIVE_SYNC_TIMESPAN = 60;
export const TRANSACTION_OUTPUT_REFRESH_OLDER_THAN = 10; export const TRANSACTION_OUTPUT_REFRESH_OLDER_THAN = 10;
export const TRANSACTION_OUTPUT_EXPIRE_OLDER_THAN = 10; export const TRANSACTION_OUTPUT_EXPIRE_OLDER_THAN = 10;
export const NODE_CONNECTION_INBOUND_MAX = 30; export const NODE_CONNECTION_INBOUND_MAX = 30;
...@@ -774,8 +774,8 @@ export const NETWORK_SHORT_TIME_WAIT_MAX = 1500; ...@@ -774,8 +774,8 @@ export const NETWORK_SHORT_TIME_WAIT_MAX = 1500;
export const DATABASE_ENGINE = 'sqlite'; export const DATABASE_ENGINE = 'sqlite';
export const DATABASE_CONNECTION = {}; export const DATABASE_CONNECTION = {};
export const MILLIX_CIRCULATION = 9e15; export const MILLIX_CIRCULATION = 9e15;
export const NODE_MILLIX_BUILD_DATE = 1618313467; export const NODE_MILLIX_BUILD_DATE = 1621005039;
export const NODE_MILLIX_VERSION = '1.10.1-tangled'; export const NODE_MILLIX_VERSION = '1.10.6-tangled';
export const DATA_BASE_DIR_MAIN_NETWORK = './millix-tangled'; export const DATA_BASE_DIR_MAIN_NETWORK = './millix-tangled';
export const DATA_BASE_DIR_TEST_NETWORK = './millix-testnet'; export const DATA_BASE_DIR_TEST_NETWORK = './millix-testnet';
let DATA_BASE_DIR = MODE_TEST_NETWORK ? DATA_BASE_DIR_TEST_NETWORK : DATA_BASE_DIR_MAIN_NETWORK; let DATA_BASE_DIR = MODE_TEST_NETWORK ? DATA_BASE_DIR_TEST_NETWORK : DATA_BASE_DIR_MAIN_NETWORK;
...@@ -784,7 +784,7 @@ export const NODE_CERTIFICATE_KEY_PATH = DATA_BASE_DIR + ...@@ -784,7 +784,7 @@ export const NODE_CERTIFICATE_KEY_PATH = DATA_BASE_DIR +
export const NODE_CERTIFICATE_PATH = DATA_BASE_DIR + '/node_certificate.pem'; export const NODE_CERTIFICATE_PATH = DATA_BASE_DIR + '/node_certificate.pem';
export const WALLET_KEY_PATH = DATA_BASE_DIR + '/millix_private_key.json'; export const WALLET_KEY_PATH = DATA_BASE_DIR + '/millix_private_key.json';
export const JOB_CONFIG_PATH = DATA_BASE_DIR + '/job.json'; export const JOB_CONFIG_PATH = DATA_BASE_DIR + '/job.json';
export const JOB_CONFIG_VERSION = 2; export const JOB_CONFIG_VERSION = 3;
export const SHARD_ZERO_NAME = 'shard_zero'; export const SHARD_ZERO_NAME = 'shard_zero';
export const PEER_ROTATION_MORE_THAN_AVERAGE = 0.5; export const PEER_ROTATION_MORE_THAN_AVERAGE = 0.5;
export const PEER_ROTATION_MORE_THAN_MOST = 0.2; export const PEER_ROTATION_MORE_THAN_MOST = 0.2;
......
...@@ -313,7 +313,7 @@ ...@@ -313,7 +313,7 @@
"option_list": { "option_list": {
"run_always": 1, "run_always": 1,
"run_delay": 600000, "run_delay": 600000,
"enable": true "enable": false
} }
}, },
"node_attribute_update": { "node_attribute_update": {
......
import config from './config/config'; import config from './config/config';
let enabled = true;
console.disable = () => enabled = false; let enabled = true;
console.enable = () => enabled = true; console.disable = () => enabled = false;
console.enable = () => enabled = true;
const _consoleLog = console.log; const _consoleLog = console.log;
console.log = function() { const filters = [];
enabled && config.MODE_DEBUG && _consoleLog.apply(console, arguments);
console.addFilter = function(filter) {
filters.push(filter);
};
console.log = function() {
let showLog = true;
if(filters.length > 0) {
const regex = new RegExp(`^\\[(${filters.join('|')})[^\\]]*\\]`, "m");
showLog = !!regex.exec(arguments[0]);
}
enabled && showLog && config.MODE_DEBUG && _consoleLog.apply(console, arguments);
}; };
export default console; export default console;
...@@ -35,7 +35,6 @@ class Service { ...@@ -35,7 +35,6 @@ class Service {
.then(() => peerRotation.initialize()) .then(() => peerRotation.initialize())
.then(() => jobEngine.initialize()) .then(() => jobEngine.initialize())
.then(() => wallet._doUpdateNodeAttribute()) .then(() => wallet._doUpdateNodeAttribute())
.then(() => wallet._doTransactionOutputRefresh())
.catch(e => { .catch(e => {
console.log(`[services] ${e.message}`); console.log(`[services] ${e.message}`);
this.initialized = false; this.initialized = false;
......
...@@ -34,10 +34,10 @@ export class WalletSync { ...@@ -34,10 +34,10 @@ export class WalletSync {
return callback(); return callback();
} }
delete this.pendingTransactions[job.transaction_id]; this.pendingTransactions[job.transaction_id] = true;
if (job.attempt >= config.TRANSACTION_RETRY_SYNC_MAX) { if (job.attempt >= config.TRANSACTION_RETRY_SYNC_MAX) {
this.unresolvedTransactionQueue.push({ this.removeTransactionSync(job.transaction_id, {
id : 'transaction_' + job.transaction_id, id : 'transaction_' + job.transaction_id,
data: job data: job
}); });
...@@ -58,6 +58,14 @@ export class WalletSync { ...@@ -58,6 +58,14 @@ export class WalletSync {
if (hasTransaction || wallet.isProcessingTransaction(job.transaction_id)) { if (hasTransaction || wallet.isProcessingTransaction(job.transaction_id)) {
return callback(); return callback();
} }
this.addSchedule(job.transaction_id, {
...job,
dispatch_request: true,
queued : true,
attempt : job.attempt + 1
}, config.NETWORK_LONG_TIME_WAIT_MAX * 2);
peer.transactionSyncRequest(job.transaction_id, job) peer.transactionSyncRequest(job.transaction_id, job)
.then(() => callback()) .then(() => callback())
.catch(() => callback()); .catch(() => callback());
...@@ -215,6 +223,9 @@ export class WalletSync { ...@@ -215,6 +223,9 @@ export class WalletSync {
return; return;
} }
const beginTimestamp = timestamp - config.TRANSACTION_PROGRESSIVE_SYNC_TIMESPAN; const beginTimestamp = timestamp - config.TRANSACTION_PROGRESSIVE_SYNC_TIMESPAN;
if (database.getRepository('transaction').isExpired(timestamp)) {
return;
}
// get transactions from shard, filtered by date // get transactions from shard, filtered by date
database.applyShards((shardID) => { database.applyShards((shardID) => {
const transactionRepository = database.getRepository('transaction', shardID); const transactionRepository = database.getRepository('transaction', shardID);
...@@ -255,6 +266,7 @@ export class WalletSync { ...@@ -255,6 +266,7 @@ export class WalletSync {
this.unresolvedTransactionQueue._store.getTask('transaction_' + transactionID, (err, unresolvedTransaction) => { this.unresolvedTransactionQueue._store.getTask('transaction_' + transactionID, (err, unresolvedTransaction) => {
const {delay, priority} = options || {}; const {delay, priority} = options || {};
const attempt = options && options.attempt ? options.attempt + 1 : 1; const attempt = options && options.attempt ? options.attempt + 1 : 1;
const timestamp = options && options.timestamp ? options.timestamp : Date.now();
if (unresolvedTransaction && (!unresolvedTransaction.data.transaction_sync_rejected || !(priority > 0 && attempt < config.TRANSACTION_RETRY_SYNC_MAX))) { if (unresolvedTransaction && (!unresolvedTransaction.data.transaction_sync_rejected || !(priority > 0 && attempt < config.TRANSACTION_RETRY_SYNC_MAX))) {
return; return;
...@@ -263,33 +275,25 @@ export class WalletSync { ...@@ -263,33 +275,25 @@ export class WalletSync {
return; return;
} }
if (attempt >= config.TRANSACTION_RETRY_SYNC_MAX) { if (attempt >= config.TRANSACTION_RETRY_SYNC_MAX || database.getRepository('transaction').isExpired(Math.floor(timestamp / 1000))) {
this.removeSchedule(transactionID); this.removeTransactionSync(transactionID, {
delete this.pendingTransactions[transactionID];
this.unresolvedTransactionQueue.push({
id : 'transaction_' + transactionID, id : 'transaction_' + transactionID,
data: { data: {
transaction_id : transactionID, transaction_id : transactionID,
dispatch_request: true, dispatch_request: true,
priority : priority === undefined ? -1 : priority, priority : priority === undefined ? -1 : priority,
timestamp,
attempt attempt
} }
}); });
} }
else if (delay && delay > 0) { else if (delay && delay > 0) {
this.scheduledQueueAdd[transactionID] = setTimeout(() => { this.addSchedule(transactionID, {
if (!this.queue || this.pendingTransactions[transactionID]) { transaction_id : transactionID,
return; dispatch_request: true,
} timestamp,
attempt,
this.pendingTransactions[transactionID] = true; priority
delete this.scheduledQueueAdd[transactionID];
this.queue.push({
transaction_id : transactionID,
dispatch_request: true,
attempt,
priority
});
}, delay); }, delay);
} }
else { else {
...@@ -298,6 +302,7 @@ export class WalletSync { ...@@ -298,6 +302,7 @@ export class WalletSync {
this.queue.push({ this.queue.push({
transaction_id : transactionID, transaction_id : transactionID,
dispatch_request: true, dispatch_request: true,
timestamp,
attempt, attempt,
priority priority
}); });
...@@ -305,22 +310,47 @@ export class WalletSync { ...@@ -305,22 +310,47 @@ export class WalletSync {
}); });
} }
addSchedule(transactionID, data = {}, delay) {
this.scheduledQueueAdd[transactionID] = setTimeout(() => {
if (!this.queue || !data.dispatch_request && this.pendingTransactions[transactionID]) {
return;
}
this.pendingTransactions[transactionID] = true;
delete this.scheduledQueueAdd[transactionID];
this.queue.push(data);
}, delay);
}
removeSchedule(transactionID) { removeSchedule(transactionID) {
this.scheduledQueueAdd[transactionID] && clearTimeout(this.scheduledQueueAdd[transactionID]); this.scheduledQueueAdd[transactionID] && clearTimeout(this.scheduledQueueAdd[transactionID]);
delete this.scheduledQueueAdd[transactionID]; delete this.scheduledQueueAdd[transactionID];
} }
removeTransactionSync(transactionID) { hasPendingTransaction(transactionID) {
return this.pendingTransactions[transactionID];
}
clearTransactionSync(transactionID) {
this.queue.cancel(transactionID); this.queue.cancel(transactionID);
this.removeSchedule(transactionID);
delete this.pendingTransactions[transactionID]; delete this.pendingTransactions[transactionID];
this.unresolvedTransactionQueue.push({ }
id : 'transaction_' + transactionID,
data: { removeTransactionSync(transactionID, data) {
transaction_id : transactionID, this.removeSchedule(transactionID);
transaction_sync_rejected: true this.clearTransactionSync(transactionID);
}
}); if (!data) {
data = {
id : 'transaction_' + transactionID,
data: {
transaction_id : transactionID,
transaction_sync_rejected: true
}
};
}
this.unresolvedTransactionQueue.push(data);
} }
close() { close() {
......
...@@ -178,7 +178,7 @@ export class WalletTransactionConsensus { ...@@ -178,7 +178,7 @@ export class WalletTransactionConsensus {
const transactionRepository = database.getRepository('transaction', shardID); const transactionRepository = database.getRepository('transaction', shardID);
transactionRepository.getTransactionObject(transactionID) transactionRepository.getTransactionObject(transactionID)
.then(transaction => transaction ? resolve([ .then(transaction => transaction ? resolve([
transactionRepository.normalizeTransactionObject(transaction), transaction,
shardID shardID
]) : reject()); ]) : reject());
}); });
...@@ -199,7 +199,12 @@ export class WalletTransactionConsensus { ...@@ -199,7 +199,12 @@ export class WalletTransactionConsensus {
console.log('[consensus][oracle] validated in consensus round after found a validated transaction at depth ', depth); console.log('[consensus][oracle] validated in consensus round after found a validated transaction at depth ', depth);
return resolve(); return resolve();
} }
else if (auditPointID) {
if (transaction && transaction.is_stable !== undefined) { // transaction object needs to be normalized
transaction = database.getRepository('transaction').normalizeTransactionObject(transaction);
}
if (auditPointID) {
console.log('[consensus][oracle] validated in consensus round after found in Local audit point ', auditPointID, ' at depth ', depth); console.log('[consensus][oracle] validated in consensus round after found in Local audit point ', auditPointID, ' at depth ', depth);
return resolve(); return resolve();
} }
...@@ -233,8 +238,8 @@ export class WalletTransactionConsensus { ...@@ -233,8 +238,8 @@ export class WalletTransactionConsensus {
transactionVisitedSet.add(transactionID); transactionVisitedSet.add(transactionID);
let sourceTransactions = new Set(); let sourceTransactions = new Set();
let inputTotalAmount = 0; let inputTotalAmount = 0;
const outputUsedInTransaction = new Set(); const outputUsedInTransaction = new Set();
// get inputs and check double // get inputs and check double
// spend // spend
...@@ -868,7 +873,11 @@ export class WalletTransactionConsensus { ...@@ -868,7 +873,11 @@ export class WalletTransactionConsensus {
delete this._validationPrepareState[transactionID]; delete this._validationPrepareState[transactionID];
} }
else if (err.cause === 'transaction_not_found') { else if (err.cause === 'transaction_not_found') {
wallet.requestTransactionFromNetwork(err.transaction_id_fail, {priority: isTransactionFundingWallet ? 1 : 0, dispatch_request: true}, isTransactionFundingWallet); wallet.requestTransactionFromNetwork(err.transaction_id_fail, {
priority : isTransactionFundingWallet ? 1 : 0,
dispatch_request : true,
force_request_sync: isTransactionFundingWallet
}, isTransactionFundingWallet);
// check if we should keep trying // check if we should keep trying
const validationState = this._validationPrepareState[transactionID]; const validationState = this._validationPrepareState[transactionID];
if (!!validationState) { if (!!validationState) {
......
This diff is collapsed.
...@@ -48,52 +48,52 @@ export default class Transaction { ...@@ -48,52 +48,52 @@ export default class Transaction {
] : Promise.reject()); ] : Promise.reject());
}).then(result => result || []).then(([transactionInput, transactionRepository]) => { }).then(result => result || []).then(([transactionInput, transactionRepository]) => {
if (transactionInput) { if (transactionInput) {
return transactionRepository.getTransactionInputs(transactionInput.transaction_id) if (transactionInput.is_stable) {
.then(inputs => { return transactionInput;
transactionInput.transaction_input_list = inputs; }
return transactionInput; else {
}); return transactionRepository.getTransactionInputs(transactionInput.transaction_id)
.then(inputs => {
transactionInput.transaction_input_list = inputs;
return transactionInput;
});
}
} }
else { else {
return new Promise(resolve => { return null;
const requestTransactionFromNetwork = () => {
wallet.enableTransactionSync(inputTransactionID);
return peer.transactionSyncRequest(inputTransactionID, {
priority : 1,
dispatch_request: true
}).then(() => wallet.flagTransactionAsRequested(inputTransactionID));
};
eventBus.once('transaction_new:' + inputTransactionID, newTransaction => {
resolve({
...newTransaction,
transaction_date: new Date(newTransaction.transaction_date)
});
});
requestTransactionFromNetwork()
.then(_ => _)
.catch(() => {
setTimeout(() => requestTransactionFromNetwork(), config.NETWORK_LONG_TIME_WAIT_MAX * 2);
});
});
} }
}).then(transactionInput => { }).then(transactionInput => {
if (!transactionInput) {
callback(true);
}
inputChain.push({ inputChain.push({
transaction_id : transactionInput.transaction_id, transaction_id : transactionInput.transaction_id,
transaction_date: transactionInput.transaction_date transaction_date: transactionInput.transaction_date
}); });
if (!database.getRepository('transaction').isExpired(Math.round(transactionInput.transaction_date.getTime() / 1000))) {
for (const input of transactionInput.transaction_input_list) { if (transactionInput.transaction_input_list) {
if (!processedInputTransactionSet.has(input.output_transaction_id)) { if (!database.getRepository('transaction').isExpired(Math.round(transactionInput.transaction_date.getTime() / 1000))) {
pendingInputsSet[input.output_transaction_id] = { for (const input of transactionInput.transaction_input_list) {
transaction_id: input.output_transaction_id, if (!processedInputTransactionSet.has(input.output_transaction_id)) {
shard_id : input.output_shard_id pendingInputsSet[input.output_transaction_id] = {
}; transaction_id: input.output_transaction_id,
shard_id : input.output_shard_id
};
}
} }
} }
else {
callback(true);
}
} }
callback(); callback();
}); });
}, () => { }, (cannotValidateTransaction) => {
if (cannotValidateTransaction) {
return resolve([]);
}
const pendingTransactionIDList = _.keys(pendingInputsSet); const pendingTransactionIDList = _.keys(pendingInputsSet);
if (pendingTransactionIDList.length > 0) { if (pendingTransactionIDList.length > 0) {
dfs(_.map(pendingTransactionIDList, p => pendingInputsSet[p]), inputChain, processedInputTransactionSet); dfs(_.map(pendingTransactionIDList, p => pendingInputsSet[p]), inputChain, processedInputTransactionSet);
...@@ -104,6 +104,8 @@ export default class Transaction { ...@@ -104,6 +104,8 @@ export default class Transaction {
} }
}); });
}; };
dfs(_.uniq(_.map(transaction.transaction_input_list, i => ({ dfs(_.uniq(_.map(transaction.transaction_input_list, i => ({
transaction_id: i.output_transaction_id, transaction_id: i.output_transaction_id,
shard_id : i.output_shard_id shard_id : i.output_shard_id
...@@ -133,8 +135,8 @@ export default class Transaction { ...@@ -133,8 +135,8 @@ export default class Transaction {
return new Promise((resolve) => { return new Promise((resolve) => {
this.database.get('SELECT SUM(amount) as amount FROM transaction_output ' + this.database.get('SELECT SUM(amount) as amount FROM transaction_output ' +
'INNER JOIN `transaction` ON `transaction`.transaction_id = transaction_output.transaction_id ' + 'INNER JOIN `transaction` ON `transaction`.transaction_id = transaction_output.transaction_id ' +
'WHERE transaction_output.address_key_identifier=? AND (`transaction`.is_stable = ' + (stable ? 1 : 0) + 'WHERE transaction_output.address_key_identifier=? AND `transaction`.is_stable = ' + (stable ? 1 : 0) +
(stable ? ' AND transaction_output.status != 2) ' : ' OR transaction_output.status = 2) ') + 'AND is_spent = 0 AND is_double_spend = 0', [keyIdentifier], ' AND is_spent = 0 AND is_double_spend = 0', [keyIdentifier],
(err, row) => { (err, row) => {
resolve(row ? row.amount || 0 : 0); resolve(row ? row.amount || 0 : 0);
}); });
...@@ -144,7 +146,7 @@ export default class Transaction { ...@@ -144,7 +146,7 @@ export default class Transaction {
getAddressBalance(address, stable) { getAddressBalance(address, stable) {
return new Promise((resolve) => { return new Promise((resolve) => {
this.database.get('SELECT SUM(amount) as amount FROM transaction_output INNER JOIN `transaction` ON `transaction`.transaction_id = transaction_output.transaction_id ' + this.database.get('SELECT SUM(amount) as amount FROM transaction_output INNER JOIN `transaction` ON `transaction`.transaction_id = transaction_output.transaction_id ' +
'WHERE address=? AND (`transaction`.is_stable = ' + (stable ? 1 : 0) + (stable ? ' AND transaction_output.status != 2) ' : ' OR transaction_output.status = 2) ') + 'AND is_spent = 0 AND is_double_spend = 0', [address], 'WHERE address=? AND `transaction`.is_stable = ' + (stable ? 1 : 0) + ' AND is_spent = 0 AND is_double_spend = 0', [address],
(err, row) => { (err, row) => {
resolve(row ? row.amount || 0 : 0); resolve(row ? row.amount || 0 : 0);
}); });
......
...@@ -109,3 +109,4 @@ db.initialize() ...@@ -109,3 +109,4 @@ db.initialize()
} }
}) })
.then(() => setTimeout(() => wallet.syncAddresses(), 2000)); .then(() => setTimeout(() => wallet.syncAddresses(), 2000));
//millix v1.10.6-tangled
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment