From e4ecb842b6726c493f9027cdce939cbaffc8b3a1 Mon Sep 17 00:00:00 2001 From: Piper Merriam Date: Tue, 21 Feb 2017 12:03:46 -0500 Subject: [PATCH 1/2] Deprecate defaulting 'from' address to coinbase --- CHANGELOG | 5 ++ README.md | 2 +- docs/web3.eth.rst | 2 +- .../test_contract_transact_interface.py | 19 ++++--- tests/eth-module/test_defaultAccount_api.py | 50 +++++++++++++++++++ web3/contract.py | 9 ++-- web3/eth.py | 18 ++----- web3/formatters.py | 24 +++++++-- 8 files changed, 99 insertions(+), 30 deletions(-) create mode 100644 tests/eth-module/test_defaultAccount_api.py diff --git a/CHANGELOG b/CHANGELOG index d54372e..c4d87b1 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,8 @@ +3.7.0 (unreleased) +----- + +* deprecate `eth.defaultAccount` defaulting to the coinbase account. + 3.6.2 ----- diff --git a/README.md b/README.md index 5b0b66f..f2ff246 100644 --- a/README.md +++ b/README.md @@ -49,7 +49,7 @@ uses `web3.py`. ### Setting defaults ```python -web3.eth.defaultAccount = +web3.eth.defaultAccount = web3.eth.defaultBlock = "latest" # Can also be an integer or one of "latest", "pending", "earliest" ``` diff --git a/docs/web3.eth.rst b/docs/web3.eth.rst index eef1f0b..d18a1af 100644 --- a/docs/web3.eth.rst +++ b/docs/web3.eth.rst @@ -19,7 +19,7 @@ The following properties are available on the ``web3.eth`` namespace. .. py:attribute:: Eth.defaultAccount The ethereum address that will be used as the default ``from`` address for - all transactions. This defaults to ``web3.eth.coinbase``. + all transactions. .. py:attribute:: Eth.defaultBlock diff --git a/tests/contracts/test_contract_transact_interface.py b/tests/contracts/test_contract_transact_interface.py index e46615f..bd4b0b3 100644 --- a/tests/contracts/test_contract_transact_interface.py +++ b/tests/contracts/test_contract_transact_interface.py @@ -7,6 +7,9 @@ from eth_utils import ( force_bytes, ) +from web3.utils.empty import ( + empty, +) from web3.utils.transactions import ( wait_for_transaction_receipt, ) @@ -64,11 +67,11 @@ def test_transacting_with_contract_with_arguments(web3, assert final_value - initial_value == 5 -def test_deploy_when_default_account_is_different_than_coinbase(web3, - wait_for_transaction, - STRING_CONTRACT): +def test_deploy_when_default_account_is_set(web3, + wait_for_transaction, + STRING_CONTRACT): web3.eth.defaultAccount = web3.eth.accounts[1] - assert web3.eth.defaultAccount != web3.eth.coinbase + assert web3.eth.defaultAccount is not empty StringContract = web3.eth.contract(**STRING_CONTRACT) @@ -78,11 +81,11 @@ def test_deploy_when_default_account_is_different_than_coinbase(web3, assert txn_after['from'] == web3.eth.defaultAccount -def test_transact_when_default_account_is_different_than_coinbase(web3, - wait_for_transaction, - math_contract): +def test_transact_when_default_account_is_set(web3, + wait_for_transaction, + math_contract): web3.eth.defaultAccount = web3.eth.accounts[1] - assert web3.eth.defaultAccount != web3.eth.coinbase + assert web3.eth.defaultAccount is not empty txn_hash = math_contract.transact().increment() wait_for_transaction(web3, txn_hash) diff --git a/tests/eth-module/test_defaultAccount_api.py b/tests/eth-module/test_defaultAccount_api.py new file mode 100644 index 0000000..39d969f --- /dev/null +++ b/tests/eth-module/test_defaultAccount_api.py @@ -0,0 +1,50 @@ +import pytest + + +@pytest.fixture(autouse=True) +def wait_for_first_block(web3, wait_for_block): + wait_for_block(web3) + + +def test_uses_defaultAccount_when_set(web3, extra_accounts, + wait_for_transaction): + web3.eth.defaultAccount = extra_accounts[2] + + txn_hash = web3.eth.sendTransaction({ + "to": extra_accounts[1], + "value": 1234, + }) + + wait_for_transaction(web3, txn_hash) + + txn = web3.eth.getTransaction(txn_hash) + assert txn['from'] == extra_accounts[2] + + +def test_raises_warning_and_defaults_to_coinbase_when_not_set(web3, extra_accounts, + wait_for_transaction): + with pytest.warns(DeprecationWarning): + txn_hash = web3.eth.sendTransaction({ + "to": extra_accounts[1], + "value": 1234, + }) + + wait_for_transaction(web3, txn_hash) + + txn = web3.eth.getTransaction(txn_hash) + assert txn['from'] == web3.eth.coinbase + + +def test_uses_given_from_address_when_provided(web3, extra_accounts, + wait_for_transaction): + web3.eth.defaultAccount = extra_accounts[2] + txn_hash = web3.eth.sendTransaction({ + "from": extra_accounts[5], + "to": extra_accounts[1], + "value": 1234, + }) + + wait_for_transaction(web3, txn_hash) + + txn = web3.eth.getTransaction(txn_hash) + assert txn['from'] == extra_accounts[5] diff --git a/web3/contract.py b/web3/contract.py index 12b3fce..d255554 100644 --- a/web3/contract.py +++ b/web3/contract.py @@ -402,7 +402,8 @@ class Contract(object): if self.address: estimate_transaction.setdefault('to', self.address) - estimate_transaction.setdefault('from', self.web3.eth.defaultAccount) + if self.web3.eth.defaultAccount is not empty: + estimate_transaction.setdefault('from', self.web3.eth.defaultAccount) if 'to' not in estimate_transaction: if isinstance(self, type): @@ -466,7 +467,8 @@ class Contract(object): if self.address: call_transaction.setdefault('to', self.address) - call_transaction.setdefault('from', self.web3.eth.defaultAccount) + if self.web3.eth.defaultAccount is not empty: + call_transaction.setdefault('from', self.web3.eth.defaultAccount) if 'to' not in call_transaction: if isinstance(self, type): @@ -544,7 +546,8 @@ class Contract(object): if self.address is not None: transact_transaction.setdefault('to', self.address) - transact_transaction.setdefault('from', self.web3.eth.defaultAccount) + if self.web3.eth.defaultAccount is not empty: + transact_transaction.setdefault('from', self.web3.eth.defaultAccount) if 'to' not in transact_transaction: if isinstance(self, type): diff --git a/web3/eth.py b/web3/eth.py index dfb32b6..fc0a471 100644 --- a/web3/eth.py +++ b/web3/eth.py @@ -16,6 +16,9 @@ from web3.contract import ( from web3.utils.blocks import ( is_predefined_block_number, ) +from web3.utils.empty import ( + empty, +) from web3.utils.encoding import ( to_decimal, ) @@ -38,20 +41,7 @@ class Eth(object): self.iban = Iban # self.sendIBANTransaction = lambda: raise NotImplementedError() - _defaultAccount = None - - @property - @coerce_return_to_text - def defaultAccount(self): - if self._defaultAccount is not None: - return self._defaultAccount - # TODO: deprecate defaulting to the coinbase for the from address. - return self.coinbase - - @defaultAccount.setter - def defaultAccount(self, value): - self._defaultAccount = value - + defaultAccount = empty defaultBlock = "latest" def namereg(self): diff --git a/web3/formatters.py b/web3/formatters.py index bd495d8..3a29214 100644 --- a/web3/formatters.py +++ b/web3/formatters.py @@ -1,5 +1,6 @@ from __future__ import absolute_import +import warnings import functools import operator @@ -22,6 +23,9 @@ from eth_utils import ( from web3.iban import Iban +from web3.utils.empty import ( + empty, +) from web3.utils.encoding import ( from_decimal, to_decimal, @@ -92,9 +96,23 @@ def input_filter_params_formatter(filter_params): @coerce_args_to_text @coerce_return_to_text def input_transaction_formatter(eth, txn): - defaults = { - 'from': eth.defaultAccount, - } + if 'from' not in txn and eth.defaultAccount is empty: + warnings.warn(DeprecationWarning( + "web3.py will no longer default the `from` address to the coinbase " + "account. Please update your code to either explicitely provide a " + "`from` address or to explicitely populate the `eth.defaultAccount` " + "address." + )) + defaults = { + 'from': eth.coinbase, + } + elif eth.defaultAccount is not empty: + defaults = { + 'from': eth.defaultAccount, + } + else: + defaults = {} + formatters = { 'from': input_address_formatter, 'to': input_address_formatter, From ed8ba1c0016d401c2ff34455ed17177d08b762ba Mon Sep 17 00:00:00 2001 From: Piper Merriam Date: Tue, 21 Feb 2017 13:32:38 -0500 Subject: [PATCH 2/2] skip deprecation warning test on py27 --- tests/eth-module/test_defaultAccount_api.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/eth-module/test_defaultAccount_api.py b/tests/eth-module/test_defaultAccount_api.py index 39d969f..572836c 100644 --- a/tests/eth-module/test_defaultAccount_api.py +++ b/tests/eth-module/test_defaultAccount_api.py @@ -1,5 +1,7 @@ import pytest +import sys + @pytest.fixture(autouse=True) def wait_for_first_block(web3, wait_for_block): @@ -21,6 +23,7 @@ def test_uses_defaultAccount_when_set(web3, extra_accounts, assert txn['from'] == extra_accounts[2] +@pytest.mark.skipif(sys.version_info.major == 2, reason="Doesn't seem to work on py27") def test_raises_warning_and_defaults_to_coinbase_when_not_set(web3, extra_accounts, wait_for_transaction): with pytest.warns(DeprecationWarning):