Skip to content

Commit

Permalink
unsafe ed25519 delegation & ballot details aux contracts (#12)
Browse files Browse the repository at this point in the history
* added ed25519 delegation contract

* updated .gitignore

* updated gitignore again

* added ballot box aux contract

* removed package-lock and yarn-error

* Rename and slightly refactor Ed25519 self dlgtion

* Update w/ init tests for self-delegation

* fix sv-lib in bb test + implement revert checks

* Add final tests for delegation

* Refactor / reformat BallotDetailsAux a little (ABI CHANGES)

* Fix up ed25519Delegation tests to work

* Rename BallotDetailsAux to match contract

* Implement bbFarmAux2 test section in index - also fix ganache

* Add some extraData to dDeployBallot in ix init tests

* Update tests - fix ganache so it should work on travis

* add mkdir db to doTests.sh (and hopefully fix github-getting-stuck-on-checks-that-have-actually-already-passed issue)

* Update truffle.js with logging
  • Loading branch information
nxtlvlrob authored and XertroV committed Aug 1, 2018
1 parent 3fc599f commit 187bc18
Show file tree
Hide file tree
Showing 14 changed files with 949 additions and 38 deletions.
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,7 @@ scTopics
deploy*.log
tmp*
_solDist
_distEns
.DS_Store
yarn-error.log
db
7 changes: 6 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,16 @@ cache:
yarn: true
directories:
- "node_modules"
sudo: enabled
- "build"
- "db"
sudo: required
before_install:
- sudo add-apt-repository -y ppa:ethereum/ethereum
- sudo apt-get update
- sudo apt-get install -y solc
before_script:
- mkdir -p db
- yarn reset-test
script:
- yarn test
after_script:
Expand Down
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,3 +66,10 @@ You'll need to interact with the paymentSettings SC used by the democIndex (this
**Problems installing dependencies** (2018-06-04)

had some problems installing dependencies of `sha3` and `scrypt` libs after upgrading `yarn` via `brew` (because it installed node). resetting `nvm` via `nvm install 8 && nvm alias default 8` fixed.


## License Stuff

### https://github.com/aragon/aragonOS - GPL 3

* scripts/manage-nodes.sh and associated package.json scripts, modified geth startup wait time
81 changes: 81 additions & 0 deletions contracts/BBFarmAux2.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
pragma solidity 0.4.24;

interface IndexInterface {
function getBBFarm(uint8) external view returns (BBFarmInterface);
function getBBFarmID(bytes4) external view returns (uint8);
function getBackend() external view returns (BackendInterface);
}

interface BackendInterface {
function getDBallotID(bytes32, uint) external view returns (uint256);
}

interface BBFarmInterface {
function getDetails(uint, address) external view returns
( bool hasVoted
, uint nVotesCast
, bytes32 secKey
, uint16 submissionBits
, uint64 startTime
, uint64 endTime
, bytes32 specHash
, bool deprecated
, address ballotOwner
, bytes16 extraData
);
}


contract BBFarmAux2 {
function _ballotIdToNamespace(uint ballotId) internal pure returns (bytes4) {
return bytes4(ballotId >> 224);
}

function getBBFarmAddressFromBallotId(IndexInterface ix, uint256 ballotId) internal view returns (address) {
return ix.getBBFarm(ix.getBBFarmID(_ballotIdToNamespace(ballotId)));
}

function getBallotId(BackendInterface ixBackend, bytes32 democHash, uint ballotN) internal view returns (uint ballotId) {
ballotId = ixBackend.getDBallotID(democHash, ballotN);
}

function getBBFarmAddressAndBallotId(
IndexInterface ix,
bytes32 democHash,
uint ballotN
) external view returns (address bbFarmAddress, uint256 ballotId) {
ballotId = getBallotId(ix.getBackend(), democHash, ballotN);
bbFarmAddress = getBBFarmAddressFromBallotId(ix, ballotId);
}

function getBallotDetails(BBFarmInterface bbFarm, uint ballotId, address voterAddress) external view returns
( bool hasVoted
, uint nVotesCast
, bytes32 secKey
, uint16 submissionBits
, uint64 startTime
, uint64 endTime
, bytes32 specHash
, bool deprecated
, address ballotOwner
, bytes16 extraData
)
{
return bbFarm.getDetails(ballotId, voterAddress);
}

function ballotIdToDetails(IndexInterface ix, uint ballotId) external view returns
( uint nVotesCast
, bytes32 secKey
, uint16 submissionBits
, uint64 startTime
, uint64 endTime
, bytes32 specHash
, bool deprecated
)
{
BBFarmInterface bbFarm = ix.getBBFarm(ix.getBBFarmID(_ballotIdToNamespace(ballotId)));
(, nVotesCast, secKey, submissionBits, startTime, endTime, specHash, deprecated,,) = bbFarm.getDetails(ballotId, address(0));
}

}
110 changes: 110 additions & 0 deletions contracts/Ed25519Delegation.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
pragma solidity 0.4.24;

import {MemArrApp as M} from "../libs/MemArrApp.sol";

contract UnsafeEd25519SelfDelegation {

event DelegationCreated(bytes32 dlgtRequest, bytes32 pubKey, bytes32[2] signature);

struct Delegation {
bytes32 dlgtRequest;
bytes32 sig1;
bytes32 sig2;
uint recordedTs;
}

// Maps a public key to delegation
// We need a list here because we can't validate delegations on-chain,
// so we store all delegaitons such that we can find the most recent valid delegation
mapping (bytes32 => Delegation[]) public delegations;
// allows us to loop through all pubkeys for which delegations have been made
bytes32[] public delegationsLog;

// Log addresses ppl are delegating _to_
mapping (address => bool) public seenAddress;
// allows us to loop through all eth addresses which have been made delegates
// (note: based on unverified delegations)
address[] public addressLog;

// Log delegation requests we haven't seen before - prevent replay attacks
mapping (bytes32 => bool) public dlgtReqsSeen;

// Constructor
constructor() public {}

// Adding a delegation - the single write operation in this contract
function addUntrustedSelfDelegation(bytes32 dlgtRequest, bytes32 pubKey, bytes32[2] signature) external {
// note: dlgtRequest is split into 9, 3, and 20 bytes; the former is a unique tag to ensure signatures from
// ED25519 keys can't be reused for transactions or other networks, the 3 bytes are used as a nonce, and
// the final 20 bytes is the ethereum address we're delegating too.

// take first 9 bytes of dlgtRequest
require(bytes9(dlgtRequest) == bytes9(0x53562d45442d455448), "dlgtReq header != SV-ED-ETH");

// // make sure we haven't seen this delegation request before with this pubkey and sig
bytes32 dlgtReqAllHash = keccak256(abi.encodePacked(dlgtRequest, pubKey, signature[0], signature[1]));
require(dlgtReqsSeen[dlgtReqAllHash] == false, "replay");
dlgtReqsSeen[dlgtReqAllHash] = true;

// log the pubkey if we haven't seen it before
if (delegations[pubKey].length == 0)
delegationsLog.push(pubKey);

delegations[pubKey].push(Delegation(dlgtRequest, signature[0], signature[1], now));
emit DelegationCreated(dlgtRequest, pubKey, signature);

// take last 20 bytes and convert to address
address dlgtTo = address(uint160(dlgtRequest));

if (!seenAddress[dlgtTo]) {
seenAddress[dlgtTo] = true;
addressLog.push(dlgtTo);
}
}

// Simple getters for list lengths
function dLogN() external view returns (uint) {
return delegationsLog.length;
}

function nDelegations(bytes32 pubKey) external view returns (uint) {
return delegations[pubKey].length;
}

function nAddressLog() external view returns (uint) {
return addressLog.length;
}

// Complex Getters

// Get all delegations recorded for a particular public key
function getAllForPubKey(bytes32 pubKey) external view returns (
bytes32[] memory dlgtRequests,
bytes32[] memory sigs1,
bytes32[] memory sigs2,
uint[] recordedTs
) {
return getAllForPubKeyBetween(pubKey, 0, 2**64-1);
}

function _delegationInRange(Delegation storage d, uint start, uint end) internal view returns (bool) {
return d.recordedTs >= start && d.recordedTs <= end;
}

// Get all recorded delegations between a start date and end date
function getAllForPubKeyBetween(bytes32 pubKey, uint startDate, uint endDate) public view returns (
bytes32[] memory dlgtRequests,
bytes32[] memory sig1s,
bytes32[] memory sig2s,
uint[] timestamps
) {
for (uint i = 0; i < delegations[pubKey].length; i++) {
if (_delegationInRange(delegations[pubKey][i], startDate, endDate)) {
dlgtRequests = M.appendBytes32(dlgtRequests, delegations[pubKey][i].dlgtRequest);
sig1s = M.appendBytes32(sig1s, delegations[pubKey][i].sig1);
sig2s = M.appendBytes32(sig2s, delegations[pubKey][i].sig2);
timestamps = M.appendUint256(timestamps, delegations[pubKey][i].recordedTs);
}
}
}
}
2 changes: 2 additions & 0 deletions doTests.sh
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
#!/bin/bash

mkdir -p db

echo "Use RUN_ALL_TESTS=true to run all tests."
if [ -n "$TRAVIS" ] || [ -n "$RUN_ALL_TESTS" ]; then
echo "Loading all env vars"
Expand Down
9 changes: 6 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
"eth-lib": "^0.2.8",
"ethereumjs-testrpc": "^6.0.3",
"ethereumjs-util": "^5.1.5",
"ganache-cli": "^6.1.0",
"ganache-cli": "^6.1.6",
"graceful-fs": "^4.1.11",
"jq": "^1.7.2",
"js-nacl": "^1.2.2",
Expand All @@ -28,8 +28,9 @@
"sanctuary": "^0.14.1",
"solidity-coverage": "^0.5.1",
"solium": "^1.1.6",
"sv-lib": "^0.1.2",
"sv-lib": "^0.2.1",
"truffle": "trufflesuite/truffle",
"tweetnacl": "^1.0.0",
"web3": "^1.0.0-beta.33",
"yargs": "^11.0.0"
},
Expand All @@ -46,6 +47,8 @@
"compile-ens": "for f in $(ls ./ens | grep sol); do ./bin/compile.sh -d ens -c $f -o _distEns; done",
"coverage": "RUN_ALL_TESTS=true solidity-coverage",
"c": "./bin/compile.sh -c",
"diff": "git diff -- . ':(exclude)_solDist/*'"
"diff": "git diff -- . ':(exclude)_solDist/*'",
"manage-nodes:dev": "scripts/manage-nodes.sh",
"test:geth": "export GETH_CLIENT=geth; yarn manage-nodes:dev && truffle test --network rpc"
}
}
77 changes: 77 additions & 0 deletions scripts/manage-nodes.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
#!/usr/bin/env bash

# Exit script as soon as a command fails.
set -o errexit

# check for coverage which will specify new port for ethereum client
if [ "$SOLIDITY_COVERAGE" = true ]; then
GETH_PORT=8555
else
GETH_PORT=8545
fi

PARITY_VERSION=v1.8.0
GETH_VERSION=v1.7.3-instantseal

client_running() {
nc -z localhost "$GETH_PORT"
}

start_testrpc() {
if [ "$SOLIDITY_COVERAGE" = true ]; then
node_modules/.bin/testrpc-sc -i 16 --gasLimit 0xfffffffffff --port "$GETH_PORT" > /dev/null &
else
node_modules/.bin/ganache-cli -i 15 --gasLimit 50000000 > /dev/null &
fi

rpc_pid=$!
}

check_docker() {
# check that docker exists before attempting to pull/run images
if ! [ -x "$(command -v docker)" ]; then
echo 'Error: docker is not installed' >&2
exit 1
fi
}

start_parity() {
check_docker
# pull the most stable release of parity
docker pull purta/parity-instantseal:$PARITY_VERSION
# run the container in detached mode
docker run -d -p 8545:8545 purta/parity-instantseal:$PARITY_VERSION

sleep 5
}

start_geth() {
check_docker
# pull the latest image using the dev test network
docker pull purta/geth-devnet:$GETH_VERSION
# run the geth dev network container
docker run -d -p 8545:8545 purta/geth-devnet:$GETH_VERSION

echo "Letting client warmup for 5 seconds..."
sleep 5
}

if client_running; then
echo "Using existing geth instance at port $GETH_PORT"
else
echo "Starting our own ethereum client at port $GETH_PORT"
case $GETH_CLIENT in
geth )
start_geth
;;
parity )
start_parity
;;
* )
echo "No ethereum client specified, using testrpc..."
start_testrpc
;;
esac
fi

sleep 5
Loading

0 comments on commit 187bc18

Please sign in to comment.