Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
c426276
feat: initial recall migration setup
phutchins Nov 4, 2025
b1b8491
feat: port recall actors and resolve dependencies
phutchins Nov 4, 2025
4003012
docs: document FVM version incompatibility blocker
phutchins Nov 4, 2025
e986d08
fix: temporarily disable sol_facade to resolve FVM version conflict
phutchins Nov 4, 2025
4c36f66
docs: update migration log with latest progress
phutchins Nov 4, 2025
46cd4de
wip: attempted netwatch fixes (unsuccessful)
phutchins Nov 4, 2025
3e0bf24
fix: patch netwatch for socket2 0.5 compatibility (BREAKTHROUGH!)
phutchins Nov 4, 2025
6173345
fix: resolve FVM 4.7 API incompatibilities in recall_executor
phutchins Nov 4, 2025
65da5c6
docs: create comprehensive migration success summary
phutchins Nov 4, 2025
fd28f17
feat: complete Phase 4 - all Recall actors compiling! 🎉
phutchins Nov 4, 2025
a4ee33b
docs: final migration completion summary
phutchins Nov 4, 2025
7e76de6
chore: clean up whitespace and comments in Cargo.toml and util.rs
phutchins Nov 4, 2025
857a9fa
docs: update migration completion summary with final metrics
phutchins Nov 4, 2025
5e6ef3b
feat: add Recall actors to custom bundle and fix testnode setup
phutchins Nov 4, 2025
42af9fc
docs: add comprehensive Recall storage testing guide
phutchins Nov 4, 2025
c62df9b
feat: Port Objects HTTP API and fix Recall API incompatibilities
phutchins Nov 4, 2025
bd4e155
docs: Add comprehensive Recall migration summary
phutchins Nov 4, 2025
1293b97
docs: Add detailed analysis of missing files in Recall migration
phutchins Nov 4, 2025
7a3d417
docs: Add comprehensive Recall storage deployment guide
phutchins Nov 4, 2025
f9c88e3
fix: Correct comment formatting in Recall deployment guide
phutchins Nov 4, 2025
8a7c0d5
docs: Expand Recall deployment guide with client-side usage instructions
phutchins Nov 4, 2025
43b72d7
by pass vote tally
Nov 5, 2025
f4272fb
fix imports
Nov 5, 2025
338191e
feat: Introduce ADM actor for machine lifecycle management
phutchins Nov 5, 2025
7aaeae9
fix compilation
Nov 6, 2025
f2f22e0
a bunch of fixes
Nov 10, 2025
6c15fc6
working
Nov 12, 2025
758623b
feat(node): removes vote tally (#1486)
cryptoAtwill Dec 10, 2025
7101c07
Recall remove vote tally (#1499)
cryptoAtwill Dec 18, 2025
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
3,245 changes: 3,095 additions & 150 deletions Cargo.lock

Large diffs are not rendered by default.

54 changes: 54 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ members = [
"ipc/api",
"ipc/types",
"ipc/observability",
"ipc-decentralized-storage",

# ipld
"ipld/resolver",
Expand Down Expand Up @@ -44,6 +45,30 @@ members = [
"fendermint/actors/eam",
"fendermint/actors/f3-light-client",
"fendermint/actors/gas_market/eip1559",
# recall actors
"fendermint/actors/adm_types", # fil_actor_adm - ADM types
"fendermint/actors/adm", # ADM actor
"fendermint/actors/machine", # Machine base trait
"fendermint/actors/blobs",
"fendermint/actors/blobs/shared",
"fendermint/actors/blobs/testing",
"fendermint/actors/blob_reader",
"fendermint/actors/bucket", # S3-like object storage
"fendermint/actors/timehub", # Timestamping service
"fendermint/actors/recall_config",
"fendermint/actors/recall_config/shared",

# recall storage (netwatch patched for socket2 0.5 compatibility!)
"recall/kernel",
"recall/kernel/ops",
"recall/syscalls",
"recall/executor",
"recall/iroh_manager",
"recall/ipld",
"recall/actor_sdk",

# recall contracts (vendored locally, FVM 4.7 upgrade)
"recall-contracts/crates/facade",

"build-rs-utils",
"contracts-artifacts",
Expand All @@ -70,13 +95,15 @@ axum = { version = "0.6", features = ["ws"] }
base64 = "0.21"
bollard = "0.15"
blake2b_simd = "1.0"
blake3 = "1.5"
bloom = "0.3"
bytes = "1.4"
clap = { version = "4.1", features = ["derive", "env", "string"] }
color-eyre = "0.5.11"
byteorder = "1.5.0"
config = "0.13"
const-hex = "1.14.0"
data-encoding = "2.3.3"
dirs = "5.0"
dircpy = "0.3.19"
either = "1.10"
Expand All @@ -96,6 +123,15 @@ hex-literal = "0.4.1"
http = "0.2.12"
im = "15.1.0"
integer-encoding = { version = "3.0.3", default-features = false }
# Recall/Iroh dependencies
ambassador = "0.3.5"
iroh = "0.35"
iroh-base = "0.35"
iroh-blobs = { version = "0.35", features = ["rpc"] }
iroh-relay = "0.35"
iroh-quinn = { version = "0.13" }
n0-future = "0.1.2"
quic-rpc = { version = "0.20", features = ["quinn-transport"] }
jsonrpc-v2 = { version = "0.11", default-features = false, features = [
"bytes-v10",
] }
Expand Down Expand Up @@ -147,8 +183,19 @@ quickcheck_macros = "1"
rand = "0.8"
rand_chacha = "0.3"
regex = "1"
replace_with = "0.1.7"
statrs = "0.18.0"
reqwest = { version = "0.11.13", features = ["json"] }
# Recall entanglement library
entangler = { package = "recall_entangler", git = "https://github.com/recallnet/entanglement.git", rev = "aee1c675ff05e5cde4771a2e2eb3ac4dab8476bc" }
entangler_storage = { package = "recall_entangler_storage", git = "https://github.com/recallnet/entanglement.git", rev = "aee1c675ff05e5cde4771a2e2eb3ac4dab8476bc" }
# Objects HTTP API dependencies
warp = "0.3"
uuid = { version = "1.0", features = ["v4"] }
mime_guess = "2.0"
urlencoding = "2.1"
# Recall Solidity facades (vendored locally, upgraded to FVM 4.7)
recall_sol_facade = { path = "recall-contracts/crates/facade" }
sha2 = "0.10"
serde = { version = "1.0.217", features = ["derive"] }
serde_bytes = "0.11"
Expand Down Expand Up @@ -223,6 +270,7 @@ fvm_ipld_amt = "0.7.4"
# NOTE: Using master branch instead of v17.0.0 tag due to serde dependency fixes
# Master is currently at commit 2f040c12 which fixes the serde::__private::PhantomData import issue
fil_actors_evm_shared = { git = "https://github.com/filecoin-project/builtin-actors", branch = "master" }
fil_actor_adm = { path = "fendermint/actors/adm_types" }
fil_actor_eam = { git = "https://github.com/filecoin-project/builtin-actors", branch = "master" }
fil_actor_evm = { git = "https://github.com/filecoin-project/builtin-actors", branch = "master" }
fil_actors_runtime = { git = "https://github.com/filecoin-project/builtin-actors", branch = "master" }
Expand All @@ -231,6 +279,7 @@ cid = { version = "0.11", default-features = false, features = [
"serde-codec",
"std",
] }
multihash-codetable = "0.1"

frc42_dispatch = { path = "./ext/frc42_dispatch" }

Expand All @@ -249,6 +298,11 @@ tendermint-proto = { version = "0.31" }
[patch.crates-io]
# Using latest FVM to match builtin-actors v17.0.0 requirements
fvm = { git = "https://github.com/consensus-shipyard/ref-fvm.git", branch = "master" }

# Fix netwatch socket2 0.5 compatibility (macOS BSD sockets)
# Patched version with socket2 0.5+ API fixes
netwatch = { path = "patches/netwatch" }

fvm_shared = { git = "https://github.com/consensus-shipyard/ref-fvm.git", branch = "master" }
fvm_sdk = { git = "https://github.com/consensus-shipyard/ref-fvm.git", branch = "master" }
fvm_ipld_blockstore = { git = "https://github.com/consensus-shipyard/ref-fvm.git", branch = "master" }
Expand Down
267 changes: 267 additions & 0 deletions RECALL_BUCKET.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,267 @@
# Recall Bucket Storage Guide (Path-Based Access)

## Configuration

```bash
# From RECALL_RUN.md
export TENDERMINT_RPC=http://localhost:26657
export OBJECTS_LISTEN_ADDR=http://localhost:8080
export NODE_OPERATION_OBJECT_API=http://localhost:8081
export ETH_RPC=http://localhost:8545
export BLOBS_ACTOR=0x6d342defae60f6402aee1f804653bbae4e66ae46
export ADM_ACTOR=0x7caec36fc8a3a867ca5b80c6acb5e5871d05aa28

# Your credentials
export USER_SK=<YOUR_PRIVATE_KEY_HEX>
export USER_ADDR=<YOUR_ETH_ADDRESS>
```

## 6. Start Gateway
```bash
cargo build --release -p ipc-decentralized-storage --bin gateway --bin node

# prepare to start node
export FM_NETWORK=test
# validator bls key file in hex format
export BLS_KEY_FILE=./test-network/bls_key.hex
# fendermint secret key file
export SECRET_KEY_FILE=./test-network/keys/alice.sk

# register as a storage node operator
./target/release/node register-operator --bls-key-file $BLS_KEY_FILE --secret-key-file $SECRET_KEY_FILE --operator-rpc-url $NODE_OPERATION_OBJECT_API

# start the node
./target/release/node run \
--secret-key-file ./test-network/bls_key.hex \
--iroh-path ./iroh_node \
--iroh-v4-addr 0.0.0.0:11204 \
--rpc-url http://localhost:26657 \
--batch-size 10 \
--poll-interval-secs 5 \
--max-concurrent-downloads 10 \
--rpc-bind-addr 127.0.0.1:8081

./target/release/gateway --bls-key-file $BLS_KEY_FILE --secret-key-file $SECRET_KEY_FILE --iroh-path ./iroh_gateway --objects-listen-addr 0.0.0.0:8080

```
## 6. Download the Blob

Download via HTTP API:

```bash
# Download the blob
curl $NODE_OPERATION_OBJECT_API/v1/blobs/${BLOB_HASH#0x}/content
# You should see the original file
```

---

## 1. Create a Bucket

First, create a bucket via the ADM (Actor Deployment Manager):

```bash
# Buy 1 FIL worth of credits
cast send $BLOBS_ACTOR "buyCredit()" \
--value 0.1ether \
--private-key $USER_SK \
--rpc-url http://localhost:8545

# Create a new bucket (caller becomes owner)
TX_RESULT=$(cast send $ADM_ACTOR "createBucket()" \
--private-key $USER_SK \
--rpc-url $ETH_RPC \
--json)

echo $TX_RESULT | jq '.'

# Extract bucket address from MachineInitialized event
# Event signature: MachineInitialized(uint8 indexed kind, address machineAddress)
BUCKET_ADDR=$(echo $TX_RESULT | jq -r '.logs[] | select(.topics[0] == "0x8f7252642373d5f0b89a0c5cd9cd242e5cd5bb1a36aec623756e4f52a8c1ea6e") | .data' | cut -c27-66)
BUCKET_ADDR="0x$BUCKET_ADDR"

echo "Bucket created at: $BUCKET_ADDR"
export BUCKET_ADDR
```

## 2. Upload and Register an Object

### Step 2a: Upload file to Iroh (same as basic flow)

```bash
# Create a test file
echo "Hello from bucket storage!" > myfile.txt

# Get file size
BLOB_SIZE=$(stat -f%z myfile.txt 2>/dev/null || stat -c%s myfile.txt)

# Upload to Iroh
UPLOAD_RESPONSE=$(curl -s -X POST $OBJECTS_API/v1/objects \
-F "size=${BLOB_SIZE}" \
-F "data=@myfile.txt")

echo $UPLOAD_RESPONSE | jq '.'

# Extract hashes
BLOB_HASH_B32=$(echo $UPLOAD_RESPONSE | jq -r '.hash')
METADATA_HASH_B32=$(echo $UPLOAD_RESPONSE | jq -r '.metadata_hash // .metadataHash')
NODE_ID_BASE32=$(curl -s $OBJECTS_API/v1/node | jq -r '.node_id')

# Convert to hex (same as RECALL_RUN.md)
export BLOB_HASH=$(python3 -c "
import base64
h = '$BLOB_HASH_B32'.upper()
padding = (8 - len(h) % 8) % 8
h = h + '=' * padding
decoded = base64.b32decode(h)
if len(decoded) > 32:
decoded = decoded[:32]
elif len(decoded) < 32:
decoded = decoded + b'\x00' * (32 - len(decoded))
print('0x' + decoded.hex())
")

export METADATA_HASH=$(python3 -c "
import base64
h = '$METADATA_HASH_B32'.upper()
padding = (8 - len(h) % 8) % 8
h = h + '=' * padding
decoded = base64.b32decode(h)
if len(decoded) > 32:
decoded = decoded[:32]
elif len(decoded) < 32:
decoded = decoded + b'\x00' * (32 - len(decoded))
print('0x' + decoded.hex())
")

export SOURCE_NODE="0x$NODE_ID_BASE32"

echo "Blob Hash: $BLOB_HASH"
echo "Metadata Hash: $METADATA_HASH"
echo "Source Node: $SOURCE_NODE"
```

### Step 2b: Register object in bucket with a path

```bash
# Add object with a path-based key
# Signature: addObject(bytes32 source, string key, bytes32 hash, bytes32 recoveryHash, uint64 size)
cast send $BUCKET_ADDR "addObject(bytes32,string,bytes32,bytes32,uint64)" \
$SOURCE_NODE \
"documents/myfile.txt" \
$BLOB_HASH \
$METADATA_HASH \
$BLOB_SIZE \
--private-key $USER_SK \
--rpc-url $ETH_RPC
```

## 3. Query Objects

### Get a single object by path

```bash
# Get object by exact path
# Returns: ObjectValue(bytes32 blobHash, bytes32 recoveryHash, uint64 size, uint64 expiry, (string,string)[] metadata)
cast call $BUCKET_ADDR "getObject(string)((bytes32,bytes32,uint64,uint64,(string,string)[]))" "documents/myfile.txt" --rpc-url $ETH_RPC
```

### List all objects (no filter)

```bash
# List all objects in bucket
cast call $BUCKET_ADDR "queryObjects()(((string,(bytes32,uint64,uint64,(string,string)[]))[],string[],string))" \
--rpc-url $ETH_RPC
```

### List with prefix (folder-like)

```bash
# List everything under "documents/"
cast call $BUCKET_ADDR "queryObjects(string)(((string,(bytes32,uint64,uint64,(string,string)[]))[],string[],string))" "documents/" --rpc-url $ETH_RPC
```

### List with delimiter (S3-style folder simulation)

```bash
# List top-level "folders" and files
# Returns: Query((string,ObjectState)[] objects, string[] commonPrefixes, string nextKey)
# Where ObjectState = (bytes32 blobHash, uint64 size, uint64 expiry, (string,string)[] metadata)
cast call $BUCKET_ADDR "queryObjects(string,string)(((string,(bytes32,uint64,uint64,(string,string)[]))[],string[],string))" "" "/" \
--rpc-url $ETH_RPC

# Example response:
# ([], ["documents/", "images/"], "")
# ^objects at root ^"folders" ^nextKey (empty = no more pages)

# Extract blob hash from first object:
# BLOB_HASH=$(cast call ... | jq -r '.[0][0][1][0]')

# List contents of "documents/" folder
cast call $BUCKET_ADDR "queryObjects(string,string)(((string,(bytes32,uint64,uint64,(string,string)[]))[],string[],string))" "documents/" "/" \
--rpc-url $ETH_RPC
```

### Paginated queries

```bash
# Query with pagination
# queryObjects(prefix, delimiter, startKey, limit)
cast call $BUCKET_ADDR "queryObjects(string,string,string,uint64)" \
"documents/" \
"/" \
"" \
100 \
--rpc-url $ETH_RPC

# If nextKey is returned, use it for the next page
cast call $BUCKET_ADDR "queryObjects(string,string,string,uint64)" \
"documents/" \
"/" \
"documents/page2start.txt" \
100 \
--rpc-url $ETH_RPC
```

---

## 4. Update Object Metadata

```bash
# Update metadata for an existing object
# Set value to empty string to delete a metadata key
cast send $BUCKET_ADDR "updateObjectMetadata(string,(string,string)[])" \
"documents/myfile.txt" \
'[("content-type","text/markdown"),("version","2")]' \
--private-key $USER_SK \
--rpc-url $ETH_RPC
```

---

## 5. Delete an Object

```bash
# Delete object by path
cast send $BUCKET_ADDR "deleteObject(string)" "documents/myfile.txt" \
--private-key $USER_SK \
--rpc-url $ETH_RPC
```

---

## 6. Download Content

Downloads still go through the Iroh/Objects API using the blob hash:

```bash
# First get the object to retrieve its blob hash
OBJECT_INFO=$(cast call $BUCKET_ADDR "getObject(string)" "documents/myfile.txt" \
--rpc-url $ETH_RPC)

# Extract blob hash from response and download
# (The blob hash is the first bytes32 in the response)
curl $NODE_OPERATION_OBJECT_API/v1/blobs/${BLOB_HASH#0x}/content
```

---
Binary file added builtin-actors/output/bundle.car
Binary file not shown.
Loading
Loading