def call(self, _from, to, value, name, params, label, assertion, abi): reference = to to = self.replace_references(to) if not name: name = abi['name'] abi = self.abis[to] if to in self.abis else [abi] translator = ContractTranslator(abi) data = encode(translator.encode(name, self.replace_references(params)), 'hex') response = self.json_rpc.eth_call( self.add_0x(to), from_address=self.add_0x(_from if _from else self._from), value=value, data=self.add_0x(data), gas=self.gas, gas_price=self.gas_price) result = translator.decode( name, decode(self.strip_0x(response['result']), 'hex')) result = result if len(result) > 1 else result[0] if label: self.references[label] = result if assertion: expected_result = self.replace_references(assertion) if isinstance(expected_result, int) or isinstance( expected_result, long): assert result == expected_result else: assert result.lower() == self.strip_0x(expected_result.lower()) self.log('Assertion of {} at {} successful'.format( name, self.format_reference(reference))) else: self.log('Call to {} calling function {} successful'.format( self.format_reference(reference), name))
def assert_call(self, contract, name, params, return_value): contract_address = self.replace_address(contract) return_value = self.replace_address(return_value) contract_abi = self.contract_abis[contract] translator = ContractTranslator(contract_abi) data = "0x" + translator.encode( name, [self.replace_address(p) for p in params]).encode("hex") logging.info('Try to assert return value of {} in contract {}.'.format( name, contract)) response = self.json_rpc.eth_call(from_address=self.user_address, to_address=contract_address, data=data) bc_return_val = response["result"] result_decoded = translator.decode(name, bc_return_val[2:].decode("hex")) result_decoded = result_decoded if len( result_decoded) > 1 else result_decoded[0] if isinstance(return_value, int) or isinstance(return_value, long): assert result_decoded == return_value else: assert result_decoded.lower() == self.strip_0x( return_value.lower()) logging.info( 'Assertion successful for return value of {} in contract {}.'. format(name, contract))
def call_const_function(priv_key, value, contract_hash, contract_abi, function_name, args): src_address = b2h(utils.privtoaddr(priv_key)) translator = ContractTranslator(contract_abi) call = translator.encode_function_call(function_name, args) nonce = get_num_transactions(src_address) gas_price = get_gas_price_in_wei() start_gas = eval_startgas(src_address, contract_hash, value, b2h(call), gas_price) nonce = int(nonce, 16) gas_price = int(gas_price, 16) start_gas = int(start_gas, 16) + 100000 params = { "from": "0x" + src_address, "to": "0x" + contract_hash, "gas": "0x" + str(start_gas), "gasPrice": "0x" + str(gas_price), "value": str(value), "data": "0x" + b2h(call) } return_value = json_call("eth_call", [params]) return_value = h2b(return_value[2:]) # remove 0x return translator.decode(function_name, return_value)
def do_assertion(json_rpc, contract, name, params, return_value): contract_address = addresses[ contract] if contract in addresses else contract return_value = addresses[ return_value] if return_value in addresses else return_value contract_abi = abis[contract] translator = ContractTranslator(contract_abi) data = translator.encode(name, [ addresses[param] if param in addresses else param for param in params ]).encode("hex") print 'Try to assert return value of {} in contract {}.'.format( name, contract) bc_return_val = json_rpc.eth_call(to_address=contract_address, data=data)["result"] result_decoded = translator.decode(name, bc_return_val[2:].decode("hex")) result_decoded = result_decoded if len( result_decoded) > 1 else result_decoded[0] assert result_decoded == return_value[2:]
def assert_call(self, contract, name, params, return_value): contract_address = self.replace_address(contract) return_value = self.replace_address(return_value) contract_abi = self.contract_abis[contract] translator = ContractTranslator(contract_abi) data = translator.encode(name, [self.replace_address(p) for p in params]).encode("hex") logging.info('Try to assert return value of {} in contract {}.'.format( name, contract)) bc_return_val = self.json_rpc.eth_call(to_address=contract_address, data=data)["result"] result_decoded = translator.decode(name, bc_return_val[2:].decode("hex")) result_decoded = result_decoded if len( result_decoded) > 1 else result_decoded[0] assert result_decoded == return_value logging.info( 'Assertion successful for return value of {} in contract {}.'. format(name, contract))
def setup(host, port, contract, gas, gas_price, private_key): gas = int(gas) gas_price = int(gas_price) json_rpc = EthJsonRpc(host, port) coinbase = json_rpc.eth_coinbase()["result"] if private_key: print "Your address for your private key: {}".format( privtoaddr(private_key.decode('hex')).encode('hex')) else: print "Your coinbase: {}".format(coinbase) contract_abi = json.loads( '[{"inputs": [], "constant": true, "type": "function", "name": "startDate", "outputs": [{"type": "uint256", "name": ""}]}, {"inputs": [], "constant": true, "type": "function", "name": "CROWDFUNDING_PERIOD", "outputs": [{"type": "uint256", "name": ""}]}, {"inputs": [], "constant": false, "type": "function", "name": "emergencyCall", "outputs": [{"type": "bool", "name": ""}]}, {"inputs": [{"type": "address", "name": "singularDTVFundAddress"}, {"type": "address", "name": "singularDTVTokenAddress"}], "constant": false, "type": "function", "name": "setup", "outputs": [{"type": "bool", "name": ""}]}, {"inputs": [], "constant": false, "type": "function", "name": "withdrawFunding", "outputs": [{"type": "bool", "name": ""}]}, {"inputs": [], "constant": true, "type": "function", "name": "fundBalance", "outputs": [{"type": "uint256", "name": ""}]}, {"inputs": [], "constant": true, "type": "function", "name": "singularDTVFund", "outputs": [{"type": "address", "name": ""}]}, {"inputs": [], "constant": true, "type": "function", "name": "baseValue", "outputs": [{"type": "uint256", "name": ""}]}, {"inputs": [], "constant": true, "type": "function", "name": "TOKEN_TARGET", "outputs": [{"type": "uint256", "name": ""}]}, {"inputs": [], "constant": true, "type": "function", "name": "singularDTVToken", "outputs": [{"type": "address", "name": ""}]}, {"inputs": [], "constant": true, "type": "function", "name": "owner", "outputs": [{"type": "address", "name": ""}]}, {"inputs": [{"type": "uint256", "name": "valueInWei"}], "constant": false, "type": "function", "name": "changeBaseValue", "outputs": [{"type": "bool", "name": ""}]}, {"inputs": [{"type": "address", "name": ""}], "constant": true, "type": "function", "name": "investments", "outputs": [{"type": "uint256", "name": ""}]}, {"inputs": [], "constant": false, "type": "function", "name": "fund", "outputs": [{"type": "uint256", "name": ""}]}, {"inputs": [], "constant": true, "type": "function", "name": "stage", "outputs": [{"type": "uint8", "name": ""}]}, {"inputs": [], "constant": false, "type": "function", "name": "updateStage", "outputs": [{"type": "uint8", "name": ""}]}, {"inputs": [], "constant": true, "type": "function", "name": "valuePerShare", "outputs": [{"type": "uint256", "name": ""}]}, {"inputs": [], "constant": true, "type": "function", "name": "TOKEN_LOCKING_PERIOD", "outputs": [{"type": "uint256", "name": ""}]}, {"inputs": [], "constant": true, "type": "function", "name": "campaignEndedSuccessfully", "outputs": [{"type": "bool", "name": ""}]}, {"inputs": [], "constant": true, "type": "function", "name": "workshopWaited2Years", "outputs": [{"type": "bool", "name": ""}]}, {"inputs": [], "constant": true, "type": "function", "name": "CAP", "outputs": [{"type": "uint256", "name": ""}]}, {"inputs": [], "constant": false, "type": "function", "name": "withdrawForWorkshop", "outputs": [{"type": "bool", "name": ""}]}, {"inputs": [], "type": "constructor"}]' ) translator = ContractTranslator(contract_abi) data = translator.encode("emergencyCall", ()).encode("hex") bc_return_val = json_rpc.eth_call(to_address=contract, data=data)["result"] result_decoded = translator.decode("emergencyCall", bc_return_val[2:].decode("hex"))[0] if result_decoded: if private_key: address = privtoaddr(private_key.decode('hex')) nonce = int( json_rpc.eth_getTransactionCount('0x' + address.encode('hex')) ["result"][2:], 16) tx = Transaction(nonce, gas_price, gas, contract, 0, data.decode('hex')) tx.sign(private_key.decode('hex')) raw_tx = rlp.encode(tx).encode('hex') transaction_hash = json_rpc.eth_sendRawTransaction( "0x" + raw_tx)["result"] else: transaction_hash = json_rpc.eth_sendTransaction( coinbase, to_address=contract, data=data, gas=gas, gas_price=gas_price)["result"] wait_for_transaction_receipt(json_rpc, transaction_hash) print 'Transaction {} for contract {} completed.'.format( "emergencyCall", contract)
def call_const_function( priv_key, value, contract_hash, contract_abi, function_name, args ): src_address = b2h( utils.privtoaddr(priv_key) ) translator = ContractTranslator(contract_abi) call = translator.encode_function_call(function_name, args) nonce = get_num_transactions( src_address ) gas_price = get_gas_price_in_wei() start_gas = eval_startgas( src_address, contract_hash, value, b2h(call), gas_price ) nonce = int( nonce, 16 ) gas_price = int( gas_price, 16 ) start_gas = int( start_gas, 16 ) + 100000 params = { "from" : "0x" + src_address, "to" : "0x" + contract_hash, "gas" : "0x" + str(start_gas), "gasPrice" : "0x" + str(gas_price), "value" : str(value), "data" : "0x" + b2h(call) } return_value = json_call( "eth_call", [params]) return_value = h2b(return_value[2:]) # remove 0x return translator.decode(function_name, return_value)
class EthJsonRpc: def __init__(self, host, port, contract_code=None, contract_address=None): self.host = host self.port = port self.contract_code = None self.signature = None self.translation = None self.contract_address = contract_address self.update_code(contract_code) def update_code(self, contract_code): if contract_code: self.contract_code = contract_code self.signature = serpent.mk_full_signature(contract_code) self.translation = ContractTranslator(self.signature) def _call(self, method, params=None, _id=0): if params is None: params = [] data = json.dumps({ 'jsonrpc': '2.0', 'method': method, 'params': params, 'id': _id }) response = requests.post("http://{}:{}".format(self.host, self.port), data=data).json() return response def create_contract(self, contract_code, value=0, from_address=None, gas=0, gas_price=0): self.update_code(contract_code) byte_code = serpent.compile(contract_code) self.contract_address = self.eth_sendTransaction( data=byte_code, value=value, from_address=from_address, gas=gas, gas_price=gas_price) return self.contract_address def eth_sendTransaction(self, to_address=None, function_name=None, data=None, value=0, from_address=None, gas=0, gas_price=0, code=None): """ Creates new message call transaction or a contract creation, if the data field contains code. """ if code: self.update_code(code) else: self.update_code(self.eth_getCode(to_address)) if function_name: if data is None: data = [] data = self.translation.encode(function_name, data) params = { 'from': from_address, 'to': to_address, 'gas': hex(gas) if gas else None, 'gasPrice': hex(gas_price) if gas_price else None, 'value': hex(value) if value else None, 'data': '0x{}'.format(data.encode('hex')) if data else None } return self._call('eth_sendTransaction', [params]) def eth_call(self, to_address, function_name, data=None, code=None, default_block="latest"): """ Executes a new message call immediately without creating a transaction on the block chain. """ if code: self.update_code(code) else: self.update_code(self.eth_getCode(to_address)) if data is None: data = [] data = self.translation.encode(function_name, data) params = [{ 'to': to_address, 'data': '0x{}'.format(data.encode('hex')) }, default_block] response = self._call('eth_call', params) if function_name: response = self.translation.decode(function_name, response[2:].decode('hex')) return response def web3_clientVersion(self): """ Returns the current client version. """ return self._call('web3_clientVersion') def web3_sha3(self, data): """ Returns SHA3 of the given data. """ data = str(data).encode('hex') return self._call('web3_sha3', [data]) def net_version(self): """ Returns the current network protocol version. """ return self._call('net_version') def net_listening(self): """ Returns true if client is actively listening for network connections. """ return self._call('net_listening') def net_peerCount(self): """ Returns number of peers currenly connected to the client. """ return self._call('net_peerCount') def eth_version(self): """ Returns the current ethereum protocol version. """ return self._call('eth_version') def eth_coinbase(self): """ Returns the client coinbase address. """ return self._call('eth_coinbase') def eth_mining(self): """ Returns true if client is actively mining new blocks. """ return self._call('eth_mining') def eth_gasPrice(self): """ Returns the current price per gas in wei. """ return self._call('eth_gasPrice') def eth_accounts(self): """ Returns a list of addresses owned by client. """ return self._call('eth_accounts') def eth_blockNumber(self): """ Returns the number of most recent block. """ return self._call('eth_blockNumber') def eth_getBalance(self, address, default_block="latest"): """ Returns the balance of the account of given address. """ return self._call('eth_getBalance', [address, default_block]) def eth_getStorageAt(self, address, position, default_block="latest"): """ Returns the value from a storage position at a given address. """ return self._call('eth_getStorageAt', [address, hex(position), default_block]) def eth_getTransactionCount(self, address, default_block="latest"): """ Returns the number of transactions send from a address. """ return self._call('eth_getTransactionCount', [address, default_block]) def eth_getBlockTransactionCountByHash(self, block_hash): """ Returns the number of transactions in a block from a block matching the given block hash. """ return self._call('eth_getTransactionCount', [block_hash]) def eth_getBlockTransactionCountByNumber(self, block_number): """ Returns the number of transactions in a block from a block matching the given block number. """ return self._call('eth_getBlockTransactionCountByNumber', [hex(block_number)]) def eth_getUncleCountByblockHash(self, block_hash): """ Returns the number of uncles in a block from a block matching the given block hash. """ return self._call('eth_getUncleCountByblockHash', [block_hash]) def eth_getUncleCountByblockNumber(self, block_number): """ Returns the number of uncles in a block from a block matching the given block number. """ return self._call('eth_getUncleCountByblockNumber', [hex(block_number)]) def eth_getCode(self, address, default_block="latest"): """ Returns code at a given address. """ return self._call('eth_getCode', [address, default_block]) def eth_getBlockByHash(self, block_hash, transaction_objects=True): """ Returns information about a block by hash. """ return self._call('eth_getBlockByHash', [block_hash, transaction_objects]) def eth_flush(self): """ """ return self._call('eth_flush') def eth_getBlockByNumber(self, block_number, transaction_objects=True): """ Returns information about a block by hash. """ return self._call('eth_getBlockByNumber', [block_number, transaction_objects]) def eth_getTransactionByHash(self, transaction_hash): """ Returns the information about a transaction requested by transaction hash. """ return self._call('eth_getTransactionByHash', [transaction_hash]) def eth_getTransactionByblockHashAndIndex(self, block_hash, index): """ Returns information about a transaction by block hash and transaction index position. """ return self._call('eth_getTransactionByblock_hashAndIndex', [block_hash, hex(index)]) def eth_getTransactionByblockNumberAndIndex(self, block_number, index): """ Returns information about a transaction by block number and transaction index position. """ return self._call('eth_getTransactionByblock_numberAndIndex', [block_number, hex(index)]) def eth_getUncleByblockHashAndIndex(self, block_hash, index, transaction_objects=True): """ Returns information about a uncle of a block by hash and uncle index position. """ return self._call( 'eth_getUncleByblock_hashAndIndex', [block_hash, hex(index), transaction_objects]) def eth_getUncleByblockNumberAndIndex(self, block_number, index, transaction_objects=True): """ Returns information about a uncle of a block by number and uncle index position. """ return self._call( 'eth_getUncleByblock_numberAndIndex', [block_number, hex(index), transaction_objects]) def eth_getCompilers(self): """ Returns a list of available compilers in the client. """ return self._call('eth_getCompilers') def eth_compileSolidity(self, code): """ Returns compiled solidity code. """ return self._call('eth_compileSolidity', [code]) def eth_compileLLL(self, code): """ Returns compiled LLL code. """ return self._call('eth_compileLLL', [code]) def eth_compileSerpent(self, code): """ Returns compiled serpent code. """ return self._call('eth_compileSerpent', [code]) def eth_newFilter(self, from_block="latest", to_block="latest", address=None, topics=None): """ Creates a filter object, based on filter options, to notify when the state changes (logs). To check if the state has changed, call eth_getFilterChanges. """ _filter = { 'fromBlock': from_block, 'toBlock': to_block, 'address': address, 'topics': topics } return self._call('eth_newFilter', [_filter]) def eth_newBlockFilter(self, default_block="latest"): """ Creates a filter object, based on an option string, to notify when state changes (logs). To check if the state has changed, call eth_getFilterChanges. """ return self._call('eth_newBlockFilter', [default_block]) def eth_uninstallFilter(self, filter_id): """ Uninstalls a filter with given id. Should always be called when watch is no longer needed. Additonally Filters timeout when they aren't requested with eth_getFilterChanges for a period of time. """ return self._call('eth_uninstallFilter', [hex(filter_id)]) def eth_getFilterChanges(self, filter_id): """ Polling method for a filter, which returns an array of logs which occurred since last poll. """ return self._call('eth_getFilterChanges', [hex(filter_id)]) def eth_getFilterLogs(self, filter_id): """ Returns an array of all logs matching filter with given id. """ return self._call('eth_getFilterLogs', [hex(filter_id)]) def eth_getLogs(self, filter_object): """ Returns an array of all logs matching a given filter object. """ return self._call('eth_getLogs', [filter_object]) def eth_getWork(self): """ Returns the hash of the current block, the seedHash, and the difficulty to be met. """ return self._call('eth_getWork') def eth_submitWork(self, nonce, header, mix_digest): """ Used for submitting a proof-of-work solution. """ return self._call('eth_submitWork', [nonce, header, mix_digest]) def db_putString(self, database_name, key_name, string): """ Stores a string in the local database. """ return self._call('db_putString', [database_name, key_name, string]) def db_getString(self, database_name, key_name): """ Stores a string in the local database. """ return self._call('db_getString', [database_name, key_name]) def db_putHex(self, database_name, key_name, string): """ Stores binary data in the local database. """ return self._call('db_putHex', [database_name, key_name, string.encode('hex')]) def db_getHex(self, database_name, key_name): """ Returns binary data from the local database. """ return self._call('db_getString', [database_name, key_name]).decode('hex') def shh_version(self): """ Returns the current whisper protocol version. """ return self._call('shh_version') def shh_post(self, topics, payload, priority, ttl, _from=None, to=None): """ Sends a whisper message. """ whisper_object = { 'from': _from, 'to': to, 'topics': topics, 'payload': payload, 'priority': priority, 'ttl': ttl } return self._call('shh_post', [whisper_object]) def shh_newIdentinty(self): """ Creates new whisper identity in the client. """ return self._call('shh_newIdentinty') def shh_hasIdentity(self, address): """ Checks if the client hold the private keys for a given identity. """ return self._call('shh_hasIdentity', [address]) def shh_newGroup(self): """ """ return self._call('shh_hasIdentity') def shh_addToGroup(self): """ """ return self._call('shh_addToGroup') def shh_newFilter(self, to, topics): """ Creates filter to notify, when client receives whisper message matching the filter options. """ _filter = {'to': to, 'topics': topics} return self._call('shh_newFilter', [_filter]) def shh_uninstallFilter(self, filter_id): """ Uninstalls a filter with given id. Should always be called when watch is no longer needed. Additonally Filters timeout when they aren't requested with shh_getFilterChanges for a period of time. """ return self._call('shh_uninstallFilter', [hex(filter_id)]) def shh_getFilterChanges(self, filter_id): """ Polling method for whisper filters. """ return self._call('shh_getFilterChanges', [hex(filter_id)]) def shh_getMessages(self, filter_id): """ Get all messages matching a filter, which are still existing in the node. """ return self._call('shh_getMessages', [hex(filter_id)])
class EthJsonRpc(object): DEFAULT_GAS_FOR_TRANSACTIONS = 500000 DEFAULT_GAS_PRICE = 10 * 10 ** 12 # 10 szabo def __init__( self, host="localhost", port=GETH_DEFAULT_RPC_PORT, tls=False, contract_code=None, contract_address=None ): self.host = host self.port = port self.tls = tls self.contract_code = None self.signature = None self.translation = None self.contract_address = contract_address self.update_code(contract_code) self.compilers = {} try: import serpent self.compilers["serpent"] = serpent.compile self.compilers["lll"] = serpent.compile_lll except ImportError: print '[WARNING] Could not import module "serpent". Compiler will not be available.' try: import solidity self.compilers["solidity"] = solidity.compile except ImportError: try: from ethereum._solidity import solc_wrapper self.compilers["solidity"] = solc_wrapper.compile except ImportError: print '[WARNING] Could not import module "solidity" or "solc_wrapper". Compiler will not be available.' def update_code(self, contract_code): if contract_code: self.contract_code = contract_code self.signature = serpent.mk_full_signature(contract_code) self.translation = ContractTranslator(self.signature) def _call(self, method, params=None, _id=0): params = params or [] data = json.dumps({"jsonrpc": "2.0", "method": method, "params": params, "id": _id}) scheme = "http" if self.tls: scheme += "s" url = "{}://{}:{}".format(scheme, self.host, self.port) response = requests.post(url, data=data).json() if "result" in response: return response["result"] else: raise RuntimeError("Error from RPC call. Returned payload: {0}".format(response)) def _encode_function(self, signature, param_values): prefix = utils.big_endian_to_int(utils.sha3(signature)[:4]) if signature.find("(") == -1: raise RuntimeError('Invalid function signature. Missing "(" and/or ")"...') if signature.find(")") - signature.find("(") == 1: return utils.encode_int(prefix) types = signature[signature.find("(") + 1 : signature.find(")")].split(",") encoded_params = encode_abi(types, param_values) return utils.zpad(utils.encode_int(prefix), 4) + encoded_params def _install_contract(self, language, contract_code, value=0, from_address=None, gas=None, gas_price=None): byte_code = self.compilers[language](contract_code) return self.eth_sendTransaction( data=byte_code, value=value, from_address=from_address, gas=gas, gas_price=gas_price ) def install_solidity_contract(self, contract_code, value=0, from_address=None, gas=None, gas_price=None): """ Installs a solidity contract into ethereum node """ return self._install_contract("solidity", contract_code, value, from_address, gas, gas_price) def install_serpent_contract(self, contract_code, value=0, from_address=None, gas=None, gas_price=None): """ Installs a serpent contract into ethereum node """ return self._install_contract("serpent", contract_code, value, from_address, gas, gas_price) def install_lll_contract(self, contract_code, value=0, from_address=None, gas=None, gas_price=None): """ Installs a lll contract into ethereum node """ return self._install_contract("lll", contract_code, value, from_address, gas, gas_price) def contract_instant_call( self, to_address, function_signature, function_parameters=None, result_types=None, default_block=BLOCK_TAG_LATEST, ): """ This method makes a instant call on a contract function without the need to have the contract source code. Examples of function_signature in solidity: mult(uint x, uint y) => sig: mult(uint256,uint256) (all uint should be transformed to uint256) setAddress(address entity_address) => sig:setAddress(address) doSomething() => sig: doSomething() (functions with no parameters must end with the '()') In serpent, all functions parameter signatures are int256. Example: setXYZ(x, y, z) => sig: setXYZ(int256,int256,int256) """ data = self._encode_function(function_signature, function_parameters) params = [{"to": to_address, "data": "0x{0}".format(data.encode("hex"))}, default_block] response = self._call("eth_call", params) return decode_abi(result_types, response[2:].decode("hex")) def contract_transaction_call( self, to_address, function_signature, function_parameters=None, from_address=None, gas=None, gas_price=None, default_block=BLOCK_TAG_LATEST, ): """ This method makes a call on a contract function through a transaction. Returns the transaction_id. Examples of function_signature in solidity: mult(uint x, uint y) => sig: mult(uint256,uint256) (all uint should be transformed to uint256) setAddress(address entity_address) => sig:setAddress(address) doSomething() => sig: doSomething() (functions with no parameters must end with the '()') In serpent, all functions parameter signatures are int256. Example: setXYZ(x, y, z) => sig: setXYZ(int256,int256,int256) """ # Default values for gas and gas_price gas = gas or self.DEFAULT_GAS_FOR_TRANSACTIONS gas_price = gas_price or self.DEFAULT_GAS_PRICE # Default value for from_address from_address = from_address or self.eth_accounts()[0] data = self._encode_function(function_signature, function_parameters) params = { "from": from_address, "to": to_address, "gas": "0x{0:x}".format(gas), "gasPrice": "0x{0:x}".format(gas_price), "value": None, "data": "0x{0}".format(data.encode("hex")) if data else None, } response = self._call("eth_sendTransaction", [params]) return response def create_contract(self, contract_code, value=0, from_address=None, gas=None, gas_price=None): self.update_code(contract_code) byte_code = serpent.compile(contract_code) self.contract_address = self.eth_sendTransaction( data=byte_code, value=value, from_address=from_address, gas=gas, gas_price=gas_price ) return self.contract_address ################################################################################ def web3_clientVersion(self): """ https://github.com/ethereum/wiki/wiki/JSON-RPC#web3_clientversion TESTED """ return self._call("web3_clientVersion") def web3_sha3(self, data): """ https://github.com/ethereum/wiki/wiki/JSON-RPC#web3_sha3 """ data = str(data).encode("hex") return self._call("web3_sha3", [data]) def net_version(self): """ https://github.com/ethereum/wiki/wiki/JSON-RPC#net_version TESTED """ return self._call("net_version") def net_peerCount(self): """ https://github.com/ethereum/wiki/wiki/JSON-RPC#net_peercount TESTED """ return hex_to_int(self._call("net_peerCount")) def net_listening(self): """ https://github.com/ethereum/wiki/wiki/JSON-RPC#net_listening TESTED """ return self._call("net_listening") def eth_protocolVersion(self): """ https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_protocolversion TESTED """ return self._call("eth_protocolVersion") def eth_coinbase(self): """ https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_coinbase TESTED """ return self._call("eth_coinbase") def eth_mining(self): """ https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_mining TESTED """ return self._call("eth_mining") def eth_hashrate(self): """ https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_hashrate TESTED """ return hex_to_int(self._call("eth_hashrate")) def eth_gasPrice(self): """ https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_gasprice TESTED """ return hex_to_int(self._call("eth_gasPrice")) def eth_accounts(self): """ https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_accounts TESTED """ return self._call("eth_accounts") def eth_blockNumber(self): """ https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_blocknumber TESTED """ return hex_to_int(self._call("eth_blockNumber")) def eth_getBalance(self, address=None, default_block=BLOCK_TAG_LATEST): """ https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_getbalance """ if isinstance(default_block, basestring): if default_block not in BLOCK_TAGS: raise ValueError address = address or self.eth_coinbase() return self._call("eth_getBalance", [address, default_block]) def eth_getStorageAt(self, address, position, default_block=BLOCK_TAG_LATEST): """ https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_getstorageat """ if isinstance(default_block, basestring): if default_block not in BLOCK_TAGS: raise ValueError return self._call("eth_getStorageAt", [address, hex(position), default_block]) def eth_getTransactionCount(self, address, block=BLOCK_TAG_LATEST): """ https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_gettransactioncount TESTED """ block = validate_block(block) return hex_to_int(self._call("eth_getTransactionCount", [address, block])) def eth_getBlockTransactionCountByHash(self, block_hash): """ https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_getblocktransactioncountbyhash TESTED """ return hex_to_int(self._call("eth_getBlockTransactionCountByHash", [block_hash])) def eth_getBlockTransactionCountByNumber(self, block=BLOCK_TAG_LATEST): """ https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_getblocktransactioncountbynumber TESTED """ block = validate_block(block) return hex_to_int(self._call("eth_getBlockTransactionCountByNumber", [block])) def eth_getUncleCountByBlockHash(self, block_hash): """ https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_getunclecountbyblockhash TESTED """ return hex_to_int(self._call("eth_getUncleCountByBlockHash", [block_hash])) def eth_getUncleCountByBlockNumber(self, block=BLOCK_TAG_LATEST): """ https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_getunclecountbyblocknumber TESTED """ block = validate_block(block) return hex_to_int(self._call("eth_getUncleCountByBlockNumber", [block])) def eth_getCode(self, address, default_block=BLOCK_TAG_LATEST): """ https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_getcode """ if isinstance(default_block, basestring): if default_block not in BLOCK_TAGS: raise ValueError return self._call("eth_getCode", [address, default_block]) def eth_sign(self, address, data): """ https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_sign """ return self._call("eth_sign", [address, data]) def eth_sendTransaction( self, to_address=None, function_name=None, data=None, value=0, from_address=None, gas=None, gas_price=None ): """ https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_sendtransaction """ # Default values for gas and gas_price gas = gas or self.DEFAULT_GAS_FOR_TRANSACTIONS gas_price = gas_price or self.DEFAULT_GAS_PRICE # Default value for from_address from_address = from_address or self.eth_accounts()[0] if function_name: if data is None: data = [] data = self.translation.encode(function_name, data) params = { "from": from_address, "to": to_address, "gas": "0x{0:x}".format(gas), "gasPrice": "0x{0:x}".format(gas_price), "value": "0x{0:x}".format(value) if value else None, "data": "0x{0}".format(data.encode("hex")) if data else None, } return self._call("eth_sendTransaction", [params]) def eth_call(self, to_address, function_name, data=None, code=None, default_block=BLOCK_TAG_LATEST): """ https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_call """ if isinstance(default_block, basestring): if default_block not in BLOCK_TAGS: raise ValueError data = data or [] data = self.translation.encode(function_name, data) params = [{"to": to_address, "data": "0x{0}".format(data.encode("hex"))}, default_block] response = self._call("eth_call", params) if function_name: response = self.translation.decode(function_name, response[2:].decode("hex")) return response def eth_estimateGas(self): """ https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_estimategas """ return self._call("eth_estimateGas") def eth_getBlockByHash(self, block_hash, tx_objects=True): """ https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_getblockbyhash TESTED """ return self._call("eth_getBlockByHash", [block_hash, tx_objects]) def eth_getBlockByNumber(self, block=BLOCK_TAG_LATEST, tx_objects=True): """ https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_getblockbynumber TESTED """ block = validate_block(block) return self._call("eth_getBlockByNumber", [block, tx_objects]) def eth_getTransactionByHash(self, tx_hash): """ https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_gettransactionbyhash TESTED """ return self._call("eth_getTransactionByHash", [tx_hash]) def eth_getTransactionByBlockHashAndIndex(self, block_hash, index): """ https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_gettransactionbyblockhashandindex """ return self._call("eth_getTransactionByBlockHashAndIndex", [block_hash, hex(index)]) def eth_getTransactionByBlockNumberAndIndex(self, block_number, index): """ https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_gettransactionbyblocknumberandindex """ return self._call("eth_getTransactionByBlockNumberAndIndex", [block_number, hex(index)]) def eth_getTransactionReceipt(self, tx_hash): """ https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_gettransactionreceipt """ return self._call("eth_getTransactionReceipt", [tx_hash]) def eth_getUncleByBlockHashAndIndex(self, block_hash, index, transaction_objects=True): """ https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_getunclebyblockhashandindex """ return self._call("eth_getUncleByBlockHashAndIndex", [block_hash, hex(index), transaction_objects]) def eth_getUncleByBlockNumberAndIndex(self, block_number, index, transaction_objects=True): """ https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_getunclebyblocknumberandindex """ return self._call("eth_getUncleByBlockNumberAndIndex", [block_number, hex(index), transaction_objects]) def eth_getCompilers(self): """ https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_getcompilers TESTED """ return self._call("eth_getCompilers") def eth_compileLLL(self, code): """ https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_compilelll """ return self._call("eth_compileLLL", [code]) def eth_compileSolidity(self, code): """ https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_compilesolidity """ return self._call("eth_compileSolidity", [code]) def eth_compileSerpent(self, code): """ https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_compileserpent """ return self._call("eth_compileSerpent", [code]) def eth_newFilter(self, from_block=BLOCK_TAG_LATEST, to_block=BLOCK_TAG_LATEST, address=None, topics=None): """ https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_newfilter """ _filter = {"fromBlock": from_block, "toBlock": to_block, "address": address, "topics": topics} return self._call("eth_newFilter", [_filter]) def eth_newBlockFilter(self, default_block=BLOCK_TAG_LATEST): """ https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_newblockfilter """ return self._call("eth_newBlockFilter", [default_block]) def eth_newPendingTransactionFilter(self): """ https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_newpendingtransactionfilter TESTED """ return hex_to_int(self._call("eth_newPendingTransactionFilter")) def eth_uninstallFilter(self, filter_id): """ https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_uninstallfilter """ return self._call("eth_uninstallFilter", [filter_id]) def eth_getFilterChanges(self, filter_id): """ https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_getfilterchanges """ return self._call("eth_getFilterChanges", [filter_id]) def eth_getFilterLogs(self, filter_id): """ https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_getfilterlogs """ return self._call("eth_getFilterLogs", [filter_id]) def eth_getLogs(self, filter_object): """ https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_getlogs """ return self._call("eth_getLogs", [filter_object]) def eth_getWork(self): """ https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_getwork TESTED """ return self._call("eth_getWork") def eth_submitWork(self, nonce, header, mix_digest): """ https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_submitwork """ return self._call("eth_submitWork", [nonce, header, mix_digest]) def eth_submitHashrate(self, hash_rate, client_id): """ https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_submithashrate """ return self._call("eth_submitHashrate", [hash_rate, client_id]) def db_putString(self, db_name, key, value): """ https://github.com/ethereum/wiki/wiki/JSON-RPC#db_putstring TESTED """ warnings.warn("deprecated", DeprecationWarning) return self._call("db_putString", [db_name, key, value]) def db_getString(self, db_name, key): """ https://github.com/ethereum/wiki/wiki/JSON-RPC#db_getstring TESTED """ warnings.warn("deprecated", DeprecationWarning) return self._call("db_getString", [db_name, key]) def db_putHex(self, db_name, key, value): """ https://github.com/ethereum/wiki/wiki/JSON-RPC#db_puthex TESTED """ if not value.startswith("0x"): value = "0x{}".format(value) warnings.warn("deprecated", DeprecationWarning) return self._call("db_putHex", [db_name, key, value]) def db_getHex(self, db_name, key): """ https://github.com/ethereum/wiki/wiki/JSON-RPC#db_gethex TESTED """ warnings.warn("deprecated", DeprecationWarning) return self._call("db_getHex", [db_name, key]) def shh_post(self, topics, payload, priority, ttl, _from=None, to=None): """ https://github.com/ethereum/wiki/wiki/JSON-RPC#shh_post """ whisper_object = { "from": _from, "to": to, "topics": topics, "payload": payload, "priority": hex(priority), "ttl": hex(ttl), } return self._call("shh_post", [whisper_object]) def shh_version(self): """ https://github.com/ethereum/wiki/wiki/JSON-RPC#shh_version N/A """ return self._call("shh_version") def shh_newIdentity(self): """ https://github.com/ethereum/wiki/wiki/JSON-RPC#shh_newidentity N/A """ return self._call("shh_newIdentity") def shh_hasIdentity(self, address): """ https://github.com/ethereum/wiki/wiki/JSON-RPC#shh_hasidentity """ return self._call("shh_hasIdentity", [address]) def shh_newGroup(self): """ https://github.com/ethereum/wiki/wiki/JSON-RPC#shh_newgroup N/A """ return self._call("shh_newGroup") def shh_addToGroup(self): """ https://github.com/ethereum/wiki/wiki/JSON-RPC#shh_addtogroup """ return self._call("shh_addToGroup") def shh_newFilter(self, to, topics): """ https://github.com/ethereum/wiki/wiki/JSON-RPC#shh_newfilter """ _filter = {"to": to, "topics": topics} return self._call("shh_newFilter", [_filter]) def shh_uninstallFilter(self, filter_id): """ https://github.com/ethereum/wiki/wiki/JSON-RPC#shh_uninstallfilter """ return self._call("shh_uninstallFilter", [filter_id]) def shh_getFilterChanges(self, filter_id): """ https://github.com/ethereum/wiki/wiki/JSON-RPC#shh_getfilterchanges """ return self._call("shh_getFilterChanges", [filter_id]) def shh_getMessages(self, filter_id): """ https://github.com/ethereum/wiki/wiki/JSON-RPC#shh_getmessages """ return self._call("shh_getMessages", [filter_id])
class Contract(object): """A class for interacting with Ethereum contracts.""" def __init__(self, address: str, interface: Sequence[Mapping], rpc_address: str, sender: str = None, gas: int = MAX_GAS): """Create a new Contract instance. Batch requests not supported! Arguments: address -- The address of the smart contract you want to use. interface -- The full signature of the smart contract. rpc_address -- The address of the RPC server for your Ethereum node. sender -- The address to send from. If None, the default sender for your node is used. gas -- The maximum amount of gas to use per transaction/call. """ err_fmt = 'Invalid {} address, must be 40 digit hex starting with \'0x\': {!r}' if not ETH_ADDR.match(address): raise ContractError(err_fmt.format('contract', address)) self.translator = ContractTranslator(interface) self.rpc_client = rpc_factory(rpc_address, False) self.common_params = {'to': address, 'gas': hex(gas)} if sender is None: pass elif ETH_ADDR.match(sender): self.common_params['from'] = sender else: raise ContractError(err_fmt.format('sender', sender)) def proxy_factory(name): # Generates proxy functions that use rpc methods under the hood. pyname = name.split('(')[0] # a python compatible name def proxy(*args, **kwds): """Calls function {} in contract {}. If the optional `call` keyword is True, then the result of the function call is decoded into a Python object and returned, otherwise the transaction hash is returned. """ tx = self.common_params.copy() data = self.translator.encode_function_call(pyname, args) tx['data'] = '0x{}'.format(data.encode('hex')) if kwds.get('call', False): return self._call(pyname, tx) else: return self._send(tx) proxy.__name__ = pyname proxy.__doc__ = proxy.__doc__.format(name, address) return proxy for item in interface: if item['type'] == 'function': proxy = proxy_factory(item['name']) if hasattr(self, proxy.__name__): raise ContractError('Polymorphism not supported!') setattr(self, proxy.__name__, proxy) def _call(self, func_name, tx): # Uses call to interact with a contract. response = self.rpc_client.eth_call(tx, 'latest') self._check_response(response) raw_result = response['result'].lstrip('0x').decode('hex') return self.translator.decode(func_name, raw_result) def _send(self, tx): response = self.rpc_client.eth_sendTransaction(tx) return response['result']
class EthJsonRpc: def __init__(self, host, port, contract_code=None, contract_address=None): self.host = host self.port = port self.contract_code = None self.signature = None self.translation = None self.contract_address = contract_address self.update_code(contract_code) def update_code(self, contract_code): if contract_code: self.contract_code = contract_code self.signature = serpent.mk_full_signature(contract_code) self.translation = ContractTranslator(self.signature) def _call(self, method, params=None, _id=0): if params is None: params = [] data = json.dumps({ 'jsonrpc': '2.0', 'method': method, 'params': params, 'id': _id }) response = requests.post("http://{}:{}".format(self.host, self.port), data=data).json() return response def create_contract(self, contract_code, value=0, from_address=None, gas=0, gas_price=0): self.update_code(contract_code) byte_code = serpent.compile(contract_code) self.contract_address = self.eth_sendTransaction(data=byte_code, value=value, from_address=from_address, gas=gas, gas_price=gas_price) return self.contract_address def eth_sendTransaction(self, to_address=None, function_name=None, data=None, value=0, from_address=None, gas=0, gas_price=0, code=None): """ Creates new message call transaction or a contract creation, if the data field contains code. """ if code: self.update_code(code) else: self.update_code(self.eth_getCode(to_address)) if function_name: if data is None: data = [] data = self.translation.encode(function_name, data) params = { 'from': from_address, 'to': to_address, 'gas': hex(gas) if gas else None, 'gasPrice': hex(gas_price) if gas_price else None, 'value': hex(value) if value else None, 'data': '0x{}'.format(data.encode('hex')) if data else None } return self._call('eth_sendTransaction', [params]) def eth_call(self, to_address, function_name, data=None, code=None, default_block="latest"): """ Executes a new message call immediately without creating a transaction on the block chain. """ if code: self.update_code(code) else: self.update_code(self.eth_getCode(to_address)) if data is None: data = [] data = self.translation.encode(function_name, data) params = [ { 'to': to_address, 'data': '0x{}'.format(data.encode('hex')) }, default_block ] response = self._call('eth_call', params) if function_name: response = self.translation.decode(function_name, response[2:].decode('hex')) return response def web3_clientVersion(self): """ Returns the current client version. """ return self._call('web3_clientVersion') def web3_sha3(self, data): """ Returns SHA3 of the given data. """ data = str(data).encode('hex') return self._call('web3_sha3', [data]) def net_version(self): """ Returns the current network protocol version. """ return self._call('net_version') def net_listening(self): """ Returns true if client is actively listening for network connections. """ return self._call('net_listening') def net_peerCount(self): """ Returns number of peers currenly connected to the client. """ return self._call('net_peerCount') def eth_version(self): """ Returns the current ethereum protocol version. """ return self._call('eth_version') def eth_coinbase(self): """ Returns the client coinbase address. """ return self._call('eth_coinbase') def eth_mining(self): """ Returns true if client is actively mining new blocks. """ return self._call('eth_mining') def eth_gasPrice(self): """ Returns the current price per gas in wei. """ return self._call('eth_gasPrice') def eth_accounts(self): """ Returns a list of addresses owned by client. """ return self._call('eth_accounts') def eth_blockNumber(self): """ Returns the number of most recent block. """ return self._call('eth_blockNumber') def eth_getBalance(self, address, default_block="latest"): """ Returns the balance of the account of given address. """ return self._call('eth_getBalance', [address, default_block]) def eth_getStorageAt(self, address, position, default_block="latest"): """ Returns the value from a storage position at a given address. """ return self._call('eth_getStorageAt', [address, hex(position), default_block]) def eth_getTransactionCount(self, address, default_block="latest"): """ Returns the number of transactions send from a address. """ return self._call('eth_getTransactionCount', [address, default_block]) def eth_getBlockTransactionCountByHash(self, block_hash): """ Returns the number of transactions in a block from a block matching the given block hash. """ return self._call('eth_getTransactionCount', [block_hash]) def eth_getBlockTransactionCountByNumber(self, block_number): """ Returns the number of transactions in a block from a block matching the given block number. """ return self._call('eth_getBlockTransactionCountByNumber', [hex(block_number)]) def eth_getUncleCountByblockHash(self, block_hash): """ Returns the number of uncles in a block from a block matching the given block hash. """ return self._call('eth_getUncleCountByblockHash', [block_hash]) def eth_getUncleCountByblockNumber(self, block_number): """ Returns the number of uncles in a block from a block matching the given block number. """ return self._call('eth_getUncleCountByblockNumber', [hex(block_number)]) def eth_getCode(self, address, default_block="latest"): """ Returns code at a given address. """ return self._call('eth_getCode', [address, default_block]) def eth_getBlockByHash(self, block_hash, transaction_objects=True): """ Returns information about a block by hash. """ return self._call('eth_getBlockByHash', [block_hash, transaction_objects]) def eth_flush(self): """ """ return self._call('eth_flush') def eth_getBlockByNumber(self, block_number, transaction_objects=True): """ Returns information about a block by hash. """ return self._call('eth_getBlockByNumber', [block_number, transaction_objects]) def eth_getTransactionByHash(self, transaction_hash): """ Returns the information about a transaction requested by transaction hash. """ return self._call('eth_getTransactionByHash', [transaction_hash]) def eth_getTransactionByblockHashAndIndex(self, block_hash, index): """ Returns information about a transaction by block hash and transaction index position. """ return self._call('eth_getTransactionByblock_hashAndIndex', [block_hash, hex(index)]) def eth_getTransactionByblockNumberAndIndex(self, block_number, index): """ Returns information about a transaction by block number and transaction index position. """ return self._call('eth_getTransactionByblock_numberAndIndex', [block_number, hex(index)]) def eth_getUncleByblockHashAndIndex(self, block_hash, index, transaction_objects=True): """ Returns information about a uncle of a block by hash and uncle index position. """ return self._call('eth_getUncleByblock_hashAndIndex', [block_hash, hex(index), transaction_objects]) def eth_getUncleByblockNumberAndIndex(self, block_number, index, transaction_objects=True): """ Returns information about a uncle of a block by number and uncle index position. """ return self._call('eth_getUncleByblock_numberAndIndex', [block_number, hex(index), transaction_objects]) def eth_getCompilers(self): """ Returns a list of available compilers in the client. """ return self._call('eth_getCompilers') def eth_compileSolidity(self, code): """ Returns compiled solidity code. """ return self._call('eth_compileSolidity', [code]) def eth_compileLLL(self, code): """ Returns compiled LLL code. """ return self._call('eth_compileLLL', [code]) def eth_compileSerpent(self, code): """ Returns compiled serpent code. """ return self._call('eth_compileSerpent', [code]) def eth_newFilter(self, from_block="latest", to_block="latest", address=None, topics=None): """ Creates a filter object, based on filter options, to notify when the state changes (logs). To check if the state has changed, call eth_getFilterChanges. """ _filter = { 'fromBlock': from_block, 'toBlock': to_block, 'address': address, 'topics': topics } return self._call('eth_newFilter', [_filter]) def eth_newBlockFilter(self, default_block="latest"): """ Creates a filter object, based on an option string, to notify when state changes (logs). To check if the state has changed, call eth_getFilterChanges. """ return self._call('eth_newBlockFilter', [default_block]) def eth_uninstallFilter(self, filter_id): """ Uninstalls a filter with given id. Should always be called when watch is no longer needed. Additonally Filters timeout when they aren't requested with eth_getFilterChanges for a period of time. """ return self._call('eth_uninstallFilter', [hex(filter_id)]) def eth_getFilterChanges(self, filter_id): """ Polling method for a filter, which returns an array of logs which occurred since last poll. """ return self._call('eth_getFilterChanges', [hex(filter_id)]) def eth_getFilterLogs(self, filter_id): """ Returns an array of all logs matching filter with given id. """ return self._call('eth_getFilterLogs', [hex(filter_id)]) def eth_getLogs(self, filter_object): """ Returns an array of all logs matching a given filter object. """ return self._call('eth_getLogs', [filter_object]) def eth_getWork(self): """ Returns the hash of the current block, the seedHash, and the difficulty to be met. """ return self._call('eth_getWork') def eth_submitWork(self, nonce, header, mix_digest): """ Used for submitting a proof-of-work solution. """ return self._call('eth_submitWork', [nonce, header, mix_digest]) def db_putString(self, database_name, key_name, string): """ Stores a string in the local database. """ return self._call('db_putString', [database_name, key_name, string]) def db_getString(self, database_name, key_name): """ Stores a string in the local database. """ return self._call('db_getString', [database_name, key_name]) def db_putHex(self, database_name, key_name, string): """ Stores binary data in the local database. """ return self._call('db_putHex', [database_name, key_name, string.encode('hex')]) def db_getHex(self, database_name, key_name): """ Returns binary data from the local database. """ return self._call('db_getString', [database_name, key_name]).decode('hex') def shh_version(self): """ Returns the current whisper protocol version. """ return self._call('shh_version') def shh_post(self, topics, payload, priority, ttl, _from=None, to=None): """ Sends a whisper message. """ whisper_object = { 'from': _from, 'to': to, 'topics': topics, 'payload': payload, 'priority': priority, 'ttl': ttl } return self._call('shh_post', [whisper_object]) def shh_newIdentinty(self): """ Creates new whisper identity in the client. """ return self._call('shh_newIdentinty') def shh_hasIdentity(self, address): """ Checks if the client hold the private keys for a given identity. """ return self._call('shh_hasIdentity', [address]) def shh_newGroup(self): """ """ return self._call('shh_hasIdentity') def shh_addToGroup(self): """ """ return self._call('shh_addToGroup') def shh_newFilter(self, to, topics): """ Creates filter to notify, when client receives whisper message matching the filter options. """ _filter = { 'to': to, 'topics': topics } return self._call('shh_newFilter', [_filter]) def shh_uninstallFilter(self, filter_id): """ Uninstalls a filter with given id. Should always be called when watch is no longer needed. Additonally Filters timeout when they aren't requested with shh_getFilterChanges for a period of time. """ return self._call('shh_uninstallFilter', [hex(filter_id)]) def shh_getFilterChanges(self, filter_id): """ Polling method for whisper filters. """ return self._call('shh_getFilterChanges', [hex(filter_id)]) def shh_getMessages(self, filter_id): """ Get all messages matching a filter, which are still existing in the node. """ return self._call('shh_getMessages', [hex(filter_id)])