From 70fa63b2bf81533e040d9b93ac7ad3f2940bb00a Mon Sep 17 00:00:00 2001 From: Kevin Griffin Date: Tue, 17 Sep 2024 14:53:50 -0400 Subject: [PATCH] adds escrow clearing, moves original escrow command to 'escrow list' Signed-off-by: Kevin Griffin --- src/keri/app/cli/commands/clean.py | 8 +- src/keri/app/cli/commands/escrow/__init__.py | 3 + src/keri/app/cli/commands/escrow/clear.py | 52 +++++++++ .../commands/{escrow.py => escrow/list.py} | 2 +- src/keri/app/cli/commands/migrate.py | 7 +- src/keri/db/basing.py | 23 ++++ tests/app/cli/test_kli_commands.py | 2 +- tests/db/test_basing.py | 109 +++++++++++++++--- 8 files changed, 181 insertions(+), 25 deletions(-) create mode 100644 src/keri/app/cli/commands/escrow/__init__.py create mode 100644 src/keri/app/cli/commands/escrow/clear.py rename src/keri/app/cli/commands/{escrow.py => escrow/list.py} (99%) diff --git a/src/keri/app/cli/commands/clean.py b/src/keri/app/cli/commands/clean.py index 63c3b4907..e3e365b30 100644 --- a/src/keri/app/cli/commands/clean.py +++ b/src/keri/app/cli/commands/clean.py @@ -47,9 +47,13 @@ def __init__(self, args): super(CleanDoer, self).__init__() def recur(self, tyme): - hby = existing.setupHby(name=self.args.name, base=self.args.base, bran=self.args.bran, temp=self.args.temp) + + print("Clearing escrows...") + hby.db.clearEscrows() + print("Finished") + print("Migrating...") hby.db.migrate() print("Finished") @@ -59,6 +63,6 @@ def recur(self, tyme): print("Database open, performing clean...") hby.db.clean() - print("Finished.") + print("Finished") return True diff --git a/src/keri/app/cli/commands/escrow/__init__.py b/src/keri/app/cli/commands/escrow/__init__.py new file mode 100644 index 000000000..defc725e9 --- /dev/null +++ b/src/keri/app/cli/commands/escrow/__init__.py @@ -0,0 +1,3 @@ +import argparse + +parser = argparse.ArgumentParser(description="A collection of escrow operations") \ No newline at end of file diff --git a/src/keri/app/cli/commands/escrow/clear.py b/src/keri/app/cli/commands/escrow/clear.py new file mode 100644 index 000000000..ae5e03d73 --- /dev/null +++ b/src/keri/app/cli/commands/escrow/clear.py @@ -0,0 +1,52 @@ +# -*- encoding: utf-8 -*- +""" +KERI +keri.kli.commands.escrow module + +""" +import argparse + +from hio import help +from hio.base import doing +from keri.app.cli.common import existing + +logger = help.ogler.getLogger() + +parser = argparse.ArgumentParser(description='Clear escrows') +parser.set_defaults(handler=lambda args: handler(args), + transferable=True) +parser.add_argument('--name', '-n', help='keystore name and file location of KERI keystore', required=True) +parser.add_argument('--base', '-b', help='additional optional prefix to file location of KERI keystore', + required=False, default="") +parser.add_argument('--passcode', '-p', help='21 character encryption passcode for keystore (is not saved)', + dest="bran", default=None) # passcode => bran +parser.add_argument('--force', action="store_true", required=False, + help='True means perform clear without prompting the user') + + +def handler(args): + if not args.force: + print() + print("This command will clear all escrows and is not reversible.") + print() + yn = input("Are you sure you want to continue? [y|N]: ") + + if yn not in ("y", "Y"): + print("...exiting") + return [] + + kwa = dict(args=args) + return [doing.doify(clear, **kwa)] + + +def clear(tymth, tock=0.0, **opts): + """ Command line clear handler + """ + _ = (yield tock) + args = opts["args"] + name = args.name + base = args.base + bran = args.bran + + with existing.existingHby(name=name, base=base, bran=bran) as hby: + hby.db.clearEscrows() diff --git a/src/keri/app/cli/commands/escrow.py b/src/keri/app/cli/commands/escrow/list.py similarity index 99% rename from src/keri/app/cli/commands/escrow.py rename to src/keri/app/cli/commands/escrow/list.py index 277ad4b7b..e1aae8ab2 100644 --- a/src/keri/app/cli/commands/escrow.py +++ b/src/keri/app/cli/commands/escrow/list.py @@ -1,7 +1,7 @@ # -*- encoding: utf-8 -*- """ KERI -keri.kli.commands module +keri.kli.commands.escrow module """ import argparse diff --git a/src/keri/app/cli/commands/migrate.py b/src/keri/app/cli/commands/migrate.py index 878587790..553f278b1 100644 --- a/src/keri/app/cli/commands/migrate.py +++ b/src/keri/app/cli/commands/migrate.py @@ -127,12 +127,7 @@ def migrate(tymth, tock=0.0, **opts): # clear escrows print("clearing escrows") - hby.db.gpwe.trim() - hby.db.gdee.trim() - hby.db.dpwe.trim() - hby.db.gpse.trim() - hby.db.epse.trim() - hby.db.dune.trim() + hby.db.clearEscrows() except ConfigurationError: print(f"identifier prefix for {name} does not exist, incept must be run first", ) diff --git a/src/keri/db/basing.py b/src/keri/db/basing.py index 14e9bfb53..ea799838a 100644 --- a/src/keri/db/basing.py +++ b/src/keri/db/basing.py @@ -1367,6 +1367,29 @@ def migrate(self): self.version = keri.__version__ + def clearEscrows(self): + """ + Clear all escrows + """ + for (k, _) in self.getUreItemIter(): + self.delUres(key=k) + for (k, _) in self.getVreItemIter(): + self.delVres(key=k) + for (k, _) in self.getPseItemIter(): + self.delPses(key=k) + for (k, _) in self.getPweItemIter(): + self.delPwes(key=k) + for (k, _) in self.getUweItemIter(): + self.delUwes(key=k) + for (k, _) in self.getOoeItemIter(): + self.delOoes(key=k) + for (k, _) in self.getLdeItemIter(): + self.delLdes(key=k) + + for escrow in [self.misfits, self.delegables, self.pdes, self.udes, self.rpes, self.epsd, self.eoobi, + self.dpub, self.gpwe, self.gdee, self.dpwe, self.gpse, self.epse, self.dune]: + escrow.trim() + @property def current(self): """ Current property determines if we are at the current database migration state. diff --git a/tests/app/cli/test_kli_commands.py b/tests/app/cli/test_kli_commands.py index 94d960424..ec30511df 100644 --- a/tests/app/cli/test_kli_commands.py +++ b/tests/app/cli/test_kli_commands.py @@ -239,7 +239,7 @@ def test_standalone_kli_commands(helpers, capsys): '\t3. DEMwUl3u8mJ-cWxSnReA0rQesIgZ8SFoHp0U2WyiZjRt\n' '\n') - args = parser.parse_args(["escrow", "--name", "test"]) + args = parser.parse_args(["escrow", "list", "--name", "test"]) assert args.handler is not None doers = args.handler(args) directing.runController(doers=doers) diff --git a/tests/db/test_basing.py b/tests/db/test_basing.py index 659403c21..7ab9a541f 100644 --- a/tests/db/test_basing.py +++ b/tests/db/test_basing.py @@ -7,28 +7,23 @@ import os from dataclasses import dataclass, asdict -import lmdb import pytest -from hio.base import doing - -from keri.help.helping import datify, dictify +import lmdb +from hio.base import doing from keri import core +from keri.app import habbing from keri.core import coring, eventing, serdering - -from keri.core.coring import Kinds, versify - +from keri.core.coring import Kinds, versify, Seqner from keri.core.eventing import incept, rotate, interact, Kever - -from keri.app import habbing - +from keri.core.serdering import Serder from keri.db import basing from keri.db import dbing from keri.db import subing -from keri.db.basing import openDB, Baser, KeyStateRecord +from keri.db.basing import openDB, Baser, KeyStateRecord, OobiRecord from keri.db.dbing import (dgKey, onKey, snKey) from keri.db.dbing import openLMDB - +from keri.help.helping import datify, dictify # this breaks when running as __main__ better to do a custom import call to # walk the directory tree and import explicity rather than depend on it # being a known package. Works with pytest because pytest contructs a path @@ -185,9 +180,6 @@ def test_baser(): assert actual.local == record.local assert db.esrs.get(key) == record - - - # test first seen event log .fels sub db preA = b'BAKY1sKmgyjAiUDdUBPNPyrSz_ad_Qf9yzhDNZlEKiMc' preB = b'EH7Oq9oxCgYa-nnNLvwhp9sFZpALILlRYyB-6n4WDi7w' @@ -1824,6 +1816,93 @@ def test_KERI_BASER_MAP_SIZE_handles_bad_values(caplog): os.environ.pop("KERI_BASER_MAP_SIZE") +def test_clear_escrows(): + with openDB() as db: + key = b'A' + vals = [b"z", b"m", b"x", b"a"] + + db.putUres(key, vals) + db.putVres(key, vals) + db.putPses(key, vals) + db.putPwes(key, vals) + db.putUwes(key, vals) + db.putOoes(key, vals) + db.putLdes(key, vals) + + pre = b'k' + snh = b'snh' + saidb = b'saidb' + db.misfits.add(keys=(pre, snh), val=saidb) + assert db.misfits.cnt(keys=(pre, snh)) == 1 + + db.delegables.add(snKey(pre, 0), saidb) + assert db.delegables.cnt(keys=snKey(pre, 0)) == 1 + + db.pdes.addOn(keys=pre, on=0, val=saidb) + assert db.pdes.cnt(keys=snKey(pre, 0)) == 1 + + udesKey = dgKey('DAzwEHHzq7K0gzQPYGGwTmuupUhPx5_yZ-Wk1x4ejhcc'.encode("utf-8"), + 'EGAPkzNZMtX-QiVgbRbyAIZGoXvbGv9IPb0foWTZvI_4'.encode("utf-8")) + db.udes.put(keys=udesKey, val=(coring.Seqner(qb64b=b'0AAAAAAAAAAAAAAAAAAAAAAB'), + coring.Saider(qb64b=b'EALkveIFUPvt38xhtgYYJRCCpAGO7WjjHVR37Pawv67E'))) + assert db.udes.get(keys=udesKey) is not None + + saider = coring.Saider(qb64b='EGAPkzNZMtX-QiVgbRbyAIZGoXvbGv9IPb0foWTZvI_4') + db.rpes.put(keys=('route',), vals=[saider]) + assert db.rpes.cnt(keys=('route',)) == 1 + + db.epsd.put(keys=('DAzwEHHzq7K0gzQPYGGwTmuupUhPx5_yZ-Wk1x4ejhcc',), val=coring.Dater()) + assert db.epsd.get(keys=('DAzwEHHzq7K0gzQPYGGwTmuupUhPx5_yZ-Wk1x4ejhcc',)) is not None + + db.eoobi.pin(keys=('url',), val=OobiRecord()) + assert db.eoobi.cntAll() == 1 + + serder = Serder(raw=b'{"v":"KERI10JSON0000cb_","t":"ixn","d":"EG8WAmM29ZBdoXbnb87yiPxQw4Y7gcQjqZS74vBAKsRm","i":"DApYGFaqnrALTyejaJaGAVhNpSCtqyerPqWVK9ZBNZk0","s":"4","p":"EAskHI462CuIMS_gNkcl_QewzrRSKH2p9zHQIO132Z30","a":[]}') + db.dpub.put(keys=(pre, 'said'), val=serder) + assert db.dpub.get(keys=(pre, 'said')) is not None + + db.gpwe.add(keys=(pre,), val=(coring.Seqner(qb64b=b'0AAAAAAAAAAAAAAAAAAAAAAB'), saider)) + assert db.gpwe.cnt(keys=(pre,)) == 1 + + db.gdee.add(keys=(pre,), val=(coring.Seqner(qb64b=b'0AAAAAAAAAAAAAAAAAAAAAAB'), saider)) + assert db.gdee.cnt(keys=(pre,)) == 1 + + db.dpwe.pin(keys=(pre, 'said'), val=serder) + assert db.dpwe.get(keys=(pre, 'said')) is not None + + db.gpse.add(keys=('qb64',), val=(coring.Seqner(qb64b=b'0AAAAAAAAAAAAAAAAAAAAAAB'), saider)) + assert db.gpse.cnt(keys=('qb64',)) == 1 + + db.epse.put(keys=('dig',), val=serder) + assert db.epse.get(keys=('dig',)) is not None + + db.dune.pin(keys=(pre, 'said'), val=serder) + assert db.dune.get(keys=(pre, 'said')) is not None + + db.clearEscrows() + + assert db.getUres(key) == [] + assert db.getVres(key) == [] + assert db.getPses(key) == [] + assert db.getPwes(key) == [] + assert db.getUwes(key) == [] + assert db.getOoes(key) == [] + assert db.getLdes(key) == [] + assert db.misfits.cnt(keys=(pre, snh)) == 0 + assert db.delegables.cnt(keys=snKey(pre, 0)) == 0 + assert db.pdes.cnt(keys=snKey(pre, 0)) == 0 + assert db.udes.get(keys=udesKey) is None + assert db.rpes.cnt(keys=('route',)) == 0 + assert db.epsd.get(keys=('DAzwEHHzq7K0gzQPYGGwTmuupUhPx5_yZ-Wk1x4ejhcc',)) is None + assert db.eoobi.cntAll() == 0 + assert db.dpub.get(keys=(pre, 'said')) is None + assert db.gpwe.cnt(keys=(pre,)) == 0 + assert db.gdee.cnt(keys=(pre,)) == 0 + assert db.dpwe.get(keys=(pre, 'said')) is None + assert db.gpse.cnt(keys=('qb64',)) == 0 + assert db.epse.get(keys=('dig',)) is None + assert db.dune.get(keys=(pre, 'said')) is None + if __name__ == "__main__": test_baser() test_clean_baser()