use crate::encoding::{SiaDecodable, SiaDecode, SiaEncodable, SiaEncode};
use crate::encoding_async::AsyncSiaDecode;
use blake2b_simd::Params;
use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use crate::consensus::ChainState;
use crate::signing::{PrivateKey, PublicKey, Signature};
use crate::types::v2::{FileContract, Transaction};
use crate::types::{Address, ChainIndex, Currency, Hash256};
pub(crate) mod merkle;
pub mod protocol;
pub use merkle::{sector_root, sector_root_from_reader};
pub const SEGMENT_SIZE: usize = 64;
pub const SECTOR_SIZE: usize = 1 << 22;
pub const LEAVES_PER_SECTOR: usize = SECTOR_SIZE / SEGMENT_SIZE;
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, SiaEncode, SiaDecode, AsyncSiaDecode)]
#[serde(rename_all = "camelCase")]
pub struct HostPrices {
pub contract_price: Currency,
pub collateral: Currency,
pub storage_price: Currency,
pub ingress_price: Currency,
pub egress_price: Currency,
pub free_sector_price: Currency,
pub tip_height: u64,
pub valid_until: DateTime<Utc>,
pub signature: Signature,
}
impl HostPrices {
pub fn sig_hash(&self) -> Hash256 {
let mut state = Params::new().hash_length(32).to_state();
self.contract_price.encode(&mut state).unwrap();
self.collateral.encode(&mut state).unwrap();
self.storage_price.encode(&mut state).unwrap();
self.ingress_price.encode(&mut state).unwrap();
self.egress_price.encode(&mut state).unwrap();
self.free_sector_price.encode(&mut state).unwrap();
self.tip_height.encode(&mut state).unwrap();
self.valid_until.encode(&mut state).unwrap();
state.finalize().into()
}
pub fn is_valid(&self, host_key: &PublicKey, timestamp: DateTime<Utc>) -> bool {
self.valid_until > timestamp
&& self.tip_height > 0
&& host_key.verify(self.sig_hash().as_ref(), &self.signature)
}
}
#[derive(Debug, PartialEq, Serialize, Deserialize, SiaEncode, SiaDecode, AsyncSiaDecode)]
#[serde(rename_all = "camelCase")]
pub struct HostSettings {
pub protocol_version: [u8; 3],
pub release: String,
pub wallet_address: Address,
pub accepting_contracts: bool,
pub max_collateral: Currency,
pub max_contract_duration: u64,
pub remaining_storage: u64,
pub total_storage: u64,
pub prices: HostPrices,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, SiaEncode, SiaDecode, AsyncSiaDecode)]
#[serde(rename_all = "camelCase")]
pub struct AccountToken {
pub host_key: PublicKey,
pub account: PublicKey,
pub valid_until: DateTime<Utc>,
pub signature: Signature,
}
impl AccountToken {
fn compute_sig_hash(
host_key: &PublicKey,
account: &PublicKey,
valid_until: &DateTime<Utc>,
) -> Hash256 {
let mut state = Params::new().hash_length(32).to_state();
host_key.encode(&mut state).unwrap();
account.encode(&mut state).unwrap();
valid_until.encode(&mut state).unwrap();
state.finalize().into()
}
pub fn new(account_key: &PrivateKey, host_key: PublicKey) -> Self {
let expiration_time = chrono::Utc::now() + chrono::Duration::minutes(5);
let sig_hash =
Self::compute_sig_hash(&host_key, &account_key.public_key(), &expiration_time);
AccountToken {
host_key,
account: account_key.public_key(),
valid_until: expiration_time,
signature: account_key.sign(sig_hash.as_ref()),
}
}
}
#[derive(Debug, PartialEq, Serialize, Deserialize, SiaEncode, SiaDecode)]
#[serde(rename_all = "camelCase")]
pub struct AccountDeposit {
pub account: PublicKey,
pub amount: Currency,
}
pub trait RenterContractSigner {
fn public_key(&self) -> PublicKey;
fn sign(&self, msg: &[u8]) -> Signature;
fn sign_revision(&self, state: &ChainState, contract: &mut FileContract);
}
impl RenterContractSigner for PrivateKey {
fn public_key(&self) -> PublicKey {
self.public_key()
}
fn sign(&self, msg: &[u8]) -> Signature {
self.sign(msg)
}
fn sign_revision(&self, state: &ChainState, contract: &mut FileContract) {
let sig_hash = contract.sig_hash(state);
contract.renter_signature = self.sign(sig_hash.as_ref());
}
}
pub trait TransactionBuilder {
fn miner_fee(&self) -> Currency;
fn fund_transaction(
&self,
transaction: &mut Transaction,
amount: Currency,
) -> Result<ChainIndex, protocol::RPCError>;
fn sign_transaction(&self, transaction: &mut Transaction) -> Result<(), protocol::RPCError>;
}