UNPKG

@nodeset/contracts

Version:

Protocol for accessing NodeSet's Constellation Ethereum staking network

250 lines (206 loc) 10.2 kB
import { getCurrentTime, increaseTime } from '../_utils/evm' import { printTitle } from '../_utils/formatting'; import { shouldRevert } from '../_utils/testing'; import { registerNode, setNodeTrusted } from '../_helpers/node' import { executeUpdatePrices, submitPrices } from './scenario-submit-prices' import { RocketDAONodeTrustedSettingsProposals, RocketDAOProtocolSettingsNetwork, RocketNetworkPrices } from '../_utils/artifacts' import { setDAOProtocolBootstrapSetting } from '../dao/scenario-dao-protocol-bootstrap'; import { setDAONodeTrustedBootstrapSetting } from '../dao/scenario-dao-node-trusted-bootstrap' import { daoNodeTrustedExecute, daoNodeTrustedMemberLeave, daoNodeTrustedPropose, daoNodeTrustedVote } from '../dao/scenario-dao-node-trusted' import { getDAOProposalEndTime, getDAOProposalStartTime } from '../dao/scenario-dao-proposal' export default function() { contract('RocketNetworkPrices', async (accounts) => { // Accounts const [ owner, node, trustedNode1, trustedNode2, trustedNode3, trustedNode4, // Joins and leaves DAO in certain tests random ] = accounts; // Constants let proposalCooldown = 60 * 60 let proposalVoteTime = 60 * 60 // 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.time', proposalCooldown, { from: owner }); await setDAONodeTrustedBootstrapSetting(RocketDAONodeTrustedSettingsProposals, 'proposal.vote.time', proposalVoteTime, { 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 increaseTime(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 prices'), async () => { // Set parameters let block = await web3.eth.getBlockNumber(); let rplPrice = '0.02'.ether; // Submit different prices await submitPrices(block, '0.03'.ether, { from: trustedNode1, }); await submitPrices(block, '0.04'.ether, { from: trustedNode2, }); await submitPrices(block, '0.05'.ether, { from: trustedNode3, }); // Set parameters block = await web3.eth.getBlockNumber(); // Submit identical prices to trigger update await submitPrices(block, rplPrice, { from: trustedNode1, }); await submitPrices(block, rplPrice, { from: trustedNode2, }); }); it(printTitle('trusted nodes', 'cannot submit network prices while price submissions are disabled'), async () => { // Set parameters let block = await web3.eth.getBlockNumber(); let rplPrice = '0.02'.ether; // Disable submissions await setDAOProtocolBootstrapSetting(RocketDAOProtocolSettingsNetwork, 'network.submit.prices.enabled', false, {from: owner}); // Attempt to submit prices await shouldRevert(submitPrices(block, rplPrice, { from: trustedNode1, }), 'Submitted prices while price submissions were disabled'); }); it(printTitle('trusted nodes', 'cannot submit network prices for a future block'), async () => { // Get current block let blockCurrent = await web3.eth.getBlockNumber(); // Set parameters let block = blockCurrent + 1; let rplPrice = '0.02'.ether; // Attempt to submit prices for future block await shouldRevert(submitPrices(block, rplPrice, { from: trustedNode1, }), 'Submitted prices for a future block'); }); it(printTitle('trusted nodes', 'cannot submit network prices for the current recorded block or lower'), async () => { // Set parameters let block = await web3.eth.getBlockNumber(); let rplPrice = '0.02'.ether; // Submit prices for block to trigger update await submitPrices(block, rplPrice, { from: trustedNode1, }); await submitPrices(block, rplPrice, { from: trustedNode2, }); // Attempt to submit prices for current block await shouldRevert(submitPrices(block, rplPrice, { from: trustedNode3, }), 'Submitted prices for the current block'); // Attempt to submit prices for lower block await shouldRevert(submitPrices(block - 1, rplPrice, { from: trustedNode3, }), 'Submitted prices for a lower block'); }); it(printTitle('trusted nodes', 'cannot submit the same network prices twice'), async () => { // Set parameters let block = await web3.eth.getBlockNumber(); let rplPrice = '0.02'.ether; // Submit prices for block await submitPrices(block, rplPrice, { from: trustedNode1, }); // Attempt to submit prices for block again await shouldRevert(submitPrices(block, rplPrice, { from: trustedNode1, }), 'Submitted the same network prices twice'); }); it(printTitle('regular nodes', 'cannot submit network prices'), async () => { // Set parameters let block = await web3.eth.getBlockNumber(); let rplPrice = '0.02'.ether; // Attempt to submit prices await shouldRevert(submitPrices(block, rplPrice, { from: node, }), 'Regular node submitted network prices'); }); it(printTitle('random', 'can execute price update when consensus is reached after member count changes'), async () => { // Setup await trustedNode4JoinDao(); // Set parameters let block = await web3.eth.getBlockNumber(); let rplPrice = '0.02'.ether; // Submit same price from 2 nodes (not enough for 4 member consensus but enough for 3) await submitPrices(block, rplPrice, { from: trustedNode1, }); await submitPrices(block, rplPrice, { from: trustedNode2, }); // trustedNode4 leaves the DAO await trustedNode4LeaveDao(); // There is now consensus with the remaining 3 trusted nodes about the price, try to execute the update await executeUpdatePrices(block, rplPrice, { from: random }) }); it(printTitle('random', 'cannot execute price update without consensus'), async () => { // Setup await trustedNode4JoinDao(); // Set parameters let block = await web3.eth.getBlockNumber(); let rplPrice = '0.02'.ether; // Submit same price from 2 nodes (not enough for 4 member consensus) await submitPrices(block, rplPrice, { from: trustedNode1, }); await submitPrices(block, rplPrice, { from: trustedNode2, }); // There is no consensus so execute should fail await shouldRevert(executeUpdatePrices(block, rplPrice, { from: random }), 'Random account could execute update prices without consensus') }); }); }