From abee401c9e2126b164c579ac281554f380c6b85e Mon Sep 17 00:00:00 2001 From: Casey Rodarmor Date: Sat, 12 Mar 2022 20:38:56 -0800 Subject: [PATCH 1/7] Open LMDB database with WRITEMAP when not on MacOS --- src/lmdb_database.rs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/lmdb_database.rs b/src/lmdb_database.rs index bd5748920e..5d9ad22dda 100644 --- a/src/lmdb_database.rs +++ b/src/lmdb_database.rs @@ -37,7 +37,15 @@ impl Database { builder.set_mapsize(options.index_size.0)?; builder - .open(path, lmdb::open::Flags::empty(), 0o600) + .open( + path, + if cfg!(target_os = "macos") { + lmdb::open::Flags::empty() + } else { + lmdb::open::WRITEMAP + }, + 0o600, + ) .unwrap() }; From 29d6434c08533465dedbebff9e9fa0400c8b30fd Mon Sep 17 00:00:00 2001 From: Casey Rodarmor Date: Sat, 12 Mar 2022 20:41:02 -0800 Subject: [PATCH 2/7] Don't delay requests on linux --- src/index.rs | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/index.rs b/src/index.rs index 83a8d927d5..2432c55672 100644 --- a/src/index.rs +++ b/src/index.rs @@ -45,17 +45,19 @@ impl Index { } fn client(&self) -> &Client { - let now = Instant::now(); + if cfg!(target_os = "macos") { + let now = Instant::now(); - let sleep_until = self.sleep_until.get(); + let sleep_until = self.sleep_until.get(); - if sleep_until > now { - std::thread::sleep(sleep_until - now); - } + if sleep_until > now { + std::thread::sleep(sleep_until - now); + } - self - .sleep_until - .set(Instant::now() + Duration::from_millis(2)); + self + .sleep_until + .set(Instant::now() + Duration::from_millis(2)); + } &self.client } From faed2ebc974bcb9aee5aa3cf7ac1f9efeb5a5ccd Mon Sep 17 00:00:00 2001 From: Casey Rodarmor Date: Sat, 12 Mar 2022 22:15:13 -0800 Subject: [PATCH 3/7] Use anyhow to add context to errors --- Cargo.lock | 7 +++++ Cargo.toml | 1 + justfile | 5 ++++ ord.service | 58 ++++++++++++++++++++++++++++++++++++++++ src/bytes.rs | 2 +- src/index.rs | 13 ++++----- src/key.rs | 2 +- src/main.rs | 23 ++++++++-------- src/subcommand/find.rs | 2 +- src/subcommand/list.rs | 2 +- src/subcommand/name.rs | 4 +-- src/subcommand/traits.rs | 2 +- 12 files changed, 97 insertions(+), 24 deletions(-) create mode 100644 ord.service diff --git a/Cargo.lock b/Cargo.lock index 1db8ffaf07..e90870b305 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -11,6 +11,12 @@ dependencies = [ "memchr", ] +[[package]] +name = "anyhow" +version = "1.0.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4361135be9122e0870de935d7c439aef945b9f9ddd4199a553b5270b49c82a27" + [[package]] name = "atty" version = "0.2.14" @@ -982,6 +988,7 @@ checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575" name = "ord" version = "0.0.0" dependencies = [ + "anyhow", "bitcoin", "bitcoincore-rpc", "chrono", diff --git a/Cargo.toml b/Cargo.toml index 6f9bffbd0e..7feb987687 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,6 +7,7 @@ edition = "2021" autotests = false [dependencies] +anyhow = "1.0.56" bitcoin = "0.27.1" bitcoincore-rpc = "0.14.0" chrono = "0.4.19" diff --git a/justfile b/justfile index d939d1aeaa..529a168846 100644 --- a/justfile +++ b/justfile @@ -23,3 +23,8 @@ watch +args='ltest': install-dev-deps: cargo install cargo-criterion + +deploy: + scp ord.service root@65.108.68.37:/etc/systemd/system/ + ssh root@65.108.68.37 systemctl enable ord + ssh root@65.108.68.37 systemctl start ord diff --git a/ord.service b/ord.service new file mode 100644 index 0000000000..a77ec04fb4 --- /dev/null +++ b/ord.service @@ -0,0 +1,58 @@ +[Unit] +After=network.target +Description=Ord server +StartLimitBurst=120 +StartLimitIntervalSec=10m + +[Service] +WorkingDirectory=/var/lib/ord +Environment="RUST_LOG=info" +ExecStart=/usr/local/bin/ord \ + --index-size 1TiB \ + --rpc-url 127.0.0.1:8332 \ + --cookie-file /var/lib/bitcoind/.cookie \ + index + +# Process management +#################### + +Type=simple +Restart=on-failure +TimeoutStopSec=10m +RestartSec=5s + +# Directory creation and permissions +#################################### + +User=ord +Group=ord + +# /var/lib/ord +StateDirectory=ord +StateDirectoryMode=0700 + +# Hardening measures +#################### + +# Provide a private /tmp and /var/tmp. +PrivateTmp=true + +# Mount /usr, /boot/ and /etc read-only for the process. +ProtectSystem=full + +# Deny access to /home, /root and /run/user +ProtectHome=true + +# Disallow the process and all of its children to gain +# new privileges through execve(). +NoNewPrivileges=true + +# Use a new /dev namespace only populated with API pseudo devices +# such as /dev/null, /dev/zero and /dev/random. +PrivateDevices=true + +# Deny the creation of writable and executable memory mappings. +MemoryDenyWriteExecute=true + +[Install] +WantedBy=multi-user.target diff --git a/src/bytes.rs b/src/bytes.rs index 7744f77f68..2004ab7c49 100644 --- a/src/bytes.rs +++ b/src/bytes.rs @@ -32,7 +32,7 @@ impl FromStr for Bytes { "tib" => TI, "pib" => PI, "eib" => EI, - _ => return Err("invalid suffix".into()), + _ => return Err(anyhow!("invalid suffix")), }; Ok(Bytes((value * multiple as f64) as usize)) diff --git a/src/index.rs b/src/index.rs index 2432c55672..c0ce5ac8c9 100644 --- a/src/index.rs +++ b/src/index.rs @@ -16,17 +16,18 @@ impl Index { options .rpc_url .as_ref() - .ok_or("This command requires `--rpc-url`")?, + .ok_or(anyhow!("This command requires `--rpc-url`"))?, options .cookie_file .as_ref() .map(|path| Auth::CookieFile(path.clone())) .unwrap_or(Auth::None), - )?; + ) + .context("Failed to connect to RPC URL")?; Ok(Self { client, - database: Database::open(options)?, + database: Database::open(options).context("Failed to open database")?, sleep_until: Cell::new(Instant::now()), }) } @@ -110,7 +111,7 @@ impl Index { let prev_hash = wtx.blockhash_at_height(prev_height)?.unwrap(); if prev_hash != block.header.prev_blockhash.as_ref() { - return Err("Reorg detected at or before {prev_height}".into()); + return Err(anyhow!("Reorg detected at or before {prev_height}")); } } @@ -140,7 +141,7 @@ impl Index { let ordinal_ranges = wtx .get_ordinal_ranges(key.as_slice())? - .ok_or("Could not find outpoint in index")?; + .ok_or(anyhow!("Could not find outpoint in index"))?; let new = input_ordinal_ranges.len(); @@ -226,7 +227,7 @@ impl Index { while remaining > 0 { let range = input_ordinal_ranges .pop_front() - .ok_or("Insufficient inputs for transaction outputs")?; + .ok_or(anyhow!("Insufficient inputs for transaction outputs"))?; let count = range.1 - range.0; diff --git a/src/key.rs b/src/key.rs index 9a23587afa..328d8ddfaa 100644 --- a/src/key.rs +++ b/src/key.rs @@ -25,7 +25,7 @@ impl Key { pub(crate) fn decode(buffer: &[u8]) -> Result { if buffer.len() != 24 { - return Err("Buffer too small to decode key from".into()); + return Err(anyhow!("Buffer too small to decode key from")); } Ok(Key { diff --git a/src/main.rs b/src/main.rs index 75e3d51bcf..550e6272c7 100644 --- a/src/main.rs +++ b/src/main.rs @@ -5,6 +5,8 @@ use { arguments::Arguments, bytes::Bytes, epoch::Epoch, height::Height, index::Index, key::Key, options::Options, ordinal::Ordinal, sat_point::SatPoint, subcommand::Subcommand, }, + anyhow::Context, + anyhow::{anyhow, Error}, bitcoin::{ blockdata::constants::COIN_VALUE, consensus::Decodable, consensus::Encodable, Block, BlockHash, OutPoint, Transaction, Txid, @@ -29,28 +31,27 @@ use { }, }; +#[cfg(feature = "redb")] +use redb_database::{Database, WriteTransaction}; + +#[cfg(not(feature = "redb"))] +use lmdb_database::{Database, WriteTransaction}; + mod arguments; mod bytes; mod epoch; mod height; mod index; mod key; +#[cfg(not(feature = "redb"))] +mod lmdb_database; mod options; mod ordinal; -mod sat_point; -mod subcommand; - #[cfg(feature = "redb")] mod redb_database; -#[cfg(feature = "redb")] -use redb_database::{Database, WriteTransaction}; - -#[cfg(not(feature = "redb"))] -mod lmdb_database; -#[cfg(not(feature = "redb"))] -use lmdb_database::{Database, WriteTransaction}; +mod sat_point; +mod subcommand; -type Error = Box; type Result = std::result::Result; static INTERRUPTS: AtomicU64 = AtomicU64::new(0); diff --git a/src/subcommand/find.rs b/src/subcommand/find.rs index def66e7b13..e4e96e2164 100644 --- a/src/subcommand/find.rs +++ b/src/subcommand/find.rs @@ -23,7 +23,7 @@ impl Find { } Ok(()) } - None => Err("Ordinal has not been mined as of index height".into()), + None => Err(anyhow!("Ordinal has not been mined as of index height")), } } } diff --git a/src/subcommand/list.rs b/src/subcommand/list.rs index a2ed797334..181600b4c5 100644 --- a/src/subcommand/list.rs +++ b/src/subcommand/list.rs @@ -16,7 +16,7 @@ impl List { } Ok(()) } - None => Err("Output not found".into()), + None => Err(anyhow!("Output not found")), } } } diff --git a/src/subcommand/name.rs b/src/subcommand/name.rs index 068039fde5..c9d9198dd3 100644 --- a/src/subcommand/name.rs +++ b/src/subcommand/name.rs @@ -8,7 +8,7 @@ pub(crate) struct Name { impl Name { pub(crate) fn run(self) -> Result { if self.name.is_empty() || self.name.chars().any(|c| !('a'..='z').contains(&c)) { - return Err("Invalid name".into()); + return Err(anyhow!("Invalid name")); } let mut min = 0; @@ -32,7 +32,7 @@ impl Name { } if max - min == 0 { - return Err("Name out of range".into()); + return Err(anyhow!("Name out of range")); } guess = min + (max - min) / 2; diff --git a/src/subcommand/traits.rs b/src/subcommand/traits.rs index 84ba6085b5..002a6b375a 100644 --- a/src/subcommand/traits.rs +++ b/src/subcommand/traits.rs @@ -8,7 +8,7 @@ pub(crate) struct Traits { impl Traits { pub(crate) fn run(self) -> Result { if self.ordinal > Ordinal::LAST { - return Err("Invalid ordinal".into()); + return Err(anyhow!("Invalid ordinal")); } let n = self.ordinal.n(); From b5baa90e3fc6257c48c18d8b408424c2250b367e Mon Sep 17 00:00:00 2001 From: Casey Rodarmor Date: Fri, 18 Mar 2022 20:26:02 -0700 Subject: [PATCH 4/7] Remove ord.service --- ord.service | 58 ----------------------------------------------------- 1 file changed, 58 deletions(-) delete mode 100644 ord.service diff --git a/ord.service b/ord.service deleted file mode 100644 index a77ec04fb4..0000000000 --- a/ord.service +++ /dev/null @@ -1,58 +0,0 @@ -[Unit] -After=network.target -Description=Ord server -StartLimitBurst=120 -StartLimitIntervalSec=10m - -[Service] -WorkingDirectory=/var/lib/ord -Environment="RUST_LOG=info" -ExecStart=/usr/local/bin/ord \ - --index-size 1TiB \ - --rpc-url 127.0.0.1:8332 \ - --cookie-file /var/lib/bitcoind/.cookie \ - index - -# Process management -#################### - -Type=simple -Restart=on-failure -TimeoutStopSec=10m -RestartSec=5s - -# Directory creation and permissions -#################################### - -User=ord -Group=ord - -# /var/lib/ord -StateDirectory=ord -StateDirectoryMode=0700 - -# Hardening measures -#################### - -# Provide a private /tmp and /var/tmp. -PrivateTmp=true - -# Mount /usr, /boot/ and /etc read-only for the process. -ProtectSystem=full - -# Deny access to /home, /root and /run/user -ProtectHome=true - -# Disallow the process and all of its children to gain -# new privileges through execve(). -NoNewPrivileges=true - -# Use a new /dev namespace only populated with API pseudo devices -# such as /dev/null, /dev/zero and /dev/random. -PrivateDevices=true - -# Deny the creation of writable and executable memory mappings. -MemoryDenyWriteExecute=true - -[Install] -WantedBy=multi-user.target From b1b0d29ce459c9ea82a0daaf2cbe1da2d21cdd05 Mon Sep 17 00:00:00 2001 From: Casey Rodarmor Date: Fri, 18 Mar 2022 20:27:00 -0700 Subject: [PATCH 5/7] Don't writemap --- src/lmdb_database.rs | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/src/lmdb_database.rs b/src/lmdb_database.rs index 5d9ad22dda..bd5748920e 100644 --- a/src/lmdb_database.rs +++ b/src/lmdb_database.rs @@ -37,15 +37,7 @@ impl Database { builder.set_mapsize(options.index_size.0)?; builder - .open( - path, - if cfg!(target_os = "macos") { - lmdb::open::Flags::empty() - } else { - lmdb::open::WRITEMAP - }, - 0o600, - ) + .open(path, lmdb::open::Flags::empty(), 0o600) .unwrap() }; From 55a537cd51cf9639853f6f3f48746a2d106a79a3 Mon Sep 17 00:00:00 2001 From: Casey Rodarmor Date: Fri, 18 Mar 2022 20:27:55 -0700 Subject: [PATCH 6/7] Fix use --- src/main.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main.rs b/src/main.rs index 550e6272c7..8d6e74bc11 100644 --- a/src/main.rs +++ b/src/main.rs @@ -5,8 +5,7 @@ use { arguments::Arguments, bytes::Bytes, epoch::Epoch, height::Height, index::Index, key::Key, options::Options, ordinal::Ordinal, sat_point::SatPoint, subcommand::Subcommand, }, - anyhow::Context, - anyhow::{anyhow, Error}, + anyhow::{anyhow, Context, Error}, bitcoin::{ blockdata::constants::COIN_VALUE, consensus::Decodable, consensus::Encodable, Block, BlockHash, OutPoint, Transaction, Txid, From 382c63138781426a94c92d109853bfd7feb741c2 Mon Sep 17 00:00:00 2001 From: Casey Rodarmor Date: Fri, 18 Mar 2022 20:31:45 -0700 Subject: [PATCH 7/7] Placate clippy --- src/index.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/index.rs b/src/index.rs index c0ce5ac8c9..d107614e8c 100644 --- a/src/index.rs +++ b/src/index.rs @@ -16,7 +16,7 @@ impl Index { options .rpc_url .as_ref() - .ok_or(anyhow!("This command requires `--rpc-url`"))?, + .ok_or_else(|| anyhow!("This command requires `--rpc-url`"))?, options .cookie_file .as_ref() @@ -141,7 +141,7 @@ impl Index { let ordinal_ranges = wtx .get_ordinal_ranges(key.as_slice())? - .ok_or(anyhow!("Could not find outpoint in index"))?; + .ok_or_else(|| anyhow!("Could not find outpoint in index"))?; let new = input_ordinal_ranges.len(); @@ -227,7 +227,7 @@ impl Index { while remaining > 0 { let range = input_ordinal_ranges .pop_front() - .ok_or(anyhow!("Insufficient inputs for transaction outputs"))?; + .ok_or_else(|| anyhow!("Insufficient inputs for transaction outputs"))?; let count = range.1 - range.0;