151 lines
5.9 KiB
Python
151 lines
5.9 KiB
Python
|
# 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)
|