|
@@ -18,20 +18,32 @@
|
|
|
|
|
|
|
|
use std::{
|
|
use std::{
|
|
|
fs::{read_dir, read_to_string},
|
|
fs::{read_dir, read_to_string},
|
|
|
- io::{stdin, Read},
|
|
|
|
|
|
|
+ io::{stdin, Cursor, Read},
|
|
|
|
|
+ process::exit,
|
|
|
|
|
+ str::FromStr,
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
-use anyhow::Result;
|
|
|
|
|
use clap::{Parser, Subcommand};
|
|
use clap::{Parser, Subcommand};
|
|
|
use darkfi::{
|
|
use darkfi::{
|
|
|
blockchain::{BlockInfo, Blockchain, BlockchainOverlay},
|
|
blockchain::{BlockInfo, Blockchain, BlockchainOverlay},
|
|
|
cli_desc,
|
|
cli_desc,
|
|
|
- tx::Transaction,
|
|
|
|
|
- util::{encoding::base64, path::expand_path, time::Timestamp},
|
|
|
|
|
- validator::verification::verify_genesis_block,
|
|
|
|
|
|
|
+ tx::{ContractCallLeaf, Transaction, TransactionBuilder},
|
|
|
|
|
+ util::{encoding::base64, parse::decode_base10, path::expand_path, time::Timestamp},
|
|
|
|
|
+ validator::{utils::deploy_native_contracts, verification::verify_genesis_block},
|
|
|
|
|
+ zk::{empty_witnesses, halo2::Field, ProvingKey, ZkCircuit},
|
|
|
|
|
+ zkas::ZkBinary,
|
|
|
|
|
+ Result,
|
|
|
};
|
|
};
|
|
|
use darkfi_contract_test_harness::vks;
|
|
use darkfi_contract_test_harness::vks;
|
|
|
-use darkfi_serial::{deserialize, serialize};
|
|
|
|
|
|
|
+use darkfi_money_contract::{
|
|
|
|
|
+ client::genesis_mint_v1::GenesisMintCallBuilder, MoneyFunction, MONEY_CONTRACT_ZKAS_MINT_NS_V1,
|
|
|
|
|
+};
|
|
|
|
|
+use darkfi_sdk::{
|
|
|
|
|
+ crypto::{contract_id::MONEY_CONTRACT_ID, FuncId, Keypair, SecretKey},
|
|
|
|
|
+ pasta::pallas,
|
|
|
|
|
+ ContractCall,
|
|
|
|
|
+};
|
|
|
|
|
+use darkfi_serial::{deserialize, serialize, AsyncEncodable};
|
|
|
|
|
|
|
|
#[derive(Parser)]
|
|
#[derive(Parser)]
|
|
|
#[command(about = cli_desc!())]
|
|
#[command(about = cli_desc!())]
|
|
@@ -58,11 +70,18 @@ enum Subcmd {
|
|
|
|
|
|
|
|
/// Read a Darkfi genesis block from stdin and verify it
|
|
/// Read a Darkfi genesis block from stdin and verify it
|
|
|
Verify,
|
|
Verify,
|
|
|
|
|
+
|
|
|
|
|
+ /// Generate a Darkfi genesis transaction using the secret
|
|
|
|
|
+ /// key from stdin
|
|
|
|
|
+ GenerateTx {
|
|
|
|
|
+ /// Amount to mint for this genesis transaction
|
|
|
|
|
+ amount: String,
|
|
|
|
|
+ },
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/// Auxiliary function to read a bs58 genesis block from stdin
|
|
/// Auxiliary function to read a bs58 genesis block from stdin
|
|
|
fn read_block() -> Result<BlockInfo> {
|
|
fn read_block() -> Result<BlockInfo> {
|
|
|
- eprintln!("Reading genesis block from stdin...");
|
|
|
|
|
|
|
+ println!("Reading genesis block from stdin...");
|
|
|
let mut buf = String::new();
|
|
let mut buf = String::new();
|
|
|
stdin().read_to_string(&mut buf)?;
|
|
stdin().read_to_string(&mut buf)?;
|
|
|
let bytes = base64::decode(buf.trim()).unwrap();
|
|
let bytes = base64::decode(buf.trim()).unwrap();
|
|
@@ -80,7 +99,6 @@ async fn main() -> Result<()> {
|
|
|
Subcmd::Display => {
|
|
Subcmd::Display => {
|
|
|
let genesis_block = read_block()?;
|
|
let genesis_block = read_block()?;
|
|
|
println!("{genesis_block:#?}");
|
|
println!("{genesis_block:#?}");
|
|
|
- Ok(())
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
Subcmd::Generate { txs_folder, genesis_timestamp } => {
|
|
Subcmd::Generate { txs_folder, genesis_timestamp } => {
|
|
@@ -88,7 +106,12 @@ async fn main() -> Result<()> {
|
|
|
let txs_folder = expand_path(&txs_folder).unwrap();
|
|
let txs_folder = expand_path(&txs_folder).unwrap();
|
|
|
let mut genesis_txs: Vec<Transaction> = vec![];
|
|
let mut genesis_txs: Vec<Transaction> = vec![];
|
|
|
for file in read_dir(txs_folder)? {
|
|
for file in read_dir(txs_folder)? {
|
|
|
- let bytes = base64::decode(read_to_string(file?.path())?.trim()).unwrap();
|
|
|
|
|
|
|
+ let file = file?;
|
|
|
|
|
+ let Ok(bytes) = bs58::decode(&read_to_string(file.path())?.trim()).into_vec()
|
|
|
|
|
+ else {
|
|
|
|
|
+ eprintln!("Error: Failed to decode transaction: {:?}", file.path());
|
|
|
|
|
+ exit(2);
|
|
|
|
|
+ };
|
|
|
let tx = deserialize(&bytes)?;
|
|
let tx = deserialize(&bytes)?;
|
|
|
genesis_txs.push(tx);
|
|
genesis_txs.push(tx);
|
|
|
}
|
|
}
|
|
@@ -98,7 +121,7 @@ async fn main() -> Result<()> {
|
|
|
|
|
|
|
|
// Update timestamp if one was provided
|
|
// Update timestamp if one was provided
|
|
|
if let Some(timestamp) = genesis_timestamp {
|
|
if let Some(timestamp) = genesis_timestamp {
|
|
|
- genesis_block.header.timestamp = Timestamp(timestamp);
|
|
|
|
|
|
|
+ genesis_block.header.timestamp = Timestamp::from_u64(timestamp);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// Retrieve genesis producer transaction
|
|
// Retrieve genesis producer transaction
|
|
@@ -113,8 +136,6 @@ async fn main() -> Result<()> {
|
|
|
// Write generated genesis block to stdin
|
|
// Write generated genesis block to stdin
|
|
|
let encoded = base64::encode(&serialize(&genesis_block));
|
|
let encoded = base64::encode(&serialize(&genesis_block));
|
|
|
println!("{encoded}");
|
|
println!("{encoded}");
|
|
|
-
|
|
|
|
|
- Ok(())
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
Subcmd::Verify => {
|
|
Subcmd::Verify => {
|
|
@@ -131,12 +152,72 @@ async fn main() -> Result<()> {
|
|
|
// Create an overlay over whole blockchain
|
|
// Create an overlay over whole blockchain
|
|
|
let blockchain = Blockchain::new(&sled_db)?;
|
|
let blockchain = Blockchain::new(&sled_db)?;
|
|
|
let overlay = BlockchainOverlay::new(&blockchain)?;
|
|
let overlay = BlockchainOverlay::new(&blockchain)?;
|
|
|
|
|
+ deploy_native_contracts(&overlay).await?;
|
|
|
|
|
|
|
|
verify_genesis_block(&overlay, &genesis_block).await?;
|
|
verify_genesis_block(&overlay, &genesis_block).await?;
|
|
|
|
|
|
|
|
println!("Genesis block {hash} verified successfully!");
|
|
println!("Genesis block {hash} verified successfully!");
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- Ok(())
|
|
|
|
|
|
|
+ Subcmd::GenerateTx { amount } => {
|
|
|
|
|
+ let mut buf = String::new();
|
|
|
|
|
+ stdin().read_to_string(&mut buf)?;
|
|
|
|
|
+ let Ok(bytes) = bs58::decode(&buf.trim()).into_vec() else {
|
|
|
|
|
+ eprintln!("Error: Failed to decode stdin buffer");
|
|
|
|
|
+ exit(2);
|
|
|
|
|
+ };
|
|
|
|
|
+ let secret = deserialize::<SecretKey>(&bytes)?;
|
|
|
|
|
+ let keypair = Keypair::new(secret);
|
|
|
|
|
+
|
|
|
|
|
+ if let Err(e) = f64::from_str(&amount) {
|
|
|
|
|
+ eprintln!("Invalid amount: {e:?}");
|
|
|
|
|
+ exit(2);
|
|
|
|
|
+ }
|
|
|
|
|
+ let amount = decode_base10(&amount, 8, false)?;
|
|
|
|
|
+
|
|
|
|
|
+ // Grab mint proving keys and zkbin
|
|
|
|
|
+ let (pks, _) = vks::get_cached_pks_and_vks()?;
|
|
|
|
|
+ let mut mint = None;
|
|
|
|
|
+ for (bincode, namespace, pk) in pks {
|
|
|
|
|
+ if namespace.as_str() != MONEY_CONTRACT_ZKAS_MINT_NS_V1 {
|
|
|
|
|
+ continue
|
|
|
|
|
+ }
|
|
|
|
|
+ let mut reader = Cursor::new(pk);
|
|
|
|
|
+ let zkbin = ZkBinary::decode(&bincode)?;
|
|
|
|
|
+ let circuit = ZkCircuit::new(empty_witnesses(&zkbin)?, &zkbin);
|
|
|
|
|
+ let proving_key = ProvingKey::read(&mut reader, circuit)?;
|
|
|
|
|
+ mint = Some((proving_key, zkbin));
|
|
|
|
|
+ }
|
|
|
|
|
+ let Some((mint_pk, mint_zkbin)) = mint else {
|
|
|
|
|
+ eprintln!("Mint proving keys not found.");
|
|
|
|
|
+ exit(2);
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ // Build the contract call
|
|
|
|
|
+ let builder = GenesisMintCallBuilder {
|
|
|
|
|
+ keypair,
|
|
|
|
|
+ amount,
|
|
|
|
|
+ spend_hook: FuncId::none(),
|
|
|
|
|
+ user_data: pallas::Base::ZERO,
|
|
|
|
|
+ mint_zkbin,
|
|
|
|
|
+ mint_pk,
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ let debris = builder.build()?;
|
|
|
|
|
+
|
|
|
|
|
+ // Encode and build the transaction
|
|
|
|
|
+ let mut data = vec![MoneyFunction::GenesisMintV1 as u8];
|
|
|
|
|
+ debris.params.encode_async(&mut data).await?;
|
|
|
|
|
+ let call = ContractCall { contract_id: *MONEY_CONTRACT_ID, data };
|
|
|
|
|
+ let mut tx_builder =
|
|
|
|
|
+ TransactionBuilder::new(ContractCallLeaf { call, proofs: debris.proofs }, vec![])?;
|
|
|
|
|
+ let mut tx = tx_builder.build()?;
|
|
|
|
|
+ let sigs = tx.create_sigs(&[keypair.secret])?;
|
|
|
|
|
+ tx.signatures = vec![sigs];
|
|
|
|
|
+
|
|
|
|
|
+ println!("{}", bs58::encode(&serialize(&tx)).into_string());
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+ Ok(())
|
|
|
}
|
|
}
|