Skip to content
This repository has been archived by the owner on Apr 16, 2024. It is now read-only.

Feature/persist block #3

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 15 additions & 4 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 5 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,10 @@ edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
themelio-stf= "0.5.5"
themelio-nodeprot= "0.4.1"
themelio-stf= "0.6.2"
#themelio-stf= { path = "../themelio-stf" }
themelio-nodeprot= "0.5.0"
#themelio-nodeprot= { path = "../themelio-nodeprot" }
http-types= "2.12.0"
tmelcrypt = "0.1.0"
smolscale= "0.3.12"
Expand All @@ -21,7 +23,7 @@ serde_json= { version = "1.0.67", features = ["arbitrary_precision"] }
dashmap= "4.0.2"
structopt= "0.3.23"
stdcode= "0.1.2"
tide= "0.16.0"
tide= "0.16.0"
tracing-subscriber = "0.2.20"
log= "0.4.14"
tracing= "0.1.26"
Expand Down
33 changes: 28 additions & 5 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@ use serde::Deserialize;
use state::AppState;
use std::fmt::Debug;
use structopt::StructOpt;
use themelio_nodeprot::{InMemoryTrustStore, TrustStore, TrustedHeight};
use themelio_stf::{
melvm::{Covenant, CovenantEnv},
CoinData, CoinID, Denom, NetID, PoolKey, StakeDoc, Transaction, TxHash, TxKind,
MICRO_CONVERTER,
melvm::Covenant, CoinData, CoinID, CoinValue, Denom, NetID, PoolKey, StakeDoc, Transaction,
TxHash, TxKind, MICRO_CONVERTER,
};
use tide::security::CorsMiddleware;
use tide::{Body, Request, StatusCode};
Expand All @@ -36,6 +36,18 @@ struct Args {

#[structopt(long, default_value = "94.237.109.44:11814")]
testnet_connect: SocketAddr,

#[structopt(
long,
default_value = "413096:7ecd81b20ab0ce678b9de7078b833f41d23856df5323a93abd409149b23a4bcd"
)]
mainnet_trusted_block: TrustedHeight,

#[structopt(
long,
default_value = "400167:bf8a7194dcef69eb3a0c9a3664d58156f68ca4092306ce04eda08bfe794db940"
)]
testnet_trusted_block: TrustedHeight,
}

// If "MELWALLETD_AUTH_TOKEN" environment variable is set, check that every HTTP request has X-Melwalletd-Auth-Token set to that string
Expand Down Expand Up @@ -78,13 +90,24 @@ fn main() -> anyhow::Result<()> {
"opened wallet directory: {:?}",
multiwallet.list().collect::<Vec<_>>()
);

let mut secret_path = args.wallet_dir.clone();
secret_path.push(".secrets.json");

let secrets = SecretStore::open(&secret_path)?;
let trusted_blocks = InMemoryTrustStore::new();

// Set trusted blocks from args if provided
//let TrustedHeight{height, header_hash} = args.mainnet_trusted_block;
let trusted_height = args.mainnet_trusted_block;
trusted_blocks.set(NetID::Mainnet, trusted_height);
let trusted_height = args.testnet_trusted_block;
trusted_blocks.set(NetID::Testnet, trusted_height);

let state = AppState::new(
multiwallet,
secrets,
trusted_blocks,
args.mainnet_connect,
args.testnet_connect,
);
Expand Down Expand Up @@ -447,12 +470,12 @@ async fn send_faucet(req: Request<Arc<AppState>>) -> tide::Result<Body> {
inputs: vec![],
outputs: vec![CoinData {
covhash: wallet.read().my_covenant().hash(),
value: 1001 * MICRO_CONVERTER,
value: CoinValue(1001 * MICRO_CONVERTER),
denom: Denom::Mel,
additional_data: vec![],
}],
data: (0..32).map(|_| fastrand::u8(0..=255)).collect(),
fee: MICRO_CONVERTER,
fee: CoinValue(MICRO_CONVERTER),
scripts: vec![],
sigs: vec![],
};
Expand Down
34 changes: 12 additions & 22 deletions src/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@ use anyhow::Context;
use dashmap::DashMap;
use parking_lot::Mutex;
use serde::{Deserialize, Serialize};
use themelio_nodeprot::ValClient;
use themelio_nodeprot::{ValClient, InMemoryTrustStore};
use themelio_stf::{
melvm::{Address, Covenant},
CoinDataHeight, CoinID, Denom, NetID, Transaction, TxHash,
CoinDataHeight, CoinID, Denom, NetID, Transaction, TxHash, CoinValue,
};
use tmelcrypt::Ed25519SK;

Expand All @@ -38,23 +38,13 @@ impl AppState {
pub fn new(
multi: MultiWallet,
secrets: SecretStore,
trusted_blocks: InMemoryTrustStore,
mainnet_addr: SocketAddr,
testnet_addr: SocketAddr,
) -> Self {
let mainnet_client = ValClient::new(NetID::Mainnet, mainnet_addr);
let testnet_client = ValClient::new(NetID::Testnet, testnet_addr);
mainnet_client.trust(
413096,
"7ecd81b20ab0ce678b9de7078b833f41d23856df5323a93abd409149b23a4bcd"
.parse()
.unwrap(),
);
testnet_client.trust(
400167,
"bf8a7194dcef69eb3a0c9a3664d58156f68ca4092306ce04eda08bfe794db940"
.parse()
.unwrap(),
);
let mainnet_client = ValClient::new_with_truststore(NetID::Mainnet, mainnet_addr, trusted_blocks.clone());
let testnet_client = ValClient::new_with_truststore(NetID::Testnet, testnet_addr, trusted_blocks);

let clients: HashMap<NetID, ValClient> = vec![
(NetID::Mainnet, mainnet_client),
(NetID::Testnet, testnet_client),
Expand Down Expand Up @@ -88,7 +78,7 @@ impl AppState {
&& cdh.coin_data.covhash == wd.my_covenant().hash()
})
.map(|(_, cdh)| cdh.coin_data.value)
.sum();
.fold(CoinValue(0), |a,b| a+b);
let mut detailed_balance = BTreeMap::new();
for (_, cdh) in unspent.iter() {
let entry = detailed_balance
Expand All @@ -101,8 +91,8 @@ impl AppState {
let staked_microsym = wd
.stake_list()
.values()
.map(|v| v.syms_staked)
.sum::<u128>();
.map(|v| v.syms_staked )
.fold(CoinValue(0), |a,b| a+b);
let locked = !self.unlocked_signers.contains_key(&name);
(
name,
Expand Down Expand Up @@ -208,9 +198,9 @@ impl AppState {

#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct WalletSummary {
pub total_micromel: u128,
pub detailed_balance: BTreeMap<String, u128>,
pub staked_microsym: u128,
pub total_micromel: CoinValue,
pub detailed_balance: BTreeMap<String, CoinValue>,
pub staked_microsym: CoinValue,
pub network: NetID,
#[serde(with = "stdcode::asstr")]
pub address: Address,
Expand Down
49 changes: 33 additions & 16 deletions src/walletdata.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ use binary_search::Direction;
use serde::{Deserialize, Serialize};
use serde_with::serde_as;
use themelio_stf::{
melvm::Covenant, CoinData, CoinDataHeight, CoinID, Denom, NetID, StakeDoc, Transaction, TxHash,
TxKind, MAX_COINVAL, STAKE_EPOCH,
melvm::Covenant, BlockHeight, CoinData, CoinDataHeight, CoinID, CoinValue, Denom, NetID,
StakeDoc, Transaction, TxHash, TxKind, MAX_COINVAL, STAKE_EPOCH,
};

/// Cloneable in-memory data that can be persisted.
Expand All @@ -19,7 +19,7 @@ pub struct WalletData {
#[serde_as(as = "Vec<(_, _)>")]
spent_coins: BTreeMap<CoinID, CoinDataHeight>,
tx_in_progress: BTreeMap<TxHash, Transaction>,
tx_confirmed: BTreeMap<TxHash, (Transaction, u64)>,
tx_confirmed: BTreeMap<TxHash, (Transaction, BlockHeight)>,
#[serde(default)]
stake_list: BTreeMap<TxHash, StakeDoc>,
my_covenant: Covenant,
Expand Down Expand Up @@ -142,7 +142,8 @@ impl WalletData {
.context("mandatory input not found in wallet")?;
mandatory_inputs.insert(input, coindata.clone());
}
let gen_transaction = |fee| {
let gen_transaction = |fee: u128| {
let fee = CoinValue(fee);
// find coins that might match
let mut txn = Transaction {
kind: TxKind::Normal,
Expand All @@ -157,11 +158,14 @@ impl WalletData {
// compute output sum
let mut output_sum = txn.total_outputs();

let mut input_sum: BTreeMap<Denom, u128> = BTreeMap::new();
let mut input_sum: BTreeMap<Denom, CoinValue> = BTreeMap::new();
// first we add the "mandatory" inputs
for (coin, data) in mandatory_inputs.iter() {
txn.inputs.push(*coin);
let existing_val = input_sum.get(&data.coin_data.denom).cloned().unwrap_or(0);
let existing_val = input_sum
.get(&data.coin_data.denom)
.cloned()
.unwrap_or(CoinValue(0));
input_sum.insert(data.coin_data.denom, existing_val + data.coin_data.value);
}

Expand All @@ -183,8 +187,16 @@ impl WalletData {
// do not consider it
continue;
}
let existing_val = input_sum.get(&data.coin_data.denom).cloned().unwrap_or(0);
if existing_val < output_sum.get(&data.coin_data.denom).cloned().unwrap_or(0) {
let existing_val = input_sum
.get(&data.coin_data.denom)
.cloned()
.unwrap_or(CoinValue(0));
if existing_val
< output_sum
.get(&data.coin_data.denom)
.cloned()
.unwrap_or(CoinValue(0))
{
txn.inputs.push(*coin);
input_sum.insert(data.coin_data.denom, existing_val + data.coin_data.value);
}
Expand All @@ -194,9 +206,14 @@ impl WalletData {
let change = {
let mut change = Vec::new();
for (cointype, sum) in output_sum.iter() {
let difference = input_sum.get(cointype).unwrap_or(&0).checked_sub(*sum);
let difference = input_sum
.get(cointype)
.unwrap_or(&CoinValue(0))
.0
.checked_sub(sum.0)
.map(CoinValue);
if let Some(difference) = difference {
if difference > 0 || *cointype == Denom::Mel {
if difference > CoinValue(0) || *cointype == Denom::Mel {
// We *always* make at least one change output
change.push(CoinData {
covhash: self.my_covenant.hash(),
Expand Down Expand Up @@ -231,8 +248,8 @@ impl WalletData {
}
};
let (_, (_, val)) = binary_search::binary_search(
(0u128, Err(anyhow::anyhow!("nothing"))),
(MAX_COINVAL, Err(anyhow::anyhow!("nothing"))),
(0, Err(anyhow::anyhow!("nothing"))),
(MAX_COINVAL.0, Err(anyhow::anyhow!("nothing"))),
gen_transaction,
);
log::debug!("prepared TX with fee {:?}", val.as_ref().map(|v| v.fee));
Expand Down Expand Up @@ -281,7 +298,7 @@ impl WalletData {
}

/// Informs the state of a confirmed transaction, based on its txhash. This will move the transaction from the in-progress to confirmed.
pub fn commit_confirmed(&mut self, txhash: TxHash, height: u64) {
pub fn commit_confirmed(&mut self, txhash: TxHash, height: BlockHeight) {
if let Some(tx) = self.tx_in_progress.remove(&txhash) {
self.tx_confirmed.insert(txhash, (tx, height));
}
Expand Down Expand Up @@ -319,16 +336,16 @@ impl WalletData {
}

/// Filter out everything in the stake list that's too old
pub fn retain_valid_stakes(&mut self, current_height: u64) {
let current_epoch = current_height / STAKE_EPOCH;
pub fn retain_valid_stakes(&mut self, current_height: BlockHeight) {
let current_epoch = current_height.0 / STAKE_EPOCH;
self.stake_list.retain(|_, v| v.e_post_end >= current_epoch);
}
}

#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct TransactionStatus {
pub raw: Transaction,
pub confirmed_height: Option<u64>,
pub confirmed_height: Option<BlockHeight>,
pub outputs: Vec<AnnCoinID>,
}

Expand Down