@nodeset/contracts
Version:
Protocol for accessing NodeSet's Constellation Ethereum staking network
274 lines (218 loc) • 11.3 kB
JavaScript
import { mineBlocks, increaseTime, getCurrentTime } from '../_utils/evm'
import { printTitle } from '../_utils/formatting';
import { shouldRevert } from '../_utils/testing';
import { registerNode, setNodeTrusted } from '../_helpers/node';
import { executeUpdateBalances, submitBalances } from './scenario-submit-balances'
import { RocketDAONodeTrustedSettingsProposals, RocketDAOProtocolSettingsNetwork } from '../_utils/artifacts'
import { setDAOProtocolBootstrapSetting } from '../dao/scenario-dao-protocol-bootstrap';
import { daoNodeTrustedExecute, daoNodeTrustedMemberLeave, daoNodeTrustedPropose, daoNodeTrustedVote } from '../dao/scenario-dao-node-trusted'
import { getDAOProposalEndTime, getDAOProposalStartTime } from '../dao/scenario-dao-proposal'
import { setDAONodeTrustedBootstrapSetting } from '../dao/scenario-dao-node-trusted-bootstrap'
export default function() {
contract('RocketNetworkBalances', async (accounts) => {
// Accounts
const [
owner,
node,
trustedNode1,
trustedNode2,
trustedNode3,
trustedNode4,
random
] = accounts;
// Constants
let proposalCooldown = 10
let proposalVoteBlocks = 10
// Setup
before(async () => {
// Register node
await registerNode({from: node});
// Register trusted nodes
await registerNode({from: trustedNode1});
await registerNode({from: trustedNode2});
await registerNode({from: trustedNode3});
await setNodeTrusted(trustedNode1, 'saas_1', 'node@home.com', owner);
await setNodeTrusted(trustedNode2, 'saas_2', 'node@home.com', owner);
await setNodeTrusted(trustedNode3, 'saas_3', 'node@home.com', owner);
// Set a small proposal cooldown
await setDAONodeTrustedBootstrapSetting(RocketDAONodeTrustedSettingsProposals, 'proposal.cooldown', proposalCooldown, { from: owner });
await setDAONodeTrustedBootstrapSetting(RocketDAONodeTrustedSettingsProposals, 'proposal.vote.blocks', proposalVoteBlocks, { from: owner });
// Set a small vote delay
await setDAONodeTrustedBootstrapSetting(RocketDAONodeTrustedSettingsProposals, 'proposal.vote.delay.blocks', 4, { from: owner });
});
async function trustedNode4JoinDao() {
await registerNode({from: trustedNode4});
await setNodeTrusted(trustedNode4, 'saas_4', 'node@home.com', owner);
}
async function trustedNode4LeaveDao() {
// Wait enough time to do a new proposal
await mineBlocks(web3, proposalCooldown);
// Encode the calldata for the proposal
let proposalCallData = web3.eth.abi.encodeFunctionCall(
{name: 'proposalLeave', type: 'function', inputs: [{type: 'address', name: '_nodeAddress'}]},
[trustedNode4]
);
// Add the proposal
let proposalId = await daoNodeTrustedPropose('hey guys, can I please leave the DAO?', proposalCallData, {
from: trustedNode4
});
// Current block
let timeCurrent = await getCurrentTime(web3);
// Now mine blocks until the proposal is 'active' and can be voted on
await increaseTime(web3, (await getDAOProposalStartTime(proposalId)-timeCurrent)+2);
// Now lets vote
await daoNodeTrustedVote(proposalId, true, { from: trustedNode1 });
await daoNodeTrustedVote(proposalId, true, { from: trustedNode2 });
await daoNodeTrustedVote(proposalId, true, { from: trustedNode3 });
// Fast forward to this voting period finishing
timeCurrent = await getCurrentTime(web3);
await increaseTime(web3, (await getDAOProposalEndTime(proposalId)-timeCurrent)+2);
// Proposal should be successful, lets execute it
await daoNodeTrustedExecute(proposalId, { from: trustedNode1 });
// Member can now leave and collect any RPL bond
await daoNodeTrustedMemberLeave(trustedNode4, { from: trustedNode4 });
}
it(printTitle('trusted nodes', 'can submit network balances'), async () => {
// Set parameters
let block = 1;
let totalBalance = '10'.ether;
let stakingBalance = '9'.ether;
let rethSupply = '8'.ether;
// Submit different balances
await submitBalances(block, totalBalance, stakingBalance, '7'.ether, {
from: trustedNode1,
});
await submitBalances(block, totalBalance, stakingBalance, '6'.ether, {
from: trustedNode2,
});
await submitBalances(block, totalBalance, stakingBalance, '5'.ether, {
from: trustedNode3,
});
// Set parameters
block = 2;
// Submit identical balances to trigger update
await submitBalances(block, totalBalance, stakingBalance, rethSupply, {
from: trustedNode1,
});
await submitBalances(block, totalBalance, stakingBalance, rethSupply, {
from: trustedNode2,
});
});
it(printTitle('trusted nodes', 'cannot submit network balances while balance submissions are disabled'), async () => {
// Set parameters
let block = 1;
let totalBalance = '10'.ether;
let stakingBalance = '9'.ether;
let rethSupply = '8'.ether;
// Disable submissions
await setDAOProtocolBootstrapSetting(RocketDAOProtocolSettingsNetwork, 'network.submit.balances.enabled', false, {from: owner});
// Attempt to submit balances
await shouldRevert(submitBalances(block, totalBalance, stakingBalance, rethSupply, {
from: trustedNode1,
}), 'Submitted balances while balance submissions were disabled');
});
it(printTitle('trusted nodes', 'cannot submit network balances for a future block'), async () => {
// Get current block
let blockCurrent = await web3.eth.getBlockNumber();
// Set parameters
let block = blockCurrent + 1;
let totalBalance = '10'.ether;
let stakingBalance = '9'.ether;
let rethSupply = '8'.ether;
// Attempt to submit balances for future block
await shouldRevert(submitBalances(block, totalBalance, stakingBalance, rethSupply, {
from: trustedNode1,
}), 'Submitted balances for a future block');
});
it(printTitle('trusted nodes', 'cannot submit network balances for the current recorded block or lower'), async () => {
// Set parameters
let block = 2;
let totalBalance = '10'.ether;
let stakingBalance = '9'.ether;
let rethSupply = '8'.ether;
// Submit balances for block to trigger update
await submitBalances(block, totalBalance, stakingBalance, rethSupply, {
from: trustedNode1,
});
await submitBalances(block, totalBalance, stakingBalance, rethSupply, {
from: trustedNode2,
});
// Attempt to submit balances for current block
await shouldRevert(submitBalances(block, totalBalance, stakingBalance, rethSupply, {
from: trustedNode3,
}), 'Submitted balances for the current block');
// Attempt to submit balances for lower block
await shouldRevert(submitBalances(block - 1, totalBalance, stakingBalance, rethSupply, {
from: trustedNode3,
}), 'Submitted balances for a lower block');
});
it(printTitle('trusted nodes', 'cannot submit the same network balances twice'), async () => {
// Set parameters
let block = 1;
let totalBalance = '10'.ether;
let stakingBalance = '9'.ether;
let rethSupply = '8'.ether;
// Submit balances for block
await submitBalances(block, totalBalance, stakingBalance, rethSupply, {
from: trustedNode1,
});
// Attempt to submit balances for block again
await shouldRevert(submitBalances(block, totalBalance, stakingBalance, rethSupply, {
from: trustedNode1,
}), 'Submitted the same network balances twice');
});
it(printTitle('regular nodes', 'cannot submit network balances'), async () => {
// Set parameters
let block = 1;
let totalBalance = '10'.ether;
let stakingBalance = '9'.ether;
let rethSupply = '8'.ether;
// Attempt to submit balances
await shouldRevert(submitBalances(block, totalBalance, stakingBalance, rethSupply, {
from: node,
}), 'Regular node submitted network balances');
});
it(printTitle('random', 'can execute balances update when consensus is reached after member count changes'), async () => {
// Setup
await trustedNode4JoinDao();
// Set parameters
let block = 1;
let totalBalance = '10'.ether;
let stakingBalance = '9'.ether;
let rethSupply = '8'.ether;
// Submit same parameters from 2 nodes (not enough for 4 member consensus but enough for 3)
await submitBalances(block, totalBalance, stakingBalance, rethSupply, {
from: trustedNode1,
});
await submitBalances(block, totalBalance, stakingBalance, rethSupply, {
from: trustedNode2,
});
// trustedNode4 leaves the DAO
await trustedNode4LeaveDao();
// There is now consensus with the remaining 3 trusted nodes about the balances, try to execute the update
await executeUpdateBalances(block, totalBalance, stakingBalance, rethSupply, {
from: random
})
});
it(printTitle('random', 'cannot execute balances update without consensus'), async () => {
// Setup
await trustedNode4JoinDao();
// Set parameters
let block = 1;
let totalBalance = '10'.ether;
let stakingBalance = '9'.ether;
let rethSupply = '8'.ether;
// Submit same price from 2 nodes (not enough for 4 member consensus)
await submitBalances(block, totalBalance, stakingBalance, rethSupply, {
from: trustedNode1,
});
await submitBalances(block, totalBalance, stakingBalance, rethSupply, {
from: trustedNode2,
});
// There is no consensus so execute should fail
await shouldRevert(executeUpdateBalances(block, totalBalance, stakingBalance, rethSupply, {
from: random
}), 'Random account could execute update balances without consensus')
});
});
}