mirror of
https://github.com/scsibug/nostr-rs-relay.git
synced 2024-11-14 23:19:07 -05:00
wip: schema addition and structure for delegation
This commit is contained in:
parent
274c61bb72
commit
43b738c434
72
src/delegation.rs
Normal file
72
src/delegation.rs
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
//! Event parsing and validation
|
||||||
|
//use crate::error::Error::*;
|
||||||
|
//use crate::error::Result;
|
||||||
|
//use crate::utils::unix_time;
|
||||||
|
//use bitcoin_hashes::{sha256, Hash};
|
||||||
|
//use lazy_static::lazy_static;
|
||||||
|
//use secp256k1::{schnorr, Secp256k1, VerifyOnly, XOnlyPublicKey};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
//use serde_json::value::Value;
|
||||||
|
//use serde_json::Number;
|
||||||
|
//use std::collections::HashMap;
|
||||||
|
//use std::collections::HashSet;
|
||||||
|
//use std::str::FromStr;
|
||||||
|
//use tracing::{debug, info};
|
||||||
|
|
||||||
|
// This handles everything related to delegation, in particular the
|
||||||
|
// condition/rune parsing and logic.
|
||||||
|
|
||||||
|
// Conditions are poorly specified, so we will implement the minimum
|
||||||
|
// necessary for now.
|
||||||
|
|
||||||
|
// fields MUST be either "kind" or "created_at".
|
||||||
|
// operators supported are ">", "<", "=", "!".
|
||||||
|
// no operations on 'content' are supported.
|
||||||
|
|
||||||
|
// this allows constraints for:
|
||||||
|
// valid date ranges (valid from X->Y dates).
|
||||||
|
// specific kinds (publish kind=1,5)
|
||||||
|
// kind ranges (publish ephemeral events, kind>19999&kind<30001)
|
||||||
|
|
||||||
|
// for more complex scenarios (allow delegatee to publish ephemeral
|
||||||
|
// AND replacement events), it may be necessary to generate and use
|
||||||
|
// different condition strings, since we do not support grouping or
|
||||||
|
// "OR" logic.
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, PartialEq, Eq, Debug, Clone)]
|
||||||
|
pub enum Field {
|
||||||
|
Kind,
|
||||||
|
CreatedAt,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, PartialEq, Eq, Debug, Clone)]
|
||||||
|
pub enum Operator {
|
||||||
|
LessThan,
|
||||||
|
GreaterThan,
|
||||||
|
Equals,
|
||||||
|
NotEquals,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, PartialEq, Eq, Debug, Clone)]
|
||||||
|
pub enum Value {
|
||||||
|
Number(u64),
|
||||||
|
List(Vec<Value>),
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Parsed delegation statement
|
||||||
|
#[derive(Serialize, Deserialize, PartialEq, Eq, Debug, Clone)]
|
||||||
|
pub struct Delegation {
|
||||||
|
pub(crate) pubkey: String,
|
||||||
|
pub(crate) conditions: Vec<Condition>,
|
||||||
|
pub(crate) signature: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Parsed delegation condition
|
||||||
|
/// see https://github.com/nostr-protocol/nips/pull/28#pullrequestreview-1084903800
|
||||||
|
/// An example complex condition would be: kind=1,2,3&created_at<1665265999
|
||||||
|
#[derive(Serialize, Deserialize, PartialEq, Eq, Debug, Clone)]
|
||||||
|
pub struct Condition {
|
||||||
|
pub(crate) field: Field,
|
||||||
|
pub(crate) operator: Operator,
|
||||||
|
pub(crate) value: Value,
|
||||||
|
}
|
36
src/event.rs
36
src/event.rs
|
@ -110,6 +110,16 @@ impl Event {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// is this event delegated (properly)?
|
||||||
|
// does the signature match, and are conditions valid?
|
||||||
|
pub fn is_delegated(&self) -> bool {
|
||||||
|
// is there a delegation tag?
|
||||||
|
let _delegation_tag = self.tag_values_by_name("delegation");
|
||||||
|
// delegation tags should have exactly 3 elements after the name (pubkey, condition, sig)
|
||||||
|
// try to construct a delegation object (
|
||||||
|
todo!();
|
||||||
|
}
|
||||||
|
|
||||||
/// Build an event tag index
|
/// Build an event tag index
|
||||||
fn build_index(&mut self) {
|
fn build_index(&mut self) {
|
||||||
// if there are no tags; just leave the index as None
|
// if there are no tags; just leave the index as None
|
||||||
|
@ -388,6 +398,32 @@ mod tests {
|
||||||
assert_eq!(v, vec!["foo", "bar", "baz"]);
|
assert_eq!(v, vec!["foo", "bar", "baz"]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn event_no_tag_select() {
|
||||||
|
let e = Event {
|
||||||
|
id: "999".to_owned(),
|
||||||
|
pubkey: "012345".to_owned(),
|
||||||
|
created_at: 501234,
|
||||||
|
kind: 1,
|
||||||
|
tags: vec![
|
||||||
|
vec!["j".to_owned(), "abc".to_owned()],
|
||||||
|
vec!["e".to_owned(), "foo".to_owned()],
|
||||||
|
vec!["e".to_owned(), "baz".to_owned()],
|
||||||
|
vec![
|
||||||
|
"p".to_owned(),
|
||||||
|
"aaaa".to_owned(),
|
||||||
|
"ws://example.com".to_owned(),
|
||||||
|
],
|
||||||
|
],
|
||||||
|
content: "this is a test".to_owned(),
|
||||||
|
sig: "abcde".to_owned(),
|
||||||
|
tagidx: None,
|
||||||
|
};
|
||||||
|
let v = e.tag_values_by_name("x");
|
||||||
|
// asking for tags that don't exist just returns zero-length vector
|
||||||
|
assert_eq!(v.len(), 0);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn event_canonical_with_tags() {
|
fn event_canonical_with_tags() {
|
||||||
let e = Event {
|
let e = Event {
|
||||||
|
|
|
@ -2,6 +2,7 @@ pub mod close;
|
||||||
pub mod config;
|
pub mod config;
|
||||||
pub mod conn;
|
pub mod conn;
|
||||||
pub mod db;
|
pub mod db;
|
||||||
|
pub mod delegation;
|
||||||
pub mod error;
|
pub mod error;
|
||||||
pub mod event;
|
pub mod event;
|
||||||
pub mod hexrange;
|
pub mod hexrange;
|
||||||
|
|
|
@ -20,7 +20,7 @@ pragma mmap_size = 536870912; -- 512MB of mmap
|
||||||
"##;
|
"##;
|
||||||
|
|
||||||
/// Latest database version
|
/// Latest database version
|
||||||
pub const DB_VERSION: usize = 6;
|
pub const DB_VERSION: usize = 7;
|
||||||
|
|
||||||
/// Schema definition
|
/// Schema definition
|
||||||
const INIT_SQL: &str = formatcp!(
|
const INIT_SQL: &str = formatcp!(
|
||||||
|
@ -40,6 +40,7 @@ event_hash BLOB NOT NULL, -- 4-byte hash
|
||||||
first_seen INTEGER NOT NULL, -- when the event was first seen (not authored!) (seconds since 1970)
|
first_seen INTEGER NOT NULL, -- when the event was first seen (not authored!) (seconds since 1970)
|
||||||
created_at INTEGER NOT NULL, -- when the event was authored
|
created_at INTEGER NOT NULL, -- when the event was authored
|
||||||
author BLOB NOT NULL, -- author pubkey
|
author BLOB NOT NULL, -- author pubkey
|
||||||
|
delegator BLOB, -- delegator pubkey (NIP-26)
|
||||||
kind INTEGER NOT NULL, -- event kind
|
kind INTEGER NOT NULL, -- event kind
|
||||||
hidden INTEGER, -- relevant for queries
|
hidden INTEGER, -- relevant for queries
|
||||||
content TEXT NOT NULL -- serialized json of event object
|
content TEXT NOT NULL -- serialized json of event object
|
||||||
|
@ -152,6 +153,9 @@ pub fn upgrade_db(conn: &mut PooledConnection) -> Result<()> {
|
||||||
if curr_version == 5 {
|
if curr_version == 5 {
|
||||||
curr_version = mig_5_to_6(conn)?;
|
curr_version = mig_5_to_6(conn)?;
|
||||||
}
|
}
|
||||||
|
if curr_version == 6 {
|
||||||
|
curr_version = mig_6_to_7(conn)?;
|
||||||
|
}
|
||||||
if curr_version == DB_VERSION {
|
if curr_version == DB_VERSION {
|
||||||
info!(
|
info!(
|
||||||
"All migration scripts completed successfully. Welcome to v{}.",
|
"All migration scripts completed successfully. Welcome to v{}.",
|
||||||
|
@ -348,3 +352,22 @@ fn mig_5_to_6(conn: &mut PooledConnection) -> Result<usize> {
|
||||||
info!("vacuumed DB after tags rebuild in {:?}", start.elapsed());
|
info!("vacuumed DB after tags rebuild in {:?}", start.elapsed());
|
||||||
Ok(6)
|
Ok(6)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn mig_6_to_7(conn: &mut PooledConnection) -> Result<usize> {
|
||||||
|
info!("database schema needs update from 6->7");
|
||||||
|
// only change is adding a hidden column to events.
|
||||||
|
let upgrade_sql = r##"
|
||||||
|
ALTER TABLE event ADD delegator BLOB;
|
||||||
|
PRAGMA user_version = 7;
|
||||||
|
"##;
|
||||||
|
match conn.execute_batch(upgrade_sql) {
|
||||||
|
Ok(()) => {
|
||||||
|
info!("database schema upgraded v6 -> v7");
|
||||||
|
}
|
||||||
|
Err(err) => {
|
||||||
|
error!("update failed: {}", err);
|
||||||
|
panic!("database could not be upgraded");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(7)
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user