Skip to content

Commit c16902e

Browse files
authored
Merge pull request #2 from tablelandnetwork/carson/hamt
Basic Objectstore Actor with S3-inspired API and basic tests
2 parents 70709ad + 186a913 commit c16902e

File tree

5 files changed

+267
-88
lines changed

5 files changed

+267
-88
lines changed

Cargo.lock

Lines changed: 1 addition & 19 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

fendermint/actors/objectstore/Cargo.toml

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,20 @@ fil_actors_runtime = { workspace = true, optional = true, features = [
1717
fvm_shared = { workspace = true }
1818
fvm_ipld_encoding = { workspace = true }
1919
fvm_ipld_blockstore = { workspace = true }
20-
fvm_ipld_kamt = { workspace = true }
20+
fvm_ipld_hamt = { workspace = true }
2121
num-derive = { workspace = true }
2222
serde = { workspace = true, features = ["derive"] }
2323
serde_tuple = { workspace = true }
2424
num-traits = { workspace = true }
2525
frc42_dispatch = { workspace = true }
2626
anyhow = { workspace = true }
2727

28+
[dev-dependencies]
29+
fil_actors_runtime = { workspace = true, features = [
30+
"test_utils",
31+
"fil-actor",
32+
] }
33+
2834
[features]
2935
default = []
3036
fil-actor = ["fil_actors_runtime"]
Lines changed: 71 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
// Copyright 2024 Textile Inc
12
// Copyright 2021-2023 Protocol Labs
23
// SPDX-License-Identifier: Apache-2.0, MIT
34

@@ -7,68 +8,88 @@ use fil_actors_runtime::builtin::singletons::SYSTEM_ACTOR_ADDR;
78
use fil_actors_runtime::runtime::{ActorCode, Runtime};
89
use fil_actors_runtime::ActorDowncast;
910
use fil_actors_runtime::ActorError;
11+
use fvm_ipld_hamt::BytesKey;
1012
use fvm_shared::error::ExitCode;
1113

12-
use crate::{ConstructorParams, Method, State, OBJECTSTORE_ACTOR_NAME};
14+
use crate::DeleteObjectParams;
15+
use crate::{Method, PutObjectParams, State, OBJECTSTORE_ACTOR_NAME};
1316

1417
fil_actors_runtime::wasm_trampoline!(Actor);
1518

1619
pub struct Actor;
1720

1821
impl Actor {
19-
fn constructor(rt: &impl Runtime, params: ConstructorParams) -> Result<(), ActorError> {
20-
// Note(sander): We're setting this up to be a subnet-wide actor for a single repo.
21-
// Note(sander): In the future, this could be deployed dynamically for multi repo subnets.
22+
fn constructor(rt: &impl Runtime) -> Result<(), ActorError> {
23+
// FIXME:(sander) We're setting this up to be a subnet-wide actor for a single repo.
24+
// FIXME:(sander) In the future, this could be deployed dynamically for multi repo subnets.
2225
rt.validate_immediate_caller_is(std::iter::once(&SYSTEM_ACTOR_ADDR))?;
2326

2427
let state = State::new(rt.store()).map_err(|e| {
25-
e.downcast_default(ExitCode::USR_ILLEGAL_STATE, "failed to create empty KAMT")
28+
e.downcast_default(
29+
ExitCode::USR_ILLEGAL_STATE,
30+
"failed to construct empty store",
31+
)
2632
})?;
2733

28-
rt.create(&state)?;
34+
rt.create(&state)
35+
}
36+
37+
fn append_object(rt: &impl Runtime, params: PutObjectParams) -> Result<(), ActorError> {
38+
// FIXME:(carsonfarmer) We'll want to validate the caller is the owner of the repo.
39+
rt.validate_immediate_caller_accept_any()?;
40+
41+
rt.transaction(|st: &mut State, rt| {
42+
st.append(rt.store(), BytesKey(params.key), params.content)
43+
.map_err(|e| {
44+
e.downcast_default(ExitCode::USR_ILLEGAL_STATE, "failed to append to object")
45+
})
46+
})?;
47+
48+
Ok(())
49+
}
50+
51+
fn put_object(rt: &impl Runtime, params: PutObjectParams) -> Result<(), ActorError> {
52+
// FIXME:(carsonfarmer) We'll want to validate the caller is the owner of the repo.
53+
rt.validate_immediate_caller_accept_any()?;
54+
55+
rt.transaction(|st: &mut State, rt| {
56+
st.put(rt.store(), BytesKey(params.key), params.content)
57+
.map_err(|e| {
58+
e.downcast_default(ExitCode::USR_ILLEGAL_STATE, "failed to put object")
59+
})
60+
})?;
61+
62+
Ok(())
63+
}
64+
65+
fn delete_object(rt: &impl Runtime, params: DeleteObjectParams) -> Result<(), ActorError> {
66+
// FIXME:(carsonfarmer) We'll want to validate the caller is the owner of the repo.
67+
rt.validate_immediate_caller_accept_any()?;
68+
69+
rt.transaction(|st: &mut State, rt| {
70+
st.delete(rt.store(), &BytesKey(params.key)).map_err(|e| {
71+
e.downcast_default(ExitCode::USR_ILLEGAL_STATE, "failed to delete to object")
72+
})
73+
})?;
2974

3075
Ok(())
3176
}
3277

33-
// Note(sander): Probably obvious, but example actor method that mutates state
34-
// fn push_block_hash(rt: &impl Runtime, params: PushBlockParams) -> Result<(), ActorError> {
35-
// rt.validate_immediate_caller_is(std::iter::once(&SYSTEM_ACTOR_ADDR))?;
36-
//
37-
// rt.transaction(|st: &mut State, rt| {
38-
// // load the blockhashes AMT
39-
// let mut blockhashes = Array::load(&st.blockhashes, rt.store()).map_err(|e| {
40-
// e.downcast_default(
41-
// ExitCode::USR_ILLEGAL_STATE,
42-
// "failed to load blockhashes states",
43-
// )
44-
// })?;
45-
//
46-
// // push the block to the AMT
47-
// blockhashes.set(params.epoch as u64, params.block).unwrap();
48-
//
49-
// // remove the oldest block if the AMT is full (note that this assume the
50-
// // for_each_while iterates in order, which it seems to do)
51-
// if blockhashes.count() > st.lookback_len {
52-
// let mut first_idx = 0;
53-
// blockhashes
54-
// .for_each_while(|i, _: &BlockHash| {
55-
// first_idx = i;
56-
// Ok(false)
57-
// })
58-
// .unwrap();
59-
// blockhashes.delete(first_idx).unwrap();
60-
// }
61-
//
62-
// // save the new blockhashes AMT cid root
63-
// st.blockhashes = blockhashes.flush().map_err(|e| {
64-
// e.downcast_default(ExitCode::USR_ILLEGAL_STATE, "failed to save blockhashes")
65-
// })?;
66-
//
67-
// Ok(())
68-
// })?;
69-
//
70-
// Ok(())
71-
// }
78+
fn get_object(rt: &impl Runtime, key: Vec<u8>) -> Result<Option<Vec<u8>>, ActorError> {
79+
let st: State = rt.state()?;
80+
81+
st.get(rt.store(), &BytesKey(key))
82+
.map_err(|e| e.downcast_default(ExitCode::USR_ILLEGAL_STATE, "failed to get object"))
83+
}
84+
85+
fn list_objects(rt: &impl Runtime) -> Result<Option<Vec<Vec<u8>>>, ActorError> {
86+
let st: State = rt.state()?;
87+
88+
let objects = st.list(rt.store()).map_err(|e| {
89+
e.downcast_default(ExitCode::USR_ILLEGAL_STATE, "failed to list objects")
90+
})?;
91+
Ok(Some(objects))
92+
}
7293
}
7394

7495
impl ActorCode for Actor {
@@ -80,8 +101,10 @@ impl ActorCode for Actor {
80101

81102
actor_dispatch! {
82103
Constructor => constructor,
83-
// PushBlockHash => push_block_hash,
84-
// LookbackLen => lookback_len,
85-
// GetBlockHash => get_block_hash,
104+
PutObject => put_object,
105+
AppendObject => append_object,
106+
DeleteObject => delete_object,
107+
GetObject => get_object,
108+
ListObjects => list_objects,
86109
}
87110
}

fendermint/actors/objectstore/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1+
// Copyright 2024 Textile Inc
12
// Copyright 2021-2023 Protocol Labs
23
// SPDX-License-Identifier: Apache-2.0, MIT
4+
35
#[cfg(feature = "fil-actor")]
46
mod actor;
57
mod shared;

0 commit comments

Comments
 (0)