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

Only index ordinals if --index-ordinals is passed #837

Merged
merged 10 commits into from
Nov 24, 2022
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
3 changes: 2 additions & 1 deletion deploy/ord-dev.service
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,9 @@ Environment=RUST_BACKTRACE=1
Environment=RUST_LOG=info
ExecStart=/usr/local/bin/ord-dev \
--bitcoin-data-dir /var/lib/bitcoind \
--data-dir /var/lib/ord-dev \
--chain ${CHAIN} \
--data-dir /var/lib/ord-dev \
--index-ordinals \
server \
--http-port 8080
Group=ord
Expand Down
1 change: 1 addition & 0 deletions deploy/ord.service
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ ExecStart=/usr/local/bin/ord \
--bitcoin-data-dir /var/lib/bitcoind \
--data-dir /var/lib/ord \
--chain ${CHAIN} \
--index-ordinals \
server \
--acme-contact mailto:[email protected] \
--http \
Expand Down
63 changes: 41 additions & 22 deletions src/index.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,6 @@ mod updater;

const HEIGHT_TO_BLOCK_HASH: TableDefinition<u64, [u8; 32]> =
TableDefinition::new("HEIGHT_TO_BLOCK_HASH");
const WRITE_TRANSACTION_STARTING_BLOCK_COUNT_TO_TIMESTAMP: TableDefinition<u64, u128> =
TableDefinition::new("WRITE_TRANSACTION_START_BLOCK_COUNT_TO_TIMESTAMP");
const ORDINAL_TO_INSCRIPTION_TXID: TableDefinition<u64, [u8; 32]> =
TableDefinition::new("ORDINAL_TO_INSCRIPTION_TXID");
const ORDINAL_TO_SATPOINT: TableDefinition<u64, [u8; 44]> =
Expand All @@ -27,6 +25,8 @@ const OUTPOINT_TO_ORDINAL_RANGES: TableDefinition<[u8; 36], [u8]> =
const STATISTIC_TO_COUNT: TableDefinition<u64, u64> = TableDefinition::new("STATISTIC_TO_COUNT");
const TXID_TO_INSCRIPTION: TableDefinition<[u8; 32], str> =
TableDefinition::new("TXID_TO_INSCRIPTION");
const WRITE_TRANSACTION_STARTING_BLOCK_COUNT_TO_TIMESTAMP: TableDefinition<u64, u128> =
TableDefinition::new("WRITE_TRANSACTION_START_BLOCK_COUNT_TO_TIMESTAMP");

fn encode_outpoint(outpoint: OutPoint) -> [u8; 36] {
let mut array = [0; 36];
Expand All @@ -53,6 +53,7 @@ pub(crate) struct Index {
genesis_block_coinbase_transaction: Transaction,
genesis_block_coinbase_txid: Txid,
height_limit: Option<u64>,
index_ordinals: bool,
reorged: AtomicBool,
rpc_url: String,
}
Expand Down Expand Up @@ -198,11 +199,20 @@ impl Index {
database_path,
genesis_block_coinbase_transaction,
height_limit: options.height_limit,
index_ordinals: options.index_ordinals,
reorged: AtomicBool::new(false),
rpc_url,
})
}

fn require_ordinal_index(&self, feature: &str) -> Result {
if !self.index_ordinals {
bail!("{feature} requires `--index-ordinals` flag")
}

Ok(())
}

pub(crate) fn info(&self) -> Result<Info> {
let wtx = self.begin_write()?;

Expand Down Expand Up @@ -297,6 +307,13 @@ impl Index {

#[cfg(test)]
pub(crate) fn statistic(&self, statistic: Statistic) -> Result<u64> {
if matches!(
statistic,
Statistic::OutputsTraversed | Statistic::OrdinalRanges
) {
self.require_ordinal_index("statistic")?;
}

Ok(
self
.database
Expand Down Expand Up @@ -332,6 +349,8 @@ impl Index {
}

pub(crate) fn rare_ordinal_satpoints(&self) -> Result<Vec<(Ordinal, SatPoint)>> {
self.require_ordinal_index("looking up rare ordinals")?;

let mut result = Vec::new();

let rtx = self.database.begin_read()?;
Expand Down Expand Up @@ -427,6 +446,8 @@ impl Index {
}

pub(crate) fn find(&self, ordinal: u64) -> Result<Option<SatPoint>> {
self.require_ordinal_index("find")?;

let rtx = self.begin_read()?;

if rtx.block_count()? <= Ordinal(ordinal).height().n() {
Expand All @@ -453,7 +474,7 @@ impl Index {
Ok(None)
}

pub(crate) fn list_inner(&self, outpoint: &[u8]) -> Result<Option<Vec<u8>>> {
fn list_inner(&self, outpoint: &[u8]) -> Result<Option<Vec<u8>>> {
Ok(
self
.database
Expand All @@ -465,6 +486,8 @@ impl Index {
}

pub(crate) fn list(&self, outpoint: OutPoint) -> Result<Option<List>> {
self.require_ordinal_index("find")?;

let outpoint_encoded = encode_outpoint(outpoint);

let ordinal_ranges = self.list_inner(&outpoint_encoded)?;
Expand Down Expand Up @@ -526,10 +549,6 @@ mod tests {
}

impl Context {
fn new() -> Self {
Self::with_args("")
}

fn with_args(args: &str) -> Self {
let rpc_server = test_bitcoincore_rpc::spawn();

Expand Down Expand Up @@ -593,7 +612,7 @@ mod tests {

#[test]
fn list_first_coinbase_transaction() {
let context = Context::new();
let context = Context::with_args("--index-ordinals");
assert_eq!(
context
.index
Expand All @@ -610,7 +629,7 @@ mod tests {

#[test]
fn list_second_coinbase_transaction() {
let context = Context::new();
let context = Context::with_args("--index-ordinals");
let txid = context.rpc_server.mine_blocks(1)[0].txdata[0].txid();
context.index.update().unwrap();
assert_eq!(
Expand All @@ -621,7 +640,7 @@ mod tests {

#[test]
fn list_split_ranges_are_tracked_correctly() {
let context = Context::new();
let context = Context::with_args("--index-ordinals");

context.rpc_server.mine_blocks(1);
let split_coinbase_output = TransactionTemplate {
Expand All @@ -647,7 +666,7 @@ mod tests {

#[test]
fn list_merge_ranges_are_tracked_correctly() {
let context = Context::new();
let context = Context::with_args("--index-ordinals");

context.rpc_server.mine_blocks(2);
let merge_coinbase_outputs = TransactionTemplate {
Expand All @@ -671,7 +690,7 @@ mod tests {

#[test]
fn list_fee_paying_transaction_range() {
let context = Context::new();
let context = Context::with_args("--index-ordinals");

context.rpc_server.mine_blocks(1);
let fee_paying_tx = TransactionTemplate {
Expand Down Expand Up @@ -705,7 +724,7 @@ mod tests {

#[test]
fn list_two_fee_paying_transaction_range() {
let context = Context::new();
let context = Context::with_args("--index-ordinals");

context.rpc_server.mine_blocks(2);
let first_fee_paying_tx = TransactionTemplate {
Expand Down Expand Up @@ -740,7 +759,7 @@ mod tests {

#[test]
fn list_null_output() {
let context = Context::new();
let context = Context::with_args("--index-ordinals");

context.rpc_server.mine_blocks(1);
let no_value_output = TransactionTemplate {
Expand All @@ -760,7 +779,7 @@ mod tests {

#[test]
fn list_null_input() {
let context = Context::new();
let context = Context::with_args("--index-ordinals");

context.rpc_server.mine_blocks(1);
let no_value_output = TransactionTemplate {
Expand Down Expand Up @@ -788,7 +807,7 @@ mod tests {

#[test]
fn list_spent_output() {
let context = Context::new();
let context = Context::with_args("--index-ordinals");
context.rpc_server.mine_blocks(1);
context.rpc_server.broadcast_tx(TransactionTemplate {
input_slots: &[(1, 0, 0)],
Expand All @@ -806,7 +825,7 @@ mod tests {

#[test]
fn list_unknown_output() {
let context = Context::new();
let context = Context::with_args("--index-ordinals");

assert_eq!(
context
Expand All @@ -823,7 +842,7 @@ mod tests {

#[test]
fn find_first_ordinal() {
let context = Context::new();
let context = Context::with_args("--index-ordinals");
assert_eq!(
context.index.find(0).unwrap().unwrap(),
SatPoint {
Expand All @@ -837,7 +856,7 @@ mod tests {

#[test]
fn find_second_ordinal() {
let context = Context::new();
let context = Context::with_args("--index-ordinals");
assert_eq!(
context.index.find(1).unwrap().unwrap(),
SatPoint {
Expand All @@ -851,7 +870,7 @@ mod tests {

#[test]
fn find_first_ordinal_of_second_block() {
let context = Context::new();
let context = Context::with_args("--index-ordinals");
context.rpc_server.mine_blocks(1);
context.index.update().unwrap();
assert_eq!(
Expand All @@ -867,13 +886,13 @@ mod tests {

#[test]
fn find_unmined_ordinal() {
let context = Context::new();
let context = Context::with_args("--index-ordinals");
assert_eq!(context.index.find(50 * COIN_VALUE).unwrap(), None);
}

#[test]
fn find_first_satoshi_spent_in_second_block() {
let context = Context::new();
let context = Context::with_args("--index-ordinals");
context.rpc_server.mine_blocks(1);
let spend_txid = context.rpc_server.broadcast_tx(TransactionTemplate {
input_slots: &[(1, 0, 0)],
Expand Down
106 changes: 55 additions & 51 deletions src/index/updater.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ pub struct Updater {
cache: HashMap<[u8; 36], Vec<u8>>,
chain: Chain,
height: u64,
index_ordinals: bool,
ordinal_ranges_since_flush: u64,
outputs_cached: u64,
outputs_inserted_since_flush: u64,
Expand Down Expand Up @@ -36,6 +37,7 @@ impl Updater {
cache: HashMap::new(),
chain: index.chain,
height,
index_ordinals: index.index_ordinals,
ordinal_ranges_since_flush: 0,
outputs_cached: 0,
outputs_inserted_since_flush: 0,
Expand Down Expand Up @@ -230,67 +232,69 @@ impl Updater {
}
}

let mut coinbase_inputs = VecDeque::new();
if self.index_ordinals {
let mut coinbase_inputs = VecDeque::new();

let h = Height(self.height);
if h.subsidy() > 0 {
let start = h.starting_ordinal();
coinbase_inputs.push_front((start.n(), (start + h.subsidy()).n()));
self.ordinal_ranges_since_flush += 1;
}
let h = Height(self.height);
if h.subsidy() > 0 {
let start = h.starting_ordinal();
coinbase_inputs.push_front((start.n(), (start + h.subsidy()).n()));
self.ordinal_ranges_since_flush += 1;
}

for (tx_offset, tx) in block.txdata.iter().enumerate().skip(1) {
let txid = tx.txid();
for (tx_offset, tx) in block.txdata.iter().enumerate().skip(1) {
let txid = tx.txid();

log::trace!("Indexing transaction {tx_offset}…");
log::trace!("Indexing transaction {tx_offset}…");

let mut input_ordinal_ranges = VecDeque::new();
let mut input_ordinal_ranges = VecDeque::new();

for input in &tx.input {
let key = encode_outpoint(input.previous_output);
for input in &tx.input {
let key = encode_outpoint(input.previous_output);

let ordinal_ranges = match self.cache.remove(&key) {
Some(ordinal_ranges) => {
self.outputs_cached += 1;
ordinal_ranges
}
None => outpoint_to_ordinal_ranges
.remove(&key)?
.ok_or_else(|| anyhow!("Could not find outpoint {} in index", input.previous_output))?
.to_value()
.to_vec(),
};
let ordinal_ranges = match self.cache.remove(&key) {
Some(ordinal_ranges) => {
self.outputs_cached += 1;
ordinal_ranges
}
None => outpoint_to_ordinal_ranges
.remove(&key)?
.ok_or_else(|| anyhow!("Could not find outpoint {} in index", input.previous_output))?
.to_value()
.to_vec(),
};

for chunk in ordinal_ranges.chunks_exact(11) {
input_ordinal_ranges.push_back(Index::decode_ordinal_range(chunk.try_into().unwrap()));
for chunk in ordinal_ranges.chunks_exact(11) {
input_ordinal_ranges.push_back(Index::decode_ordinal_range(chunk.try_into().unwrap()));
}
}
}

self.index_transaction(
txid,
tx,
&mut ordinal_to_satpoint,
&mut ordinal_to_inscription_txid,
&mut txid_to_inscription,
&mut input_ordinal_ranges,
&mut ordinal_ranges_written,
&mut outputs_in_block,
)?;

coinbase_inputs.extend(input_ordinal_ranges);
}
self.index_transaction(
txid,
tx,
&mut ordinal_to_satpoint,
&mut ordinal_to_inscription_txid,
&mut txid_to_inscription,
&mut input_ordinal_ranges,
&mut ordinal_ranges_written,
&mut outputs_in_block,
)?;

coinbase_inputs.extend(input_ordinal_ranges);
}

if let Some(tx) = block.coinbase() {
self.index_transaction(
tx.txid(),
tx,
&mut ordinal_to_satpoint,
&mut ordinal_to_inscription_txid,
&mut txid_to_inscription,
&mut coinbase_inputs,
&mut ordinal_ranges_written,
&mut outputs_in_block,
)?;
if let Some(tx) = block.coinbase() {
self.index_transaction(
tx.txid(),
tx,
&mut ordinal_to_satpoint,
&mut ordinal_to_inscription_txid,
&mut txid_to_inscription,
&mut coinbase_inputs,
&mut ordinal_ranges_written,
&mut outputs_in_block,
)?;
}
}

height_to_block_hash.insert(&self.height, &block.block_hash().as_hash().into_inner())?;
Expand Down
Loading