NIP-40 expiration timestamp

This commit is contained in:
Doug Hoyte
2023-02-08 06:48:38 -05:00
parent b32999cee8
commit 7661865bcc
9 changed files with 88 additions and 55 deletions

View File

@ -21,6 +21,7 @@ table Event {
kind: uint64;
tagsGeneral: [TagGeneral];
tagsFixed32: [TagFixed32];
expiration: uint64;
}
table Empty {}

View File

@ -46,6 +46,9 @@ tables:
multi: true
deletion: # eventId, pubkey
multi: true
expiration:
integer: true
multi: true
indexPrelude: |
auto *flat = v.flat_nested();
@ -70,6 +73,10 @@ tables:
if (flat->kind() == 5 && tagName == 'e') deletion.push_back(std::string(tagVal) + std::string(sv(flat->pubkey())));
}
if (flat->expiration() != 0) {
expiration.push_back(flat->expiration());
}
CompressionDictionary:
fields:
- name: dict

View File

@ -1,5 +1,4 @@
#include "RelayServer.h"
#include "render.h"
#include "app_git_version.h"

View File

@ -9,7 +9,6 @@
#include "DBScan.h"
#include "events.h"
#include "render.h"
static const char USAGE[] =

View File

@ -19,13 +19,14 @@ std::string nostrJsonToFlat(const tao::json::value &v) {
std::vector<flatbuffers::Offset<NostrIndex::TagGeneral>> tagsGeneral;
std::vector<flatbuffers::Offset<NostrIndex::TagFixed32>> tagsFixed32;
uint64_t expiration = 0;
if (v.at("tags").get_array().size() > cfg().events__maxNumTags) throw herr("too many tags: ", v.at("tags").get_array().size());
for (auto &tagArr : v.at("tags").get_array()) {
auto &tag = tagArr.get_array();
if (tag.size() < 2) throw herr("too few fields in tag");
auto tagName = tag.at(0).get_string();
if (tagName.size() != 1) continue; // only single-char tags need indexing
auto tagVal = tag.at(1).get_string();
@ -37,8 +38,14 @@ std::string nostrJsonToFlat(const tao::json::value &v) {
(uint8_t)tagName[0],
(NostrIndex::Fixed32Bytes*)tagVal.data()
));
} else {
if (tagVal.size() < 1 || tagVal.size() > cfg().events__maxTagValSize) throw herr("tag val too small/large: ", tagVal.size());
} else if (tagName == "expiration") {
if (expiration == 0) {
expiration = parseUint64(tagVal);
if (expiration == 0) expiration = 1; // special value to indicate expiration of 0 was set
}
} else if (tagName.size() == 1) {
if (tagVal.size() == 0) throw herr("tag val empty");
if (tagVal.size() > cfg().events__maxTagValSize) throw herr("tag val too large: ", tagVal.size());
if (tagVal.size() <= MAX_INDEXED_TAG_VAL_SIZE) {
tagsGeneral.emplace_back(NostrIndex::CreateTagGeneral(builder,
@ -57,7 +64,8 @@ std::string nostrJsonToFlat(const tao::json::value &v) {
created_at,
kind,
builder.CreateVector<flatbuffers::Offset<NostrIndex::TagGeneral>>(tagsGeneral),
builder.CreateVector<flatbuffers::Offset<NostrIndex::TagFixed32>>(tagsFixed32)
builder.CreateVector<flatbuffers::Offset<NostrIndex::TagFixed32>>(tagsFixed32),
expiration
);
builder.Finish(eventPtr);
@ -122,6 +130,8 @@ void verifyEventTimestamp(const NostrIndex::Event *flat) {
if (ts < earliest) throw herr("created_at too early");
if (ts > latest || ts > MAX_TIMESTAMP) throw herr("created_at too late");
if (flat->expiration() != 0 && flat->expiration() <= now) throw herr("event expired");
}
void parseAndVerifyEvent(const tao::json::value &origJson, secp256k1_context *secpCtx, bool verifyMsg, bool verifyTime, std::string &flatStr, std::string &jsonStr) {

View File

@ -2,8 +2,6 @@
#include "golpe.h"
#include "render.h"
inline void quadrableGarbageCollect(quadrable::Quadrable &qdb, int logLevel = 0) {
quadrable::Quadrable::GarbageCollector<flat_hash_set<uint64_t>> gc(qdb);

View File

@ -12,7 +12,10 @@ quadrable::Quadrable getQdbInstance(lmdb::txn &txn);
quadrable::Quadrable getQdbInstance();
std::string renderIP(std::string_view ipBytes);
#include "constants.h"
std::string renderIP(std::string_view ipBytes);
std::string renderSize(uint64_t si);
std::string renderPercent(double p);
uint64_t parseUint64(const std::string &s);

View File

@ -1,7 +1,12 @@
#include <arpa/inet.h>
#include <stdio.h>
#include <algorithm>
#include <string>
#include "golpe.h"
std::string renderIP(std::string_view ipBytes) {
char buf[128];
@ -15,3 +20,58 @@ std::string renderIP(std::string_view ipBytes) {
return std::string(buf);
}
std::string renderSize(uint64_t si) {
if (si < 1024) return std::to_string(si) + "b";
double s = si;
char buf[128];
char unit;
do {
s /= 1024;
if (s < 1024) {
unit = 'K';
break;
}
s /= 1024;
if (s < 1024) {
unit = 'M';
break;
}
s /= 1024;
if (s < 1024) {
unit = 'G';
break;
}
s /= 1024;
unit = 'T';
} while(0);
::snprintf(buf, sizeof(buf), "%.2f%c", s, unit);
return std::string(buf);
}
std::string renderPercent(double p) {
char buf[128];
::snprintf(buf, sizeof(buf), "%.1f%%", p * 100);
return std::string(buf);
}
uint64_t parseUint64(const std::string &s) {
auto digitChar = [](char c){
return c >= '0' && c <= '9';
};
if (!std::all_of(s.begin(), s.end(), digitChar)) throw herr("non-digit character");
return std::stoull(s);
}

View File

@ -1,44 +0,0 @@
#pragma once
#include <stdio.h>
inline std::string renderSize(uint64_t si) {
if (si < 1024) return std::to_string(si) + "b";
double s = si;
char buf[128];
char unit;
do {
s /= 1024;
if (s < 1024) {
unit = 'K';
break;
}
s /= 1024;
if (s < 1024) {
unit = 'M';
break;
}
s /= 1024;
if (s < 1024) {
unit = 'G';
break;
}
s /= 1024;
unit = 'T';
} while(0);
::snprintf(buf, sizeof(buf), "%.2f%c", s, unit);
return std::string(buf);
}
inline std::string renderPercent(double p) {
char buf[128];
::snprintf(buf, sizeof(buf), "%.1f%%", p * 100);
return std::string(buf);
}