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

update millix node

parent 681cdb22
......@@ -2,7 +2,7 @@
<br>
<a href="#"><img src="https://github.com/millix/millix-wallet/blob/master/app/icon.png?raw=true" alt="millix node" width="200"></a>
<br>
millix node <small>v1.10.1</small>
millix node <small>v1.10.6</small>
<br>
</h1>
......
......@@ -13,8 +13,7 @@ class _OBexeX0f0MsnL1S3 extends Endpoint {
}
/**
* get the active wallet in the node
* in the node
* gets the active wallet in the node
* @param app
* @param req
* @param res
......
......@@ -27,8 +27,16 @@ class _Xim7SaikcsHICvfQ extends Endpoint {
});
}
try {
const {address: addressBase, identifier: addressKeyIdentifier} = this.addressRepository.getAddressComponent(address);
res.send({is_valid: walletUtils.isValidAddress(addressBase) && walletUtils.isValidAddress(addressKeyIdentifier)});
const {
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) {
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 @@
"version_released": "1.10.2",
"permission": "{\"require_identity\": true, \"private\": 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;
export const TRANSACTION_OUTPUT_MAX = 128;
export const TRANSACTION_PARENT_MAX = 16;
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_EXPIRE_OLDER_THAN = 10;
export const NODE_CONNECTION_INBOUND_MAX = 30;
......@@ -774,8 +774,8 @@ export const NETWORK_SHORT_TIME_WAIT_MAX = 1500;
export const DATABASE_ENGINE = 'sqlite';
export const DATABASE_CONNECTION = {};
export const MILLIX_CIRCULATION = 9e15;
export const NODE_MILLIX_BUILD_DATE = 1618313467;
export const NODE_MILLIX_VERSION = '1.10.1-tangled';
export const NODE_MILLIX_BUILD_DATE = 1621005039;
export const NODE_MILLIX_VERSION = '1.10.6-tangled';
export const DATA_BASE_DIR_MAIN_NETWORK = './millix-tangled';
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;
......@@ -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 WALLET_KEY_PATH = DATA_BASE_DIR + '/millix_private_key.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 PEER_ROTATION_MORE_THAN_AVERAGE = 0.5;
export const PEER_ROTATION_MORE_THAN_MOST = 0.2;
......
......@@ -313,7 +313,7 @@
"option_list": {
"run_always": 1,
"run_delay": 600000,
"enable": true
"enable": false
}
},
"node_attribute_update": {
......
import config from './config/config';
let enabled = true;
console.disable = () => enabled = false;
console.enable = () => enabled = true;
let enabled = true;
console.disable = () => enabled = false;
console.enable = () => enabled = true;
const _consoleLog = console.log;
console.log = function() {
enabled && config.MODE_DEBUG && _consoleLog.apply(console, arguments);
const filters = [];
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;
......@@ -35,7 +35,6 @@ class Service {
.then(() => peerRotation.initialize())
.then(() => jobEngine.initialize())
.then(() => wallet._doUpdateNodeAttribute())
.then(() => wallet._doTransactionOutputRefresh())
.catch(e => {
console.log(`[services] ${e.message}`);
this.initialized = false;
......
......@@ -34,10 +34,10 @@ export class WalletSync {
return callback();
}
delete this.pendingTransactions[job.transaction_id];
this.pendingTransactions[job.transaction_id] = true;
if (job.attempt >= config.TRANSACTION_RETRY_SYNC_MAX) {
this.unresolvedTransactionQueue.push({
this.removeTransactionSync(job.transaction_id, {
id : 'transaction_' + job.transaction_id,
data: job
});
......@@ -58,6 +58,14 @@ export class WalletSync {
if (hasTransaction || wallet.isProcessingTransaction(job.transaction_id)) {
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)
.then(() => callback())
.catch(() => callback());
......@@ -215,6 +223,9 @@ export class WalletSync {
return;
}
const beginTimestamp = timestamp - config.TRANSACTION_PROGRESSIVE_SYNC_TIMESPAN;
if (database.getRepository('transaction').isExpired(timestamp)) {
return;
}
// get transactions from shard, filtered by date
database.applyShards((shardID) => {
const transactionRepository = database.getRepository('transaction', shardID);
......@@ -255,6 +266,7 @@ export class WalletSync {
this.unresolvedTransactionQueue._store.getTask('transaction_' + transactionID, (err, unresolvedTransaction) => {
const {delay, priority} = options || {};
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))) {
return;
......@@ -263,33 +275,25 @@ export class WalletSync {
return;
}
if (attempt >= config.TRANSACTION_RETRY_SYNC_MAX) {
this.removeSchedule(transactionID);
delete this.pendingTransactions[transactionID];
this.unresolvedTransactionQueue.push({
if (attempt >= config.TRANSACTION_RETRY_SYNC_MAX || database.getRepository('transaction').isExpired(Math.floor(timestamp / 1000))) {
this.removeTransactionSync(transactionID, {
id : 'transaction_' + transactionID,
data: {
transaction_id : transactionID,
dispatch_request: true,
priority : priority === undefined ? -1 : priority,
timestamp,
attempt
}
});
}
else if (delay && delay > 0) {
this.scheduledQueueAdd[transactionID] = setTimeout(() => {
if (!this.queue || this.pendingTransactions[transactionID]) {
return;
}
this.pendingTransactions[transactionID] = true;
delete this.scheduledQueueAdd[transactionID];
this.queue.push({
transaction_id : transactionID,
dispatch_request: true,
attempt,
priority
});
this.addSchedule(transactionID, {
transaction_id : transactionID,
dispatch_request: true,
timestamp,
attempt,
priority
}, delay);
}
else {
......@@ -298,6 +302,7 @@ export class WalletSync {
this.queue.push({
transaction_id : transactionID,
dispatch_request: true,
timestamp,
attempt,
priority
});
......@@ -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) {
this.scheduledQueueAdd[transactionID] && clearTimeout(this.scheduledQueueAdd[transactionID]);
delete this.scheduledQueueAdd[transactionID];
}
removeTransactionSync(transactionID) {
hasPendingTransaction(transactionID) {
return this.pendingTransactions[transactionID];
}
clearTransactionSync(transactionID) {
this.queue.cancel(transactionID);
this.removeSchedule(transactionID);
delete this.pendingTransactions[transactionID];
this.unresolvedTransactionQueue.push({
id : 'transaction_' + transactionID,
data: {
transaction_id : transactionID,
transaction_sync_rejected: true
}
});
}
removeTransactionSync(transactionID, data) {
this.removeSchedule(transactionID);
this.clearTransactionSync(transactionID);
if (!data) {
data = {
id : 'transaction_' + transactionID,
data: {
transaction_id : transactionID,
transaction_sync_rejected: true
}
};
}
this.unresolvedTransactionQueue.push(data);
}
close() {
......
......@@ -178,7 +178,7 @@ export class WalletTransactionConsensus {
const transactionRepository = database.getRepository('transaction', shardID);
transactionRepository.getTransactionObject(transactionID)
.then(transaction => transaction ? resolve([
transactionRepository.normalizeTransactionObject(transaction),
transaction,
shardID
]) : reject());
});
......@@ -199,7 +199,12 @@ export class WalletTransactionConsensus {
console.log('[consensus][oracle] validated in consensus round after found a validated transaction at depth ', depth);
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);
return resolve();
}
......@@ -233,8 +238,8 @@ export class WalletTransactionConsensus {
transactionVisitedSet.add(transactionID);
let sourceTransactions = new Set();
let inputTotalAmount = 0;
let sourceTransactions = new Set();
let inputTotalAmount = 0;
const outputUsedInTransaction = new Set();
// get inputs and check double
// spend
......@@ -868,7 +873,11 @@ export class WalletTransactionConsensus {
delete this._validationPrepareState[transactionID];
}
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
const validationState = this._validationPrepareState[transactionID];
if (!!validationState) {
......
This diff is collapsed.
......@@ -48,52 +48,52 @@ export default class Transaction {
] : Promise.reject());
}).then(result => result || []).then(([transactionInput, transactionRepository]) => {
if (transactionInput) {
return transactionRepository.getTransactionInputs(transactionInput.transaction_id)
.then(inputs => {
transactionInput.transaction_input_list = inputs;
return transactionInput;
});
if (transactionInput.is_stable) {
return transactionInput;
}
else {
return transactionRepository.getTransactionInputs(transactionInput.transaction_id)
.then(inputs => {
transactionInput.transaction_input_list = inputs;
return transactionInput;
});
}
}
else {
return new Promise(resolve => {
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);
});
});
return null;
}
}).then(transactionInput => {
if (!transactionInput) {
callback(true);
}
inputChain.push({
transaction_id : transactionInput.transaction_id,
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 (!processedInputTransactionSet.has(input.output_transaction_id)) {
pendingInputsSet[input.output_transaction_id] = {
transaction_id: input.output_transaction_id,
shard_id : input.output_shard_id
};
if (transactionInput.transaction_input_list) {
if (!database.getRepository('transaction').isExpired(Math.round(transactionInput.transaction_date.getTime() / 1000))) {
for (const input of transactionInput.transaction_input_list) {
if (!processedInputTransactionSet.has(input.output_transaction_id)) {
pendingInputsSet[input.output_transaction_id] = {
transaction_id: input.output_transaction_id,
shard_id : input.output_shard_id
};
}
}
}
else {
callback(true);
}
}
callback();
});
}, () => {
}, (cannotValidateTransaction) => {
if (cannotValidateTransaction) {
return resolve([]);
}
const pendingTransactionIDList = _.keys(pendingInputsSet);
if (pendingTransactionIDList.length > 0) {
dfs(_.map(pendingTransactionIDList, p => pendingInputsSet[p]), inputChain, processedInputTransactionSet);
......@@ -104,6 +104,8 @@ export default class Transaction {
}
});
};
dfs(_.uniq(_.map(transaction.transaction_input_list, i => ({
transaction_id: i.output_transaction_id,
shard_id : i.output_shard_id
......@@ -133,8 +135,8 @@ export default class Transaction {
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 ' +
'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],
'WHERE transaction_output.address_key_identifier=? AND `transaction`.is_stable = ' + (stable ? 1 : 0) +
' AND is_spent = 0 AND is_double_spend = 0', [keyIdentifier],
(err, row) => {
resolve(row ? row.amount || 0 : 0);
});
......@@ -144,7 +146,7 @@ export default class Transaction {
getAddressBalance(address, stable) {
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 ' +
'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) => {
resolve(row ? row.amount || 0 : 0);
});
......
......@@ -109,3 +109,4 @@ db.initialize()
}
})
.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