Skip to content

Commit

Permalink
Merge a7b72ff into 7483331
Browse files Browse the repository at this point in the history
  • Loading branch information
gjgd committed Jul 26, 2018
2 parents 7483331 + a7b72ff commit 75a8e8e
Show file tree
Hide file tree
Showing 10 changed files with 181 additions and 32 deletions.
1 change: 1 addition & 0 deletions contracts/RoundManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ contract RoundManager is Ownable {
uint public unbondingPeriod;

modifier onlyBeforeActiveRoundIsLocked() {
require(roundNumber > 0);
require(block.number.sub(startOfCurrentRound) < electionPeriodLength.sub(rateLockDeadline));
_;
}
Expand Down
4 changes: 2 additions & 2 deletions contracts/TransmuteDPOS.sol
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,8 @@ contract TransmuteDPOS is TransmuteToken, RoundManager, ProviderPool {
// FIXME: Those are temporary values
constructor() public {
// Set constants from RoundManager
electionPeriodLength = 20;
rateLockDeadline = 5;
electionPeriodLength = 50;
rateLockDeadline = 10;
unbondingPeriod = 10;
}

Expand Down
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@
"description": "",
"main": "index.js",
"scripts": {
"test": "truffle migrate --reset && truffle test",
"test:unit": "truffle migrate --reset && truffle test test/unit/*",
"test:integration": "truffle migrate --reset && truffle test test/integration/*",
"test": "truffle migrate --reset && truffle test test/unit/* test/integration/*; ",
"coverage": "./node_modules/.bin/solidity-coverage"
},
"author": "",
Expand Down
139 changes: 139 additions & 0 deletions test/integration/DPOS.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
const TransmuteDPOS = artifacts.require('./TestTransmuteDPOS.sol');
const { blockMiner, assertFail, roundManagerHelper } = require('../utils.js');

contract('integration/TransmuteDPOS', accounts => {

let tdpos;
let contractAddress;
const PROVIDER_POOL_SIZE = 4;

// Provider states
const PROVIDER_UNREGISTERED = 0;
const PROVIDER_REGISTERED = 1;

let provider1 = accounts[1];
let provider2 = accounts[2];
let provider3 = accounts[3];
let provider4 = accounts[4];
let provider5 = accounts[5];

async function reset() {
tdpos = await TransmuteDPOS.new();
contractAddress = tdpos.address;
for(let i = 0; i < 10; i++) {
await tdpos.mint(accounts[i], 1000, {from: accounts[0]});
}
await tdpos.setMaxNumberOfProviders(PROVIDER_POOL_SIZE);
}

describe('Registering as Providers', () => {

before(async () => {
await reset();
// Make sure that block.number > electionPeriodLength otherwise some tests containing initializeRound might fail
// it is ok to do this because in the main network block.number >> 100
await blockMiner.mine(100);
});

it('provider1 delegates tokens to himself before calling provider()', async () => {
await tdpos.approve(contractAddress, 100, {from: provider1});
await tdpos.bond(provider1, 100, {from: provider1});
});

it('provider1 fails to register because initializeRound() was not called', async () => {
await assertFail( tdpos.provider(22, 10, 1, 25, {from: provider1}) );
});

it('someone calls initializeRound()', async () => {
const roundNumber = await tdpos.roundNumber.call();
await tdpos.initializeRound();
assert.deepEqual(roundNumber.add(1), await tdpos.roundNumber.call());
});

it('provider1 registers as Provider', async () => {
assert.equal(PROVIDER_UNREGISTERED, await tdpos.providerStatus(provider1));
await tdpos.provider(22, 10, 1, 25, {from: provider1});
assert.equal(PROVIDER_REGISTERED, await tdpos.providerStatus(provider1));
});

it('someone calls initializeRound again but it fails because election period of current round is not over', async () => {
await assertFail( tdpos.initializeRound() );
});

it("provider2 fails to register because he didn't delegate tokens to himself", async () => {
await assertFail( tdpos.provider(22, 10, 1, 25, {from: provider2}) );
});

it('provider2 delegates tokens to himself', async () => {
await tdpos.approve(contractAddress, 200, {from: provider2});
await tdpos.bond(provider2, 200, {from: provider2});
});

it('provider2 registers as Provider', async () => {
assert.equal(PROVIDER_UNREGISTERED, await tdpos.providerStatus(provider2));
await tdpos.provider(22, 10, 1, 25, {from: provider2});
assert.equal(PROVIDER_REGISTERED, await tdpos.providerStatus(provider2));
});

it('provider3 delegates tokens to himself', async () => {
await tdpos.approve(contractAddress, 300, {from: provider3});
await tdpos.bond(provider3, 300, {from: provider3});
});

it('provider3 fails to register with invalid parameters', async () => {
// Cannot have negative blockRewardCut
await assertFail( tdpos.provider(22, 10, -1, 25, {from: provider3}) );
// Cannot have over 100% of feeShare
await assertFail( tdpos.provider(22, 10, 1, 125, {from: provider3}) );
});

it('provider3 registers as Provider with valid parameters', async () => {
assert.equal(PROVIDER_UNREGISTERED, await tdpos.providerStatus(provider3));
await tdpos.provider(22, 10, 1, 25, {from: provider3});
assert.equal(PROVIDER_REGISTERED, await tdpos.providerStatus(provider3));
});

it('provider4 delegates tokens to himself', async () => {
await tdpos.approve(contractAddress, 400, {from: provider4});
await tdpos.bond(provider4, 400, {from: provider4});
});

it('provider4 fails to register because rateLockDeadline has passed for the current round', async () => {
const rateLockDeadlineBlock = await roundManagerHelper.getRateLockDeadlineBlock(tdpos);
await blockMiner.mineUntilBlock(rateLockDeadlineBlock);
await assertFail( tdpos.provider(22, 10, 1, 25, {from: provider4}) );
});

it('someone calls initializeRound() but it fails because Election Period is not over', async () => {
await assertFail( tdpos.initializeRound() );
});

it('someone calls initializeRound() after Election Period is over', async () => {
const electionPeriodEndBlock = await roundManagerHelper.getElectionPeriodEndBlock(tdpos);
await blockMiner.mineUntilBlock(electionPeriodEndBlock);
const roundNumber = await tdpos.roundNumber.call();
await tdpos.initializeRound();
assert.deepEqual(roundNumber.add(1), await tdpos.roundNumber.call());
});

it('provider4 registers as Provider in the new round', async () => {
assert.equal(PROVIDER_UNREGISTERED, await tdpos.providerStatus(provider4));
await tdpos.provider(22, 10, 1, 25, {from: provider4});
assert.equal(PROVIDER_REGISTERED, await tdpos.providerStatus(provider4));
});

it('provider5 delegates tokens to himself', async () => {
await tdpos.approve(contractAddress, 500, {from: provider5});
await tdpos.bond(provider5, 500, {from: provider5});
});

it('provider5 registers as Provider but fails because the providerPool is at maximum capacity', async () => {
const providerPool = await tdpos.providerPool.call();
let maxSize = providerPool[2];
let size = providerPool[3];
assert.deepEqual(maxSize, size);
await assertFail( tdpos.provider(22, 10, 1, 25, {from: provider5}) );
});
});
});

2 changes: 1 addition & 1 deletion test/JobManager.spec.js → test/unit/JobManager.spec.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
const JobManager = artifacts.require('./JobManager.sol');
const { assertFail } = require('./utils.js');
const { assertFail } = require('../utils.js');
require('truffle-test-utils').init();

contract('JobManager', accounts => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// This is to be able to test the addProvider function which has internal visibility
// through the publicAddProvider function from TestProviderPool which has public visibility
const ProviderPool = artifacts.require('./TestProviderPool.sol');
const { blockMiner, assertFail } = require('./utils.js');
const { blockMiner, assertFail } = require('../utils.js');

contract('ProviderPool', accounts => {

Expand Down
4 changes: 1 addition & 3 deletions test/RoundManager.spec.js → test/unit/RoundManager.spec.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
const RoundManager = artifacts.require('./RoundManager.sol');
const { blockMiner, assertFail } = require('./utils.js');
const { blockMiner, assertFail } = require('../utils.js');

contract('RoundManager', accounts => {

Expand All @@ -15,8 +15,6 @@ contract('RoundManager', accounts => {
await rm.setElectionPeriodLength(electionPeriodLength);
await rm.setRateLockDeadline(rateLockDeadline);
await rm.setUnbondingPeriod(unbondingPeriod);
await blockMiner.mineUntilEndOfElectionPeriod(rm);
assert.equal(0, (web3.eth.blockNumber + 1) % electionPeriodLength);
});

it('should initialize the round', async () => {
Expand Down
21 changes: 13 additions & 8 deletions test/TransmuteDPOS.spec.js → test/unit/TransmuteDPOS.spec.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
const TransmuteDPOS = artifacts.require('./TestTransmuteDPOS.sol');
const { blockMiner, assertFail } = require('./utils.js');
const { blockMiner, assertFail, roundManagerHelper } = require('../utils.js');
require('truffle-test-utils').init();

contract('TransmuteDPOS', accounts => {
Expand Down Expand Up @@ -34,7 +34,8 @@ contract('TransmuteDPOS', accounts => {
await tdpos.mint(accounts[i], 1000, {from: accounts[0]});
}
await tdpos.setMaxNumberOfProviders(PROVIDER_POOL_SIZE);
await blockMiner.mineUntilEndOfElectionPeriod(tdpos);
const electionPeriodEndBlock = await roundManagerHelper.getElectionPeriodEndBlock(tdpos);
await blockMiner.mineUntilBlock(electionPeriodEndBlock);
await tdpos.initializeRound();
}

Expand All @@ -50,7 +51,8 @@ contract('TransmuteDPOS', accounts => {
});

beforeEach(async () => {
await blockMiner.mineUntilEndOfElectionPeriod(tdpos);
const electionPeriodEndBlock = await roundManagerHelper.getElectionPeriodEndBlock(tdpos);
await blockMiner.mineUntilBlock(electionPeriodEndBlock);
await tdpos.initializeRound();
});

Expand Down Expand Up @@ -90,22 +92,25 @@ contract('TransmuteDPOS', accounts => {
});

it('should fail if not called during an active round', async () => {
await blockMiner.mineUntilEndOfElectionPeriod(tdpos);
const electionPeriodEndBlock = await roundManagerHelper.getElectionPeriodEndBlock(tdpos);
await blockMiner.mineUntilBlock(electionPeriodEndBlock);
await assertFail( tdpos.provider(22, 10, 1, 25, {from: accounts[0]}) );
});

it('should work if called before the lock period of an active round', async () => {
await blockMiner.mineUntilLastBlockBeforeLockPeriod(tdpos);
const rateLockDeadlineBlock = await roundManagerHelper.getRateLockDeadlineBlock(tdpos);
// One block before lock deadline
await blockMiner.mineUntilBlock(rateLockDeadlineBlock - 1);
await tdpos.provider(23, 10, 1, 25, {from: accounts[0]});
const provider = await tdpos.providers(accounts[0]);
const pricePerStorageMineral = provider[0];
assert.equal(23, pricePerStorageMineral);
});

it('should fail during the lock period of an active round', async () => {
await blockMiner.mineUntilLastBlockBeforeLockPeriod(tdpos);
// Enter lock period
await blockMiner.mine(1);
const rateLockDeadlineBlock = await roundManagerHelper.getRateLockDeadlineBlock(tdpos);
// lock deadline block
await blockMiner.mineUntilBlock(rateLockDeadlineBlock);
await assertFail( tdpos.provider(22, 10, 1, 25, {from: accounts[0]}) );
});

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
const TST = artifacts.require('./TransmuteToken.sol');
const utils = require('./utils.js');
const utils = require('../utils.js');
const assertFail = utils.assertFail;

contract('TST', accounts => {
Expand Down
34 changes: 19 additions & 15 deletions test/utils.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,22 @@
class RoundManagerHelper {
// At that block, a new round can be initialized
async getElectionPeriodEndBlock(roundManager) {
const startOfCurrentRound = await roundManager.startOfCurrentRound.call();
const electionPeriodLength = await roundManager.electionPeriodLength.call();
return startOfCurrentRound.add(electionPeriodLength).sub(1).toNumber();
}

// At that block, a provider can no longer update his parameters
async getRateLockDeadlineBlock(roundManager) {
const startOfCurrentRound = await roundManager.startOfCurrentRound.call();
const electionPeriodLength = await roundManager.electionPeriodLength.call();
const rateLockDeadline = await roundManager.rateLockDeadline.call();
return startOfCurrentRound.add(electionPeriodLength).sub(rateLockDeadline).sub(1);
}
}

module.exports.roundManagerHelper = new RoundManagerHelper();

class BlockMiner {
async mine(numberOfBlocks) {
for(let i = 0; i < numberOfBlocks; i++) {
Expand All @@ -7,21 +26,6 @@ class BlockMiner {
}
}

async mineUntilEndOfElectionPeriod(roundManager) {
const electionPeriodLength = await roundManager.electionPeriodLength.call();
const currentBlockNumber = web3.eth.blockNumber;
const padding = electionPeriodLength - currentBlockNumber % electionPeriodLength - 1;
await this.mine(padding);
}

async mineUntilLastBlockBeforeLockPeriod(roundManager) {
const electionPeriodLength = await roundManager.electionPeriodLength.call();
const rateLockDeadline = await roundManager.rateLockDeadline.call();
const currentBlockNumber = web3.eth.blockNumber;
const padding = electionPeriodLength - rateLockDeadline - 1 - currentBlockNumber % electionPeriodLength - 1;
await this.mine(padding);
}

async mineUntilBlock(blockNumber) {
const padding = blockNumber - web3.eth.blockNumber;
await this.mine(padding);
Expand Down

0 comments on commit 75a8e8e

Please sign in to comment.