commit b7f02d9064e2615043978e48e109dfef3fd0b2c9
parent d2fc48a40122066dbcd7574eed482204d252b84e
Author: lash <dev@holbrook.no>
Date: Thu, 6 Nov 2025 00:08:35 +0000
Add xml export
Diffstat:
3 files changed, 112 insertions(+), 5 deletions(-)
diff --git a/dummy/create.py b/dummy/create.py
@@ -16,6 +16,16 @@ state_serial = 0
state_digest = b'00' * 64
+class DemoWallet:
+
+ def sign(self, v):
+ r = pk.sign(v)
+ return r.signature
+
+ def pubkey(self):
+ return pubk.encode()
+
+
def save_state():
f = open('.state', 'wb')
b = state_serial.to_bytes(8, byteorder='big')
@@ -58,6 +68,10 @@ if __name__ == '__main__':
state_serial += 1
entry = Entry(arg.t, amount, arg.u, state_serial, arg.a, arg.date)
+ wallet = DemoWallet()
ledger.add_entry(entry)
+ entry.package(wallet)
+ r = lxml.etree.tostring(entry.to_tree())
+ print(r.decode('utf-8'))
save_state()
diff --git a/dummy/running.xml b/dummy/running.xml
@@ -18,8 +18,8 @@
<identity keyid="f1d2d2f924e986ac86fdf7b36c94bcdf32beec15" didtype="web">holbrook.no</identity>
<incoming serial="231">
<digest algo="sha512">b5bb9d8014a0f9b1d61e21e796d78dccdf1352f23cd32812f4850b878ae4944cb5bb9d8014a0f9b1d61e21e796d78dccdf1352f23cd32812f4850b878ae4944c</digest>
- <sig keyid="58851ae2166b3f1454193e0a7e821402dd1c1a91">1f74a9c0196a025f27d4e940c4abedfa2d37504f268aea359659cb65b85bd4d7974369507950006964c93391d3d4580ab8064f6d30a62908468ef771be952e95</sig>
- <sig keyid="566c38287d3f31c7e50836cae58e426c6bccc52d">117a57c72ed210b91469307a1c2e73fe2d5ee306cd8ccf1a9db4ecb15d38ecbbfc97d62fec4ab8aadb08c531f2d1ede34cb6e4d3987bcba63322a0767e532e13</sig>
+ <sig type='ed25519' keyid="58851ae2166b3f1454193e0a7e821402dd1c1a91">1f74a9c0196a025f27d4e940c4abedfa2d37504f268aea359659cb65b85bd4d7974369507950006964c93391d3d4580ab8064f6d30a62908468ef771be952e95</sig>
+ <sig type='ed25519' keyid="566c38287d3f31c7e50836cae58e426c6bccc52d">117a57c72ed210b91469307a1c2e73fe2d5ee306cd8ccf1a9db4ecb15d38ecbbfc97d62fec4ab8aadb08c531f2d1ede34cb6e4d3987bcba63322a0767e532e13</sig>
<real unit="BTC">
<asset>6323141</asset>
<liability>0</liability>
@@ -53,7 +53,7 @@
<digest algo="sha512">777b30c8fc40aea3c717777831a05c9f29c7b6735f1573e9b0b55373c264f6f3777b30c8fc40aea3c717777831a05c9f29c7b6735f1573e9b0b55373c264f6f3</digest>
</attachment>
</data>
- <sig keyid="e242ed3bffccdf271b7fbaf34ed72d089537b42f">0cf9180a764aba863a67b6d72f0918bc131c6772642cb2dce5a34f0a702f9470ddc2bf125c12198b1995c233c34b4afd346c54a2334c350a948a51b6e8b4e6b6/</sig>
+ <sig type='ed25519' keyid="e242ed3bffccdf271b7fbaf34ed72d089537b42f">0cf9180a764aba863a67b6d72f0918bc131c6772642cb2dce5a34f0a702f9470ddc2bf125c12198b1995c233c34b4afd346c54a2334c350a948a51b6e8b4e6b6/</sig>
</entry>
<entry type="liability">
<data>
@@ -62,10 +62,11 @@
<serial>245</serial>
<unit>BTC</unit>
<date>2025-11-03</date>
+ <dateTimeRegistered>2025-11-05T12:24:05Z</dateTimeRegistered>
<account>Construction</account>
<description>Install AC</description>
<amount>1000000</amount>
</data>
- <sig keyid="f1d2d2f924e986ac86fdf7b36c94bcdf32beec15">cc06808cbbee0510331aa97974132e8dc296aeb795be229d064bae784b0a87a5cf4281d82e8c99271b75db2148f08a026c1a60ed9cabdb8cac6d24242dac4063</sig>
+ <sig type='ed25519' keyid="f1d2d2f924e986ac86fdf7b36c94bcdf32beec15">cc06808cbbee0510331aa97974132e8dc296aeb795be229d064bae784b0a87a5cf4281d82e8c99271b75db2148f08a026c1a60ed9cabdb8cac6d24242dac4063</sig>
</entry>
</ledger>
diff --git a/dummy/svcontas/__init__.py b/dummy/svcontas/__init__.py
@@ -1,12 +1,17 @@
import sys
import logging
import datetime
+import uuid
+import hashlib
from lxml import etree
+import rencode
logging.basicConfig(level=logging.DEBUG)
logg = logging.getLogger()
+DEFAULTPARENT = b'\x00' * 64
+
class NoopSigVerifier:
@@ -84,8 +89,18 @@ class UnitIndex:
class Entry:
- def __init__(self, typ, amount, unit, serial, account, tx_date, description=None, parent=None):
+ # TODO: parent only 0 if serial 0
+ def __init__(self, typ, amount, unit, serial, account, tx_date, ref=None, description=None, parent=None):
self.typ = typ
+ if isinstance(parent, str):
+ parent = bytes.fromhex(parent)
+ elif parent == None:
+ parent = DEFAULTPARENT
+ elif len(parent) != 64:
+ raise ValueError('invalid parent hash')
+ if ref == None:
+ ref = str(uuid.uuid4())
+ self.ref = ref
self.parent = parent
self.amount = amount
self.unit = unit
@@ -95,6 +110,7 @@ class Entry:
self.dtreg = datetime.datetime.now()
self.attachment = []
self.sigs = {}
+ self.description = description
def attach(self, mime, algo, digest, description=None, slug=None):
@@ -117,6 +133,82 @@ class Entry:
return r
+ def serialize(self):
+ d = [
+ self.parent,
+ self.serial,
+ self.ref,
+ self.dtreg.strftime('%Y%m%d%H%M%S'),
+ self.dt.strftime('%Y%m%d'),
+ self.unit,
+ self.amount,
+ ]
+ return rencode.dumps(d)
+
+
+ def package(self, wallet):
+ b = self.serialize()
+ h = hashlib.new('sha512')
+ h.update(b)
+ z = h.digest()
+ r = wallet.sign(z)
+ pubk_hx = wallet.pubkey().hex()
+ self.sigs[pubk_hx] = r
+ logg.debug('added signature from key {}'.format(pubk_hx))
+ return (b, z, r,)
+
+
+ def to_tree(self):
+ tree = etree.Element('entry', type=self.typ)
+ data = etree.Element('data')
+
+ o = etree.Element('parent')
+ o.text = self.parent.hex()
+ data.append(o)
+
+ o = etree.Element('ref')
+ o.text = self.ref
+ data.append(o)
+
+ o = etree.Element('serial')
+ o.text = str(self.serial)
+ data.append(o)
+
+ o = etree.Element('unit')
+ o.text = self.unit
+ data.append(o)
+
+ o = etree.Element('date')
+ o.text = self.dt.strftime('%Y-%m-%d')
+ data.append(o)
+
+ o = etree.Element('dateTimeRegistered')
+ o.text = self.dt.strftime('%Y-%m-%dT%H:%M:%SZ')
+ data.append(o)
+
+ o = etree.Element('account')
+ o.text = self.account
+ data.append(o)
+
+ if self.description:
+ o = etree.Element('description')
+ o.text = self.account
+ data.append(o)
+
+ o = etree.Element('amount')
+ o.text = self.account
+ data.append(o)
+
+ tree.append(data)
+
+ for k in self.sigs.keys():
+ o = etree.Element('sig', type='ed25519', keyid=k)
+ o.text = self.sigs[k].hex()
+ tree.append(o)
+
+ return tree
+
+
class RunningTotal:
def __init__(self, sym, unitindex, asset=0, liability=0, income=0, expense=0):