nostrdb

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

commit 40d3a7069fec8e54f88a23a6398f45478aeb36f7
parent c4d8fc63a9a367643dc080bd3f3fac89c3640c4e
Author: William Casarin <jb55@jb55.com>
Date:   Thu, 28 Dec 2023 16:11:29 -0800

parser: fix bech32 block decoding

Diffstat:
Msrc/block.c | 34++++++++++++++++++++++++----------
Msrc/content_parser.c | 8++++----
Msrc/nostr_bech32.c | 16++++++++++------
Msrc/nostr_bech32.h | 66+-----------------------------------------------------------------
Msrc/nostrdb.h | 71+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mtest.c | 34++++++++++++++++++++++++++++++++--
6 files changed, 142 insertions(+), 87 deletions(-)

diff --git a/src/block.c b/src/block.c @@ -32,7 +32,7 @@ static int pull_nostr_bech32_type(struct cursor *cur, enum nostr_bech32_type *ty if (!cursor_pull_varint(cur, &inttype)) return 0; - if (inttype > NOSTR_BECH32_KNOWN_TYPES) + if (inttype <= 0 || inttype > NOSTR_BECH32_KNOWN_TYPES) return 0; *type = inttype; @@ -43,9 +43,7 @@ static int pull_nostr_bech32_type(struct cursor *cur, enum nostr_bech32_type *ty static int pull_bech32_mention(const char *content, struct cursor *cur, struct ndb_mention_bech32_block *block) { uint16_t size; unsigned char *start; - enum nostr_bech32_type type; - - start = cur->p; + struct cursor bech32; if (!pull_str_block(cur, content, &block->str)) return 0; @@ -53,12 +51,17 @@ static int pull_bech32_mention(const char *content, struct cursor *cur, struct n if (!cursor_pull_u16(cur, &size)) return 0; - if (!pull_nostr_bech32_type(cur, &type)) + if (!pull_nostr_bech32_type(cur, &block->bech32.type)) return 0; - if (!parse_nostr_bech32_buffer(cur, type, &block->bech32)) + make_cursor(cur->p, cur->p + size, &bech32); + + start = cur->p; + + if (!parse_nostr_bech32_buffer(&bech32, block->bech32.type, &block->bech32)) return 0; + //assert(bech32.p == start + size); cur->p = start + size; return 1; } @@ -153,10 +156,11 @@ void ndb_blocks_iterate_free(struct ndb_block_iterator *iter) struct ndb_block *ndb_blocks_iterate_next(struct ndb_block_iterator *iter) { while (iter->cur.p < iter->cur.end) { - if (!pull_block(iter->content, &iter->cur, &iter->block)) + if (!pull_block(iter->content, &iter->cur, &iter->block)) { return NULL; - else + } else { return &iter->block; + } } return NULL; @@ -180,5 +184,15 @@ struct ndb_str_block *ndb_block_str(struct ndb_block *block) return NULL; } -//const char *ndb_str_block_ptr(struct ndb_str_block *); -//uint32_t ndb_str_block_len(struct ndb_str_block *); + +const char *ndb_str_block_ptr(struct ndb_str_block *str_block) { + return str_block->str; +} + +uint32_t ndb_str_block_len(struct ndb_str_block *str_block) { + return str_block->len; +} + +struct nostr_bech32 *ndb_bech32_block(struct ndb_block *block) { + return &block->block.mention_bech32.bech32; +} diff --git a/src/content_parser.c b/src/content_parser.c @@ -119,15 +119,15 @@ static int push_bech32_mention(struct ndb_content_parser *p, struct ndb_str_bloc // make sure to push the str block! if (!push_str_block(&p->buffer, (const char*)p->content.start, bech32)) goto fail; - - if (!cursor_push_varint(&p->buffer, type)) - goto fail; - + // // save a spot for the raw bech32 buffer size u8_size = (uint16_t*)p->buffer.p; if (!cursor_skip(&p->buffer, 2)) goto fail; + if (!cursor_push_varint(&p->buffer, type)) + goto fail; + if (!cursor_malloc_slice(&p->buffer, &u8, bech32->len)) goto fail; diff --git a/src/nostr_bech32.c b/src/nostr_bech32.c @@ -88,11 +88,11 @@ static int parse_nostr_bech32_nsec(struct cursor *cur, struct bech32_nsec *nsec) return pull_bytes(cur, 32, &nsec->nsec); } -static int add_relay(struct relays *relays, struct nostr_tlv *tlv) +static int add_relay(struct ndb_relays *relays, struct nostr_tlv *tlv) { struct ndb_str_block *str; - if (relays->num_relays + 1 > MAX_RELAYS) + if (relays->num_relays + 1 > NDB_MAX_RELAYS) return 0; str = &relays->relays[relays->num_relays++]; @@ -116,11 +116,13 @@ static int parse_nostr_bech32_nevent(struct cursor *cur, struct bech32_nevent *n switch (tlv.type) { case TLV_SPECIAL: - if (tlv.len != 32) return 0; + if (tlv.len != 32) + return 0; nevent->event_id = tlv.value; break; case TLV_AUTHOR: - if (tlv.len != 32) return 0; + if (tlv.len != 32) + return 0; nevent->pubkey = tlv.value; break; case TLV_RELAY: @@ -269,7 +271,7 @@ int parse_nostr_bech32(unsigned char *buf, int buflen, size_t parsed_len, u5_out_len, u8_out_len; enum nostr_bech32_type type; static const int MAX_PREFIX = 8; - struct cursor cur, bech32; + struct cursor cur, bech32, u8; make_cursor(buf, buf + buflen, &cur); make_cursor((unsigned char*)bech32_str, (unsigned char*)bech32_str + bech32_len, &bech32); @@ -296,6 +298,8 @@ int parse_nostr_bech32(unsigned char *buf, int buflen, if (!bech32_convert_bits(cur.p, &u8_out_len, 8, u5, u5_out_len, 5, 0)) return 0; - return parse_nostr_bech32_buffer(&cur, type, obj); + make_cursor(cur.p, cur.p + u8_out_len, &u8); + + return parse_nostr_bech32_buffer(&u8, type, obj); } diff --git a/src/nostr_bech32.h b/src/nostr_bech32.h @@ -10,72 +10,8 @@ #include <stdio.h> #include "str_block.h" +#include "nostrdb.h" #include "cursor.h" -#define MAX_RELAYS 24 - -struct relays { - struct ndb_str_block relays[MAX_RELAYS]; - int num_relays; -}; - -enum nostr_bech32_type { - NOSTR_BECH32_NOTE = 1, - NOSTR_BECH32_NPUB = 2, - NOSTR_BECH32_NPROFILE = 3, - NOSTR_BECH32_NEVENT = 4, - NOSTR_BECH32_NRELAY = 5, - NOSTR_BECH32_NADDR = 6, - NOSTR_BECH32_NSEC = 7, -}; -#define NOSTR_BECH32_KNOWN_TYPES 7 - -struct bech32_note { - const unsigned char *event_id; -}; - -struct bech32_npub { - const unsigned char *pubkey; -}; - -struct bech32_nsec { - const unsigned char *nsec; -}; - -struct bech32_nevent { - struct relays relays; - const unsigned char *event_id; - const unsigned char *pubkey; // optional -}; - -struct bech32_nprofile { - struct relays relays; - const unsigned char *pubkey; -}; - -struct bech32_naddr { - struct relays relays; - struct ndb_str_block identifier; - const unsigned char *pubkey; -}; - -struct bech32_nrelay { - struct ndb_str_block relay; -}; - -struct nostr_bech32 { - enum nostr_bech32_type type; - - union { - struct bech32_note note; - struct bech32_npub npub; - struct bech32_nsec nsec; - struct bech32_nevent nevent; - struct bech32_nprofile nprofile; - struct bech32_naddr naddr; - struct bech32_nrelay nrelay; - }; -}; - int parse_nostr_bech32_str(struct cursor *bech32, enum nostr_bech32_type *type); int parse_nostr_bech32_type(const char *prefix, enum nostr_bech32_type *type); diff --git a/src/nostrdb.h b/src/nostrdb.h @@ -18,6 +18,8 @@ #define ndb_debug(...) (void)0 #endif +#include "str_block.h" + struct ndb_json_parser; struct ndb; struct ndb_blocks; @@ -402,6 +404,72 @@ enum ndb_block_type { }; #define NDB_NUM_BLOCK_TYPES 6 +#define NDB_MAX_RELAYS 24 + +struct ndb_relays { + struct ndb_str_block relays[NDB_MAX_RELAYS]; + int num_relays; +}; + +enum nostr_bech32_type { + NOSTR_BECH32_NOTE = 1, + NOSTR_BECH32_NPUB = 2, + NOSTR_BECH32_NPROFILE = 3, + NOSTR_BECH32_NEVENT = 4, + NOSTR_BECH32_NRELAY = 5, + NOSTR_BECH32_NADDR = 6, + NOSTR_BECH32_NSEC = 7, +}; +#define NOSTR_BECH32_KNOWN_TYPES 7 + +struct bech32_note { + const unsigned char *event_id; +}; + +struct bech32_npub { + const unsigned char *pubkey; +}; + +struct bech32_nsec { + const unsigned char *nsec; +}; + +struct bech32_nevent { + struct ndb_relays relays; + const unsigned char *event_id; + const unsigned char *pubkey; // optional +}; + +struct bech32_nprofile { + struct ndb_relays relays; + const unsigned char *pubkey; +}; + +struct bech32_naddr { + struct ndb_relays relays; + struct ndb_str_block identifier; + const unsigned char *pubkey; +}; + +struct bech32_nrelay { + struct ndb_str_block relay; +}; + +struct nostr_bech32 { + enum nostr_bech32_type type; + + union { + struct bech32_note note; + struct bech32_npub npub; + struct bech32_nsec nsec; + struct bech32_nevent nevent; + struct bech32_nprofile nprofile; + struct bech32_naddr naddr; + struct bech32_nrelay nrelay; + }; +}; + + enum ndb_block_type ndb_block_type(struct ndb_blocks *blocks); // BLOCK ITERATORS @@ -414,5 +482,8 @@ enum ndb_block_type ndb_get_block_type(struct ndb_block *block); struct ndb_str_block *ndb_block_str(struct ndb_block *); const char *ndb_str_block_ptr(struct ndb_str_block *); uint32_t ndb_str_block_len(struct ndb_str_block *); +struct nostr_bech32 *ndb_bech32_block(struct ndb_block *block); + +// BECH32 BLOCKS #endif diff --git a/test.c b/test.c @@ -774,12 +774,42 @@ static void test_strings_work_before_finalization() { } static void test_parse_content() { +} + +static void test_parse_nevent() { unsigned char buf[4096]; - const char *content = "hello,#world,https://github.com/damus-io"; + const char *content = "nostr:nevent1qqs9qhc0pjvp6jl2w6ppk5cft8ets8fhxy7fcqcjnp7g38whjy0x5aqpzpmhxue69uhkummnw3ezuamfdejsyg86np9a0kajstc8u9h846rmy6320wdepdeydfz8w8cv7kh9sqv02g947d58,#hashtag"; struct ndb_blocks *blocks; + struct ndb_block *block = NULL; + struct nostr_bech32 *bech32; + int ok = 0; + + static unsigned char event_id[] = { 0x50, 0x5f, 0x0f, 0x0c, 0x98, 0x1d, 0x4b, 0xea, 0x76, 0x82, 0x1b, 0x53, + 0x09, 0x59, 0xf2, 0xb8, 0x1d, 0x37, 0x31, 0x3c, 0x9c, 0x03, 0x12, 0x98, + 0x7c, 0x88, 0x9d, 0xd7, 0x91, 0x1e, 0x6a, 0x74 }; assert(ndb_parse_content(buf, sizeof(buf), content, strlen(content), &blocks)); - assert(blocks->num_blocks == 4); + struct ndb_block_iterator *iter = ndb_blocks_iterate_start(content, blocks); + assert(blocks->num_blocks == 3); + while ((block = ndb_blocks_iterate_next(iter))) { + switch (++ok) { + case 1: + assert(ndb_get_block_type(block) == BLOCK_MENTION_BECH32); + bech32 = ndb_bech32_block(block); + assert(bech32->type == NOSTR_BECH32_NEVENT); + assert(!memcmp(bech32->nevent.event_id, event_id, 32)); + break; + case 2: + assert(ndb_get_block_type(block) == BLOCK_TEXT); + assert(ndb_str_block_ptr(ndb_block_str(block))[0] == ','); + break; + case 3: + assert(ndb_get_block_type(block) == BLOCK_HASHTAG); + assert(!strncmp("hashtag", ndb_str_block_ptr(ndb_block_str(block)), 7)); + break; + } + } + assert(ok == 3); } static void test_url_parsing() {