Skip to content

Commit

Permalink
Lookup rune by number (ordinals#3440)
Browse files Browse the repository at this point in the history
  • Loading branch information
lugondev authored Apr 13, 2024
1 parent 534d50d commit 1e267e1
Show file tree
Hide file tree
Showing 4 changed files with 86 additions and 7 deletions.
17 changes: 17 additions & 0 deletions src/index.rs
Original file line number Diff line number Diff line change
Expand Up @@ -855,6 +855,23 @@ impl Index {
)
}

pub(crate) fn get_rune_by_number(&self, number: usize) -> Result<Option<Rune>> {
match self
.database
.begin_read()?
.open_table(RUNE_ID_TO_RUNE_ENTRY)?
.iter()?
.nth(number)
{
Some(result) => {
let rune_result =
result.map(|(_id, entry)| RuneEntry::load(entry.value()).spaced_rune.rune);
Ok(rune_result.ok())
}
None => Ok(None),
}
}

pub(crate) fn rune(
&self,
rune: Rune,
Expand Down
1 change: 1 addition & 0 deletions src/re.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ lazy_static! {
pub(crate) static ref INSCRIPTION_NUMBER: Regex = re(r"-?[0-9]+");
pub(crate) static ref OUTPOINT: Regex = re(r"[[:xdigit:]]{64}:\d+");
pub(crate) static ref RUNE_ID: Regex = re(r"[0-9]+:[0-9]+");
pub(crate) static ref RUNE_NUMBER: Regex = re(r"-?[0-9]+");
pub(crate) static ref SATPOINT: Regex = re(r"[[:xdigit:]]{64}:\d+:\d+");
pub(crate) static ref SAT_NAME: Regex = re(r"[a-z]{1,11}");
pub(crate) static ref SPACED_RUNE: Regex = re(r"[A-Z•.]+");
Expand Down
63 changes: 60 additions & 3 deletions src/subcommand/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ pub(crate) use server_config::ServerConfig;
mod accept_encoding;
mod accept_json;
mod error;
pub(crate) mod query;
pub mod query;
mod server_config;

enum SpawnConfig {
Expand Down Expand Up @@ -656,10 +656,13 @@ impl Server {
}

let rune = match rune_query {
query::Rune::SpacedRune(spaced_rune) => spaced_rune.rune,
query::Rune::RuneId(rune_id) => index
query::Rune::Spaced(spaced_rune) => spaced_rune.rune,
query::Rune::Id(rune_id) => index
.get_rune_by_id(rune_id)?
.ok_or_not_found(|| format!("rune {rune_id}"))?,
query::Rune::Number(number) => index
.get_rune_by_number(usize::try_from(number).unwrap())?
.ok_or_not_found(|| format!("rune number {number}"))?,
};

let (id, entry, parent) = index
Expand Down Expand Up @@ -2650,6 +2653,60 @@ mod tests {
);
}

#[test]
fn runes_can_be_queried_by_rune_number() {
let server = TestServer::builder()
.chain(Chain::Regtest)
.index_runes()
.build();

server.mine_blocks(1);

server.assert_response_regex("/rune/0", StatusCode::NOT_FOUND, ".*");

for i in 0..10 {
let rune = Rune(RUNE + i);
server.etch(
Runestone {
edicts: vec![Edict {
id: RuneId::default(),
amount: u128::MAX,
output: 0,
}],
etching: Some(Etching {
rune: Some(rune),
..default()
}),
..default()
},
1,
None,
);

server.mine_blocks(1);
}

server.assert_response_regex(
"/rune/0",
StatusCode::OK,
".*<title>Rune AAAAAAAAAAAAA</title>.*",
);

for i in 1..6 {
server.assert_response_regex(
format!("/rune/{}", i),
StatusCode::OK,
".*<title>Rune AAAAAAAAAAAA.*</title>.*",
);
}

server.assert_response_regex(
"/rune/9",
StatusCode::OK,
".*<title>Rune AAAAAAAAAAAAJ</title>.*",
);
}

#[test]
fn runes_are_displayed_on_runes_page() {
let server = TestServer::builder()
Expand Down
12 changes: 8 additions & 4 deletions src/subcommand/server/query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,19 +50,23 @@ impl Display for Inscription {
}
}

#[derive(Debug)]
pub(super) enum Rune {
SpacedRune(SpacedRune),
RuneId(RuneId),
Spaced(SpacedRune),
Id(RuneId),
Number(u64),
}

impl FromStr for Rune {
type Err = Error;

fn from_str(s: &str) -> Result<Self, Self::Err> {
if s.contains(':') {
Ok(Self::RuneId(s.parse()?))
Ok(Self::Id(s.parse()?))
} else if re::RUNE_NUMBER.is_match(s) {
Ok(Self::Number(s.parse()?))
} else {
Ok(Self::SpacedRune(s.parse()?))
Ok(Self::Spaced(s.parse()?))
}
}
}

0 comments on commit 1e267e1

Please sign in to comment.