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:
committed by
Daniel D’Aquino
parent
e0a2dcf3db
commit
1b09e9458c
@@ -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;
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
Reference in New Issue
Block a user