From 92534c66cec0abc4af97fe2a4dce591a7cc1c016 Mon Sep 17 00:00:00 2001 From: Nick Gheorghita Date: Tue, 26 Feb 2019 15:06:25 -0700 Subject: [PATCH] Update geth.personal to compose personal endpoints --- docs/web3.personal.rst | 105 +++++++++++--- tests/integration/go_ethereum/common.py | 8 +- tests/integration/go_ethereum/conftest.py | 8 +- tests/integration/parity/common.py | 52 +------ tests/integration/parity/test_parity_http.py | 2 + tests/integration/parity/test_parity_ipc.py | 2 + tests/integration/parity/test_parity_ws.py | 2 + tests/integration/test_ethereum_tester.py | 24 ++-- web3/_utils/module_testing/__init__.py | 3 +- web3/_utils/module_testing/personal_module.py | 101 +++++++++++++- web3/geth.py | 32 +++-- web3/main.py | 31 ++-- web3/parity.py | 38 +++-- web3/personal.py | 132 ++++++++++-------- 14 files changed, 342 insertions(+), 198 deletions(-) diff --git a/docs/web3.personal.rst b/docs/web3.personal.rst index ecdf8b39f6..46bdb08fb8 100644 --- a/docs/web3.personal.rst +++ b/docs/web3.personal.rst @@ -1,20 +1,22 @@ Personal API ============ -.. py:module:: web3.personal +There are 2 objects that expose methods to interact with the RPC APIS +under the ``personal_`` namespace, each supporting the endpoints +implemented in the respective clients. -.. py:class:: Personal +- ``web3.geth.personal`` +- ``web3.parity.personal`` -The ``web3.personal`` object exposes methods to interact with the RPC APIs -under the ``personal_`` namespace. +.. py:module:: web3.geth.personal -Properties ----------- +Geth Methods +------------ -The following properties are available on the ``web3.personal`` namespace. +The following methods are available on the ``web3.geth.personal`` namespace. -.. py:attribute:: listAccounts +.. py:method:: listAccounts * Delegates to ``personal_listAccounts`` RPC Method @@ -22,15 +24,10 @@ The following properties are available on the ``web3.personal`` namespace. .. code-block:: python - >>> web3.personal.listAccounts + >>> web3.geth.personal.listAccounts() ['0xd3cda913deb6f67967b99d67acdfa1712c293601'] -Methods -------- - -The following methods are available on the ``web3.personal`` namespace. - .. py:method:: importRawKey(self, private_key, passphrase) * Delegates to ``personal_importRawKey`` RPC Method @@ -40,7 +37,7 @@ The following methods are available on the ``web3.personal`` namespace. .. code-block:: python - >>> web3.personal.importRawKey(some_private_key, 'the-passphrase') + >>> web3.geth.personal.importRawKey(some_private_key, 'the-passphrase') '0xd3cda913deb6f67967b99d67acdfa1712c293601' @@ -53,7 +50,7 @@ The following methods are available on the ``web3.personal`` namespace. .. code-block:: python - >>> web3.personal.newAccount('the-passphrase') + >>> web3.geth.personal.newAccount('the-passphrase') '0xd3cda913deb6f67967b99d67acdfa1712c293601' @@ -65,7 +62,74 @@ The following methods are available on the ``web3.personal`` namespace. .. code-block:: python - >>> web3.personal.lockAccount('0xd3cda913deb6f67967b99d67acdfa1712c293601') + >>> web3.geth.personal.lockAccount('0xd3cda913deb6f67967b99d67acdfa1712c293601') + + +.. py:method:: unlockAccount(self, account, passphrase, duration=None) + + * Delegates to ``personal_unlockAccount`` RPC Method + + Unlocks the given ``account`` for ``duration`` seconds. If ``duration`` is + ``None`` then the account will remain unlocked indefinitely. Returns + boolean as to whether the account was successfully unlocked. + + .. code-block:: python + + >>> web3.geth.personal.unlockAccount('0xd3cda913deb6f67967b99d67acdfa1712c293601', 'wrong-passphrase') + False + >>> web3.geth.personal.unlockAccount('0xd3cda913deb6f67967b99d67acdfa1712c293601', 'the-passphrase') + True + +.. py:method:: sendTransaction(self, transaction, passphrase) + + * Delegates to ``personal_sendTransaction`` RPC Method + + Sends the transaction. + + +.. py:module:: web3.parity.personal + +Parity Methods +-------------- + +The following methods are available on the ``web3.parity.personal`` namespace. + +.. py:method:: listAccounts + + * Delegates to ``personal_listAccounts`` RPC Method + + Returns the list of known accounts. + + .. code-block:: python + + >>> web3.parity.personal.listAccounts() + ['0xd3cda913deb6f67967b99d67acdfa1712c293601'] + + +.. py:method:: importRawKey(self, private_key, passphrase) + + * Delegates to ``personal_importRawKey`` RPC Method + + Adds the given ``private_key`` to the node's keychain, encrypted with the + given ``passphrase``. Returns the address of the imported account. + + .. code-block:: python + + >>> web3.parity.personal.importRawKey(some_private_key, 'the-passphrase') + '0xd3cda913deb6f67967b99d67acdfa1712c293601' + + +.. py:method:: newAccount(self, password) + + * Delegates to ``personal_newAccount`` RPC Method + + Generates a new account in the node's keychain encrypted with the + given ``passphrase``. Returns the address of the created account. + + .. code-block:: python + + >>> web3.parity.personal.newAccount('the-passphrase') + '0xd3cda913deb6f67967b99d67acdfa1712c293601' .. py:method:: unlockAccount(self, account, passphrase, duration=None) @@ -78,9 +142,9 @@ The following methods are available on the ``web3.personal`` namespace. .. code-block:: python - >>> web3.personal.unlockAccount('0xd3cda913deb6f67967b99d67acdfa1712c293601', 'wrong-passphrase') + >>> web3.parity.personal.unlockAccount('0xd3cda913deb6f67967b99d67acdfa1712c293601', 'wrong-passphrase') False - >>> web3.personal.unlockAccount('0xd3cda913deb6f67967b99d67acdfa1712c293601', 'the-passphrase') + >>> web3.parity.personal.unlockAccount('0xd3cda913deb6f67967b99d67acdfa1712c293601', 'the-passphrase') True .. py:method:: sendTransaction(self, transaction, passphrase) @@ -88,3 +152,6 @@ The following methods are available on the ``web3.personal`` namespace. * Delegates to ``personal_sendTransaction`` RPC Method Sends the transaction. + + + diff --git a/tests/integration/go_ethereum/common.py b/tests/integration/go_ethereum/common.py index 145b5864b0..c41a096e07 100644 --- a/tests/integration/go_ethereum/common.py +++ b/tests/integration/go_ethereum/common.py @@ -1,9 +1,9 @@ import pytest -from web3._utils.module_testing import ( +from web3._utils.module_testing import ( # noqa: F401 EthModuleTest, + GoEthereumPersonalModuleTest, NetModuleTest, - PersonalModuleTest, VersionModuleTest, Web3ModuleTest, ) @@ -66,7 +66,3 @@ class GoEthereumVersionModuleTest(VersionModuleTest): class GoEthereumNetModuleTest(NetModuleTest): pass - - -class GoEthereumPersonalModuleTest(PersonalModuleTest): - pass diff --git a/tests/integration/go_ethereum/conftest.py b/tests/integration/go_ethereum/conftest.py index 9c4da553fb..d6291d301a 100644 --- a/tests/integration/go_ethereum/conftest.py +++ b/tests/integration/go_ethereum/conftest.py @@ -184,9 +184,9 @@ def emitter_contract_address(emitter_contract, address_conversion_func): @pytest.fixture def unlocked_account(web3, unlockable_account, unlockable_account_pw): - web3.personal.unlockAccount(unlockable_account, unlockable_account_pw) + web3.geth.personal.unlockAccount(unlockable_account, unlockable_account_pw) yield unlockable_account - web3.personal.lockAccount(unlockable_account) + web3.geth.personal.lockAccount(unlockable_account) @pytest.fixture(scope='module') @@ -206,9 +206,9 @@ def unlockable_account_dual_type(unlockable_account, address_conversion_func): @pytest.yield_fixture def unlocked_account_dual_type(web3, unlockable_account_dual_type, unlockable_account_pw): - web3.personal.unlockAccount(unlockable_account_dual_type, unlockable_account_pw) + web3.geth.personal.unlockAccount(unlockable_account_dual_type, unlockable_account_pw) yield unlockable_account_dual_type - web3.personal.lockAccount(unlockable_account_dual_type) + web3.geth.personal.lockAccount(unlockable_account_dual_type) @pytest.fixture(scope="module") diff --git a/tests/integration/parity/common.py b/tests/integration/parity/common.py index b0918e7336..3612d3a32e 100644 --- a/tests/integration/parity/common.py +++ b/tests/integration/parity/common.py @@ -4,10 +4,10 @@ flaky, ) -from web3._utils.module_testing import ( +from web3._utils.module_testing import ( # noqa: F401 EthModuleTest, ParityModuleTest as TraceModuleTest, - PersonalModuleTest, + ParityPersonalModuleTest, Web3ModuleTest, ) @@ -120,54 +120,6 @@ def test_eth_call_old_contract_state(self, web3, math_contract, unlocked_account raise AssertionError("pending call result was %d!" % pending_call_result) -class ParityPersonalModuleTest(PersonalModuleTest): - def test_personal_importRawKey(self, web3): - pytest.xfail('this non-standard json-rpc method is not implemented on parity') - super().test_personal_importRawKey(web3) - - def test_personal_listAccounts(self, web3): - pytest.xfail('this non-standard json-rpc method is not implemented on parity') - super().test_personal_listAccounts(web3) - - def test_personal_lockAccount(self, web3, unlocked_account): - pytest.xfail('this non-standard json-rpc method is not implemented on parity') - super().test_personal_lockAccount(web3, unlocked_account) - - def test_personal_unlockAccount_success(self, web3): - pytest.xfail('this non-standard json-rpc method is not implemented on parity') - super().test_personal_unlockAccount_success(web3) - - def test_personal_unlockAccount_failure(self, web3, unlockable_account): - pytest.xfail('this non-standard json-rpc method is not implemented on parity') - super().test_personal_unlockAccount_failure(web3, unlockable_account) - - def test_personal_newAccount(self, web3): - pytest.xfail('this non-standard json-rpc method is not implemented on parity') - super().test_personal_newAccount(web3) - - def test_personal_sendTransaction( - self, - web3, - unlockable_account, - unlockable_account_pw): - pytest.xfail('this non-standard json-rpc method is not implemented on parity') - super().test_personal_sendTransaction( - web3, - unlockable_account, - unlockable_account_pw) - - def test_personal_sign_and_ecrecover( - self, - web3, - unlockable_account, - unlockable_account_pw): - pytest.xfail('this non-standard json-rpc method is not implemented on parity') - super().test_personal_sign_and_ecrecover( - web3, - unlockable_account, - unlockable_account_pw) - - class ParityTraceModuleTest(TraceModuleTest): def test_list_storage_keys_no_support(self, web3, emitter_contract_address): super().test_list_storage_keys_no_support(web3, emitter_contract_address) diff --git a/tests/integration/parity/test_parity_http.py b/tests/integration/parity/test_parity_http.py index 1b0ad45458..2b072ed969 100644 --- a/tests/integration/parity/test_parity_http.py +++ b/tests/integration/parity/test_parity_http.py @@ -47,6 +47,7 @@ def parity_command_arguments( '--unlock', author, '--password', passwordfile, '--jsonrpc-port', rpc_port, + '--jsonrpc-apis', 'all', '--no-ipc', '--no-ws', ) @@ -61,6 +62,7 @@ def parity_import_blocks_command(parity_binary, rpc_port, datadir, passwordfile) '--base-path', datadir, '--password', passwordfile, '--jsonrpc-port', str(rpc_port), + '--jsonrpc-apis', 'all', '--no-ipc', '--no-ws', '--tracing', 'on', diff --git a/tests/integration/parity/test_parity_ipc.py b/tests/integration/parity/test_parity_ipc.py index 48dc537875..7bd7a49aa7 100644 --- a/tests/integration/parity/test_parity_ipc.py +++ b/tests/integration/parity/test_parity_ipc.py @@ -45,6 +45,7 @@ def parity_command_arguments( '--base-path', datadir, '--unlock', author, '--password', passwordfile, + '--ipc-apis', 'all', '--no-jsonrpc', '--no-ws', ) @@ -59,6 +60,7 @@ def parity_import_blocks_command(parity_binary, ipc_path, datadir, passwordfile) '--ipc-path', ipc_path, '--base-path', datadir, '--password', passwordfile, + '--ipc-apis', 'all', '--no-jsonrpc', '--no-ws', '--tracing', 'on', diff --git a/tests/integration/parity/test_parity_ws.py b/tests/integration/parity/test_parity_ws.py index 3d24520818..b23ae79033 100644 --- a/tests/integration/parity/test_parity_ws.py +++ b/tests/integration/parity/test_parity_ws.py @@ -49,6 +49,7 @@ def parity_command_arguments( '--password', passwordfile, '--ws-port', ws_port, '--ws-origins', '*', + '--ws-apis', 'all', '--no-ipc', '--no-jsonrpc', ) @@ -64,6 +65,7 @@ def parity_import_blocks_command(parity_binary, ws_port, datadir, passwordfile): '--password', passwordfile, '--ws-port', str(ws_port), '--ws-origins', '*', + '--ws-apis', 'all', '--no-ipc', '--no-jsonrpc', '--tracing', 'on', diff --git a/tests/integration/test_ethereum_tester.py b/tests/integration/test_ethereum_tester.py index 233adffe6f..dfaa228749 100644 --- a/tests/integration/test_ethereum_tester.py +++ b/tests/integration/test_ethereum_tester.py @@ -12,8 +12,8 @@ from web3 import Web3 from web3._utils.module_testing import ( EthModuleTest, + GoEthereumPersonalModuleTest, NetModuleTest, - PersonalModuleTest, VersionModuleTest, Web3ModuleTest, ) @@ -146,7 +146,7 @@ def unlockable_account_pw(web3): @pytest.fixture(scope='module') def unlockable_account(web3, unlockable_account_pw): - account = web3.personal.importRawKey(UNLOCKABLE_PRIVATE_KEY, unlockable_account_pw) + account = web3.geth.personal.importRawKey(UNLOCKABLE_PRIVATE_KEY, unlockable_account_pw) web3.eth.sendTransaction({ 'from': web3.eth.coinbase, 'to': account, @@ -157,9 +157,9 @@ def unlockable_account(web3, unlockable_account_pw): @pytest.fixture def unlocked_account(web3, unlockable_account, unlockable_account_pw): - web3.personal.unlockAccount(unlockable_account, unlockable_account_pw) + web3.geth.personal.unlockAccount(unlockable_account, unlockable_account_pw) yield unlockable_account - web3.personal.lockAccount(unlockable_account) + web3.geth.personal.lockAccount(unlockable_account) @pytest.fixture() @@ -169,9 +169,9 @@ def unlockable_account_dual_type(unlockable_account, address_conversion_func): @pytest.fixture def unlocked_account_dual_type(web3, unlockable_account_dual_type, unlockable_account_pw): - web3.personal.unlockAccount(unlockable_account_dual_type, unlockable_account_pw) + web3.geth.personal.unlockAccount(unlockable_account_dual_type, unlockable_account_pw) yield unlockable_account_dual_type - web3.personal.lockAccount(unlockable_account_dual_type) + web3.geth.personal.lockAccount(unlockable_account_dual_type) @pytest.fixture(scope="module") @@ -297,8 +297,16 @@ class TestEthereumTesterNetModule(NetModuleTest): pass -class TestEthereumTesterPersonalModule(PersonalModuleTest): +# Use web3.geth.personal namespace for testing eth-tester +class TestEthereumTesterPersonalModule(GoEthereumPersonalModuleTest): test_personal_sign_and_ecrecover = not_implemented( - PersonalModuleTest.test_personal_sign_and_ecrecover, + GoEthereumPersonalModuleTest.test_personal_sign_and_ecrecover, ValueError, ) + + # Test overridden here since eth-tester returns False rather than None for failed unlock + def test_personal_unlockAccount_failure(self, + web3, + unlockable_account_dual_type): + result = web3.geth.personal.unlockAccount(unlockable_account_dual_type, 'bad-password') + assert result is False diff --git a/web3/_utils/module_testing/__init__.py b/web3/_utils/module_testing/__init__.py index 285847a0a6..c5af56f83b 100644 --- a/web3/_utils/module_testing/__init__.py +++ b/web3/_utils/module_testing/__init__.py @@ -8,7 +8,8 @@ NetModuleTest, ) from .personal_module import ( # noqa: F401 - PersonalModuleTest, + GoEthereumPersonalModuleTest, + ParityPersonalModuleTest, ) from .version_module import ( # noqa: F401 VersionModuleTest, diff --git a/web3/_utils/module_testing/personal_module.py b/web3/_utils/module_testing/personal_module.py index a588910351..435c7a450b 100644 --- a/web3/_utils/module_testing/personal_module.py +++ b/web3/_utils/module_testing/personal_module.py @@ -1,3 +1,5 @@ +import pytest + from eth_utils import ( is_checksum_address, is_list_like, @@ -13,13 +15,13 @@ ACCOUNT_FOR_UNLOCK = '0x12efDc31B1a8FA1A1e756DFD8A1601055C971E13' -class PersonalModuleTest: +class GoEthereumPersonalModuleTest: def test_personal_importRawKey(self, web3): actual = web3.geth.personal.importRawKey(PRIVATE_KEY_HEX, PASSWORD) assert actual == ADDRESS def test_personal_listAccounts(self, web3): - accounts = web3.geth.personal.listAccounts + accounts = web3.geth.personal.listAccounts() assert is_list_like(accounts) assert len(accounts) > 0 assert all(( @@ -36,14 +38,17 @@ def test_personal_unlockAccount_success(self, web3, unlockable_account_dual_type, unlockable_account_pw): - result = web3.geth.personal.unlockAccount(unlockable_account_dual_type, unlockable_account_pw) + result = web3.geth.personal.unlockAccount( + unlockable_account_dual_type, + unlockable_account_pw + ) assert result is True def test_personal_unlockAccount_failure(self, web3, unlockable_account_dual_type): - result = web3.geth.personal.unlockAccount(unlockable_account_dual_type, 'bad-password') - assert result is False + with pytest.raises(ValueError): + web3.geth.personal.unlockAccount(unlockable_account_dual_type, 'bad-password') def test_personal_newAccount(self, web3): new_account = web3.geth.personal.newAccount(PASSWORD) @@ -76,6 +81,90 @@ def test_personal_sign_and_ecrecover(self, unlockable_account_dual_type, unlockable_account_pw): message = 'test-web3-geth-personal-sign' - signature = web3.geth.personal.sign(message, unlockable_account_dual_type, unlockable_account_pw) + signature = web3.geth.personal.sign( + message, + unlockable_account_dual_type, + unlockable_account_pw + ) signer = web3.geth.personal.ecRecover(message, signature) assert is_same_address(signer, unlockable_account_dual_type) + + +class ParityPersonalModuleTest(): + def test_personal_listAccounts(self, web3): + accounts = web3.parity.personal.listAccounts() + assert is_list_like(accounts) + assert len(accounts) > 0 + assert all(( + is_checksum_address(item) + for item + in accounts + )) + + def test_personal_unlockAccount_success(self, + web3, + unlockable_account_dual_type, + unlockable_account_pw): + result = web3.parity.personal.unlockAccount( + unlockable_account_dual_type, + unlockable_account_pw, + None + ) + assert result is True + + def test_personal_unlockAccount_failure(self, + web3, + unlockable_account_dual_type): + result = web3.parity.personal.unlockAccount( + unlockable_account_dual_type, + 'bad-password', + None + ) + assert result is True + + def test_personal_newAccount(self, web3): + new_account = web3.parity.personal.newAccount(PASSWORD) + assert is_checksum_address(new_account) + + def test_personal_lockAccount(self, web3, unlocked_account): + pytest.xfail('this non-standard json-rpc method is not implemented on parity') + super().test_personal_lockAccount(web3, unlocked_account) + + def test_personal_importRawKey(self, web3): + pytest.xfail('this non-standard json-rpc method is not implemented on parity') + super().test_personal_importRawKey(web3) + + def test_personal_sendTransaction(self, + web3, + unlockable_account_dual_type, + unlockable_account_pw): + assert web3.eth.getBalance(unlockable_account_dual_type) > web3.toWei(1, 'ether') + txn_params = { + 'from': unlockable_account_dual_type, + 'to': unlockable_account_dual_type, + 'gas': 21000, + 'value': 1, + 'gasPrice': web3.toWei(1, 'gwei'), + } + txn_hash = web3.parity.personal.sendTransaction(txn_params, unlockable_account_pw) + assert txn_hash + transaction = web3.eth.getTransaction(txn_hash) + + assert is_same_address(transaction['from'], txn_params['from']) + assert is_same_address(transaction['to'], txn_params['to']) + assert transaction['gas'] == txn_params['gas'] + assert transaction['value'] == txn_params['value'] + assert transaction['gasPrice'] == txn_params['gasPrice'] + + def test_personal_sign_and_ecrecover(self, + web3, + unlockable_account_dual_type, + unlockable_account_pw): + message = 'test-web3-parity-personal-sign' + signature = web3.parity.personal.sign( + message, + unlockable_account_dual_type, + unlockable_account_pw + ) + signer = web3.parity.personal.ecRecover(message, signature) + assert is_same_address(signer, unlockable_account_dual_type) diff --git a/web3/geth.py b/web3/geth.py index 07ccbfa793..558af44bad 100644 --- a/web3/geth.py +++ b/web3/geth.py @@ -1,20 +1,32 @@ from web3.module import ( Module, + ModuleV2, ) from web3.personal import ( - Personal, + ecRecover, + importRawKey, + listAccounts, + lockAccount, + newAccount, + sendTransaction, + sign, + unlockAccount, ) -class GethPersonal(Personal): +class Geth(Module): + pass + + +class GethPersonal(ModuleV2): """ https://github.com/ethereum/go-ethereum/wiki/Management-APIs#personal """ - def __init__(self, w3): - self.w3 = w3 - - -class Geth(Module): - @property - def personal(self): - return GethPersonal(self.web3) + ecRecover = ecRecover() + importRawKey = importRawKey() + listAccounts = listAccounts() + lockAccount = lockAccount() + newAccount = newAccount() + sendTransaction = sendTransaction() + sign = sign() + unlockAccount = unlockAccount() diff --git a/web3/main.py b/web3/main.py index ad1eed30ab..bc58a398aa 100644 --- a/web3/main.py +++ b/web3/main.py @@ -42,6 +42,7 @@ ) from web3.geth import ( Geth, + GethPersonal, ) from web3.iban import ( Iban, @@ -57,6 +58,7 @@ ) from web3.parity import ( Parity, + ParityPersonal, ) from web3.providers.eth_tester import ( EthereumTesterProvider, @@ -82,17 +84,17 @@ def get_default_modules(): - return { - "eth": Eth, - "net": Net, - "version": Version, - "txpool": TxPool, - "miner": Miner, - "admin": Admin, - "parity": Parity, - "geth": Geth, - "testing": Testing, - } + return [ + {"name": "eth", "module": Eth}, + {"name": "net", "module": Net}, + {"name": "version", "module": Version}, + {"name": "txpool", "module": TxPool}, + {"name": "miner", "module": Miner}, + {"name": "admin", "module": Admin}, + {"name": "parity", "module": Parity, 'submodules': {'personal': ParityPersonal}}, + {"name": "geth", "module": Geth, 'submodules': {'personal': GethPersonal}}, + {"name": "testing", "module": Testing}, + ] class Web3: @@ -130,8 +132,11 @@ def __init__(self, provider=None, middlewares=None, modules=None, ens=empty): if modules is None: modules = get_default_modules() - for module_name, module_class in modules.items(): - module_class.attach(self, module_name) + for module in modules: + module['module'].attach(self, module['name']) + if 'submodules' in module: + for subname, submodule in module['submodules'].items(): + submodule.attach(getattr(self, module['name']), subname) self.ens = ens diff --git a/web3/parity.py b/web3/parity.py index d750539941..6ca2a31249 100644 --- a/web3/parity.py +++ b/web3/parity.py @@ -5,30 +5,32 @@ from web3._utils.toolz import ( assoc, ) -from web3.personal import ( - Personal, -) from web3.module import ( Module, + ModuleV2, +) +from web3.personal import ( + ecRecover, + importRawKey, + listAccounts, + newAccount, + sendTransaction, + sign, + unlockAccount, ) -class ParityPersonal(Personal): +class ParityPersonal(ModuleV2): """ https://wiki.parity.io/JSONRPC-personal-module """ - def __init__(self, w3): - self.w3 = w3 - - def importRawKey(self, private_key, passphrase): - raise NotImplementedError( - "personal_importRawKey RPC-endpoint is not supported by the Parity client." - ) - - def lockAccount(self, account): - raise NotImplementedError( - "personal_lockAccount RPC-endpoint is not supported by the Parity client." - ) + ecRecover = ecRecover() + importRawKey = importRawKey() + listAccounts = listAccounts() + newAccount = newAccount() + sendTransaction = sendTransaction() + sign = sign() + unlockAccount = unlockAccount() class Parity(Module): @@ -37,10 +39,6 @@ class Parity(Module): """ defaultBlock = "latest" - @property - def personal(self): - return ParityPersonal(self.web3) - def enode(self): return self.web3.manager.request_blocking( "parity_enode", diff --git a/web3/personal.py b/web3/personal.py index 44f3804ca7..608534244b 100644 --- a/web3/personal.py +++ b/web3/personal.py @@ -1,61 +1,71 @@ -class Personal(): - """ - This API is not automatically available on a `web3` instance, rather it should be accessed - through `web3.geth.personal` or `web3.parity.personal`. - - All RPC endpoints under the personal namespace should be added here, and NotImplementedErrors - should be raised in subclasses if the endpoints are not supported by the respective client. - """ - def importRawKey(self, private_key, passphrase): - return self.web3.manager.request_blocking( - "personal_importRawKey", - [private_key, passphrase], - ) - - def newAccount(self, password): - return self.web3.manager.request_blocking( - "personal_newAccount", [password], - ) - - @property - def listAccounts(self): - return self.web3.manager.request_blocking( - "personal_listAccounts", [], - ) - - def sendTransaction(self, transaction, passphrase): - return self.web3.manager.request_blocking( - "personal_sendTransaction", - [transaction, passphrase], - ) - - def lockAccount(self, account): - return self.web3.manager.request_blocking( - "personal_lockAccount", - [account], - ) - - def unlockAccount(self, account, passphrase, duration=None): - try: - return self.web3.manager.request_blocking( - "personal_unlockAccount", - [account, passphrase, duration], - ) - except ValueError as err: - if "could not decrypt" in str(err): - # Hack to handle go-ethereum error response. - return False - else: - raise - - def sign(self, message, signer, passphrase): - return self.web3.manager.request_blocking( - 'personal_sign', - [message, signer, passphrase], - ) - - def ecRecover(self, message, signature): - return self.web3.manager.request_blocking( - 'personal_ecRecover', - [message, signature], - ) +from web3.method import ( + Method, +) + + +def default_root_munger(module, *args): + return [*args] + + +def importRawKey(): + return Method( + "personal_importRawKey", + mungers=[default_root_munger], + formatter_lookup_fn=None, + ) + + +def newAccount(): + return Method( + "personal_newAccount", + mungers=[default_root_munger], + formatter_lookup_fn=None, + ) + + +def listAccounts(): + return Method( + "personal_listAccounts", + mungers=None, + formatter_lookup_fn=None, + ) + + +def sendTransaction(): + return Method( + "personal_sendTransaction", + mungers=[default_root_munger], + formatter_lookup_fn=None, + ) + + +def lockAccount(): + return Method( + "personal_lockAccount", + mungers=[default_root_munger], + formatter_lookup_fn=None, + ) + + +def unlockAccount(): + return Method( + "personal_unlockAccount", + mungers=[default_root_munger], + formatter_lookup_fn=None, + ) + + +def sign(): + return Method( + "personal_sign", + mungers=[default_root_munger], + formatter_lookup_fn=None, + ) + + +def ecRecover(): + return Method( + "personal_ecRecover", + mungers=[default_root_munger], + formatter_lookup_fn=None, + )