def test_getters(): minimal_code = \ """ pragma solidity ^0.4.6; contract Test { uint256 public the_var = 5; } """ from ethjsonrpc import EthJsonRpc c = EthJsonRpc('127.0.0.1', 9999) xx = c.eth_compileSolidity(minimal_code) compiled = xx['code'] contract_tx = c.create_contract( c.eth_coinbase(), compiled, gas=3000000, ) contract_address = str(c.get_contract_address(contract_tx)) rr = c.call( address=contract_address, sig='the_var()', args=[], result_types=['uint256'], ) assert rr[0] == 5, rr print('PASSED')
class AddressToUrlTestCase(unittest.TestCase): def setUp(self): with open('compiled.evm') as f: compiled = f.read().rstrip() self.c = EthJsonRpc() self.c._call('evm_reset') self.cb = self.c.eth_coinbase() self.contract_addr = self.AddressToUrl(self.cb, compiled) def tearDown(self): pass def test_set(self): url = 'http://www.yahoo.com' self.set_url(self.cb, self.contract_addr, url) result = self.get_url(self.contract_addr, self.cb[2:]) self.assertEqual(url, result) def test_set_clear(self): url = 'http://www.yahoo.com' self.set_url(self.cb, self.contract_addr, url) result = self.get_url(self.contract_addr, self.cb[2:]) self.assertEqual(url, result) self.set_url(self.cb, self.contract_addr, '') result = self.get_url(self.contract_addr, self.cb[2:]) self.assertEqual('', result) def test_get(self): result = self.get_url(self.contract_addr, self.cb[2:]) self.assertEqual('', result) ################################################################################ def AddressToUrl(self, sender, compiled): ''' constructor ''' sig = 'AddressToUrl()' args = [] tx = self.c.create_contract(sender, compiled, 300000, sig, args) return self.c.get_contract_address(tx) def set_url(self, sender, contract_addr, ip): sig = 'set_url(string)' args = [ip] self.c.call_with_transaction(sender, contract_addr, sig, args) def get_url(self, contract_addr, addr): sig = 'get_url(address)' args = [addr] result_types = ['string'] return self.c.call(contract_addr, sig, args, result_types)[0]
def main(): # # create rpc interface # try: rpc = EthJsonRpc(RPC_HOST, RPC_PORT) except: print('unable to connect to rpc server at {}:{}'.format( RPC_HOST, RPC_PORT)) sys.exit(-1) method = sys.argv[1] if method == "newContract": owner = sys.argv[2] partner = sys.argv[3] text = sys.argv[4] tx = rpc.call_with_transaction(owner, CONTRACT_STORAGE_ADDRESS, 'createNewContract(string,string)', [partner, text], gas=GAS) print(format(tx)) elif method == "contractData": trans_addr = sys.argv[2] trans = rpc.eth_getTransactionByHash(trans_addr) res = Decoder.decodeABI(trans['input'], 'createNewContract(string,string)', ['string', 'string']) print(res) elif method == "newUser": address = sys.argv[2] dataString = sys.argv[3] tx = rpc.call_with_transaction(address, USER_STORAGE_ADDRESS, 'setUserIdentityDocs(string)', [dataString], gas=GAS) elif method == "identification": account_addr = sys.argv[2] transactionHashes, identityDocuments = rpc.call( USER_STORAGE_ADDRESS, 'getUser(address)', [account_addr], ['string', 'string']) print(identityDocuments) elif method == "accounts": account_id = sys.argv[2] print(rpc.eth_accounts()[int(account_id)]) else: print("method not recognized!")
def main01(): load_dotenv() eth_host = os.environ.get('ETH_HOST') eth_port = os.environ.get('ETH_PORT') contract_addr = os.environ.get('CONTRACT_ADDR') c = EthJsonRpc(eth_host, eth_port) # data = c.call(contract_addr, 'rooms(uint256)', [0], ['Room']) # print(data) data = c.call(contract_addr, 'name()', [], ['string']) print(decode(data, 'string'))
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
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 Ipv4TestCase(unittest.TestCase): def setUp(self): with open('compiled.evm') as f: compiled = f.read().rstrip() self.c = EthJsonRpc() self.c._call('evm_reset') self.cb = self.c.eth_coinbase() self.contract_addr = self.AddressToIPv4(self.cb, compiled) def tearDown(self): pass ################################################################################ def test_read(self): result = self.get_ip(self.contract_addr, self.cb[2:]) unchained_ip = self.ip_from_chain(result) self.assertEqual('0.0.0.0', unchained_ip) def test_set_read(self): ip = u'192.168.1.1' chained_ip = self.ip_to_chain(ip) self.set_ip(self.cb, self.contract_addr, chained_ip) result = self.get_ip(self.contract_addr, self.cb[2:]) unchained_ip = self.ip_from_chain(result) self.assertEqual(ip, unchained_ip) def test_set_delete_read(self): ip = u'192.168.1.1' chained_ip = self.ip_to_chain(ip) self.set_ip(self.cb, self.contract_addr, chained_ip) self.delete_ip(self.cb, self.contract_addr) result = self.get_ip(self.contract_addr, self.cb[2:]) unchained_ip = self.ip_from_chain(result) self.assertEqual('0.0.0.0', unchained_ip) ################################################################################ def ip_to_chain(self, ip): return int(IPv4Address(ip)) def ip_from_chain(self, ip): return str(IPv4Address(ip)) ################################################################################ def AddressToIPv4(self, sender, compiled): ''' constructor ''' sig = 'AddressToIPv4()' args = [] tx = self.c.create_contract(sender, compiled, sig, args) return self.c.get_contract_address(tx) def set_ip(self, sender, contract_addr, ip): sig = 'set_ip(uint32)' args = [ip] self.c.call_with_transaction(sender, contract_addr, sig, args) def delete_ip(self, sender, contract_addr): sig = 'delete_ip()' args = [] self.c.call_with_transaction(sender, contract_addr, sig, args) def get_ip(self, contract_addr, addr): sig = 'get_ip(address)' args = [addr] result_types = ['uint32'] return self.c.call(contract_addr, sig, args, result_types)[0]
def main(): # # create rpc interface # try: rpc = EthJsonRpc(RPC_HOST, RPC_PORT) except: print('unable to connect to rpc server at {}:{}'.format( RPC_HOST, RPC_PORT)) sys.exit(-1) if sys.argv[1] == "contracts": transactionHashes, identityDocuments = rpc.call( USER_STORAGE_ADDRESS, 'getUser(address)', [0x866d9f0b315afa2dcf31be291882ae9a1965f86a], ['string', 'string']) print(transactionHashes) elif sys.argv[1] == "newContract": owner = sys.argv[2] partner = sys.argv[3] text = sys.argv[4] tx = rpc.call_with_transaction(owner, CONTRACT_STORAGE_ADDRESS, 'createNewContract(string,string)', [partner, text], gas=GAS) print('done, transaction id: {}'.format(tx)) transHash = format(tx) trans = rpc.eth_getTransactionByHash(transHash) res = Decoder.decodeABI(trans['input'], 'createNewContract(string,string)', ['string', 'string']) print(res) transHashes = transHash #rpc.call(USER_STORAGE_ADDRESS, 'getUserTransactions(address)', [owner], ['string']) #transHashes += "," + transHash; tx = rpc.call_with_transaction(owner, USER_STORAGE_ADDRESS, 'setUserTransactions(string)', [transHashes], gas=GAS) trans = rpc.eth_getTransactionByHash(format(tx)) res = Decoder.decodeABI(trans['input'], 'setUserTransactions(string)', ['string']) print(res) transHashes = transHash #rpc.call(USER_STORAGE_ADDRESS, 'getUserTransactions(address)', [partner], ['string']) #transHashes += "," + transHash; tx = rpc.call_with_transaction(partner, USER_STORAGE_ADDRESS, 'setUserTransactions(string)', [transHashes], gas=GAS) print('done, transaction id: {}'.format(tx)) trans = rpc.eth_getTransactionByHash(format(tx)) res = Decoder.decodeABI(trans['input'], 'setUserTransactions(string)', ['string']) print(res) owner = "0x866d9f0b315afa2dcf31be291882ae9a1965f86a" partner = "0x115908c9272fc6b915286de90e25a24862d69988"
def main(): """ Runs doorman and listens for incoming whispers on the configured node. When receiving a valid command, starts the configured script with the arguments address and command. """ if len(sys.argv) < 2: config_filepath = "/etc/lokkit/doorman.yml" else: config_filepath = sys.argv[1] if not os.path.isfile(config_filepath): logger.error( 'Error reading the config file "{}": The file does not exist'. format(config_filepath)) _print_help() return 1 logger.info("Reading config file: {}".format(config_filepath)) config = _parse_config_file(config_filepath) if not config: logger.error( "Config file could not be parsed: {}".format(config_filepath)) _print_help() return 1 host = config['node_ip'] port = config['node_rpc_port'] rentable_addresses = config['rentable_addresses'] script = config['script'] symmetric_key_password = config['symmetric_key_password'] logger.info('Connecting to {0}:{1}'.format(host, port)) c = EthJsonRpc(host, port) try: logger.info('Node shh version: {0}'.format(c.shh_version())) except ConnectionError: logger.error('Could not connect to {0}:{1}'.format(host, port)) return except: logger.error('Shh is not enabled on this node.') return # config topics = [] logger.info('listening for whispers for {0} addresses'.format( len(rentable_addresses))) for rentable_address in rentable_addresses: try: description = c.call(rentable_address, 'description()', [], ['string'])[0] deposit = c.call(rentable_address, 'deposit()', [], ['uint256'])[0] location = c.call(rentable_address, 'location()', [], ['string'])[0] costPerSecond = c.call(rentable_address, 'costPerSecond()', [], ['uint256'])[0] current_renter = c.call(rentable_address, 'currentRenter()', [], ['address'])[0] address_sha3 = c.web3_sha3(rentable_address)[:10] topics.append(address_sha3) logger.info('Configured rentable contract {0}\n\ description: {1}\n\ location: {2}\n\ deposit: {3}\n\ costPerSecond: {4}\n\ current_renter: {5}\n\ address sha3: {6}'.format(rentable_address, description, location, deposit, costPerSecond, current_renter, address_sha3)) except AssertionError: logger.error( 'Address {0} is not a Rentable'.format(rentable_address)) return symmetric_key_address = c.shh_addSymmetricKeyFromPassword( symmetric_key_password) filter_id = c.shh_subscribe(type='sym', key=symmetric_key_address, sig=None, minPow=None, topics=topics) logger.info('Listen for incomming messages..') try: while True: messages = c.shh_getNewSubscriptionMessages(filter_id) for message in messages: logger.debug( 'Message details:\n hash {0}\n ttl {1}\n payload: {2}\n topic: {3}' .format(message['hash'], message['ttl'], message['payload'], message['topic'])) payload = None try: # payload contains digest and message message_payload_string = message['payload'][2:].decode( 'hex') payload = json.loads(message_payload_string, object_pairs_hook=OrderedDict) except: logger.error( 'Error parsing whisper message payload: {0}'.format( message['payload'])) continue signature = payload['digest'] # hex value starting with 0x.... lokkit_message = payload['message'] # dict object logger.debug('signature: {0}\nlokkit_message {1}'.format( signature, lokkit_message)) # get ethereum address of the sender message_json = json.dumps( lokkit_message, separators=(',', ':')) # separators: no whitespaces message_hex_string = '0x{0}'.format(message_json.encode('hex')) logger.debug( 'message_json_string {0}\nmessage_json_string_hex {1}'. format(message_json, message_hex_string)) signer = c.personal_ecRecover(message_hex_string, signature) key = lokkit_message['key'] logger.info( 'command "{0}", rentableAddress "{1}", key "{2}"'.format( lokkit_message['command'], lokkit_message['rentableAddress'], key)) logger.info( 'signing ethereum account (recovered) "{0}"'.format( signer)) current_renter = c.call(rentable_address, 'currentRenter()', [], ['address'])[0] logger.info( 'current renter (smart contract) "0x{0}"'.format( current_renter)) if signer[2:] != current_renter: logger.error( 'Refuse execution of command "{0}": requester ({1}) is not the current renter ({2}) of rentable "{3}"' .format(lokkit_message['command'], signer, current_renter, lokkit_message['rentableAddress'])) continue if message['sig'] == '': logger.error( 'The envelope was not signed by the sender. Signature with an asymmetric key is required.' ) continue if key != message['sig']: logger.error( 'Encrypted public key is not of the sender. Possible replay attack detected' ) logger.error(key) logger.error(message['sig']) continue logger.info( 'Executing script "{0}" with argument "{1}" for rentable "{2}"' .format(script, lokkit_message['command'], lokkit_message['rentableAddress'])) subprocess.call([script, lokkit_message['command']]) sleep(1) except KeyboardInterrupt: pass
class LiteIDContract: def __init__(self, ip='127.0.0.1', port=8545, contract_id=None): self.connection = EthJsonRpc(ip, port) self.contract_id = contract_id self.abi_def = [{ "constant": False, "inputs": [], "name": "dumpSaltedHashArray", "outputs": [{ "name": "Hashes", "type": "bytes32[]" }, { "name": "Salts", "type": "bytes32[]" }, { "name": "Timestamps", "type": "uint256[]" }], "payable": False, "type": "function" }, { "constant": False, "inputs": [{ "name": "Hash", "type": "bytes32" }, { "name": "Salt", "type": "bytes32" }], "name": "addHash", "outputs": [], "payable": False, "type": "function" }, { "inputs": [{ "name": "Hash", "type": "bytes32" }, { "name": "Salt", "type": "bytes32" }], "payable": False, "type": "constructor" }] @staticmethod def _calculate_hash(data_to_hash): salt = SHA256.new() salt.update(bytes(random.getrandbits(256))) original_hash = SHA256.new() original_hash.update(data_to_hash) salted_hash = SHA256.new() salted_hash.update(original_hash.digest() + salt.digest()) salt = salt.hexdigest().decode("hex") original_hash = original_hash.hexdigest().decode("hex") salted_hash = salted_hash.hexdigest().decode("hex") return salted_hash, salt, original_hash, data_to_hash def unlock_account(self, account, password): self.connection._call('personal_unlockAccount', params=[account, password, 36000]) def add_hash(self, data): if self.contract_id is None: raise IOError salted_hash, salt, original_hash, _ = self._calculate_hash(data) tx = self.connection.call_with_transaction( self.connection.eth_coinbase(), self.contract_id, 'addHash(bytes32,bytes32)', [salted_hash, salt]) print("Waiting for addHash to be mined") while self.connection.eth_getTransactionReceipt(tx) is None: time.sleep(1) return original_hash def create_contract(self, data): if not hasattr(self, 'byte_code'): contract_file = open(__file__[:-11] + '\LiteID-Contract.sol') code_data = self.connection.eth_compileSolidity( contract_file.read()) self.byte_code = code_data['ID']['code'] self.abi_def = code_data['ID']['info']['abiDefinition'] salted_hash, salt, original_hash, _ = self._calculate_hash(data) tx_id = self.connection.create_contract(self.connection.eth_coinbase(), self.byte_code, 300000, sig='addHash(bytes32,bytes32)', args=[salted_hash, salt]) print("Waiting for contract to be mined") while self.connection.eth_getTransactionReceipt(tx_id) is None: time.sleep(1) self.contract_id = self.connection.eth_getTransactionReceipt( tx_id)['contractAddress'] return self.contract_id def dump_hashes(self): return_types = list() for item in self.abi_def: try: if item['name'] == 'dumpSaltedHashArray': for i in item['outputs']: return_types.append(i['type']) except KeyError: pass return_types = ['bytes32[]', 'bytes32[]', 'uint256[]'] return self.connection.call(self.contract_id, 'dumpSaltedHashArray()', [], return_types)
import sys, os, time #from solc import compile_source, compile_files, link_code from ethjsonrpc import EthJsonRpc import RPi.GPIO as GPIO from telnetlib import theNULL GPIO.setwarnings(False) GPIO.setmode(GPIO.BCM) GPIO.setup(4, GPIO.OUT) GPIO.setup(17, GPIO.OUT) GPIO.setup(27, GPIO.OUT) GPIO.setup(22, GPIO.OUT) relays = [4, 17, 27, 22] results = [1] c = EthJsonRpc('192.168.0.109', 8545) #compiled = "6060604052341561000f57600080fd5b6102e38061001e6000396000f30060606040526004361061004c576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806375d74f3914610051578063e7aab290146100df575b600080fd5b341561005c57600080fd5b61006461013c565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156100a4578082015181840152602081019050610089565b50505050905090810190601f1680156100d15780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34156100ea57600080fd5b61013a600480803590602001908201803590602001908080601f016020809104026020016040519081016040528093929190818152602001838380828437820191505050505050919050506101e4565b005b6101446101fe565b60008054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156101da5780601f106101af576101008083540402835291602001916101da565b820191906000526020600020905b8154815290600101906020018083116101bd57829003601f168201915b5050505050905090565b80600090805190602001906101fa929190610212565b5050565b602060405190810160405280600081525090565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061025357805160ff1916838001178555610281565b82800160010185558215610281579182015b82811115610280578251825591602001919060010190610265565b5b50905061028e9190610292565b5090565b6102b491905b808211156102b0576000816000905550600101610298565b5090565b905600a165627a7a72305820a1b6671ab3bfba7a22ca49ff7a553d8902a18e098e285942773f570bbc6868b20029" #contractTx = c.create_contract(c.eth_coinbase(), compiled, gas=300000) #contractAddr = c.get_contract_address(contractTx) contractAddr = '0xed4b68c46a5fc176e62fb66b2fe840dc4e5812a8' while (True): time.sleep(5) for x in range(0, 4): #print(relays[x]) results = c.call(contractAddr, 'getRelay(uint256)', [x], ['uint256', 'uint256']) GPIO.output(relays[x], results[0]) print(results) time.sleep(1)
from ethjsonrpc import EthJsonRpc # to use Parity-specific methods, import ParityEthJsonRpc base_address = "0xbb1588c5debc2871cd8852c4bd6c6e4cb1d9fe15" c = EthJsonRpc('127.0.0.1', 8545) print(c.net_version()) print(c.web3_clientVersion()) print(c.net_listening()) print(c.net_peerCount()) print(c.eth_mining()) print(c.eth_gasPrice()) contract_addr = "0xc1bba31875a1a66eb4794e6e4dd07811fb58b5c5" my_addr = str(c.eth_coinbase()) print my_addr tx = c.call_with_transaction(my_addr, contract_addr, 'pushByte(string)', ['Hello, world']) print(tx) results = c.call(contract_addr, 'getdata()', [], ['string']) print(results)