commit 7f2dadcfc9d407e16559f4f36b36023c6ee10cc4
parent 6778818f21d28e73f8068fdff505c54c56004b57
Author: lash <dev@holbrook.no>
Date: Sun, 17 May 2026 19:51:26 -0600
Enable link handling in store
Diffstat:
3 files changed, 50 insertions(+), 19 deletions(-)
diff --git a/dummy/tests/link.py b/dummy/tests/link.py
@@ -4,7 +4,9 @@ import unittest
import os
import uuid
-from usawa import Entry, Ledger, UnitIndex
+from whee.mem import MemStore
+from usawa.store import LedgerStore
+from usawa import Entry, Ledger, UnitIndex, DemoWallet
from usawa.link import EntryLink
logging.basicConfig(level=logging.DEBUG)
@@ -20,7 +22,7 @@ class TestLink(unittest.TestCase):
self.linker = EntryLink(self.ledger)
- def test_dup(self):
+ def test_link_dup(self):
o = Entry(serial=42, tx_date=datetime.datetime.now(datetime.UTC))
self.linker.link(o)
o = Entry(serial=666, tx_date=datetime.datetime.now(datetime.UTC))
@@ -30,7 +32,7 @@ class TestLink(unittest.TestCase):
self.linker.link(o)
- def test_explicit(self):
+ def test_link_explicit(self):
uu = uuid.uuid4()
o = Entry(serial=42, tx_date=datetime.datetime.now(datetime.UTC), ref=str(uu))
self.linker.link(o)
@@ -46,7 +48,7 @@ class TestLink(unittest.TestCase):
self.assertEqual(r, str(uu))
- def test_implicit(self):
+ def test_link_implicit(self):
uu = uuid.uuid4()
entry_a = Entry(serial=42, tx_date=datetime.datetime.now(datetime.UTC), ref=str(uu))
entry_b = Entry(serial=666, tx_date=datetime.datetime.now(datetime.UTC))
@@ -59,7 +61,7 @@ class TestLink(unittest.TestCase):
self.assertEqual(r[0], 42)
- def test_implicit_ref(self):
+ def test_link_implicit_ref(self):
linker = EntryLink(self.ledger, refs=True)
uu = uuid.uuid4()
entry_a = Entry(serial=42, tx_date=datetime.datetime.now(datetime.UTC), ref=str(uu))
@@ -72,7 +74,7 @@ class TestLink(unittest.TestCase):
self.assertEqual(r[1], 666)
- def test_entry_serialize(self):
+ def test_link_entry_serialize(self):
uu = uuid.uuid4()
entry_a = Entry(serial=42, tx_date=datetime.datetime.now(datetime.UTC), ref=str(uu))
entry_b = Entry(serial=666, tx_date=datetime.datetime.now(datetime.UTC))
@@ -84,5 +86,34 @@ class TestLink(unittest.TestCase):
self.assertEqual(v, str(uu))
+
+ def test_link_store(self):
+ wallet = DemoWallet()
+ uu = uuid.uuid4()
+ db = MemStore()
+ store = LedgerStore(db, self.ledger)
+ entry_a = Entry(serial=42, tx_date=datetime.datetime.now(datetime.UTC), ref=str(uu))
+ entry_b = Entry(serial=666, tx_date=datetime.datetime.now(datetime.UTC))
+ self.linker.link_to(entry_a, entry_b)
+ entry_a.sign(wallet)
+ store.add_entry(entry_a, linker=self.linker)
+ entry_b.sign(wallet)
+ store.add_entry(entry_b, linker=self.linker)
+
+ linker = EntryLink(self.ledger)
+ entry_a_recover = store.get_entry(entry_a, linker=linker)
+ v = linker.get(entry_a_recover)
+ self.assertEqual(v, str(uu))
+
+ entry_b_recover = store.get_entry(entry_b, linker=linker)
+ r = linker.get_for(entry_b_recover)
+ self.assertEqual(len(r), 1)
+ self.assertEqual(r[0], 42)
+
+ r = linker.get_for(entry_a_recover)
+ self.assertEqual(len(r), 1)
+ self.assertEqual(r[0], 666)
+
+
if __name__ == '__main__':
unittest.main()
diff --git a/dummy/usawa/entry.py b/dummy/usawa/entry.py
@@ -555,17 +555,17 @@ class Entry(UsawaElement):
:type wallet: usawa.Wallet
:todo: Current specifying wallet has no effect.
"""
- def wrap(self, wallet=None):
+ def wrap(self, wallet=None, linker=None):
digest = None
data = None
if wallet != None:
(digest, _sig, _data) = self.sign(wallet)
- data = self.serialize()
+ data = self.serialize(linker=linker)
elif len(self.sigs) == 0:
raise PermissionError('at least one signature required')
else:
(digest, _data) = self.sum()
- data = self.serialize()
+ data = self.serialize(linker=linker)
hdr = []
sigs = []
@@ -603,9 +603,9 @@ class Entry(UsawaElement):
:todo: Current version only takes into account single signature
"""
@staticmethod
- def unwrap(data, acl=None, unitindex=None):
+ def unwrap(data, acl=None, unitindex=None, linker=None):
v = rencode.loads(data)
- entry = Entry.deserialize(v[2], unitindex=unitindex)
+ entry = Entry.deserialize(v[2], unitindex=unitindex, linker=linker)
pubkey_bytes = v[0][0][1]
sig = v[1][0]
entry.add_signature(pubkey_bytes, sig)
diff --git a/dummy/usawa/store.py b/dummy/usawa/store.py
@@ -295,9 +295,9 @@ class EntryStore(KeyStore):
:raises: ValueError if the entry is not the right object type.
:raises: FileExistsError if entry is already in store.
"""
- def add_entry(self, entry, update_ledger=False, overwrite=False):
+ def add_entry(self, entry, update_ledger=False, overwrite=False, linker=None):
k = pfx_entry(self.ledger, entry)
- v = entry.wrap()
+ v = entry.wrap(linker=linker)
self.db.put(k, v, exist_ok=overwrite)
if update_ledger:
self.ledger.add_entry(entry)
@@ -317,10 +317,10 @@ class EntryStore(KeyStore):
:raises: FileExistsError if entry is already in store.
:todo: optimize replacing asset stub with deserialized asset
"""
- def get_entry(self, entry, acl=None, unitindex=None):
+ def get_entry(self, entry, acl=None, unitindex=None, linker=None):
k = pfx_entry(self.ledger, entry)
v = self.db.get(k)
- entry = Entry.unwrap(v, unitindex=unitindex)
+ entry = Entry.unwrap(v, unitindex=unitindex, linker=linker)
# TODO: hacky!
i = 0
for o in entry.attachment:
@@ -366,7 +366,7 @@ class LedgerStore(EntryStore, AssetStore, KeyStore):
:raises FileNotFoundError: If an entry cannot be found.
"""
- def load(self, acl=None, until=0, unitindex=None, entry_callback_pre=None, entry_callback_post=None):
+ def load(self, acl=None, until=0, unitindex=None, entry_callback_pre=None, entry_callback_post=None, linker=None):
logg.debug('load ledger from store {} until {}'.format(self.ledger, until))
v = 0
while True:
@@ -376,7 +376,7 @@ class LedgerStore(EntryStore, AssetStore, KeyStore):
if until == v:
break
v = self.ledger.peek()
- o = self.get_entry(v, acl=acl, unitindex=unitindex)
+ o = self.get_entry(v, acl=acl, unitindex=unitindex, linker=linker)
self.ledger.next_serial()
except FileNotFoundError as e:
logg.debug('entry serial {} not found, terminating ({})'.format(v, e))
@@ -396,13 +396,13 @@ class LedgerStore(EntryStore, AssetStore, KeyStore):
:raises FileNotFoundError: If an entry cannot be found.
"""
- def restore(self, until=0, acl=None):
+ def restore(self, until=0, acl=None, linker=None):
logg.debug('restore ledger from store {}'.format(self.ledger))
i = self.ledger.current_serial()
while i > until:
logg.debug('get entry serial {} ledger {}'.format(i, self.ledger))
#try:
- o = self.get_entry(i, acl=acl)
+ o = self.get_entry(i, acl=acl, linker=linker)
#except FileNotFoundError:
# break
self.ledger.add_entry(o, check_parent=False)