create-sia-app 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +1 -0
- package/dist/index.js +179 -0
- package/package.json +29 -0
- package/template/CLAUDE.md +160 -0
- package/template/README.md +102 -0
- package/template/_gitignore +5 -0
- package/template/biome.json +40 -0
- package/template/index.html +13 -0
- package/template/package.json +30 -0
- package/template/rust/README.md +16 -0
- package/template/rust/sia-sdk-rs/.changeset/added_cancel_function_to_cancel_inflight_packed_uploads.md +6 -0
- package/template/rust/sia-sdk-rs/.changeset/check_if_we_have_enough_hosts_prior_to_encoding_in_upload_slabs.md +16 -0
- package/template/rust/sia-sdk-rs/.changeset/fix_slab_length_in_packed_object.md +5 -0
- package/template/rust/sia-sdk-rs/.changeset/fix_upload_racing_race_conditon.md +13 -0
- package/template/rust/sia-sdk-rs/.changeset/improved_parallelism_of_packed_uploads.md +5 -0
- package/template/rust/sia-sdk-rs/.changeset/progress_callback_will_now_be_called_as_expected_for_packed_uploads.md +5 -0
- package/template/rust/sia-sdk-rs/.github/dependabot.yml +10 -0
- package/template/rust/sia-sdk-rs/.github/workflows/main.yml +36 -0
- package/template/rust/sia-sdk-rs/.github/workflows/prepare-release.yml +34 -0
- package/template/rust/sia-sdk-rs/.github/workflows/release.yml +30 -0
- package/template/rust/sia-sdk-rs/.rustfmt.toml +4 -0
- package/template/rust/sia-sdk-rs/Cargo.lock +4127 -0
- package/template/rust/sia-sdk-rs/Cargo.toml +3 -0
- package/template/rust/sia-sdk-rs/LICENSE +21 -0
- package/template/rust/sia-sdk-rs/README.md +30 -0
- package/template/rust/sia-sdk-rs/indexd/CHANGELOG.md +79 -0
- package/template/rust/sia-sdk-rs/indexd/Cargo.toml +79 -0
- package/template/rust/sia-sdk-rs/indexd/benches/upload.rs +258 -0
- package/template/rust/sia-sdk-rs/indexd/src/app_client.rs +1710 -0
- package/template/rust/sia-sdk-rs/indexd/src/builder.rs +354 -0
- package/template/rust/sia-sdk-rs/indexd/src/download.rs +379 -0
- package/template/rust/sia-sdk-rs/indexd/src/hosts.rs +659 -0
- package/template/rust/sia-sdk-rs/indexd/src/lib.rs +827 -0
- package/template/rust/sia-sdk-rs/indexd/src/mock.rs +162 -0
- package/template/rust/sia-sdk-rs/indexd/src/object_encryption.rs +125 -0
- package/template/rust/sia-sdk-rs/indexd/src/quic.rs +575 -0
- package/template/rust/sia-sdk-rs/indexd/src/rhp4.rs +52 -0
- package/template/rust/sia-sdk-rs/indexd/src/slabs.rs +497 -0
- package/template/rust/sia-sdk-rs/indexd/src/upload.rs +629 -0
- package/template/rust/sia-sdk-rs/indexd/src/wasm_time.rs +41 -0
- package/template/rust/sia-sdk-rs/indexd/src/web_transport.rs +398 -0
- package/template/rust/sia-sdk-rs/indexd_ffi/CHANGELOG.md +76 -0
- package/template/rust/sia-sdk-rs/indexd_ffi/Cargo.toml +47 -0
- package/template/rust/sia-sdk-rs/indexd_ffi/examples/python/README.md +10 -0
- package/template/rust/sia-sdk-rs/indexd_ffi/examples/python/example.py +130 -0
- package/template/rust/sia-sdk-rs/indexd_ffi/src/bin/uniffi-bindgen.rs +3 -0
- package/template/rust/sia-sdk-rs/indexd_ffi/src/builder.rs +377 -0
- package/template/rust/sia-sdk-rs/indexd_ffi/src/io.rs +155 -0
- package/template/rust/sia-sdk-rs/indexd_ffi/src/lib.rs +1039 -0
- package/template/rust/sia-sdk-rs/indexd_ffi/src/logging.rs +58 -0
- package/template/rust/sia-sdk-rs/indexd_ffi/src/tls.rs +23 -0
- package/template/rust/sia-sdk-rs/indexd_wasm/Cargo.toml +33 -0
- package/template/rust/sia-sdk-rs/indexd_wasm/src/lib.rs +818 -0
- package/template/rust/sia-sdk-rs/knope.toml +54 -0
- package/template/rust/sia-sdk-rs/sia_derive/CHANGELOG.md +38 -0
- package/template/rust/sia-sdk-rs/sia_derive/Cargo.toml +19 -0
- package/template/rust/sia-sdk-rs/sia_derive/src/lib.rs +278 -0
- package/template/rust/sia-sdk-rs/sia_sdk/CHANGELOG.md +91 -0
- package/template/rust/sia-sdk-rs/sia_sdk/Cargo.toml +59 -0
- package/template/rust/sia-sdk-rs/sia_sdk/benches/merkle_root.rs +12 -0
- package/template/rust/sia-sdk-rs/sia_sdk/src/blake2.rs +22 -0
- package/template/rust/sia-sdk-rs/sia_sdk/src/consensus.rs +767 -0
- package/template/rust/sia-sdk-rs/sia_sdk/src/encoding/v1.rs +257 -0
- package/template/rust/sia-sdk-rs/sia_sdk/src/encoding/v2.rs +291 -0
- package/template/rust/sia-sdk-rs/sia_sdk/src/encoding.rs +26 -0
- package/template/rust/sia-sdk-rs/sia_sdk/src/encoding_async/v2.rs +367 -0
- package/template/rust/sia-sdk-rs/sia_sdk/src/encoding_async.rs +6 -0
- package/template/rust/sia-sdk-rs/sia_sdk/src/encryption.rs +303 -0
- package/template/rust/sia-sdk-rs/sia_sdk/src/erasure_coding.rs +347 -0
- package/template/rust/sia-sdk-rs/sia_sdk/src/lib.rs +15 -0
- package/template/rust/sia-sdk-rs/sia_sdk/src/macros.rs +435 -0
- package/template/rust/sia-sdk-rs/sia_sdk/src/merkle.rs +112 -0
- package/template/rust/sia-sdk-rs/sia_sdk/src/rhp/merkle.rs +357 -0
- package/template/rust/sia-sdk-rs/sia_sdk/src/rhp/rpc.rs +1507 -0
- package/template/rust/sia-sdk-rs/sia_sdk/src/rhp/types.rs +146 -0
- package/template/rust/sia-sdk-rs/sia_sdk/src/rhp.rs +7 -0
- package/template/rust/sia-sdk-rs/sia_sdk/src/seed.rs +278 -0
- package/template/rust/sia-sdk-rs/sia_sdk/src/signing.rs +236 -0
- package/template/rust/sia-sdk-rs/sia_sdk/src/types/common.rs +677 -0
- package/template/rust/sia-sdk-rs/sia_sdk/src/types/currency.rs +450 -0
- package/template/rust/sia-sdk-rs/sia_sdk/src/types/specifier.rs +110 -0
- package/template/rust/sia-sdk-rs/sia_sdk/src/types/spendpolicy.rs +778 -0
- package/template/rust/sia-sdk-rs/sia_sdk/src/types/utils.rs +117 -0
- package/template/rust/sia-sdk-rs/sia_sdk/src/types/v1.rs +1737 -0
- package/template/rust/sia-sdk-rs/sia_sdk/src/types/v2.rs +1726 -0
- package/template/rust/sia-sdk-rs/sia_sdk/src/types/work.rs +59 -0
- package/template/rust/sia-sdk-rs/sia_sdk/src/types.rs +16 -0
- package/template/scripts/setup-rust.js +29 -0
- package/template/src/App.tsx +13 -0
- package/template/src/components/DevNote.tsx +21 -0
- package/template/src/components/auth/ApproveScreen.tsx +84 -0
- package/template/src/components/auth/AuthFlow.tsx +77 -0
- package/template/src/components/auth/ConnectScreen.tsx +214 -0
- package/template/src/components/auth/LoadingScreen.tsx +8 -0
- package/template/src/components/auth/RecoveryScreen.tsx +182 -0
- package/template/src/components/upload/UploadZone.tsx +314 -0
- package/template/src/index.css +9 -0
- package/template/src/lib/constants.ts +8 -0
- package/template/src/lib/format.ts +35 -0
- package/template/src/lib/hex.ts +13 -0
- package/template/src/lib/sdk.ts +25 -0
- package/template/src/lib/wasm-env.ts +5 -0
- package/template/src/main.tsx +12 -0
- package/template/src/stores/auth.ts +86 -0
- package/template/tsconfig.app.json +31 -0
- package/template/tsconfig.json +7 -0
- package/template/tsconfig.node.json +26 -0
- package/template/vite.config.ts +18 -0
- package/template/wasm/indexd_wasm/indexd_wasm.d.ts +309 -0
- package/template/wasm/indexd_wasm/indexd_wasm.js +1507 -0
- package/template/wasm/indexd_wasm/indexd_wasm_bg.wasm +0 -0
- package/template/wasm/indexd_wasm/package.json +31 -0
|
@@ -0,0 +1,435 @@
|
|
|
1
|
+
// Macro to implement types used as identifiers which are 32 byte hashes and are
|
|
2
|
+
// serialized with a prefix
|
|
3
|
+
macro_rules! impl_hash_id {
|
|
4
|
+
($name:ident) => {
|
|
5
|
+
#[derive(
|
|
6
|
+
Debug,
|
|
7
|
+
Clone,
|
|
8
|
+
Copy,
|
|
9
|
+
PartialEq,
|
|
10
|
+
Eq,
|
|
11
|
+
Hash,
|
|
12
|
+
$crate::encoding_async::AsyncSiaEncode,
|
|
13
|
+
$crate::encoding_async::AsyncSiaDecode,
|
|
14
|
+
$crate::encoding::SiaEncode,
|
|
15
|
+
$crate::encoding::SiaDecode,
|
|
16
|
+
$crate::encoding::V1SiaEncode,
|
|
17
|
+
$crate::encoding::V1SiaDecode,
|
|
18
|
+
)]
|
|
19
|
+
pub struct $name([u8; 32]);
|
|
20
|
+
|
|
21
|
+
impl serde::Serialize for $name {
|
|
22
|
+
fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
|
|
23
|
+
if serializer.is_human_readable() {
|
|
24
|
+
String::serialize(&self.to_string(), serializer)
|
|
25
|
+
} else {
|
|
26
|
+
<[u8; 32]>::serialize(&self.0, serializer)
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
impl<'de> serde::Deserialize<'de> for $name {
|
|
32
|
+
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
|
33
|
+
where
|
|
34
|
+
D: serde::Deserializer<'de>,
|
|
35
|
+
{
|
|
36
|
+
let s = String::deserialize(deserializer)?;
|
|
37
|
+
s.parse()
|
|
38
|
+
.map_err(|e| serde::de::Error::custom(format!("{:?}", e)))
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
impl $name {
|
|
43
|
+
pub const fn new(b: [u8; 32]) -> Self {
|
|
44
|
+
Self(b)
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
impl core::fmt::Display for $name {
|
|
49
|
+
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
|
|
50
|
+
write!(f, "{}", hex::encode(self.0))
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
impl From<blake2b_simd::Hash> for $name {
|
|
55
|
+
fn from(hash: blake2b_simd::Hash) -> Self {
|
|
56
|
+
let mut h = [0; 32];
|
|
57
|
+
h.copy_from_slice(&hash.as_bytes()[..32]);
|
|
58
|
+
Self(h)
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
impl From<crate::blake2::Output> for $name {
|
|
63
|
+
fn from(output: crate::blake2::Output) -> Self {
|
|
64
|
+
let mut h = [0; 32];
|
|
65
|
+
h.copy_from_slice(&output[..32]);
|
|
66
|
+
Self(h)
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
impl From<[u8; 32]> for $name {
|
|
71
|
+
fn from(data: [u8; 32]) -> Self {
|
|
72
|
+
$name(data)
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
impl From<$name> for [u8; 32] {
|
|
77
|
+
fn from(hash: $name) -> [u8; 32] {
|
|
78
|
+
hash.0
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
impl std::str::FromStr for $name {
|
|
83
|
+
type Err = $crate::types::HexParseError;
|
|
84
|
+
|
|
85
|
+
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
|
86
|
+
let s = match s.split_once(':') {
|
|
87
|
+
Some((_prefix, suffix)) => suffix,
|
|
88
|
+
None => s,
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
if s.len() != 64 {
|
|
92
|
+
return Err($crate::types::HexParseError::InvalidLength(s.len()));
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
let mut data = [0u8; 32];
|
|
96
|
+
hex::decode_to_slice(s, &mut data)
|
|
97
|
+
.map_err($crate::types::HexParseError::HexError)?;
|
|
98
|
+
Ok($name(data))
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
impl AsRef<[u8; 32]> for $name {
|
|
103
|
+
fn as_ref(&self) -> &[u8; 32] {
|
|
104
|
+
&self.0
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
impl AsRef<[u8]> for $name {
|
|
109
|
+
fn as_ref(&self) -> &[u8] {
|
|
110
|
+
&self.0
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
impl Default for $name {
|
|
115
|
+
fn default() -> Self {
|
|
116
|
+
$name([0; 32])
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
pub(crate) use impl_hash_id;
|
|
122
|
+
|
|
123
|
+
#[inline]
|
|
124
|
+
pub(crate) const fn decode_hex_char(c: u8) -> Option<u8> {
|
|
125
|
+
match c {
|
|
126
|
+
b'0'..=b'9' => Some(c - b'0'),
|
|
127
|
+
b'a'..=b'f' => Some(c - b'a' + 10),
|
|
128
|
+
b'A'..=b'F' => Some(c - b'A' + 10),
|
|
129
|
+
_ => None,
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
#[inline]
|
|
134
|
+
pub(crate) const fn decode_hex_pair(hi: u8, lo: u8) -> Option<u8> {
|
|
135
|
+
let hi = decode_hex_char(hi);
|
|
136
|
+
let lo = decode_hex_char(lo);
|
|
137
|
+
match (hi, lo) {
|
|
138
|
+
(Some(hi), Some(lo)) => Some((hi << 4) | lo),
|
|
139
|
+
_ => None,
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/// Decode a hex string of length 64 into a 32-byte array.
|
|
144
|
+
///
|
|
145
|
+
/// # Panics
|
|
146
|
+
/// if the input is not valid hex.
|
|
147
|
+
///
|
|
148
|
+
/// # Safety
|
|
149
|
+
/// This function is intended to be used in const contexts, such as macros.
|
|
150
|
+
#[inline]
|
|
151
|
+
#[doc(hidden)]
|
|
152
|
+
pub const fn decode_hex_256(input: &[u8]) -> [u8; 32] {
|
|
153
|
+
// note: this must be public to be used in macros
|
|
154
|
+
let mut result = [0u8; 32];
|
|
155
|
+
let mut i = 0;
|
|
156
|
+
while i < 64 {
|
|
157
|
+
match decode_hex_pair(input[i], input[i + 1]) {
|
|
158
|
+
Some(byte) => result[i / 2] = byte,
|
|
159
|
+
_ => panic!("invalid hex char"),
|
|
160
|
+
}
|
|
161
|
+
i += 2;
|
|
162
|
+
}
|
|
163
|
+
result
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/// Decode a hex string of length 128 into a 64-byte array.
|
|
167
|
+
///
|
|
168
|
+
/// # Panics
|
|
169
|
+
/// if the input is not valid hex.
|
|
170
|
+
///
|
|
171
|
+
/// # Safety
|
|
172
|
+
/// This function is intended to be used in const contexts, such as macros.
|
|
173
|
+
#[inline]
|
|
174
|
+
#[doc(hidden)]
|
|
175
|
+
pub const fn decode_hex_512(input: &[u8]) -> [u8; 64] {
|
|
176
|
+
// note: this must be public to be used in macros
|
|
177
|
+
let mut result = [0u8; 64];
|
|
178
|
+
let mut i = 0;
|
|
179
|
+
while i < 128 {
|
|
180
|
+
match decode_hex_pair(input[i], input[i + 1]) {
|
|
181
|
+
Some(byte) => result[i / 2] = byte,
|
|
182
|
+
_ => panic!("invalid hex char"),
|
|
183
|
+
}
|
|
184
|
+
i += 2;
|
|
185
|
+
}
|
|
186
|
+
result
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/// A macro to create an [sia::types::Address] from a literal hex string. The string must be 76 characters long.
|
|
190
|
+
///
|
|
191
|
+
/// The checksum is not verified.
|
|
192
|
+
/// ```
|
|
193
|
+
/// use sia::types::Address;
|
|
194
|
+
/// use sia::address;
|
|
195
|
+
///
|
|
196
|
+
/// const addr: Address = address!("8fb49ccf17dfdcc9526dec6ee8a5cca20ff8247302053d3777410b9b0494ba8cdf32abee86f0");
|
|
197
|
+
/// ```
|
|
198
|
+
#[macro_export]
|
|
199
|
+
macro_rules! address {
|
|
200
|
+
($text:literal) => {{
|
|
201
|
+
if $text.len() != 76 {
|
|
202
|
+
panic!("Address must be 76 characters");
|
|
203
|
+
}
|
|
204
|
+
$crate::types::Address::new($crate::macros::decode_hex_256($text.as_bytes()))
|
|
205
|
+
}};
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/// A macro to create a [sia::types::Hash256] from a literal hex string. The string must be 64 characters long.
|
|
209
|
+
///
|
|
210
|
+
/// ```
|
|
211
|
+
/// use sia::types::Hash256;
|
|
212
|
+
/// use sia::hash_256;
|
|
213
|
+
///
|
|
214
|
+
/// const h: Hash256 = hash_256!("8fb49ccf17dfdcc9526dec6ee8a5cca20ff8247302053d3777410b9b0494ba8c");
|
|
215
|
+
/// ```
|
|
216
|
+
#[macro_export]
|
|
217
|
+
macro_rules! hash_256 {
|
|
218
|
+
($text:literal) => {{
|
|
219
|
+
if $text.len() != 64 {
|
|
220
|
+
panic!("Hash256 must be 64 characters");
|
|
221
|
+
}
|
|
222
|
+
$crate::types::Hash256::new($crate::macros::decode_hex_256($text.as_bytes()))
|
|
223
|
+
}};
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
/// A macro to create a [sia::types::SiacoinOutputID] from a literal hex string. The string must be 64 characters long.
|
|
227
|
+
///
|
|
228
|
+
///```
|
|
229
|
+
/// use sia::types::SiacoinOutputID;
|
|
230
|
+
/// use sia::siacoin_id;
|
|
231
|
+
///
|
|
232
|
+
/// const scoid: SiacoinOutputID = siacoin_id!("8fb49ccf17dfdcc9526dec6ee8a5cca20ff8247302053d3777410b9b0494ba8c");
|
|
233
|
+
/// ```
|
|
234
|
+
#[macro_export]
|
|
235
|
+
macro_rules! siacoin_id {
|
|
236
|
+
($text:literal) => {{
|
|
237
|
+
if $text.len() != 64 {
|
|
238
|
+
panic!("SiacoinOutputID must be 64 characters");
|
|
239
|
+
}
|
|
240
|
+
$crate::types::SiacoinOutputID::new($crate::macros::decode_hex_256($text.as_bytes()))
|
|
241
|
+
}};
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
/// A macro to create a [sia::types::SiafundOutputID] from a literal hex string. The string must be 64 characters long.
|
|
245
|
+
///
|
|
246
|
+
/// ```
|
|
247
|
+
/// use sia::types::SiafundOutputID;
|
|
248
|
+
/// use sia::siafund_id;
|
|
249
|
+
///
|
|
250
|
+
/// const sfoid: SiafundOutputID = siafund_id!("8fb49ccf17dfdcc9526dec6ee8a5cca20ff8247302053d3777410b9b0494ba8c");
|
|
251
|
+
/// ```
|
|
252
|
+
#[macro_export]
|
|
253
|
+
macro_rules! siafund_id {
|
|
254
|
+
($text:literal) => {{
|
|
255
|
+
if $text.len() != 64 {
|
|
256
|
+
panic!("SiafundOutputID must be 64 characters");
|
|
257
|
+
}
|
|
258
|
+
$crate::types::SiafundOutputID::new($crate::macros::decode_hex_256($text.as_bytes()))
|
|
259
|
+
}};
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
/// A macro to create a [sia::types::FileContractID] from a literal hex string. The string must be 64 characters long.
|
|
263
|
+
///
|
|
264
|
+
/// ```
|
|
265
|
+
/// use sia::types::FileContractID;
|
|
266
|
+
/// use sia::contract_id;
|
|
267
|
+
///
|
|
268
|
+
/// const fcid: FileContractID = contract_id!("8fb49ccf17dfdcc9526dec6ee8a5cca20ff8247302053d3777410b9b0494ba8c");
|
|
269
|
+
/// ```
|
|
270
|
+
#[macro_export]
|
|
271
|
+
macro_rules! contract_id {
|
|
272
|
+
($text:literal) => {{
|
|
273
|
+
if $text.len() != 64 {
|
|
274
|
+
panic!("FileContractID must be 64 characters");
|
|
275
|
+
}
|
|
276
|
+
$crate::types::FileContractID::new($crate::macros::decode_hex_256($text.as_bytes()))
|
|
277
|
+
}};
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
/// A macro to create a [sia::types::TransactionID] from a literal hex string. The string must be 64 characters long.
|
|
281
|
+
///
|
|
282
|
+
/// ```
|
|
283
|
+
/// use sia::types::TransactionID;
|
|
284
|
+
/// use sia::transaction_id;
|
|
285
|
+
///
|
|
286
|
+
/// const txid: TransactionID = transaction_id!("8fb49ccf17dfdcc9526dec6ee8a5cca20ff8247302053d3777410b9b0494ba8c");
|
|
287
|
+
/// ```
|
|
288
|
+
#[macro_export]
|
|
289
|
+
macro_rules! transaction_id {
|
|
290
|
+
($text:literal) => {{
|
|
291
|
+
if $text.len() != 64 {
|
|
292
|
+
panic!("TransactionID must be 64 characters");
|
|
293
|
+
}
|
|
294
|
+
$crate::types::TransactionID::new($crate::macros::decode_hex_256($text.as_bytes()))
|
|
295
|
+
}};
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
/// A macro to create a [sia::types::BlockID] from a literal hex string. The string must be 64 characters long.
|
|
299
|
+
///
|
|
300
|
+
/// ```
|
|
301
|
+
/// use sia::types::BlockID;
|
|
302
|
+
/// use sia::block_id;
|
|
303
|
+
///
|
|
304
|
+
/// const bid: BlockID = block_id!("8fb49ccf17dfdcc9526dec6ee8a5cca20ff8247302053d3777410b9b0494ba8c");
|
|
305
|
+
/// ```
|
|
306
|
+
#[macro_export]
|
|
307
|
+
macro_rules! block_id {
|
|
308
|
+
($text:literal) => {{
|
|
309
|
+
if $text.len() != 64 {
|
|
310
|
+
panic!("BlockID must be 64 characters");
|
|
311
|
+
}
|
|
312
|
+
$crate::types::BlockID::new($crate::macros::decode_hex_256($text.as_bytes()))
|
|
313
|
+
}};
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
/// A macro to create a [sia::signing::PublicKey] from a literal hex string. The string must be 72 characters long and start with "ed25519:".
|
|
317
|
+
///
|
|
318
|
+
/// ```
|
|
319
|
+
/// use sia::signing::PublicKey;
|
|
320
|
+
/// use sia::public_key;
|
|
321
|
+
///
|
|
322
|
+
/// const pk: PublicKey = public_key!("ed25519:8fb49ccf17dfdcc9526dec6ee8a5cca20ff8247302053d3777410b9b0494ba8c");
|
|
323
|
+
/// ```
|
|
324
|
+
#[macro_export]
|
|
325
|
+
macro_rules! public_key {
|
|
326
|
+
($text:literal) => {{
|
|
327
|
+
if $text.len() != 72 {
|
|
328
|
+
panic!("PublicKey must be 72 characters");
|
|
329
|
+
}
|
|
330
|
+
const ED25519_PREFIX: &[u8; 8] = b"ed25519:";
|
|
331
|
+
|
|
332
|
+
let buf = $text.as_bytes();
|
|
333
|
+
let mut s = [0u8; 64];
|
|
334
|
+
let mut i = 0;
|
|
335
|
+
while i < 72 {
|
|
336
|
+
if i < 8 {
|
|
337
|
+
if buf[i] != ED25519_PREFIX[i] {
|
|
338
|
+
panic!("PublicKey must start with ed25519:")
|
|
339
|
+
}
|
|
340
|
+
} else {
|
|
341
|
+
s[i - 8] = buf[i];
|
|
342
|
+
}
|
|
343
|
+
i += 1;
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
$crate::signing::PublicKey::new($crate::macros::decode_hex_256(&s))
|
|
347
|
+
}};
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
/// A macro to create a [sia::signing::Signature] from a literal hex string. The string must be 128 characters long.
|
|
351
|
+
///
|
|
352
|
+
/// ```
|
|
353
|
+
/// use sia::signing::Signature;
|
|
354
|
+
/// use sia::signature;
|
|
355
|
+
///
|
|
356
|
+
/// const sig: Signature = signature!("458283fd707c9d170d5e1814944f35893c53c9445fd46c74a6b285bf3029bf404c9af509ea271d811726bd20d8c7d8fe4b9efdc4bebb445f18059eca886ece03");
|
|
357
|
+
/// ```
|
|
358
|
+
#[macro_export]
|
|
359
|
+
macro_rules! signature {
|
|
360
|
+
($text:literal) => {{
|
|
361
|
+
if $text.len() != 128 {
|
|
362
|
+
panic!("Signature must be 128 characters");
|
|
363
|
+
}
|
|
364
|
+
$crate::signing::Signature::new($crate::macros::decode_hex_512($text.as_bytes()))
|
|
365
|
+
}};
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
#[cfg(test)]
|
|
369
|
+
mod tests {
|
|
370
|
+
use crate::signing::PublicKey;
|
|
371
|
+
use crate::types::{
|
|
372
|
+
Address, BlockID, FileContractID, SiacoinOutputID, SiafundOutputID, TransactionID,
|
|
373
|
+
};
|
|
374
|
+
|
|
375
|
+
const EXPECTED_BYTES: [u8; 32] = [
|
|
376
|
+
94, 183, 15, 20, 19, 135, 223, 30, 46, 205, 67, 75, 34, 190, 80, 191, 245, 122, 110, 8, 72,
|
|
377
|
+
79, 56, 144, 254, 68, 21, 166, 211, 35, 181, 233,
|
|
378
|
+
];
|
|
379
|
+
|
|
380
|
+
#[test]
|
|
381
|
+
fn test_address_macro() {
|
|
382
|
+
const ADDRESS: Address = address!(
|
|
383
|
+
"5eb70f141387df1e2ecd434b22be50bff57a6e08484f3890fe4415a6d323b5e9e758b4f79b34"
|
|
384
|
+
);
|
|
385
|
+
assert_eq!(ADDRESS.as_ref(), EXPECTED_BYTES);
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
#[test]
|
|
389
|
+
#[should_panic]
|
|
390
|
+
fn test_bad_address() {
|
|
391
|
+
address!("5eb70f141387df1e2ecd434b22be50bff57a6e08484f3890fe4415a6d323b5e9e758b4");
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
#[test]
|
|
395
|
+
fn test_public_key_macro() {
|
|
396
|
+
const PUBLIC_KEY: PublicKey =
|
|
397
|
+
public_key!("ed25519:5eb70f141387df1e2ecd434b22be50bff57a6e08484f3890fe4415a6d323b5e9");
|
|
398
|
+
assert_eq!(PUBLIC_KEY.as_ref(), EXPECTED_BYTES);
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
#[test]
|
|
402
|
+
fn test_block_id_macro() {
|
|
403
|
+
const BLOCK_ID: BlockID =
|
|
404
|
+
block_id!("5eb70f141387df1e2ecd434b22be50bff57a6e08484f3890fe4415a6d323b5e9");
|
|
405
|
+
assert_eq!(BLOCK_ID.as_ref(), EXPECTED_BYTES);
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
#[test]
|
|
409
|
+
fn test_transaction_id_macro() {
|
|
410
|
+
const TRANSACTION_ID: TransactionID =
|
|
411
|
+
transaction_id!("5eb70f141387df1e2ecd434b22be50bff57a6e08484f3890fe4415a6d323b5e9");
|
|
412
|
+
assert_eq!(TRANSACTION_ID.as_ref(), EXPECTED_BYTES);
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
#[test]
|
|
416
|
+
fn test_contract_id_macro() {
|
|
417
|
+
const CONTRACT_ID: FileContractID =
|
|
418
|
+
contract_id!("5eb70f141387df1e2ecd434b22be50bff57a6e08484f3890fe4415a6d323b5e9");
|
|
419
|
+
assert_eq!(CONTRACT_ID.as_ref(), EXPECTED_BYTES);
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
#[test]
|
|
423
|
+
fn test_siacoin_id_macro() {
|
|
424
|
+
const SIACOIN_ID: SiacoinOutputID =
|
|
425
|
+
siacoin_id!("5eb70f141387df1e2ecd434b22be50bff57a6e08484f3890fe4415a6d323b5e9");
|
|
426
|
+
assert_eq!(SIACOIN_ID.as_ref(), EXPECTED_BYTES);
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
#[test]
|
|
430
|
+
fn test_siafund_id_macro() {
|
|
431
|
+
const SIAFUND_ID: SiafundOutputID =
|
|
432
|
+
siafund_id!("5eb70f141387df1e2ecd434b22be50bff57a6e08484f3890fe4415a6d323b5e9");
|
|
433
|
+
assert_eq!(SIAFUND_ID.as_ref(), EXPECTED_BYTES);
|
|
434
|
+
}
|
|
435
|
+
}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
use crate::types::Hash256;
|
|
2
|
+
use blake2b_simd::Params;
|
|
3
|
+
|
|
4
|
+
pub const LEAF_HASH_PREFIX: &[u8; 1] = &[0];
|
|
5
|
+
pub const NODE_HASH_PREFIX: &[u8; 1] = &[1];
|
|
6
|
+
|
|
7
|
+
// A generic Merkle tree accumulator.
|
|
8
|
+
pub struct Accumulator {
|
|
9
|
+
trees: [Hash256; 64],
|
|
10
|
+
num_leaves: u64,
|
|
11
|
+
params: Params,
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
impl Accumulator {
|
|
15
|
+
pub fn new() -> Self {
|
|
16
|
+
let mut params = Params::new();
|
|
17
|
+
params.hash_length(32);
|
|
18
|
+
Self {
|
|
19
|
+
trees: [Hash256::default(); 64],
|
|
20
|
+
num_leaves: 0,
|
|
21
|
+
params,
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const fn has_tree_at_height(&self, height: usize) -> bool {
|
|
26
|
+
self.num_leaves & (1 << height) != 0
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
pub fn add_leaf(&mut self, mut h: Hash256) {
|
|
30
|
+
let mut i = 0;
|
|
31
|
+
while self.has_tree_at_height(i) {
|
|
32
|
+
h = sum_node(&self.params, &self.trees[i], &h);
|
|
33
|
+
i += 1;
|
|
34
|
+
}
|
|
35
|
+
self.trees[i] = h;
|
|
36
|
+
self.num_leaves += 1;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
pub fn insert_node(&mut self, mut h: Hash256, height: usize) {
|
|
40
|
+
let mut i = height;
|
|
41
|
+
while self.has_tree_at_height(i) {
|
|
42
|
+
h = sum_node(&self.params, &self.trees[i], &h);
|
|
43
|
+
i += 1;
|
|
44
|
+
}
|
|
45
|
+
self.trees[i] = h;
|
|
46
|
+
self.num_leaves += 1 << height;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
pub fn reset(&mut self) {
|
|
50
|
+
self.trees.fill(Default::default());
|
|
51
|
+
self.num_leaves = 0;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
pub fn root(&self) -> Hash256 {
|
|
55
|
+
let mut i = self.num_leaves.trailing_zeros() as usize;
|
|
56
|
+
if i == 64 {
|
|
57
|
+
return Hash256::default();
|
|
58
|
+
}
|
|
59
|
+
let mut root = self.trees[i];
|
|
60
|
+
i += 1;
|
|
61
|
+
while i < 64 {
|
|
62
|
+
if self.has_tree_at_height(i) {
|
|
63
|
+
root = sum_node(&self.params, &self.trees[i], &root);
|
|
64
|
+
}
|
|
65
|
+
i += 1;
|
|
66
|
+
}
|
|
67
|
+
root
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
pub fn sum_leaf(params: &Params, leaf: &[u8]) -> Hash256 {
|
|
72
|
+
let h = params
|
|
73
|
+
.to_state()
|
|
74
|
+
.update(LEAF_HASH_PREFIX)
|
|
75
|
+
.update(leaf)
|
|
76
|
+
.finalize();
|
|
77
|
+
|
|
78
|
+
h.into()
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
pub fn sum_node(params: &Params, left: &Hash256, right: &Hash256) -> Hash256 {
|
|
82
|
+
let h = params
|
|
83
|
+
.to_state()
|
|
84
|
+
.update(NODE_HASH_PREFIX)
|
|
85
|
+
.update(left.as_ref())
|
|
86
|
+
.update(right.as_ref())
|
|
87
|
+
.finalize();
|
|
88
|
+
|
|
89
|
+
h.into()
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
#[cfg(test)]
|
|
93
|
+
mod tests {
|
|
94
|
+
use super::*;
|
|
95
|
+
use crate::hash_256;
|
|
96
|
+
use crate::rhp::{SECTOR_SIZE, SEGMENT_SIZE};
|
|
97
|
+
|
|
98
|
+
#[test]
|
|
99
|
+
fn test_sector_root_from_leaves() {
|
|
100
|
+
let data = vec![0u8; SECTOR_SIZE];
|
|
101
|
+
|
|
102
|
+
let mut acc = Accumulator::new();
|
|
103
|
+
for chunk in data.chunks(SEGMENT_SIZE) {
|
|
104
|
+
let leaf_hash = sum_leaf(&acc.params, chunk);
|
|
105
|
+
acc.add_leaf(leaf_hash);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
let expected_root =
|
|
109
|
+
hash_256!("50ed59cecd5ed3ca9e65cec0797202091dbba45272dafa3faa4e27064eedd52c");
|
|
110
|
+
assert_eq!(acc.root(), expected_root);
|
|
111
|
+
}
|
|
112
|
+
}
|