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.
Files changed (112) hide show
  1. package/dist/index.d.ts +1 -0
  2. package/dist/index.js +179 -0
  3. package/package.json +29 -0
  4. package/template/CLAUDE.md +160 -0
  5. package/template/README.md +102 -0
  6. package/template/_gitignore +5 -0
  7. package/template/biome.json +40 -0
  8. package/template/index.html +13 -0
  9. package/template/package.json +30 -0
  10. package/template/rust/README.md +16 -0
  11. package/template/rust/sia-sdk-rs/.changeset/added_cancel_function_to_cancel_inflight_packed_uploads.md +6 -0
  12. package/template/rust/sia-sdk-rs/.changeset/check_if_we_have_enough_hosts_prior_to_encoding_in_upload_slabs.md +16 -0
  13. package/template/rust/sia-sdk-rs/.changeset/fix_slab_length_in_packed_object.md +5 -0
  14. package/template/rust/sia-sdk-rs/.changeset/fix_upload_racing_race_conditon.md +13 -0
  15. package/template/rust/sia-sdk-rs/.changeset/improved_parallelism_of_packed_uploads.md +5 -0
  16. package/template/rust/sia-sdk-rs/.changeset/progress_callback_will_now_be_called_as_expected_for_packed_uploads.md +5 -0
  17. package/template/rust/sia-sdk-rs/.github/dependabot.yml +10 -0
  18. package/template/rust/sia-sdk-rs/.github/workflows/main.yml +36 -0
  19. package/template/rust/sia-sdk-rs/.github/workflows/prepare-release.yml +34 -0
  20. package/template/rust/sia-sdk-rs/.github/workflows/release.yml +30 -0
  21. package/template/rust/sia-sdk-rs/.rustfmt.toml +4 -0
  22. package/template/rust/sia-sdk-rs/Cargo.lock +4127 -0
  23. package/template/rust/sia-sdk-rs/Cargo.toml +3 -0
  24. package/template/rust/sia-sdk-rs/LICENSE +21 -0
  25. package/template/rust/sia-sdk-rs/README.md +30 -0
  26. package/template/rust/sia-sdk-rs/indexd/CHANGELOG.md +79 -0
  27. package/template/rust/sia-sdk-rs/indexd/Cargo.toml +79 -0
  28. package/template/rust/sia-sdk-rs/indexd/benches/upload.rs +258 -0
  29. package/template/rust/sia-sdk-rs/indexd/src/app_client.rs +1710 -0
  30. package/template/rust/sia-sdk-rs/indexd/src/builder.rs +354 -0
  31. package/template/rust/sia-sdk-rs/indexd/src/download.rs +379 -0
  32. package/template/rust/sia-sdk-rs/indexd/src/hosts.rs +659 -0
  33. package/template/rust/sia-sdk-rs/indexd/src/lib.rs +827 -0
  34. package/template/rust/sia-sdk-rs/indexd/src/mock.rs +162 -0
  35. package/template/rust/sia-sdk-rs/indexd/src/object_encryption.rs +125 -0
  36. package/template/rust/sia-sdk-rs/indexd/src/quic.rs +575 -0
  37. package/template/rust/sia-sdk-rs/indexd/src/rhp4.rs +52 -0
  38. package/template/rust/sia-sdk-rs/indexd/src/slabs.rs +497 -0
  39. package/template/rust/sia-sdk-rs/indexd/src/upload.rs +629 -0
  40. package/template/rust/sia-sdk-rs/indexd/src/wasm_time.rs +41 -0
  41. package/template/rust/sia-sdk-rs/indexd/src/web_transport.rs +398 -0
  42. package/template/rust/sia-sdk-rs/indexd_ffi/CHANGELOG.md +76 -0
  43. package/template/rust/sia-sdk-rs/indexd_ffi/Cargo.toml +47 -0
  44. package/template/rust/sia-sdk-rs/indexd_ffi/examples/python/README.md +10 -0
  45. package/template/rust/sia-sdk-rs/indexd_ffi/examples/python/example.py +130 -0
  46. package/template/rust/sia-sdk-rs/indexd_ffi/src/bin/uniffi-bindgen.rs +3 -0
  47. package/template/rust/sia-sdk-rs/indexd_ffi/src/builder.rs +377 -0
  48. package/template/rust/sia-sdk-rs/indexd_ffi/src/io.rs +155 -0
  49. package/template/rust/sia-sdk-rs/indexd_ffi/src/lib.rs +1039 -0
  50. package/template/rust/sia-sdk-rs/indexd_ffi/src/logging.rs +58 -0
  51. package/template/rust/sia-sdk-rs/indexd_ffi/src/tls.rs +23 -0
  52. package/template/rust/sia-sdk-rs/indexd_wasm/Cargo.toml +33 -0
  53. package/template/rust/sia-sdk-rs/indexd_wasm/src/lib.rs +818 -0
  54. package/template/rust/sia-sdk-rs/knope.toml +54 -0
  55. package/template/rust/sia-sdk-rs/sia_derive/CHANGELOG.md +38 -0
  56. package/template/rust/sia-sdk-rs/sia_derive/Cargo.toml +19 -0
  57. package/template/rust/sia-sdk-rs/sia_derive/src/lib.rs +278 -0
  58. package/template/rust/sia-sdk-rs/sia_sdk/CHANGELOG.md +91 -0
  59. package/template/rust/sia-sdk-rs/sia_sdk/Cargo.toml +59 -0
  60. package/template/rust/sia-sdk-rs/sia_sdk/benches/merkle_root.rs +12 -0
  61. package/template/rust/sia-sdk-rs/sia_sdk/src/blake2.rs +22 -0
  62. package/template/rust/sia-sdk-rs/sia_sdk/src/consensus.rs +767 -0
  63. package/template/rust/sia-sdk-rs/sia_sdk/src/encoding/v1.rs +257 -0
  64. package/template/rust/sia-sdk-rs/sia_sdk/src/encoding/v2.rs +291 -0
  65. package/template/rust/sia-sdk-rs/sia_sdk/src/encoding.rs +26 -0
  66. package/template/rust/sia-sdk-rs/sia_sdk/src/encoding_async/v2.rs +367 -0
  67. package/template/rust/sia-sdk-rs/sia_sdk/src/encoding_async.rs +6 -0
  68. package/template/rust/sia-sdk-rs/sia_sdk/src/encryption.rs +303 -0
  69. package/template/rust/sia-sdk-rs/sia_sdk/src/erasure_coding.rs +347 -0
  70. package/template/rust/sia-sdk-rs/sia_sdk/src/lib.rs +15 -0
  71. package/template/rust/sia-sdk-rs/sia_sdk/src/macros.rs +435 -0
  72. package/template/rust/sia-sdk-rs/sia_sdk/src/merkle.rs +112 -0
  73. package/template/rust/sia-sdk-rs/sia_sdk/src/rhp/merkle.rs +357 -0
  74. package/template/rust/sia-sdk-rs/sia_sdk/src/rhp/rpc.rs +1507 -0
  75. package/template/rust/sia-sdk-rs/sia_sdk/src/rhp/types.rs +146 -0
  76. package/template/rust/sia-sdk-rs/sia_sdk/src/rhp.rs +7 -0
  77. package/template/rust/sia-sdk-rs/sia_sdk/src/seed.rs +278 -0
  78. package/template/rust/sia-sdk-rs/sia_sdk/src/signing.rs +236 -0
  79. package/template/rust/sia-sdk-rs/sia_sdk/src/types/common.rs +677 -0
  80. package/template/rust/sia-sdk-rs/sia_sdk/src/types/currency.rs +450 -0
  81. package/template/rust/sia-sdk-rs/sia_sdk/src/types/specifier.rs +110 -0
  82. package/template/rust/sia-sdk-rs/sia_sdk/src/types/spendpolicy.rs +778 -0
  83. package/template/rust/sia-sdk-rs/sia_sdk/src/types/utils.rs +117 -0
  84. package/template/rust/sia-sdk-rs/sia_sdk/src/types/v1.rs +1737 -0
  85. package/template/rust/sia-sdk-rs/sia_sdk/src/types/v2.rs +1726 -0
  86. package/template/rust/sia-sdk-rs/sia_sdk/src/types/work.rs +59 -0
  87. package/template/rust/sia-sdk-rs/sia_sdk/src/types.rs +16 -0
  88. package/template/scripts/setup-rust.js +29 -0
  89. package/template/src/App.tsx +13 -0
  90. package/template/src/components/DevNote.tsx +21 -0
  91. package/template/src/components/auth/ApproveScreen.tsx +84 -0
  92. package/template/src/components/auth/AuthFlow.tsx +77 -0
  93. package/template/src/components/auth/ConnectScreen.tsx +214 -0
  94. package/template/src/components/auth/LoadingScreen.tsx +8 -0
  95. package/template/src/components/auth/RecoveryScreen.tsx +182 -0
  96. package/template/src/components/upload/UploadZone.tsx +314 -0
  97. package/template/src/index.css +9 -0
  98. package/template/src/lib/constants.ts +8 -0
  99. package/template/src/lib/format.ts +35 -0
  100. package/template/src/lib/hex.ts +13 -0
  101. package/template/src/lib/sdk.ts +25 -0
  102. package/template/src/lib/wasm-env.ts +5 -0
  103. package/template/src/main.tsx +12 -0
  104. package/template/src/stores/auth.ts +86 -0
  105. package/template/tsconfig.app.json +31 -0
  106. package/template/tsconfig.json +7 -0
  107. package/template/tsconfig.node.json +26 -0
  108. package/template/vite.config.ts +18 -0
  109. package/template/wasm/indexd_wasm/indexd_wasm.d.ts +309 -0
  110. package/template/wasm/indexd_wasm/indexd_wasm.js +1507 -0
  111. package/template/wasm/indexd_wasm/indexd_wasm_bg.wasm +0 -0
  112. package/template/wasm/indexd_wasm/package.json +31 -0
@@ -0,0 +1,767 @@
1
+ use crate::address;
2
+ use chrono::{DateTime, Duration, Utc};
3
+ use serde::ser::SerializeStruct;
4
+ use serde::{Deserialize, Serialize, Serializer};
5
+
6
+ use crate::encoding::{self, SiaDecodable, SiaEncodable};
7
+ use crate::types::{Address, BlockID, ChainIndex, Currency, Hash256, SiacoinOutput, Work};
8
+
9
+ /// HardforkDevAddr contains the parameters for a hardfork that changed
10
+ /// the developer address.
11
+ #[derive(PartialEq, Debug, Serialize, Deserialize)]
12
+ #[serde(rename_all = "camelCase")]
13
+ pub struct HardforkDevAddr {
14
+ pub height: u64,
15
+ pub old_address: Address,
16
+ pub new_address: Address,
17
+ }
18
+
19
+ /// HardforkTax contains the parameters for a hardfork that changed the
20
+ /// SiaFund file contract tax calculation.
21
+ #[derive(PartialEq, Debug, Serialize, Deserialize)]
22
+ #[serde(rename_all = "camelCase")]
23
+ pub struct HardforkTax {
24
+ pub height: u64,
25
+ }
26
+
27
+ /// HardforkStorageProof contains the parameters for a hardfork that changed
28
+ /// the leaf selection algorithm for storage proofs.
29
+ #[derive(PartialEq, Debug, Serialize, Deserialize)]
30
+ #[serde(rename_all = "camelCase")]
31
+ pub struct HardforkStorageProof {
32
+ pub height: u64,
33
+ }
34
+
35
+ /// HardforkBlockSubsidy contains the parameters for a hardfork that changed
36
+ /// the difficulty adjustment algorithm.
37
+ #[derive(PartialEq, Debug, Serialize, Deserialize)]
38
+ #[serde(rename_all = "camelCase")]
39
+ pub struct HardforkOak {
40
+ pub height: u64,
41
+ pub fix_height: u64,
42
+ pub genesis_timestamp: DateTime<Utc>,
43
+ }
44
+
45
+ /// HardforkASIC contains the parameters for a hardfork that changed the mining algorithm
46
+ /// to Blake2B-Sia
47
+ #[derive(PartialEq, Debug, Serialize, Deserialize)]
48
+ #[serde(rename_all = "camelCase")]
49
+ pub struct HardforkASIC {
50
+ pub height: u64,
51
+ #[serde(with = "crate::types::utils::nano_second_duration")]
52
+ pub oak_time: Duration,
53
+ pub oak_target: BlockID,
54
+ }
55
+
56
+ /// HardforkFoundation contains the parameters for a hardfork that introduced the Foundation
57
+ /// subsidy.
58
+ #[derive(PartialEq, Debug, Serialize, Deserialize)]
59
+ #[serde(rename_all = "camelCase")]
60
+ pub struct HardforkFoundation {
61
+ pub height: u64,
62
+ pub primary_address: Address,
63
+ pub failsafe_address: Address,
64
+ }
65
+
66
+ /// HardforkV2 contains the parameters for the v2 consensus hardfork.
67
+ #[derive(PartialEq, Debug, Serialize, Deserialize)]
68
+ #[serde(rename_all = "camelCase")]
69
+ pub struct HardforkV2 {
70
+ pub allow_height: u64,
71
+ pub require_height: u64,
72
+ }
73
+
74
+ /// Network contains consensus parameters that are network-specific.
75
+ #[derive(PartialEq, Debug, Serialize, Deserialize)]
76
+ #[serde(rename_all = "camelCase")]
77
+ pub struct Network {
78
+ pub name: String,
79
+
80
+ pub initial_coinbase: Currency,
81
+ pub minimum_coinbase: Currency,
82
+ pub initial_target: BlockID,
83
+ #[serde(with = "crate::types::utils::nano_second_duration")]
84
+ pub block_interval: Duration,
85
+ pub maturity_delay: u64,
86
+
87
+ pub hardfork_dev_addr: HardforkDevAddr,
88
+ pub hardfork_tax: HardforkTax,
89
+ pub hardfork_storage_proof: HardforkStorageProof,
90
+ pub hardfork_oak: HardforkOak,
91
+ #[serde(rename = "hardforkASIC")]
92
+ pub hardfork_asic: HardforkASIC,
93
+ pub hardfork_foundation: HardforkFoundation,
94
+ pub hardfork_v2: HardforkV2,
95
+ }
96
+
97
+ const fn unix_timestamp(secs: i64) -> DateTime<Utc> {
98
+ match DateTime::from_timestamp_secs(secs) {
99
+ Some(t) => t,
100
+ None => panic!("invalid timestamp"),
101
+ }
102
+ }
103
+
104
+ impl Network {
105
+ pub fn mainnet() -> Self {
106
+ Network {
107
+ name: "mainnet".to_string(),
108
+ initial_coinbase: Currency::siacoins(300_000),
109
+ minimum_coinbase: Currency::siacoins(30_000),
110
+ initial_target: BlockID::new([
111
+ 0, 0, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
112
+ 0, 0, 0, 0, 0,
113
+ ]),
114
+ block_interval: Duration::minutes(10),
115
+ maturity_delay: 144,
116
+
117
+ hardfork_dev_addr: HardforkDevAddr {
118
+ height: 10000,
119
+ old_address: address!(
120
+ "7d0c44f7664e2d34e53efde0661a6f628ec9264785ae8e3cd7c973e8d190c3c97b5e3ecbc567"
121
+ ),
122
+ new_address: address!(
123
+ "f371c70bce9eb8979cd5099f599ec4e4fcb14e0afcf31f9791e03e6496a4c0b358c98279730b"
124
+ ),
125
+ },
126
+ hardfork_tax: HardforkTax { height: 21000 },
127
+ hardfork_storage_proof: HardforkStorageProof { height: 100000 },
128
+ hardfork_oak: HardforkOak {
129
+ height: 135000,
130
+ fix_height: 139000,
131
+ genesis_timestamp: unix_timestamp(1433600000), // June 6th, 2015 @ 2:13pm UTC
132
+ },
133
+ hardfork_asic: HardforkASIC {
134
+ height: 179000,
135
+ oak_time: Duration::seconds(120000),
136
+ oak_target: BlockID::new([
137
+ 0, 0, 0, 0, 0, 0, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
138
+ 0, 0, 0, 0, 0, 0,
139
+ ]),
140
+ },
141
+ hardfork_foundation: HardforkFoundation {
142
+ height: 298000,
143
+ primary_address: address!(
144
+ "053b2def3cbdd078c19d62ce2b4f0b1a3c5e0ffbeeff01280efb1f8969b2f5bb4fdc680f0807"
145
+ ),
146
+ failsafe_address: address!(
147
+ "27c22a6c6e6645802a3b8fa0e5374657438ef12716d2205d3e866272de1b644dbabd53d6d560"
148
+ ),
149
+ },
150
+ hardfork_v2: HardforkV2 {
151
+ allow_height: 1000000,
152
+ require_height: 1025000,
153
+ },
154
+ }
155
+ }
156
+
157
+ pub fn zen() -> Self {
158
+ Network {
159
+ name: "zen".to_string(),
160
+ initial_coinbase: Currency::siacoins(300_000),
161
+ minimum_coinbase: Currency::siacoins(300_000),
162
+ initial_target: BlockID::new([
163
+ 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
164
+ 0, 0, 0, 0,
165
+ ]),
166
+ block_interval: Duration::minutes(10),
167
+ maturity_delay: 144,
168
+
169
+ hardfork_dev_addr: HardforkDevAddr {
170
+ height: 1,
171
+ old_address: Address::new([0u8; 32]),
172
+ new_address: Address::new([0u8; 32]),
173
+ },
174
+ hardfork_tax: HardforkTax { height: 2 },
175
+ hardfork_storage_proof: HardforkStorageProof { height: 5 },
176
+ hardfork_oak: HardforkOak {
177
+ height: 10,
178
+ fix_height: 12,
179
+ genesis_timestamp: unix_timestamp(1673600000), // January 13, 2023 @ 08:53 GMT
180
+ },
181
+ hardfork_asic: HardforkASIC {
182
+ height: 20,
183
+ oak_time: Duration::seconds(10000),
184
+ oak_target: BlockID::new([
185
+ 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
186
+ 0, 0, 0, 0, 0, 0,
187
+ ]),
188
+ },
189
+ hardfork_foundation: HardforkFoundation {
190
+ height: 30,
191
+ primary_address: address!(
192
+ "053b2def3cbdd078c19d62ce2b4f0b1a3c5e0ffbeeff01280efb1f8969b2f5bb4fdc680f0807"
193
+ ),
194
+ failsafe_address: Address::new([0u8; 32]),
195
+ },
196
+ hardfork_v2: HardforkV2 {
197
+ allow_height: 100000,
198
+ require_height: 102000,
199
+ },
200
+ }
201
+ }
202
+
203
+ pub fn anagami() -> Self {
204
+ Network {
205
+ name: "anagami".to_string(),
206
+ initial_coinbase: Currency::siacoins(300_000),
207
+ minimum_coinbase: Currency::siacoins(300_000),
208
+ initial_target: BlockID::new([
209
+ 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
210
+ 0, 0, 0, 0,
211
+ ]),
212
+ block_interval: Duration::minutes(10),
213
+ maturity_delay: 144,
214
+
215
+ hardfork_dev_addr: HardforkDevAddr {
216
+ height: 1,
217
+ old_address: Address::new([0u8; 32]),
218
+ new_address: Address::new([0u8; 32]),
219
+ },
220
+ hardfork_tax: HardforkTax { height: 2 },
221
+ hardfork_storage_proof: HardforkStorageProof { height: 5 },
222
+ hardfork_oak: HardforkOak {
223
+ height: 10,
224
+ fix_height: 12,
225
+ genesis_timestamp: unix_timestamp(1724284800), // August 22, 2024 @ 0:00 UTC
226
+ },
227
+ hardfork_asic: HardforkASIC {
228
+ height: 20,
229
+ oak_time: Duration::seconds(10000),
230
+ oak_target: BlockID::new([
231
+ 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
232
+ 0, 0, 0, 0, 0, 0,
233
+ ]),
234
+ },
235
+ hardfork_foundation: HardforkFoundation {
236
+ height: 30,
237
+ primary_address: address!(
238
+ "241352c83da002e61f57e96b14f3a5f8b5de22156ce83b753ea495e64f1affebae88736b2347"
239
+ ),
240
+ failsafe_address: Address::new([0u8; 32]),
241
+ },
242
+ hardfork_v2: HardforkV2 {
243
+ allow_height: 2016,
244
+ require_height: 2016 + 288,
245
+ },
246
+ }
247
+ }
248
+ }
249
+
250
+ fn has_tree_at_height(num_leaves: &u64, height: usize) -> bool {
251
+ num_leaves & (1 << height) != 0
252
+ }
253
+
254
+ #[derive(PartialEq, Debug)]
255
+ pub struct ElementAccumulator {
256
+ pub num_leaves: u64,
257
+ pub trees: [Hash256; 64],
258
+ }
259
+
260
+ impl Default for ElementAccumulator {
261
+ fn default() -> Self {
262
+ ElementAccumulator {
263
+ num_leaves: 0,
264
+ trees: [Hash256::default(); 64],
265
+ }
266
+ }
267
+ }
268
+
269
+ impl SiaEncodable for ElementAccumulator {
270
+ fn encode<W: std::io::Write>(&self, w: &mut W) -> encoding::Result<()> {
271
+ self.num_leaves.encode(w)?;
272
+ for (i, root) in self.trees.iter().enumerate() {
273
+ if has_tree_at_height(&self.num_leaves, i) {
274
+ root.encode(w)?;
275
+ }
276
+ }
277
+ Ok(())
278
+ }
279
+ }
280
+
281
+ impl SiaDecodable for ElementAccumulator {
282
+ fn decode<R: std::io::Read>(r: &mut R) -> encoding::Result<Self> {
283
+ let num_leaves = u64::decode(r)?;
284
+ let mut trees = [Hash256::default(); 64];
285
+ for (i, root) in trees.iter_mut().enumerate() {
286
+ if has_tree_at_height(&num_leaves, i) {
287
+ let h = Hash256::decode(r)?;
288
+ *root = h;
289
+ }
290
+ }
291
+ Ok(ElementAccumulator { num_leaves, trees })
292
+ }
293
+ }
294
+
295
+ impl Serialize for ElementAccumulator {
296
+ fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
297
+ let mut state = serializer.serialize_struct("ElementAccumulator", 2)?;
298
+ state.serialize_field("numLeaves", &self.num_leaves)?;
299
+ let trees: Vec<Hash256> = self
300
+ .trees
301
+ .iter()
302
+ .enumerate()
303
+ .filter(|(i, _)| has_tree_at_height(&self.num_leaves, *i))
304
+ .map(|(_, root)| *root)
305
+ .collect();
306
+ state.serialize_field("trees", &trees)?;
307
+ state.end()
308
+ }
309
+ }
310
+
311
+ impl<'de> Deserialize<'de> for ElementAccumulator {
312
+ fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
313
+ where
314
+ D: serde::Deserializer<'de>,
315
+ {
316
+ #[derive(Deserialize)]
317
+ #[serde(rename_all = "camelCase")]
318
+ struct InterElementAccumulator {
319
+ num_leaves: u64,
320
+ trees: Vec<Hash256>,
321
+ }
322
+
323
+ let inter = InterElementAccumulator::deserialize(deserializer)?;
324
+
325
+ if inter.trees.len() != inter.num_leaves.count_ones() as usize {
326
+ return Err(serde::de::Error::custom("invalid number of trees"));
327
+ }
328
+
329
+ let mut ea = ElementAccumulator {
330
+ num_leaves: inter.num_leaves,
331
+ trees: [Hash256::default(); 64],
332
+ };
333
+ let mut trees_iter = inter.trees.into_iter();
334
+ for i in 0..64 {
335
+ if has_tree_at_height(&ea.num_leaves, i) {
336
+ if let Some(root) = trees_iter.next() {
337
+ ea.trees[i] = root
338
+ } else {
339
+ return Err(serde::de::Error::custom("missing tree"));
340
+ }
341
+ }
342
+ }
343
+ Ok(ea)
344
+ }
345
+ }
346
+
347
+ /// State represents the state of the chain as of a particular block.
348
+ #[derive(PartialEq, Debug, Serialize, Deserialize)]
349
+ #[serde(rename_all = "camelCase")]
350
+ pub struct State {
351
+ pub index: ChainIndex,
352
+ #[serde(with = "crate::types::utils::timestamp_array")]
353
+ pub prev_timestamps: [DateTime<Utc>; 11],
354
+ pub depth: BlockID,
355
+ pub child_target: BlockID,
356
+ pub siafund_pool: Currency,
357
+
358
+ // Oak hardfork state
359
+ #[serde(with = "crate::types::utils::nano_second_duration")]
360
+ pub oak_time: Duration,
361
+ pub oak_target: BlockID,
362
+
363
+ // Foundation hardfork state
364
+ pub foundation_primary_address: Address,
365
+ pub foundation_failsafe_address: Address,
366
+ // v2 hardfork state
367
+ pub total_work: Work,
368
+ pub difficulty: Work,
369
+ pub oak_work: Work,
370
+ pub elements: ElementAccumulator,
371
+ pub attestations: u64,
372
+ }
373
+
374
+ impl SiaEncodable for State {
375
+ fn encode<W: std::io::Write>(&self, w: &mut W) -> crate::encoding::Result<()> {
376
+ self.index.encode(w)?;
377
+ let timestamps_count = if self.index.child_height() < 11 {
378
+ self.index.child_height() as usize
379
+ } else {
380
+ 11
381
+ };
382
+ self.prev_timestamps
383
+ .iter()
384
+ .take(timestamps_count)
385
+ .for_each(|ts| ts.encode(w).unwrap());
386
+ self.depth.encode(w)?;
387
+ self.child_target.encode(w)?;
388
+ self.siafund_pool.encode(w)?;
389
+ self.oak_time.encode(w)?;
390
+ self.oak_target.encode(w)?;
391
+ self.foundation_primary_address.encode(w)?;
392
+ self.foundation_failsafe_address.encode(w)?;
393
+ self.total_work.encode(w)?;
394
+ self.difficulty.encode(w)?;
395
+ self.oak_work.encode(w)?;
396
+ self.elements.encode(w)?;
397
+ self.attestations.encode(w)?;
398
+ Ok(())
399
+ }
400
+ }
401
+
402
+ impl SiaDecodable for State {
403
+ fn decode<R: std::io::Read>(r: &mut R) -> crate::encoding::Result<Self> {
404
+ let index = ChainIndex::decode(r)?;
405
+ let timestamps_count = if index.child_height() < 11 {
406
+ index.child_height() as usize
407
+ } else {
408
+ 11
409
+ };
410
+ let mut prev_timestamps = [DateTime::UNIX_EPOCH; 11];
411
+ prev_timestamps[..timestamps_count]
412
+ .iter_mut()
413
+ .try_for_each(|ts| -> encoding::Result<()> {
414
+ *ts = DateTime::<Utc>::decode(r)?;
415
+ Ok(())
416
+ })?;
417
+ Ok(State {
418
+ index,
419
+ prev_timestamps,
420
+ depth: BlockID::decode(r)?,
421
+ child_target: BlockID::decode(r)?,
422
+ siafund_pool: Currency::decode(r)?,
423
+ oak_time: Duration::decode(r)?,
424
+ oak_target: BlockID::decode(r)?,
425
+ foundation_primary_address: Address::decode(r)?,
426
+ foundation_failsafe_address: Address::decode(r)?,
427
+ total_work: Work::decode(r)?,
428
+ difficulty: Work::decode(r)?,
429
+ oak_work: Work::decode(r)?,
430
+ elements: ElementAccumulator::decode(r)?,
431
+ attestations: u64::decode(r)?,
432
+ })
433
+ }
434
+ }
435
+
436
+ /// ChainState contains the network parameters and the state of the chain.
437
+ /// It is used to determine the consensus rules in effect for a particular block.
438
+ #[derive(PartialEq, Debug, Serialize, Deserialize)]
439
+ pub struct ChainState {
440
+ pub network: Network,
441
+ pub state: State,
442
+ }
443
+
444
+ impl ChainState {
445
+ /// child_height returns the height of the next block
446
+ pub fn child_height(&self) -> u64 {
447
+ self.state.index.child_height()
448
+ }
449
+
450
+ /// block_reward returns the reward for mining a child block
451
+ pub fn block_reward(&self) -> Currency {
452
+ let reward = self
453
+ .network
454
+ .initial_coinbase
455
+ .checked_sub(Currency::siacoins(self.child_height()));
456
+
457
+ match reward {
458
+ Some(reward) if reward >= self.network.minimum_coinbase => reward,
459
+ _ => self.network.minimum_coinbase,
460
+ }
461
+ }
462
+
463
+ /// maturity_height is the height at which outputs created by the child block will "mature" (become spendable).
464
+ pub fn maturity_height(&self) -> u64 {
465
+ self.child_height() + self.network.maturity_delay
466
+ }
467
+
468
+ /// siafund_count is the number of siafunds in existence
469
+ pub fn siafund_count(&self) -> u64 {
470
+ 10000
471
+ }
472
+
473
+ /// ancestor_depth is used to determine the target timestamp in the pre-Oak difficulty adjustment algorithm
474
+ pub fn ancestor_depth(&self) -> u64 {
475
+ 1000
476
+ }
477
+
478
+ // blocks_per_month estimates the number of blocks expected in a calendar month
479
+ pub fn blocks_per_month(&self) -> u64 {
480
+ (Duration::days(365).num_milliseconds()
481
+ / 12
482
+ / self.network.block_interval.num_milliseconds()) as u64
483
+ }
484
+
485
+ /// foundation_subsidy returns the Foundation subsidy output for the child block.
486
+ /// If no subsidy is due, returns None.
487
+ pub fn foundation_subsidy(&self) -> Option<SiacoinOutput> {
488
+ if self.child_height() < self.network.hardfork_foundation.height {
489
+ return None;
490
+ }
491
+ let blocks_per_month = self.blocks_per_month();
492
+ if !(self.child_height() - self.network.hardfork_foundation.height)
493
+ .is_multiple_of(blocks_per_month)
494
+ {
495
+ return None;
496
+ }
497
+
498
+ let subsidy_per_block = Currency::siacoins(30000);
499
+ Some(SiacoinOutput {
500
+ value: if self.child_height() == self.network.hardfork_foundation.height {
501
+ subsidy_per_block * Currency::new(12)
502
+ } else {
503
+ subsidy_per_block
504
+ },
505
+ address: self.network.hardfork_foundation.primary_address.clone(),
506
+ })
507
+ }
508
+
509
+ pub fn replay_prefix(&self) -> &[u8] {
510
+ if self.state.index.height >= self.network.hardfork_v2.allow_height {
511
+ return &[2];
512
+ } else if self.state.index.height >= self.network.hardfork_foundation.height {
513
+ return &[1];
514
+ } else if self.state.index.height >= self.network.hardfork_asic.height {
515
+ return &[0];
516
+ }
517
+ &[]
518
+ }
519
+
520
+ pub fn nonce_factor(&self) -> u64 {
521
+ if self.child_height() < self.network.hardfork_asic.height {
522
+ return 1;
523
+ }
524
+ 1009
525
+ }
526
+
527
+ pub fn max_block_weight(&self) -> u64 {
528
+ 2_000_000
529
+ }
530
+ }
531
+
532
+ #[cfg(test)]
533
+ mod tests {
534
+ use crate::{block_id, hash_256};
535
+
536
+ use super::*;
537
+ use chrono::FixedOffset;
538
+ use serde_json;
539
+
540
+ #[test]
541
+ fn test_serialize_network() {
542
+ let test_cases = vec![
543
+ (
544
+ Network::anagami(),
545
+ "{\"name\":\"anagami\",\"initialCoinbase\":\"300000000000000000000000000000\",\"minimumCoinbase\":\"300000000000000000000000000000\",\"initialTarget\":\"0000000100000000000000000000000000000000000000000000000000000000\",\"blockInterval\":600000000000,\"maturityDelay\":144,\"hardforkDevAddr\":{\"height\":1,\"oldAddress\":\"000000000000000000000000000000000000000000000000000000000000000089eb0d6a8a69\",\"newAddress\":\"000000000000000000000000000000000000000000000000000000000000000089eb0d6a8a69\"},\"hardforkTax\":{\"height\":2},\"hardforkStorageProof\":{\"height\":5},\"hardforkOak\":{\"height\":10,\"fixHeight\":12,\"genesisTimestamp\":\"2024-08-22T00:00:00Z\"},\"hardforkASIC\":{\"height\":20,\"oakTime\":10000000000000,\"oakTarget\":\"0000000100000000000000000000000000000000000000000000000000000000\"},\"hardforkFoundation\":{\"height\":30,\"primaryAddress\":\"241352c83da002e61f57e96b14f3a5f8b5de22156ce83b753ea495e64f1affebae88736b2347\",\"failsafeAddress\":\"000000000000000000000000000000000000000000000000000000000000000089eb0d6a8a69\"},\"hardforkV2\":{\"allowHeight\":2016,\"requireHeight\":2304}}",
546
+ ),
547
+ (
548
+ Network::mainnet(),
549
+ "{\"name\":\"mainnet\",\"initialCoinbase\":\"300000000000000000000000000000\",\"minimumCoinbase\":\"30000000000000000000000000000\",\"initialTarget\":\"0000000020000000000000000000000000000000000000000000000000000000\",\"blockInterval\":600000000000,\"maturityDelay\":144,\"hardforkDevAddr\":{\"height\":10000,\"oldAddress\":\"7d0c44f7664e2d34e53efde0661a6f628ec9264785ae8e3cd7c973e8d190c3c97b5e3ecbc567\",\"newAddress\":\"f371c70bce9eb8979cd5099f599ec4e4fcb14e0afcf31f9791e03e6496a4c0b358c98279730b\"},\"hardforkTax\":{\"height\":21000},\"hardforkStorageProof\":{\"height\":100000},\"hardforkOak\":{\"height\":135000,\"fixHeight\":139000,\"genesisTimestamp\":\"2015-06-06T14:13:20Z\"},\"hardforkASIC\":{\"height\":179000,\"oakTime\":120000000000000,\"oakTarget\":\"0000000000000000200000000000000000000000000000000000000000000000\"},\"hardforkFoundation\":{\"height\":298000,\"primaryAddress\":\"053b2def3cbdd078c19d62ce2b4f0b1a3c5e0ffbeeff01280efb1f8969b2f5bb4fdc680f0807\",\"failsafeAddress\":\"27c22a6c6e6645802a3b8fa0e5374657438ef12716d2205d3e866272de1b644dbabd53d6d560\"},\"hardforkV2\":{\"allowHeight\":1000000,\"requireHeight\":1025000}}",
550
+ ),
551
+ (
552
+ Network::zen(),
553
+ "{\"name\":\"zen\",\"initialCoinbase\":\"300000000000000000000000000000\",\"minimumCoinbase\":\"300000000000000000000000000000\",\"initialTarget\":\"0000000100000000000000000000000000000000000000000000000000000000\",\"blockInterval\":600000000000,\"maturityDelay\":144,\"hardforkDevAddr\":{\"height\":1,\"oldAddress\":\"000000000000000000000000000000000000000000000000000000000000000089eb0d6a8a69\",\"newAddress\":\"000000000000000000000000000000000000000000000000000000000000000089eb0d6a8a69\"},\"hardforkTax\":{\"height\":2},\"hardforkStorageProof\":{\"height\":5},\"hardforkOak\":{\"height\":10,\"fixHeight\":12,\"genesisTimestamp\":\"2023-01-13T08:53:20Z\"},\"hardforkASIC\":{\"height\":20,\"oakTime\":10000000000000,\"oakTarget\":\"0000000100000000000000000000000000000000000000000000000000000000\"},\"hardforkFoundation\":{\"height\":30,\"primaryAddress\":\"053b2def3cbdd078c19d62ce2b4f0b1a3c5e0ffbeeff01280efb1f8969b2f5bb4fdc680f0807\",\"failsafeAddress\":\"000000000000000000000000000000000000000000000000000000000000000089eb0d6a8a69\"},\"hardforkV2\":{\"allowHeight\":100000,\"requireHeight\":102000}}",
554
+ ),
555
+ ];
556
+
557
+ for (network, expected) in test_cases {
558
+ let serialized = serde_json::to_string(&network).unwrap();
559
+ assert_eq!(expected, serialized, "{} failed", network.name);
560
+ let deserialized: Network = serde_json::from_str(&serialized).unwrap();
561
+ assert_eq!(network, deserialized, "{} failed", network.name);
562
+ }
563
+ }
564
+
565
+ #[test]
566
+ fn test_serialize_state() {
567
+ let s = State {
568
+ index: ChainIndex {
569
+ height: 0,
570
+ id: block_id!("0000000000000000000000000000000000000000000000000000000000000000"),
571
+ },
572
+ prev_timestamps: [DateTime::UNIX_EPOCH; 11],
573
+ depth: block_id!("0000000000000000000000000000000000000000000000000000000000000000"),
574
+ child_target: block_id!(
575
+ "0000000000000000000000000000000000000000000000000000000000000000"
576
+ ),
577
+ siafund_pool: Currency::zero(),
578
+ oak_time: Duration::zero(),
579
+ oak_target: block_id!(
580
+ "0000000000000000000000000000000000000000000000000000000000000000"
581
+ ),
582
+ foundation_primary_address: address!(
583
+ "000000000000000000000000000000000000000000000000000000000000000089eb0d6a8a69"
584
+ ),
585
+ foundation_failsafe_address: address!(
586
+ "000000000000000000000000000000000000000000000000000000000000000089eb0d6a8a69"
587
+ ),
588
+ total_work: Work::zero(),
589
+ difficulty: Work::zero(),
590
+ oak_work: Work::zero(),
591
+ elements: ElementAccumulator {
592
+ num_leaves: 0,
593
+ trees: [Hash256::default(); 64],
594
+ },
595
+ attestations: 0,
596
+ };
597
+
598
+ const EMPTY_JSON_STR: &str = "{\"index\":{\"height\":0,\"id\":\"0000000000000000000000000000000000000000000000000000000000000000\"},\"prevTimestamps\":[\"1970-01-01T00:00:00+00:00\",\"1970-01-01T00:00:00+00:00\",\"1970-01-01T00:00:00+00:00\",\"1970-01-01T00:00:00+00:00\",\"1970-01-01T00:00:00+00:00\",\"1970-01-01T00:00:00+00:00\",\"1970-01-01T00:00:00+00:00\",\"1970-01-01T00:00:00+00:00\",\"1970-01-01T00:00:00+00:00\",\"1970-01-01T00:00:00+00:00\",\"1970-01-01T00:00:00+00:00\"],\"depth\":\"0000000000000000000000000000000000000000000000000000000000000000\",\"childTarget\":\"0000000000000000000000000000000000000000000000000000000000000000\",\"siafundPool\":\"0\",\"oakTime\":0,\"oakTarget\":\"0000000000000000000000000000000000000000000000000000000000000000\",\"foundationPrimaryAddress\":\"000000000000000000000000000000000000000000000000000000000000000089eb0d6a8a69\",\"foundationFailsafeAddress\":\"000000000000000000000000000000000000000000000000000000000000000089eb0d6a8a69\",\"totalWork\":\"0\",\"difficulty\":\"0\",\"oakWork\":\"0\",\"elements\":{\"numLeaves\":0,\"trees\":[]},\"attestations\":0}";
599
+
600
+ let serialized = serde_json::to_string(&s).unwrap();
601
+ assert_eq!(EMPTY_JSON_STR, serialized);
602
+ let deserialized: State = serde_json::from_str(&serialized).unwrap();
603
+ assert_eq!(s, deserialized);
604
+
605
+ const EMPTY_BINARY_STR: &str = "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000";
606
+
607
+ let mut serialized = Vec::new();
608
+ s.encode(&mut serialized).unwrap();
609
+ assert_eq!(EMPTY_BINARY_STR, hex::encode(serialized.clone()));
610
+ let deserialized = State::decode(&mut &serialized[..]).unwrap();
611
+ assert_eq!(s, deserialized);
612
+
613
+ let s = State {
614
+ index: ChainIndex {
615
+ height: 16173070238323073115,
616
+ id: block_id!("54b6800181215b654a2b64e8a0f39da6d5ad20f4e6eda87d50d36e93efd9cdb9"),
617
+ },
618
+ prev_timestamps: [
619
+ DateTime::<FixedOffset>::parse_from_rfc3339("2167-03-18T17:08:40-07:00")
620
+ .unwrap()
621
+ .to_utc(),
622
+ DateTime::<FixedOffset>::parse_from_rfc3339("1971-03-30T07:40:44-08:00")
623
+ .unwrap()
624
+ .to_utc(),
625
+ DateTime::<FixedOffset>::parse_from_rfc3339("2226-11-12T19:51:30-08:00")
626
+ .unwrap()
627
+ .to_utc(),
628
+ DateTime::<FixedOffset>::parse_from_rfc3339("2013-09-10T15:07:20-07:00")
629
+ .unwrap()
630
+ .to_utc(),
631
+ DateTime::<FixedOffset>::parse_from_rfc3339("2230-05-18T20:13:07-07:00")
632
+ .unwrap()
633
+ .to_utc(),
634
+ DateTime::<FixedOffset>::parse_from_rfc3339("1983-10-27T20:37:21-07:00")
635
+ .unwrap()
636
+ .to_utc(),
637
+ DateTime::<FixedOffset>::parse_from_rfc3339("2068-03-31T10:25:10-07:00")
638
+ .unwrap()
639
+ .to_utc(),
640
+ DateTime::<FixedOffset>::parse_from_rfc3339("2159-06-29T18:46:49-07:00")
641
+ .unwrap()
642
+ .to_utc(),
643
+ DateTime::<FixedOffset>::parse_from_rfc3339("2089-05-02T23:45:50-07:00")
644
+ .unwrap()
645
+ .to_utc(),
646
+ DateTime::<FixedOffset>::parse_from_rfc3339("2073-02-27T00:01:11-08:00")
647
+ .unwrap()
648
+ .to_utc(),
649
+ DateTime::<FixedOffset>::parse_from_rfc3339("2005-07-10T11:50:37-07:00")
650
+ .unwrap()
651
+ .to_utc(),
652
+ ],
653
+ depth: block_id!("fb66f6dd0517bd80a57c6fc1dd186eeb25a5f7dc550adc94a996731734f4a478"),
654
+ child_target: block_id!(
655
+ "188d65bc61f7398757be167c70139bc79e2f387551bd0338b81f3938850033c2"
656
+ ),
657
+ siafund_pool: Currency::new(184937863921143879963732603265618430015),
658
+ oak_time: Duration::nanoseconds(5097318764767379519),
659
+ oak_target: block_id!(
660
+ "5e7e960e017d5772f3341bd8d80fc797de245c760a3f9e84f4da66f9e0ee95aa"
661
+ ),
662
+ foundation_primary_address: address!(
663
+ "95ae9eb00188ade3367e57e5bdc522a16e95a8d28e1b940d2d128273aa7a833001a060dec431"
664
+ ),
665
+ foundation_failsafe_address: address!(
666
+ "cfb49736296ae52965fd7d66d55720eeadfc2be586db65699050bce175c56056d3fbc1803e15"
667
+ ),
668
+ total_work: Work::from_dec_str(
669
+ "74729819229046869798018345563024899883189146032533830356652983039509219541660",
670
+ )
671
+ .unwrap(),
672
+ difficulty: Work::from_dec_str(
673
+ "65194889020289389878379369533805235500859175566680960159551424936807420310662",
674
+ )
675
+ .unwrap(),
676
+ oak_work: Work::from_dec_str(
677
+ "57256974569838769713335634640292932580615837804690422146878608831130432685755",
678
+ )
679
+ .unwrap(),
680
+ elements: ElementAccumulator {
681
+ num_leaves: 4899977171010125798,
682
+ trees: [
683
+ hash_256!("0000000000000000000000000000000000000000000000000000000000000000"),
684
+ hash_256!("78a9fabda865dafcaf474d48bdb1272595513cf92290917392ff58ca8bea591a"),
685
+ hash_256!("e6a5ea278d90592e0518fbf2e83f41507486fe57e8e4ffbe152f13250df696bf"),
686
+ hash_256!("0000000000000000000000000000000000000000000000000000000000000000"),
687
+ hash_256!("0000000000000000000000000000000000000000000000000000000000000000"),
688
+ hash_256!("2488cae3f7046f8b04aec217a09358db22d8ae36f883d1ccae9382edca79c54e"),
689
+ hash_256!("e498f1adbe88c58bc9dabf487437b8d191a78fbb3d8cfe19a4c1759ae232b4f4"),
690
+ hash_256!("96130e35228422970057745ef4b92d285434c25187c44110922554d0ae040678"),
691
+ hash_256!("44f29b39d6e4f509d5d41834db4fd6a831ccca33bb46185a5ad01f2789581337"),
692
+ hash_256!("75f0b42f9d291c4ff4e57f403893e0ca18fdc64f0723e0f29b6aeed834db1ac2"),
693
+ hash_256!("4ce129d69c69971497c556d9eeec0de8c1dd9cc4b0750be9fffd9ec3226ce7a3"),
694
+ hash_256!("f3321bf48aed89100db44b3080f3f350d10b6de213527b19ad57bdd1cd47576a"),
695
+ hash_256!("724c8bf4c8459625190ae18b2fc1d9353d2d3b34c80d4d4fbcd48258c9a11c97"),
696
+ hash_256!("062b2371de9dfad15931a1e72c46afe492ad697447680ea43300ed516bcc2742"),
697
+ hash_256!("b23ca0a83b0367755e2c53c1f7ed9e6d372c220ae0f344082cf5d52c40287893"),
698
+ hash_256!("9b1b446dd599fd5dab08e83738b92651d8aaa7be072db313d237c68ce1094ea1"),
699
+ hash_256!("0000000000000000000000000000000000000000000000000000000000000000"),
700
+ hash_256!("0000000000000000000000000000000000000000000000000000000000000000"),
701
+ hash_256!("a03c962c184055ccbf7a42c9a13a0d4c38125535a830832a6fff3029d6deada3"),
702
+ hash_256!("0000000000000000000000000000000000000000000000000000000000000000"),
703
+ hash_256!("df5d9e1e3a220d2429f9064adecb86ecae916619c93e17d237b5972692e558fd"),
704
+ hash_256!("0000000000000000000000000000000000000000000000000000000000000000"),
705
+ hash_256!("0000000000000000000000000000000000000000000000000000000000000000"),
706
+ hash_256!("2d6315b7a91d62bd31e4738259f56f58075bd14ee2f1e2625738f506a7564176"),
707
+ hash_256!("26b1d48ab8c3f0707bd5afdf4a3ef757abc9b6a0be75b8a3cecbcd5994473a72"),
708
+ hash_256!("0000000000000000000000000000000000000000000000000000000000000000"),
709
+ hash_256!("f897c92aca8d6ef46a41a3a50aff0527bd09be029355d28c2360ec9cb309b1ae"),
710
+ hash_256!("f80ff7cbcad8c465278a59588a3a0d000cc3130e96fb56d257229c1a50d93125"),
711
+ hash_256!("7a84f42433ecd9352e2ffd8bdc8556c87ec93697cf4c4873d4ab51d2b85c44c1"),
712
+ hash_256!("0000000000000000000000000000000000000000000000000000000000000000"),
713
+ hash_256!("0000000000000000000000000000000000000000000000000000000000000000"),
714
+ hash_256!("00c03e0af90a26d0a4bb4b243f99b2d361de2412d82f357f6224eceb2f19c142"),
715
+ hash_256!("0000000000000000000000000000000000000000000000000000000000000000"),
716
+ hash_256!("e0a8f77abd726e928580656d7ab49dc276603e936e04b9caf53a2a27338e3cd1"),
717
+ hash_256!("e376ebd2f0c93013cf6c856fb76e7b60e64a300a9a4b839844074cac4da42b8d"),
718
+ hash_256!("0000000000000000000000000000000000000000000000000000000000000000"),
719
+ hash_256!("0000000000000000000000000000000000000000000000000000000000000000"),
720
+ hash_256!("0000000000000000000000000000000000000000000000000000000000000000"),
721
+ hash_256!("5fcc77f29cfdb51aac9fff250e1ee7607457ce5a280e946150931d793272593a"),
722
+ hash_256!("0000000000000000000000000000000000000000000000000000000000000000"),
723
+ hash_256!("ad34b2dce6a7136584c5ffea74c66e5613593dddac9eb666ff6a6aef42386968"),
724
+ hash_256!("3d1afa6b931fea014211bb6b08d9508389dd0a9c47a25670ca110bcc8ce8ead1"),
725
+ hash_256!("df427b938f6ef07cd67da1ab11ad8fb4e6b0a97c03325c1fc8b1c3b0c4b8f7f4"),
726
+ hash_256!("0000000000000000000000000000000000000000000000000000000000000000"),
727
+ hash_256!("8c3d435fdb6ee44e26155c116a86f4dc2b54b05becb08777a63e1d1ad7c3cbc2"),
728
+ hash_256!("11671f5bd2856de1b4925ee0b82f9cda6179db132c9930431d26f0ccdbb8a822"),
729
+ hash_256!("0000000000000000000000000000000000000000000000000000000000000000"),
730
+ hash_256!("0000000000000000000000000000000000000000000000000000000000000000"),
731
+ hash_256!("0000000000000000000000000000000000000000000000000000000000000000"),
732
+ hash_256!("0000000000000000000000000000000000000000000000000000000000000000"),
733
+ hash_256!("0000000000000000000000000000000000000000000000000000000000000000"),
734
+ hash_256!("0000000000000000000000000000000000000000000000000000000000000000"),
735
+ hash_256!("0000000000000000000000000000000000000000000000000000000000000000"),
736
+ hash_256!("0000000000000000000000000000000000000000000000000000000000000000"),
737
+ hash_256!("0000000000000000000000000000000000000000000000000000000000000000"),
738
+ hash_256!("0000000000000000000000000000000000000000000000000000000000000000"),
739
+ hash_256!("0000000000000000000000000000000000000000000000000000000000000000"),
740
+ hash_256!("0000000000000000000000000000000000000000000000000000000000000000"),
741
+ hash_256!("19dcd3ac59669e10420b36d4e588206ae123a0c8ae64b20e1ede697efc556291"),
742
+ hash_256!("0000000000000000000000000000000000000000000000000000000000000000"),
743
+ hash_256!("0000000000000000000000000000000000000000000000000000000000000000"),
744
+ hash_256!("0000000000000000000000000000000000000000000000000000000000000000"),
745
+ hash_256!("65542a8b2c1bca8d78d6517357853c1d54f6b53f04a8327f28ae2d5d022c5597"),
746
+ hash_256!("0000000000000000000000000000000000000000000000000000000000000000"),
747
+ ],
748
+ },
749
+ attestations: 4796228701811883082,
750
+ };
751
+
752
+ const JSON_STR: &str = "{\"index\":{\"height\":16173070238323073115,\"id\":\"54b6800181215b654a2b64e8a0f39da6d5ad20f4e6eda87d50d36e93efd9cdb9\"},\"prevTimestamps\":[\"2167-03-19T00:08:40+00:00\",\"1971-03-30T15:40:44+00:00\",\"2226-11-13T03:51:30+00:00\",\"2013-09-10T22:07:20+00:00\",\"2230-05-19T03:13:07+00:00\",\"1983-10-28T03:37:21+00:00\",\"2068-03-31T17:25:10+00:00\",\"2159-06-30T01:46:49+00:00\",\"2089-05-03T06:45:50+00:00\",\"2073-02-27T08:01:11+00:00\",\"2005-07-10T18:50:37+00:00\"],\"depth\":\"fb66f6dd0517bd80a57c6fc1dd186eeb25a5f7dc550adc94a996731734f4a478\",\"childTarget\":\"188d65bc61f7398757be167c70139bc79e2f387551bd0338b81f3938850033c2\",\"siafundPool\":\"184937863921143879963732603265618430015\",\"oakTime\":5097318764767379519,\"oakTarget\":\"5e7e960e017d5772f3341bd8d80fc797de245c760a3f9e84f4da66f9e0ee95aa\",\"foundationPrimaryAddress\":\"95ae9eb00188ade3367e57e5bdc522a16e95a8d28e1b940d2d128273aa7a833001a060dec431\",\"foundationFailsafeAddress\":\"cfb49736296ae52965fd7d66d55720eeadfc2be586db65699050bce175c56056d3fbc1803e15\",\"totalWork\":\"74729819229046869798018345563024899883189146032533830356652983039509219541660\",\"difficulty\":\"65194889020289389878379369533805235500859175566680960159551424936807420310662\",\"oakWork\":\"57256974569838769713335634640292932580615837804690422146878608831130432685755\",\"elements\":{\"numLeaves\":4899977171010125798,\"trees\":[\"78a9fabda865dafcaf474d48bdb1272595513cf92290917392ff58ca8bea591a\",\"e6a5ea278d90592e0518fbf2e83f41507486fe57e8e4ffbe152f13250df696bf\",\"2488cae3f7046f8b04aec217a09358db22d8ae36f883d1ccae9382edca79c54e\",\"e498f1adbe88c58bc9dabf487437b8d191a78fbb3d8cfe19a4c1759ae232b4f4\",\"96130e35228422970057745ef4b92d285434c25187c44110922554d0ae040678\",\"44f29b39d6e4f509d5d41834db4fd6a831ccca33bb46185a5ad01f2789581337\",\"75f0b42f9d291c4ff4e57f403893e0ca18fdc64f0723e0f29b6aeed834db1ac2\",\"4ce129d69c69971497c556d9eeec0de8c1dd9cc4b0750be9fffd9ec3226ce7a3\",\"f3321bf48aed89100db44b3080f3f350d10b6de213527b19ad57bdd1cd47576a\",\"724c8bf4c8459625190ae18b2fc1d9353d2d3b34c80d4d4fbcd48258c9a11c97\",\"062b2371de9dfad15931a1e72c46afe492ad697447680ea43300ed516bcc2742\",\"b23ca0a83b0367755e2c53c1f7ed9e6d372c220ae0f344082cf5d52c40287893\",\"9b1b446dd599fd5dab08e83738b92651d8aaa7be072db313d237c68ce1094ea1\",\"a03c962c184055ccbf7a42c9a13a0d4c38125535a830832a6fff3029d6deada3\",\"df5d9e1e3a220d2429f9064adecb86ecae916619c93e17d237b5972692e558fd\",\"2d6315b7a91d62bd31e4738259f56f58075bd14ee2f1e2625738f506a7564176\",\"26b1d48ab8c3f0707bd5afdf4a3ef757abc9b6a0be75b8a3cecbcd5994473a72\",\"f897c92aca8d6ef46a41a3a50aff0527bd09be029355d28c2360ec9cb309b1ae\",\"f80ff7cbcad8c465278a59588a3a0d000cc3130e96fb56d257229c1a50d93125\",\"7a84f42433ecd9352e2ffd8bdc8556c87ec93697cf4c4873d4ab51d2b85c44c1\",\"00c03e0af90a26d0a4bb4b243f99b2d361de2412d82f357f6224eceb2f19c142\",\"e0a8f77abd726e928580656d7ab49dc276603e936e04b9caf53a2a27338e3cd1\",\"e376ebd2f0c93013cf6c856fb76e7b60e64a300a9a4b839844074cac4da42b8d\",\"5fcc77f29cfdb51aac9fff250e1ee7607457ce5a280e946150931d793272593a\",\"ad34b2dce6a7136584c5ffea74c66e5613593dddac9eb666ff6a6aef42386968\",\"3d1afa6b931fea014211bb6b08d9508389dd0a9c47a25670ca110bcc8ce8ead1\",\"df427b938f6ef07cd67da1ab11ad8fb4e6b0a97c03325c1fc8b1c3b0c4b8f7f4\",\"8c3d435fdb6ee44e26155c116a86f4dc2b54b05becb08777a63e1d1ad7c3cbc2\",\"11671f5bd2856de1b4925ee0b82f9cda6179db132c9930431d26f0ccdbb8a822\",\"19dcd3ac59669e10420b36d4e588206ae123a0c8ae64b20e1ede697efc556291\",\"65542a8b2c1bca8d78d6517357853c1d54f6b53f04a8327f28ae2d5d022c5597\"]},\"attestations\":4796228701811883082}";
753
+
754
+ let serialized = serde_json::to_string(&s).unwrap();
755
+ assert_eq!(JSON_STR, serialized);
756
+ let deserialized: State = serde_json::from_str(&serialized).unwrap();
757
+ assert_eq!(s, deserialized);
758
+
759
+ const BINARY_STR: &str = "5b60b072b14972e054b6800181215b654a2b64e8a0f39da6d5ad20f4e6eda87d50d36e93efd9cdb9086ff17201000000fc13560200000000420d26e30100000018982f5200000000c378c1e901000000f146ff1900000000f6f6ccb80000000089116d64010000009eb377e000000000c79509c200000000fd6dd14200000000fb66f6dd0517bd80a57c6fc1dd186eeb25a5f7dc550adc94a996731734f4a478188d65bc61f7398757be167c70139bc79e2f387551bd0338b81f3938850033c23f48064ca312d68970452ce1abbc218b3f80e4e86850bd465e7e960e017d5772f3341bd8d80fc797de245c760a3f9e84f4da66f9e0ee95aa95ae9eb00188ade3367e57e5bdc522a16e95a8d28e1b940d2d128273aa7a8330cfb49736296ae52965fd7d66d55720eeadfc2be586db65699050bce175c56056a537942b3dcc3fb364ca2cdd33416f2ad78e92cd50081c59c5c9f67c9a64829c9022ffe17973176b934cf5ab04186591c97b2b86f290de9dace84dac6fe2b4867e964c967126699e34e7e3114292eca3140a6f0a94e76e39c047b064bfdbc6bbe6ff949d4637004478a9fabda865dafcaf474d48bdb1272595513cf92290917392ff58ca8bea591ae6a5ea278d90592e0518fbf2e83f41507486fe57e8e4ffbe152f13250df696bf2488cae3f7046f8b04aec217a09358db22d8ae36f883d1ccae9382edca79c54ee498f1adbe88c58bc9dabf487437b8d191a78fbb3d8cfe19a4c1759ae232b4f496130e35228422970057745ef4b92d285434c25187c44110922554d0ae04067844f29b39d6e4f509d5d41834db4fd6a831ccca33bb46185a5ad01f278958133775f0b42f9d291c4ff4e57f403893e0ca18fdc64f0723e0f29b6aeed834db1ac24ce129d69c69971497c556d9eeec0de8c1dd9cc4b0750be9fffd9ec3226ce7a3f3321bf48aed89100db44b3080f3f350d10b6de213527b19ad57bdd1cd47576a724c8bf4c8459625190ae18b2fc1d9353d2d3b34c80d4d4fbcd48258c9a11c97062b2371de9dfad15931a1e72c46afe492ad697447680ea43300ed516bcc2742b23ca0a83b0367755e2c53c1f7ed9e6d372c220ae0f344082cf5d52c402878939b1b446dd599fd5dab08e83738b92651d8aaa7be072db313d237c68ce1094ea1a03c962c184055ccbf7a42c9a13a0d4c38125535a830832a6fff3029d6deada3df5d9e1e3a220d2429f9064adecb86ecae916619c93e17d237b5972692e558fd2d6315b7a91d62bd31e4738259f56f58075bd14ee2f1e2625738f506a756417626b1d48ab8c3f0707bd5afdf4a3ef757abc9b6a0be75b8a3cecbcd5994473a72f897c92aca8d6ef46a41a3a50aff0527bd09be029355d28c2360ec9cb309b1aef80ff7cbcad8c465278a59588a3a0d000cc3130e96fb56d257229c1a50d931257a84f42433ecd9352e2ffd8bdc8556c87ec93697cf4c4873d4ab51d2b85c44c100c03e0af90a26d0a4bb4b243f99b2d361de2412d82f357f6224eceb2f19c142e0a8f77abd726e928580656d7ab49dc276603e936e04b9caf53a2a27338e3cd1e376ebd2f0c93013cf6c856fb76e7b60e64a300a9a4b839844074cac4da42b8d5fcc77f29cfdb51aac9fff250e1ee7607457ce5a280e946150931d793272593aad34b2dce6a7136584c5ffea74c66e5613593dddac9eb666ff6a6aef423869683d1afa6b931fea014211bb6b08d9508389dd0a9c47a25670ca110bcc8ce8ead1df427b938f6ef07cd67da1ab11ad8fb4e6b0a97c03325c1fc8b1c3b0c4b8f7f48c3d435fdb6ee44e26155c116a86f4dc2b54b05becb08777a63e1d1ad7c3cbc211671f5bd2856de1b4925ee0b82f9cda6179db132c9930431d26f0ccdbb8a82219dcd3ac59669e10420b36d4e588206ae123a0c8ae64b20e1ede697efc55629165542a8b2c1bca8d78d6517357853c1d54f6b53f04a8327f28ae2d5d022c55974abc07c197a08f42";
760
+
761
+ let mut serialized = Vec::new();
762
+ s.encode(&mut serialized).unwrap();
763
+ assert_eq!(BINARY_STR, hex::encode(serialized.clone()));
764
+ let deserialized = State::decode(&mut &serialized[..]).unwrap();
765
+ assert_eq!(s, deserialized);
766
+ }
767
+ }