From f4ed3868fbb7014f70550cf91e4d7053cf3675f2 Mon Sep 17 00:00:00 2001 From: Kent Bull Date: Thu, 5 Sep 2024 10:29:03 -0600 Subject: [PATCH] fix: update smids and rmids for group lead on new event The prior code would fix smids and rmids for all new rotation members on each rotation yet would not fix the smids and rmids for the group lead submitting the multisig event because of the early return when the serder arg is not present. This fixes that Signed-off-by: Kent Bull --- src/keri/app/habbing.py | 22 +++++---- tests/app/test_grouping.py | 94 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 107 insertions(+), 9 deletions(-) diff --git a/src/keri/app/habbing.py b/src/keri/app/habbing.py index d9431aa4..aad0992c 100644 --- a/src/keri/app/habbing.py +++ b/src/keri/app/habbing.py @@ -2745,13 +2745,21 @@ def make(self, *, code=coring.MtrDex.Blake3_256, transferable=True, isith=None, self.inited = True + def _update_smids_rmids(self, smids, rmids): + if (habord := self.db.habs.get(keys=(self.pre,))) is None: + raise kering.ValidationError(f"Missing HabitatRecord for pre={self.pre}") + self.smids = smids + self.rmids = rmids + habord.smids = smids + habord.rmids = rmids + self.db.habs.pin(keys=self.pre, val=habord) + def rotate(self, smids=None, rmids=None, serder=None, **kwargs): if serder is None: - return super(GroupHab, self).rotate(**kwargs) - - if (habord := self.db.habs.get(keys=(self.pre,))) is None: - raise kering.ValidationError(f"Missing HabitatRecord for pre={self.pre}") + msg = super(GroupHab, self).rotate(**kwargs) + self._update_smids_rmids(smids, rmids) + return msg # sign handles group hab with .mhab case sigers = self.sign(ser=serder.raw, verfers=serder.verfers, rotated=True) @@ -2767,11 +2775,7 @@ def rotate(self, smids=None, rmids=None, serder=None, **kwargs): raise kering.ValidationError("Improper Habitat rotation for " "pre={self.pre}.") from ex - self.smids = smids - self.rmids = rmids - habord.smids = smids - habord.rmids = rmids - self.db.habs.pin(keys=(self.pre,), val=habord) + self._update_smids_rmids(smids, rmids) return msg diff --git a/tests/app/test_grouping.py b/tests/app/test_grouping.py index c50d9402..e9d3e435 100644 --- a/tests/app/test_grouping.py +++ b/tests/app/test_grouping.py @@ -673,6 +673,100 @@ def test_multisig_rotate(mockHelpingNowUTC): assert data["gid"] == ghab1.pre assert "rot" in exn.ked["e"] +def test_multisig_rotate_new_group_member_updates_smids(mockHelpingNowUTC): + # Create a multisig with three members, test_1, test_2, and test_3 + with openMultiSig(prefix="smidstest") as ((hby1, ghab1), (hby2, ghab2), (hby3, ghab3)): + # Create a new member, test_4 + with habbing.openHab(name="smidstest_4", salt=b'0123456789abcdef', transferable=True, temp=True) as (hby4, hab4): + icp4 = hab4.makeOwnEvent(sn=0) # Get test_4's inception event to introduce to group members + + hab1 = hby1.habByName("smidstest_1") + hab2 = hby2.habByName("smidstest_2") + hab3 = hby3.habByName("smidstest_3") + # Create member Kevery instances to parse each other's events and update their keystate + kev1 = eventing.Kevery(db=hab1.db, lax=True, local=False) + kev2 = eventing.Kevery(db=hab2.db, lax=True, local=False) + kev3 = eventing.Kevery(db=hab3.db, lax=True, local=False) + kev4 = eventing.Kevery(db=hab4.db, lax=True, local=False) + + # Introduce test_4 member to group by parsing test_4's inception event (latest key state) + parsing.Parser().parse(ims=bytearray(icp4), kvy=kev1) + parsing.Parser().parse(ims=bytearray(icp4), kvy=kev2) + parsing.Parser().parse(ims=bytearray(icp4), kvy=kev3) + # introduce each member to 4 + parsing.Parser().parse(ims=bytearray(hab1.makeOwnEvent(sn=0)), kvy=kev4) + parsing.Parser().parse(ims=bytearray(hab2.makeOwnEvent(sn=0)), kvy=kev4) + parsing.Parser().parse(ims=bytearray(hab3.makeOwnEvent(sn=0)), kvy=kev4) + + # rotate each individual hab to satisfy the rotation threshold with new keys + hab1.rotate() + hab2.rotate() + hab3.rotate() + + # Update keystate in each hab for each other member + rot1 = hab1.makeOwnEvent(sn=1) # get latest event for hab1 and update keystate for other members + parsing.Parser().parse(ims=bytearray(rot1), kvy=kev2) + parsing.Parser().parse(ims=bytearray(rot1), kvy=kev3) + parsing.Parser().parse(ims=bytearray(rot1), kvy=kev4) + + rot2 = hab2.makeOwnEvent(sn=1) # get latest event for hab2 and update keystate for other members + parsing.Parser().parse(ims=bytearray(rot2), kvy=kev1) + parsing.Parser().parse(ims=bytearray(rot2), kvy=kev3) + parsing.Parser().parse(ims=bytearray(rot2), kvy=kev4) + + rot3 = hab3.makeOwnEvent(sn=1) # get latest event for hab3 and update keystate for other members + parsing.Parser().parse(ims=bytearray(rot3), kvy=kev1) + parsing.Parser().parse(ims=bytearray(rot3), kvy=kev2) + parsing.Parser().parse(ims=bytearray(rot3), kvy=kev4) + + # create signing and rotation member AID lists for upcoming rotation + smids = [hab1.pre, hab2.pre, hab3.pre, hab4.pre] + rmids = [hab1.pre, hab2.pre, hab3.pre, hab4.pre] + + # make group hab for test_4 + ghab4 = hby4.joinGroupHab(hab4.pre, group="smidstest_group4", mhab=hab4, smids=smids, rmids=rmids) + + isith = '["1/4", "1/4", "1/4", "1/4"]' + nsith = '["1/4", "1/4", "1/4", "1/4"]' + merfers = [hab1.kever.verfers[0], hab2.kever.verfers[0], hab3.kever.verfers[0], hab4.kever.verfers[0]] + migers = [hab1.kever.ndigers[0], hab2.kever.ndigers[0], hab3.kever.ndigers[0], hab4.kever.ndigers[0]] + rot = ghab1.rotate(smids=smids, rmids=rmids, isith=isith, nsith=nsith, toad=None, cuts=None, adds=None, data=None, + verfers=merfers, digers=migers) + rserder = serdering.SerderKERI(raw=rot) + + # start counselor for group hab 1 + prefixer = coring.Prefixer(qb64=ghab1.pre) + seqner = coring.Seqner(sn=ghab1.kever.sn + 1) + saider = coring.Saider(qb64=rserder.said) + counselor = grouping.Counselor(hby=hby1) + counselor.start(ghab=ghab1, prefixer=prefixer, seqner=seqner, saider=saider) + + # hab2 signs rotation event and parse into hab1 Kevery + sigers2 = hab2.mgr.sign(rserder.raw, verfers=hab2.kever.verfers, indexed=True, indices=[1]) + msg2 = eventing.messagize(serder=rserder, sigers=sigers2) + parsing.Parser().parse(ims=bytearray(msg2), kvy=kev1) + + # hab3 signs rotation event and parse into hab1 Kevery + sigers3 = hab3.mgr.sign(rserder.raw, verfers=hab3.kever.verfers, indexed=True, indices=[2]) + msg3 = eventing.messagize(serder=rserder, sigers=sigers3) + parsing.Parser().parse(ims=bytearray(msg3), kvy=kev1) + + # hab4 signs rotation event and parse into hab1 Kevery. This should commit the event + sigers4 = hab4.mgr.sign(rserder.raw, verfers=hab4.kever.verfers, indexed=True, indices=[3]) + msg4 = eventing.messagize(serder=rserder, sigers=sigers4) + parsing.Parser().parse(ims=bytearray(msg4), kvy=kev1) + + kev1.processEscrows() # Runs escrows for Kevery1 so he processes all sigs together + + counselor.processEscrows() # Get the rest of the way through counselor. + assert counselor.complete(prefixer=prefixer, seqner=seqner, saider=saider) + assert ghab4.smids == smids + assert ghab4.rmids == rmids + hby1.loadHabs() + ghab1 = hby1.habByName("smidstest_group1") # reload hab to get updated smids and rmids values + assert ghab1.smids == smids + assert ghab1.rmids == rmids + def test_multisig_interact(mockHelpingNowUTC): with openMultiSig(prefix="test") as ((hby1, ghab1), (_, _), (_, _)):