kee

Offline IOU signer with QR as transport
git clone https://holbrook.no/src/kee
Info | Log | Files | Refs | README | LICENSE

commit 96539f09287c86af39108d0f06c5a0e889e46657
parent a299c44d845108efa5f53e7e0f97c9b113823c8f
Author: lash <dev@holbrook.no>
Date:   Wed, 27 Mar 2024 17:38:02 +0000

WIP entry edit and data generation

Diffstat:
MMakefile | 4++++
Arequirements.txt | 2++
Asrc/gtk/kee-entry.c | 26++++++++++++++++++++++++++
Asrc/gtk/kee-entry.h | 19+++++++++++++++++++
Mtestdata.py | 289+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------
5 files changed, 298 insertions(+), 42 deletions(-)

diff --git a/Makefile b/Makefile @@ -22,3 +22,7 @@ debug: gtk all test: gtk all make -C src/gtk/tests + +testdata: + rm -vrf testdata_mdb + python testdata.py diff --git a/requirements.txt b/requirements.txt @@ -0,0 +1,2 @@ +varint~=1.0.2 +lmdb~=1.4.0 diff --git a/src/gtk/kee-entry.c b/src/gtk/kee-entry.c @@ -0,0 +1,26 @@ +#include <glib-object.h> +#include <gtk/gtk.h> + +#include "kee-entry.h" +#include "db.h" +#include "err.h" + +typedef struct { +} KeeEntryPrivate; + +struct _KeeEntry { + GtkWidget parent; + char *current_id; +}; + +G_DEFINE_TYPE(KeeEntry, kee_entry, GTK_TYPE_BOX); + +static void kee_entry_class_init(KeeEntryClass *kls) { +} + +static void kee_entry_init(KeeEntry *o) { +} + +int kee_entry_load(KeeEntry *o, struct db_ctx *db, const char *id) { + return ERR_OK; +} diff --git a/src/gtk/kee-entry.h b/src/gtk/kee-entry.h @@ -0,0 +1,19 @@ +#ifndef _GTK_KEE_ENTRY_H +#define _GTK_KEE_ENTRY_H + +#include <glib-object.h> +#include <gtk/gtk.h> + +#include "db.h" + +G_BEGIN_DECLS + +#define KEE_TYPE_ENTRY kee_entry_get_type() +G_DECLARE_FINAL_TYPE(KeeEntry, kee_entry, KEE, ENTRY, GtkBox); + +int kee_entry_load(KeeEntry *o, struct db_ctx *db, const char *id); + +G_END_DECLS + + +#endif //_GTK_KEE_ENTRY_H diff --git a/testdata.py b/testdata.py @@ -1,56 +1,261 @@ -import lmdb import tempfile import logging import os import shutil import hashlib +import sys +import io +import random +import time + +import lmdb +import varint + +FLAGS_RESULT = 1 << 0 +FLAGS_FIRST = 1 << 1 +FLAGS_CREDIT_DELTA_NEGATIVE = 1 << 2 +FLAGS_COLLATERAL_DELTA_NEGATIVE = 1 << 2 +FLAGS_SIGNER_IS_GIVER = 1 << 6 +FLAGS_BODY_STRING = 1 << 7 +NOBODY = b'\x00' * 64 +NOSIG = b'\x00' * 65 +PFX_LEDGER_HEAD = b'\x01' +PFX_LEDGER_ENTRY = b'\x02' logging.basicConfig(level=logging.DEBUG) logg = logging.getLogger() -d = os.path.dirname(__file__) -d = os.path.join(d, 'testdata_mdb') -logg.info('using ' + d) -try: - shutil.rmtree(d) -except FileNotFoundError: - pass -os.makedirs(d) -env = lmdb.open(d) -dbi = env.open_db() +def db_init(d): + d = os.path.join(d, 'testdata_mdb') + logg.info('using d for db' + d) + + try: + shutil.rmtree(d) + except FileNotFoundError: + pass + os.makedirs(d) + return d + + +def to_absflag(v): + flag = False + if v < 0: + flag = True + return (abs(v), flag,) + + +class LedgerHead: + + def __init__(self, body=NOBODY): + self.uoa = "USD" + self.uoa_decimals = 2 + self.taker_pubkey_ref = b'\x00' * 64 + self.giver_pubkey_ref = b'\x00' * 64 + self.body = body + + + def __serialize_add(self, b, w): + c = varint.encode(len(b)) + w.write(c) + w.write(b) + + + def serialize(self, w=sys.stdout.buffer): + b = self.uoa.encode('utf-8') + self.__serialize_add(b, w) + + b = varint.encode(self.uoa_decimals) + self.__serialize_add(b, w) + + b = self.taker_pubkey_ref + self.__serialize_add(b, w) + + b = self.giver_pubkey_ref + self.__serialize_add(b, w) + + b = self.body + self.__serialize_add(b, w) + + + @staticmethod + def to_key(b): + r = b'' + r += PFX_LEDGER_HEAD + v = time.time_ns() + b = v.to_bytes(8, byteorder='big') + r += b + + return r + + +class LedgerEntry: + + credit_delta_min = -1000 + credit_delta_max = 1000 + collateral_delta_min = 0 + collateral_delta_max = 0 + + def __init__(self, head, parent=None, body=NOBODY, signer=None): + self.head = head + self.flags = 0 + self.parent = parent + if self.parent != None: + self.flags |= FLAGS_FIRST + else: + self.parent = head + self.timestamp = time.time_ns() + + self.body = body + + v = random.randint(self.credit_delta_min, self.credit_delta_max) + (v, neg) = to_absflag(v) + self.credit_delta = v + if neg: + self.flags |= FLAGS_CREDIT_DELTA_NEGATIVE + + v = random.randint(self.collateral_delta_min, self.collateral_delta_max) + (v, neg) = to_absflag(v) + self.collateral_delta = v + if neg: + self.flags |= FLAGS_COLLATERAL_DELTA_NEGATIVE + + self.signature = NOSIG + self.signer = signer + + + def __serialize_add(self, b, w): + c = varint.encode(len(b)) + w.write(c) + w.write(b) + + + def serialize(self, w=sys.stdout.buffer): + b = self.flags.to_bytes(1) + self.__serialize_add(b, w) + + b = self.parent + self.__serialize_add(b, w) + + b = self.timestamp.to_bytes(8, byteorder='big') + self.__serialize_add(b, w) + + realvalue = self.credit_delta + if (self.flags & FLAGS_CREDIT_DELTA_NEGATIVE): + realvalue *= -1 + logg.debug('encoding credit delta {}'.format(realvalue)) + b = varint.encode(self.credit_delta) + self.__serialize_add(b, w) + + logg.debug('encoding collateral delta {}'.format(self.collateral_delta)) + b = varint.encode(self.collateral_delta) + self.__serialize_add(b, w) + + self.__serialize_add(self.body, w) + + if self.signer != None: + self.signature = self.signer(b) + + return b + + + @staticmethod + def to_key(v, k): + r = b'' + r += PFX_LEDGER_ENTRY + r += k + ts = v[65:65+8] + logg.debug('ts {}: of {}'.format(ts.hex(), v.hex())) + r += ts + return r + + +def generate_entry(head, parent): + o = LedgerEntry(head, parent=parent) + w = io.BytesIO() + r = o.serialize(w=w) + h = hashlib.new('sha512') + b = w.getvalue() + h.update(b) + z = h.digest() + return (z, b,) + + +def generate_ledger(entry_count=3): + r = [] + o = LedgerHead() + w = io.BytesIO() + o.serialize(w=w) + h = hashlib.new('sha512') + b = w.getvalue() + h.update(b) + z = h.digest() + r.append((z, b,)) + + k = z + parent = None + for i in range(entry_count): + v = generate_entry(k, parent=parent) + # \todo generate key value already here + parent = v[0] + r.append(v) + + return r + + +if __name__ == '__main__': + d = os.path.dirname(__file__) + d = db_init(d) + + env = lmdb.open(d) + dbi = env.open_db() + + with env.begin(write=True) as tx: + c = random.randint(1, 20) + r = generate_ledger(entry_count=c) + + v = r.pop(0) + + z = v[0] + k = LedgerHead.to_key(v[0]) + tx.put(k, v[1]) + + for v in r: + k = LedgerEntry.to_key(v[1], z) + tx.put(k, v[1]) + #pfx = b'\x00\x00\x00' #pfx_two = b'\x00\x00\x01' -keys = [] -vals = [ - b"\x03foo\x03bar", - b"\x05xyzzy\x05plugh", - b"\x04inky\x05pinky", - b"\x06blinky\x05clyde", - ] - -for i in range(len(vals)): - k = b'\x01' + i.to_bytes(16, 'big') - #k += os.urandom(32) - h = hashlib.sha256() - h.update(vals[i]) - k += h.digest() - keys.append(k) - -with env.begin(write=True) as tx: - for i in range(len(vals)): - v = i.to_bytes(2, byteorder='big') - tx.put(keys[i], vals[i]) - #tx.put(keys[i], vals[i].encode('utf-8')) - #tx.put(pfx + v, vals[i].encode('utf-8')) - #tx.put(pfx_two + b'\x00\x00', b'xyzzy') - #tx.put(pfx_two + b'\x00\x01', b'plugh') - -with env.begin() as tx: - c = tx.cursor() - #if not c.set_range(b'\x00\x00\x01'): - # raise ValueError("no key") - for k, v in c: - logg.debug('have {} {}'.format(k, v)) +#keys = [] +#vals = [ +# b"\x03foo\x03bar", +# b"\x05xyzzy\x05plugh", +# b"\x04inky\x05pinky", +# b"\x06blinky\x05clyde", +# ] +# +#for i in range(len(vals)): +# k = b'\x01' + i.to_bytes(16, 'big') +# #k += os.urandom(32) +# h = hashlib.sha256() +# h.update(vals[i]) +# k += h.digest() +# keys.append(k) +# +#with env.begin(write=True) as tx: +# for i in range(len(vals)): +# v = i.to_bytes(2, byteorder='big') +# tx.put(keys[i], vals[i]) +# #tx.put(keys[i], vals[i].encode('utf-8')) +# #tx.put(pfx + v, vals[i].encode('utf-8')) +# #tx.put(pfx_two + b'\x00\x00', b'xyzzy') +# #tx.put(pfx_two + b'\x00\x01', b'plugh') +# +#with env.begin() as tx: +# c = tx.cursor() +# #if not c.set_range(b'\x00\x00\x01'): +# # raise ValueError("no key") +# for k, v in c: +# logg.debug('have {} {}'.format(k, v))