diff --git a/Cargo.lock b/Cargo.lock index 11b212ad47ed..675bbe41264f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5420,8 +5420,7 @@ dependencies = [ [[package]] name = "serde_cbor" version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e18acfa2f90e8b735b2836ab8d538de304cbb6729a7360729ea5a895d15a622" +source = "git+https://github.com/ChainSafe/cbor?rev=3e7bf81f57e9010762dbc12292bd6f927fdfe83a#3e7bf81f57e9010762dbc12292bd6f927fdfe83a" dependencies = [ "half", "serde", @@ -5430,7 +5429,8 @@ dependencies = [ [[package]] name = "serde_cbor" version = "0.11.1" -source = "git+https://github.com/ChainSafe/cbor?rev=3e7bf81f57e9010762dbc12292bd6f927fdfe83a#3e7bf81f57e9010762dbc12292bd6f927fdfe83a" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e18acfa2f90e8b735b2836ab8d538de304cbb6729a7360729ea5a895d15a622" dependencies = [ "half", "serde", diff --git a/utils/bitfield/Cargo.toml b/utils/bitfield/Cargo.toml index b9034808e09e..1a39b62a3bb7 100644 --- a/utils/bitfield/Cargo.toml +++ b/utils/bitfield/Cargo.toml @@ -12,6 +12,7 @@ unsigned-varint = "0.5" serde = { version = "1.0", features = ["derive"] } serde_bytes = "0.11.3" ahash = "0.5" +encoding = { package = "forest_encoding", path = "../../encoding" } [dev-dependencies] rand_xorshift = "0.2.0" diff --git a/utils/bitfield/src/lib.rs b/utils/bitfield/src/lib.rs index c82feef68253..8cb9c83aca57 100644 --- a/utils/bitfield/src/lib.rs +++ b/utils/bitfield/src/lib.rs @@ -3,6 +3,9 @@ pub mod iter; mod rleplus; +mod unvalidated; + +pub use unvalidated::{UnvalidatedBitField, Validate}; use ahash::AHashSet; use iter::{ranges_from_bits, RangeIterator}; @@ -13,7 +16,7 @@ use std::{ type Result = std::result::Result; -/// An bit field with buffered insertion/removal that serializes to/from RLE+. Similar to +/// A bit field with buffered insertion/removal that serializes to/from RLE+. Similar to /// `HashSet`, but more memory-efficient when long runs of 1s and 0s are present. #[derive(Debug, Default, Clone)] pub struct BitField { diff --git a/utils/bitfield/src/unvalidated.rs b/utils/bitfield/src/unvalidated.rs new file mode 100644 index 000000000000..28e01bca6519 --- /dev/null +++ b/utils/bitfield/src/unvalidated.rs @@ -0,0 +1,67 @@ +// Copyright 2020 ChainSafe Systems +// SPDX-License-Identifier: Apache-2.0, MIT + +use super::{BitField, Result}; +use encoding::serde_bytes; +use serde::{Deserialize, Deserializer, Serialize}; + +/// A trait for types that can produce a `&BitField` (or fail to do so). +/// Generalizes over `&BitField` and `&mut UnvalidatedBitField`. +pub trait Validate<'a> { + fn validate(self) -> Result<&'a BitField>; +} + +impl<'a> Validate<'a> for &'a mut UnvalidatedBitField { + /// Validates the RLE+ encoding of the bit field, returning a shared + /// reference to the decoded bit field. + fn validate(self) -> Result<&'a BitField> { + self.validate_mut().map(|bf| &*bf) + } +} + +impl<'a> Validate<'a> for &'a BitField { + fn validate(self) -> Result<&'a BitField> { + Ok(self) + } +} + +/// A bit field that may not yet have been validated for valid RLE+. +/// Used to defer this validation step until when the bit field is +/// first used, rather than at deserialization. +#[derive(Debug, Serialize)] +#[serde(untagged)] +pub enum UnvalidatedBitField { + Validated(BitField), + Unvalidated(#[serde(with = "serde_bytes")] Vec), +} + +impl UnvalidatedBitField { + /// Validates the RLE+ encoding of the bit field, returning a unique + /// reference to the decoded bit field. + pub fn validate_mut(&mut self) -> Result<&mut BitField> { + if let Self::Unvalidated(bytes) = self { + *self = Self::Validated(BitField::from_bytes(&bytes)?); + } + + match self { + Self::Validated(bf) => Ok(bf), + Self::Unvalidated(_) => unreachable!(), + } + } +} + +impl From for UnvalidatedBitField { + fn from(bf: BitField) -> Self { + Self::Validated(bf) + } +} + +impl<'de> Deserialize<'de> for UnvalidatedBitField { + fn deserialize(deserializer: D) -> std::result::Result + where + D: Deserializer<'de>, + { + let bytes: Vec = serde_bytes::deserialize(deserializer)?; + Ok(Self::Unvalidated(bytes)) + } +} diff --git a/vm/actor/src/builtin/miner/deadline_state.rs b/vm/actor/src/builtin/miner/deadline_state.rs index f2007fa1e622..d9f56d2a2af3 100644 --- a/vm/actor/src/builtin/miner/deadline_state.rs +++ b/vm/actor/src/builtin/miner/deadline_state.rs @@ -439,7 +439,7 @@ impl Deadline { store: &BS, sectors: &Sectors<'_, BS>, epoch: ChainEpoch, - partition_sectors: &PartitionSectorMap, + partition_sectors: &mut PartitionSectorMap, sector_size: SectorSize, quant: QuantSpec, ) -> Result> { @@ -611,7 +611,7 @@ impl Deadline { sector_size: SectorSize, quant: QuantSpec, fault_expiration_epoch: ChainEpoch, - partition_sectors: &PartitionSectorMap, + partition_sectors: &mut PartitionSectorMap, ) -> Result> { let mut partitions = self.partitions_amt(store)?; @@ -687,8 +687,8 @@ impl Deadline { store: &BS, sectors: &Sectors<'_, BS>, sector_size: SectorSize, - partition_sectors: &PartitionSectorMap, - ) -> Result<(), ActorError> { + partition_sectors: &mut PartitionSectorMap, + ) -> Result<(), Box> { let mut partitions = self.partitions_amt(store)?; for (partition_idx, sector_numbers) in partition_sectors.iter() { @@ -705,7 +705,7 @@ impl Deadline { partition .declare_faults_recovered(sectors, sector_size, sector_numbers) - .map_err(|e| e.wrap("failed to add recoveries"))?; + .map_err(|e| e.downcast_wrap("failed to add recoveries"))?; partitions.set(partition_idx, partition).map_err(|e| { e.downcast_default( @@ -870,7 +870,7 @@ impl Deadline { sector_size: SectorSize, quant: QuantSpec, fault_expiration: ChainEpoch, - post_partitions: &[PoStPartition], + post_partitions: &mut [PoStPartition], ) -> Result> { let mut partitions = self.partitions_amt(store)?; @@ -905,7 +905,7 @@ impl Deadline { sector_size, quant, fault_expiration, - &post.skipped, + &mut post.skipped, ) .map_err(|e| { e.wrap(format!( @@ -994,7 +994,7 @@ impl Deadline { store: &BS, sectors: &Sectors<'_, BS>, expiration: ChainEpoch, - partition_sectors: &PartitionSectorMap, + partition_sectors: &mut PartitionSectorMap, sector_size: SectorSize, quant: QuantSpec, ) -> Result<(), Box> { diff --git a/vm/actor/src/builtin/miner/mod.rs b/vm/actor/src/builtin/miner/mod.rs index ca766030cbbe..f600d78a86c4 100644 --- a/vm/actor/src/builtin/miner/mod.rs +++ b/vm/actor/src/builtin/miner/mod.rs @@ -51,7 +51,7 @@ use crate::{ ActorDowncast, }; use address::{Address, Payload, Protocol}; -use bitfield::BitField; +use bitfield::{BitField, UnvalidatedBitField, Validate}; use byteorder::{BigEndian, ByteOrder, WriteBytesExt}; use cid::{multihash::Blake2b256, Cid}; use clock::ChainEpoch; @@ -384,7 +384,7 @@ impl Actor { /// Invoked by miner's worker address to submit their fallback post fn submit_windowed_post( rt: &mut RT, - params: SubmitWindowedPoStParams, + mut params: SubmitWindowedPoStParams, ) -> Result<(), ActorError> where BS: BlockStore, @@ -514,7 +514,7 @@ impl Actor { info.sector_size, current_deadline.quant_spec(), fault_expiration, - ¶ms.partitions, + &mut params.partitions, ) .map_err(|e| { e.downcast_default( @@ -1279,7 +1279,7 @@ impl Actor { /// The sector's power is recomputed for the new expiration. fn extend_sector_expiration( rt: &mut RT, - params: ExtendSectorExpirationParams, + mut params: ExtendSectorExpirationParams, ) -> Result<(), ActorError> where BS: BlockStore, @@ -1298,7 +1298,7 @@ impl Actor { // https://github.com/filecoin-project/specs-actors/issues/416 let mut sector_count: u64 = 0; - for decl in ¶ms.extensions { + for decl in &mut params.extensions { if decl.deadline >= WPOST_PERIOD_DEADLINES { return Err(actor_error!( ErrIllegalArgument, @@ -1308,7 +1308,20 @@ impl Actor { )); } - match sector_count.checked_add(decl.sectors.len() as u64) { + let sectors = match decl.sectors.validate() { + Ok(sectors) => sectors, + Err(e) => { + return Err(actor_error!( + ErrIllegalArgument, + "failed to validate sectors for deadline {}, partition {}: {}", + decl.deadline, + decl.partition, + e + )) + } + }; + + match sector_count.checked_add(sectors.len() as u64) { Some(sum) => sector_count = sum, None => { return Err(actor_error!( @@ -1344,10 +1357,10 @@ impl Actor { .map_err(|e| e.wrap("failed to load deadlines"))?; // Group declarations by deadline, and remember iteration order. - let mut decls_by_deadline = HashMap::>::new(); + let mut decls_by_deadline = HashMap::>::new(); let mut deadlines_to_load = Vec::::new(); - for decl in ¶ms.extensions { + for decl in params.extensions { decls_by_deadline .entry(decl.deadline) .or_insert_with(|| { @@ -1378,7 +1391,7 @@ impl Actor { let quant = state.quant_spec_for_deadline(deadline_idx); - for &decl in &decls_by_deadline[&deadline_idx] { + for decl in decls_by_deadline.get_mut(&deadline_idx).unwrap() { let key = PartitionKey { deadline: deadline_idx, partition: decl.partition, @@ -1396,7 +1409,7 @@ impl Actor { .ok_or_else(|| actor_error!(ErrNotFound, "no such partition {:?}", key))?; let old_sectors = sectors - .load_sector(&decl.sectors) + .load_sector(&mut decl.sectors) .map_err(|e| e.wrap("failed to load sectors"))?; let new_sectors: Vec = old_sectors @@ -1841,10 +1854,10 @@ impl Actor { deadline .declare_faults_recovered(store, §ors, info.sector_size, partition_map) .map_err(|e| { - e.wrap(format!( - "failed to declare recoveries for deadline {}", - deadline_idx - )) + e.downcast_default( + ExitCode::ErrIllegalState, + format!("failed to declare recoveries for deadline {}", deadline_idx), + ) })?; deadlines @@ -1876,7 +1889,7 @@ impl Actor { /// May not be invoked if the deadline has any un-processed early terminations. fn compact_partitions( rt: &mut RT, - params: CompactPartitionsParams, + mut params: CompactPartitionsParams, ) -> Result<(), ActorError> where BS: BlockStore, @@ -1890,7 +1903,16 @@ impl Actor { )); } - let partition_count = params.partitions.len() as u64; + let partitions = params.partitions.validate().map_err(|e| { + actor_error!( + ErrIllegalArgument, + "failed to parse partitions bitfield: {}", + e + ) + })?; + let partition_count = partitions.len() as u64; + + let params_deadline = params.deadline; rt.transaction(|state: &mut State, rt| { let info = get_miner_info(rt, state)?; @@ -1903,11 +1925,11 @@ impl Actor { let store = rt.store(); - if !deadline_is_mutable(state.proving_period_start, params.deadline, rt.curr_epoch()) { + if !deadline_is_mutable(state.proving_period_start, params_deadline, rt.curr_epoch()) { return Err(actor_error!( ErrForbidden, "cannot compact deadline {} during its challenge window or the prior challenge window", - params.deadline + params_deadline )); } @@ -1922,25 +1944,25 @@ impl Actor { )); } - let quant = state.quant_spec_for_deadline(params.deadline); + let quant = state.quant_spec_for_deadline(params_deadline); let deadlines = state .load_deadlines(store) .map_err(|e| e.wrap("failed to load deadlines"))?; let mut deadline = deadlines - .load_deadline(store, params.deadline) + .load_deadline(store, params_deadline) .map_err(|e| { - e.wrap(format!("failed to load deadline {}", params.deadline)) + e.wrap(format!("failed to load deadline {}", params_deadline)) })?; let (live, dead, removed_power) = deadline - .remove_partitions(store, ¶ms.partitions, quant) + .remove_partitions(store, partitions, quant) .map_err(|e| { e.downcast_default( ExitCode::ErrIllegalState, format!( "failed to remove partitions from deadline {}", - params.deadline + params_deadline ), ) })?; @@ -1994,14 +2016,18 @@ impl Actor { /// 99 can be masked out to collapse these two ranges into one. fn compact_sector_numbers( rt: &mut RT, - params: CompactSectorNumbersParams, + mut params: CompactSectorNumbersParams, ) -> Result<(), ActorError> where BS: BlockStore, RT: Runtime, { - let last_sector_number = params + let mask_sector_numbers = params .mask_sector_numbers + .validate() + .map_err(|e| actor_error!(ErrIllegalArgument, "invalid mask bitfield: {}", e))?; + + let last_sector_number = mask_sector_numbers .iter() .last() .ok_or_else(|| actor_error!(ErrIllegalArgument, "invalid mask bitfield"))? @@ -2025,7 +2051,7 @@ impl Actor { .chain(&[info.worker, info.owner]), )?; - state.mask_sector_number(rt.store(), ¶ms.mask_sector_numbers) + state.mask_sector_numbers(rt.store(), mask_sector_numbers) })?; Ok(()) @@ -3272,13 +3298,17 @@ fn validate_fr_declaration_deadline(deadline: &DeadlineInfo) -> Result<(), Strin /// Validates that a partition contains the given sectors. fn validate_partition_contains_sectors( partition: &Partition, - sectors: &BitField, -) -> Result<(), &'static str> { + sectors: &mut UnvalidatedBitField, +) -> Result<(), String> { + let sectors = sectors + .validate() + .map_err(|e| format!("failed to check sectors: {}", e))?; + // Check that the declared sectors are actually assigned to the partition. if partition.sectors.contains_all(sectors) { Ok(()) } else { - Err("not all sectors are assigned to the partition") + Err("not all sectors are assigned to the partition".to_string()) } } diff --git a/vm/actor/src/builtin/miner/partition_state.rs b/vm/actor/src/builtin/miner/partition_state.rs index 29b4ea5a529c..54d5b9931884 100644 --- a/vm/actor/src/builtin/miner/partition_state.rs +++ b/vm/actor/src/builtin/miner/partition_state.rs @@ -6,7 +6,7 @@ use super::{ ExpirationSet, SectorOnChainInfo, Sectors, TerminationResult, }; use crate::{actor_error, ActorDowncast}; -use bitfield::BitField; +use bitfield::{BitField, UnvalidatedBitField, Validate}; use cid::Cid; use clock::ChainEpoch; use encoding::tuple::*; @@ -161,7 +161,7 @@ impl Partition { &mut self, store: &BS, sectors: &Sectors<'_, BS>, - sector_numbers: &BitField, + sector_numbers: &mut UnvalidatedBitField, fault_expiration_epoch: ChainEpoch, sector_size: SectorSize, quant: QuantSpec, @@ -169,6 +169,10 @@ impl Partition { validate_partition_contains_sectors(&self, sector_numbers) .map_err(|e| actor_error!(ErrIllegalArgument; "failed fault declaration: {}", e))?; + let sector_numbers = sector_numbers + .validate() + .map_err(|e| format!("failed to intersect sectors with recoveries: {}", e))?; + // Split declarations into declarations of new faults, and retraction of declared recoveries. let retracted_recoveries = &self.recoveries & sector_numbers; let mut new_faults = sector_numbers - &retracted_recoveries; @@ -244,12 +248,16 @@ impl Partition { &mut self, sectors: &Sectors<'_, BS>, sector_size: SectorSize, - sector_numbers: &BitField, - ) -> Result<(), ActorError> { + sector_numbers: &mut UnvalidatedBitField, + ) -> Result<(), Box> { // Check that the declared sectors are actually assigned to the partition. validate_partition_contains_sectors(self, sector_numbers) .map_err(|e| actor_error!(ErrIllegalArgument; "failed fault declaration: {}", e))?; + let sector_numbers = sector_numbers + .validate() + .map_err(|e| format!("failed to validate recoveries: {}", e))?; + // Ignore sectors not faulty or already declared recovered let mut recoveries = sector_numbers & &self.faults; recoveries -= &self.recoveries; @@ -296,12 +304,14 @@ impl Partition { store: &BS, sectors: &Sectors<'_, BS>, new_expiration: ChainEpoch, - sector_numbers: &BitField, + sector_numbers: &mut UnvalidatedBitField, sector_size: SectorSize, quant: QuantSpec, ) -> Result> { + let sector_numbers = sector_numbers.validate()?; + // Ensure these sectors actually belong to this partition. - let present = sector_numbers & &self.sectors; + let present = &*sector_numbers & &self.sectors; // Filter out terminated sectors. let live = &present - &self.terminated; @@ -396,11 +406,19 @@ impl Partition { store: &BS, sectors: &Sectors<'_, BS>, epoch: ChainEpoch, - sector_numbers: &BitField, + sector_numbers: &mut UnvalidatedBitField, sector_size: SectorSize, quant: QuantSpec, ) -> Result> { let live_sectors = self.live_sectors(); + let sector_numbers = sector_numbers.validate().map_err(|e| { + actor_error!( + ErrIllegalArgument, + "failed to validate terminating sectors: {}", + e + ) + })?; + if live_sectors.contains_all(sector_numbers) { return Err(actor_error!(ErrIllegalArgument; "can only terminate live sectors").into()); } @@ -599,14 +617,22 @@ impl Partition { sector_size: SectorSize, quant: QuantSpec, fault_expiration: ChainEpoch, - skipped: &BitField, + skipped: &mut UnvalidatedBitField, ) -> Result<(PowerPair, PowerPair), ActorError> { + let skipped = skipped.validate().map_err(|e| { + actor_error!( + ErrIllegalArgument, + "failed to validate skipped sectors: {}", + e + ) + })?; + if skipped.is_empty() { return Ok((PowerPair::zero(), PowerPair::zero())); } // Check that the declared sectors are actually in the partition. - if !self.sectors.contains_all(skipped) { + if !self.sectors.contains_all(&skipped) { return Err( actor_error!(ErrIllegalArgument; "skipped faults contains sectors outside partition"), ); @@ -620,7 +646,7 @@ impl Partition { let retracted_recovery_power = power_for_sectors(sector_size, &retracted_recovery_sectors); // Ignore skipped faults that are already faults or terminated. - let new_faults = &(skipped - &self.terminated) - &self.faults; + let new_faults = &(&*skipped - &self.terminated) - &self.faults; let new_fault_sectors = sectors .load_sector(&new_faults) .map_err(|e| e.wrap("failed to load sectors"))?; diff --git a/vm/actor/src/builtin/miner/sector_map.rs b/vm/actor/src/builtin/miner/sector_map.rs index 3c161582cf8a..1b05c2c1a246 100644 --- a/vm/actor/src/builtin/miner/sector_map.rs +++ b/vm/actor/src/builtin/miner/sector_map.rs @@ -2,7 +2,7 @@ // SPDX-License-Identifier: Apache-2.0, MIT use super::WPOST_PERIOD_DEADLINES; -use bitfield::BitField; +use bitfield::{BitField, UnvalidatedBitField, Validate}; use std::collections::HashMap; /// Maps deadlines to partition maps. @@ -17,7 +17,7 @@ impl DeadlineSectorMap { /// Check validates all bitfields and counts the number of partitions & sectors /// contained within the map, and returns an error if they exceed the given /// maximums. - pub fn check(&self, max_partitions: u64, max_sectors: u64) -> Result<(), String> { + pub fn check(&mut self, max_partitions: u64, max_sectors: u64) -> Result<(), String> { let (partition_count, sector_count) = self .count() .map_err(|e| format!("failed to count sectors: {:?}", e))?; @@ -40,8 +40,8 @@ impl DeadlineSectorMap { } /// Counts the number of partitions & sectors within the map. - pub fn count(&self) -> Result<(/* partitions */ u64, /* sectors */ u64), String> { - self.0.iter().try_fold( + pub fn count(&mut self) -> Result<(/* partitions */ u64, /* sectors */ u64), String> { + self.0.iter_mut().try_fold( (0_u64, 0_u64), |(partitions, sectors), (deadline_idx, pm)| { let (partition_count, sector_count) = pm @@ -64,7 +64,7 @@ impl DeadlineSectorMap { &mut self, deadline_idx: u64, partition_idx: u64, - sector_numbers: BitField, + sector_numbers: UnvalidatedBitField, ) -> Result<(), String> { if deadline_idx >= WPOST_PERIOD_DEADLINES { return Err(format!("invalid deadline {}", deadline_idx)); @@ -73,9 +73,7 @@ impl DeadlineSectorMap { self.0 .entry(deadline_idx) .or_default() - .add(partition_idx, sector_numbers); - - Ok(()) + .add(partition_idx, sector_numbers) } /// Records the given sectors at the given deadline/partition index. @@ -88,7 +86,11 @@ impl DeadlineSectorMap { self.add( deadline_idx, partition_idx, - sector_numbers.iter().map(|&i| i as usize).collect(), + sector_numbers + .iter() + .map(|&i| i as usize) + .collect::() + .into(), ) } @@ -100,41 +102,71 @@ impl DeadlineSectorMap { } /// Walks the deadlines in deadline order. - pub fn iter(&self) -> impl Iterator + '_ { - self.deadlines().into_iter().map(move |i| (i, &self.0[&i])) + pub fn iter(&mut self) -> impl Iterator + '_ { + let mut vec: Vec<_> = self.0.iter_mut().map(|(&i, x)| (i, x)).collect(); + vec.sort_unstable_by_key(|&(i, _)| i); + vec.into_iter() } } /// Maps partitions to sector bitfields. #[derive(Default)] -pub struct PartitionSectorMap(HashMap); +pub struct PartitionSectorMap(HashMap); impl PartitionSectorMap { /// Records the given sectors at the given partition. - pub fn add_values(&mut self, partition_idx: u64, sector_numbers: Vec) { + pub fn add_values( + &mut self, + partition_idx: u64, + sector_numbers: Vec, + ) -> Result<(), String> { self.add( partition_idx, - sector_numbers.into_iter().map(|i| i as usize).collect(), - ); + sector_numbers + .into_iter() + .map(|i| i as usize) + .collect::() + .into(), + ) } /// Records the given sector bitfield at the given partition index, merging /// it with any existing bitfields if necessary. - pub fn add(&mut self, partition_idx: u64, sector_numbers: BitField) { - self.0 - .entry(partition_idx) - .and_modify(|old_sector_numbers| *old_sector_numbers |= §or_numbers) - .or_insert(sector_numbers); + pub fn add( + &mut self, + partition_idx: u64, + mut sector_numbers: UnvalidatedBitField, + ) -> Result<(), String> { + match self.0.get_mut(&partition_idx) { + Some(old_sector_numbers) => { + let old = old_sector_numbers + .validate_mut() + .map_err(|e| format!("failed to validate sector bitfield: {}", e))?; + let new = sector_numbers + .validate() + .map_err(|e| format!("failed to validate new sector bitfield: {}", e))?; + *old |= new; + } + None => { + self.0.insert(partition_idx, sector_numbers); + } + } + Ok(()) } /// Counts the number of partitions & sectors within the map. - pub fn count(&self) -> Result<(/* partitions */ u64, /* sectors */ u64), String> { + pub fn count(&mut self) -> Result<(/* partitions */ u64, /* sectors */ u64), String> { let sectors = self .0 - .values() - .map(|bf| bf.len()) - .try_fold(0_u64, |sectors, count| { + .iter_mut() + .try_fold(0_u64, |sectors, (partition_idx, bf)| { + let validated = bf.validate().map_err(|e| { + format!( + "failed to parse bitmap for partition {}: {}", + partition_idx, e + ) + })?; sectors - .checked_add(count as u64) + .checked_add(validated.len() as u64) .ok_or_else(|| "integer overflow when counting sectors".to_string()) })?; Ok((self.0.len() as u64, sectors)) @@ -148,8 +180,10 @@ impl PartitionSectorMap { } /// Walks the partitions in the map, in order of increasing index. - pub fn iter(&self) -> impl Iterator + '_ { - self.partitions().into_iter().map(move |i| (i, &self.0[&i])) + pub fn iter(&mut self) -> impl Iterator + '_ { + let mut vec: Vec<_> = self.0.iter_mut().map(|(&i, x)| (i, x)).collect(); + vec.sort_unstable_by_key(|&(i, _)| i); + vec.into_iter() } pub fn len(&self) -> usize { diff --git a/vm/actor/src/builtin/miner/sectors.rs b/vm/actor/src/builtin/miner/sectors.rs index 101273c2a4a4..a0efae7afeb8 100644 --- a/vm/actor/src/builtin/miner/sectors.rs +++ b/vm/actor/src/builtin/miner/sectors.rs @@ -3,7 +3,6 @@ use super::SectorOnChainInfo; use crate::{actor_error, ActorDowncast, ActorError, ExitCode}; -use bitfield::BitField; use cid::Cid; use fil_types::{SectorNumber, MAX_SECTOR_NUMBER}; use ipld_amt::{Amt, Error as AmtError}; @@ -21,10 +20,21 @@ impl<'db, BS: BlockStore> Sectors<'db, BS> { }) } - pub fn load_sector( + pub fn load_sector<'a>( &self, - sector_numbers: &BitField, + sector_numbers: impl bitfield::Validate<'a>, ) -> Result, ActorError> { + let sector_numbers = match sector_numbers.validate() { + Ok(sector_numbers) => sector_numbers, + Err(e) => { + return Err(actor_error!( + ErrIllegalArgument, + "failed to load sectors: {}", + e + )) + } + }; + let mut sector_infos: Vec = Vec::new(); for sector_number in sector_numbers.iter() { let sector_on_chain = self diff --git a/vm/actor/src/builtin/miner/state.rs b/vm/actor/src/builtin/miner/state.rs index 6a02d1be205f..1ff510e5482c 100644 --- a/vm/actor/src/builtin/miner/state.rs +++ b/vm/actor/src/builtin/miner/state.rs @@ -200,7 +200,7 @@ impl State { Ok(()) } - pub fn mask_sector_number( + pub fn mask_sector_numbers( &mut self, store: &BS, sector_numbers: &BitField, @@ -399,7 +399,7 @@ impl State { store: &BS, current_epoch: ChainEpoch, sector_size: SectorSize, - deadline_sectors: DeadlineSectorMap, + mut deadline_sectors: DeadlineSectorMap, ) -> Result<(), Box> { let mut deadlines = self.load_deadlines(store)?; let sectors = Sectors::load(store, &self.sectors)?; diff --git a/vm/actor/src/builtin/miner/types.rs b/vm/actor/src/builtin/miner/types.rs index d7ff2c5f7d19..9fb095352c2f 100644 --- a/vm/actor/src/builtin/miner/types.rs +++ b/vm/actor/src/builtin/miner/types.rs @@ -3,7 +3,7 @@ use crate::DealWeight; use address::Address; -use bitfield::BitField; +use bitfield::UnvalidatedBitField; use cid::Cid; use clock::ChainEpoch; use encoding::{serde_bytes, tuple::*, BytesDe}; @@ -74,7 +74,7 @@ pub struct PoStPartition { /// Partitions are numbered per-deadline, from zero. pub index: u64, /// Sectors skipped while proving that weren't already declared faulty. - pub skipped: BitField, + pub skipped: UnvalidatedBitField, } /// Information submitted by a miner to provide a Window PoSt. @@ -114,7 +114,7 @@ pub struct ExtendSectorExpirationParams { pub struct ExpirationExtension { pub deadline: u64, pub partition: u64, - pub sectors: BitField, + pub sectors: UnvalidatedBitField, pub new_expiration: ChainEpoch, } @@ -127,7 +127,7 @@ pub struct TerminateSectorsParams { pub struct TerminationDeclaration { pub deadline: u64, pub partition: u64, - pub sectors: BitField, + pub sectors: UnvalidatedBitField, } #[derive(Serialize_tuple, Deserialize_tuple)] @@ -152,7 +152,7 @@ pub struct FaultDeclaration { /// Partition index within the deadline containing the faulty sectors. pub partition: u64, /// Sectors in the partition being declared faulty. - pub sectors: BitField, + pub sectors: UnvalidatedBitField, } #[derive(Serialize_tuple, Deserialize_tuple)] @@ -167,18 +167,18 @@ pub struct RecoveryDeclaration { /// Partition index within the deadline containing the recovered sectors. pub partition: u64, /// Sectors in the partition being declared recovered. - pub sectors: BitField, + pub sectors: UnvalidatedBitField, } #[derive(Serialize_tuple, Deserialize_tuple)] pub struct CompactPartitionsParams { pub deadline: u64, - pub partitions: BitField, + pub partitions: UnvalidatedBitField, } #[derive(Serialize_tuple, Deserialize_tuple)] pub struct CompactSectorNumbersParams { - pub mask_sector_numbers: BitField, + pub mask_sector_numbers: UnvalidatedBitField, } #[derive(Serialize_tuple, Deserialize_tuple)]