# standard imports import os import logging import argparse import re import json import signal import random import time # third-party imports import confini import web3 from cic_registry.chain import ChainSpec from cic_registry.chain import ChainRegistry from cic_registry import CICRegistry from eth_token_index import TokenUniqueSymbolIndex as TokenIndex from eth_accounts_index import AccountRegistry from cic_eth.api import Api logging.basicConfig(level=logging.WARNING) logg = logging.getLogger() logging.getLogger('websockets.protocol').setLevel(logging.CRITICAL) logging.getLogger('web3.RequestManager').setLevel(logging.CRITICAL) logging.getLogger('web3.providers.WebsocketProvider').setLevel(logging.CRITICAL) logging.getLogger('web3.providers.HTTPProvider').setLevel(logging.CRITICAL) default_data_dir = '/usr/local/share/cic/solidity/abi' argparser = argparse.ArgumentParser() argparser.add_argument('-c', type=str, default='./config', help='config file') argparser.add_argument('-i', '--chain-spec', dest='i', type=str, help='chain spec') argparser.add_argument('--env-prefix', default=os.environ.get('CONFINI_ENV_PREFIX'), dest='env_prefix', type=str, help='environment prefix for variables to overwrite configuration') argparser.add_argument('--abi-dir', dest='abi_dir', type=str, default=default_data_dir, help='Directory containing bytecode and abi (default: {})'.format(default_data_dir)) argparser.add_argument('-v', action='store_true', help='be verbose') argparser.add_argument('-vv', action='store_true', help='be more verbose') argparser.add_argument('--wait-max', dest='wait_max', default=2.0, type=float, help='maximum time in decimal seconds to wait between transactions') argparser.add_argument('--account-index-address', dest='account_index', type=str, help='Contract address of accounts index') argparser.add_argument('--token-index-address', dest='token_index', type=str, help='Contract address of token index') argparser.add_argument('--approval-escrow-address', dest='approval_escrow', type=str, help='Contract address for transfer approvals') argparser.add_argument('--declarator-address', dest='declarator', type=str, help='Address of declarations contract to perform lookup against') argparser.add_argument('-a', '--accounts-index-writer', dest='a', type=str, help='Address of account with access to add to accounts index') args = argparser.parse_args() if args.vv: logging.getLogger().setLevel(logging.DEBUG) elif args.v: logging.getLogger().setLevel(logging.INFO) config = confini.Config(args.c, args.env_prefix) config.process() args_override = { 'ETH_ABI_DIR': getattr(args, 'abi_dir'), 'CIC_CHAIN_SPEC': getattr(args, 'i'), 'DEV_ETH_ACCOUNTS_INDEX_ADDRESS': getattr(args, 'account_index'), 'DEV_ETH_ACCOUNT_ACCOUNTS_INDEX_WRITER': getattr(args, 'a'), 'DEV_ETH_ERC20_APPROVAL_ESCROW_ADDRESS': getattr(args, 'approval_escrow'), 'DEV_ETH_TOKEN_INDEX_ADDRESS': getattr(args, 'token_index'), } config.dict_override(args_override, 'cli flag') config.validate() config.censor('PASSWORD', 'DATABASE') config.censor('PASSWORD', 'SSL') logg.debug('config:\n{}'.format(config)) re_websocket = r'^wss?:' re_http = r'^https?:' blockchain_provider = None if re.match(re_websocket, config.get('ETH_PROVIDER')): blockchain_provider = web3.Web3.WebsocketProvider(config.get('ETH_PROVIDER')) elif re.match(re_http, config.get('ETH_PROVIDER')): blockchain_provider = web3.Web3.HTTPProvider(config.get('ETH_PROVIDER')) w3 = web3.Web3(blockchain_provider) chain_spec = ChainSpec.from_chain_str(config.get('CIC_CHAIN_SPEC')) CICRegistry.init(w3, config.get('CIC_REGISTRY_ADDRESS'), chain_spec) CICRegistry.add_path(config.get('ETH_ABI_DIR')) chain_registry = ChainRegistry(chain_spec) CICRegistry.add_chain_registry(chain_registry, True) run = True def inthandler(name, frame): logg.warning('got {}, stopping'.format(name)) global run run = False signal.signal(signal.SIGTERM, inthandler) signal.signal(signal.SIGINT, inthandler) api = Api(str(chain_spec)) f = open(os.path.join(config.get('ETH_ABI_DIR'), 'ERC20.json')) erc20_abi = json.load(f) f.close() def get_tokens(): tokens = [] token_index = TokenIndex(w3, config.get('CIC_TOKEN_INDEX_ADDRESS')) token_count = token_index.count() for i in range(token_count): tokens.append(token_index.get_index(i)) logg.debug('tokens {}'.format(tokens)) return tokens def get_addresses(): address_index = AccountRegistry(w3, config.get('CIC_ACCOUNTS_INDEX_ADDRESS')) address_count = address_index.count() addresses = address_index.last(address_count-1) logg.debug('addresses {} {}'.format(address_count, addresses)) return addresses random.seed() while run: n = random.randint(0, 255) # some of the time do other things than transfers if n & 0xf8 == 0xf8: t = api.create_account() logg.info('create account {}'.format(t)) else: tokens = get_tokens() addresses = get_addresses() address_pair = random.choices(addresses, k=2) sender = address_pair[0] recipient = address_pair[1] token = random.choice(tokens) c = w3.eth.contract(abi=erc20_abi, address=token) sender_balance = c.functions.balanceOf(sender).call() token_symbol = c.functions.symbol().call() amount = int(random.random() * (sender_balance / 2)) n = random.randint(0, 255) if n & 0xc0 == 0xc0: t = api.transfer_request(sender, recipient, config.get('CIC_APPROVAL_ESCROW_ADDRESS'), amount, token_symbol) logg.info('transfer REQUEST {} {} from {} to {} => {}'.format(amount, token_symbol, sender, recipient, t)) else: t = api.transfer(sender, recipient, amount, token_symbol) logg.info('transfer {} {} from {} to {} => {}'.format(amount, token_symbol, sender, recipient, t)) time.sleep(random.random() * args.wait_max)