Skip to content

Commit

Permalink
Allow inscribing without file (ordinals#3451)
Browse files Browse the repository at this point in the history
This allows inscribing only the delegate without having to specify a file. In the batch it allows you to comletely omit the file as well.
  • Loading branch information
raphjaph authored Apr 11, 2024
1 parent b2ae17d commit f77ee3f
Show file tree
Hide file tree
Showing 15 changed files with 250 additions and 110 deletions.
106 changes: 52 additions & 54 deletions src/inscriptions/inscription.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,79 +25,77 @@ pub struct Inscription {
}

impl Inscription {
#[cfg(test)]
pub(crate) fn new(content_type: Option<Vec<u8>>, body: Option<Vec<u8>>) -> Self {
Self {
content_type,
body,
..default()
}
}

pub(crate) fn from_file(
pub fn new(
chain: Chain,
compress: bool,
delegate: Option<InscriptionId>,
metadata: Option<Vec<u8>>,
metaprotocol: Option<String>,
parents: Vec<InscriptionId>,
path: impl AsRef<Path>,
path: Option<PathBuf>,
pointer: Option<u64>,
rune: Option<Rune>,
) -> Result<Self, Error> {
let path = path.as_ref();

let body = fs::read(path).with_context(|| format!("io error reading {}", path.display()))?;
let (body, content_type, content_encoding) = if let Some(path) = path {
let body = fs::read(path).with_context(|| format!("io error reading {}", path.display()))?;

let (content_type, compression_mode) = Media::content_type_for_path(path)?;
let content_type = Media::content_type_for_path(path)?.0;

let (body, content_encoding) = if compress {
let mut compressed = Vec::new();
let (body, content_encoding) = if compress {
let compression_mode = Media::content_type_for_path(path)?.1;
let mut compressed = Vec::new();

{
CompressorWriter::with_params(
&mut compressed,
body.len(),
&BrotliEncoderParams {
lgblock: 24,
lgwin: 24,
mode: compression_mode,
quality: 11,
size_hint: body.len(),
..default()
},
)
.write_all(&body)?;
{
CompressorWriter::with_params(
&mut compressed,
body.len(),
&BrotliEncoderParams {
lgblock: 24,
lgwin: 24,
mode: compression_mode,
quality: 11,
size_hint: body.len(),
..default()
},
)
.write_all(&body)?;

let mut decompressor = brotli::Decompressor::new(compressed.as_slice(), compressed.len());
let mut decompressor = brotli::Decompressor::new(compressed.as_slice(), compressed.len());

let mut decompressed = Vec::new();
let mut decompressed = Vec::new();

decompressor.read_to_end(&mut decompressed)?;
decompressor.read_to_end(&mut decompressed)?;

ensure!(decompressed == body, "decompression roundtrip failed");
}
ensure!(decompressed == body, "decompression roundtrip failed");
}

if compressed.len() < body.len() {
(compressed, Some("br".as_bytes().to_vec()))
if compressed.len() < body.len() {
(compressed, Some("br".as_bytes().to_vec()))
} else {
(body, None)
}
} else {
(body, None)
};

if let Some(limit) = chain.inscription_content_size_limit() {
let len = body.len();
if len > limit {
bail!("content size of {len} bytes exceeds {limit} byte limit for {chain} inscriptions");
}
}

(Some(body), Some(content_type), content_encoding)
} else {
(body, None)
(None, None, None)
};

if let Some(limit) = chain.inscription_content_size_limit() {
let len = body.len();
if len > limit {
bail!("content size of {len} bytes exceeds {limit} byte limit for {chain} inscriptions");
}
}

Ok(Self {
body: Some(body),
body,
content_encoding,
content_type: Some(content_type.into()),
content_type: content_type.map(|content_type| content_type.into()),
delegate: delegate.map(|delegate| delegate.value()),
metadata,
metaprotocol: metaprotocol.map(|metaprotocol| metaprotocol.into_bytes()),
Expand Down Expand Up @@ -771,59 +769,59 @@ mod tests {

write!(file, "foo").unwrap();

let inscription = Inscription::from_file(
let inscription = Inscription::new(
Chain::Mainnet,
false,
None,
None,
None,
Vec::new(),
file.path(),
Some(file.path().to_path_buf()),
None,
None,
)
.unwrap();

assert_eq!(inscription.pointer, None);

let inscription = Inscription::from_file(
let inscription = Inscription::new(
Chain::Mainnet,
false,
None,
None,
None,
Vec::new(),
file.path(),
Some(file.path().to_path_buf()),
Some(0),
None,
)
.unwrap();

assert_eq!(inscription.pointer, Some(Vec::new()));

let inscription = Inscription::from_file(
let inscription = Inscription::new(
Chain::Mainnet,
false,
None,
None,
None,
Vec::new(),
file.path(),
Some(file.path().to_path_buf()),
Some(1),
None,
)
.unwrap();

assert_eq!(inscription.pointer, Some(vec![1]));

let inscription = Inscription::from_file(
let inscription = Inscription::new(
Chain::Mainnet,
false,
None,
None,
None,
Vec::new(),
file.path(),
Some(file.path().to_path_buf()),
Some(256),
None,
)
Expand Down
57 changes: 48 additions & 9 deletions src/subcommand/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3126,7 +3126,12 @@ mod tests {
3,
0,
0,
Inscription::new(None, Some("hello".as_bytes().into())).to_witness(),
Inscription {
content_type: None,
body: Some("hello".as_bytes().into()),
..default()
}
.to_witness(),
)],
..default()
});
Expand Down Expand Up @@ -3974,7 +3979,11 @@ mod tests {
fn content_response_no_content() {
assert_eq!(
Server::content_response(
Inscription::new(Some("text/plain".as_bytes().to_vec()), None),
Inscription {
content_type: Some("text/plain".as_bytes().to_vec()),
body: None,
..default()
},
AcceptEncoding::default(),
&ServerConfig::default(),
)
Expand All @@ -3986,7 +3995,11 @@ mod tests {
#[test]
fn content_response_with_content() {
let (headers, body) = Server::content_response(
Inscription::new(Some("text/plain".as_bytes().to_vec()), Some(vec![1, 2, 3])),
Inscription {
content_type: Some("text/plain".as_bytes().to_vec()),
body: Some(vec![1, 2, 3]),
..default()
},
AcceptEncoding::default(),
&ServerConfig::default(),
)
Expand All @@ -4000,7 +4013,11 @@ mod tests {
#[test]
fn content_security_policy_no_origin() {
let (headers, _) = Server::content_response(
Inscription::new(Some("text/plain".as_bytes().to_vec()), Some(vec![1, 2, 3])),
Inscription {
content_type: Some("text/plain".as_bytes().to_vec()),
body: Some(vec![1, 2, 3]),
..default()
},
AcceptEncoding::default(),
&ServerConfig::default(),
)
Expand All @@ -4016,7 +4033,11 @@ mod tests {
#[test]
fn content_security_policy_with_origin() {
let (headers, _) = Server::content_response(
Inscription::new(Some("text/plain".as_bytes().to_vec()), Some(vec![1, 2, 3])),
Inscription {
content_type: Some("text/plain".as_bytes().to_vec()),
body: Some(vec![1, 2, 3]),
..default()
},
AcceptEncoding::default(),
&ServerConfig {
csp_origin: Some("https://ordinals.com".into()),
Expand Down Expand Up @@ -4107,7 +4128,11 @@ mod tests {
#[test]
fn content_response_no_content_type() {
let (headers, body) = Server::content_response(
Inscription::new(None, Some(Vec::new())),
Inscription {
content_type: None,
body: Some(Vec::new()),
..default()
},
AcceptEncoding::default(),
&ServerConfig::default(),
)
Expand All @@ -4121,7 +4146,11 @@ mod tests {
#[test]
fn content_response_bad_content_type() {
let (headers, body) = Server::content_response(
Inscription::new(Some("\n".as_bytes().to_vec()), Some(Vec::new())),
Inscription {
content_type: Some("\n".as_bytes().to_vec()),
body: Some(Vec::new()),
..Default::default()
},
AcceptEncoding::default(),
&ServerConfig::default(),
)
Expand Down Expand Up @@ -4471,7 +4500,12 @@ mod tests {
1,
0,
0,
Inscription::new(Some("foo/bar".as_bytes().to_vec()), None).to_witness(),
Inscription {
content_type: Some("foo/bar".as_bytes().to_vec()),
body: None,
..default()
}
.to_witness(),
)],
..default()
});
Expand Down Expand Up @@ -4500,7 +4534,12 @@ mod tests {
1,
0,
0,
Inscription::new(Some("image/png".as_bytes().to_vec()), None).to_witness(),
Inscription {
content_type: Some("image/png".as_bytes().to_vec()),
body: None,
..default()
}
.to_witness(),
)],
..default()
});
Expand Down
4 changes: 2 additions & 2 deletions src/subcommand/wallet/batch_command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -224,12 +224,12 @@ inscriptions:
batch::File {
inscriptions: vec![
batch::Entry {
file: inscription_path,
file: Some(inscription_path),
metadata: Some(Value::Mapping(metadata)),
..default()
},
batch::Entry {
file: brc20_path,
file: Some(brc20_path),
metaprotocol: Some("brc-20".to_string()),
..default()
}
Expand Down
Loading

0 comments on commit f77ee3f

Please sign in to comment.