Remove python code

This commit is contained in:
Fred Carlsen
2019-02-13 00:06:21 +01:00
committed by Jacob Evans
parent b7fcc70cd9
commit 4f7d6132fc
15 changed files with 0 additions and 5153 deletions

View File

@@ -1,8 +0,0 @@
# Running Dev
start backend (see `backend/README.md`)
`npm install`
`npm run dev`
go to http://localhost:3000/vote.html

View File

@@ -1 +0,0 @@
env

View File

@@ -1,14 +0,0 @@
# Requirements
- python v3.6+
- virtualenv
- postgresql
# Starting
### Local dev
`./run.sh`
On Linux you will have to create a `v0x` database under the current user manually, or modity the `DATABASE_URL` variable in the script.

View File

@@ -1,6 +0,0 @@
aiohttp==3.5.4
asyncpg==0.18.3
coloredlogs==10.0
coloredlogs==10.0
eth-abi==1.3.0
ethereum==2.3.2

View File

@@ -1,23 +0,0 @@
#!/bin/bash
set -euo pipefail
IFS=$'\n\t'
export DATABASE_URL="postgresql:///v0x"
export DATABASE_SSL_ENABLED=0
export PORT=5000
if ! pg_isready -q; then
echo "Postgresql isn't running! you need to start it..."
exit 1
fi
if ! psql $DATABASE_URL -c "SELECT 1" > /dev/null; then
createdb v0x
fi
if [ ! -d env ]; then
virtualenv -p python3.7 env
env/bin/pip install -r requirements.txt
fi
env/bin/python -m v0x

View File

@@ -1,13 +0,0 @@
import coloredlogs
import logging
import os
from aiohttp import web
from v0x.app import create_app
if __name__ == '__main__':
coloredlogs.install()
logging.getLogger('aiohttp.access').setLevel(logging.DEBUG)
logging.getLogger('aiohttp.server').setLevel(logging.DEBUG)
app = create_app()
web.run_app(app, port=os.environ.get('PORT', 5000))

View File

@@ -1,10 +0,0 @@
from aiohttp import web
from v0x.database import init_database
from v0x.handlers import routes
def create_app():
app = web.Application()
app.add_routes(routes)
app.on_startup.append(init_database)
return app

View File

@@ -1,45 +0,0 @@
import asyncpg
import os
import ssl
from aiohttp import web
from distutils.util import strtobool
SSL_CTX = ssl.create_default_context()
SSL_CTX.check_hostname = False
SSL_CTX.verify_mode = ssl.CERT_NONE
async def init_database(app: web.Application):
pool = await asyncpg.create_pool(
dsn=os.environ.get('DATABASE_URL'),
ssl=SSL_CTX if strtobool(os.environ.get('DATABASE_SSL_ENABLED', '0')) else None)
async with pool.acquire() as con:
await con.execute(
"""
CREATE TABLE IF NOT EXISTS votes (
campaign_id BIGINT,
voter_address VARCHAR, -- hex
preference VARCHAR,
comment VARCHAR,
zrx VARCHAR, -- hex
timestamp TIMESTAMP WITHOUT TIME ZONE DEFAULT (NOW() AT TIME ZONE 'UTC'),
signature VARCHAR, -- hex
PRIMARY KEY (campaign_id, voter_address)
);
CREATE TABLE IF NOT EXISTS campaigns (
campaign_id BIGSERIAL PRIMARY KEY,
open_date TIMESTAMP WITHOUT TIME ZONE,
close_date TIMESTAMP WITHOUT TIME ZONE,
open_block BIGINT
);
""")
# TODO: make an admin way to add this
from datetime import datetime
await con.execute(
"""
INSERT INTO campaigns (campaign_id, open_date, close_date, open_block)
VALUES ($1, $2, $3, $4) ON CONFLICT (campaign_id) DO NOTHING;
""",
1, datetime.utcnow(), datetime.utcnow(), 0x6be328)
app['pool'] = pool

View File

@@ -1,112 +0,0 @@
from aiohttp import web
from v0x.vote_utils import verify_signature
routes = web.RouteTableDef()
@routes.post('/api/vote')
async def vote(request: web.Request) -> web.Response:
data = await request.json()
try:
campaign_id = int(data['campaignId'])
preference = data['preference']
voter_address = data['voterAddress']
signature = data['signature']
comment = data.get('comment', '').strip()
except KeyError as ke:
return web.json_response({'error': 'Bad Arguments',
'missingKeys': list(ke.args)}, status=400)
except AttributeError:
# raised if comments is not a string
return web.json_response({
'error': 'Bad Arguments',
'invalidKeys': ['comment']
}, status=400)
except ValueError:
# raised if campaignId is not convertable to an integer
return web.json_response({
'error': 'Bad Arguments',
'invalidKeys': ['campaignId']
}, status=400)
# signature validation
try:
signature_bytes = bytes.fromhex(signature[2:])
if len(signature_bytes) != 65:
return web.json_response({
'error': 'Bad Arguments',
'invalidKeys': ['signature']
}, status=400)
except (ValueError, TypeError):
return web.json_response({
'error': 'Bad Arguments',
'invalidKeys': ['signature']
}, status=400)
# address validation
try:
if len(bytes.fromhex(voter_address[2:])) != 20:
return web.json_response({
'error': 'Bad Arguments',
'invalidKeys': ['voterAddress']
}, status=400)
voter_address = voter_address.lower()
except (ValueError, TypeError):
return web.json_response({
'error': 'Bad Arguments',
'invalidKeys': ['voterAddress']
}, status=400)
# validate preference
if preference != 'Yes' and preference != 'No':
return web.json_response({
'error': 'Bad Arguments',
'invalidKeys': ['preference']
}, status=400)
if not verify_signature(campaign_id, voter_address, preference, signature_bytes):
return web.json_response({
'error': 'Bad Arguments',
'message': 'signature does not match voterAddress'
}, status=400)
# TODO: verify campaign can be voted on now
async with request.app['pool'].acquire() as con:
await con.execute("INSERT INTO votes "
"(campaign_id, voter_address, preference, comment, signature) "
"VALUES ($1, $2, $3, $4, $5) "
"ON CONFLICT (campaign_id, voter_address) "
"DO UPDATE SET "
"preference = EXCLUDED.preference, "
"comment = EXCLUDED.comment, "
"signature = EXCLUDED.signature",
campaign_id, voter_address, preference, comment, signature)
return web.json_response({'ok': True})
@routes.get('/api/votes/{campaign_id}')
async def list_votes(request: web.Request) -> web.Response:
try:
campaign_id = int(request.match_info['campaign_id'])
except ValueError:
return web.json_response({
'error': 'Bad Arguments',
'message': 'Invalid campaign Id'
}, status=400)
async with request.app['pool'].acquire() as con:
votes = await con.fetch("SELECT * FROM votes "
"WHERE campaign_id = $1 "
"ORDER BY timestamp DESC",
campaign_id)
return web.json_response({'votes': [
{
'voterAddress': v['voter_address'],
'preference': v['preference'],
'comment': v['comment'],
'timestamp': v['timestamp'].isoformat() + "Z",
'zrx': v['zrx']
} for v in votes
]})

View File

@@ -1,44 +0,0 @@
from eth_abi import encode_abi
from ethereum.utils import sha3 as keccak256, encode_hex, safe_ord, big_endian_to_int, ecrecover_to_pub
EIP191_HEADER = b"\x19\x01"
EIP712_DOMAIN_NAME = b"0x V0x"
EIP712_DOMAIN_VERSION = b"1"
EIP712_DOMAIN_SEPARATOR_SCHEMA_HASH = keccak256(
b"EIP712Domain(" +
b"string name," +
b"string version" +
b")")
EIP712_DOMAIN_HASH = keccak256(encode_abi(
['bytes32', 'bytes32', 'bytes32'],
[EIP712_DOMAIN_SEPARATOR_SCHEMA_HASH,
keccak256(EIP712_DOMAIN_NAME),
keccak256(EIP712_DOMAIN_VERSION)]))
EIP712_VOTE_TYPE_HASH = keccak256(
b"Vote(" +
b"uint256 campaignId," +
b"string preference" +
b")")
def verify_signature(campaign_id, voter_address, preference, signature):
# encode and hash vote
encoded = encode_abi(
['bytes32', 'uint256', 'bytes32'],
[EIP712_VOTE_TYPE_HASH, campaign_id,
keccak256(preference.encode('utf-8'))])
hash_struct = keccak256(encoded)
hashed = keccak256(EIP191_HEADER +
EIP712_DOMAIN_HASH +
hash_struct)
# ecrecover
v = safe_ord(signature[64])
r = big_endian_to_int(signature[0:32])
s = big_endian_to_int(signature[32:64])
if v == 0 or v == 1:
v += 27
pub = ecrecover_to_pub(hashed, v, r, s)
recovered_address = '0x' + encode_hex(keccak256(pub)[-20:])
return recovered_address == voter_address

File diff suppressed because it is too large Load Diff

View File

@@ -1,17 +0,0 @@
{
"name": "v0x",
"version": "1.0.0",
"description": "",
"scripts": {
"dev": "webpack-dev-server --mode=development",
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"dependencies": {},
"devDependencies": {
"webpack": "^4.26.0",
"webpack-cli": "^3.1.2",
"webpack-dev-server": "^3.1.10"
}
}

View File

@@ -1,11 +0,0 @@
<html>
<body>
Vote:
<button onClick="vote('Yes')">Yes</button>
<button onClick="vote('No')">No</button>
Comment: <textarea id="comment"></textarea>
<br/>
<pre id="comments"></pre>
<script type="text/javascript" src="vote.js"></script>
</body>
</html>

View File

@@ -1,74 +0,0 @@
// https://gist.github.com/bitpshr/076b164843f0414077164fe7fe3278d9
// use the whole thing here preferably
window.addEventListener('load', function() {
console.log('...');
if (window.ethereum) {
window.web3 = new Web3(ethereum);
ethereum.enable();
}
var xhr = new XMLHttpRequest();
xhr.open('GET', '/api/votes/1', true);
xhr.addEventListener("load", function() {
document.getElementById("comments").innerHTML = xhr.responseText;
});
xhr.send();
});
function signVote(preference) {
let domainType = [
{ name: "name", type: "string" },
{ name: "version", type: "string" },
];
let voteType = [
{ name: "campaignId", type: "uint256" },
{ name: "preference", type: "string" },
];
let domainData = {
name: "0x V0x",
version: "1"
};
var voteData = {
campaignId: "1",
preference: preference,
};
let zdata = JSON.stringify({
types: {
EIP712Domain: domainType,
Vote: voteType,
},
domain: domainData,
primaryType: "Vote",
message: voteData
});
signer = web3.eth.coinbase
console.log(zdata, signer, preference);
return new Promise(function(resolve, reject) {
function done(error, result) {
if (error) { console.error(error); reject(error); }
else { console.log(result); resolve(result.result); }
}
web3.currentProvider.sendAsync({
method: "eth_signTypedData_v3",
params: [signer, zdata],
from: signer
}, done)
})
}
function vote(preference) {
signVote(preference).then(function(sig) {
var xhr = new XMLHttpRequest();
xhr.open('POST', '/api/vote', true);
xhr.setRequestHeader("Content-Type", "application/json");
xhr.send(JSON.stringify({
preference: preference,
voterAddress: web3.eth.coinbase,
signature: sig,
comment: document.getElementById("comment").value,
campaignId: 1}));
});
}

View File

@@ -1,19 +0,0 @@
var path = require('path');
module.exports = {
devServer: {
contentBase: path.join(__dirname, '/src'),
compress: true,
host: '0.0.0.0',
port: 3000,
proxy: {
'/api/': {
target: 'http://localhost:5000/',
secure: false,
logLevel: 'debug',
changeOrigin: true,
xfwd: true
}
}
}
};