nostrdb

an unfairly fast embedded nostr database backed by lmdb
git clone git://jb55.com/nostrdb
Log | Files | Refs | Submodules | README | LICENSE

commit 860878c1662b1df65daaab78ea6118d7dd38ca04
parent b49cf0268181ccabca1f71686bfd39201ae35947
Author: William Casarin <jb55@jb55.com>
Date:   Sat, 23 Dec 2023 14:46:00 -0800

block: add bolt11 invoice encoding/decoding

Diffstat:
MMakefile | 2+-
Msrc/bolt11/bolt11.h | 1+
Asrc/invoice.c | 69+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/invoice.h | 20++++++++++++++++++++
Mtest.c | 42+++++++++++++++++++++++++++++++++++++++++-
5 files changed, 132 insertions(+), 2 deletions(-)

diff --git a/Makefile b/Makefile @@ -2,7 +2,7 @@ CFLAGS = -Wall -Wno-misleading-indentation -Wno-unused-function -Werror -O2 -g - HEADERS = deps/lmdb/lmdb.h deps/secp256k1/include/secp256k1.h src/sha256.h src/nostrdb.h src/cursor.h src/hex.h src/jsmn.h src/config.h src/sha256.h src/random.h src/memchr.h src/cpu.h $(C_BINDINGS) FLATCC_SRCS=deps/flatcc/src/runtime/json_parser.c deps/flatcc/src/runtime/verifier.c deps/flatcc/src/runtime/builder.c deps/flatcc/src/runtime/emitter.c deps/flatcc/src/runtime/refmap.c BOLT11_SRCS = src/bolt11/bolt11.c src/bolt11/bech32.c src/bolt11/tal.c src/bolt11/talstr.c src/bolt11/take.c src/bolt11/list.c src/bolt11/utf8.c src/bolt11/amount.c src/bolt11/hash_u5.c -SRCS = src/nostrdb.c src/sha256.c $(BOLT11_SRCS) $(FLATCC_SRCS) +SRCS = src/nostrdb.c src/sha256.c src/invoice.c $(BOLT11_SRCS) $(FLATCC_SRCS) LDS = $(OBJS) $(ARS) OBJS = $(SRCS:.c=.o) DEPS = $(OBJS) $(HEADERS) $(ARS) diff --git a/src/bolt11/bolt11.h b/src/bolt11/bolt11.h @@ -4,6 +4,7 @@ #include "short_types.h" #include "hash_u5.h" #include "list.h" +#include "amount.h" #include "node_id.h" //#include <secp256k1_recovery.h> diff --git a/src/invoice.c b/src/invoice.c @@ -0,0 +1,69 @@ + +#include "cursor.h" +#include "invoice.h" +#include "bolt11/bolt11.h" +#include "bolt11/amount.h" + +int ndb_encode_invoice(struct cursor *cur, struct bolt11 *invoice) { + if (!invoice->description && !invoice->description_hash) + return 0; + + if (!cursor_push_byte(cur, 1)) + return 0; + + // TODO: make cursor_cursor_push_varint uint64_t + if (!cursor_push_varint(cur, invoice->msat->millisatoshis)) + return 0; + + if (!cursor_push_varint(cur, invoice->timestamp)) + return 0; + + if (!cursor_push_varint(cur, invoice->expiry)) + return 0; + + if (invoice->description) { + if (!cursor_push_byte(cur, 1)) + return 0; + if (!cursor_push_c_str(cur, invoice->description)) + return 0; + } else { + if (!cursor_push_byte(cur, 2)) + return 0; + if (!cursor_push(cur, invoice->description_hash->u.u8, 32)) + return 0; + } + + return 1; +} + +int ndb_decode_invoice(struct cursor *cur, struct ndb_invoice *invoice) +{ + unsigned char desc_type; + if (!cursor_pull_byte(cur, &invoice->version)) + return 0; + + if (!cursor_pull_varint(cur, &invoice->amount)) + return 0; + + if (!cursor_pull_varint(cur, &invoice->timestamp)) + return 0; + + if (!cursor_pull_varint(cur, &invoice->expiry)) + return 0; + + if (!cursor_pull_byte(cur, &desc_type)) + return 0; + + if (desc_type == 1) { + if (!cursor_pull_c_str(cur, (const char**)&invoice->description)) + return 0; + } else if (desc_type == 2) { + invoice->description_hash = cur->p; + if (!cursor_skip(cur, 32)) + return 0; + } else { + return 0; + } + + return 1; +} diff --git a/src/invoice.h b/src/invoice.h @@ -0,0 +1,20 @@ + +#ifndef NDB_INVOICE_H +#define NDB_INVOICE_H + +struct bolt11; + +struct ndb_invoice { + unsigned char version; + uint64_t amount; + uint64_t timestamp; + uint64_t expiry; + char *description; + unsigned char *description_hash; +}; + +// ENCODING +int ndb_encode_invoice(struct cursor *cur, struct bolt11 *invoice); +int ndb_decode_invoice(struct cursor *cur, struct ndb_invoice *invoice); + +#endif /* NDB_INVOICE_H */ diff --git a/test.c b/test.c @@ -3,7 +3,7 @@ #include "hex.h" #include "io.h" #include "bolt11/bolt11.h" -#include "bolt11/amount.h" +#include "invoice.h" #include "protected_queue.h" #include "memchr.h" #include "print_util.h" @@ -108,6 +108,45 @@ static void test_filters() ndb_filter_free(f); } +static void test_invoice_encoding(const char *bolt11_str) +{ + unsigned char buf[4096]; + char *fail = NULL; + struct cursor cur; + struct ndb_invoice invoice; + struct bolt11 *bolt11; + + bolt11 = bolt11_decode(NULL, bolt11_str, &fail); + make_cursor(buf, buf + sizeof(buf), &cur); + + assert(fail == NULL); + assert(ndb_encode_invoice(&cur, bolt11)); + cur.p = cur.start; + assert(ndb_decode_invoice(&cur, &invoice)); + + assert(bolt11->msat->millisatoshis == invoice.amount); + assert(bolt11->timestamp == invoice.timestamp); + assert(bolt11->expiry == invoice.expiry); + + if (bolt11->description != NULL && invoice.description != NULL) + assert(!strcmp(bolt11->description, invoice.description)); + else if (bolt11->description_hash != NULL && invoice.description_hash != NULL) + assert(!memcmp(bolt11->description_hash->u.u8, invoice.description_hash, 32)); + else + assert(0); + + tal_free(bolt11); +} + +static void test_encode_decode_invoice() +{ + const char *deschash = "lnbc12n1pjctuljsp57l6za0xry37prkrz7vuv4324ljnssm8ukr2vrf6qvvrgclsmpyhspp5xqfuk89duzjlt2yg56ym7p3enrfxxltyfpc364qc8nsu3kznkl8shp5eugmd894yph7wq68u09gke5x2hmn7mg3zrwd06fs57gmcrjm0uxsxqyjw5qcqpjrzjqd7yw3w4kvhx8uvcj7qusfw4uqre3j56zjz9t07nd2u55yuya3awsrqdlcqqdzcqqqqqqqqqqqqqqzqqyg9qxpqysgqwm2tsc448ellvf5xem2c95hfvc07lakph9r8hffh704uxqhs22r9s4ly0jel48zv6f7fy8zjkgmjt5h2l4jc9gyj4av42s40qvve2ysqwuega8"; + const char *desc = "lnbc12u1pjctuklsp5lg8wdhq2g5xfphkqd5k6gf0femt06wfevu94uuqfprc4ggyqma7spp54lmpmz0mhv3lczepdckr0acf3gdany2654u4k2s8fp5xh0yanjhsdq5w3jhxapdd9h8vmmfvdjsxqyjw5qcqpjrzjqgtsq68q0s9wdadpg32gcfu7hslgkhdpaysj2ha3dtnm8882wa6jyzahpqqqpsgqqyqqqqlgqqqqqpsq9q9qxpqysgqdqzhl8gz46nmalhg27stl25z2u7mqtclv3zz223mjwut90m24fa46xqprjewsqys78j2uljfznz5vtefctu6fw7375ee66e62tj965gpcs85tc"; + + test_invoice_encoding(deschash); + test_invoice_encoding(desc); +} + // Test fetched_at profile records. These are saved when new profiles are // processed, or the last time we've fetched the profile. static void test_fetched_at() @@ -1021,6 +1060,7 @@ static int test_varints() { int main(int argc, const char *argv[]) { test_varints(); + test_encode_decode_invoice(); test_filters(); //test_migrate(); test_fetched_at();