commit 93843d782e4979521d213e8c3cd2e482e63e2d4e
parent f5754dc907aa1afa7015fe0e5767a528feb10ec1
Author: lash <dev@holbrook.no>
Date:   Mon, 29 Apr 2024 20:41:34 +0100
Add ledger put
Diffstat:
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)
-