Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

brc20 utxo assets index #34

Merged
merged 4 commits into from
Mar 31, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 21 additions & 10 deletions src/index.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use crate::okx::datastore::brc20::redb::table::{
get_balance, get_balances, get_token_info, get_tokens_info, get_transaction_receipts,
get_transferable, get_transferable_by_tick,
get_transferable_assets_by_account, get_transferable_assets_by_account_ticker,
get_transferable_assets_by_outpoint,
};
use crate::okx::datastore::ord::redb::table::{
get_collection_inscription_id, get_collections_of_inscription, get_transaction_operations,
Expand Down Expand Up @@ -95,13 +96,13 @@ define_table! { WRITE_TRANSACTION_STARTING_BLOCK_COUNT_TO_TIMESTAMP, u32, u128 }
// new
define_table! { ORD_TX_TO_OPERATIONS, &TxidValue, &[u8] }
define_table! { COLLECTIONS_KEY_TO_INSCRIPTION_ID, &str, InscriptionIdValue }
define_table! { COLLECTIONS_INSCRIPTION_ID_TO_KINDS, InscriptionIdValue, &[u8] }
define_multimap_table! { COLLECTIONS_INSCRIPTION_ID_TO_KINDS, InscriptionIdValue, &[u8] }

define_table! { BRC20_BALANCES, &str, &[u8] }
define_table! { BRC20_TOKEN, &str, &[u8] }
define_table! { BRC20_EVENTS, &TxidValue, &[u8] }
define_table! { BRC20_TRANSFERABLELOG, &str, &[u8] }
define_table! { BRC20_INSCRIBE_TRANSFER, InscriptionIdValue, &[u8] }
define_table! { BRC20_SATPOINT_TO_TRANSFERABLE_ASSETS, &SatPointValue, &[u8] }
define_multimap_table! { BRC20_ADDRESS_TICKER_TO_TRANSFERABLE_ASSETS, &str, &SatPointValue }

#[derive(Debug, PartialEq)]
pub enum List {
Expand Down Expand Up @@ -359,14 +360,14 @@ impl Index {
// new ord tables
tx.open_table(ORD_TX_TO_OPERATIONS)?;
tx.open_table(COLLECTIONS_KEY_TO_INSCRIPTION_ID)?;
tx.open_table(COLLECTIONS_INSCRIPTION_ID_TO_KINDS)?;
tx.open_multimap_table(COLLECTIONS_INSCRIPTION_ID_TO_KINDS)?;

// brc20 tables
tx.open_multimap_table(BRC20_ADDRESS_TICKER_TO_TRANSFERABLE_ASSETS)?;
tx.open_table(BRC20_BALANCES)?;
tx.open_table(BRC20_TOKEN)?;
tx.open_table(BRC20_EVENTS)?;
tx.open_table(BRC20_TRANSFERABLELOG)?;
tx.open_table(BRC20_INSCRIBE_TRANSFER)?;
tx.open_table(BRC20_SATPOINT_TO_TRANSFERABLE_ASSETS)?;

{
let mut outpoint_to_sat_ranges = tx.open_table(OUTPOINT_TO_SAT_RANGES)?;
Expand Down Expand Up @@ -637,7 +638,7 @@ impl Index {
total_bytes,
COLLECTIONS_KEY_TO_INSCRIPTION_ID,
);
insert_table_info(
insert_multimap_table_info(
&mut tables,
&wtx,
total_bytes,
Expand All @@ -646,8 +647,18 @@ impl Index {
insert_table_info(&mut tables, &wtx, total_bytes, BRC20_BALANCES);
insert_table_info(&mut tables, &wtx, total_bytes, BRC20_TOKEN);
insert_table_info(&mut tables, &wtx, total_bytes, BRC20_EVENTS);
insert_table_info(&mut tables, &wtx, total_bytes, BRC20_TRANSFERABLELOG);
insert_table_info(&mut tables, &wtx, total_bytes, BRC20_INSCRIBE_TRANSFER);
insert_table_info(
&mut tables,
&wtx,
total_bytes,
BRC20_SATPOINT_TO_TRANSFERABLE_ASSETS,
);
insert_multimap_table_info(
&mut tables,
&wtx,
total_bytes,
BRC20_ADDRESS_TICKER_TO_TRANSFERABLE_ASSETS,
);

for table in wtx.list_tables()? {
assert!(tables.contains_key(table.name()));
Expand Down
2 changes: 1 addition & 1 deletion src/index/entry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -325,7 +325,7 @@ impl Entry for OutPoint {
}
}

pub(super) type SatPointValue = [u8; 44];
pub(crate) type SatPointValue = [u8; 44];

impl Entry for SatPoint {
type Value = SatPointValue;
Expand Down
112 changes: 111 additions & 1 deletion src/index/extend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ impl Index {
tick: brc20::Tick,
script_key: ScriptKey,
rtx: &Rtx,
) -> Result<Option<Vec<brc20::TransferableLog>>> {
) -> Result<Option<Vec<(SatPoint, brc20::TransferableLog)>>> {
let transferable_utxo_assets = rtx.brc20_get_tick_transferable_by_address(&tick, script_key)?;

if transferable_utxo_assets.is_empty() {
Expand Down Expand Up @@ -267,4 +267,114 @@ impl Index {
)
}
}

pub(crate) fn list_sat_range(
rtx: &Rtx,
outpoint: OutPoint,
index_sats: bool,
) -> Result<Option<Vec<SatRange>>> {
if !index_sats || outpoint == unbound_outpoint() {
return Ok(None);
}

let sat_ranges = rtx.list_sat_range(outpoint.store())?;

match sat_ranges {
Some(sat_ranges) => Ok(Some(
sat_ranges
.chunks_exact(11)
.map(|chunk| SatRange::load(chunk.try_into().unwrap()))
.collect(),
)),
None => Ok(None),
}
}

pub(crate) fn calculate_rarity_for_sat_range(sat_range: SatRange) -> Vec<(Sat, Rarity)> {
let start_sat = Sat(sat_range.0);
let end_sat = Sat(sat_range.1);

let start_height = if start_sat.third() > 0 {
start_sat.height().0 + 1
} else {
start_sat.height().0
};
let end_height = if end_sat.third() > 0 {
end_sat.height().0
} else {
end_sat.height().0 - 1
};

let mut result = Vec::new();
for height in start_height..=end_height {
let sat = Height(height).starting_sat();
let rarity = sat.rarity();
result.push((sat, rarity));
}
result
}
}

#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_calculate_rarity_for_sat_range_mythic() {
let sat_range: SatRange = (0, 100);
let rarity = Index::calculate_rarity_for_sat_range(sat_range);
assert_eq!(rarity, vec![(Sat(0), Rarity::Mythic)]);
let sat_range: SatRange = (1, 100);
let rarity = Index::calculate_rarity_for_sat_range(sat_range);
assert_eq!(rarity, vec![]);
}
#[test]
fn test_legendary_sat() {
let sat_range: SatRange = (
Height(SUBSIDY_HALVING_INTERVAL * 6).starting_sat().0,
Height(SUBSIDY_HALVING_INTERVAL * 6).starting_sat().0 + 1,
);
let rarity = Index::calculate_rarity_for_sat_range(sat_range);
assert_eq!(rarity, vec![(Sat(2067187500000000), Rarity::Legendary)]);
}
#[test]
fn test_epic_sat() {
let sat_range: SatRange = (
Height(SUBSIDY_HALVING_INTERVAL).starting_sat().0,
Height(SUBSIDY_HALVING_INTERVAL).starting_sat().0 + 1,
);
let rarity = Index::calculate_rarity_for_sat_range(sat_range);
assert_eq!(rarity, vec![(Sat(1050000000000000), Rarity::Epic)]);
}

#[test]
fn test_rare_sat() {
let sat_range: SatRange = (
Height(DIFFCHANGE_INTERVAL).starting_sat().0,
Height(DIFFCHANGE_INTERVAL).starting_sat().0 + 1,
);
let rarity = Index::calculate_rarity_for_sat_range(sat_range);
assert_eq!(rarity, vec![(Sat(10080000000000), Rarity::Rare)]);
}

#[test]
fn test_two_rarity_sat() {
let sat_range: SatRange = (0, 4999999999);
let rarity = Index::calculate_rarity_for_sat_range(sat_range);
assert_eq!(rarity, vec![(Sat(0), Rarity::Mythic)]);
let sat_range: SatRange = (0, 5000000000);
let rarity = Index::calculate_rarity_for_sat_range(sat_range);
assert_eq!(rarity, vec![(Sat(0), Rarity::Mythic)]);
let sat_range: SatRange = (0, 5000000001);
let rarity = Index::calculate_rarity_for_sat_range(sat_range);
assert_eq!(
rarity,
vec![
(Sat(0), Rarity::Mythic),
(Sat(5000000000), Rarity::Uncommon)
]
);
let sat_range: SatRange = (1, 5000000001);
let rarity = Index::calculate_rarity_for_sat_range(sat_range);
assert_eq!(rarity, vec![(Sat(5000000000), Rarity::Uncommon)]);
}
}
40 changes: 33 additions & 7 deletions src/index/rtx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,9 @@ impl Rtx<'_> {
&self,
inscription_id: InscriptionId,
) -> Result<Option<Vec<CollectionKind>>> {
let table = self.0.open_table(COLLECTIONS_INSCRIPTION_ID_TO_KINDS)?;
let table = self
.0
.open_multimap_table(COLLECTIONS_INSCRIPTION_ID_TO_KINDS)?;
get_collections_of_inscription(&table, &inscription_id)
}

Expand Down Expand Up @@ -219,16 +221,40 @@ impl Rtx<'_> {
&self,
tick: &brc20::Tick,
script_key: ScriptKey,
) -> Result<Vec<brc20::TransferableLog>> {
let table = self.0.open_table(BRC20_TRANSFERABLELOG)?;
get_transferable_by_tick(&table, &script_key, tick)
) -> Result<Vec<(SatPoint, brc20::TransferableLog)>> {
let address_table = self
.0
.open_multimap_table(BRC20_ADDRESS_TICKER_TO_TRANSFERABLE_ASSETS)?;
let satpoint_table = self.0.open_table(BRC20_SATPOINT_TO_TRANSFERABLE_ASSETS)?;
get_transferable_assets_by_account_ticker(&address_table, &satpoint_table, &script_key, tick)
}

pub(crate) fn brc20_get_all_transferable_by_address(
&self,
script_key: ScriptKey,
) -> Result<Vec<brc20::TransferableLog>> {
let table = self.0.open_table(BRC20_TRANSFERABLELOG)?;
get_transferable(&table, &script_key)
) -> Result<Vec<(SatPoint, brc20::TransferableLog)>> {
let address_table = self
.0
.open_multimap_table(BRC20_ADDRESS_TICKER_TO_TRANSFERABLE_ASSETS)?;
let satpoint_table = self.0.open_table(BRC20_SATPOINT_TO_TRANSFERABLE_ASSETS)?;
get_transferable_assets_by_account(&address_table, &satpoint_table, &script_key)
}

pub(crate) fn brc20_transferable_assets_on_output_with_satpoints(
&self,
outpoint: OutPoint,
) -> Result<Vec<(SatPoint, brc20::TransferableLog)>> {
let satpoint_to_sequence_number = self.0.open_table(BRC20_SATPOINT_TO_TRANSFERABLE_ASSETS)?;
get_transferable_assets_by_outpoint(&satpoint_to_sequence_number, outpoint)
}

pub(super) fn list_sat_range(&self, outpoint: OutPointValue) -> Result<Option<Vec<u8>>> {
Ok(
self
.0
.open_table(OUTPOINT_TO_SAT_RANGES)?
.get(&outpoint)?
.map(|outpoint| outpoint.value().to_vec()),
)
}
}
8 changes: 5 additions & 3 deletions src/index/updater.rs
Original file line number Diff line number Diff line change
Expand Up @@ -632,14 +632,16 @@ impl<'index> Updater<'_> {
ORD_TX_TO_OPERATIONS: &mut wtx.open_table(ORD_TX_TO_OPERATIONS)?,
COLLECTIONS_KEY_TO_INSCRIPTION_ID: &mut wtx.open_table(COLLECTIONS_KEY_TO_INSCRIPTION_ID)?,
COLLECTIONS_INSCRIPTION_ID_TO_KINDS: &mut wtx
.open_table(COLLECTIONS_INSCRIPTION_ID_TO_KINDS)?,
.open_multimap_table(COLLECTIONS_INSCRIPTION_ID_TO_KINDS)?,
SEQUENCE_NUMBER_TO_INSCRIPTION_ENTRY: &mut sequence_number_to_inscription_entry,
OUTPOINT_TO_ENTRY: &mut outpoint_to_entry,
BRC20_BALANCES: &mut wtx.open_table(BRC20_BALANCES)?,
BRC20_TOKEN: &mut wtx.open_table(BRC20_TOKEN)?,
BRC20_EVENTS: &mut wtx.open_table(BRC20_EVENTS)?,
BRC20_TRANSFERABLELOG: &mut wtx.open_table(BRC20_TRANSFERABLELOG)?,
BRC20_INSCRIBE_TRANSFER: &mut wtx.open_table(BRC20_INSCRIBE_TRANSFER)?,
BRC20_SATPOINT_TO_TRANSFERABLE_ASSETS: &mut wtx
.open_table(BRC20_SATPOINT_TO_TRANSFERABLE_ASSETS)?,
BRC20_ADDRESS_TICKER_TO_TRANSFERABLE_ASSETS: &mut wtx
.open_multimap_table(BRC20_ADDRESS_TICKER_TO_TRANSFERABLE_ASSETS)?,
};

// Create a protocol manager to index the block of bitmap data.
Expand Down
53 changes: 18 additions & 35 deletions src/okx/datastore/brc20/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,15 @@ pub(super) mod events;
pub mod redb;
pub(super) mod tick;
pub(super) mod token_info;
pub(super) mod transfer;
pub(super) mod transferable_log;

pub use self::{
balance::Balance, errors::BRC20Error, events::Receipt, events::*, tick::*, token_info::TokenInfo,
transfer::TransferInfo, transferable_log::TransferableLog,
transferable_log::TransferableLog,
};
use super::ScriptKey;
use crate::{InscriptionId, Result};
use bitcoin::Txid;
use crate::{Result, SatPoint};
use bitcoin::{OutPoint, Txid};
use std::fmt::{Debug, Display};

pub trait Brc20Reader {
Expand All @@ -31,22 +30,23 @@ pub trait Brc20Reader {

fn get_transaction_receipts(&self, txid: &Txid) -> Result<Option<Vec<Receipt>>, Self::Error>;

fn get_transferable(&self, script: &ScriptKey) -> Result<Vec<TransferableLog>, Self::Error>;
fn get_transferable_by_tick(
fn get_transferable_assets_by_satpoint(
&self,
satpoint: &SatPoint,
) -> Result<Option<TransferableLog>, Self::Error>;
fn get_transferable_assets_by_account(
&self,
script: &ScriptKey,
tick: &Tick,
) -> Result<Vec<TransferableLog>, Self::Error>;
fn get_transferable_by_id(
) -> Result<Vec<(SatPoint, TransferableLog)>, Self::Error>;
fn get_transferable_assets_by_account_ticker(
&self,
script: &ScriptKey,
inscription_id: &InscriptionId,
) -> Result<Option<TransferableLog>, Self::Error>;

fn get_inscribe_transfer_inscription(
tick: &Tick,
) -> Result<Vec<(SatPoint, TransferableLog)>, Self::Error>;
fn get_transferable_assets_by_outpoint(
&self,
inscription_id: &InscriptionId,
) -> Result<Option<TransferInfo>, Self::Error>;
outpoint: OutPoint,
) -> Result<Vec<(SatPoint, TransferableLog)>, Self::Error>;
}

pub trait Brc20ReaderWriter: Brc20Reader {
Expand All @@ -71,28 +71,11 @@ pub trait Brc20ReaderWriter: Brc20Reader {
receipt: &[Receipt],
) -> Result<(), Self::Error>;

fn insert_transferable(
fn insert_transferable_asset(
&mut self,
script: &ScriptKey,
tick: &Tick,
satpoint: SatPoint,
inscription: &TransferableLog,
) -> Result<(), Self::Error>;

fn remove_transferable(
&mut self,
script: &ScriptKey,
tick: &Tick,
inscription_id: &InscriptionId,
) -> Result<(), Self::Error>;

fn insert_inscribe_transfer_inscription(
&mut self,
inscription_id: &InscriptionId,
transfer_info: TransferInfo,
) -> Result<(), Self::Error>;

fn remove_inscribe_transfer_inscription(
&mut self,
inscription_id: &InscriptionId,
) -> Result<(), Self::Error>;
fn remove_transferable_asset(&mut self, satpoint: SatPoint) -> Result<(), Self::Error>;
}
10 changes: 0 additions & 10 deletions src/okx/datastore/brc20/redb/mod.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,6 @@
pub mod table;

use super::{LowerTick, ScriptKey, Tick};
use crate::inscriptions::InscriptionId;

fn script_tick_id_key(script: &ScriptKey, tick: &Tick, inscription_id: &InscriptionId) -> String {
format!(
"{}_{}_{}",
script,
tick.to_lowercase().hex(),
inscription_id
)
}

fn min_script_tick_id_key(script: &ScriptKey, tick: &Tick) -> String {
script_tick_key(script, tick)
Expand Down
Loading
Loading