Home Reference Source Test

test/specs/generic/miner/Miner.spec.js

describe('Miner', () => {

    it('creates valid blocks', (done) => {
        (async () => {
            const testBlockchain = await TestBlockchain.createVolatileTest(5, 10);
            const mempool = new Mempool(testBlockchain, testBlockchain.accounts);
            const minerAddr = testBlockchain.users[0].address;
            const miner = new Miner(testBlockchain, testBlockchain.accounts, mempool, testBlockchain.time, minerAddr);

            let block = await miner.getNextBlock();
            block.header._timestamp = 1000;
            block.header.nonce = 0;
            expect(block).toBeTruthy();
            await testBlockchain.setOrMineBlockNonce(block);
            expect(await testBlockchain.pushBlock(block)).toBeGreaterThan(-1);

            const txs = await testBlockchain.generateTransactions(5);
            for (const tx of txs) {
                expect(await mempool.pushTransaction(tx)).toBe(Mempool.ReturnCode.ACCEPTED);
            }

            block = await miner.getNextBlock();
            expect(block).toBeTruthy();
            const cache = testBlockchain.transactionCache.clone();
            await testBlockchain.accounts.commitBlock(block, cache);
            cache.pushBlock(block);

            const txs2 = await testBlockchain.generateTransactions(5);

            await testBlockchain.accounts.revertBlock(block, cache);
            cache.revertBlock(block);

            for (const tx of txs2) {
                expect(await mempool.pushTransaction(tx)).toBe(Mempool.ReturnCode.ACCEPTED);
            }

            block = await miner.getNextBlock();
            block.header._timestamp = 1001;
            block.header.nonce = 0;

            await testBlockchain.setOrMineBlockNonce(block);
            expect(await testBlockchain.pushBlock(block)).toBeGreaterThan(-1);
        })().then(done, done.fail);
    });

    it('can mine a block', (done) => {
        if (typeof WebAssembly === 'undefined') {
            // Do not run this test without WASM.
            done();
            return;
        }

        (async() => {
            const testBlockchain = await TestBlockchain.createVolatileTest(0);

            // Choose the timestamp such that the block is mined quickly.
            spyOn(testBlockchain.time, 'now').and.returnValue(0);

            const mempool = new Mempool(testBlockchain, testBlockchain.accounts);
            const miner = new Miner(testBlockchain, testBlockchain.accounts, mempool, testBlockchain.time, GenesisConfig.GENESIS_BLOCK.minerAddr);

            let unsuccessfulOnce = false;
            const SUCCESS_NONCE = 201203;
            miner._workerPool.multiMineBackup = miner._workerPool.multiMine;
            miner.threads = 1;
            miner._workerPool.multiMine = ((blockHeader, compact, minNonce, maxNonce) => {
                if (!unsuccessfulOnce) {
                    unsuccessfulOnce = true;
                    return miner._workerPool.multiMineBackup(blockHeader, compact, minNonce, maxNonce);
                }
                if (minNonce <= SUCCESS_NONCE && maxNonce >= SUCCESS_NONCE) {
                    const promise = miner._workerPool.multiMineBackup(blockHeader, compact, minNonce, maxNonce);
                    miner.stopWork();
                    return promise;
                }
                return false;
            });
            const block = await new Promise((resolve) => {
                miner.on('block-mined', resolve);
                miner.startWork();
            });
            expect(block.header.nonce).toEqual(SUCCESS_NONCE);
            expect(await block.verify(testBlockchain._time)).toBeTruthy();
            expect(await testBlockchain.pushBlock(block)).toBeGreaterThan(-1);
        })().then(done, done.fail);
    });
});