Skip to content

Commit

Permalink
Merge pull request #58 from Lamden/account
Browse files Browse the repository at this point in the history
accounts
  • Loading branch information
StuartFarmer committed Sep 24, 2017
2 parents adf2cd8 + 8eee830 commit 5908d8b
Show file tree
Hide file tree
Showing 6 changed files with 198 additions and 7 deletions.
26 changes: 26 additions & 0 deletions Makefile
@@ -0,0 +1,26 @@
.PHONY: clean-pyc clean-build docs

help:
@echo "clean-build - remove build artifacts"
@echo "clean-pyc - remove Python file artifacts"
@echo "release - package and upload a release"
@echo "sdist - package"

clean: clean-build clean-pyc

clean-build:
rm -fr build/
rm -fr dist/
rm -fr *.egg-info

clean-pyc:
find . -name '*.pyc' -exec rm -f {} +
find . -name '*.pyo' -exec rm -f {} +
find . -name '*~' -exec rm -f {} +

release: clean
python setup.py sdist bdist bdist_wheel upload

sdist: clean
python setup.py sdist bdist bdist_wheel
ls -l dist
1 change: 1 addition & 0 deletions docker/docker_dapp
Submodule docker_dapp added at 95cb0c
49 changes: 49 additions & 0 deletions gpg/jmunsch
@@ -0,0 +1,49 @@
-----BEGIN PGP PUBLIC KEY BLOCK-----
Version: SKS 1.1.5
Comment: Hostname: pgp.mit.edu

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
=2NUP
-----END PGP PUBLIC KEY BLOCK-----
23 changes: 19 additions & 4 deletions saffron/accounts.py
Expand Up @@ -46,10 +46,23 @@ class Account:
_address (str): chain address.
_name (str): name of token/chain.
Ethereum methods :
self.p.importRawKey
self.p.newAccount
self.p.listAccounts
self.p.getListAccounts
self.p.sendTransaction
self.p.signAndSendTransaction
self.p.lockAccount
self.p.unlockAccount
self.p.sign
self.p.ecRecover
'''
def __init__(self, name=None, address=None, password=None, chain=None):
'''initialize the class
TODO : document chain ()
TODO : salt passwords with bcrypt or better
Args:
_address (str): chain address.
_name (str): name of token/chain.
Expand All @@ -66,13 +79,15 @@ def __init__(self, name=None, address=None, password=None, chain=None):
self.name = _name
self.address = _address
self._new_account = False

node_info = json.loads(open(os.environ['NODE_INFO_JSON']).read())
self.web3 = Web3(Web3.HTTPProvider("http://127.0.0.1:{port}".format(port=node_info.get('rpcport'))))
self.p = Personal(self.web3)

@classmethod
def _from_db(self, name=None, address=None):
return

#TODO
#fancy shit making interacting with the blockchain easy (get balance, transact, etc)
def balance(self):
return Eth.get_balance(self.address)
return Eth.get_balance(self.address)


2 changes: 1 addition & 1 deletion setup.py
Expand Up @@ -3,7 +3,7 @@

setup(name='saffron-cli',
packages=find_packages(),
version = '0.1.10',
version = '0.1.11',
description = 'blockchain artifact development tools',
author = 'Lamden',
author_email = 'james@lamden.io',
Expand Down
104 changes: 102 additions & 2 deletions tests/test_accounts.py
@@ -1,4 +1,10 @@
import pytest, os
from http.server import BaseHTTPRequestHandler, HTTPServer
import json
import re
import socket
from threading import Thread

from saffron.accounts import Account
from saffron.genesis import Chain
from saffron.database import insert_account
Expand Down Expand Up @@ -26,6 +32,45 @@ def read(self, *args, **kwargs):
# monkeypatch.setattr( 'some.Example', Example)
return Chain()



class MockServerRequestHandler(BaseHTTPRequestHandler):
def do_POST(self, *args, **kwargs):
content_len = int(self.headers.get('content-length'))
post_body = self.rfile.read(content_len)
p_body = json.loads(post_body)
# tests = [b'{"jsonrpc": "2.0", "method": "personal_listAccounts", "params": [], "id": 0}',
# b'{"jsonrpc": "2.0", "method": "personal_newAccount", "params": ["doesnt_matter"], "id": 0}']
try:
stub = json.dumps({"result": ''})
tests = {"personal_listAccounts": stub,
"personal_newAccount": stub,
"personal_importRawKey": stub,
"personal_newAccount": stub,
"personal_listAccounts": stub,
"personal_sendTransaction": stub,
"personal_lockAccount": stub,
"personal_unlockAccount": stub,
"personal_sign": stub,
"personal_ecRecover": stub}
self.send_response(200)
self.send_header('Content-Type', 'application/json; charset=utf-8')
self.end_headers()
self.wfile.write(tests.get(p_body['method']).encode('utf-8'))
return
except Exception as e:
import traceback
print(traceback.format_exc(), p_body['method'])

def start_mock_server(port):
mock_server = HTTPServer(('127.0.0.1', port), MockServerRequestHandler)
mock_server_thread = Thread(target=mock_server.serve_forever)
mock_server_thread.setDaemon(True)
mock_server_thread.start()

start_mock_server(8545)
p = 'doesnt_matter'

def test_accounts(chain):
new_account = str(uuid.uuid1())
a = Account(name=new_account, password='testing123', chain=chain)
Expand All @@ -38,8 +83,63 @@ def test_accounts(chain):

def test_account_stored_in_db_when_created():
new_account = str(uuid.uuid1())
a = Account(name=new_account, password='doesnt_matter', chain=Chain())
b = Account(name=new_account, password='doesnt_matter', chain=Chain())
a = Account(name=new_account, password=p, chain=Chain())
b = Account(name=new_account, password=p, chain=Chain())
assert a.name == b.name
assert a._new_account
# assert b._new_account is False

# def test_importRawKey(chain):
# new_account = str(uuid.uuid1())
# p = 'doesnt_matter'
# a = Account(name=new_account, password=p, chain=Chain())
# private_key = 'asdf'
# a.p.importRawKey(private_key, p)

def test_newAccount(chain):
new_account = str(uuid.uuid1())
a = Account(name=new_account, password=p, chain=Chain())
a.p.newAccount(password=p)

def test_listAccounts(chain):
new_account = str(uuid.uuid1())
a = Account(name=new_account, password=p, chain=Chain())
a.p.listAccounts

def test_getListAccounts(chain):
new_account = str(uuid.uuid1())
a = Account(name=new_account, password=p, chain=Chain())
try:
a.p.getListAccounts()
except NotImplementedError:
pass

def test_sendTransaction(chain):
new_account = str(uuid.uuid1())
a = Account(name=new_account, password=p, chain=Chain())
a.p.sendTransaction({"from": "0xhere", "data": 'hello'}, p)

def test_signAndSendTransaction(chain):
new_account = str(uuid.uuid1())
a = Account(name=new_account, password=p, chain=Chain())
a.p.signAndSendTransaction({"from": "0xhere", "data": 'hello'}, p)

def test_lockAccount(chain):
new_account = str(uuid.uuid1())
a = Account(name=new_account, password=p, chain=Chain())
a.p.unlockAccount(new_account, p, duration=None)

def test_unlockAccount(chain):
new_account = str(uuid.uuid1())
a = Account(name=new_account, password=p, chain=Chain())
a.p.unlockAccount(new_account, p)

def test_sign(chain):
new_account = str(uuid.uuid1())
a = Account(name=new_account, password=p, chain=Chain())
a.p.sign('message', new_account, p)

def test_ecRecover(chain):
new_account = str(uuid.uuid1())
a = Account(name=new_account, password=p, chain=Chain())
a.p.ecRecover('message', 'signature')

0 comments on commit 5908d8b

Please sign in to comment.