diff --git a/.gitignore b/.gitignore
index 539da74..0966e83 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1,6 @@
*.py[co]
+.idea/
+build/lib/
+ethjsonrpc.egg-info/
+.ropeproject/
+dist/
diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml
new file mode 100644
index 0000000..8b7960a
--- /dev/null
+++ b/.idea/inspectionProfiles/Project_Default.xml
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
new file mode 100644
index 0000000..8cc6fb6
--- /dev/null
+++ b/.idea/misc.xml
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000..94a25f7
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/README.rst b/README.rst
index 5db894e..9dcea37 100644
--- a/README.rst
+++ b/README.rst
@@ -1,10 +1,12 @@
-ethjsonrpc
+InfuraEthJsonRpc
==========
+Extension of the ethjsonrpc library (https://github.com/ConsenSys/ethjsonrpc)
-Python client for Ethereum using the JSON-RPC interface
+* Provides classes to query data from an infura node
+* To speed up the methods, get an access token from Infura. (https://infura.io/register.html)
-* complete: implements all 62 JSON-RPC methods plus several client-specific methods
-* provides a high-level interface to create contracts on the blockchain and to call contract methods
+Earlier instructions
+====================
Important note
--------------
@@ -35,104 +37,32 @@ On Ubuntu 14.04:
$ sudo apt-get install libpython-dev
$ sudo apt-get install libssl-dev
-
-To install ethjsonrpc:
+New Instructions
+================
+To install:
.. code:: bash
- $ pip install ethjsonrpc
-
+ $ git clone https://github.com/ankitchiplunkar/ethjsonrpc.git
+ $ cd ethjsonrpc
+ $ python setup.py install
-Make sure to have a node running an Ethereum client (such as geth) for the library to connect to.
Example
-------
.. code:: python
- >>> from ethjsonrpc import EthJsonRpc # to use Parity-specific methods, import ParityEthJsonRpc
- >>> c = EthJsonRpc('127.0.0.1', 8545)
- >>> c.net_version()
- u'1'
- >>> c.web3_clientVersion()
- u'Geth/v1.3.3/linux/go1.5.1'
- >>> c.eth_gasPrice()
- 50000000000
- >>> c.eth_blockNumber()
- 828948
-
-
-High-level functionality
-------------------------
-
-These examples assume the following simple Solidity contract:
-
-.. code::
-
- contract Example {
-
- string s;
-
- function set_s(string new_s) {
- s = new_s;
- }
-
- function get_s() returns (string) {
- return s;
- }
- }
-
-
-Compile it like this:
-
-.. code:: bash
-
- $ solc --binary stdout example.sol
-
-
-Setup
-`````
-
-.. code:: python
-
- >>> compiled = '606060405261020f806100136000396000f30060606040526000357c01000000000000000000000000000000000000000000000000000000009004806375d74f3914610044578063e7aab290146100bd57610042565b005b61004f600450610191565b60405180806020018281038252838181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156100af5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b61010d6004803590602001906004018035906020019191908080601f016020809104026020016040519081016040528093929190818152602001838380828437820191505050505050905061010f565b005b806000600050908051906020019082805482825590600052602060002090601f01602090048101928215610160579182015b8281111561015f578251826000505591602001919060010190610141565b5b50905061018b919061016d565b80821115610187576000818150600090555060010161016d565b5090565b50505b50565b60206040519081016040528060008152602001506000600050805480601f0160208091040260200160405190810160405280929190818152602001828054801561020057820191906000526020600020905b8154815290600101906020018083116101e357829003601f168201915b5050505050905061020c565b9056'
- >>> from ethjsonrpc import EthJsonRpc # to use Parity-specific methods, import ParityEthJsonRpc
- >>> c = EthJsonRpc('127.0.0.1', 8545)
-
-
-Creating a contract on the blockchain
-`````````````````````````````````````
-
-.. code:: python
-
- >>> # continued from above
- >>> contract_tx = c.create_contract(c.eth_coinbase(), compiled, gas=300000)
- >>> # wait here for the contract to be created when a new block is mined
- >>> contract_addr = c.get_contract_address(contract_tx)
- >>> contract_addr
- u'0x24988147f2f2300450103d8c42c43182cf226857'
-
-
-Calling a contract function with a transaction (storing data)
-`````````````````````````````````````````````````````````````
-
-.. code:: python
-
- >>> # continued from above
- >>> tx = c.call_with_transaction(c.eth_coinbase(), contract_addr, 'set_s(string)', ['Hello, world'])
- >>> tx
- u'0x15bde63d79466e3db5169a913bb2069130ca387033d2ff2e29f4dfbef1bc6e0d'
-
-
-Calling a contract function on the local blockchain (reading data)
-``````````````````````````````````````````````````````````````````
-
-.. code:: python
-
- >>> # continued from above
- >>> results = c.call(contract_addr, 'get_s()', [], ['string'])
- >>> results
- ['Hello, world']
+ >>> c = InfuraEthJsonRpc(network='mainnet')
+ # other possible networks are 'ropsten', 'rinkeby', 'kovan' and 'infuranet'
+ >>> c.net_version()
+ u'1'
+ >>> c.web3_clientVersion()
+ u'Geth/v1.3.3/linux/go1.5.1'
+ >>> c.eth_gasPrice()
+ 50000000000
+ >>> c.eth_blockNumber()
+ 4896520
Additional examples
@@ -140,90 +70,42 @@ Additional examples
Please see ``test.py`` for additional examples.
-Implemented JSON-RPC methods
-----------------------------
-
-* web3_clientVersion
-* web3_sha3
-* net_version
-* net_listening
-* net_peerCount
-* eth_protocolVersion
-* eth_syncing
-* eth_coinbase
-* eth_mining
-* eth_hashrate
-* eth_gasPrice
-* eth_accounts
-* eth_blockNumber
-* eth_getBalance
-* eth_getStorageAt
-* eth_getTransactionCount
-* eth_getBlockTransactionCountByHash
-* eth_getBlockTransactionCountByNumber
-* eth_getUncleCountByBlockHash
-* eth_getUncleCountByBlockNumber
-* eth_getCode
-* eth_sign
-* eth_sendTransaction
-* eth_sendRawTransaction
-* eth_call
-* eth_estimateGas
-* eth_getBlockByHash
-* eth_getBlockByNumber
-* eth_getTransactionByHash
-* eth_getTransactionByBlockHashAndIndex
-* eth_getTransactionByBlockNumberAndIndex
-* eth_getTransactionReceipt
-* eth_getUncleByBlockHashAndIndex
-* eth_getUncleByBlockNumberAndIndex
-* eth_getCompilers
-* eth_compileSolidity
-* eth_compileLLL
-* eth_compileSerpent
-* eth_newFilter
-* eth_newBlockFilter
-* eth_newPendingTransactionFilter
-* eth_uninstallFilter
-* eth_getFilterChanges
-* eth_getFilterLogs
-* eth_getLogs
-* eth_getWork
-* eth_submitWork
-* eth_submitHashrate
-* db_putString
-* db_getString
-* db_putHex
-* db_getHex
-* shh_version
-* shh_post
-* shh_newIdentity
-* shh_hasIdentity
-* shh_newGroup
-* shh_addToGroup
-* shh_newFilter
-* shh_uninstallFilter
-* shh_getFilterChanges
-* shh_getMessages
-
-Parity-only JSON-RPC methods
-----------------------------
-
-To use these methods, make sure that you're
-
-* running Parity as your client
-* running with the ``--tracing on`` option
-* using this library's ``ParityEthJsonRpc`` client (not the vanilla ``EthJsonRpc`` client)
-
-Methods:
-
-* trace_filter
-* trace_get
-* trace_transaction
-* trace_block
+Table of unavailable methods
+-------------------
+Since this is not a local node, the following methods are unavailable.
+
+* ~~web3_sha3~~
+* ~~eth_coinbase~~
+* ~~eth_sign~~
+* ~~eth_sendTransaction~~
+* ~~eth_compileSolidity~~
+* ~~eth_compileLLL~~
+* ~~eth_compileSerpent~~
+* ~~eth_newFilter~~
+* ~~eth_newBlockFilter~~
+* ~~eth_newPendingTransactionFilter~~
+* ~~eth_uninstallFilter~~
+* ~~eth_getFilterChanges~~
+* ~~eth_getFilterLogs~~
+* ~~db_putString~~
+* ~~db_getString~~
+* ~~db_putHex~~
+* ~~db_getHex~~
+* ~~shh_version~~
+* ~~shh_post~~
+* ~~shh_newIdentity~~
+* ~~shh_hasIdentity~~
+* ~~shh_newGroup~~
+* ~~shh_addToGroup~~
+* ~~shh_newFilter~~
+* ~~shh_uninstallFilter~~
+* ~~shh_getFilterChanges~~
+* ~~shh_getMessages~~
Reference
---------
+* https://blog.infura.io/getting-started-with-infura-28e41844cc89
* https://github.com/ethereum/wiki/wiki/JSON-RPC
* https://github.com/ethcore/parity/wiki/JSONRPC-trace-module
+
diff --git a/ethjsonrpc/__init__.py b/ethjsonrpc/__init__.py
index 1813aae..df09920 100644
--- a/ethjsonrpc/__init__.py
+++ b/ethjsonrpc/__init__.py
@@ -1,8 +1,8 @@
-from ethjsonrpc.client import (EthJsonRpc, ParityEthJsonRpc,
+from ethjsonrpc.client import (EthJsonRpc, ParityEthJsonRpc, InfuraEthJsonRpc,
ETH_DEFAULT_RPC_PORT, GETH_DEFAULT_RPC_PORT,
PYETHAPP_DEFAULT_RPC_PORT)
-from ethjsonrpc.exceptions import (ConnectionError, BadStatusCodeError,
+from ethjsonrpc.exceptions import (ConnectionError, BadStatusCodeError, BadMethodError,
BadJsonError, BadResponseError)
from ethjsonrpc.utils import wei_to_ether, ether_to_wei
diff --git a/ethjsonrpc/client.py b/ethjsonrpc/client.py
index 89a9edb..73be1b8 100644
--- a/ethjsonrpc/client.py
+++ b/ethjsonrpc/client.py
@@ -10,7 +10,7 @@
from ethjsonrpc.constants import BLOCK_TAGS, BLOCK_TAG_LATEST
from ethjsonrpc.utils import hex_to_dec, clean_hex, validate_block
from ethjsonrpc.exceptions import (ConnectionError, BadStatusCodeError,
- BadJsonError, BadResponseError)
+ BadJsonError, BadResponseError, BadMethodError)
GETH_DEFAULT_RPC_PORT = 8545
ETH_DEFAULT_RPC_PORT = 8545
@@ -18,6 +18,9 @@
PYETHAPP_DEFAULT_RPC_PORT = 4000
MAX_RETRIES = 3
JSON_MEDIA_TYPE = 'application/json'
+DEFAULT_NODE = 'local'
+DEFAULT_INFURA_NETWORK = 'mainnet'
+DEFAULT_INFURA_TOKEN = ""
class EthJsonRpc(object):
@@ -26,31 +29,38 @@ class EthJsonRpc(object):
'''
DEFAULT_GAS_PER_TX = 90000
- DEFAULT_GAS_PRICE = 50 * 10**9 # 50 gwei
+ DEFAULT_GAS_PRICE = 50 * 10 ** 9 # 50 gwei
- def __init__(self, host='localhost', port=GETH_DEFAULT_RPC_PORT, tls=False):
+ def __init__(self, host='localhost', port=GETH_DEFAULT_RPC_PORT, tls=False, node=DEFAULT_NODE):
self.host = host
self.port = port
self.tls = tls
+
self.session = requests.Session()
self.session.mount(self.host, HTTPAdapter(max_retries=MAX_RETRIES))
+ scheme = 'http'
+ if self.tls:
+ scheme += 's'
+
+ if node == 'local':
+ self.url = '{}://{}:{}'.format(scheme, self.host, self.port)
+ elif node == 'infura':
+ self.url = '{}://{}'.format(scheme, self.host)
+
def _call(self, method, params=None, _id=1):
params = params or []
data = {
'jsonrpc': '2.0',
- 'method': method,
- 'params': params,
- 'id': _id,
+ 'method': method,
+ 'params': params,
+ 'id': _id,
}
- scheme = 'http'
- if self.tls:
- scheme += 's'
- url = '{}://{}:{}'.format(scheme, self.host, self.port)
+
headers = {'Content-Type': JSON_MEDIA_TYPE}
try:
- r = self.session.post(url, headers=headers, data=json.dumps(data))
+ r = self.session.post(self.url, headers=headers, data=json.dumps(data))
except RequestsConnectionError:
raise ConnectionError
if r.status_code / 100 != 2:
@@ -78,9 +88,9 @@ def _encode_function(self, signature, param_values):
encoded_params = encode_abi(types, param_values)
return utils.zpad(utils.encode_int(prefix), 4) + encoded_params
-################################################################################
-# high-level methods
-################################################################################
+ ################################################################################
+ # high-level methods
+ ################################################################################
def transfer(self, from_, to, amount):
'''
@@ -95,9 +105,9 @@ def create_contract(self, from_, code, gas, sig=None, args=None):
'''
from_ = from_ or self.eth_coinbase()
if sig is not None and args is not None:
- types = sig[sig.find('(') + 1: sig.find(')')].split(',')
- encoded_params = encode_abi(types, args)
- code += encoded_params.encode('hex')
+ types = sig[sig.find('(') + 1: sig.find(')')].split(',')
+ encoded_params = encode_abi(types, args)
+ code += encoded_params.encode('hex')
return self.eth_sendTransaction(from_address=from_, gas=gas, data=code)
def get_contract_address(self, tx):
@@ -129,9 +139,9 @@ def call_with_transaction(self, from_, address, sig, args, gas=None, gas_price=N
return self.eth_sendTransaction(from_address=from_, to_address=address, data=data_hex, gas=gas,
gas_price=gas_price, value=value)
-################################################################################
-# JSON-RPC methods
-################################################################################
+ ################################################################################
+ # JSON-RPC methods
+ ################################################################################
def web3_clientVersion(self):
'''
@@ -506,9 +516,9 @@ def eth_newFilter(self, from_block=BLOCK_TAG_LATEST, to_block=BLOCK_TAG_LATEST,
'''
_filter = {
'fromBlock': from_block,
- 'toBlock': to_block,
- 'address': address,
- 'topics': topics,
+ 'toBlock': to_block,
+ 'address': address,
+ 'topics': topics,
}
return self._call('eth_newFilter', [_filter])
@@ -637,12 +647,12 @@ def shh_post(self, topics, payload, priority, ttl, from_=None, to=None):
NEEDS TESTING
'''
whisper_object = {
- 'from': from_,
- 'to': to,
- 'topics': topics,
- 'payload': payload,
+ 'from': from_,
+ 'to': to,
+ 'topics': topics,
+ 'payload': payload,
'priority': hex(priority),
- 'ttl': hex(ttl),
+ 'ttl': hex(ttl),
}
return self._call('shh_post', [whisper_object])
@@ -685,7 +695,7 @@ def shh_newFilter(self, to, topics):
NEEDS TESTING
'''
_filter = {
- 'to': to,
+ 'to': to,
'topics': topics,
}
return self._call('shh_newFilter', [_filter])
@@ -714,14 +724,13 @@ def shh_getMessages(self, filter_id):
'''
return self._call('shh_getMessages', [filter_id])
-
class ParityEthJsonRpc(EthJsonRpc):
'''
EthJsonRpc subclass for Parity-specific methods
'''
def __init__(self, host='localhost', port=PARITY_DEFAULT_RPC_PORT, tls=False):
- EthJsonRpc.__init__(self, host=host, port=port, tls=tls)
+ EthJsonRpc.__init__(self, host=host, port=port, tls=tls, node=DEFAULT_NODE)
def trace_filter(self, from_block=None, to_block=None, from_addresses=None, to_addresses=None):
'''
@@ -772,3 +781,133 @@ def trace_block(self, block=BLOCK_TAG_LATEST):
'''
block = validate_block(block)
return self._call('trace_block', [block])
+
+ def trace_replayTransaction(self, tx_hash, mode='trace'):
+ '''
+ https://wiki.parity.io/JSONRPC-trace-module.html#trace_replaytransaction
+
+ NEEDS TESTING
+ '''
+ return self._call(method='trace_replayTransaction', params=[tx_hash,
+ [mode]])
+
+ def trace_replayBlockTransactions(self, block=BLOCK_TAG_LATEST, mode='trace'):
+ '''
+ https://wiki.parity.io/JSONRPC-trace-module.html#trace_replayblocktransactions
+
+ NEEDS TESTING
+ '''
+ block = validate_block(block)
+ return self._call(method='trace_replayBlockTransactions',
+ params=[block, [mode]])
+
+
+class InfuraEthJsonRpc(EthJsonRpc):
+ '''
+ EthJsonRpc subclass for Infura-specific methods
+ '''
+ def __init__(self, network=DEFAULT_INFURA_NETWORK, infura_token=DEFAULT_INFURA_TOKEN, tls=True):
+ if infura_token:
+ host = '{}.infura.io/{}'.format(network, infura_token)
+ else:
+ host = '{}.infura.io'.format(network)
+
+ EthJsonRpc.__init__(self, host=host, tls=tls, node='infura')
+
+ # methods to disable unavailable functions
+ def call(self, address, sig, args, result_types):
+ raise BadMethodError()
+
+ def call_with_transaction(self, from_, address, sig, args, gas=None, gas_price=None, value=None):
+ raise BadMethodError()
+
+ def create_contract(self, from_, code, gas, sig=None, args=None):
+ raise BadMethodError()
+
+ def transfer(self, from_, to, amount):
+ raise BadMethodError()
+
+ def web3_sha3(self, data):
+ raise BadMethodError()
+
+ def eth_coinbase(self):
+ raise BadMethodError()
+
+ def eth_sign(self, address, data):
+ raise BadMethodError()
+
+ def eth_sendTransaction(self, to_address=None, from_address=None, gas=None, gas_price=None, value=None, data=None,
+ nonce=None):
+ raise BadMethodError()
+
+ def eth_compileSolidity(self, code):
+ raise BadMethodError()
+
+ def eth_compileLLL(self, code):
+ raise BadMethodError()
+
+ def eth_compileSerpent(self, code):
+ raise BadMethodError()
+
+ def eth_newFilter(self, from_block=BLOCK_TAG_LATEST, to_block=BLOCK_TAG_LATEST, address=None, topics=None):
+ raise BadMethodError()
+
+ def eth_newBlockFilter(self):
+ raise BadMethodError()
+
+ def eth_newPendingTransactionFilter(self):
+ raise BadMethodError()
+
+ def eth_uninstallFilter(self, filter_id):
+ raise BadMethodError()
+
+ def eth_getFilterChanges(self, filter_id):
+ raise BadMethodError()
+
+ def eth_getFilterLogs(self, filter_id):
+ raise BadMethodError()
+
+ def db_putString(self, db_name, key, value):
+ raise BadMethodError()
+
+ def db_getString(self, db_name, key):
+ raise BadMethodError()
+
+ def db_putHex(self, db_name, key, value):
+ raise BadMethodError()
+
+ def db_getHex(self, db_name, key):
+ raise BadMethodError()
+
+ def shh_version(self):
+ raise BadMethodError()
+
+ def shh_post(self, topics, payload, priority, ttl, from_=None, to=None):
+ raise BadMethodError()
+
+ def shh_newIdentity(self):
+ raise BadMethodError()
+
+ def shh_hasIdentity(self, address):
+ raise BadMethodError()
+
+ def shh_newGroup(self):
+ raise BadMethodError()
+
+ def shh_addToGroup(self):
+ raise BadMethodError()
+
+ def shh_newFilter(self, to, topics):
+ raise BadMethodError()
+
+ def shh_uninstallFilter(self, filter_id):
+ raise BadMethodError()
+
+ def shh_getFilterChanges(self, filter_id):
+ raise BadMethodError()
+
+ def shh_getMessages(self, filter_id):
+ raise BadMethodError()
+
+ def eth_getCompilers(self):
+ raise BadMethodError()
diff --git a/ethjsonrpc/exceptions.py b/ethjsonrpc/exceptions.py
index 05e70ba..6ce6dad 100644
--- a/ethjsonrpc/exceptions.py
+++ b/ethjsonrpc/exceptions.py
@@ -16,3 +16,6 @@ class BadJsonError(EthJsonRpcError):
class BadResponseError(EthJsonRpcError):
pass
+
+class BadMethodError(EthJsonRpcError):
+ pass
\ No newline at end of file
diff --git a/test.py b/test.py
index 3518e88..acbef85 100644
--- a/test.py
+++ b/test.py
@@ -1,4 +1,4 @@
-from ethjsonrpc import EthJsonRpc
+from ethjsonrpc import InfuraEthJsonRpc
methods = [
'web3_clientVersion',
@@ -7,21 +7,20 @@
'net_listening',
'eth_protocolVersion',
'eth_syncing',
- 'eth_coinbase',
'eth_mining',
'eth_hashrate',
'eth_gasPrice',
'eth_accounts',
'eth_blockNumber',
- 'eth_getCompilers',
- 'eth_newPendingTransactionFilter',
- 'eth_getWork',
+# 'eth_getCompilers',
+# 'eth_newPendingTransactionFilter',
+# 'eth_getWork',
# 'shh_version',
# 'shh_newIdentity',
# 'shh_newGroup',
]
-c = EthJsonRpc()
+c = InfuraEthJsonRpc()
print len(methods)
for m in methods:
meth = getattr(c, m)
@@ -44,7 +43,6 @@
result = c.eth_getBlockTransactionCountByNumber(x)
print 'eth_getBlockTransactionCountByNumber: %s (%s)' % (result, type(result))
-
b = (199583, '0x19d761c6f944eefe91ad70b9aff3d2d76c972e5bb68c443eea7c0eaa144cef9f')
result = c.eth_getUncleCountByBlockHash(b[1])
print 'eth_getUncleCountByBlockHash: %s (%s)' % (result, type(result))
@@ -56,25 +54,6 @@
################################################################################
print '*' * 80
-db_name = 'db_name'
-k = 'my_key'
-v = 'my_value'
-print c.db_putString(db_name, k, v)
-x = c.db_getString(db_name, k)
-print x
-assert v == x
-
-db_name = 'db_name'
-k = 'my_key'
-v = '0xabcdef'
-print c.db_putHex(db_name, k, v)
-x = c.db_getHex(db_name, k)
-print x
-assert v == x
-
-################################################################################
-print '*' * 80
-
b = (199583, '0x19d761c6f944eefe91ad70b9aff3d2d76c972e5bb68c443eea7c0eaa144cef9f')
print c.eth_getBlockByHash(b[1], tx_objects=False)
@@ -87,18 +66,6 @@
################################################################################
print '*' * 80
-code = 'contract Test {}'
-print c.eth_compileSolidity(code)
-
-#code = ''
-#print c.eth_compileSerpent(code)
-
-#code = ''
-#print c.eth_compileLLL(code)
-
-################################################################################
-print '*' * 80
-
b = (246236, '0xcd43703a1ead33ffa1f317636c7b67453c5cc03a3350cd71dbbdd70fcbe0987a')
index = 2
print c.eth_getTransactionByBlockHashAndIndex(b[1], index)
@@ -134,7 +101,3 @@
client_id = '0x59daa26581d0acd1fce254fb7e85952f4c09d0915afd33d3886cd914bc7d283c'
print c.eth_submitHashrate(hash_rate, client_id)
-digest = c.web3_sha3('')
-print digest
-# keccak-256, not sha3-256
-assert digest == '0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470'