usawa

Unnamed repository; edit this file 'description' to name the repository.
Info | Log | Files | Refs | Submodules | LICENSE

commit 0d4c21d0b8736a3d6a78728cdfdb7a9c257332c4
parent 3d30b886581ba5dfae00befbd8ec163481294a91
Author: lash <dev@holbrook.no>
Date:   Tue, 20 Jan 2026 11:14:43 +0000

Fix (hackily) duplicate identity entries

Diffstat:
Mdummy/doc/appendix.texi | 192+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mdummy/doc/protocol.texi | 5+++++
Mdummy/doc/xml.texi | 10++++------
Mdummy/tests/ledger.py | 2+-
Mdummy/usawa/data/schema.xsd | 9++++++++-
Mdummy/usawa/ledger.py | 26+++++++++++++++++++-------
6 files changed, 229 insertions(+), 15 deletions(-)

diff --git a/dummy/doc/appendix.texi b/dummy/doc/appendix.texi @@ -171,3 +171,195 @@ </xs:schema> @end example +@anchor{xml_example} +@appendix Example XML + +The two following examples are of the same ledger, containing two entries. + +The first displays header and entries from the initial (zero) state. It lists two entries. + +The second displays header and entries for the ledger state after the first entry added. It lists one entry. + +The third displays header for the ledger state after last entry added. It lists zero entries. + + +@section Ledger from initial state + +@example +<?xml version="1.0"?> +<ledger xmlns="http://usawa.defalsify.org/" version="1"> + <topic xmlns:ns="http://usawa.defalsify.org/">24448167713e4f7d7e09fd06716b17ffcbd8bd10aa2ebbaac0a0902292993a86244acb9683c7dc45500daf1193a760b87de6fadd0f7b30c1a7b63ac06c555ca8</topic> + <generated xmlns:ns="http://usawa.defalsify.org/">2026-01-20T09:30:34Z</generated> + <src xmlns:ns="http://usawa.defalsify.org/">defalsify.org</src> + <units xmlns:ns="http://usawa.defalsify.org/" base="BTC"> + <unit sym="BTC"> + <precision>2</precision> + <exchange>1000000000</exchange> + </unit> + </units> + <identity xmlns:ns="http://usawa.defalsify.org/" keyid="3b54648d60bb8a5b9e84fa0057f79b3a5996e511682e80176dc948dcbff5a4fc" didtype="usawa"/> + <incoming xmlns:ns="http://usawa.defalsify.org/" serial="0"> + <real unit="BTC"> + <asset>0</asset> + <liability>0</liability> + </real> + <digest algo="sha512">00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000</digest> + </incoming> + <entry> + <data> + <parent>00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000</parent> + <ref>2ae1dae8-8071-4a40-983d-e25f80634d6b</ref> + <serial>1</serial> + <date>2026-01-20</date> + <dateTimeRegistered>2026-01-20T09:29:28Z</dateTimeRegistered> + <description>awergaergh</description> + <debit type="expense"> + <unit>BTC</unit> + <account>general</account> + <amount>-2346300</amount> + </debit> + <credit type="asset"> + <unit>BTC</unit> + <account>general</account> + <amount>2346300</amount> + </credit> + </data> + <sig type="ed25519" keyid="3b54648d60bb8a5b9e84fa0057f79b3a5996e511682e80176dc948dcbff5a4fc">0a0bec86152bd411dff6d7569778305f30bf52dd03c060992d8bfd1f3432fe27cf3acd17d8019a0e5e3fe0c038664c478b1576fed027f3902bb32b56b05fd708</sig> + </entry> + <entry> + <data> + <parent>50740013c78726ddd4fd199bbe21ad3eb3c50dcfd3540e12c5b52151a9b9f3a41346a22a2d1928dfc5749faac332a8c15ff2f545e8ff92b07aa037c39b1ba93e</parent> + <ref>182536c7-f2ce-4976-af2a-6b0d2cf10e0c</ref> + <serial>2</serial> + <date>2026-01-20</date> + <dateTimeRegistered>2026-01-20T09:29:40Z</dateTimeRegistered> + <description>wergagh</description> + <debit type="expense"> + <unit>BTC</unit> + <account>general</account> + <amount>-1251613262700</amount> + </debit> + <credit type="asset"> + <unit>BTC</unit> + <account>general</account> + <amount>1251613262700</amount> + </credit> + </data> + <sig type="ed25519" keyid="3b54648d60bb8a5b9e84fa0057f79b3a5996e511682e80176dc948dcbff5a4fc">603bf1bf05951f1c78e3ba9ab430e914f73f03b6570c15cb241695393e57eb178029ba1ff0f86afa5f29ea10ea49418825e387feb8d03f79280593e4598b1b0d</sig> + </entry> +</ledger> +@end example + + +@section Ledger after last entry + +@example +<?xml version="1.0"?> +<ledger xmlns="http://usawa.defalsify.org/" version="1"> + <topic xmlns:ns="http://usawa.defalsify.org/">24448167713e4f7d7e09fd06716b17ffcbd8bd10aa2ebbaac0a0902292993a86244acb9683c7dc45500daf1193a760b87de6fadd0f7b30c1a7b63ac06c555ca8</topic> + <generated xmlns:ns="http://usawa.defalsify.org/">2026-01-20T09:30:34Z</generated> + <src xmlns:ns="http://usawa.defalsify.org/">defalsify.org</src> + <units xmlns:ns="http://usawa.defalsify.org/" base="BTC"> + <unit sym="BTC"> + <precision>2</precision> + <exchange>1000000000</exchange> + </unit> + </units> + <identity xmlns:ns="http://usawa.defalsify.org/" keyid="3b54648d60bb8a5b9e84fa0057f79b3a5996e511682e80176dc948dcbff5a4fc" didtype="usawa"/> + <incoming xmlns:ns="http://usawa.defalsify.org/" serial="0"> + <real unit="BTC"> + <asset>0</asset> + <liability>0</liability> + </real> + <digest algo="sha512">00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000</digest> + </incoming> + <entry> + <data> + <parent>00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000</parent> + <ref>2ae1dae8-8071-4a40-983d-e25f80634d6b</ref> + <serial>1</serial> + <date>2026-01-20</date> + <dateTimeRegistered>2026-01-20T09:29:28Z</dateTimeRegistered> + <description>awergaergh</description> + <debit type="expense"> + <unit>BTC</unit> + <account>general</account> + <amount>-2346300</amount> + </debit> + <credit type="asset"> + <unit>BTC</unit> + <account>general</account> + <amount>2346300</amount> + </credit> + </data> + <sig type="ed25519" keyid="3b54648d60bb8a5b9e84fa0057f79b3a5996e511682e80176dc948dcbff5a4fc">0a0bec86152bd411dff6d7569778305f30bf52dd03c060992d8bfd1f3432fe27cf3acd17d8019a0e5e3fe0c038664c478b1576fed027f3902bb32b56b05fd708</sig> + </entry> + <entry> + <data> + <parent>50740013c78726ddd4fd199bbe21ad3eb3c50dcfd3540e12c5b52151a9b9f3a41346a22a2d1928dfc5749faac332a8c15ff2f545e8ff92b07aa037c39b1ba93e</parent> + <ref>182536c7-f2ce-4976-af2a-6b0d2cf10e0c</ref> + <serial>2</serial> + <date>2026-01-20</date> + <dateTimeRegistered>2026-01-20T09:29:40Z</dateTimeRegistered> + <description>wergagh</description> + <debit type="expense"> + <unit>BTC</unit> + <account>general</account> + <amount>-1251613262700</amount> + </debit> + <credit type="asset"> + <unit>BTC</unit> + <account>general</account> + <amount>1251613262700</amount> + </credit> + </data> + <sig type="ed25519" keyid="3b54648d60bb8a5b9e84fa0057f79b3a5996e511682e80176dc948dcbff5a4fc">603bf1bf05951f1c78e3ba9ab430e914f73f03b6570c15cb241695393e57eb178029ba1ff0f86afa5f29ea10ea49418825e387feb8d03f79280593e4598b1b0d</sig> + </entry> +</ledger> +@end example + +@section Ledger after last entry + +@example +<?xml version="1.0"?> +<ledger xmlns="http://usawa.defalsify.org/" version="1"> + <topic xmlns:ns="http://usawa.defalsify.org/">24448167713e4f7d7e09fd06716b17ffcbd8bd10aa2ebbaac0a0902292993a86244acb9683c7dc45500daf1193a760b87de6fadd0f7b30c1a7b63ac06c555ca8</topic> + <generated xmlns:ns="http://usawa.defalsify.org/">2026-01-20T09:32:09Z</generated> + <src xmlns:ns="http://usawa.defalsify.org/">defalsify.org</src> + <units xmlns:ns="http://usawa.defalsify.org/" base="BTC"> + <unit sym="BTC"> + <precision>2</precision> + <exchange>1000000000</exchange> + </unit> + </units> + <identity xmlns:ns="http://usawa.defalsify.org/" keyid="3b54648d60bb8a5b9e84fa0057f79b3a5996e511682e80176dc948dcbff5a4fc" didtype="usawa"/> + <incoming xmlns:ns="http://usawa.defalsify.org/" serial="1"> + <real unit="BTC"> + <asset>2346300</asset> + <liability>0</liability> + </real> + <digest algo="sha512">50740013c78726ddd4fd199bbe21ad3eb3c50dcfd3540e12c5b52151a9b9f3a41346a22a2d1928dfc5749faac332a8c15ff2f545e8ff92b07aa037c39b1ba93e</digest> + </incoming> + <entry> + <data> + <parent>50740013c78726ddd4fd199bbe21ad3eb3c50dcfd3540e12c5b52151a9b9f3a41346a22a2d1928dfc5749faac332a8c15ff2f545e8ff92b07aa037c39b1ba93e</parent> + <ref>182536c7-f2ce-4976-af2a-6b0d2cf10e0c</ref> + <serial>2</serial> + <date>2026-01-20</date> + <dateTimeRegistered>2026-01-20T09:29:40Z</dateTimeRegistered> + <description>wergagh</description> + <debit type="expense"> + <unit>BTC</unit> + <account>general</account> + <amount>-1251613262700</amount> + </debit> + <credit type="asset"> + <unit>BTC</unit> + <account>general</account> + <amount>1251613262700</amount> + </credit> + </data> + <sig type="ed25519" keyid="3b54648d60bb8a5b9e84fa0057f79b3a5996e511682e80176dc948dcbff5a4fc">603bf1bf05951f1c78e3ba9ab430e914f73f03b6570c15cb241695393e57eb178029ba1ff0f86afa5f29ea10ea49418825e387feb8d03f79280593e4598b1b0d</sig> + </entry> +</ledger> +@end example diff --git a/dummy/doc/protocol.texi b/dummy/doc/protocol.texi @@ -17,3 +17,8 @@ There should be more than one channel through which entries are published, and i All participants could be asked to follow both a @strong{nostr}@footnote{nostr is an ownerless, client- and server-agnostic protocol for publishing arbitrary content ("notes and other stuff"): @url{https://nostr.com/}} and an @emph{email mailist list}, that both would publish the full entry data as clearly defined data structures. Also, all participants would be encouraged to follow an @emph{EVM chain}@footnote{A list of EVM chains: @url{https://chainlist.org/}} that could publish the latest ledger state digest in the data field of a transaction. + + +@section Determining trust + + diff --git a/dummy/doc/xml.texi b/dummy/doc/xml.texi @@ -7,6 +7,7 @@ The XML schema is designed to allow embedding of all data necessary to verify in Order of elements are important in the XML document. The schema is cited in @ref{xml_schema, appendix A}. +@anchor{ledger_header} @section Ledger header The responsibility of the ledger header is to give the consumer the necessary resources to validate the entries in the ledger. @@ -17,8 +18,8 @@ It includes: @item The document version, indicating which version of schema to use. @item Topic, which uniquely identifies the legder instance. @item Generation date and time of the XML document. -@item Index of units of account used in the following entries. @ref{unit_index,Unix Index} -@item The public key identities whose signatures appear in the document. @ref{identity,Public Key Identities}. +@item Index of units of account used in the following entries. @xref{unit_index,Unit Index} +@item The public key identities whose signatures appear in the document. @xref{identity,Public Key Identities} and their trust details. @item Details on resolver services that can be used to expand assets references by digests. @xref{resolver, Resolvers} and @ref{assets, Referencing assets}. @item Ledger state, under the element @code{incoming}, defining the digest of the position of the entry chain the ledger document starts at. @xref{incoming, Ledger State}. @item Signatures that may authenticate the ledger state. @@ -29,7 +30,7 @@ It includes: An important feature of the header is to allow only a portion of the ledger's entries to appear in the document. -This is accomplished by populating the @code{digest} and @code{serial} values in the ledger state with those of the parent of the first entry listed. @xref{xml_example_trunc, Truncated XML example} for more details. +This is accomplished by populating the @code{digest} and @code{serial} values in the ledger state with those of the parent of the first entry listed. @xref{xml_example, The XML example} for more details. In order to list all entries in a ledger, the @code{digest} value should be the zero-digest (64 zero-value bytes), and with a @code{serial} of @code{0}. @@ -60,6 +61,3 @@ The entry representation also defines data necessary for the immutability chain @item The datetime when the transaction was registered in the ledger. @item A free-text description for the entry. @end itemize - - -@anchor{xml_example_trunc} diff --git a/dummy/tests/ledger.py b/dummy/tests/ledger.py @@ -85,7 +85,7 @@ class TestLedger(unittest.TestCase): o = Ledger(uidx) store = LedgerStore(self.store, ledger=o) store.start() - + wallet = DemoWallet() o.set_wallet(wallet) x = EntryPart(s, 'income', 'foo', 1337, debit=True) diff --git a/dummy/usawa/data/schema.xsd b/dummy/usawa/data/schema.xsd @@ -97,6 +97,14 @@ </xs:sequence> </xs:complexType> + <xs:complexType name="Permission"> + <xs:simpleContent> + <xs:extension base="xs:string"> + <xs:attribute name="flag" type="xs:positiveInteger" /> + </xs:extension> + </xs:simpleContent> + + </xs:complexType> <xs:complexType name="Identity"> <xs:simpleContent> <xs:extension base="xs:string"> @@ -120,7 +128,6 @@ <xs:element name="data" type="EntryData" /> <xs:element name="sig" type="Signature" minOccurs="1" maxOccurs="unbounded" /> </xs:sequence> - <!-- TODO: attribute enum --> </xs:complexType> <xs:complexType name="EntryData"> diff --git a/dummy/usawa/ledger.py b/dummy/usawa/ledger.py @@ -207,6 +207,7 @@ class Ledger: self.wallet = v if self.acl == None: self.acl = ACL.from_wallet(self.wallet) + self.apply_wallet() """ @@ -214,6 +215,12 @@ class Ledger: def apply_wallet(self): incoming = self.tree.find('incoming', namespaces=nsmap()) v = self.wallet.pubkey() + try: + self.sigs[v] + return + except KeyError: + pass + self.sigs[v] = b'' o = lxml.etree.Element(NSPREFIX + 'identity', nsmap=nsmap()) o.set('keyid', v.hex()) @@ -302,17 +309,19 @@ class Ledger: # TODO: move identity tree generation to wallet object identities = [] for tree_identity in self.tree.xpath('ns:identity', namespaces=ns): + keyid = tree_identity.get('keyid') + try: + self.sigs[keyid] + continue + except KeyError: + pass v = tree_identity.text - identities.append(v) + identities.append(keyid) identity = lxml.etree.SubElement(tree, NSPREFIX + 'identity', nsmap=nsmap()) identity.text = v - identity.set('keyid', tree_identity.get('keyid')) + identity.set('keyid', keyid) identity.set('didtype', tree_identity.get('didtype')) - if self.wallet != None: - if self.wallet.pubkey() not in identities: - self.apply_wallet() - if acl != None: for v in acl.pubkeys(binary=False): if v not in identities: @@ -326,7 +335,8 @@ class Ledger: incoming = lxml.etree.SubElement(tree, NSPREFIX + 'incoming', nsmap=nsmap()) incoming.set('serial', str(self.serial)) - + + # swap running and apply all bases self.running = {} incoming_old = self.tree.find('incoming', namespaces=nsmap()) @@ -452,6 +462,8 @@ class Ledger: except KeyError: logg.debug('no signature from {}'.format(k)) continue + if sig == None: + raise ValueError('Signature entry without signature value') wallet = DemoWallet(publickey=b) v = entry.sum() return wallet.verify(v[0], sig)