nostrdb/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)

Signed-off-by: William Casarin <jb55@jb55.com>
This commit is contained in:
William Casarin
2023-12-27 14:28:20 -08:00
committed by Daniel D’Aquino
parent e0a2dcf3db
commit 1b09e9458c
2 changed files with 107 additions and 125 deletions

View File

@@ -24,17 +24,11 @@ struct nostr_tlv {
const unsigned char *value; 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) { static int parse_nostr_tlv(struct cursor *cur, struct nostr_tlv *tlv) {
// get the tlv tag // get the tlv tag
if (!cursor_pull_byte(cur, &tlv->type)) if (!cursor_pull_byte(cur, &tlv->type))
return 0; return 0;
// unknown, fail!
if (tlv->type >= TLV_KNOWN_TLVS) if (tlv->type >= TLV_KNOWN_TLVS)
return 0; return 0;
@@ -52,37 +46,6 @@ static int parse_nostr_tlv(struct cursor *cur, struct nostr_tlv *tlv) {
return 1; 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) { int parse_nostr_bech32_type(const char *prefix, enum nostr_bech32_type *type) {
// Parse type // Parse type
if (strncmp(prefix, "note", 4) == 0) { 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); return pull_bytes(cur, 32, &nsec->nsec);
} }
static int tlvs_to_relays(struct nostr_tlvs *tlvs, struct relays *relays) { static int add_relay(struct relays *relays, struct nostr_tlv *tlv)
struct nostr_tlv *tlv; {
struct str_block *str; struct str_block *str;
if (relays->num_relays + 1 > MAX_RELAYS)
return 0;
relays->num_relays = 0; str = &relays->relays[relays->num_relays++];
str->str = (const char*)tlv->value;
for (int i = 0; i < tlvs->num_tlvs; i++) { str->len = tlv->len;
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;
}
return 1; return 1;
} }
static int parse_nostr_bech32_nevent(struct cursor *cur, struct bech32_nevent *nevent) { static int parse_nostr_bech32_nevent(struct cursor *cur, struct bech32_nevent *nevent) {
struct nostr_tlvs tlvs; struct nostr_tlv tlv;
struct nostr_tlv *tlv; int i;
if (!parse_nostr_tlvs(cur, &tlvs)) nevent->event_id = NULL;
return 0; nevent->pubkey = NULL;
nevent->relays.num_relays = 0;
if (!find_tlv(&tlvs, TLV_SPECIAL, &tlv))
return 0; for (i = 0; i < MAX_TLVS; i++) {
if (!parse_nostr_tlv(cur, &tlv))
if (tlv->len != 32) break;
return 0;
switch (tlv.type) {
nevent->event_id = tlv->value; case TLV_SPECIAL:
if (tlv.len != 32) return 0;
if (find_tlv(&tlvs, TLV_AUTHOR, &tlv)) { nevent->event_id = tlv.value;
nevent->pubkey = tlv->value; break;
} else { case TLV_AUTHOR:
nevent->pubkey = NULL; 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) { static int parse_nostr_bech32_naddr(struct cursor *cur, struct bech32_naddr *naddr) {
struct nostr_tlvs tlvs; struct nostr_tlv tlv;
struct nostr_tlv *tlv; int i;
if (!parse_nostr_tlvs(cur, &tlvs)) naddr->identifier.str = NULL;
return 0; naddr->identifier.len = 0;
naddr->pubkey = NULL;
if (!find_tlv(&tlvs, TLV_SPECIAL, &tlv)) naddr->relays.num_relays = 0;
return 0;
for (i = 0; i < MAX_TLVS; i++) {
naddr->identifier.str = (const char*)tlv->value; if (!parse_nostr_tlv(cur, &tlv))
naddr->identifier.len = tlv->len; break;
if (!find_tlv(&tlvs, TLV_AUTHOR, &tlv)) switch (tlv.type) {
return 0; case TLV_SPECIAL:
naddr->identifier.str = (const char*)tlv.value;
naddr->pubkey = tlv->value; naddr->identifier.len = tlv.len;
break;
return tlvs_to_relays(&tlvs, &naddr->relays); 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) { static int parse_nostr_bech32_nprofile(struct cursor *cur, struct bech32_nprofile *nprofile) {
struct nostr_tlvs tlvs; struct nostr_tlv tlv;
struct nostr_tlv *tlv; int i;
if (!parse_nostr_tlvs(cur, &tlvs)) nprofile->pubkey = NULL;
return 0; nprofile->relays.num_relays = 0;
if (!find_tlv(&tlvs, TLV_SPECIAL, &tlv)) for (i = 0; i < MAX_TLVS; i++) {
return 0; if (!parse_nostr_tlv(cur, &tlv))
break;
if (tlv->len != 32)
return 0; switch (tlv.type) {
case TLV_SPECIAL:
nprofile->pubkey = tlv->value; if (tlv.len != 32) return 0;
nprofile->pubkey = tlv.value;
return tlvs_to_relays(&tlvs, &nprofile->relays); 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) { static int parse_nostr_bech32_nrelay(struct cursor *cur, struct bech32_nrelay *nrelay) {
struct nostr_tlvs tlvs; struct nostr_tlv tlv;
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;
}
}
if (!parse_nostr_tlvs(cur, &tlvs)) return nrelay->relay.str != NULL;
return 0;
if (!find_tlv(&tlvs, TLV_SPECIAL, &tlv))
return 0;
nrelay->relay.str = (const char*)tlv->value;
nrelay->relay.len = tlv->len;
return 1;
} }
/* int parse_nostr_bech32_buffer(struct cursor *cur,
int parse_nostr_bech32_buffer(unsigned char *cur, int buflen,
enum nostr_bech32_type type, enum nostr_bech32_type type,
struct nostr_bech32 *obj) struct nostr_bech32 *obj)
{ {
@@ -264,7 +247,6 @@ int parse_nostr_bech32_buffer(unsigned char *cur, int buflen,
return 1; return 1;
} }
*/
int parse_nostr_bech32_str(struct cursor *bech32) { int parse_nostr_bech32_str(struct cursor *bech32) {
enum nostr_bech32_type type; enum nostr_bech32_type type;

View File

@@ -27,6 +27,7 @@ enum nostr_bech32_type {
NOSTR_BECH32_NADDR = 6, NOSTR_BECH32_NADDR = 6,
NOSTR_BECH32_NSEC = 7, NOSTR_BECH32_NSEC = 7,
}; };
#define NOSTR_BECH32_KNOWN_TYPES 7
struct bech32_note { struct bech32_note {
const unsigned char *event_id; const unsigned char *event_id;
@@ -79,11 +80,10 @@ struct nostr_bech32 {
int parse_nostr_bech32_str(struct cursor *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_type(const char *prefix, enum nostr_bech32_type *type);
/* int parse_nostr_bech32_buffer(struct cursor *cur, enum nostr_bech32_type type,
int parse_nostr_bech32_buffer(unsigned char *buf, int buflen,
enum nostr_bech32_type type,
struct nostr_bech32 *obj); struct nostr_bech32 *obj);
/*
int parse_nostr_bech32(const char *bech32, size_t input_len, int parse_nostr_bech32(const char *bech32, size_t input_len,
unsigned char *outbuf, size_t outlen, unsigned char *outbuf, size_t outlen,
enum nostr_bech32_type *type); enum nostr_bech32_type *type);