Skip to content

Commit

Permalink
feat: add basic CAS test
Browse files Browse the repository at this point in the history
Stop one of the validators, make sure the period is not submitted, run again and make sure the period has went through
  • Loading branch information
troggy committed Aug 5, 2019
1 parent d305735 commit 7d7a29f
Show file tree
Hide file tree
Showing 9 changed files with 212 additions and 72 deletions.
3 changes: 2 additions & 1 deletion .dockerignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,5 @@ Dockerfile
out/
build/
.github/
.node_modules/
.node_modules/
data/
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
node_modules
build/*
out
process.json
process.json
data/
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
"ethers": "^4.0.33",
"ganache-cli": "6.5.0",
"jsbi-utils": "^1.0.0",
"leap-core": "^0.33.0"
"leap-core": "^0.33.0",
"leap-provider": "^1.0.0",
"rimraf": "^2.6.3"
}
}
3 changes: 1 addition & 2 deletions src/getEnv.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,9 +69,8 @@ const getContracts = async (nodeConfig, wallet) => {

module.exports = async () => {


const networkProcess = require('../process.json');
const nodes = networkProcess.nodes.map(n => new Node(n.hostname, n.port))
const nodes = networkProcess.nodes.map(n => new Node(n.hostname, n.port, n.configURL, n.pid))

const nodeConfig = await nodes[0].getConfig();

Expand Down
85 changes: 78 additions & 7 deletions src/nodeClient.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
const fs = require('fs');
const spawn = require('child_process').spawn;
const ethers = require('ethers');
const LeapProvider = require('leap-provider');
const { helpers } = require('leap-core');

const erc20abi = require('./erc20abi');
Expand All @@ -7,17 +10,85 @@ const { formatHostname, advanceBlocks, sleep } = require('./helpers');
let idCounter = 0;

class Node extends helpers.LeapEthers {
constructor(hostname, jsonrpcPort) {
const provider = new ethers.providers.JsonRpcProvider(formatHostname(hostname, jsonrpcPort))
super(provider);

constructor(hostname, port, configURL, pid) {
super(new LeapProvider(`http://${hostname}:${port}`));

this.id = idCounter++;
this.hostname = hostname;
this.port = jsonrpcPort;
this.port = port;
this.configURL = configURL;
this.pid = pid;
}

static async spawn(id, port, configURL) {
const nodeIndex = id + 1;
console.log(`Starting node ${nodeIndex}. Logs: ./out/node-${nodeIndex}.log`);

let basePort = port;
const env = {
...process.env,
DEBUG: 'tendermint,leap-node*'
};
const args = [
'build/node/index.js',
'--config', configURL,
'--rpcaddr', '127.0.0.1',
'--rpcport', (basePort++).toString(),
'--wsaddr', '127.0.0.1',
'--wsport', (basePort++).toString(),
'--abciPort', (basePort++).toString(),
'--p2pPort', (basePort++).toString(),
'--tendermintAddr', '127.0.0.1',
'--tendermintPort', (basePort++).toString(),
'--dataPath', `./data/node${nodeIndex}`,
];

const logOutput = fs.createWriteStream(`./out/node-${nodeIndex}.log`);

const proc = spawn('node', args, { env });

proc.stdout.pipe(logOutput);
proc.stderr.pipe(logOutput);
proc.on('exit', exitCode => console.log(`leap-node ${nodeIndex} exited`, exitCode));

return new Promise(
async (resolve, reject) => {
while (true) {
let res;
try {
// if we construct the rpc provider before the node is up,
// we will get a uncaught promise rejection because ethers.js
// invokes a request to it we can not catch :/
res = await ethers.utils.fetchJson(
formatHostname('localhost', port),
'{"jsonrpc":"2.0","id":42,"method":"plasma_getConfig","params":[]}'
);
} catch (e) {}
// ready
if (res) {
return resolve(new Node('localhost', port, configURL, proc.pid));
}

await new Promise((resolve) => setTimeout(() => resolve(), 100));
}
}
);
}

async start() {
const node = await Node.spawn(this.id, this.port, this.configURL);
console.log(node.pid);
this.pid = node.pid;
}

async stop() {
console.log(`Stopping node ${this.id + 1}`);
return process.kill(this.pid, 'SIGHUP');
}

async sendTx(tx) {
return helpers.sendSignedTransaction(this.provider, tx.hex());
return this.provider.sendTransaction(tx).then(tx => tx.wait());
};

async getBalance(addr) {
Expand Down Expand Up @@ -93,8 +164,8 @@ class Node extends helpers.LeapEthers {
}

toString() {
const { hostname, port } = this;
return { hostname, port };
const { hostname, port, configURL, pid } = this;
return { hostname, port, configURL, pid };
}
}

Expand Down
67 changes: 8 additions & 59 deletions src/run.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
const fs = require('fs');
const spawn = require('child_process').spawn;
const ethers = require('ethers');
const ganache = require('ganache-cli');
const rimraf = require('rimraf');

const getEnv = require('./getEnv');

const mnemonic = require('./mnemonic');

const Node = require('./nodeClient');
const setup = require('./setup');
const { formatHostname } = require('./helpers');

async function setupGanache(port, mnemonic) {
return new Promise(
Expand All @@ -33,8 +32,6 @@ async function deployContracts(ganachePort) {
const env = {
...process.env,
PROPOSAL_TIME: '0',
PARENT_BLOCK_INTERVAL: '0',
ADVANCE_BLOCK: '0',
EVENTS_DELAY: '1'
};
const cwd = process.cwd();
Expand Down Expand Up @@ -69,38 +66,6 @@ async function deployContracts(ganachePort) {
);
}

async function spawnNode(rpcPort, args, env, logOutput) {
return new Promise(
async (resolve, reject) => {
const proc = spawn('node', args, { env });

proc.stdout.pipe(logOutput);
proc.stderr.pipe(logOutput);
proc.on('exit', (exitCode) => console.log('leap-node exit', exitCode));

while (true) {
let res;
try {
// if we construct the rpc provider before the node is up,
// we will get a uncaught promise rejection because ethers.js
// invokes a request to it we can not catch :/
res = await ethers.utils.fetchJson(
formatHostname('localhost', rpcPort),
'{"jsonrpc":"2.0","id":42,"method":"plasma_status","params":[]}'
);
} catch (e) {}
// ready
if (res && res.result === 'ok') {
const node = new Node('localhost', rpcPort);
return resolve(node);
}

await new Promise((resolve) => setTimeout(() => resolve(), 100));
}
}
);
}

module.exports = async () => {
const ganachePort = parseInt(process.env['ganache_port']) || 8545;
// seems like only one connection from the same source addr can connect to the same tendermint instance
Expand All @@ -115,32 +80,11 @@ module.exports = async () => {

let basePort = parseInt(process.env['base_port']) || 7000;
const firstNodeURL = `http://localhost:${basePort}`;
rimraf.sync(`./data`);

for (let i = 0; i < numNodes; i++) {
const rpcPort = basePort;
const env = {
...process.env,
DEBUG: 'tendermint,leap-node*'
};
const configURL = i === 0 ? generatedConfigPath : firstNodeURL;
const args = [
'build/node/index.js',
'--config', configURL,
'--rpcaddr', '127.0.0.1',
'--rpcport', (basePort++).toString(),
'--wsaddr', '127.0.0.1',
'--wsport', (basePort++).toString(),
'--abciPort', (basePort++).toString(),
'--p2pPort', (basePort++).toString(),
'--tendermintAddr', '127.0.0.1',
'--tendermintPort', (basePort++).toString(),
'--devMode', 'true',
];

const logOutput = fs.createWriteStream(`./out/node-${i + 1}.log`);

console.log(`Starting node ${i + 1} of ${numNodes} Logs: ./out/node-${i + 1}.log`);
nodes.push(await spawnNode(rpcPort, args, env, logOutput));
nodes.push(await Node.spawn(i, basePort + i * 5, configURL));
}

const config = {
Expand All @@ -159,6 +103,11 @@ module.exports = async () => {
console.log(`\n Leap JSON RPC: ${nodes[0].getRpcUrl()}`);
console.log(`Root chain RPC: http://localhost:${ganachePort}\n`);
console.log('Priv key: ', accounts[0].privKey);
console.log();

process.on('exit', () => {
rimraf.sync(`./data`);
});

return { contracts, nodes, accounts, wallet, plasmaWallet };
};
Expand Down
2 changes: 1 addition & 1 deletion src/setup.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ module.exports = async function(contracts, nodes, accounts, wallet, plasmaWallet
await mine(contracts.token.approve(contracts.exitHandler.address, '500000000000000000000'));
await mine(contracts.token.approve(contracts.operator.address, '500000000000000000000'));

for (let i = 0; i < nodes.length - 1; i++) {
for (let i = 0; i < nodes.length; i++) {
const validatorInfo = await nodes[i].getValidatorInfo();
const overloadedSlotId = `${contracts.operator.address}00000000000000000000000${i}`;

Expand Down
33 changes: 33 additions & 0 deletions tests/9_CAS.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
const chai = require("chai");
const chaiAsPromised = require("chai-as-promised");

const exitUnspent = require('./actions/exitUnspent');
const minePeriod = require('./actions/minePeriod');
const { sleep } = require('../src/helpers');

chai.use(chaiAsPromised);
const expect = chai.expect;


module.exports = async function(contracts, [node1, node2], accounts, wallet) {
const alice = accounts[0];
const submissions = [];

contracts.operator.on("Submission", (...args) => {
console.log(args);
submissions.push(args);
});

//node2.stop();
await minePeriod(node1, accounts);
console.log('Try to exit..');
await sleep(4000);
expect(submissions.length).to.equal(0);
await expect(exitUnspent(contracts, node1, wallet, alice)).to.eventually.be.rejectedWith("");

await node2.start();
await sleep(2000);
console.log('Try to exit again..');
expect(submissions.length).to.equal(1);
await exitUnspent(contracts, node1, wallet, alice);
}
Loading

0 comments on commit 7d7a29f

Please sign in to comment.