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,677 @@
|
|
|
1
|
+
use core::fmt;
|
|
2
|
+
|
|
3
|
+
use crate::encoding_async::{AsyncSiaDecodable, AsyncSiaDecode, AsyncSiaEncodable, AsyncSiaEncode};
|
|
4
|
+
use blake2b_simd::Params;
|
|
5
|
+
use chrono::{DateTime, Utc};
|
|
6
|
+
use serde::{Deserialize, Serialize};
|
|
7
|
+
use thiserror::Error;
|
|
8
|
+
|
|
9
|
+
use crate::encoding::{
|
|
10
|
+
self, SiaDecodable, SiaDecode, SiaEncodable, SiaEncode, V1SiaDecodable, V1SiaDecode,
|
|
11
|
+
V1SiaEncodable, V1SiaEncode,
|
|
12
|
+
};
|
|
13
|
+
use crate::macros::impl_hash_id;
|
|
14
|
+
use crate::types::currency::Currency;
|
|
15
|
+
use crate::types::v1;
|
|
16
|
+
|
|
17
|
+
use super::{Specifier, specifier};
|
|
18
|
+
|
|
19
|
+
impl_hash_id!(Hash256);
|
|
20
|
+
impl_hash_id!(SiacoinOutputID);
|
|
21
|
+
impl_hash_id!(AttestationID);
|
|
22
|
+
|
|
23
|
+
impl_hash_id!(SiafundOutputID);
|
|
24
|
+
|
|
25
|
+
impl SiafundOutputID {
|
|
26
|
+
/// claim_output_id returns the SiacoinOutputID for the claim output of the siafund output
|
|
27
|
+
pub fn claim_output_id(&self) -> SiacoinOutputID {
|
|
28
|
+
let mut state = Params::new().hash_length(32).to_state();
|
|
29
|
+
state.update(self.as_ref());
|
|
30
|
+
state.finalize().into()
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
pub fn v2_claim_output_id(&self) -> SiacoinOutputID {
|
|
34
|
+
let mut state = Params::new().hash_length(32).to_state();
|
|
35
|
+
state.update(b"sia/id/v2siacoinclaimoutput|");
|
|
36
|
+
state.update(self.as_ref());
|
|
37
|
+
state.finalize().into()
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
impl_hash_id!(BlockID);
|
|
42
|
+
|
|
43
|
+
impl BlockID {
|
|
44
|
+
const FOUNDATION_OUTPUT_ID_PREFIX: Specifier = specifier!("foundation");
|
|
45
|
+
|
|
46
|
+
pub fn foundation_output_id(&self) -> SiacoinOutputID {
|
|
47
|
+
let mut state = Params::new().hash_length(32).to_state();
|
|
48
|
+
state.update(self.as_ref());
|
|
49
|
+
state.update(Self::FOUNDATION_OUTPUT_ID_PREFIX.as_ref());
|
|
50
|
+
state.finalize().into()
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
pub fn miner_output_id(&self, i: usize) -> SiacoinOutputID {
|
|
54
|
+
let mut state = Params::new().hash_length(32).to_state();
|
|
55
|
+
state.update(self.as_ref());
|
|
56
|
+
state.update(&(i as u64).to_le_bytes());
|
|
57
|
+
state.finalize().into()
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
impl_hash_id!(TransactionID);
|
|
62
|
+
|
|
63
|
+
impl TransactionID {
|
|
64
|
+
const V2_SIACOIN_OUTPUT_PREFIX: &[u8] = b"sia/id/siacoinoutput|";
|
|
65
|
+
const V2_SIAFUND_OUTPUT_PREFIX: &[u8] = b"sia/id/siafundoutput|";
|
|
66
|
+
const V2_FILE_CONTRACT_PREFIX: &[u8] = b"sia/id/filecontract|";
|
|
67
|
+
const V2_ATTESTATION_PREFIX: &[u8] = b"sia/id/attestation|";
|
|
68
|
+
|
|
69
|
+
fn derive_v2_child_id<T: From<blake2b_simd::Hash>>(&self, prefix: &[u8], i: usize) -> T {
|
|
70
|
+
let mut state = Params::new().hash_length(32).to_state();
|
|
71
|
+
state.update(prefix.as_ref());
|
|
72
|
+
state.update(self.as_ref());
|
|
73
|
+
state.update(&(i as u64).to_le_bytes());
|
|
74
|
+
state.finalize().into()
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/// v2_siacoin_output_id returns the SiacoinOutputID for the i-th siacoin output of the V2 transaction
|
|
78
|
+
pub fn v2_siacoin_output_id(&self, i: usize) -> SiacoinOutputID {
|
|
79
|
+
self.derive_v2_child_id(Self::V2_SIACOIN_OUTPUT_PREFIX, i)
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/// v2_siafund_output_id returns the SiafundOutputID for the i-th siafund output of the V2 transaction
|
|
83
|
+
pub fn v2_siafund_output_id(&self, i: usize) -> SiafundOutputID {
|
|
84
|
+
self.derive_v2_child_id(Self::V2_SIAFUND_OUTPUT_PREFIX, i)
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/// v2_file_contract_id returns the FileContractID for the i-th file contract of the V2 transaction
|
|
88
|
+
pub fn v2_file_contract_id(&self, i: usize) -> FileContractID {
|
|
89
|
+
self.derive_v2_child_id(Self::V2_FILE_CONTRACT_PREFIX, i)
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/// v2_attestation_id returns the AttestationID for the i-th attestation of the V2 transaction
|
|
93
|
+
pub fn v2_attestation_id(&self, i: usize) -> AttestationID {
|
|
94
|
+
self.derive_v2_child_id(Self::V2_ATTESTATION_PREFIX, i)
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
impl_hash_id!(FileContractID);
|
|
99
|
+
|
|
100
|
+
impl FileContractID {
|
|
101
|
+
const PROOF_OUTPUT_ID_PREFIX: Specifier = specifier!("storage proof");
|
|
102
|
+
const V2_PROOF_OUTPUT_ID_PREFIX: &'static str = "id/v2filecontractoutput";
|
|
103
|
+
const V2_FILE_CONTRACT_RENEWAL_PREFIX: &'static str = "id/v2filecontractrenewal";
|
|
104
|
+
|
|
105
|
+
fn derive_proof_output_id<T: From<blake2b_simd::Hash>>(&self, valid: bool, i: usize) -> T {
|
|
106
|
+
let mut state = Params::new().hash_length(32).to_state();
|
|
107
|
+
state.update(Self::PROOF_OUTPUT_ID_PREFIX.as_ref());
|
|
108
|
+
state.update(self.as_ref());
|
|
109
|
+
state.update(&(valid as u8).to_le_bytes());
|
|
110
|
+
state.update(&(i as u64).to_le_bytes());
|
|
111
|
+
state.finalize().into()
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
fn derive_v2_proof_output_id<T: From<blake2b_simd::Hash>>(&self, i: usize) -> T {
|
|
115
|
+
let mut state = Params::new().hash_length(32).to_state();
|
|
116
|
+
state.update(Self::V2_PROOF_OUTPUT_ID_PREFIX.as_ref());
|
|
117
|
+
state.update(self.as_ref());
|
|
118
|
+
state.update(&(i as u64).to_le_bytes());
|
|
119
|
+
state.finalize().into()
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/// valid_output_id returns the SiacoinOutputID for the i-th valid output of the contract
|
|
123
|
+
pub fn valid_output_id(&self, i: usize) -> SiacoinOutputID {
|
|
124
|
+
self.derive_proof_output_id(true, i)
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/// missed_output_id returns the SiacoinOutputID for the i-th missed output of the contract
|
|
128
|
+
pub fn missed_output_id(&self, i: usize) -> SiacoinOutputID {
|
|
129
|
+
self.derive_proof_output_id(false, i)
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/// v2_renter_output_id returns the SiacoinOutputID for the renter output of a V2 file contract
|
|
133
|
+
pub fn v2_renter_output_id(&self) -> SiacoinOutputID {
|
|
134
|
+
self.derive_v2_proof_output_id(0)
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/// v2_host_output_id returns the SiacoinOutputID for the host output of a V2 file contract
|
|
138
|
+
pub fn v2_host_output_id(&self) -> SiacoinOutputID {
|
|
139
|
+
self.derive_v2_proof_output_id(1)
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/// v2_renewal_id returns the ID of the new contract created by renewing a V2 contract
|
|
143
|
+
pub fn v2_renewal_id(&self) -> FileContractID {
|
|
144
|
+
let mut state = Params::new().hash_length(32).to_state();
|
|
145
|
+
state.update(Self::V2_FILE_CONTRACT_RENEWAL_PREFIX.as_ref());
|
|
146
|
+
state.update(self.as_ref());
|
|
147
|
+
state.finalize().into()
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
#[derive(
|
|
152
|
+
Debug, PartialEq, SiaEncode, SiaDecode, AsyncSiaDecode, AsyncSiaEncode, Serialize, Deserialize,
|
|
153
|
+
)]
|
|
154
|
+
pub struct ChainIndex {
|
|
155
|
+
pub height: u64,
|
|
156
|
+
pub id: BlockID,
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
impl ChainIndex {
|
|
160
|
+
pub fn child_height(&self) -> u64 {
|
|
161
|
+
self.height + 1
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
impl fmt::Display for ChainIndex {
|
|
166
|
+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
167
|
+
write!(f, "{}:{}", self.height, hex::encode(self.id))
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/// A Block is a collection of transactions
|
|
172
|
+
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
|
173
|
+
#[serde(rename_all = "camelCase")]
|
|
174
|
+
pub struct Block {
|
|
175
|
+
#[serde(rename = "parentID")]
|
|
176
|
+
pub parent_id: BlockID,
|
|
177
|
+
pub nonce: u64,
|
|
178
|
+
pub timestamp: DateTime<Utc>,
|
|
179
|
+
pub miner_payouts: Vec<SiacoinOutput>,
|
|
180
|
+
pub transactions: Vec<v1::Transaction>,
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
impl V1SiaEncodable for Block {
|
|
184
|
+
fn encode_v1<W: std::io::Write>(&self, w: &mut W) -> encoding::Result<()> {
|
|
185
|
+
self.parent_id.encode(w)?;
|
|
186
|
+
self.nonce.encode(w)?;
|
|
187
|
+
self.timestamp.encode(w)?;
|
|
188
|
+
self.miner_payouts.encode_v1(w)?;
|
|
189
|
+
self.transactions.encode_v1(w)
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
impl V1SiaDecodable for Block {
|
|
194
|
+
fn decode_v1<R: std::io::Read>(r: &mut R) -> encoding::Result<Self> {
|
|
195
|
+
Ok(Block {
|
|
196
|
+
parent_id: BlockID::decode(r)?,
|
|
197
|
+
nonce: u64::decode(r)?,
|
|
198
|
+
timestamp: DateTime::<Utc>::decode(r)?,
|
|
199
|
+
miner_payouts: Vec::<SiacoinOutput>::decode_v1(r)?,
|
|
200
|
+
transactions: Vec::<v1::Transaction>::decode_v1(r)?,
|
|
201
|
+
})
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/// encapsulates the various errors that can occur when parsing a Sia object
|
|
206
|
+
/// from a string
|
|
207
|
+
#[derive(Debug, Error, PartialEq)]
|
|
208
|
+
pub enum HexParseError {
|
|
209
|
+
#[error("Missing prefix")]
|
|
210
|
+
MissingPrefix,
|
|
211
|
+
|
|
212
|
+
#[error("Unexpected length")]
|
|
213
|
+
InvalidLength(usize),
|
|
214
|
+
|
|
215
|
+
#[error("Invalid prefix {0}")]
|
|
216
|
+
InvalidPrefix(String),
|
|
217
|
+
|
|
218
|
+
#[error("Invalid checksum")]
|
|
219
|
+
InvalidChecksum, // not every object has a checksum
|
|
220
|
+
|
|
221
|
+
#[error("Hex error: {0}")]
|
|
222
|
+
HexError(#[from] hex::FromHexError),
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
/// An address that can be used to receive UTXOs
|
|
226
|
+
#[derive(
|
|
227
|
+
Default,
|
|
228
|
+
Debug,
|
|
229
|
+
PartialEq,
|
|
230
|
+
Clone,
|
|
231
|
+
SiaEncode,
|
|
232
|
+
V1SiaEncode,
|
|
233
|
+
SiaDecode,
|
|
234
|
+
V1SiaDecode,
|
|
235
|
+
AsyncSiaEncode,
|
|
236
|
+
AsyncSiaDecode,
|
|
237
|
+
)]
|
|
238
|
+
pub struct Address([u8; 32]);
|
|
239
|
+
|
|
240
|
+
impl<'de> Deserialize<'de> for Address {
|
|
241
|
+
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
|
242
|
+
where
|
|
243
|
+
D: serde::Deserializer<'de>,
|
|
244
|
+
{
|
|
245
|
+
let s = String::deserialize(deserializer)?;
|
|
246
|
+
s.parse()
|
|
247
|
+
.map_err(|e| serde::de::Error::custom(format!("{e:?}")))
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
impl Serialize for Address {
|
|
252
|
+
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
|
253
|
+
where
|
|
254
|
+
S: serde::Serializer,
|
|
255
|
+
{
|
|
256
|
+
self.to_string().serialize(serializer)
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
impl Address {
|
|
261
|
+
pub const fn new(addr: [u8; 32]) -> Address {
|
|
262
|
+
Address(addr)
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
impl AsRef<[u8]> for Address {
|
|
267
|
+
fn as_ref(&self) -> &[u8] {
|
|
268
|
+
&self.0
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
impl From<&[u8]> for Address {
|
|
273
|
+
fn from(val: &[u8]) -> Self {
|
|
274
|
+
let mut data = [0u8; 32];
|
|
275
|
+
data.copy_from_slice(val);
|
|
276
|
+
Address(data)
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
impl From<[u8; 32]> for Address {
|
|
281
|
+
fn from(val: [u8; 32]) -> Self {
|
|
282
|
+
Address(val)
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
impl std::str::FromStr for Address {
|
|
287
|
+
type Err = crate::types::HexParseError;
|
|
288
|
+
|
|
289
|
+
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
|
290
|
+
if s.len() != 76 {
|
|
291
|
+
return Err(HexParseError::InvalidLength(s.len()));
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
let mut data = [0u8; 38];
|
|
295
|
+
hex::decode_to_slice(s, &mut data).map_err(HexParseError::HexError)?;
|
|
296
|
+
|
|
297
|
+
let h = Params::new()
|
|
298
|
+
.hash_length(32)
|
|
299
|
+
.to_state()
|
|
300
|
+
.update(&data[..32])
|
|
301
|
+
.finalize();
|
|
302
|
+
let checksum = h.as_bytes();
|
|
303
|
+
|
|
304
|
+
if checksum[..6] != data[32..] {
|
|
305
|
+
return Err(HexParseError::InvalidChecksum);
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
Ok(data[..32].into())
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
impl fmt::Display for Address {
|
|
313
|
+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
314
|
+
let mut buf = [0u8; 32 + 6];
|
|
315
|
+
buf[..32].copy_from_slice(&self.0);
|
|
316
|
+
|
|
317
|
+
let h = Params::new()
|
|
318
|
+
.hash_length(32)
|
|
319
|
+
.to_state()
|
|
320
|
+
.update(&self.0)
|
|
321
|
+
.finalize();
|
|
322
|
+
|
|
323
|
+
buf[32..].copy_from_slice(&h.as_bytes()[..6]);
|
|
324
|
+
write!(f, "{}", hex::encode(buf))
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
/// A SiacoinOutput is a Siacoin UTXO that can be spent using the unlock conditions
|
|
329
|
+
/// for Address
|
|
330
|
+
#[derive(
|
|
331
|
+
Debug,
|
|
332
|
+
PartialEq,
|
|
333
|
+
Serialize,
|
|
334
|
+
Deserialize,
|
|
335
|
+
AsyncSiaEncode,
|
|
336
|
+
AsyncSiaDecode,
|
|
337
|
+
SiaEncode,
|
|
338
|
+
SiaDecode,
|
|
339
|
+
V1SiaEncode,
|
|
340
|
+
V1SiaDecode,
|
|
341
|
+
Clone,
|
|
342
|
+
)]
|
|
343
|
+
#[serde(rename_all = "camelCase")]
|
|
344
|
+
pub struct SiacoinOutput {
|
|
345
|
+
pub value: Currency,
|
|
346
|
+
pub address: Address,
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
/// A SiafundOutput is a Siafund UTXO that can be spent using the unlock conditions
|
|
350
|
+
/// for Address
|
|
351
|
+
#[derive(
|
|
352
|
+
Debug, PartialEq, Serialize, Deserialize, SiaEncode, SiaDecode, AsyncSiaEncode, AsyncSiaDecode,
|
|
353
|
+
)]
|
|
354
|
+
#[serde(rename_all = "camelCase")]
|
|
355
|
+
pub struct SiafundOutput {
|
|
356
|
+
pub value: u64,
|
|
357
|
+
pub address: Address,
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
impl V1SiaEncodable for SiafundOutput {
|
|
361
|
+
fn encode_v1<W: std::io::Write>(&self, w: &mut W) -> encoding::Result<()> {
|
|
362
|
+
Currency::new(self.value as u128).encode_v1(w)?;
|
|
363
|
+
self.address.encode_v1(w)?;
|
|
364
|
+
Currency::new(0).encode_v1(w) // siad encodes a "claim start," but its an error if it's non-zero.
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
impl V1SiaDecodable for SiafundOutput {
|
|
369
|
+
fn decode_v1<R: std::io::Read>(r: &mut R) -> encoding::Result<Self> {
|
|
370
|
+
let se = SiafundOutput {
|
|
371
|
+
value: Currency::decode_v1(r)?
|
|
372
|
+
.try_into()
|
|
373
|
+
.map_err(|_| encoding::Error::Custom("invalid value".to_string()))?,
|
|
374
|
+
address: Address::decode_v1(r)?,
|
|
375
|
+
};
|
|
376
|
+
Currency::decode_v1(r)?; // ignore claim start
|
|
377
|
+
Ok(se)
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
/// A Leaf is a 64-byte piece of data that is stored in a Merkle tree.
|
|
382
|
+
#[derive(
|
|
383
|
+
Debug,
|
|
384
|
+
PartialEq,
|
|
385
|
+
Clone,
|
|
386
|
+
SiaEncode,
|
|
387
|
+
V1SiaEncode,
|
|
388
|
+
SiaDecode,
|
|
389
|
+
V1SiaDecode,
|
|
390
|
+
AsyncSiaEncode,
|
|
391
|
+
AsyncSiaDecode,
|
|
392
|
+
)]
|
|
393
|
+
pub struct Leaf([u8; 64]);
|
|
394
|
+
|
|
395
|
+
impl From<[u8; 64]> for Leaf {
|
|
396
|
+
fn from(data: [u8; 64]) -> Self {
|
|
397
|
+
Leaf(data)
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
impl std::str::FromStr for Leaf {
|
|
402
|
+
type Err = crate::types::HexParseError;
|
|
403
|
+
|
|
404
|
+
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
|
405
|
+
if s.len() != 128 {
|
|
406
|
+
return Err(HexParseError::InvalidLength(s.len()));
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
let mut data = [0u8; 64];
|
|
410
|
+
hex::decode_to_slice(s, &mut data).map_err(HexParseError::HexError)?;
|
|
411
|
+
Ok(Leaf(data))
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
impl fmt::Display for Leaf {
|
|
416
|
+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
417
|
+
write!(f, "{}", hex::encode(self.0))
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
impl Serialize for Leaf {
|
|
422
|
+
fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
|
|
423
|
+
String::serialize(&self.to_string(), serializer)
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
impl<'de> Deserialize<'de> for Leaf {
|
|
428
|
+
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
|
429
|
+
where
|
|
430
|
+
D: serde::Deserializer<'de>,
|
|
431
|
+
{
|
|
432
|
+
let s = String::deserialize(deserializer)?;
|
|
433
|
+
let data = hex::decode(s).map_err(|e| serde::de::Error::custom(format!("{e:?}")))?;
|
|
434
|
+
if data.len() != 64 {
|
|
435
|
+
return Err(serde::de::Error::custom("invalid length"));
|
|
436
|
+
}
|
|
437
|
+
Ok(Leaf(data.try_into().unwrap()))
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
/// A StateElement is a generic element within the state accumulator.
|
|
442
|
+
#[derive(
|
|
443
|
+
Debug,
|
|
444
|
+
PartialEq,
|
|
445
|
+
Serialize,
|
|
446
|
+
Deserialize,
|
|
447
|
+
SiaEncode,
|
|
448
|
+
SiaDecode,
|
|
449
|
+
AsyncSiaDecode,
|
|
450
|
+
AsyncSiaEncode,
|
|
451
|
+
Clone,
|
|
452
|
+
)]
|
|
453
|
+
#[serde(rename_all = "camelCase")]
|
|
454
|
+
pub struct StateElement {
|
|
455
|
+
pub leaf_index: u64,
|
|
456
|
+
pub merkle_proof: Vec<Hash256>,
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
#[cfg(test)]
|
|
460
|
+
mod tests {
|
|
461
|
+
use crate::{
|
|
462
|
+
address, block_id, contract_id, public_key, siacoin_id, siafund_id, transaction_id,
|
|
463
|
+
};
|
|
464
|
+
|
|
465
|
+
use super::*;
|
|
466
|
+
|
|
467
|
+
#[test]
|
|
468
|
+
fn test_serialize_hash256() {
|
|
469
|
+
let hash_str = "9aac1ffb1cfd1079a8c6c87b47da1d567e35b97234993c288c1ad0db1d1ce1b6";
|
|
470
|
+
let hash = Hash256(hex::decode(hash_str).unwrap().try_into().unwrap());
|
|
471
|
+
|
|
472
|
+
// binary
|
|
473
|
+
let mut hash_serialized: Vec<u8> = Vec::new();
|
|
474
|
+
hash.encode(&mut hash_serialized).unwrap();
|
|
475
|
+
assert_eq!(hash_serialized, hex::decode(hash_str).unwrap());
|
|
476
|
+
let hash_deserialized = Hash256::decode(&mut &hash_serialized[..]).unwrap();
|
|
477
|
+
assert_eq!(hash_deserialized, hash); // deserialize
|
|
478
|
+
|
|
479
|
+
// json
|
|
480
|
+
let hash_serialized = serde_json::to_string(&hash).unwrap();
|
|
481
|
+
let hash_deserialized: Hash256 = serde_json::from_str(&hash_serialized).unwrap();
|
|
482
|
+
assert_eq!(hash_serialized, format!("\"{hash_str}\"")); // serialize
|
|
483
|
+
assert_eq!(hash_deserialized, hash); // deserialize
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
#[test]
|
|
487
|
+
fn test_serialize_address() {
|
|
488
|
+
let addr_str = "8fb49ccf17dfdcc9526dec6ee8a5cca20ff8247302053d3777410b9b0494ba8c";
|
|
489
|
+
let checksum = "df32abee86f0";
|
|
490
|
+
let address = address!(
|
|
491
|
+
"8fb49ccf17dfdcc9526dec6ee8a5cca20ff8247302053d3777410b9b0494ba8cdf32abee86f0"
|
|
492
|
+
);
|
|
493
|
+
|
|
494
|
+
// binary
|
|
495
|
+
let mut addr_serialized: Vec<u8> = Vec::new();
|
|
496
|
+
address.encode(&mut addr_serialized).unwrap();
|
|
497
|
+
assert_eq!(addr_serialized, hex::decode(addr_str).unwrap()); // serialize
|
|
498
|
+
let addr_deserialized = Address::decode(&mut &addr_serialized[..]).unwrap();
|
|
499
|
+
assert_eq!(addr_deserialized, address); // deserialize
|
|
500
|
+
|
|
501
|
+
// json
|
|
502
|
+
let addr_serialized = serde_json::to_string(&address).unwrap();
|
|
503
|
+
let addr_deserialized: Address = serde_json::from_str(&addr_serialized).unwrap();
|
|
504
|
+
assert_eq!(addr_serialized, format!("\"{addr_str}{checksum}\"")); // serialize
|
|
505
|
+
assert_eq!(addr_deserialized, address); // deserialize
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
#[test]
|
|
509
|
+
fn test_serialize_block() {
|
|
510
|
+
let b = Block {
|
|
511
|
+
parent_id: block_id!(
|
|
512
|
+
"8fb49ccf17dfdcc9526dec6ee8a5cca20ff8247302053d3777410b9b0494ba8c"
|
|
513
|
+
),
|
|
514
|
+
nonce: 1236112,
|
|
515
|
+
timestamp: DateTime::UNIX_EPOCH,
|
|
516
|
+
miner_payouts: vec![SiacoinOutput {
|
|
517
|
+
value: Currency::new(57234234623612361),
|
|
518
|
+
address: address!(
|
|
519
|
+
"000000000000000000000000000000000000000000000000000000000000000089eb0d6a8a69"
|
|
520
|
+
),
|
|
521
|
+
}],
|
|
522
|
+
transactions: vec![v1::Transaction {
|
|
523
|
+
siacoin_inputs: vec![v1::SiacoinInput {
|
|
524
|
+
parent_id: siacoin_id!(
|
|
525
|
+
"8fb49ccf17dfdcc9526dec6ee8a5cca20ff8247302053d3777410b9b0494ba8c"
|
|
526
|
+
),
|
|
527
|
+
unlock_conditions: v1::UnlockConditions::standard_unlock_conditions(
|
|
528
|
+
public_key!(
|
|
529
|
+
"ed25519:8fb49ccf17dfdcc9526dec6ee8a5cca20ff8247302053d3777410b9b0494ba8c"
|
|
530
|
+
),
|
|
531
|
+
),
|
|
532
|
+
}],
|
|
533
|
+
siacoin_outputs: vec![SiacoinOutput {
|
|
534
|
+
value: Currency::new(67856467336433871),
|
|
535
|
+
address: address!(
|
|
536
|
+
"000000000000000000000000000000000000000000000000000000000000000089eb0d6a8a69"
|
|
537
|
+
),
|
|
538
|
+
}],
|
|
539
|
+
file_contracts: Vec::new(),
|
|
540
|
+
file_contract_revisions: Vec::new(),
|
|
541
|
+
storage_proofs: Vec::new(),
|
|
542
|
+
siafund_inputs: Vec::new(),
|
|
543
|
+
siafund_outputs: Vec::new(),
|
|
544
|
+
miner_fees: Vec::new(),
|
|
545
|
+
arbitrary_data: Vec::new(),
|
|
546
|
+
signatures: Vec::new(),
|
|
547
|
+
}],
|
|
548
|
+
};
|
|
549
|
+
|
|
550
|
+
const BINARY_STR: &str = "8fb49ccf17dfdcc9526dec6ee8a5cca20ff8247302053d3777410b9b0494ba8c90dc120000000000000000000000000001000000000000000700000000000000cb563bafbb55c90000000000000000000000000000000000000000000000000000000000000000010000000000000001000000000000008fb49ccf17dfdcc9526dec6ee8a5cca20ff8247302053d3777410b9b0494ba8c000000000000000001000000000000006564323535313900000000000000000020000000000000008fb49ccf17dfdcc9526dec6ee8a5cca20ff8247302053d3777410b9b0494ba8c010000000000000001000000000000000700000000000000f11318f74d10cf000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000";
|
|
551
|
+
let mut serialized = Vec::new();
|
|
552
|
+
b.encode_v1(&mut serialized).unwrap();
|
|
553
|
+
assert_eq!(serialized, hex::decode(BINARY_STR).unwrap());
|
|
554
|
+
let deserialized = Block::decode_v1(&mut &serialized[..]).unwrap();
|
|
555
|
+
assert_eq!(deserialized, b);
|
|
556
|
+
|
|
557
|
+
const JSON_STR: &str = "{\"parentID\":\"8fb49ccf17dfdcc9526dec6ee8a5cca20ff8247302053d3777410b9b0494ba8c\",\"nonce\":1236112,\"timestamp\":\"1970-01-01T00:00:00Z\",\"minerPayouts\":[{\"value\":\"57234234623612361\",\"address\":\"000000000000000000000000000000000000000000000000000000000000000089eb0d6a8a69\"}],\"transactions\":[{\"siacoinInputs\":[{\"parentID\":\"8fb49ccf17dfdcc9526dec6ee8a5cca20ff8247302053d3777410b9b0494ba8c\",\"unlockConditions\":{\"timelock\":0,\"publicKeys\":[\"ed25519:8fb49ccf17dfdcc9526dec6ee8a5cca20ff8247302053d3777410b9b0494ba8c\"],\"signaturesRequired\":1}}],\"siacoinOutputs\":[{\"value\":\"67856467336433871\",\"address\":\"000000000000000000000000000000000000000000000000000000000000000089eb0d6a8a69\"}]}]}";
|
|
558
|
+
let serialized = serde_json::to_string(&b).unwrap();
|
|
559
|
+
assert_eq!(serialized, JSON_STR);
|
|
560
|
+
let deserialized: Block = serde_json::from_str(&serialized).unwrap();
|
|
561
|
+
assert_eq!(deserialized, b);
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
#[test]
|
|
565
|
+
fn test_transaction_derive() {
|
|
566
|
+
const TXN_JSON: &str = r#"{"siacoinInputs":[{"parentID":"750d22eff727689d1d8d1c83e513a30bb68ee7f9125a4dafc882459e34c2069d","unlockConditions":{"timelock":0,"publicKeys":["ed25519:800ed6c2760e3e4ba1ff00128585c8cf8fed2e3dc1e3da1eb92d49f405bd6360"],"signaturesRequired":6312611591377486220}}],"siacoinOutputs":[{"value":"890415399000000000000000000000000","address":"480a064b5fca13002a7fe575845154bbf0b3af4cc4f147cbed387d43cce3568ae2497366eaa7"}],"fileContracts":[{"filesize":0,"fileMerkleRoot":"0000000000000000000000000000000000000000000000000000000000000000","windowStart":10536451586783908586,"windowEnd":9324702155635244357,"payout":"0","validProofOutputs":[{"value":"1933513214000000000000000000000000","address":"944524fff2c49c401e748db37cfda7569fa6df35b704fe716394f2ac3f40ce87b4506e9906f0"}],"missedProofOutputs":[{"value":"2469287901000000000000000000000000","address":"1df67838262d7109ffcd9018f183b1eb33f05659a274b89ea6b52ff3617d34a770e9dd071d2e"}],"unlockHash":"000000000000000000000000000000000000000000000000000000000000000089eb0d6a8a69","revisionNumber":9657412421282982780}],"fileContractRevisions":[{"parentID":"e4e26d93771d3bbb3d9dd306105d77cfb3a6254d1cc3495903af6e013442c63c","unlockConditions":{"timelock":0,"publicKeys":["ed25519:e6b9cde4eb058f8ecbb083d99779cb0f6d518d5386f019af6ead09fa52de8567"],"signaturesRequired":206644730660526450},"revisionNumber":10595710523108536025,"filesize":0,"fileMerkleRoot":"0000000000000000000000000000000000000000000000000000000000000000","windowStart":4348934140507359445,"windowEnd":14012366839994454386,"validProofOutputs":[{"value":"2435858510000000000000000000000000","address":"543bc0eda69f728d0a0fbce08e5bfc5ed7b961300e0af226949e135f7d12e32f0544e5262d6f"}],"missedProofOutputs":[{"value":"880343701000000000000000000000000","address":"7b7f9aee981fe0d93bb3f49c6233cf847ebdd39d7dc5253f7fc330df2167073b35f035703237"}],"unlockHash":"000000000000000000000000000000000000000000000000000000000000000089eb0d6a8a69"}],"storageProofs":[{"parentID":"c0b9e98c9e03a2740c75d673871c1ee91f36d1bb329ff3ddbf1dfa8c6e1a64eb","leaf":"b78fa521dc62d9ced82bc3b61e0aa5a5c221d6cca5db63d94c9879543fb98c0a971094a89cd4408487ae32902248d321b545f9a051729aa0bb1725b848e3d453","proof":["fe08c0a061475e7e5dec19e717cf98792fa7b555d0b5d3540a05db09f59ab8de"]}],"minerFees":["241119475000000000000000000000000"],"arbitraryData":["2shzIHEUJYwuNHz6c/gPz+aTEWZRTpDTmemX9yYAKlY="],"signatures":[{"parentID":"06d1fca03c5ddd9b09116db1b97c5451f7dc792b05362969f83e3e8dc1007f46","publicKeyIndex":6088345341283457116,"timelock":2014247885072555224,"coveredFields":{"wholeTransaction":true},"signature":"2XNEKGZrl9RhMa2JmGsvcmqQWAIX/uxtMwLnPI6VJPcXqub6qYIuoAThYp9NAwadk+1GG6CXC66g4rOjFYuNSA=="}]}"#;
|
|
567
|
+
|
|
568
|
+
const EXPECTED_TRANSACTION_ID: TransactionID =
|
|
569
|
+
transaction_id!("71a10d363f4af09c3fbce499b725067b0b19afe2bc9a8236704e85256f3244a6");
|
|
570
|
+
const EXPECTED_SIACOIN_OUTPUT_ID: SiacoinOutputID =
|
|
571
|
+
siacoin_id!("ea315efdd5914c54e8082d0de90b5afa9d4b92103d60661ec86b2a095413d836");
|
|
572
|
+
const EXPECTED_SIAFUND_OUTPUT_ID: SiafundOutputID =
|
|
573
|
+
siafund_id!("a8190ea7b4d41e08f45f27653b882faf8ff9fd57bb098d7022f105ef142279ec");
|
|
574
|
+
const EXPECTED_FILE_CONTRACT_ID: FileContractID =
|
|
575
|
+
contract_id!("ff7102bb111a64c7ff8a3cd68dbc962a03a8943065c3852a359662c8935fa979");
|
|
576
|
+
|
|
577
|
+
let txn: v1::Transaction =
|
|
578
|
+
serde_json::from_str(TXN_JSON).expect("transaction to deserialize");
|
|
579
|
+
|
|
580
|
+
assert_eq!(txn.id(), EXPECTED_TRANSACTION_ID, "transaction id");
|
|
581
|
+
|
|
582
|
+
assert_eq!(
|
|
583
|
+
txn.siacoin_output_id(678569214627704587),
|
|
584
|
+
EXPECTED_SIACOIN_OUTPUT_ID,
|
|
585
|
+
"siacoin output id"
|
|
586
|
+
);
|
|
587
|
+
|
|
588
|
+
assert_eq!(
|
|
589
|
+
txn.siafund_output_id(8940170890223196046),
|
|
590
|
+
EXPECTED_SIAFUND_OUTPUT_ID,
|
|
591
|
+
"siafund output id"
|
|
592
|
+
);
|
|
593
|
+
|
|
594
|
+
assert_eq!(
|
|
595
|
+
txn.file_contract_id(3470616158951613631),
|
|
596
|
+
EXPECTED_FILE_CONTRACT_ID,
|
|
597
|
+
"file contract id"
|
|
598
|
+
);
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
#[test]
|
|
602
|
+
fn test_transaction_id_v2_derive() {
|
|
603
|
+
const EXPECTED_V2_SIACOIN_OUTPUT_ID: SiacoinOutputID =
|
|
604
|
+
siacoin_id!("f74e0d8eae89ec820184c9bacfcad0181c781c02020f8a3fcbc82fd4ebf2fcf0");
|
|
605
|
+
const EXPECTED_V2_SIAFUND_OUTPUT_ID: SiafundOutputID =
|
|
606
|
+
siafund_id!("f7d9ad77bfe9a102ef9590f97024f3aa8f54877d10447c128b52d5ca18cca983");
|
|
607
|
+
const EXPECTED_V2_FILE_CONTRACT_ID: FileContractID =
|
|
608
|
+
contract_id!("c67764bc06df3dd933e0d4e93c6f7cbe5b56670d1baae156b578d417f08e65cf");
|
|
609
|
+
|
|
610
|
+
let txn_id =
|
|
611
|
+
transaction_id!("168ecf3133ae713c26f90fe1790fb7536f12cc2a492985627856b77c6ad99070");
|
|
612
|
+
|
|
613
|
+
assert_eq!(
|
|
614
|
+
txn_id.v2_siacoin_output_id(3543556734851495409),
|
|
615
|
+
EXPECTED_V2_SIACOIN_OUTPUT_ID,
|
|
616
|
+
"v2 siacoin output id"
|
|
617
|
+
);
|
|
618
|
+
|
|
619
|
+
assert_eq!(
|
|
620
|
+
txn_id.v2_siafund_output_id(4957302981402025980),
|
|
621
|
+
EXPECTED_V2_SIAFUND_OUTPUT_ID,
|
|
622
|
+
"v2 siafund output id"
|
|
623
|
+
);
|
|
624
|
+
|
|
625
|
+
assert_eq!(
|
|
626
|
+
txn_id.v2_file_contract_id(5375460735837768427),
|
|
627
|
+
EXPECTED_V2_FILE_CONTRACT_ID,
|
|
628
|
+
"v2 file contract id"
|
|
629
|
+
);
|
|
630
|
+
}
|
|
631
|
+
|
|
632
|
+
#[test]
|
|
633
|
+
fn test_block_id_derive() {
|
|
634
|
+
const EXPECTED_FOUNDATION_OUTPUT_ID: SiacoinOutputID =
|
|
635
|
+
siacoin_id!("159e2c4159a112ea9a70242d541a26f49fce41b6126f9105eab9b68dba4cfafb");
|
|
636
|
+
const EXPECTED_MINER_OUTPUT_ID: SiacoinOutputID =
|
|
637
|
+
siacoin_id!("69e68779991392663d808276e6661d94628632354e258d8ab6724de1d9ca6208");
|
|
638
|
+
|
|
639
|
+
let block_id =
|
|
640
|
+
block_id!("c56d879b07b27fab3bdd06b833dbd1ad7eb167058851f543a517308b634a80a1");
|
|
641
|
+
|
|
642
|
+
assert_eq!(
|
|
643
|
+
block_id.foundation_output_id(),
|
|
644
|
+
EXPECTED_FOUNDATION_OUTPUT_ID,
|
|
645
|
+
"foundation output id"
|
|
646
|
+
);
|
|
647
|
+
|
|
648
|
+
assert_eq!(
|
|
649
|
+
block_id.miner_output_id(3072616177397065894),
|
|
650
|
+
EXPECTED_MINER_OUTPUT_ID,
|
|
651
|
+
"miner output id"
|
|
652
|
+
);
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
#[test]
|
|
656
|
+
fn test_siafund_output_id_derive() {
|
|
657
|
+
const EXPECTED_CLAIM_ID: SiacoinOutputID =
|
|
658
|
+
siacoin_id!("8eec57722c2ac040e34322ba77cb6b488ac8081f856d93bea1bf1bef42aeaabb");
|
|
659
|
+
const EXPECTED_V2_CLAIM_ID: SiacoinOutputID =
|
|
660
|
+
siacoin_id!("b949006c65c70b5973da46cc783981d701dd854316e7efb1947c0b5f2fdc8db4");
|
|
661
|
+
|
|
662
|
+
let siafund_output_id =
|
|
663
|
+
siafund_id!("58ea19fd87ae5e10f928035e1021c3d9ee091fb3c0bbd5a1a6af41eea12e0f85");
|
|
664
|
+
|
|
665
|
+
assert_eq!(
|
|
666
|
+
siafund_output_id.claim_output_id(),
|
|
667
|
+
EXPECTED_CLAIM_ID,
|
|
668
|
+
"claim output id"
|
|
669
|
+
);
|
|
670
|
+
|
|
671
|
+
assert_eq!(
|
|
672
|
+
siafund_output_id.v2_claim_output_id(),
|
|
673
|
+
EXPECTED_V2_CLAIM_ID,
|
|
674
|
+
"v2 claim output id"
|
|
675
|
+
);
|
|
676
|
+
}
|
|
677
|
+
}
|