iuna

iuna - experimental devnet protocol
git clone https://iuna.jhx.app/git/iuna.git
Log | Files | Refs | README | LICENSE

commit dde7679e31e33e5c15f3708d561af99ca51f7d19
parent d6f4b5724e84c15166e7e0e0f6164a12bbdf0015
Author: Joris Hartog <jorishartog@hotmail.com>
Date:   Wed, 22 Jul 2026 11:57:37 +0200

Move runtime configuration into UI


Diffstat:
MREADME.md | 25+++++++++++--------------
Massets/mivora-ui.js | 14++++++++++++--
Msrc/adapters/http.rs | 54+++++++++++++++++++++++++++++++++---------------------
Msrc/adapters/p2p.rs | 4++--
Msrc/app.rs | 19++-----------------
Msrc/main.rs | 35+++++++++++++++--------------------
Mtests/coin.rs | 69+++++++++++++--------------------------------------------------------
7 files changed, 88 insertions(+), 132 deletions(-)

diff --git a/README.md b/README.md @@ -15,26 +15,26 @@ The validated chain is persisted to `.mivora/chain.sqlite3` and resumes automati Mining is automatic. There is no "mine block" button and no exact sleep. Each node can burn its configured amount once per chain height. Those burns become one-shot leader tickets for a future height after the launch profile's maturity delay. Only the selected ticket owner builds the next block, signs a leader proof, performs the VDF work, and gossips the finished block. The VDF is the clock. -The plain command above creates the default zero-balance starter chain: genesis mints 1 coin and immediately burns it into the first leader ticket. That is enough to mine block 1 and earn the first reward. For a self-running local demo, leave one extra coin after genesis and burn it into block 1 so block 2 already has a ticket: +The plain command above creates the default zero-balance starter chain: genesis mints 1 coin and immediately burns it into the first leader ticket. That is enough to mine block 1 and earn the first reward. For a local demo with room to configure automatic burns, leave one extra coin after genesis and set the burn rate in the Configuration tab before block 1 is mined: ```sh -cargo run -- --start --genesis-amount 2 --burn-per-block 1 --http 127.0.0.1:8443 --p2p 127.0.0.1:9444 +cargo run -- --start --genesis-amount 2 --http 127.0.0.1:8443 --p2p 127.0.0.1:9444 ``` The management UI is a small AlpineJS app served from local vendored assets. It polls JSON endpoints every few seconds and includes: - wallet and transaction controls, -- fixed burn-per-block settings, +- runtime mining and peer settings in the Configuration screen, - P2P peer status with gossip send/receive counters and last error, - a blockchain explorer and mempool view. For a second local node joining Alice's chain: ```sh -cargo run -- --name bob --data-dir .mivora-bob --http 127.0.0.1:8444 --p2p 127.0.0.1:9445 --join 127.0.0.1:9444 +cargo run -- --data-dir .mivora-bob --http 127.0.0.1:8444 --p2p 127.0.0.1:9445 --join 127.0.0.1:9444 ``` -`--join` fetches a chain snapshot from the peer before mining starts and announces this node's P2P listener back to that peer, so newly mined blocks can flow back without restarting the first node. If the peer cannot provide a snapshot, the node exits instead of silently starting a separate chain. Plain `--peer` only adds a gossip peer and does not require bootstrap success. +`--join` fetches a chain snapshot from the peer before mining starts and announces this node's P2P listener back to that peer, so newly mined blocks can flow back without restarting the first node. If the peer cannot provide a snapshot, the node exits instead of silently starting a separate chain. Additional peers can be added from the Configuration screen. If `<data-dir>/chain.sqlite3` already exists, the node resumes that chain first. That makes restarts boring in the good way: `--start` will not create a new genesis over an existing local chain, and `--join` remains useful for reconnecting to peers without replacing local state. Pass `--chain-db path/to/chain.sqlite3` to override the database path. @@ -49,17 +49,18 @@ To start a small friendly network: 1. Start your node with a public P2P bind: ```sh -cargo run -- --start --genesis-amount 2 --burn-per-block 1 --p2p 0.0.0.0:9444 --http 127.0.0.1:8443 +cargo run -- --start --genesis-amount 2 --p2p 0.0.0.0:9444 --http 127.0.0.1:8443 ``` -2. Give friends your public `host:9444`. -3. Friends join your chain: +2. Open the Configuration tab and set the starter burn rate before block 1 is mined. +3. Give friends your public `host:9444`. +4. Friends join your chain: ```sh cargo run -- --data-dir .mivora-friend --p2p 0.0.0.0:9445 --http 127.0.0.1:8443 --join your-host:9444 ``` -Friends who join after you start will adopt your genesis and current chain. With the default genesis amount, the starter wallet begins with a 0 balance because genesis mints 1 coin and immediately burns it as the first leader ticket. For a moving demo, `--genesis-amount 2 --burn-per-block 1` leaves the starter one coin to burn into block 1, creating the ticket for block 2. After the starter mines the first block reward, send friends coins from the UI; then they can choose a burn amount and compete for future blocks. Every joining node starts with a 0-coin automatic burn unless it is configured otherwise. +Friends who join after you start will adopt your genesis and current chain. With the default genesis amount, the starter wallet begins with a 0 balance because genesis mints 1 coin and immediately burns it as the first leader ticket. For a moving demo, `--genesis-amount 2` leaves the starter one coin that can be configured as the block 1 burn from the UI, creating the ticket for block 2. After the starter mines the first block reward, send friends coins from the UI; then they can choose a burn amount and compete for future blocks. Every joining node starts with a 0-coin automatic burn unless it is configured otherwise. The genesis block bootstraps the chain with a 1-coin burn from the starter wallet. Burns included in a block create one-shot tickets for a future height through a deterministic ticket lottery. The selected leader creates the next block content, signs a proof for the selected ticket, and runs a hash-chain VDF before gossiping the block. @@ -67,11 +68,7 @@ Every non-genesis block must consume the selected mature ticket. A block may con The protocol targets 60-second blocks by retargeting the expected VDF rounds after each block. It uses a rolling average of recent block intervals and only moves the next round count by about 10% per block, so short bursts do not make the delay swing wildly. Every node derives the same next-round count from the validated chain. -The block reward is fixed at 100 coins. The default burn is 0 coins per block, so new nodes can join before they own coins. After a wallet has coins, raise the burn from the UI or with: - -```sh -cargo run -- --burn-per-block 25 -``` +The block reward is fixed at 100 coins. The default burn is 0 coins per block, so new nodes can join before they own coins. After a wallet has coins, raise the burn from the Configuration screen. The default VDF round count is only the initial delay. After the first blocks, the protocol steers rounds toward the 60-second target. For fast local demos and tests, pass a smaller initial value: diff --git a/assets/mivora-ui.js b/assets/mivora-ui.js @@ -32,17 +32,27 @@ window.mivoraApp = function mivoraApp() { tabFromHash() { const hash = window.location.hash.replace(/^#\/?/, ""); - return ["wallet", "mining", "p2p", "chain"].includes(hash) ? hash : "wallet"; + return ["wallet", "mining", "p2p", "chain", "config"].includes(hash) ? hash : "wallet"; }, setTab(tab) { - if (!["wallet", "mining", "p2p", "chain"].includes(tab)) return; + if (!["wallet", "mining", "p2p", "chain", "config"].includes(tab)) return; this.tab = tab; if (window.location.hash !== `#${tab}`) { window.location.hash = tab; } }, + pageTitle() { + return { + wallet: "Mivora", + mining: "Mining", + p2p: "P2P", + chain: "Chain", + config: "Configuration", + }[this.tab] || "Mivora"; + }, + async refresh() { try { const [status, blocks, mempool, peers] = await Promise.all([ diff --git a/src/adapters/http.rs b/src/adapters/http.rs @@ -263,8 +263,9 @@ const INDEX_HTML: &str = r#"<!doctype html> .nav-button svg.chain-icon { stroke-width: 1.35; } .nav-button span { font-size: 11px; font-weight: 800; } .nav-button:hover, .nav-button.active { background: #202328; border-color: #3b4448; color: #d5f55f; } - .content { min-width: 0; padding: 22px 24px 48px; } - main { max-width: 1240px; margin: 0 auto; } + .content { width: 100%; min-width: 0; padding: 22px 24px 48px; } + main { width: 100%; } + main > section { width: 100%; } header { display: flex; justify-content: space-between; gap: 18px; align-items: flex-start; padding: 0 0 18px; } h1 { margin: 0 0 4px; font-size: 28px; } h2 { margin: 0 0 12px; font-size: 18px; } @@ -295,9 +296,10 @@ const INDEX_HTML: &str = r#"<!doctype html> .flash.error { color: #ffb1a8; background: #2a1717; border-color: #713434; } .ok { color: #d5f55f; } .page-title { margin-bottom: 16px; } - .wallet-grid { display: grid; grid-template-columns: minmax(0, 1fr) minmax(300px, .8fr); gap: 12px; align-items: start; } + .wallet-grid { width: 100%; display: grid; grid-template-columns: minmax(0, 1fr) minmax(300px, .8fr); gap: 12px; align-items: start; } .wallet-actions { display: grid; gap: 12px; } - .mining-grid { display: grid; grid-template-columns: minmax(0, .95fr) minmax(300px, .7fr); gap: 12px; align-items: start; } + .mining-grid { width: 100%; display: grid; grid-template-columns: minmax(0, .95fr) minmax(300px, .7fr); gap: 12px; align-items: start; } + .config-grid { width: 100%; display: grid; grid-template-columns: minmax(0, .9fr) minmax(300px, .75fr); gap: 12px; align-items: start; } .receive-address { display: grid; gap: 8px; } .address-box { border: 1px solid #2f363c; border-radius: 8px; padding: 11px; background: #111316; } .panel-head { display: flex; justify-content: space-between; gap: 12px; align-items: center; margin-bottom: 12px; } @@ -309,7 +311,7 @@ const INDEX_HTML: &str = r#"<!doctype html> .wallet-tx-main { display: grid; gap: 4px; min-width: 0; } .wallet-tx-amount { font-weight: 900; } .panel .grid + form { margin-top: 12px; } - .explorer-shell { display: grid; gap: 12px; } + .explorer-shell { width: 100%; display: grid; gap: 12px; } .block-rail-wrap { background: #181b1f; border: 1px solid #2a3035; border-radius: 8px; padding: 12px; overflow: hidden; } .block-rail-head { display: flex; justify-content: space-between; gap: 10px; align-items: center; margin-bottom: 10px; } .block-rail { display: flex; gap: 8px; overflow-x: auto; padding: 1px 0 10px; scroll-snap-type: x proximity; } @@ -339,22 +341,23 @@ const INDEX_HTML: &str = r#"<!doctype html> .pill.transfer { background: #17312a; color: #8de9cd; } .mempool-strip { display: flex; gap: 8px; overflow-x: auto; padding-bottom: 4px; } .mempool-item { flex: 0 0 200px; border: 1px solid #2f363c; border-radius: 8px; padding: 10px; background: #111316; } - @media (max-width: 920px) { .wallet-grid, .mining-grid, .detail-grid { grid-template-columns: 1fr; } } + @media (max-width: 920px) { .wallet-grid, .mining-grid, .config-grid, .detail-grid { grid-template-columns: 1fr; } } @media (max-width: 760px) { .app-shell { grid-template-columns: 1fr; } .sidebar { position: sticky; z-index: 5; bottom: 0; top: auto; height: auto; flex-direction: row; justify-content: space-between; padding: 8px; border-right: 0; border-bottom: 1px solid #262b2f; } .brand-mark { width: 38px; height: 38px; font-size: 19px; } .side-nav { display: flex; width: auto; gap: 8px; } - .nav-button { width: 58px; min-height: 48px; } + .nav-button { width: 52px; min-height: 48px; } + .nav-button span { font-size: 10px; } .content { padding: 16px 12px 36px; } - header, .split, .wallet-grid, .mining-grid, .detail-grid, .wallet-tx-row { grid-template-columns: 1fr; } + header, .split, .wallet-grid, .mining-grid, .config-grid, .detail-grid, .wallet-tx-row { grid-template-columns: 1fr; } header { display: grid; } input { min-width: 0; width: 100%; } .switch input { width: auto; } .block-card { flex-basis: 108px; } } </style> - <script defer src="/assets/mivora-ui.js?v=13"></script> + <script defer src="/assets/mivora-ui.js?v=15"></script> <script defer src="/assets/alpine.min.js"></script> </head> <body x-data="mivoraApp()" x-init="init()" x-cloak> @@ -378,14 +381,17 @@ const INDEX_HTML: &str = r#"<!doctype html> <svg class="chain-icon" viewBox="0 0 24 24" aria-hidden="true"><rect x="1.5" y="9" width="5.5" height="5.5"></rect><rect x="9.25" y="9" width="5.5" height="5.5"></rect><rect x="17" y="9" width="5.5" height="5.5"></rect></svg> <span>Chain</span> </button> + <button class="nav-button" :class="{ active: tab === 'config' }" @click="setTab('config')" type="button" title="Configuration" aria-label="Configuration"> + <svg viewBox="0 0 24 24" aria-hidden="true"><path d="M4 21v-7"></path><path d="M4 10V3"></path><path d="M12 21v-9"></path><path d="M12 8V3"></path><path d="M20 21v-5"></path><path d="M20 12V3"></path><path d="M2 14h4"></path><path d="M10 8h4"></path><path d="M18 16h4"></path></svg> + <span>Config</span> + </button> </nav> </aside> <main class="content"> <header> <div> - <h1>Mivora</h1> - <div class="muted">Consensus node console</div> + <h1 x-text="pageTitle()">Mivora</h1> </div> <div class="muted" x-text="lastUpdatedLabel()"></div> </header> @@ -394,7 +400,6 @@ const INDEX_HTML: &str = r#"<!doctype html> <section x-show="tab === 'wallet'"> <div class="page-title"> - <h2>Wallet</h2> <div class="muted">Balance <strong x-text="status.wallet_balance ?? '-'"></strong></div> </div> <div class="wallet-grid"> @@ -444,7 +449,6 @@ const INDEX_HTML: &str = r#"<!doctype html> <section x-show="tab === 'mining'"> <div class="page-title"> - <h2>Mining</h2> <div class="muted">Automatic VDF-paced block production</div> </div> <div class="mining-grid"> @@ -457,19 +461,12 @@ const INDEX_HTML: &str = r#"<!doctype html> <div class="metric"><div class="label">Target</div><div class="value" x-text="targetSecondsLabel()"></div></div> </div> </div> - <div class="panel"> - <h3>Burn Rate</h3> - <form @submit.prevent="saveBurn"> - <label>Coins per block<input x-model.number="burnAmount" type="number" min="0"></label> - <button class="primary" type="submit">Save</button> - </form> - </div> </div> </section> <section x-show="tab === 'p2p'"> <div class="panel"> - <h2>P2P</h2> + <h2>Add Peer</h2> <form @submit.prevent="addPeer"> <label>Peer address<input x-model="peerAddress" placeholder="127.0.0.1:9445"></label> <button class="primary" type="submit">Add</button> @@ -488,6 +485,21 @@ const INDEX_HTML: &str = r#"<!doctype html> </div> </section> + <section x-show="tab === 'config'"> + <div class="page-title"> + <div class="muted">Runtime node settings</div> + </div> + <div class="config-grid"> + <div class="panel"> + <h3>Mining</h3> + <form @submit.prevent="saveBurn"> + <label>Coins per block<input x-model.number="burnAmount" type="number" min="0"></label> + <button class="primary" type="submit">Save</button> + </form> + </div> + </div> + </section> + <section x-show="tab === 'chain'"> <div class="explorer-shell"> <div class="block-rail-wrap"> diff --git a/src/adapters/p2p.rs b/src/adapters/p2p.rs @@ -1603,14 +1603,14 @@ mod tests { assert!(addresses.contains(&"127.0.0.1:9546".to_string())); } - fn node(name: &str, wallet: Wallet, allocations: BTreeMap<String, Amount>) -> NodeCore { + fn node(_network_key: &str, wallet: Wallet, allocations: BTreeMap<String, Amount>) -> NodeCore { let ledger = Ledger::new_with_genesis_burns( allocations, vec![GenesisBurn::new(wallet.address(), 1)], 25, ) .unwrap(); - NodeCore::from_ledger(name.to_string(), wallet, ledger, 0) + NodeCore::from_ledger(wallet, ledger, 0) } fn allocations(wallets: &[Wallet], amount: Amount) -> BTreeMap<String, Amount> { diff --git a/src/app.rs b/src/app.rs @@ -25,7 +25,6 @@ const IMPORT_REBROADCAST_LIMIT: usize = 128; #[derive(Clone, Debug)] pub struct NodeConfig { - pub name: String, pub wallet: Wallet, pub genesis_allocations: BTreeMap<String, Amount>, pub vdf_rounds: u32, @@ -90,7 +89,6 @@ pub struct BlockInventory { #[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] pub struct NodeStatus { - pub name: String, pub wallet_address: String, pub wallet_balance: Amount, pub launch_profile: LaunchProfileStatus, @@ -131,7 +129,6 @@ pub struct AutoMinePlan { #[derive(Clone, Debug)] pub struct NodeCore { - name: String, wallet: Wallet, ledger: Ledger, burn_per_block: Amount, @@ -142,17 +139,11 @@ pub struct NodeCore { impl NodeCore { pub fn new(config: NodeConfig) -> Self { let ledger = Ledger::new(config.genesis_allocations, config.vdf_rounds); - Self::from_ledger(config.name, config.wallet, ledger, config.burn_per_block) + Self::from_ledger(config.wallet, ledger, config.burn_per_block) } - pub fn from_ledger( - name: String, - wallet: Wallet, - ledger: Ledger, - burn_per_block: Amount, - ) -> Self { + pub fn from_ledger(wallet: Wallet, ledger: Ledger, burn_per_block: Amount) -> Self { Self { - name, wallet, ledger, burn_per_block, @@ -161,10 +152,6 @@ impl NodeCore { } } - pub fn name(&self) -> &str { - &self.name - } - pub fn wallet_address(&self) -> &str { self.wallet.address() } @@ -309,7 +296,6 @@ impl NodeCore { .is_none_or(|leader| leader == self.wallet.address()); NodeStatus { - name: self.name.clone(), wallet_address: self.wallet.address().to_string(), wallet_balance: self.ledger.balance_of(self.wallet.address()), launch_profile: LaunchProfileStatus { @@ -697,7 +683,6 @@ mod tests { let mut allocations = BTreeMap::new(); allocations.insert(alice.address().to_string(), 1_000); let mut node = NodeCore::new(NodeConfig { - name: "alice".to_string(), wallet: alice, genesis_allocations: allocations, vdf_rounds: 10, diff --git a/src/main.rs b/src/main.rs @@ -24,10 +24,9 @@ async fn main() -> Result<()> { let ledger = initialize_ledger(&opts, wallet.address(), &chain_store).await?; let node: SharedNode = Arc::new(Mutex::new(NodeCore::from_ledger( - opts.node_name, wallet, ledger, - opts.burn_per_block, + DEFAULT_BURN_PER_BLOCK, ))); let peers: SharedPeerBook = Arc::new(Mutex::new(PeerBook::from_addresses(opts.peers))); let initial_snapshot = { node.lock().await.chain_snapshot() }; @@ -40,7 +39,7 @@ async fn main() -> Result<()> { println!("p2p listener: {}", opts.p2p_addr); println!( "automatic mining: VDF-driven, burning {} coins per block", - opts.burn_per_block + DEFAULT_BURN_PER_BLOCK ); let persistence_node = Arc::clone(&node); @@ -94,7 +93,6 @@ async fn initialize_ledger( #[derive(Debug)] struct CliOptions { - node_name: String, wallet_path: Option<PathBuf>, chain_db_path: Option<PathBuf>, http_addr: SocketAddr, @@ -104,7 +102,6 @@ struct CliOptions { start_new_chain: bool, genesis_amount: Amount, vdf_rounds: u32, - burn_per_block: Amount, data_dir: PathBuf, } @@ -115,7 +112,6 @@ impl CliOptions { fn parse_from(args: impl IntoIterator<Item = String>) -> Result<Option<Self>> { let mut opts = Self { - node_name: "mivora-dev".to_string(), wallet_path: None, chain_db_path: None, http_addr: SocketAddr::from_str("127.0.0.1:8443")?, @@ -125,7 +121,6 @@ impl CliOptions { start_new_chain: false, genesis_amount: 1, vdf_rounds: DEFAULT_VDF_ROUNDS, - burn_per_block: DEFAULT_BURN_PER_BLOCK, data_dir: PathBuf::from(".mivora"), }; @@ -139,7 +134,6 @@ impl CliOptions { while let Some(arg) = args.next() { match arg.as_str() { "--start" => opts.start_new_chain = true, - "--name" => opts.node_name = next_value(&mut args, "--name")?, "--wallet" => { opts.wallet_path = Some(PathBuf::from(next_value(&mut args, "--wallet")?)) } @@ -161,7 +155,6 @@ impl CliOptions { .parse() .context("invalid --p2p address")?; } - "--peer" => opts.peers.push(next_value(&mut args, "--peer")?), "--join" => { let peer = next_value(&mut args, "--join")?; opts.peers.push(peer.clone()); @@ -180,11 +173,6 @@ impl CliOptions { .parse() .context("invalid --vdf-rounds")?; } - "--burn-per-block" => { - opts.burn_per_block = next_value(&mut args, "--burn-per-block")? - .parse() - .context("invalid --burn-per-block")?; - } "--data-dir" => opts.data_dir = PathBuf::from(next_value(&mut args, "--data-dir")?), "--help" | "-h" => { print_help(); @@ -217,9 +205,9 @@ impl CliOptions { } } -fn next_value(args: &mut impl Iterator<Item = String>, name: &str) -> Result<String> { +fn next_value(args: &mut impl Iterator<Item = String>, flag: &str) -> Result<String> { args.next() - .with_context(|| format!("missing value after {name}")) + .with_context(|| format!("missing value after {flag}")) } fn print_help() { @@ -230,16 +218,13 @@ fn print_help() { mivora --join <addr:port> [options]\n\n\ Options:\n\ --start Create a new chain with a genesis burn\n\ - --name <name> Node display name\n\ --wallet <path> Wallet file (default <data-dir>/wallet.json)\n\ --chain-db <path> Chain SQLite database (default <data-dir>/chain.sqlite3)\n\ --http <addr:port> HTTP management UI address (default 127.0.0.1:8443)\n\ --p2p <addr:port> P2P TCP listener address (default 127.0.0.1:9444)\n\ - --peer <addr:port> P2P peer to gossip to; may be repeated\n\ --join <addr:port> Fetch chain snapshot from this peer before mining\n\ --genesis-amount <amount> Genesis allocation before the 1-coin bootstrap ticket (default 1)\n\ --vdf-rounds <rounds> Initial VDF delay rounds; protocol retargets toward 60s blocks\n\ - --burn-per-block <amount> Fixed automatic burn before each block attempt\n\ --data-dir <path> Local wallet directory\n" ); } @@ -460,6 +445,17 @@ mod tests { } #[test] + fn runtime_configuration_flags_are_rejected() { + for flag in ["--name", "--burn-per-block", "--peer"] { + let error = parse(&["--start", flag, "value"]).unwrap_err(); + assert!( + error.to_string().contains("unknown argument"), + "{flag} should not be accepted" + ); + } + } + + #[test] fn start_mode_is_explicit() { let opts = parse(&["--start"]).unwrap().unwrap(); assert!(opts.start_new_chain); @@ -623,7 +619,6 @@ VALUES (1, 4, 'bad-tip', '{"not":"a chain snapshot"}', 0) let wallet = Wallet::from_seed("background-persistence"); let ledger = ledger_with_one_spendable_coin(&wallet); let node = Arc::new(Mutex::new(NodeCore::from_ledger( - "persistence".to_string(), wallet.clone(), ledger, DEFAULT_BURN_PER_BLOCK, diff --git a/tests/coin.rs b/tests/coin.rs @@ -9,9 +9,8 @@ use mivora::{ }; use tempfile::tempdir; -fn node(name: &str, wallet: Wallet, allocations: BTreeMap<String, Amount>) -> NodeCore { +fn node(_network_key: &str, wallet: Wallet, allocations: BTreeMap<String, Amount>) -> NodeCore { NodeCore::new(NodeConfig { - name: name.to_string(), wallet, genesis_allocations: allocations, vdf_rounds: 25, @@ -72,19 +71,19 @@ fn fork_with_worse_vrf_block( None } -fn starter_node(name: &str, wallet: Wallet) -> NodeCore { +fn starter_node(wallet: Wallet) -> NodeCore { let mut genesis = BTreeMap::new(); genesis.insert(wallet.address().to_string(), 1); let ledger = Ledger::new_with_genesis_burns(genesis, vec![GenesisBurn::new(wallet.address(), 1)], 25) .unwrap(); - NodeCore::from_ledger(name.to_string(), wallet, ledger, DEFAULT_BURN_PER_BLOCK) + NodeCore::from_ledger(wallet, ledger, DEFAULT_BURN_PER_BLOCK) } #[test] fn genesis_burn_starts_chain_with_zero_balance_and_first_leader() { let alice = Wallet::from_seed("alice"); - let node = starter_node("alice", alice.clone()); + let node = starter_node(alice.clone()); let genesis = &node.ledger().chain()[0]; assert_eq!(node.ledger().balance_of(alice.address()), 0); @@ -101,7 +100,7 @@ fn genesis_burn_starts_chain_with_zero_balance_and_first_leader() { #[test] fn starter_node_mines_first_reward_from_genesis_ticket() { let alice = Wallet::from_seed("alice"); - let mut node = starter_node("alice", alice.clone()); + let mut node = starter_node(alice.clone()); let outcome = node.automatic_mine_once(1); assert!(outcome.burned.is_none()); @@ -312,7 +311,6 @@ fn automatic_mining_burns_configured_amount_once_per_height() { allocations.insert(alice.address().to_string(), 1_000); let mut node = NodeCore::new(NodeConfig { - name: "alice".to_string(), wallet: alice.clone(), genesis_allocations: allocations, vdf_rounds: 10, @@ -645,12 +643,7 @@ fn joined_nodes_import_transfer_block_and_every_wallet_mines() { let mut network = InMemoryNetwork::default(); network.insert( "a", - NodeCore::from_ledger( - "a".to_string(), - alice.clone(), - alice_ledger, - DEFAULT_BURN_PER_BLOCK, - ), + NodeCore::from_ledger(alice.clone(), alice_ledger, DEFAULT_BURN_PER_BLOCK), ); let mut mined_by = Vec::new(); @@ -665,12 +658,7 @@ fn joined_nodes_import_transfer_block_and_every_wallet_mines() { let bob_ledger = Ledger::from_snapshot(network.node("a").unwrap().chain_snapshot()).unwrap(); network.insert( "b", - NodeCore::from_ledger( - "b".to_string(), - bob.clone(), - bob_ledger, - DEFAULT_BURN_PER_BLOCK, - ), + NodeCore::from_ledger(bob.clone(), bob_ledger, DEFAULT_BURN_PER_BLOCK), ); for height in 3..=4 { @@ -684,12 +672,7 @@ fn joined_nodes_import_transfer_block_and_every_wallet_mines() { let carol_ledger = Ledger::from_snapshot(network.node("a").unwrap().chain_snapshot()).unwrap(); network.insert( "c", - NodeCore::from_ledger( - "c".to_string(), - carol.clone(), - carol_ledger, - DEFAULT_BURN_PER_BLOCK, - ), + NodeCore::from_ledger(carol.clone(), carol_ledger, DEFAULT_BURN_PER_BLOCK), ); network @@ -814,12 +797,7 @@ fn persisted_joined_nodes_restart_and_keep_syncing_without_tcp() { let mut network = InMemoryNetwork::default(); network.insert( "a", - NodeCore::from_ledger( - "a".to_string(), - alice.clone(), - alice_ledger, - DEFAULT_BURN_PER_BLOCK, - ), + NodeCore::from_ledger(alice.clone(), alice_ledger, DEFAULT_BURN_PER_BLOCK), ); network.node_mut("a").unwrap().burn(1).unwrap(); @@ -833,12 +811,7 @@ fn persisted_joined_nodes_restart_and_keep_syncing_without_tcp() { let bob_joined_ledger = Ledger::from_snapshot(bob_store.load().unwrap().unwrap()).unwrap(); network.insert( "b", - NodeCore::from_ledger( - "b".to_string(), - bob.clone(), - bob_joined_ledger, - DEFAULT_BURN_PER_BLOCK, - ), + NodeCore::from_ledger(bob.clone(), bob_joined_ledger, DEFAULT_BURN_PER_BLOCK), ); assert_eq!( network.node("b").unwrap().ledger().status().tip_hash, @@ -869,12 +842,7 @@ fn persisted_joined_nodes_restart_and_keep_syncing_without_tcp() { let bob_restarted_ledger = Ledger::from_snapshot(bob_store.load().unwrap().unwrap()).unwrap(); network.insert( "b", - NodeCore::from_ledger( - "b".to_string(), - bob.clone(), - bob_restarted_ledger, - DEFAULT_BURN_PER_BLOCK, - ), + NodeCore::from_ledger(bob.clone(), bob_restarted_ledger, DEFAULT_BURN_PER_BLOCK), ); assert_eq!( network.node("b").unwrap().ledger().status().tip_hash, @@ -889,12 +857,7 @@ fn persisted_joined_nodes_restart_and_keep_syncing_without_tcp() { let carol_joined_ledger = Ledger::from_snapshot(carol_store.load().unwrap().unwrap()).unwrap(); network.insert( "c", - NodeCore::from_ledger( - "c".to_string(), - carol, - carol_joined_ledger, - DEFAULT_BURN_PER_BLOCK, - ), + NodeCore::from_ledger(carol, carol_joined_ledger, DEFAULT_BURN_PER_BLOCK), ); network.node_mut("b").unwrap().burn(1).unwrap(); @@ -955,7 +918,6 @@ fn mined_block_gossip_does_not_include_full_chain_snapshot() { let allocations = allocations(&wallets, 1_000); let mut alice_node = NodeCore::new(NodeConfig { - name: "alice".to_string(), wallet: alice, genesis_allocations: allocations.clone(), vdf_rounds: 10, @@ -1273,12 +1235,7 @@ fn friend_node_can_join_snapshot_from_started_chain() { alice_node.automatic_mine_once(1); let joined_ledger = Ledger::from_snapshot(alice_node.chain_snapshot()).unwrap(); - let mut bob_node = NodeCore::from_ledger( - "bob".to_string(), - bob.clone(), - joined_ledger, - DEFAULT_BURN_PER_BLOCK, - ); + let mut bob_node = NodeCore::from_ledger(bob.clone(), joined_ledger, DEFAULT_BURN_PER_BLOCK); assert_eq!( bob_node.ledger().status().tip_hash,