def test_witness(): """ Test event validation logic with witnesses cam is controller van is validator wes is a witness wok is a witness wam is a witness """ salt = coring.Salter(raw=b'abcdef0123456789').qb64 with dbing.openDB(name="cam") as camDB, keeping.openKS(name="cam") as camKS, \ dbing.openDB(name="van") as vanDB, keeping.openKS(name="van") as vanKS, \ dbing.openDB(name="wes") as wesDB, keeping.openKS(name="wes") as wesKS, \ dbing.openDB(name="wok") as wokDB, keeping.openKS(name="wok") as wokKS, \ dbing.openDB(name="wam") as wamDB, keeping.openKS(name="wam") as wamKS, \ dbing.openDB(name="wil") as wilDB, keeping.openKS(name="wil") as wilKS: # witnesses first so can setup inception event for cam wsith = 1 # setup Wes's habitat nontrans # Wes's receipts will be rcts with a receipt couple attached wesHab = directing.Habitat(name='wes', ks=wesKS, db=wesDB, isith=wsith, icount=1, salt=salt, transferable=False, temp=True) # stem is .name assert wesHab.ks == wesKS assert wesHab.db == wesDB assert not wesHab.kever.prefixer.transferable # create non-local kevery for Wes to process nonlocal msgs wesKvy = eventing.Kevery(kevers=wesHab.kevers, db=wesHab.db, framed=True, opre=wesHab.pre, local=False) # setup Wok's habitat nontrans # Wok's receipts will be rcts with a receipt couple attached wokHab = directing.Habitat(name='wok', ks=wokKS, db=wokDB, isith=wsith, icount=1, salt=salt, transferable=False, temp=True) # stem is .name assert wokHab.ks == wokKS assert wokHab.db == wokDB assert not wokHab.kever.prefixer.transferable # create non-local kevery for Wok to process nonlocal msgs wokKvy = eventing.Kevery(kevers=wokHab.kevers, db=wokHab.db, framed=True, opre=wokHab.pre, local=False) # setup Wam's habitat nontrans # Wams's receipts will be rcts with a receipt couple attached wamHab = directing.Habitat(name='wam', ks=wamKS, db=wamDB, isith=wsith, icount=1, salt=salt, transferable=False, temp=True) # stem is .name assert wamHab.ks == wamKS assert wamHab.db == wamDB assert not wamHab.kever.prefixer.transferable # create non-local kevery for Wam to process nonlocal msgs wamKvy = eventing.Kevery(kevers=wamHab.kevers, db=wamHab.db, framed=True, opre=wamHab.pre, local=False) # setup Wil's habitat nontrans # Wil's receipts will be rcts with a receipt couple attached wilHab = directing.Habitat(name='wil', ks=wilKS, db=wilDB, isith=wsith, icount=1, salt=salt, transferable=False, temp=True) # stem is .name assert wilHab.ks == wilKS assert wilHab.db == wilDB assert not wilHab.kever.prefixer.transferable # create non-local kevery for Wam to process nonlocal msgs wilKvy = eventing.Kevery(kevers=wilHab.kevers, db=wilHab.db, framed=True, opre=wilHab.pre, local=False) # setup Cam's habitat trans multisig wits = [wesHab.pre, wokHab.pre, wamHab.pre] csith = 2 # hex str of threshold int camHab = directing.Habitat(name='cam', ks=camKS, db=camDB, isith=csith, icount=3, toad=2, wits=wits, salt=salt, temp=True) # stem is .name assert camHab.ks == camKS assert camHab.db == camDB assert camHab.kever.prefixer.transferable for werfer in camHab.iserder.werfers: assert werfer.qb64 in wits assert camHab.kever.wits == wits assert camHab.kever.toad == 2 assert camHab.kever.sn == 0 # create non-local kevery for Cam to process onlocal msgs camKvy = eventing.Kevery(kevers=camHab.kevers, db=camHab.db, framed=True, opre=camHab.pre, local=False) # setup Van's habitat trans multisig vsith = 2 # two of three signing threshold vanHab = directing.Habitat(name='van', ks=vanKS, db=vanDB, isith=vsith, icount=3, salt=salt, temp=True) # stem is .name assert vanHab.ks == vanKS assert vanHab.db == vanDB assert vanHab.kever.prefixer.transferable # create non-local kevery for Van to process nonlocal msgs vanKvy = eventing.Kevery(kevers=vanHab.kevers, db=vanHab.db, framed=True, opre=vanHab.pre, local=False) # make list so easier to batch camWitKvys = [wesKvy, wokKvy, wamKvy] camWitHabs = [wesHab, wokHab, wamHab] # Create Cam inception and send to each of Cam's witnesses camIcpMsg = camHab.makeOwnInception() rctMsgs = [] # list of receipts from each witness for i in range(len(camWitKvys)): kvy = camWitKvys[i] kvy.process(ims=bytearray( camIcpMsg)) # send copy of cam icp msg to witness assert kvy.kevers[camHab.pre].sn == 0 # accepted event assert len(kvy.cues) == 1 # queued receipt cue hab = camWitHabs[i] rctMsg = hab.processCues(kvy.cues) # process cue returns rct msg assert len(rctMsg) == 559 rctMsgs.append(rctMsg) for msg in rctMsgs: # process rct msgs from all witnesses camKvy.process(ims=bytearray(msg)) # make copy for hab in camWitHabs: assert hab.pre in camKvy.kevers # get from Cam database copies of witness receipts received by Cam # and send to witnesses so all witnesses have full set of receipts # from all other witnesses # reply one event or receipt one event with all witness attachments dgkey = dbing.dgKey(pre=camHab.pre, dig=camHab.kever.serder.dig) wigs = camHab.db.getWigs(dgkey) assert len(wigs) == 3 wigers = [coring.Siger(qb64b=bytes(wig)) for wig in wigs] rserder = eventing.receipt(pre=camHab.pre, sn=camHab.kever.sn, dig=camHab.kever.serder.dig) camIcpWitRctMsg = eventing.messagize(serder=rserder, wigers=wigers) assert len(camIcpWitRctMsg) == 413 for i in range(len(camWitKvys)): kvy = camWitKvys[i] kvy.process( ims=bytearray(camIcpWitRctMsg)) # send copy of witness rcts assert len(kvy.db.getWigs(dgkey)) == 3 # fully witnessed assert len(kvy.cues) == 0 # no cues # send Cam icp and witness rcts to Van vanKvy.process( ims=bytearray(camIcpMsg)) # should escrow since not witnesses assert camHab.pre not in vanKvy.kevers vanKvy.process(ims=bytearray(camIcpWitRctMsg)) vanKvy.processEscrows() assert camHab.pre in vanKvy.kevers vcKvr = vanKvy.kevers[camHab.pre] assert vcKvr.sn == 0 assert vcKvr.wits == wits # Create Cam ixn and send to each of Cam's witnesses camIxnMsg = camHab.interact() rctMsgs = [] # list of receipts from each witness for i in range(len(camWitKvys)): kvy = camWitKvys[i] kvy.process(ims=bytearray( camIxnMsg)) # send copy of cam icp msg to witness assert kvy.kevers[camHab.pre].sn == 1 # accepted event assert len(kvy.cues) == 1 # queued receipt cue hab = camWitHabs[i] rctMsg = hab.processCues(kvy.cues) # process cue returns rct msg assert len(rctMsg) == 281 rctMsgs.append(rctMsg) for msg in rctMsgs: # process rct msgs from all witnesses camKvy.process(ims=bytearray(msg)) # make copy for hab in camWitHabs: assert hab.pre in camKvy.kevers # get from Cam database copies of witness receipts received by Cam # and send to witnesses so all witnesses have full set of receipts # from all other witnesses # reply one event or receipt one event with all witness attachments dgkey = dbing.dgKey(pre=camHab.pre, dig=camHab.kever.serder.dig) wigs = camHab.db.getWigs(dgkey) assert len(wigs) == 3 wigers = [coring.Siger(qb64b=bytes(wig)) for wig in wigs] rserder = eventing.receipt(pre=camHab.pre, sn=camHab.kever.sn, dig=camHab.kever.serder.dig) camIxnWitRctMsg = eventing.messagize(serder=rserder, wigers=wigers) assert len(camIxnWitRctMsg) == 413 for i in range(len(camWitKvys)): kvy = camWitKvys[i] kvy.process( ims=bytearray(camIxnWitRctMsg)) # send copy of witness rcts assert len(kvy.db.getWigs(dgkey)) == 3 # fully witnessed assert len(kvy.cues) == 0 # no cues # send Cam ixn's witness rcts to Van first then send Cam ixn vanKvy.process(ims=bytearray(camIxnWitRctMsg)) vanKvy.processEscrows() assert vcKvr.sn == 0 vanKvy.process( ims=bytearray(camIxnMsg)) # should escrow since not witnesses assert vcKvr.sn == 0 vanKvy.processEscrows() assert vcKvr.sn == 1 # Cam replace Wok with Wil as a witness. # Cam update Wil all event witnessed events for Cam by replay # Cam update itself with Wil receipts including Wils inception camReplayMsg = camHab.replay() assert len(camReplayMsg) == 1824 wilKvy.process(ims=bytearray(camReplayMsg)) assert camHab.pre in wilKvy.kevers assert wilKvy.kevers[camHab.pre].sn == 1 # asscepted both events assert len(wilKvy.cues) == 2 wilRctMsg = wilHab.processCues( wilKvy.cues) # process cue returns rct msg assert len(wilKvy.cues) == 0 camKvy.process(ims=bytearray(wilRctMsg)) # make copy assert wilHab.pre in camKvy.kevers # Cam rotation with witness rotation camRotMsg = camHab.rotate(toad=2, cuts=[wokHab.pre], adds=[wilHab.pre]) assert camHab.kever.wits == [wesHab.pre, wamHab.pre, wilHab.pre] assert camHab.kever.toad == 2 assert camHab.kever.sn == 2 # update lists of witness kvys and habs camWitKvys = [wesKvy, wamKvy, wilKvy] camWitHabs = [wesHab, wamHab, wilHab] rctMsgs = [] # list of receipt msgs from each witness for i in range(len(camWitKvys)): kvy = camWitKvys[i] kvy.process( ims=bytearray(camRotMsg)) # send copy of cam msg to witness assert kvy.kevers[camHab.pre].sn == 2 # accepted event assert len(kvy.cues) == 1 # queued receipt cue hab = camWitHabs[i] rctMsg = hab.processCues(kvy.cues) # process cue returns rct msg assert len(rctMsg) == 281 rctMsgs.append(rctMsg) for msg in rctMsgs: # process rct msgs from all witnesses camKvy.process(ims=bytearray(msg)) # make copy for hab in camWitHabs: assert hab.pre in camKvy.kevers # get from Cam database copies of witness receipts received by Cam # and send to witnesses so all witnesses have full set of receipts # from all other witnesses # reply one event or receipt one event with all witness attachments dgkey = dbing.dgKey(pre=camHab.pre, dig=camHab.kever.serder.dig) wigs = camHab.db.getWigs(dgkey) assert len(wigs) == 3 wigers = [coring.Siger(qb64b=bytes(wig)) for wig in wigs] rserder = eventing.receipt(pre=camHab.pre, sn=camHab.kever.sn, dig=camHab.kever.serder.dig) camRotWitRctMsg = eventing.messagize(serder=rserder, wigers=wigers) assert len(camRotWitRctMsg) == 413 for i in range(len(camWitKvys)): kvy = camWitKvys[i] kvy.process( ims=bytearray(camRotWitRctMsg)) # send copy of witness rcts assert len(kvy.db.getWigs(dgkey)) == 3 # fully witnessed assert len(kvy.cues) == 0 # no cues # send Cam's rot and wit receipts to Van #vanKvy.process(ims=bytearray(camRotMsg)) # should escrow since not witnesses #vanKvy.process(ims=bytearray(camRotWitRctMsg)) #vanKvy.processEscrows() #assert vcKvr.sn == 2 #assert vcKvr.wits == camHab.kever.wits # send Cam rot's witness rcts to Van first then send Cam rot vanKvy.process(ims=bytearray(camRotWitRctMsg)) vanKvy.processEscrows() assert vcKvr.sn == 1 vanKvy.process( ims=bytearray(camRotMsg)) # should escrow since not witnesses assert vcKvr.sn == 1 vanKvy.processEscrows() assert vcKvr.sn == 2 assert vcKvr.wits == camHab.kever.wits assert not os.path.exists(wokKS.path) assert not os.path.exists(wokDB.path) assert not os.path.exists(wesKS.path) assert not os.path.exists(wesDB.path) assert not os.path.exists(vanKS.path) assert not os.path.exists(vanDB.path) assert not os.path.exists(camKS.path) assert not os.path.exists(camDB.path) """End Test"""
def test_direct_mode_with_manager(): """ Test direct mode with transferable validator event receipts """ # manual process to generate a list of secrets # root = pysodium.randombytes(pysodium.crypto_pwhash_SALTBYTES) # secrets = generateSecrets(root=root, count=8) # Direct Mode initiated by coe is controller, val is validator # but goes both ways once initiated. # set of secrets (seeds for private keys) coeSalt = Salter(raw=b'0123456789abcdea').qb64 # set of secrets (seeds for private keys) valSalt = Salter(raw=b'1123456789abcdea').qb64 with openDB("controller") as coeLogger, openDB("validator") as valLogger, \ openKS(name="controller") as coeKpr, openKS(name="validator") as valKpr: # Init key pair manager coeMgr = Manager(keeper=coeKpr, salt=coeSalt) coeVerfers, coeDigers, cst, nst = coeMgr.incept(icount=1, ncount=1) # init Keverys coeKevery = eventing.Kevery(db=coeLogger) valKevery = eventing.Kevery(db=valLogger) coe_event_digs = [] # list of controller's own event log digs to verify against database val_event_digs = [] # list of validator's own event log digs to verify against database # init sequence numbers for both controller and validator csn = cesn = 0 # sn and last establishment sn = esn vsn = vesn = 0 # sn and last establishment sn = esn # Controller Event 0 Inception Transferable (nxt digest not empty) coeSerder = incept(keys=[coeVerfers[0].qb64], nxt=eventing.Nexter(digs=[coeDigers[0].qb64]).qb64, code=MtrDex.Blake3_256) assert csn == int(coeSerder.ked["s"], 16) == 0 coepre = coeSerder.ked["i"] coe_event_digs.append(coeSerder.dig) # sign serialization sigers = coeMgr.sign(ser=coeSerder.raw, verfers=coeVerfers) # create serialized message cmsg = messagize(coeSerder, sigers=sigers) # create own Controller Kever in Controller's Kevery parsing.Parser().parseOne(ims=bytearray(cmsg), kvy=coeKevery) # coeKevery.processOne(ims=bytearray(cmsg)) # send copy of cmsg coeKever = coeKevery.kevers[coepre] assert coeKever.prefixer.qb64 == coepre # Validator Event 0 Inception Transferable (nxt digest not empty) # Init key pair manager valMgr = Manager(keeper=valKpr, salt=valSalt) valVerfers, valDigers, cst, nst = valMgr.incept(icount=1, ncount=1) valSerder = incept(keys=[valVerfers[0].qb64], nxt=eventing.Nexter(digs=[valDigers[0].qb64]).qb64, code=MtrDex.Blake3_256) assert vsn == int(valSerder.ked["s"], 16) == 0 valpre = valSerder.ked["i"] val_event_digs.append(valSerder.dig) # sign serialization sigers = valMgr.sign(valSerder.raw, verfers=valVerfers) # return Siger if index # create serialized message vmsg = messagize(valSerder, sigers=sigers) # create own Validator Kever in Validator's Kevery parsing.Parser().parseOne(ims=bytearray(vmsg), kvy=valKevery) # valKevery.processOne(ims=bytearray(vmsg)) # send copy of vmsg valKever = valKevery.kevers[valpre] assert valKever.prefixer.qb64 == valpre # simulate sending of controller's inception message to validator parsing.Parser().parse(ims=bytearray(cmsg), kvy=valKevery) # valKevery.process(ims=bytearray(cmsg)) # make copy of msg assert coepre in valKevery.kevers # creates Kever for controller in validator's .kevers # create receipt of controller's inception # create seal of validator's last establishment event seal = SealEvent(i=valpre, s="{:x}".format(valKever.lastEst.s), d=valKever.lastEst.d) coeK = valKevery.kevers[coepre] # lookup coeKever from validator's .kevers # create trans receipt reserder = receipt(pre=coeK.prefixer.qb64, sn=coeK.sn, dig=coeK.serder.diger.qb64) #reserder = chit(pre=coeK.prefixer.qb64, #sn=coeK.sn, #dig=coeK.serder.diger.qb64, #seal=seal) # Validate receipt # sign controller's event not receipt # look up event to sign from validator's kever for coe coeIcpDig = bytes(valKevery.db.getKeLast(key=snKey(pre=coepre, sn=csn))) assert coeIcpDig == coeK.serder.diger.qb64b coeIcpRaw = bytes(valKevery.db.getEvt(key=dgKey(pre=coepre, dig=coeIcpDig))) #counter = Counter(CtrDex.ControllerIdxSigs) #assert counter.qb64 == '-AAB' sigers = valMgr.sign(ser=coeIcpRaw, verfers=valVerfers) # return Siger if index # process own validator receipt in validator's Kevery so have copy in own log rmsg = messagize(reserder, sigers=sigers, seal=seal) assert len(rmsg) == 353 parsing.Parser().parseOne(ims=bytearray(rmsg), kvy=valKevery) # valKevery.processOne(ims=bytearray(rmsg)) # process copy of rmsg # attach receipt message to existing message with validators inception message # simulate streaming. validator first sends it's inception event, then sends a receipt to controller vmsg.extend(rmsg) # Simulate sending validator's inception event and receipt of # controller's inception message to controller parsing.Parser().parse(ims=vmsg, kvy=coeKevery) # coeKevery.process(ims=vmsg) # controller process validator's inception and receipt # check if validator's Kever in controller's .kevers assert valpre in coeKevery.kevers # check if receipt quadruple from validator in receipt database result = coeKevery.db.getVrcs(key=dgKey(pre=coeKever.prefixer.qb64, dig=coeKever.serder.diger.qb64)) assert bytes(result[0]) == (valKever.prefixer.qb64b + Seqner(sn=valKever.sn).qb64b + valKever.serder.diger.qb64b + sigers[0].qb64b) # create receipt to escrow use invalid digest and sequence number so not in controller's db fake = reserder.dig # some other digest reserder = receipt(pre=coeK.prefixer.qb64, sn=10, dig=fake) # sign event not receipt sigers = valMgr.sign(ser=coeIcpRaw, verfers=valVerfers) # return Siger if index # create receipt message vmsg = messagize(reserder, sigers=sigers, seal=seal) parsing.Parser().parse(ims=bytearray(vmsg), kvy=coeKevery) # coeKevery.process(ims=vmsg) # controller process the escrow receipt from validator # check if receipt quadruple in escrow database result = coeKevery.db.getVres(key=snKey(pre=coeKever.prefixer.qb64, sn=10)) assert bytes(result[0]) == (fake.encode("utf-8") + valKever.prefixer.qb64b + Seqner(sn=valKever.sn).qb64b + valKever.serder.diger.qb64b + sigers[0].qb64b) # Send receipt from controller to validator # create receipt of validator's inception # create seal of controller's last establishment event seal = SealEvent(i=coepre, s="{:x}".format(coeKever.lastEst.s), d=coeKever.lastEst.d) valK = coeKevery.kevers[valpre] # lookup valKever from controller's .kevers # create trans receipt reserder = receipt(pre=valK.prefixer.qb64, sn=valK.sn, dig=valK.serder.diger.qb64,) # sign validator's event not receipt # look up event to sign from controller's kever for validator valIcpDig = bytes(coeKevery.db.getKeLast(key=snKey(pre=valpre, sn=vsn))) assert valIcpDig == valK.serder.diger.qb64b valIcpRaw = bytes(coeKevery.db.getEvt(key=dgKey(pre=valpre, dig=valIcpDig))) sigers = coeMgr.sign(ser=valIcpRaw, verfers=coeVerfers) # return Siger if index # create receipt message cmsg = messagize(reserder, sigers=sigers, seal=seal) # controller process own receipt in own Kevery so have copy in own log parsing.Parser().parseOne(ims=bytearray(cmsg), kvy=coeKevery) # coeKevery.processOne(ims=bytearray(cmsg)) # make copy # Simulate sending controller's receipt of validator's inception message to validator parsing.Parser().parse(ims=cmsg, kvy=valKevery) # valKevery.process(ims=cmsg) # controller process validator's inception and receipt # check if receipt quadruple from controller in validator's receipt database result = valKevery.db.getVrcs(key=dgKey(pre=valKever.prefixer.qb64, dig=valKever.serder.diger.qb64)) assert bytes(result[0]) == (coeKever.prefixer.qb64b + Seqner(sn=coeKever.sn).qb64b + coeKever.serder.diger.qb64b + sigers[0].qb64b) # Controller Event 1 Rotation Transferable csn += 1 cesn += 1 assert csn == cesn == 1 coeVerfers, coeDigers, cst, nst = coeMgr.rotate(pre=coeVerfers[0].qb64) coeSerder = rotate(pre=coeKever.prefixer.qb64, keys=[coeVerfers[0].qb64], dig=coeKever.serder.diger.qb64, nxt=eventing.Nexter(digs=[coeDigers[0].qb64]).qb64, sn=csn) coe_event_digs.append(coeSerder.dig) # sign serialization sigers = coeMgr.sign(coeSerder.raw, verfers=coeVerfers) # returns sigers # create serialized message cmsg = messagize(coeSerder, sigers=sigers) # update controller's key event verifier state parsing.Parser().parseOne(ims=bytearray(cmsg), kvy=coeKevery) # coeKevery.processOne(ims=bytearray(cmsg)) # make copy # verify controller's copy of controller's event stream is updated assert coeKever.sn == csn assert coeKever.serder.diger.qb64 == coeSerder.dig # simulate send message from controller to validator parsing.Parser().parse(ims=cmsg, kvy=valKevery) # valKevery.process(ims=cmsg) # verify validator's copy of controller's event stream is updated assert coeK.sn == csn assert coeK.serder.diger.qb64 == coeSerder.dig # create receipt of controller's rotation # create seal of validator's last establishment event seal = SealEvent(i=valpre, s="{:x}".format(valKever.lastEst.s), d=valKever.lastEst.d) # create validator receipt reserder = receipt(pre=coeK.prefixer.qb64, sn=coeK.sn, dig=coeK.serder.diger.qb64) # sign controller's event not receipt # look up event to sign from validator's kever for controller coeRotDig = bytes(valKevery.db.getKeLast(key=snKey(pre=coepre, sn=csn))) assert coeRotDig == coeK.serder.diger.qb64b coeRotRaw = bytes(valKevery.db.getEvt(key=dgKey(pre=coepre, dig=coeRotDig))) sigers = valMgr.sign(ser=coeRotRaw, verfers=valVerfers) # validator create receipt message vmsg = messagize(reserder, sigers=sigers, seal=seal) # validator process own receipt in own kevery so have copy in own log parsing.Parser().parseOne(ims=bytearray(vmsg), kvy=valKevery) # valKevery.processOne(ims=bytearray(vmsg)) # make copy # Simulate send to controller of validator's receipt of controller's rotation message parsing.Parser().parse(ims=vmsg, kvy=coeKevery) # coeKevery.process(ims=vmsg) # controller process validator's incept and receipt # check if receipt quadruple from validator in receipt database result = coeKevery.db.getVrcs(key=dgKey(pre=coeKever.prefixer.qb64, dig=coeKever.serder.diger.qb64)) assert bytes(result[0]) == (valKever.prefixer.qb64b + Seqner(sn=valKever.sn).qb64b + valKever.serder.diger.qb64b + sigers[0].qb64b) # Next Event 2 Controller Interaction csn += 1 # do not increment esn assert csn == 2 assert cesn == 1 coeSerder = interact(pre=coeKever.prefixer.qb64, dig=coeKever.serder.diger.qb64, sn=csn) coe_event_digs.append(coeSerder.dig) # sign serialization sigers = coeMgr.sign(coeSerder.raw, verfers=coeVerfers) # create msg cmsg = messagize(coeSerder, sigers=sigers) # update controller's key event verifier state parsing.Parser().parseOne(ims=bytearray(cmsg), kvy=coeKevery) # coeKevery.processOne(ims=bytearray(cmsg)) # make copy # verify controller's copy of controller's event stream is updated assert coeKever.sn == csn assert coeKever.serder.diger.qb64 == coeSerder.dig # simulate send message from controller to validator parsing.Parser().parse(ims=cmsg, kvy=valKevery) # valKevery.process(ims=cmsg) # verify validator's copy of controller's event stream is updated assert coeK.sn == csn assert coeK.serder.diger.qb64 == coeSerder.dig # create receipt of controller's interaction # create seal of validator's last est event seal = SealEvent(i=valpre, s="{:x}".format(valKever.lastEst.s), d=valKever.lastEst.d) # create validator receipt reserder = receipt(pre=coeK.prefixer.qb64, sn=coeK.sn, dig=coeK.serder.diger.qb64) # sign controller's event not receipt # look up event to sign from validator's kever for controller coeIxnDig = bytes(valKevery.db.getKeLast(key=snKey(pre=coepre, sn=csn))) assert coeIxnDig == coeK.serder.diger.qb64b coeIxnRaw = bytes(valKevery.db.getEvt(key=dgKey(pre=coepre, dig=coeIxnDig))) sigers = valMgr.sign(ser=coeIxnRaw, verfers=valVerfers) # create receipt message vmsg = messagize(reserder, sigers=sigers, seal=seal) # validator process own receipt in own kevery so have copy in own log parsing.Parser().parseOne(ims=bytearray(vmsg), kvy=valKevery) # valKevery.processOne(ims=bytearray(vmsg)) # make copy # Simulate send to controller of validator's receipt of controller's rotation message parsing.Parser().parse(ims=bytearray(vmsg), kvy=coeKevery) # coeKevery.process(ims=vmsg) # controller process validator's incept and receipt # check if receipt quadruple from validator in receipt database result = coeKevery.db.getVrcs(key=dgKey(pre=coeKever.prefixer.qb64, dig=coeKever.serder.diger.qb64)) assert bytes(result[0]) == (valKever.prefixer.qb64b + Seqner(sn=valKever.sn).qb64b + valKever.serder.diger.qb64b + sigers[0].qb64b) # verify final controller event state assert coeKever.sn == coeK.sn == csn db_digs = [bytes(v).decode("utf-8") for v in coeKever.baser.getKelIter(coepre)] assert len(db_digs) == len(coe_event_digs) == csn + 1 assert db_digs == coe_event_digs db_digs = [bytes(v).decode("utf-8") for v in valKever.baser.getKelIter(coepre)] assert len(db_digs) == len(coe_event_digs) == csn + 1 assert db_digs == coe_event_digs # verify final validator event state assert valKever.sn == valK.sn == vsn db_digs = [bytes(v).decode("utf-8") for v in valKever.baser.getKelIter(valpre)] assert len(db_digs) == len(val_event_digs) == vsn + 1 assert db_digs == val_event_digs db_digs = [bytes(v).decode("utf-8") for v in coeKever.baser.getKelIter(valpre)] assert len(db_digs) == len(val_event_digs) == vsn + 1 assert db_digs == val_event_digs assert not os.path.exists(valKevery.db.path) assert not os.path.exists(coeKever.baser.path)