Skip to content

Commit

Permalink
Merge branch 'release/20181031'
Browse files Browse the repository at this point in the history
  • Loading branch information
AndreMiras committed Oct 31, 2018
2 parents 34b0545 + 851a4d7 commit a3e7d5b
Show file tree
Hide file tree
Showing 12 changed files with 580 additions and 91 deletions.
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
# Change Log


## [20181031]

- Remove legacy pyetherapp & pyethereum dependencies
- Migrate to pipenv, refs #1
- Improve install from setup.py


## [20181030]

- Add tox testing
Expand Down
22 changes: 22 additions & 0 deletions Pipfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
[[source]]
url = "https://pypi.org/simple"
verify_ssl = true
name = "pypi"

[dev-packages]
flake8 = {version="*"}
ipdb = {version="*"}
isort = {version="*"}
pytest = {version="*"}

[packages]
eth-account = "*"
eth-utils = "*"
pycryptodome = "*"
py-etherscan-api = {file = "https://github.com/corpetty/py-etherscan-api/archive/18ee101.zip"}
requests-cache = "*"
rlp = "*"
"web3" = "*"

[requires]
python_version = "3.6"
439 changes: 439 additions & 0 deletions Pipfile.lock

Large diffs are not rendered by default.

12 changes: 7 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ from pyetheroll.etheroll import Etheroll
etheroll = Etheroll()
bet_size_ether = 0.1
chances = 50
wallet_path = '~/.ethereum/keystore/wallet.json'
wallet_path = 'wallet.json'
wallet_password = 'password'

transaction = etheroll.player_roll_dice(
Expand All @@ -33,12 +33,14 @@ etheroll = Etheroll(chain_id, contract_address)

## Install

Latest stable release:
[Latest stable release](https://github.com/AndreMiras/pyetheroll/tree/master):
```sh
pip install https://github.com/AndreMiras/pyetheroll/archive/master.zip
pip install --process-dependency-links \
https://github.com/AndreMiras/pyetheroll/archive/master.zip
```

Development branch:
[Development branch](https://github.com/AndreMiras/pyetheroll/tree/develop):
```sh
pip install https://github.com/AndreMiras/pyetheroll/archive/develop.zip
pip install --process-dependency-links \
https://github.com/AndreMiras/pyetheroll/archive/develop.zip
```
30 changes: 30 additions & 0 deletions docs/Release.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# How to release

This is documenting the release process.


## Git flow & CHANGELOG.md

Make sure the CHANGELOG.md is up to date and follows the http://keepachangelog.com guidelines.
Start the release with git flow:
```
git flow release start YYYYMMDD
```
Now update the [CHANGELOG.md](/CHANGELOG.md) `[Unreleased]` section to match the new release version.
Also update the `version` string in the [setup.py](/setup.py) file. Then commit and finish release.
```
git commit -a -m "YYYYMMDD"
git flow release finish
```
Push everything, make sure tags are also pushed:
```
git push
git push origin master:master
git push --tags
```

## GitHub

Got to GitHub [Release/Tags](https://github.com/AndreMiras/pyetheroll/tags), click "Add release notes" for the tag just created.
Add the tag name in the "Release title" field and the relevant CHANGELOG.md section in the "Describe this release" textarea field.
Finally, attach the generated APK release file and click "Publish release".
28 changes: 7 additions & 21 deletions pyetheroll/etheroll.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,11 @@

import requests
import requests_cache
from ethereum.utils import checksum_encode
from eth_account import Account
from eth_keyfile import load_keyfile
from eth_utils import to_checksum_address
from etherscan.client import EmptyResponse
from hexbytes.main import HexBytes
from pyethapp.accounts import Account
from web3 import Web3
from web3.auto import w3
from web3.contract import Contract
Expand Down Expand Up @@ -151,10 +152,9 @@ def player_roll_dice(
value_wei = int(bet_size_ether * 1e18)
gas = 310000
gas_price = w3.toWei(gas_price_gwei, 'gwei')
# since Account.load is hanging while decrypting the password
# we set password to None and use `w3.eth.account.decrypt` instead
account = Account.load(wallet_path, password=None)
from_address_normalized = checksum_encode(account.address)
wallet_encrypted = load_keyfile(wallet_path)
address = wallet_encrypted['address']
from_address_normalized = to_checksum_address(address)
nonce = self.web3.eth.getTransactionCount(from_address_normalized)
transaction = {
'chainId': self.chain_id.value,
Expand All @@ -165,26 +165,12 @@ def player_roll_dice(
}
transaction = self.contract.functions.playerRollDice(
roll_under).buildTransaction(transaction)
private_key = self.get_private_key(
wallet_path, wallet_password)
private_key = Account.decrypt(wallet_encrypted, wallet_password)
signed_tx = self.web3.eth.account.signTransaction(
transaction, private_key)
tx_hash = self.web3.eth.sendRawTransaction(signed_tx.rawTransaction)
return tx_hash

@staticmethod
def get_private_key(wallet_path, wallet_password):
"""
Given wallet path and password, returns private key.
Made this way to workaround pyethapp slow account management:
https://github.com/ethereum/pyethapp/issues/292
"""
# lazy loading
from web3.auto import w3
encrypted_key = open(wallet_path).read()
private_key = w3.eth.account.decrypt(encrypted_key, wallet_password)
return private_key

def get_transaction_page(
self, address=None, page=1, offset=100, internal=False):
"""
Expand Down
23 changes: 7 additions & 16 deletions pyetheroll/transaction_debugger.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
import json

import eth_abi
from ethereum.abi import decode_abi
from ethereum.abi import method_id as get_abi_method_id
from ethereum.abi import normalize_name as normalize_abi_method_name
from ethereum.utils import decode_hex, encode_int, zpad
from eth_abi import decode_abi
from eth_utils import decode_hex, function_abi_to_4byte_selector
from web3 import HTTPProvider, Web3

from pyetheroll.constants import ChainID
Expand All @@ -22,16 +19,10 @@ def decode_contract_call(contract_abi: list, call_data: str):
for description in contract_abi:
if description.get('type') != 'function':
continue
method_name = normalize_abi_method_name(description['name'])
arg_types = [item['type'] for item in description['inputs']]
method_id = get_abi_method_id(method_name, arg_types)
if zpad(encode_int(method_id), 4) == method_signature:
try:
# TODO: ethereum.abi.decode_abi vs eth_abi.decode_abi
args = decode_abi(arg_types, call_data_bin[4:])
except AssertionError:
# Invalid args
continue
if function_abi_to_4byte_selector(description) == method_signature:
method_name = description['name']
arg_types = [item['type'] for item in description['inputs']]
args = decode_abi(arg_types, call_data_bin[4:])
return method_name, args


Expand Down Expand Up @@ -117,7 +108,7 @@ def decode_method(self, topics, log_data):
# is crashing with `InsufficientDataBytes` during `LogResult` decoding.
types = ['bytes32' if t == 'bytes' else t for t in types]
names = [e_input['name'] for e_input in event_inputs]
values = eth_abi.decode_abi(types, topics_log_data)
values = decode_abi(types, topics_log_data)
call = {name: value for name, value in zip(names, values)}
decoded_method = {
'method_info': method_info,
Expand Down
14 changes: 6 additions & 8 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
isort
https://github.com/corpetty/py-etherscan-api/archive/cb91fb3.zip#egg=py-etherscan-api
eth-account
ethereum==2.1.1
web3==4.0.0b11
https://github.com/ethereum/pyethapp/archive/8406f32.zip#egg=pyethapp
rlp==0.6.0
requests-cache
eth-account==0.3.0
eth-utils==1.2.2
https://github.com/corpetty/py-etherscan-api/archive/18ee101.zip#egg=py-etherscan-api
requests-cache==0.4.13
rlp==1.0.3
web3==4.8.1
19 changes: 16 additions & 3 deletions setup.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,23 @@
from distutils.core import setup


install_requires = [
'eth-account',
'eth-utils',
'py-etherscan-api==0.7.0',
'pycryptodome',
'requests-cache',
'rlp',
'web3',
]
dependency_links = [
('https://github.com/corpetty/py-etherscan-api'
'/archive/18ee101.zip#egg=py-etherscan-api-0.7.0'),
]
setup(name='pyetheroll',
version='20181030',
version='20181031',
description='Python library to Etheroll smart contract',
author='Andre Miras',
url='https://github.com/AndreMiras/pyetheroll',
packages=['pyetheroll'],
install_requires=[])
install_requires=install_requires,
dependency_links=dependency_links)
34 changes: 25 additions & 9 deletions tests/test_etheroll.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,13 @@
import shutil
import unittest
from datetime import datetime
from functools import partial
from tempfile import mkdtemp
from unittest import mock

import eth_account
from eth_account.internal.transactions import assert_valid_fields
from ethereum.tools.keys import PBKDF2_CONSTANTS
from pyethapp.accounts import Account
from eth_keyfile import create_keyfile_json

from pyetheroll.constants import ChainID
from pyetheroll.etheroll import Etheroll
Expand Down Expand Up @@ -149,12 +150,20 @@ def test_init(self):
self.assertIsNotNone(etheroll.contract)

def create_account_helper(self, password):
# reduces key derivation iterations to speed up creation
PBKDF2_CONSTANTS['c'] = 1
"""
Reduces the PBKDF2 iterations/work-factor to speed up account creation.
"""
wallet_path = os.path.join(self.keystore_dir, 'wallet.json')
account = Account.new(password, path=wallet_path)
with open(account.path, 'w') as f:
f.write(account.dump())
account = eth_account.Account.create()
# monkey patching to set iterations to the minimum, refs:
# https://github.com/ethereum/eth-account/issues/48
eth_account.account.create_keyfile_json = partial(
create_keyfile_json, iterations=1)
encrypted = eth_account.Account.encrypt(account.privateKey, password)
with open(wallet_path, 'w') as f:
f.write(json.dumps(encrypted))
# a bit hacky, but OK for now
account.path = wallet_path
return account

def test_player_roll_dice(self):
Expand Down Expand Up @@ -184,6 +193,13 @@ def test_player_roll_dice(self):
bet_size_ether, chances, wallet_path, wallet_password)
# the method should return a transaction hash
self.assertIsNotNone(transaction)
# and getTransactionCount been called with the normalized address
normalized_address = account.address
self.assertEqual(
m_getTransactionCount.call_args_list,
[mock.call(normalized_address)]
)
# getTransactionCount
# a second one with custom gas (in gwei), refs #23
gas_price_gwei = 12
transaction = etheroll.player_roll_dice(
Expand All @@ -206,8 +222,8 @@ def test_player_roll_dice(self):
}
expected_transaction2 = expected_transaction1.copy()
expected_transaction2['gasPrice'] = 12*1e9
expected_call1 = mock.call(expected_transaction1, account.privkey)
expected_call2 = mock.call(expected_transaction2, account.privkey)
expected_call1 = mock.call(expected_transaction1, account.privateKey)
expected_call2 = mock.call(expected_transaction2, account.privateKey)
# the method should have been called only once
expected_calls = [expected_call1, expected_call2]
self.assertEqual(m_signTransaction.call_args_list, expected_calls)
Expand Down
13 changes: 3 additions & 10 deletions tests/test_transaction_debugger.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from unittest import mock

from hexbytes.main import HexBytes
from web3.utils.datastructures import AttributeDict
from web3.datastructures import AttributeDict

from pyetheroll.constants import ChainID
from pyetheroll.transaction_debugger import (TransactionDebugger,
Expand Down Expand Up @@ -214,7 +214,7 @@ def test_decode_contract_call(self):
self.assertEqual(method_name, 'transfer')
self.assertEqual(
args,
['0x67fa2c06c9c6d4332f330e14a66bdf1873ef3d2b', 1000000000000000000]
('0x67fa2c06c9c6d4332f330e14a66bdf1873ef3d2b', 1000000000000000000)
)

def test_decode_contract_call_callback(self):
Expand Down Expand Up @@ -263,14 +263,7 @@ def test_decode_contract_call_callback(self):
proof = bytes.fromhex(
'1220ba7237d9ed277fdd4bf2b358049b1c5e971b2bc5fa0edd47b3345d3890e4'
'15fc')
self.assertEqual(
args,
[
myid,
result,
proof,
]
)
self.assertEqual(args, (myid, result, proof))

def m_get_abi(self, instance):
"""
Expand Down
30 changes: 11 additions & 19 deletions tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -2,29 +2,21 @@
envlist = pep8,isort,py3
# no setup.py to be ran
skipsdist = True
# trick to enable pre-installation modules
# https://stackoverflow.com/a/50081741/185510
# used to downgrade to setuptools 37, see:
# https://github.com/ethereum/pyethereum/pull/831
indexserver =
preinstall = https://pypi.python.org/simple

[testenv]
deps =
:preinstall: setuptools<=37.0.0
pytest
-r{toxinidir}/requirements.txt
deps = pipenv
commands =
pytest tests/
python setup.py install
pipenv install --dev
pipenv run pytest tests/
# makes sure the project install properly
pipenv run python setup.py install

[testenv:pep8]
deps = flake8
commands = flake8 pyetheroll/ tests/
commands=
pipenv install --dev
pipenv run flake8 pyetheroll/ tests/ setup.py

[testenv:isort]
# isort needs to know the requirements to properly sort
deps =
:preinstall: setuptools<=37.0.0
-r{toxinidir}/requirements.txt
commands = isort --check-only --recursive --diff pyetheroll/ tests/
commands=
pipenv install --dev
pipenv run isort --check-only --recursive --diff pyetheroll/ tests/ setup.py

0 comments on commit a3e7d5b

Please sign in to comment.