PIE-1515: Rules contract with linked list library (#39)

pull/40/head
Lucas Saldanha 6 years ago committed by GitHub
parent 643f4bb2ee
commit 672dbb162c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 3
      .gitignore
  2. 5
      .soliumrc.json
  3. 14
      contracts/AdminList.sol
  4. 31
      contracts/ExposedRulesList.sol
  5. 186
      contracts/Rules.sol
  6. 93
      contracts/RulesList.sol
  7. 2
      genesis.json
  8. 171
      test/test-get-all-enodes.js
  9. 0
      test/test-ingress-proxy.js
  10. 159
      test/test-rules-list.js
  11. 146
      test/test-rules-permissioning.js
  12. 155
      test/test-rules.js

3
.gitignore vendored

@ -6,6 +6,9 @@ yarn-debug.log*
yarn-error.log*
lerna-debug.log*
# Idea
.idea
# Directories used by tools like mocha & istanbul
coverage
shippable

@ -18,6 +18,9 @@
],
"blank-lines": "error",
"no-trailing-whitespace": "error",
"arg-overflow": "error"
"arg-overflow": [
"error",
4
]
}
}

@ -17,7 +17,7 @@ contract AdminList {
}
function add(address _address) internal returns (bool) {
return list.push(uint(_address), true);
return list.push(uint(_address), false);
}
function remove(address _address) internal returns (bool) {
@ -43,13 +43,13 @@ contract AdminList {
break;
} else {
counter++;
pointer = prev;
pointer = next;
}
} else {
break;
}
//Getting rid of unused variable warning
next;
prev;
}
if (hasFound) {
@ -78,16 +78,16 @@ contract AdminList {
allAddresses[counter++] = address(pointer);
}
if (prev != 0) {
pointer = prev;
if (next != 0) {
pointer = next;
} else {
hasNext = false;
}
}
//Getting rid of unused variable warning
next;
prev;
}
return allAddresses;
}
}
}

@ -0,0 +1,31 @@
pragma solidity >=0.4.22 <0.6.0;
import "./RulesList.sol";
contract ExposedRulesList is RulesList {
function _calculateKey(bytes32 _enodeHigh, bytes32 _enodeLow, bytes16 _ip, uint16 _port) public pure returns(uint256) {
return calculateKey(_enodeHigh, _enodeLow, _ip, _port);
}
function _size() public view returns (uint256) {
return size();
}
function _exists(bytes32 _enodeHigh, bytes32 _enodeLow, bytes16 _ip, uint16 _port) public view returns (bool) {
return exists(_enodeHigh, _enodeLow, _ip, _port);
}
function _add(bytes32 _enodeHigh, bytes32 _enodeLow, bytes16 _ip, uint16 _port) public returns (bool) {
return add(_enodeHigh, _enodeLow, _ip, _port);
}
function _remove(bytes32 _enodeHigh, bytes32 _enodeLow, bytes16 _ip, uint16 _port) public returns (bool) {
return remove(_enodeHigh, _enodeLow, _ip, _port);
}
function _get(uint _index) public view returns (bool _found, bytes32 _enodeHigh, bytes32 _enodeLow, bytes16 _ip, uint16 _port) {
return get(_index);
}
}

@ -1,33 +1,18 @@
pragma solidity >=0.4.22 <0.6.0;
import "./RulesProxy.sol";
import "./RulesList.sol";
import "./Ingress.sol";
import "./Admin.sol";
contract Rules is RulesProxy {
contract Rules is RulesProxy, RulesList {
// on read-only mode rules can't be added/removed
bool readOnlyMode = false;
// version of this contract: semver like 1.2.14 represented like 001002014
uint version = 1000000;
struct Enode {
bytes next;
bytes prev;
bytes32 enodeHigh;
bytes32 enodeLow;
bytes16 enodeHost;
uint16 enodePort;
}
mapping(bytes => Enode) private whitelist; // should there be a size for the whitelists?
// keys
uint countWhitelist;
bytes[] keysWhitelist;
// head of linked list
bytes headWhitelist;
address private ingressContractAddress;
modifier onlyOnEditMode() {
@ -70,7 +55,6 @@ contract Rules is RulesProxy {
return true;
}
// RULES - IS CONNECTION ALLOWED
function connectionAllowed(
bytes32 sourceEnodeHigh,
bytes32 sourceEnodeLow,
@ -82,12 +66,12 @@ contract Rules is RulesProxy {
uint16 destinationEnodePort
) public view returns (bytes32) {
if (
enodeAllowed(
enodeInWhitelist (
sourceEnodeHigh,
sourceEnodeLow,
sourceEnodeIp,
sourceEnodePort
) && enodeAllowed(
) && enodeInWhitelist(
destinationEnodeHigh,
destinationEnodeLow,
destinationEnodeIp,
@ -100,162 +84,54 @@ contract Rules is RulesProxy {
}
}
// RULES - IS ENODE ALLOWED
function enodeAllowed(
bytes32 sourceEnodeHigh,
bytes32 sourceEnodeLow,
bytes16 sourceEnodeIp,
uint16 sourceEnodePort
) public view returns (bool){
bytes memory key = computeKey(
sourceEnodeHigh,
sourceEnodeLow,
sourceEnodeIp,
sourceEnodePort
);
Enode storage whitelistSource = whitelist[key];
if (enodeExists(whitelistSource)) {
return true;
}
function enodeInWhitelist(
bytes32 enodeHigh,
bytes32 enodeLow,
bytes16 ip,
uint16 port
) public view returns (bool) {
return exists(enodeHigh, enodeLow, ip, port);
}
// RULES MODIFIERS - ADD
function addEnode(
bytes32 enodeHigh,
bytes32 enodeLow,
bytes16 enodeIp,
uint16 enodePort
bytes16 ip,
uint16 port
) public onlyAdmin onlyOnEditMode returns (bool) {
bytes memory key = computeKey(
enodeHigh,
enodeLow,
enodeIp,
enodePort
);
// return false if already in the list
if (enodeExists(whitelist[key])) {
return false;
}
bytes memory next;
bytes memory prev;
if (countWhitelist == 0) {
next = key;
prev = key;
headWhitelist = key;
} else {
next = whitelist[headWhitelist].next;
prev = headWhitelist;
}
Enode memory newEnode = Enode(
next,
prev,
enodeHigh,
enodeLow,
enodeIp,
enodePort
);
whitelist[key] = newEnode;
keysWhitelist.push(key);
countWhitelist = countWhitelist + 1;
whitelist[newEnode.next].prev = key;
whitelist[headWhitelist].next = key;
bool added = add(enodeHigh, enodeLow, ip, port);
triggerRulesChangeEvent(false);
if (added) {
triggerRulesChangeEvent(false);
}
return true;
return added;
}
// RULES MODIFIERS - REMOVE
function removeEnode(
bytes32 enodeHigh,
bytes32 enodeLow,
bytes16 enodeIp,
uint16 enodePort
bytes16 ip,
uint16 port
) public onlyAdmin onlyOnEditMode returns (bool) {
bytes memory key = computeKey(
enodeHigh,
enodeLow,
enodeIp,
enodePort
);
if (!enodeExists(whitelist[key])) {
return false;
}
Enode memory e = whitelist[key];
bool removed = remove(enodeHigh, enodeLow, ip, port);
// update keys
for (uint i = 0; i < keysWhitelist.length; i++) {
if (bytesEqual(keysWhitelist[i], key)) {
keysWhitelist[i] = keysWhitelist[keysWhitelist.length - 1];
delete keysWhitelist[keysWhitelist.length - 1];
keysWhitelist.length--;
}
if (removed) {
triggerRulesChangeEvent(true);
}
// update linked list
headWhitelist = e.next;
whitelist[e.prev].next = e.next;
whitelist[e.next].prev = e.prev;
countWhitelist = countWhitelist - 1;
delete whitelist[key];
triggerRulesChangeEvent(true);
return true;
return removed;
}
function bytesEqual(bytes memory a, bytes memory b) public pure returns(bool) {
if (a.length != b.length) {
return false;
} else {
// check each byte
for (uint j = 0; j < b.length; j++) {
if (a[j] != b[j]) {
return false;
}
}
}
return true;
function getSize() public view returns (uint) {
return size();
}
// RULES - LINKED LIST
function getHeadEnode() public view returns (bytes memory, bytes memory, bytes32, bytes32, bytes16, uint16) {
require(countWhitelist > 0, "Whitelist is empty");
return getEnode(headWhitelist);
}
function getEnode(bytes memory key) public view returns (bytes memory, bytes memory, bytes32 , bytes32 , bytes16 , uint16) {
Enode memory e = whitelist[key];
return (e.next, e.prev, e.enodeHigh, e.enodeLow, e.enodeHost, e.enodePort);
}
// RULES - UTILS
function getWhitelistKey(uint index) public view returns(bytes memory) {
return keysWhitelist[index];
}
function enodeExists(Enode memory enode) private pure returns (bool) {
// TODO do we need to check all fields?
return enode.enodeHost > 0 && enode.enodeHigh > 0 && enode.enodeLow > 0;
}
function computeKey(
bytes32 enodeHigh,
bytes32 enodeLow,
bytes16 enodeHostIp,
uint16 enodePort
) public pure returns (bytes memory) {
return abi.encode(
enodeHigh,
enodeLow,
enodeHostIp,
enodePort
);
}
function getKeyCount() public view returns (uint) {
return keysWhitelist.length;
function getByIndex(uint index) public view returns (bytes32 enodeHigh, bytes32 enodeLow, bytes16 ip, uint16 port) {
(bool _exists, bytes32 _enodeHigh, bytes32 _enodeLow, bytes16 _ip, uint16 _port) = get(index);
if (_exists) {
return (_enodeHigh, _enodeLow, _ip, _port);
}
}
function triggerRulesChangeEvent(bool addsRestrictions) public {

@ -0,0 +1,93 @@
pragma solidity >=0.4.22 <0.6.0;
import "solidity-linked-list/contracts/StructuredLinkedList.sol";
contract RulesList {
using StructuredLinkedList for StructuredLinkedList.List;
// struct size = 82 bytes
struct enode {
bytes32 enodeHigh;
bytes32 enodeLow;
bytes16 ip;
uint16 port;
}
StructuredLinkedList.List private list;
mapping (uint256 => enode) private enodeMapping;
function calculateKey(bytes32 _enodeHigh, bytes32 _enodeLow, bytes16 _ip, uint16 _port) internal pure returns(uint256) {
return uint256(keccak256(abi.encodePacked(_enodeHigh, _enodeLow, _ip, _port)));
}
function size() internal view returns (uint256) {
return list.sizeOf();
}
function exists(bytes32 _enodeHigh, bytes32 _enodeLow, bytes16 _ip, uint16 _port) internal view returns (bool) {
return list.nodeExists(calculateKey(_enodeHigh, _enodeLow, _ip, _port));
}
function add(bytes32 _enodeHigh, bytes32 _enodeLow, bytes16 _ip, uint16 _port) internal returns (bool) {
uint key = calculateKey(_enodeHigh, _enodeLow, _ip, _port);
if (!list.nodeExists(key)) {
enode memory newEnode = enode(
_enodeHigh,
_enodeLow,
_ip,
_port
);
enodeMapping[key] = newEnode;
return list.push(calculateKey(_enodeHigh, _enodeLow, _ip, _port), false);
} else {
return false;
}
}
function remove(bytes32 _enodeHigh, bytes32 _enodeLow, bytes16 _ip, uint16 _port) internal returns (bool) {
uint key = calculateKey(_enodeHigh, _enodeLow, _ip, _port);
if (list.nodeExists(key)) {
delete enodeMapping[key];
return list.remove(key) != 0 ? true : false;
} else {
return false;
}
}
function get(uint _index) internal view returns (bool _exists, bytes32 _enodeHigh, bytes32 _enodeLow, bytes16 _ip, uint16 _port) {
uint listSize = list.sizeOf();
if (_index >= listSize) {
return (false, bytes32(0), bytes32(0), bytes16(0), uint16(0));
}
uint counter = 0;
uint pointer = 0;
bool hasFound = false;
while(counter <= listSize) {
(bool nodeExists, uint256 prev, uint256 next) = list.getNode(pointer);
if (nodeExists) {
if (counter == _index + 1) {
hasFound = true;
break;
} else {
counter++;
pointer = next;
}
} else {
break;
}
//Getting rid of unused variable warning
prev;
}
if (hasFound) {
enode memory e = enodeMapping[pointer];
return (true, e.enodeHigh, e.enodeLow, e.ip, e.port);
} else {
return (false, bytes32(0), bytes32(0), bytes16(0), uint16(0));
}
}
}

File diff suppressed because one or more lines are too long

@ -1,171 +0,0 @@
const Ingress = artifacts.require('Ingress.sol');
const Rules = artifacts.require('Rules.sol');
const Admin = artifacts.require('Admin.sol');
const ADMIN_NAME = "0x61646d696e697374726174696f6e000000000000000000000000000000000000";
var node1High = "0x9bd359fdc3a2ed5df436c3d8914b1532740128929892092b7fcb320c1b62f375";
var node1HighCopy = "0x9bd359fdc3a2ed5df436c3d8914b1532740128929892092b7fcb320c1b62f375";
var node1Low = "0x2e1092b7fcb320c1b62f3759bd359fdc3a2ed5df436c3d8914b1532740128929";
var node1Host = "0x0000000000000000000011119bd359fd";
var node1Port = 1;
var node2High = "0x892092b7fcb320c1b62f3759bd359fdc3a2ed5df436c3d8914b1532740128929";
var node2Low = "0xcb320c1b62f37892092b7f59bd359fdc3a2ed5df436c3d8914b1532740128929";
var node2Host = "0x0000000000000000000011119bd359fd";
var node2Port = 2;
var node3High = "0x765092b7fcb320c1b62f3759bd359fdc3a2ed5df436c3d8914b1532740128929";
var node3Low = "0x920982b7fcb320c1b62f3759bd359fdc3a2ed5df436c3d8914b1532740128929";
var node3Host = "0x0000000000000000000011117fc359fd";
var node3Port = 3;
// use 1,2,3 as port numbers and index into this array
var nodes = [[0,0,0,0],
[node1High, node1Low, node1Host, node1Port],
[node2High, node2Low, node2Host, node2Port],
[node3High, node3Low, node3Host, node3Port]];
var newAdmin = "f17f52151EbEF6C7334FAD080c5704D77216b732";
// Contract keys
var RULES_CONTRACT = "0x72756c6573000000000000000000000000000000000000000000000000000000";
contract('Rules (node permissioning)', () => {
let ingressContract;
let rulesContract;
let adminContract;
before(async () => {
ingressContract = await Ingress.new();
adminContract = await Admin.new();
result = await ingressContract.setContractAddress(ADMIN_NAME, adminContract.address);
rulesContract = await Rules.new(ingressContract.address);
})
it('Should NOT permit any node when none have been added', async () => {
try {
let permitted = await rulesContract.enodeAllowed(node1High, node1Low, node1Host, node1Port);
assert.equal(permitted, false, 'expected node NOT permitted');
// get head when no nodes in list should fail
await rulesContract.getHeadEnode();
} catch (err) {
assert(true, err.toString().includes('revert'), 'expected revert in message');
return;
}
assert(false, 'did not catch expected error from getHeadEnode() when no nodes in whitelist');
});
it('Should add a node to the whitelist and then permit that node', async () => {
// Register the Rules contract to permit adding enodes
await ingressContract.setContractAddress(RULES_CONTRACT, rulesContract.address);
// add node1
await rulesContract.addEnode(node1High, node1Low, node1Host, node1Port);
let result = await rulesContract.getHeadEnode();
assert.equal(result[2], node1High, 'expected high node1');
assert.equal(result[3], node1Low, 'expected low node1');
assert.equal(result[4], node1Host, 'expected host node1');
assert.equal(result[5], node1Port, 'expected port node1');
assert.equal(result[0], result[1], 'for node1 expected next == prev when only one node added');
// add node2
await rulesContract.addEnode(node2High, node2Low, node2Host, node2Port);
// add node3
await rulesContract.addEnode(node3High, node3Low, node3Host, node3Port);
result = await rulesContract.getHeadEnode();
let key = result[0];
let foundNode1, foundNode2, foundNode3 = false;
let i = 0;
let originalKey = key;
while (i<9 ) {
result = await rulesContract.getEnode(key);
// assert the values match the nodes array
assert.equal(result[2], nodes[result[5]][0], 'expected high node' + result[5]);
assert.equal(result[3], nodes[result[5]][1], 'expected low node' + result[5]);
assert.equal(result[4], nodes[result[5]][2], 'expected host node' + result[5]);
if (result[2] == node1High) {
foundNode1 = true;
}
if (result[2] == node2High) {
foundNode2 = true;
}
if (result[2] == node3High) {
foundNode3 = true;
}
key = result[0];
i++;
if (key == originalKey) {
break;
}
}
assert.equal(i, 3, 'expected 3 values');
assert.equal(foundNode1, true, 'expected to find node1');
assert.equal(foundNode2, true, 'expected to find node2');
assert.equal(foundNode3, true, 'expected to find node3');
// test keycount
result = await rulesContract.getKeyCount();
assert.equal(result, 3, 'expected count 3');
});
it('Should remove a node from the whitelist and then NOT find it in the list', async () => {
result = await rulesContract.getHeadEnode();
let key = result[0];
// remove node3
result = await rulesContract.removeEnode(node1High, node1Low, node1Host, node1Port);
result = await rulesContract.getHeadEnode();
key = result[0];
let foundNode1 = false;
let foundNode2 = false;
let foundNode3 = false;
let i = 0;
let originalKey = key;
while (i<9) {
result = await rulesContract.getEnode(key);
// assert the values match the nodes array
assert.equal(result[2], nodes[result[5]][0], 'expected high node' + result[5]);
assert.equal(result[3], nodes[result[5]][1], 'expected low node' + result[5]);
assert.equal(result[4], nodes[result[5]][2], 'expected host node' + result[5]);
if (result[2] == node1High) {
foundNode1 = true;
}
if (result[2] == node2High) {
foundNode2 = true;
}
if (result[2] == node3High) {
foundNode3 = true;
}
key = result[0];
i++;
if (key == originalKey) {
break;
}
}
assert.equal(foundNode1, false, 'expected to NOT find node1');
assert.equal(foundNode2, true, 'expected to find node2');
assert.equal(foundNode3, true, 'expected to find node3');
assert.equal(i, 2, 'expected 2 values');
result = await rulesContract.getKeyCount();
assert.equal(result, 2, 'expected count 2');
});
it('Should compare bytes', async () => {
result = await rulesContract.bytesEqual(node1High, node1Low);
assert.equal(result, false, 'expected not equal');
result = await rulesContract.bytesEqual(node1High, node1HighCopy);
assert.equal(result, true, 'expected equal');
});
});

@ -0,0 +1,159 @@
const BN = web3.utils.BN;
const RulesList = artifacts.require('ExposedRulesList.sol');
const node1High = "0x9bd359fdc3a2ed5df436c3d8914b1532740128929892092b7fcb320c1b62f375";
const node1Low = "0x2e1092b7fcb320c1b62f3759bd359fdc3a2ed5df436c3d8914b1532740128929";
const node1Host = "0x0000000000000000000011119bd359fd";
const node1Port = 30303;
const node2High = "0x892092b7fcb320c1b62f3759bd359fdc3a2ed5df436c3d8914b1532740128929";
const node2Low = "0xcb320c1b62f37892092b7f59bd359fdc3a2ed5df436c3d8914b1532740128929";
const node2Host = "0x0000000000000000000011119bd359fd";
const node2Port = 30304;
const node3High = "0x765092b7fcb320c1b62f3759bd359fdc3a2ed5df436c3d8914b1532740128929";
const node3Low = "0x920982b7fcb320c1b62f3759bd359fdc3a2ed5df436c3d8914b1532740128929";
const node3Host = "0x0000000000000000000011117fc359fd";
const node3Port = 30305;
contract("RulesList (list manipulation)", async () => {
let rulesListContract;
beforeEach(async () => {
rulesListContract = await RulesList.new();
});
it("should calculate same key for same enode", async () => {
let key1 = new BN(await rulesListContract._calculateKey(node1High, node1Low, node1Host, node1Port));
let key2 = new BN(await rulesListContract._calculateKey(node1High, node1Low, node1Host, node1Port));
assert.ok(key1.eq(key2))
});
it("should calculate different key for different enode", async () => {
let key1 = new BN(await rulesListContract._calculateKey(node1High, node1Low, node1Host, node1Port));
let key2 = new BN(await rulesListContract._calculateKey(node2High, node2Low, node2Host, node2Port));
assert.notOk(key1.eq(key2))
});
it("should start with an empty list of rules", async () => {
let size = await rulesListContract._size();
assert.equal(size, 0);
});
it("size method reflect list size", async () => {
await rulesListContract._add(node1High, node1Low, node1Host, node1Port);
await rulesListContract._add(node2High, node2Low, node2Host, node2Port);
await rulesListContract._add(node3High, node3Low, node3Host, node3Port);
let size = await rulesListContract._size();
assert.equal(size, 3);
});
it("exists should return true for existing address", async () => {
await rulesListContract._add(node1High, node1Low, node1Host, node1Port);
let exists = await rulesListContract._exists(node1High, node1Low, node1Host, node1Port);
assert.ok(exists);
});
it("exists should return false for absent address", async () => {
// adding another address so list is not empty
await rulesListContract._add(node1High, node1Low, node1Host, node1Port);
let exists = await rulesListContract._exists(node2High, node2Low, node2Host, node2Port);
assert.notOk(exists);
});
it("exists should return false when list is empty", async () => {
let exists = await rulesListContract._exists(node1High, node1Low, node1Host, node1Port);
assert.notOk(exists);
});
it("add enode to list should add node to the list and increase list size", async () => {
let exists = await rulesListContract._exists(node1High, node1Low, node1Host, node1Port);
assert.notOk(exists);
let size = await rulesListContract._size();
assert.equal(size, 0);
await rulesListContract._add(node1High, node1Low, node1Host, node1Port);
exists = await rulesListContract._exists(node1High, node1Low, node1Host, node1Port);
assert.ok(exists);
size = await rulesListContract._size();
assert.equal(size, 1);
});
it("add existing enode should do nothing on second insert", async () => {
await rulesListContract._add(node1High, node1Low, node1Host, node1Port);
await rulesListContract._add(node1High, node1Low, node1Host, node1Port);
let size = await rulesListContract._size();
assert.equal(size, 1);
let exists = await rulesListContract._exists(node1High, node1Low, node1Host, node1Port);
assert.ok(exists);
});
it("remove absent enode should not fail", async () => {
let txResult = await rulesListContract._remove(node1High, node1Low, node1Host, node1Port);
assert.ok(txResult.receipt.status);
});
it("remove enode from list should remove enode from list and decrease list size", async () => {
await rulesListContract._add(node1High, node1Low, node1Host, node1Port);
let size = await rulesListContract._size();
assert.equal(size, 1);
let exists = await rulesListContract._exists(node1High, node1Low, node1Host, node1Port);
assert.ok(exists);
await rulesListContract._remove(node1High, node1Low, node1Host, node1Port);
size = await rulesListContract._size();
assert.equal(size, 0);
exists = await rulesListContract._exists(node1High, node1Low, node1Host, node1Port);
assert.notOk(exists);
});
it("remove address in the middle of list should maintain list order", async () => {
await rulesListContract._add(node1High, node1Low, node1Host, node1Port);
await rulesListContract._add(node2High, node2Low, node2Host, node2Port);
await rulesListContract._add(node3High, node3Low, node3Host, node3Port);
node = await rulesListContract._get(1);
assert.ok(node._found);
assert.equal(node[1], node2High);
await rulesListContract._remove(node2High, node2Low, node2Host, node2Port);
node = await rulesListContract._get(1);
assert.ok(node._found);
assert.equal(node[1], node3High);
});
it("get by index on empty list should return false", async () => {
let node = await rulesListContract._get(0);
assert.notOk(node._found);
});
it("get by index returns expected order", async () => {
await rulesListContract._add(node1High, node1Low, node1Host, node1Port);
await rulesListContract._add(node2High, node2Low, node2Host, node2Port);
await rulesListContract._add(node3High, node3Low, node3Host, node3Port);
let enode = await rulesListContract._get(0);
assert.equal(enode._enodeHigh, node1High);
enode = await rulesListContract._get(1);
assert.equal(enode._enodeHigh, node2High);
enode = await rulesListContract._get(2);
assert.equal(enode._enodeHigh, node3High);
});
});

@ -0,0 +1,146 @@
const IngressContract = artifacts.require('Ingress.sol');
const RulesContract = artifacts.require('Rules.sol');
const AdminContract = artifacts.require('Admin.sol');
// Contract keys
const RULES_NAME = "0x72756c6573000000000000000000000000000000000000000000000000000000";
const ADMIN_NAME = "0x61646d696e697374726174696f6e000000000000000000000000000000000000";
// enodeAllowed reponses
const PERMITTED = "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff";
const NOT_PERMITTED = "0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff";
const node1High = "0x9bd359fdc3a2ed5df436c3d8914b1532740128929892092b7fcb320c1b62f375";
const node1Low = "0x2e1092b7fcb320c1b62f3759bd359fdc3a2ed5df436c3d8914b1532740128929";
const node1Host = "0x0000000000000000000011119bd359fd";
const node1Port = 30303;
const node2High = "0x892092b7fcb320c1b62f3759bd359fdc3a2ed5df436c3d8914b1532740128929";
const node2Low = "0xcb320c1b62f37892092b7f59bd359fdc3a2ed5df436c3d8914b1532740128929";
const node2Host = "0x0000000000000000000011119bd359fd";
const node2Port = 30304;
const node3High = "0x765092b7fcb320c1b62f3759bd359fdc3a2ed5df436c3d8914b1532740128929";
const node3Low = "0x920982b7fcb320c1b62f3759bd359fdc3a2ed5df436c3d8914b1532740128929";
const node3Host = "0x0000000000000000000011117fc359fd";
const node3Port = 30305;
const newAdmin = "f17f52151EbEF6C7334FAD080c5704D77216b732";
contract("Rules (Permissioning)", (accounts) => {
let ingressContract;
let rulesContract;
let adminContract;
before(async () => {
ingressContract = await IngressContract.new();
adminContract = await AdminContract.new();
await ingressContract.setContractAddress(ADMIN_NAME, adminContract.address);
rulesContract = await RulesContract.new(ingressContract.address);
await ingressContract.setContractAddress(RULES_NAME, rulesContract.address);
});
it('should NOT permit node when whitelist is empty', async () => {
let size = await rulesContract.getSize();
assert.equal(size, 0, "expected empty whitelist");
let permitted = await rulesContract.enodeInWhitelist(node1High, node1Low, node1Host, node1Port);
assert.notOk(permitted, 'expected node NOT permitted');
});
it('Should NOT fail when removing enode from empty list', async () => {
let size = await rulesContract.getSize();
assert.equal(size, 0, "expected empty whitelist");
let tx = await rulesContract.removeEnode(node1High, node1Low, node1Host, node1Port);
assert.ok(tx.receipt.status);
});
it('should add multiple nodes to whitelist', async () => {
await rulesContract.addEnode(node1High, node1Low, node1Host, node1Port);
await rulesContract.addEnode(node2High, node2Low, node2Host, node2Port);
await rulesContract.addEnode(node3High, node3Low, node3Host, node3Port);
permitted = await rulesContract.enodeInWhitelist(node1High, node1Low, node1Host, node1Port);
assert.ok(permitted, 'expected node 1 added to be in whitelist');
permitted = await rulesContract.enodeInWhitelist(node2High, node2Low, node2Host, node2Port);
assert.ok(permitted, 'expected node 2 added to be in whitelist');
permitted = await rulesContract.enodeInWhitelist(node3High, node3Low, node3Host, node3Port);
assert.ok(permitted, 'expected node 3 added to be in whitelist');
});
it('should allow a connection between nodes added to the whitelist', async () => {
let permitted = await rulesContract.connectionAllowed(node1High, node1Low, node1Host, node1Port, node2High, node2Low, node2Host, node2Port);
assert.equal(permitted, PERMITTED, 'expected permitted node1 <---> node2');
permitted = await rulesContract.connectionAllowed(node1High, node1Low, node1Host, node1Port, node3High, node3Low, node3Host, node3Port);
assert.equal(permitted, PERMITTED, 'expected permitted node1 <---> node3');
permitted = await rulesContract.connectionAllowed(node2High, node2Low, node2Host, node2Port, node3High, node3Low, node3Host, node3Port);
assert.equal(permitted, PERMITTED, 'expected permitted node2 <---> node3');
});
it('should NOT allow connection with node removed from whitelist', async () => {
await rulesContract.removeEnode(node3High, node3Low, node3Host, node3Port);
let permitted = await rulesContract.enodeInWhitelist(node3High, node3Low, node3Host, node3Port);
assert.notOk(permitted, 'expected removed node NOT permitted');
permitted = await rulesContract.connectionAllowed(node3High, node3Low, node3Host, node3Port, node2High, node2Low, node2Host, node2Port);
assert.equal(permitted, NOT_PERMITTED, 'expected source disallowed since it was removed');
let result = await rulesContract.getSize();
assert.equal(result, 2, "expected number of nodes");
});
it('should permit a node added back to the whitelist', async () => {
let permitted = await rulesContract.enodeInWhitelist(node3High, node3Low, node3Host, node3Port);
assert.notOk(permitted, 'expected removed node NOT permitted');
await rulesContract.addEnode(node3High, node3Low, node3Host, node3Port);
permitted = await rulesContract.enodeInWhitelist(node3High, node3Low, node3Host, node3Port);
assert.ok(permitted, 'expected added node permitted');
permitted = await rulesContract.connectionAllowed(node3High, node3Low, node3Host, node3Port, node2High, node2Low, node2Host, node2Port);
assert.equal(permitted, PERMITTED, 'expected connection allowed since node was added back to whitelist');
});
it('should not allow non-admin account to add node to whitelist', async () => {
try {
await rulesContract.addEnode(node1High, node1Low, node1Host, node1Port, { from: accounts[1] });
expect.fail(null, null, "Modifier was not enforced")
} catch(err) {
expect(err.reason).to.contain('Sender not authorized');
}
});
it('should not allow non-admin account to remove node to whitelist', async () => {
try {
await rulesContract.addEnode(node1High, node1Low, node1Host, node1Port, { from: accounts[1] });
expect.fail(null, null, "Modifier was not enforced")
} catch(err) {
expect(err.reason).to.contain('Sender not authorized');
}
});
it('should allow new admin account to remove node from whitelist', async () => {
await adminContract.addAdmin(accounts[1]);
await rulesContract.removeEnode(node1High, node1Low, node1Host, node1Port, { from: accounts[1] });
let permitted = await rulesContract.enodeInWhitelist(node1High, node1Low, node1Host, node1Port);
assert.notOk(permitted, 'expected added node NOT permitted');
});
it('should allow new admin account to add node to whitelist', async () => {
await adminContract.addAdmin(accounts[2]);
await rulesContract.addEnode(node1High, node1Low, node1Host, node1Port, { from: accounts[2] });
let permitted = await rulesContract.enodeInWhitelist(node1High, node1Low, node1Host, node1Port);
assert.ok(permitted, 'expected added node permitted');
});
});

@ -1,155 +0,0 @@
const IngressContract = artifacts.require('Ingress.sol');
const RulesContract = artifacts.require('Rules.sol');
const AdminContract = artifacts.require('Admin.sol');
// Contract keys
const RULES_NAME = "0x72756c6573000000000000000000000000000000000000000000000000000000";
const ADMIN_NAME = "0x61646d696e697374726174696f6e000000000000000000000000000000000000";
var node1High = "0x9bd359fdc3a2ed5df436c3d8914b1532740128929892092b7fcb320c1b62f375";
var node1Low = "0x2e1092b7fcb320c1b62f3759bd359fdc3a2ed5df436c3d8914b1532740128929";
var node1Host = "0x0000000000000000000011119bd359fd";
var node1Port = 30303;
var node2High = "0x892092b7fcb320c1b62f3759bd359fdc3a2ed5df436c3d8914b1532740128929";
var node2Low = "0xcb320c1b62f37892092b7f59bd359fdc3a2ed5df436c3d8914b1532740128929";
var node2Host = "0x0000000000000000000011119bd359fd";
var node2Port = 30304;
var node3High = "0x765092b7fcb320c1b62f3759bd359fdc3a2ed5df436c3d8914b1532740128929";
var node3Low = "0x920982b7fcb320c1b62f3759bd359fdc3a2ed5df436c3d8914b1532740128929";
var node3Host = "0x0000000000000000000011117fc359fd";
var node3Port = 30305;
var newAdmin = "f17f52151EbEF6C7334FAD080c5704D77216b732";
contract("Rules", () => {
let ingressContract;
let rulesContract;
let adminContract;
before(async () => {
ingressContract = await IngressContract.new();
adminContract = await AdminContract.new();
result = await ingressContract.setContractAddress(ADMIN_NAME, adminContract.address);
rulesContract = await RulesContract.new(ingressContract.address);
});
it('Should NOT permit any node when none have been added', async () => {
ingressContract = await IngressContract.new();
result = await ingressContract.setContractAddress(ADMIN_NAME, adminContract.address);
rulesContract = await RulesContract.new(ingressContract.address);
let permitted = await rulesContract.enodeAllowed(node1High, node1Low, node1Host, node1Port);
assert.equal(permitted, false, 'expected node NOT permitted');
});
it('Should NOT be able to remove enode from empty list', async () => {
await rulesContract.removeEnode(node3High, node3Low, node3Host, node3Port);
let permitted = await rulesContract.enodeAllowed(node3High, node3Low, node3Host, node3Port);
assert.equal(permitted, false, 'expected removed node NOT permitted');
});
it('Should compute key', async () => {
let key1 = await rulesContract.computeKey(node1High, node1Low, node1Host, node1Port);
let key2 = await rulesContract.computeKey(node1High, node1Low, node1Host, node1Port);
assert.equal(key1, key2, "computed keys should be the same");
let key3 = await rulesContract.computeKey(node1High, node1Low, node1Host, node2Port);
assert(key3 != key2, "keys for different ports should be different");
});
it('Should add a node to the whitelist and then permit that node', async () => {
// Register the Rules contract to permit adding enodes
await ingressContract.setContractAddress(RULES_NAME, rulesContract.address);
// add node1
await rulesContract.addEnode(node1High, node1Low, node1Host, node1Port);
let permitted = await rulesContract.enodeAllowed(node1High, node1Low, node1Host, node1Port);
assert.equal(permitted, true, 'expected node added to be permitted');
// add node2
await rulesContract.addEnode(node2High, node2Low, node2Host, node2Port);
permitted = await rulesContract.enodeAllowed(node2High, node2Low, node2Host, node2Port);
assert.equal(permitted, true, 'expected node 2 added to be permitted');
// first one still permitted
permitted = await rulesContract.enodeAllowed(node1High, node1Low, node1Host, node1Port);
assert.equal(permitted, true, 'expected node 1 added to be permitted');
// add node3
await rulesContract.addEnode(node3High, node3Low, node3Host, node3Port);
permitted = await rulesContract.enodeAllowed(node3High, node3Low, node3Host, node3Port);
assert.equal(permitted, true, 'expected node 3 added to be permitted');
// node1 still permitted
permitted = await rulesContract.enodeAllowed(node1High, node1Low, node1Host, node1Port);
assert.equal(permitted, true, 'expected node 1 added to be permitted');
// node2 still permitted
permitted = await rulesContract.enodeAllowed(node2High, node2Low, node2Host, node2Port);
assert.equal(permitted, true, 'expected node 2 added to be permitted');
});
it('Should allow a connection between 2 added nodes', async () => {
let permitted = await rulesContract.connectionAllowed(node1High, node1Low, node1Host, node1Port, node2High, node2Low, node2Host, node2Port);
assert.equal(permitted, "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 'expected permitted node1 <> node2');
permitted = await rulesContract.connectionAllowed(node1High, node1Low, node1Host, node1Port, node3High, node3Low, node3Host, node3Port);
assert.equal(permitted, "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 'expected permitted node1 <> node3');
permitted = await rulesContract.connectionAllowed(node2High, node2Low, node2Host, node2Port, node3High, node3Low, node3Host, node3Port);
assert.equal(permitted, "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 'expected permitted node2 <> node3');
});
it('Should remove END node from the whitelist and then NOT permit that node', async () => {
await rulesContract.removeEnode(node3High, node3Low, node3Host, node3Port);
let permitted = await rulesContract.enodeAllowed(node3High, node3Low, node3Host, node3Port);
assert.equal(permitted, false, 'expected removed node NOT permitted');
permitted = await rulesContract.connectionAllowed(node3High, node3Low, node3Host, node3Port, node2High, node2Low, node2Host, node2Port);
assert.equal(permitted, "0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 'expected source disallowed since it was removed');
let result = await rulesContract.getKeyCount();
assert.equal(result, 2, "expected number of nodes");
});
it('Should remove a node from the whitelist and then NOT permit that node', async () => {
await rulesContract.removeEnode(node1High, node1Low, node1Host, node1Port);
let permitted = await rulesContract.enodeAllowed(node1High, node1Low, node1Host, node1Port);
assert.equal(permitted, false, 'expected removed node NOT permitted');
permitted = await rulesContract.connectionAllowed(node1High, node1Low, node1Host, node1Port, node2High, node2Low, node2Host, node2Port);
assert.equal(permitted, "0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 'expected source disallowed since it was removed');
let result = await rulesContract.getKeyCount();
assert.equal(result, 1, "expected number of nodes");
});
it('Should remove FINAL node from the whitelist AND then NOT permit that node AND list now empty', async () => {
await rulesContract.removeEnode(node2High, node2Low, node2Host, node2Port);
let permitted = await rulesContract.enodeAllowed(node2High, node2Low, node2Host, node2Port);
assert.equal(permitted, false, 'expected removed node NOT permitted');
permitted = await rulesContract.connectionAllowed(node1High, node1Low, node1Host, node1Port, node2High, node2Low, node2Host, node2Port);
assert.equal(permitted, "0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 'expected source disallowed since it was removed');
let result = await rulesContract.getKeyCount();
assert.equal(result, 0, "expected number of nodes");
});
it('Should add a node to the list after it has been emptied', async () => {
// no nodes in the list
let permitted = await rulesContract.enodeAllowed(node2High, node2Low, node2Host, node2Port);
assert.equal(permitted, false, 'expected removed node NOT permitted');
permitted = await rulesContract.connectionAllowed(node1High, node1Low, node1Host, node1Port, node2High, node2Low, node2Host, node2Port);
assert.equal(permitted, "0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 'expected source disallowed since it was removed');
// add node2
await rulesContract.addEnode(node2High, node2Low, node2Host, node2Port);
permitted = await rulesContract.enodeAllowed(node2High, node2Low, node2Host, node2Port);
assert.equal(permitted, true, 'expected node 2 added to be permitted');
// should be one node
let result = await rulesContract.getKeyCount();
assert.equal(result, 1, "expected number of nodes");
});
});
Loading…
Cancel
Save