Skip to content

Commit a5254e3

Browse files
convert fvm and update type bounds accordingly
1 parent d730baa commit a5254e3

File tree

13 files changed

+156
-115
lines changed

13 files changed

+156
-115
lines changed

fvm/src/blockstore/buffered.rs

Lines changed: 62 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
// Copyright 2019-2022 ChainSafe Systems
22
// SPDX-License-Identifier: Apache-2.0, MIT
33

4-
use anyhow::{anyhow, Result};
54
use byteorder::{BigEndian, ByteOrder, ReadBytesExt};
65
use cid::Cid;
76
use fvm_ipld_blockstore::{Blockstore, Buffered};
@@ -38,33 +37,72 @@ where
3837
}
3938
}
4039

40+
#[derive(thiserror::Error, Debug)]
41+
pub enum Error<E> {
42+
#[error("flush: {0}")]
43+
Flush(#[from] FlushError),
44+
#[error("blockstore: {0}")]
45+
Blockstore(E),
46+
}
47+
4148
impl<BS> Buffered for BufferedBlockstore<BS>
4249
where
4350
BS: Blockstore,
4451
{
4552
/// Flushes the buffered cache based on the root node.
4653
/// This will recursively traverse the cache and write all data connected by links to this
4754
/// root Cid.
48-
fn flush(&self, root: &Cid) -> Result<()> {
55+
fn flush(&self, root: &Cid) -> Result<(), Error<BS::Error>> {
4956
let mut buffer = Vec::new();
5057
let mut s = self.write.borrow_mut();
5158
copy_rec(&s, *root, &mut buffer)?;
5259

53-
self.base.put_many_keyed(buffer)?;
60+
self.base
61+
.put_many_keyed(buffer)
62+
.map_err(Error::Blockstore)?;
5463
*s = Default::default();
5564

5665
Ok(())
5766
}
5867
}
5968

69+
#[derive(thiserror::Error, Debug)]
70+
pub enum FlushError {
71+
#[error("io: {0}")]
72+
Io(#[from] std::io::Error),
73+
#[error("cid: {0}")]
74+
Cid(#[from] cid::Error),
75+
#[error("cbor input was not canonical (lval 24 with value < 24)")]
76+
HeaderLval24,
77+
#[error("cbor input was not canonical (lval 25 with value <= MaxUint8)")]
78+
HeaderLval25,
79+
#[error("cbor input was not canonical (lval 26 with value <= MaxUint16)")]
80+
HeaderLval26,
81+
#[error("cbor input was not canonical (lval 27 with value <= MaxUint32)")]
82+
HeaderLval27,
83+
#[error("invalid header cbor_read_header_buf")]
84+
HeaderInvalid,
85+
#[error("expected cbor type byte string in input")]
86+
UnexpectedByteString,
87+
#[error("string in cbor input too long")]
88+
StringTooLong,
89+
#[error("Invalid link ({0}) in flushing buffered store")]
90+
InvalidLink(Cid),
91+
#[error("unhandled cbor type: {0}")]
92+
UnhandledCborType(u8),
93+
}
94+
6095
/// Given a CBOR encoded Buffer, returns a tuple of:
6196
/// the type of the CBOR object along with extra
6297
/// elements we expect to read. More info on this can be found in
6398
/// Appendix C. of RFC 7049 which defines the CBOR specification.
6499
/// This was implemented because the CBOR library we use does not expose low
65100
/// methods like this, requiring us to deserialize the whole CBOR payload, which
66101
/// is unnecessary and quite inefficient for our usecase here.
67-
fn cbor_read_header_buf<B: Read>(br: &mut B, scratch: &mut [u8]) -> anyhow::Result<(u8, usize)> {
102+
fn cbor_read_header_buf<B: Read>(
103+
br: &mut B,
104+
scratch: &mut [u8],
105+
) -> Result<(u8, usize), FlushError> {
68106
let first = br.read_u8()?;
69107
let maj = (first & 0xe0) >> 5;
70108
let low = first & 0x1f;
@@ -74,49 +112,41 @@ fn cbor_read_header_buf<B: Read>(br: &mut B, scratch: &mut [u8]) -> anyhow::Resu
74112
} else if low == 24 {
75113
let val = br.read_u8()?;
76114
if val < 24 {
77-
return Err(anyhow!(
78-
"cbor input was not canonical (lval 24 with value < 24)"
79-
));
115+
return Err(FlushError::HeaderLval24);
80116
}
81117
Ok((maj, val as usize))
82118
} else if low == 25 {
83119
br.read_exact(&mut scratch[..2])?;
84120
let val = BigEndian::read_u16(&scratch[..2]);
85121
if val <= u8::MAX as u16 {
86-
return Err(anyhow!(
87-
"cbor input was not canonical (lval 25 with value <= MaxUint8)"
88-
));
122+
return Err(FlushError::HeaderLval25);
89123
}
90124
Ok((maj, val as usize))
91125
} else if low == 26 {
92126
br.read_exact(&mut scratch[..4])?;
93127
let val = BigEndian::read_u32(&scratch[..4]);
94128
if val <= u16::MAX as u32 {
95-
return Err(anyhow!(
96-
"cbor input was not canonical (lval 26 with value <= MaxUint16)"
97-
));
129+
return Err(FlushError::HeaderLval26);
98130
}
99131
Ok((maj, val as usize))
100132
} else if low == 27 {
101133
br.read_exact(&mut scratch[..8])?;
102134
let val = BigEndian::read_u64(&scratch[..8]);
103135
if val <= u32::MAX as u64 {
104-
return Err(anyhow!(
105-
"cbor input was not canonical (lval 27 with value <= MaxUint32)"
106-
));
136+
return Err(FlushError::HeaderLval27);
107137
}
108138
Ok((maj, val as usize))
109139
} else {
110-
Err(anyhow!("invalid header cbor_read_header_buf"))
140+
Err(FlushError::HeaderInvalid)
111141
}
112142
}
113143

114144
/// Given a CBOR serialized IPLD buffer, read through all of it and return all the Links.
115145
/// This function is useful because it is quite a bit more fast than doing this recursively on a
116146
/// deserialized IPLD object.
117-
fn scan_for_links<B: Read + Seek, F>(buf: &mut B, mut callback: F) -> Result<()>
147+
fn scan_for_links<B: Read + Seek, F>(buf: &mut B, mut callback: F) -> Result<(), FlushError>
118148
where
119-
F: FnMut(Cid) -> anyhow::Result<()>,
149+
F: FnMut(Cid) -> Result<(), FlushError>,
120150
{
121151
let mut scratch: [u8; 100] = [0; 100];
122152
let mut remaining = 1;
@@ -136,10 +166,10 @@ where
136166
let (maj, extra) = cbor_read_header_buf(buf, &mut scratch)?;
137167
// The actual CID is expected to be a byte string
138168
if maj != 2 {
139-
return Err(anyhow!("expected cbor type byte string in input"));
169+
return Err(FlushError::UnexpectedByteString);
140170
}
141171
if extra > 100 {
142-
return Err(anyhow!("string in cbor input too long"));
172+
return Err(FlushError::StringTooLong);
143173
}
144174
buf.read_exact(&mut scratch[..extra])?;
145175
let c = Cid::try_from(&scratch[1..extra])?;
@@ -157,7 +187,7 @@ where
157187
remaining += extra * 2;
158188
}
159189
_ => {
160-
return Err(anyhow!("unhandled cbor type: {}", maj));
190+
return Err(FlushError::UnhandledCborType(maj));
161191
}
162192
}
163193
remaining -= 1;
@@ -170,16 +200,14 @@ fn copy_rec<'a>(
170200
cache: &'a HashMap<Cid, Vec<u8>>,
171201
root: Cid,
172202
buffer: &mut Vec<(Cid, &'a [u8])>,
173-
) -> Result<()> {
203+
) -> Result<(), FlushError> {
174204
// TODO: Make this non-recursive.
175205
// Skip identity and Filecoin commitment Cids
176206
if root.codec() != DAG_CBOR {
177207
return Ok(());
178208
}
179209

180-
let block = &*cache
181-
.get(&root)
182-
.ok_or_else(|| anyhow!("Invalid link ({}) in flushing buffered store", root))?;
210+
let block = &*cache.get(&root).ok_or(FlushError::InvalidLink(root))?;
183211

184212
scan_for_links(&mut Cursor::new(block), |link| {
185213
if link.codec() != DAG_CBOR {
@@ -205,28 +233,30 @@ impl<BS> Blockstore for BufferedBlockstore<BS>
205233
where
206234
BS: Blockstore,
207235
{
208-
fn get(&self, cid: &Cid) -> Result<Option<Vec<u8>>> {
236+
type Error = Error<BS::Error>;
237+
238+
fn get(&self, cid: &Cid) -> Result<Option<Vec<u8>>, Self::Error> {
209239
Ok(if let Some(data) = self.write.borrow().get(cid) {
210240
Some(data.clone())
211241
} else {
212-
self.base.get(cid)?
242+
self.base.get(cid).map_err(Error::Blockstore)?
213243
})
214244
}
215245

216-
fn put_keyed(&self, cid: &Cid, buf: &[u8]) -> Result<()> {
246+
fn put_keyed(&self, cid: &Cid, buf: &[u8]) -> Result<(), Self::Error> {
217247
self.write.borrow_mut().insert(*cid, Vec::from(buf));
218248
Ok(())
219249
}
220250

221-
fn has(&self, k: &Cid) -> Result<bool> {
251+
fn has(&self, k: &Cid) -> Result<bool, Self::Error> {
222252
if self.write.borrow().contains_key(k) {
223253
Ok(true)
224254
} else {
225-
Ok(self.base.has(k)?)
255+
Ok(self.base.has(k).map_err(Error::Blockstore)?)
226256
}
227257
}
228258

229-
fn put_many_keyed<D, I>(&self, blocks: I) -> Result<()>
259+
fn put_many_keyed<D, I>(&self, blocks: I) -> Result<(), Self::Error>
230260
where
231261
Self: Sized,
232262
D: AsRef<[u8]>,

ipld/amt/benches/amt_benchmark.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,9 @@ fn for_each(c: &mut Criterion) {
117117
c.bench_function("AMT for_each function", |b| {
118118
b.iter(|| {
119119
let a = Amt::load(&cid, &db).unwrap();
120-
black_box(a).for_each(|_, _v: &u64| Ok(())).unwrap();
120+
black_box(a)
121+
.for_each(|_, _v: &u64| Ok::<_, ()>(()))
122+
.unwrap();
121123
})
122124
});
123125
}

ipld/amt/src/amt.rs

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ where
7272
}
7373

7474
/// Constructs an AMT with a blockstore and a Cid of the root of the AMT
75-
pub fn load(cid: &Cid, block_store: BS) -> Result<Self, Error<BS>> {
75+
pub fn load(cid: &Cid, block_store: BS) -> Result<Self, Error<BS::Error>> {
7676
// Load root bytes from database
7777
let root: Root<V> = block_store
7878
.get_cbor(cid)?
@@ -100,7 +100,7 @@ where
100100
pub fn new_from_iter(
101101
block_store: BS,
102102
vals: impl IntoIterator<Item = V>,
103-
) -> Result<Cid, Error<BS>> {
103+
) -> Result<Cid, Error<BS::Error>> {
104104
let mut t = Self::new(block_store);
105105

106106
t.batch_set(vals)?;
@@ -109,7 +109,7 @@ where
109109
}
110110

111111
/// Get value at index of AMT
112-
pub fn get(&self, i: u64) -> Result<Option<&V>, Error<BS>> {
112+
pub fn get(&self, i: u64) -> Result<Option<&V>, Error<BS::Error>> {
113113
if i > MAX_INDEX {
114114
return Err(Error::OutOfRange(i));
115115
}
@@ -124,7 +124,7 @@ where
124124
}
125125

126126
/// Set value at index
127-
pub fn set(&mut self, i: u64, val: V) -> Result<(), Error<BS>> {
127+
pub fn set(&mut self, i: u64, val: V) -> Result<(), Error<BS::Error>> {
128128
if i > MAX_INDEX {
129129
return Err(Error::OutOfRange(i));
130130
}
@@ -166,7 +166,7 @@ where
166166

167167
/// Batch set (naive for now)
168168
// TODO Implement more efficient batch set to not have to traverse tree and keep cache for each
169-
pub fn batch_set(&mut self, vals: impl IntoIterator<Item = V>) -> Result<(), Error<BS>> {
169+
pub fn batch_set(&mut self, vals: impl IntoIterator<Item = V>) -> Result<(), Error<BS::Error>> {
170170
for (i, val) in (0u64..).zip(vals) {
171171
self.set(i, val)?;
172172
}
@@ -175,7 +175,7 @@ where
175175
}
176176

177177
/// Delete item from AMT at index
178-
pub fn delete(&mut self, i: u64) -> Result<Option<V>, Error<BS>> {
178+
pub fn delete(&mut self, i: u64) -> Result<Option<V>, Error<BS::Error>> {
179179
if i > MAX_INDEX {
180180
return Err(Error::OutOfRange(i));
181181
}
@@ -246,7 +246,7 @@ where
246246
&mut self,
247247
iter: impl IntoIterator<Item = u64>,
248248
strict: bool,
249-
) -> Result<bool, Error<BS>> {
249+
) -> Result<bool, Error<BS::Error>> {
250250
// TODO: optimize this
251251
let mut modified = false;
252252

@@ -262,7 +262,7 @@ where
262262
}
263263

264264
/// flush root and return Cid used as key in block store
265-
pub fn flush(&mut self) -> Result<Cid, Error<BS>> {
265+
pub fn flush(&mut self) -> Result<Cid, Error<BS::Error>> {
266266
self.root.node.flush(&self.block_store)?;
267267
Ok(self.block_store.put_cbor(&self.root, Code::Blake2b256)?)
268268
}
@@ -291,7 +291,7 @@ where
291291
/// assert_eq!(&values, &[(1, "One".to_owned()), (4, "Four".to_owned())]);
292292
/// ```
293293
#[inline]
294-
pub fn for_each<F, U>(&self, mut f: F) -> Result<(), EitherError<U, BS>>
294+
pub fn for_each<F, U>(&self, mut f: F) -> Result<(), EitherError<U, BS::Error>>
295295
where
296296
F: FnMut(u64, &V) -> Result<(), U>,
297297
{
@@ -303,7 +303,7 @@ where
303303

304304
/// Iterates over each value in the Amt and runs a function on the values, for as long as that
305305
/// function keeps returning `true`.
306-
pub fn for_each_while<F, U>(&self, mut f: F) -> Result<(), EitherError<U, BS>>
306+
pub fn for_each_while<F, U>(&self, mut f: F) -> Result<(), EitherError<U, BS::Error>>
307307
where
308308
F: FnMut(u64, &V) -> Result<bool, U>,
309309
{
@@ -321,7 +321,7 @@ where
321321

322322
/// Iterates over each value in the Amt and runs a function on the values that allows modifying
323323
/// each value.
324-
pub fn for_each_mut<F, U>(&mut self, mut f: F) -> Result<(), EitherError<U, BS>>
324+
pub fn for_each_mut<F, U>(&mut self, mut f: F) -> Result<(), EitherError<U, BS::Error>>
325325
where
326326
V: Clone,
327327
F: FnMut(u64, &mut ValueMut<'_, V>) -> Result<(), U>,
@@ -334,7 +334,7 @@ where
334334

335335
/// Iterates over each value in the Amt and runs a function on the values that allows modifying
336336
/// each value, for as long as that function keeps returning `true`.
337-
pub fn for_each_while_mut<F, U>(&mut self, mut f: F) -> Result<(), EitherError<U, BS>>
337+
pub fn for_each_while_mut<F, U>(&mut self, mut f: F) -> Result<(), EitherError<U, BS::Error>>
338338
where
339339
// TODO remove clone bound when go-interop doesn't require it.
340340
// (If needed without, this bound can be removed by duplicating function signatures)

ipld/amt/src/error.rs

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,12 @@
22
// SPDX-License-Identifier: Apache-2.0, MIT
33

44
use cid::Error as CidError;
5-
use fvm_ipld_blockstore::Blockstore;
65
use fvm_ipld_encoding::{CborStoreError, Error as EncodingError};
76
use thiserror::Error;
87

98
/// AMT Error
109
#[derive(Debug, Error)]
11-
pub enum Error<BS: Blockstore> {
10+
pub enum Error<E> {
1211
/// Index referenced it above arbitrary max set
1312
#[error("index {0} out of range for the amt")]
1413
OutOfRange(u64),
@@ -29,13 +28,13 @@ pub enum Error<BS: Blockstore> {
2928
#[error("no such index {0} in Amt for batch delete")]
3029
BatchDelteNotFound(u64),
3130
#[error("blockstore {0}")]
32-
Blockstore(BS::Error),
31+
Blockstore(E),
3332
#[error("encoding error {0}")]
3433
Encoding(#[from] EncodingError),
3534
}
3635

37-
impl<BS: Blockstore> From<CborStoreError<BS>> for Error<BS> {
38-
fn from(err: CborStoreError<BS>) -> Self {
36+
impl<E> From<CborStoreError<E>> for Error<E> {
37+
fn from(err: CborStoreError<E>) -> Self {
3938
match err {
4039
CborStoreError::Blockstore(err) => Error::Blockstore(err),
4140
CborStoreError::Encoding(err) => Error::Encoding(err),
@@ -44,15 +43,15 @@ impl<BS: Blockstore> From<CborStoreError<BS>> for Error<BS> {
4443
}
4544

4645
#[derive(Debug, Error)]
47-
pub enum EitherError<U, BS: Blockstore> {
46+
pub enum EitherError<U, E> {
4847
#[error("user: {0}")]
4948
User(U),
5049
#[error("hamt: {0}")]
51-
Hamt(#[from] Error<BS>),
50+
Hamt(#[from] Error<E>),
5251
}
5352

54-
impl<U, BS: Blockstore> From<CborStoreError<BS>> for EitherError<U, BS> {
55-
fn from(err: CborStoreError<BS>) -> Self {
53+
impl<U, E> From<CborStoreError<E>> for EitherError<U, E> {
54+
fn from(err: CborStoreError<E>) -> Self {
5655
EitherError::Hamt(err.into())
5756
}
5857
}

0 commit comments

Comments
 (0)