1use std::{fmt, str};
10
11use bech32::{FromBase32, ToBase32, Variant};
12use property::Property;
13
14pub mod error;
15use error::{Error, Result};
16
17use crate::{blake2b, utilities};
18
19#[cfg(test)]
20mod tests;
21
22pub const CODE_HASH_SIZE: usize = 32;
23pub const BLAKE160_SIZE: usize = 20;
24pub const SINCE_SIZE: usize = 8;
25
26#[derive(Debug, Clone, Copy, PartialEq, Eq)]
28pub enum Network {
29 Main,
30 Test,
31}
32
33#[derive(Debug, Clone, Copy, PartialEq, Eq)]
35pub enum PayloadFormat {
36 Short,
37 Full(CodeHashType),
38}
39
40#[derive(Debug, Clone, Copy, PartialEq, Eq)]
42pub enum CodeHashIndex {
43 Secp256k1Blake160 = 0x00,
44 Secp256k1MultiSig = 0x01,
45}
46
47#[derive(Debug, Clone, Copy, PartialEq, Eq)]
49pub enum CodeHashType {
50 Data = 0x02,
51 Type = 0x04,
52}
53
54#[derive(Debug, Clone, Copy, PartialEq, Eq)]
56pub enum CodeHash {
57 Index(CodeHashIndex),
58 Data {
59 hash_type: CodeHashType,
60 content: [u8; CODE_HASH_SIZE],
61 },
62}
63
64#[derive(Debug, Clone)]
66pub enum Args {
67 Simple(Vec<u8>),
68 MultiSig {
69 version: u8,
70 first_n_required: u8,
71 threshold: u8,
72 contents: Vec<[u8; BLAKE160_SIZE]>,
73 since: Option<[u8; 8]>,
74 },
75}
76
77#[derive(Property, Clone)]
78#[property(get(public), set(disable), mut(disable))]
79pub struct Address {
80 network: Network,
81 code_hash: CodeHash,
82 args: Args,
83}
84
85#[derive(Property, Default, Clone)]
86#[property(get(disable), set(public, prefix = "", type = "own"), mut(disable))]
87pub struct AddressBuilder {
88 network: Network,
89 code_hash: CodeHash,
90 args: Args,
91}
92
93impl Default for Network {
94 fn default() -> Self {
95 Network::Main
96 }
97}
98
99impl Default for CodeHashIndex {
100 fn default() -> Self {
101 CodeHashIndex::Secp256k1Blake160
102 }
103}
104
105impl Default for CodeHash {
106 fn default() -> Self {
107 Self::Index(Default::default())
108 }
109}
110
111impl Default for Args {
112 fn default() -> Self {
113 Self::Simple(vec![0u8; BLAKE160_SIZE])
114 }
115}
116
117impl Network {
118 pub fn value(self) -> &'static str {
119 match self {
120 Self::Main => "ckb",
121 Self::Test => "ckt",
122 }
123 }
124
125 pub fn from_value(value: &str) -> Result<Self> {
126 match value {
127 "ckb" => Ok(Self::Main),
128 "ckt" => Ok(Self::Test),
129 v => Err(Error::UnknownNetwork(v.to_owned())),
130 }
131 }
132}
133
134impl fmt::Display for Network {
135 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
136 let s = match self {
137 Self::Main => "mainnet",
138 Self::Test => "testnet",
139 };
140 write!(f, "{}", s)
141 }
142}
143
144impl PayloadFormat {
145 pub fn value(self) -> u8 {
146 if let Self::Full(t) = self {
147 t.value()
148 } else {
149 0x01 }
151 }
152
153 pub fn from_value(value: u8) -> Result<Self> {
154 match value {
155 0x01 => Ok(Self::Short),
156 0x02 => Ok(Self::Full(CodeHashType::Data)),
157 0x04 => Ok(Self::Full(CodeHashType::Type)),
158 v => Err(Error::UnknownPayloadFormat(v)),
159 }
160 }
161}
162
163impl CodeHashIndex {
164 pub fn value(self) -> u8 {
165 self as u8
166 }
167
168 pub fn from_value(value: u8) -> Result<Self> {
169 match value {
170 0x00 => Ok(Self::Secp256k1Blake160),
171 0x01 => Ok(Self::Secp256k1MultiSig),
172 v => Err(Error::UnknownCodeHashIndex(v)),
173 }
174 }
175}
176
177impl CodeHashType {
178 pub fn value(self) -> u8 {
179 self as u8
180 }
181}
182
183impl fmt::Display for CodeHash {
184 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
185 match *self {
186 CodeHash::Index(index) => write!(f, "CodeHash::Index({:?})", index),
187 CodeHash::Data {
188 hash_type,
189 ref content,
190 } => write!(
191 f,
192 "CodeHash::Data {{ hash_type: {:?}, content: {} }}",
193 hash_type,
194 utilities::hex_string(&content[..])
195 ),
196 }
197 }
198}
199
200impl Args {
201 pub fn serialize_into(&self, buf: &mut Vec<u8>) {
202 match self {
203 Args::Simple(ref args) => {
204 buf.extend_from_slice(&args[..]);
205 }
206 Args::MultiSig {
207 version,
208 first_n_required,
209 threshold,
210 contents,
211 since,
212 } => {
213 let len = 4 + BLAKE160_SIZE * contents.len();
214 let mut bin = Vec::with_capacity(len);
215 bin.push(*version);
216 bin.push(*first_n_required);
217 bin.push(*threshold);
218 bin.push(contents.len() as u8);
219 for content in &contents[..] {
220 bin.extend_from_slice(&content[..]);
221 }
222 let hash = blake2b::blake160(&bin);
223 buf.extend_from_slice(&hash[..]);
224 if let Some(since) = since {
225 buf.extend_from_slice(&since[..]);
226 }
227 }
228 }
229 }
230}
231
232impl fmt::Display for Args {
233 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
234 write!(f, "Args {{")?;
235 match self {
236 Self::Simple(content) => {
237 write!(f, " Simple({})", utilities::hex_string(&content[..]))?;
238 }
239 Self::MultiSig {
240 version,
241 first_n_required,
242 threshold,
243 contents,
244 since,
245 } => {
246 write!(f, " MultiSig {{")?;
247 write!(f, " version: {}", version)?;
248 write!(f, " first_n: {}", first_n_required)?;
249 write!(f, " threshold: {}", threshold)?;
250 write!(f, " number: {}", contents.len())?;
251 let mut first = true;
252 write!(f, " contents: [")?;
253 for content in &contents[..] {
254 if first {
255 first = false;
256 } else {
257 write!(f, ", ")?;
258 }
259 write!(f, "{}", utilities::hex_string(&content[..]))?;
260 }
261 write!(f, "]")?;
262 if let Some(since) = since {
263 write!(f, " since: {}", utilities::hex_string(&since[..]))?;
264 }
265 write!(f, " }}")?;
266 }
267 };
268 write!(f, " }}")
269 }
270}
271
272impl Address {
273 pub fn into_builder(self) -> AddressBuilder {
274 let Self {
275 network,
276 code_hash,
277 args,
278 } = self;
279 AddressBuilder {
280 network,
281 code_hash,
282 args,
283 }
284 }
285}
286
287impl fmt::Debug for Address {
288 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
289 write!(f, "Address {{")?;
290 write!(f, " network: {}", self.network)?;
291 write!(f, " , code_hash: {}", self.code_hash)?;
292 write!(f, " , args: {}", self.args)?;
293 write!(f, " }}")
294 }
295}
296
297impl fmt::Display for Address {
298 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
299 let hrp = self.network.value();
300 let data: Vec<u8> = match self.code_hash {
301 CodeHash::Index(index) => {
302 let mut data = Vec::with_capacity(2 + BLAKE160_SIZE);
303 data.push(PayloadFormat::Short.value());
304 data.push(index.value());
305 match index {
306 CodeHashIndex::Secp256k1Blake160 => match self.args {
307 Args::Simple(_) => {
308 self.args.serialize_into(&mut data);
309 Ok(data)
310 }
311 _ => Err(Error::Unreachable(
312 "unsupported args for Secp256k1Blake160".to_owned(),
313 )),
314 },
315 CodeHashIndex::Secp256k1MultiSig => match self.args {
316 Args::Simple(_) => {
317 self.args.serialize_into(&mut data);
318 Ok(data)
319 }
320 Args::MultiSig { since, .. } => {
321 if since.is_none() {
322 self.args.serialize_into(&mut data);
323 Ok(data)
324 } else {
325 Err(Error::Unreachable(
326 "since should be None for Secp256k1MultiSig in Short Format"
327 .to_owned(),
328 ))
329 }
330 }
331 },
332 }
333 }
334 CodeHash::Data {
335 hash_type,
336 ref content,
337 } => {
338 let args_len = match self.args {
339 Args::Simple(ref args) => args.len(),
340 Args::MultiSig { since, .. } => {
341 BLAKE160_SIZE + since.map(|x| x.len()).unwrap_or(0)
342 }
343 };
344 let mut data = Vec::with_capacity(1 + CODE_HASH_SIZE + content.len() + args_len);
345 data.push(PayloadFormat::Full(hash_type).value());
346 data.extend_from_slice(&content[..]);
347 self.args.serialize_into(&mut data);
348 Ok(data)
349 }
350 }
351 .unwrap();
352 bech32::encode_to_fmt(f, hrp, data.to_base32(), Variant::Bech32).unwrap()
353 }
354}
355
356impl str::FromStr for Address {
357 type Err = Error;
358 fn from_str(s: &str) -> Result<Self> {
359 bech32::decode(s)
360 .map_err(Error::Bech32)
361 .and_then(|(ref hrp, ref base32, variant)| {
362 if variant != Variant::Bech32 {
363 return Err(Error::UnsupportedBech32Variant(variant));
364 }
365 let network = Network::from_value(hrp)?;
366 let bytes = Vec::<u8>::from_base32(base32).map_err(Error::Bech32)?;
367 let mut offset = 0;
368 let mut data = &bytes[offset..];
369 if data.is_empty() {
370 Err(Error::InvalidDataSince(offset))
371 } else {
372 let format = PayloadFormat::from_value(data[0])?;
373 offset += 1;
374 data = &bytes[offset..];
375 let (code_hash, args) = match format {
376 PayloadFormat::Short => {
377 if data.is_empty() {
378 return Err(Error::InvalidDataSince(offset));
379 }
380 let index = CodeHashIndex::from_value(data[0])?;
381 offset += 1;
382 data = &bytes[offset..];
383 let args = if data.len() == BLAKE160_SIZE {
384 Ok(Args::Simple(data.to_owned()))
385 } else {
386 Err(Error::ShortFormatArgs)
387 }?;
388 (CodeHash::Index(index), args)
389 }
390 PayloadFormat::Full(hash_type) => {
391 if data.len() < CODE_HASH_SIZE {
392 return Err(Error::InvalidDataSince(offset));
393 }
394 let mut content = [0u8; CODE_HASH_SIZE];
395 content.copy_from_slice(&data[..CODE_HASH_SIZE]);
396 offset += CODE_HASH_SIZE;
397 data = &bytes[offset..];
398 (
399 CodeHash::Data { hash_type, content },
400 Args::Simple(data.to_owned()),
401 )
402 }
403 };
404 AddressBuilder::default()
405 .network(network)
406 .code_hash(code_hash)
407 .args(args)
408 .build()
409 }
410 })
411 }
412}
413
414impl AddressBuilder {
415 pub fn new() -> Self {
416 Self::default()
417 }
418
419 pub fn code_hash_by_index(mut self, index: CodeHashIndex) -> Self {
420 self.code_hash = CodeHash::Index(index);
421 self
422 }
423
424 pub fn code_hash_by_data(
425 mut self,
426 hash_type: CodeHashType,
427 content: [u8; CODE_HASH_SIZE],
428 ) -> Self {
429 self.code_hash = CodeHash::Data { hash_type, content };
430 self
431 }
432
433 pub fn args_simple(mut self, args: Vec<u8>) -> Self {
434 self.args = Args::Simple(args);
435 self
436 }
437
438 pub fn args_multisig(
439 mut self,
440 version: u8,
441 first_n_required: u8,
442 threshold: u8,
443 contents: Vec<[u8; BLAKE160_SIZE]>,
444 since: Option<[u8; SINCE_SIZE]>,
445 ) -> Self {
446 self.args = Args::MultiSig {
447 version,
448 first_n_required,
449 threshold,
450 contents,
451 since,
452 };
453 self
454 }
455
456 pub fn build(self) -> Result<Address> {
457 let Self {
458 network,
459 code_hash,
460 args,
461 } = self;
462 match code_hash {
463 CodeHash::Index(index) => match index {
464 CodeHashIndex::Secp256k1Blake160 => match args {
465 Args::Simple(ref content) => {
466 if content.len() == BLAKE160_SIZE {
467 Ok(())
468 } else {
469 Err(Error::ShortFormatArgs)
470 }
471 }
472 _ => Err(Error::Secp256k1Blake160Args),
473 },
474 CodeHashIndex::Secp256k1MultiSig => match args {
475 Args::Simple(ref content) => {
476 if content.len() == BLAKE160_SIZE {
477 Ok(())
478 } else {
479 Err(Error::ShortFormatArgs)
480 }
481 }
482 Args::MultiSig { .. } => Ok(()),
483 },
484 },
485 CodeHash::Data { .. } => Ok(()),
486 }?;
487 if let Args::MultiSig {
488 first_n_required,
489 threshold,
490 ref contents,
491 ..
492 } = args
493 {
494 if first_n_required > threshold || threshold > contents.len() as u8 {
495 return Err(Error::MultiSigArgs);
496 }
497 };
498 Ok(Address {
499 network,
500 code_hash,
501 args,
502 })
503 }
504}