diff --git a/eospy/__init__.py b/eospy/__init__.py index 8b13789..e69de29 100644 --- a/eospy/__init__.py +++ b/eospy/__init__.py @@ -1 +0,0 @@ - diff --git a/eospy/cleos.py b/eospy/cleos.py index 86a927a..4f306c8 100644 --- a/eospy/cleos.py +++ b/eospy/cleos.py @@ -12,25 +12,26 @@ import os from binascii import hexlify -class Cleos : - - def __init__(self, url='http://localhost:8888', version='v1') : + +class Cleos: + + def __init__(self, url='http://localhost:8888', version='v1'): ''' ''' self._prod_url = url self._version = version self._dynurl = DynamicUrl(url=self._prod_url, version=self._version) - + ##### # private functions ##### - def get(self, func='', **kwargs) : + def get(self, func='', **kwargs): ''' ''' cmd = eval('self._dynurl.{0}'.format(func)) url = cmd.create_url() return cmd.get_url(url, **kwargs) - def post(self, func='', **kwargs) : + def post(self, func='', **kwargs): ''' ''' cmd = eval('self._dynurl.{0}'.format(func)) url = cmd.create_url() @@ -39,92 +40,92 @@ def post(self, func='', **kwargs) : ##### # get methods ##### - def get_info(self, timeout=30) : + def get_info(self, timeout=30): ''' ''' return self.get('chain.get_info', timeout=timeout) - def get_chain_lib_info(self, timeout=30) : + def get_chain_lib_info(self, timeout=30): ''' ''' chain_info = self.get('chain.get_info', timeout=timeout) lib_info = self.get_block(chain_info['last_irreversible_block_num'], timeout=timeout) return chain_info, lib_info - - def get_block(self, block_num, timeout=30) : + + def get_block(self, block_num, timeout=30): ''' ''' - return self.post('chain.get_block', params=None, json={'block_num_or_id' : block_num}, timeout=timeout) - - def get_account(self, acct_name, timeout=30) : + return self.post('chain.get_block', params=None, json={'block_num_or_id': block_num}, timeout=timeout) + + def get_account(self, acct_name, timeout=30): ''' ''' - return self.post('chain.get_account', params=None, json={'account_name' : acct_name}, timeout=timeout) + return self.post('chain.get_account', params=None, json={'account_name': acct_name}, timeout=timeout) - def get_code(self, acct_name, code_as_wasm=True, timeout=30) : + def get_code(self, acct_name, code_as_wasm=True, timeout=30): ''' ''' - return self.post('chain.get_code', params=None, json={'account_name':acct_name, 'code_as_wasm':code_as_wasm}, timeout=timeout) - - def get_accounts(self, public_key, timeout=30) : + return self.post('chain.get_code', params=None, json={'account_name': acct_name, 'code_as_wasm': code_as_wasm}, timeout=timeout) + + def get_accounts(self, public_key, timeout=30): ''' ''' - return self.post('history.get_key_accounts', params=None, json={'public_key':public_key}, timeout=timeout) + return self.post('history.get_key_accounts', params=None, json={'public_key': public_key}, timeout=timeout) - def get_abi(self, acct_name, timeout=30) : + def get_abi(self, acct_name, timeout=30): ''' ''' - return self.post('chain.get_abi', params=None, json={'account_name' : acct_name}, timeout=timeout) + return self.post('chain.get_abi', params=None, json={'account_name': acct_name}, timeout=timeout) - def get_raw_abi(self, acct_name, timeout=30) : + def get_raw_abi(self, acct_name, timeout=30): ''' ''' - return self.post('chain.get_raw_abi', params=None, json={'account_name' : acct_name}, timeout=timeout) - - def get_actions(self, acct_name, pos=-1, offset=-20, timeout=30) : + return self.post('chain.get_raw_abi', params=None, json={'account_name': acct_name}, timeout=timeout) + + def get_actions(self, acct_name, pos=-1, offset=-20, timeout=30): ''' POST /v1/history/get_actions {"account_name":"eosnewyorkio","pos":-1,"offset":-20} ''' - json={'account_name' : acct_name, "pos" : pos, "offset" : offset} + json = {'account_name': acct_name, "pos": pos, "offset": offset} return self.post('history.get_actions', params=None, json=json, timeout=timeout) - def get_currency(self, code='eosio.token', symbol='EOS', timeout=30) : + def get_currency(self, code='eosio.token', symbol='EOS', timeout=30): ''' POST /v1/chain/get_currency_stats HTTP/1.0 {"json":false,"code":"eosio.token","symbol":"EOS"} ''' - json={'json':False, 'code':code, 'symbol':symbol} + json = {'json': False, 'code': code, 'symbol': symbol} return self.post('chain.get_currency_stats', params=None, json=json, timeout=timeout) - def get_currency_balance(self, account, code='eosio.token', symbol='EOS', timeout=30) : - ''' - POST /v1/chain/get_currency_balance HTTP/1.0 - {"account":"eosio","code":"eosio.token","symbol":"EOS"} - ''' - json={'account':account, 'code':code, 'symbol':symbol} - return self.post('chain.get_currency_balance', params=None, json=json, timeout=timeout) - - def get_currency_stats(self, code, symbol, timeout=30) : - return self.post('chain.get_currency_stats', json={'code':code, 'symbol':symbol}) - - def get_servants(self, acct_name, timeout=30) : + def get_currency_balance(self, account, code='eosio.token', symbol='EOS', timeout=30): + ''' + POST /v1/chain/get_currency_balance HTTP/1.0 + {"account":"eosio","code":"eosio.token","symbol":"EOS"} + ''' + json = {'account': account, 'code': code, 'symbol': symbol} + return self.post('chain.get_currency_balance', params=None, json=json, timeout=timeout) + + def get_currency_stats(self, code, symbol, timeout=30): + return self.post('chain.get_currency_stats', json={'code': code, 'symbol': symbol}) + + def get_servants(self, acct_name, timeout=30): ''' ''' - return self.post('account_history.get_controlled_accounts', params=None, json={'controlling_account':acct_name}, timeout=timeout) + return self.post('account_history.get_controlled_accounts', params=None, json={'controlling_account': acct_name}, timeout=timeout) - def get_transaction(self, trans_id, timeout=30) : + def get_transaction(self, trans_id, timeout=30): ''' POST /v1/history/get_transaction {"id":"abcd1234"} ''' return self.post('history.get_transaction', params=None, json={'id': trans_id}, timeout=timeout) - def get_table(self, code, scope, table, index_position='',key_type='', lower_bound='', upper_bound='', limit=10, timeout=30) : + def get_table(self, code, scope, table, index_position='', key_type='', lower_bound='', upper_bound='', limit=10, timeout=30): ''' POST /v1/chain/get_table_rows {"json":true,"code":"eosio","scope":"eosio","table":"producers","index_position":"","key_type":"name","lower_bound":"","upper_bound":"","limit":10} ''' - json = {"json":True, "code":code, "scope":scope, "table":table, "key_type":key_type, "index_position":index_position, "lower_bound": lower_bound, "upper_bound": upper_bound, "limit": limit} + json = {"json": True, "code": code, "scope": scope, "table": table, "key_type": key_type, "index_position": index_position, "lower_bound": lower_bound, "upper_bound": upper_bound, "limit": limit} return self.post('chain.get_table_rows', params=None, json=json, timeout=timeout) - def get_producers(self, lower_bound='', limit=50, timeout=30) : + def get_producers(self, lower_bound='', limit=50, timeout=30): ''' POST /v1/chain/get_producers HTTP/1.0 {"json":true,"lower_bound":"","limit":50} ''' - return self.post('chain.get_producers', params=None, json={'json':True, 'lower_bound':lower_bound, 'limit':limit}, timeout=timeout) + return self.post('chain.get_producers', params=None, json={'json': True, 'lower_bound': lower_bound, 'limit': limit}, timeout=timeout) ##### # set @@ -135,14 +136,14 @@ def set_abi(self, account, permission, abi_file, key, broadcast=True, timeout=30 current_sha = sha256(current_abi.get_raw().encode('utf-8')) with open(abi_file) as rf: abi = json.load(rf) - new_abi = Abi(abi) + new_abi = Abi(abi) # hex_abi = hexlify(abi) new_sha = sha256(new_abi.get_raw().encode('utf-8')) if current_sha == new_sha: raise EOSSetSameAbi() # generate trx arguments = { - "account": account, + "account": account, "abi": new_abi.get_raw() } payload = { @@ -161,7 +162,6 @@ def set_abi(self, account, permission, abi_file, key, broadcast=True, timeout=30 sign_key = EOSKey(key) return self.push_transaction(trx, sign_key, broadcast=broadcast) - def set_code(self, account, permission, code_file, key, broadcast=True, timeout=30): current_code = self.get_code(account) # print(current_code) @@ -195,14 +195,14 @@ def set_code(self, account, permission, code_file, key, broadcast=True, timeout= trx = {"actions": [payload]} sign_key = EOSKey(key) return self.push_transaction(trx, sign_key, broadcast=broadcast) - ##### # transactions ##### + def push_transaction(self, transaction, keys, broadcast=True, compression='none', timeout=30): ''' parameter keys can be a list of WIF strings or EOSKey objects or a filename to key file''' - chain_info,lib_info = self.get_chain_lib_info() + chain_info, lib_info = self.get_chain_lib_info() trx = Transaction(transaction, chain_info, lib_info) #encoded = trx.encode() digest = sig_digest(trx.encode(), chain_info['chain_id']) @@ -215,58 +215,58 @@ def push_transaction(self, transaction, keys, broadcast=True, compression='none' raise EOSKeyError('Must pass a class that extends the eospy.Signer class') keys = [keys] - for key in keys : + for key in keys: # if check_wif(key) : # k = EOSKey(key) - if not isinstance(key, Signer) : - raise EOSKeyError('Must pass a class that extends the eospy.Signer class') + if not isinstance(key, Signer): + raise EOSKeyError('Must pass a class that extends the eospy.Signer class') signatures.append(key.sign(digest)) # build final trx final_trx = { - 'compression' : compression, - 'transaction' : trx.__dict__, - 'signatures' : signatures + 'compression': compression, + 'transaction': trx.__dict__, + 'signatures': signatures } data = json.dumps(final_trx, cls=EOSEncoder) - if broadcast : + if broadcast: return self.post('chain.push_transaction', params=None, data=data, timeout=timeout) return data - - def push_block(self, timeout=30) : + + def push_block(self, timeout=30): raise NotImplementedError - + ##### - # bin/json + # bin/json ##### - - def abi_bin_to_json(self, code, action, binargs, timeout=30) : + + def abi_bin_to_json(self, code, action, binargs, timeout=30): ''' ''' - json = {'code':code, 'action':action, 'binargs': binargs} + json = {'code': code, 'action': action, 'binargs': binargs} return self.post('chain.abi_bin_to_json', params=None, json=json, timeout=timeout) - def abi_json_to_bin(self, code, action, args, timeout=30) : + def abi_json_to_bin(self, code, action, args, timeout=30): ''' ''' - json = {'code':code, 'action':action, 'args': args} + json = {'code': code, 'action': action, 'args': args} return self.post('chain.abi_json_to_bin', params=None, json=json, timeout=timeout) - + ##### # create keys ##### - def create_key(self) : + def create_key(self): ''' ''' k = EOSKey() return k - + ##### # multisig ##### - + def multisig_review(self, proposer, proposal): - ''' ''' + ''' ''' review = [] prop = self.get_table(code="eosio.msig", scope=proposer, table="proposal", lower_bound=proposal, limit=1) - if prop['rows'] : + if prop['rows']: for row in prop['rows']: packed = PackedTransaction(row['packed_transaction'], self) trx = packed.get_transaction() @@ -280,102 +280,99 @@ def multisig_review(self, proposer, proposal): review = p else: raise EOSMsigInvalidProposal("{} is not a valid proposal".format(proposal)) - # + # return review - - + ##### # system functions ##### - def vote_producers(self, voter, proxy, producers) : - return self.get('chain.abi_json_to_bin', params=None,json={"voter":voter, "proxy":proxy,"producers":producers}) + def vote_producers(self, voter, proxy, producers): + return self.get('chain.abi_json_to_bin', params=None, json={"voter": voter, "proxy": proxy, "producers": producers}) - - def create_account(self, creator, creator_privkey, acct_name, owner_key, - active_key='', stake_net='1.0000 EOS', stake_cpu='1.0000 EOS', ramkb=8, permission='active', - transfer=False, broadcast=True, timeout=30) : + def create_account(self, creator, creator_privkey, acct_name, owner_key, + active_key='', stake_net='1.0000 EOS', stake_cpu='1.0000 EOS', ramkb=8, permission='active', + transfer=False, broadcast=True, timeout=30): ''' ''' # check account doesn't exist - try : + try: self.get_account(acct_name) #print('{} already exists.'.format(acct_name)) raise ValueError('{} already exists.'.format(acct_name)) - except: + except: pass - if not active_key : + if not active_key: active_key = owner_key # create newaccount trx owner_auth = { - "threshold": 1, - "keys": [{ - "key": owner_key, - "weight": 1 - }], - "accounts": [], - "waits": [] - } - active_auth ={ - "threshold": 1, - "keys": [{ - "key": active_key, - "weight": 1 - } ], - "accounts": [], - "waits": [] - } + "threshold": 1, + "keys": [{ + "key": owner_key, + "weight": 1 + }], + "accounts": [], + "waits": [] + } + active_auth = { + "threshold": 1, + "keys": [{ + "key": active_key, + "weight": 1 + }], + "accounts": [], + "waits": [] + } print({ - 'creator' : creator, - 'name' : acct_name, - 'owner' : owner_auth, - 'active' : active_auth + 'creator': creator, + 'name': acct_name, + 'owner': owner_auth, + 'active': active_auth }) - - newaccount_data = self.abi_json_to_bin('eosio', 'newaccount',{'creator' : creator, 'name' : acct_name, 'owner': owner_auth, 'active':active_auth}) + + newaccount_data = self.abi_json_to_bin('eosio', 'newaccount', {'creator': creator, 'name': acct_name, 'owner': owner_auth, 'active': active_auth}) print(newaccount_data) newaccount_json = { - 'account' : 'eosio', - 'name' : 'newaccount', - 'authorization' : [ - { - 'actor' : creator, - 'permission' : permission - } ], - 'data' : newaccount_data['binargs'] + 'account': 'eosio', + 'name': 'newaccount', + 'authorization': [ + { + 'actor': creator, + 'permission': permission + }], + 'data': newaccount_data['binargs'] } # create buyrambytes trx - buyram_data = self.abi_json_to_bin('eosio', 'buyrambytes', {'payer':creator, 'receiver':acct_name, 'bytes': ramkb*1024}) + buyram_data = self.abi_json_to_bin('eosio', 'buyrambytes', {'payer': creator, 'receiver': acct_name, 'bytes': ramkb * 1024}) buyram_json = { - 'account' : 'eosio', - 'name' : 'buyrambytes', - 'authorization' : [ + 'account': 'eosio', + 'name': 'buyrambytes', + 'authorization': [ { - 'actor' : creator, - 'permission' : permission - } ], - 'data' : buyram_data['binargs'] + 'actor': creator, + 'permission': permission + }], + 'data': buyram_data['binargs'] } # create delegatebw - delegate_data = self.abi_json_to_bin('eosio', 'delegatebw', - {'from': creator, 'receiver': acct_name, 'stake_net_quantity':stake_net, 'stake_cpu_quantity': stake_cpu, 'transfer': transfer }) + delegate_data = self.abi_json_to_bin('eosio', 'delegatebw', + {'from': creator, 'receiver': acct_name, 'stake_net_quantity': stake_net, 'stake_cpu_quantity': stake_cpu, 'transfer': transfer}) delegate_json = { - 'account' : 'eosio', - 'name' : 'delegatebw', - 'authorization' : [ + 'account': 'eosio', + 'name': 'delegatebw', + 'authorization': [ { - 'actor' : creator, - 'permission' : permission - } ], - 'data' : delegate_data['binargs'] + 'actor': creator, + 'permission': permission + }], + 'data': delegate_data['binargs'] } trx = {"actions": - [newaccount_json, buyram_json, delegate_json] - } + [newaccount_json, buyram_json, delegate_json] + } # push transaction return self.push_transaction(trx, creator_privkey, broadcast=broadcast, timeout=timeout) - def register_producer(self) : + def register_producer(self): raise NotImplementedError() - diff --git a/eospy/command_line.py b/eospy/command_line.py index de60c4d..c672ec6 100644 --- a/eospy/command_line.py +++ b/eospy/command_line.py @@ -5,9 +5,11 @@ from .exceptions import InvalidPermissionFormat, EOSSetSameAbi, EOSSetSameCode import json + def console_print(data): print(json.dumps(data, indent=4)) + def set_abi(ce, account, permission, abi, key, broadcast, timeout): print('setting abi file {}'.format(abi)) try: @@ -15,6 +17,7 @@ def set_abi(ce, account, permission, abi, key, broadcast, timeout): except EOSSetSameAbi: print('Skipping set abi because the new abi is the same as the existing abi') + def set_code(ce, account, permission, code, key, broadcast, timeout): print('setting code file {}'.format(code)) try: @@ -22,9 +25,10 @@ def set_code(ce, account, permission, code, key, broadcast, timeout): except EOSSetSameCode: print('Skipping set code because the new code is the same as the existing code') + def cleos(): parser = argparse.ArgumentParser(description='Command Line Interface to EOSIO via python') - parser.add_argument('--api-version','-v', type=str, default='v1', action='store', dest='api_version') + parser.add_argument('--api-version', '-v', type=str, default='v1', action='store', dest='api_version') parser.add_argument('--url', '-u', type=str, action='store', default='https://proxy.eosnode.tools', dest='url') parser.add_argument('--time-out', type=int, action='store', default=30, dest='timeout') subparsers = parser.add_subparsers(dest='subparser') @@ -36,28 +40,28 @@ def cleos(): # block block_parser = get_subparsers.add_parser('block') #block_parser.add_argument('block', type=str) - block_parser.add_argument('--block','-b', type=str, action='store', required=True, dest='block') + block_parser.add_argument('--block', '-b', type=str, action='store', required=True, dest='block') # account account_parser = get_subparsers.add_parser('account') - account_parser.add_argument('--account','-a', type=str, action='store', required=True, dest='account') + account_parser.add_argument('--account', '-a', type=str, action='store', required=True, dest='account') #account_parser.add_argument('account', type=str) # code code_parser = get_subparsers.add_parser('code') - code_parser.add_argument('--account','-a', type=str, action='store', required=True, dest='account') + code_parser.add_argument('--account', '-a', type=str, action='store', required=True, dest='account') #code_parser.add_argument('account', type=str) # abi abi_parser = get_subparsers.add_parser('abi') - abi_parser.add_argument('--account','-a', type=str, action='store', required=True, dest='account') + abi_parser.add_argument('--account', '-a', type=str, action='store', required=True, dest='account') abi_parser.add_argument('--raw', action='store_true', dest='raw') #abi_parser.add_argument('account', type=str) # table table_parser = get_subparsers.add_parser('table') table_parser.add_argument('--code', '-c', type=str, action='store', required=True, dest='code') table_parser.add_argument('--scope', '-S', type=str, action='store', required=True, dest='scope') - table_parser.add_argument('--table','-t', type=str, action='store', required=True, dest='table') + table_parser.add_argument('--table', '-t', type=str, action='store', required=True, dest='table') #table_parser.add_argument('contract', type=str, help='The contract who owns the table (required)') #table_parser.add_argument('scope', type=str, help='The scope within the contract in which the table is found (required)') - #table_parser.add_argu`ment('table', type=str, help='The name of the table as specified by the contract abi (required)') + # table_parser.add_argu`ment('table', type=str, help='The name of the table as specified by the contract abi (required)') table_parser.add_argument('--index', type=int, action='store', default=1, dest='index_position', help='Index number') table_parser.add_argument('--key-type', type=str, action='store', default="i64", dest='key_type', help='The key type of --index') table_parser.add_argument('--lower-bound', type=str, action='store', default=0, dest='lower_bound', help='The name of the key to index by as defined by the abi, defaults to primary key') @@ -65,26 +69,26 @@ def cleos(): table_parser.add_argument('--limit', type=int, action='store', default=1000, dest='limit') # currency currency = get_subparsers.add_parser('currency') - currency.add_argument('type',choices=['balance','stats'], type=str) - currency.add_argument('--code','-c', type=str, action='store', required=True, dest='code') - currency.add_argument('--symbol','-s', type=str, action='store', required=True, dest='symbol') - currency.add_argument('--account','-a', type=str, action='store', dest='account') + currency.add_argument('type', choices=['balance', 'stats'], type=str) + currency.add_argument('--code', '-c', type=str, action='store', required=True, dest='code') + currency.add_argument('--symbol', '-s', type=str, action='store', required=True, dest='symbol') + currency.add_argument('--account', '-a', type=str, action='store', dest='account') # accounts accounts = get_subparsers.add_parser('accounts') - accounts.add_argument('--key','-k', type=str, action='store', required=True, dest='key') + accounts.add_argument('--key', '-k', type=str, action='store', required=True, dest='key') # transaction transaction = get_subparsers.add_parser('transaction') - transaction.add_argument('--transaction','-t', type=str, action='store', required=True, dest='transaction') + transaction.add_argument('--transaction', '-t', type=str, action='store', required=True, dest='transaction') # actions actions = get_subparsers.add_parser('actions') - actions.add_argument('--account','-a', type=str, action='store', required=True, dest='account') + actions.add_argument('--account', '-a', type=str, action='store', required=True, dest='account') actions.add_argument('--pos', type=int, action='store', default=-1, dest='pos') actions.add_argument('--offset', type=int, action='store', default=-20, dest='offset') # bin2json bin_json = get_subparsers.add_parser('bin2json') - bin_json.add_argument('--code','-c', type=str, action='store', required=True, dest='code') - bin_json.add_argument('--action','-a', type=str, action='store', required=True, dest='action') - bin_json.add_argument('--binargs','-b', type=str, action='store', required=True, dest='binargs') + bin_json.add_argument('--code', '-c', type=str, action='store', required=True, dest='code') + bin_json.add_argument('--action', '-a', type=str, action='store', required=True, dest='action') + bin_json.add_argument('--binargs', '-b', type=str, action='store', required=True, dest='binargs') # json2bin # create create_parser = subparsers.add_parser('create') @@ -92,8 +96,8 @@ def cleos(): # create EOS key create_key = create_subparsers.add_parser('key') group_key = create_key.add_mutually_exclusive_group(required=True) - group_key.add_argument('--key-file','-k', type=str, action='store', help='file to output the keys too', dest='key_file') - group_key.add_argument('--to-console','-c', action='store_true', help='output to the console', dest='to_console') + group_key.add_argument('--key-file', '-k', type=str, action='store', help='file to output the keys too', dest='key_file') + group_key.add_argument('--to-console', '-c', action='store_true', help='output to the console', dest='to_console') # push push_parser = subparsers.add_parser('push') push_subparsers = push_parser.add_subparsers(dest='push') @@ -101,9 +105,9 @@ def cleos(): push_action.add_argument('account', type=str, action='store', help='account name for the contract to execute') push_action.add_argument('action', type=str, action='store', help='action to execute') push_action.add_argument('data', type=str, action='store', help='JSON string of the arguments to the contract action') - push_action.add_argument('--key-file','-k', type=str, action='store', required=True, help='file containing the private key that will be used', dest='key_file') - push_action.add_argument('--permission','-p', type=str, action='store', required=True, help='account and permission level to use, e.g \'account@permission\'', dest='permission') - push_action.add_argument('--dont-broadcast','-d', action='store_false', default=True, help='do not broadcast the transaction to the network.', dest='broadcast') + push_action.add_argument('--key-file', '-k', type=str, action='store', required=True, help='file containing the private key that will be used', dest='key_file') + push_action.add_argument('--permission', '-p', type=str, action='store', required=True, help='account and permission level to use, e.g \'account@permission\'', dest='permission') + push_action.add_argument('--dont-broadcast', '-d', action='store_false', default=True, help='do not broadcast the transaction to the network.', dest='broadcast') # multisig msig_parser = subparsers.add_parser('multisig') msig_subparsers = msig_parser.add_subparsers(dest='multisig') @@ -123,13 +127,13 @@ def cleos(): newacct_parser.add_argument('creator_key', type=str, action='store') newacct_parser.add_argument('account', type=str, action='store') newacct_parser.add_argument('owner', type=str, action='store') - newacct_parser.add_argument('--active','-a', type=str, action='store', dest='active') + newacct_parser.add_argument('--active', '-a', type=str, action='store', dest='active') newacct_parser.add_argument('--stake-net', type=str, action='store', default='1.0000 EOS', dest='stake_net') newacct_parser.add_argument('--stake-cpu', type=str, action='store', default='1.0000 EOS', dest='stake_cpu') newacct_parser.add_argument('--buy-ram-kbytes', type=int, action='store', default=8, dest='ramkb') - newacct_parser.add_argument('--permission','-p', type=str, action='store', default='active', dest='permission') + newacct_parser.add_argument('--permission', '-p', type=str, action='store', default='active', dest='permission') newacct_parser.add_argument('--transfer', action='store_true', default=False, dest='transfer') - newacct_parser.add_argument('--dont-broadcast','-d', action='store_false', default=True, dest='broadcast') + newacct_parser.add_argument('--dont-broadcast', '-d', action='store_false', default=True, dest='broadcast') # set set_parser = subparsers.add_parser('set') set_subparsers = set_parser.add_subparsers(dest='set', help='Set or update blockchain state') @@ -138,71 +142,71 @@ def cleos(): set_abi_parser.add_argument('account', type=str, action='store', help='The account to set code for') set_abi_parser.add_argument('abi', type=str, action='store', help='The fullpath containing the contract abi') set_abi_parser.add_argument('key', type=str, action='store', help='Key to sign ') - set_abi_parser.add_argument('--permission','-p', type=str, action='store', default='active', dest='permission') - set_abi_parser.add_argument('--dont-broadcast','-d', action='store_false', default=True, dest='broadcast') + set_abi_parser.add_argument('--permission', '-p', type=str, action='store', default='active', dest='permission') + set_abi_parser.add_argument('--dont-broadcast', '-d', action='store_false', default=True, dest='broadcast') # code set_code_parser = set_subparsers.add_parser('code') set_code_parser.add_argument('account', type=str, action='store', help='The account to set abi for') set_code_parser.add_argument('code', type=str, action='store', help='The fullpath containing the contract code') set_code_parser.add_argument('key', type=str, action='store', help='Key to sign the transaction') - set_code_parser.add_argument('--permission','-p', type=str, action='store', default='active', dest='permission') - set_code_parser.add_argument('--dont-broadcast','-d', action='store_false', default=True, dest='broadcast') + set_code_parser.add_argument('--permission', '-p', type=str, action='store', default='active', dest='permission') + set_code_parser.add_argument('--dont-broadcast', '-d', action='store_false', default=True, dest='broadcast') # contract set_contract_parser = set_subparsers.add_parser('contract') set_contract_parser.add_argument('account', type=str, action='store', help='The account to set abi for') set_contract_parser.add_argument('code', type=str, action='store', help='The fullpath containing the contract code') set_contract_parser.add_argument('abi', type=str, action='store', help='The fullpath containing the contract abo') set_contract_parser.add_argument('key', type=str, action='store', help='Key to sign the transaction') - set_contract_parser.add_argument('--permission','-p', type=str, action='store', default='active', dest='permission') - set_contract_parser.add_argument('--dont-broadcast','-d', action='store_false', default=True, dest='broadcast') + set_contract_parser.add_argument('--permission', '-p', type=str, action='store', default='active', dest='permission') + set_contract_parser.add_argument('--dont-broadcast', '-d', action='store_false', default=True, dest='broadcast') # process args args = parser.parse_args() - # - # connect + # + # connect ce = Cleos(url=args.url, version=args.api_version) # run commands based on subparser # GET - if args.subparser == 'get' : - if args.get == 'info' : + if args.subparser == 'get': + if args.get == 'info': console_print(ce.get_info(timeout=args.timeout)) - elif args.get == 'block' : + elif args.get == 'block': console_print(ce.get_block(args.block, timeout=args.timeout)) - elif args.get == 'account' : + elif args.get == 'account': console_print(ce.get_account(args.account, timeout=args.timeout)) - elif args.get == 'code' : + elif args.get == 'code': console_print(ce.get_code(args.account, timeout=args.timeout)) - elif args.get == 'abi' : + elif args.get == 'abi': if args.raw: console_print(ce.get_raw_abi(args.account, timeout=args.timeout)) else: console_print(ce.get_abi(args.account, timeout=args.timeout)) - elif args.get == 'table' : - console_print(ce.get_table(code=args.code, - scope=args.scope, - table=args.table, - index_position=args.index_position, + elif args.get == 'table': + console_print(ce.get_table(code=args.code, + scope=args.scope, + table=args.table, + index_position=args.index_position, key_type=args.key_type, - lower_bound=args.lower_bound, - upper_bound=args.upper_bound, - limit=args.limit, + lower_bound=args.lower_bound, + upper_bound=args.upper_bound, + limit=args.limit, timeout=args.timeout)) - - elif args.get == 'currency' : - if args.type == 'balance' : - if args.account : + + elif args.get == 'currency': + if args.type == 'balance': + if args.account: console_print(ce.get_currency_balance(args.account, code=args.code, symbol=args.symbol, timeout=args.timeout)) - else : + else: raise ValueError('--account is required') - else : + else: console_print(ce.get_currency(code=args.code, symbol=args.symbol, timeout=args.timeout)) - elif args.get == 'accounts' : + elif args.get == 'accounts': console_print(ce.get_accounts(args.key, timeout=args.timeout)) - elif args.get == 'transaction' : + elif args.get == 'transaction': console_print(ce.get_transaction(args.transaction, timeout=args.timeout)) - elif args.get == 'actions' : + elif args.get == 'actions': console_print(ce.get_actions(args.account, pos=args.pos, offset=args.offset, timeout=args.timeout)) - elif args.get == 'bin2json' : + elif args.get == 'bin2json': console_print(ce.abi_bin_to_json(args.code, args.action, args.binargs, timeout=args.timeout)) # PUSH elif args.subparser == 'push': @@ -210,17 +214,17 @@ def cleos(): priv_key = parse_key_file(args.key_file) arguments = json.loads(args.data) try: - account,permission = args.permission.split('@') + account, permission = args.permission.split('@') except ValueError: raise InvalidPermissionFormat('Permission format needs to be account@permission') payload = { - "account": args.account, - "name": args.action, - "authorization": [{ - "actor": account, - "permission": permission, - }], - } + "account": args.account, + "name": args.action, + "authorization": [{ + "actor": account, + "permission": permission, + }], + } data = ce.abi_json_to_bin(args.account, args.action, arguments) print(data) payload['data'] = data['binargs'] @@ -258,21 +262,22 @@ def cleos(): set_code(ce, args.account, args.permission, args.code, args.key, broadcast=args.broadcast, timeout=args.timeout) pass # SYSTEM - elif args.subparser == 'system' : - if args.system == 'newaccount' : - resp = ce.create_account(args.creator, args.creator_key, args.account, args.owner, args.active, - stake_net=args.stake_net, stake_cpu=args.stake_cpu, ramkb=args.ramkb, - permission=args.permission, transfer=args.transfer, broadcast=args.transfer, + elif args.subparser == 'system': + if args.system == 'newaccount': + resp = ce.create_account(args.creator, args.creator_key, args.account, args.owner, args.active, + stake_net=args.stake_net, stake_cpu=args.stake_cpu, ramkb=args.ramkb, + permission=args.permission, transfer=args.transfer, broadcast=args.transfer, timeout=args.timeout) console_print(resp) elif args.system == 'listproducers': resp = ce.get_producers(lower_bound=args.lower_bound, limit=args.limit) console_print(resp) -def testeos(): + +def testeos(): parser = argparse.ArgumentParser(description='EOSIO testing harness') - parser.add_argument('--yaml','-y', type=str, action='store', required=True, dest='yaml_loc') - parser.add_argument('--tests','-t', nargs='*', action='store', default="all", dest='tests') + parser.add_argument('--yaml', '-y', type=str, action='store', required=True, dest='yaml_loc') + parser.add_argument('--tests', '-t', nargs='*', action='store', default="all", dest='tests') # process args args = parser.parse_args() @@ -281,4 +286,4 @@ def testeos(): tester.run_test_all() else: for test in args.tests: - tester.run_test_one(test) \ No newline at end of file + tester.run_test_one(test) diff --git a/eospy/dynamic_url.py b/eospy/dynamic_url.py index a86bd53..8daf225 100644 --- a/eospy/dynamic_url.py +++ b/eospy/dynamic_url.py @@ -3,42 +3,43 @@ # import requests -class DynamicUrl : - #def __init__(self, url='http://localhost:8888', version='v1', cache=None) : - def __init__(self, url='http://localhost:8888', version='v1', cache=None) : + +class DynamicUrl: + # def __init__(self, url='http://localhost:8888', version='v1', cache=None) : + def __init__(self, url='http://localhost:8888', version='v1', cache=None): self._cache = cache or [] self._baseurl = url self._version = version - def __getattr__(self, name) : + def __getattr__(self, name): return self._(name) - def __del__(self) : + def __del__(self): pass - def _(self, name) : - return DynamicUrl(url=self._baseurl, version=self._version, cache=self._cache+[name]) + def _(self, name): + return DynamicUrl(url=self._baseurl, version=self._version, cache=self._cache + [name]) - def method(self) : + def method(self): return self._cache - + def create_url(self): - url_str = '{0}/{1}'.format(self._baseurl,self._version) - for obj in self.method() : + url_str = '{0}/{1}'.format(self._baseurl, self._version) + for obj in self.method(): url_str = '{0}/{1}'.format(url_str, obj) return url_str - def get_url(self, url, params=None, json=None, timeout=30) : + def get_url(self, url, params=None, json=None, timeout=30): # get request - r = requests.get(url,params=params, json=json, timeout=timeout) + r = requests.get(url, params=params, json=json, timeout=timeout) r.raise_for_status() return r.json() - def post_url(self, url, params=None, json=None, data=None, timeout=30) : + def post_url(self, url, params=None, json=None, data=None, timeout=30): # post request - r = requests.post(url,params=params, json=json, data=data, timeout=timeout) - try : + r = requests.post(url, params=params, json=json, data=data, timeout=timeout) + try: r.raise_for_status() - except : + except: raise requests.exceptions.HTTPError('Error: {}'.format(r.json())) return r.json() diff --git a/eospy/exceptions.py b/eospy/exceptions.py index edb53e8..492487f 100644 --- a/eospy/exceptions.py +++ b/eospy/exceptions.py @@ -3,38 +3,47 @@ class InvalidKeyFile(Exception): ''' Raised when the key file format is invalid ''' pass + class InvalidPermissionFormat(Exception): ''' Raised when the permission format is invalid''' pass + class EOSKeyError(Exception): ''' Raised when there is an EOSKey error ''' pass + class EOSMsigInvalidProposal(Exception): ''' Raised when an invalid proposal is queried''' pass + class EOSBufferInvalidType(Exception): ''' Raised when trying to encode/decode an invalid type ''' pass + class EOSInvalidSchema(Exception): ''' Raised when trying to process a schema ''' pass + class EOSUnknownObj(Exception): ''' Raised when an object is not found in the ABI ''' pass + class EOSAbiProcessingError(Exception): ''' Raised when the abi action cannot be processed ''' pass + class EOSSetSameCode(Exception): ''' Raised when the code would not change on a set''' pass + class EOSSetSameAbi(Exception): ''' Raised when the abi would not change on a set''' - pass \ No newline at end of file + pass diff --git a/eospy/keys.py b/eospy/keys.py index a54b6c2..04a83f9 100644 --- a/eospy/keys.py +++ b/eospy/keys.py @@ -10,98 +10,99 @@ import struct import array -def check_wif(key) : - if isinstance(key, str) : - try : + +def check_wif(key): + if isinstance(key, str): + try: EOSKey(key) return True except Exception as ex: pass return False -class EOSKey(Signer) : - def __init__(self, private_str='') : + +class EOSKey(Signer): + def __init__(self, private_str=''): ''' ''' - if private_str : + if private_str: private_key, format, key_type = self._parse_key(private_str) self._sk = ecdsa.SigningKey.from_string(unhexlify(private_key), curve=ecdsa.SECP256k1) - else : + else: prng = self._create_entropy() self._sk = ecdsa.SigningKey.generate(curve=ecdsa.SECP256k1, entropy=prng) self._vk = self._sk.get_verifying_key() - def __str__(self) : + def __str__(self): return self.to_public() - - def _parse_key(self, private_str) : + + def _parse_key(self, private_str): ''' ''' match = re.search('^PVT_([A-Za-z0-9]+)_([A-Za-z0-9]+)$', private_str) - if not match : - # legacy WIF - format + if not match: + # legacy WIF - format version_key = self._check_decode(private_str, 'sha256x2') # ensure first 2 chars == 0x80 - version = int(version_key[0:2],16) - if not version == 0x80 : + version = int(version_key[0:2], 16) + if not version == 0x80: raise ValueError('Expected version 0x80, instead got {0}', version) private_key = version_key[2:] key_type = 'K1' format = 'WIF' - else : + else: key_type, key_string = match.groups() private_key = self._check_decode(key_string, key_type) format = 'PVT' return (private_key, format, key_type) - def _create_entropy(self) : + def _create_entropy(self): ''' ''' ba = bytearray(os.urandom(32)) seed = sha256(ba) return ecdsa.util.PRNG(seed) - def _check_encode(self, key_buffer, key_type=None) : + def _check_encode(self, key_buffer, key_type=None): ''' ''' - if isinstance(key_buffer, bytes) : + if isinstance(key_buffer, bytes): key_buffer = key_buffer.decode() check = key_buffer - if key_type == 'sha256x2' : + if key_type == 'sha256x2': first_sha = sha256(unhexlify(check)) chksum = sha256(unhexlify(first_sha))[:8] - else : - if key_type : - check += hexlify(bytearray(key_type,'utf-8')).decode() + else: + if key_type: + check += hexlify(bytearray(key_type, 'utf-8')).decode() chksum = ripemd160(unhexlify(check))[:8] - return base58.b58encode(unhexlify(key_buffer+chksum)) - - def _check_decode(self, key_string, key_type=None) : + return base58.b58encode(unhexlify(key_buffer + chksum)) + + def _check_decode(self, key_string, key_type=None): ''' ''' buffer = hexlify(base58.b58decode(key_string)).decode() chksum = buffer[-8:] key = buffer[:-8] - if key_type == 'sha256x2' : + if key_type == 'sha256x2': # legacy first_sha = sha256(unhexlify(key)) newChk = sha256(unhexlify(first_sha))[:8] - else : + else: check = key - if key_type : + if key_type: check += hexlify(bytearray(key_type, 'utf-8')).decode() newChk = ripemd160(unhexlify(check))[:8] #print('newChk: '+newChk) - if chksum != newChk : + if chksum != newChk: raise ValueError('checksums do not match: {0} != {1}'.format(chksum, newChk)) return key - - def _recover_key(self, digest, signature, i) : + def _recover_key(self, digest, signature, i): ''' Recover the public key from the sig http://www.secg.org/sec1-v2.pdf ''' curve = ecdsa.SECP256k1.curve G = ecdsa.SECP256k1.generator order = ecdsa.SECP256k1.order - yp = (i %2) + yp = (i % 2) r, s = ecdsa.util.sigdecode_string(signature, order) - x = r + (i // 2 ) * order + x = r + (i // 2) * order alpha = ((x * x * x) + (curve.a() * x) + curve.b()) % curve.p() beta = ecdsa.numbertheory.square_root_mod_prime(alpha, curve.p()) y = beta if (beta - yp) % 2 == 0 else curve.p() - beta @@ -112,20 +113,20 @@ def _recover_key(self, digest, signature, i) : Q = ecdsa.numbertheory.inverse_mod(r, order) * (s * R + (-e % order) * G) # verify message if not ecdsa.VerifyingKey.from_public_point(Q, curve=ecdsa.SECP256k1).verify_digest(signature, digest, - sigdecode=ecdsa.util.sigdecode_string) : + sigdecode=ecdsa.util.sigdecode_string): return None return ecdsa.VerifyingKey.from_public_point(Q, curve=ecdsa.SECP256k1) - - def _recovery_pubkey_param(self, digest, signature) : + + def _recovery_pubkey_param(self, digest, signature): ''' Use to derive a number that will allow for the easy recovery of the public key from the signature ''' - for i in range(0,4) : + for i in range(0, 4): p = self._recover_key(digest, signature, i) - if (p.to_string() == self._vk.to_string()) : + if (p.to_string() == self._vk.to_string()): return i - def _compress_pubkey(self) : + def _compress_pubkey(self): ''' ''' order = self._sk.curve.generator.order() p = self._vk.pubkey.point @@ -142,12 +143,12 @@ def _is_canonical(self, sig): t4 = not (sig[33] == 0 and ((sig[34] & 0x80) == 0)) return t1 and t2 and t3 and t4 - def to_public(self) : + def to_public(self): ''' ''' cmp = self._compress_pubkey() return 'EOS' + self._check_encode(cmp).decode() - - def to_wif(self) : + + def to_wif(self): ''' ''' pri_key = '80' + hexlify(self._sk.to_string()).decode() return self._check_encode(pri_key, 'sha256x2').decode() @@ -157,25 +158,25 @@ def sign_string(self, data, encoding="utf-8"): digest = sha256(bytearray(data, encoding)) return self.sign(digest) - def sign(self, digest) : + def sign(self, digest): ''' ''' cnt = 0 # convert digest to hex string digest = unhexlify(digest) - if len(digest) != 32 : + if len(digest) != 32: raise ValueError("32 byte buffer required") - while 1 : + while 1: # get deterministic k if cnt: sha_digest = hashlib.sha256(digest + bytearray(cnt)).digest() - else : + else: sha_digest = hashlib.sha256(digest).digest() - k = ecdsa.rfc6979.generate_k( self._sk.curve.generator.order(), - self._sk.privkey.secret_multiplier, - hashlib.sha256, - # hashlib.sha256(digest + struct.pack('d', time.time())).digest() # use time to randomize - sha_digest - ) + k = ecdsa.rfc6979.generate_k(self._sk.curve.generator.order(), + self._sk.privkey.secret_multiplier, + hashlib.sha256, + # hashlib.sha256(digest + struct.pack('d', time.time())).digest() # use time to randomize + sha_digest + ) # sign the message sigder = self._sk.sign_digest(digest, sigencode=ecdsa.util.sigencode_der, k=k) @@ -187,7 +188,7 @@ def sign(self, digest) : # ensure signature is canonical lenR = sigder[3] lenS = sigder[5 + lenR] - + if lenR == 32 and lenS == 32: # derive recover parameter i = self._recovery_pubkey_param(digest, sig) @@ -198,20 +199,20 @@ def sign(self, digest) : sigstr = struct.pack('>= 7 buf |= (((val > 0) if 1 else 0) << 7) self._push_byte(buf) - while val : + while val: buf = int((val) & 0x7f) val >>= 7 buf |= (((val > 0) if 1 else 0) << 7) self._push_byte(buf) return self._b_arr - def _pop(self,buf, length): + def _pop(self, buf, length): return buf[:length], buf[length:] def decode(self, buf): @@ -104,87 +140,90 @@ def decode(self, buf): shift = 0 result = 0 while True: - tmp,buf = self._pop(buf, 2) + tmp, buf = self._pop(buf, 2) i = hex_to_int(tmp) result |= (i & 0x7f) << shift shift += 7 if not(i & 0x80): break return result, buf - -class BaseObject(object) : - def __init__(self, d) : + + +class BaseObject(object): + def __init__(self, d): ''' ''' try: self._obj = self._validator.deserialize(d) except Invalid: raise EOSInvalidSchema('Unable to process schema for {}'.format(type(self))) # instantiate the class - for k,v in self._obj.items() : + for k, v in self._obj.items(): setattr(self, k, v) # clean up del self._obj del self._validator - - def __repr__(self) : + + def __repr__(self): ''' ''' return '{}({})'.format(self.__class__, self.__dict__) - - def _encode_buffer(self, value) : + + def _encode_buffer(self, value): ''' ''' return EOSBuffer(value).encode() - def _create_obj_array(self, arr, class_type) : + def _create_obj_array(self, arr, class_type): ''' ''' new_arr = [] - for item in arr : + for item in arr: new_arr.append(class_type(item)) return new_arr -class Action(BaseObject) : - def __init__(self, d) : + +class Action(BaseObject): + def __init__(self, d): ''' ''' self._validator = ActionSchema() super(Action, self).__init__(d) # setup permissions self.authorization = self._create_obj_array(self.authorization, Authorization) - - def encode(self) : + + def encode(self): ''' ''' acct = self._encode_buffer(AccountName(self.account)) name = self._encode_buffer(Name(self.name)) auth = self._encode_buffer(self.authorization) # need to figure out how to process data # get length - data_len = self._encode_buffer(VarUInt(len(self.data)/2)) - data = data_len + self.data + data_len = self._encode_buffer(VarUInt(len(self.data) / 2)) + data = data_len + self.data return '{}{}{}{}'.format(acct, name, auth, data) -class Asset : - def __init__(self, value, precision=4) : + +class Asset: + def __init__(self, value, precision=4): # self.amount = amt # self.symbol = sym # self.precision = precision self.from_string(value) - def __str__(self) : + def __str__(self): return '{amount:.{precision}f} {symbol}'.format(amount=self.amount, symbol=self.symbol, precision=self.precision) - - def __add__(self, other) : - if self.symbol != other.symbol : + + def __add__(self, other): + if self.symbol != other.symbol: raise TypeError('Symbols must match: {} != {}', self.symbol, other.symbol) - return Asset(self.amount+other.amount, self.symbol) + return Asset(self.amount + other.amount, self.symbol) - def __sub__(self, other) : - if self.amount - other.amount < 0 : + def __sub__(self, other): + if self.amount - other.amount < 0: raise ValueError('Subtraction would result in a negative.') - if self.symbol != other.symbol : + if self.symbol != other.symbol: raise TypeError('Symbols must match: {} != {}', self.symbol, other.symbol) - return Asset(self.amount-other.amount, self.symbol) + return Asset(self.amount - other.amount, self.symbol) - def from_string(self, s) : + def from_string(self, s): splt = s.split() - try : + try: self.amount = float(splt[0]) self.symbol = splt[1] self.precision = len(splt[0].split(".")[1]) @@ -199,10 +238,10 @@ def _string_to_symbol(self): letter = self.symbol[cnt] if letter >= 'A' or letter <= 'Z': l = ord(letter) - rslt |= (UInt64(l) << (8*(cnt+1))) + rslt |= (UInt64(l) << (8 * (cnt + 1))) else: raise ValueError("{} contains an invalid symbol. Must be [A-Z].".format(self.symbol)) - + cnt += 1 rslt |= UInt64(self.precision) return EOSBuffer(UInt64(rslt)).encode() @@ -214,54 +253,59 @@ def encode(self): symbol = self._string_to_symbol() return '{amount}{symbol}'.format(amount=amount, symbol=symbol) + class AbiType(BaseObject): def __init__(self, d): self._validator = AbiTypeSchema() super(AbiTypes, self).__init__(d) - + def encode(self): new_type_name = self._encode_buffer(self.new_type_name) type = self._encode_buffer(self.type) return '{}{}'.format(new_type_name, type) + class AbiStructField(BaseObject): def __init__(self, d): self._validator = AbiStructFieldSchema() super(AbiStructField, self).__init__(d) - + def encode(self): name = self._encode_buffer(self.name) type = self._encode_buffer(self.type) return '{}{}'.format(name, type) + class AbiStruct(BaseObject): def __init__(self, d): self._validator = AbiStructSchema() super(AbiStruct, self).__init__(d) self.fields = self._create_obj_array(self.fields, AbiStructField) - + def encode(self): name = self._encode_buffer(self.name) base = self._encode_buffer(self.base) fields = self._encode_buffer(self.fields) return '{}{}{}'.format(name, base, fields) + class AbiAction(BaseObject): def __init__(self, d): self._validator = AbiActionSchema() super(AbiAction, self).__init__(d) - + def encode(self): name = self._encode_buffer(Name(self.name)) type = self._encode_buffer(self.type) ricardian_contract = self._encode_buffer(self.ricardian_contract) return '{}{}{}'.format(name, type, ricardian_contract) + class AbiTable(BaseObject): def __init__(self, d): self._validator = AbiTableSchema() super(AbiTable, self).__init__(d) - + def encode(self): name = self._encode_buffer(Name(self.name)) index_type = self._encode_buffer(self.index_type) @@ -270,43 +314,48 @@ def encode(self): type = self._encode_buffer(self.type) return '{}{}{}{}{}'.format(name, index_type, key_names, key_types, type) + class AbiRicardianClauses(BaseObject): def __init__(self, d): self._validator = AbiRicardianClauseSchema() super(AbiRicardianClauses, self).__init__(d) - + def encode(self): id = self._encode_buffer(self.id) body = self._encode_buffer(self.body) return '{}{}'.format(id, body) + class AbiErrorMessages(BaseObject): # TODO implement encode def __init__(self, d): self._validator = AbiErrorMessagesSchema() super(AbiErrorMessages, self).__init__(d) - + def encode(): raise NotImplementedError + class AbiExtensions(BaseObject): # TODO implement encode def __init__(self, d): self._validator = AbiExtensionsSchema() super(AbiExtensions, self).__init__(d) - + def encode(): raise NotImplementedError + class AbiVariants(BaseObject): # TODO implement encode def __init__(self, d): self._validator = AbiVariantsSchema() super(AbiVariants, self).__init__(d) - + def encode(): raise NotImplementedError + class Abi(BaseObject): _abi_map = { # name @@ -325,20 +374,20 @@ class Abi(BaseObject): 'float64': Float(), # NotImplemented # 'varuint32': VarUInt # NotImplemented # complex - 'asset' : Asset("1.0000 EOS"), + 'asset': Asset("1.0000 EOS"), # 'checksum256': str, # NotImplemented # 'block_timestamp_type': UInt64, # NotImplemented # 'time_point': UInt64, # NotImplemented # 'connector': str, # NotImplemented # 'public_key': str, # NotImplemented - # 'authority': str, # NotImplemented + # 'authority': str, # NotImplemented # 'block_header': str, # NotImplemented # 'bytes': str, # NotImplemented # 'permission_level': str, # NotImplemented # 'permission_level_weight': str, #NotImplemented } - def __init__(self,d): + def __init__(self, d): ''' ''' self._validator = AbiSchema() super(Abi, self).__init__(d) @@ -381,10 +430,10 @@ def get_action_parameters(self, name): if(f in self._abi_map): field_type = self._abi_map[f] # check if the field is a list - if '[]' in field.type : + if '[]' in field.type: field_type = [field_type] parameters[field.name] = field_type - else : + else: raise EOSUnknownObj("{} is not a known abi type".format(field.type)) return parameters @@ -399,17 +448,17 @@ def get_raw(self): error_messages = self._encode_buffer(self.error_messages) abi_extensions = self._encode_buffer(self.abi_extensions) variants = self._encode_buffer(self.variants) - return '{}{}{}{}{}{}{}{}{}'.format(version, types, structs, actions, tables, - ricardian_clauses, error_messages, abi_extensions, - variants) + return '{}{}{}{}{}{}{}{}{}'.format(version, types, structs, actions, tables, + ricardian_clauses, error_messages, abi_extensions, + variants) def encode(self): ''' ''' raw_abi = self.get_raw() # divide by two because it is hex - length = self._encode_buffer(VarUInt(len(raw_abi)/2)) + length = self._encode_buffer(VarUInt(len(raw_abi) / 2)) return length + raw_abi - + def json_to_bin(self, name, data): # act = self.get_action(name) params = self.get_action_parameters(name) @@ -419,7 +468,7 @@ def json_to_bin(self, name, data): if isinstance(params[field], list): field_type = type(params[field][0]) arr = [] - for f in data[field]: + for f in data[field]: print(f) arr.append(field_type(f)) field_buffer = EOSBuffer(arr) @@ -430,48 +479,52 @@ def json_to_bin(self, name, data): bin_buffer += field_buffer.encode() return bin_buffer + class Authorization(BaseObject): - def __init__(self, d) : + def __init__(self, d): ''' ''' # create validator self._validator = PermissionLevelSchema() super(Authorization, self).__init__(d) - def encode(self) : + def encode(self): ''' ''' actor = self._encode_buffer(AccountName(self.actor)) perms = self._encode_buffer(PermissionName(self.permission)) return '{}{}'.format(actor, perms) -class ChainInfo(BaseObject) : - def __init__(self, d) : + +class ChainInfo(BaseObject): + def __init__(self, d): ''' ''' self._validator = ChainInfoSchema() super(ChainInfo, self).__init__(d) -class BlockInfo(BaseObject) : - def __init__(self, d) : + +class BlockInfo(BaseObject): + def __init__(self, d): ''' ''' self._validator = BlockInfoSchema() super(BlockInfo, self).__init__(d) -class Transaction(BaseObject) : - def __init__(self, d, chain_info, lib_info) : + +class Transaction(BaseObject): + def __init__(self, d, chain_info, lib_info): ''' ''' # add defaults - if 'expiration' not in d : + if 'expiration' not in d: d['expiration'] = str((dt.datetime.utcnow() + dt.timedelta(seconds=30)).replace(tzinfo=pytz.UTC)) - if 'ref_block_num' not in d : + if 'ref_block_num' not in d: d['ref_block_num'] = chain_info['last_irreversible_block_num'] & 0xFFFF - if 'ref_block_prefix' not in d : + if 'ref_block_prefix' not in d: d['ref_block_prefix'] = lib_info['ref_block_prefix'] # validate self._validator = TransactionSchema() super(Transaction, self).__init__(d) # parse actions self.actions = self._create_obj_array(self.actions, Action) - - def _encode_hdr(self) : + + def _encode_hdr(self): ''' ''' # convert exp_ts = (self.expiration - dt.datetime(1970, 1, 1, tzinfo=self.expiration.tzinfo)).total_seconds() @@ -485,17 +538,18 @@ def _encode_hdr(self) : hdr = '{}{}{}{}{}{}'.format(exp, ref_blk, ref_block_prefix, net_usage_words, max_cpu_usage_ms, delay_sec) return hdr - def encode(self) : + def encode(self): ''' ''' hdr_buf = self._encode_hdr() context_actions = self._encode_buffer(self.context_free_actions) actions = self._encode_buffer(self.actions) trans_exts = self._encode_buffer(self.transaction_extensions) return bytearray.fromhex(hdr_buf + context_actions + actions + trans_exts) - - def get_id(self) : + + def get_id(self): return sha256(self.encode()) + class PackedTransaction: def __init__(self, trx, ce): self._cleos = ce @@ -503,8 +557,8 @@ def __init__(self, trx, ce): # empty header self._is_unpacked = False self._unpacked_trx = OrderedDict() - - def _decode_buffer(self, objType, buf): + + def _decode_buffer(self, objType, buf): ''' ''' eBuf = EOSBuffer("") return eBuf.decode(objType, buf) @@ -513,7 +567,7 @@ def _decode_header(self, buf): ''' ''' buf = self._packed_trx # get expiration buffer - (exp,buf) = self._decode_buffer(UInt32(), buf) + (exp, buf) = self._decode_buffer(UInt32(), buf) # get expiration in UTC exp_dt = dt.datetime.utcfromtimestamp(exp) self._unpacked_trx['expiration'] = exp_dt.strftime("%Y-%m-%dT%H:%M:%S") @@ -523,7 +577,7 @@ def _decode_header(self, buf): # get ref_block_prefix (ref_blk_pre, buf) = self._decode_buffer(UInt32(), buf) self._unpacked_trx['ref_block_prefix'] = ref_blk_pre - # get net usage + # get net usage (max_net_usage, buf) = self._decode_buffer(VarUInt(), buf) self._unpacked_trx['max_net_usage_words'] = max_net_usage # get cpu usage @@ -555,7 +609,7 @@ def decode_actions(self, buf): abi_act = abi.get_action(action_name) # temp check need to handle this better if abi_act["type"] != action_name: - raise EOSAbiProcessingError("Error processing the {} action".format(action_name)) + raise EOSAbiProcessingError("Error processing the {} action".format(action_name)) abi_struct = abi.get_action_parameters(action_name) data = OrderedDict() # save data for hex_data @@ -619,7 +673,7 @@ def get_id(self): def get_transaction(self): ''' ''' # only unpack once - if not self._is_unpacked: + if not self._is_unpacked: # decode the header and get the rest of the trx back trx_buf = self._decode_header(self._packed_trx) # process list of context free actions @@ -629,17 +683,18 @@ def get_transaction(self): (actions, trx_buf) = self.decode_actions(trx_buf) self._unpacked_trx['actions'] = actions # process transaction extensions - (trx_ext, trx_buf)= self.decode_trx_extensions(trx_buf) - self._unpacked_trx['transaction_extensions'] = trx_ext + (trx_ext, trx_buf) = self.decode_trx_extensions(trx_buf) + self._unpacked_trx['transaction_extensions'] = trx_ext # set boolean self._is_unpacked = True return self._unpacked_trx -class EOSBuffer : - def __init__(self, v) : + +class EOSBuffer: + def __init__(self, v): self._value = v self._count = 0 - + def _decode_number(self, val, format='L'): byte_val = binascii.unhexlify(val) return convert_big_endian(byte_val, format) @@ -652,41 +707,41 @@ def _decode_name(self, val, format='Q'): ''' ''' num = self._decode_number(val, format) return name_to_string(num) - + def _decode_str(self, val): ''' ''' # get length vu = VarUInt() - (length,val) = vu.decode(val) + (length, val) = vu.decode(val) string = '' leftover = val # if there is data parse it - if length > 0: - (str_data,leftover) = self._splice_buf(val, length*2) + if length > 0: + (str_data, leftover) = self._splice_buf(val, length * 2) string = binascii.unhexlify(str_data).decode() return (string, leftover) def _splice_buf(self, buf, length): return buf[:length], buf[length:] - def _write_number(self, val, format='q') : + def _write_number(self, val, format='q'): ''' ''' le = convert_little_endian(val, format) return binascii.hexlify(le).decode() - def _write_name(self, w_str) : + def _write_name(self, w_str): ''' ''' val = string_to_name(w_str) le = convert_little_endian(val, 'Q') return binascii.hexlify(le).decode() - def _write_str(self, w_str) : + def _write_str(self, w_str): b = bytearray() length = VarUInt(len(w_str)).encode() b.extend(map(ord, w_str)) return binascii.hexlify(length + b).decode() - def _write_varuint(self, vuint) : + def _write_varuint(self, vuint): buf = vuint.encode() return binascii.hexlify(buf).decode() @@ -703,27 +758,27 @@ def decode(self, objType, buf=None): elif isinstance(objType, VarUInt): (val, leftover) = objType.decode(buf) elif(isinstance(objType, Byte) or - isinstance(objType, bool)) : + isinstance(objType, bool)): (hex_str, leftover) = self._splice_buf(buf, 2) val = hex_to_int(hex_str) elif isinstance(objType, Float): (val, leftover) = self._splice_buf(buf, objType.hex_str_len) val = self._decode_float(val, 'f') elif(isinstance(objType, int) or - isinstance(objType, long)) : + isinstance(objType, long)): (val, leftover) = self._splice_buf(buf, objType.hex_str_len) val = self._decode_number(val, 'q') elif (isinstance(objType, Name) or - isinstance(objType, AccountName) or - isinstance(objType, PermissionName) or - isinstance(objType, ActionName) or - isinstance(objType, TableName) or - isinstance(objType, ScopeName) ) : + isinstance(objType, AccountName) or + isinstance(objType, PermissionName) or + isinstance(objType, ActionName) or + isinstance(objType, TableName) or + isinstance(objType, ScopeName)): (val, leftover) = self._splice_buf(buf, objType.hex_str_len) val = self._decode_name(val) elif isinstance(objType, str): (val, leftover) = self._decode_str(buf) - elif(isinstance(objType, list)) : + elif(isinstance(objType, list)): # get count(VarUint) val = [] (length, leftover) = VarUInt("").decode(buf) @@ -732,58 +787,58 @@ def decode(self, objType, buf=None): val.append(out) else: raise EOSBufferInvalidType("Cannot decode type: {}".format(type(objType))) - + return (val, leftover) - def encode(self, val=None) : - if not val : + def encode(self, val=None): + if not val: val = self._value if (isinstance(val, Name) or - isinstance(val, AccountName) or - isinstance(val, PermissionName) or - isinstance(val, ActionName) or - isinstance(val, TableName) or - isinstance(val, ScopeName) ) : + isinstance(val, AccountName) or + isinstance(val, PermissionName) or + isinstance(val, ActionName) or + isinstance(val, TableName) or + isinstance(val, ScopeName)): val = self._write_name(val) return val - elif(isinstance(val, str)) : + elif(isinstance(val, str)): return self._write_str(val) elif(isinstance(val, Byte) or - isinstance(val, bool)) : - #return self._write_number(val, '?') + isinstance(val, bool)): + # return self._write_number(val, '?') return int_to_hex(val) - elif(isinstance(val, UInt16)) : + elif(isinstance(val, UInt16)): return self._write_number(val, 'H') - elif(isinstance(val,UInt32)) : + elif(isinstance(val, UInt32)): return self._write_number(val, 'I') - elif(isinstance(val,UInt64)) : + elif(isinstance(val, UInt64)): return self._write_number(val, 'q') elif(isinstance(val, Float)): return self._write_number(val, 'f') - elif(isinstance(val,VarUInt)) : + elif(isinstance(val, VarUInt)): # temp encoding return self._write_varuint(val) elif(isinstance(val, int) or - isinstance(val, long)) : + isinstance(val, long)): return self._write_number(val, 'l') - elif(isinstance(val, Action) or - isinstance(val, AbiStruct) or - isinstance(val, AbiStructField) or + elif(isinstance(val, Action) or + isinstance(val, AbiStruct) or + isinstance(val, AbiStructField) or isinstance(val, AbiType) or - isinstance(val, AbiAction) or + isinstance(val, AbiAction) or isinstance(val, AbiTable) or - isinstance(val, AbiRicardianClauses) or + isinstance(val, AbiRicardianClauses) or isinstance(val, AbiErrorMessages) or - isinstance(val, AbiExtensions) or + isinstance(val, AbiExtensions) or isinstance(val, AbiVariants) or isinstance(val, Asset) or isinstance(val, Authorization)): return val.encode() - elif(isinstance(val, list)) : - buf = self._write_varuint(VarUInt(len(val))) - for item in val : + elif(isinstance(val, list)): + buf = self._write_varuint(VarUInt(len(val))) + for item in val: e_item = self.encode(item) buf = '{}{}'.format(buf, e_item) return buf - else : - raise EOSBufferInvalidType('Cannot encode type: {}'.format(type(val))) \ No newline at end of file + else: + raise EOSBufferInvalidType('Cannot encode type: {}'.format(type(val))) diff --git a/eospy/utils.py b/eospy/utils.py index 7aa39a0..072e1ed 100644 --- a/eospy/utils.py +++ b/eospy/utils.py @@ -4,17 +4,18 @@ import six from .exceptions import InvalidKeyFile + def parse_key_file(filename, first_key=True): - keys=[] - with open(filename) as fo: + keys = [] + with open(filename) as fo: lines = fo.readlines() for line in lines: if line.startswith('Private'): try: - header,key = line.replace(' ', '').rstrip().split(':') + header, key = line.replace(' ', '').rstrip().split(':') if key and first_key: return key - elif key: + elif key: keys.append(key) except ValueError: # invalid format @@ -23,10 +24,12 @@ def parse_key_file(filename, first_key=True): return keys raise InvalidKeyFile('Key file was in an invalid format. Must contain one key pair and have a prefix of "Private key:"') + def sha256(data): ''' ''' return hashlib.sha256(data).hexdigest() + def ripemd160(data): ''' ''' #h = hashlib.new('ripemd160') @@ -34,61 +37,68 @@ def ripemd160(data): h.update(data) return h.hexdigest() -def sig_digest(payload, chain_id=None, context_free_data=None) : + +def sig_digest(payload, chain_id=None, context_free_data=None): ''' ''' - if chain_id : + if chain_id: buf = bytearray.fromhex(chain_id) - else : + else: buf = bytearray(32) # already a bytearray buf.extend(payload) - if context_free_data : + if context_free_data: #buf += sha256(context_free_data) pass - else : + else: # empty buffer buf.extend(bytearray(32)) return sha256(buf) - -def int_to_hex(i) : + + +def int_to_hex(i): return '{:02x}'.format(i) -def hex_to_int(i) : + +def hex_to_int(i): return int(i, 16) - -def str_to_hex(c) : + + +def str_to_hex(c): hex_data = hexlify(bytearray(c, 'ascii')).decode() - return int(hex_data,16) + return int(hex_data, 16) + -def char_subtraction(a, b, add) : +def char_subtraction(a, b, add): x = str_to_hex(a) y = str_to_hex(b) ans = str((x - y) + add) - if len(ans) % 2 == 1 : + if len(ans) % 2 == 1: ans = '0' + ans return int(ans) -#static constexpr uint64_t char_to_symbol( char c ) { +# static constexpr uint64_t char_to_symbol( char c ) { # if( c >= 'a' && c <= 'z' ) # return (c - 'a') + 6; # if( c >= '1' && c <= '5' ) # return (c - '1') + 1; # return 0; -#} -def char_to_symbol(c) : +# } + + +def char_to_symbol(c): ''' ''' - if c >= 'a' and c <= 'z' : + if c >= 'a' and c <= 'z': return char_subtraction(c, 'a', 6) - if c >= '1' and c <= '5' : + if c >= '1' and c <= '5': return char_subtraction(c, '1', 1) return 0 - -#// Each char of the string is encoded into 5-bit chunk and left-shifted -#// to its 5-bit slot starting with the highest slot for the first char. -#// The 13th char, if str is long enough, is encoded into 4-bit chunk -#// and placed in the lowest 4 bits. 64 = 12 * 5 + 4 -#static constexpr uint64_t string_to_name( const char* str ) -#{ + +# // Each char of the string is encoded into 5-bit chunk and left-shifted +# // to its 5-bit slot starting with the highest slot for the first char. +# // The 13th char, if str is long enough, is encoded into 4-bit chunk +# // and placed in the lowest 4 bits. 64 = 12 * 5 + 4 +# static constexpr uint64_t string_to_name( const char* str ) +# { # uint64_t name = 0; # int i = 0; # for ( ; str[i] && i < 12; ++i) { @@ -97,7 +107,7 @@ def char_to_symbol(c) : # // of string_to_name(), where the usage requires constant (compile time) expression. # name |= (char_to_symbol(str[i]) & 0x1f) << (64 - 5 * (i + 1)); # } -# +# # // The for-loop encoded up to 60 high bits into uint64 'name' variable, # // if (strlen(str) > 12) then encode str[12] into the low (remaining) # // 4 bits of 'name' @@ -105,27 +115,29 @@ def char_to_symbol(c) : # name |= char_to_symbol(str[12]) & 0x0F; # return name; # } -def string_to_name(s) : + + +def string_to_name(s): ''' ''' i = 0 name = 0 - while i < len(s) : + while i < len(s): #sym = char_to_symbol(s[i]) - name += (char_to_symbol(s[i]) & 0x1F) << (64-5 * (i + 1)) + name += (char_to_symbol(s[i]) & 0x1F) << (64 - 5 * (i + 1)) i += 1 - if i > 12 : + if i > 12: name |= char_to_symbol(s[11]) & 0x0F return name -def name_to_string(n) : +def name_to_string(n): ''' ''' charmap = '.12345abcdefghijklmnopqrstuvwxyz' name = ['.'] * 13 i = 0 while i <= 12: c = charmap[n & (0x0F if i == 0 else 0x1F)] - name[12-i] = c + name[12 - i] = c n >>= 4 if i == 0 else 5 i += 1 return ''.join(name).rstrip('.') diff --git a/examples/push_transaction.py b/examples/push_transaction.py index e9f35d1..cdbdb8c 100644 --- a/examples/push_transaction.py +++ b/examples/push_transaction.py @@ -1,3 +1,4 @@ +import datetime as dt import eospy.cleos import eospy.keys from eospy.types import Abi, Action @@ -25,13 +26,12 @@ "permission": "owner", }], } -#Converting payload to binary +# Converting payload to binary data = ce.abi_json_to_bin(payload['account'], payload['name'], arguments) -#Inserting payload binary form as "data" field in original payload +# Inserting payload binary form as "data" field in original payload payload['data'] = data['binargs'] -#final transaction formed +# final transaction formed trx = {"actions": [payload]} -import datetime as dt trx['expiration'] = str( (dt.datetime.utcnow() + dt.timedelta(seconds=60)).replace(tzinfo=pytz.UTC)) # use a string or EOSKey for push_transaction @@ -64,14 +64,14 @@ "quantity": '1.1234 EOS', # In EOS "memo": "EOS to the moon", } - #Converting payload to binary + # Converting payload to binary data = ce.abi_json_to_bin(payload['account'], payload['name'], act_params) print(data) act_data = token_abi.json_to_bin(payload['name'], act_params) print(act_data) - #Inserting payload binary form as "data" field in original payload + # Inserting payload binary form as "data" field in original payload payload['data'] = act_data - #final transaction formed + # final transaction formed trx = {"actions": [payload]} resp = ce.push_transaction(trx, eospy.keys.EOSKey(key), broadcast=True) diff --git a/examples/sign_trx.py b/examples/sign_trx.py index 1537542..a012b3f 100644 --- a/examples/sign_trx.py +++ b/examples/sign_trx.py @@ -7,12 +7,11 @@ k = EOSKey("5KQwrPbwdL6PhXujxW37FSSQZ1JiwsST4cqQzDeyXtP79zkvFD3") digest=binascii.hexlify(b"This is a test string1") ''' -number=10 -key_results=timeit.timeit('k=EOSKey("5KQwrPbwdL6PhXujxW37FSSQZ1JiwsST4cqQzDeyXtP79zkvFD3")', - setup="from eospy.cleos import EOSKey", number=number) -print("Creating Key: Ran {} times and averaged {} seconds/run".format(number, key_results/number)) +number = 10 +key_results = timeit.timeit('k=EOSKey("5KQwrPbwdL6PhXujxW37FSSQZ1JiwsST4cqQzDeyXtP79zkvFD3")', + setup="from eospy.cleos import EOSKey", number=number) +print("Creating Key: Ran {} times and averaged {} seconds/run".format(number, key_results / number)) -results=timeit.timeit('k.sign(digest)', setup=setup_str, number=number) - -print("Signing: Ran {} times and averaged {} seconds/run".format(number, results/number)) +results = timeit.timeit('k.sign(digest)', setup=setup_str, number=number) +print("Signing: Ran {} times and averaged {} seconds/run".format(number, results / number)) diff --git a/tests/test_cleos.py b/tests/test_cleos.py index 41227b6..538e3fa 100644 --- a/tests/test_cleos.py +++ b/tests/test_cleos.py @@ -1,18 +1,18 @@ +from nose.tools import raises +import requests +import eospy.cleos import sys sys.path.append('../eospy') -import eospy.cleos -import requests -from nose.tools import raises -class TestCleos : +class TestCleos: - def setup(self) : + def setup(self): self.ce = eospy.cleos.Cleos('https://api.pennstation.eosnewyork.io:7101') self.json_to_bin = {u'to': u'eosio', u'memo': u'test', u'from': u'eosio', u'quantity': u'1.0000 EOS'} self.bin_to_json = '0000000000ea30550000000000ea3055102700000000000004454f53000000000474657374' - def test_get_info(self) : + def test_get_info(self): output = self.ce.get_info() # test output is valid assert "server_version" in output @@ -26,71 +26,69 @@ def test_get_info(self) : assert "block_cpu_limit" in output assert "block_net_limit" in output - def test_get_block(self) : + def test_get_block(self): block = self.ce.get_block(1) assert block['block_num'] == 1 @raises(requests.exceptions.HTTPError) - def test_get_block_invalid(self) : + def test_get_block_invalid(self): block = self.ce.get_block(-1) - - def test_get_account(self) : + + def test_get_account(self): acct = self.ce.get_account('eosio') assert acct['account_name'] == 'eosio' @raises(requests.exceptions.HTTPError) - def test_get_account_invalid(self) : + def test_get_account_invalid(self): acct = self.ce.get_account('eosioeosioeosio') - def test_get_abi(self) : + def test_get_abi(self): abi = self.ce.get_abi('eosio') - def test_get_code(self) : + def test_get_code(self): code = self.ce.get_code('eosio') - def test_get_code_bad(self) : + def test_get_code_bad(self): code = self.ce.get_code('eosio.ram') assert code['code_hash'] == u'0000000000000000000000000000000000000000000000000000000000000000' def test_get_table(self): - table = self.ce.get_table('eosio','eosio', 'producers', lower_bound='eosnewyorkio') + table = self.ce.get_table('eosio', 'eosio', 'producers', lower_bound='eosnewyorkio') @raises(requests.exceptions.HTTPError) def test_get_table_bad(self): table = self.ce.get_table('eosio', 'eosio', 'producer') - def test_get_currency_balance(self) : + def test_get_currency_balance(self): bal = self.ce.get_currency_balance('eosio', 'eosio.token', 'EOS') @raises(requests.exceptions.HTTPError) - def test_get_currency_balance_fail(self) : + def test_get_currency_balance_fail(self): bal = self.ce.get_currency_balance('eosio', 'eosio', 'SYS') - def test_json_to_bin(self) : + def test_json_to_bin(self): bin = self.ce.abi_json_to_bin('eosio.token', 'transfer', self.json_to_bin) assert bin['binargs'] == self.bin_to_json @raises(requests.exceptions.HTTPError) - def test_json_to_bin_bad(self) : + def test_json_to_bin_bad(self): bin = self.ce.abi_json_to_bin('eosio.token', 'transfer', '') assert bin['binargs'] == '' - def test_bin_to_json(self) : + def test_bin_to_json(self): bin = self.ce.abi_bin_to_json('eosio.token', 'transfer', self.bin_to_json) assert bin['args'] == self.json_to_bin @raises(requests.exceptions.HTTPError) - def test_bin_to_json_fail(self) : + def test_bin_to_json_fail(self): bin = self.ce.abi_bin_to_json('eosio.token', 'transfer', '00') - def test_get_currency_stats(self) : + def test_get_currency_stats(self): self.ce.get_currency_stats('eosio.token', 'EOS') - def test_get_currency_stats_bad(self) : + def test_get_currency_stats_bad(self): stats = self.ce.get_currency_stats('eosio.token', 'SYS') assert stats == {} - def test_get_producers(self) : + def test_get_producers(self): self.ce.get_producers() - -