Skip to content

Commit

Permalink
fix: consider mint caps
Browse files Browse the repository at this point in the history
  • Loading branch information
rafaelcr committed Jun 29, 2024
1 parent 8589378 commit 909b59e
Show file tree
Hide file tree
Showing 7 changed files with 154 additions and 44 deletions.
6 changes: 3 additions & 3 deletions migrations/V1__runes.sql
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,10 @@ CREATE TABLE IF NOT EXISTS runes (
terms_offset_end NUMERIC,
turbo BOOLEAN NOT NULL DEFAULT FALSE,
minted NUMERIC NOT NULL DEFAULT 0,
total_mints BIGINT NOT NULL DEFAULT 0,
total_mints NUMERIC NOT NULL DEFAULT 0,
burned NUMERIC NOT NULL DEFAULT 0,
total_burns BIGINT NOT NULL DEFAULT 0,
total_operations BIGINT NOT NULL DEFAULT 0,
total_burns NUMERIC NOT NULL DEFAULT 0,
total_operations NUMERIC NOT NULL DEFAULT 0,
timestamp BIGINT NOT NULL
);
CREATE INDEX runes_block_height_tx_index_index ON runes (block_height, tx_index);
Expand Down
70 changes: 64 additions & 6 deletions src/db/cache/index_cache.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ use crate::db::{
db_balance_update::DbBalanceUpdate, db_ledger_entry::DbLedgerEntry,
db_ledger_operation::DbLedgerOperation, db_rune::DbRune, db_rune_update::DbRuneUpdate,
},
pg_get_missed_input_rune_balances, pg_get_rune_by_id,
pg_get_missed_input_rune_balances, pg_get_rune_by_id, pg_get_rune_total_mints,
};

use super::{
Expand All @@ -34,6 +34,8 @@ pub struct IndexCache {
next_rune_number: u32,
/// LRU cache for runes.
rune_cache: LruCache<RuneId, DbRune>,
/// LRU cache for total mints for runes.
rune_total_mints_cache: LruCache<RuneId, u128>,
/// LRU cache for outputs with rune balances.
output_cache: LruCache<(String, u32), HashMap<RuneId, Vec<InputRuneBalance>>>,
/// Holds a single transaction's rune cache. Must be cleared every time a new transaction is processed.
Expand All @@ -49,6 +51,7 @@ impl IndexCache {
network,
next_rune_number: max_rune_number + 1,
rune_cache: LruCache::new(cap),
rune_total_mints_cache: LruCache::new(cap),
output_cache: LruCache::new(cap),
tx_cache: TransactionCache::new(network, &"".to_string(), 1, 0, &"".to_string(), 0),
db_cache: DbCache::new(),
Expand Down Expand Up @@ -88,7 +91,10 @@ impl IndexCache {
db_tx: &mut Transaction<'_>,
ctx: &Context,
) {
debug!(ctx.expect_logger(), "Runestone {}", self.tx_cache.location);
debug!(
ctx.expect_logger(),
"{:?} {}", runestone, self.tx_cache.location
);
self.scan_tx_input_rune_balance(tx_inputs, db_tx, ctx).await;
self.tx_cache
.apply_runestone_pointer(runestone, tx_outputs, ctx);
Expand Down Expand Up @@ -154,8 +160,21 @@ impl IndexCache {
);
return;
};
let ledger_entry = self.tx_cache.apply_mint(&rune_id, &db_rune, ctx);
self.add_ledger_entries_to_db_cache(&vec![ledger_entry]);
let total_mints = self
.get_cached_rune_total_mints(rune_id, db_tx, ctx)
.await
.unwrap_or(0);
if let Some(ledger_entry) = self
.tx_cache
.apply_mint(&rune_id, total_mints, &db_rune, ctx)
{
self.add_ledger_entries_to_db_cache(&vec![ledger_entry.clone()]);
if let Some(total) = self.rune_total_mints_cache.get_mut(rune_id) {
*total += 1;
} else {
self.rune_total_mints_cache.put(rune_id.clone(), 1);
}
}
}

pub async fn apply_cenotaph_mint(
Expand All @@ -171,8 +190,21 @@ impl IndexCache {
);
return;
};
let ledger_entry = self.tx_cache.apply_cenotaph_mint(&rune_id, &db_rune, ctx);
self.add_ledger_entries_to_db_cache(&vec![ledger_entry]);
let total_mints = self
.get_cached_rune_total_mints(rune_id, db_tx, ctx)
.await
.unwrap_or(0);
if let Some(ledger_entry) =
self.tx_cache
.apply_cenotaph_mint(&rune_id, total_mints, &db_rune, ctx)
{
self.add_ledger_entries_to_db_cache(&vec![ledger_entry]);
if let Some(total) = self.rune_total_mints_cache.get_mut(rune_id) {
*total += 1;
} else {
self.rune_total_mints_cache.put(rune_id.clone(), 1);
}
}
}

pub async fn apply_edict(&mut self, edict: &Edict, db_tx: &mut Transaction<'_>, ctx: &Context) {
Expand Down Expand Up @@ -215,6 +247,32 @@ impl IndexCache {
return Some(db_rune);
}

async fn get_cached_rune_total_mints(
&mut self,
rune_id: &RuneId,
db_tx: &mut Transaction<'_>,
ctx: &Context,
) -> Option<u128> {
let real_rune_id = if rune_id.block == 0 && rune_id.tx == 0 {
let Some(etching) = self.tx_cache.etching.as_ref() else {
return None;
};
RuneId::from_str(etching.id.as_str()).unwrap()
} else {
rune_id.clone()
};
if let Some(total) = self.rune_total_mints_cache.get(&real_rune_id) {
return Some(*total);
}
// Cache miss, look in DB.
self.db_cache.flush(db_tx, ctx).await;
let Some(total) = pg_get_rune_total_mints(rune_id, db_tx, ctx).await else {
return None;
};
self.rune_total_mints_cache.put(rune_id.clone(), total);
return Some(total);
}

/// Takes all transaction inputs and transform them into rune balances to be allocated.
async fn scan_tx_input_rune_balance(
&mut self,
Expand Down
46 changes: 33 additions & 13 deletions src/db/cache/transaction_cache.rs
Original file line number Diff line number Diff line change
Expand Up @@ -233,57 +233,77 @@ impl TransactionCache {
pub fn apply_mint(
&mut self,
rune_id: &RuneId,
total_mints: u128,
db_rune: &DbRune,
ctx: &Context,
) -> DbLedgerEntry {
) -> Option<DbLedgerEntry> {
// TODO: What's the default mint amount if none was provided?
let mint_amount = db_rune.terms_amount.unwrap_or(PgNumericU128(0));
let terms_amount = db_rune.terms_amount.unwrap_or(PgNumericU128(0));
if let Some(terms_cap) = db_rune.terms_cap {
if total_mints >= terms_cap.0 {
debug!(
ctx.expect_logger(),
"Mint {} exceeds mint cap, ignoring {}", rune_id, self.location
);
return None;
}
}
info!(
ctx.expect_logger(),
"MINT {} ({}) {} {}", rune_id, db_rune.spaced_name, mint_amount.0, self.location
"MINT {} ({}) {} {}", rune_id, db_rune.spaced_name, terms_amount.0, self.location
);
self.add_input_runes(
rune_id,
InputRuneBalance {
address: None,
amount: mint_amount.0,
amount: terms_amount.0,
},
);
new_ledger_entry(
Some(new_ledger_entry(
&self.location,
mint_amount.0,
terms_amount.0,
rune_id.clone(),
None,
None,
None,
DbLedgerOperation::Mint,
&mut self.next_event_index,
)
))
}

pub fn apply_cenotaph_mint(
&mut self,
rune_id: &RuneId,
total_mints: u128,
db_rune: &DbRune,
ctx: &Context,
) -> DbLedgerEntry {
) -> Option<DbLedgerEntry> {
// TODO: What's the default mint amount if none was provided?
let mint_amount = db_rune.terms_amount.unwrap_or(PgNumericU128(0));
let terms_amount = db_rune.terms_amount.unwrap_or(PgNumericU128(0));
if let Some(terms_cap) = db_rune.terms_cap {
if total_mints >= terms_cap.0 {
debug!(
ctx.expect_logger(),
"Cenotaph mint {} exceeds mint cap, ignoring {}", rune_id, self.location
);
return None;
}
}
info!(
ctx.expect_logger(),
"CENOTAPH MINT {} {} {}", db_rune.spaced_name, mint_amount.0, self.location
"CENOTAPH MINT {} {} {}", db_rune.spaced_name, terms_amount.0, self.location
);
// This entry does not go in the input runes, it gets burned immediately.
new_ledger_entry(
Some(new_ledger_entry(
&self.location,
mint_amount.0,
terms_amount.0,
rune_id.clone(),
None,
None,
None,
DbLedgerOperation::Burn,
&mut self.next_event_index,
)
))
}

pub fn apply_edict(&mut self, edict: &Edict, ctx: &Context) -> Vec<DbLedgerEntry> {
Expand Down
26 changes: 26 additions & 0 deletions src/db/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -337,6 +337,32 @@ pub async fn pg_get_rune_by_id(
Some(DbRune::from_pg_row(&row))
}

pub async fn pg_get_rune_total_mints(
id: &RuneId,
db_tx: &mut Transaction<'_>,
ctx: &Context,
) -> Option<u128> {
let row = match db_tx
.query_opt("SELECT total_mints FROM runes WHERE id = $1", &[&id.to_string()])
.await
{
Ok(row) => row,
Err(e) => {
error!(
ctx.expect_logger(),
"error retrieving rune minted total: {}",
e.to_string()
);
panic!();
}
};
let Some(row) = row else {
return None;
};
let minted: PgNumericU128 = row.get("total_mints");
Some(minted.0)
}

pub async fn pg_get_missed_input_rune_balances(
outputs: Vec<(u32, String, u32)>,
db_tx: &mut Transaction<'_>,
Expand Down
18 changes: 9 additions & 9 deletions src/db/models/db_rune.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,10 @@ pub struct DbRune {
pub terms_offset_end: Option<PgNumericU64>,
pub turbo: bool,
pub minted: PgNumericU128,
pub total_mints: PgBigIntU32,
pub total_mints: PgNumericU128,
pub burned: PgNumericU128,
pub total_burns: PgBigIntU32,
pub total_operations: PgBigIntU32,
pub total_burns: PgNumericU128,
pub total_operations: PgNumericU128,
pub timestamp: PgBigIntU32,
}

Expand Down Expand Up @@ -93,10 +93,10 @@ impl DbRune {
terms_offset_end,
turbo: etching.turbo,
minted: PgNumericU128(0),
total_mints: PgBigIntU32(0),
total_mints: PgNumericU128(0),
burned: PgNumericU128(0),
total_burns: PgBigIntU32(0),
total_operations: PgBigIntU32(0),
total_burns: PgNumericU128(0),
total_operations: PgNumericU128(0),
timestamp: PgBigIntU32(location.timestamp),
}
}
Expand All @@ -122,10 +122,10 @@ impl DbRune {
terms_offset_end: None,
turbo: false,
minted: PgNumericU128(0),
total_mints: PgBigIntU32(0),
total_mints: PgNumericU128(0),
burned: PgNumericU128(0),
total_burns: PgBigIntU32(0),
total_operations: PgBigIntU32(0),
total_burns: PgNumericU128(0),
total_operations: PgNumericU128(0),
timestamp: PgBigIntU32(location.timestamp),
}
}
Expand Down
26 changes: 13 additions & 13 deletions src/db/models/db_rune_update.rs
Original file line number Diff line number Diff line change
@@ -1,47 +1,47 @@
use crate::db::types::{pg_bigint_u32::PgBigIntU32, pg_numeric_u128::PgNumericU128};
use crate::db::types::pg_numeric_u128::PgNumericU128;

/// An update to a rune that affects its total counts.
#[derive(Debug, Clone)]
pub struct DbRuneUpdate {
pub id: String,
pub minted: PgNumericU128,
pub total_mints: PgBigIntU32,
pub total_mints: PgNumericU128,
pub burned: PgNumericU128,
pub total_burns: PgBigIntU32,
pub total_operations: PgBigIntU32,
pub total_burns: PgNumericU128,
pub total_operations: PgNumericU128,
}

impl DbRuneUpdate {
pub fn from_mint(id: String, amount: PgNumericU128) -> Self {
DbRuneUpdate {
id,
minted: amount,
total_mints: PgBigIntU32(1),
total_mints: PgNumericU128(1),
burned: PgNumericU128(0),
total_burns: PgBigIntU32(0),
total_operations: PgBigIntU32(1),
total_burns: PgNumericU128(0),
total_operations: PgNumericU128(1),
}
}

pub fn from_burn(id: String, amount: PgNumericU128) -> Self {
DbRuneUpdate {
id,
minted: PgNumericU128(0),
total_mints: PgBigIntU32(0),
total_mints: PgNumericU128(0),
burned: amount,
total_burns: PgBigIntU32(1),
total_operations: PgBigIntU32(1),
total_burns: PgNumericU128(1),
total_operations: PgNumericU128(1),
}
}

pub fn from_operation(id: String) -> Self {
DbRuneUpdate {
id,
minted: PgNumericU128(0),
total_mints: PgBigIntU32(0),
total_mints: PgNumericU128(0),
burned: PgNumericU128(0),
total_burns: PgBigIntU32(0),
total_operations: PgBigIntU32(1),
total_burns: PgNumericU128(0),
total_operations: PgNumericU128(1),
}
}
}
6 changes: 6 additions & 0 deletions src/db/types/pg_numeric_u128.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,12 @@ impl AddAssign for PgNumericU128 {
}
}

impl AddAssign<u128> for PgNumericU128 {
fn add_assign(&mut self, other: u128) {
self.0 += other;
}
}

#[cfg(test)]
mod test {
use test_case::test_case;
Expand Down

0 comments on commit 909b59e

Please sign in to comment.