// Copyright (C) 2019-2021 Aleo Systems Inc.
// This file is part of the Aleo library.
// The Aleo library is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// The Aleo library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with the Aleo library. If not, see <https://www.gnu.org/licenses/>.
use crate::{helpers::Ledger, Network};
use snarkvm::{
file::{AleoFile, Manifest},
package::Package,
};
use anyhow::{ensure, Result};
use clap::Parser;
use colored::*;
use std::sync::Arc;
/// Commands to operate a local development node.
#[derive(Debug, Parser)]
pub enum Node {
/// Starts a local development node
Start {
/// Skips deploying the local program at genesis.
#[clap(long)]
nodeploy: bool,
},
}
impl Node {
pub fn parse(self) -> Result<String> {
match self {
Self::Start { nodeploy } => {
// Derive the program directory path.
let directory = std::env::current_dir()?;
// Ensure the directory path exists.
ensure!(directory.exists(), "The program directory does not exist: {}", directory.display());
// Ensure the manifest file exists.
ensure!(
Manifest::<Network>::exists_at(&directory),
"Please start a local node in an Aleo program directory (missing '{}' at '{}')",
Manifest::<Network>::file_name(),
directory.display()
);
// Open the manifest file.
let manifest = Manifest::open(&directory)?;
println!(
"⏳ Starting a local development node for '{}' (in-memory)...\n",
manifest.program_id().to_string().bold()
);
// Retrieve the private key.
let private_key = manifest.development_private_key();
// Initialize the ledger.
let ledger = Arc::new(Ledger::<Network>::load(private_key)?);
// Deploy the local program.
if !nodeploy {
// Load the package.
let package = Package::open(&directory)?;
// Load the program.
let program = package.program();
// Prepare the imports directory.
let imports_directory = package.imports_directory();
// Load all of the imported programs (in order of imports).
let programs = program
.imports()
.keys()
.map(|program_id| {
// Open the Aleo imported program file.
let import_program_file = AleoFile::open(&imports_directory, program_id, false)?;
// Return the imported program.
Ok(import_program_file.program().clone())
})
.collect::<Result<Vec<_>>>()?;
// Deploy the imported programs (in order of imports), and the main program.
for program in programs.iter().chain([program.clone()].iter()) {
println!(
"📦 Deploying '{}' to the local development node...\n",
program.id().to_string().bold()
);
// Create a deployment transaction.
let transaction = ledger.create_deploy(program, 1)?;
// Add the transaction to the memory pool.
ledger.add_to_memory_pool(transaction.clone())?;
// Advance to the next block.
let next_block = ledger.advance_to_next_block()?;
println!(
"\n🛡️ Produced block {} ({})\n\n{}\n",
next_block.height(),
next_block.hash(),
serde_json::to_string_pretty(&next_block.header())?.dimmed()
);
println!(
"✅ Deployed '{}' in transaction '{}'\n",
program.id().to_string().bold(),
transaction.id()
);
}
}
loop {
// Create a transfer transaction.
let transaction = ledger.create_transfer(ledger.address(), 1)?;
// Add the transaction to the memory pool.
ledger.add_to_memory_pool(transaction)?;
// Advance to the next block.
let next_block = ledger.advance_to_next_block()?;
println!(
"\n🛡️ Produced block {} ({})\n\n{}\n",
next_block.height(),
next_block.hash(),
serde_json::to_string_pretty(&next_block.header())?.dimmed()
);
}
}
}
}
}