diff --git a/Cargo.lock b/Cargo.lock index 09f4fd7f..a209c544 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -138,9 +138,9 @@ checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" [[package]] name = "baid58" -version = "0.4.1" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "052064cc0caa02b62c88f06a7237304fb297873c78b6e95addecc3c5ddfce4ae" +checksum = "bc0585242d87ed976e05db6ae86a0f771f140104a4b6c91b4c3e43b9b2357486" dependencies = [ "base58", "blake3", @@ -166,6 +166,12 @@ version = "0.21.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "604178f6c5c21f02dc555784810edfb88d34ac2c73b2eae109655649ee73ce3d" +[[package]] +name = "base85" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88b68cde48c539cf9db81c5598e215dc32d0401a167f899cf26e35f61815eb9e" + [[package]] name = "bitcoin-private" version = "0.1.0" @@ -203,9 +209,9 @@ dependencies = [ [[package]] name = "bp-core" -version = "0.10.6" +version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2cc8924479a43c605f789d7777fc622e8a110e49322fef87e69a40fa1724b6ed" +checksum = "8ad89567d378fb0bf06e1d3370b12c17b587563fa3ea075d22a6a3d7e3b77f2b" dependencies = [ "amplify", "bp-dbc", @@ -220,12 +226,12 @@ dependencies = [ [[package]] name = "bp-dbc" -version = "0.10.6" +version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b38314a8d4db1f7ef279be39568a24d008138e28fef4d8584a7303c62c4a7368" +checksum = "ac8b9fa8ce5e85c3b052f2857eb14b710e893052f2680584f48959627e78148b" dependencies = [ "amplify", - "baid58", + "base85", "bp-primitives", "commit_verify", "secp256k1", @@ -249,9 +255,9 @@ dependencies = [ [[package]] name = "bp-seals" -version = "0.10.6" +version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23f55e8ca6b1a0e411df160131f21b1991051984b5037b3f33e4f6c724c82f8a" +checksum = "6f02ea90eaca184fda85230cfac2457fd352c3d81bd28f67254185d0b199eb6f" dependencies = [ "amplify", "baid58", diff --git a/Cargo.toml b/Cargo.toml index 3d8002d1..13328998 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -28,9 +28,9 @@ strict_types = "~1.6.0" aluvm = { version = "~0.10.5", features = ["std"] } commit_verify = { version = "~0.10.5", features = ["rand", "derive"] } single_use_seals = "~0.10.0" -bp-core = { version = "~0.10.6" } +bp-core = { version = "~0.10.7" } secp256k1-zkp = { version = "0.8.0", features = ["use-rand", "rand-std", "global-context"] } -baid58 = "~0.4.1" +baid58 = "~0.4.4" mime = "~0.3.16" serde_crate = { package = "serde", version = "1", features = ["derive"], optional = true } diff --git a/src/contract/attachment.rs b/src/contract/attachment.rs index 775827d5..8603b9b1 100644 --- a/src/contract/attachment.rs +++ b/src/contract/attachment.rs @@ -23,7 +23,7 @@ use std::str::FromStr; use amplify::{Bytes32, RawArray}; -use baid58::{Baid58ParseError, FromBaid58, ToBaid58}; +use baid58::{Baid58ParseError, Chunking, FromBaid58, ToBaid58, CHUNKING_32}; use bp::secp256k1::rand::{thread_rng, RngCore}; use commit_verify::{CommitVerify, Conceal, StrictEncodedProtocol}; use strict_encoding::StrictEncode; @@ -49,18 +49,21 @@ pub struct AttachId( ); impl ToBaid58<32> for AttachId { - const HRI: &'static str = "rgb-file"; + const HRI: &'static str = "stashfs"; + const CHUNKING: Option = CHUNKING_32; fn to_baid58_payload(&self) -> [u8; 32] { self.to_raw_array() } + fn to_baid58_string(&self) -> String { self.to_string() } } impl FromBaid58<32> for AttachId {} impl AttachId { - pub fn to_baid58_string(&self) -> String { format!("{::<#}", self.to_baid58()) } + pub fn to_baid58_string(&self) -> String { format!("{::<#.2}", self.to_baid58()) } } impl FromStr for AttachId { type Err = Baid58ParseError; - fn from_str(s: &str) -> Result { - Self::from_baid58_str(s.trim_start_matches("rgb-file:")) - } + fn from_str(s: &str) -> Result { Self::from_baid58_chunked_str(s, ':', '#') } +} +impl AttachId { + pub fn to_mnemonic(&self) -> String { self.to_baid58().mnemonic() } } #[derive(Clone, PartialOrd, Ord, PartialEq, Eq, Hash, Debug)] @@ -141,10 +144,11 @@ mod test { #[test] fn attach_id_display() { const ID: &str = - "rgb-file:8JEvTXJ6sD5U4n1p7GEERYMPN9ijjs9ZM4ysJ3qhgyqM#flash-plasma-sinatra"; + "stashfs:8JEvTX-J6sD5U4n-1p7GEERY-MPN9ijjs-9ZM4ysJ3-qhgyqM#juice-empty-joker"; let id = AttachId::from_raw_array([0x6c; 32]); assert_eq!(ID, id.to_string()); assert_eq!(ID, id.to_baid58_string()); + assert_eq!("juice-empty-joker", id.to_mnemonic()); } #[test] @@ -153,12 +157,12 @@ mod test { assert_eq!( Ok(id), AttachId::from_str( - "rgb-file:8JEvTXJ6sD5U4n1p7GEERYMPN9ijjs9ZM4ysJ3qhgyqM#flash-plasma-sinatra" + "stashfs:8JEvTX-J6sD5U4n-1p7GEERY-MPN9ijjs-9ZM4ysJ3-qhgyqM#juice-empty-joker" ) ); assert_eq!( Ok(id), - AttachId::from_str("rgb-file:8JEvTXJ6sD5U4n1p7GEERYMPN9ijjs9ZM4ysJ3qhgyqM") + AttachId::from_str("stashfs:8JEvTX-J6sD5U4n-1p7GEERY-MPN9ijjs-9ZM4ysJ3-qhgyqM") ); } } diff --git a/src/contract/operations.rs b/src/contract/operations.rs index eae6949c..c8f6797c 100644 --- a/src/contract/operations.rs +++ b/src/contract/operations.rs @@ -22,13 +22,14 @@ use std::cmp::Ordering; use std::collections::{btree_map, btree_set}; +use std::fmt::{self, Display, Formatter}; use std::iter; use std::str::FromStr; use amplify::confinement::{SmallBlob, TinyOrdMap, TinyOrdSet}; use amplify::hex::{FromHex, ToHex}; use amplify::{hex, Bytes32, RawArray, Wrapper}; -use baid58::{Baid58ParseError, FromBaid58, ToBaid58}; +use baid58::{Baid58ParseError, Chunking, FromBaid58, ToBaid58, CHUNKING_32CHECKSUM}; use bp::Chain; use commit_verify::{mpc, CommitmentId, Conceal}; use strict_encoding::{StrictDeserialize, StrictEncode, StrictSerialize}; @@ -155,9 +156,8 @@ impl OpId { } /// Unique contract identifier equivalent to the contract genesis commitment -#[derive(Wrapper, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, Display, From)] +#[derive(Wrapper, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, From)] #[wrapper(Deref, BorrowSlice, Hex, Index, RangeOps)] -#[display(Self::to_baid58_string)] #[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] #[strict_type(lib = LIB_NAME_RGB)] #[cfg_attr( @@ -186,17 +186,25 @@ impl ContractId { impl ToBaid58<32> for ContractId { const HRI: &'static str = "rgb"; + const CHUNKING: Option = CHUNKING_32CHECKSUM; fn to_baid58_payload(&self) -> [u8; 32] { self.to_raw_array() } + fn to_baid58_string(&self) -> String { self.to_string() } } impl FromBaid58<32> for ContractId {} - -impl ContractId { - fn to_baid58_string(&self) -> String { format!("{::^}", self.to_baid58()) } +impl Display for ContractId { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + if f.alternate() { + write!(f, "{::^}", self.to_baid58()) + } else { + write!(f, "{::^.3}", self.to_baid58()) + } + } } - impl FromStr for ContractId { type Err = Baid58ParseError; - fn from_str(s: &str) -> Result { Self::from_baid58_str(s) } + fn from_str(s: &str) -> Result { + Self::from_baid58_maybe_chunked_str(s, ':', '#') + } } impl From for ContractId { @@ -637,9 +645,10 @@ mod test { #[test] fn contract_id_display() { - const ID: &str = "rgb:pkXwpsbaemTWhtSgVDGF25hEijtTAnPjzhB63ZwSehEWvfhF9"; + const ID: &str = "rgb:pkXwpsb-aemTWhtSg-VDGF25hEi-jtTAnPjzh-B63ZwSehE-WvfhF9"; let id = ContractId::from_raw_array([0x6c; 32]); - assert_eq!(ID.len(), 53); + assert_eq!(ID.len(), 58); + assert_eq!(ID.replace('-', ""), format!("{id:#}")); assert_eq!(ID, id.to_string()); assert_eq!(ID, id.to_baid58_string()); } @@ -647,6 +656,14 @@ mod test { #[test] fn contract_id_from_str() { let id = ContractId::from_raw_array([0x6c; 32]); + assert_eq!( + Ok(id), + ContractId::from_str("rgb:pkXwpsb-aemTWhtSg-VDGF25hEi-jtTAnPjzh-B63ZwSehE-WvfhF9") + ); + assert_eq!( + Ok(id), + ContractId::from_str("pkXwpsb-aemTWhtSg-VDGF25hEi-jtTAnPjzh-B63ZwSehE-WvfhF9") + ); assert_eq!( Ok(id), ContractId::from_str("rgb:pkXwpsbaemTWhtSgVDGF25hEijtTAnPjzhB63ZwSehEWvfhF9") @@ -655,5 +672,16 @@ mod test { Ok(id), ContractId::from_str("pkXwpsbaemTWhtSgVDGF25hEijtTAnPjzhB63ZwSehEWvfhF9") ); + + // Wrong separator placement + assert!( + ContractId::from_str("rgb:pkXwpsb-aemTWhtSg-VDGF25hEi-jtTAnPjzh-B63ZwSeh-EWvfhF9") + .is_err() + ); + // Wrong separator number + assert!( + ContractId::from_str("rgb:pkXwpsb-aemTWhtSg-VDGF25hEi-jtTAnPjzh-B63ZwSehEWvfhF9") + .is_err() + ); } } diff --git a/src/schema/schema.rs b/src/schema/schema.rs index ae01668f..e12c7831 100644 --- a/src/schema/schema.rs +++ b/src/schema/schema.rs @@ -26,7 +26,7 @@ use std::str::FromStr; use amplify::confinement::{TinyOrdMap, TinyOrdSet}; use amplify::{Bytes32, RawArray}; -use baid58::{Baid58ParseError, FromBaid58, ToBaid58}; +use baid58::{Baid58ParseError, Chunking, FromBaid58, ToBaid58, CHUNKING_32}; use commit_verify::{CommitStrategy, CommitmentId}; use strict_encoding::{StrictDecode, StrictDeserialize, StrictEncode, StrictSerialize, StrictType}; use strict_types::TypeSystem; @@ -68,25 +68,32 @@ pub struct SchemaId( impl ToBaid58<32> for SchemaId { const HRI: &'static str = "sc"; + const CHUNKING: Option = CHUNKING_32; fn to_baid58_payload(&self) -> [u8; 32] { self.to_raw_array() } + fn to_baid58_string(&self) -> String { self.to_string() } } impl FromBaid58<32> for SchemaId {} impl Display for SchemaId { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + if !f.alternate() { + f.write_str("urn:lnp-bp:sc:")?; + } if f.sign_minus() { - write!(f, "urn:lnp-bp:{::<}", self.to_baid58()) + write!(f, "{:.2}", self.to_baid58()) } else { - write!(f, "urn:lnp-bp:{::<#}", self.to_baid58()) + write!(f, "{:#.2}", self.to_baid58()) } } } - impl FromStr for SchemaId { type Err = Baid58ParseError; fn from_str(s: &str) -> Result { - Self::from_baid58_str(s.trim_start_matches("urn:lnp-bp:")) + Self::from_baid58_maybe_chunked_str(s.trim_start_matches("urn:lnp-bp:"), ':', '#') } } +impl SchemaId { + pub fn to_mnemonic(&self) -> String { self.to_baid58().mnemonic() } +} pub trait SchemaRoot: Clone + Eq + StrictType + StrictEncode + StrictDecode + Default {} impl SchemaRoot for () {} @@ -168,18 +175,24 @@ mod test { let dumb = SchemaId::strict_dumb(); assert_eq!( dumb.to_string(), - "urn:lnp-bp:sc:11111111111111111111111111111111#comedy-vega-mary" + "urn:lnp-bp:sc:111111-11111111-11111111-11111111-11#comedy-vega-mary" ); - assert_eq!(&format!("{dumb:-}"), "urn:lnp-bp:sc:11111111111111111111111111111111"); + assert_eq!(&format!("{dumb:-}"), "urn:lnp-bp:sc:111111-11111111-11111111-11111111-11"); let less_dumb = SchemaId::from_raw_array(*b"EV4350-'4vwj'4;v-w94w'e'vFVVDhpq"); assert_eq!( less_dumb.to_string(), - "urn:lnp-bp:sc:5ffNUkMTVSnWquPLT6xKb7VmAxUbw8CUNqCkUWsZfkwz#distant-thermos-arctic" + "urn:lnp-bp:sc:5ffNUk-MTVSnWqu-PLT6xKb7-VmAxUbw8-CUNqCkUW-sZfkwz#\ + distant-thermos-arctic" ); assert_eq!( &format!("{less_dumb:-}"), - "urn:lnp-bp:sc:5ffNUkMTVSnWquPLT6xKb7VmAxUbw8CUNqCkUWsZfkwz" + "urn:lnp-bp:sc:5ffNUk-MTVSnWqu-PLT6xKb7-VmAxUbw8-CUNqCkUW-sZfkwz" + ); + assert_eq!( + &format!("{less_dumb:#}"), + "5ffNUk-MTVSnWqu-PLT6xKb7-VmAxUbw8-CUNqCkUW-sZfkwz#distant-thermos-arctic" ); + assert_eq!(&format!("{less_dumb:-#}"), "5ffNUk-MTVSnWqu-PLT6xKb7-VmAxUbw8-CUNqCkUW-sZfkwz"); } }