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

feat(storage-provider-server): add p2p bootstrap and registration #666

Merged
merged 34 commits into from
Jan 16, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
26323fc
feat: Add P2P functionality to storage server
aidan46 Dec 27, 2024
5871fa6
feat: Add peer_id command
aidan46 Jan 7, 2025
d8f682b
fix: Change peer ID printing
aidan46 Jan 7, 2025
990bc09
feat: Add default p2p node type
aidan46 Jan 7, 2025
187abbb
fix: Move example keys and config into central example folder
aidan46 Jan 7, 2025
9eda31f
fix: Parse p2p config before running
aidan46 Jan 9, 2025
21207ad
fix: PeerId in storagext and pallets
aidan46 Jan 10, 2025
f1bd75a
feat: Add @ dialect to p2p key parsing
aidan46 Jan 10, 2025
efc6f7d
fix: TOML formatting
aidan46 Jan 10, 2025
910802f
fix: Keypair path in register node config
aidan46 Jan 13, 2025
e1efcef
fix: Add PEER_ID_MAX_BYTES const
aidan46 Jan 13, 2025
74f3c52
fix: Add p2p namespace as a const value
aidan46 Jan 13, 2025
cb97c2e
fix: Add new config to polka-storage-server
aidan46 Jan 14, 2025
8c84b15
docs: Update polka-storage-provider-server docs
aidan46 Jan 15, 2025
731e867
fix: Add p2p node to example scripts (#673)
aidan46 Jan 15, 2025
7f8b7ad
fix: Remove peer ID writing to file
aidan46 Jan 15, 2025
30e5fc4
fix: Use debug for NodeType Display
aidan46 Jan 15, 2025
1aab240
fix: P2PError members naming
aidan46 Jan 15, 2025
54f32a5
fix: Fully qualify tracing logs
aidan46 Jan 15, 2025
8464af8
docs: Add docs to p2p functions
aidan46 Jan 15, 2025
2ed411e
fix: Move register and bootstrap fn into their modules
aidan46 Jan 15, 2025
e816c5b
fix: Move p2p node spawning into separate function
aidan46 Jan 15, 2025
3bdf06b
fix: Change default for NodeType
aidan46 Jan 15, 2025
4e03a6d
feat: Add macro for spawning and inspecting errors
aidan46 Jan 15, 2025
c9057a9
fix: Remove task spawning macro
aidan46 Jan 15, 2025
2528fce
fix: Remove unused import
aidan46 Jan 15, 2025
f40c851
fix: Cargo fmt
aidan46 Jan 15, 2025
2f50126
fix: Remove unused configs
aidan46 Jan 15, 2025
dae95d0
docs: Improve macro comment
aidan46 Jan 15, 2025
bf4295c
docs: Fix proof defaults in server docs
aidan46 Jan 15, 2025
ceb74a6
fix: Move p2p.rs to mod.rs
aidan46 Jan 15, 2025
5537922
docs: Add docs to publish script
aidan46 Jan 15, 2025
a31984b
fix: Use if let over match for early return
aidan46 Jan 15, 2025
89f1fe1
docs: Update PeerID comment for register command
aidan46 Jan 15, 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
655 changes: 590 additions & 65 deletions Cargo.lock

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ color-print = "0.3.4"
criterion = "0.5.1"
digest = "0.10.7"
docify = { version = "0.2.8" }
ed25519-dalek = { version = "2.1.1", default-features = false }
aidan46 marked this conversation as resolved.
Show resolved Hide resolved
env_logger = "0.11.2"
ff = "0.13.0"
futures = "0.3.28"
Expand All @@ -79,6 +80,7 @@ ipld-core = "0.4.1"
ipld-dagpb = "0.2.1"
itertools = "0.13.0"
jsonrpsee = { version = "0.24.7" }
libp2p = { version = "0.54", default-features = false }
log = { version = "0.4.21", default-features = false }
multihash-codetable = { version = "0.1.1", default-features = false }
num-bigint = { version = "0.4.5", default-features = false }
Expand Down
44 changes: 33 additions & 11 deletions docs/src/storage-provider-cli/server.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,28 +81,50 @@ The path to the PoRep proving parameters. They are shared across all of the node

The path to the PoSt proving parameters. They are shared across all of the nodes in the network, as the chain stores corresponding Verifying Key parameters.

### `--node-type`

The P2P node type that the server will be running. Can be either `bootstrap` or `registration` node.

### `--p2p-key`

The ED25519 private key used by the P2P node.

### `--rendezvous-point-address`

Rendezvous point address that the registration node connects to or the bootstrap node binds to.

### `--rendezvous-point`

Peer ID of the rendezvous point that the registration node connects to. Only needed if running a registration P2P node.

### `--config`

Takes in a path to a configuration file, it supports both JSON and TOML (files _must_ have the right extension).
The supported configuration parameters are:

| Name | Default |
| ----------------------- | ------------------------------ |
| `upload-listen-address` | `127.0.0.1:8000` |
| `rpc-listen-address` | `127.0.0.1:8001` |
| `node-url` | `ws://127.0.0.1:42069` |
| `database-directory` | `/tmp/<random>/deals_database` |
| `storage-directory` | `/tmp/<random>/deals_storage` |
| `seal-proof` | 2KiB |
| `post-proof` | 2KiB |
| `porep_parameters` | NA |
| `post_parameters` | NA |
| Name | Default |
| -------------------------- | ------------------------------ |
| `upload-listen-address` | `127.0.0.1:8000` |
| `rpc-listen-address` | `127.0.0.1:8001` |
| `node-url` | `ws://127.0.0.1:42069` |
| `database-directory` | `/tmp/<random>/deals_database` |
| `storage-directory` | `/tmp/<random>/deals_storage` |
| `seal-proof` | `2KiB` |
| `post-proof` | `2KiB` |
| `porep_parameters` | NA |
| `post_parameters` | NA |
| `node_type` | `bootstrap` |
| `p2p_key` | NA |
| `rendezvous_point_address` | NA |
| `rendezvous_point` | `None` |

#### Bare bones configuration

```json
{
"porep_parameters": "/home/storage_provider/porep.params",
"post_parameters": "/home/storage_provider/post.params",
"p2p_key": "/home/storage_provider/private_key.pem",
"rendezvous_point_address": "/ip4/127.0.0.1/tcp/62649",
}
```
31 changes: 28 additions & 3 deletions examples/rpc_publish.sh
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,38 @@ PROVIDER="//Charlie"

INPUT_FILE="$1"
INPUT_FILE_NAME="$(basename "$INPUT_FILE")"
# CARv2 file location
INPUT_TMP_FILE="/tmp/$INPUT_FILE_NAME.car"

# Config file location
CONFIG="/tmp/config.toml"
# P2P Node variables
P2P_PUBLIC_KEY="/tmp/public.pem"
P2P_PRIVATE_KEY="/tmp/private.pem"
P2P_ADDRESS="/ip4/127.0.0.1/tcp/62649"

# Generate ED25519 private key to be replaced with a polka-storage-provider-client command
# TODO(@aidan46, 15/01, #676)
openssl genpkey -algorithm ED25519 -out "$P2P_PRIVATE_KEY" -outpubkey "$P2P_PUBLIC_KEY"

# Convert file to CARv2 format
target/release/mater-cli convert -q --overwrite "$INPUT_FILE" "$INPUT_TMP_FILE" &&

# Calculate COMMP and set PIECE_CID and PIECE_SIZE
INPUT_COMMP="$(target/release/polka-storage-provider-client proofs commp "$INPUT_TMP_FILE")"
PIECE_CID="$(echo "$INPUT_COMMP" | jq -r ".cid")"
PIECE_SIZE="$(echo "$INPUT_COMMP" | jq ".size")"

# Generate Peer ID from public key
PEER_ID="$(target/release/polka-storage-provider-client generate-peer-id --pubkey "$P2P_PUBLIC_KEY")"

# echo config file in the file in the /tmp folder
echo "seal_proof = '2KiB'
post_proof = '2KiB'
porep_parameters = '2KiB.porep.params'
post_parameters = '2KiB.post.params'
rendezvous_point_address = '$P2P_ADDRESS'
p2p_key = '@$P2P_PRIVATE_KEY'" > "$CONFIG"


# Setup balances
target/release/storagext-cli --sr25519-key "$CLIENT" market add-balance 250000000000 &
Expand All @@ -39,7 +64,7 @@ wait
# It's a test setup based on the local verifying keys, everyone can run those extrinsics currently.
# Each of the keys is different, because the processes are running in parallel.
# If they were running in parallel on the same account, they'd conflict with each other on the transaction nonce.
target/release/storagext-cli --sr25519-key "//Charlie" storage-provider register "peer_id" &
target/release/storagext-cli --sr25519-key "//Charlie" storage-provider register "$PEER_ID" &
target/release/storagext-cli --sr25519-key "//Alice" proofs set-porep-verifying-key @2KiB.porep.vk.scale &
target/release/storagext-cli --sr25519-key "//Bob" proofs set-post-verifying-key @2KiB.post.vk.scale &

Expand All @@ -64,7 +89,7 @@ DEAL_JSON=$(
)
SIGNED_DEAL_JSON="$(RUST_LOG=error target/release/polka-storage-provider-client sign-deal --sr25519-key "$CLIENT" "$DEAL_JSON")"

(RUST_LOG=debug target/release/polka-storage-provider-server --sr25519-key "$PROVIDER" --seal-proof "2KiB" --post-proof "2KiB" --porep-parameters 2KiB.porep.params --post-parameters 2KiB.post.params) &
(RUST_LOG=debug target/release/polka-storage-provider-server --sr25519-key "$PROVIDER" --config "$CONFIG") &
sleep 5 # gives time for the server to start

DEAL_CID="$(RUST_LOG=error target/release/polka-storage-provider-client propose-deal "$DEAL_JSON")"
Expand Down
15 changes: 13 additions & 2 deletions examples/start_sp.sh
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,15 @@ export DISABLE_XT_WAIT_WARNING=1

CLIENT="//Alice"
PROVIDER="//Charlie"
P2P_PUBLIC_KEY="/tmp/public.pem"
P2P_PRIVATE_KEY="/tmp/private.pem"
P2P_ADDRESS="/ip4/127.0.0.1/tcp/62649"

# Generate ED25519 private key
openssl genpkey -algorithm ED25519 -out "$P2P_PRIVATE_KEY" -outpubkey "$P2P_PUBLIC_KEY"

# Generate Peer ID
PEER_ID="$(target/release/polka-storage-provider-client generate-peer-id --pubkey "$P2P_PUBLIC_KEY")"

# Setup balances
RUST_LOG=debug target/release/storagext-cli --sr25519-key "$CLIENT" market add-balance 250000000000 &
Expand All @@ -19,7 +28,7 @@ wait
# It's a test setup based on the local verifying keys, everyone can run those extrinsics currently.
# Each of the keys is different, because the processes are running in parallel.
# If they were running in parallel on the same account, they'd conflict with each other on the transaction nonce.
RUST_LOG=debug target/release/storagext-cli --sr25519-key "//Charlie" storage-provider register "peer_id" &
RUST_LOG=debug target/release/storagext-cli --sr25519-key "//Charlie" storage-provider register "$PEER_ID" &
RUST_LOG=debug target/release/storagext-cli --sr25519-key "//Alice" proofs set-porep-verifying-key @2KiB.porep.vk.scale &
RUST_LOG=debug target/release/storagext-cli --sr25519-key "//Bob" proofs set-post-verifying-key @2KiB.post.vk.scale &
wait
Expand All @@ -28,7 +37,9 @@ echo '{
"seal_proof": "2KiB",
"post_proof": "2KiB",
"porep_parameters": "2KiB.porep.params",
"post_parameters": "2KiB.post.params"
"post_parameters": "2KiB.post.params",
"p2p_key": "@/tmp/private.pem",
"rendezvous_point_address": "/ip4/127.0.0.1/tcp/62649"
}' > /tmp/storage_provider.config.json
RUST_LOG=debug target/release/polka-storage-provider-server \
--sr25519-key "$PROVIDER" \
Expand Down
4 changes: 2 additions & 2 deletions pallets/market/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use frame_support::{
PalletId,
};
use frame_system::pallet_prelude::BlockNumberFor;
use primitives::proofs::RegisteredPoStProof;
use primitives::{proofs::RegisteredPoStProof, PEER_ID_MAX_BYTES};
use sp_core::Pair;
use sp_runtime::{
traits::{ConstU32, ConstU64, IdentifyAccount, IdentityLookup, Verify, Zero},
Expand Down Expand Up @@ -119,7 +119,7 @@ impl pallet_storage_provider::Config for Test {
type RuntimeEvent = RuntimeEvent;
type Randomness = DummyRandomnessGenerator<Self>;
type AuthorVrfHistory = DummyRandomnessGenerator<Self>;
type PeerId = BoundedVec<u8, ConstU32<32>>; // Max length of SHA256 hash
type PeerId = BoundedVec<u8, ConstU32<PEER_ID_MAX_BYTES>>; // https://github.com/libp2p/specs/blob/master/peer-ids/peer-ids.md#peer-ids
type Currency = Balances;
type Market = Market;
type ProofVerification = Proofs;
Expand Down
4 changes: 2 additions & 2 deletions pallets/storage-provider/src/tests/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ use primitives::{
sector::SectorNumber,
DealId, PartitionNumber, CID_SIZE_IN_BYTES, MAX_DEALS_PER_SECTOR, MAX_PARTITIONS_PER_DEADLINE,
MAX_POST_PROOF_BYTES, MAX_PROOFS_PER_BLOCK, MAX_REPLICAS_PER_BLOCK, MAX_SEAL_PROOF_BYTES,
MAX_TERMINATIONS_PER_CALL,
MAX_TERMINATIONS_PER_CALL, PEER_ID_MAX_BYTES,
};
use sp_arithmetic::traits::Zero;
use sp_core::{bounded_vec, Pair};
Expand Down Expand Up @@ -198,7 +198,7 @@ impl pallet_storage_provider::Config for Test {
type RuntimeEvent = RuntimeEvent;
type Randomness = DummyRandomnessGenerator<Self>;
type AuthorVrfHistory = DummyRandomnessGenerator<Self>;
type PeerId = BoundedVec<u8, ConstU32<32>>; // Max length of SHA256 hash
type PeerId = BoundedVec<u8, ConstU32<PEER_ID_MAX_BYTES>>; // https://github.com/libp2p/specs/blob/master/peer-ids/peer-ids.md#peer-ids
type Currency = Balances;
type Market = Market;
type ProofVerification = DummyProofsVerification;
Expand Down
6 changes: 6 additions & 0 deletions primitives/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,3 +76,9 @@ pub const MAX_SEAL_PROOF_BYTES: u32 = 1_920;
/// References:
/// * <https://github.com/filecoin-project/ref-fvm/blob/32583cc05aa422c8e1e7ba81d56a888ac9d90e61/shared/src/sector/registered_proof.rs#L159>
pub const MAX_POST_PROOF_BYTES: u32 = 192;

/// The maximum amount of bytes of a libp2p Peer ID.
///
/// References:
/// * https://github.com/libp2p/specs/blob/master/peer-ids/peer-ids.md#peer-ids
pub const PEER_ID_MAX_BYTES: u32 = 42;
3 changes: 2 additions & 1 deletion runtime/src/configs/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ use parachains_common::message_queue::{NarrowOriginToSibling, ParaIdToSibling};
use polkadot_runtime_common::{
xcm_sender::NoPriceForMessageDelivery, BlockHashCount, SlowAdjustingFeeUpdate,
};
use primitives::PEER_ID_MAX_BYTES;
use sp_consensus_aura::sr25519::AuthorityId as AuraId;
use sp_runtime::{traits::Verify, MultiSignature, Perbill};
use sp_version::RuntimeVersion;
Expand Down Expand Up @@ -368,7 +369,7 @@ impl pallet_storage_provider::Config for Runtime {
type RuntimeEvent = RuntimeEvent;
type Randomness = crate::Randomness;
type AuthorVrfHistory = crate::Randomness;
type PeerId = BoundedVec<u8, ConstU32<32>>; // Max length of SHA256 hash
type PeerId = BoundedVec<u8, ConstU32<PEER_ID_MAX_BYTES>>; // https://github.com/libp2p/specs/blob/master/peer-ids/peer-ids.md#peer-ids
type Currency = Balances;
type Market = crate::Market;
type ProofVerification = crate::Proofs;
Expand Down
2 changes: 2 additions & 0 deletions storage-provider/client/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,10 @@ bls12_381 = { workspace = true }
cid = { workspace = true, features = ["std"] }
clap = { workspace = true, features = ["derive"] }
codec = { workspace = true }
ed25519-dalek = { workspace = true, features = ["pem", "pkcs8"] }
hex = { workspace = true }
jsonrpsee = { workspace = true, features = ["http-client", "macros", "server", "ws-client"] }
libp2p.workspace = true
sc-cli = { workspace = true }
serde = { workspace = true }
serde_json = { workspace = true }
Expand Down
28 changes: 28 additions & 0 deletions storage-provider/client/src/commands/mod.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
mod proofs;
mod wallet;

use std::path::PathBuf;

use clap::Parser;
use ed25519_dalek::pkcs8::{DecodePublicKey, PublicKeyBytes};
use jsonrpsee::core::ClientError;
use libp2p::{identity::ed25519::PublicKey as EdPubKey, PeerId};
use polka_storage_provider_common::rpc::StorageProviderRpcClient;
use storagext::{
deser::DeserializablePath,
Expand Down Expand Up @@ -47,6 +51,12 @@ pub enum CliError {

#[error("no signer key was provider")]
NoSigner,

#[error(transparent)]
PubKeyError(#[from] ed25519_dalek::pkcs8::spki::Error),

#[error(transparent)]
DecodingError(#[from] libp2p::identity::DecodingError),
}

/// A CLI application that facilitates management operations over a running full
Expand Down Expand Up @@ -98,6 +108,13 @@ pub(crate) enum Cli {
#[command(flatten)]
signer_key: MultiPairArgs,
},

/// Generate a Peer ID from a ED25519 public key pem file
GeneratePeerID {
aidan46 marked this conversation as resolved.
Show resolved Hide resolved
/// Path to the ED25519 public key pem file
#[arg(long)]
pubkey: PathBuf,
},
}

impl Cli {
Expand Down Expand Up @@ -131,6 +148,7 @@ impl Cli {
deal_proposal,
signer_key,
} => Self::sign_deal(deal_proposal, signer_key),
Self::GeneratePeerID { pubkey } => Self::generate_peer_id(pubkey),
}
}

Expand Down Expand Up @@ -182,4 +200,14 @@ impl Cli {
);
Ok(())
}

fn generate_peer_id(path: PathBuf) -> Result<(), CliError> {
let pubkey_bytes = PublicKeyBytes::read_public_key_pem_file(path)?;
let pubkey = EdPubKey::try_from_bytes(&pubkey_bytes.to_bytes())?;
let key = libp2p::identity::PublicKey::from(pubkey);
let peer_id = PeerId::from_public_key(&key);

println!("{peer_id}");
Ok(())
}
}
2 changes: 2 additions & 0 deletions storage-provider/server/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,12 @@ axum = { workspace = true, features = ["macros", "multipart"] }
cid = { workspace = true, features = ["serde", "std"] }
clap = { workspace = true, features = ["derive"] }
codec = { workspace = true }
ed25519-dalek = { workspace = true, features = ["pem", "std"] }
futures = { workspace = true }
hex = { workspace = true, features = ["std"] }
hyper = { workspace = true }
jsonrpsee = { workspace = true, features = ["http-client", "macros", "server", "ws-client"] }
libp2p = { workspace = true, features = ["identify", "macros", "noise", "rendezvous", "tcp", "tokio", "yamux"] }
rand = { workspace = true }
rocksdb = { workspace = true }
sc-cli = { workspace = true }
Expand Down
31 changes: 28 additions & 3 deletions storage-provider/server/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,15 @@ use std::{
};

use clap::Args;
use libp2p::{identity::Keypair, Multiaddr, PeerId};
use primitives::proofs::{RegisteredPoStProof, RegisteredSealProof};
use serde::{Deserialize, Serialize};
use serde::Deserialize;
use url::Url;

use crate::DEFAULT_NODE_ADDRESS;
use crate::{
p2p::{deser_keypair, keypair_value_parser, string_to_peer_id_option, NodeType},
DEFAULT_NODE_ADDRESS,
};

/// Default address to bind the RPC server to.
const fn default_rpc_listen_address() -> SocketAddr {
Expand All @@ -31,7 +35,7 @@ fn default_node_address() -> Url {
Url::parse(DEFAULT_NODE_ADDRESS).expect("DEFAULT_NODE_ADDRESS must be a valid Url")
}

#[derive(Debug, Clone, Deserialize, Serialize, Args)]
#[derive(Debug, Clone, Deserialize, Args)]
#[group(multiple = true, conflicts_with = "config")]
#[serde(deny_unknown_fields)]
pub struct ConfigurationArgs {
Expand Down Expand Up @@ -98,4 +102,25 @@ pub struct ConfigurationArgs {
/// **they need to be set** via an extrinsic pallet-proofs::set_post_verifyingkey.
#[arg(long, required = false)]
pub(crate) post_parameters: PathBuf,

/// P2P Node type, can be either a bootstrap node or a registration node.
#[serde(default = "NodeType::default")]
#[arg(long, default_value_t = NodeType::Bootstrap)]
pub(crate) node_type: NodeType,

/// P2P ED25519 private key
#[serde(deserialize_with = "deser_keypair")]
#[arg(long, value_parser = keypair_value_parser)]
pub(crate) p2p_key: Keypair,

/// Rendezvous point address that the registration node connects to
/// or the bootstrap node binds to.
#[arg(long)]
pub(crate) rendezvous_point_address: Multiaddr,

/// PeerID of the bootstrap node used by the registration node.
/// Optional because it is not used by the bootstrap node.
#[serde(default, deserialize_with = "string_to_peer_id_option")]
#[arg(long)]
pub(crate) rendezvous_point: Option<PeerId>,
}
Loading
Loading