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

Emit location update events to optional channel #3137

Merged
merged 16 commits into from
Feb 17, 2024
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/*.redb
/.idea/
/.vagrant
/.vscode
/docs/build
/fuzz/artifacts
/fuzz/corpus
Expand Down
89 changes: 88 additions & 1 deletion src/index.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use {
Entry, HeaderValue, InscriptionEntry, InscriptionEntryValue, InscriptionIdValue,
OutPointValue, RuneEntryValue, RuneIdValue, SatPointValue, SatRange, TxidValue,
},
event::Event,
reorg::*,
runes::{Rune, RuneId},
updater::Updater,
Expand Down Expand Up @@ -33,6 +34,7 @@ use {
pub use {self::entry::RuneEntry, entry::MintEntry};

pub(crate) mod entry;
pub mod event;
mod fetcher;
mod reorg;
mod rtx;
Expand Down Expand Up @@ -201,6 +203,7 @@ pub struct Index {
client: Client,
database: Database,
durability: redb::Durability,
event_sender: Option<tokio::sync::mpsc::Sender<Event>>,
first_inscription_height: u32,
genesis_block_coinbase_transaction: Transaction,
genesis_block_coinbase_txid: Txid,
Expand All @@ -217,6 +220,13 @@ pub struct Index {

impl Index {
pub fn open(options: &Options) -> Result<Self> {
Index::open_with_event_sender(options, None)
}

pub fn open_with_event_sender(
options: &Options,
event_sender: Option<tokio::sync::mpsc::Sender<Event>>,
) -> Result<Self> {
let client = options.bitcoin_rpc_client(None)?;

let path = options
Expand Down Expand Up @@ -397,6 +407,7 @@ impl Index {
client,
database,
durability,
event_sender,
first_inscription_height: options.first_inscription_height(),
genesis_block_coinbase_transaction,
height_limit: options.height_limit,
Expand Down Expand Up @@ -568,7 +579,7 @@ impl Index {
Ok(info)
}

pub(crate) fn update(&self) -> Result {
pub fn update(&self) -> Result {
let mut updater = Updater::new(self)?;

loop {
Expand Down Expand Up @@ -5655,4 +5666,80 @@ mod tests {
assert_eq!(context.index.inscription_number(b), 0);
}
}

#[test]
fn event_sender_channel() {
let (event_sender, mut event_receiver) = tokio::sync::mpsc::channel(1024);
let context = Context::builder().event_sender(event_sender).build();

context.mine_blocks(1);

let inscription = Inscription::default();
let create_txid = context.rpc_server.broadcast_tx(TransactionTemplate {
inputs: &[(1, 0, 0, inscription.to_witness())],
fee: 0,
outputs: 1,
..Default::default()
});

context.mine_blocks(1);

let inscription_id = InscriptionId {
txid: create_txid,
index: 0,
};
let create_event = event_receiver.blocking_recv().unwrap();
let expected_charms = if context.index.index_sats { 513 } else { 0 };
assert_eq!(
create_event,
Event::InscriptionCreated {
inscription_id,
location: Some(SatPoint {
outpoint: OutPoint {
txid: create_txid,
vout: 0
},
offset: 0
}),
sequence_number: 0,
block_height: 2,
charms: expected_charms,
parent_inscription_id: None
}
);

// Transfer inscription
let transfer_txid = context.rpc_server.broadcast_tx(TransactionTemplate {
inputs: &[(2, 1, 0, Default::default())],
fee: 0,
outputs: 1,
..Default::default()
});

context.mine_blocks(1);

let transfer_event = event_receiver.blocking_recv().unwrap();
assert_eq!(
transfer_event,
Event::InscriptionTransferred {
block_height: 3,
inscription_id,
new_location: SatPoint {
outpoint: OutPoint {
txid: transfer_txid,
vout: 0
},
offset: 0
},
old_location: SatPoint {
outpoint: OutPoint {
txid: create_txid,
vout: 0
},
offset: 0
},
sequence_number: 0,
}
);
}
}
20 changes: 20 additions & 0 deletions src/index/event.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
use crate::{InscriptionId, SatPoint};

#[derive(Debug, Clone, PartialEq)]
pub enum Event {
InscriptionCreated {
block_height: u32,
charms: u16,
inscription_id: InscriptionId,
location: Option<SatPoint>,
parent_inscription_id: Option<InscriptionId>,
sequence_number: u32,
},
InscriptionTransferred {
block_height: u32,
inscription_id: InscriptionId,
new_location: SatPoint,
old_location: SatPoint,
sequence_number: u32,
},
}
15 changes: 11 additions & 4 deletions src/index/testing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use {super::*, std::ffi::OsString, tempfile::TempDir};
pub(crate) struct ContextBuilder {
args: Vec<OsString>,
chain: Chain,
event_sender: Option<tokio::sync::mpsc::Sender<Event>>,
tempdir: Option<TempDir>,
}

Expand Down Expand Up @@ -32,13 +33,13 @@ impl ContextBuilder {
];

let options = Options::try_parse_from(command.into_iter().chain(self.args)).unwrap();
let index = Index::open(&options)?;
let index = Index::open_with_event_sender(&options, self.event_sender)?;
index.update().unwrap();

Ok(Context {
index,
rpc_server,
tempdir,
index,
})
}

Expand All @@ -61,21 +62,27 @@ impl ContextBuilder {
self.tempdir = Some(tempdir);
self
}

pub(crate) fn event_sender(mut self, sender: tokio::sync::mpsc::Sender<Event>) -> Self {
self.event_sender = Some(sender);
self
}
}

pub(crate) struct Context {
pub(crate) index: Index,
pub(crate) rpc_server: test_bitcoincore_rpc::Handle,
#[allow(unused)]
pub(crate) tempdir: TempDir,
pub(crate) index: Index,
}

impl Context {
pub(crate) fn builder() -> ContextBuilder {
ContextBuilder {
args: Vec::new(),
tempdir: None,
chain: Chain::Regtest,
event_sender: None,
tempdir: None,
}
}

Expand Down
1 change: 1 addition & 0 deletions src/index/updater.rs
Original file line number Diff line number Diff line change
Expand Up @@ -424,6 +424,7 @@ impl<'index> Updater<'_> {
blessed_inscription_count,
chain: self.index.options.chain(),
cursed_inscription_count,
event_sender: self.index.event_sender.as_ref(),
flotsam: Vec::new(),
height: self.height,
home_inscription_count,
Expand Down
41 changes: 31 additions & 10 deletions src/index/updater/inscription_updater.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ pub(super) struct InscriptionUpdater<'a, 'db, 'tx> {
pub(super) blessed_inscription_count: u64,
pub(super) chain: Chain,
pub(super) cursed_inscription_count: u64,
pub(super) event_sender: Option<&'a Sender<Event>>,
pub(super) flotsam: Vec<Flotsam>,
pub(super) height: u32,
pub(super) home_inscription_count: u64,
Expand Down Expand Up @@ -387,14 +388,23 @@ impl<'a, 'db, 'tx> InscriptionUpdater<'a, 'db, 'tx> {
.satpoint_to_sequence_number
.remove_all(&old_satpoint.store())?;

(
false,
self
.id_to_sequence_number
.get(&inscription_id.store())?
.unwrap()
.value(),
)
let sequence_number = self
.id_to_sequence_number
.get(&inscription_id.store())?
.unwrap()
.value();

if let Some(sender) = self.event_sender {
sender.blocking_send(Event::InscriptionTransferred {
block_height: self.height,
inscription_id,
new_location: new_satpoint,
old_location: old_satpoint,
sequence_number,
})?;
}

(false, sequence_number)
}
Origin::New {
cursed,
Expand Down Expand Up @@ -473,7 +483,7 @@ impl<'a, 'db, 'tx> InscriptionUpdater<'a, 'db, 'tx> {
self.sat_to_sequence_number.insert(&n, &sequence_number)?;
}

let parent = match parent {
let parent_sequence_number = match parent {
Some(parent_id) => {
let parent_sequence_number = self
.id_to_sequence_number
Expand All @@ -489,6 +499,17 @@ impl<'a, 'db, 'tx> InscriptionUpdater<'a, 'db, 'tx> {
None => None,
};

if let Some(sender) = self.event_sender {
sender.blocking_send(Event::InscriptionCreated {
block_height: self.height,
charms,
inscription_id,
location: (!unbound).then_some(new_satpoint),
parent_inscription_id: parent,
sequence_number,
})?;
}

self.sequence_number_to_entry.insert(
sequence_number,
&InscriptionEntry {
Expand All @@ -497,7 +518,7 @@ impl<'a, 'db, 'tx> InscriptionUpdater<'a, 'db, 'tx> {
height: self.height,
id: inscription_id,
inscription_number,
parent,
parent: parent_sequence_number,
sat,
sequence_number,
timestamp: self.timestamp,
Expand Down
Loading