SHOWING: First 60
0#47,101,630text0#47,101,166text #47,098,843text #47,097,077text #47,096,690text #47,096,601text #47,096,423text #47,093,474text #47,092,156text #47,092,069text #47,092,042text #47,091,983text outpoint
),
);
ord_server.assert_response_regex(
format!("/inscription/{}", output.inscriptions[2].id),
format!(
r".*<dt>location</dt>.*<dd class=monospace>{}:20000</dd>.*",
outpoint
),
);
ord_server.assert_response_regex(
format!("/output/{}", output.inscriptions[0].location.outpoint),
format!(r".*<a href=/inscription/{}>.*</a>.*<a href=/inscription/{}>.*</a>.*<a href=/inscription/{}>.*</a>.*", output.inscriptions[0].id, output.inscriptions[1].id, output.inscriptions[2].id),
);
}
#[test]
fn batch_in_same_output_with_non_default_postage() {
let rpc_server = test_bitcoincore_rpc::spawn();
rpc_server.mine_blocks(1);
create_wallet(&rpc_server);
let output = CommandBuilder::new("wallet inscribe --fee-rate 1 --batch batch.yaml")
.write("inscription.txt", "Hello World")
.write("tulip.png", [0; 555])
.write("meow.wav", [0; 2048])
.write(
"batch.yaml",
"mode: shared-output\npostage: 777\ninscriptions:\n- file: inscription.txt\n- file: tulip.png\n- file: meow.wav\n"
#45,160,776text CommandBuilder::new(format!(
"wallet inscribe --satpoint {txid}:0:0 --file degenerate.png --fee-rate 0"
))
.write("degenerate.png", [1; 100])
.rpc_server(&rpc_server)
.run_and_deserialize_output::<Inscribe>();
let txid = rpc_server.mine_blocks_with_subsidy(1, 100)[0].txdata[0].txid();
CommandBuilder::new(format!(
"wallet send --fee-rate 1 bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4 {txid}:0:0"
))
.rpc_server(&rpc_server)
.expected_exit_code(1)
.expected_stderr("error: wallet does not contain enough cardinal UTXOs, please add additional funds to wallet.\n")
.run_and_extract_stdout();
}
#[test]
fn do_not_send_within_dust_limit_of_an_inscription() {
let rpc_server = test_bitcoincore_rpc::spawn();
create_wallet(&rpc_server);
let (inscription, reveal) = inscribe(&rpc_server);
rpc_server.mine_blocks(1);
let output = OutPoint {
txid: reveal,
vout: 0,
};
CommandBuilder::new(format!(
"wallet send --fee-rate 1 bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4 {output}:329"
#45,159,660text index: 1
},
InscriptionId {
txid: reveal_txid,
index: 2
},
],
runes: BTreeMap::new(),
}
);
// try and fail to send first
CommandBuilder::new(format!(
"wallet send --fee-rate 1 bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4 {}i0",
reveal_txid,
))
.rpc_server(&rpc_server)
.expected_exit_code(1)
.expected_stderr(format!(
"error: cannot send {reveal_txid}:0:0 without also sending inscription {reveal_txid}i2 at {reveal_txid}:0:{}\n", 100 * COIN_VALUE
))
.run_and_extract_stdout();
// splitting out last
CommandBuilder::new(format!(
"wallet send --fee-rate 1 bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4 {}i2",
reveal_txid,
))
.rpc_server(&rpc_server)
.run_and_deserialize_output::<Output>();
rpc_server.mine_blocks(1);
// splitting second to last
CommandBuilder::new(format!(
"wallet send --fee-rate 1 bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4 {}i1",
reveal_txid,
))
.rpc_server(&rpc_server)
#45,159,659text .run_and_deserialize_output::<send::Output>()
.transaction;
rpc_server.mine_blocks(1);
let output = CommandBuilder::new("wallet inscriptions")
.rpc_server(&rpc_server)
.run_and_deserialize_output::<Vec<inscriptions::Output>>();
assert_eq!(output.len(), 1);
assert_eq!(output[0].inscription, inscription);
assert_eq!(output[0].location, format!("{txid}:0:0").parse().unwrap());
}
#[test]
fn inscriptions_includes_locked_utxos() {
let rpc_server = test_bitcoincore_rpc::spawn();
create_wallet(&rpc_server);
rpc_server.mine_blocks(1);
let (inscription, reveal) = inscribe(&rpc_server);
rpc_server.mine_blocks(1);
rpc_server.lock(OutPoint {
txid: reveal,
vout: 0,
});
let output = CommandBuilder::new("wallet inscriptions")
.rpc_server(&rpc_server)
.run_and_deserialize_output::<Vec<inscriptions::Output>>();
assert_eq!(output.len(), 1);
assert_eq!(output[0].inscription, inscription);
assert_eq!(output[0].location, format!("{reveal}:0:0").parse().unwrap());
#45,023,648textuse {super::*, ord::subcommand::wallet::balance::Output};
#[test]
fn wallet_balance() {
let rpc_server = test_bitcoincore_rpc::spawn();
create_wallet(&rpc_server);
assert_eq!(
CommandBuilder::new("wallet balance")
.rpc_server(&rpc_server)
.run_and_deserialize_output::<Output>()
.cardinal,
0
);
rpc_server.mine_blocks(1);
assert_eq!(
CommandBuilder::new("wallet balance")
.rpc_server(&rpc_server)
.run_and_deserialize_output::<Output>()
.cardinal,
50 * COIN_VALUE
);
}
#[test]
fn wallet_balance_only_counts_cardinal_utxos() {
let rpc_server = test_bitcoincore_rpc::spawn();
create_wallet(&rpc_server);
assert_eq!(
CommandBuilder::new("wallet balance")
.rpc_server(&rpc_server)
.run_and_deserialize_output::<Output>()
.cardinal,
0
);
inscribe(&rpc_server);
assert_eq!(
CommandBuilder::new("wallet balance")
.rpc_server(&rpc_server)
.run_and_deserialize_output::<Output>()
.cardinal,
100 * COIN_VALUE - 10_000
#45,023,643text })
}
fn get_blockchain_info(&self) -> Result<GetBlockchainInfoResult, jsonrpc_core::Error> {
Ok(GetBlockchainInfoResult {
chain: String::from(match self.network {
Network::Bitcoin => "main",
Network::Testnet => "test",
Network::Signet => "signet",
Network::Regtest => "regtest",
_ => panic!(),
}),
blocks: 0,
headers: 0,
best_block_hash: self.state().hashes[0],
difficulty: 0.0,
median_time: 0,
verification_progress: 0.0,
initial_block_download: false,
chain_work: Vec::new(),
size_on_disk: 0,
pruned: false,
prune_height: None,
automatic_pruning: None,
prune_target_size: None,
softforks: HashMap::new(),
warnings: String::new(),
})
}
fn get_network_info(&self) -> Result<GetNetworkInfoResult, jsonrpc_core::Error> {
Ok(GetNetworkInfoResult {
version: self.state().version,
subversion: String::new(),
protocol_version: 0,
local_services: String::new(),
#44,995,180text 0xA2, 0x63, b'f', b'o', b'o', 0x63, b'b', b'a', b'r', 0x63, b'b', b'a', b'z', 0x01,
],
)
.rpc_server(&rpc_server)
.run_and_deserialize_output();
let inscription = inscriptions[0].id;
rpc_server.mine_blocks(1);
let ord_server = TestServer::spawn_with_args(&rpc_server, &[]);
ord_server.assert_response_regex(
format!("/inscription/{inscription}"),
".*<dt>metadata</dt>.*<dl><dt>foo</dt><dd>bar</dd><dt>baz</dt><dd>1</dd></dl>.*",
);
}
#[test]
fn error_message_when_parsing_json_metadata_is_reasonable() {
CommandBuilder::new(
"wallet inscribe --fee-rate 1 --json-metadata metadata.json --file content.png",
)
.write("content.png", [1; 520])
.write("metadata.json", "{")
.stderr_regex(".*failed to parse JSON metadata.*")
.expected_exit_code(1)
.run_and_extract_stdout();
}
#[test]
fn error_message_when_parsing_cbor_metadata_is_reasonable() {
CommandBuilder::new(
"wallet inscribe --fee-rate 1 --cbor-metadata metadata.cbor --file content.png",
)
.write("content.png", [1; 520])
#44,994,778text .run_and_deserialize_output::<send::Output>()
.transaction;
rpc_server.mine_blocks(1);
let output = CommandBuilder::new("wallet inscriptions")
.rpc_server(&rpc_server)
.run_and_deserialize_output::<Vec<inscriptions::Output>>();
assert_eq!(output.len(), 1);
assert_eq!(output[0].inscription, inscription);
assert_eq!(output[0].location, format!("{txid}:0:0").parse().unwrap());
}
#[test]
fn inscriptions_includes_locked_utxos() {
let rpc_server = test_bitcoincore_rpc::spawn();
create_wallet(&rpc_server);
rpc_server.mine_blocks(1);
let (inscription, reveal) = inscribe(&rpc_server);
rpc_server.mine_blocks(1);
rpc_server.lock(OutPoint {
txid: reveal,
vout: 0,
});
let output = CommandBuilder::new("wallet inscriptions")
.rpc_server(&rpc_server)
.run_and_deserialize_output::<Vec<inscriptions::Output>>();
assert_eq!(output.len(), 1);
assert_eq!(output[0].inscription, inscription);
assert_eq!(output[0].location, format!("{reveal}:0:0").parse().unwrap());
#44,991,649text
let ord_server = TestServer::spawn_with_args(&rpc_server, &[]);
ord_server.assert_response_regex(
format!("/inscription/{inscription}"),
format!(
".*<h1>Inscription 0</h1>.*<dt>location</dt>.*<dd class=monospace>{send_txid}:0:0</dd>.*",
),
);
}
#[test]
fn send_on_mainnnet_works_with_wallet_named_foo() {
let rpc_server = test_bitcoincore_rpc::spawn();
let txid = rpc_server.mine_blocks(1)[0].txdata[0].txid();
CommandBuilder::new("--wallet foo wallet create")
.rpc_server(&rpc_server)
.run_and_deserialize_output::<ord::subcommand::wallet::create::Output>();
CommandBuilder::new(format!(
"--wallet foo wallet send --fee-rate 1 bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4 {txid}:0:0"
))
.rpc_server(&rpc_server)
.run_and_deserialize_output::<Output>();
}
#[test]
fn send_addresses_must_be_valid_for_network() {
let rpc_server = test_bitcoincore_rpc::builder().build();
let txid = rpc_server.mine_blocks_with_subsidy(1, 1_000)[0].txdata[0].txid();
create_wallet(&rpc_server);
#44,990,338text ))
.rpc_server(&rpc_server)
.expected_exit_code(1)
.expected_stderr(format!(
"error: cannot send {output}:329 without also sending inscription {inscription} at {output}:0\n"
))
.run_and_extract_stdout();
}
#[test]
fn can_send_after_dust_limit_from_an_inscription() {
let rpc_server = test_bitcoincore_rpc::spawn();
create_wallet(&rpc_server);
let (_, reveal) = inscribe(&rpc_server);
rpc_server.mine_blocks(1);
let output = OutPoint {
txid: reveal,
vout: 0,
};
CommandBuilder::new(format!(
"wallet send --fee-rate 1 bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4 {output}:330"
))
.rpc_server(&rpc_server)
.run_and_deserialize_output::<Output>();
}
#[test]
fn splitting_merged_inscriptions_is_possible() {
let rpc_server = test_bitcoincore_rpc::spawn();
create_wallet(&rpc_server);
rpc_server.mine_blocks(3);
let inscription = envelope(&[b"ord", &[1], b"text/plain;charset=utf-8", &[], b"bar"]);
// merging 3 inscriptions into one utxo
let reveal_txid = rpc_server.broadcast_tx(TransactionTemplate {
#44,990,330text"unlocking new classes of collector."
msgstr ""
"Ces bitcoiners pourraient être plus intéressés par les inscriptions que par "
"les NFTs Ethereum, ce qui ouvrirait la porte à d’autres types de "
"collectionneurs."
#: src\faq.md:204
msgid "_Inscriptions have a richer data model._"
msgstr "_Les inscriptions disposent d’un modèle de données plus riche._"
#: src\faq.md:206
msgid ""
"Inscriptions consist of a content type, also known as a MIME type, and "
"content, which is an arbitrary byte string. This is the same data model used "
"by the web, and allows inscription content to evolve with the web, and come "
"to support any kind of content supported by web browsers, without requiring "
"changes to the underlying protocol."
msgstr ""
"Une entrée se compose du type de contenu, appelé type MIME, et d’une chaîne "
"d’octets arbitraire constituant le contenu. Il s’agit du même modèle de "
"données que celui utilisé par le web, qui permet au contenu de l’inscription "
"d’évoluer avec le web et de prendre en charge tout type de contenu supporté "
#44,986,762textuse {super::*, ord::subcommand::list::Output};
#[test]
fn output_found() {
let rpc_server = test_bitcoincore_rpc::spawn();
let output = CommandBuilder::new(
"--index-sats list 4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b:0",
)
.rpc_server(&rpc_server)
.run_and_deserialize_output::<Vec<Output>>();
assert_eq!(
output,
vec![Output {
output: "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b:0"
.parse()
.unwrap(),
start: 0,
end: 50 * COIN_VALUE,
size: 50 * COIN_VALUE,
offset: 0,
rarity: "mythic".parse().unwrap(),
name: "nvtdijuwxlp".into(),
}]
);
}
#[test]
fn output_not_found() {
let rpc_server = test_bitcoincore_rpc::spawn();
CommandBuilder::new(
"--index-sats list 0000000000000000000000000000000000000000000000000000000000000000:0",
)
.rpc_server(&rpc_server)
.expected_exit_code(1)
.expected_stderr("error: output not found\n")
.run_and_extract_stdout();
}
#[test]
fn no_satoshi_index() {
#44,986,642textimport { marked } from 'https://cdn.jsdelivr.net/npm/marked@9/+esm'
const inscription = document.documentElement.dataset.inscription;
const response = await fetch(`/content/${inscription}`);
const markdown = await response.text();
document.body.innerHTML = marked.parse(markdown);
#44,981,487textuse super::*;
#[derive(Debug, PartialEq, Serialize, Deserialize)]
pub struct Output {
pub supply: u64,
pub first: u64,
pub last: u64,
pub last_mined_in_block: u32,
}
pub(crate) fn run() -> SubcommandResult {
let mut last = 0;
loop {
if Height(last + 1).subsidy() == 0 {
break;
}
last += 1;
}
Ok(Box::new(Output {
supply: Sat::SUPPLY,
first: 0,
last: Sat::SUPPLY - 1,
last_mined_in_block: last,
}))
}
#44,981,420textmsgstr "序数理论有什么用?"
#: src/faq.md:23
msgid ""
"Collecting, trading, and scheming. Ordinal theory assigns identities to "
"individual satoshis, allowing them to be individually tracked and traded, as "
"curios and for numismatic value."
msgstr ""
"收集、交易和策划。序数理论将身份分配给单个聪,允许它们作为古玩和钱币价值被单"
"独跟踪和交易。"
#: src/faq.md:27
msgid ""
"Ordinal theory also enables inscriptions, a protocol for attaching arbitrary "
"content to individual satoshis, turning them into bitcoin-native digital "
"artifacts."
msgstr ""
"序数理论还赋能铭文,这是一种将任意内容附加到单个聪的协议,将它们变成比特币原"
"生的数字文物。"
#: src/faq.md:31
msgid "How does ordinal theory work?"
msgstr "序数理论是如何运作的?"
#: src/faq.md:34
msgid ""
"Ordinal numbers are assigned to satoshis in the order in which they are "
"mined. The first satoshi in the first block has ordinal number 0, the second "
"has ordinal number 1, and the last satoshi of the first block has ordinal "
"number 4,999,999,999."
msgstr ""
"序数是按照挖矿的顺序分配给聪的。第一个区块的首聪序数为0,第二个聪的序数为1,"
"第一个区块的最后一个聪的序数为4,999,999,999。"
#: src/faq.md:39
msgid ""
#44,979,347texttransfer171.opnp#44,745,702brc-20transfer85.opnp#44,229,467brc-20transfer42.opnp#43,009,136brc-20dmt-mint.nat#42,586,409tapdmt-mint.nat#42,586,236tapdmt-mint.nat#42,569,895tapdmt-mint.nat#42,569,883tapdmt-mint.nat#42,569,839tapdmt-mint.nat#42,569,835tapdmt-mint.nat#42,569,800tapdmt-mint.nat#42,569,767tapdmt-mint.nat#42,569,746tapdmt-mint.nat#42,569,728tapdmt-mint.nat#42,569,706tapdmt-mint.nat#42,569,655tapdmt-mint.nat#42,569,648tapdmt-mint.nat#42,569,623tapdmt-mint.nat#42,569,622taptransfer42.opnp#42,566,712brc-20dmt-mint.nat#42,515,352tapdmt-mint.nat#42,515,317tapdmt-mint.nat#42,515,169tapdmt-mint.nat#42,515,085tapdmt-mint.nat#42,515,084tapdmt-mint.nat#42,503,020tapdmt-mint.nat#42,502,747tapdmt-mint.nat#42,502,697taptransfer42.opnp#42,462,427brc-20