adding cic-eth as sub dir

This commit is contained in:
2021-02-01 09:12:51 -08:00
parent ed3991e997
commit a4587deac5
317 changed files with 819441 additions and 0 deletions

View File

@@ -0,0 +1,167 @@
# standard imports
import socket
import celery
import threading
import logging
import time
import json
# third-party imports
import pytest
import redis as redis_interface
# local imports
from cic_eth.callbacks import http
from cic_eth.callbacks import tcp
from cic_eth.callbacks import redis
celery_app = celery.current_app
logg = celery_app.log.get_default_logger()
class Response:
status = 200
@pytest.mark.skip()
def test_callback_http(
celery_session_worker,
mocker,
):
mocker.patch('cic_eth.callbacks.http.urlopen', return_value=Response())
s = celery.signature(
'cic_eth.callbacks.http.http',
[
'foo',
'http://localhost:65000',
1,
],
)
t = s.apply_async()
t.get()
@pytest.mark.skip()
def test_callback_tcp(
celery_session_worker,
):
timeout=2
data = {
'foo': 'bar',
'xyzzy': 42,
}
class Accept(threading.Thread):
def __init__(self, socket):
super(Accept, self).__init__()
self.socket = socket
self.exception = None
def run(self):
(c, sockaddr) = self.socket.accept()
echo = c.recv(1024)
c.close()
logg.debug('recived {} '.format(data))
o = json.loads(echo)
try:
assert o == data
except Exception as e:
self.exception = e
def join(self):
threading.Thread.join(self)
if self.exception != None:
raise self.exception
s = socket.socket(family=socket.AF_INET, type=socket.SOCK_STREAM)
s.bind(('localhost', 0))
s.settimeout(timeout)
s.listen(1)
sockaddr = s.getsockname()
a = Accept(s)
a.start()
s_cb = celery.signature(
'cic_eth.callbacks.tcp.tcp',
[
data,
'{}:{}'.format(sockaddr[0], sockaddr[1]),
'1',
],
queue=None,
)
s_cb.apply_async()
a.join()
s.close()
def test_callback_redis(
load_config,
celery_session_worker,
):
timeout=2
channel = 'barbarbar'
host = load_config.get('REDIS_HOST', 'localhost')
port = load_config.get('REDIS_PORT', '6379')
db = load_config.get('REDIS_DB', '0')
data = {
'foo': 'bar',
'xyzzy': 42,
}
class Accept(threading.Thread):
def __init__(self, pubsub):
super(Accept, self).__init__()
self.pubsub = pubsub
self.exception = None
def run(self):
self.pubsub.get_message() # subscribe message
echo = self.pubsub.get_message(timeout=timeout)
o = json.loads(echo['data'])
logg.debug('recived {} '.format(o))
try:
assert o == data
except Exception as e:
self.exception = e
def join(self):
threading.Thread.join(self)
if self.exception != None:
raise self.exception
ps = None
try:
r = redis_interface.Redis(host=host, port=int(port), db=int(db))
ps = r.pubsub(
)
ps.subscribe(channel)
except redis_interface.exceptions.ConnectionError as e:
pytest.skip('cannot connect to redis, skipping test: {}'.format(e))
a = Accept(ps)
a.start()
s_cb = celery.signature(
'cic_eth.callbacks.redis.redis',
[
data,
'{}:{}:{}:{}'.format(host, port, db, channel),
'1',
],
queue=None,
)
s_cb.apply_async()
a.join()
r.close()

View File

@@ -0,0 +1,29 @@
# standard imports
import logging
# local imports
from cic_eth.db.models.otx import OtxSync
logg = logging.getLogger()
def test_db_block_sync(
init_database,
):
s = OtxSync('eip155:8995:bloxberg')
s.head(666, 12)
assert s.head() == (666, 12)
s.session(42, 13)
assert s.session() == (42, 13)
s.backlog(13, 2)
assert s.backlog() == (13, 2)
assert not s.synced
s.backlog(42, 13)
assert s.backlog() == (42, 13)
assert s.synced

View File

@@ -0,0 +1,29 @@
import os
import logging
import pytest
from cic_eth.db import TxConvertTransfer
from cic_eth.db.error import UnknownConvertError
logg = logging.getLogger()
def test_convert_transfer(
init_database,
default_chain_spec,
):
tx_hash_hex = '0x' + os.urandom(32).hex()
recipient = '0x' + os.urandom(20).hex()
txct = TxConvertTransfer(tx_hash_hex, recipient, str(default_chain_spec))
init_database.add(txct)
init_database.commit()
txct = TxConvertTransfer.get(tx_hash_hex)
assert txct.convert_tx_hash == tx_hash_hex
tx_hash_bogus_hex = '0x' + os.urandom(32).hex()
with pytest.raises(UnknownConvertError):
TxConvertTransfer.get(tx_hash_bogus_hex)

View File

@@ -0,0 +1,5 @@
def test_db_init(
init_database,
):
pass

View File

@@ -0,0 +1,67 @@
# standard imports
import os
# local imports
from cic_eth.db.models.lock import Lock
from cic_eth.db.enum import LockEnum
def test_lock(
init_database,
default_chain_spec,
):
chain_str = str(default_chain_spec)
# Check matching flag for global (zero-address) lock
a = 0xffffffffffffffff & LockEnum.CREATE
r = Lock.set(chain_str, a)
assert r == a
assert Lock.check(chain_str, a) > 0
# Check matching flag for address specific lock
address = '0x' + os.urandom(20).hex()
b = 0xffffffffffffffff & (LockEnum.QUEUE | LockEnum.SEND)
Lock.set(chain_str, b, address=address)
assert Lock.check(chain_str, b, address=address) == b
assert Lock.check(chain_str, a, address=address) == 0
assert Lock.check(chain_str, b & LockEnum.QUEUE, address=address) == LockEnum.QUEUE
assert Lock.check(chain_str, b) == 0
# Reset single flag
r = Lock.reset(chain_str, LockEnum.QUEUE, address=address)
assert r == LockEnum.SEND
# Reset to 0
r = Lock.reset(chain_str, LockEnum.SEND, address=address)
assert r == 0
# Row should be deleted when flags value reaches 0
q = init_database.query(Lock)
q = q.filter(Lock.address==address)
assert q.first() == None
def test_lock_merge_check(
init_database,
default_chain_spec,
):
chain_str = str(default_chain_spec)
foo_address = '0x' + os.urandom(20).hex()
bar_address = '0x' + os.urandom(20).hex()
Lock.set(chain_str, LockEnum.CREATE)
assert Lock.check_aggregate(chain_str, LockEnum.CREATE, address=foo_address) > 0
assert Lock.check_aggregate(chain_str, LockEnum.CREATE, address=bar_address) > 0
Lock.set(chain_str, LockEnum.CREATE, address=foo_address)
assert Lock.check_aggregate(chain_str, LockEnum.CREATE, address=foo_address) > 0
assert Lock.check_aggregate(chain_str, LockEnum.CREATE, address=bar_address) > 0
Lock.reset(chain_str, LockEnum.CREATE)
assert Lock.check_aggregate(chain_str, LockEnum.CREATE, address=foo_address) > 0
assert Lock.check_aggregate(chain_str, LockEnum.CREATE, address=bar_address) == 0

View File

@@ -0,0 +1,20 @@
# third-party imports
import pytest
# local imports
from cic_eth.db.models.nonce import Nonce
def test_nonce_increment(
init_database,
eth_empty_accounts,
database_engine,
):
# if database_engine[:6] == 'sqlite':
# pytest.skip('sqlite cannot lock tables which is required for this test, skipping')
nonce = Nonce.next(eth_empty_accounts[0], 3)
assert nonce == 3
nonce = Nonce.next(eth_empty_accounts[0], 3)
assert nonce == 4

View File

@@ -0,0 +1,84 @@
# standard imports
import os
import logging
# third-party imports
import pytest
# local imports
from cic_eth.db.models.base import SessionBase
from cic_eth.db.models.otx import OtxStateLog
from cic_eth.db.models.otx import Otx
from cic_eth.db.enum import StatusEnum
logg = logging.getLogger()
@pytest.mark.skip()
def test_get(
init_w3,
init_database,
):
tx_def = {
'from': init_w3.eth.accounts[0],
'to': init_w3.eth.accounts[1],
'nonce': 0,
'value': 101,
'gasPrice': 2000000000,
'gas': 21000,
'data': '',
'chainId': 1,
}
session = init_database
txs = []
for i in range(10):
nonce = init_w3.eth.getTransactionCount(init_w3.eth.accounts[0], 'pending')
tx_def['nonce'] = nonce
tx = init_w3.eth.sign_transaction(tx_def)
tx_hash = init_w3.eth.send_raw_transaction(tx['raw'])
logg.debug('tx {}'.format(tx))
address = init_w3.eth.accounts[i%3]
otx = Otx(int((i/3)+1), address, '0x'+tx_hash.hex(), tx['raw'])
txs.append(otx)
session.add(otx)
session.flush()
logg.debug(txs)
session.commit()
txs[0].status = 0
session.add(txs[0])
session.commit()
session.close()
get_txs = Otx.get()
logg.debug(get_txs)
def test_state_log(
init_database,
):
Otx.tracing = True
address = '0x' + os.urandom(20).hex()
tx_hash = '0x' + os.urandom(32).hex()
signed_tx = '0x' + os.urandom(128).hex()
otx = Otx.add(0, address, tx_hash, signed_tx, session=init_database)
otx.waitforgas(session=init_database)
otx.sent(session=init_database)
otx.success(1024, session=init_database)
q = init_database.query(OtxStateLog)
q = q.filter(OtxStateLog.otx_id==otx.id)
q = q.order_by(OtxStateLog.date.asc())
logs = q.all()
assert logs[0].status == StatusEnum.PENDING
assert logs[1].status == StatusEnum.WAITFORGAS
assert logs[2].status == StatusEnum.SENT
assert logs[3].status == StatusEnum.SUCCESS

View File

@@ -0,0 +1,55 @@
# standard imports
import logging
# third-party imports
import pytest
# local imports
from cic_eth.db import Otx
from cic_eth.db.error import TxStateChangeError
logg = logging.getLogger()
# Check that invalid transitions throw exceptions
# sent
def test_db_queue_states(
init_database,
):
session = init_database
# these values are completely arbitary
tx_hash = '0xF182DFA3AD48723E7E222FE7B4C2C44C23CD4D7FF413E8999DFA15ECE53F'
address = '0x38C5559D6EDDDA1F705D3AB1A664CA1B397EB119'
signed_tx = '0xA5866A5383249AE843546BDA46235A1CA1614F538FB486140693C2EF1956FC53213F6AEF0F99F44D7103871AF3A12B126DCF9BFB7AF11143FAB3ECE2B452EE35D1320C4C7C6F999C8DF4EB09E729715B573F6672ED852547F552C4AE99D17DCD14C810'
o = Otx(
nonce=42,
address=address[2:],
tx_hash=tx_hash[2:],
signed_tx=signed_tx[2:],
)
session.add(o)
session.commit()
o.sent(session=session)
session.commit()
# send after sent is ok
o.sent(session=session)
session.commit()
o.sendfail(session=session)
session.commit()
with pytest.raises(TxStateChangeError):
o.sendfail(session=session)
o.sent(session=session)
session.commit()
o.minefail(1234, session=session)
session.commit()
with pytest.raises(TxStateChangeError):
o.sent(session=session)

View File

@@ -0,0 +1,29 @@
# local imports
from cic_eth.db.models.role import AccountRole
def test_db_role(
init_database,
eth_empty_accounts,
):
foo = AccountRole.set('foo', eth_empty_accounts[0])
init_database.add(foo)
init_database.commit()
assert AccountRole.get_address('foo') == eth_empty_accounts[0]
bar = AccountRole.set('bar', eth_empty_accounts[1])
init_database.add(bar)
init_database.commit()
assert AccountRole.get_address('bar') == eth_empty_accounts[1]
foo = AccountRole.set('foo', eth_empty_accounts[2])
init_database.add(foo)
init_database.commit()
assert AccountRole.get_address('foo') == eth_empty_accounts[2]
assert AccountRole.get_address('bar') == eth_empty_accounts[1]
tag = AccountRole.role_for(eth_empty_accounts[2])
assert tag == 'foo'
tag = AccountRole.role_for(eth_empty_accounts[3])
assert tag == None

View File

@@ -0,0 +1,124 @@
# standard imports
import os
# third-party imports
import pytest
from cic_registry import zero_address
# local imports
from cic_eth.db.models.tx import TxCache
from cic_eth.db.models.otx import Otx
from cic_eth.eth.task import sign_tx
def test_set(
init_w3,
init_database,
):
tx_def = {
'from': init_w3.eth.accounts[0],
'to': init_w3.eth.accounts[1],
'nonce': 0,
'value': 500000000000000000000,
'gasPrice': 2000000000,
'gas': 21000,
'data': '',
'chainId': 1,
}
(tx_hash, tx_signed) = sign_tx(tx_def, 'Foo:1')
otx = Otx(
tx_def['nonce'],
tx_def['from'],
tx_hash,
tx_signed,
)
init_database.add(otx)
init_database.commit()
bogus_from_token = '0x' + os.urandom(20).hex()
to_value = int(tx_def['value'] / 2)
tx = TxCache(
tx_hash,
tx_def['from'],
tx_def['to'],
bogus_from_token,
zero_address,
tx_def['value'],
to_value,
666,
13,
)
init_database.add(tx)
init_database.commit()
tx_stored = init_database.query(TxCache).first()
assert (tx_stored.sender == tx_def['from'])
assert (tx_stored.recipient == tx_def['to'])
assert (tx_stored.source_token_address == bogus_from_token)
assert (tx_stored.destination_token_address == zero_address)
assert (tx_stored.from_value == '1b1ae4d6e2ef500000')
assert (tx_stored.to_value == '0d8d726b7177a80000')
assert (tx_stored.values() == (tx_def['value'], to_value))
assert (tx_stored.block_number == 666)
assert (tx_stored.tx_index == 13)
def test_clone(
init_database,
init_w3,
):
txs = []
for i in range(2):
tx_def = {
'from': init_w3.eth.accounts[0],
'to': init_w3.eth.accounts[1],
'nonce': 0,
'value': 500000000000000000000,
'gasPrice': 2000000000 + i,
'gas': 21000,
'data': '',
'chainId': 1,
}
(tx_hash, tx_signed) = sign_tx(tx_def, 'Foo:1')
otx = Otx(
tx_def['nonce'],
tx_def['from'],
tx_hash,
tx_signed,
)
init_database.add(otx)
tx_def['hash'] = tx_hash
txs.append(tx_def)
init_database.commit()
txc = TxCache(
txs[0]['hash'],
txs[0]['from'],
txs[0]['to'],
zero_address,
zero_address,
txs[0]['value'],
txs[0]['value'],
)
init_database.add(txc)
init_database.commit()
TxCache.clone(txs[0]['hash'], txs[1]['hash'])
q = init_database.query(TxCache)
q = q.join(Otx)
q = q.filter(Otx.tx_hash==txs[1]['hash'])
txc_clone = q.first()
assert txc_clone != None
assert txc_clone.sender == txc.sender
assert txc_clone.recipient == txc.recipient
assert txc_clone.source_token_address == txc.source_token_address
assert txc_clone.destination_token_address == txc.destination_token_address
assert txc_clone.from_value == txc.from_value
assert txc_clone.to_value == txc.to_value

View File

@@ -0,0 +1,129 @@
# standard imports
import logging
# third-party imports
import pytest
from cic_registry import CICRegistry
# local imports
from cic_eth.eth.bancor import BancorTxFactory, unpack_convert
from cic_eth.eth.bancor import resolve_converters_by_tokens
from cic_eth.eth.util import unpack_signed_raw_tx
from cic_eth.queue.tx import create as queue_create
from cic_eth.eth.bancor import otx_cache_convert
from cic_eth.db.models.otx import Otx
from cic_eth.db.models.tx import TxCache
logg = logging.getLogger()
def test_resolve_converters_by_tokens(
cic_registry,
init_w3,
bancor_tokens,
bancor_registry,
default_chain_spec,
):
r = resolve_converters_by_tokens(
[
{
'address': bancor_tokens[0],
},
{
'address': bancor_tokens[1],
},
],
str(default_chain_spec),
)
logg.warning('this test should be hardened by verifying the converters')
for t in r:
assert t['converters'] != None
assert len(t['converters']) == 1
def test_unpack_convert(
default_chain_spec,
cic_registry,
init_w3,
init_rpc,
bancor_tokens,
bancor_registry,
):
txf = BancorTxFactory(init_w3.eth.accounts[0], init_rpc)
default_reserve = CICRegistry.get_contract(default_chain_spec, 'BNTToken')
convert_tx = txf.convert(
bancor_tokens[0],
bancor_tokens[1],
default_reserve.address(),
42,
13,
default_chain_spec,
)
s = init_w3.eth.sign_transaction(convert_tx)
s_bytes = bytes.fromhex(s['raw'][2:])
tx_dict = unpack_signed_raw_tx(s_bytes, default_chain_spec.chain_id())
convert_contract = CICRegistry.get_contract(default_chain_spec, 'BancorNetwork')
assert tx_dict['from'] == init_w3.eth.accounts[0]
assert tx_dict['to'] == convert_contract.address()
assert tx_dict['value'] == 0
convert_data = unpack_convert(tx_dict['data'])
assert convert_data['amount'] == 42
assert convert_data['min_return'] == 13
assert convert_data['source_token'] == bancor_tokens[0]
assert convert_data['destination_token'] == bancor_tokens[1]
assert convert_data['fee_recipient'] == '0000000000000000000000000000000000000000000000000000000000000000'
assert convert_data['fee'] == 0
def test_queue_cache_convert(
default_chain_spec,
init_w3,
init_rpc,
init_database,
cic_registry,
bancor_registry,
bancor_tokens,
):
txf = BancorTxFactory(init_w3.eth.accounts[0], init_rpc)
amount = 42
min_return = 13
default_reserve = CICRegistry.get_contract(default_chain_spec, 'BNTToken', 'ERC20')
transfer_tx = txf.convert(
bancor_tokens[0],
bancor_tokens[1],
default_reserve.address(),
amount,
min_return,
default_chain_spec,
)
tx_signed = init_w3.eth.sign_transaction(transfer_tx)
tx_hash = init_w3.eth.sendRawTransaction(tx_signed['raw'])
tx_hash_hex = tx_hash.hex()
nonce = int(tx_signed['nonce'][2:], 16)
tx_hash_queue = queue_create(nonce, init_w3.eth.accounts[0], tx_hash_hex, tx_signed['raw'], str(default_chain_spec))
tx_hash_cache = otx_cache_convert(tx_hash_hex, tx_signed['raw'], str(default_chain_spec))
assert tx_hash_hex == tx_hash_queue
assert tx_hash_hex == tx_hash_cache
session = Otx.create_session()
otx = session.query(Otx).filter(Otx.tx_hash==tx_hash_hex).first()
assert otx.tx_hash == tx_hash_hex
txc = session.query(TxCache).filter(TxCache.otx_id==otx.id).first()
assert txc.sender == init_w3.eth.accounts[0]
assert txc.recipient == init_w3.eth.accounts[0]
assert txc.source_token_address == bancor_tokens[0]
assert txc.destination_token_address == bancor_tokens[1]
assert txc.values() == (amount, amount)

View File

@@ -0,0 +1,51 @@
# standard imports
import logging
# local imports
from cic_eth.eth.nonce import NonceOracle
logg = logging.getLogger()
def test_nonce_sequence(
eth_empty_accounts,
init_database,
init_rpc,
):
account= init_rpc.w3.eth.personal.new_account('')
no = NonceOracle(account, 0)
n = no.next()
assert n == 0
n = no.next()
assert n == 1
init_rpc.w3.eth.sendTransaction({
'from': init_rpc.w3.eth.accounts[0],
'to': account,
'value': 200000000,
})
init_rpc.w3.eth.sendTransaction({
'from': account,
'to': eth_empty_accounts[0],
'value': 100,
})
c = init_rpc.w3.eth.getTransactionCount(account, 'pending')
logg.debug('nonce {}'.format(c))
account= init_rpc.w3.eth.personal.new_account('')
no = NonceOracle(account, c)
n = no.next()
assert n == 1
n = no.next()
assert n == 2
# try with bogus value
no = NonceOracle(account, 4)
n = no.next()
assert n == 3

View File

@@ -0,0 +1,24 @@
from cic_eth.eth.util import unpack_signed_raw_tx
from cic_eth.eth.task import sign_tx
def test_unpack(
init_rpc,
w3,
):
tx = {
'from': w3.eth.accounts[1],
'to': w3.eth.accounts[0],
'nonce': 0,
'value': 1024,
'gas': 21000,
'gasPrice': 200000000,
'data': '0x',
'chainId': 8995,
}
(tx_hash, tx_raw) = sign_tx(tx, 'Foo:8995')
tx_recovered = unpack_signed_raw_tx(bytes.fromhex(tx_raw[2:]), 8995)
assert tx_hash == tx_recovered['hash']

View File

@@ -0,0 +1,88 @@
# standard imports
import logging
# third-party imports
import pytest
from cic_registry import CICRegistry
# local imports
from cic_eth.eth.token import TokenTxFactory, unpack_transfer, otx_cache_transfer
from cic_eth.eth.util import unpack_signed_raw_tx
from cic_eth.queue.tx import create as queue_create
from cic_eth.db.models.otx import Otx
from cic_eth.db.models.tx import TxCache
logg = logging.getLogger()
def test_unpack_transfer(
default_chain_spec,
init_w3,
init_rpc,
cic_registry,
bancor_tokens,
bancor_registry,
):
source_token = CICRegistry.get_address(default_chain_spec, bancor_tokens[0])
logg.debug('bancor tokens {} {}'.format(bancor_tokens, source_token))
txf = TokenTxFactory(init_w3.eth.accounts[0], init_rpc)
transfer_tx = txf.transfer(
source_token.address(),
init_w3.eth.accounts[1],
42,
default_chain_spec,
)
s = init_w3.eth.sign_transaction(transfer_tx)
s_bytes = bytes.fromhex(s['raw'][2:])
tx_dict = unpack_signed_raw_tx(s_bytes, default_chain_spec.chain_id())
assert tx_dict['from'] == init_w3.eth.accounts[0]
assert tx_dict['to'] == bancor_tokens[0]
assert tx_dict['value'] == 0
transfer_data = unpack_transfer(tx_dict['data'])
assert transfer_data['to'] == init_w3.eth.accounts[1]
assert transfer_data['amount'] == 42
def test_queue_cache_transfer(
default_chain_spec,
init_w3,
init_rpc,
init_database,
cic_registry,
bancor_tokens,
bancor_registry,
):
source_token = CICRegistry.get_address(default_chain_spec, bancor_tokens[0])
txf = TokenTxFactory(init_w3.eth.accounts[0], init_rpc)
value = 42
transfer_tx = txf.transfer(
source_token.address(),
init_w3.eth.accounts[1],
value,
default_chain_spec,
)
tx_signed = init_w3.eth.sign_transaction(transfer_tx)
tx_hash = init_w3.eth.sendRawTransaction(tx_signed['raw'])
tx_hash_hex = tx_hash.hex()
nonce = int(tx_signed['nonce'][2:], 16)
tx_hash_queue = queue_create(nonce, init_w3.eth.accounts[0], tx_hash_hex, tx_signed['raw'], str(default_chain_spec))
tx_hash_cache = otx_cache_transfer(tx_hash_hex, tx_signed['raw'], str(default_chain_spec))
assert tx_hash_hex == tx_hash_queue
assert tx_hash_hex == tx_hash_cache
session = Otx.create_session()
otx = session.query(Otx).filter(Otx.tx_hash==tx_hash_hex).first()
assert otx.tx_hash == tx_hash_hex
txc = session.query(TxCache).filter(TxCache.otx_id==otx.id).first()
assert txc.sender == init_w3.eth.accounts[0]
assert txc.recipient == init_w3.eth.accounts[1]
assert txc.source_token_address == bancor_tokens[0]
assert txc.destination_token_address == bancor_tokens[0]
assert txc.values() == (value, value)

View File

@@ -0,0 +1,22 @@
# standard imports
import os
# local imports
from cic_eth.db.models.otx import Otx
from cic_eth.queue.tx import get_state_log
def test_otx_state_log(
init_database,
):
Otx.tracing = True
address = '0x' + os.urandom(20).hex()
tx_hash = '0x' + os.urandom(32).hex()
signed_tx = '0x' + os.urandom(128).hex()
otx = Otx.add(0, address, tx_hash, signed_tx, session=init_database)
init_database.commit()
log = get_state_log(tx_hash)
assert len(log) == 1

View File

@@ -0,0 +1,65 @@
# standard imports
import os
# third-party imports
import pytest
# local imports
from cic_eth.queue.tx import create as queue_create
from cic_eth.db.models.lock import Lock
from cic_eth.db.enum import LockEnum
from cic_eth.error import LockedError
def test_queue_lock(
init_database,
default_chain_spec,
):
chain_str = str(default_chain_spec)
address = '0x' + os.urandom(20).hex()
tx_hash = '0x' + os.urandom(32).hex()
tx_raw = '0x' + os.urandom(128).hex()
Lock.set(chain_str, LockEnum.QUEUE)
with pytest.raises(LockedError):
queue_create(
0,
address,
tx_hash,
tx_raw,
chain_str
)
Lock.set(chain_str, LockEnum.QUEUE, address=address)
with pytest.raises(LockedError):
queue_create(
0,
address,
tx_hash,
tx_raw,
chain_str
)
Lock.reset(chain_str, LockEnum.QUEUE)
with pytest.raises(LockedError):
queue_create(
0,
address,
tx_hash,
tx_raw,
chain_str
)
Lock.set(chain_str, LockEnum.QUEUE, address=address, tx_hash=tx_hash)
with pytest.raises(LockedError):
queue_create(
0,
address,
tx_hash,
tx_raw,
chain_str
)

View File

@@ -0,0 +1,500 @@
# standard imports import logging
import datetime
import os
import logging
# third-party imports
import pytest
from sqlalchemy import DateTime
from cic_registry import CICRegistry
# local imports
from cic_eth.eth.rpc import RpcClient
from cic_eth.eth.tx import cache_gas_refill_data
from cic_eth.db.models.otx import Otx
from cic_eth.db.models.otx import OtxSync
from cic_eth.db.models.tx import TxCache
from cic_eth.db.models.lock import Lock
from cic_eth.db.models.base import SessionBase
from cic_eth.db.enum import StatusEnum
from cic_eth.db.enum import LockEnum
from cic_eth.queue.tx import create as queue_create
from cic_eth.queue.tx import set_final_status
from cic_eth.queue.tx import set_sent_status
from cic_eth.queue.tx import set_waitforgas
from cic_eth.queue.tx import set_ready
from cic_eth.queue.tx import get_paused_txs
from cic_eth.queue.tx import get_upcoming_tx
from cic_eth.queue.tx import get_account_tx
from cic_eth.queue.tx import get_tx
from cic_eth.eth.util import unpack_signed_raw_tx
from cic_eth.db.error import TxStateChangeError
logg = logging.getLogger()
def test_finalize(
default_chain_spec,
init_w3,
init_database,
):
tx_hashes = []
for i in range(1, 6):
tx = {
'from': init_w3.eth.accounts[0],
'to': init_w3.eth.accounts[1],
'nonce': 42 + int(i/5),
'gas': 21000,
'gasPrice': 1000000*i,
'value': 128,
'chainId': 666,
'data': '',
}
logg.debug('nonce {}'.format(tx['nonce']))
tx_signed = init_w3.eth.sign_transaction(tx)
#tx_hash = RpcClient.w3.keccak(hexstr=tx_signed['raw'])
tx_hash = init_w3.keccak(hexstr=tx_signed['raw'])
queue_create(tx['nonce'], tx['from'], tx_hash.hex(), tx_signed['raw'], str(default_chain_spec))
cache_gas_refill_data(tx_hash.hex(), tx)
tx_hashes.append(tx_hash.hex())
if i < 4:
set_sent_status(tx_hash.hex())
otx = init_database.query(Otx).filter(Otx.tx_hash==tx_hashes[0]).first()
assert otx.status == StatusEnum.OBSOLETED
otx = init_database.query(Otx).filter(Otx.tx_hash==tx_hashes[1]).first()
assert otx.status == StatusEnum.OBSOLETED
otx = init_database.query(Otx).filter(Otx.tx_hash==tx_hashes[2]).first()
assert otx.status == StatusEnum.OBSOLETED
otx = init_database.query(Otx).filter(Otx.tx_hash==tx_hashes[3]).first()
assert otx.status == StatusEnum.PENDING
otx = init_database.query(Otx).filter(Otx.tx_hash==tx_hashes[4]).first()
assert otx.status == StatusEnum.PENDING
set_sent_status(tx_hashes[3], False)
set_sent_status(tx_hashes[4], False)
set_final_status(tx_hashes[3], 1024)
otx = init_database.query(Otx).filter(Otx.tx_hash==tx_hashes[0]).first()
assert otx.status == StatusEnum.CANCELLED
otx = init_database.query(Otx).filter(Otx.tx_hash==tx_hashes[1]).first()
assert otx.status == StatusEnum.CANCELLED
otx = init_database.query(Otx).filter(Otx.tx_hash==tx_hashes[2]).first()
assert otx.status == StatusEnum.CANCELLED
otx = init_database.query(Otx).filter(Otx.tx_hash==tx_hashes[3]).first()
assert otx.status == StatusEnum.SUCCESS
otx = init_database.query(Otx).filter(Otx.tx_hash==tx_hashes[4]).first()
assert otx.status == StatusEnum.SENT
def test_expired(
default_chain_spec,
init_database,
init_w3,
):
tx_hashes = []
for i in range(1, 6):
tx = {
'from': init_w3.eth.accounts[0],
'to': init_w3.eth.accounts[1],
'nonce': 42 + int(i/2),
'gas': 21000,
'gasPrice': 1000000*i,
'value': 128,
'chainId': 666,
'data': '0x',
}
tx_signed = init_w3.eth.sign_transaction(tx)
#tx_hash = RpcClient.w3.keccak(hexstr=tx_signed['raw'])
tx_hash = init_w3.keccak(hexstr=tx_signed['raw'])
queue_create(tx['nonce'], tx['from'], tx_hash.hex(), tx_signed['raw'], str(default_chain_spec))
cache_gas_refill_data(tx_hash.hex(), tx)
tx_hashes.append(tx_hash.hex())
set_sent_status(tx_hash.hex(), False)
otx = init_database.query(Otx).filter(Otx.tx_hash==tx_hash.hex()).first()
fake_created = datetime.datetime.utcnow() - datetime.timedelta(seconds=40*i)
otx.date_created = fake_created
init_database.add(otx)
init_database.commit()
init_database.refresh(otx)
now = datetime.datetime.utcnow()
delta = datetime.timedelta(seconds=61)
then = now - delta
otxs = OtxSync.get_expired(then)
nonce_acc = 0
for otx in otxs:
nonce_acc += otx.nonce
assert nonce_acc == (43 + 44)
def test_get_paused(
init_w3,
init_database,
cic_registry,
default_chain_spec,
):
tx_hashes = []
for i in range(1, 3):
tx = {
'from': init_w3.eth.accounts[0],
'to': init_w3.eth.accounts[1],
'nonce': 42 + int(i),
'gas': 21000,
'gasPrice': 1000000*i,
'value': 128,
'chainId': 8995,
'data': '0x',
}
logg.debug('nonce {}'.format(tx['nonce']))
tx_signed = init_w3.eth.sign_transaction(tx)
#tx_hash = RpcClient.w3.keccak(hexstr=tx_signed['raw'])
tx_hash = init_w3.keccak(hexstr=tx_signed['raw'])
queue_create(tx['nonce'], tx['from'], tx_hash.hex(), tx_signed['raw'], str(default_chain_spec))
cache_gas_refill_data(tx_hash.hex(), tx)
tx_hashes.append(tx_hash.hex())
#txs = get_paused_txs(recipient=init_w3.eth.accounts[1])
txs = get_paused_txs(sender=init_w3.eth.accounts[0])
assert len(txs.keys()) == 0
q = init_database.query(Otx)
q = q.filter(Otx.tx_hash==tx_hashes[0])
r = q.first()
r.waitforgas(session=init_database)
init_database.add(r)
init_database.commit()
chain_id = default_chain_spec.chain_id()
txs = get_paused_txs(chain_id=chain_id)
assert len(txs.keys()) == 1
#txs = get_paused_txs(recipient=init_w3.eth.accounts[1])
txs = get_paused_txs(sender=init_w3.eth.accounts[0], chain_id=chain_id)
assert len(txs.keys()) == 1
txs = get_paused_txs(status=StatusEnum.WAITFORGAS)
assert len(txs.keys()) == 1
#txs = get_paused_txs(recipient=init_w3.eth.accounts[1], status=StatusEnum.WAITFORGAS)
txs = get_paused_txs(sender=init_w3.eth.accounts[0], status=StatusEnum.WAITFORGAS, chain_id=chain_id)
assert len(txs.keys()) == 1
q = init_database.query(Otx)
q = q.filter(Otx.tx_hash==tx_hashes[1])
o = q.first()
o.waitforgas(session=init_database)
init_database.add(o)
init_database.commit()
txs = get_paused_txs()
assert len(txs.keys()) == 2
#txs = get_paused_txs(recipient=init_w3.eth.accounts[1])
txs = get_paused_txs(sender=init_w3.eth.accounts[0], chain_id=chain_id)
assert len(txs.keys()) == 2
txs = get_paused_txs(status=StatusEnum.WAITFORGAS, chain_id=chain_id)
assert len(txs.keys()) == 2
#txs = get_paused_txs(recipient=init_w3.eth.accounts[1], status=StatusEnum.WAITFORGAS)
txs = get_paused_txs(sender=init_w3.eth.accounts[0], status=StatusEnum.WAITFORGAS, chain_id=chain_id)
assert len(txs.keys()) == 2
q = init_database.query(Otx)
q = q.filter(Otx.tx_hash==tx_hashes[1])
o = q.first()
o.sendfail(session=init_database)
init_database.add(o)
init_database.commit()
txs = get_paused_txs()
assert len(txs.keys()) == 2
txs = get_paused_txs(sender=init_w3.eth.accounts[0], chain_id=chain_id)
assert len(txs.keys()) == 2
txs = get_paused_txs(status=StatusEnum.WAITFORGAS, chain_id=chain_id)
assert len(txs.keys()) == 1
#txs = get_paused_txs(recipient=init_w3.eth.accounts[1], status=StatusEnum.WAITFORGAS)
txs = get_paused_txs(sender=init_w3.eth.accounts[0], status=StatusEnum.WAITFORGAS, chain_id=chain_id)
assert len(txs.keys()) == 1
def test_get_upcoming(
default_chain_spec,
init_w3,
init_database,
cic_registry,
):
tx_hashes = []
for i in range(0, 7):
tx = {
'from': init_w3.eth.accounts[i % 3],
'to': init_w3.eth.accounts[1],
'nonce': 42 + int(i / 3),
'gas': 21000,
'gasPrice': 1000000*i,
'value': 128,
'chainId': 8995,
'data': '0x',
}
tx_signed = init_w3.eth.sign_transaction(tx)
tx_hash = init_w3.keccak(hexstr=tx_signed['raw'])
logg.debug('{} nonce {} {}'.format(i, tx['nonce'], tx_hash.hex()))
queue_create(tx['nonce'], tx['from'], tx_hash.hex(), tx_signed['raw'], str(default_chain_spec))
cache_gas_refill_data(tx_hash.hex(), tx)
tx_hashes.append(tx_hash.hex())
chain_id = int(default_chain_spec.chain_id())
txs = get_upcoming_tx(StatusEnum.PENDING, chain_id=chain_id)
assert len(txs.keys()) == 3
tx = unpack_signed_raw_tx(bytes.fromhex(txs[tx_hashes[0]][2:]), chain_id)
assert tx['nonce'] == 42
tx = unpack_signed_raw_tx(bytes.fromhex(txs[tx_hashes[1]][2:]), chain_id)
assert tx['nonce'] == 42
tx = unpack_signed_raw_tx(bytes.fromhex(txs[tx_hashes[2]][2:]), chain_id)
assert tx['nonce'] == 42
q = init_database.query(TxCache)
q = q.filter(TxCache.sender==init_w3.eth.accounts[0])
for o in q.all():
o.date_checked -= datetime.timedelta(seconds=30)
init_database.add(o)
init_database.commit()
before = datetime.datetime.now() - datetime.timedelta(seconds=20)
logg.debug('before {}'.format(before))
txs = get_upcoming_tx(StatusEnum.PENDING, before=before)
logg.debug('txs {} {}'.format(txs.keys(), txs.values()))
assert len(txs.keys()) == 1
# Now date checked has been set to current time, and the check returns no results
txs = get_upcoming_tx(StatusEnum.PENDING, before=before)
logg.debug('txs {} {}'.format(txs.keys(), txs.values()))
assert len(txs.keys()) == 0
set_sent_status(tx_hashes[0])
txs = get_upcoming_tx(StatusEnum.PENDING)
assert len(txs.keys()) == 3
with pytest.raises(KeyError):
tx = txs[tx_hashes[0]]
tx = unpack_signed_raw_tx(bytes.fromhex(txs[tx_hashes[3]][2:]), chain_id)
assert tx['nonce'] == 43
set_waitforgas(tx_hashes[1])
txs = get_upcoming_tx(StatusEnum.PENDING)
assert len(txs.keys()) == 3
with pytest.raises(KeyError):
tx = txs[tx_hashes[1]]
tx = unpack_signed_raw_tx(bytes.fromhex(txs[tx_hashes[3]][2:]), chain_id)
assert tx['nonce'] == 43
txs = get_upcoming_tx(StatusEnum.WAITFORGAS)
assert len(txs.keys()) == 1
def test_upcoming_with_lock(
default_chain_spec,
init_database,
init_w3,
):
chain_id = int(default_chain_spec.chain_id())
chain_str = str(default_chain_spec)
tx = {
'from': init_w3.eth.accounts[0],
'to': init_w3.eth.accounts[1],
'nonce': 42,
'gas': 21000,
'gasPrice': 1000000,
'value': 128,
'chainId': 8995,
'data': '0x',
}
tx_signed = init_w3.eth.sign_transaction(tx)
tx_hash = init_w3.keccak(hexstr=tx_signed['raw'])
logg.debug('nonce {} {}'.format(tx['nonce'], tx_hash.hex()))
queue_create(tx['nonce'], tx['from'], tx_hash.hex(), tx_signed['raw'], str(default_chain_spec))
cache_gas_refill_data(tx_hash.hex(), tx)
txs = get_upcoming_tx(StatusEnum.PENDING, chain_id=chain_id)
assert len(txs.keys()) == 1
Lock.set(chain_str, LockEnum.SEND, address=init_w3.eth.accounts[0])
txs = get_upcoming_tx(StatusEnum.PENDING, chain_id=chain_id)
assert len(txs.keys()) == 0
tx = {
'from': init_w3.eth.accounts[1],
'to': init_w3.eth.accounts[0],
'nonce': 42,
'gas': 21000,
'gasPrice': 1000000,
'value': 128,
'chainId': 8995,
'data': '0x',
}
tx_signed = init_w3.eth.sign_transaction(tx)
tx_hash = init_w3.keccak(hexstr=tx_signed['raw'])
logg.debug('nonce {} {}'.format(tx['nonce'], tx_hash.hex()))
queue_create(tx['nonce'], tx['from'], tx_hash.hex(), tx_signed['raw'], str(default_chain_spec))
cache_gas_refill_data(tx_hash.hex(), tx)
txs = get_upcoming_tx(StatusEnum.PENDING, chain_id=chain_id)
assert len(txs.keys()) == 1
def test_obsoletion(
default_chain_spec,
init_w3,
init_database,
):
tx_hashes = []
for i in range(0, 4):
tx = {
'from': init_w3.eth.accounts[int(i/2)],
'to': init_w3.eth.accounts[1],
'nonce': 42 + int(i/3),
'gas': 21000,
'gasPrice': 1000000*i,
'value': 128,
'chainId': 8995,
'data': '0x',
}
logg.debug('nonce {}'.format(tx['nonce']))
tx_signed = init_w3.eth.sign_transaction(tx)
tx_hash = init_w3.keccak(hexstr=tx_signed['raw'])
queue_create(tx['nonce'], tx['from'], tx_hash.hex(), tx_signed['raw'], str(default_chain_spec))
cache_gas_refill_data(tx_hash.hex(), tx)
tx_hashes.append(tx_hash.hex())
if i < 2:
set_sent_status(tx_hash.hex())
session = SessionBase.create_session()
q = session.query(Otx)
q = q.filter(Otx.status==StatusEnum.OBSOLETED)
z = 0
for o in q.all():
z += o.nonce
session.close()
assert z == 42
set_final_status(tx_hashes[1], 362436, True)
session = SessionBase.create_session()
q = session.query(Otx)
q = q.filter(Otx.status==StatusEnum.OBSOLETED)
zo = 0
for o in q.all():
zo += o.nonce
q = session.query(Otx)
q = q.filter(Otx.status==StatusEnum.CANCELLED)
zc = 0
for o in q.all():
zc += o.nonce
session.close()
assert zo == 0
assert zc == 42
def test_retry(
init_database,
):
address = '0x' + os.urandom(20).hex()
tx_hash = '0x' + os.urandom(32).hex()
signed_tx = '0x' + os.urandom(128).hex()
otx = Otx(0, address, tx_hash, signed_tx)
init_database.add(otx)
init_database.commit()
set_sent_status(tx_hash, True)
set_ready(tx_hash)
q = init_database.query(Otx)
q = q.filter(Otx.tx_hash==tx_hash)
otx = q.first()
assert otx.status == StatusEnum.RETRY
set_sent_status(tx_hash, False)
set_ready(tx_hash)
q = init_database.query(Otx)
q = q.filter(Otx.tx_hash==tx_hash)
otx = q.first()
assert otx.status == StatusEnum.RETRY
def test_get_account_tx(
default_chain_spec,
init_database,
init_w3,
):
tx_hashes = []
for i in range(0, 4):
tx = {
'from': init_w3.eth.accounts[int(i/3)],
'to': init_w3.eth.accounts[3-i],
'nonce': 42 + i,
'gas': 21000,
'gasPrice': 1000000*i,
'value': 128,
'chainId': 666,
'data': '',
}
logg.debug('nonce {}'.format(tx['nonce']))
tx_signed = init_w3.eth.sign_transaction(tx)
tx_hash = init_w3.keccak(hexstr=tx_signed['raw'])
queue_create(tx['nonce'], tx['from'], tx_hash.hex(), tx_signed['raw'], str(default_chain_spec))
cache_gas_refill_data(tx_hash.hex(), tx)
tx_hashes.append(tx_hash.hex())
txs = get_account_tx(init_w3.eth.accounts[0])
logg.debug('tx {} tx {}'.format(list(txs.keys()), tx_hashes))
assert list(txs.keys()) == tx_hashes
txs = get_account_tx(init_w3.eth.accounts[0], as_recipient=False)
assert list(txs.keys()) == tx_hashes[:3]
txs = get_account_tx(init_w3.eth.accounts[0], as_sender=False)
assert list(txs.keys()) == tx_hashes[3:]

View File

@@ -0,0 +1,43 @@
# standard imports
import logging
# local imports
from cic_eth.sync.head import HeadSyncer
from cic_eth.sync.backend import SyncerBackend
logg = logging.getLogger()
def test_head(
init_rpc,
init_database,
init_eth_tester,
mocker,
eth_empty_accounts,
):
#backend = SyncBackend(eth_empty_accounts[0], 'foo')
block_number = init_rpc.w3.eth.blockNumber
backend = SyncerBackend.live('foo:666', block_number)
syncer = HeadSyncer(backend)
#init_eth_tester.mine_block()
nonce = init_rpc.w3.eth.getTransactionCount(init_rpc.w3.eth.accounts[0], 'pending')
logg.debug('nonce {}'.format(nonce))
tx = {
'from': init_rpc.w3.eth.accounts[0],
'to': eth_empty_accounts[0],
'value': 404,
'gas': 21000,
'gasPrice': init_rpc.w3.eth.gasPrice,
'nonce': nonce,
}
tx_hash_one = init_rpc.w3.eth.sendTransaction(tx)
block_number = init_rpc.w3.eth.blockNumber
backend.set(block_number, 0)
b = syncer.get(init_rpc.w3)
tx = init_rpc.w3.eth.getTransactionByBlock(b[0], 0)
assert tx.hash.hex() == tx_hash_one.hex()

View File

@@ -0,0 +1,194 @@
# standard imports
import logging
# third-party imports
import pytest
from web3.exceptions import BlockNotFound
from cic_registry import CICRegistry
# local imports
from cic_eth.sync.history import HistorySyncer
from cic_eth.sync.head import HeadSyncer
#from cic_eth.sync import Syncer
from cic_eth.db.models.otx import OtxSync
from cic_eth.db.models.base import SessionBase
from cic_eth.sync.backend import SyncerBackend
logg = logging.getLogger()
class FinishedError(Exception):
pass
class DebugFilter:
def __init__(self, address):
self.txs = []
self.monitor_to_address = address
def filter(self, w3, tx, rcpt, chain_spec):
logg.debug('sync filter {}'.format(tx['hash'].hex()))
if tx['to'] == self.monitor_to_address:
self.txs.append(tx)
# hack workaround, latest block hash not found in eth_tester for some reason
if len(self.txs) == 2:
raise FinishedError('intentionally finished on tx {}'.format(tx))
def test_history(
init_rpc,
init_database,
init_eth_tester,
#celery_session_worker,
eth_empty_accounts,
):
nonce = init_rpc.w3.eth.getTransactionCount(init_rpc.w3.eth.accounts[0], 'pending')
logg.debug('nonce {}'.format(nonce))
tx = {
'from': init_rpc.w3.eth.accounts[0],
'to': eth_empty_accounts[0],
'value': 404,
'gas': 21000,
'gasPrice': init_rpc.w3.eth.gasPrice,
'nonce': nonce,
}
tx_hash_one = init_rpc.w3.eth.sendTransaction(tx)
nonce = init_rpc.w3.eth.getTransactionCount(init_rpc.w3.eth.accounts[0], 'pending')
logg.debug('nonce {}'.format(nonce))
tx = {
'from': init_rpc.w3.eth.accounts[1],
'to': eth_empty_accounts[0],
'value': 404,
'gas': 21000,
'gasPrice': init_rpc.w3.eth.gasPrice,
'nonce': nonce,
}
tx_hash_two = init_rpc.w3.eth.sendTransaction(tx)
init_eth_tester.mine_block()
block_number = init_rpc.w3.eth.blockNumber
live_syncer = SyncerBackend.live('foo:666', 0)
HeadSyncer(live_syncer)
history_syncers = SyncerBackend.resume('foo:666', block_number)
for history_syncer in history_syncers:
logg.info('history syncer start {} target {}'.format(history_syncer.start(), history_syncer.target()))
backend = history_syncers[0]
syncer = HistorySyncer(backend)
fltr = DebugFilter(eth_empty_accounts[0])
syncer.filter.append(fltr.filter)
logg.debug('have txs {} {}'.format(tx_hash_one.hex(), tx_hash_two.hex()))
try:
syncer.loop(0.1)
except FinishedError:
pass
except BlockNotFound as e:
logg.error('the last block given in loop does not seem to exist :/ {}'.format(e))
check_hashes = []
for h in fltr.txs:
check_hashes.append(h['hash'].hex())
assert tx_hash_one.hex() in check_hashes
assert tx_hash_two.hex() in check_hashes
def test_history_multiple(
init_rpc,
init_database,
init_eth_tester,
#celery_session_worker,
eth_empty_accounts,
):
block_number = init_rpc.w3.eth.blockNumber
live_syncer = SyncerBackend.live('foo:666', block_number)
HeadSyncer(live_syncer)
nonce = init_rpc.w3.eth.getTransactionCount(init_rpc.w3.eth.accounts[0], 'pending')
logg.debug('nonce {}'.format(nonce))
tx = {
'from': init_rpc.w3.eth.accounts[0],
'to': eth_empty_accounts[0],
'value': 404,
'gas': 21000,
'gasPrice': init_rpc.w3.eth.gasPrice,
'nonce': nonce,
}
tx_hash_one = init_rpc.w3.eth.sendTransaction(tx)
init_eth_tester.mine_block()
block_number = init_rpc.w3.eth.blockNumber
history_syncers = SyncerBackend.resume('foo:666', block_number)
for history_syncer in history_syncers:
logg.info('halfway history syncer start {} target {}'.format(history_syncer.start(), history_syncer.target()))
live_syncer = SyncerBackend.live('foo:666', block_number)
HeadSyncer(live_syncer)
nonce = init_rpc.w3.eth.getTransactionCount(init_rpc.w3.eth.accounts[0], 'pending')
logg.debug('nonce {}'.format(nonce))
tx = {
'from': init_rpc.w3.eth.accounts[1],
'to': eth_empty_accounts[0],
'value': 404,
'gas': 21000,
'gasPrice': init_rpc.w3.eth.gasPrice,
'nonce': nonce,
}
tx_hash_two = init_rpc.w3.eth.sendTransaction(tx)
init_eth_tester.mine_block()
block_number = init_rpc.w3.eth.blockNumber
history_syncers = SyncerBackend.resume('foo:666', block_number)
live_syncer = SyncerBackend.live('foo:666', block_number)
HeadSyncer(live_syncer)
for history_syncer in history_syncers:
logg.info('history syncer start {} target {}'.format(history_syncer.start(), history_syncer.target()))
assert len(history_syncers) == 2
backend = history_syncers[0]
syncer = HistorySyncer(backend)
fltr = DebugFilter(eth_empty_accounts[0])
syncer.filter.append(fltr.filter)
try:
syncer.loop(0.1)
except FinishedError:
pass
except BlockNotFound as e:
logg.error('the last block given in loop does not seem to exist :/ {}'.format(e))
check_hashes = []
for h in fltr.txs:
check_hashes.append(h['hash'].hex())
assert tx_hash_one.hex() in check_hashes
backend = history_syncers[1]
syncer = HistorySyncer(backend)
fltr = DebugFilter(eth_empty_accounts[0])
syncer.filter.append(fltr.filter)
try:
syncer.loop(0.1)
except FinishedError:
pass
except BlockNotFound as e:
logg.error('the last block given in loop does not seem to exist :/ {}'.format(e))
check_hashes = []
for h in fltr.txs:
check_hashes.append(h['hash'].hex())
assert tx_hash_two.hex() in check_hashes
history_syncers = SyncerBackend.resume('foo:666', block_number)
assert len(history_syncers) == 0

View File

@@ -0,0 +1,79 @@
# third-party imports
import pytest
# local imports
from cic_eth.db.models.sync import BlockchainSync
from cic_eth.sync.backend import SyncerBackend
def test_scratch(
init_database,
):
with pytest.raises(ValueError):
s = SyncerBackend('Testchain:666', 13)
syncer = SyncerBackend.live('Testchain:666', 13)
s = SyncerBackend('Testchain:666', syncer.object_id)
def test_live(
init_database,
):
s = SyncerBackend.live('Testchain:666', 13)
s.connect()
assert s.db_object.target() == None
s.disconnect()
assert s.get() == (13, 0)
s.set(14, 1)
assert s.get() == (14, 1)
def test_resume(
init_database,
):
live = SyncerBackend.live('Testchain:666', 13)
live.set(13, 2)
resumes = SyncerBackend.resume('Testchain:666', 26)
assert len(resumes) == 1
resume = resumes[0]
assert resume.get() == (13, 2)
resume.set(13, 4)
assert resume.get() == (13, 4)
assert resume.start() == (13, 2)
assert resume.target() == 26
def test_unsynced(
init_database,
):
live = SyncerBackend.live('Testchain:666', 13)
live.set(13, 2)
resumes = SyncerBackend.resume('Testchain:666', 26)
live = SyncerBackend.live('Testchain:666', 26)
resumes[0].set(18, 12)
resumes = SyncerBackend.resume('Testchain:666', 42)
assert len(resumes) == 2
assert resumes[0].start() == (13, 2)
assert resumes[0].get() == (18, 12)
assert resumes[0].target() == 26
assert resumes[1].start() == (26, 0)
assert resumes[1].get() == (26, 0)
assert resumes[1].target() == 42

View File

@@ -0,0 +1,19 @@
# third-party imports
import pytest
# local imports
from cic_eth.db.util import num_serialize
@pytest.mark.parametrize(
'n,b',
[
(0, b'\x00'),
(1, b'\x01'),
(255, b'\xff'),
(256, b'\x01\x00'),
(18446744073709551616, b'\x01\x00\x00\x00\x00\x00\x00\x00\x00'),
],
)
def test_num_serialize(n, b):
assert(num_serialize(n) == b)

View File

@@ -0,0 +1,30 @@
from cic_eth.eth.task import sign_tx
from cic_eth.eth.util import tx_hex_string
from cic_eth.eth.util import unpack_signed_raw_tx_hex
def test_unpack(
init_w3_conn,
):
tx = {
'nonce': 42,
'from': init_w3_conn.eth.accounts[0],
'to': init_w3_conn.eth.accounts[1],
'data': '0xdeadbeef',
'value': 1024,
'gas': 23000,
'gasPrice': 1422521,
'chainId': 1337,
}
(tx_hash, tx_signed) = sign_tx(tx, 'Foo:1337')
tx_unpacked = unpack_signed_raw_tx_hex(tx_signed, 1337)
for k in tx.keys():
assert tx[k] == tx_unpacked[k]
tx_str = tx_hex_string(tx_signed, 1337)
assert tx_str == 'tx nonce 42 from 0x7E5F4552091A69125d5DfCb7b8C2659029395Bdf to 0x2B5AD5c4795c026514f8317c7a215E218DcCD6cF hash 0xe5aba32b1a7255d035faccb70cd8bb92c8c4a2f6bbea3f655bc5a8b802bbaa91'