mirror of
https://github.com/darkrenaissance/darkfi.git
synced 2026-04-28 03:00:18 -04:00
contract/consensus: use new ConsensusBurn proof in ConsensusUnstake
This commit is contained in:
@@ -23,16 +23,32 @@ use darkfi::{
|
||||
zkas::ZkBinary,
|
||||
Result,
|
||||
};
|
||||
use darkfi_money_contract::client::MoneyNote;
|
||||
use darkfi_sdk::{
|
||||
crypto::{
|
||||
pasta_prelude::*, pedersen_commitment_u64, poseidon_hash, Coin, PublicKey, TokenId,
|
||||
CONSENSUS_CONTRACT_ID,
|
||||
pasta_prelude::*, pedersen_commitment_base, pedersen_commitment_u64, poseidon_hash, Coin,
|
||||
MerkleNode, MerklePosition, Nullifier, PublicKey, SecretKey, TokenId,
|
||||
},
|
||||
incrementalmerkletree::Hashable,
|
||||
pasta::pallas,
|
||||
};
|
||||
use rand::rngs::OsRng;
|
||||
|
||||
use crate::model::ZERO;
|
||||
use crate::client::ConsensusNote;
|
||||
|
||||
pub struct TransactionBuilderInputInfo {
|
||||
pub leaf_position: MerklePosition,
|
||||
pub merkle_path: Vec<MerkleNode>,
|
||||
pub secret: SecretKey,
|
||||
pub note: MoneyNote,
|
||||
}
|
||||
|
||||
pub struct TransactionBuilderConsensusInputInfo {
|
||||
pub leaf_position: MerklePosition,
|
||||
pub merkle_path: Vec<MerkleNode>,
|
||||
pub secret: SecretKey,
|
||||
pub note: ConsensusNote,
|
||||
}
|
||||
|
||||
pub struct TransactionBuilderOutputInfo {
|
||||
pub value: u64,
|
||||
@@ -41,7 +57,7 @@ pub struct TransactionBuilderOutputInfo {
|
||||
}
|
||||
|
||||
pub struct ConsensusMintRevealed {
|
||||
pub epoch: pallas::Base,
|
||||
pub epoch: u64,
|
||||
pub coin: Coin,
|
||||
pub value_commit: pallas::Point,
|
||||
}
|
||||
@@ -49,10 +65,11 @@ pub struct ConsensusMintRevealed {
|
||||
impl ConsensusMintRevealed {
|
||||
pub fn to_vec(&self) -> Vec<pallas::Base> {
|
||||
let valcom_coords = self.value_commit.to_affine().coordinates().unwrap();
|
||||
let epoch_palas = pallas::Base::from(self.epoch);
|
||||
|
||||
// NOTE: It's important to keep these in the same order
|
||||
// as the `constrain_instance` calls in the zkas code.
|
||||
vec![self.epoch, self.coin.inner(), *valcom_coords.x(), *valcom_coords.y()]
|
||||
vec![epoch_palas, self.coin.inner(), *valcom_coords.x(), *valcom_coords.y()]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -73,7 +90,7 @@ pub fn create_consensus_mint_proof(
|
||||
let coin =
|
||||
Coin::from(poseidon_hash([pub_x, pub_y, value_pallas, epoch_pallas, serial, coin_blind]));
|
||||
|
||||
let public_inputs = ConsensusMintRevealed { epoch: epoch_pallas, coin, value_commit };
|
||||
let public_inputs = ConsensusMintRevealed { epoch, coin, value_commit };
|
||||
|
||||
let prover_witnesses = vec![
|
||||
Witness::Base(Value::known(pub_x)),
|
||||
@@ -90,3 +107,202 @@ pub fn create_consensus_mint_proof(
|
||||
|
||||
Ok((proof, public_inputs))
|
||||
}
|
||||
|
||||
pub struct ConsensusBurnRevealed {
|
||||
pub nullifier: Nullifier,
|
||||
pub epoch: u64,
|
||||
pub signature_public: PublicKey,
|
||||
pub merkle_root: MerkleNode,
|
||||
pub value_commit: pallas::Point,
|
||||
}
|
||||
|
||||
impl ConsensusBurnRevealed {
|
||||
pub fn to_vec(&self) -> Vec<pallas::Base> {
|
||||
let valcom_coords = self.value_commit.to_affine().coordinates().unwrap();
|
||||
let sigpub_coords = self.signature_public.inner().to_affine().coordinates().unwrap();
|
||||
let epoch_palas = pallas::Base::from(self.epoch);
|
||||
|
||||
// NOTE: It's important to keep these in the same order
|
||||
// as the `constrain_instance` calls in the zkas code.
|
||||
vec![
|
||||
self.nullifier.inner(),
|
||||
epoch_palas,
|
||||
*sigpub_coords.x(),
|
||||
*sigpub_coords.y(),
|
||||
self.merkle_root.inner(),
|
||||
*valcom_coords.x(),
|
||||
*valcom_coords.y(),
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
pub fn create_consensus_burn_proof(
|
||||
zkbin: &ZkBinary,
|
||||
pk: &ProvingKey,
|
||||
input: &TransactionBuilderConsensusInputInfo,
|
||||
value_blind: pallas::Scalar,
|
||||
) -> Result<(Proof, ConsensusBurnRevealed, SecretKey)> {
|
||||
let nullifier = Nullifier::from(poseidon_hash([input.secret.inner(), input.note.serial]));
|
||||
let epoch = input.note.epoch;
|
||||
let epoch_pallas = pallas::Base::from(epoch);
|
||||
let value_pallas = pallas::Base::from(input.note.value);
|
||||
let value_commit = pedersen_commitment_u64(input.note.value, value_blind);
|
||||
let public_key = PublicKey::from_secret(input.secret);
|
||||
let (pub_x, pub_y) = public_key.xy();
|
||||
|
||||
let coin = poseidon_hash([
|
||||
pub_x,
|
||||
pub_y,
|
||||
value_pallas,
|
||||
epoch_pallas,
|
||||
input.note.serial,
|
||||
input.note.coin_blind,
|
||||
]);
|
||||
|
||||
let merkle_root = {
|
||||
let position: u64 = input.leaf_position.into();
|
||||
let mut current = MerkleNode::from(coin);
|
||||
for (level, sibling) in input.merkle_path.iter().enumerate() {
|
||||
let level = level as u8;
|
||||
current = if position & (1 << level) == 0 {
|
||||
MerkleNode::combine(level.into(), ¤t, sibling)
|
||||
} else {
|
||||
MerkleNode::combine(level.into(), sibling, ¤t)
|
||||
};
|
||||
}
|
||||
current
|
||||
};
|
||||
|
||||
let public_inputs = ConsensusBurnRevealed {
|
||||
nullifier,
|
||||
epoch,
|
||||
signature_public: public_key,
|
||||
merkle_root,
|
||||
value_commit,
|
||||
};
|
||||
|
||||
let prover_witnesses = vec![
|
||||
Witness::Base(Value::known(value_pallas)),
|
||||
Witness::Base(Value::known(epoch_pallas)),
|
||||
Witness::Base(Value::known(input.note.serial)),
|
||||
Witness::Base(Value::known(input.note.coin_blind)),
|
||||
Witness::Scalar(Value::known(value_blind)),
|
||||
Witness::Base(Value::known(input.secret.inner())),
|
||||
Witness::Uint32(Value::known(u64::from(input.leaf_position).try_into().unwrap())),
|
||||
Witness::MerklePath(Value::known(input.merkle_path.clone().try_into().unwrap())),
|
||||
];
|
||||
|
||||
let circuit = ZkCircuit::new(prover_witnesses, zkbin.clone());
|
||||
let proof = Proof::create(pk, &[circuit], &public_inputs.to_vec(), &mut OsRng)?;
|
||||
|
||||
Ok((proof, public_inputs, input.secret))
|
||||
}
|
||||
|
||||
// TODO: Remove everything following
|
||||
pub struct ConsensusUnstakeBurnRevealed {
|
||||
pub value_commit: pallas::Point,
|
||||
pub token_commit: pallas::Point,
|
||||
pub nullifier: Nullifier,
|
||||
pub merkle_root: MerkleNode,
|
||||
pub spend_hook: pallas::Base,
|
||||
pub user_data_enc: pallas::Base,
|
||||
pub signature_public: PublicKey,
|
||||
}
|
||||
|
||||
impl ConsensusUnstakeBurnRevealed {
|
||||
pub fn to_vec(&self) -> Vec<pallas::Base> {
|
||||
let valcom_coords = self.value_commit.to_affine().coordinates().unwrap();
|
||||
let tokcom_coords = self.token_commit.to_affine().coordinates().unwrap();
|
||||
let sigpub_coords = self.signature_public.inner().to_affine().coordinates().unwrap();
|
||||
|
||||
// NOTE: It's important to keep these in the same order
|
||||
// as the `constrain_instance` calls in the zkas code.
|
||||
vec![
|
||||
self.nullifier.inner(),
|
||||
*valcom_coords.x(),
|
||||
*valcom_coords.y(),
|
||||
*tokcom_coords.x(),
|
||||
*tokcom_coords.y(),
|
||||
self.merkle_root.inner(),
|
||||
self.user_data_enc,
|
||||
*sigpub_coords.x(),
|
||||
*sigpub_coords.y(),
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
pub fn create_unstake_burn_proof(
|
||||
zkbin: &ZkBinary,
|
||||
pk: &ProvingKey,
|
||||
input: &TransactionBuilderInputInfo,
|
||||
value_blind: pallas::Scalar,
|
||||
token_blind: pallas::Scalar,
|
||||
user_data_blind: pallas::Base,
|
||||
signature_secret: SecretKey,
|
||||
) -> Result<(Proof, ConsensusUnstakeBurnRevealed)> {
|
||||
let nullifier = Nullifier::from(poseidon_hash([input.secret.inner(), input.note.serial]));
|
||||
let public_key = PublicKey::from_secret(input.secret);
|
||||
let (pub_x, pub_y) = public_key.xy();
|
||||
|
||||
let signature_public = PublicKey::from_secret(signature_secret);
|
||||
|
||||
let coin = poseidon_hash([
|
||||
pub_x,
|
||||
pub_y,
|
||||
pallas::Base::from(input.note.value),
|
||||
input.note.token_id.inner(),
|
||||
input.note.serial,
|
||||
input.note.spend_hook,
|
||||
input.note.user_data,
|
||||
input.note.coin_blind,
|
||||
]);
|
||||
|
||||
let merkle_root = {
|
||||
let position: u64 = input.leaf_position.into();
|
||||
let mut current = MerkleNode::from(coin);
|
||||
for (level, sibling) in input.merkle_path.iter().enumerate() {
|
||||
let level = level as u8;
|
||||
current = if position & (1 << level) == 0 {
|
||||
MerkleNode::combine(level.into(), ¤t, sibling)
|
||||
} else {
|
||||
MerkleNode::combine(level.into(), sibling, ¤t)
|
||||
};
|
||||
}
|
||||
current
|
||||
};
|
||||
|
||||
let user_data_enc = poseidon_hash([input.note.user_data, user_data_blind]);
|
||||
let value_commit = pedersen_commitment_u64(input.note.value, value_blind);
|
||||
let token_commit = pedersen_commitment_base(input.note.token_id.inner(), token_blind);
|
||||
|
||||
let public_inputs = ConsensusUnstakeBurnRevealed {
|
||||
value_commit,
|
||||
token_commit,
|
||||
nullifier,
|
||||
merkle_root,
|
||||
spend_hook: input.note.spend_hook,
|
||||
user_data_enc,
|
||||
signature_public,
|
||||
};
|
||||
|
||||
let prover_witnesses = vec![
|
||||
Witness::Base(Value::known(pallas::Base::from(input.note.value))),
|
||||
Witness::Base(Value::known(input.note.token_id.inner())),
|
||||
Witness::Scalar(Value::known(value_blind)),
|
||||
Witness::Scalar(Value::known(token_blind)),
|
||||
Witness::Base(Value::known(input.note.serial)),
|
||||
Witness::Base(Value::known(input.note.spend_hook)),
|
||||
Witness::Base(Value::known(input.note.user_data)),
|
||||
Witness::Base(Value::known(user_data_blind)),
|
||||
Witness::Base(Value::known(input.note.coin_blind)),
|
||||
Witness::Base(Value::known(input.secret.inner())),
|
||||
Witness::Uint32(Value::known(u64::from(input.leaf_position).try_into().unwrap())),
|
||||
Witness::MerklePath(Value::known(input.merkle_path.clone().try_into().unwrap())),
|
||||
Witness::Base(Value::known(signature_secret.inner())),
|
||||
];
|
||||
|
||||
let circuit = ZkCircuit::new(prover_witnesses, zkbin.clone());
|
||||
let proof = Proof::create(pk, &[circuit], &public_inputs.to_vec(), &mut OsRng)?;
|
||||
|
||||
Ok((proof, public_inputs))
|
||||
}
|
||||
|
||||
@@ -23,20 +23,20 @@ use darkfi::{
|
||||
zkas::ZkBinary,
|
||||
Result,
|
||||
};
|
||||
use darkfi_money_contract::{client::MoneyNote, model::ClearInput};
|
||||
use darkfi_money_contract::model::ClearInput;
|
||||
use darkfi_sdk::{
|
||||
crypto::{
|
||||
note::AeadEncryptedNote, pasta_prelude::*, Keypair, PublicKey, CONSENSUS_CONTRACT_ID,
|
||||
DARK_TOKEN_ID,
|
||||
},
|
||||
crypto::{note::AeadEncryptedNote, pasta_prelude::*, Keypair, PublicKey, DARK_TOKEN_ID},
|
||||
pasta::pallas,
|
||||
};
|
||||
use log::{debug, info};
|
||||
use rand::rngs::OsRng;
|
||||
|
||||
use crate::{
|
||||
client::common::{create_consensus_mint_proof, TransactionBuilderOutputInfo},
|
||||
model::{ConsensusGenesisStakeParamsV1, ConsensusOutput, ZERO},
|
||||
client::{
|
||||
common::{create_consensus_mint_proof, TransactionBuilderOutputInfo},
|
||||
ConsensusNote,
|
||||
},
|
||||
model::{ConsensusGenesisStakeParamsV1, ConsensusOutput},
|
||||
};
|
||||
|
||||
pub struct ConsensusGenesisStakeCallDebris {
|
||||
@@ -96,17 +96,7 @@ impl ConsensusGenesisStakeCallBuilder {
|
||||
)?;
|
||||
|
||||
// Encrypted note
|
||||
let note = MoneyNote {
|
||||
serial,
|
||||
value: output.value,
|
||||
token_id: output.token_id,
|
||||
spend_hook: CONSENSUS_CONTRACT_ID.inner(),
|
||||
user_data: ZERO,
|
||||
coin_blind,
|
||||
value_blind,
|
||||
token_blind,
|
||||
memo: vec![],
|
||||
};
|
||||
let note = ConsensusNote { serial, value: output.value, epoch, coin_blind, value_blind };
|
||||
|
||||
let encrypted_note = AeadEncryptedNote::encrypt(¬e, &output.public_key, &mut OsRng)?;
|
||||
|
||||
|
||||
@@ -25,6 +25,15 @@
|
||||
//! the necessary objects provided by the caller. This is intentional, so we
|
||||
//! are able to abstract away any wallet interfaces to client implementations.
|
||||
|
||||
use darkfi_money_contract::client::{MoneyNote, OwnCoin};
|
||||
use darkfi_sdk::{
|
||||
crypto::{pasta_prelude::Field, Coin, MerklePosition, Nullifier, SecretKey, DARK_TOKEN_ID},
|
||||
pasta::pallas,
|
||||
};
|
||||
use darkfi_serial::{SerialDecodable, SerialEncodable};
|
||||
|
||||
use crate::model::ZERO;
|
||||
|
||||
/// Common functions
|
||||
pub(crate) mod common;
|
||||
|
||||
@@ -41,3 +50,61 @@ pub mod proposal_v1;
|
||||
|
||||
/// `Consensus::UnstakeV1` API
|
||||
pub mod unstake_v1;
|
||||
|
||||
/// `ConsensusNote` holds the inner attributes of a `Coin`.
|
||||
#[derive(Debug, Clone, Eq, PartialEq, SerialEncodable, SerialDecodable)]
|
||||
pub struct ConsensusNote {
|
||||
/// Serial number of the coin, used for the nullifier
|
||||
pub serial: pallas::Base,
|
||||
/// Value of the coin
|
||||
pub value: u64,
|
||||
/// Epoch the coin was minted
|
||||
pub epoch: u64,
|
||||
/// Blinding factor for the coin bulla
|
||||
pub coin_blind: pallas::Base,
|
||||
/// Blinding factor for the value pedersen commitment
|
||||
pub value_blind: pallas::Scalar,
|
||||
}
|
||||
|
||||
impl From<ConsensusNote> for MoneyNote {
|
||||
fn from(consensus_note: ConsensusNote) -> Self {
|
||||
MoneyNote {
|
||||
serial: consensus_note.serial,
|
||||
value: consensus_note.value,
|
||||
token_id: *DARK_TOKEN_ID,
|
||||
spend_hook: ZERO,
|
||||
user_data: ZERO,
|
||||
coin_blind: consensus_note.coin_blind,
|
||||
value_blind: consensus_note.value_blind,
|
||||
token_blind: pallas::Scalar::zero(),
|
||||
memo: vec![],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// `ConsensusOwnCoin` is a representation of `Coin` with its respective metadata.
|
||||
#[derive(Debug, Clone, Eq, PartialEq, SerialEncodable, SerialDecodable)]
|
||||
pub struct ConsensusOwnCoin {
|
||||
/// The coin hash
|
||||
pub coin: Coin,
|
||||
/// The attached `ConsensusNote`
|
||||
pub note: ConsensusNote,
|
||||
/// Coin's secret key
|
||||
pub secret: SecretKey,
|
||||
/// Coin's nullifier
|
||||
pub nullifier: Nullifier,
|
||||
/// Coin's leaf position in the Merkle tree of coins
|
||||
pub leaf_position: MerklePosition,
|
||||
}
|
||||
|
||||
impl From<ConsensusOwnCoin> for OwnCoin {
|
||||
fn from(consensus_own_coin: ConsensusOwnCoin) -> Self {
|
||||
OwnCoin {
|
||||
coin: consensus_own_coin.coin,
|
||||
note: consensus_own_coin.note.into(),
|
||||
secret: consensus_own_coin.secret,
|
||||
nullifier: consensus_own_coin.nullifier,
|
||||
leaf_position: consensus_own_coin.leaf_position,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,8 +42,8 @@ use rand::rngs::OsRng;
|
||||
|
||||
use crate::{
|
||||
client::{
|
||||
common::{create_unstake_burn_proof, TransactionBuilderInputInfo as UnstakeTBII},
|
||||
stake_v1::{TransactionBuilderOutputInfo as StakeTBOI, TransactionBuilderOutputInfo},
|
||||
unstake_v1::{create_unstake_burn_proof, TransactionBuilderInputInfo as UnstakeTBII},
|
||||
},
|
||||
model::{
|
||||
ConsensusProposalBurnParamsV1, ConsensusProposalMintParamsV1,
|
||||
|
||||
@@ -19,25 +19,24 @@
|
||||
//! This API is crufty. Please rework it into something nice to read and nice to use.
|
||||
|
||||
use darkfi::{
|
||||
zk::{halo2::Value, Proof, ProvingKey, Witness, ZkCircuit},
|
||||
zk::{Proof, ProvingKey},
|
||||
zkas::ZkBinary,
|
||||
Result,
|
||||
};
|
||||
use darkfi_money_contract::{
|
||||
client::{MoneyNote, OwnCoin},
|
||||
model::{ConsensusUnstakeParamsV1, Input},
|
||||
};
|
||||
use darkfi_money_contract::model::{ConsensusUnstakeParamsV1, UnstakeInput};
|
||||
use darkfi_sdk::{
|
||||
crypto::{
|
||||
pasta_prelude::*, pedersen_commitment_base, pedersen_commitment_u64, poseidon_hash,
|
||||
MerkleNode, MerklePosition, MerkleTree, Nullifier, PublicKey, SecretKey, DARK_TOKEN_ID,
|
||||
},
|
||||
incrementalmerkletree::{Hashable, Tree},
|
||||
crypto::{pasta_prelude::*, MerkleTree, SecretKey},
|
||||
incrementalmerkletree::Tree,
|
||||
pasta::pallas,
|
||||
};
|
||||
use log::{debug, info};
|
||||
use rand::rngs::OsRng;
|
||||
|
||||
use crate::client::{
|
||||
common::{create_consensus_burn_proof, TransactionBuilderConsensusInputInfo},
|
||||
ConsensusOwnCoin,
|
||||
};
|
||||
|
||||
pub struct ConsensusUnstakeCallDebris {
|
||||
pub params: ConsensusUnstakeParamsV1,
|
||||
pub proofs: Vec<Proof>,
|
||||
@@ -45,54 +44,15 @@ pub struct ConsensusUnstakeCallDebris {
|
||||
pub value_blind: pallas::Scalar,
|
||||
}
|
||||
|
||||
pub struct ConsensusUnstakeBurnRevealed {
|
||||
pub value_commit: pallas::Point,
|
||||
pub token_commit: pallas::Point,
|
||||
pub nullifier: Nullifier,
|
||||
pub merkle_root: MerkleNode,
|
||||
pub spend_hook: pallas::Base,
|
||||
pub user_data_enc: pallas::Base,
|
||||
pub signature_public: PublicKey,
|
||||
}
|
||||
|
||||
impl ConsensusUnstakeBurnRevealed {
|
||||
pub fn to_vec(&self) -> Vec<pallas::Base> {
|
||||
let valcom_coords = self.value_commit.to_affine().coordinates().unwrap();
|
||||
let tokcom_coords = self.token_commit.to_affine().coordinates().unwrap();
|
||||
let sigpub_coords = self.signature_public.inner().to_affine().coordinates().unwrap();
|
||||
|
||||
// NOTE: It's important to keep these in the same order
|
||||
// as the `constrain_instance` calls in the zkas code.
|
||||
vec![
|
||||
self.nullifier.inner(),
|
||||
*valcom_coords.x(),
|
||||
*valcom_coords.y(),
|
||||
*tokcom_coords.x(),
|
||||
*tokcom_coords.y(),
|
||||
self.merkle_root.inner(),
|
||||
self.user_data_enc,
|
||||
*sigpub_coords.x(),
|
||||
*sigpub_coords.y(),
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
pub struct TransactionBuilderInputInfo {
|
||||
pub leaf_position: MerklePosition,
|
||||
pub merkle_path: Vec<MerkleNode>,
|
||||
pub secret: SecretKey,
|
||||
pub note: MoneyNote,
|
||||
}
|
||||
|
||||
/// Struct holding necessary information to build a `Consensus::UnstakeV1` contract call.
|
||||
pub struct ConsensusUnstakeCallBuilder {
|
||||
/// `OwnCoin` we're given to use in this builder
|
||||
pub coin: OwnCoin,
|
||||
/// `ConsensusOwnCoin` we're given to use in this builder
|
||||
pub coin: ConsensusOwnCoin,
|
||||
/// Merkle tree of coins used to create inclusion proofs
|
||||
pub tree: MerkleTree,
|
||||
/// `Burn_V1` zkas circuit ZkBinary
|
||||
/// `ConsensusBurn_V1` zkas circuit ZkBinary
|
||||
pub burn_zkbin: ZkBinary,
|
||||
/// Proving key for the `Burn_V1` zk circuit
|
||||
/// Proving key for the `ConsensusBurn_V1` zk circuit
|
||||
pub burn_pk: ProvingKey,
|
||||
}
|
||||
|
||||
@@ -100,13 +60,12 @@ impl ConsensusUnstakeCallBuilder {
|
||||
pub fn build(&self) -> Result<ConsensusUnstakeCallDebris> {
|
||||
debug!("Building Consensus::UnstakeV1 contract call");
|
||||
assert!(self.coin.note.value != 0);
|
||||
assert!(self.coin.note.token_id == *DARK_TOKEN_ID);
|
||||
|
||||
debug!("Building anonymous input");
|
||||
let leaf_position = self.coin.leaf_position;
|
||||
let root = self.tree.root(0).unwrap();
|
||||
let merkle_path = self.tree.authentication_path(leaf_position, &root).unwrap();
|
||||
let input = TransactionBuilderInputInfo {
|
||||
let input = TransactionBuilderConsensusInputInfo {
|
||||
leaf_position,
|
||||
merkle_path,
|
||||
secret: self.coin.secret,
|
||||
@@ -115,32 +74,20 @@ impl ConsensusUnstakeCallBuilder {
|
||||
debug!("Finished building input");
|
||||
|
||||
let value_blind = pallas::Scalar::random(&mut OsRng);
|
||||
let token_blind = pallas::Scalar::random(&mut OsRng);
|
||||
let signature_secret = SecretKey::random(&mut OsRng);
|
||||
let user_data_blind = pallas::Base::random(&mut OsRng);
|
||||
info!("Creating unstake burn proof for input");
|
||||
let (proof, public_inputs) = create_unstake_burn_proof(
|
||||
&self.burn_zkbin,
|
||||
&self.burn_pk,
|
||||
&input,
|
||||
value_blind,
|
||||
token_blind,
|
||||
user_data_blind,
|
||||
signature_secret,
|
||||
)?;
|
||||
let (proof, public_inputs, signature_secret) =
|
||||
create_consensus_burn_proof(&self.burn_zkbin, &self.burn_pk, &input, value_blind)?;
|
||||
|
||||
let input = Input {
|
||||
let input = UnstakeInput {
|
||||
epoch: self.coin.note.epoch,
|
||||
value_commit: public_inputs.value_commit,
|
||||
token_commit: public_inputs.token_commit,
|
||||
nullifier: public_inputs.nullifier,
|
||||
merkle_root: public_inputs.merkle_root,
|
||||
spend_hook: public_inputs.spend_hook,
|
||||
user_data_enc: public_inputs.user_data_enc,
|
||||
signature_public: public_inputs.signature_public,
|
||||
};
|
||||
|
||||
// We now fill this with necessary stuff
|
||||
let params = ConsensusUnstakeParamsV1 { token_blind, input };
|
||||
let params = ConsensusUnstakeParamsV1 { input };
|
||||
let proofs = vec![proof];
|
||||
|
||||
// Now we should have all the params, zk proof, signature secret and token blind.
|
||||
@@ -149,79 +96,3 @@ impl ConsensusUnstakeCallBuilder {
|
||||
Ok(debris)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn create_unstake_burn_proof(
|
||||
zkbin: &ZkBinary,
|
||||
pk: &ProvingKey,
|
||||
input: &TransactionBuilderInputInfo,
|
||||
value_blind: pallas::Scalar,
|
||||
token_blind: pallas::Scalar,
|
||||
user_data_blind: pallas::Base,
|
||||
signature_secret: SecretKey,
|
||||
) -> Result<(Proof, ConsensusUnstakeBurnRevealed)> {
|
||||
let nullifier = Nullifier::from(poseidon_hash([input.secret.inner(), input.note.serial]));
|
||||
let public_key = PublicKey::from_secret(input.secret);
|
||||
let (pub_x, pub_y) = public_key.xy();
|
||||
|
||||
let signature_public = PublicKey::from_secret(signature_secret);
|
||||
|
||||
let coin = poseidon_hash([
|
||||
pub_x,
|
||||
pub_y,
|
||||
pallas::Base::from(input.note.value),
|
||||
input.note.token_id.inner(),
|
||||
input.note.serial,
|
||||
input.note.spend_hook,
|
||||
input.note.user_data,
|
||||
input.note.coin_blind,
|
||||
]);
|
||||
|
||||
let merkle_root = {
|
||||
let position: u64 = input.leaf_position.into();
|
||||
let mut current = MerkleNode::from(coin);
|
||||
for (level, sibling) in input.merkle_path.iter().enumerate() {
|
||||
let level = level as u8;
|
||||
current = if position & (1 << level) == 0 {
|
||||
MerkleNode::combine(level.into(), ¤t, sibling)
|
||||
} else {
|
||||
MerkleNode::combine(level.into(), sibling, ¤t)
|
||||
};
|
||||
}
|
||||
current
|
||||
};
|
||||
|
||||
let user_data_enc = poseidon_hash([input.note.user_data, user_data_blind]);
|
||||
let value_commit = pedersen_commitment_u64(input.note.value, value_blind);
|
||||
let token_commit = pedersen_commitment_base(input.note.token_id.inner(), token_blind);
|
||||
|
||||
let public_inputs = ConsensusUnstakeBurnRevealed {
|
||||
value_commit,
|
||||
token_commit,
|
||||
nullifier,
|
||||
merkle_root,
|
||||
spend_hook: input.note.spend_hook,
|
||||
user_data_enc,
|
||||
signature_public,
|
||||
};
|
||||
|
||||
let prover_witnesses = vec![
|
||||
Witness::Base(Value::known(pallas::Base::from(input.note.value))),
|
||||
Witness::Base(Value::known(input.note.token_id.inner())),
|
||||
Witness::Scalar(Value::known(value_blind)),
|
||||
Witness::Scalar(Value::known(token_blind)),
|
||||
Witness::Base(Value::known(input.note.serial)),
|
||||
Witness::Base(Value::known(input.note.spend_hook)),
|
||||
Witness::Base(Value::known(input.note.user_data)),
|
||||
Witness::Base(Value::known(user_data_blind)),
|
||||
Witness::Base(Value::known(input.note.coin_blind)),
|
||||
Witness::Base(Value::known(input.secret.inner())),
|
||||
Witness::Uint32(Value::known(u64::from(input.leaf_position).try_into().unwrap())),
|
||||
Witness::MerklePath(Value::known(input.merkle_path.clone().try_into().unwrap())),
|
||||
Witness::Base(Value::known(signature_secret.inner())),
|
||||
];
|
||||
|
||||
let circuit = ZkCircuit::new(prover_witnesses, zkbin.clone());
|
||||
let proof = Proof::create(pk, &[circuit], &public_inputs.to_vec(), &mut OsRng)?;
|
||||
|
||||
Ok((proof, public_inputs))
|
||||
}
|
||||
|
||||
@@ -92,15 +92,17 @@ fn init_contract(cid: ContractId, _ix: &[u8]) -> ContractResult {
|
||||
// order to be able to verify the circuits being bundled and enforcing
|
||||
// a specific tree inside sled, and also creation of VerifyingKey.
|
||||
let money_mint_v1_bincode = include_bytes!("../../money/proof/mint_v1.zk.bin");
|
||||
let consensus_mint_v1_bincode = include_bytes!("../proof/consensus_mint_v1.zk.bin");
|
||||
let money_burn_v1_bincode = include_bytes!("../../money/proof/burn_v1.zk.bin");
|
||||
let consensus_mint_v1_bincode = include_bytes!("../proof/consensus_mint_v1.zk.bin");
|
||||
let consensus_burn_v1_bincode = include_bytes!("../proof/consensus_burn_v1.zk.bin");
|
||||
let proposal_reward_v1_bincode = include_bytes!("../proof/proposal_reward_v1.zk.bin");
|
||||
let proposal_mint_v1_bincode = include_bytes!("../proof/proposal_mint_v1.zk.bin");
|
||||
|
||||
// For that, we use `zkas_db_set` and pass in the bincode.
|
||||
zkas_db_set(&money_mint_v1_bincode[..])?;
|
||||
zkas_db_set(&consensus_mint_v1_bincode[..])?;
|
||||
zkas_db_set(&money_burn_v1_bincode[..])?;
|
||||
zkas_db_set(&consensus_mint_v1_bincode[..])?;
|
||||
zkas_db_set(&consensus_burn_v1_bincode[..])?;
|
||||
zkas_db_set(&proposal_reward_v1_bincode[..])?;
|
||||
zkas_db_set(&proposal_mint_v1_bincode[..])?;
|
||||
|
||||
|
||||
@@ -20,13 +20,10 @@ use darkfi_money_contract::{
|
||||
error::MoneyError,
|
||||
model::{ConsensusUnstakeParamsV1, ConsensusUnstakeUpdateV1, MoneyUnstakeParamsV1},
|
||||
CONSENSUS_CONTRACT_COIN_ROOTS_TREE, CONSENSUS_CONTRACT_NULLIFIERS_TREE,
|
||||
MONEY_CONTRACT_ZKAS_BURN_NS_V1,
|
||||
CONSENSUS_CONTRACT_ZKAS_BURN_NS_V1,
|
||||
};
|
||||
use darkfi_sdk::{
|
||||
crypto::{
|
||||
pasta_prelude::*, pedersen_commitment_base, ContractId, CONSENSUS_CONTRACT_ID,
|
||||
DARK_TOKEN_ID, MONEY_CONTRACT_ID,
|
||||
},
|
||||
crypto::{pasta_prelude::*, ContractId, MONEY_CONTRACT_ID},
|
||||
db::{db_contains_key, db_lookup, db_set},
|
||||
error::{ContractError, ContractResult},
|
||||
msg,
|
||||
@@ -35,7 +32,7 @@ use darkfi_sdk::{
|
||||
};
|
||||
use darkfi_serial::{deserialize, serialize, Encodable, WriteExt};
|
||||
|
||||
use crate::{model::ZERO, ConsensusFunction};
|
||||
use crate::ConsensusFunction;
|
||||
|
||||
/// `get_metadata` function for `Consensus::UnstakeV1`
|
||||
pub(crate) fn consensus_unstake_get_metadata_v1(
|
||||
@@ -55,24 +52,22 @@ pub(crate) fn consensus_unstake_get_metadata_v1(
|
||||
// Grab the pedersen commitments and signature pubkeys from the
|
||||
// anonymous input
|
||||
let value_coords = input.value_commit.to_affine().coordinates().unwrap();
|
||||
let token_coords = input.token_commit.to_affine().coordinates().unwrap();
|
||||
let (sig_x, sig_y) = input.signature_public.xy();
|
||||
let epoch_palas = pallas::Base::from(input.epoch);
|
||||
|
||||
// It is very important that these are in the same order as the
|
||||
// `constrain_instance` calls in the zkas code.
|
||||
// Otherwise verification will fail.
|
||||
zk_public_inputs.push((
|
||||
MONEY_CONTRACT_ZKAS_BURN_NS_V1.to_string(),
|
||||
CONSENSUS_CONTRACT_ZKAS_BURN_NS_V1.to_string(),
|
||||
vec![
|
||||
input.nullifier.inner(),
|
||||
*value_coords.x(),
|
||||
*value_coords.y(),
|
||||
*token_coords.x(),
|
||||
*token_coords.y(),
|
||||
input.merkle_root.inner(),
|
||||
input.user_data_enc,
|
||||
epoch_palas,
|
||||
sig_x,
|
||||
sig_y,
|
||||
input.merkle_root.inner(),
|
||||
*value_coords.x(),
|
||||
*value_coords.y(),
|
||||
],
|
||||
));
|
||||
|
||||
@@ -105,12 +100,6 @@ pub(crate) fn consensus_unstake_process_instruction_v1(
|
||||
msg!("[ConsensusUnstakeV1] Validating anonymous input");
|
||||
let input = ¶ms.input;
|
||||
|
||||
// Only native token can be unstaked
|
||||
if input.token_commit != pedersen_commitment_base(DARK_TOKEN_ID.inner(), params.token_blind) {
|
||||
msg!("[ConsensusUnstakeV1] Error: Input used non-native token");
|
||||
return Err(MoneyError::StakeInputNonNativeToken.into())
|
||||
}
|
||||
|
||||
// The Merkle root is used to know whether this is a coin that
|
||||
// existed in a previous state.
|
||||
if !db_contains_key(coin_roots_db, &serialize(&input.merkle_root))? {
|
||||
@@ -137,17 +126,6 @@ pub(crate) fn consensus_unstake_process_instruction_v1(
|
||||
return Err(MoneyError::UnstakeNextCallNotMoneyContract.into())
|
||||
}
|
||||
|
||||
// Check if spend hook is set and its correctness
|
||||
if input.spend_hook == ZERO {
|
||||
msg!("[ConsensusUnstakeV1] Error: Missing spend hook");
|
||||
return Err(MoneyError::StakeMissingSpendHook.into())
|
||||
}
|
||||
|
||||
if input.spend_hook != CONSENSUS_CONTRACT_ID.inner() {
|
||||
msg!("[ConsensusUnstakeV1] Error: Spend hook is not consensus contract");
|
||||
return Err(MoneyError::UnstakeSpendHookNotConsensusContract.into())
|
||||
}
|
||||
|
||||
// Verify next call corresponds to Money::UnstakeV1 (0x07)
|
||||
if next.data[0] != 0x07 {
|
||||
msg!("[ConsensusUnstakeV1] Error: Next call function mismatch");
|
||||
|
||||
@@ -106,48 +106,50 @@ async fn consensus_contract_genesis_stake_unstake() -> Result<()> {
|
||||
|
||||
// Gather new staked owncoin
|
||||
let alice_staked_oc =
|
||||
th.gather_consensus_owncoin(Holder::Alice, genesis_stake_params.output)?;
|
||||
th.gather_consensus_owncoin(Holder::Alice, genesis_stake_params.output, None)?;
|
||||
|
||||
// Verify values match
|
||||
assert!(ALICE_INITIAL == alice_staked_oc.note.value);
|
||||
/*
|
||||
// We simulate the proposal of genesis slot
|
||||
let slot_checkpoint = th.get_slot_checkpoints_by_slot(current_slot).await?;
|
||||
|
||||
// We simulate the proposal of genesis slot
|
||||
let slot_checkpoint = th.get_slot_checkpoints_by_slot(current_slot).await?;
|
||||
// With alice's current coin value she can become the slot proposer,
|
||||
// so she creates a proposal transaction to burn her staked coin,
|
||||
// reward herself and mint the new coin.
|
||||
info!(target: "consensus", "[Alice] ====================");
|
||||
info!(target: "consensus", "[Alice] Building proposal tx");
|
||||
info!(target: "consensus", "[Alice] ====================");
|
||||
let (proposal_tx, proposal_params) =
|
||||
th.proposal(Holder::Alice, slot_checkpoint, alice_staked_oc.clone())?;
|
||||
|
||||
// With alice's current coin value she can become the slot proposer,
|
||||
// so she creates a proposal transaction to burn her staked coin,
|
||||
// reward herself and mint the new coin.
|
||||
info!(target: "consensus", "[Alice] ====================");
|
||||
info!(target: "consensus", "[Alice] Building proposal tx");
|
||||
info!(target: "consensus", "[Alice] ====================");
|
||||
let (proposal_tx, proposal_params) =
|
||||
th.proposal(Holder::Alice, slot_checkpoint, alice_staked_oc.clone())?;
|
||||
info!(target: "consensus", "[Faucet] ===========================");
|
||||
info!(target: "consensus", "[Faucet] Executing Alice proposal tx");
|
||||
info!(target: "consensus", "[Faucet] ===========================");
|
||||
th.execute_proposal_tx(Holder::Faucet, proposal_tx.clone(), &proposal_params, current_slot)
|
||||
.await?;
|
||||
|
||||
info!(target: "consensus", "[Faucet] ===========================");
|
||||
info!(target: "consensus", "[Faucet] Executing Alice proposal tx");
|
||||
info!(target: "consensus", "[Faucet] ===========================");
|
||||
th.execute_proposal_tx(Holder::Faucet, proposal_tx.clone(), &proposal_params, current_slot)
|
||||
.await?;
|
||||
info!(target: "consensus", "[Alice] ===========================");
|
||||
info!(target: "consensus", "[Alice] Executing Alice proposal tx");
|
||||
info!(target: "consensus", "[Alice] ===========================");
|
||||
th.execute_proposal_tx(Holder::Alice, proposal_tx, &proposal_params, current_slot).await?;
|
||||
|
||||
info!(target: "consensus", "[Alice] ===========================");
|
||||
info!(target: "consensus", "[Alice] Executing Alice proposal tx");
|
||||
info!(target: "consensus", "[Alice] ===========================");
|
||||
th.execute_proposal_tx(Holder::Alice, proposal_tx, &proposal_params, current_slot).await?;
|
||||
th.assert_trees();
|
||||
|
||||
th.assert_trees();
|
||||
// Gather new staked owncoin which includes the reward
|
||||
let alice_rewarded_staked_oc =
|
||||
th.gather_consensus_owncoin(Holder::Alice, proposal_params.output)?;
|
||||
|
||||
// Gather new staked owncoin which includes the reward
|
||||
let alice_rewarded_staked_oc =
|
||||
th.gather_owncoin(Holder::Alice, proposal_params.output, true)?;
|
||||
|
||||
// Verify values match
|
||||
assert!((alice_staked_oc.note.value + REWARD) == alice_rewarded_staked_oc.note.value);
|
||||
// Verify values match
|
||||
assert!((alice_staked_oc.note.value + REWARD) == alice_rewarded_staked_oc.note.value);
|
||||
*/
|
||||
let alice_rewarded_staked_oc = alice_staked_oc;
|
||||
|
||||
// Now Alice can unstake her owncoin
|
||||
info!(target: "consensus", "[Alice] ===================");
|
||||
info!(target: "consensus", "[Alice] Building unstake tx");
|
||||
info!(target: "consensus", "[Alice] ===================");
|
||||
let (unstake_tx, unstake_params) =
|
||||
let (unstake_tx, unstake_params, unstake_secret_key) =
|
||||
th.unstake_native(Holder::Alice, alice_rewarded_staked_oc.clone())?;
|
||||
|
||||
info!(target: "consensus", "[Faucet] ==========================");
|
||||
@@ -164,7 +166,8 @@ async fn consensus_contract_genesis_stake_unstake() -> Result<()> {
|
||||
th.assert_trees();
|
||||
|
||||
// Gather new unstaked owncoin
|
||||
let alice_unstaked_oc = th.gather_owncoin(Holder::Alice, unstake_params.output, false)?;
|
||||
let alice_unstaked_oc =
|
||||
th.gather_owncoin(Holder::Alice, unstake_params.output, Some(unstake_secret_key))?;
|
||||
|
||||
// Verify values match
|
||||
assert!(alice_rewarded_staked_oc.note.value == alice_unstaked_oc.note.value);
|
||||
|
||||
@@ -35,7 +35,7 @@ use darkfi::{
|
||||
use darkfi_sdk::{
|
||||
crypto::{
|
||||
merkle_prelude::*, poseidon_hash, Coin, Keypair, MerkleNode, MerkleTree, Nullifier,
|
||||
PublicKey, CONSENSUS_CONTRACT_ID, DARK_TOKEN_ID, MONEY_CONTRACT_ID,
|
||||
PublicKey, SecretKey, CONSENSUS_CONTRACT_ID, DARK_TOKEN_ID, MONEY_CONTRACT_ID,
|
||||
},
|
||||
pasta::pallas,
|
||||
ContractCall,
|
||||
@@ -48,7 +48,7 @@ use darkfi_consensus_contract::{
|
||||
client::{
|
||||
genesis_stake_v1::ConsensusGenesisStakeCallBuilder,
|
||||
proposal_v1::ConsensusProposalCallBuilder, stake_v1::ConsensusStakeCallBuilder,
|
||||
unstake_v1::ConsensusUnstakeCallBuilder,
|
||||
unstake_v1::ConsensusUnstakeCallBuilder, ConsensusNote, ConsensusOwnCoin,
|
||||
},
|
||||
model::{ConsensusGenesisStakeParamsV1, ConsensusOutput, ConsensusProposalMintParamsV1},
|
||||
ConsensusFunction,
|
||||
@@ -59,9 +59,9 @@ use darkfi_money_contract::{
|
||||
unstake_v1::MoneyUnstakeCallBuilder, MoneyNote, OwnCoin,
|
||||
},
|
||||
model::{ConsensusStakeParamsV1, MoneyTransferParamsV1, MoneyUnstakeParamsV1, Output},
|
||||
MoneyFunction, CONSENSUS_CONTRACT_ZKAS_MINT_NS_V1, CONSENSUS_CONTRACT_ZKAS_PROPOSAL_MINT_NS_V1,
|
||||
CONSENSUS_CONTRACT_ZKAS_PROPOSAL_REWARD_NS_V1, MONEY_CONTRACT_ZKAS_BURN_NS_V1,
|
||||
MONEY_CONTRACT_ZKAS_MINT_NS_V1,
|
||||
MoneyFunction, CONSENSUS_CONTRACT_ZKAS_BURN_NS_V1, CONSENSUS_CONTRACT_ZKAS_MINT_NS_V1,
|
||||
CONSENSUS_CONTRACT_ZKAS_PROPOSAL_MINT_NS_V1, CONSENSUS_CONTRACT_ZKAS_PROPOSAL_REWARD_NS_V1,
|
||||
MONEY_CONTRACT_ZKAS_BURN_NS_V1, MONEY_CONTRACT_ZKAS_MINT_NS_V1,
|
||||
};
|
||||
|
||||
pub fn init_logger() {
|
||||
@@ -232,6 +232,7 @@ impl ConsensusTestHarness {
|
||||
mkpk!(MONEY_CONTRACT_ZKAS_MINT_NS_V1);
|
||||
mkpk!(CONSENSUS_CONTRACT_ZKAS_MINT_NS_V1);
|
||||
mkpk!(MONEY_CONTRACT_ZKAS_BURN_NS_V1);
|
||||
mkpk!(CONSENSUS_CONTRACT_ZKAS_BURN_NS_V1);
|
||||
mkpk!(CONSENSUS_CONTRACT_ZKAS_PROPOSAL_REWARD_NS_V1);
|
||||
mkpk!(CONSENSUS_CONTRACT_ZKAS_PROPOSAL_MINT_NS_V1);
|
||||
|
||||
@@ -606,10 +607,11 @@ impl ConsensusTestHarness {
|
||||
pub fn unstake_native(
|
||||
&mut self,
|
||||
holder: Holder,
|
||||
staked_oc: OwnCoin,
|
||||
) -> Result<(Transaction, MoneyUnstakeParamsV1)> {
|
||||
staked_oc: ConsensusOwnCoin,
|
||||
) -> Result<(Transaction, MoneyUnstakeParamsV1, SecretKey)> {
|
||||
let wallet = self.holders.get_mut(&holder).unwrap();
|
||||
let (burn_pk, burn_zkbin) = self.proving_keys.get(&MONEY_CONTRACT_ZKAS_BURN_NS_V1).unwrap();
|
||||
let (burn_pk, burn_zkbin) =
|
||||
self.proving_keys.get(&CONSENSUS_CONTRACT_ZKAS_BURN_NS_V1).unwrap();
|
||||
let (mint_pk, mint_zkbin) = self.proving_keys.get(&MONEY_CONTRACT_ZKAS_MINT_NS_V1).unwrap();
|
||||
let tx_action_benchmark = self.tx_action_benchmarks.get_mut(&TxAction::Unstake).unwrap();
|
||||
let timer = Instant::now();
|
||||
@@ -636,10 +638,8 @@ impl ConsensusTestHarness {
|
||||
|
||||
// Building Money::Unstake params
|
||||
let money_unstake_call_debris = MoneyUnstakeCallBuilder {
|
||||
coin: staked_oc,
|
||||
recipient: wallet.keypair.public,
|
||||
coin: staked_oc.into(),
|
||||
value_blind: consensus_unstake_value_blind,
|
||||
token_blind: consensus_unstake_params.token_blind,
|
||||
nullifier: consensus_unstake_params.input.nullifier,
|
||||
merkle_root: consensus_unstake_params.input.merkle_root,
|
||||
signature_public: consensus_unstake_params.input.signature_public,
|
||||
@@ -675,7 +675,7 @@ impl ConsensusTestHarness {
|
||||
let size = ::std::mem::size_of_val(&*base58);
|
||||
tx_action_benchmark.broadcasted_sizes.push(size);
|
||||
|
||||
Ok((unstake_tx, money_unstake_params))
|
||||
Ok((unstake_tx, money_unstake_params, consensus_unstake_secret_key))
|
||||
}
|
||||
|
||||
pub async fn execute_unstake_native_tx(
|
||||
@@ -698,10 +698,19 @@ impl ConsensusTestHarness {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn gather_owncoin(&mut self, holder: Holder, output: Output) -> Result<OwnCoin> {
|
||||
pub fn gather_owncoin(
|
||||
&mut self,
|
||||
holder: Holder,
|
||||
output: Output,
|
||||
secret_key: Option<SecretKey>,
|
||||
) -> Result<OwnCoin> {
|
||||
let wallet = self.holders.get_mut(&holder).unwrap();
|
||||
let leaf_position = wallet.merkle_tree.witness().unwrap();
|
||||
let note: MoneyNote = output.note.decrypt(&wallet.keypair.secret)?;
|
||||
let secret_key = match secret_key {
|
||||
Some(key) => key,
|
||||
None => wallet.keypair.secret,
|
||||
};
|
||||
let note: MoneyNote = output.note.decrypt(&secret_key)?;
|
||||
let oc = OwnCoin {
|
||||
coin: Coin::from(output.coin),
|
||||
note: note.clone(),
|
||||
@@ -717,11 +726,16 @@ impl ConsensusTestHarness {
|
||||
&mut self,
|
||||
holder: Holder,
|
||||
output: ConsensusOutput,
|
||||
) -> Result<OwnCoin> {
|
||||
secret_key: Option<SecretKey>,
|
||||
) -> Result<ConsensusOwnCoin> {
|
||||
let wallet = self.holders.get_mut(&holder).unwrap();
|
||||
let leaf_position = wallet.consensus_merkle_tree.witness().unwrap();
|
||||
let note: MoneyNote = output.note.decrypt(&wallet.keypair.secret)?;
|
||||
let oc = OwnCoin {
|
||||
let secret_key = match secret_key {
|
||||
Some(key) => key,
|
||||
None => wallet.keypair.secret,
|
||||
};
|
||||
let note: ConsensusNote = output.note.decrypt(&secret_key)?;
|
||||
let oc = ConsensusOwnCoin {
|
||||
coin: Coin::from(output.coin),
|
||||
note: note.clone(),
|
||||
secret: wallet.keypair.secret,
|
||||
|
||||
@@ -77,12 +77,8 @@ pub struct TransactionBuilderOutputInfo {
|
||||
pub struct MoneyUnstakeCallBuilder {
|
||||
/// `OwnCoin` we're given to use in this builder
|
||||
pub coin: OwnCoin,
|
||||
/// Recipient's public key
|
||||
pub recipient: PublicKey,
|
||||
/// Blinding factor for value commitment
|
||||
pub value_blind: pallas::Scalar,
|
||||
/// Blinding factor for `token_id`
|
||||
pub token_blind: pallas::Scalar,
|
||||
/// Revealed nullifier
|
||||
pub nullifier: Nullifier,
|
||||
/// Revealed Merkle root
|
||||
@@ -105,13 +101,14 @@ impl MoneyUnstakeCallBuilder {
|
||||
let output = TransactionBuilderOutputInfo {
|
||||
value: self.coin.note.value,
|
||||
token_id: self.coin.note.token_id,
|
||||
public_key: self.recipient,
|
||||
public_key: self.signature_public,
|
||||
};
|
||||
debug!("Finished building output");
|
||||
|
||||
let serial = pallas::Base::random(&mut OsRng);
|
||||
let spend_hook = pallas::Base::zero();
|
||||
let user_data_enc = pallas::Base::zero();
|
||||
let token_blind = pallas::Scalar::random(&mut OsRng);
|
||||
let coin_blind = pallas::Base::random(&mut OsRng);
|
||||
|
||||
info!("Creating unstake mint proof for output");
|
||||
@@ -120,7 +117,7 @@ impl MoneyUnstakeCallBuilder {
|
||||
&self.mint_pk,
|
||||
&output,
|
||||
self.value_blind,
|
||||
self.token_blind,
|
||||
token_blind,
|
||||
serial,
|
||||
spend_hook,
|
||||
user_data_enc,
|
||||
@@ -136,7 +133,7 @@ impl MoneyUnstakeCallBuilder {
|
||||
user_data: user_data_enc,
|
||||
coin_blind,
|
||||
value_blind: self.value_blind,
|
||||
token_blind: self.token_blind,
|
||||
token_blind,
|
||||
memo: vec![],
|
||||
};
|
||||
|
||||
@@ -150,7 +147,7 @@ impl MoneyUnstakeCallBuilder {
|
||||
};
|
||||
|
||||
let input = StakeInput {
|
||||
token_blind: self.token_blind,
|
||||
token_blind,
|
||||
value_commit: public_inputs.value_commit,
|
||||
nullifier: self.nullifier,
|
||||
merkle_root: self.merkle_root,
|
||||
|
||||
@@ -152,12 +152,6 @@ pub(crate) fn money_unstake_process_instruction_v1(
|
||||
return Err(MoneyError::PreviousCallInputMissmatch.into())
|
||||
}
|
||||
|
||||
// Check spend hook correctness
|
||||
if previous_input.spend_hook != CONSENSUS_CONTRACT_ID.inner() {
|
||||
msg!("[MoneyUnstakeV1] Error: Invoking contract call does not match spend hook in input");
|
||||
return Err(MoneyError::SpendHookMismatch.into())
|
||||
}
|
||||
|
||||
// If next spend hook is set, check its correctness
|
||||
if params.spend_hook != pallas::Base::zero() {
|
||||
let next_call_idx = call_idx + 1;
|
||||
|
||||
@@ -102,6 +102,8 @@ pub const CONSENSUS_CONTRACT_COIN_MERKLE_TREE: &str = "consensus_coin_tree";
|
||||
|
||||
/// zkas consensus mint circuit namespace
|
||||
pub const CONSENSUS_CONTRACT_ZKAS_MINT_NS_V1: &str = "ConsensusMint_V1";
|
||||
/// zkas consensus burn circuit namespace
|
||||
pub const CONSENSUS_CONTRACT_ZKAS_BURN_NS_V1: &str = "ConsensusBurn_V1";
|
||||
/// zkas proposal reward circuit namespace
|
||||
pub const CONSENSUS_CONTRACT_ZKAS_PROPOSAL_REWARD_NS_V1: &str = "ProposalReward_V1";
|
||||
/// zkas proposal mint circuit namespace
|
||||
|
||||
@@ -84,6 +84,30 @@ impl PartialEq<StakeInput> for Input {
|
||||
}
|
||||
}
|
||||
|
||||
/// Anonymous input for unstaking contract calls
|
||||
#[derive(Clone, Debug, PartialEq, SerialEncodable, SerialDecodable)]
|
||||
pub struct UnstakeInput {
|
||||
/// Epoch the coin was minted
|
||||
pub epoch: u64,
|
||||
/// Pedersen commitment for the staked coin's value
|
||||
pub value_commit: pallas::Point,
|
||||
/// Revealed nullifier
|
||||
pub nullifier: Nullifier,
|
||||
/// Revealed Merkle root
|
||||
pub merkle_root: MerkleNode,
|
||||
/// Public key for the signature
|
||||
pub signature_public: PublicKey,
|
||||
}
|
||||
|
||||
impl PartialEq<StakeInput> for UnstakeInput {
|
||||
fn eq(&self, other: &StakeInput) -> bool {
|
||||
self.value_commit == other.value_commit &&
|
||||
self.nullifier == other.nullifier &&
|
||||
self.merkle_root == other.merkle_root &&
|
||||
self.signature_public == other.signature_public
|
||||
}
|
||||
}
|
||||
|
||||
/// A contract call's anonymous output
|
||||
#[derive(Clone, Debug, PartialEq, SerialEncodable, SerialDecodable)]
|
||||
pub struct Output {
|
||||
@@ -208,10 +232,8 @@ pub struct ConsensusStakeUpdateV1 {
|
||||
/// Parameters for `Consensus::Unstake`
|
||||
#[derive(Clone, Debug, SerialEncodable, SerialDecodable)]
|
||||
pub struct ConsensusUnstakeParamsV1 {
|
||||
/// Blinding factor for `token_id`
|
||||
pub token_blind: pallas::Scalar,
|
||||
/// Anonymous input
|
||||
pub input: Input,
|
||||
pub input: UnstakeInput,
|
||||
}
|
||||
|
||||
/// State update for `Consensus::Unstake`
|
||||
|
||||
Reference in New Issue
Block a user