commit 0c7e0ebfc3c2b176fcaad8dbf0039feb43a03169
parent 8febfdeb102f1bbafaebdbe5671f3d88294d74f4
Author: lash <dev@holbrook.no>
Date: Tue, 10 Mar 2026 13:12:32 -0600
Add ledger restore (from tip) to store
Diffstat:
3 files changed, 66 insertions(+), 4 deletions(-)
diff --git a/dummy/tests/store.py b/dummy/tests/store.py
@@ -121,5 +121,41 @@ class TestStore(unittest.TestCase):
self.assertEqual(len(ledger.entries), 2)
+ def test_store_restore(self):
+ uidx = UnitIndex('FOO')
+ wallet = DemoWallet()
+ acl = ACL.from_wallet(wallet)
+ ledger = Ledger(uidx, base=self.parent, acl=acl, wallet=wallet)
+ store = LedgerStore(self.store, ledger)
+
+ dst = EntryPart('FOO', 'asset', 'foo', 1337)
+ src = EntryPart('FOO', 'income', 'foo', 1337, debit=True)
+ o = Entry(ledger.next_serial(), datetime.datetime.strptime('2025-11-11', '%Y-%m-%d'), parent=self.parent, ref=self.ref, description=self.description, tx_datereg=self.dtreg, unitindex=uidx)
+ o.add_part(src, debit=True)
+ o.add_part(dst)
+ o.sign(wallet)
+ store.add_entry(o)
+
+ ref = str(uuid.uuid4())
+ parent = o.sum()[0]
+ description = 'barbarbar'
+ dtreg = datetime.datetime.now()
+ dst = EntryPart('FOO', 'expense', 'bar', 4200)
+ src = EntryPart('FOO', 'liability', 'bar', 4200, debit=True)
+ o = Entry(ledger.next_serial(), datetime.datetime.strptime('2025-11-12', '%Y-%m-%d'), parent=parent, ref=ref, description=description, tx_datereg=dtreg, unitindex=uidx)
+ o.add_part(src, debit=True)
+ o.add_part(dst)
+ o.sign(wallet)
+ store.add_entry(o)
+
+ ledger.truncate()
+ s = ledger.to_string()
+ ledger = Ledger.from_string(s)
+ store = LedgerStore(self.store, ledger)
+ store.restore()
+
+ self.assertEqual(len(ledger.entries), 2)
+
+
if __name__ == '__main__':
unittest.main()
diff --git a/dummy/usawa/ledger.py b/dummy/usawa/ledger.py
@@ -720,6 +720,15 @@ class Ledger:
return self.cur
+ """Returns the serial of the latest entry added to the ledger.
+
+ :return: Serial.
+ :rtype: int
+ """
+ def current_serial(self):
+ return self.serial
+
+
"""Generate canonical XML for signature material.
:return: Signature material.
diff --git a/dummy/usawa/store.py b/dummy/usawa/store.py
@@ -210,11 +210,9 @@ class LedgerStore(Interface):
return Asset.deserialize(v, digest)
- """Flush ledger and load all entries from store.
+ """Load all entries from store, oldest to newest.
- The existing state will always be lost.
-
- If the load fails, the ledger will be reset before returning.
+ Must be called on an unused ledger instance. Using with a ledger that contains or has contains entries is undefined.
:raises FileNotFoundError: If an entry cannot be found.
"""
@@ -229,6 +227,25 @@ class LedgerStore(Interface):
self.ledger.add_entry(o)
+ """Load all entries from store, newest to oldest.
+
+ Must be called on an unused ledger instance. Using with a ledger that contains or has contains entries is undefined.
+
+ :raises FileNotFoundError: If an entry cannot be found.
+ """
+ def restore(self, until=0, acl=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)
+ #except FileNotFoundError:
+ # break
+ self.ledger.add_entry(o, check_parent=False)
+ i -= 1
+
+
"""Add signing key to the store.
If this is the first key in the store, it will be set as default.