cic-stack/apps/cic-eth/scripts/generator.py

182 lines
5.1 KiB
Python

import os
import logging
import random
import alembic
import argparse
import datetime
import hashlib
import math
import confini
from cic_eth.db import SessionBase
from cic_eth.db import dsn_from_config
from cic_eth.db.enum import StatusEnum
from cic_eth.db.models.tx import Tx
from cic_eth.db.models.tx import TxCache
from cic_eth.db.models.otx import Otx
from cic_eth.db.models.otx import Otx
# connect to database
dsn = dsn_from_config(config)
SessionBase.connect(dsn)
pending_states = [
StatusEnum.PENDING,
StatusEnum.SENDFAIL,
StatusEnum.WAITFORGAS,
]
synced_states = [
StatusEnum.SENT,
StatusEnum.CANCELLED,
]
failed_states = [
StatusEnum.REJECTED,
StatusEnum.FUBAR,
]
mined_states = [
StatusEnum.REVERTED,
StatusEnum.SUCCESS,
]
all_states = pending_states + synced_states + failed_states + mined_states
class MalarkeyCommitter():
"""Adds entries to the cic-eth transaction cache backend.
All values generated by this class are deterministic but completely arbitrary.
:param generator: Generator instance used to generate the transactions
:type generator: Generator
:param block_change_factor: Probabiliy of advancing to next block per entry (Optional; default: 0.6)
:type block_change_factor: float
:param tx_index_max: Maximum transaction index number to generate (Optional; default: 200)
:type ix_index_max: int
:param block_time_seconds: Seconds to advance block timestamp datetime on block advance
:type block_time_seconds: int
"""
def __init__(self, generator, block_change_factor=0.6, tx_index_max=200, block_time_seconds=15):
self.g = generator
self.s = SessionBase.create_session()
self.datetime = datetime.datetime.utcnow()
self.block = 0
self.tx = 0
self.block_change_factor = block_change_factor
self.tx_index_max = tx_index_max
self.block_time_seconds = block_time_seconds
def advance(self):
"""Randomly advances block number and transaction index.
"""
if random.random() < self.block_change_factor:
self.block_advance()
tx_advance = random.randint(0, self.tx_index_max - self.tx)
self.tx_advance(tx_advance)
def tx_advance(self, n=1):
"""Advance tx index number.
:param n: Will be added to tx index (Optional; default: 1)
:type n: int
"""
self.tx += n
def block_advance(self, n=1):
"""Advance block number.
:param n: Will be added to tx index (Optional; default: 1)
:type n: int
"""
self.block += n
self.datetime += datetime.timedelta(seconds=self.block_time_seconds)
self.tx = 0
def stamp(self, entry):
"""Calls the random advance method, and sets the corresponding block, tx index and dates on the entry.
"""
self.advance()
entry.mine(self.block, self.tx, self.datetime)
def commit_func(self, entry):
"""Implements interface needed for GeneratorSession.commit_func, storing a given entry.
Generates random block and tx index for entry, advancing date correspondingly.
Also generates random transaction queue states for the entries:
- For any entry with foreign origin, queue state will always be in the set of "mined" states if applicable.
- For any entry with local origin and "mined" queue state, an incoming transaction record will be added.
:param entry: Entry to commit
:type entry: GeneratorEntry
"""
self.stamp(entry)
nonce = self.g.get_nonce(entry.sender)
tx_hash = '0x{:064x}'.format(random.getrandbits(256))
signed_tx_bytes = b''
h = hashlib.sha256()
for i in range(4):
h.update(tx_hash.encode('utf-8'))
signed_tx_bytes += h.digest()
signed_tx = '0x' + signed_tx_bytes.hex()
state = None
if entry.sender in self.g.addresses['foreign']:
state = random.choice(mined_states)
else:
state = random.choice(all_states)
otx = None
tx = None
if entry.sender in self.g.addresses['local']:
otx = Otx(
nonce,
entry.sender,
tx_hash,
signed_tx,
)
otx.status = state
self.s.add(otx)
self.s.flush()
if state in mined_states:
tx = Tx(
tx_hash,
state == StatusEnum.SUCCESS,
)
self.s.add(tx)
self.s.flush()
self.s.commit()
txc = TxCache(
tx_hash,
entry.sender,
entry.recipient,
entry.source_token,
entry.destination_token,
entry.from_value,
entry.to_value,
entry.block,
entry.tx,
entry.sender in self.g.addresses['local'],
)
txc.date_registered = entry.datetime
self.s.add(txc)
self.s.commit()
logg.info('committed {}'.format(entry))