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

Disable features that require ordinal index when not present #845

Merged
merged 7 commits into from
Nov 25, 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
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