From ccd9be194a38ce9dd7544a459df23efdb27e14a8 Mon Sep 17 00:00:00 2001 From: nolash Date: Thu, 27 May 2021 20:52:38 +0200 Subject: [PATCH] Add check nonce (blocking) test --- apps/cic-eth/cic_eth/api/api_admin.py | 13 +-- apps/cic-eth/cic_eth/queue/query.py | 2 +- apps/cic-eth/tests/task/api/test_admin.py | 124 +++++++++++++++++++++- 3 files changed, 130 insertions(+), 9 deletions(-) diff --git a/apps/cic-eth/cic_eth/api/api_admin.py b/apps/cic-eth/cic_eth/api/api_admin.py index 618ad0cf..b559b8ce 100644 --- a/apps/cic-eth/cic_eth/api/api_admin.py +++ b/apps/cic-eth/cic_eth/api/api_admin.py @@ -209,7 +209,7 @@ class AdminApi: return s_manual.apply_async() - def check_nonce(self, address): + def check_nonce(self, chain_spec, address): s = celery.signature( 'cic_eth.queue.query.get_account_tx', [ @@ -230,13 +230,12 @@ class AdminApi: s_get_tx = celery.signature( 'cic_eth.queue.query.get_tx', [ - chain_spec.asdict(), + chain_spec.asdict(), k, ], queue=self.queue, ) tx = s_get_tx.apply_async().get() - #tx = get_tx(k) logg.debug('checking nonce {} (previous {})'.format(tx['nonce'], last_nonce)) nonce_otx = tx['nonce'] if not is_alive(tx['status']) and tx['status'] & local_fail > 0: @@ -244,7 +243,9 @@ class AdminApi: blocking_tx = k blocking_nonce = nonce_otx elif nonce_otx - last_nonce > 1: - logg.error('nonce gap; {} followed {} for account {}'.format(nonce_otx, last_nonce, tx['from'])) + logg.debug('tx {}'.format(tx)) + tx_obj = unpack(bytes.fromhex(strip_0x(tx['signed_tx'])), chain_spec) + logg.error('nonce gap; {} followed {} for account {}'.format(nonce_otx, last_nonce, tx_obj['from'])) blocking_tx = k blocking_nonce = nonce_otx break @@ -258,9 +259,9 @@ class AdminApi: 'blocking': blocking_nonce, }, 'tx': { - 'blocking': blocking_tx, - } + 'blocking': add_0x(blocking_tx), } + } def fix_nonce(self, address, nonce, chain_spec): diff --git a/apps/cic-eth/cic_eth/queue/query.py b/apps/cic-eth/cic_eth/queue/query.py index 1572289b..44ed7547 100644 --- a/apps/cic-eth/cic_eth/queue/query.py +++ b/apps/cic-eth/cic_eth/queue/query.py @@ -37,7 +37,7 @@ def get_tx_cache(chain_spec_dict, tx_hash): def get_tx(chain_spec_dict, tx_hash): chain_spec = ChainSpec.from_dict(chain_spec_dict) session = SessionBase.create_session() - r = chainqueue.query.get_tx(chain_spec, tx_hash) + r = chainqueue.query.get_tx(chain_spec, tx_hash, session=session) session.close() return r diff --git a/apps/cic-eth/tests/task/api/test_admin.py b/apps/cic-eth/tests/task/api/test_admin.py index f504e999..e94d3200 100644 --- a/apps/cic-eth/tests/task/api/test_admin.py +++ b/apps/cic-eth/tests/task/api/test_admin.py @@ -9,8 +9,14 @@ from chainlib.eth.tx import ( unpack, TxFormat, ) -from chainlib.eth.nonce import RPCNonceOracle -from chainlib.eth.gas import Gas +from chainlib.eth.nonce import ( + RPCNonceOracle, + OverrideNonceOracle, + ) +from chainlib.eth.gas import ( + Gas, + OverrideGasOracle, + ) from chainlib.eth.address import to_checksum_address from hexathon import ( strip_0x, @@ -23,6 +29,11 @@ from chainqueue.db.enum import ( StatusBits, status_str, ) +from chainqueue.state import ( + set_fubar, + set_ready, + set_reserved, + ) from chainqueue.query import get_tx # local imports @@ -36,6 +47,7 @@ from cic_eth.queue.tx import queue_create logg = logging.getLogger() +@pytest.mark.skip() def test_have_account( default_chain_spec, custodial_roles, @@ -54,6 +66,7 @@ def test_have_account( assert t.get() == None +@pytest.mark.skip() def test_locking( default_chain_spec, init_database, @@ -77,6 +90,7 @@ def test_locking( assert len(r) == 0 +@pytest.mark.skip() def test_tag_account( default_chain_spec, init_database, @@ -121,6 +135,7 @@ def test_tag_account( # api.ready() +@pytest.mark.skip() def test_tx( default_chain_spec, cic_registry, @@ -142,3 +157,108 @@ def test_tx( api = AdminApi(eth_rpc, queue=None, call_address=contract_roles['DEFAULT']) tx = api.tx(default_chain_spec, tx_hash=tx_hash_hex) logg.warning('code missing to verify tx contents {}'.format(tx)) + + + +def test_check_nonce_gap( + default_chain_spec, + init_database, + eth_rpc, + eth_signer, + agent_roles, + contract_roles, + celery_worker, + caplog, + ): + + # NOTE: this only works as long as agents roles start at nonce 0 + nonce_oracle = OverrideNonceOracle(agent_roles['ALICE'], 0) + gas_oracle = OverrideGasOracle(limit=21000, conn=eth_rpc) + + tx_hashes = [] + txs = [] + + j = 0 + for i in range(10): + c = Gas(default_chain_spec, signer=eth_signer, nonce_oracle=nonce_oracle, gas_oracle=gas_oracle) + (tx_hash_hex, tx_signed_raw_hex) = c.create(agent_roles['ALICE'], agent_roles['BOB'], 100 * (10 ** 6), tx_format=TxFormat.RLP_SIGNED) + if i == 3: + j = 1 + nonce_oracle = OverrideNonceOracle(agent_roles['ALICE'], i+1) + + queue_create( + default_chain_spec, + i+j, + agent_roles['ALICE'], + tx_hash_hex, + tx_signed_raw_hex, + session=init_database, + ) + cache_gas_data( + tx_hash_hex, + tx_signed_raw_hex, + default_chain_spec.asdict(), + ) + tx_hashes.append(tx_hash_hex) + txs.append(tx_signed_raw_hex) + + + init_database.commit() + + api = AdminApi(eth_rpc, queue=None, call_address=contract_roles['DEFAULT']) + r = api.check_nonce(default_chain_spec, agent_roles['ALICE']) + + assert r['nonce']['blocking'] == 4 + assert r['tx']['blocking'] == tx_hashes[3] # one less because there is a gap + + +def test_check_nonce_localfail( + default_chain_spec, + init_database, + eth_rpc, + eth_signer, + agent_roles, + contract_roles, + celery_worker, + caplog, + ): + + # NOTE: this only works as long as agents roles start at nonce 0 + nonce_oracle = OverrideNonceOracle(agent_roles['ALICE'], 0) + gas_oracle = OverrideGasOracle(limit=21000, conn=eth_rpc) + + tx_hashes = [] + txs = [] + + j = 0 + for i in range(10): + c = Gas(default_chain_spec, signer=eth_signer, nonce_oracle=nonce_oracle, gas_oracle=gas_oracle) + (tx_hash_hex, tx_signed_raw_hex) = c.create(agent_roles['ALICE'], agent_roles['BOB'], 100 * (10 ** 6), tx_format=TxFormat.RLP_SIGNED) + + queue_create( + default_chain_spec, + i, + agent_roles['ALICE'], + tx_hash_hex, + tx_signed_raw_hex, + session=init_database, + ) + cache_gas_data( + tx_hash_hex, + tx_signed_raw_hex, + default_chain_spec.asdict(), + ) + tx_hashes.append(tx_hash_hex) + txs.append(tx_signed_raw_hex) + + set_ready(default_chain_spec, tx_hashes[4], session=init_database) + set_reserved(default_chain_spec, tx_hashes[4], session=init_database) + set_fubar(default_chain_spec, tx_hashes[4], session=init_database) + + init_database.commit() + + api = AdminApi(eth_rpc, queue=None, call_address=contract_roles['DEFAULT']) + r = api.check_nonce(default_chain_spec, agent_roles['ALICE']) + + assert r['nonce']['blocking'] == 4 + assert r['tx']['blocking'] == tx_hashes[4]