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,347 @@
|
|
|
1
|
+
use crate::rhp::{SECTOR_SIZE, SEGMENT_SIZE};
|
|
2
|
+
use reed_solomon_erasure::galois_8::ReedSolomon;
|
|
3
|
+
use thiserror::Error;
|
|
4
|
+
use tokio::io::{self, AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt};
|
|
5
|
+
|
|
6
|
+
#[derive(Debug, Error)]
|
|
7
|
+
pub enum Error {
|
|
8
|
+
#[error("ReedSolomon error: {0}")]
|
|
9
|
+
ReedSolomon(#[from] reed_solomon_erasure::Error),
|
|
10
|
+
|
|
11
|
+
#[error("IO error: {0}")]
|
|
12
|
+
Io(#[from] io::Error),
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
pub type Result<T> = std::result::Result<T, Error>;
|
|
16
|
+
|
|
17
|
+
pub struct ErasureCoder {
|
|
18
|
+
encoder: ReedSolomon,
|
|
19
|
+
data_shards: usize,
|
|
20
|
+
parity_shards: usize,
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
impl ErasureCoder {
|
|
24
|
+
pub fn new(data_shards: usize, parity_shards: usize) -> Result<Self> {
|
|
25
|
+
Ok(ErasureCoder {
|
|
26
|
+
encoder: ReedSolomon::new(data_shards, parity_shards)?,
|
|
27
|
+
data_shards,
|
|
28
|
+
parity_shards,
|
|
29
|
+
})
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/// encodes the shards using reed solomon erasure coding,
|
|
33
|
+
/// computing the parity shards and overwriting their values.
|
|
34
|
+
pub fn encode_shards(&self, shards: &mut [Vec<u8>]) -> Result<()> {
|
|
35
|
+
self.encoder.encode(shards)?;
|
|
36
|
+
Ok(())
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/// reconstructs the missing shards from the available ones.
|
|
40
|
+
pub fn reconstruct(&self, shards: &mut [Option<Vec<u8>>]) -> Result<()> {
|
|
41
|
+
self.encoder.reconstruct(shards)?;
|
|
42
|
+
Ok(())
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/// reconstructs the missing datashards from the available ones.
|
|
46
|
+
pub fn reconstruct_data_shards(&self, shards: &mut [Option<Vec<u8>>]) -> Result<()> {
|
|
47
|
+
self.encoder.reconstruct_data(shards)?;
|
|
48
|
+
Ok(())
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/// write_data_shards writes up to 'n' bytes from the given reconstructed shards
|
|
52
|
+
/// to the provided writer, skipping the first `skip` bytes.
|
|
53
|
+
pub async fn write_data_shards<W: AsyncWrite + Unpin>(
|
|
54
|
+
w: &mut W,
|
|
55
|
+
shards: &[Option<Vec<u8>>],
|
|
56
|
+
mut skip: usize,
|
|
57
|
+
mut n: usize,
|
|
58
|
+
) -> Result<()> {
|
|
59
|
+
let row_bytes = shards.len() * SEGMENT_SIZE;
|
|
60
|
+
let rows = skip / row_bytes;
|
|
61
|
+
let mut offset = rows * SEGMENT_SIZE;
|
|
62
|
+
skip %= row_bytes;
|
|
63
|
+
while n > 0 {
|
|
64
|
+
for shard in shards {
|
|
65
|
+
if n == 0 {
|
|
66
|
+
return Ok(());
|
|
67
|
+
} else if skip > SEGMENT_SIZE {
|
|
68
|
+
skip -= SEGMENT_SIZE;
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
let segment = shard.as_ref().ok_or(Error::ReedSolomon(
|
|
73
|
+
reed_solomon_erasure::Error::TooFewDataShards,
|
|
74
|
+
))?;
|
|
75
|
+
|
|
76
|
+
let start = offset + skip;
|
|
77
|
+
let length = n.min(SEGMENT_SIZE - skip);
|
|
78
|
+
|
|
79
|
+
w.write_all(&segment[start..start + length]).await?;
|
|
80
|
+
n -= length;
|
|
81
|
+
skip = 0;
|
|
82
|
+
}
|
|
83
|
+
offset += SEGMENT_SIZE;
|
|
84
|
+
}
|
|
85
|
+
Ok(())
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
pub async fn read_slab_shards<R: AsyncRead + Unpin>(
|
|
89
|
+
r: &mut R,
|
|
90
|
+
data_shards: usize,
|
|
91
|
+
shards: &mut [Vec<u8>],
|
|
92
|
+
) -> Result<usize> {
|
|
93
|
+
// limit total read size to the size of the slab's data shards
|
|
94
|
+
let mut r = r.take(data_shards as u64 * SECTOR_SIZE as u64);
|
|
95
|
+
let mut data_size = 0;
|
|
96
|
+
for off in (0..SECTOR_SIZE).step_by(SEGMENT_SIZE) {
|
|
97
|
+
let start = off;
|
|
98
|
+
let end = off + SEGMENT_SIZE;
|
|
99
|
+
for shard in &mut shards[..data_shards].iter_mut() {
|
|
100
|
+
let segment = &mut shard[start..end];
|
|
101
|
+
let mut bytes_read = 0;
|
|
102
|
+
while bytes_read < SEGMENT_SIZE {
|
|
103
|
+
// note: read_exact + UnexpectedEoF is not used due to the documentation
|
|
104
|
+
// saying "the contents of buf are unspecified." when UnexpectedEoF is
|
|
105
|
+
// returned. It's *most likely* fine to rely on the contents being
|
|
106
|
+
// a partial read, but better to not make the assumption for every
|
|
107
|
+
// possible implementation of the Read trait.
|
|
108
|
+
let n = r.read(&mut segment[bytes_read..]).await?;
|
|
109
|
+
if n == 0 {
|
|
110
|
+
return Ok(data_size);
|
|
111
|
+
}
|
|
112
|
+
bytes_read += n;
|
|
113
|
+
data_size += n;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
Ok(data_size)
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/// read_shards reads data from the given reader into a vector of shards.
|
|
121
|
+
pub async fn read_shards<R: AsyncRead + Unpin>(
|
|
122
|
+
&self,
|
|
123
|
+
r: &mut R,
|
|
124
|
+
) -> Result<(Vec<Vec<u8>>, u32)> {
|
|
125
|
+
let total_shards = self.data_shards + self.parity_shards;
|
|
126
|
+
let mut shards = vec![vec![0u8; SECTOR_SIZE]; total_shards];
|
|
127
|
+
let mut r = r.take(self.data_shards as u64 * SECTOR_SIZE as u64);
|
|
128
|
+
let slab_size = Self::read_slab_shards(&mut r, self.data_shards, &mut shards).await?;
|
|
129
|
+
Ok((shards, slab_size as u32))
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
#[cfg(test)]
|
|
134
|
+
mod tests {
|
|
135
|
+
use rand::Rng;
|
|
136
|
+
|
|
137
|
+
use super::*;
|
|
138
|
+
|
|
139
|
+
#[tokio::test]
|
|
140
|
+
async fn test_encode_shards() {
|
|
141
|
+
let data_shards = 2;
|
|
142
|
+
let parity_shards = 3;
|
|
143
|
+
let coder = ErasureCoder::new(data_shards, parity_shards).unwrap();
|
|
144
|
+
|
|
145
|
+
let mut shards: Vec<Vec<u8>> = [
|
|
146
|
+
vec![1u8; SECTOR_SIZE],
|
|
147
|
+
vec![2u8; SECTOR_SIZE],
|
|
148
|
+
vec![0u8; SECTOR_SIZE],
|
|
149
|
+
vec![0u8; SECTOR_SIZE],
|
|
150
|
+
vec![0u8; SECTOR_SIZE],
|
|
151
|
+
]
|
|
152
|
+
.into();
|
|
153
|
+
|
|
154
|
+
coder.encode_shards(&mut shards).unwrap();
|
|
155
|
+
|
|
156
|
+
let expected_shards: Vec<Vec<u8>> = vec![
|
|
157
|
+
vec![1u8; SECTOR_SIZE],
|
|
158
|
+
vec![2u8; SECTOR_SIZE],
|
|
159
|
+
vec![7u8; SECTOR_SIZE], // parity shard 1
|
|
160
|
+
vec![4u8; SECTOR_SIZE], // parity shard 2
|
|
161
|
+
vec![13u8; SECTOR_SIZE], // parity shard 3
|
|
162
|
+
];
|
|
163
|
+
assert_eq!(shards, expected_shards);
|
|
164
|
+
|
|
165
|
+
// reconstruct every shard
|
|
166
|
+
for i in 0..shards.len() {
|
|
167
|
+
let mut shards: Vec<Option<Vec<u8>>> = shards.iter().cloned().map(Some).collect();
|
|
168
|
+
shards[i] = None;
|
|
169
|
+
coder.reconstruct(&mut shards).unwrap();
|
|
170
|
+
let shards: Vec<Vec<u8>> = shards.into_iter().map(|s| s.unwrap()).collect();
|
|
171
|
+
assert_eq!(shards, expected_shards);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// reconstruct data shards
|
|
175
|
+
for i in 0..data_shards {
|
|
176
|
+
let mut shards: Vec<Option<Vec<u8>>> = shards.iter().cloned().map(Some).collect();
|
|
177
|
+
shards[i] = None;
|
|
178
|
+
coder.reconstruct_data_shards(&mut shards).unwrap();
|
|
179
|
+
let shards: Vec<Vec<u8>> = shards.into_iter().map(|s| s.unwrap()).collect();
|
|
180
|
+
assert_eq!(shards, expected_shards);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
#[tokio::test]
|
|
185
|
+
async fn test_striped_read() {
|
|
186
|
+
const DATA_SHARDS: usize = 3;
|
|
187
|
+
const PARITY_SHARDS: usize = 2;
|
|
188
|
+
|
|
189
|
+
let test_cases = vec![
|
|
190
|
+
// (data size, expected size)
|
|
191
|
+
(100, 100), // under
|
|
192
|
+
(SECTOR_SIZE * DATA_SHARDS, SECTOR_SIZE * DATA_SHARDS), // exact
|
|
193
|
+
(2 * SECTOR_SIZE * DATA_SHARDS, SECTOR_SIZE * DATA_SHARDS), // over
|
|
194
|
+
];
|
|
195
|
+
|
|
196
|
+
let coder = ErasureCoder::new(DATA_SHARDS, PARITY_SHARDS).unwrap();
|
|
197
|
+
|
|
198
|
+
for (data_size, expected_size) in test_cases {
|
|
199
|
+
let mut data = vec![0u8; data_size];
|
|
200
|
+
rand::rng().fill_bytes(&mut data);
|
|
201
|
+
|
|
202
|
+
let (shards, size) = coder.read_shards(&mut &data[..]).await.unwrap();
|
|
203
|
+
|
|
204
|
+
assert_eq!(
|
|
205
|
+
size as usize, expected_size,
|
|
206
|
+
"data size {data_size} mismatch"
|
|
207
|
+
);
|
|
208
|
+
assert_eq!(
|
|
209
|
+
shards.len(),
|
|
210
|
+
DATA_SHARDS + PARITY_SHARDS,
|
|
211
|
+
"data size {data_size} shard count mismatch"
|
|
212
|
+
);
|
|
213
|
+
|
|
214
|
+
for (i, data) in data[..size as usize].chunks(64).enumerate() {
|
|
215
|
+
let mut chunk = [0u8; SEGMENT_SIZE];
|
|
216
|
+
chunk[..data.len()].copy_from_slice(data); // pad it out with zeros
|
|
217
|
+
let index = i % DATA_SHARDS;
|
|
218
|
+
let offset = (i / DATA_SHARDS) * SEGMENT_SIZE;
|
|
219
|
+
|
|
220
|
+
assert_eq!(
|
|
221
|
+
&shards[index][offset..offset + 64],
|
|
222
|
+
chunk,
|
|
223
|
+
"data size {data_size} shard {index} mismatch at offset {offset}"
|
|
224
|
+
);
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
#[tokio::test]
|
|
230
|
+
async fn test_striped_read_write() {
|
|
231
|
+
const DATA_SHARDS: usize = 4;
|
|
232
|
+
const PARITY_SHARDS: usize = 1;
|
|
233
|
+
let coder = ErasureCoder::new(DATA_SHARDS, PARITY_SHARDS).unwrap();
|
|
234
|
+
|
|
235
|
+
let mut data = vec![0u8; SECTOR_SIZE * 7 / 2]; // 3.5 shards of data
|
|
236
|
+
data[..SECTOR_SIZE].fill(1);
|
|
237
|
+
data[SECTOR_SIZE..2 * SECTOR_SIZE].fill(2);
|
|
238
|
+
data[2 * SECTOR_SIZE..3 * SECTOR_SIZE].fill(3);
|
|
239
|
+
data[3 * SECTOR_SIZE..].fill(4);
|
|
240
|
+
|
|
241
|
+
let (mut shards, size) = coder.read_shards(&mut data.as_slice()).await.unwrap();
|
|
242
|
+
|
|
243
|
+
// we expect 5 shards and the last one is an empty parity shard
|
|
244
|
+
assert_eq!(shards.len(), 5);
|
|
245
|
+
assert_eq!(size as usize, SECTOR_SIZE * 7 / 2);
|
|
246
|
+
assert_eq!(shards[4], [0u8; SECTOR_SIZE]);
|
|
247
|
+
|
|
248
|
+
for shard in &shards[..4] {
|
|
249
|
+
// every shard should be of SECTOR_SIZE
|
|
250
|
+
assert_eq!(shard.len(), SECTOR_SIZE);
|
|
251
|
+
|
|
252
|
+
// first quarter of every shard is 1s
|
|
253
|
+
assert_eq!(shard[0..SECTOR_SIZE / 4], [1u8; SECTOR_SIZE / 4]);
|
|
254
|
+
|
|
255
|
+
// second quarter is 2s
|
|
256
|
+
assert_eq!(
|
|
257
|
+
shard[SECTOR_SIZE / 4..SECTOR_SIZE / 2],
|
|
258
|
+
[2u8; SECTOR_SIZE / 4]
|
|
259
|
+
);
|
|
260
|
+
|
|
261
|
+
// third quarter is 3s
|
|
262
|
+
assert_eq!(
|
|
263
|
+
shard[SECTOR_SIZE / 2..SECTOR_SIZE / 4 * 3],
|
|
264
|
+
[3u8; SECTOR_SIZE / 4]
|
|
265
|
+
);
|
|
266
|
+
|
|
267
|
+
// half of the fourth quarter is 4s
|
|
268
|
+
assert_eq!(
|
|
269
|
+
shard[SECTOR_SIZE / 4 * 3..SECTOR_SIZE / 8 * 7],
|
|
270
|
+
[4u8; SECTOR_SIZE / 8]
|
|
271
|
+
);
|
|
272
|
+
|
|
273
|
+
// remainder is padded with 0s
|
|
274
|
+
assert_eq!(shard[SECTOR_SIZE / 8 * 7..], [0u8; SECTOR_SIZE / 8]);
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
// encoding the read shards should succeed without errors and cause the
|
|
278
|
+
// parity shard to be filled
|
|
279
|
+
coder.encode_shards(&mut shards).unwrap();
|
|
280
|
+
assert_ne!(shards[4], [0u8; SECTOR_SIZE]);
|
|
281
|
+
|
|
282
|
+
// joining the shards back together should result in the original data
|
|
283
|
+
let shards: Vec<Option<Vec<u8>>> = shards.iter().cloned().map(Some).collect();
|
|
284
|
+
let mut joined_data = Vec::new();
|
|
285
|
+
ErasureCoder::write_data_shards(&mut joined_data, &shards[..DATA_SHARDS], 0, data.len())
|
|
286
|
+
.await
|
|
287
|
+
.unwrap();
|
|
288
|
+
assert_eq!(joined_data, data);
|
|
289
|
+
|
|
290
|
+
// join only the first half
|
|
291
|
+
let mut joined_data = Vec::new();
|
|
292
|
+
ErasureCoder::write_data_shards(
|
|
293
|
+
&mut joined_data,
|
|
294
|
+
&shards[..DATA_SHARDS],
|
|
295
|
+
0,
|
|
296
|
+
data.len() / 2,
|
|
297
|
+
)
|
|
298
|
+
.await
|
|
299
|
+
.unwrap();
|
|
300
|
+
assert_eq!(joined_data, data[..data.len() / 2]);
|
|
301
|
+
|
|
302
|
+
// join only the second half
|
|
303
|
+
let mut joined_data = Vec::new();
|
|
304
|
+
ErasureCoder::write_data_shards(
|
|
305
|
+
&mut joined_data,
|
|
306
|
+
&shards[..DATA_SHARDS],
|
|
307
|
+
data.len() / 2,
|
|
308
|
+
data.len() / 2,
|
|
309
|
+
)
|
|
310
|
+
.await
|
|
311
|
+
.unwrap();
|
|
312
|
+
assert_eq!(joined_data, data[data.len() / 2..]);
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
#[tokio::test]
|
|
316
|
+
async fn test_read_encoded_write_reconstructed() {
|
|
317
|
+
const DATA_SHARDS: usize = 4;
|
|
318
|
+
const PARITY_SHARDS: usize = 1;
|
|
319
|
+
let coder = ErasureCoder::new(DATA_SHARDS, PARITY_SHARDS).unwrap();
|
|
320
|
+
let mut data = vec![0u8; SECTOR_SIZE * 7 / 2]; // 3.5 shards of data
|
|
321
|
+
data[..SECTOR_SIZE].fill(1);
|
|
322
|
+
data[SECTOR_SIZE..2 * SECTOR_SIZE].fill(2);
|
|
323
|
+
data[2 * SECTOR_SIZE..3 * SECTOR_SIZE].fill(3);
|
|
324
|
+
data[3 * SECTOR_SIZE..].fill(4);
|
|
325
|
+
|
|
326
|
+
// encode the data
|
|
327
|
+
let (mut shards, _) = coder.read_shards(&mut &data[..]).await.unwrap();
|
|
328
|
+
coder.encode_shards(&mut shards).unwrap();
|
|
329
|
+
|
|
330
|
+
// drop a shard
|
|
331
|
+
let mut encoded_shards = shards.into_iter().map(Some).collect::<Vec<_>>();
|
|
332
|
+
encoded_shards[2] = None; // drop the third shard
|
|
333
|
+
|
|
334
|
+
// reconstruct the data shards
|
|
335
|
+
let mut reconstructed_data: Vec<u8> = Vec::new();
|
|
336
|
+
coder.reconstruct_data_shards(&mut encoded_shards).unwrap();
|
|
337
|
+
ErasureCoder::write_data_shards(
|
|
338
|
+
&mut reconstructed_data,
|
|
339
|
+
&encoded_shards[..DATA_SHARDS],
|
|
340
|
+
0,
|
|
341
|
+
data.len(),
|
|
342
|
+
)
|
|
343
|
+
.await
|
|
344
|
+
.unwrap();
|
|
345
|
+
assert_eq!(data, reconstructed_data);
|
|
346
|
+
}
|
|
347
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
pub mod blake2;
|
|
2
|
+
pub mod consensus;
|
|
3
|
+
pub mod encoding;
|
|
4
|
+
pub mod encoding_async;
|
|
5
|
+
pub mod encryption;
|
|
6
|
+
pub mod erasure_coding;
|
|
7
|
+
pub mod rhp;
|
|
8
|
+
pub mod seed;
|
|
9
|
+
pub mod signing;
|
|
10
|
+
pub mod types;
|
|
11
|
+
|
|
12
|
+
pub mod macros;
|
|
13
|
+
pub(crate) mod merkle;
|
|
14
|
+
|
|
15
|
+
extern crate self as sia;
|