feat(NIP-111): pay to relay (experimental)
This commit is contained in:
committed by
Greg Heartsfield
parent
164603dedd
commit
c0158af18b
@@ -4,6 +4,7 @@ use crate::error::{Error, Result};
|
||||
use crate::event::Event;
|
||||
use crate::nauthz;
|
||||
use crate::notice::Notice;
|
||||
use crate::payment::PaymentMessage;
|
||||
use crate::repo::postgres::{PostgresPool, PostgresRepo};
|
||||
use crate::repo::sqlite::SqliteRepo;
|
||||
use crate::repo::NostrRepo;
|
||||
@@ -19,6 +20,8 @@ use std::thread;
|
||||
use std::time::{Duration, Instant};
|
||||
use tracing::log::LevelFilter;
|
||||
use tracing::{debug, info, trace, warn};
|
||||
use nostr::key::FromPkStr;
|
||||
use nostr::key::Keys;
|
||||
|
||||
pub type SqlitePool = r2d2::Pool<r2d2_sqlite::SqliteConnectionManager>;
|
||||
pub type PooledConnection = r2d2::PooledConnection<r2d2_sqlite::SqliteConnectionManager>;
|
||||
@@ -83,6 +86,7 @@ pub async fn db_writer(
|
||||
mut event_rx: tokio::sync::mpsc::Receiver<SubmittedEvent>,
|
||||
bcast_tx: tokio::sync::broadcast::Sender<Event>,
|
||||
metadata_tx: tokio::sync::broadcast::Sender<Event>,
|
||||
payment_tx: tokio::sync::broadcast::Sender<PaymentMessage>,
|
||||
mut shutdown: tokio::sync::broadcast::Receiver<()>,
|
||||
) -> Result<()> {
|
||||
// are we performing NIP-05 checking?
|
||||
@@ -90,6 +94,10 @@ pub async fn db_writer(
|
||||
// are we requriing NIP-05 user verification?
|
||||
let nip05_enabled = settings.verified_users.is_enabled();
|
||||
|
||||
let pay_to_relay_enabled = settings.pay_to_relay.enabled;
|
||||
let cost_per_event = settings.pay_to_relay.cost_per_event;
|
||||
debug!("Pay to relay: {}", pay_to_relay_enabled);
|
||||
|
||||
//upgrade_db(&mut pool.get()?)?;
|
||||
|
||||
// Make a copy of the whitelist
|
||||
@@ -136,24 +144,6 @@ pub async fn db_writer(
|
||||
let subm_event = next_event.unwrap();
|
||||
let event = subm_event.event;
|
||||
let notice_tx = subm_event.notice_tx;
|
||||
// check if this event is authorized.
|
||||
if let Some(allowed_addrs) = whitelist {
|
||||
// TODO: incorporate delegated pubkeys
|
||||
// if the event address is not in allowed_addrs.
|
||||
if !allowed_addrs.contains(&event.pubkey) {
|
||||
debug!(
|
||||
"rejecting event: {}, unauthorized author",
|
||||
event.get_event_id_prefix()
|
||||
);
|
||||
notice_tx
|
||||
.try_send(Notice::blocked(
|
||||
event.id,
|
||||
"pubkey is not allowed to publish to this relay",
|
||||
))
|
||||
.ok();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Check that event kind isn't blacklisted
|
||||
let kinds_blacklist = &settings.limits.event_kind_blacklist.clone();
|
||||
@@ -187,6 +177,91 @@ pub async fn db_writer(
|
||||
}
|
||||
}
|
||||
|
||||
// Set to none until balance is got from db
|
||||
// Will stay none if user in whitelisted and does not have to pay to post
|
||||
// When pay to relay is enabled the whitelist is not a list of who can post
|
||||
// It is a list of who can post for free
|
||||
let mut user_balance: Option<u64> = None;
|
||||
if !pay_to_relay_enabled {
|
||||
// check if this event is authorized.
|
||||
if let Some(allowed_addrs) = whitelist {
|
||||
// TODO: incorporate delegated pubkeys
|
||||
// if the event address is not in allowed_addrs.
|
||||
if !allowed_addrs.contains(&event.pubkey) {
|
||||
debug!(
|
||||
"rejecting event: {}, unauthorized author",
|
||||
event.get_event_id_prefix()
|
||||
);
|
||||
notice_tx
|
||||
.try_send(Notice::blocked(
|
||||
event.id,
|
||||
"pubkey is not allowed to publish to this relay",
|
||||
))
|
||||
.ok();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// If the user is on whitelist there is no need to check if the user is admitted or has balance to post
|
||||
if whitelist.is_none()
|
||||
|| (whitelist.is_some() && !whitelist.as_ref().unwrap().contains(&event.pubkey))
|
||||
{
|
||||
let key = Keys::from_pk_str(&event.pubkey).unwrap();
|
||||
match repo.get_account_balance(&key).await {
|
||||
Ok((user_admitted, balance)) => {
|
||||
// Checks to make sure user is admitted
|
||||
if !user_admitted {
|
||||
debug!("user: {}, is not admitted", &event.pubkey);
|
||||
|
||||
// If the user is in DB but not admitted
|
||||
// Send meeage to payment thread to check if outstanding invoice has been paid
|
||||
payment_tx
|
||||
.send(PaymentMessage::CheckAccount(event.pubkey))
|
||||
.ok();
|
||||
notice_tx
|
||||
.try_send(Notice::blocked(event.id, "User is not admitted"))
|
||||
.ok();
|
||||
continue;
|
||||
}
|
||||
|
||||
// Checks that user has enough balance to post
|
||||
// TODO: this should send an invoice to user to top up
|
||||
if balance < cost_per_event {
|
||||
debug!("user: {}, does not have a balance", &event.pubkey,);
|
||||
notice_tx
|
||||
.try_send(Notice::blocked(event.id, "Insufficient balance"))
|
||||
.ok();
|
||||
continue;
|
||||
}
|
||||
user_balance = Some(balance);
|
||||
debug!("User balance: {:?}", user_balance);
|
||||
}
|
||||
Err(
|
||||
Error::SqlError(rusqlite::Error::QueryReturnedNoRows)
|
||||
| Error::SqlxError(sqlx::Error::RowNotFound),
|
||||
) => {
|
||||
// User does not exist
|
||||
info!("Unregistered user");
|
||||
if settings.pay_to_relay.sign_ups {
|
||||
payment_tx
|
||||
.send(PaymentMessage::NewAccount(event.pubkey))
|
||||
.ok();
|
||||
}
|
||||
let msg = "Pubkey not registered";
|
||||
notice_tx.try_send(Notice::error(event.id, msg)).ok();
|
||||
continue;
|
||||
}
|
||||
Err(err) => {
|
||||
warn!("Error checking admission status: {:?}", err);
|
||||
let msg = "relay experienced an error checking your admission status";
|
||||
notice_tx.try_send(Notice::error(event.id, msg)).ok();
|
||||
// Other error
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// send any metadata events to the NIP-05 verifier
|
||||
if nip05_active && event.is_kind_metadata() {
|
||||
// we are sending this prior to even deciding if we
|
||||
@@ -335,6 +410,17 @@ pub async fn db_writer(
|
||||
|
||||
// use rate limit, if defined, and if an event was actually written.
|
||||
if event_write {
|
||||
// If pay to relay is diabaled or the cost per event is 0
|
||||
// No need to update user balance
|
||||
if pay_to_relay_enabled && cost_per_event > 0 {
|
||||
// If the user balance is some, user was not on whitelist
|
||||
// Their balance should be reduced by the cost per event
|
||||
if let Some(_balance) = user_balance {
|
||||
let pubkey = Keys::from_pk_str(&event.pubkey)?;
|
||||
repo.update_account_balance(&pubkey, false, cost_per_event)
|
||||
.await?;
|
||||
}
|
||||
}
|
||||
if let Some(ref lim) = lim_opt {
|
||||
if let Err(n) = lim.check() {
|
||||
let wait_for = n.wait_time_from(clock.now());
|
||||
|
||||
Reference in New Issue
Block a user