Skip to content

Commit

Permalink
Check Bitcoin Core version before inscribing (ordinals#1048)
Browse files Browse the repository at this point in the history
  • Loading branch information
rot13maxi authored Dec 31, 2022
1 parent 7c9712a commit a2394a5
Show file tree
Hide file tree
Showing 7 changed files with 216 additions and 72 deletions.
6 changes: 4 additions & 2 deletions src/options.rs
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ impl Options {

#[cfg(test)]
mod tests {
use {super::*, std::path::Path};
use {super::*, bitcoin::Network, std::path::Path};

#[test]
fn rpc_url_overrides_network() {
Expand Down Expand Up @@ -395,7 +395,9 @@ mod tests {

#[test]
fn rpc_server_chain_must_match() {
let rpc_server = test_bitcoincore_rpc::spawn_with(bitcoin::Network::Testnet, "ord");
let rpc_server = test_bitcoincore_rpc::builder()
.network(Network::Testnet)
.build();

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

Expand Down
22 changes: 21 additions & 1 deletion src/subcommand/wallet/inscribe.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,17 @@ use {
std::collections::BTreeSet,
};

const MIN_BITCOIN_VERSION: usize = 240000;

fn format_bitcoin_core_version(version: usize) -> String {
format!(
"{}.{}.{}",
version / 10000,
version % 10000 / 100,
version % 100
)
}

#[derive(Debug, Parser)]
pub(crate) struct Inscribe {
#[clap(long, help = "Inscribe <SATPOINT>")]
Expand All @@ -30,6 +41,15 @@ impl Inscribe {
pub(crate) fn run(self, options: Options) -> Result {
let client = options.bitcoin_rpc_client_mainnet_forbidden("ord wallet inscribe")?;

let bitcoin_version = client.version()?;
if bitcoin_version < MIN_BITCOIN_VERSION {
bail!(
"Bitcoin Core {} or newer required, current version is {}",
format_bitcoin_core_version(MIN_BITCOIN_VERSION),
format_bitcoin_core_version(bitcoin_version),
);
}

let inscription = Inscription::from_file(options.chain(), &self.file)?;

let index = Index::open(&options)?;
Expand Down Expand Up @@ -223,7 +243,7 @@ impl Inscribe {
assert_eq!(
Address::p2tr_tweaked(
TweakedPublicKey::dangerous_assume_tweaked(x_only_pub_key),
network
network,
),
commit_tx_address
);
Expand Down
95 changes: 65 additions & 30 deletions test-bitcoincore-rpc/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,44 +33,79 @@ mod api;
mod server;
mod state;

pub fn spawn_with(network: Network, wallet_name: &str) -> Handle {
let state = Arc::new(Mutex::new(State::new(network, wallet_name)));
let server = Server::new(state.clone());
let mut io = IoHandler::default();
io.extend_with(server.to_delegate());

let rpc_server = ServerBuilder::new(io)
.threads(1)
.start_http(&"127.0.0.1:0".parse().unwrap())
.unwrap();

let close_handle = rpc_server.close_handle();
let port = rpc_server.address().port();

thread::spawn(|| rpc_server.wait());

for i in 0.. {
match reqwest::blocking::get(format!("http://127.0.0.1:{port}/")) {
Ok(_) => break,
Err(err) => {
if i == 400 {
panic!("Server failed to start: {err}");
pub fn builder() -> Builder {
Builder {
network: Network::Bitcoin,
version: 240000,
wallet_name: "ord",
}
}

pub struct Builder {
network: Network,
version: usize,
wallet_name: &'static str,
}

impl Builder {
pub fn network(self, network: Network) -> Self {
Self { network, ..self }
}

pub fn version(self, version: usize) -> Self {
Self { version, ..self }
}

pub fn wallet_name(self, wallet_name: &'static str) -> Self {
Self {
wallet_name,
..self
}
}

pub fn build(self) -> Handle {
let state = Arc::new(Mutex::new(State::new(
self.network,
self.version,
self.wallet_name,
)));
let server = Server::new(state.clone());
let mut io = IoHandler::default();
io.extend_with(server.to_delegate());

let rpc_server = ServerBuilder::new(io)
.threads(1)
.start_http(&"127.0.0.1:0".parse().unwrap())
.unwrap();

let close_handle = rpc_server.close_handle();
let port = rpc_server.address().port();

thread::spawn(|| rpc_server.wait());

for i in 0.. {
match reqwest::blocking::get(format!("http://127.0.0.1:{port}/")) {
Ok(_) => break,
Err(err) => {
if i == 400 {
panic!("Server failed to start: {err}");
}
}
}
}

thread::sleep(Duration::from_millis(25));
}
thread::sleep(Duration::from_millis(25));
}

Handle {
close_handle: Some(close_handle),
port,
state,
Handle {
close_handle: Some(close_handle),
port,
state,
}
}
}

pub fn spawn() -> Handle {
spawn_with(Network::Bitcoin, "ord")
builder().build()
}

#[derive(Default)]
Expand Down
2 changes: 1 addition & 1 deletion test-bitcoincore-rpc/src/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ impl Api for Server {

fn get_network_info(&self) -> Result<GetNetworkInfoResult, jsonrpc_core::Error> {
Ok(GetNetworkInfoResult {
version: 230000,
version: self.state().version,
subversion: String::new(),
protocol_version: 0,
local_services: String::new(),
Expand Down
4 changes: 3 additions & 1 deletion test-bitcoincore-rpc/src/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,13 @@ pub(crate) struct State {
pub(crate) nonce: u32,
pub(crate) transactions: BTreeMap<Txid, Transaction>,
pub(crate) utxos: BTreeMap<OutPoint, Amount>,
pub(crate) version: usize,
pub(crate) wallet_name: String,
pub(crate) wallets: BTreeSet<String>,
}

impl State {
pub(crate) fn new(network: Network, wallet_name: &str) -> Self {
pub(crate) fn new(network: Network, version: usize, wallet_name: &str) -> Self {
let mut hashes = Vec::new();
let mut blocks = BTreeMap::new();

Expand All @@ -32,6 +33,7 @@ impl State {
nonce: 0,
transactions: BTreeMap::new(),
utxos: BTreeMap::new(),
version,
wallet_name: wallet_name.to_string(),
wallets: BTreeSet::new(),
}
Expand Down
37 changes: 28 additions & 9 deletions tests/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,9 @@ fn run() {

#[test]
fn inscription_page() {
let rpc_server = test_bitcoincore_rpc::spawn_with(Network::Regtest, "ord");
let rpc_server = test_bitcoincore_rpc::builder()
.network(Network::Regtest)
.build();
let txid = rpc_server.mine_blocks(1)[0].txdata[0].txid();

let stdout = CommandBuilder::new(format!(
Expand Down Expand Up @@ -77,7 +79,9 @@ fn inscription_page() {

#[test]
fn inscription_appears_on_reveal_transaction_page() {
let rpc_server = test_bitcoincore_rpc::spawn_with(Network::Regtest, "ord");
let rpc_server = test_bitcoincore_rpc::builder()
.network(Network::Regtest)
.build();
let txid = rpc_server.mine_blocks(1)[0].txdata[0].txid();

let stdout = CommandBuilder::new(format!(
Expand All @@ -100,7 +104,9 @@ fn inscription_appears_on_reveal_transaction_page() {

#[test]
fn inscription_page_after_send() {
let rpc_server = test_bitcoincore_rpc::spawn_with(Network::Regtest, "ord");
let rpc_server = test_bitcoincore_rpc::builder()
.network(Network::Regtest)
.build();
let txid = rpc_server.mine_blocks(1)[0].txdata[0].txid();

let stdout = CommandBuilder::new(format!(
Expand Down Expand Up @@ -152,7 +158,9 @@ fn inscription_page_after_send() {

#[test]
fn inscription_content() {
let rpc_server = test_bitcoincore_rpc::spawn_with(Network::Regtest, "ord");
let rpc_server = test_bitcoincore_rpc::builder()
.network(Network::Regtest)
.build();
let txid = rpc_server.mine_blocks(1)[0].txdata[0].txid();

let stdout = CommandBuilder::new(format!(
Expand Down Expand Up @@ -184,7 +192,9 @@ fn inscription_content() {

#[test]
fn home_page_includes_latest_inscriptions() {
let rpc_server = test_bitcoincore_rpc::spawn_with(Network::Regtest, "ord");
let rpc_server = test_bitcoincore_rpc::builder()
.network(Network::Regtest)
.build();

let inscription_id = create_inscription(&rpc_server, "foo.png");

Expand All @@ -201,7 +211,9 @@ fn home_page_includes_latest_inscriptions() {

#[test]
fn home_page_only_includes_graphical_inscriptions() {
let rpc_server = test_bitcoincore_rpc::spawn_with(Network::Regtest, "ord");
let rpc_server = test_bitcoincore_rpc::builder()
.network(Network::Regtest)
.build();

create_inscription(&rpc_server, "hello.txt");
let inscription_id = create_inscription(&rpc_server, "foo.png");
Expand All @@ -219,7 +231,9 @@ fn home_page_only_includes_graphical_inscriptions() {

#[test]
fn home_page_inscriptions_are_sorted() {
let rpc_server = test_bitcoincore_rpc::spawn_with(Network::Regtest, "ord");
let rpc_server = test_bitcoincore_rpc::builder()
.network(Network::Regtest)
.build();

let mut inscriptions = String::new();

Expand All @@ -240,7 +254,10 @@ fn home_page_inscriptions_are_sorted() {

#[test]
fn inscriptions_page() {
let rpc_server = test_bitcoincore_rpc::spawn_with(Network::Regtest, "ord");
let rpc_server = test_bitcoincore_rpc::builder()
.network(Network::Regtest)
.build();

let txid = rpc_server.mine_blocks(1)[0].txdata[0].txid();

let stdout = CommandBuilder::new(format!(
Expand Down Expand Up @@ -269,7 +286,9 @@ fn inscriptions_page() {

#[test]
fn inscriptions_page_is_sorted() {
let rpc_server = test_bitcoincore_rpc::spawn_with(Network::Regtest, "ord");
let rpc_server = test_bitcoincore_rpc::builder()
.network(Network::Regtest)
.build();

let mut inscriptions = String::new();

Expand Down
Loading

0 comments on commit a2394a5

Please sign in to comment.