create-sia-app 0.1.7 → 0.1.9
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/package.json +2 -6
- package/template/AGENTS.md +143 -0
- package/template/CLAUDE.md +25 -46
- package/template/README.md +6 -12
- package/template/_gitignore +0 -1
- package/template/dist/assets/index-BEylY2j7.css +1 -0
- package/template/dist/assets/index-CnYqArKN.js +8741 -0
- package/template/dist/assets/sia_bg-BTOHUC1A.wasm +0 -0
- package/template/dist/assets/slab-download-worker-DhW6ZBJs.js +2 -0
- package/template/dist/assets/slab-upload-worker-B2uSB2iY.js +2 -0
- package/template/dist/index.html +13 -0
- package/template/e2e/smoke.spec.ts +20 -0
- package/template/index.html +0 -1
- package/template/package.json +2 -2
- package/template/playwright.config.ts +13 -0
- package/template/src/components/Navbar.tsx +3 -3
- package/template/src/components/auth/ApproveScreen.tsx +10 -13
- package/template/src/components/auth/AuthFlow.tsx +13 -10
- package/template/src/components/auth/ConnectScreen.tsx +2 -3
- package/template/src/components/auth/RecoveryScreen.tsx +7 -7
- package/template/src/components/upload/UploadZone.tsx +192 -74
- package/template/src/index.css +14 -4
- package/template/src/stores/auth.ts +6 -12
- package/template/test-results/.last-run.json +4 -0
- package/template/tsconfig.app.json +1 -1
- package/template/tsconfig.node.json +0 -1
- package/template/vite.config.ts +2 -3
- package/template/rust/README.md +0 -16
- package/template/rust/sia-sdk-rs/.changeset/added_cancel_function_to_cancel_inflight_packed_uploads.md +0 -6
- package/template/rust/sia-sdk-rs/.changeset/check_if_we_have_enough_hosts_prior_to_encoding_in_upload_slabs.md +0 -16
- package/template/rust/sia-sdk-rs/.changeset/fix_slab_length_in_packed_object.md +0 -5
- package/template/rust/sia-sdk-rs/.changeset/fix_upload_racing_race_conditon.md +0 -13
- package/template/rust/sia-sdk-rs/.changeset/improved_parallelism_of_packed_uploads.md +0 -5
- package/template/rust/sia-sdk-rs/.changeset/progress_callback_will_now_be_called_as_expected_for_packed_uploads.md +0 -5
- package/template/rust/sia-sdk-rs/.github/dependabot.yml +0 -10
- package/template/rust/sia-sdk-rs/.github/workflows/main.yml +0 -36
- package/template/rust/sia-sdk-rs/.github/workflows/prepare-release.yml +0 -34
- package/template/rust/sia-sdk-rs/.github/workflows/release.yml +0 -30
- package/template/rust/sia-sdk-rs/.rustfmt.toml +0 -4
- package/template/rust/sia-sdk-rs/Cargo.lock +0 -4127
- package/template/rust/sia-sdk-rs/Cargo.toml +0 -3
- package/template/rust/sia-sdk-rs/LICENSE +0 -21
- package/template/rust/sia-sdk-rs/README.md +0 -30
- package/template/rust/sia-sdk-rs/indexd/CHANGELOG.md +0 -79
- package/template/rust/sia-sdk-rs/indexd/Cargo.toml +0 -79
- package/template/rust/sia-sdk-rs/indexd/benches/upload.rs +0 -258
- package/template/rust/sia-sdk-rs/indexd/src/app_client.rs +0 -1710
- package/template/rust/sia-sdk-rs/indexd/src/builder.rs +0 -354
- package/template/rust/sia-sdk-rs/indexd/src/download.rs +0 -379
- package/template/rust/sia-sdk-rs/indexd/src/hosts.rs +0 -659
- package/template/rust/sia-sdk-rs/indexd/src/lib.rs +0 -827
- package/template/rust/sia-sdk-rs/indexd/src/mock.rs +0 -162
- package/template/rust/sia-sdk-rs/indexd/src/object_encryption.rs +0 -125
- package/template/rust/sia-sdk-rs/indexd/src/quic.rs +0 -575
- package/template/rust/sia-sdk-rs/indexd/src/rhp4.rs +0 -52
- package/template/rust/sia-sdk-rs/indexd/src/slabs.rs +0 -497
- package/template/rust/sia-sdk-rs/indexd/src/upload.rs +0 -629
- package/template/rust/sia-sdk-rs/indexd/src/wasm_time.rs +0 -41
- package/template/rust/sia-sdk-rs/indexd/src/web_transport.rs +0 -398
- package/template/rust/sia-sdk-rs/indexd_ffi/CHANGELOG.md +0 -76
- package/template/rust/sia-sdk-rs/indexd_ffi/Cargo.toml +0 -47
- package/template/rust/sia-sdk-rs/indexd_ffi/examples/python/README.md +0 -10
- package/template/rust/sia-sdk-rs/indexd_ffi/examples/python/example.py +0 -130
- package/template/rust/sia-sdk-rs/indexd_ffi/src/bin/uniffi-bindgen.rs +0 -3
- package/template/rust/sia-sdk-rs/indexd_ffi/src/builder.rs +0 -377
- package/template/rust/sia-sdk-rs/indexd_ffi/src/io.rs +0 -155
- package/template/rust/sia-sdk-rs/indexd_ffi/src/lib.rs +0 -1039
- package/template/rust/sia-sdk-rs/indexd_ffi/src/logging.rs +0 -58
- package/template/rust/sia-sdk-rs/indexd_ffi/src/tls.rs +0 -23
- package/template/rust/sia-sdk-rs/indexd_wasm/Cargo.toml +0 -33
- package/template/rust/sia-sdk-rs/indexd_wasm/src/lib.rs +0 -818
- package/template/rust/sia-sdk-rs/knope.toml +0 -54
- package/template/rust/sia-sdk-rs/sia_derive/CHANGELOG.md +0 -38
- package/template/rust/sia-sdk-rs/sia_derive/Cargo.toml +0 -19
- package/template/rust/sia-sdk-rs/sia_derive/src/lib.rs +0 -278
- package/template/rust/sia-sdk-rs/sia_sdk/CHANGELOG.md +0 -91
- package/template/rust/sia-sdk-rs/sia_sdk/Cargo.toml +0 -59
- package/template/rust/sia-sdk-rs/sia_sdk/benches/merkle_root.rs +0 -12
- package/template/rust/sia-sdk-rs/sia_sdk/src/blake2.rs +0 -22
- package/template/rust/sia-sdk-rs/sia_sdk/src/consensus.rs +0 -767
- package/template/rust/sia-sdk-rs/sia_sdk/src/encoding/v1.rs +0 -257
- package/template/rust/sia-sdk-rs/sia_sdk/src/encoding/v2.rs +0 -291
- package/template/rust/sia-sdk-rs/sia_sdk/src/encoding.rs +0 -26
- package/template/rust/sia-sdk-rs/sia_sdk/src/encoding_async/v2.rs +0 -367
- package/template/rust/sia-sdk-rs/sia_sdk/src/encoding_async.rs +0 -6
- package/template/rust/sia-sdk-rs/sia_sdk/src/encryption.rs +0 -303
- package/template/rust/sia-sdk-rs/sia_sdk/src/erasure_coding.rs +0 -347
- package/template/rust/sia-sdk-rs/sia_sdk/src/lib.rs +0 -15
- package/template/rust/sia-sdk-rs/sia_sdk/src/macros.rs +0 -435
- package/template/rust/sia-sdk-rs/sia_sdk/src/merkle.rs +0 -112
- package/template/rust/sia-sdk-rs/sia_sdk/src/rhp/merkle.rs +0 -357
- package/template/rust/sia-sdk-rs/sia_sdk/src/rhp/rpc.rs +0 -1507
- package/template/rust/sia-sdk-rs/sia_sdk/src/rhp/types.rs +0 -146
- package/template/rust/sia-sdk-rs/sia_sdk/src/rhp.rs +0 -7
- package/template/rust/sia-sdk-rs/sia_sdk/src/seed.rs +0 -278
- package/template/rust/sia-sdk-rs/sia_sdk/src/signing.rs +0 -236
- package/template/rust/sia-sdk-rs/sia_sdk/src/types/common.rs +0 -677
- package/template/rust/sia-sdk-rs/sia_sdk/src/types/currency.rs +0 -450
- package/template/rust/sia-sdk-rs/sia_sdk/src/types/specifier.rs +0 -110
- package/template/rust/sia-sdk-rs/sia_sdk/src/types/spendpolicy.rs +0 -778
- package/template/rust/sia-sdk-rs/sia_sdk/src/types/utils.rs +0 -117
- package/template/rust/sia-sdk-rs/sia_sdk/src/types/v1.rs +0 -1737
- package/template/rust/sia-sdk-rs/sia_sdk/src/types/v2.rs +0 -1726
- package/template/rust/sia-sdk-rs/sia_sdk/src/types/work.rs +0 -59
- package/template/rust/sia-sdk-rs/sia_sdk/src/types.rs +0 -16
- package/template/scripts/setup-rust.js +0 -29
- package/template/src/lib/format.ts +0 -35
- package/template/src/lib/hex.ts +0 -13
- package/template/src/lib/sdk.ts +0 -25
- package/template/src/lib/wasm-env.ts +0 -5
- package/template/wasm/indexd_wasm/indexd_wasm.d.ts +0 -309
- package/template/wasm/indexd_wasm/indexd_wasm.js +0 -1507
- package/template/wasm/indexd_wasm/indexd_wasm_bg.wasm +0 -0
- package/template/wasm/indexd_wasm/package.json +0 -31
|
@@ -1,1507 +0,0 @@
|
|
|
1
|
-
use crate::rhp::merkle;
|
|
2
|
-
use bytes::Bytes;
|
|
3
|
-
use serde::{Deserialize, Serialize};
|
|
4
|
-
use std::fmt::Display;
|
|
5
|
-
use std::marker::PhantomData;
|
|
6
|
-
use thiserror::Error;
|
|
7
|
-
use tokio::sync::oneshot;
|
|
8
|
-
|
|
9
|
-
use super::types::*;
|
|
10
|
-
use crate::consensus::ChainState;
|
|
11
|
-
use crate::encoding::{Error as EncodingError, SiaEncodable};
|
|
12
|
-
use crate::encoding_async::{
|
|
13
|
-
AsyncDecoder, AsyncEncoder, AsyncSiaDecodable, AsyncSiaDecode, AsyncSiaEncodable,
|
|
14
|
-
AsyncSiaEncode,
|
|
15
|
-
};
|
|
16
|
-
use crate::rhp::merkle::ProofValidationError;
|
|
17
|
-
use crate::rhp::{self, SECTOR_SIZE};
|
|
18
|
-
use blake2b_simd::Params;
|
|
19
|
-
|
|
20
|
-
use crate::signing::{PrivateKey, PublicKey, Signature};
|
|
21
|
-
use crate::types::v2::{FileContract, SatisfiedPolicy, SiacoinElement, SiacoinInput, Transaction};
|
|
22
|
-
use crate::types::{
|
|
23
|
-
Address, ChainIndex, Currency, FileContractID, Hash256, Leaf, SiacoinOutput, specifier,
|
|
24
|
-
};
|
|
25
|
-
|
|
26
|
-
macro_rules! impl_rpc_request {
|
|
27
|
-
($name:ident, $text:literal) => {
|
|
28
|
-
impl RPCRequest for $name {
|
|
29
|
-
async fn encode_request<E: AsyncEncoder>(&self, w: &mut E) -> Result<(), E::Error> {
|
|
30
|
-
specifier!($text).encode_async(w).await?;
|
|
31
|
-
self.encode_async(w).await?;
|
|
32
|
-
Ok(())
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
impl sealed::Sealed for $name {}
|
|
36
|
-
};
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
macro_rules! impl_rpc_response {
|
|
40
|
-
($name:ident) => {
|
|
41
|
-
impl RPCResponse for $name {
|
|
42
|
-
async fn encode_response<E: AsyncEncoder>(&self, w: &mut E) -> Result<(), E::Error> {
|
|
43
|
-
false.encode_async(w).await?; // nil error
|
|
44
|
-
self.encode_async(w).await?;
|
|
45
|
-
Ok(())
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
async fn decode_response<D: AsyncDecoder>(r: &mut D) -> Result<Self, D::Error>
|
|
49
|
-
where
|
|
50
|
-
D::Error: From<rhp::Error>,
|
|
51
|
-
{
|
|
52
|
-
let has_error = bool::decode_async(r).await?;
|
|
53
|
-
match has_error {
|
|
54
|
-
false => {
|
|
55
|
-
let resp = Self::decode_async(r).await?;
|
|
56
|
-
Ok(resp)
|
|
57
|
-
}
|
|
58
|
-
true => {
|
|
59
|
-
let error = RPCError::decode_async(r).await?;
|
|
60
|
-
Err(Error::from(error).into())
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
impl sealed::Sealed for $name {}
|
|
67
|
-
};
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
pub trait RenterContractSigner {
|
|
71
|
-
fn public_key(&self) -> PublicKey;
|
|
72
|
-
fn sign(&self, msg: &[u8]) -> Signature;
|
|
73
|
-
fn sign_revision(&self, state: &ChainState, contract: &mut FileContract);
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
impl RenterContractSigner for PrivateKey {
|
|
77
|
-
fn public_key(&self) -> PublicKey {
|
|
78
|
-
self.public_key()
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
fn sign(&self, msg: &[u8]) -> Signature {
|
|
82
|
-
self.sign(msg)
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
fn sign_revision(&self, state: &ChainState, contract: &mut FileContract) {
|
|
86
|
-
let sig_hash = contract.sig_hash(state);
|
|
87
|
-
contract.renter_signature = self.sign(sig_hash.as_ref());
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
pub trait TransactionBuilder {
|
|
92
|
-
fn miner_fee(&self) -> Currency;
|
|
93
|
-
fn fund_transaction(
|
|
94
|
-
&self,
|
|
95
|
-
transaction: &mut Transaction,
|
|
96
|
-
amount: Currency,
|
|
97
|
-
) -> Result<ChainIndex, RPCError>;
|
|
98
|
-
fn sign_transaction(&self, transaction: &mut Transaction) -> Result<(), RPCError>;
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
/// HostInputsResponse contains the host's Siacoin inputs for funding a
|
|
102
|
-
/// formation or resolution transaction.
|
|
103
|
-
#[derive(Debug, PartialEq, AsyncSiaEncode, AsyncSiaDecode)]
|
|
104
|
-
struct HostInputsResponse {
|
|
105
|
-
pub host_inputs: Vec<SiacoinInput>,
|
|
106
|
-
}
|
|
107
|
-
impl_rpc_response!(HostInputsResponse);
|
|
108
|
-
|
|
109
|
-
/// RPCFormContractThirdResponse contains the finalized formation
|
|
110
|
-
/// transaction set.
|
|
111
|
-
#[derive(Debug, PartialEq, AsyncSiaEncode, AsyncSiaDecode)]
|
|
112
|
-
struct TransactionSetResponse {
|
|
113
|
-
pub basis: ChainIndex,
|
|
114
|
-
pub transaction_set: Vec<Transaction>,
|
|
115
|
-
}
|
|
116
|
-
impl_rpc_response!(TransactionSetResponse);
|
|
117
|
-
|
|
118
|
-
/// HostSignatureResponse contains the host's signature for a
|
|
119
|
-
/// contract revision.
|
|
120
|
-
#[derive(Debug, PartialEq, AsyncSiaEncode, AsyncSiaDecode)]
|
|
121
|
-
#[allow(dead_code)] // TODO: use RPC
|
|
122
|
-
struct HostSignatureResponse {
|
|
123
|
-
pub host_signature: Signature,
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
/// RenterSignatureResponse contains the renter's signature for a
|
|
127
|
-
/// contract revision.
|
|
128
|
-
#[derive(Debug, PartialEq, AsyncSiaEncode, AsyncSiaDecode)]
|
|
129
|
-
#[allow(dead_code)] // TODO: use RPC
|
|
130
|
-
struct RenterSignatureResponse {
|
|
131
|
-
pub renter_signature: Signature,
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
/// RenterResolutionSignaturesResponse contains the renter's signatures for the
|
|
135
|
-
/// contract resolution transaction.
|
|
136
|
-
///
|
|
137
|
-
/// At this point, the host has enough information to broadcast the refresh.
|
|
138
|
-
#[derive(Debug, PartialEq, AsyncSiaEncode, AsyncSiaDecode)]
|
|
139
|
-
#[allow(dead_code)] // TODO: use RPC
|
|
140
|
-
struct RenterResolutionSignaturesResponse {
|
|
141
|
-
pub renter_renewal_signature: Signature,
|
|
142
|
-
pub renter_contract_signature: Signature,
|
|
143
|
-
pub renter_satisfied_policies: Vec<SatisfiedPolicy>,
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
/// RPCRefreshContractParams contains the parameters for refreshing a contract.
|
|
147
|
-
#[derive(Debug, PartialEq, AsyncSiaEncode, AsyncSiaDecode)]
|
|
148
|
-
pub struct RefreshContractParams {
|
|
149
|
-
pub contract_id: FileContractID,
|
|
150
|
-
pub allowance: Currency,
|
|
151
|
-
pub collateral: Currency,
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
pub struct RPCRefreshContractRequestParams {
|
|
155
|
-
pub prices: HostPrices,
|
|
156
|
-
pub refresh: RefreshContractParams,
|
|
157
|
-
pub miner_fee: Currency,
|
|
158
|
-
pub basis: ChainIndex,
|
|
159
|
-
pub renter_inputs: Vec<SiacoinElement>,
|
|
160
|
-
pub renter_parents: Vec<Transaction>,
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
/// RPCRefreshContractRequest is the request type for RPCRefreshContract.
|
|
164
|
-
#[derive(Debug, PartialEq, AsyncSiaEncode, AsyncSiaDecode)]
|
|
165
|
-
struct RPCRefreshContractRequest {
|
|
166
|
-
pub prices: HostPrices,
|
|
167
|
-
pub refresh: RefreshContractParams,
|
|
168
|
-
pub miner_fee: Currency,
|
|
169
|
-
pub basis: ChainIndex,
|
|
170
|
-
pub renter_inputs: Vec<SiacoinElement>,
|
|
171
|
-
pub renter_parents: Vec<Transaction>,
|
|
172
|
-
|
|
173
|
-
pub challenge_signature: Signature,
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
impl RPCRefreshContractRequest {
|
|
177
|
-
#[allow(dead_code)] // TODO: remove
|
|
178
|
-
pub fn new<S: RenterContractSigner>(
|
|
179
|
-
signer: S,
|
|
180
|
-
params: RPCRefreshContractRequestParams,
|
|
181
|
-
revision_number: u64,
|
|
182
|
-
) -> Self {
|
|
183
|
-
let mut state = Params::new().hash_length(32).to_state();
|
|
184
|
-
params.refresh.contract_id.encode(&mut state).unwrap();
|
|
185
|
-
revision_number.encode(&mut state).unwrap();
|
|
186
|
-
|
|
187
|
-
Self {
|
|
188
|
-
prices: params.prices,
|
|
189
|
-
refresh: params.refresh,
|
|
190
|
-
miner_fee: params.miner_fee,
|
|
191
|
-
basis: params.basis,
|
|
192
|
-
renter_inputs: params.renter_inputs,
|
|
193
|
-
renter_parents: params.renter_parents,
|
|
194
|
-
challenge_signature: signer.sign(state.finalize().as_ref()),
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
/// RPCRenewContractParams contains the parameters for renewing a contract.
|
|
200
|
-
#[derive(Debug, PartialEq, AsyncSiaEncode, AsyncSiaDecode)]
|
|
201
|
-
struct RenewContractParams {
|
|
202
|
-
pub contract_id: FileContractID,
|
|
203
|
-
pub allowance: Currency,
|
|
204
|
-
pub collateral: Currency,
|
|
205
|
-
pub proof_height: u64,
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
struct RPCRenewContractRequestParams {
|
|
209
|
-
pub prices: HostPrices,
|
|
210
|
-
pub renewal: RenewContractParams,
|
|
211
|
-
pub miner_fee: Currency,
|
|
212
|
-
pub basis: ChainIndex,
|
|
213
|
-
pub renter_inputs: Vec<SiacoinElement>,
|
|
214
|
-
pub renter_parents: Vec<Transaction>,
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
/// RPCRenewContractRequest is the request type for RPCRenewContract.
|
|
218
|
-
#[derive(Debug, PartialEq, AsyncSiaEncode, AsyncSiaDecode)]
|
|
219
|
-
struct RPCRenewContractRequest {
|
|
220
|
-
pub prices: HostPrices,
|
|
221
|
-
pub renewal: RenewContractParams,
|
|
222
|
-
pub miner_fee: Currency,
|
|
223
|
-
pub basis: ChainIndex,
|
|
224
|
-
pub renter_inputs: Vec<SiacoinElement>,
|
|
225
|
-
pub renter_parents: Vec<Transaction>,
|
|
226
|
-
|
|
227
|
-
pub challenge_signature: Signature,
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
impl RPCRenewContractRequest {
|
|
231
|
-
#[allow(dead_code)] // TODO: remove
|
|
232
|
-
pub fn new<S: RenterContractSigner>(
|
|
233
|
-
signer: S,
|
|
234
|
-
params: RPCRenewContractRequestParams,
|
|
235
|
-
revision_number: u64,
|
|
236
|
-
) -> Self {
|
|
237
|
-
let mut state = Params::new().hash_length(32).to_state();
|
|
238
|
-
params.renewal.contract_id.encode(&mut state).unwrap();
|
|
239
|
-
revision_number.encode(&mut state).unwrap();
|
|
240
|
-
|
|
241
|
-
Self {
|
|
242
|
-
prices: params.prices,
|
|
243
|
-
renewal: params.renewal,
|
|
244
|
-
miner_fee: params.miner_fee,
|
|
245
|
-
basis: params.basis,
|
|
246
|
-
renter_inputs: params.renter_inputs,
|
|
247
|
-
renter_parents: params.renter_parents,
|
|
248
|
-
challenge_signature: signer.sign(state.finalize().as_ref()),
|
|
249
|
-
}
|
|
250
|
-
}
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
pub struct RPCFreeSectorsRequestParams {
|
|
254
|
-
pub contract_id: FileContractID,
|
|
255
|
-
pub prices: HostPrices,
|
|
256
|
-
pub indices: Vec<u64>,
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
/// RPCFreeSectorsRequest is the request type for removing sectors from a contract.
|
|
260
|
-
#[derive(Debug, PartialEq, AsyncSiaEncode, AsyncSiaDecode)]
|
|
261
|
-
struct RPCFreeSectorsRequest {
|
|
262
|
-
pub contract_id: FileContractID,
|
|
263
|
-
pub prices: HostPrices,
|
|
264
|
-
pub indices: Vec<u64>,
|
|
265
|
-
|
|
266
|
-
pub challenge_signature: Signature,
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
impl RPCFreeSectorsRequest {
|
|
270
|
-
#[allow(dead_code)] // TODO: remove
|
|
271
|
-
pub fn new<S: RenterContractSigner>(
|
|
272
|
-
signer: S,
|
|
273
|
-
params: RPCFreeSectorsRequestParams,
|
|
274
|
-
revision_number: u64,
|
|
275
|
-
) -> Self {
|
|
276
|
-
let mut state = Params::new().hash_length(32).to_state();
|
|
277
|
-
params.contract_id.encode(&mut state).unwrap();
|
|
278
|
-
revision_number.encode(&mut state).unwrap();
|
|
279
|
-
|
|
280
|
-
RPCFreeSectorsRequest {
|
|
281
|
-
contract_id: params.contract_id,
|
|
282
|
-
prices: params.prices,
|
|
283
|
-
indices: params.indices,
|
|
284
|
-
challenge_signature: signer.sign(state.finalize().as_ref()),
|
|
285
|
-
}
|
|
286
|
-
}
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
/// RPCFreeSectorsResponse contains the host's old subtree hashes, old leaf hashes,
|
|
290
|
-
/// and the new merkle root after freeing sectors.
|
|
291
|
-
///
|
|
292
|
-
/// The renter must validate the response
|
|
293
|
-
#[derive(Debug, PartialEq, AsyncSiaEncode, AsyncSiaDecode)]
|
|
294
|
-
#[allow(dead_code)] // TODO: use RPC
|
|
295
|
-
struct RPCFreeSectorsResponse {
|
|
296
|
-
pub old_subtree_hashes: Vec<Hash256>,
|
|
297
|
-
pub old_leaf_hashes: Vec<Hash256>,
|
|
298
|
-
pub new_merkle_root: Hash256,
|
|
299
|
-
}
|
|
300
|
-
impl_rpc_response!(RPCFreeSectorsResponse);
|
|
301
|
-
|
|
302
|
-
/// RPCLatestRevisionRequest is the request type for getting the latest
|
|
303
|
-
/// revision of a file contract.
|
|
304
|
-
#[derive(Debug, PartialEq, AsyncSiaEncode, AsyncSiaDecode)]
|
|
305
|
-
#[allow(dead_code)] // TODO: use RPC
|
|
306
|
-
struct RPCLatestRevisionRequest {
|
|
307
|
-
pub contract_id: FileContractID,
|
|
308
|
-
}
|
|
309
|
-
|
|
310
|
-
/// RPCLatestRevisionResponse contains the latest revision of a file contract,
|
|
311
|
-
/// whether it is revisable, and whether it has been renewed.
|
|
312
|
-
///
|
|
313
|
-
/// If either `revisable` or `renewed` is false, the host will not accept
|
|
314
|
-
/// further revisions or renewals of the contract.
|
|
315
|
-
#[derive(Debug, PartialEq, AsyncSiaEncode, AsyncSiaDecode)]
|
|
316
|
-
#[allow(dead_code)] // TODO: use RPC
|
|
317
|
-
struct RPCLatestRevisionResponse {
|
|
318
|
-
pub contract: FileContract,
|
|
319
|
-
pub revisable: bool,
|
|
320
|
-
pub renewed: bool,
|
|
321
|
-
}
|
|
322
|
-
|
|
323
|
-
struct RPCAppendSectorsRequestParams {
|
|
324
|
-
pub prices: HostPrices,
|
|
325
|
-
pub sectors: Vec<Hash256>,
|
|
326
|
-
pub contract_id: FileContractID,
|
|
327
|
-
}
|
|
328
|
-
|
|
329
|
-
/// RPCAppendSectorsRequest is the request type for appending sectors to a contract.
|
|
330
|
-
#[derive(Debug, PartialEq, AsyncSiaEncode, AsyncSiaDecode)]
|
|
331
|
-
struct RPCAppendSectorsRequest {
|
|
332
|
-
pub prices: HostPrices,
|
|
333
|
-
pub sectors: Vec<Hash256>,
|
|
334
|
-
pub contract_id: FileContractID,
|
|
335
|
-
|
|
336
|
-
pub challenge_signature: Signature,
|
|
337
|
-
}
|
|
338
|
-
|
|
339
|
-
impl RPCAppendSectorsRequest {
|
|
340
|
-
#[allow(dead_code)] // TODO: remove
|
|
341
|
-
pub fn new<S: RenterContractSigner>(
|
|
342
|
-
signer: S,
|
|
343
|
-
params: RPCAppendSectorsRequestParams,
|
|
344
|
-
revision_number: u64,
|
|
345
|
-
) -> Self {
|
|
346
|
-
let mut state = Params::new().hash_length(32).to_state();
|
|
347
|
-
params.contract_id.encode(&mut state).unwrap();
|
|
348
|
-
revision_number.encode(&mut state).unwrap();
|
|
349
|
-
Self {
|
|
350
|
-
prices: params.prices,
|
|
351
|
-
sectors: params.sectors,
|
|
352
|
-
contract_id: params.contract_id,
|
|
353
|
-
challenge_signature: signer.sign(state.finalize().as_ref()),
|
|
354
|
-
}
|
|
355
|
-
}
|
|
356
|
-
}
|
|
357
|
-
|
|
358
|
-
/// RPCAppendSectorsResponse contains the host's response to an append request.
|
|
359
|
-
///
|
|
360
|
-
/// It includes the sectors that were accepted, the subtree roots, and the new
|
|
361
|
-
/// merkle root after the append operation. The renter must validate the proof
|
|
362
|
-
/// against the accepted roots.
|
|
363
|
-
#[derive(Debug, PartialEq, AsyncSiaEncode, AsyncSiaDecode)]
|
|
364
|
-
#[allow(dead_code)] // TODO: use RPC
|
|
365
|
-
struct RPCAppendSectorsResponse {
|
|
366
|
-
pub accepted: Vec<bool>,
|
|
367
|
-
pub subtree_roots: Vec<Hash256>,
|
|
368
|
-
pub new_merkle_root: Hash256,
|
|
369
|
-
}
|
|
370
|
-
|
|
371
|
-
/// RPCSectorRootsRequest is the request type for getting the sector roots
|
|
372
|
-
/// for a contract.
|
|
373
|
-
#[derive(Debug, PartialEq, AsyncSiaEncode, AsyncSiaDecode)]
|
|
374
|
-
#[allow(dead_code)] // TODO: use RPC
|
|
375
|
-
struct RPCSectorRootsRequest {
|
|
376
|
-
pub prices: HostPrices,
|
|
377
|
-
pub contract_id: FileContractID,
|
|
378
|
-
pub renter_signature: Signature,
|
|
379
|
-
pub offset: u64,
|
|
380
|
-
pub length: u64,
|
|
381
|
-
}
|
|
382
|
-
|
|
383
|
-
/// RPCSectorRootsResponse contains the sector roots and a proof for a contract.
|
|
384
|
-
/// The renter must validate the proof against the roots.
|
|
385
|
-
#[derive(Debug, PartialEq, AsyncSiaEncode, AsyncSiaDecode)]
|
|
386
|
-
#[allow(dead_code)] // TODO: use RPC
|
|
387
|
-
struct RPCSectorRootsResponse {
|
|
388
|
-
pub proof: Vec<Hash256>,
|
|
389
|
-
pub roots: Vec<Hash256>,
|
|
390
|
-
pub host_signature: Signature,
|
|
391
|
-
}
|
|
392
|
-
|
|
393
|
-
struct RPCReplenishAccountsParams {
|
|
394
|
-
pub accounts: Vec<PublicKey>,
|
|
395
|
-
pub target: Currency,
|
|
396
|
-
pub contract_id: FileContractID,
|
|
397
|
-
}
|
|
398
|
-
|
|
399
|
-
/// RPCReplenishAccountsRequest is the request type for replenishing accounts
|
|
400
|
-
/// with Siacoin deposits.
|
|
401
|
-
///
|
|
402
|
-
/// The host will fund the account to the target amount and send
|
|
403
|
-
/// a revision to the renter for verification.
|
|
404
|
-
#[derive(Debug, PartialEq, AsyncSiaEncode, AsyncSiaDecode)]
|
|
405
|
-
struct RPCReplenishAccountsRequest {
|
|
406
|
-
pub accounts: Vec<PublicKey>,
|
|
407
|
-
pub target: Currency,
|
|
408
|
-
pub contract_id: FileContractID,
|
|
409
|
-
|
|
410
|
-
pub challenge_signature: Signature,
|
|
411
|
-
}
|
|
412
|
-
|
|
413
|
-
impl RPCReplenishAccountsRequest {
|
|
414
|
-
#[allow(dead_code)] // TODO: remove
|
|
415
|
-
pub fn new<S: RenterContractSigner>(
|
|
416
|
-
signer: S,
|
|
417
|
-
params: RPCReplenishAccountsParams,
|
|
418
|
-
revision_number: u64,
|
|
419
|
-
) -> Self {
|
|
420
|
-
let mut state = Params::new().hash_length(32).to_state();
|
|
421
|
-
params.accounts.encode(&mut state).unwrap();
|
|
422
|
-
params.target.encode(&mut state).unwrap();
|
|
423
|
-
params.contract_id.encode(&mut state).unwrap();
|
|
424
|
-
revision_number.encode(&mut state).unwrap();
|
|
425
|
-
|
|
426
|
-
Self {
|
|
427
|
-
accounts: params.accounts,
|
|
428
|
-
target: params.target,
|
|
429
|
-
contract_id: params.contract_id,
|
|
430
|
-
challenge_signature: signer.sign(state.finalize().as_ref()),
|
|
431
|
-
}
|
|
432
|
-
}
|
|
433
|
-
}
|
|
434
|
-
|
|
435
|
-
/// RPCReplenishAccountsResponse contains the host's response to the replenish
|
|
436
|
-
/// request.
|
|
437
|
-
///
|
|
438
|
-
/// The renter should verify the deposits and construct a revision
|
|
439
|
-
/// transferring the funds.
|
|
440
|
-
#[derive(Debug, PartialEq, AsyncSiaEncode, AsyncSiaDecode)]
|
|
441
|
-
#[allow(dead_code)] // TODO: use RPC
|
|
442
|
-
struct RPCReplenishAccountsResponse {
|
|
443
|
-
pub deposits: Vec<AccountDeposit>,
|
|
444
|
-
}
|
|
445
|
-
|
|
446
|
-
/// RPCVerifySectorRequest is the request type for verifying the host
|
|
447
|
-
/// is storing a sector.
|
|
448
|
-
#[derive(Debug, PartialEq, AsyncSiaEncode, AsyncSiaDecode)]
|
|
449
|
-
#[allow(dead_code)] // TODO: use RPC
|
|
450
|
-
struct RPCVerifySectorRequest {
|
|
451
|
-
pub prices: HostPrices,
|
|
452
|
-
pub token: AccountToken,
|
|
453
|
-
pub root: Hash256,
|
|
454
|
-
pub leaf_index: u64,
|
|
455
|
-
}
|
|
456
|
-
|
|
457
|
-
/// RPCVerifySectorResponse contains a proof that the host is storing a
|
|
458
|
-
/// sector.
|
|
459
|
-
#[derive(Debug, PartialEq, AsyncSiaEncode, AsyncSiaDecode)]
|
|
460
|
-
#[allow(dead_code)] // TODO: use RPC
|
|
461
|
-
struct RPCVerifySectorResponse {
|
|
462
|
-
pub proof: Vec<Hash256>,
|
|
463
|
-
pub leaf: Leaf,
|
|
464
|
-
}
|
|
465
|
-
|
|
466
|
-
/// RPCFundAccountsRequest is the request type for funding accounts
|
|
467
|
-
/// with Siacoin deposits.
|
|
468
|
-
///
|
|
469
|
-
/// RPCReplenishAccounts should be preferred
|
|
470
|
-
#[derive(Debug, PartialEq, AsyncSiaEncode, AsyncSiaDecode)]
|
|
471
|
-
#[allow(dead_code)] // TODO: use RPC
|
|
472
|
-
struct RPCFundAccountsRequest {
|
|
473
|
-
pub contract_id: FileContractID,
|
|
474
|
-
pub deposits: Vec<AccountDeposit>,
|
|
475
|
-
pub renter_signature: Signature,
|
|
476
|
-
}
|
|
477
|
-
|
|
478
|
-
/// RPCFundAccountsResponse contains the host's signature and new
|
|
479
|
-
/// balance after funding the accounts.
|
|
480
|
-
#[derive(Debug, PartialEq, AsyncSiaEncode, AsyncSiaDecode)]
|
|
481
|
-
#[allow(dead_code)] // TODO: use RPC
|
|
482
|
-
struct RPCFundAccountsResponse {
|
|
483
|
-
pub balances: Vec<Currency>,
|
|
484
|
-
pub host_signature: Signature,
|
|
485
|
-
}
|
|
486
|
-
|
|
487
|
-
/// RPCError is the error type returned by the RPC server.
|
|
488
|
-
#[derive(Debug, PartialEq, AsyncSiaDecode, AsyncSiaEncode)]
|
|
489
|
-
pub struct RPCError {
|
|
490
|
-
pub code: u8,
|
|
491
|
-
pub description: String,
|
|
492
|
-
}
|
|
493
|
-
|
|
494
|
-
impl Display for RPCError {
|
|
495
|
-
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
496
|
-
write!(f, "{} ({})", self.description, self.code)
|
|
497
|
-
}
|
|
498
|
-
}
|
|
499
|
-
|
|
500
|
-
impl std::error::Error for RPCError {}
|
|
501
|
-
|
|
502
|
-
#[derive(Debug, Error)]
|
|
503
|
-
pub enum Error {
|
|
504
|
-
#[error("IO error: {0}")]
|
|
505
|
-
Io(#[from] std::io::Error),
|
|
506
|
-
#[error("Encoding error: {0}")]
|
|
507
|
-
Encoding(#[from] EncodingError),
|
|
508
|
-
|
|
509
|
-
#[error("RPC error: {0}")]
|
|
510
|
-
RPC(#[from] RPCError),
|
|
511
|
-
|
|
512
|
-
#[error("not enough host funds {0} < {1}")]
|
|
513
|
-
NotEnoughHostFunds(Currency, Currency),
|
|
514
|
-
|
|
515
|
-
#[error("invalid response: {0}")]
|
|
516
|
-
InvalidResponse(String),
|
|
517
|
-
|
|
518
|
-
#[error("invalid signature")]
|
|
519
|
-
InvalidSignature,
|
|
520
|
-
|
|
521
|
-
#[error("expected single file contract in response, found {0}")]
|
|
522
|
-
ExpectedContractTransaction(usize),
|
|
523
|
-
|
|
524
|
-
#[error("expected transaction set in response")]
|
|
525
|
-
ExpectedTransactionSet,
|
|
526
|
-
|
|
527
|
-
#[error("proof validation failed")]
|
|
528
|
-
ProofValidation(#[from] ProofValidationError),
|
|
529
|
-
|
|
530
|
-
#[error(
|
|
531
|
-
"root of uploaded data doesn't match root returned by host: expected {expected}, got {got}"
|
|
532
|
-
)]
|
|
533
|
-
SectorRootMismatch { expected: Hash256, got: Hash256 },
|
|
534
|
-
}
|
|
535
|
-
|
|
536
|
-
#[derive(Debug, Default, PartialEq, Clone, Copy, Serialize, Deserialize)]
|
|
537
|
-
#[serde(rename_all = "camelCase")]
|
|
538
|
-
pub struct Usage {
|
|
539
|
-
pub rpc: Currency,
|
|
540
|
-
pub storage: Currency,
|
|
541
|
-
pub egress: Currency,
|
|
542
|
-
pub ingress: Currency,
|
|
543
|
-
pub account_funding: Currency,
|
|
544
|
-
pub risked_collateral: Currency,
|
|
545
|
-
}
|
|
546
|
-
|
|
547
|
-
impl Usage {
|
|
548
|
-
const fn round_4kib(size: u64) -> u64 {
|
|
549
|
-
(size + 4095) & !4095
|
|
550
|
-
}
|
|
551
|
-
|
|
552
|
-
pub fn renter_cost(&self) -> Currency {
|
|
553
|
-
self.rpc + self.storage + self.egress + self.ingress + self.account_funding
|
|
554
|
-
}
|
|
555
|
-
|
|
556
|
-
pub fn host_collateral(&self) -> Currency {
|
|
557
|
-
self.risked_collateral
|
|
558
|
-
}
|
|
559
|
-
|
|
560
|
-
pub fn write_sector(prices: &HostPrices, data_length: usize) -> Self {
|
|
561
|
-
const TEMP_SECTOR_DURATION: u64 = 144 * 3;
|
|
562
|
-
let data_length = Currency::from(Self::round_4kib(data_length as u64));
|
|
563
|
-
Usage {
|
|
564
|
-
storage: prices.storage_price * data_length * Currency::from(TEMP_SECTOR_DURATION),
|
|
565
|
-
ingress: prices.ingress_price * data_length,
|
|
566
|
-
..Default::default()
|
|
567
|
-
}
|
|
568
|
-
}
|
|
569
|
-
|
|
570
|
-
pub fn read_sector(prices: &HostPrices, data_length: usize) -> Self {
|
|
571
|
-
Usage {
|
|
572
|
-
egress: prices.egress_price * Currency::from(Self::round_4kib(data_length as u64)),
|
|
573
|
-
..Default::default()
|
|
574
|
-
}
|
|
575
|
-
}
|
|
576
|
-
|
|
577
|
-
pub fn sector_roots(prices: &HostPrices, num_roots: usize) -> Self {
|
|
578
|
-
Usage {
|
|
579
|
-
egress: prices.egress_price * Currency::from(Self::round_4kib(32 * (num_roots as u64))),
|
|
580
|
-
..Default::default()
|
|
581
|
-
}
|
|
582
|
-
}
|
|
583
|
-
|
|
584
|
-
pub fn verify_sector(prices: &HostPrices) -> Self {
|
|
585
|
-
Usage {
|
|
586
|
-
egress: prices.egress_price * Currency::from(SECTOR_SIZE),
|
|
587
|
-
..Default::default()
|
|
588
|
-
}
|
|
589
|
-
}
|
|
590
|
-
|
|
591
|
-
pub fn free_sectors(prices: &HostPrices, num_sectors: usize) -> Self {
|
|
592
|
-
Usage {
|
|
593
|
-
rpc: prices.free_sector_price * Currency::from(num_sectors),
|
|
594
|
-
..Default::default()
|
|
595
|
-
}
|
|
596
|
-
}
|
|
597
|
-
|
|
598
|
-
pub fn append_sectors(prices: &HostPrices, num_sectors: usize, duration: u64) -> Self {
|
|
599
|
-
Usage {
|
|
600
|
-
storage: prices.storage_price * Currency::from(num_sectors) * Currency::from(duration),
|
|
601
|
-
ingress: prices.ingress_price
|
|
602
|
-
* Currency::from(Self::round_4kib(32 * num_sectors as u64)),
|
|
603
|
-
risked_collateral: prices.collateral
|
|
604
|
-
* Currency::from(num_sectors)
|
|
605
|
-
* Currency::from(duration),
|
|
606
|
-
..Default::default()
|
|
607
|
-
}
|
|
608
|
-
}
|
|
609
|
-
|
|
610
|
-
pub fn form_contract(prices: &HostPrices) -> Self {
|
|
611
|
-
Usage {
|
|
612
|
-
rpc: prices.contract_price,
|
|
613
|
-
..Default::default()
|
|
614
|
-
}
|
|
615
|
-
}
|
|
616
|
-
}
|
|
617
|
-
|
|
618
|
-
pub trait RPCRequest: Sized + sealed::Sealed {
|
|
619
|
-
fn encode_request<E: AsyncEncoder>(
|
|
620
|
-
&self,
|
|
621
|
-
w: &mut E,
|
|
622
|
-
) -> impl Future<Output = Result<(), E::Error>>;
|
|
623
|
-
}
|
|
624
|
-
|
|
625
|
-
pub trait RPCResponse: Sized + sealed::Sealed {
|
|
626
|
-
fn decode_response<D: AsyncDecoder>(r: &mut D) -> impl Future<Output = Result<Self, D::Error>>
|
|
627
|
-
where
|
|
628
|
-
D::Error: From<rhp::Error>;
|
|
629
|
-
fn encode_response<E: AsyncEncoder>(
|
|
630
|
-
&self,
|
|
631
|
-
w: &mut E,
|
|
632
|
-
) -> impl Future<Output = Result<(), E::Error>>;
|
|
633
|
-
}
|
|
634
|
-
|
|
635
|
-
mod sealed {
|
|
636
|
-
pub trait Sealed {}
|
|
637
|
-
}
|
|
638
|
-
|
|
639
|
-
pub trait Transport {
|
|
640
|
-
type Error: From<Error>;
|
|
641
|
-
|
|
642
|
-
fn write_request<R: RPCRequest>(
|
|
643
|
-
&mut self,
|
|
644
|
-
request: &R,
|
|
645
|
-
) -> impl Future<Output = Result<(), Self::Error>>;
|
|
646
|
-
|
|
647
|
-
fn write_bytes(&mut self, data: Bytes) -> impl Future<Output = Result<(), Self::Error>>;
|
|
648
|
-
|
|
649
|
-
fn write_response<R: RPCResponse>(
|
|
650
|
-
&mut self,
|
|
651
|
-
response: &R,
|
|
652
|
-
) -> impl Future<Output = Result<(), Self::Error>>;
|
|
653
|
-
|
|
654
|
-
fn read_response<R: RPCResponse>(&mut self) -> impl Future<Output = Result<R, Self::Error>>;
|
|
655
|
-
}
|
|
656
|
-
|
|
657
|
-
/// Marker type for the initial stage of the RPC process.
|
|
658
|
-
pub struct RPCInit;
|
|
659
|
-
|
|
660
|
-
/// Marker type for the waiting stage for host inputs.
|
|
661
|
-
pub struct RPCAwaitingHostInputs;
|
|
662
|
-
|
|
663
|
-
/// Marker type for the waiting stage for host signatures.
|
|
664
|
-
pub struct RPCAwaitingHostSignatures;
|
|
665
|
-
|
|
666
|
-
/// Marker type for the waiting stage for renter signatures.
|
|
667
|
-
pub struct RPCAwaitingRenterSignatures;
|
|
668
|
-
|
|
669
|
-
/// Marker type for the completion stage of the RPC process.
|
|
670
|
-
pub struct RPCComplete;
|
|
671
|
-
|
|
672
|
-
/// RPCSettingsRequest is the request type getting the host's current settings.
|
|
673
|
-
/// It is encoded as 0 bytes.
|
|
674
|
-
#[derive(Debug, PartialEq, AsyncSiaEncode, AsyncSiaDecode)]
|
|
675
|
-
struct RPCSettingsRequest {}
|
|
676
|
-
|
|
677
|
-
impl_rpc_request!(RPCSettingsRequest, "Settings");
|
|
678
|
-
|
|
679
|
-
/// RPCSettingsResponse is the response type for the RPC settings endpoint.
|
|
680
|
-
#[derive(Debug, PartialEq, AsyncSiaDecode, AsyncSiaEncode)]
|
|
681
|
-
struct RPCSettingsResponse {
|
|
682
|
-
pub settings: HostSettings,
|
|
683
|
-
}
|
|
684
|
-
impl_rpc_response!(RPCSettingsResponse);
|
|
685
|
-
|
|
686
|
-
#[derive(Debug, Serialize, Deserialize)]
|
|
687
|
-
#[serde(rename_all = "camelCase")]
|
|
688
|
-
pub struct RPCSettingsResult {
|
|
689
|
-
pub settings: HostSettings,
|
|
690
|
-
pub usage: Usage,
|
|
691
|
-
}
|
|
692
|
-
|
|
693
|
-
/// RPCSettings returns the host's current settings.
|
|
694
|
-
pub struct RPCSettings<T: Transport, State> {
|
|
695
|
-
transport: T,
|
|
696
|
-
state: PhantomData<State>,
|
|
697
|
-
}
|
|
698
|
-
|
|
699
|
-
impl<T: Transport> RPCSettings<T, RPCInit> {
|
|
700
|
-
pub async fn send_request(mut transport: T) -> Result<RPCSettings<T, RPCComplete>, T::Error> {
|
|
701
|
-
transport.write_request(&RPCSettingsRequest {}).await?;
|
|
702
|
-
|
|
703
|
-
Ok(RPCSettings {
|
|
704
|
-
transport,
|
|
705
|
-
state: PhantomData,
|
|
706
|
-
})
|
|
707
|
-
}
|
|
708
|
-
}
|
|
709
|
-
|
|
710
|
-
impl<T: Transport> RPCSettings<T, RPCComplete> {
|
|
711
|
-
pub async fn complete(mut self) -> Result<RPCSettingsResult, T::Error> {
|
|
712
|
-
let response: RPCSettingsResponse = self.transport.read_response().await?;
|
|
713
|
-
Ok(RPCSettingsResult {
|
|
714
|
-
settings: response.settings,
|
|
715
|
-
usage: Usage::default(),
|
|
716
|
-
})
|
|
717
|
-
}
|
|
718
|
-
}
|
|
719
|
-
|
|
720
|
-
/// RPCWriteSectorRequest is the request type for writing a sector to the host's
|
|
721
|
-
/// temporary storage.
|
|
722
|
-
///
|
|
723
|
-
/// The host will store the sector for 432 blocks. If the sector is not
|
|
724
|
-
/// appended to a contract within that time, it will be deleted.
|
|
725
|
-
#[derive(Debug, PartialEq, AsyncSiaEncode, AsyncSiaDecode)]
|
|
726
|
-
struct RPCWriteSectorRequest {
|
|
727
|
-
pub prices: HostPrices,
|
|
728
|
-
pub token: AccountToken,
|
|
729
|
-
pub data_len: usize,
|
|
730
|
-
}
|
|
731
|
-
impl_rpc_request!(RPCWriteSectorRequest, "WriteSector");
|
|
732
|
-
|
|
733
|
-
/// RPCWriteSectorResponse contains the root hash of the written sector.
|
|
734
|
-
///
|
|
735
|
-
/// The renter must verify the root hash against the data written.
|
|
736
|
-
#[derive(Debug, PartialEq, AsyncSiaEncode, AsyncSiaDecode)]
|
|
737
|
-
struct RPCWriteSectorResponse {
|
|
738
|
-
pub root: Hash256,
|
|
739
|
-
}
|
|
740
|
-
impl_rpc_response!(RPCWriteSectorResponse);
|
|
741
|
-
|
|
742
|
-
/// RPCWriteSectorResult contains the result of a write sector operation,
|
|
743
|
-
pub struct RPCWriteSectorResult {
|
|
744
|
-
pub root: Hash256,
|
|
745
|
-
pub usage: Usage,
|
|
746
|
-
}
|
|
747
|
-
|
|
748
|
-
/// RPCWriteSector writes a sector to the host's temporary storage.
|
|
749
|
-
/// The host will store the sector for 432 blocks.
|
|
750
|
-
/// If the sector is not appended to a contract within that time, it will be deleted.
|
|
751
|
-
pub struct RPCWriteSector<T: Transport, State> {
|
|
752
|
-
root: Hash256,
|
|
753
|
-
transport: T,
|
|
754
|
-
usage: Usage,
|
|
755
|
-
state: PhantomData<State>,
|
|
756
|
-
}
|
|
757
|
-
|
|
758
|
-
impl<T: Transport> RPCWriteSector<T, RPCInit> {
|
|
759
|
-
pub async fn send_request(
|
|
760
|
-
mut transport: T,
|
|
761
|
-
prices: HostPrices,
|
|
762
|
-
token: AccountToken,
|
|
763
|
-
data: Bytes,
|
|
764
|
-
) -> Result<RPCWriteSector<T, RPCComplete>, T::Error> {
|
|
765
|
-
let usage = Usage::write_sector(&prices, data.len());
|
|
766
|
-
let request = RPCWriteSectorRequest {
|
|
767
|
-
prices,
|
|
768
|
-
token,
|
|
769
|
-
data_len: data.len(),
|
|
770
|
-
};
|
|
771
|
-
|
|
772
|
-
#[cfg(not(target_arch = "wasm32"))]
|
|
773
|
-
let root_rx = {
|
|
774
|
-
let (tx, rx) = oneshot::channel();
|
|
775
|
-
let root_data = data.clone();
|
|
776
|
-
rayon::spawn(move || {
|
|
777
|
-
let root = merkle::sector_root(root_data.as_ref());
|
|
778
|
-
let _ = tx.send(root);
|
|
779
|
-
});
|
|
780
|
-
Some(rx)
|
|
781
|
-
};
|
|
782
|
-
#[cfg(target_arch = "wasm32")]
|
|
783
|
-
let root_rx: Option<oneshot::Receiver<crate::types::Hash256>> = None;
|
|
784
|
-
|
|
785
|
-
transport.write_request(&request).await?;
|
|
786
|
-
transport.write_bytes(data.clone()).await?;
|
|
787
|
-
|
|
788
|
-
let root = match root_rx {
|
|
789
|
-
Some(rx) => rx.await.unwrap(),
|
|
790
|
-
None => merkle::sector_root(data.as_ref()),
|
|
791
|
-
};
|
|
792
|
-
|
|
793
|
-
Ok(RPCWriteSector {
|
|
794
|
-
root,
|
|
795
|
-
transport,
|
|
796
|
-
usage,
|
|
797
|
-
state: PhantomData,
|
|
798
|
-
})
|
|
799
|
-
}
|
|
800
|
-
}
|
|
801
|
-
|
|
802
|
-
impl<T: Transport> RPCWriteSector<T, RPCComplete> {
|
|
803
|
-
pub async fn complete(mut self) -> Result<RPCWriteSectorResult, T::Error> {
|
|
804
|
-
let response: RPCWriteSectorResponse = self.transport.read_response().await?;
|
|
805
|
-
if response.root != self.root {
|
|
806
|
-
return Err(Error::SectorRootMismatch {
|
|
807
|
-
expected: self.root,
|
|
808
|
-
got: response.root,
|
|
809
|
-
}
|
|
810
|
-
.into());
|
|
811
|
-
}
|
|
812
|
-
|
|
813
|
-
Ok(RPCWriteSectorResult {
|
|
814
|
-
root: response.root,
|
|
815
|
-
usage: self.usage,
|
|
816
|
-
})
|
|
817
|
-
}
|
|
818
|
-
}
|
|
819
|
-
|
|
820
|
-
/// RPCReadSectorRequest is the request type for reading a sector from the
|
|
821
|
-
/// host.
|
|
822
|
-
#[derive(Debug, PartialEq, AsyncSiaEncode, AsyncSiaDecode)]
|
|
823
|
-
struct RPCReadSectorRequest {
|
|
824
|
-
pub prices: HostPrices,
|
|
825
|
-
pub token: AccountToken,
|
|
826
|
-
pub root: Hash256,
|
|
827
|
-
pub offset: u64,
|
|
828
|
-
pub length: u64,
|
|
829
|
-
}
|
|
830
|
-
impl_rpc_request!(RPCReadSectorRequest, "ReadSector");
|
|
831
|
-
|
|
832
|
-
/// RPCReadSectorResponse contains the proof and data for a sector read request.
|
|
833
|
-
/// The renter must validate the proof against the root hash.
|
|
834
|
-
#[derive(Debug, PartialEq, AsyncSiaEncode, AsyncSiaDecode)]
|
|
835
|
-
struct RPCReadSectorResponse {
|
|
836
|
-
pub data: merkle::RangeProof,
|
|
837
|
-
}
|
|
838
|
-
impl_rpc_response!(RPCReadSectorResponse);
|
|
839
|
-
|
|
840
|
-
pub struct RPCReadSectorResult {
|
|
841
|
-
pub data: Bytes,
|
|
842
|
-
pub usage: Usage,
|
|
843
|
-
}
|
|
844
|
-
|
|
845
|
-
/// RPCReadSector reads a sector from the host.
|
|
846
|
-
/// The proof must be validated against the expected
|
|
847
|
-
/// root hash.
|
|
848
|
-
pub struct RPCReadSector<T: Transport, State> {
|
|
849
|
-
transport: T,
|
|
850
|
-
usage: Usage,
|
|
851
|
-
state: PhantomData<State>,
|
|
852
|
-
offset: usize,
|
|
853
|
-
length: usize,
|
|
854
|
-
root: Hash256,
|
|
855
|
-
}
|
|
856
|
-
|
|
857
|
-
impl<T: Transport> RPCReadSector<T, RPCInit> {
|
|
858
|
-
pub async fn send_request(
|
|
859
|
-
mut transport: T,
|
|
860
|
-
prices: HostPrices,
|
|
861
|
-
token: AccountToken,
|
|
862
|
-
root: Hash256,
|
|
863
|
-
offset: usize,
|
|
864
|
-
length: usize,
|
|
865
|
-
) -> Result<RPCReadSector<T, RPCComplete>, T::Error> {
|
|
866
|
-
let usage = Usage::read_sector(&prices, length);
|
|
867
|
-
let request = RPCReadSectorRequest {
|
|
868
|
-
prices,
|
|
869
|
-
token,
|
|
870
|
-
root,
|
|
871
|
-
offset: offset as u64,
|
|
872
|
-
length: length as u64,
|
|
873
|
-
};
|
|
874
|
-
transport.write_request(&request).await?;
|
|
875
|
-
|
|
876
|
-
Ok(RPCReadSector {
|
|
877
|
-
transport,
|
|
878
|
-
usage,
|
|
879
|
-
state: PhantomData,
|
|
880
|
-
offset,
|
|
881
|
-
length,
|
|
882
|
-
root,
|
|
883
|
-
})
|
|
884
|
-
}
|
|
885
|
-
}
|
|
886
|
-
|
|
887
|
-
impl<T: Transport> RPCReadSector<T, RPCComplete> {
|
|
888
|
-
pub async fn complete(mut self) -> Result<RPCReadSectorResult, T::Error> {
|
|
889
|
-
let response: RPCReadSectorResponse = self.transport.read_response().await?;
|
|
890
|
-
|
|
891
|
-
// verify proof
|
|
892
|
-
let start = self.offset / SEGMENT_SIZE;
|
|
893
|
-
let end = (self.offset + self.length).div_ceil(SEGMENT_SIZE);
|
|
894
|
-
#[cfg(not(target_arch = "wasm32"))]
|
|
895
|
-
let data = {
|
|
896
|
-
let (tx, rx) = oneshot::channel();
|
|
897
|
-
let root = self.root;
|
|
898
|
-
rayon::spawn(move || {
|
|
899
|
-
let res = response
|
|
900
|
-
.data
|
|
901
|
-
.verify(&root, start, end)
|
|
902
|
-
.map_err(Error::ProofValidation);
|
|
903
|
-
tx.send(res).unwrap();
|
|
904
|
-
});
|
|
905
|
-
rx.await.unwrap()?
|
|
906
|
-
};
|
|
907
|
-
#[cfg(target_arch = "wasm32")]
|
|
908
|
-
let data = response
|
|
909
|
-
.data
|
|
910
|
-
.verify(&self.root, start, end)
|
|
911
|
-
.map_err(Error::ProofValidation)?;
|
|
912
|
-
Ok(RPCReadSectorResult {
|
|
913
|
-
usage: self.usage,
|
|
914
|
-
data,
|
|
915
|
-
})
|
|
916
|
-
}
|
|
917
|
-
}
|
|
918
|
-
|
|
919
|
-
/// RPCAccountBalanceRequest is the request type for getting the balance of
|
|
920
|
-
/// an account.
|
|
921
|
-
#[derive(Debug, PartialEq, AsyncSiaEncode, AsyncSiaDecode)]
|
|
922
|
-
struct RPCAccountBalanceRequest {
|
|
923
|
-
pub account: PublicKey,
|
|
924
|
-
}
|
|
925
|
-
impl_rpc_request!(RPCAccountBalanceRequest, "AccountBalance");
|
|
926
|
-
|
|
927
|
-
/// RPCAccountBalanceResponse contains the balance of an account.
|
|
928
|
-
#[derive(Debug, PartialEq, AsyncSiaEncode, AsyncSiaDecode)]
|
|
929
|
-
struct RPCAccountBalanceResponse {
|
|
930
|
-
pub balance: Currency,
|
|
931
|
-
}
|
|
932
|
-
impl_rpc_response!(RPCAccountBalanceResponse);
|
|
933
|
-
|
|
934
|
-
/// RPCAccountBalanceResult contains the result of an account balance RPC.
|
|
935
|
-
pub struct RPCAccountBalanceResult {
|
|
936
|
-
pub balance: Currency,
|
|
937
|
-
pub usage: Usage,
|
|
938
|
-
}
|
|
939
|
-
|
|
940
|
-
/// Requests the current balance of an account.
|
|
941
|
-
pub struct RPCAccountBalance<T: Transport, State> {
|
|
942
|
-
transport: T,
|
|
943
|
-
state: PhantomData<State>,
|
|
944
|
-
}
|
|
945
|
-
|
|
946
|
-
impl<T: Transport> RPCAccountBalance<T, RPCInit> {
|
|
947
|
-
pub async fn send_request(
|
|
948
|
-
mut transport: T,
|
|
949
|
-
account: PublicKey,
|
|
950
|
-
) -> Result<RPCAccountBalance<T, RPCComplete>, T::Error> {
|
|
951
|
-
let request = RPCAccountBalanceRequest { account };
|
|
952
|
-
transport.write_request(&request).await?;
|
|
953
|
-
|
|
954
|
-
Ok(RPCAccountBalance {
|
|
955
|
-
transport,
|
|
956
|
-
state: PhantomData,
|
|
957
|
-
})
|
|
958
|
-
}
|
|
959
|
-
}
|
|
960
|
-
|
|
961
|
-
impl<T: Transport> RPCAccountBalance<T, RPCComplete> {
|
|
962
|
-
pub async fn complete(mut self) -> Result<RPCAccountBalanceResult, T::Error> {
|
|
963
|
-
let response: RPCAccountBalanceResponse = self.transport.read_response().await?;
|
|
964
|
-
Ok(RPCAccountBalanceResult {
|
|
965
|
-
balance: response.balance,
|
|
966
|
-
usage: Usage::default(),
|
|
967
|
-
})
|
|
968
|
-
}
|
|
969
|
-
}
|
|
970
|
-
|
|
971
|
-
/// FormContractParams contains the parameters for forming a new contract.
|
|
972
|
-
#[derive(Debug, PartialEq, AsyncSiaEncode, AsyncSiaDecode)]
|
|
973
|
-
struct FormContractParams {
|
|
974
|
-
pub renter_public_key: PublicKey,
|
|
975
|
-
pub renter_address: Address,
|
|
976
|
-
pub allowance: Currency,
|
|
977
|
-
pub collateral: Currency,
|
|
978
|
-
pub proof_height: u64,
|
|
979
|
-
}
|
|
980
|
-
|
|
981
|
-
/// RPCFormContractRequest is the request type for RPCFormContract.
|
|
982
|
-
#[derive(Debug, PartialEq, AsyncSiaEncode, AsyncSiaDecode)]
|
|
983
|
-
struct RPCFormContractRequest {
|
|
984
|
-
pub prices: HostPrices,
|
|
985
|
-
pub contract: FormContractParams,
|
|
986
|
-
pub miner_fee: Currency,
|
|
987
|
-
pub basis: ChainIndex,
|
|
988
|
-
pub renter_inputs: Vec<SiacoinElement>,
|
|
989
|
-
pub renter_parents: Vec<Transaction>,
|
|
990
|
-
}
|
|
991
|
-
impl_rpc_request!(RPCFormContractRequest, "FormContract");
|
|
992
|
-
|
|
993
|
-
/// RenterFormContractSignaturesResponse contains the renter's contract signature and
|
|
994
|
-
/// Siacoin input signatures for the contract formation transaction.
|
|
995
|
-
///
|
|
996
|
-
/// At this point, the host has enough information to broadcast the formation.
|
|
997
|
-
#[derive(Debug, PartialEq, AsyncSiaEncode, AsyncSiaDecode)]
|
|
998
|
-
struct RenterFormContractSignaturesResponse {
|
|
999
|
-
pub renter_contract_signature: Signature,
|
|
1000
|
-
pub renter_satisfied_policies: Vec<SatisfiedPolicy>,
|
|
1001
|
-
}
|
|
1002
|
-
impl_rpc_response!(RenterFormContractSignaturesResponse);
|
|
1003
|
-
|
|
1004
|
-
pub struct RPCFormContractParams {
|
|
1005
|
-
state: ChainState,
|
|
1006
|
-
prices: HostPrices,
|
|
1007
|
-
contract: FormContractParams,
|
|
1008
|
-
host_public_key: PublicKey,
|
|
1009
|
-
host_address: Address,
|
|
1010
|
-
}
|
|
1011
|
-
|
|
1012
|
-
pub struct RPCFormContract<T, S, B, State>
|
|
1013
|
-
where
|
|
1014
|
-
T: Transport,
|
|
1015
|
-
S: RenterContractSigner,
|
|
1016
|
-
B: TransactionBuilder,
|
|
1017
|
-
{
|
|
1018
|
-
transport: T,
|
|
1019
|
-
contract_signer: S,
|
|
1020
|
-
transaction_builder: B,
|
|
1021
|
-
state: PhantomData<State>,
|
|
1022
|
-
|
|
1023
|
-
usage: Usage,
|
|
1024
|
-
chain_state: ChainState,
|
|
1025
|
-
contract: FileContract,
|
|
1026
|
-
formation_transaction: Transaction,
|
|
1027
|
-
renter_inputs_len: usize,
|
|
1028
|
-
}
|
|
1029
|
-
|
|
1030
|
-
impl<T: Transport, S: RenterContractSigner, B: TransactionBuilder, State>
|
|
1031
|
-
RPCFormContract<T, S, B, State>
|
|
1032
|
-
{
|
|
1033
|
-
pub fn file_contract(&self) -> &FileContract {
|
|
1034
|
-
&self.contract
|
|
1035
|
-
}
|
|
1036
|
-
|
|
1037
|
-
pub fn formation_transaction(&self) -> &Transaction {
|
|
1038
|
-
&self.formation_transaction
|
|
1039
|
-
}
|
|
1040
|
-
|
|
1041
|
-
pub fn renter_inputs(&self) -> &[SiacoinInput] {
|
|
1042
|
-
&self.formation_transaction.siacoin_inputs[..self.renter_inputs_len]
|
|
1043
|
-
}
|
|
1044
|
-
}
|
|
1045
|
-
|
|
1046
|
-
pub struct RPCFormContractResult {
|
|
1047
|
-
pub basis: ChainIndex,
|
|
1048
|
-
pub transaction_set: Vec<Transaction>,
|
|
1049
|
-
pub contract: FileContract,
|
|
1050
|
-
pub usage: Usage,
|
|
1051
|
-
}
|
|
1052
|
-
|
|
1053
|
-
impl<T: Transport, S: RenterContractSigner, B: TransactionBuilder>
|
|
1054
|
-
RPCFormContract<T, S, B, RPCInit>
|
|
1055
|
-
{
|
|
1056
|
-
pub async fn send_request(
|
|
1057
|
-
mut transport: T,
|
|
1058
|
-
contract_signer: S,
|
|
1059
|
-
transaction_builder: B,
|
|
1060
|
-
params: RPCFormContractParams,
|
|
1061
|
-
) -> Result<RPCFormContract<T, S, B, RPCAwaitingHostInputs>, T::Error> {
|
|
1062
|
-
let usage = Usage::form_contract(¶ms.prices);
|
|
1063
|
-
let mut contract = FileContract {
|
|
1064
|
-
revision_number: 0,
|
|
1065
|
-
capacity: 0,
|
|
1066
|
-
filesize: 0,
|
|
1067
|
-
file_merkle_root: Hash256::default(),
|
|
1068
|
-
proof_height: params.contract.proof_height,
|
|
1069
|
-
expiration_height: params.contract.proof_height + 144,
|
|
1070
|
-
renter_output: SiacoinOutput {
|
|
1071
|
-
address: params.contract.renter_address.clone(),
|
|
1072
|
-
value: params.contract.allowance,
|
|
1073
|
-
},
|
|
1074
|
-
host_output: SiacoinOutput {
|
|
1075
|
-
address: params.host_address,
|
|
1076
|
-
value: params.contract.collateral + params.prices.contract_price,
|
|
1077
|
-
},
|
|
1078
|
-
missed_host_value: params.contract.collateral,
|
|
1079
|
-
total_collateral: params.contract.collateral,
|
|
1080
|
-
host_public_key: params.host_public_key,
|
|
1081
|
-
renter_public_key: params.contract.renter_public_key,
|
|
1082
|
-
|
|
1083
|
-
host_signature: Signature::default(),
|
|
1084
|
-
renter_signature: Signature::default(),
|
|
1085
|
-
};
|
|
1086
|
-
contract.renter_signature = contract_signer.sign(contract.sig_hash(¶ms.state).as_ref());
|
|
1087
|
-
|
|
1088
|
-
let miner_fee = transaction_builder.miner_fee() * Currency::new(1000);
|
|
1089
|
-
let mut formation_txn = Transaction {
|
|
1090
|
-
miner_fee,
|
|
1091
|
-
..Default::default()
|
|
1092
|
-
};
|
|
1093
|
-
|
|
1094
|
-
let renter_fund_amount = params.contract.allowance
|
|
1095
|
-
+ params.prices.contract_price
|
|
1096
|
-
+ miner_fee
|
|
1097
|
-
+ contract.tax(¶ms.state);
|
|
1098
|
-
let renter_basis = transaction_builder
|
|
1099
|
-
.fund_transaction(&mut formation_txn, renter_fund_amount)
|
|
1100
|
-
.map_err(Error::from)?;
|
|
1101
|
-
|
|
1102
|
-
let request = RPCFormContractRequest {
|
|
1103
|
-
prices: params.prices,
|
|
1104
|
-
miner_fee,
|
|
1105
|
-
contract: params.contract,
|
|
1106
|
-
basis: renter_basis,
|
|
1107
|
-
renter_inputs: formation_txn
|
|
1108
|
-
.siacoin_inputs
|
|
1109
|
-
.iter()
|
|
1110
|
-
.map(|si| si.parent.clone())
|
|
1111
|
-
.collect(),
|
|
1112
|
-
renter_parents: Vec::new(),
|
|
1113
|
-
};
|
|
1114
|
-
transport.write_request(&request).await?;
|
|
1115
|
-
|
|
1116
|
-
Ok(RPCFormContract {
|
|
1117
|
-
transport,
|
|
1118
|
-
contract_signer,
|
|
1119
|
-
transaction_builder,
|
|
1120
|
-
state: PhantomData,
|
|
1121
|
-
usage,
|
|
1122
|
-
chain_state: params.state,
|
|
1123
|
-
contract,
|
|
1124
|
-
renter_inputs_len: formation_txn.siacoin_inputs.len(),
|
|
1125
|
-
formation_transaction: formation_txn,
|
|
1126
|
-
})
|
|
1127
|
-
}
|
|
1128
|
-
}
|
|
1129
|
-
|
|
1130
|
-
impl<T: Transport, S: RenterContractSigner, B: TransactionBuilder>
|
|
1131
|
-
RPCFormContract<T, S, B, RPCAwaitingHostInputs>
|
|
1132
|
-
{
|
|
1133
|
-
pub async fn receive_host_inputs(
|
|
1134
|
-
mut self,
|
|
1135
|
-
) -> Result<RPCFormContract<T, S, B, RPCAwaitingRenterSignatures>, T::Error> {
|
|
1136
|
-
let host_inputs_response: HostInputsResponse = self.transport.read_response().await?;
|
|
1137
|
-
let mut formation_txn = self.formation_transaction;
|
|
1138
|
-
|
|
1139
|
-
let host_funding = self.contract.total_collateral;
|
|
1140
|
-
let host_sum: Currency = host_inputs_response
|
|
1141
|
-
.host_inputs
|
|
1142
|
-
.iter()
|
|
1143
|
-
.map(|si| si.parent.siacoin_output.value)
|
|
1144
|
-
.sum();
|
|
1145
|
-
if host_sum < host_funding {
|
|
1146
|
-
return Err(Error::NotEnoughHostFunds(host_sum, host_funding).into());
|
|
1147
|
-
} else if host_sum > host_funding {
|
|
1148
|
-
formation_txn.siacoin_outputs.push(SiacoinOutput {
|
|
1149
|
-
address: self.contract.host_output.address.clone(),
|
|
1150
|
-
value: host_sum - host_funding,
|
|
1151
|
-
});
|
|
1152
|
-
}
|
|
1153
|
-
formation_txn.siacoin_inputs = host_inputs_response.host_inputs;
|
|
1154
|
-
|
|
1155
|
-
Ok(RPCFormContract {
|
|
1156
|
-
transport: self.transport,
|
|
1157
|
-
contract_signer: self.contract_signer,
|
|
1158
|
-
transaction_builder: self.transaction_builder,
|
|
1159
|
-
state: PhantomData,
|
|
1160
|
-
usage: self.usage,
|
|
1161
|
-
chain_state: self.chain_state,
|
|
1162
|
-
contract: self.contract,
|
|
1163
|
-
renter_inputs_len: self.renter_inputs_len,
|
|
1164
|
-
formation_transaction: formation_txn,
|
|
1165
|
-
})
|
|
1166
|
-
}
|
|
1167
|
-
}
|
|
1168
|
-
|
|
1169
|
-
impl<T: Transport, S: RenterContractSigner, B: TransactionBuilder>
|
|
1170
|
-
RPCFormContract<T, S, B, RPCAwaitingRenterSignatures>
|
|
1171
|
-
{
|
|
1172
|
-
pub fn host_inputs(&self) -> &[SiacoinInput] {
|
|
1173
|
-
&self.formation_transaction.siacoin_inputs[self.renter_inputs_len..]
|
|
1174
|
-
}
|
|
1175
|
-
|
|
1176
|
-
pub async fn send_renter_signatures(
|
|
1177
|
-
mut self,
|
|
1178
|
-
) -> Result<RPCFormContract<T, S, B, RPCComplete>, T::Error> {
|
|
1179
|
-
let mut formation_txn = self.formation_transaction;
|
|
1180
|
-
let mut contract = self.contract;
|
|
1181
|
-
|
|
1182
|
-
self.contract_signer
|
|
1183
|
-
.sign_revision(&self.chain_state, &mut contract);
|
|
1184
|
-
self.transaction_builder
|
|
1185
|
-
.sign_transaction(&mut formation_txn)
|
|
1186
|
-
.map_err(Error::from)?;
|
|
1187
|
-
|
|
1188
|
-
let renter_sigs_response = RenterFormContractSignaturesResponse {
|
|
1189
|
-
renter_contract_signature: contract.renter_signature.clone(),
|
|
1190
|
-
renter_satisfied_policies: formation_txn.siacoin_inputs[..self.renter_inputs_len]
|
|
1191
|
-
.iter()
|
|
1192
|
-
.map(|si| si.satisfied_policy.clone())
|
|
1193
|
-
.collect(),
|
|
1194
|
-
};
|
|
1195
|
-
self.transport.write_response(&renter_sigs_response).await?;
|
|
1196
|
-
|
|
1197
|
-
Ok(RPCFormContract {
|
|
1198
|
-
transport: self.transport,
|
|
1199
|
-
contract_signer: self.contract_signer,
|
|
1200
|
-
transaction_builder: self.transaction_builder,
|
|
1201
|
-
state: PhantomData,
|
|
1202
|
-
usage: self.usage,
|
|
1203
|
-
chain_state: self.chain_state,
|
|
1204
|
-
renter_inputs_len: self.renter_inputs_len,
|
|
1205
|
-
contract,
|
|
1206
|
-
formation_transaction: formation_txn,
|
|
1207
|
-
})
|
|
1208
|
-
}
|
|
1209
|
-
}
|
|
1210
|
-
|
|
1211
|
-
impl<T: Transport, S: RenterContractSigner, B: TransactionBuilder>
|
|
1212
|
-
RPCFormContract<T, S, B, RPCComplete>
|
|
1213
|
-
{
|
|
1214
|
-
pub async fn complete(mut self) -> Result<RPCFormContractResult, T::Error> {
|
|
1215
|
-
let resp: TransactionSetResponse = self.transport.read_response().await?;
|
|
1216
|
-
let formation_txn = resp
|
|
1217
|
-
.transaction_set
|
|
1218
|
-
.last()
|
|
1219
|
-
.ok_or(Error::ExpectedTransactionSet)?;
|
|
1220
|
-
if formation_txn.file_contracts.len() != 1 {
|
|
1221
|
-
return Err(
|
|
1222
|
-
Error::ExpectedContractTransaction(formation_txn.file_contracts.len()).into(),
|
|
1223
|
-
);
|
|
1224
|
-
}
|
|
1225
|
-
let contract = formation_txn.file_contracts.first().unwrap().clone();
|
|
1226
|
-
|
|
1227
|
-
Ok(RPCFormContractResult {
|
|
1228
|
-
basis: resp.basis,
|
|
1229
|
-
transaction_set: resp.transaction_set,
|
|
1230
|
-
contract,
|
|
1231
|
-
usage: self.usage,
|
|
1232
|
-
})
|
|
1233
|
-
}
|
|
1234
|
-
}
|
|
1235
|
-
|
|
1236
|
-
#[cfg(test)]
|
|
1237
|
-
mod test {
|
|
1238
|
-
use bytes::BytesMut;
|
|
1239
|
-
use chrono::DateTime;
|
|
1240
|
-
use std::io::Cursor;
|
|
1241
|
-
use tokio::io::AsyncWriteExt;
|
|
1242
|
-
|
|
1243
|
-
use super::*;
|
|
1244
|
-
|
|
1245
|
-
struct BufStream {
|
|
1246
|
-
buf: Cursor<Vec<u8>>,
|
|
1247
|
-
}
|
|
1248
|
-
|
|
1249
|
-
impl BufStream {
|
|
1250
|
-
fn new() -> Self {
|
|
1251
|
-
Self {
|
|
1252
|
-
buf: Cursor::new(Vec::new()),
|
|
1253
|
-
}
|
|
1254
|
-
}
|
|
1255
|
-
|
|
1256
|
-
fn inner(self) -> Vec<u8> {
|
|
1257
|
-
self.buf.clone().into_inner()
|
|
1258
|
-
}
|
|
1259
|
-
}
|
|
1260
|
-
|
|
1261
|
-
impl From<Cursor<Vec<u8>>> for BufStream {
|
|
1262
|
-
fn from(buf: Cursor<Vec<u8>>) -> Self {
|
|
1263
|
-
Self { buf }
|
|
1264
|
-
}
|
|
1265
|
-
}
|
|
1266
|
-
|
|
1267
|
-
impl AsyncDecoder for BufStream {
|
|
1268
|
-
type Error = Error;
|
|
1269
|
-
async fn decode_buf(&mut self, buf: &mut [u8]) -> Result<(), Self::Error> {
|
|
1270
|
-
self.buf.decode_buf(buf).await?;
|
|
1271
|
-
Ok(())
|
|
1272
|
-
}
|
|
1273
|
-
}
|
|
1274
|
-
|
|
1275
|
-
impl AsyncEncoder for BufStream {
|
|
1276
|
-
type Error = Error;
|
|
1277
|
-
async fn encode_buf(&mut self, buf: &[u8]) -> Result<(), Self::Error> {
|
|
1278
|
-
self.buf.encode_buf(buf).await?;
|
|
1279
|
-
Ok(())
|
|
1280
|
-
}
|
|
1281
|
-
}
|
|
1282
|
-
|
|
1283
|
-
impl Transport for BufStream {
|
|
1284
|
-
type Error = Error;
|
|
1285
|
-
|
|
1286
|
-
async fn write_request<R: RPCRequest>(&mut self, request: &R) -> Result<(), Self::Error> {
|
|
1287
|
-
request.encode_request(self).await?;
|
|
1288
|
-
self.buf.flush().await?;
|
|
1289
|
-
self.buf.set_position(0); // ready to read
|
|
1290
|
-
Ok(())
|
|
1291
|
-
}
|
|
1292
|
-
|
|
1293
|
-
async fn write_bytes(&mut self, data: Bytes) -> Result<(), Self::Error> {
|
|
1294
|
-
self.buf.write_all(&data).await?;
|
|
1295
|
-
Ok(())
|
|
1296
|
-
}
|
|
1297
|
-
|
|
1298
|
-
async fn write_response<R: RPCResponse>(
|
|
1299
|
-
&mut self,
|
|
1300
|
-
response: &R,
|
|
1301
|
-
) -> Result<(), Self::Error> {
|
|
1302
|
-
response.encode_response(self).await?;
|
|
1303
|
-
self.buf.flush().await?;
|
|
1304
|
-
self.buf.set_position(0); // ready to read
|
|
1305
|
-
Ok(())
|
|
1306
|
-
}
|
|
1307
|
-
|
|
1308
|
-
async fn read_response<R: RPCResponse>(&mut self) -> Result<R, Self::Error> {
|
|
1309
|
-
R::decode_response(self).await
|
|
1310
|
-
}
|
|
1311
|
-
}
|
|
1312
|
-
|
|
1313
|
-
const TEST_PRICES: HostPrices = HostPrices {
|
|
1314
|
-
contract_price: Currency::siacoins(1),
|
|
1315
|
-
collateral: Currency::siacoins(2),
|
|
1316
|
-
storage_price: Currency::siacoins(3),
|
|
1317
|
-
ingress_price: Currency::siacoins(4),
|
|
1318
|
-
egress_price: Currency::siacoins(5),
|
|
1319
|
-
free_sector_price: Currency::siacoins(6),
|
|
1320
|
-
tip_height: 7,
|
|
1321
|
-
valid_until: DateTime::UNIX_EPOCH,
|
|
1322
|
-
signature: Signature::new([0u8; 64]),
|
|
1323
|
-
};
|
|
1324
|
-
|
|
1325
|
-
const TEST_ACCOUNT_TOKEN: AccountToken = AccountToken {
|
|
1326
|
-
host_key: PublicKey::new({
|
|
1327
|
-
let mut bytes = [0u8; 32];
|
|
1328
|
-
bytes[0] = 10;
|
|
1329
|
-
bytes
|
|
1330
|
-
}),
|
|
1331
|
-
account: PublicKey::new({
|
|
1332
|
-
let mut bytes = [0u8; 32];
|
|
1333
|
-
bytes[0] = 11;
|
|
1334
|
-
bytes
|
|
1335
|
-
}),
|
|
1336
|
-
valid_until: DateTime::UNIX_EPOCH,
|
|
1337
|
-
signature: Signature::new({
|
|
1338
|
-
let mut bytes = [0u8; 64];
|
|
1339
|
-
bytes[0] = 13;
|
|
1340
|
-
bytes
|
|
1341
|
-
}),
|
|
1342
|
-
};
|
|
1343
|
-
|
|
1344
|
-
#[tokio::test]
|
|
1345
|
-
async fn test_write_request() {
|
|
1346
|
-
const EXPECTED_HEX: &str = "52656164536563746f72000000000000000000a1edccce1bc2d300000000000000000042db999d3784a7010000000000000000e3c8666c53467b02000000000000000084b6333b6f084f03000000000000000025a4000a8bca22040000000000000000c691cdd8a68cf604000000000007000000000000000800000000000000090000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000b000000000000000000000000000000000000000000000000000000000000000c000000000000000d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000f000000000000001000000000000000";
|
|
1347
|
-
|
|
1348
|
-
let mut prices = TEST_PRICES;
|
|
1349
|
-
prices.valid_until = DateTime::from_timestamp_secs(8).unwrap();
|
|
1350
|
-
prices.signature = Signature::new({
|
|
1351
|
-
let mut bytes = [0u8; 64];
|
|
1352
|
-
bytes[0] = 9;
|
|
1353
|
-
bytes
|
|
1354
|
-
});
|
|
1355
|
-
|
|
1356
|
-
let mut token = TEST_ACCOUNT_TOKEN;
|
|
1357
|
-
token.valid_until = DateTime::from_timestamp_secs(12).unwrap();
|
|
1358
|
-
token.signature = Signature::new({
|
|
1359
|
-
let mut bytes = [0u8; 64];
|
|
1360
|
-
bytes[0] = 13;
|
|
1361
|
-
bytes
|
|
1362
|
-
});
|
|
1363
|
-
|
|
1364
|
-
let req = RPCReadSectorRequest {
|
|
1365
|
-
prices,
|
|
1366
|
-
token,
|
|
1367
|
-
root: Hash256::new({
|
|
1368
|
-
let mut bytes = [0u8; 32];
|
|
1369
|
-
bytes[0] = 14;
|
|
1370
|
-
bytes
|
|
1371
|
-
}),
|
|
1372
|
-
offset: 15,
|
|
1373
|
-
length: 16,
|
|
1374
|
-
};
|
|
1375
|
-
|
|
1376
|
-
let mut transport = BufStream::new();
|
|
1377
|
-
transport.write_request(&req).await.unwrap();
|
|
1378
|
-
assert_eq!(transport.inner(), hex::decode(EXPECTED_HEX).unwrap());
|
|
1379
|
-
}
|
|
1380
|
-
|
|
1381
|
-
#[tokio::test]
|
|
1382
|
-
async fn test_read_response() {
|
|
1383
|
-
const HEX_BYTES: &str = "00030000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000003000000000000000400000000000000000000000000000000000000000000000000000000000000050000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000700000000000000000000000000000000000000000000000000000000000000";
|
|
1384
|
-
|
|
1385
|
-
let mut transport = BufStream::from(Cursor::new(hex::decode(HEX_BYTES).unwrap()));
|
|
1386
|
-
let resp: RPCFreeSectorsResponse = transport.read_response().await.unwrap();
|
|
1387
|
-
|
|
1388
|
-
let expected = RPCFreeSectorsResponse {
|
|
1389
|
-
old_subtree_hashes: vec![
|
|
1390
|
-
Hash256::new({
|
|
1391
|
-
let mut bytes = [0u8; 32];
|
|
1392
|
-
bytes[0] = 1;
|
|
1393
|
-
bytes
|
|
1394
|
-
}),
|
|
1395
|
-
Hash256::new({
|
|
1396
|
-
let mut bytes = [0u8; 32];
|
|
1397
|
-
bytes[0] = 2;
|
|
1398
|
-
bytes
|
|
1399
|
-
}),
|
|
1400
|
-
Hash256::new({
|
|
1401
|
-
let mut bytes = [0u8; 32];
|
|
1402
|
-
bytes[0] = 3;
|
|
1403
|
-
bytes
|
|
1404
|
-
}),
|
|
1405
|
-
],
|
|
1406
|
-
old_leaf_hashes: vec![
|
|
1407
|
-
Hash256::new({
|
|
1408
|
-
let mut bytes = [0u8; 32];
|
|
1409
|
-
bytes[0] = 4;
|
|
1410
|
-
bytes
|
|
1411
|
-
}),
|
|
1412
|
-
Hash256::new({
|
|
1413
|
-
let mut bytes = [0u8; 32];
|
|
1414
|
-
bytes[0] = 5;
|
|
1415
|
-
bytes
|
|
1416
|
-
}),
|
|
1417
|
-
Hash256::new({
|
|
1418
|
-
let mut bytes = [0u8; 32];
|
|
1419
|
-
bytes[0] = 6;
|
|
1420
|
-
bytes
|
|
1421
|
-
}),
|
|
1422
|
-
],
|
|
1423
|
-
new_merkle_root: Hash256::new({
|
|
1424
|
-
let mut bytes = [0u8; 32];
|
|
1425
|
-
bytes[0] = 7;
|
|
1426
|
-
bytes
|
|
1427
|
-
}),
|
|
1428
|
-
};
|
|
1429
|
-
|
|
1430
|
-
assert_eq!(resp, expected);
|
|
1431
|
-
}
|
|
1432
|
-
|
|
1433
|
-
#[tokio::test]
|
|
1434
|
-
async fn test_response_error() {
|
|
1435
|
-
const HEX_BYTES: &str = "01010b00000000000000666f6f206261722062617a";
|
|
1436
|
-
|
|
1437
|
-
let mut transport = BufStream::from(Cursor::new(hex::decode(HEX_BYTES).unwrap()));
|
|
1438
|
-
let err = transport
|
|
1439
|
-
.read_response::<RPCReadSectorResponse>()
|
|
1440
|
-
.await
|
|
1441
|
-
.unwrap_err();
|
|
1442
|
-
|
|
1443
|
-
let expected_err = RPCError {
|
|
1444
|
-
code: 1,
|
|
1445
|
-
description: "foo bar baz".to_string(),
|
|
1446
|
-
};
|
|
1447
|
-
|
|
1448
|
-
match err {
|
|
1449
|
-
Error::RPC(rpc_err) => {
|
|
1450
|
-
assert_eq!(rpc_err, expected_err);
|
|
1451
|
-
}
|
|
1452
|
-
_ => panic!("Expected RPCError, got {err:?}"),
|
|
1453
|
-
}
|
|
1454
|
-
}
|
|
1455
|
-
|
|
1456
|
-
#[tokio::test]
|
|
1457
|
-
async fn test_rpc_write_sector_send_request() {
|
|
1458
|
-
let mut data = BytesMut::zeroed(SECTOR_SIZE);
|
|
1459
|
-
rand::fill(&mut data[..]);
|
|
1460
|
-
let root = merkle::sector_root(&data);
|
|
1461
|
-
let transport = BufStream::new();
|
|
1462
|
-
let rpc =
|
|
1463
|
-
RPCWriteSector::send_request(transport, TEST_PRICES, TEST_ACCOUNT_TOKEN, data.freeze())
|
|
1464
|
-
.await
|
|
1465
|
-
.unwrap();
|
|
1466
|
-
assert_eq!(rpc.root, root);
|
|
1467
|
-
}
|
|
1468
|
-
|
|
1469
|
-
#[tokio::test]
|
|
1470
|
-
async fn test_rpc_write_sector_complete() {
|
|
1471
|
-
let mut data = BytesMut::zeroed(SECTOR_SIZE);
|
|
1472
|
-
rand::fill(&mut data[..]);
|
|
1473
|
-
let root = merkle::sector_root(&data);
|
|
1474
|
-
|
|
1475
|
-
// helper to prepare the transport and fill it with the expected host
|
|
1476
|
-
// response
|
|
1477
|
-
let transport = async || -> BufStream {
|
|
1478
|
-
let mut transport = BufStream::new();
|
|
1479
|
-
let response = RPCWriteSectorResponse { root };
|
|
1480
|
-
transport.write_response(&response).await.unwrap();
|
|
1481
|
-
transport
|
|
1482
|
-
};
|
|
1483
|
-
|
|
1484
|
-
// perform the RPC with the correct root
|
|
1485
|
-
let rpc = RPCWriteSector::<_, RPCComplete> {
|
|
1486
|
-
root,
|
|
1487
|
-
transport: transport().await,
|
|
1488
|
-
usage: Usage::default(),
|
|
1489
|
-
state: PhantomData,
|
|
1490
|
-
};
|
|
1491
|
-
rpc.complete().await.unwrap();
|
|
1492
|
-
|
|
1493
|
-
// change the root to force a mismatch
|
|
1494
|
-
let rpc = RPCWriteSector::<_, RPCComplete> {
|
|
1495
|
-
root: Hash256::default(),
|
|
1496
|
-
transport: transport().await,
|
|
1497
|
-
usage: Usage::default(),
|
|
1498
|
-
state: PhantomData,
|
|
1499
|
-
};
|
|
1500
|
-
if let Err(Error::SectorRootMismatch { expected, got }) = rpc.complete().await {
|
|
1501
|
-
assert_eq!(expected, Hash256::default());
|
|
1502
|
-
assert_eq!(got, root);
|
|
1503
|
-
} else {
|
|
1504
|
-
panic!("Expected SectorRootMismatch");
|
|
1505
|
-
}
|
|
1506
|
-
}
|
|
1507
|
-
}
|