class EthLocust(Locust): ''' This is the abstract Locust class which should be subclassed. It provides an Ethereum JSON-RPC client that can be used for requests that will be tracked in Locust's statistics. ''' def __init__(self, *args, **kwargs): super(EthLocust, self).__init__(*args, **kwargs) server, port = self.host.split(':') if int(port) == 443: tls_flag = True else: tls_flag = False self.client = EthJsonRpc(server, port, tls=tls_flag) self.addresses = self.get_target_address_list() def get_target_address_list(self, count=100): ''' As part of the initialization, we build up a list of 1k addresses which will be the targets of the getBal call. We do it as part of the initialization so that we dont slow down the concurrent tests. ''' addrs = [] block = self.client.eth_getBlockByNumber() while len(addrs) < count: block = self.client.eth_getBlockByHash(block['parentHash']) if block['transactions'] is not None: addrs += [ t['to'] for t in block['transactions'] if t['to'] is not None ] # Use a set to dedupe commonly used addresses (coinbase, poloniex, etc) return list(set(addrs))
class ContractWrapper: def __init__( self, the_code=False, the_sig=None, the_args=None, the_address=False, events_callback=False, deploy_callback=False, blocking_sleep_time=0.1, rpc_host=DEFAULT_RPC_HOST, rpc_port=DEFAULT_RPC_PORT, settings_confirm_states={}, contract_address=False, start_at_current_block=False, auto_deploy=True, contract_thread_sleep_time=1.0, reorg_callback=False, ): """ Simple contract wrapper, assists with deploying contract, sending transactions, and tracking event logs. Args: - the_code: solidity code for contract that should be deployed, prior to any operations. - the_address: address of already-deployed main contract. - contract_address: contract address, from previous `deploy()` call. - the_sig: optional constructor signature. - the_args: optional constructor args. - events_callback: callback for event messages e.g. `TheLog()`, `MintEvent()`, `LockupTokEvent()`, `TransferTokEvent()`. - deploy_callback: callback for contract deploys. - blocking_sleep_time: time to sleep when blocking and polling for a transaction receipt. """ self.block_details = {} self.reorg_callback = reorg_callback self.confirmation_tracker = { } ## {'block_hash':{'prev_block_hash':xx, 'block_num':yy}} self.done_block_nums = {} ## {confirm_state:set()} self.done_transactions = {} ## {confirm_state:set()} self.prev_block_num = {} ## {confirm_state:set()} self.blocking_sleep_time = blocking_sleep_time self.c = EthJsonRpc(rpc_host, rpc_port) self.contract_thread_sleep_time = contract_thread_sleep_time self.start_at_current_block = start_at_current_block self.current_block_at_init = self.c.eth_blockNumber() if self.start_at_current_block: self.last_incoming_block = max(0, self.current_block_at_init - 1) else: self.last_incoming_block = 0 self.starting_block_num = self.last_incoming_block self.msgs = {} ## {block_num:[msg, msg, msg]} self.the_code = the_code self.the_sig = the_sig self.the_args = the_args self.contract_address = the_address assert self.the_code or self.contract_address self.loop_block_num = -1 self.confirm_states = settings_confirm_states self.events_callback = events_callback self.pending_transactions = {} ## {tx:callback} self.pending_logs = {} self.latest_block_num = -1 self.latest_block_num_done = 0 self.send_transaction_queue = Queue() self.is_deployed = False if auto_deploy: if the_address: assert self.check_anything_deployed(the_address), ( 'NOTHING DEPLOYED AT SPECIFIED ADDRESS:', the_address) self.is_deployed = True elif the_code: self.deploy() def check_anything_deployed(self, address): """ Basic sanity check, checks if ANY code is deployed at provided address. """ if self.c.eth_getCode(address) == '0x0': return False return True def deploy( self, the_sig=False, the_args=False, block=False, deploy_from=False, callback=False, ): """ Deploy contract. Optional args_sig and args used to pass arguments to contract constructor.""" if the_sig is not False: self.the_sig = the_sig if the_args is not False: self.the_args = the_args assert self.the_code if deploy_from is False: deploy_from = self.c.eth_coinbase() print('DEPLOYING_CONTRACT...', 'deploy_from:', deploy_from, 'the_sig:', the_sig, 'the_args:', the_args) # get contract address xx = self.c.eth_compileSolidity(self.the_code) #print ('GOT',xx) compiled = get_compiled_code(xx) contract_tx = self.c.create_contract( from_=deploy_from, code=compiled, gas=3000000, sig=self.the_sig, args=self.the_args, ) if block: ## NOTE: @yusef feel free to switch back to this method if you want: #print('CONTRACT DEPLOYED, WAITING FOR CONFIRMATION') #wait_for_confirmation(self.c, contract_tx) print('BLOCKING FOR RECEIPT..') while True: receipt = self.c.eth_getTransactionReceipt( contract_tx) ## blocks to ensure transaction is mined if receipt: break sleep(self.blocking_sleep_time) print('GOT RECEIPT') else: self.pending_transactions[contract_tx] = (callback, self.latest_block_num) self.contract_address = str(self.c.get_contract_address(contract_tx)) self.is_deployed = True print('DEPLOYED', self.contract_address) return self.contract_address def loop_once(self): assert self.is_deployed, 'Must deploy contract first.' had_any_events = False if self.c.eth_syncing(): print('BLOCKCHAIN_STILL_SYNCING') return False if self.events_callback is not False: had_any_events = self.poll_incoming() had_any_events = self.poll_outgoing() or had_any_events num_fails = 0 while self.send_transaction_queue.qsize(): print('TRY_TO_SEND') tries, args, kw = self.send_transaction_queue.get() try: self._send_transaction(*args, **kw) except Exception as e: print('FAILED_TO_SEND', e, tries, args, kw) sleep(1) ## TODO self.send_transaction_queue.put((tries + 1, args, kw)) break return had_any_events def check_for_reorg( self, block_num, ): """ Check for reorg since last check, and reorgs during our reorg rewinding... """ print('START check_for_reorg', block_num) return block_num = ethereum.utils.parse_int_or_hex(block_num) while True: cur_num = block_num had_reorg = False while True: if cur_num == self.starting_block_num: break assert cur_num >= self.starting_block_num, ( cur_num, self.starting_block_num) ## Get info for prev and current: for x_block_num in [block_num, block_num - 1]: if x_block_num not in self.block_details: rh = self.c.eth_getBlockByNumber(x_block_num) ## Strip down to just a couple fields: block_h = { 'timestamp': ethereum.utils.parse_int_or_hex(rh['timestamp']), 'hash': rh['hash'], 'parentHash': rh['parentHash'], 'blockNumber': x_block_num, } self.block_details[x_block_num] = block_h ## Check for reorg: block_h = self.block_details[block_num] if block_h['parentHash'] != self.block_details[ block_h['blockNumber'] - 1]['hash']: print('!!! REORG', block_num, '->', cur_num) cur_num -= 1 self.latest_done_block = cur_num had_reorg = True continue break ## Rewind state if had_reorg: if had_reorg and (self.reorg_callback is not False): self.reorg_callback(cur_num) self.last_incoming_block = cur_num - 1 ## If had_reorg, loop again - to detect another reorg that occured while we tracked down the reorg... if not had_reorg: break return had_reorg def poll_incoming(self, chunk_size=50): """ https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_newfilter - track buffer of events from old blocks - track pointer to last processed block """ assert self.is_deployed, 'Must deploy contract first.' #self.latest_block_num = self.c.eth_blockNumber() from_block = self.last_incoming_block + 1 params = { 'from_block': fixed_int_to_hex(from_block), 'to_block': 'latest', #fixed_int_to_hex(from_block + chunk_size), 'address': self.contract_address, } print('eth_newFilter', 'from_block:', from_block, 'params:', params) self.the_filter = str(self.c.eth_newFilter(**params)) num_blocks = len(self.msgs) xx_msgs = self.c.eth_getFilterLogs(self.the_filter) for msg in xx_msgs: msg['blockNumber'] = ethereum.utils.parse_int_or_hex( msg['blockNumber']) if msg['blockNumber'] not in self.msgs: self.msgs[msg['blockNumber']] = [] self.msgs[msg['blockNumber']].append(msg) if num_blocks == len(self.msgs): ## Nothing new assert not len(xx_msgs), len(xx_msgs) return False for do_state, state_num_blocks in self.confirm_states.items(): longest_confirm_state = max(self.confirm_states.values()) newest_block_num = max(max(self.msgs), self.last_incoming_block) ## Oldest to newest: for nn in xrange( max(1, self.last_incoming_block - state_num_blocks), newest_block_num + 1, ): if self.check_for_reorg(nn): ## Just wait for next call to poll_incoming() before resuming. return False if nn in self.msgs: for msg in self.msgs[nn]: print('EMIT', do_state, nn, msg['data']) self.events_callback(msg=msg, receipt=False, received_via=do_state) ## Clear out old buffer: for nn in self.msgs.keys(): if nn < newest_block_num - longest_confirm_state - 1: del self.msgs[nn] self.last_incoming_block = newest_block_num return True if False: ## START CHECKS if do_state not in self.done_transactions: self.done_transactions[do_state] = set() self.done_block_nums[do_state] = set() msg_block_num = ethereum.utils.parse_int_or_hex(msg['blockNumber']) if cm == 0: assert msg_block_num not in self.done_block_nums[do_state], ( 'Seen block twice?', msg_block_num, ) self.done_block_nums[do_state].add(msg_block_num) if do_state in self.prev_block_num: assert msg_block_num >= self.prev_block_num[do_state], ( 'REORG?', msg_block_num, self.prev_block_num[do_state], ) self.prev_block_num[do_state] = msg_block_num assert msg['transactionHash'] not in self.done_transactions[ do_state], ( 'Seen transaction twice?', msg_block_num, msg['transactionHash'], ) self.done_transactions[do_state].add(msg['transactionHash']) ## END CHECKS return had_any_events def _start_contract_thread( self, terminate_on_exception=False, ): while True: try: had_any_events = self.loop_once() except Exception as e: print('-----LOOP_ONCE_EXCEPTION', e) #exit(-1) raise if terminate_on_exception: raise continue if not had_any_events: print('NO_NEW_EVENTS') sleep(self.contract_thread_sleep_time) def start_contract_thread( self, start_in_foreground=False, terminate_on_exception=False, ): """ Start ContractWrapper loop_once() in background thread, which (in that thread!) calls back to self.process_event() """ if start_in_foreground: self._start_contract_thread( terminate_on_exception=terminate_on_exception) else: self.t = Thread( target=self._start_contract_thread, args=(terminate_on_exception, ), ) self.t.daemon = True self.t.start() def send_transaction(self, *args, **kw): assert len(args) <= 2 if kw.get('block'): self.send_transaction(*args, **kw) else: self.send_transaction_queue.put((0, args, kw)) def _send_transaction( self, args_sig, args, callback=False, send_from=False, block=False, gas_limit=False, gas_price=100, value=100000000000, ): """ 1) Attempt to send transaction. 2) Get first confirmation via transaction receipt. 3) Re-check receipt again after N blocks pass. https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_sendtransaction """ assert self.is_deployed, 'Must deploy contract first.' print('SEND_TRANSACTION:', args_sig, args) if send_from is False: send_from = self.c.eth_coinbase() send_to = self.contract_address print('====TRANSACTION') print('send_from', send_from) print('send_to', send_to) print('args_sig', args_sig) print('args', args) #print ('gas', gas_limit) gas_limit = 1000000 gas_price = self.c.DEFAULT_GAS_PRICE value = web3.utils.currency.to_wei(1, 'ether') data = self.c._encode_function(args_sig, args) data_hex = '0x' + data.encode('hex') tx = self.c.eth_sendTransaction( from_address=send_from, to_address=send_to, data=data_hex, gas=gas_limit, gas_price=gas_price, value=value, ) if block: print('BLOCKING FOR RECEIPT..') while True: receipt = self.c.eth_getTransactionReceipt( tx) ## blocks to ensure transaction is mined if receipt: break sleep(self.blocking_sleep_time) print('GOT RECEIPT') #print ('GOT_RECEIPT', receipt) #if receipt['blockNumber']: # self.latest_block_num = max(ethereum.utils.parse_int_or_hex(receipt['blockNumber']), self.latest_block_num) else: self.pending_transactions[tx] = (callback, self.latest_block_num) self.latest_block_num = self.c.eth_blockNumber() return tx def poll_outgoing(self): """ Confirm outgoing transactions. """ assert self.is_deployed, 'Must deploy contract first.' had_any_events = False if self.pending_transactions: had_any_events = True for tx, (callback, attempt_block_num) in self.pending_transactions.items(): ## Compare against the block_number where it attempted to be included: if (attempt_block_num <= self.latest_block_num - self.confirm_states['BLOCKCHAIN_CONFIRMED']): continue receipt = self.c.eth_getTransactionReceipt(tx) if receipt is not None and 'blockNumber' in receipt: actual_block_number = ethereum.utils.parse_int_or_hex( receipt['blockNumber']) else: ## TODO: wasn't confirmed after a long time. actual_block_number = False ## Now compare against the block_number where it was actually included: if (actual_block_number is not False) and ( actual_block_number >= self.latest_block_num - self.confirm_states['BLOCKCHAIN_CONFIRMED']): if callback is not False: callback(receipt) del self.pending_transactions[tx] return had_any_events def read_transaction(self, args_sig, value): rr = self.c.call(self.c.eth_coinbase(), self.contract_address, args_sig, value) return rr def sign(self, user_address, value): rr = self.c.eth_sign(self.c.eth_coinbase(), self.contract_address, user_address, value) return rr
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)) for x in ['earliest', 'latest', 'pending', b[0]]: print(c.eth_getBlockByNumber(x, tx_objects=False)) tx = '0x12cd5d9a82049154c8990214a551479853d1bfe45852688833bc4ef86a29b1a3' print(c.eth_getTransactionByHash(tx)) ################################################################################ print('*' * 80) code = 'contract Test {}' print(c.eth_compileSolidity(code)) ################################################################################ print('*' * 80) b = (246236, '0xcd43703a1ead33ffa1f317636c7b67453c5cc03a3350cd71dbbdd70fcbe0987a') index = 2
def main(): # # receive contract addr # if len(sys.argv) != 3: print('Usage:\npython user.py <contract addr> <account addr>') sys.exit(-1) contract_addr = sys.argv[1] account_addr = sys.argv[2] # # create rpc interface # try: print('-' * 80) rpc = EthJsonRpc(RPC_HOST, RPC_PORT) print('client software: {}'.format(rpc.web3_clientVersion())) print('block: {}'.format(rpc.eth_blockNumber())) print('address: {}'.format(rpc.eth_coinbase())) except: print('unable to connect to rpc server at {}:{}'.format( RPC_HOST, RPC_PORT)) sys.exit(-1) # # check contract is online # print('-' * 80) if rpc.eth_getCode(contract_addr) == '0x0': print('!!! contract code not available on blockchain !!!') sys.exit(-1) print('found contract on blockchain!') # # console # topics = [] print('-' * 80) print('starting chat command line...') while True: # # simply read input # sys.stdout.write('>> ') command = sys.stdin.readline() # # quit? # if 'q' in command: sys.exit(0) # # show help # elif command == '\n' or 'help' in command: print('commands: help, send, status, topics, search, listen') # # compose new message # elif 'send' in command: print('-' * 80) print('[composing new message]') sys.stdout.write('message....: ') msg = sys.stdin.readline().strip() sys.stdout.write('image file.: ') img = sys.stdin.readline().strip() sys.stdout.write('custom tags: ') tag = sys.stdin.readline().strip() print('-' * 80) print('sending...') # loading image try: image = Image.open(img) except Exception as e: print('loading {} failed'.format(img)) continue # prediction print('precessing image...') label = ImageClassifier.predict(img) if label is None: print('classification failed') continue print('label: {}'.format(label)) tag += ' #' + label bs = ImageHelper.imgToBytes(image) tx = rpc.call_with_transaction( account_addr, contract_addr, 'setNewUserState(string,bytes,string)', [msg, bs, tag], gas=GAS) print('done, transaction id: {}'.format(tx)) # # get own last post # elif 'status' in command: print('-' * 80) print('[receiving last post]') userMessage, userImage, userTags = rpc.call( contract_addr, 'getUserState(address)', [account_addr], ['string', 'bytes', 'string']) if not userMessage: print('nothing posted yet') continue print(' content: {}'.format(userMessage)) print(' tags...: {}'.format(userTags)) ImageHelper.bytesToImg(userImage).show() # # set tag filters # elif 'topics' in command: topics = [t.strip() for t in command.split()[1:]] if len(topics) == 0: print('please provide actual topics after <topics> command') continue print('filter set for messages on topics: {}'.format(topics)) # # search complete blockchain for messages with certain tags # elif 'search' in command: if len(topics) == 0: print('call topics first') continue curBlock = rpc.eth_blockNumber() for i in range(curBlock + 1): for trans in rpc.eth_getBlockByNumber(i)['transactions']: res = Decoder.decodeABI(trans['input']) if res is None: continue msg, code, tags = res if all(t not in tags for t in topics): continue print('-' * 80) print('message from user {} (block {}):'.format( trans['from'], i)) print(' content: {}'.format(msg)) print(' tags...: {}'.format(tags)) ImageHelper.bytesToImg(code).show(title='{}'.format(tags)) # # start listening for messages # elif 'listen' in command: if len(topics) == 0: print('call topics first') continue global LISTENING LISTENING = True curBlock = rpc.eth_blockNumber() while LISTENING: newBlock = rpc.eth_blockNumber() if newBlock > curBlock: print('new block detected ({})'.format(newBlock)) curBlock = newBlock for trans in rpc.eth_getBlockByNumber( newBlock)['transactions']: res = Decoder.decodeABI(trans['input']) if res is None: continue msg, code, tags = res if all(t not in tags for t in topics): continue print('-' * 80) print('message from user {} (block {}):'.format( trans['from'], newBlock)) print(' content: {}'.format(msg)) print(' tags...: {}'.format(tags)) ImageHelper.bytesToImg(code).show( title='{}'.format(tags)) time.sleep(1) # # default response # else: print('command not recognized')
class EthereumBlockchain: def __init__(self, the_code = False, the_sig = None, the_args = None, the_address = False, rpc_host = DEFAULT_RPC_HOST, rpc_port = DEFAULT_RPC_PORT, background_thread_sleep_time = 1.0, ): self.con = EthJsonRpc(rpc_host, rpc_port) self.the_code = the_code self.the_sig = the_sig self.the_args = the_args self.contract_address = the_address assert self.the_code or self.contract_address self.loop_once_started = False self.sig_to_topic_id_cache = {} self.send_transaction_queue = Queue() self.background_thread_sleep_time = background_thread_sleep_time self.pending_transactions = {} ## {tx:callback} self.is_deployed = False if the_address: assert self.check_anything_deployed(the_address), ('NOTHING DEPLOYED AT SPECIFIED ADDRESS:', the_address) self.is_deployed = True elif the_code: if auto_deploy: self.deploy() #def setup_create_pending_transaction(func): # self._create_pending_transaction = func #def setup_logic_callback(func): # self._logic_callback = func def event_sig_to_topic_id(self, sig): """ Compute ethereum topic_ids from function signatures. """ if sig in self.sig_to_topic_id_cache: return self.sig_to_topic_id_cache[sig] name = sig[:sig.find('(')] types = [x.strip().split()[0] for x in sig[sig.find('(')+1:sig.find(')')].split(',')] topic_id = ethereum.utils.int_to_hex(ethereum.abi.event_id(name,types)) self.sig_to_topic_id_cache[sig] = topic_id return topic_id def setup_event_callbacks(self, log_handlers, pending_handlers, ): self.log_handlers = log_handlers self.log_handlers_hashed = {((x == 'DEFAULT') and 'DEFAULT' or self.event_sig_to_topic_id(x)):y for x,y in log_handlers.items()} self.pending_handlers = pending_handlers def logic_callback(self, msg, *args, **kw): default_func = self.log_handlers_hashed.get('DEFAULT', False) if 'topics' not in msg: assert default_func is not False, ('Unknown topic_id and no DEFAULT handler.') print ('PROXY logic_callback()', '->', default_func, kw) default_func(msg, *args, **kw) return for topic in msg['topics']: func = self.log_handlers_hashed.get(topic, default_func) print ('PROXY logic_callback()', topic, '->', func) assert func is not False, ('Unknown topic_id and no DEFAULT handler.', topic, kw) func(msg, *args, **kw) def simulate_pending(self, args_sig, args, *aa, **bb): """ See: https://github.com/ethereum/wiki/wiki/Ethereum-Contract-ABI#events """ ## TODO: support indexed topics? func = self.pending_handlers.get(args_sig, self.pending_handlers.get('DEFAULT', False)) print ('Proxy: simulate_pending()', args_sig, '->', func) return func(args_sig, args, *aa, **bb) def get_block_by_hash_callback(self, block_hash): """ Get block by blockHash. https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_getblockbyhash """ print ('bcc.get_block_by_hash_callback()', block_hash) rh = self.con.eth_getBlockByHash(block_hash) for k in ['number', 'timestamp']: rh[k] = ethereum.utils.parse_int_or_hex(rh[k]) return rh def get_logs_by_block_num_callback(self, block_num): """ Get event logs for a particular block num. It's OK if the block_num has an unexpected hash, that'll be taken care of by caller. https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_getlogs """ print ('bcc.get_logs_by_block_num_callback()', block_num) the_filter = self.con.eth_newFilter(from_block = fixed_int_to_hex(block_num), to_block = fixed_int_to_hex(block_num), address = self.contract_address, ) rr = self.con.eth_getFilterLogs(str(the_filter)) rr2 = [] for msg in rr: #assert 'topics' in msg, list(sorted(msg.keys())) got_num = ethereum.utils.parse_int_or_hex(msg['blockNumber']) if got_num != block_num: continue msg['data'] = solidity_string_decode(msg['data']) msg['blockNumber'] = got_num msg["logIndex"] = ethereum.utils.parse_int_or_hex(msg['logIndex']) msg["transactionIndex"] = ethereum.utils.parse_int_or_hex(msg['transactionIndex']) #msg_data = loads_compact(msg['data']) #payload_decoded = loads_compact(msg_data['payload']) rr2.append(msg) rr = rr2 return rr def get_latest_block_number(self): print ('bcc.get_latest_block_number()') bn = self.con.eth_blockNumber() return bn def get_latest_block_callback(self): """ Returns the single latest block. Missing intermediate blocks will be automatically looked up by caller. """ print ('bcc.get_latest_block_callback()') bn = self.get_latest_block_number() block = self.con.eth_getBlockByNumber(bn) return block def check_anything_deployed(self, address): """ Basic sanity check, checks if ANY code is deployed at provided address. """ print ('bcc.check_anything_deployed()', address) if self.con.eth_getCode(address) == '0x0': return False return True def deploy(self, the_sig = False, the_args = False, block = False, deploy_from = False, callback = False, ): """ Deploy contract. Optional args_sig and args used to pass arguments to contract constructor.""" print ('bcc.deploy()') if the_sig is not False: self.contract_sig = the_sig if the_args is not False: self.contract_args = the_args assert self.the_code if deploy_from is False: deploy_from = self.con.eth_coinbase() print ('DEPLOYING_CONTRACT...', 'deploy_from:', deploy_from, 'the_sig:', the_sig, 'the_args:', the_args) # get contract address xx = self.con.eth_compileSolidity(self.the_code) #print ('GOT',xx) compiled = None try: compiled = xx['code'] except KeyError: # geth seems to like putting the compiler output into an inner dict keyed by input filename, # e.g {'CCCoinToken.sol': {'code': '...', 'etc': '...'} for k, v in xx.iteritems(): if isinstance(v, dict) and 'code' in v: compiled = v['code'] break assert compiled contract_tx = self.con.create_contract(from_ = deploy_from, code = compiled, gas = 3000000, sig = self.contract_sig, args = self.contract_args, ) if block: ## NOTE: @yusef feel free to switch back to this method if you want: #print('CONTRACT DEPLOYED, WAITING FOR CONFIRMATION') #wait_for_confirmation(self.c, contract_tx) print ('BLOCKING FOR RECEIPT..') while True: receipt = self.con.eth_getTransactionReceipt(contract_tx) ## blocks to ensure transaction is mined if receipt: break sleep(self.blocking_sleep_time) print ('GOT RECEIPT') else: self.pending_transactions[contract_tx] = callback self.contract_address = str(self.con.get_contract_address(contract_tx)) self.is_deployed = True print ('DEPLOYED', self.contract_address) return self.contract_address def send_transaction(self, *args, **kw): """ 1) If possible create simulated outputs of transactions, to use as pending state. 2) Queue the transaction for blockchain commit. Used for e.g.: - addLog(bytes) - mintTokens(address, uint, uint, uint, uint, uint, uint) - withdrawTok(bytes) - lockupTok(bytes) """ print ('bcc.send_transaction()') assert len(args) <= 2 #assert self.loop_once_started, 'loop_once() not started?' ## Potentially slow blocking call to commit it to the blockchain: if kw.get('block'): ## Send transaction in blocking mode, and grab actual event logs that are committed: rh = self.inner_send_transaction(*args, **kw) pending_logs = rh['pending_logs'] is_pending = False else: ## Run callbacks, return simulated event logs where possible: self.send_transaction_queue.put((0, args, kw)) pending_logs = self.simulate_pending(*args, **kw) is_pending = True ## Run logic_callback() against pending transactions: for log in pending_logs: print ('CALLING', 'is_pending:', is_pending, 'is_noop:', log.get('is_noop', False)) self.logic_callback(log, is_pending = is_pending, is_noop = log.get('is_noop', False) ) return pending_logs def inner_send_transaction(self, args_sig, args, callback = False, send_from = False, block = False, gas_limit = False, gas_price = 100, value = 100000000000, ): """ 1) Attempt to send transaction. 2) Get first confirmation via transaction receipt. 3) Re-check receipt again after N blocks pass. https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_sendtransaction """ print ('bcc.inner_send_transaction()') assert self.is_deployed, 'Must deploy contract first.' print ('SEND_TRANSACTION:', args_sig, args) if send_from is False: send_from = self.con.eth_coinbase() send_to = self.contract_address print ('====TRANSACTION') print ('send_from', send_from) print ('send_to', send_to) print ('args_sig', args_sig) print ('args', args) #print ('gas', gas_limit) gas_limit = 1000000 gas_price = self.con.DEFAULT_GAS_PRICE value = web3.utils.currency.to_wei(1,'ether') data = self.con._encode_function(args_sig, args) data_hex = '0x' + data.encode('hex') tx = self.con.eth_sendTransaction(from_address = send_from, to_address = send_to, data = data_hex, gas = gas_limit, gas_price = gas_price, value = value, ) if block: print ('BLOCKING FOR RECEIPT..') while True: receipt = self.con.eth_getTransactionReceipt(tx) ## blocks to ensure transaction is mined if receipt: break sleep(self.blocking_sleep_time) print ('GOT RECEIPT') #print ('GOT_RECEIPT', receipt) #if receipt['blockNumber']: # self.latest_block_num = max(ethereum.utils.parse_int_or_hex(receipt['blockNumber']), self.latest_block_num) else: self.pending_transactions[tx] = callback #self.latest_block_num = self.con.eth_blockNumber() return {'tx':tx} def poll_outgoing_receipts(self): """ Check for transaction receipts on transactions sent from this node. TODO - why not replace this with just watching for incoming transactions??? """ assert self.is_deployed, 'Must deploy contract first.' had_any_events = False if self.pending_transactions: had_any_events = True for tx, callback in self.pending_transactions.items(): receipt = self.con.eth_getTransactionReceipt(tx) if receipt is not None and 'blockNumber' in receipt: actual_block_number = ethereum.utils.parse_int_or_hex(receipt['blockNumber']) else: ## TODO: wasn't confirmed after a long time. actual_block_number = False ## Now compare against the block_number where it was actually included: if actual_block_number is not False: if callback is not False: callback(receipt) del self.pending_transactions[tx] return had_any_events def _start_background_thread(self, terminate_on_exception = False, ): last_event = False while True: try: had_any_events = self.loop_once_blockchain() except Exception as e: print ('-----LOOP_ONCE_EXCEPTION', e) #exit(-1) raise if terminate_on_exception: raise continue if had_any_events: last_event = time() else: print ('NO_NEW_EVENTS', last_event and (time() - last_event)) sleep(self.background_thread_sleep_time) def start_background_thread(self, start_in_foreground = False, terminate_on_exception = False, ): """ Start ContractWrapper loop_once() in background thread, which (in that thread!) calls back to self.process_event() """ if start_in_foreground: self._start_background_thread(terminate_on_exception = terminate_on_exception) else: self.t = Thread(target = self._start_background_thread, args = (terminate_on_exception,), ) self.t.daemon = True self.t.start() def loop_once_blockchain(self): ## Check for available write receipts: #self.poll_outgoing_receipts() self.loop_once_started = True ## Do write transactions transactions: while self.send_transaction_queue.qsize(): print ('TRY_TO_SEND') tries, args, kw = self.send_transaction_queue.get() try: self.inner_send_transaction(*args, **kw) except Exception as e: print ('FAILED_TO_SEND', e, tries, args, kw) sleep(1) ## TODO self.send_transaction_queue.put((tries + 1, args, kw)) break
from ethjsonrpc import EthJsonRpc # to use Parity-specific methods, import ParityEthJsonRpc import binascii c = EthJsonRpc("something.420blaze.in", 8545) print c.net_version() chars = [""] * 256 for i in range(500): tx = c.eth_getBlockByNumber(i, True) if len(tx['transactions']) > 1: inp = binascii.unhexlify(tx['transactions'][0]['input'][2:]) if 'character' in inp: index = ord( inp.split( "\xd1\xd1>\xbf\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" )[1][0]) char = inp.split("character: ")[1][0] print index, char chars[index] = char print "".join(chars)
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) for x in ['earliest', 'latest', 'pending', b[0]]: print c.eth_getBlockByNumber(x, tx_objects=False) tx = '0x12cd5d9a82049154c8990214a551479853d1bfe45852688833bc4ef86a29b1a3' print c.eth_getTransactionByHash(tx) ################################################################################ print '*' * 80 code = 'contract Test {}' print c.eth_compileSolidity(code) #code = '' #print c.eth_compileSerpent(code) #code = '' #print c.eth_compileLLL(code)
# k = 'my_key' # v = '0xabcdef' # print(geth_client.db_putHex(db_name, k, v)) # x = geth_client.db_getHex(db_name, k) # print(x) # assert v == x ################################################################################ print('*' * 80) b = (199583, '0x19d761c6f944eefe91ad70b9aff3d2d76c972e5bb68c443eea7c0eaa144cef9f') print(geth_client.eth_getBlockByHash(b[1], tx_objects=False)) for x in ['earliest', 'latest', 'pending', b[0]]: print(geth_client.eth_getBlockByNumber(x, tx_objects=False)) tx = '0x12cd5d9a82049154c8990214a551479853d1bfe45852688833bc4ef86a29b1a3' print(geth_client.eth_getTransactionByHash(tx)) ################################################################################ print('*' * 80) code = 'contract Test {}' print(geth_client.eth_compileSolidity(code)) #code = '' #print(geth_client.eth_compileSerpent(code) #code = '' #print(geth_client.eth_compileLLL(code)