Add fix nonce test, upgrade chainqueue
This commit is contained in:
		
							parent
							
								
									e54e7cf864
								
							
						
					
					
						commit
						0b5fb22b25
					
				| @ -10,8 +10,8 @@ from chainlib.eth.tx import ( | ||||
|         TxFactory, | ||||
|         ) | ||||
| from chainlib.eth.gas import OverrideGasOracle | ||||
| from chainqueue.query import get_tx | ||||
| from chainqueue.state import set_cancel | ||||
| from chainqueue.sql.query import get_tx | ||||
| from chainqueue.sql.state import set_cancel | ||||
| from chainqueue.db.models.otx import Otx | ||||
| from chainqueue.db.models.tx import TxCache | ||||
| from hexathon import strip_0x | ||||
| @ -28,13 +28,14 @@ from cic_eth.admin.ctrl import ( | ||||
|         ) | ||||
| from cic_eth.queue.tx import queue_create | ||||
| from cic_eth.eth.gas import create_check_gas_task | ||||
| from cic_eth.task import BaseTask | ||||
| 
 | ||||
| celery_app = celery.current_app | ||||
| logg = logging.getLogger() | ||||
| 
 | ||||
| 
 | ||||
| @celery_app.task(bind=True) | ||||
| def shift_nonce(self, chain_str, tx_hash_orig_hex, delta=1): | ||||
| @celery_app.task(bind=True, base=BaseTask) | ||||
| def shift_nonce(self, chainspec_dict, tx_hash_orig_hex, delta=1): | ||||
|     """Shift all transactions with nonces higher than the offset by the provided position delta. | ||||
| 
 | ||||
|     Transactions who are replaced by transactions that move nonces will be marked as OVERRIDDEN. | ||||
| @ -45,7 +46,7 @@ def shift_nonce(self, chain_str, tx_hash_orig_hex, delta=1): | ||||
|     :type tx_hash_orig_hex: str, 0x-hex | ||||
|     :param delta: Amount | ||||
|     """ | ||||
|     chain_spec = ChainSpec.from_chain_str(chain_str) | ||||
|     chain_spec = ChainSpec.from_dict(chainspec_dict) | ||||
|     rpc = RPCConnection.connect(chain_spec, 'default') | ||||
|     rpc_signer = RPCConnection.connect(chain_spec, 'signer') | ||||
|     queue = None | ||||
| @ -54,18 +55,20 @@ def shift_nonce(self, chain_str, tx_hash_orig_hex, delta=1): | ||||
|     except AttributeError: | ||||
|         pass | ||||
| 
 | ||||
|     session = SessionBase.create_session() | ||||
|     session = BaseTask.session_func() | ||||
|     tx_brief = get_tx(chain_spec, tx_hash_orig_hex, session=session) | ||||
|     tx_raw = bytes.fromhex(strip_0x(tx_brief['signed_tx'])) | ||||
|     tx = unpack(tx_raw, chain_spec) | ||||
|     nonce = tx_brief['nonce'] | ||||
|     address = tx['from'] | ||||
| 
 | ||||
|     logg.debug('shifting nonce {} position(s) for address {}, offset {}'.format(delta, address, nonce)) | ||||
|     logg.debug('shifting nonce {} position(s) for address {}, offset {}, hash {}'.format(delta, address, nonce, tx['hash'])) | ||||
| 
 | ||||
|     lock_queue(None, chain_spec.asdict(), address=address) | ||||
|     lock_send(None, chain_spec.asdict(), address=address) | ||||
| 
 | ||||
|     set_cancel(chain_spec, strip_0x(tx['hash']), manual=True, session=session) | ||||
| 
 | ||||
|     q = session.query(Otx) | ||||
|     q = q.join(TxCache) | ||||
|     q = q.filter(TxCache.sender==address) | ||||
| @ -83,13 +86,16 @@ def shift_nonce(self, chain_str, tx_hash_orig_hex, delta=1): | ||||
|         tx_previous_hash_hex = tx_new['hash'] | ||||
|         tx_previous_nonce = tx_new['nonce'] | ||||
| 
 | ||||
|         del(tx_new['hash']) | ||||
|         del(tx_new['hash_unsigned']) | ||||
|         tx_new['gas_price'] += 1 | ||||
|         tx_new['gasPrice'] = tx_new['gas_price'] | ||||
|         tx_new['nonce'] -= delta | ||||
| 
 | ||||
|         logg.debug('tx_nex {}'.format(tx_new)) | ||||
|         logg.debug('tx_new {}'.format(tx_new)) | ||||
| 
 | ||||
|         del(tx_new['hash']) | ||||
|         del(tx_new['hash_unsigned']) | ||||
|         del(tx_new['hashUnsigned']) | ||||
| 
 | ||||
|         gas_oracle = OverrideGasOracle(limit=tx_new['gas'], price=tx_new['gas_price'] + 1) # TODO: it should be possible to merely set this price here and if missing in the existing struct then fill it in (chainlib.eth.tx) | ||||
|         c = TxFactory(chain_spec, signer=rpc_signer, gas_oracle=gas_oracle) | ||||
|         (tx_hash_hex, tx_signed_raw_hex) = c.build_raw(tx_new) | ||||
| @ -101,15 +107,15 @@ def shift_nonce(self, chain_str, tx_hash_orig_hex, delta=1): | ||||
|             tx_signed_raw_hex, | ||||
|             ) | ||||
|         session.add(otx) | ||||
|         session.commit() | ||||
| 
 | ||||
|         # TODO: cancel all first, then replace. Otherwise we risk two non-locked states for two different nonces. | ||||
|         set_cancel(chain_spec, tx_previous_hash_hex, manual=True, session=session) | ||||
|         set_cancel(chain_spec, strip_0x(tx_previous_hash_hex), manual=True, session=session) | ||||
| 
 | ||||
|         TxCache.clone(tx_previous_hash_hex, tx_hash_hex, session=session) | ||||
| 
 | ||||
|         tx_hashes.append(tx_hash_hex) | ||||
|         txs.append(tx_signed_raw_hex) | ||||
|         session.commit() | ||||
| 
 | ||||
|     session.close() | ||||
| 
 | ||||
|  | ||||
| @ -30,13 +30,13 @@ from chainqueue.db.enum import ( | ||||
|         status_str, | ||||
|     ) | ||||
| from chainqueue.error import TxStateChangeError | ||||
| from chainqueue.query import get_tx | ||||
| 
 | ||||
| # local imports | ||||
| from cic_eth.db.models.base import SessionBase | ||||
| from cic_eth.db.models.role import AccountRole | ||||
| from cic_eth.db.models.nonce import Nonce | ||||
| from cic_eth.error import InitializationError | ||||
| from cic_eth.queue.query import get_tx | ||||
| 
 | ||||
| app = celery.current_app | ||||
| 
 | ||||
| @ -264,7 +264,8 @@ class AdminApi: | ||||
|         } | ||||
| 
 | ||||
| 
 | ||||
|     def fix_nonce(self, address, nonce, chain_spec): | ||||
|     # TODO: is risky since it does not validate that there is actually a nonce problem? | ||||
|     def fix_nonce(self, chain_spec, address, nonce): | ||||
|         s = celery.signature( | ||||
|                 'cic_eth.queue.query.get_account_tx', | ||||
|                 [ | ||||
| @ -278,15 +279,17 @@ class AdminApi: | ||||
|         txs = s.apply_async().get() | ||||
| 
 | ||||
|         tx_hash_hex = None | ||||
|         session = SessionBase.create_session() | ||||
|         for k in txs.keys(): | ||||
|             tx_dict = get_tx(k) | ||||
|             tx_dict = get_tx(chain_spec, k, session=session) | ||||
|             if tx_dict['nonce'] == nonce: | ||||
|                 tx_hash_hex = k | ||||
|         session.close() | ||||
| 
 | ||||
|         s_nonce = celery.signature( | ||||
|                 'cic_eth.admin.nonce.shift_nonce', | ||||
|                 [ | ||||
|                     self.rpc.chain_spec.asdict(), | ||||
|                     chain_spec.asdict(), | ||||
|                     tx_hash_hex,  | ||||
|                 ], | ||||
|                 queue=self.queue | ||||
|  | ||||
| @ -17,7 +17,7 @@ eth-address-index~=0.1.1a11 | ||||
| chainlib~=0.0.3rc2 | ||||
| hexathon~=0.0.1a7 | ||||
| chainsyncer[sql]~=0.0.2a4 | ||||
| chainqueue~=0.0.2a2 | ||||
| chainqueue~=0.0.2b1 | ||||
| sarafu-faucet==0.0.3a3 | ||||
| erc20-faucet==0.2.1a4 | ||||
| coincurve==15.0.0 | ||||
|  | ||||
| @ -34,7 +34,10 @@ from chainqueue.state import ( | ||||
|         set_ready, | ||||
|         set_reserved, | ||||
|         ) | ||||
| from chainqueue.query import get_tx | ||||
| from chainqueue.query import ( | ||||
|         get_tx, | ||||
|         get_nonce_tx_cache, | ||||
|         ) | ||||
| 
 | ||||
| # local imports | ||||
| from cic_eth.api import AdminApi | ||||
| @ -133,7 +136,6 @@ def test_tx( | ||||
|     logg.warning('code missing to verify tx contents {}'.format(tx)) | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| def test_check_nonce_gap( | ||||
|         default_chain_spec, | ||||
|         init_database, | ||||
| @ -236,3 +238,64 @@ def test_check_nonce_localfail( | ||||
| 
 | ||||
|     assert r['nonce']['blocking'] == 4 | ||||
|     assert r['tx']['blocking'] == tx_hashes[4] | ||||
| 
 | ||||
| 
 | ||||
| def test_fix_nonce( | ||||
|         default_chain_spec, | ||||
|         init_database, | ||||
|         eth_rpc, | ||||
|         eth_signer, | ||||
|         agent_roles, | ||||
|         contract_roles, | ||||
|         celery_session_worker, | ||||
|         init_celery_tasks, | ||||
|         caplog, | ||||
|         ): | ||||
| 
 | ||||
|     nonce_oracle = OverrideNonceOracle(agent_roles['ALICE'], 0) | ||||
|     gas_oracle = OverrideGasOracle(limit=21000, conn=eth_rpc) | ||||
| 
 | ||||
|     tx_hashes = [] | ||||
|     txs = [] | ||||
| 
 | ||||
|     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) | ||||
| 
 | ||||
|     init_database.commit() | ||||
| 
 | ||||
|     api = AdminApi(eth_rpc, queue=None, call_address=contract_roles['DEFAULT']) | ||||
|     t = api.fix_nonce(default_chain_spec, agent_roles['ALICE'], 3) | ||||
|     r = t.get_leaf() | ||||
|     assert t.successful() | ||||
| 
 | ||||
|     init_database.commit() | ||||
|      | ||||
|     txs = get_nonce_tx_cache(default_chain_spec, 3, agent_roles['ALICE'], session=init_database) | ||||
|     ks = txs.keys() | ||||
|     assert len(ks) == 2 | ||||
|     for k in ks: | ||||
|         hsh = add_0x(k) | ||||
|         otx = Otx.load(hsh, session=init_database) | ||||
|         init_database.refresh(otx) | ||||
|         logg.debug('checking nonce {} tx {} status {}'.format(3, otx.tx_hash, otx.status)) | ||||
|         if add_0x(k) == tx_hashes[3]: | ||||
|             assert otx.status & StatusBits.OBSOLETE == StatusBits.OBSOLETE | ||||
|         else: | ||||
|             assert otx.status == 1 | ||||
|  | ||||
| @ -65,7 +65,7 @@ def test_shift_nonce( | ||||
|     s = celery.signature( | ||||
|             'cic_eth.admin.nonce.shift_nonce', | ||||
|             [ | ||||
|                 str(default_chain_spec), | ||||
|                 default_chain_spec.asdict(), | ||||
|                 tx_hashes[3], | ||||
|                 ], | ||||
|             queue=None | ||||
| @ -76,7 +76,7 @@ def test_shift_nonce( | ||||
|     init_database.commit() | ||||
| 
 | ||||
| 
 | ||||
|     for i in range(42+4, 42+10): | ||||
|     for i in range(42+3, 42+10): | ||||
|         txs = get_nonce_tx_cache(default_chain_spec, i, agent_roles['ALICE'], session=init_database) | ||||
|         for k in txs.keys(): | ||||
|             hsh = add_0x(k) | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user