nostrdb

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

commit f29c38c11b375a20532b3a0be8e93606c9739086
parent dc254e38e4eec5f56f020f070301b82bb5d9ade1
Author: William Casarin <jb55@jb55.com>
Date:   Wed, 27 Dec 2023 14:28:20 -0800

nostr_bech32: parse in one pass

since we will be decoding these in realtime, let's make sure we can
decode them in O(1)

Diffstat:
Msrc/nostr_bech32.c | 226++++++++++++++++++++++++++++++++++++-------------------------------------------
Msrc/nostr_bech32.h | 6+++---
2 files changed, 107 insertions(+), 125 deletions(-)

diff --git a/src/nostr_bech32.c b/src/nostr_bech32.c @@ -24,17 +24,11 @@ struct nostr_tlv { const unsigned char *value; }; -struct nostr_tlvs { - struct nostr_tlv tlvs[MAX_TLVS]; - int num_tlvs; -}; - static int parse_nostr_tlv(struct cursor *cur, struct nostr_tlv *tlv) { // get the tlv tag if (!cursor_pull_byte(cur, &tlv->type)) return 0; - - // unknown, fail! + if (tlv->type >= TLV_KNOWN_TLVS) return 0; @@ -52,37 +46,6 @@ static int parse_nostr_tlv(struct cursor *cur, struct nostr_tlv *tlv) { return 1; } -static int parse_nostr_tlvs(struct cursor *cur, struct nostr_tlvs *tlvs) { - int i; - tlvs->num_tlvs = 0; - - for (i = 0; i < MAX_TLVS; i++) { - if (parse_nostr_tlv(cur, &tlvs->tlvs[i])) { - tlvs->num_tlvs++; - } else { - break; - } - } - - if (tlvs->num_tlvs == 0) - return 0; - - return 1; -} - -static int find_tlv(struct nostr_tlvs *tlvs, unsigned char type, struct nostr_tlv **tlv) { - *tlv = NULL; - - for (int i = 0; i < tlvs->num_tlvs; i++) { - if (tlvs->tlvs[i].type == type) { - *tlv = &tlvs->tlvs[i]; - return 1; - } - } - - return 0; -} - int parse_nostr_bech32_type(const char *prefix, enum nostr_bech32_type *type) { // Parse type if (strncmp(prefix, "note", 4) == 0) { @@ -123,109 +86,129 @@ static int parse_nostr_bech32_nsec(struct cursor *cur, struct bech32_nsec *nsec) return pull_bytes(cur, 32, &nsec->nsec); } -static int tlvs_to_relays(struct nostr_tlvs *tlvs, struct relays *relays) { - struct nostr_tlv *tlv; +static int add_relay(struct relays *relays, struct nostr_tlv *tlv) +{ struct str_block *str; + + if (relays->num_relays + 1 > MAX_RELAYS) + return 0; - relays->num_relays = 0; - - for (int i = 0; i < tlvs->num_tlvs; i++) { - tlv = &tlvs->tlvs[i]; - if (tlv->type != TLV_RELAY) - continue; - - if (relays->num_relays + 1 > MAX_RELAYS) - break; - - str = &relays->relays[relays->num_relays++]; - str->str = (const char*)tlv->value; - str->len = tlv->len; - } + str = &relays->relays[relays->num_relays++]; + str->str = (const char*)tlv->value; + str->len = tlv->len; return 1; } static int parse_nostr_bech32_nevent(struct cursor *cur, struct bech32_nevent *nevent) { - struct nostr_tlvs tlvs; - struct nostr_tlv *tlv; - - if (!parse_nostr_tlvs(cur, &tlvs)) - return 0; - - if (!find_tlv(&tlvs, TLV_SPECIAL, &tlv)) - return 0; - - if (tlv->len != 32) - return 0; - - nevent->event_id = tlv->value; - - if (find_tlv(&tlvs, TLV_AUTHOR, &tlv)) { - nevent->pubkey = tlv->value; - } else { - nevent->pubkey = NULL; + struct nostr_tlv tlv; + int i; + + nevent->event_id = NULL; + nevent->pubkey = NULL; + nevent->relays.num_relays = 0; + + for (i = 0; i < MAX_TLVS; i++) { + if (!parse_nostr_tlv(cur, &tlv)) + break; + + switch (tlv.type) { + case TLV_SPECIAL: + if (tlv.len != 32) return 0; + nevent->event_id = tlv.value; + break; + case TLV_AUTHOR: + if (tlv.len != 32) return 0; + nevent->pubkey = tlv.value; + break; + case TLV_RELAY: + add_relay(&nevent->relays, &tlv); + break; + } } - - return tlvs_to_relays(&tlvs, &nevent->relays); + + return nevent->event_id != NULL; } static int parse_nostr_bech32_naddr(struct cursor *cur, struct bech32_naddr *naddr) { - struct nostr_tlvs tlvs; - struct nostr_tlv *tlv; - - if (!parse_nostr_tlvs(cur, &tlvs)) - return 0; - - if (!find_tlv(&tlvs, TLV_SPECIAL, &tlv)) - return 0; - - naddr->identifier.str = (const char*)tlv->value; - naddr->identifier.len = tlv->len; - - if (!find_tlv(&tlvs, TLV_AUTHOR, &tlv)) - return 0; - - naddr->pubkey = tlv->value; - - return tlvs_to_relays(&tlvs, &naddr->relays); + struct nostr_tlv tlv; + int i; + + naddr->identifier.str = NULL; + naddr->identifier.len = 0; + naddr->pubkey = NULL; + naddr->relays.num_relays = 0; + + for (i = 0; i < MAX_TLVS; i++) { + if (!parse_nostr_tlv(cur, &tlv)) + break; + + switch (tlv.type) { + case TLV_SPECIAL: + naddr->identifier.str = (const char*)tlv.value; + naddr->identifier.len = tlv.len; + break; + case TLV_AUTHOR: + if (tlv.len != 32) return 0; + naddr->pubkey = tlv.value; + break; + case TLV_RELAY: + add_relay(&naddr->relays, &tlv); + break; + } + } + + return naddr->identifier.str != NULL; } static int parse_nostr_bech32_nprofile(struct cursor *cur, struct bech32_nprofile *nprofile) { - struct nostr_tlvs tlvs; - struct nostr_tlv *tlv; - - if (!parse_nostr_tlvs(cur, &tlvs)) - return 0; - - if (!find_tlv(&tlvs, TLV_SPECIAL, &tlv)) - return 0; - - if (tlv->len != 32) - return 0; - - nprofile->pubkey = tlv->value; - - return tlvs_to_relays(&tlvs, &nprofile->relays); + struct nostr_tlv tlv; + int i; + + nprofile->pubkey = NULL; + nprofile->relays.num_relays = 0; + + for (i = 0; i < MAX_TLVS; i++) { + if (!parse_nostr_tlv(cur, &tlv)) + break; + + switch (tlv.type) { + case TLV_SPECIAL: + if (tlv.len != 32) return 0; + nprofile->pubkey = tlv.value; + break; + case TLV_RELAY: + add_relay(&nprofile->relays, &tlv); + break; + } + } + + return nprofile->pubkey != NULL; } static int parse_nostr_bech32_nrelay(struct cursor *cur, struct bech32_nrelay *nrelay) { - struct nostr_tlvs tlvs; - struct nostr_tlv *tlv; - - if (!parse_nostr_tlvs(cur, &tlvs)) - return 0; - - if (!find_tlv(&tlvs, TLV_SPECIAL, &tlv)) - return 0; - - nrelay->relay.str = (const char*)tlv->value; - nrelay->relay.len = tlv->len; + struct nostr_tlv tlv; + int i; + + nrelay->relay.str = NULL; + nrelay->relay.len = 0; + + for (i = 0; i < MAX_TLVS; i++) { + if (!parse_nostr_tlv(cur, &tlv)) + break; + + switch (tlv.type) { + case TLV_SPECIAL: + nrelay->relay.str = (const char*)tlv.value; + nrelay->relay.len = tlv.len; + break; + } + } - return 1; + return nrelay->relay.str != NULL; } -/* -int parse_nostr_bech32_buffer(unsigned char *cur, int buflen, +int parse_nostr_bech32_buffer(struct cursor *cur, enum nostr_bech32_type type, struct nostr_bech32 *obj) { @@ -264,7 +247,6 @@ int parse_nostr_bech32_buffer(unsigned char *cur, int buflen, return 1; } -*/ int parse_nostr_bech32_str(struct cursor *bech32) { enum nostr_bech32_type type; diff --git a/src/nostr_bech32.h b/src/nostr_bech32.h @@ -27,6 +27,7 @@ enum nostr_bech32_type { NOSTR_BECH32_NADDR = 6, NOSTR_BECH32_NSEC = 7, }; +#define NOSTR_BECH32_KNOWN_TYPES 7 struct bech32_note { const unsigned char *event_id; @@ -79,11 +80,10 @@ struct nostr_bech32 { int parse_nostr_bech32_str(struct cursor *bech32); int parse_nostr_bech32_type(const char *prefix, enum nostr_bech32_type *type); -/* -int parse_nostr_bech32_buffer(unsigned char *buf, int buflen, - enum nostr_bech32_type type, +int parse_nostr_bech32_buffer(struct cursor *cur, enum nostr_bech32_type type, struct nostr_bech32 *obj); +/* int parse_nostr_bech32(const char *bech32, size_t input_len, unsigned char *outbuf, size_t outlen, enum nostr_bech32_type *type);