mirror of
https://github.com/darkrenaissance/darkfi.git
synced 2026-04-28 03:00:18 -04:00
contract/consensus: use previous proposal/block hash in vrf input
This commit is contained in:
@@ -599,8 +599,7 @@ impl ConsensusState {
|
||||
}
|
||||
|
||||
if hashes.is_empty() {
|
||||
let (_, hash) = self.blockchain.last().unwrap();
|
||||
hashes.push(hash);
|
||||
hashes.push(self.genesis_block);
|
||||
}
|
||||
|
||||
hashes
|
||||
|
||||
@@ -115,6 +115,8 @@ pub struct ConsensusProposalCallBuilder {
|
||||
pub coin: ConsensusOwnCoin,
|
||||
/// Rewarded slot checkpoint
|
||||
pub slot_checkpoint: SlotCheckpoint,
|
||||
/// Extending fork last proposal/block hash
|
||||
pub previous_hash: blake3::Hash,
|
||||
/// Merkle tree of coins used to create inclusion proofs
|
||||
pub tree: MerkleTree,
|
||||
/// `Proposal_V1` zkas circuit ZkBinary
|
||||
@@ -162,6 +164,7 @@ impl ConsensusProposalCallBuilder {
|
||||
&input,
|
||||
&output,
|
||||
&self.slot_checkpoint,
|
||||
self.previous_hash,
|
||||
)?;
|
||||
|
||||
let input = ConsensusInput {
|
||||
@@ -205,6 +208,7 @@ impl ConsensusProposalCallBuilder {
|
||||
reward_blind,
|
||||
new_serial_commit,
|
||||
slot,
|
||||
previous_hash: self.previous_hash,
|
||||
vrf_proof,
|
||||
y,
|
||||
rho,
|
||||
@@ -225,6 +229,7 @@ pub fn create_proposal_proof(
|
||||
input: &ConsensusBurnInputInfo,
|
||||
output: &ConsensusMintOutputInfo,
|
||||
slot_checkpoint: &SlotCheckpoint,
|
||||
previous_hash: blake3::Hash,
|
||||
) -> Result<(Proof, ConsensusProposalRevealed)> {
|
||||
// Proof parameters
|
||||
let nullifier = Nullifier::from(poseidon_hash([input.secret.inner(), input.note.serial]));
|
||||
@@ -278,8 +283,9 @@ pub fn create_proposal_proof(
|
||||
|
||||
let slot_pallas = pallas::Base::from(slot_checkpoint.slot);
|
||||
let seed = poseidon_hash([SEED_PREFIX, input.note.serial]);
|
||||
let mut vrf_input = Vec::with_capacity(32 + 32);
|
||||
let mut vrf_input = Vec::with_capacity(32 + blake3::OUT_LEN + 32);
|
||||
vrf_input.extend_from_slice(&slot_checkpoint.previous_eta.to_repr());
|
||||
vrf_input.extend_from_slice(previous_hash.as_bytes());
|
||||
vrf_input.extend_from_slice(&slot_pallas.to_repr());
|
||||
let vrf_proof = VrfProof::prove(input.secret, &vrf_input, &mut OsRng);
|
||||
let mut eta = [0u8; 64];
|
||||
|
||||
@@ -95,10 +95,17 @@ pub(crate) fn consensus_proposal_get_metadata_v1(
|
||||
};
|
||||
let slot_checkpoint: SlotCheckpoint = deserialize(&slot_checkpoint)?;
|
||||
|
||||
// Verify proposal extends a known fork
|
||||
if !slot_checkpoint.fork_hashes.contains(¶ms.previous_hash) {
|
||||
msg!("[ConsensusProposalV1] Error: Proposal extends unknown fork {}", params.previous_hash);
|
||||
return Err(ConsensusError::ProposalExtendsUnknownFork.into())
|
||||
}
|
||||
|
||||
// Verify eta VRF proof
|
||||
let slot_pallas = pallas::Base::from(slot_checkpoint.slot);
|
||||
let mut vrf_input = Vec::with_capacity(32 + 32);
|
||||
let mut vrf_input = Vec::with_capacity(32 + blake3::OUT_LEN + 32);
|
||||
vrf_input.extend_from_slice(&slot_checkpoint.previous_eta.to_repr());
|
||||
vrf_input.extend_from_slice(params.previous_hash.as_bytes());
|
||||
vrf_input.extend_from_slice(&slot_pallas.to_repr());
|
||||
let vrf_proof = ¶ms.vrf_proof;
|
||||
if !vrf_proof.verify(params.input.signature_public, &vrf_input) {
|
||||
|
||||
@@ -23,6 +23,9 @@ pub enum ConsensusError {
|
||||
#[error("Missing slot checkpoint from db")]
|
||||
ProposalMissingSlotCheckpoint,
|
||||
|
||||
#[error("Proposal extends unknown fork")]
|
||||
ProposalExtendsUnknownFork,
|
||||
|
||||
#[error("Eta VRF proof couldn't be verified")]
|
||||
ProposalErroneousVrfProof,
|
||||
|
||||
@@ -37,9 +40,10 @@ impl From<ConsensusError> for ContractError {
|
||||
fn from(e: ConsensusError) -> Self {
|
||||
match e {
|
||||
ConsensusError::ProposalMissingSlotCheckpoint => Self::Custom(1),
|
||||
ConsensusError::ProposalErroneousVrfProof => Self::Custom(2),
|
||||
ConsensusError::CoinStillInGracePeriod => Self::Custom(3),
|
||||
ConsensusError::CoinNotInUnstakeSet => Self::Custom(4),
|
||||
ConsensusError::ProposalExtendsUnknownFork => Self::Custom(2),
|
||||
ConsensusError::ProposalErroneousVrfProof => Self::Custom(3),
|
||||
ConsensusError::CoinStillInGracePeriod => Self::Custom(4),
|
||||
ConsensusError::CoinNotInUnstakeSet => Self::Custom(5),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,6 +49,8 @@ pub struct ConsensusProposalParamsV1 {
|
||||
pub new_serial_commit: pallas::Point,
|
||||
/// Rewarded slot
|
||||
pub slot: u64,
|
||||
/// Extending fork last proposal/block hash
|
||||
pub previous_hash: blake3::Hash,
|
||||
/// VRF proof for eta calculation
|
||||
pub vrf_proof: VrfProof,
|
||||
/// Coin y
|
||||
|
||||
@@ -112,7 +112,9 @@ async fn consensus_contract_genesis_stake_unstake() -> Result<()> {
|
||||
assert!(ALICE_INITIAL == alice_staked_oc.note.value);
|
||||
|
||||
// We simulate the proposal of genesis slot
|
||||
let slot_checkpoint = th.get_slot_checkpoint_by_slot(current_slot).await?;
|
||||
// We progress 1 slot and simulate its proposal
|
||||
current_slot += 1;
|
||||
let slot_checkpoint = th.generate_slot_checkpoint(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,
|
||||
@@ -121,7 +123,7 @@ async fn consensus_contract_genesis_stake_unstake() -> Result<()> {
|
||||
info!(target: "consensus", "[Alice] Building proposal tx");
|
||||
info!(target: "consensus", "[Alice] ====================");
|
||||
let (proposal_tx, proposal_params, proposal_secret_key) =
|
||||
th.proposal(Holder::Alice, slot_checkpoint, alice_staked_oc.clone())?;
|
||||
th.proposal(Holder::Alice, slot_checkpoint, alice_staked_oc.clone()).await?;
|
||||
|
||||
info!(target: "consensus", "[Faucet] ===========================");
|
||||
info!(target: "consensus", "[Faucet] Executing Alice proposal tx");
|
||||
|
||||
@@ -511,7 +511,7 @@ impl ConsensusTestHarness {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn proposal(
|
||||
pub async fn proposal(
|
||||
&mut self,
|
||||
holder: Holder,
|
||||
slot_checkpoint: SlotCheckpoint,
|
||||
@@ -523,10 +523,14 @@ impl ConsensusTestHarness {
|
||||
let tx_action_benchmark = self.tx_action_benchmarks.get_mut(&TxAction::Proposal).unwrap();
|
||||
let timer = Instant::now();
|
||||
|
||||
// Proposals always extend genesis block
|
||||
let previous_hash = wallet.state.read().await.consensus.genesis_block;
|
||||
|
||||
// Building Consensus::Unstake params
|
||||
let proposal_call_debris = ConsensusProposalCallBuilder {
|
||||
coin: staked_oc,
|
||||
slot_checkpoint,
|
||||
previous_hash,
|
||||
tree: wallet.consensus_merkle_tree.clone(),
|
||||
proposal_zkbin: proposal_zkbin.clone(),
|
||||
proposal_pk: proposal_pk.clone(),
|
||||
|
||||
@@ -102,7 +102,7 @@ async fn consensus_contract_stake_unstake() -> Result<()> {
|
||||
info!(target: "consensus", "[Malicious] Checking proposal before grace period");
|
||||
info!(target: "consensus", "[Malicious] =====================================");
|
||||
let (proposal_tx, _, _) =
|
||||
th.proposal(Holder::Alice, slot_checkpoint, alice_staked_oc.clone())?;
|
||||
th.proposal(Holder::Alice, slot_checkpoint, alice_staked_oc.clone()).await?;
|
||||
th.execute_erroneous_proposal_txs(Holder::Alice, vec![proposal_tx], current_slot, 1).await?;
|
||||
|
||||
// We progress after grace period
|
||||
@@ -116,7 +116,7 @@ async fn consensus_contract_stake_unstake() -> Result<()> {
|
||||
info!(target: "consensus", "[Alice] Building proposal tx");
|
||||
info!(target: "consensus", "[Alice] ====================");
|
||||
let (proposal_tx, proposal_params, proposal_secret_key) =
|
||||
th.proposal(Holder::Alice, slot_checkpoint, alice_staked_oc.clone())?;
|
||||
th.proposal(Holder::Alice, slot_checkpoint, alice_staked_oc.clone()).await?;
|
||||
|
||||
info!(target: "consensus", "[Faucet] ===========================");
|
||||
info!(target: "consensus", "[Faucet] Executing Alice proposal tx");
|
||||
@@ -194,7 +194,7 @@ async fn consensus_contract_stake_unstake() -> Result<()> {
|
||||
info!(target: "consensus", "[Malicious] Checking using unstaked coin in proposal");
|
||||
info!(target: "consensus", "[Malicious] ========================================");
|
||||
let (proposal_tx, _, _) =
|
||||
th.proposal(Holder::Alice, slot_checkpoint, alice_unstake_request_oc.clone())?;
|
||||
th.proposal(Holder::Alice, slot_checkpoint, alice_unstake_request_oc.clone()).await?;
|
||||
th.execute_erroneous_proposal_txs(Holder::Alice, vec![proposal_tx], current_slot, 1).await?;
|
||||
|
||||
info!(target: "consensus", "[Malicious] =============================");
|
||||
|
||||
Reference in New Issue
Block a user