commit f3f2c3c7b5f5f770b785b7bdbd29a1c022c63594
parent 7a5464f4646437451fadc1b15c96b7452c1985a3
Author: lash <dev@holbrook.no>
Date: Tue, 9 Dec 2025 22:20:50 +0000
Add store implementation for entry
Diffstat:
6 files changed, 104 insertions(+), 20 deletions(-)
diff --git a/dummy/svcontas/entry.py b/dummy/svcontas/entry.py
@@ -9,7 +9,7 @@ import rencode
from .constant import DEFAULTPARENT, NSPREFIX
from .crypto import DemoWallet
-from .error import ACLError
+from .error import ACLError, VerifyError
from .xml import nsmap
logg = logging.getLogger('svcontas.entry')
@@ -172,15 +172,27 @@ class Entry:
return (z, r, b,)
- def wrap(self, wallet):
- (digest, sig, data) = self.sign(wallet)
- pubkey = wallet.pubkey()
+ def wrap(self, wallet=None):
+ digest = None
+ sig = None
+ data = None
+ if wallet != None:
+ (digest, sig, data) = self.sign(wallet)
+ hdr = []
+ sigs = []
+ for k in self.sigs:
+ hdr.append([
+ KeyStoreFormat.LITERAL.value,
+ bytes.fromhex(k)
+ ])
+ sigs.append(self.sigs[k])
+
+ if len(sigs) == 0:
+ raise VerifyError()
+
d = [
- [
- KeyStoreFormat.LITERAL.value,
- pubkey,
- ],
- sig,
+ hdr,
+ sigs,
data,
]
return rencode.dumps(d)
@@ -189,7 +201,8 @@ class Entry:
@staticmethod
def unwrap(data, acl=None):
v = rencode.loads(data)
- pubkey_bytes = v[0][1]
+ # TODO: demo only takes into account single signature
+ pubkey_bytes = v[0][0][1]
if acl != None:
label = None
try:
@@ -199,7 +212,8 @@ class Entry:
if not acl.may(label, 0x01):
raise ACLError()
wallet = DemoWallet(publickey=pubkey_bytes)
- sig = v[1]
+ # TODO: demo only takes into account single signature
+ sig = v[1][0]
entry = Entry.deserialize(v[2])
(z, b) = entry.sum()
wallet.verify(z, sig)
diff --git a/dummy/svcontas/error.py b/dummy/svcontas/error.py
@@ -1,2 +1,6 @@
class ACLError(Exception):
pass
+
+
+class VerifyError(Exception):
+ pass
diff --git a/dummy/svcontas/store.py b/dummy/svcontas/store.py
@@ -8,25 +8,31 @@ from .entry import Entry
PFX_LEDGER = b'\x01'
-PFX_ENTRY = b'\x02'
+PFX_LEDGER_LOCK = b'\x02'
+PFX_ENTRY = b'\x04'
def pfx_ledger_topic(topic):
r = PFX_LEDGER + topic
return r
+def pfx_ledger_lock(topic):
+ r = PFX_LEDGER_LOCK + topic
+ return r
+
def pfx_ledger(ledger):
- if not isintance(ledger, Ledger):
+ if not isinstance(ledger, Ledger):
raise ValueError('invalid ledger')
return pfx_ledger_topic(topic)
def pfx_entry(ledger, entry):
- if not isintance(entry, Entry):
+ if not isinstance(entry, Entry):
raise ValueError('invalid entry')
- if not isintance(ledger, Ledger):
+ if not isinstance(ledger, Ledger):
raise ValueError('invalid ledger')
+ return PFX_LEDGER + ledger.topic + entry.serial.to_bytes(8, byteorder='big')
class LedgerStore(Interface):
@@ -52,5 +58,24 @@ class LedgerStore(Interface):
self.ledger.serial = serial
- def put(self):
- pass
+ def lock(self):
+ k = pfx_ledger_lock(self.ledger.topic)
+ v = None
+ # TODO: needs to be an atomic routine
+ try:
+ v = self.__o.get(k)
+ except KeyError:
+ raise PermissionError()
+ self.__o.put(k, 0x01, exist_ok)
+ # atomic until here
+
+
+ def unlock(self):
+ k = pfx_ledger_lock(self.ledger.topic)
+ v = self.__o.delete(k)
+
+
+ def add_entry(self, entry):
+ k = pfx_entry(self.ledger, entry)
+ v = entry.wrap()
+ self.__o.put(k, v)
diff --git a/dummy/tests/entry.py b/dummy/tests/entry.py
@@ -48,7 +48,7 @@ class TestEntry(unittest.TestCase):
src = EntryPart('income', 'foo', 1337, src=True)
o = Entry(src, dst, 'USD', 42, datetime.datetime.strptime('2025-11-11', '%Y-%m-%d'), parent=self.parent, ref=self.ref, description=self.description, tx_datereg=self.dtreg)
wallet = DemoWallet()
- data = o.wrap(wallet)
+ data = o.wrap(wallet=wallet)
r = Entry.unwrap(data)
diff --git a/dummy/tests/ledger.py b/dummy/tests/ledger.py
@@ -59,8 +59,6 @@ class TestLedger(unittest.TestCase):
v.sign(wallet)
o.add_entry(v)
- print(o.to_string())
-
if __name__ == '__main__':
unittest.main()
diff --git a/dummy/tests/store.py b/dummy/tests/store.py
@@ -0,0 +1,43 @@
+import logging
+import datetime
+import unittest
+import os
+import copy
+
+import lxml.etree
+from whee.mem import MemStore
+
+from svcontas import Ledger, UnitIndex, EntryPart, Entry, DemoWallet
+from svcontas.store import LedgerStore
+
+logging.basicConfig(level=logging.DEBUG)
+logg = logging.getLogger()
+
+testdir = os.path.realpath(os.path.dirname(__file__))
+
+
+class TestStore(unittest.TestCase):
+
+ def setUp(self):
+ self.store = MemStore()
+ self.parent = bytes.fromhex('0cf9180a764aba863a67b6d72f0918bc131c6772642cb2dce5a34f0a702f9470ddc2bf125c12198b1995c233c34b4afd346c54a2334c350a948a51b6e8b4e6b6')
+ self.ref = '1bda7dfa-b8fd-400d-8b42-1d2861ad7f70'
+ self.description = "foo bar baz"
+ self.dtreg = datetime.datetime.now()
+
+
+ def test_store_entry(self):
+ uidx = UnitIndex('FOO')
+ ledger = Ledger(uidx)
+ store = LedgerStore(self.store, ledger)
+ dst = EntryPart('asset', 'foo', 1337)
+ src = EntryPart('income', 'foo', 1337, src=True)
+ o = Entry(src, dst, 'USD', 42, datetime.datetime.strptime('2025-11-11', '%Y-%m-%d'), parent=self.parent, ref=self.ref, description=self.description, tx_datereg=self.dtreg)
+ wallet = DemoWallet()
+ #data = o.wrap(wallet)
+ o.sign(wallet)
+ store.add_entry(o)
+
+
+if __name__ == '__main__':
+ unittest.main()