Global config instance (#769)

* config: global instance

* fix: cli tests

* fix: owner api tests

* config: save tor config

* fix: owner rpc tests

* fix: set config file path on init and owner api call

* tor: store launched services, get global config at command loop, remove unused listen args, check for empty global config to set default, do not save empty tor config at owner

* api: update config in memory after successful file write

* arti: restart proxy in loop

* fix: comment for tor config save

* config: set or init, update without error

* config: scoped tor config

* build: update lock file

* config: ability to store multiple configurations at memory from config path

* tor: restart service on config change

* fix: owner api test

* foreign: pass tor config from args, stop service, error handling

* arti: move runtime wrapper to single file

* config: read existing config from file at create_config

* config: handle error on read

* arti: single dir for cache

* foreign: register config listener before launch

* config: save temp

* config: remove unused error type

* config: make path and members not optional, return an error on config creation if it exists, pass default tor config to send if not set

* arti: non public runtime wrapper

* config: migrate comments

* fix: rpc tests

* config: return from cache if exists

* config: save disabled tor config when null provided at owner and tor section was not set

* config: update tor with args at listener

* config: pass pathbuf directly on creation

* config: unique tmp file name, setting permissions and providing config version

* fix global config handling

* fix config persistence

* fix tor service restart

* fix config synchronization

* require wallet close before changing data directory

* unify global config updates

---------

Co-authored-by: wiesche <wiesche89@googlemail.com>
This commit is contained in:
ardocrat
2026-07-24 22:15:19 +02:00
committed by GitHub
co-authored by wiesche
parent 7fb47646e9
commit d2fe2b90f6
46 changed files with 4880 additions and 3311 deletions
+163 -102
View File
@@ -19,6 +19,7 @@ extern crate grin_wallet_impls as impls;
extern crate grin_wallet_libwallet as libwallet;
use grin_core as core;
use std::path::PathBuf;
use self::libwallet::{InitTxArgs, Slate};
use impls::test_framework::{self, LocalWalletClient};
@@ -74,18 +75,28 @@ fn file_repost_test_impl(test_dir: &'static str) -> Result<(), libwallet::Error>
let reward = core::consensus::REWARD;
// add some accounts
wallet::controller::owner_single_use(Some(wallet1.clone()), mask1, None, |api, m| {
api.create_account_path(m, "mining")?;
api.create_account_path(m, "listener")?;
Ok(())
})?;
wallet::controller::owner_single_use(
wallet1.clone(),
mask1,
PathBuf::from(test_dir),
|api, m| {
api.create_account_path(m, "mining")?;
api.create_account_path(m, "listener")?;
Ok(())
},
)?;
// add some accounts
wallet::controller::owner_single_use(Some(wallet2.clone()), mask2, None, |api, m| {
api.create_account_path(m, "account1")?;
api.create_account_path(m, "account2")?;
Ok(())
})?;
wallet::controller::owner_single_use(
wallet2.clone(),
mask2,
PathBuf::from(test_dir),
|api, m| {
api.create_account_path(m, "account1")?;
api.create_account_path(m, "account2")?;
Ok(())
},
)?;
// Get some mining done
{
@@ -102,26 +113,31 @@ fn file_repost_test_impl(test_dir: &'static str) -> Result<(), libwallet::Error>
let mut slate = Slate::blank(2, false);
// Should have 5 in account1 (5 spendable), 5 in account (2 spendable)
wallet::controller::owner_single_use(Some(wallet1.clone()), mask1, None, |api, m| {
let (wallet1_refreshed, wallet1_info) = api.retrieve_summary_info(m, true, 1)?;
assert!(wallet1_refreshed);
assert_eq!(wallet1_info.last_confirmed_height, bh);
assert_eq!(wallet1_info.total, bh * reward);
// send to send
let args = InitTxArgs {
src_acct_name: Some("mining".to_owned()),
amount: reward * 2,
minimum_confirmations: 2,
max_outputs: 500,
num_change_outputs: 1,
selection_strategy_is_use_all: true,
..Default::default()
};
let slate = api.init_send_tx(m, args)?;
PathToSlate((&send_file).into()).put_tx(&slate, false)?;
api.tx_lock_outputs(m, &slate)?;
Ok(())
})?;
wallet::controller::owner_single_use(
wallet1.clone(),
mask1,
PathBuf::from(test_dir),
|api, m| {
let (wallet1_refreshed, wallet1_info) = api.retrieve_summary_info(m, true, 1)?;
assert!(wallet1_refreshed);
assert_eq!(wallet1_info.last_confirmed_height, bh);
assert_eq!(wallet1_info.total, bh * reward);
// send to send
let args = InitTxArgs {
src_acct_name: Some("mining".to_owned()),
amount: reward * 2,
minimum_confirmations: 2,
max_outputs: 500,
num_change_outputs: 1,
selection_strategy_is_use_all: true,
..Default::default()
};
let slate = api.init_send_tx(m, args)?;
PathToSlate((&send_file).into()).put_tx(&slate, false)?;
api.tx_lock_outputs(m, &slate)?;
Ok(())
},
)?;
let _ = test_framework::award_blocks_to_wallet(&chain, wallet1.clone(), mask1, 3, false);
bh += 3;
@@ -132,12 +148,17 @@ fn file_repost_test_impl(test_dir: &'static str) -> Result<(), libwallet::Error>
w.set_parent_key_id_by_name("listener")?;
}
wallet::controller::foreign_single_use(wallet1.clone(), mask1_i.clone(), |api| {
slate = PathToSlate((&send_file).into()).get_tx()?.0;
slate = api.receive_tx(&slate, None, None)?;
PathToSlate((&receive_file).into()).put_tx(&slate, false)?;
Ok(())
})?;
wallet::controller::foreign_single_use(
wallet1.clone(),
PathBuf::from(test_dir),
mask1_i.clone(),
|api| {
slate = PathToSlate((&send_file).into()).get_tx()?.0;
slate = api.receive_tx(&slate, None, None)?;
PathToSlate((&receive_file).into()).put_tx(&slate, false)?;
Ok(())
},
)?;
// wallet 1 receives file to different account, completes
{
@@ -146,47 +167,67 @@ fn file_repost_test_impl(test_dir: &'static str) -> Result<(), libwallet::Error>
}
// wallet 1 finalize
wallet::controller::owner_single_use(Some(wallet1.clone()), mask1, None, |api, m| {
slate = PathToSlate((&receive_file).into()).get_tx()?.0;
slate = api.finalize_tx(m, &slate)?;
Ok(())
})?;
wallet::controller::owner_single_use(
wallet1.clone(),
mask1,
PathBuf::from(test_dir),
|api, m| {
slate = PathToSlate((&receive_file).into()).get_tx()?.0;
slate = api.finalize_tx(m, &slate)?;
Ok(())
},
)?;
// Now repost from cached
wallet::controller::owner_single_use(Some(wallet1.clone()), mask1, None, |api, m| {
let (_, txs) = api.retrieve_txs(m, true, None, Some(slate.id), None)?;
println!("TXS[0]: {:?}", txs[0]);
let stored_tx = api.get_stored_tx(m, None, Some(&txs[0].tx_slate_id.unwrap()))?;
println!("Stored tx: {:?}", stored_tx);
api.post_tx(m, &slate, false)?;
bh += 1;
Ok(())
})?;
wallet::controller::owner_single_use(
wallet1.clone(),
mask1,
PathBuf::from(test_dir),
|api, m| {
let (_, txs) = api.retrieve_txs(m, true, None, Some(slate.id), None)?;
println!("TXS[0]: {:?}", txs[0]);
let stored_tx = api.get_stored_tx(m, None, Some(&txs[0].tx_slate_id.unwrap()))?;
println!("Stored tx: {:?}", stored_tx);
api.post_tx(m, &slate, false)?;
bh += 1;
Ok(())
},
)?;
let _ = test_framework::award_blocks_to_wallet(&chain, wallet1.clone(), mask1, 3, false);
bh += 3;
// update/test contents of both accounts
wallet::controller::owner_single_use(Some(wallet1.clone()), mask1, None, |api, m| {
let (wallet1_refreshed, wallet1_info) = api.retrieve_summary_info(m, true, 1)?;
assert!(wallet1_refreshed);
assert_eq!(wallet1_info.last_confirmed_height, bh);
assert_eq!(wallet1_info.total, bh * reward - reward * 2);
Ok(())
})?;
wallet::controller::owner_single_use(
wallet1.clone(),
mask1,
PathBuf::from(test_dir),
|api, m| {
let (wallet1_refreshed, wallet1_info) = api.retrieve_summary_info(m, true, 1)?;
assert!(wallet1_refreshed);
assert_eq!(wallet1_info.last_confirmed_height, bh);
assert_eq!(wallet1_info.total, bh * reward - reward * 2);
Ok(())
},
)?;
{
wallet_inst!(wallet1, w);
w.set_parent_key_id_by_name("listener")?;
}
wallet::controller::owner_single_use(Some(wallet1.clone()), mask1, None, |api, m| {
let (wallet2_refreshed, wallet2_info) = api.retrieve_summary_info(m, true, 1)?;
assert!(wallet2_refreshed);
assert_eq!(wallet2_info.last_confirmed_height, bh);
assert_eq!(wallet2_info.total, 2 * reward);
Ok(())
})?;
wallet::controller::owner_single_use(
wallet1.clone(),
mask1,
PathBuf::from(test_dir),
|api, m| {
let (wallet2_refreshed, wallet2_info) = api.retrieve_summary_info(m, true, 1)?;
assert!(wallet2_refreshed);
assert_eq!(wallet2_info.last_confirmed_height, bh);
assert_eq!(wallet2_info.total, 2 * reward);
Ok(())
},
)?;
// as above, but syncronously
{
@@ -201,55 +242,75 @@ fn file_repost_test_impl(test_dir: &'static str) -> Result<(), libwallet::Error>
let mut slate = Slate::blank(2, false);
let amount = 60_000_000_000;
wallet::controller::owner_single_use(Some(wallet1.clone()), mask1, None, |sender_api, m| {
// note this will increment the block count as part of the transaction "Posting"
let args = InitTxArgs {
src_acct_name: None,
amount: reward * 2,
minimum_confirmations: 2,
max_outputs: 500,
num_change_outputs: 1,
selection_strategy_is_use_all: true,
..Default::default()
};
let slate_i = sender_api.init_send_tx(m, args)?;
slate = client1.send_tx_slate_direct("wallet2", &slate_i)?;
sender_api.tx_lock_outputs(m, &slate)?;
slate = sender_api.finalize_tx(m, &slate)?;
Ok(())
})?;
wallet::controller::owner_single_use(
wallet1.clone(),
mask1,
PathBuf::from(test_dir),
|sender_api, m| {
// note this will increment the block count as part of the transaction "Posting"
let args = InitTxArgs {
src_acct_name: None,
amount: reward * 2,
minimum_confirmations: 2,
max_outputs: 500,
num_change_outputs: 1,
selection_strategy_is_use_all: true,
..Default::default()
};
let slate_i = sender_api.init_send_tx(m, args)?;
slate = client1.send_tx_slate_direct("wallet2", &slate_i)?;
sender_api.tx_lock_outputs(m, &slate)?;
slate = sender_api.finalize_tx(m, &slate)?;
Ok(())
},
)?;
let _ = test_framework::award_blocks_to_wallet(&chain, wallet1.clone(), mask1, 3, false);
bh += 3;
// Now repost from cached
wallet::controller::owner_single_use(Some(wallet1.clone()), mask1, None, |api, m| {
let (_, txs) = api.retrieve_txs(m, true, None, Some(slate.id), None)?;
let stored_tx_slate = api.get_stored_tx(m, Some(txs[0].id), None)?.unwrap();
api.post_tx(m, &stored_tx_slate, false)?;
bh += 1;
Ok(())
})?;
wallet::controller::owner_single_use(
wallet1.clone(),
mask1,
PathBuf::from(test_dir),
|api, m| {
let (_, txs) = api.retrieve_txs(m, true, None, Some(slate.id), None)?;
let stored_tx_slate = api.get_stored_tx(m, Some(txs[0].id), None)?.unwrap();
api.post_tx(m, &stored_tx_slate, false)?;
bh += 1;
Ok(())
},
)?;
let _ = test_framework::award_blocks_to_wallet(&chain, wallet1.clone(), mask1, 3, false);
bh += 3;
//
// update/test contents of both accounts
wallet::controller::owner_single_use(Some(wallet1.clone()), mask1, None, |api, m| {
let (wallet1_refreshed, wallet1_info) = api.retrieve_summary_info(m, true, 1)?;
assert!(wallet1_refreshed);
assert_eq!(wallet1_info.last_confirmed_height, bh);
assert_eq!(wallet1_info.total, bh * reward - reward * 4);
Ok(())
})?;
wallet::controller::owner_single_use(
wallet1.clone(),
mask1,
PathBuf::from(test_dir),
|api, m| {
let (wallet1_refreshed, wallet1_info) = api.retrieve_summary_info(m, true, 1)?;
assert!(wallet1_refreshed);
assert_eq!(wallet1_info.last_confirmed_height, bh);
assert_eq!(wallet1_info.total, bh * reward - reward * 4);
Ok(())
},
)?;
wallet::controller::owner_single_use(Some(wallet2.clone()), mask2, None, |api, m| {
let (wallet2_refreshed, wallet2_info) = api.retrieve_summary_info(m, true, 1)?;
assert!(wallet2_refreshed);
assert_eq!(wallet2_info.last_confirmed_height, bh);
assert_eq!(wallet2_info.total, 2 * amount);
Ok(())
})?;
wallet::controller::owner_single_use(
wallet2.clone(),
mask2,
PathBuf::from(test_dir),
|api, m| {
let (wallet2_refreshed, wallet2_info) = api.retrieve_summary_info(m, true, 1)?;
assert!(wallet2_refreshed);
assert_eq!(wallet2_info.last_confirmed_height, bh);
assert_eq!(wallet2_info.total, 2 * amount);
Ok(())
},
)?;
// let logging finish
stopper.store(false, Ordering::Relaxed);