182 lines
5.1 KiB
Python
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))
|
||
|
|
||
|
|