def prepare_replacement_transaction(web3, current_transaction, new_transaction): if current_transaction['blockHash'] is not None: raise ValueError( 'Supplied transaction with hash {} has already been mined'.format( current_transaction['hash'])) if 'nonce' in new_transaction and new_transaction[ 'nonce'] != current_transaction['nonce']: raise ValueError( 'Supplied nonce in new_transaction must match the pending transaction' ) if 'nonce' not in new_transaction: new_transaction = assoc(new_transaction, 'nonce', current_transaction['nonce']) if 'gasPrice' in new_transaction: if new_transaction['gasPrice'] <= current_transaction['gasPrice']: raise ValueError( 'Supplied gas price must exceed existing transaction gas price' ) else: generated_gas_price = web3.eth.generateGasPrice(new_transaction) minimum_gas_price = int( math.ceil(current_transaction['gasPrice'] * 1.1)) if generated_gas_price and generated_gas_price > minimum_gas_price: new_transaction = assoc(new_transaction, 'gasPrice', generated_gas_price) else: new_transaction = assoc(new_transaction, 'gasPrice', minimum_gas_price) return new_transaction
def apply_formatters(method, params, make_request, request_formatters, result_formatters, error_formatters): if method in request_formatters: formatter = request_formatters[method] formatted_params = formatter(params) response = make_request(method, formatted_params) else: response = make_request(method, params) if 'result' in response and method in result_formatters: formatter = result_formatters[method] formatted_response = assoc( response, 'result', formatter(response['result']), ) return formatted_response elif 'error' in response and method in error_formatters: formatter = error_formatters[method] formatted_response = assoc( response, 'error', formatter(response['error']), ) return formatted_response else: return response
def apply_formatters( method, params, make_request, request_formatters, result_formatters, error_formatters): if method in request_formatters: formatter = request_formatters[method] formatted_params = formatter(params) response = make_request(method, formatted_params) else: response = make_request(method, params) if 'result' in response and method in result_formatters: formatter = result_formatters[method] formatted_response = assoc( response, 'result', formatter(response['result']), ) return formatted_response elif 'error' in response and method in error_formatters: formatter = error_formatters[method] formatted_response = assoc( response, 'error', formatter(response['error']), ) return formatted_response else: return response
def extract_valid_transaction_params(transaction_params): extracted_params = { key: transaction_params[key] for key in VALID_TRANSACTION_PARAMS if key in transaction_params } if extracted_params.get('data') is not None: if transaction_params.get('input') is not None: if extracted_params['data'] != transaction_params['input']: msg = 'failure to handle this transaction due to both "input: {}" and' msg += ' "data: {}" are populated. You need to resolve this conflict.' err_vals = (transaction_params['input'], extracted_params['data']) raise AttributeError(msg.format(*err_vals)) else: return extracted_params else: return extracted_params elif extracted_params.get('data') is None: if transaction_params.get('input') is not None: return assoc(extracted_params, 'data', transaction_params['input']) else: return extracted_params else: raise Exception( "Unreachable path: transaction's 'data' is either set or not set")
def sendTransaction(self, transaction): # TODO: move to middleware if 'from' not in transaction and is_checksum_address(self.defaultAccount): transaction = assoc(transaction, 'from', self.defaultAccount) # TODO: move gas estimation in middleware if 'gas' not in transaction: transaction = assoc( transaction, 'gas', get_buffered_gas_estimate(self.web3, transaction), ) return self.web3.manager.request_blocking( "eth_sendTransaction", [transaction], )
def fill_nonce(web3, transaction): if 'from' in transaction and 'nonce' not in transaction: return assoc( transaction, 'nonce', web3.eth.getTransactionCount(transaction['from'], block_identifier='pending')) else: return transaction
def estimateGas(self, transaction): # TODO: move to middleware if 'from' not in transaction and is_checksum_address(self.defaultAccount): transaction = assoc(transaction, 'from', self.defaultAccount) return self.web3.manager.request_blocking( "eth_estimateGas", [transaction], )
def middleware(method, params): if method == 'eth_sendTransaction': transaction = params[0] if 'gasPrice' not in transaction: generated_gas_price = web3.eth.generateGasPrice(transaction) if generated_gas_price is not None: transaction = assoc(transaction, 'gasPrice', generated_gas_price) return make_request(method, [transaction]) return make_request(method, params)
def fill_nonce(web3, transaction): if 'from' in transaction and 'nonce' not in transaction: return assoc( transaction, 'nonce', web3.eth.getTransactionCount( transaction['from'], block_identifier='pending')) else: return transaction
def middleware(method, params): response = make_request(method, params) if 'result' in response: result = response['result'] if is_dict(result) and not isinstance(result, AttributeDict): return assoc(response, 'result', AttributeDict.recursive(result)) else: return response else: return response
def traceCall(self, transaction, mode=['trace'], block_identifier=None): # TODO: move to middleware if 'from' not in transaction and is_checksum_address(self.defaultAccount): transaction = assoc(transaction, 'from', self.defaultAccount) # TODO: move to middleware if block_identifier is None: block_identifier = self.defaultBlock return self.web3.manager.request_blocking( "trace_call", [transaction, mode, block_identifier], )
def prepare_replacement_transaction(web3, current_transaction, new_transaction): if current_transaction['blockHash'] is not None: raise ValueError('Supplied transaction with hash {} has already been mined' .format(current_transaction['hash'])) if 'nonce' in new_transaction and new_transaction['nonce'] != current_transaction['nonce']: raise ValueError('Supplied nonce in new_transaction must match the pending transaction') if 'nonce' not in new_transaction: new_transaction = assoc(new_transaction, 'nonce', current_transaction['nonce']) if 'gasPrice' in new_transaction: if new_transaction['gasPrice'] <= current_transaction['gasPrice']: raise ValueError('Supplied gas price must exceed existing transaction gas price') else: generated_gas_price = web3.eth.generateGasPrice(new_transaction) minimum_gas_price = int(math.ceil(current_transaction['gasPrice'] * 1.1)) if generated_gas_price and generated_gas_price > minimum_gas_price: new_transaction = assoc(new_transaction, 'gasPrice', generated_gas_price) else: new_transaction = assoc(new_transaction, 'gasPrice', minimum_gas_price) return new_transaction
def estimateGas(self, transaction, block_identifier=None): # TODO: move to middleware if 'from' not in transaction and is_checksum_address(self.defaultAccount): transaction = assoc(transaction, 'from', self.defaultAccount) if block_identifier is None: params = [transaction] else: params = [transaction, block_identifier] return self.web3.manager.request_blocking( "eth_estimateGas", params, )
def estimateGas(self, transaction, block_identifier=None): # TODO: move to middleware if 'from' not in transaction and is_checksum_address( self.defaultAccount): transaction = assoc(transaction, 'from', self.defaultAccount) if block_identifier is None: params = [transaction] else: params = [transaction, block_identifier] return self.web3.manager.request_blocking( "eth_estimateGas", params, )
def call(self, transaction, block_identifier=None): # TODO: move to middleware if 'from' not in transaction and is_checksum_address( self.defaultAccount): transaction = assoc(transaction, 'from', self.defaultAccount) # TODO: move to middleware if block_identifier is None: block_identifier = self.defaultBlock result = self.web3.manager.request_blocking( "eth_call", [transaction, block_identifier], ) print("eth_call", result) return result
def middleware(method, params): result = make_request(method, params) # As of v1.8, Geth returns errors when you request a # receipt for a transaction that is not in the chain. # It used to return a result of None, so we simulate the old behavior. if method == 'eth_getTransactionReceipt' and 'error' in result: is_geth = web3.version.node.startswith('Geth') if is_geth and result['error']['code'] == -32000: return assoc( dissoc(result, 'error'), 'result', None, ) else: return result else: return result
def middleware(method, params): result = make_request(method, params) # As of v1.8, Geth returns errors when you request a # receipt for a transaction that is not in the chain. # It used to return a result of None, so we simulate the old behavior. if method == 'eth_getTransactionReceipt' and 'error' in result: is_geth = web3.clientVersion.startswith('Geth') if is_geth and result['error']['code'] == -32000: return assoc( dissoc(result, 'error'), 'result', None, ) else: return result else: return result
def extract_valid_transaction_params(transaction_params): extracted_params = {key: transaction_params[key] for key in VALID_TRANSACTION_PARAMS if key in transaction_params} if extracted_params.get('data') is not None: if transaction_params.get('input') is not None: if extracted_params['data'] != transaction_params['input']: msg = 'failure to handle this transaction due to both "input: {}" and' msg += ' "data: {}" are populated. You need to resolve this conflict.' err_vals = (transaction_params['input'], extracted_params['data']) raise AttributeError(msg.format(*err_vals)) else: return extracted_params else: return extracted_params elif extracted_params.get('data') is None: if transaction_params.get('input') is not None: return assoc(extracted_params, 'data', transaction_params['input']) else: return extracted_params else: raise Exception("Unreachable path: transaction's 'data' is either set or not set")
def fill_default(field, guess_func, web3, transaction): if field in transaction and transaction[field] is not None: return transaction else: guess_val = guess_func(web3, transaction) return assoc(transaction, field, guess_val)
def load_fixture_data(fixture_path): fixture_path = absolute_datadir(fixture_path) config_path = os.path.join(fixture_path, 'config.json') with open(config_path) as config_file: loaded_data = json.loads(config_file.read()) return assoc(loaded_data, 'datadir', fixture_path)