Skip to content

Commit

Permalink
Conditionally disable ordinal index dependent server features (#845)
Browse files Browse the repository at this point in the history
  • Loading branch information
casey authored Nov 25, 2022
1 parent bad112f commit 3ef2bd8
Show file tree
Hide file tree
Showing 8 changed files with 235 additions and 59 deletions.
72 changes: 42 additions & 30 deletions src/index.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,6 @@ 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 @@ -161,37 +160,43 @@ impl Index {

let database = match unsafe { redb::Database::open(&database_path) } {
Ok(database) => database,
Err(redb::Error::Io(error)) if error.kind() == io::ErrorKind::NotFound => unsafe {
Database::builder()
.set_write_strategy(if cfg!(test) {
WriteStrategy::Checksum
} else {
WriteStrategy::TwoPhase
})
.create(&database_path)?
},
Err(error) => return Err(error.into()),
};
Err(redb::Error::Io(error)) if error.kind() == io::ErrorKind::NotFound => {
let database = unsafe {
Database::builder()
.set_write_strategy(if cfg!(test) {
WriteStrategy::Checksum
} else {
WriteStrategy::TwoPhase
})
.create(&database_path)?
};
let tx = database.begin_write()?;

#[cfg(test)]
let tx = {
let mut tx = tx;
tx.set_durability(redb::Durability::None);
tx
};

tx.open_table(HEIGHT_TO_BLOCK_HASH)?;
tx.open_table(ORDINAL_TO_INSCRIPTION_TXID)?;
tx.open_table(ORDINAL_TO_SATPOINT)?;
tx.open_table(STATISTIC_TO_COUNT)?;
tx.open_table(TXID_TO_INSCRIPTION)?;
tx.open_table(WRITE_TRANSACTION_STARTING_BLOCK_COUNT_TO_TIMESTAMP)?;

if options.index_ordinals {
tx.open_table(OUTPOINT_TO_ORDINAL_RANGES)?;
}

let tx = database.begin_write()?;
tx.commit()?;

#[cfg(test)]
let tx = {
let mut tx = tx;
tx.set_durability(redb::Durability::None);
tx
database
}
Err(error) => return Err(error.into()),
};

tx.open_table(HEIGHT_TO_BLOCK_HASH)?;
tx.open_table(ORDINAL_TO_INSCRIPTION_TXID)?;
tx.open_table(ORDINAL_TO_SATPOINT)?;
tx.open_table(OUTPOINT_TO_ORDINAL_RANGES)?;
tx.open_table(STATISTIC_TO_COUNT)?;
tx.open_table(TXID_TO_INSCRIPTION)?;
tx.open_table(WRITE_TRANSACTION_STARTING_BLOCK_COUNT_TO_TIMESTAMP)?;

tx.commit()?;

let genesis_block_coinbase_transaction =
options.chain.genesis_block().coinbase().unwrap().clone();

Expand All @@ -204,14 +209,21 @@ impl Index {
database_path,
genesis_block_coinbase_transaction,
height_limit: options.height_limit,
index_ordinals: options.index_ordinals,
reorged: AtomicBool::new(false),
rpc_url,
})
}

pub(crate) fn has_ordinal_index(&self) -> Result<bool> {
match self.begin_read()?.0.open_table(OUTPOINT_TO_ORDINAL_RANGES) {
Ok(_) => Ok(true),
Err(redb::Error::TableDoesNotExist(_)) => Ok(false),
Err(err) => Err(err.into()),
}
}

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

Expand Down
7 changes: 4 additions & 3 deletions src/index/updater.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ impl Updater {
cache: HashMap::new(),
chain: index.chain,
height,
index_ordinals: index.index_ordinals,
index_ordinals: index.has_ordinal_index()?,
ordinal_ranges_since_flush: 0,
outputs_cached: 0,
outputs_inserted_since_flush: 0,
Expand Down Expand Up @@ -207,7 +207,6 @@ impl Updater {
let mut height_to_block_hash = wtx.open_table(HEIGHT_TO_BLOCK_HASH)?;
let mut ordinal_to_satpoint = wtx.open_table(ORDINAL_TO_SATPOINT)?;
let mut ordinal_to_inscription_txid = wtx.open_table(ORDINAL_TO_INSCRIPTION_TXID)?;
let mut outpoint_to_ordinal_ranges = wtx.open_table(OUTPOINT_TO_ORDINAL_RANGES)?;
let mut txid_to_inscription = wtx.open_table(TXID_TO_INSCRIPTION)?;

let start = Instant::now();
Expand All @@ -233,6 +232,8 @@ impl Updater {
}

if self.index_ordinals {
let mut outpoint_to_ordinal_ranges = wtx.open_table(OUTPOINT_TO_ORDINAL_RANGES)?;

let mut coinbase_inputs = VecDeque::new();

let h = Height(self.height);
Expand Down Expand Up @@ -396,7 +397,7 @@ impl Updater {
self.outputs_cached
);

{
if self.index_ordinals {
log::info!(
"Flushing {} entries ({:.1}% resulting from {} insertions) from memory to database",
self.cache.len(),
Expand Down
2 changes: 1 addition & 1 deletion src/options.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ pub(crate) struct Options {
data_dir: Option<PathBuf>,
#[clap(long, help = "Limit index to <HEIGHT_LIMIT> blocks.")]
pub(crate) height_limit: Option<u64>,
#[clap(long, help = "Index ordinal ranges")]
#[clap(long, help = "Index ordinal ranges.")]
pub(crate) index_ordinals: bool,
#[clap(long, help = "Connect to Bitcoin Core RPC at <RPC_URL>.")]
rpc_url: Option<String>,
Expand Down
103 changes: 88 additions & 15 deletions src/subcommand/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -320,7 +320,10 @@ impl Server {
))
})?,
}
.page(chain),
.page(
chain,
index.has_ordinal_index().map_err(ServerError::Internal)?,
),
)
}

Expand All @@ -329,11 +332,6 @@ impl Server {
Extension(index): Extension<Arc<Index>>,
Path(outpoint): Path<OutPoint>,
) -> ServerResult<PageHtml> {
let list = index
.list(outpoint)
.map_err(ServerError::Internal)?
.ok_or_else(|| ServerError::NotFound(format!("output {outpoint} unknown")))?;

let output = index
.transaction(outpoint.txid)
.map_err(ServerError::Internal)?
Expand All @@ -346,16 +344,29 @@ impl Server {
Ok(
OutputHtml {
outpoint,
list,
list: if index.has_ordinal_index().map_err(ServerError::Internal)? {
Some(
index
.list(outpoint)
.map_err(ServerError::Internal)?
.ok_or_else(|| ServerError::NotFound(format!("output {outpoint} unknown")))?,
)
} else {
None
},
chain,
output,
}
.page(chain),
.page(
chain,
index.has_ordinal_index().map_err(ServerError::Internal)?,
),
)
}

async fn range(
Extension(chain): Extension<Chain>,
Extension(index): Extension<Arc<Index>>,
Path((DeserializeFromStr(start), DeserializeFromStr(end))): Path<(
DeserializeFromStr<Ordinal>,
DeserializeFromStr<Ordinal>,
Expand All @@ -366,7 +377,10 @@ impl Server {
Ordering::Greater => Err(ServerError::BadRequest(
"range start greater than range end".to_string(),
)),
Ordering::Less => Ok(RangeHtml { start, end }.page(chain)),
Ordering::Less => Ok(RangeHtml { start, end }.page(
chain,
index.has_ordinal_index().map_err(ServerError::Internal)?,
)),
}
}

Expand All @@ -386,7 +400,10 @@ impl Server {
.blocks(100)
.map_err(|err| ServerError::Internal(anyhow!("error getting blocks: {err}")))?,
)
.page(chain),
.page(
chain,
index.has_ordinal_index().map_err(ServerError::Internal)?,
),
)
}

Expand Down Expand Up @@ -431,7 +448,12 @@ impl Server {
}
};

Ok(BlockHtml::new(block, Height(height), Self::index_height(&index)?).page(chain))
Ok(
BlockHtml::new(block, Height(height), Self::index_height(&index)?).page(
chain,
index.has_ordinal_index().map_err(ServerError::Internal)?,
),
)
}

async fn transaction(
Expand All @@ -451,7 +473,10 @@ impl Server {
.ok_or_else(|| ServerError::NotFound(format!("transaction {txid} unknown")))?,
chain,
)
.page(chain),
.page(
chain,
index.has_ordinal_index().map_err(ServerError::Internal)?,
),
)
}

Expand Down Expand Up @@ -569,7 +594,10 @@ impl Server {
.nth(path.2)
.ok_or_else(not_found)?;

Ok(InputHtml { path, input }.page(chain))
Ok(InputHtml { path, input }.page(
chain,
index.has_ordinal_index().map_err(ServerError::Internal)?,
))
}

async fn faq() -> Redirect {
Expand Down Expand Up @@ -597,7 +625,10 @@ impl Server {
})?
.ok_or_else(|| ServerError::NotFound(format!("transaction {txid} has no inscription")))?,
}
.page(chain),
.page(
chain,
index.has_ordinal_index().map_err(ServerError::Internal)?,
),
)
}
}
Expand Down Expand Up @@ -1064,8 +1095,9 @@ mod tests {
"Invalid URL: error parsing TXID",
);
}

#[test]
fn output() {
fn output_with_ordinal_index() {
TestServer::new_with_args(&["--index-ordinals"]).assert_response_regex(
"/output/4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b:0",
StatusCode::OK,
Expand All @@ -1081,6 +1113,24 @@ mod tests {
);
}

#[test]
fn output_without_ordinal_index() {
TestServer::new().assert_response_regex(
"/output/4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b:0",
StatusCode::OK,
".*<title>Output 4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b:0</title>.*<h1>Output <span class=monospace>4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b:0</span></h1>
<dl>
<dt>value</dt><dd>5000000000</dd>
<dt>script pubkey</dt><dd class=data>OP_PUSHBYTES_65 04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f OP_CHECKSIG</dd>
</dl>
</main>
</body>
</html>
",
);
}

#[test]
fn unknown_output_returns_404() {
TestServer::new_with_args(&["--index-ordinals"]).assert_response(
Expand Down Expand Up @@ -1305,6 +1355,29 @@ next.*",
);
}

#[test]
fn show_rare_txt_in_header_with_ordinal_index() {
TestServer::new_with_args(&["--index-ordinals"]).assert_response_regex(
"/",
StatusCode::OK,
".*
<a href=/clock>Clock</a>
<a href=/rare.txt>rare.txt</a>
<form action=/search method=get>.*",
);
}

#[test]
fn dont_show_rare_txt_in_header_without_ordinal_index() {
TestServer::new().assert_response_regex(
"/",
StatusCode::OK,
".*
<a href=/clock>Clock</a>
<form action=/search method=get>.*",
);
}

#[test]
fn input() {
TestServer::new().assert_response_regex(
Expand Down
Loading

0 comments on commit 3ef2bd8

Please sign in to comment.