Skip to content

Commit

Permalink
Add commands to etch and list runes (ordinals#2544)
Browse files Browse the repository at this point in the history
  • Loading branch information
casey committed Nov 29, 2023
1 parent 6053e75 commit 66c730d
Show file tree
Hide file tree
Showing 31 changed files with 1,455 additions and 157 deletions.
2 changes: 2 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ bip39 = "2.0.0"
bitcoin = { version = "0.30.1", features = ["rand"] }
boilerplate = { version = "1.0.0", features = ["axum"] }
brotli = "3.4.0"
chrono = "0.4.19"
chrono = { version = "0.4.19", features = ["serde"] }
ciborium = "0.2.1"
clap = { version = "4.4.2", features = ["derive"] }
ctrlc = { version = "3.2.1", features = ["termination"] }
Expand Down
27 changes: 25 additions & 2 deletions src/index.rs
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,7 @@ impl Index {
.unwrap()
.value()
!= 0;

index_sats = statistics
.get(&Statistic::IndexSats.key())?
.unwrap()
Expand Down Expand Up @@ -312,9 +313,11 @@ impl Index {

statistics.insert(
&Statistic::IndexRunes.key(),
&u64::from(options.index_runes()),
&u64::from(index_runes),
)?;
statistics.insert(&Statistic::IndexSats.key(), &u64::from(options.index_sats))?;

statistics.insert(&Statistic::IndexSats.key(), &u64::from(index_sats))?;

statistics.insert(&Statistic::Schema.key(), &SCHEMA_VERSION)?;
}

Expand Down Expand Up @@ -422,6 +425,10 @@ impl Index {
.collect()
}

pub(crate) fn has_rune_index(&self) -> bool {
self.index_runes
}

pub(crate) fn has_sat_index(&self) -> bool {
self.index_sats
}
Expand Down Expand Up @@ -830,6 +837,22 @@ impl Index {
Ok(balances)
}

pub(crate) fn get_runic_outputs(&self, outpoints: &[OutPoint]) -> Result<BTreeSet<OutPoint>> {
let rtx = self.database.begin_read()?;

let outpoint_to_balances = rtx.open_table(OUTPOINT_TO_RUNE_BALANCES)?;

let mut runic = BTreeSet::new();

for outpoint in outpoints {
if outpoint_to_balances.get(&outpoint.store())?.is_some() {
runic.insert(*outpoint);
}
}

Ok(runic)
}

#[cfg(test)]
pub(crate) fn get_rune_balances(&self) -> Vec<(OutPoint, Vec<(RuneId, u128)>)> {
let mut result = Vec::new();
Expand Down
13 changes: 8 additions & 5 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,11 @@ use {
options::Options,
outgoing::Outgoing,
representation::Representation,
runes::{Pile, Rune, RuneId},
runes::{Edict, Etching, Pile, Runestone},
subcommand::{Subcommand, SubcommandResult},
tally::Tally,
},
anyhow::{anyhow, bail, Context, Error},
anyhow::{anyhow, bail, ensure, Context, Error},
bip39::Mnemonic,
bitcoin::{
address::{Address, NetworkUnchecked},
Expand All @@ -56,7 +56,7 @@ use {
serde::{Deserialize, Deserializer, Serialize, Serializer},
std::{
cmp,
collections::{BTreeMap, HashMap, HashSet, VecDeque},
collections::{BTreeMap, BTreeSet, HashMap, HashSet, VecDeque},
env,
ffi::OsString,
fmt::{self, Display, Formatter},
Expand All @@ -79,11 +79,12 @@ use {
tokio::{runtime::Runtime, task},
};

pub use crate::{
pub use self::{
fee_rate::FeeRate,
inscription::Inscription,
object::Object,
rarity::Rarity,
runes::{Rune, RuneId},
sat::Sat,
sat_point::SatPoint,
subcommand::wallet::transaction_builder::{Target, TransactionBuilder},
Expand Down Expand Up @@ -147,13 +148,15 @@ static SHUTTING_DOWN: AtomicBool = AtomicBool::new(false);
static LISTENERS: Mutex<Vec<axum_server::Handle>> = Mutex::new(Vec::new());
static INDEXER: Mutex<Option<thread::JoinHandle<()>>> = Mutex::new(Option::None);

const TARGET_POSTAGE: Amount = Amount::from_sat(10_000);

fn integration_test() -> bool {
env::var_os("ORD_INTEGRATION_TEST")
.map(|value| value.len() > 0)
.unwrap_or(false)
}

fn timestamp(seconds: u32) -> DateTime<Utc> {
pub fn timestamp(seconds: u32) -> DateTime<Utc> {
Utc.timestamp_opt(seconds.into(), 0).unwrap()
}

Expand Down
28 changes: 22 additions & 6 deletions src/options.rs
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,12 @@ impl Options {
"Using credentials from cookie file at `{}`",
cookie_file.display()
);

ensure!(
cookie_file.is_file(),
"cookie file `{}` does not exist",
cookie_file.display()
);
}

let client = Client::new(&rpc_url, auth)
Expand Down Expand Up @@ -532,15 +538,10 @@ mod tests {
.network(Network::Testnet)
.build();

let tempdir = TempDir::new().unwrap();

let cookie_file = tempdir.path().join(".cookie");
fs::write(&cookie_file, "username:password").unwrap();

let options = Options::try_parse_from([
"ord",
"--cookie-file",
cookie_file.to_str().unwrap(),
rpc_server.cookie_file().to_str().unwrap(),
"--rpc-url",
&rpc_server.url(),
])
Expand Down Expand Up @@ -825,4 +826,19 @@ mod tests {
.options
.index_runes(),);
}

#[test]
fn cookie_file_does_not_exist_error() {
assert_eq!(
Options {
cookie_file: Some("/foo/bar/baz/qux/.cookie".into()),
..Default::default()
}
.bitcoin_rpc_client()
.map(|_| "")
.unwrap_err()
.to_string(),
"cookie file `/foo/bar/baz/qux/.cookie` does not exist"
);
}
}
6 changes: 3 additions & 3 deletions src/runes.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
use {self::error::Error, super::*};

pub use runestone::Runestone;
pub use {rune::Rune, rune_id::RuneId};

pub(crate) use {edict::Edict, etching::Etching, pile::Pile, rune::Rune, rune_id::RuneId};
pub(crate) use {edict::Edict, etching::Etching, pile::Pile, runestone::Runestone};

pub const MAX_DIVISIBILITY: u8 = 38;
pub(crate) const CLAIM_BIT: u128 = 1 << 48;
const MAX_DIVISIBILITY: u8 = 38;
pub(crate) const MAX_LIMIT: u128 = 1 << 64;

mod edict;
Expand Down
35 changes: 32 additions & 3 deletions src/runes/rune_id.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
use {super::*, std::num::TryFromIntError};

#[derive(Debug, PartialEq, Copy, Clone, Hash, Eq, Ord, PartialOrd)]
pub(crate) struct RuneId {
pub(crate) height: u32,
pub(crate) index: u16,
pub struct RuneId {
pub height: u32,
pub index: u16,
}

impl TryFrom<u128> for RuneId {
Expand Down Expand Up @@ -44,6 +44,24 @@ impl FromStr for RuneId {
}
}

impl Serialize for RuneId {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.collect_str(self)
}
}

impl<'de> Deserialize<'de> for RuneId {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
Ok(DeserializeFromStr::deserialize(deserializer)?.0)
}
}

#[cfg(test)]
mod tests {
use super::*;
Expand Down Expand Up @@ -100,4 +118,15 @@ mod tests {

assert!(RuneId::try_from(0x07060504030201).is_err());
}

#[test]
fn serde() {
let rune_id = RuneId {
height: 1,
index: 2,
};
let json = "\"1/2\"";
assert_eq!(serde_json::to_string(&rune_id).unwrap(), json);
assert_eq!(serde_json::from_str::<RuneId>(json).unwrap(), rune_id);
}
}
Loading

0 comments on commit 66c730d

Please sign in to comment.