SHOWING: First 60
"bitflags 1.3.2",
]
[[package]]
name = "redox_users"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b"
dependencies = [
"getrandom 0.2.10",
"redox_syscall 0.2.16",
"thiserror",
]
[[package]]
name = "regex"
version = "1.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b2eae68fc220f7cf2532e4494aded17545fce192d59cd996e0fe7887f4ceb575"
dependencies = [
"aho-corasick",
"memchr",
"regex-automata",
"regex-syntax",
]
[[package]]
name = "regex-automata"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "39354c10dd07468c2e73926b23bb9c2caca74c5501e38a35da70406f1d923310"
dependencies = [
"aho-corasick",
"memchr",
"regex-syntax",
]
[[package]]
name = "regex-syntax"
version = "0.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e5ea92a5b6195c6ef2a0295ea818b312502c6fc94dde986c5553242e18fd4ce2"
#44,990,590textchecksum = "e17bb3549cc1321ae1296b9cdc2698e2b6cb1992adfa19a8c72e5b7a738f44cd"
dependencies = [
"time 0.3.23",
]
#44,990,562textedition = "2018"
max_width = 100
newline_style = "Unix"
tab_spaces = 2
use_field_init_shorthand = true
use_try_shorthand = true
#44,986,934text };
fields.entry(tag).or_insert(value);
}
Self { fields, body }
}
}
impl Runestone {
pub fn from_transaction(transaction: &Transaction) -> Option<Self> {
Self::decipher(transaction).ok().flatten()
}
fn decipher(transaction: &Transaction) -> Result<Option<Self>> {
let Some(payload) = Runestone::payload(transaction)? else {
return Ok(None);
};
let mut integers = Vec::new();
let mut i = 0;
while i < payload.len() {
let (integer, length) = varint::decode(&payload[i..])?;
integers.push(integer);
i += length;
}
let Message { mut fields, body } = Message::from_integers(&integers);
let etching = fields.remove(&TAG_RUNE).map(|rune| Etching {
divisibility: fields
.remove(&TAG_DIVISIBILITY)
.and_then(|divisibility| u8::try_from(divisibility).ok())
.and_then(|divisibility| (divisibility <= MAX_DIVISIBILITY).then_some(divisibility))
.unwrap_or_default(),
limit: fields
.remove(&TAG_LIMIT)
#44,985,374text version: 0,
}),
Ok(Some(Runestone {
edicts: vec![Edict {
id: 1,
amount: 2,
output: 3,
}],
..Default::default()
}))
);
}
#[test]
fn runestone_may_be_after_non_matching_op_return() {
let payload = payload(&[0, 1, 2, 3]);
let payload: &PushBytes = payload.as_slice().try_into().unwrap();
assert_eq!(
Runestone::decipher(&Transaction {
input: Vec::new(),
output: vec![
TxOut {
script_pubkey: script::Builder::new()
.push_opcode(opcodes::all::OP_RETURN)
.push_slice(b"FOO")
.into_script(),
value: 0,
},
TxOut {
script_pubkey: script::Builder::new()
.push_opcode(opcodes::all::OP_RETURN)
.push_slice(b"RUNE_TEST")
.push_slice(payload)
.into_script(),
value: 0
}
],
lock_time: locktime::absolute::LockTime::ZERO,
#44,985,370text version: 0,
}),
Ok(Some(Runestone {
edicts: vec![Edict {
id: 1,
amount: 2,
output: 3,
}],
etching: Some(Etching {
rune: Rune(4),
divisibility: 5,
..Default::default()
}),
..Default::default()
}))
);
}
#[test]
fn runestone_may_be_in_second_output() {
let payload = payload(&[0, 1, 2, 3]);
let payload: &PushBytes = payload.as_slice().try_into().unwrap();
assert_eq!(
Runestone::decipher(&Transaction {
input: Vec::new(),
output: vec![
TxOut {
script_pubkey: ScriptBuf::new(),
value: 0,
},
TxOut {
script_pubkey: script::Builder::new()
.push_opcode(opcodes::all::OP_RETURN)
.push_slice(b"RUNE_TEST")
.push_slice(payload)
.into_script(),
value: 0
}
],
lock_time: locktime::absolute::LockTime::ZERO,
#44,985,359text
assert_eq!(
"0000000000000000000000000000000000000000000000000000000000000000:0:0"
.parse::<Outgoing>()
.unwrap(),
Outgoing::SatPoint(
"0000000000000000000000000000000000000000000000000000000000000000:0:0"
.parse()
.unwrap()
),
);
assert_eq!(
"0 sat".parse::<Outgoing>().unwrap(),
Outgoing::Amount("0 sat".parse().unwrap()),
);
assert_eq!(
"0sat".parse::<Outgoing>().unwrap(),
Outgoing::Amount("0 sat".parse().unwrap()),
);
assert!("0".parse::<Outgoing>().is_err());
}
}
#44,985,358textuse super::*;
#[derive(Copy, Clone)]
pub(crate) enum Blocktime {
Confirmed(DateTime<Utc>),
Expected(DateTime<Utc>),
}
impl Blocktime {
pub(crate) fn confirmed(seconds: u32) -> Self {
Self::Confirmed(timestamp(seconds))
}
pub(crate) fn timestamp(self) -> DateTime<Utc> {
match self {
Self::Confirmed(timestamp) | Self::Expected(timestamp) => timestamp,
}
}
pub(crate) fn unix_timestamp(self) -> i64 {
match self {
Self::Confirmed(timestamp) | Self::Expected(timestamp) => timestamp.timestamp(),
}
}
pub(crate) fn suffix(self) -> &'static str {
match self {
Self::Confirmed(_) => "",
Self::Expected(_) => " (expected)",
}
}
}
#44,983,636text .iter()
.flat_map(|(_, _, _, extensions)| extensions.first().cloned())
.collect::<Vec<&str>>();
extensions.sort();
Err(anyhow!(
"unsupported file extension `.{extension}`, supported extensions: {}",
extensions.join(" "),
))
}
pub(crate) fn check_mp4_codec(path: &Path) -> Result<(), Error> {
let f = File::open(path)?;
let size = f.metadata()?.len();
let reader = BufReader::new(f);
let mp4 = Mp4Reader::read_header(reader, size)?;
for track in mp4.tracks().values() {
if let TrackType::Video = track.track_type()? {
let media_type = track.media_type()?;
if media_type != MediaType::H264 {
return Err(anyhow!(
"Unsupported video codec, only H.264 is supported in MP4: {media_type}"
));
}
}
}
Ok(())
}
}
impl FromStr for Media {
type Err = Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
for entry in Self::TABLE {
if entry.0 == s {
return Ok(entry.2);
#44,983,510texttoken-mint1.tapart tapx 44226185#44,518,673taptoken-mint1.tapart tapx 44226185#44,518,672taptoken-mint1.tapart tapx 44226185#44,518,671tap