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

Check core version before attempting inscription. #1048

Merged
merged 15 commits into from
Dec 31, 2022
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