mirror of
https://github.com/darkrenaissance/darkfi.git
synced 2026-04-28 03:00:18 -04:00
contract/consensus: Create new output keypair for UnstakeRequest.
This commit is contained in:
@@ -28,7 +28,7 @@ use darkfi_money_contract::{
|
||||
model::{ConsensusInput, ConsensusOutput, ConsensusUnstakeReqParamsV1},
|
||||
};
|
||||
use darkfi_sdk::{
|
||||
crypto::{note::AeadEncryptedNote, pasta_prelude::*, MerkleTree, SecretKey},
|
||||
crypto::{note::AeadEncryptedNote, pasta_prelude::*, Keypair, MerkleTree, SecretKey},
|
||||
incrementalmerkletree::Tree,
|
||||
pasta::pallas,
|
||||
};
|
||||
@@ -41,15 +41,20 @@ use crate::client::common::{
|
||||
};
|
||||
|
||||
pub struct ConsensusUnstakeRequestCallDebris {
|
||||
/// Payload params
|
||||
pub params: ConsensusUnstakeReqParamsV1,
|
||||
/// ZK proofs
|
||||
pub proofs: Vec<Proof>,
|
||||
/// The new output keypair (used in the minted coin)
|
||||
pub keypair: Keypair,
|
||||
/// Secret key used to sign the transaction
|
||||
pub signature_secret: SecretKey,
|
||||
}
|
||||
|
||||
/// Struct holding necessary information to build a `Consensus::UnstakeRequestV1` contract call.
|
||||
pub struct ConsensusUnstakeRequestCallBuilder {
|
||||
/// `ConsensusOwnCoin` we're given to use in this builder
|
||||
pub coin: ConsensusOwnCoin,
|
||||
pub owncoin: ConsensusOwnCoin,
|
||||
/// Epoch unstaked coin is minted
|
||||
pub epoch: u64,
|
||||
/// Merkle tree of coins used to create inclusion proofs
|
||||
@@ -66,81 +71,82 @@ pub struct ConsensusUnstakeRequestCallBuilder {
|
||||
|
||||
impl ConsensusUnstakeRequestCallBuilder {
|
||||
pub fn build(&self) -> Result<ConsensusUnstakeRequestCallDebris> {
|
||||
debug!("Building Consensus::UnstakeRequestV1 contract call");
|
||||
assert!(self.coin.note.value != 0);
|
||||
info!("Building Consensus::UnstakeRequestV1 contract call");
|
||||
assert!(self.owncoin.note.value != 0);
|
||||
|
||||
debug!("Building anonymous input");
|
||||
let leaf_position = self.coin.leaf_position;
|
||||
debug!("Building Consensus::UnstakeRequestV1 anonymous input");
|
||||
let root = self.tree.root(0).unwrap();
|
||||
let merkle_path = self.tree.authentication_path(leaf_position, &root).unwrap();
|
||||
let value_blind = pallas::Scalar::random(&mut OsRng);
|
||||
let input = ConsensusBurnInputInfo {
|
||||
leaf_position,
|
||||
merkle_path,
|
||||
secret: self.coin.secret,
|
||||
note: self.coin.note.clone(),
|
||||
value_blind,
|
||||
};
|
||||
debug!("Finished building input");
|
||||
let merkle_path = self.tree.authentication_path(self.owncoin.leaf_position, &root).unwrap();
|
||||
|
||||
info!("Creating unstake burn proof for input");
|
||||
let value_blind = input.value_blind;
|
||||
let input = ConsensusBurnInputInfo {
|
||||
leaf_position: self.owncoin.leaf_position,
|
||||
merkle_path,
|
||||
secret: self.owncoin.secret,
|
||||
note: self.owncoin.note.clone(),
|
||||
value_blind: pallas::Scalar::random(&mut OsRng),
|
||||
};
|
||||
|
||||
debug!("Building Consensus::UnstakeRequestV1 anonymous output");
|
||||
let output_serial = pallas::Base::random(&mut OsRng);
|
||||
let output_coin_blind = pallas::Base::random(&mut OsRng);
|
||||
|
||||
// We create a new random keypair for the output
|
||||
let output_keypair = Keypair::random(&mut OsRng);
|
||||
|
||||
let output = ConsensusMintOutputInfo {
|
||||
value: self.owncoin.note.value,
|
||||
epoch: self.epoch,
|
||||
public_key: output_keypair.public,
|
||||
value_blind: input.value_blind,
|
||||
serial: output_serial,
|
||||
coin_blind: output_coin_blind,
|
||||
};
|
||||
|
||||
info!("Building Consensus::UnstakeRequestV1 Burn ZK proof");
|
||||
let (burn_proof, public_inputs, signature_secret) =
|
||||
create_consensus_burn_proof(&self.burn_zkbin, &self.burn_pk, &input)?;
|
||||
|
||||
let input = ConsensusInput {
|
||||
epoch: self.coin.note.epoch,
|
||||
let tx_input = ConsensusInput {
|
||||
epoch: self.owncoin.note.epoch,
|
||||
value_commit: public_inputs.value_commit,
|
||||
nullifier: public_inputs.nullifier,
|
||||
merkle_root: public_inputs.merkle_root,
|
||||
signature_public: public_inputs.signature_public,
|
||||
};
|
||||
|
||||
debug!("Building anonymous output");
|
||||
let serial = pallas::Base::random(&mut OsRng);
|
||||
let coin_blind = pallas::Base::random(&mut OsRng);
|
||||
let public_key = public_inputs.signature_public;
|
||||
|
||||
let output = ConsensusMintOutputInfo {
|
||||
value: self.coin.note.value,
|
||||
epoch: self.epoch,
|
||||
public_key,
|
||||
value_blind,
|
||||
serial,
|
||||
coin_blind,
|
||||
};
|
||||
debug!("Finished building output");
|
||||
|
||||
info!("Creating stake mint proof for output");
|
||||
info!("Building Consensus::UnstakeRequestV1 Mint ZK proof");
|
||||
let (mint_proof, public_inputs) =
|
||||
create_consensus_mint_proof(&self.mint_zkbin, &self.mint_pk, &output)?;
|
||||
|
||||
// Encrypted note
|
||||
let note = ConsensusNote {
|
||||
serial,
|
||||
serial: output_serial,
|
||||
value: output.value,
|
||||
epoch: self.epoch,
|
||||
coin_blind,
|
||||
value_blind,
|
||||
epoch: output.epoch,
|
||||
coin_blind: output_coin_blind,
|
||||
value_blind: input.value_blind,
|
||||
reward: 0,
|
||||
reward_blind: value_blind,
|
||||
reward_blind: pallas::Scalar::ZERO,
|
||||
};
|
||||
|
||||
let encrypted_note = AeadEncryptedNote::encrypt(¬e, &output.public_key, &mut OsRng)?;
|
||||
|
||||
let output = ConsensusOutput {
|
||||
let tx_output = ConsensusOutput {
|
||||
value_commit: public_inputs.value_commit,
|
||||
coin: public_inputs.coin,
|
||||
note: encrypted_note,
|
||||
};
|
||||
|
||||
// We now fill this with necessary stuff
|
||||
let params = ConsensusUnstakeReqParamsV1 { input, output };
|
||||
let proofs = vec![burn_proof, mint_proof];
|
||||
let params = ConsensusUnstakeReqParamsV1 { input: tx_input, output: tx_output };
|
||||
|
||||
// Now we should have all the params, zk proof, and signature secret.
|
||||
// We return it all and let the caller deal with it.
|
||||
let debris = ConsensusUnstakeRequestCallDebris { params, proofs, signature_secret };
|
||||
// Construct debris
|
||||
let debris = ConsensusUnstakeRequestCallDebris {
|
||||
params,
|
||||
proofs: vec![burn_proof, mint_proof],
|
||||
keypair: output_keypair,
|
||||
signature_secret,
|
||||
};
|
||||
Ok(debris)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
use darkfi_money_contract::{
|
||||
error::MoneyError,
|
||||
model::{ConsensusStakeParamsV1, ConsensusStakeUpdateV1, MoneyStakeParamsV1},
|
||||
CONSENSUS_CONTRACT_INFO_TREE, CONSENSUS_CONTRACT_STAKED_COINS_TREE,
|
||||
MoneyFunction, CONSENSUS_CONTRACT_INFO_TREE, CONSENSUS_CONTRACT_STAKED_COINS_TREE,
|
||||
CONSENSUS_CONTRACT_STAKED_COIN_MERKLE_TREE, CONSENSUS_CONTRACT_STAKED_COIN_ROOTS_TREE,
|
||||
CONSENSUS_CONTRACT_UNSTAKED_COINS_TREE, CONSENSUS_CONTRACT_ZKAS_MINT_NS_V1,
|
||||
MONEY_CONTRACT_COIN_ROOTS_TREE, MONEY_CONTRACT_NULLIFIERS_TREE,
|
||||
@@ -90,7 +90,7 @@ pub(crate) fn consensus_stake_process_instruction_v1(
|
||||
return Err(MoneyError::CallIdxOutOfBounds.into())
|
||||
}
|
||||
|
||||
// Verify previous call corresponds to Money::StakeV1 (0x06)
|
||||
// Verify previous call corresponds to Money::StakeV1
|
||||
let previous_call_idx = call_idx - 1;
|
||||
let previous = &calls[previous_call_idx as usize];
|
||||
if previous.contract_id.inner() != MONEY_CONTRACT_ID.inner() {
|
||||
@@ -98,7 +98,7 @@ pub(crate) fn consensus_stake_process_instruction_v1(
|
||||
return Err(MoneyError::StakePreviousCallNotMoneyContract.into())
|
||||
}
|
||||
|
||||
if previous.data[0] != 0x06 {
|
||||
if previous.data[0] != MoneyFunction::StakeV1 as u8 {
|
||||
msg!("[ConsensusStakeV1] Error: Previous call function mismatch");
|
||||
return Err(MoneyError::PreviousCallFunctionMismatch.into())
|
||||
}
|
||||
|
||||
@@ -156,8 +156,12 @@ async fn consensus_contract_genesis_stake_unstake() -> Result<()> {
|
||||
info!(target: "consensus", "[Alice] ===========================");
|
||||
info!(target: "consensus", "[Alice] Building unstake request tx");
|
||||
info!(target: "consensus", "[Alice] ===========================");
|
||||
let (unstake_request_tx, unstake_request_params, unstake_request_secret_key) =
|
||||
th.unstake_request(Holder::Alice, current_slot, alice_rewarded_staked_oc.clone()).await?;
|
||||
let (
|
||||
unstake_request_tx,
|
||||
unstake_request_params,
|
||||
unstake_request_output_secret_key,
|
||||
_unstake_request_signature_secret_key,
|
||||
) = th.unstake_request(Holder::Alice, current_slot, alice_rewarded_staked_oc.clone()).await?;
|
||||
|
||||
info!(target: "consensus", "[Faucet] ==================================");
|
||||
info!(target: "consensus", "[Faucet] Executing Alice unstake request tx");
|
||||
@@ -187,7 +191,7 @@ async fn consensus_contract_genesis_stake_unstake() -> Result<()> {
|
||||
let alice_unstake_request_oc = th.gather_consensus_unstaked_owncoin(
|
||||
Holder::Alice,
|
||||
unstake_request_params.output,
|
||||
Some(unstake_request_secret_key),
|
||||
Some(unstake_request_output_secret_key),
|
||||
)?;
|
||||
|
||||
// Verify values match
|
||||
|
||||
@@ -624,7 +624,7 @@ impl ConsensusTestHarness {
|
||||
holder: Holder,
|
||||
slot: u64,
|
||||
staked_oc: ConsensusOwnCoin,
|
||||
) -> Result<(Transaction, ConsensusUnstakeReqParamsV1, SecretKey)> {
|
||||
) -> Result<(Transaction, ConsensusUnstakeReqParamsV1, SecretKey, SecretKey)> {
|
||||
let wallet = self.holders.get_mut(&holder).unwrap();
|
||||
let (burn_pk, burn_zkbin) =
|
||||
self.proving_keys.get(&CONSENSUS_CONTRACT_ZKAS_BURN_NS_V1).unwrap();
|
||||
@@ -637,7 +637,7 @@ impl ConsensusTestHarness {
|
||||
|
||||
// Building Consensus::Unstake params
|
||||
let unstake_request_call_debris = ConsensusUnstakeRequestCallBuilder {
|
||||
coin: staked_oc.clone(),
|
||||
owncoin: staked_oc.clone(),
|
||||
epoch,
|
||||
tree: wallet.consensus_staked_merkle_tree.clone(),
|
||||
burn_zkbin: burn_zkbin.clone(),
|
||||
@@ -646,9 +646,16 @@ impl ConsensusTestHarness {
|
||||
mint_pk: mint_pk.clone(),
|
||||
}
|
||||
.build()?;
|
||||
let (unstake_request_params, unstake_request_proofs, unstake_request_secret_key) = (
|
||||
|
||||
let (
|
||||
unstake_request_params,
|
||||
unstake_request_proofs,
|
||||
unstake_request_output_keypair,
|
||||
unstake_request_signature_secret_key,
|
||||
) = (
|
||||
unstake_request_call_debris.params,
|
||||
unstake_request_call_debris.proofs,
|
||||
unstake_request_call_debris.keypair,
|
||||
unstake_request_call_debris.signature_secret,
|
||||
);
|
||||
|
||||
@@ -659,19 +666,25 @@ impl ConsensusTestHarness {
|
||||
let calls = vec![call];
|
||||
let proofs = vec![unstake_request_proofs];
|
||||
let mut unstake_request_tx = Transaction { calls, proofs, signatures: vec![] };
|
||||
let sigs = unstake_request_tx.create_sigs(&mut OsRng, &[unstake_request_secret_key])?;
|
||||
let sigs =
|
||||
unstake_request_tx.create_sigs(&mut OsRng, &[unstake_request_signature_secret_key])?;
|
||||
unstake_request_tx.signatures = vec![sigs];
|
||||
tx_action_benchmark.creation_times.push(timer.elapsed());
|
||||
|
||||
// Calculate transaction sizes
|
||||
let encoded: Vec<u8> = serialize(&unstake_request_tx);
|
||||
let size = ::std::mem::size_of_val(&*encoded);
|
||||
let size = std::mem::size_of_val(&*encoded);
|
||||
tx_action_benchmark.sizes.push(size);
|
||||
let base58 = bs58::encode(&encoded).into_string();
|
||||
let size = ::std::mem::size_of_val(&*base58);
|
||||
let size = std::mem::size_of_val(&*base58);
|
||||
tx_action_benchmark.broadcasted_sizes.push(size);
|
||||
|
||||
Ok((unstake_request_tx, unstake_request_params, unstake_request_secret_key))
|
||||
Ok((
|
||||
unstake_request_tx,
|
||||
unstake_request_params,
|
||||
unstake_request_output_keypair.secret,
|
||||
unstake_request_signature_secret_key,
|
||||
))
|
||||
}
|
||||
|
||||
pub async fn execute_unstake_request_tx(
|
||||
|
||||
@@ -156,8 +156,12 @@ async fn consensus_contract_stake_unstake() -> Result<()> {
|
||||
info!(target: "consensus", "[Alice] ===========================");
|
||||
info!(target: "consensus", "[Alice] Building unstake request tx");
|
||||
info!(target: "consensus", "[Alice] ===========================");
|
||||
let (unstake_request_tx, unstake_request_params, unstake_request_secret_key) =
|
||||
th.unstake_request(Holder::Alice, current_slot, alice_rewarded_staked_oc.clone()).await?;
|
||||
let (
|
||||
unstake_request_tx,
|
||||
unstake_request_params,
|
||||
unstake_request_output_secret_key,
|
||||
unstake_request_signature_secret_key,
|
||||
) = th.unstake_request(Holder::Alice, current_slot, alice_rewarded_staked_oc.clone()).await?;
|
||||
|
||||
info!(target: "consensus", "[Faucet] ==================================");
|
||||
info!(target: "consensus", "[Faucet] Executing Alice unstake request tx");
|
||||
@@ -187,7 +191,7 @@ async fn consensus_contract_stake_unstake() -> Result<()> {
|
||||
let alice_unstake_request_oc = th.gather_consensus_unstaked_owncoin(
|
||||
Holder::Alice,
|
||||
unstake_request_params.output,
|
||||
Some(unstake_request_secret_key),
|
||||
Some(unstake_request_output_secret_key),
|
||||
)?;
|
||||
|
||||
// Verify values match
|
||||
@@ -207,7 +211,7 @@ async fn consensus_contract_stake_unstake() -> Result<()> {
|
||||
info!(target: "consensus", "[Malicious] =============================");
|
||||
info!(target: "consensus", "[Malicious] Checking unstaking coin again");
|
||||
info!(target: "consensus", "[Malicious] =============================");
|
||||
let (unstake_request_tx, _, _) =
|
||||
let (unstake_request_tx, _, _, _) =
|
||||
th.unstake_request(Holder::Alice, current_slot, alice_unstake_request_oc.clone()).await?;
|
||||
th.execute_erroneous_unstake_request_txs(
|
||||
Holder::Alice,
|
||||
|
||||
Reference in New Issue
Block a user