Skip to content
This repository has been archived by the owner on Jun 11, 2024. It is now read-only.

Commit

Permalink
Merge pull request #21 from LiskHQ/0.9.10-multisig-unconfirmed-bug
Browse files Browse the repository at this point in the history
0.9.10 - Multisig transactions from the same account bug resolution
  • Loading branch information
Isabella Dell authored Oct 12, 2017
2 parents 8f95a2e + e4ba44c commit 231e5ab
Show file tree
Hide file tree
Showing 7 changed files with 845 additions and 9 deletions.
9 changes: 9 additions & 0 deletions Jenkinsfile
Original file line number Diff line number Diff line change
Expand Up @@ -297,6 +297,15 @@ lock(resource: "Lisk-Core-Nodes", inversePrecedence: true) {
'''
}
},
"Functional - Multisignature 3": {
node('node-03'){
sh '''
export TEST=test/functional/multisignature.js TEST_TYPE='FUNC'
cd "$(echo $WORKSPACE | cut -f 1 -d '@')"
npm run jenkins
'''
}
},
"Functional Peer - Votes" : {
node('node-02'){
sh '''
Expand Down
19 changes: 18 additions & 1 deletion helpers/database.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ var async = require('async');
var bignum = require('./bignum');
var fs = require('fs');
var path = require('path');
var monitor = require('pg-monitor');

// var isWin = /^win/.test(process.platform);
// var isMac = /^darwin/.test(process.platform);
Expand Down Expand Up @@ -185,7 +186,10 @@ module.exports.connect = function (config, logger, cb) {
};

var pgp = require('pg-promise')(pgOptions);
var monitor = require('pg-monitor');

try {
monitor.detach();
} catch (ex) {}

monitor.attach(pgOptions, config.logEvents);
monitor.setTheme('matrix');
Expand All @@ -211,3 +215,16 @@ module.exports.connect = function (config, logger, cb) {
return cb(err, db);
});
};

/**
* Detaches pg-monitor. Should be invoked after connect.
* @param {Object} logger
*/
module.exports.disconnect = function (logger) {
logger = logger || console;
try {
monitor.detach();
} catch (ex) {
logger.log('database disconnect exception - ', ex);
}
};
2 changes: 1 addition & 1 deletion logic/transaction.js
Original file line number Diff line number Diff line change
Expand Up @@ -471,7 +471,7 @@ Transaction.prototype.verify = function (trs, sender, requester, cb) {
}

// Determine multisignatures from sender or transaction asset
var multisignatures = sender.multisignatures || sender.u_multisignatures || [];
var multisignatures = sender.multisignatures || [];
if (multisignatures.length === 0) {
if (trs.asset && trs.asset.multisignature && trs.asset.multisignature.keysgroup) {

Expand Down
316 changes: 316 additions & 0 deletions test/common/application.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,316 @@
'use strict';

// Global imports
var child_process = require('child_process');
var Promise = require('bluebird');
var rewire = require('rewire');
var sinon = require('sinon');

// Application-specific imports
var node = require('./../node.js');
var database = require('../../helpers/database.js');
var jobsQueue = require('../../helpers/jobsQueue.js');
var Sequence = require('../../helpers/sequence.js');

var dbSandbox;
var currentAppScope;
var testDatabaseNames = [];

function DBSandbox (dbConfig, testDatabaseName) {
this.dbConfig = dbConfig;
this.originalDatabaseName = dbConfig.database;
this.testDatabaseName = testDatabaseName || this.originalDatabaseName;
this.dbConfig.database = this.testDatabaseName;
testDatabaseNames.push(this.testDatabaseName);

var dropCreatedDatabases = function () {
testDatabaseNames.forEach(function (testDatabaseName) {
child_process.exec('dropdb ' + testDatabaseName);
});
};

process.on('exit', function () {
dropCreatedDatabases();
});
}

DBSandbox.prototype.create = function (cb) {
child_process.exec('dropdb ' + this.dbConfig.database, function () {
child_process.exec('createdb ' + this.dbConfig.database, function () {
database.connect(this.dbConfig, console, cb);
}.bind(this));
}.bind(this));
};

DBSandbox.prototype.destroy = function (logger) {
database.disconnect(logger);
this.dbConfig.database = this.originalDatabaseName;
};

// Init whole application inside tests - public
function init (options, cb) {
options = options ? options : {};
options.scope = options.scope ? options.scope : {};

if (options.sandbox) {
dbSandbox = new DBSandbox(options.sandbox.config || node.config.db, options.sandbox.name);
dbSandbox.create(function (err, __db) {
options.scope.db = __db;
__init(options.scope, cb);
});
} else {
__init(options.scope, cb);
}
}

// Init whole application inside tests - private
function __init (initScope, done) {
node.debug('initApplication: Application initialization inside test environment started...');

// Reset jobsQueue
jobsQueue.jobs = {};

var modules = [], rewiredModules = {};
// Init dummy connection with database - valid, used for tests here
var options = {
promiseLib: Promise
};
var db = initScope.db;
if (!db) {
var pgp = require('pg-promise')(options);
node.config.db.user = node.config.db.user || process.env.USER;
db = pgp(node.config.db);
}

node.debug('initApplication: Target database - ' + node.config.db.database);

// Clear tables
db.task(function (t) {
return t.batch([
t.none('DELETE FROM blocks WHERE height > 1'),
t.none('DELETE FROM blocks'),
t.none('DELETE FROM mem_accounts')
]);
}).then(function () {
var logger = initScope.logger || {
trace: sinon.spy(),
debug: sinon.spy(),
info: sinon.spy(),
log: sinon.spy(),
warn: sinon.spy(),
error: sinon.spy()
};

var modulesInit = {
accounts: '../../modules/accounts.js',
rounds: '../../modules/rounds.js',
transactions: '../../modules/transactions.js',
blocks: '../../modules/blocks.js',
signatures: '../../modules/signatures.js',
transport: '../../modules/transport.js',
loader: '../../modules/loader.js',
system: '../../modules/system.js',
peers: '../../modules/peers.js',
delegates: '../../modules/delegates.js',
multisignatures: '../../modules/multisignatures.js'
};

// Init limited application layer
node.async.auto({
config: function (cb) {
cb(null, node.config);
},
genesisblock: function (cb) {
var genesisblock = require('../../genesisBlock.json');
cb(null, {block: genesisblock});
},

schema: function (cb) {
var z_schema = require('../../helpers/z_schema.js');
cb(null, new z_schema());
},
network: function (cb) {
// Init with empty function
cb(null, {io: {sockets: {emit: function () {}}}});
},
logger: function (cb) {
cb(null, logger);
},
dbSequence: ['logger', function (scope, cb) {
var sequence = new Sequence({
onWarning: function (current, limit) {
scope.logger.warn('DB queue', current);
}
});
cb(null, sequence);
}],
sequence: ['logger', function (scope, cb) {
var sequence = new Sequence({
onWarning: function (current, limit) {
scope.logger.warn('Main queue', current);
}
});
cb(null, sequence);
}],
balancesSequence: ['logger', function (scope, cb) {
var sequence = new Sequence({
onWarning: function (current, limit) {
scope.logger.warn('Balance queue', current);
}
});
cb(null, sequence);
}],
ed: function (cb) {
cb(null, require('../../helpers/ed.js'));
},
bus: ['ed', function (scope, cb) {
var changeCase = require('change-case');
var bus = function () {
this.message = function () {
var args = [];
Array.prototype.push.apply(args, arguments);
var topic = args.shift();
var eventName = 'on' + changeCase.pascalCase(topic);

// Iterate over modules and execute event functions (on*)
modules.forEach(function (module) {
if (typeof(module[eventName]) === 'function') {
module[eventName].apply(module[eventName], args);
}
if (module.submodules) {
node.async.each(module.submodules, function (submodule) {
if (submodule && typeof(submodule[eventName]) === 'function') {
submodule[eventName].apply(submodule[eventName], args);
}
});
}
});
};
};
cb(null, new bus());
}],
db: function (cb) {
cb(null, db);
},
logic: ['db', 'bus', 'schema', 'genesisblock', function (scope, cb) {
var Transaction = require('../../logic/transaction.js');
var Block = require('../../logic/block.js');
var Account = require('../../logic/account.js');
var Peers = require('../../logic/peers.js');

node.async.auto({
bus: function (cb) {
cb(null, scope.bus);
},
db: function (cb) {
cb(null, scope.db);
},
ed: function (cb) {
cb(null, scope.ed);
},
logger: function (cb) {
cb(null, scope.logger);
},
schema: function (cb) {
cb(null, scope.schema);
},
genesisblock: function (cb) {
cb(null, {
block: scope.genesisblock.block
});
},
account: ['db', 'bus', 'ed', 'schema', 'genesisblock', 'logger', function (scope, cb) {
new Account(scope.db, scope.schema, scope.logger, cb);
}],
transaction: ['db', 'bus', 'ed', 'schema', 'genesisblock', 'account', 'logger', function (scope, cb) {
new Transaction(scope.db, scope.ed, scope.schema, scope.genesisblock, scope.account, scope.logger, cb);
}],
block: ['db', 'bus', 'ed', 'schema', 'genesisblock', 'account', 'transaction', function (scope, cb) {
new Block(scope.ed, scope.schema, scope.transaction, cb);
}],
peers: ['logger', function (scope, cb) {
new Peers(scope.logger, cb);
}]
}, cb);
}],
modules: ['network', 'logger', 'bus', 'sequence', 'dbSequence', 'balancesSequence', 'db', 'logic', function (scope, cb) {
var tasks = {};
scope.rewiredModules = {};

Object.keys(modulesInit).forEach(function (name) {
tasks[name] = function (cb) {
var Instance = rewire(modulesInit[name]);

rewiredModules[name] = Instance;
var obj = new rewiredModules[name](cb, scope);
modules.push(obj);
node.debug('initApplication: Module ' + name + ' loaded');
};
});

node.async.parallel(tasks, function (err, results) {
cb(err, results);
});
}],
ready: ['modules', 'bus', 'logic', function (scope, cb) {
// Fire onBind event in every module
scope.bus.message('bind', scope.modules);
scope.logic.transaction.bindModules(scope.modules);
scope.logic.peers.bindModules(scope.modules);
node.debug('initApplication: Modules binding done');
cb();
}]
}, function (err, scope) {
node.expect(err).to.be.null;

scope.rewiredModules = rewiredModules;
currentAppScope = scope;
node.debug('initApplication: Rewired modules available');

// Overwrite onBlockchainReady function to prevent automatic forging
scope.modules.delegates.onBlockchainReady = function () {
node.debug('initApplication: Fake onBlockchainReady event called');
node.debug('initApplication: Loading delegates...');

var loadDelegates = scope.rewiredModules.delegates.__get__('__private.loadDelegates');
loadDelegates(function (err) {
node.expect(err).to.be.null;

var keypairs = scope.rewiredModules.delegates.__get__('__private.keypairs');
var delegates_cnt = Object.keys(keypairs).length;
node.expect(delegates_cnt).to.equal(node.config.forging.secret.length);

node.debug('initApplication: Delegates loaded from config file - ' + delegates_cnt);
node.debug('initApplication: Done');
return done(scope);
});
};
});
});
};

function cleanup (cb) {
node.async.eachSeries(currentAppScope.modules, function (module, seriesCb) {
if (typeof(module.cleanup) === 'function') {
module.cleanup(seriesCb);
} else {
seriesCb();
}
}, function (err) {
if (err) {
currentAppScope.logger.error(err);
} else {
currentAppScope.logger.info('Cleaned up successfully');
}
// Disconnect from database instance if sandbox was used
if (dbSandbox) {
dbSandbox.destroy();
}
cb();
});
};

module.exports = {
init: init,
cleanup: cleanup
};
Loading

0 comments on commit 231e5ab

Please sign in to comment.