Skip to content

Commit

Permalink
added a check for POA extraData
Browse files Browse the repository at this point in the history
WIP

fixed apply_formatter_index_at
  • Loading branch information
voith committed Apr 20, 2018
1 parent 4ada39f commit b3a30a7
Show file tree
Hide file tree
Showing 4 changed files with 97 additions and 15 deletions.
5 changes: 4 additions & 1 deletion tests/core/eth-module/test_poa.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import pytest

from web3.exceptions import (
ValidationError,
)
from web3.middleware import (
construct_fixture_middleware,
geth_poa_middleware,
Expand All @@ -12,7 +15,7 @@ def test_long_extra_data(web3):
'eth_getBlockByNumber': {'extraData': '0x' + 'ff' * 33},
})
web3.middleware_stack.inject(return_block_with_long_extra_data, layer=0)
with pytest.raises(ValueError):
with pytest.raises(ValidationError):
web3.eth.getBlock('latest')


Expand Down
9 changes: 8 additions & 1 deletion web3/middleware/formatting.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,27 @@

def construct_formatting_middleware(request_formatters=None,
result_formatters=None,
error_formatters=None):
error_formatters=None,
request_formatters_with_web3=None):
if request_formatters is None:
request_formatters = {}
if result_formatters is None:
result_formatters = {}
if error_formatters is None:
error_formatters = {}
if request_formatters_with_web3 is None:
request_formatters_with_web3 = {}

def formatter_middleware(make_request, web3):
def middleware(method, params):
if method in request_formatters:
formatter = request_formatters[method]
formatted_params = formatter(params)
response = make_request(method, formatted_params)
elif method in request_formatters_with_web3:
formatter = request_formatters_with_web3[method]
formatted_params = formatter(web3, params)
response = make_request(method, formatted_params)
else:
response = make_request(method, params)

Expand Down
78 changes: 65 additions & 13 deletions web3/middleware/validation.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,26 @@
)
from eth_utils.curried import (
apply_formatter_at_index,
apply_formatter_if,
apply_formatters_to_dict,
)
from hexbytes import (
HexBytes,
)

from web3.exceptions import (
ValidationError,
)
from web3.middleware.formatting import (
construct_formatting_middleware,
)
from web3.utils.formatters import (
apply_formatter_with_web3_at_index,
apply_formatters_with_web3_to_dict,
is_not_null,
)


@curry
def validate_chain_id(web3, chain_id):
if chain_id == web3.version.network:
return None
Expand All @@ -27,21 +38,62 @@ def validate_chain_id(web3, chain_id):
)


@curry
def check_extradata_length(val, length):
if not isinstance(val, (str, int, bytes)):
return val
result = HexBytes(val)
if len(result) > length:
raise ValidationError(
"The field extraData is %d bytes, but should be %d. "
"It is quite likely that you are connected to a POA chain. "
"Refer "
"http://web3py.readthedocs.io/en/latest/middleware.html#geth-style-proof-of-authority "
"for more details. The full extraData is: %r" % (
len(result), length, result
)
)
return val


def transaction_normalizer(transaction):
return dissoc(transaction, 'chainId')


def validation_middleware(make_request, web3):
transaction_validator = apply_formatters_to_dict({
'chainId': validate_chain_id(web3),
})
BLOCK_VALIDATORS = {
'extraData': check_extradata_length(length=32),
}


transaction_sanitizer = compose(transaction_normalizer, transaction_validator)
block_validator = apply_formatters_to_dict(BLOCK_VALIDATORS)

def middleware(method, params):
if method in {'eth_sendTransaction', 'eth_estimateGas', 'eth_call'}:
post_validated_params = apply_formatter_at_index(transaction_sanitizer, 0, params)
return make_request(method, post_validated_params)
else:
return make_request(method, params)
return middleware

TRANSACTION_PARAMS_VALIDATORS = apply_formatters_with_web3_to_dict({
'chainId': validate_chain_id,
})


transaction_params_validator = apply_formatter_with_web3_at_index(
TRANSACTION_PARAMS_VALIDATORS,
0,
)

chain_id_validator = compose(
apply_formatter_at_index(transaction_normalizer, 0),
transaction_params_validator
)

extra_data_validator = apply_formatter_if(is_not_null, block_validator)


validation_middleware = construct_formatting_middleware(
request_formatters_with_web3={
'eth_sendTransaction': chain_id_validator,
'eth_estimateGas': chain_id_validator,
'eth_call': chain_id_validator,
},
result_formatters={
'eth_getBlockByHash': extra_data_validator,
'eth_getBlockByNumber': extra_data_validator,
},
)
20 changes: 20 additions & 0 deletions web3/utils/formatters.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
)

from cytoolz import (
complement,
dissoc,
)
from cytoolz.functoolz import (
Expand All @@ -13,6 +14,7 @@
from eth_utils import (
is_dict,
is_list_like,
is_null,
is_string,
to_dict,
to_list,
Expand All @@ -30,6 +32,9 @@ def hex_to_integer(value):
integer_to_hex = hex


is_not_null = complement(is_null)


@curry
@to_list
def apply_formatter_at_index(formatter, at_index, value):
Expand Down Expand Up @@ -158,3 +163,18 @@ def remove_key_if(key, remove_if, input_dict):
return dissoc(input_dict, key)
else:
return input_dict


@curry
def apply_formatter_with_web3_at_index(validator, at_index, web3, value):
_validator = curry(validator)(web3)
return apply_formatter_at_index(_validator, at_index, value)


@curry
def apply_formatters_with_web3_to_dict(validators, web3, value):
class _dict(dict):
def __getitem__(self, key):
validator = super().__getitem__(key)
return curry(validator)(web3)
return apply_formatters_to_dict(_dict(validators), value)

0 comments on commit b3a30a7

Please sign in to comment.