From 7a36cd1e417f4560f4fb861ffc26a09ac956409a Mon Sep 17 00:00:00 2001 From: William Luke Date: Mon, 7 Feb 2022 15:35:01 +0300 Subject: [PATCH] feat: add `get_latest_txs` query --- .gitignore | 1 + chainqueue/sql/query.py | 64 +++++++++++++++++++++++++++++++++++++++++ test_requirements.txt | 1 - tests/test_query.py | 59 +++++++++++++++++++++++++++++++++++++ 4 files changed, 124 insertions(+), 1 deletion(-) delete mode 100644 test_requirements.txt diff --git a/.gitignore b/.gitignore index 399d953..a2de8c4 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,4 @@ build/ dist/ *.html *.egg-info/ +.venv diff --git a/chainqueue/sql/query.py b/chainqueue/sql/query.py index 1454a85..1cc28d5 100644 --- a/chainqueue/sql/query.py +++ b/chainqueue/sql/query.py @@ -462,6 +462,70 @@ def get_account_tx(chain_spec, address, as_sender=True, as_recipient=True, count return txs +def get_latest_txs(chain_spec, count=10, since=None, until=None, status=None, not_status=None, status_target=None, session=None): + """Returns the lastest local queue transactions + + The since parameter effect depends on its type. Results are returned inclusive of the given parameter condition. + + :param chain_spec: Chain spec for transaction network + :type chain_spec: chainlib.chain.ChainSpec + :param status: Only include transactions where the given status bits are set + :type status: chainqueue.enum.StatusEnum + :param not_status: Only include transactions where the given status bits are not set + :type not_status: chainqueue.enum.StatusEnum + :param status_target: Only include transaction where the status argument is exact match + :type status_target: chainqueue.enum.StatusEnum + :param session: Backend state integrity session + :type session: varies + :raises ValueError: If address is set to be neither sender nor recipient + :returns: Transactions + :rtype: dict, with transaction hash as key, signed raw transaction as value + """ + txs = {} + + session = SessionBase.bind_session(session) + + try: + filter_offset = sql_range_filter(session, criteria=since) + filter_limit = sql_range_filter(session, criteria=until) + except NotLocalTxError as e: + logg.error('query build failed: {}'.format(e)) + return {} + + q = session.query(Otx) + q = q.join(TxCache) + + if filter_offset != None: + if filter_offset[0] == 'id': + q = q.filter(Otx.id>=filter_offset[1]) + elif filter_offset[0] == 'date': + q = q.filter(Otx.date_created>=filter_offset[1]) + + if filter_limit != None: + if filter_limit[0] == 'id': + q = q.filter(Otx.id<=filter_limit[1]) + elif filter_limit[0] == 'date': + q = q.filter(Otx.date_created<=filter_limit[1]) + + if status != None: + if status_target == None: + status_target = status + q = q.filter(Otx.status.op('&')(status)==status_target) + + if not_status != None: + q = q.filter(Otx.status.op('&')(not_status)==0) + + q = q.order_by(Otx.nonce.asc(), Otx.date_created.asc()).limit(count) + results = q.all() + for r in results: + if txs.get(r.tx_hash) != None: + logg.debug('tx {} already recorded'.format(r.tx_hash)) + continue + txs[r.tx_hash] = r.signed_tx + + SessionBase.release_session(session) + + return txs def count_tx(chain_spec, sender=None, status=None, status_target=None, session=None): """Count transaction records matching the given criteria. diff --git a/test_requirements.txt b/test_requirements.txt deleted file mode 100644 index 96d1a07..0000000 --- a/test_requirements.txt +++ /dev/null @@ -1 +0,0 @@ -chainlib==0.0.9a10 diff --git a/tests/test_query.py b/tests/test_query.py index 7849cc2..dd21578 100644 --- a/tests/test_query.py +++ b/tests/test_query.py @@ -345,6 +345,65 @@ class TestTxQuery(TestTxBase): txs = get_account_tx(self.chain_spec, self.alice, as_sender=True, as_recipient=False, not_status=StatusBits.QUEUED, status=StatusBits.IN_NETWORK, session=self.session) self.assertEqual(len(txs.keys()), 1) + def test_latest_txs(self): + + nonce_hashes = [self.tx_hash] + tx_hash = add_0x(os.urandom(32).hex()) + signed_tx = add_0x(os.urandom(128).hex()) + create( + self.chain_spec, + 42, + self.alice, + tx_hash, + signed_tx, + session=self.session, + ) + txc = TxCache( + tx_hash, + self.alice, + self.bob, + self.foo_token, + self.bar_token, + self.from_value, + self.to_value, + session=self.session, + ) + self.session.add(txc) + self.session.commit() + + nonce_hashes.append(tx_hash) + + time_between = datetime.datetime.utcnow() + + tx_hash = add_0x(os.urandom(32).hex()) + signed_tx = add_0x(os.urandom(128).hex()) + create( + self.chain_spec, + 41, + self.alice, + tx_hash, + signed_tx, + session=self.session, + ) + txc = TxCache( + tx_hash, + self.alice, + self.bob, + self.foo_token, + self.bar_token, + self.from_value, + self.to_value, + session=self.session, + ) + self.session.add(txc) + + nonce_hashes.append(tx_hash) + + txs = get_latest_txs(self.chain_spec, session=self.session) + self.assertEqual(len(txs.keys()), 3) + + txs = get_latest_txs(self.chain_spec, count=1, session=self.session) + self.assertEqual(len(txs.keys()), 1) if __name__ == '__main__': unittest.main()