Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 2 additions & 4 deletions src/keri/app/cli/common/displaying.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,7 @@ def printIdentifier(hby, pre, label="Identifier"):
ser = kever.serder
dgkey = dbing.dgKey(ser.preb, ser.saidb)
wigs = hab.db.getWigs(dgkey)
dgkey = dbing.dgKey(ser.preb, kever.lastEst.d)
seal = hab.db.getAes(dgkey)
seal = hab.db.aess.get(keys=dbing.dgKey(ser.preb, kever.lastEst.d))

print(f"Alias: \t{hab.name}")
print("{}: {}".format(label, pre))
Expand Down Expand Up @@ -86,8 +85,7 @@ def printExternal(hby, pre, label="Identifier"):
ser = kever.serder
dgkey = dbing.dgKey(ser.preb, ser.saidb)
wigs = hby.db.getWigs(dgkey)
dgkey = dbing.dgKey(ser.preb, kever.lastEst.d)
anchor = hby.db.getAes(dgkey)
anchor = hby.db.aess.get(keys=dbing.dgKey(ser.preb, kever.lastEst.d))

print("{}: {}".format(label, pre))
print("Seq No:\t{}".format(kever.sner.num))
Expand Down
8 changes: 4 additions & 4 deletions src/keri/app/delegating.py
Original file line number Diff line number Diff line change
Expand Up @@ -144,10 +144,10 @@ def processUnanchoredEscrow(self):

seal = dict(i=serder.pre, s=serder.snh, d=serder.said)
if dserder := self.hby.db.fetchLastSealingEventByEventSeal(dkever.prefixer.qb64, seal=seal):
seqner = coring.Seqner(sn=dserder.sn)
couple = seqner.qb64b + dserder.saidb
dgkey = dbing.dgKey(kever.prefixer.qb64b, kever.serder.saidb)
self.hby.db.setAes(dgkey, couple) # authorizer event seal (delegator/issuer)
sner = coring.Number(num=dserder.sn, code=coring.NumDex.Huge)
saider = coring.Saider(qb64b=dserder.saidb)
self.hby.db.aess.pin(keys=dbing.dgKey(kever.prefixer.qb64b, kever.serder.saidb),
val=(sner, saider)) # authorizer event seal (delegator/issuer)

# Move to escrow waiting for witness receipts
logger.info(f"Delegation approval received, {serder.pre} confirmed, publishing to my witnesses")
Expand Down
15 changes: 8 additions & 7 deletions src/keri/app/grouping.py
Original file line number Diff line number Diff line change
Expand Up @@ -197,10 +197,10 @@ def processDelegateEscrow(self):
else: # Not witnesser, we need to look for the anchor and then wait for receipts
if serder := self.hby.db.fetchLastSealingEventByEventSeal(kever.delpre,
seal=anchor):
aseq = coring.Seqner(sn=serder.sn)
couple = aseq.qb64b + serder.saidb
dgkey = dbing.dgKey(pre, saider.qb64b)
self.hby.db.setAes(dgkey, couple) # authorizer event seal (delegator/issuer)
sner = coring.Number(num=serder.sn, code=coring.NumDex.Huge)
asaider = coring.Saider(qb64b=serder.saidb)
self.hby.db.aess.pin(keys=dbing.dgKey(pre, saider.qb64b),
val=(sner, asaider)) # authorizer event seal (delegator/issuer)
self.hby.db.gdee.rem(keys=(pre,))
logger.info("AID %s...%s: Delegation approval for %s received.", pre[:4], pre[-4:], pre)

Expand Down Expand Up @@ -541,7 +541,7 @@ def getEscrowedEvent(db, pre, sn):
for sig in db.getSigsIter(key):
sigs.append(indexing.Siger(qb64b=bytes(sig)))

couple = db.getAes(key)
duple = db.aess.get(keys=key)

msg = bytearray()
msg.extend(serder.raw)
Expand All @@ -550,10 +550,11 @@ def getEscrowedEvent(db, pre, sn):
for sig in sigs:
msg.extend(sig.qb64b) # attach sig

if couple is not None:
if duple is not None:
seqner, saider = duple
msg.extend(core.Counter(core.Codens.SealSourceCouples,
count=1, version=kering.Vrsn_1_0).qb64b)
msg.extend(couple)
msg.extend(seqner.qb64b + saider.qb64b)

return msg

Expand Down
11 changes: 6 additions & 5 deletions src/keri/app/habbing.py
Original file line number Diff line number Diff line change
Expand Up @@ -2041,9 +2041,9 @@ def getOwnEvent(self, sn, allowPartiallySigned=False):
for sig in self.db.getSigsIter(key):
sigs.append(indexing.Siger(qb64b=bytes(sig)))

couple = self.db.getAes(key)
duple = self.db.aess.get(keys=key)

return serder, sigs, couple
return serder, sigs, duple


def makeOwnEvent(self, sn, allowPartiallySigned=False):
Expand All @@ -2059,18 +2059,19 @@ def makeOwnEvent(self, sn, allowPartiallySigned=False):
allowPartiallySigned(bool): True means attempt to load from partial signed escrow
"""
msg = bytearray()
serder, sigs, couple = self.getOwnEvent(sn=sn,
serder, sigs, duple = self.getOwnEvent(sn=sn,
allowPartiallySigned=allowPartiallySigned)
msg.extend(serder.raw)
msg.extend(Counter(Codens.ControllerIdxSigs, count=len(sigs),
version=kering.Vrsn_1_0).qb64b) # attach cnt
for sig in sigs:
msg.extend(sig.qb64b) # attach sig

if couple is not None:
if duple is not None:
seqner, saider = duple
msg.extend(Counter(Codens.SealSourceCouples, count=1,
version=kering.Vrsn_1_0).qb64b)
msg.extend(couple)
msg.extend(seqner.qb64b + saider.qb64b)

return msg

Expand Down
30 changes: 12 additions & 18 deletions src/keri/core/eventing.py
Original file line number Diff line number Diff line change
Expand Up @@ -3280,16 +3280,16 @@ def fetchDelegatingEvent(self, delpre, serder, *, original=True, eager=False):
"""
dgkey = dgKey(pre=serder.preb, dig=serder.saidb) # database key of delegate

if (couple := self.db.getAes(dgkey)): # delegation source couple at delegate
seqner, saider = deSourceCouple(couple)
if (duple := self.db.aess.get(keys=dgkey)): # delegation source couple at delegate
seqner, saider = duple
deldig = saider.qb64 # dig of delegating event
# extra careful double check that .aes is valid by getting
# fner = first seen Number instance index
if not self.db.fons.get(keys=(delpre, deldig)): # Not first seen yet?
if original: # should not happen aes database broken
# repair by deleting aes and returning None so it escrows
# and then next time around find below with repair it
self.db.delAes(dgkey) # delete aes so next time repairs it
self.db.aess.rem(keys=dgkey) # delete aes so next time repairs it
# superseding may not have happened yet so let it escrow
return None
ddgkey = dgKey(pre=delpre, dig=deldig) # database key of delegation
Expand Down Expand Up @@ -3330,8 +3330,9 @@ def fetchDelegatingEvent(self, delpre, serder, *, original=True, eager=False):
# Repair .aess of delegated event by writing found source
# seal couple of delegation. This is safe becaause we confirmed
# delegation event was accepted in delegator's kel.
couple = dserder.sner.huge.encode() + dserder.saidb
self.db.setAes(dgkey, couple) # authorizer (delegator/issuer) event seal
sner = coring.Number(num=dserder.sn, code=coring.NumDex.Huge)
saider = coring.Saider(qb64b=dserder.saidb)
self.db.aess.pin(keys=dgkey, val=(sner, saider)) # authorizer (delegator/issuer) event seal

return dserder

Expand Down Expand Up @@ -3395,8 +3396,7 @@ def logEvent(self, serder, sigers=None, wigers=None, wits=None, first=False,
# MUST NOT setAes if not delegated or locallyOwned or locallyWitnessed
if (self.delpre and not serder.ilk == Ilks.ixn and not self.locallyOwned()
and not self.locallyWitnessed(wits=wits) and seqner and saider):
couple = seqner.qb64b + saider.qb64b
self.db.setAes(dgkey, couple) # authorizer (delegator/issuer) event seal
self.db.aess.pin(keys=dgkey, val=(coring.Number(num=seqner.sn, code=coring.NumDex.Huge), saider)) # authorizer (delegator/issuer) event seal

#if seqner and saider:
#couple = seqner.qb64b + saider.qb64b
Expand Down Expand Up @@ -6549,12 +6549,9 @@ def processEscrowDelegables(self):
wigs = self.db.getWigs(dgKey(pre, bytes(edig))) # list of wigs
wigers = [Siger(qb64b=bytes(wig)) for wig in wigs]

# get delgate seal
couple = self.db.getAes(dgkey)
if couple is not None: # Only try to parse the event if we have the del seal
raw = bytearray(couple)
seqner = coring.Seqner(qb64b=raw, strip=True)
saider = coring.Saider(qb64b=raw)
# parse the event if we have a delegate seal
if (duple := self.db.aess.get(keys=dgKey(pre.encode("utf-8"), edig))) is not None:
seqner, saider = duple

# process event
self.processEvent(serder=eserder, sigers=sigers, wigers=wigers, delseqner=seqner,
Expand Down Expand Up @@ -7154,11 +7151,8 @@ def loadEvent(db, preb, dig):
event["witness_signatures"] = dwigs

# add authorizer (delegator/issuer) source seal event couple to attachments
couple = db.getAes(dgkey)
if couple is not None:
raw = bytearray(couple)
seqner = coring.Seqner(qb64b=raw, strip=True)
saider = coring.Saider(qb64b=raw)
if (duple := db.aess.get(keys=dgkey)) is not None:
seqner, saider = duple
event["source_seal"] = dict(sequence=seqner.sn, said=saider.qb64)

receipts = dict()
Expand Down
60 changes: 13 additions & 47 deletions src/keri/db/basing.py
Original file line number Diff line number Diff line change
Expand Up @@ -695,16 +695,16 @@ class Baser(dbing.LMDBer):
DB is keyed by identifier prefix plus digest of serialized event
Value is ISO 8601 datetime stamp bytes

.aess is named sub DB of authorizing event source seal couples
that map digest to seal source couple of authorizer's
(delegator or issuer) event. Each couple is a concatenation of full
qualified items, snu+dig of the authorizing (delegating or issuing)
source event.
.aess is named sub DB instance of CatCesrSuber for authorizing event
source seal couples that map digest of key event to seal source
couple of authorizer's (delegator or issuer) event.
subkey "aess."
dgKey
Values are couples used to lookup authorizer's source event in
.kels sub DB
DB is keyed by identifier prefix plus digest of key event
Only one value per DB key is allowed
Value is (Number, Saider) tuple; first component serialized as
Huge (fixed 24-char), used to lookup authorizer's source event
in .kels sub DB.
Only one value per DB key is allowed.

.sigs is named sub DB of fully qualified indexed event signatures
dgKey
Expand Down Expand Up @@ -1010,7 +1010,8 @@ def reopen(self, **kwa):
self.fels = self.env.open_db(key=b'fels.')
self.kels = self.env.open_db(key=b'kels.', dupsort=True)
self.dtss = self.env.open_db(key=b'dtss.')
self.aess = self.env.open_db(key=b'aess.')
self.aess = subing.CatCesrSuber(db=self, subkey='aess.',
klas=(coring.Number, coring.Saider))
self.sigs = self.env.open_db(key=b'sigs.', dupsort=True)
self.wigs = self.env.open_db(key=b'wigs.', dupsort=True)
self.rcts = self.env.open_db(key=b'rcts.', dupsort=True)
Expand Down Expand Up @@ -1683,11 +1684,11 @@ def cloneEvtMsg(self, pre, fn, dig):
atc.extend(wig)

# add authorizer (delegator/issuer) source seal event couple to attachments
couple = self.getAes(dgkey)
if couple is not None:
if (duple := self.aess.get(keys=dgkey)) is not None:
seqner, saider = duple
atc.extend(core.Counter(code=core.Codens.SealSourceCouples,
count=1, version=kering.Vrsn_1_0).qb64b)
atc.extend(couple)
atc.extend(seqner.qb64b + saider.qb64b)

# add trans endorsement quadruples to attachments not controller
# may have been originally key event attachments or receipted endorsements
Expand Down Expand Up @@ -2145,41 +2146,6 @@ def delDts(self, key):
"""
return self.delVal(self.dtss, key)

def putAes(self, key, val):
"""
Use dgKey()
Write serialized source seal event couple val to key
Does not overwrite existing val if any
Returns True If val successfully written Else False
Returns False if key already exists
"""
return self.putVal(self.aess, key, val)

def setAes(self, key, val):
"""
Use dgKey()
Write serialized source seal event couple val to key
Overwrites existing val if any
Returns True If val successfully written Else False
"""
return self.setVal(self.aess, key, val)

def getAes(self, key):
"""
Use dgKey()
Return source seal event couple at key
Returns None if no entry at key
"""
return self.getVal(self.aess, key)

def delAes(self, key):
"""
Use dgKey()
Deletes value at key.
Returns True If key exists in database Else False
"""
return self.delVal(self.aess, key)

def getSigs(self, key):
"""
Use dgKey()
Expand Down
19 changes: 16 additions & 3 deletions tests/app/test_delegating.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,13 @@ def test_anchorer(seeder):
# Get the key of the seal we will create when delegation is anchored
dgkey = dbing.dgKey(delHab.kever.prefixer.qb64b, delHab.kever.serder.saidb)
# Get the value of the seal created when delegation is anchored
couple = coring.Seqner(sn=palHab.kever.sn).qb64b + palHab.kever.serder.saidb
assert bytes(delHby.db.getAes(dgkey)) == couple
seqner = coring.Seqner(sn=palHab.kever.sn)
saider = coring.Saider(qb64b=palHab.kever.serder.saidb)
couple = seqner.qb64b + saider.qb64b
result = delHby.db.aess.get(keys=dgkey)
assert result is not None
rseqner, rsaider = result
assert rseqner.qb64b + rsaider.qb64b == couple


def anchorer_test_do(tymth=None, tock=0.0, **opts):
Expand Down Expand Up @@ -115,7 +120,15 @@ def anchorer_test_do(tymth=None, tock=0.0, **opts):
parsing.Parser(version=Vrsn_1_0).parseOne(ims=bytearray(msg), kvy=kvy, local=True)

# Wait for the anchor. If we timeout before that happens, assertion in test will fail
while delHby.db.getAes(dgkey) != couple:
dgkey = dbing.dgKey(delHab.kever.prefixer.qb64b, delHab.kever.serder.saidb)
seqner = coring.Seqner(sn=palHab.kever.sn)
saider = coring.Saider(qb64b=palHab.kever.serder.saidb)
couple = seqner.qb64b + saider.qb64b

while result := delHby.db.aess.get(keys=dgkey):
rseqner, rsaider = result
if rseqner.qb64b + rsaider.qb64b == couple:
break
yield tock


Expand Down
77 changes: 75 additions & 2 deletions tests/app/test_habbing.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@
from keri.help import helping

from keri import core
from keri.core import coring, eventing, parsing
from keri.core import coring, eventing, parsing, serdering

from keri.app import habbing, keeping, configing
from keri.db import basing
from keri.db import basing, dbing



Expand Down Expand Up @@ -850,6 +850,79 @@ def test_make_other_event():
b'p8Sc4CcESKA-q5O0O5CmpCbSrA29UpqZnfvUagrwm8w3M1a1WJKy64OQYXIG')


def test_get_own_event():
"""Test Hab.getOwnEvent: happy path sn=0 and sn=1, delegated duple, error path missing event."""
with habbing.openHby(salt=core.Salter(raw=b'0123456789abcdef').qb64) as hby:
hab = hby.makeHab(name="test")
assert hab.pre == "EIaGMMWJFPmtXznY1IIiKDIrg-vIyge6mBl2QV8dDjI3"

# Happy path: inception at sn=0
serder, sigs, duple = hab.getOwnEvent(sn=0)
assert serder.sad["t"] == "icp"
assert serder.sad["s"] == "0"
assert serder.sad["i"] == hab.pre
assert len(sigs) >= 1
assert duple is None

# Happy path: rotation at sn=1
hab.rotate()
serder, sigs, duple = hab.getOwnEvent(sn=1)
assert serder.sad["t"] == "rot"
assert serder.sad["s"] == "1"
assert serder.sad["i"] == hab.pre
assert len(sigs) >= 1
assert duple is None # rotation has no authorizer seal

# Happy path: delegated hab with authorizer seal (duple is not None)
with habbing.openHby(salt=core.Salter(raw=b'0123456789abcdef').qb64) as hby:
delHab = hby.makeHab(name="delegator")
delHab.interact(data=[]) # anchoring event at sn=1
anchorSner = coring.Number(num=delHab.kever.sn, code=coring.NumDex.Huge)
anchorSaider = coring.Saider(qb64b=delHab.kever.serder.saidb)

subHab = hby.makeHab(name="delegate", delpre=delHab.pre)
dgkey = dbing.dgKey(subHab.pre, subHab.kever.serder.saidb)
hby.db.aess.pin(keys=dgkey, val=(anchorSner, anchorSaider))

serder, sigs, duple = subHab.getOwnEvent(sn=0)
assert serder.sad["t"] == "dip"
assert serder.sad["i"] == subHab.pre
assert duple is not None
sner, saider = duple
assert sner.sn == delHab.kever.sn
assert saider.qb64 == delHab.kever.serder.said

# Error path: missing event at sn (no event at sn=1 for inception-only hab)
with habbing.openHby(salt=core.Salter(raw=b'0123456789abcdef').qb64) as hby:
hab = hby.makeHab(name="other")
with pytest.raises(kering.MissingEntryError) as exc_info:
hab.getOwnEvent(sn=1)
assert hab.pre in str(exc_info.value)
assert "1" in str(exc_info.value)


def test_make_own_event():
"""Test Hab.makeOwnEvent: sn=0 vs makeOwnInception, sn=1 after rotate."""
with habbing.openHby(salt=core.Salter(raw=b'0123456789abcdef').qb64) as hby:
hab = hby.makeHab(name="test")
assert hab.pre == "EIaGMMWJFPmtXznY1IIiKDIrg-vIyge6mBl2QV8dDjI3"

# makeOwnEvent(sn=0) equals makeOwnInception()
msg0 = hab.makeOwnEvent(sn=0)
msg_icp = hab.makeOwnInception()
assert msg0 == msg_icp
assert len(msg0) > 0
assert msg0.startswith(b'{"v":"KERI10JSON')

# makeOwnEvent(sn=1) after rotate
hab.rotate()
msg1 = hab.makeOwnEvent(sn=1)
assert len(msg1) > 0
serder = serdering.SerderKERI(raw=bytes(msg1))
assert serder.sad["t"] == "rot"
assert serder.sad["s"] == "1"


def test_hab_by_pre():
with habbing.openHby() as hby:
# Create two habs in the default namespace
Expand Down
Loading
Loading