Skip to content

Commit

Permalink
Merge pull request #25 from hirosystems/develop
Browse files Browse the repository at this point in the history
release to beta
  • Loading branch information
rafaelcr authored Jul 8, 2024
2 parents 03c7ebd + 68784da commit 7857b78
Show file tree
Hide file tree
Showing 7 changed files with 501 additions and 506 deletions.
7 changes: 7 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,13 @@ jobs:
fetch-depth: 0
persist-credentials: false

- name: Checkout tag
if: needs.semantic-release.outputs.new_release_version != ''
uses: actions/checkout@v4
with:
persist-credentials: false
ref: v${{ needs.semantic-release.outputs.new_release_version }}

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

Expand Down
19 changes: 11 additions & 8 deletions api/src/pg/pg-store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -144,12 +144,15 @@ export class PgStore extends BasePgStore {
cte?: PgSqlQuery
): Promise<DbPaginatedResult<DbItemWithRune<DbLedgerEntry>>> {
const results = await this.sql<DbCountedQueryResult<DbItemWithRune<DbLedgerEntry>>[]>`
${cte ? cte : this.sql``}
SELECT l.*, r.name, r.spaced_name, r.divisibility, ${count} AS total
FROM ledger AS l
INNER JOIN runes AS r ON r.id = l.rune_id
WHERE ${filter}
ORDER BY l.block_height DESC, l.tx_index DESC, l.event_index DESC
WITH ${cte ? cte : this.sql`none AS (SELECT NULL)`},
results AS (
SELECT l.*, r.name, r.spaced_name, r.divisibility, ${count} AS total
FROM ledger AS l
INNER JOIN runes AS r ON r.id = l.rune_id
WHERE ${filter}
)
SELECT * FROM results
ORDER BY block_height DESC, tx_index DESC, event_index DESC
OFFSET ${offset} LIMIT ${limit}
`;
return {
Expand All @@ -164,7 +167,7 @@ export class PgStore extends BasePgStore {
this.sql`COALESCE((SELECT total_operations FROM count), 0)`,
offset,
limit,
this.sql`WITH count AS (
this.sql`count AS (
SELECT total_operations FROM supply_changes
WHERE rune_id = (SELECT id FROM runes WHERE ${runeFilter(this.sql, runeId)})
ORDER BY block_height DESC LIMIT 1
Expand All @@ -187,7 +190,7 @@ export class PgStore extends BasePgStore {
this.sql`COALESCE((SELECT total_operations FROM count), 0)`,
offset,
limit,
this.sql`WITH recent AS (
this.sql`recent AS (
SELECT DISTINCT ON (rune_id) total_operations
FROM balance_changes
WHERE address = ${address}
Expand Down
2 changes: 1 addition & 1 deletion migrations/V1__runes.sql
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ CREATE TABLE IF NOT EXISTS runes (
id TEXT NOT NULL PRIMARY KEY,
number BIGINT NOT NULL UNIQUE,
name TEXT NOT NULL UNIQUE,
spaced_name TEXT NOT NULL,
spaced_name TEXT NOT NULL UNIQUE,
block_hash TEXT NOT NULL,
block_height NUMERIC NOT NULL,
tx_index BIGINT NOT NULL,
Expand Down
117 changes: 64 additions & 53 deletions src/db/cache/index_cache.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
use std::{collections::HashMap, num::NonZeroUsize, str::FromStr};

use bitcoin::Network;
use chainhook_sdk::{
types::bitcoin::{TxIn, TxOut},
utils::Context,
};
use bitcoin::{Network, ScriptBuf};
use chainhook_sdk::{types::bitcoin::TxIn, utils::Context};
use lru::LruCache;
use ordinals::{Cenotaph, Edict, Etching, Rune, RuneId, Runestone};
use tokio_postgres::{Client, Transaction};
Expand All @@ -26,13 +23,14 @@ use crate::{
use super::{
db_cache::DbCache,
transaction_cache::{InputRuneBalance, TransactionCache},
utils::move_tx_output_cache_to_output_cache,
transaction_location::TransactionLocation,
utils::move_block_output_cache_to_output_cache,
};

/// Holds rune data across multiple blocks for faster computations. Processes rune events as they happen during transactions and
/// generates database rows for later insertion.
pub struct IndexCache {
network: Network,
pub network: Network,
/// Number to be assigned to the next rune etching.
next_rune_number: u32,
/// LRU cache for runes.
Expand All @@ -41,9 +39,9 @@ pub struct IndexCache {
rune_total_mints_cache: LruCache<RuneId, u128>,
/// LRU cache for outputs with rune balances.
output_cache: LruCache<(String, u32), HashMap<RuneId, Vec<InputRuneBalance>>>,
/// Same as above but only for the current transaction. We use a `HashMap` instead of an LRU cache to make sure we keep all
/// outputs in memory while we index this transaction. Must be cleared every time a new transaction is processed.
tx_output_cache: HashMap<(String, u32), HashMap<RuneId, Vec<InputRuneBalance>>>,
/// Same as above but only for the current block. We use a `HashMap` instead of an LRU cache to make sure we keep all outputs
/// in memory while we index this block. Must be cleared every time a new block is processed.
block_output_cache: HashMap<(String, u32), HashMap<RuneId, Vec<InputRuneBalance>>>,
/// Holds a single transaction's rune cache. Must be cleared every time a new transaction is processed.
tx_cache: TransactionCache,
/// Keeps rows that have not yet been inserted in the DB.
Expand All @@ -60,8 +58,21 @@ impl IndexCache {
rune_cache: LruCache::new(cap),
rune_total_mints_cache: LruCache::new(cap),
output_cache: LruCache::new(cap),
tx_output_cache: HashMap::new(),
tx_cache: TransactionCache::new(network, &"".to_string(), 1, 0, &"".to_string(), 0),
block_output_cache: HashMap::new(),
tx_cache: TransactionCache::new(
TransactionLocation {
network,
block_hash: "".to_string(),
block_height: 1,
timestamp: 0,
tx_index: 0,
tx_id: "".to_string(),
},
HashMap::new(),
HashMap::new(),
None,
0,
),
db_cache: DbCache::new(),
}
}
Expand All @@ -73,69 +84,69 @@ impl IndexCache {
/// Creates a fresh transaction index cache.
pub async fn begin_transaction(
&mut self,
block_hash: &String,
block_height: u64,
tx_index: u32,
tx_id: &String,
timestamp: u32,
location: TransactionLocation,
tx_inputs: &Vec<TxIn>,
eligible_outputs: HashMap<u32, ScriptBuf>,
first_eligible_output: Option<u32>,
total_outputs: u32,
db_tx: &mut Transaction<'_>,
ctx: &Context,
) {
let input_runes = input_rune_balances_from_tx_inputs(
tx_inputs,
&self.block_output_cache,
&mut self.output_cache,
db_tx,
ctx,
)
.await;
#[cfg(not(feature = "release"))]
{
for (rune_id, balances) in input_runes.iter() {
try_debug!(ctx, "INPUT {rune_id} {balances:?} {location}");
}
if input_runes.len() > 0 {
try_debug!(ctx, "First output: {first_eligible_output:?}, total_outputs: {total_outputs}");
}
}
self.tx_cache = TransactionCache::new(
self.network,
block_hash,
block_height,
tx_index,
tx_id,
timestamp,
location,
input_runes,
eligible_outputs,
first_eligible_output,
total_outputs,
);
self.tx_output_cache.clear();
}

/// Finalizes the current transaction index cache.
/// Finalizes the current transaction index cache by moving all unallocated balances to the correct output.
pub fn end_transaction(&mut self, _db_tx: &mut Transaction<'_>, ctx: &Context) {
let entries = self.tx_cache.allocate_remaining_balances(ctx);
self.add_ledger_entries_to_db_cache(&entries);
move_tx_output_cache_to_output_cache(&mut self.tx_output_cache, &mut self.output_cache);
}

pub fn end_block(&mut self) {
move_block_output_cache_to_output_cache(&mut self.block_output_cache, &mut self.output_cache);
}

pub async fn apply_runestone(
&mut self,
runestone: &Runestone,
tx_inputs: &Vec<TxIn>,
tx_outputs: &Vec<TxOut>,
db_tx: &mut Transaction<'_>,
_db_tx: &mut Transaction<'_>,
ctx: &Context,
) {
try_debug!(ctx, "{:?} {}", runestone, self.tx_cache.location);
let input_balances = input_rune_balances_from_tx_inputs(
tx_inputs,
&self.tx_output_cache,
&mut self.output_cache,
db_tx,
ctx,
)
.await;
self.tx_cache.set_input_rune_balances(input_balances, ctx);
self.tx_cache
.apply_runestone_pointer(runestone, tx_outputs, ctx);
if let Some(new_pointer) = runestone.pointer {
self.tx_cache.output_pointer = Some(new_pointer);
}
}

pub async fn apply_cenotaph(
&mut self,
cenotaph: &Cenotaph,
tx_inputs: &Vec<TxIn>,
db_tx: &mut Transaction<'_>,
_db_tx: &mut Transaction<'_>,
ctx: &Context,
) {
try_debug!(ctx, "{:?} {}", cenotaph, self.tx_cache.location);
let input_balances = input_rune_balances_from_tx_inputs(
tx_inputs,
&self.tx_output_cache,
&mut self.output_cache,
db_tx,
ctx,
)
.await;
self.tx_cache.set_input_rune_balances(input_balances, ctx);
let entries = self.tx_cache.apply_cenotaph_input_burn(cenotaph);
self.add_ledger_entries_to_db_cache(&entries);
}
Expand Down Expand Up @@ -407,7 +418,7 @@ impl IndexCache {
address,
entry.amount.unwrap(),
));
// Add to current transaction's output cache if it's received balance.
// Add to current block's output cache if it's received balance.
let k = (entry.tx_id.clone(), entry.output.unwrap().0);
let rune_id = RuneId::from_str(entry.rune_id.as_str()).unwrap();
let balance = InputRuneBalance {
Expand All @@ -416,7 +427,7 @@ impl IndexCache {
};
let mut default = HashMap::new();
default.insert(rune_id, vec![balance.clone()]);
self.tx_output_cache
self.block_output_cache
.entry(k)
.and_modify(|i| {
i.entry(rune_id)
Expand Down
Loading

0 comments on commit 7857b78

Please sign in to comment.