Skip to content
Open
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
34 changes: 34 additions & 0 deletions src/indexer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ use metashrew::{
};
use protorune::Protorune;
use protorune_support::network::{set_network, NetworkParams};
use crate::tables::BLOCK_TRACES_CACHE;
use crate::tables::BLOCK_TRACES;
use std::sync::Arc;
use metashrew_support::index_pointer::KeyValuePointer;

#[cfg(all(
not(feature = "mainnet"),
Expand Down Expand Up @@ -68,12 +72,42 @@ pub fn configure_network() {
}

pub fn index_block(block: &Block, height: u32) -> Result<()> {
// Reset the BlockTrace cache at the beginning of each block
BLOCK_TRACES_CACHE.write().unwrap().clear();

configure_network();
let really_is_genesis = is_genesis(height.into());
if really_is_genesis {
genesis(&block).unwrap();
}
FuelTank::initialize(&block);
Protorune::index_block::<AlkaneMessageContext>(block.clone(), height.into())?;

// Save the complete BlockTrace to persistent storage
save_trace_block(height.into())?;

Ok(())
}

// Function to save the complete BlockTrace to persistent storage
fn save_trace_block(height: u64) -> Result<()> {
// Get the cached BlockTrace
let cached_bytes = {
let cache = BLOCK_TRACES_CACHE.read().unwrap();
if let Some(bytes) = cache.get(&height) {
bytes.clone()
} else {
// If no events were processed for this block, create an empty BlockTrace
use alkanes_support::proto::alkanes::AlkanesBlockTraceEvent;
use protobuf::Message;

let empty_trace = AlkanesBlockTraceEvent::new();
empty_trace.write_to_bytes()?
}
};

// Store in the persistent BLOCK_TRACES table
BLOCK_TRACES.select_value::<u64>(height).set(Arc::new(cached_bytes));

Ok(())
}
12 changes: 12 additions & 0 deletions src/tables.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,20 @@
use metashrew::index_pointer::IndexPointer;
use metashrew_support::index_pointer::KeyValuePointer;
use once_cell::sync::Lazy;
use std::collections::HashMap;
use std::sync::RwLock;
use protobuf::Message;
use alkanes_support::proto;

pub static TRACES: Lazy<IndexPointer> = Lazy::new(|| IndexPointer::from_keyword("/trace/"));

pub static TRACES_BY_HEIGHT: Lazy<IndexPointer> =
Lazy::new(|| IndexPointer::from_keyword("/trace/"));

// New table for storing complete BlockTrace structures by height
pub static BLOCK_TRACES: Lazy<IndexPointer> =
Lazy::new(|| IndexPointer::from_keyword("/traces/byblock/"));

// Cache for storing complete BlockTrace structures by height
pub static BLOCK_TRACES_CACHE: Lazy<RwLock<HashMap<u64, Vec<u8>>>> =
Lazy::new(|| RwLock::new(HashMap::new()));
57 changes: 51 additions & 6 deletions src/trace.rs
Original file line number Diff line number Diff line change
@@ -1,25 +1,70 @@
use crate::tables::{TRACES, TRACES_BY_HEIGHT};
use crate::tables::{TRACES, TRACES_BY_HEIGHT, BLOCK_TRACES_CACHE};
use alkanes_support::proto;
use alkanes_support::trace::Trace;
use anyhow::Result;
use bitcoin::OutPoint;
use bitcoin::hashes::Hash;
use metashrew_support::index_pointer::KeyValuePointer;
use metashrew_support::utils::consensus_encode;
use protobuf::Message;
use protobuf::{Message, MessageField};
use std::sync::Arc;
#[allow(unused_imports)]
use {
metashrew::{println, stdio::stdout},
std::fmt::Write,
};
use protorune::tables::RUNES;

pub fn save_trace(outpoint: &OutPoint, height: u64, trace: Trace) -> Result<()> {
let buffer: Vec<u8> = consensus_encode::<OutPoint>(outpoint)?;
TRACES.select(&buffer).set(Arc::<Vec<u8>>::new(
<Trace as Into<proto::alkanes::AlkanesTrace>>::into(trace).write_to_bytes()?,
));

// Convert trace to AlkanesTrace protobuf and save to TRACES
let alkanes_trace = <Trace as Into<proto::alkanes::AlkanesTrace>>::into(trace);
let trace_bytes = alkanes_trace.write_to_bytes()?;
TRACES.select(&buffer).set(Arc::<Vec<u8>>::new(trace_bytes.clone()));

// Add to TRACES_BY_HEIGHT
TRACES_BY_HEIGHT
.select_value(height)
.append(Arc::new(buffer));
.append(Arc::new(buffer.clone()));

// Update or create BlockTrace in cache
update_block_trace_cache(outpoint, height, alkanes_trace)?;

Ok(())
}

// Helper function to update the block trace cache
fn update_block_trace_cache(outpoint: &OutPoint, height: u64, trace: proto::alkanes::AlkanesTrace) -> Result<()> {
let txid = outpoint.txid.as_byte_array().to_vec();
let txindex: u32 = RUNES.TXID_TO_TXINDEX.select(&txid).get_value();

// Create block event for this trace
let block_event = proto::alkanes::AlkanesBlockEvent {
txindex: txindex as u64,
outpoint: MessageField::some(proto::alkanes::Outpoint {
txid: outpoint.txid.as_byte_array().to_vec(),
vout: outpoint.vout,
..Default::default()
}),
traces: MessageField::some(trace),
..Default::default()
};

// Get or create block trace
let mut cache = BLOCK_TRACES_CACHE.write().unwrap();
let mut block_trace = if let Some(cached_bytes) = cache.get(&height) {
proto::alkanes::AlkanesBlockTraceEvent::parse_from_bytes(cached_bytes)?
} else {
proto::alkanes::AlkanesBlockTraceEvent::new()
};

// Add the event to the block trace
block_trace.events.push(block_event);

// Serialize and store updated BlockTrace
let serialized = block_trace.write_to_bytes()?;
cache.insert(height, serialized);

Ok(())
}
36 changes: 33 additions & 3 deletions src/view.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::message::AlkaneMessageContext;
use crate::network::set_view_mode;
use crate::tables::{TRACES, TRACES_BY_HEIGHT};
use crate::tables::{BLOCK_TRACES, BLOCK_TRACES_CACHE, TRACES, TRACES_BY_HEIGHT};
use crate::utils::{
alkane_inventory_pointer, balance_pointer, credit_balances, debit_balances, pipe_storagemap_to,
};
Expand Down Expand Up @@ -294,8 +294,29 @@ pub fn alkane_inventory(req: &AlkaneInventoryRequest) -> Result<AlkaneInventoryR
}

pub fn traceblock(height: u32) -> Result<Vec<u8>> {
use crate::tables::{BLOCK_TRACES, BLOCK_TRACES_CACHE};

// First check if we have the data in the persistent storage
let height_u64 = height as u64;

// Try to get data from the persistent BLOCK_TRACES table
let pointer = BLOCK_TRACES.select_value::<u64>(height_u64);
// We'll use the get() method which returns Arc<Vec<u8>> and check if it's empty or not
let stored_data = pointer.get();
if !stored_data.as_ref().is_empty() {
return Ok(stored_data.as_ref().clone());
}

// Then check if we have a cached version (fallback)
if let Some(cached_bytes) = BLOCK_TRACES_CACHE.read().unwrap().get(&height_u64) {
return Ok(cached_bytes.clone());
}

// If not found in storage or cache, rebuild it (fallback - this shouldn't happen if indexer is working correctly)
println!("Warning: BlockTrace for height {} not found in storage or cache, rebuilding...", height);

let mut block_events: Vec<proto::alkanes::AlkanesBlockEvent> = vec![];
for outpoint in TRACES_BY_HEIGHT.select_value(height as u64).get_list() {
for outpoint in TRACES_BY_HEIGHT.select_value(height_u64).get_list() {
let op = outpoint.clone().to_vec();
let outpoint_decoded = consensus_decode::<OutPoint>(&mut Cursor::new(op))?;
let txid = outpoint_decoded.txid.as_byte_array().to_vec();
Expand All @@ -320,7 +341,16 @@ pub fn traceblock(height: u32) -> Result<Vec<u8>> {
..Default::default()
};

result.write_to_bytes().map_err(|e| anyhow!("{:?}", e))
// Serialize the result
let serialized = result.write_to_bytes().map_err(|e| anyhow!("{:?}", e))?;

// Store in cache for future use
BLOCK_TRACES_CACHE.write().unwrap().insert(height_u64, serialized.clone());

// Also store in persistent storage
BLOCK_TRACES.select_value::<u64>(height_u64).set(Arc::new(serialized.clone()));

Ok(serialized)
}

pub fn trace(outpoint: &OutPoint) -> Result<Vec<u8>> {
Expand Down