1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
use std::fmt;
use std::io::{Read, Write};
use error::Error;
use hex::Hexed;
use ser;
const TAG_SIZE: usize = 8;
const MAX_URI_LEN: usize = 1000;
const BITCOIN_TAG: &'static [u8] = b"\x05\x88\x96\x0d\x73\xd7\x19\x01";
const PENDING_TAG: &'static [u8] = b"\x83\xdf\xe3\x0d\x2e\xf9\x0c\x8e";
#[allow(missing_docs)]
#[derive(Clone, PartialEq, Eq, Debug)]
pub enum Attestation {
Bitcoin {
height: usize
},
Pending {
uri: String
},
Unknown {
tag: Vec<u8>,
data: Vec<u8>
}
}
impl Attestation {
pub fn deserialize<R: Read>(deser: &mut ser::Deserializer<R>) -> Result<Attestation, Error> {
let tag = deser.read_fixed_bytes(TAG_SIZE)?;
let len = deser.read_uint()?;
if tag == BITCOIN_TAG {
let height = deser.read_uint()?;
Ok(Attestation::Bitcoin {
height: height
})
} else if tag == PENDING_TAG {
let uri_bytes = deser.read_bytes(0, MAX_URI_LEN)?;
let uri_string = String::from_utf8(uri_bytes)?;
for ch in uri_string.chars() {
match ch {
'a'...'z' => {}
'A'...'Z' => {}
'0'...'9' => {}
'.' | '-' | '_' | '/' | ':' => {},
x => return Err(Error::InvalidUriChar(x))
}
}
Ok(Attestation::Pending {
uri: uri_string
})
} else {
Ok(Attestation::Unknown {
tag: tag,
data: deser.read_fixed_bytes(len)?
})
}
}
pub fn serialize<W: Write>(&self, ser: &mut ser::Serializer<W>) -> Result<(), Error> {
let mut byte_ser = ser::Serializer::new(vec![]);
match *self {
Attestation::Bitcoin { height } => {
ser.write_fixed_bytes(BITCOIN_TAG)?;
byte_ser.write_uint(height)?;
ser.write_bytes(&byte_ser.into_inner())
}
Attestation::Pending { ref uri } => {
ser.write_fixed_bytes(PENDING_TAG)?;
byte_ser.write_bytes(uri.as_bytes())?;
ser.write_bytes(&byte_ser.into_inner())
}
Attestation::Unknown { ref tag, ref data } => {
ser.write_fixed_bytes(tag)?;
ser.write_bytes(data)
}
}
}
}
impl fmt::Display for Attestation {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
Attestation::Bitcoin { height } => write!(f, "Bitcoin block {}", height),
Attestation::Pending { ref uri } => write!(f, "Pending: update URI {}", uri),
Attestation::Unknown { ref tag, ref data } => write!(f, "unknown attestation type {}: {}", Hexed(tag), Hexed(data)),
}
}
}