Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ashanti/winning posts #493

Merged
merged 15 commits into from
Jun 15, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion blockchain/chain/src/store/chain_store.rs
Original file line number Diff line number Diff line change
Expand Up @@ -306,7 +306,7 @@ pub fn get_randomness<DB: BlockStore>(
}

/// Computes a pseudorandom 32 byte Vec
fn draw_randomness(
pub fn draw_randomness(
rbase: &[u8],
pers: DomainSeparationTag,
round: ChainEpoch,
Expand Down
4 changes: 4 additions & 0 deletions blockchain/chain_sync/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ futures = "0.3.5"
lru = "0.4.3"
thiserror = "1.0"
num-traits = "0.2"
filecoin-proofs-api = { git = "https://github.com/filecoin-project/rust-filecoin-proofs-api", rev = "0e1c7cb464707c7a7ad82b0f8303f000f6f3fc8a" }
fil_types = { path = "../../types" }
commcid = { path = "../../utils/commcid" }



[dev-dependencies]
Expand Down
90 changes: 85 additions & 5 deletions blockchain/chain_sync/src/sync.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,21 @@ use super::bucket::{SyncBucket, SyncBucketSet};
use super::network_handler::NetworkHandler;
use super::peer_manager::PeerManager;
use super::{Error, SyncNetworkContext};
use address::Address;
use address::{Address, Protocol};
use amt::Amt;
use async_std::sync::{channel, Receiver, Sender};
use async_std::task;
use beacon::Beacon;
use blocks::{Block, FullTipset, Tipset, TipsetKeys, TxMeta};
use beacon::{Beacon, BeaconEntry};
use blocks::{Block, BlockHeader, FullTipset, Tipset, TipsetKeys, TxMeta};
use chain::ChainStore;
use cid::{multihash::Blake2b256, Cid};
use commcid::cid_to_replica_commitment_v1;
use core::time::Duration;
use crypto::verify_bls_aggregate;
use crypto::DomainSeparationTag;
use encoding::{Cbor, Error as EncodingError};
use fil_types::SectorInfo;
use filecoin_proofs_api::{post::verify_winning_post, ProverId, PublicReplicaInfo, SectorId};
use forest_libp2p::{
hello::HelloMessage, BlockSyncRequest, NetworkEvent, NetworkMessage, MESSAGES,
};
Expand All @@ -28,14 +32,15 @@ use futures::{
};
use ipld_blockstore::BlockStore;
use libp2p::core::PeerId;
use log::error;
use log::{debug, info, warn};
use lru::LruCache;
use message::{Message, SignedMessage, UnsignedMessage};
use num_traits::Zero;
use state_manager::StateManager;
use state_manager::{utils, StateManager};
use state_tree::StateTree;
use std::cmp::min;
use std::collections::HashMap;
use std::collections::{BTreeMap, HashMap};
use std::convert::TryFrom;
use std::sync::Arc;
use vm::TokenAmount;
Expand Down Expand Up @@ -729,6 +734,81 @@ where
Ok(())
}

pub async fn verify_winning_post_proof(
&self,
block: BlockHeader,
prev_entry: BeaconEntry,
lbst: Cid,
) -> Result<(), Error> {
let marshal_miner_work_addr = block.miner_address().marshal_cbor()?;
let rbase = block.beacon_entries().iter().last().unwrap_or(&prev_entry);
let rand = chain::draw_randomness(
rbase.data(),
DomainSeparationTag::WinningPoStChallengeSeed,
block.epoch(),
&marshal_miner_work_addr,
)
.map_err(|err| {
Error::Validation(format!(
"failed to get randomness for verifying winningPost proof: {:}",
err
))
})?;
if block.miner_address().protocol() != Protocol::ID {
return Err(Error::Validation(format!(
"failed to get ID from miner address {:}",
block.miner_address()
)));
};
let sectors = utils::get_sectors_for_winning_post(
&self.state_manager,
&lbst,
&block.miner_address(),
&rand,
)?;

let proofs = block
.win_post_proof()
.iter()
.fold(Vec::new(), |mut proof, p| {
proof.extend_from_slice(&p.proof_bytes);
proof
});

let replicas = sectors
.iter()
.map::<Result<(SectorId, PublicReplicaInfo), Error>, _>(|sector_info: &SectorInfo| {
let commr =
cid_to_replica_commitment_v1(&sector_info.sealed_cid).map_err(|err| {
Error::Validation(format!("failed to get replica commitment: {:}", err))
})?;
let replica = PublicReplicaInfo::new(
sector_info
.proof
.registered_window_post_proof()
.map_err(|err| {
Error::Validation(format!("failed to get registered proof: {:}", err))
})?
.into(),
commr,
);
Ok((SectorId::from(sector_info.sector_number), replica))
})
.collect::<Result<BTreeMap<SectorId, PublicReplicaInfo>, _>>()?;

let mut prover_id = ProverId::default();
let prover_bytes = block.miner_address().to_bytes();
prover_id[..prover_bytes.len()].copy_from_slice(&prover_bytes);
if !verify_winning_post(&rand, &proofs, &replicas, prover_id)
.map_err(|err| Error::Validation(format!("failed to verify election post: {:}", err)))?
{
error!("invalid winning post ({:?}; {:?})", rand, sectors);
Err(Error::Validation("Winning post was invalid".to_string()))
} else {
Ok(())
}
}

/// Syncs chain data and persists it to blockstore
async fn sync_headers_reverse(
&mut self,
Expand Down
4 changes: 3 additions & 1 deletion blockchain/state_manager/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,6 @@ clock = { path = "../../node/clock" }
chain = { path = "../chain" }
async-std = "1.5.0"
async-log = "2.0.0"
log = "0.4.8"
log = "0.4.8"
filecoin-proofs-api = { git = "https://github.com/filecoin-project/rust-filecoin-proofs-api", rev = "0e1c7cb464707c7a7ad82b0f8303f000f6f3fc8a" }
fil_types = { path = "../../types" }
2 changes: 1 addition & 1 deletion blockchain/state_manager/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// SPDX-License-Identifier: Apache-2.0, MIT

mod errors;

pub mod utils;
pub use self::errors::*;
use actor::{init, miner, power, ActorState, INIT_ACTOR_ADDR, STORAGE_POWER_ACTOR_ADDR};
use address::{Address, BLSPublicKey, Payload, BLS_PUB_LEN};
Expand Down
105 changes: 105 additions & 0 deletions blockchain/state_manager/src/utils.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
// Copyright 2020 ChainSafe Systems
// SPDX-License-Identifier: Apache-2.0, MIT

use crate::errors::*;
use crate::StateManager;
use actor::miner;
use address::{Address, Protocol};
use blockstore::BlockStore;
use cid::Cid;
use fil_types::{RegisteredProof, SectorInfo, SectorSize};
use filecoin_proofs_api::{post::generate_winning_post_sector_challenge, ProverId};

pub fn get_sectors_for_winning_post<DB>(
state_manager: &StateManager<DB>,
st: &Cid,
address: &Address,
rand: &[u8; 32],
) -> Result<Vec<SectorInfo>, Error>
where
DB: BlockStore,
{
let miner_actor_state: miner::State =
state_manager
.load_actor_state(&address, &st)
.map_err(|err| {
Error::State(format!(
"(get sectors) failed to load miner actor state: %{:}",
err
))
})?;
let sector_set = get_proving_set_raw(state_manager, &miner_actor_state)?;
if sector_set.is_empty() {
return Ok(Vec::new());
}
let seal_proof_type = match miner_actor_state.info.sector_size {
SectorSize::_2KiB => RegisteredProof::StackedDRG2KiBSeal,
SectorSize::_8MiB => RegisteredProof::StackedDRG8MiBSeal,
SectorSize::_512MiB => RegisteredProof::StackedDRG512MiBSeal,
SectorSize::_32GiB => RegisteredProof::StackedDRG32GiBSeal,
SectorSize::_64GiB => RegisteredProof::StackedDRG64GiBSeal,
};
let wpt = seal_proof_type.registered_winning_post_proof()?;

if address.protocol() != Protocol::ID {
return Err(Error::Other(format!(
"failed to get ID from miner address {:}",
address
)));
};
let mut prover_id = ProverId::default();
let prover_bytes = address.to_bytes();
prover_id[..prover_bytes.len()].copy_from_slice(&prover_bytes);
let ids = generate_winning_post_sector_challenge(
wpt.into(),
&rand,
sector_set.len() as u64,
prover_id,
)
.map_err(|err| Error::State(format!("generate winning posts challenge {:}", err)))?;

Ok(ids
.iter()
.map::<Result<SectorInfo, Error>, _>(|i: &u64| {
let index = *i as usize;
let sector_number = sector_set
.get(index)
.ok_or_else(|| {
Error::Other(format!("Could not get sector_number at index {:}", index))
})?
.info
.sector_number;
let sealed_cid = sector_set
.get(index)
.ok_or_else(|| {
Error::Other(format!("Could not get sealed cid at index {:}", index))
})?
.info
.sealed_cid
.clone();
Ok(SectorInfo {
proof: wpt,
sector_number,
sealed_cid,
})
})
.collect::<Result<Vec<SectorInfo>, _>>()?)
}

fn get_proving_set_raw<DB>(
state_manager: &StateManager<DB>,
actor_state: &miner::State,
) -> Result<Vec<miner::SectorOnChainInfo>, Error>
where
DB: BlockStore,
{
let mut not_proving = actor_state
.faults
.clone()
.merge(&actor_state.recoveries)
.map_err(|_| Error::Other("Could not merge bitfield".to_string()))?;

actor_state
.load_sector_infos(&*state_manager.get_block_store(), &mut not_proving)
.map_err(|err| Error::Other(format!("failed to get proving set :{:}", err)))
}
1 change: 1 addition & 0 deletions vm/runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,7 @@ pub trait Syscalls {

Ok(())
}

/// Verifies that two block headers provide proof of a consensus fault:
/// - both headers mined by the same actor
/// - headers are different
Expand Down