Skip to content
This repository has been archived by the owner on Aug 8, 2018. It is now read-only.

Fix eth gas limit missing #153

Open
wants to merge 12 commits into
base: develop
Choose a base branch
from
1 change: 1 addition & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ install:
- pip install -r requirements.txt
- pip install coveralls readme_renderer
script:
- python setup.py install

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this necessary for this issue?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was added to invoke the Popen(['pyethapp']). Otherwise it won't find the executable.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well the transport can be mocked int the same way as in #168 so this will not be necessary.

- coverage run --source pyethapp setup.py test
- python setup.py check --restructuredtext --strict
after_success:
Expand Down
1 change: 1 addition & 0 deletions pyethapp/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@ def set_config_param(config, s, strict=True):
raise ValueError('Invalid config parameter')
d = config
for key in keys[:-1]:
key = key.strip()
if strict and key not in d:
raise KeyError('Unknown config option %s' % param)
d = d.setdefault(key, {})
Expand Down
3 changes: 2 additions & 1 deletion pyethapp/jsonrpc.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
import ethereum.bloom as bloom
from accounts import Account
from ipc_rpc import bind_unix_listener, serve
from ethereum.exceptions import InvalidTransaction

from ethereum.utils import int32

Expand Down Expand Up @@ -1190,7 +1191,7 @@ def call(self, data, block_id='pending'):

try:
success, output = processblock.apply_transaction(test_block, tx)
except processblock.InvalidTransaction:
except InvalidTransaction as e:
success = False
# make sure we didn't change the real state
snapshot_after = block.snapshot()
Expand Down
27 changes: 22 additions & 5 deletions pyethapp/rpc_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@
# pylint: disable=invalid-name,too-many-arguments,too-few-public-methods
# The number of arguments an it's names are determined by the JSON-RPC spec


DEFAULT_TX_GAS = 3141591 # genesis block gasLimit - 1

z_address = '\x00' * 20
log = logging.getLogger(__name__)

Expand Down Expand Up @@ -116,13 +119,14 @@ class JSONRPCClientReplyError(Exception):
class JSONRPCClient(object):
protocol = JSONRPCProtocol()

def __init__(self, host='127.0.0.1', port=4000, print_communication=True, privkey=None, sender=None):
def __init__(self, host='127.0.0.1', port=4000, print_communication=True, privkey=None, sender=None, default_tx_gas=None):
"specify privkey for local signing"
self.transport = HttpPostClientTransport('http://{}:{}'.format(host, port))
self.print_communication = print_communication
self.privkey = privkey
self._sender = sender
self.port = port
self._default_tx_gas = default_tx_gas

def __repr__(self):
return '<JSONRPCClient @%d>' % self.port
Expand All @@ -141,6 +145,20 @@ def sender(self):
def coinbase(self):
""" Return the client coinbase address. """
return address_decoder(self.call('eth_coinbase'))

@property
def default_tx_gas(self):
if self._default_tx_gas:
return self._default_tx_gas
else:
return DEFAULT_TX_GAS

def call(self, method, *args):
request = self.protocol.create_request(method, args)
reply = self.transport.send_message(request.serialize())
if self.print_communication:
print json.dumps(json.loads(request.serialize()), indent=2)
print reply

def blocknumber(self):
""" Return the most recent block. """
Expand Down Expand Up @@ -362,15 +380,14 @@ def send_transaction(self, sender, to, value=0, data='', startgas=0,
locally sign the transaction. This requires an extended server
implementation that accepts the variables v, r, and s.
"""

if not self.privkey and not sender:
raise ValueError('Either privkey or sender needs to be supplied.')

if self.privkey and not sender:
sender = privtoaddr(self.privkey)

if nonce is None:
nonce = self.nonce(sender)
if nonce is None:
nonce = self.nonce(sender)
elif self.privkey:
if sender != privtoaddr(self.privkey):
raise ValueError('sender for a different privkey.')
Expand All @@ -382,7 +399,7 @@ def send_transaction(self, sender, to, value=0, data='', startgas=0,
nonce = 0

if not startgas:
startgas = self.gaslimit() - 1
startgas = self.default_tx_gas

tx = Transaction(nonce, gasprice, startgas, to=to, value=value, data=data)

Expand Down
130 changes: 130 additions & 0 deletions pyethapp/tests/test_rpc_client.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,74 @@
from pyethapp.jsonrpc import quantity_decoder
from pyethapp.rpc_client import JSONRPCClient
import pytest
from subprocess import Popen
import time
from pyethapp.jsonrpc import address_encoder
from ethereum import utils

def executable_installed(program):
import os

def is_exe(fpath):
return os.path.isfile(fpath) and os.access(fpath, os.X_OK)

for path in os.environ["PATH"].split(os.pathsep):
path = path.strip('"')
exe_file = os.path.join(path, program)
if is_exe(exe_file):
return exe_file
return None

def prepare_rpc_tests(tmpdir):
rpc_tests = tmpdir.mkdir('testdata')

assert Popen(['git', 'clone', 'https://github.com/ethereum/rpc-tests'], cwd=str(rpc_tests)).wait() == 0
tests_dir = rpc_tests.join('rpc-tests')
import os.path
fpath = str(tests_dir.join('lib/config.js'))
assert os.path.isfile(fpath)
assert Popen(['git', 'submodule', 'update', '--init', '--recursive'], cwd=str(tests_dir)).wait() == 0
assert os.path.isfile(str(tests_dir.join('lib/tests/BlockchainTests/bcRPC_API_Test.json')).decode('unicode-escape'))
return tests_dir


@pytest.fixture()
def test_setup(request, tmpdir):
"""
start the test_app with `subprocess.Popen`, so we can kill it properly.
:param request:
:param tmpdir:
:return:
"""
rpc_tests_dir = prepare_rpc_tests(tmpdir)

test_data = rpc_tests_dir.join('lib/tests/BlockchainTests/bcRPC_API_Test.json')
assert executable_installed('pyethapp')
test_app = Popen([
'pyethapp',
'-d', str(tmpdir),
'-l:info,eth.chainservice:debug,jsonrpc:debug',
'-c jsonrpc.listen_port=8081',
'-c p2p.max_peers=0',
'-c p2p.min_peers=0',
'blocktest',
str(test_data),
'RPC_API_Test'
])
def fin():
test_app.terminate()
request.addfinalizer(fin)

time.sleep(60)
return (test_app, rpc_tests_dir)


def test_find_block():
restore = JSONRPCClient.call
JSONRPCClient.call = lambda self, cmd, num, flag: num
client = JSONRPCClient()
client.find_block(lambda x: x == '0x5')
JSONRPCClient.call = restore


def test_default_host():
Expand All @@ -18,3 +83,68 @@ def test_set_host():
client = JSONRPCClient(host)
assert client.transport.endpoint == 'http://{}:{}'.format(host, client.port)
assert client.transport.endpoint != 'http://{}:{}'.format(default_host, client.port)

# The fixture takes much time to initialize, so the tests are grouped into one method
def test_client(test_setup):
(test_app, rpc_tests_dir) = test_setup
client = JSONRPCClient(port=8081)

genesis_block_info = client.call('eth_getBlockByNumber', 'earliest', False)
genesis_gas_limit = quantity_decoder(genesis_block_info['gasLimit'])
assert client.default_tx_gas == (genesis_gas_limit - 1)

sender = client.sender
assert sender == '\xde\x0b)Vi\xa9\xfd\x93\xd5\xf2\x8d\x9e\xc8^@\xf4\xcbi{\xae'

coinbase = client.coinbase
assert coinbase == '\xde\x0b)Vi\xa9\xfd\x93\xd5\xf2\x8d\x9e\xc8^@\xf4\xcbi{\xae'

blocknumber = client.blocknumber()
assert blocknumber == 32

nonce = client.nonce(sender)
assert nonce == 0

balance1 = client.balance(sender)
assert balance1 == 5156250000000000000

gaslimit = client.gaslimit()
assert gaslimit == 3141592

lastgasprice = client.lastgasprice()
assert lastgasprice == 1

balance2 = client.balance('\xff' * 20)
assert balance2 == 0
fid = client.new_filter('pending', 'pending')

# The following tests require an account with a positive balance
# accs = client.call('eth_accounts')
# sender = accs[0]
# res_est = client.eth_sendTransaction(nonce, sender, address_encoder('\xff' * 20), 1)
# assert 'result' in res_est.keys()

# res_call = client.eth_call(utils.encode_hex(a0), '\xff' * 20, 0)
# assert 'result' in res_call.keys()

# res_st = client.send_transaction(sender, address_encoder('\xff' * 20), 1)
# assert 'result' in res_st.keys()

# solidity_code = "contract test { function multiply(uint a) returns(uint d) { return a * 7; } }"

# import ethereum._solidity
# s = ethereum._solidity.get_solidity()
# if s is None:
# pytest.xfail("solidity not installed, not tested")
# else:
# abi = s.mk_full_signature(solidity_code)
# abic = client.new_abi_contract(abi, sender)
# mult = abic.multiply(11111111)
# assert mult == 77777777

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can this be updated or removed?

Copy link
Author

@RomanZacharia RomanZacharia Aug 25, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@konradkonrad Yes, it can be updated. A while ago you sent me the authorization hash for validating transactions with non-zero transfers, but it remained on slack unlike me. Could you please remind what's been there? You can send me the whole chat log so you don't have to search for it, thank you


def test_default_tx_gas_assigned():
default_gas = 12345
client = JSONRPCClient(default_tx_gas=default_gas)
assert client.default_tx_gas == default_gas