kee

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

commit 93843d782e4979521d213e8c3cd2e482e63e2d4e
parent f5754dc907aa1afa7015fe0e5767a528feb10ec1
Author: lash <dev@holbrook.no>
Date:   Mon, 29 Apr 2024 20:41:34 +0100

Add ledger put

Diffstat:
Msrc/db.c | 130+++++++++++++++++++++++++++++++++++++++++++------------------------------------
Msrc/db.h | 4+++-
Msrc/gtk/kee-entry.c | 1-
Msrc/ledger.c | 91++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---
Msrc/ledger.h | 3+++
Msrc/term_debug.c | 6+++---
Msrc/tests/debug.c | 2+-
Msrc/tests/ledger.c | 26++++++++++++++++++++++++++
Msrc/tests/testutil.c | 20++++++++++++++++++++
Msrc/tests/testutil.h | 3+++
Mtestdata_asn1.py | 4+++-
11 files changed, 221 insertions(+), 69 deletions(-)

diff --git a/src/db.c b/src/db.c @@ -29,97 +29,109 @@ int db_connect(struct db_ctx *ctx, char *conn) { return ERR_OK; } -/** - * \todo split up and optimize - */ -int db_put(struct db_ctx *ctx, enum DbKey pfx, char *data, size_t data_len) { + +/// \todo atomic tx put +int db_put(struct db_ctx *ctx, char *key, size_t key_len, char *data, size_t data_len) { int r; - char *buf; - char buf_reverse[33]; - unsigned char *rv; - char kv; - struct timespec ts; - char rts[sizeof(struct timespec)]; - gcry_error_t e; - gcry_md_hd_t h; MDB_txn *tx; MDB_dbi dbi; MDB_val k; MDB_val v; - buf = (char*)malloc(1 + 32 + sizeof(struct timespec)); // length should be lookup in sizes array for each key - - r = clock_gettime(CLOCK_REALTIME, &ts); - if (r) { - free(buf); - return ERR_FAIL; - } - memcpy(rts, &ts.tv_sec, sizeof(ts.tv_sec)); - memcpy(rts + sizeof(ts.tv_sec), &ts.tv_nsec, sizeof(ts.tv_nsec)); - to_endian(0, sizeof(ts.tv_sec), rts); - to_endian(0, sizeof(ts.tv_nsec), rts + sizeof(ts.tv_sec)); - - e = gcry_md_open(&h, GCRY_MD_SHA256, 0); - if (e) { - free(buf); - return ERR_DIGESTFAIL; - } - gcry_md_write(h, data, data_len); - rv = gcry_md_read(h, 0); - kv = (char)pfx; - memcpy(buf, &kv, 1); - memcpy(buf + 1, rts, sizeof(struct timespec)); - memcpy(buf + 1 + sizeof(struct timespec), rv, 32); - r = mdb_txn_begin(ctx->env, NULL, 0, &tx); if (r) { - free(buf); return ERR_FAIL; } r = mdb_dbi_open(tx, NULL, MDB_CREATE, &dbi); if (r) { - free(buf); return ERR_FAIL; } - k.mv_data = buf; - k.mv_size = 1 + 32 + sizeof(struct timespec); + k.mv_data = key; + k.mv_size = key_len; v.mv_data = data; v.mv_size = data_len; r = mdb_put(tx, dbi, &k, &v, 0); if (r) { - free(buf); - return ERR_FAIL; - } - - // put reverse lookup - buf_reverse[0] = (char)DbKeyReverse; - memcpy(buf_reverse+1, rv, 32); - k.mv_data = buf_reverse; - k.mv_size = 33; - v.mv_data = buf; - v.mv_size = 1 + 32 + sizeof(struct timespec); - gcry_md_close(h); // keep the handle open until here because we use its digest value again for the key - - r = mdb_put(tx, dbi, &k, &v, 0); - if (r) { - free(buf); return ERR_FAIL; } r = mdb_txn_commit(tx); if (r) { - free(buf); return ERR_FAIL; } - free(buf); return ERR_OK; - } +///** +// * \todo split up and optimize +// */ +//int db_put(struct db_ctx *ctx, enum DbKey pfx, char *data, size_t data_len) { +// int r; +// char *buf; +// char buf_reverse[33]; +// unsigned char *rv; +// char kv; +// struct timespec ts; +// char rts[sizeof(struct timespec)]; +// gcry_error_t e; +// gcry_md_hd_t h; +// +// buf = (char*)malloc(1 + 32 + sizeof(struct timespec)); // length should be lookup in sizes array for each key +// +// r = clock_gettime(CLOCK_REALTIME, &ts); +// if (r) { +// free(buf); +// return ERR_FAIL; +// } +// memcpy(rts, &ts.tv_sec, sizeof(ts.tv_sec)); +// memcpy(rts + sizeof(ts.tv_sec), &ts.tv_nsec, sizeof(ts.tv_nsec)); +// to_endian(0, sizeof(ts.tv_sec), rts); +// to_endian(0, sizeof(ts.tv_nsec), rts + sizeof(ts.tv_sec)); +// +// e = gcry_md_open(&h, GCRY_MD_SHA256, 0); +// if (e) { +// free(buf); +// return ERR_DIGESTFAIL; +// } +// gcry_md_write(h, data, data_len); +// rv = gcry_md_read(h, 0); +// kv = (char)pfx; +// memcpy(buf, &kv, 1); +// memcpy(buf + 1, rts, sizeof(struct timespec)); +// memcpy(buf + 1 + sizeof(struct timespec), rv, 32); +// +// +// +// // put reverse lookup +// buf_reverse[0] = (char)DbKeyReverse; +// memcpy(buf_reverse+1, rv, 32); +// k.mv_data = buf_reverse; +// k.mv_size = 33; +// v.mv_data = buf; +// v.mv_size = 1 + 32 + sizeof(struct timespec); +// gcry_md_close(h); // keep the handle open until here because we use its digest value again for the key +// +// r = mdb_put(tx, dbi, &k, &v, 0); +// if (r) { +// free(buf); +// return ERR_FAIL; +// } +// +// r = mdb_txn_commit(tx); +// if (r) { +// free(buf); +// return ERR_FAIL; +// } +// free(buf); +// +// return ERR_OK; +// +//} + /** * * \todo change cursor to jump to new search match when current (last) prefix does not match lookup prefix. diff --git a/src/db.h b/src/db.h @@ -15,6 +15,7 @@ enum DbErr { ERR_DB_FAIL = 1, ERR_DB_NOMATCH, + ERR_DB_EXISTS, ERR_DB_INVALID, }; @@ -54,7 +55,8 @@ struct db_ctx { }; int db_connect(struct db_ctx *ctx, char *conn); -int db_put(struct db_ctx *ctx, enum DbKey pfx, char *data, size_t data_len); +//int db_put(struct db_ctx *ctx, enum DbKey pfx, char *data, size_t data_len); +int db_put(struct db_ctx *ctx, char *key, size_t key_len, char *data, size_t data_len); int db_next(struct db_ctx *ctx, enum DbKey pfx, char **key, size_t *key_len, char **value, size_t *value_len); void db_rewind(struct db_ctx *ctx); void db_reset(struct db_ctx *ctx); diff --git a/src/gtk/kee-entry.c b/src/gtk/kee-entry.c @@ -81,7 +81,6 @@ static void kee_entry_handle_add(GtkButton *butt, KeeEntry *o) { struct kee_ledger_item_t *item; GtkEntryBuffer *buf; char *b; - size_t c; struct kee_transport_t trans; char *out; size_t out_len; diff --git a/src/ledger.c b/src/ledger.c @@ -136,7 +136,7 @@ static int verify_item(struct kee_ledger_t *ledger, asn1_node item, const char * if (r) { return 1; } - debug_log(DEBUG_DEBUG, "ledger item verified\n"); + debug_log(DEBUG_DEBUG, "ledger item verified"); } // c = 0; @@ -202,9 +202,10 @@ void kee_ledger_item_apply_cache(struct kee_ledger_t *ledger, struct kee_ledger_ } ledger->cache->alice_credit_balance += item->alice_credit_delta; - ledger->cache->bob_credit_balance += item->bob_credit_delta; ledger->cache->alice_collateral_balance += item->alice_collateral_delta; + ledger->cache->bob_credit_balance += item->bob_credit_delta; ledger->cache->bob_collateral_balance += item->bob_collateral_delta; + ledger->cache->count++; } @@ -220,7 +221,7 @@ struct kee_ledger_item_t *kee_ledger_add_item(struct kee_ledger_t *ledger) { struct kee_ledger_item_t *prev; prev = ledger->last_item; - ledger->last_item = malloc(sizeof(struct kee_ledger_item_t)); + ledger->last_item = calloc(sizeof(struct kee_ledger_item_t), 1); kee_ledger_item_init(ledger->last_item); ledger->last_item->prev_item = prev; @@ -798,6 +799,8 @@ int kee_ledger_parse_open(struct kee_ledger_t *ledger, char *in, size_t in_len) struct kee_ledger_item_t *item; char is_bob; + kee_ledger_init(ledger); + memset(&root, 0, sizeof(root)); memset(&pair, 0, sizeof(root)); r = asn1_array2tree(schema_entry_asn1_tab, &root, err); @@ -862,3 +865,85 @@ int kee_ledger_parse_open(struct kee_ledger_t *ledger, char *in, size_t in_len) return ERR_OK; } + +static size_t ledger_db_key(char *out) { + int r; + char *p; + struct timespec ts; + unsigned int sec; + unsigned int nsec; + + *out = DbKeyLedgerHead; + p = out + 1; + + r = clock_gettime(CLOCK_REALTIME, &ts); + if (r) { + return 0; + } + + sec = (unsigned int)ts.tv_sec; + nsec = (unsigned int)ts.tv_nsec; + + memcpy(p, &sec, sizeof(sec)); + memcpy(p + sizeof(sec), &nsec, sizeof(nsec)); + to_endian(TO_ENDIAN_BIG, sizeof(sec), p); + to_endian(TO_ENDIAN_BIG, sizeof(nsec), p + sizeof(sec)); + return sizeof(sec) + sizeof(nsec) + 1; +} + +int kee_ledger_put(struct kee_ledger_t *ledger, struct db_ctx *db) { + int r; + size_t c; + size_t l; + char mem[1024]; + char *k; + char *v; + + k = (char*)mem; + v = ((char*)mem)+96; + + k[0] = DbKeyReverse; + memcpy(((char*)k)+1, ledger->digest, DIGEST_LENGTH); + l = DIGEST_LENGTH + 1; + c = 928; // 1024 - 96 + db_rewind(db); + r = db_next(db, DbKeyReverse, &k, &l, &v, &c); + if (!r) { + k = v; + l = c; + c = 928; + db_rewind(db); + r = db_next(db, DbKeyLedgerHead, &k, &l, &v, &c); + if (!r) { + return ERR_DB_EXISTS; + } + } + + l = ledger_db_key(k); + if (l == 0) { + return ERR_FAIL; + } + + c = 928; + r = kee_ledger_serialize(ledger, v, &c); + if (r) { + return ERR_DB_FAIL; + } + + r = db_put(db, k, l, v, c); + if (r) { + return ERR_DB_FAIL; + } + + memcpy(v, k, l); + c = l; + l = DIGEST_LENGTH + 1; + *k = DbKeyReverse; + memcpy(k+1, ledger->digest, DIGEST_LENGTH); + r = db_put(db, k, l, v, c); + if (r) { + return ERR_DB_FAIL; + } + + return ERR_OK; +} diff --git a/src/ledger.h b/src/ledger.h @@ -6,6 +6,7 @@ #include "content.h" #include "cadiz.h" #include "gpg.h" +#include "db.h" enum kee_initiator_e { ALICE, @@ -66,5 +67,7 @@ void kee_ledger_item_init(struct kee_ledger_item_t *item); int kee_ledger_item_serialize(struct kee_ledger_item_t *item, char *out, size_t *out_len, enum kee_item_serialize_mode_e mode); int kee_ledger_serialize_open(struct kee_ledger_t *ledger, char *out, size_t *out_len); int kee_ledger_parse_open(struct kee_ledger_t *ledger, char *in, size_t in_len); +int kee_ledger_put(struct kee_ledger_t *ledger, struct db_ctx *db); + #endif diff --git a/src/term_debug.c b/src/term_debug.c @@ -2,6 +2,6 @@ #include "debug.h" -void debugLog(enum debugLevel level, const char *s) { - fprintf(stderr, "%d: %s\n", level, s); -} +//void debug_log(enum debugLevel level, const char *s) { +// fprintf(stderr, "%d: %s\n", level, s); +//} diff --git a/src/tests/debug.c b/src/tests/debug.c @@ -3,5 +3,5 @@ #include "debug.h" void debug_log(enum debugLevel level, const char *s) { - fprintf(stderr, s); + fprintf(stderr, "%s\n", s); } diff --git a/src/tests/ledger.c b/src/tests/ledger.c @@ -402,6 +402,28 @@ int test_pair() { return 0; } +int test_put() { + int r; + struct kee_test_t t; + + r = kee_test_generate(&t); + if (r) { + return 1; + } + + r = kee_test_db(&t); + if (r) { + return 1; + } + + r = kee_ledger_put(&t.ledger, &t.db); + if (r) { + return 1; + } + + return 0; +} + int main() { int r; @@ -425,6 +447,10 @@ int main() { if (r) { return 1; } + r = test_put(); + if (r) { + return 1; + } return 0; } diff --git a/src/tests/testutil.c b/src/tests/testutil.c @@ -8,7 +8,26 @@ #include "err.h" #include "content.h" #include "digest.h" +#include "db.h" +int kee_test_db(struct kee_test_t *t) { + int r; + char *p; + char path[64]; + + strcpy(path, "/tmp/keetest_db_XXXXXX"); + p = mkdtemp(path); + if (p == NULL) { + return 1; + } + + r = db_connect(&t->db, p); + if (r) { + return 1; + } + + return 0; +} int kee_test_generate(struct kee_test_t *t) { int r; @@ -85,6 +104,7 @@ int kee_test_generate(struct kee_test_t *t) { return 1; } + /// \todo oh dear, they are serialized as platform endian, should be big. item = kee_ledger_add_item(&t->ledger); item->alice_credit_delta = 666; item->bob_credit_delta = -42; diff --git a/src/tests/testutil.h b/src/tests/testutil.h @@ -4,6 +4,7 @@ #include <gcrypt.h> #include "ledger.h" +#include "db.h" static const char *content_test = "Subject: foo\n\nsome content\n"; static const char *content_test_item = "Subject: bar\n\nsome other content\n"; @@ -23,6 +24,7 @@ struct kee_test_t { char ledger_item_bytes[1024]; size_t ledger_item_bytes_len; size_t item_count; + struct db_ctx db; }; int kee_test_generate(struct kee_test_t *t); @@ -30,5 +32,6 @@ int kee_test_ledger_data(struct kee_test_t *t); void kee_test_free(struct kee_test_t *t); size_t kee_test_get_ledger_data(struct kee_test_t *t, char **out); size_t kee_test_get_ledger_item_data(struct kee_test_t *t, int idx, char **out); +int kee_test_db(struct kee_test_t *t); #endif diff --git a/testdata_asn1.py b/testdata_asn1.py @@ -479,6 +479,9 @@ if __name__ == '__main__': z = v[0] k = LedgerHead.to_key(v[0]) tx.put(k, v[1]) + # reverse lookup + kr = b'\xff' + v[0] + tx.put(kr, k[1:]) for v in r: k = LedgerEntry.to_key(v[1], z) @@ -488,4 +491,3 @@ if __name__ == '__main__': pubk = signer.get_pubkey(k) name = signer.get_name(k).encode('utf-8') tx.put(PFX_LEDGER_PUBKEY + pubk, b'CN=' + name) -