diff --git a/modules/blocks/chain.js b/modules/blocks/chain.js index 5a5b87564b0..40e564308d4 100644 --- a/modules/blocks/chain.js +++ b/modules/blocks/chain.js @@ -587,29 +587,31 @@ Chain.prototype.deleteLastBlock = function (cb) { async.waterfall( [ - function (waterCb) { + function popLastBlock (waterCb) { // Delete last block, replace last block with previous block, undo things __private.popLastBlock(lastBlock, function (err, newLastBlock) { if (err) { library.logger.error('Error deleting last block', lastBlock); } else { // Replace last block with previous - lastBlock = modules.blocks.lastBlock.set(newLastBlock); + modules.blocks.lastBlock.set(newLastBlock); } - return setImmediate(waterCb, err, lastBlock); + return setImmediate(waterCb, err, newLastBlock); }); }, - function (newLastBlock, waterCb) { - modules.transactions.receiveTransactions( - lastBlock.transactions.reverse(), - false, - function (err) { - if (err) { - library.logger.error('Error receiving transactions after deleting block', err); - } - return setImmediate(waterCb, null, lastBlock); + function receiveTransactionsFromDeletedBlock (newLastBlock, waterCb) { + library.balancesSequence.add(function (balanceSequenceCb) { + modules.transactions.receiveTransactions( + lastBlock.transactions.reverse(), + false, + balanceSequenceCb + ); + }, function (err) { + if (err) { + library.logger.error('Error receiving transactions after deleting block', err); } - ); + return setImmediate(waterCb, null, newLastBlock); + }); } ], cb diff --git a/test/system/blocks/chain.js b/test/system/blocks/chain.js new file mode 100644 index 00000000000..5b0dd2c5101 --- /dev/null +++ b/test/system/blocks/chain.js @@ -0,0 +1,91 @@ +var async = require('async'); +var sinon = require('sinon'); +var chai = require('chai'); +var expect = require('chai').expect; +var Promise = require('bluebird'); +var _ = require('lodash'); +var common = require('../common.js'); +var genesisBlock = require('../../genesisBlock.json'); +var node = require('../../node.js'); +var slots = require('../../../helpers/slots.js'); +var application = require('../../common/application'); + +describe('chain', function () { + + var library; + + before('init sandboxed application', function (done) { + application.init({sandbox: {name: 'lisk_test_block_deletion'}}, function (scope) { + library = scope; + done(); + }); + }); + + after('cleanup sandboxed application', function (done) { + application.cleanup(done); + }); + + describe('deleteLastBlock', function () { + + var transactions; + + before('forge a block with 25 transactions', function (done) { + transactions = _.range(25).map(function () { + var account = node.randomAccount(); + return node.lisk.transaction.createTransaction(account.address, 1000000000*100, node.gAccount.password); + }); + common.addTransactionsAndForge(library, transactions, done); + }); + + describe('after deleting last block', function () { + + var lastBlock; + var receiveTransactionsSpy; + + before(function (done) { + receiveTransactionsSpy = sinon.spy(library.modules.transactions, 'receiveTransactions'); + lastBlock = library.modules.blocks.lastBlock.get(); + library.modules.blocks.chain.deleteLastBlock(done); + }); + + after(function () { + receiveTransactionsSpy.restore(); + }); + + it('should remove block from the database', function (done) { + library.balancesSequence.add(function (balanceSequenceCb) { + common.getBlocks(library, function (err, blockIds) { + expect(blockIds).to.not.include(lastBlock.id); + balanceSequenceCb(); + done(); + }); + }); + }); + + it('should set the last block to genesis block', function (done) { + library.balancesSequence.add(function (balanceSequenceCb) { + common.getBlocks(library, function (err, blockIds) { + expect(blockIds.length).to.equal(1); + expect(blockIds).to.include(genesisBlock.id); + expect(library.modules.blocks.lastBlock.get().id).eql(genesisBlock.id); + balanceSequenceCb(); + done(); + }); + }); + }); + + it('should call modules.transactions.receiveTransactions with the deleted transactions', function () { + var reappliedTransactionIds = _.map(receiveTransactionsSpy.args[0][0], 'id'); + transactions.map(function (transaction) { + expect(reappliedTransactionIds).to.contain(transaction.id); + }); + }); + + it('should put the block transactions back in the queue', function () { + transactions.forEach(function (trs) { + expect(library.modules.transactions.transactionInPool(trs.id)).to.equal(true); + }); + }); + }); + }); +});