feat: storage hub client (#149)

Co-authored-by: Steve Degosserie <723552+stiiifff@users.noreply.github.com>
Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
undercover-cactus 2025-09-10 08:15:27 +02:00 committed by GitHub
parent 1f38b4e343
commit a9d0f7157a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
27 changed files with 6033 additions and 1146 deletions

View file

@ -68,9 +68,160 @@ runs:
shell: bash
run: sudo apt-get update && sudo apt-get install -y libpq-dev libclang-dev
# Auto-install missing dependencies when install-deps is false (for self-hosted runners)
- name: Setup system dependencies (self-hosted)
if: inputs.install-deps == 'false'
shell: bash
run: |
echo "Checking and installing system dependencies locally if needed..."
# Setup local directories
LOCAL_DIR="$HOME/.local"
LOCAL_BIN="$LOCAL_DIR/bin"
LOCAL_LIB="$LOCAL_DIR/lib"
LOCAL_INCLUDE="$LOCAL_DIR/include"
LOCAL_PKG_CONFIG="$LOCAL_DIR/lib/pkgconfig"
mkdir -p "$LOCAL_BIN" "$LOCAL_LIB" "$LOCAL_INCLUDE" "$LOCAL_PKG_CONFIG"
# Export paths for future steps (avoid duplication)
echo "$LOCAL_BIN" >> $GITHUB_PATH
echo "LD_LIBRARY_PATH=$LOCAL_LIB:${LD_LIBRARY_PATH:-}" >> $GITHUB_ENV
echo "PKG_CONFIG_PATH=$LOCAL_PKG_CONFIG:${PKG_CONFIG_PATH:-}" >> $GITHUB_ENV
echo "C_INCLUDE_PATH=$LOCAL_INCLUDE:${C_INCLUDE_PATH:-}" >> $GITHUB_ENV
echo "CPLUS_INCLUDE_PATH=$LOCAL_INCLUDE:${CPLUS_INCLUDE_PATH:-}" >> $GITHUB_ENV
# Check and install PostgreSQL client libraries if needed
if ! pkg-config --exists libpq 2>/dev/null; then
echo "Installing libpq..."
ARCH=$(dpkg --print-architecture 2>/dev/null || echo "amd64")
WORK_DIR="$LOCAL_DIR/tmp"
mkdir -p "$WORK_DIR" && cd "$WORK_DIR"
# Download PostgreSQL 17 packages
wget -q "https://apt.postgresql.org/pub/repos/apt/pool/main/p/postgresql-17/libpq5_17.6-1.pgdg+1_${ARCH}.deb"
wget -q "https://apt.postgresql.org/pub/repos/apt/pool/main/p/postgresql-17/libpq-dev_17.6-1.pgdg+1_${ARCH}.deb"
# Extract and install
for pkg in *.deb; do
ar p "$pkg" data.tar.xz | tar -xJ --no-same-owner 2>/dev/null || true
done
cp -r usr/lib/*/libpq* usr/lib/libpq* "$LOCAL_LIB/" 2>/dev/null || true
cp -r usr/include/* "$LOCAL_INCLUDE/" 2>/dev/null || true
find usr -name "*.pc" -exec cp {} "$LOCAL_PKG_CONFIG/" \; 2>/dev/null || true
# Fix pkg-config paths
sed -i "s|/usr|$LOCAL_DIR|g" "$LOCAL_PKG_CONFIG"/*.pc 2>/dev/null || true
cd "$HOME" && rm -rf "$WORK_DIR"
# Export build flags for libpq
echo "LDFLAGS=-L$LOCAL_LIB ${LDFLAGS:-}" >> $GITHUB_ENV
echo "CPPFLAGS=-I$LOCAL_INCLUDE ${CPPFLAGS:-}" >> $GITHUB_ENV
echo "LIBRARY_PATH=$LOCAL_LIB:${LIBRARY_PATH:-}" >> $GITHUB_ENV
echo "RUSTFLAGS=-L $LOCAL_LIB" >> $GITHUB_ENV
echo "✓ libpq installed"
else
echo "✓ libpq found: $(pkg-config --modversion libpq 2>/dev/null || echo 'version unknown')"
fi
# Check and install LLVM/Clang if needed
if ! command -v clang &> /dev/null || ! ls $LOCAL_LIB/libclang* 2>/dev/null && ! ldconfig -p 2>/dev/null | grep -q libclang; then
echo "LLVM/Clang not found, installing locally..."
LLVM_VERSION="18.1.8"
ARCH=$(uname -m)
# Map architecture names
case "$ARCH" in
x86_64) LLVM_ARCH="x86_64-linux-gnu-ubuntu-22.04" ;;
aarch64) LLVM_ARCH="aarch64-linux-gnu" ;;
*) LLVM_ARCH="$ARCH-linux-gnu" ;;
esac
# Download pre-built LLVM/Clang binaries
echo "Downloading LLVM ${LLVM_VERSION} for ${LLVM_ARCH}..."
wget -q -O- "https://github.com/llvm/llvm-project/releases/download/llvmorg-${LLVM_VERSION}/clang+llvm-${LLVM_VERSION}-${LLVM_ARCH}.tar.xz" | \
tar -xJf - -C /tmp --strip-components=1 || {
echo "Failed to download pre-built binaries, trying alternative version..."
# Try an older, more widely available version
LLVM_VERSION="17.0.6"
wget -q -O- "https://github.com/llvm/llvm-project/releases/download/llvmorg-${LLVM_VERSION}/clang+llvm-${LLVM_VERSION}-${LLVM_ARCH}.tar.xz" | \
tar -xJf - -C /tmp --strip-components=1
}
# Copy required files
if [ -d "/tmp/bin" ]; then
cp /tmp/bin/clang* "$LOCAL_BIN/" 2>/dev/null || true
cp /tmp/bin/llvm-config "$LOCAL_BIN/" 2>/dev/null || true
cp -r /tmp/lib/libclang* "$LOCAL_LIB/" 2>/dev/null || true
cp -r /tmp/lib/clang "$LOCAL_LIB/" 2>/dev/null || true
cp -r /tmp/include/clang* "$LOCAL_INCLUDE/" 2>/dev/null || true
rm -rf /tmp/bin /tmp/lib /tmp/include /tmp/share
# Set LIBCLANG_PATH for rust bindgen
echo "LIBCLANG_PATH=$LOCAL_LIB" >> $GITHUB_ENV
echo "LLVM_CONFIG_PATH=$LOCAL_BIN/llvm-config" >> $GITHUB_ENV
fi
echo "✓ LLVM/Clang ${LLVM_VERSION} installed locally"
else
echo "✓ clang found: $(clang --version 2>/dev/null | head -n1 || echo 'installed')"
fi
echo "All required system dependencies ready!"
# Install protoc only when install-deps is true
- name: Install Protoc
if: inputs.install-deps == 'true'
uses: arduino/setup-protoc@v3
with:
repo-token: ${{ github.token }}
repo-token: ${{ github.token }}
# Auto-install protoc when install-deps is false (for self-hosted runners)
- name: Setup Protoc (self-hosted)
if: inputs.install-deps == 'false'
shell: bash
run: |
echo "Checking and installing protoc locally if needed..."
if ! command -v protoc &> /dev/null; then
echo "protoc not found, installing locally..."
PROTOC_VERSION="28.3"
ARCH=$(uname -m)
# Map architecture names for protoc
case "$ARCH" in
x86_64) PROTOC_ARCH="x86_64" ;;
aarch64) PROTOC_ARCH="aarch_64" ;;
*) PROTOC_ARCH="$ARCH" ;;
esac
# Download and install protoc
mkdir -p ~/.local/bin
wget -q -O /tmp/protoc.zip "https://github.com/protocolbuffers/protobuf/releases/download/v${PROTOC_VERSION}/protoc-${PROTOC_VERSION}-linux-${PROTOC_ARCH}.zip"
unzip -q -o /tmp/protoc.zip -d ~/.local
rm /tmp/protoc.zip
# Make sure it's executable
chmod +x ~/.local/bin/protoc
# Add to PATH if not already there
echo "$HOME/.local/bin" >> $GITHUB_PATH
export PATH="$HOME/.local/bin:$PATH"
echo "✓ protoc ${PROTOC_VERSION} installed locally"
else
PROTOC_VERSION=$(protoc --version | grep -oP '\d+\.\d+(\.\d+)?')
echo "✓ protoc found: version $PROTOC_VERSION"
# Check minimum version (3.0 or higher recommended)
MAJOR_VERSION=$(echo $PROTOC_VERSION | cut -d. -f1)
if [ "$MAJOR_VERSION" -lt 3 ]; then
echo "WARNING: protoc version $PROTOC_VERSION is older than recommended (3.0+)"
fi
fi
echo "Protoc ready!"

View file

@ -21,7 +21,6 @@ jobs:
RUSTC_WRAPPER: "sccache"
CARGO_INCREMENTAL: "0"
CARGO_TERM_COLOR: always
RUSTFLAGS: "-C linker=clang -C link-arg=-fuse-ld=mold"
SCCACHE_GHA_ENABLED: "true"
defaults:
run:
@ -38,7 +37,10 @@ jobs:
- uses: ./.github/workflows/actions/setup-env
with:
cache-key: BUILD-RELEASE
install-deps: false # Self-hosted runners have deps pre-installed
install-deps: false
- name: Set build flags
run: echo "RUSTFLAGS=${{ env.RUSTFLAGS }} -C linker=clang -C link-arg=-fuse-ld=mold" >> $GITHUB_ENV
- name: Build node binary
run: |

View file

@ -17,7 +17,6 @@ on:
env:
CARGO_TERM_COLOR: always
WORKING_DIR: operator
RUSTFLAGS: "-C linker=clang -C link-arg=-fuse-ld=mold"
SCCACHE_GHA_ENABLED: "true"
RUSTC_WRAPPER: "sccache"
@ -56,6 +55,9 @@ jobs:
cache-key: LINT
install-deps: false # Self-hosted runners have deps pre-installed
- name: Set build flags
run: echo "RUSTFLAGS=${{ env.RUSTFLAGS }} -C linker=clang -C link-arg=-fuse-ld=mold" >> $GITHUB_ENV
- name: Run cargo clippy
run: SKIP_WASM_BUILD=1 cargo clippy --features try-runtime,runtime-benchmarks --locked --release

View file

@ -22,7 +22,6 @@ jobs:
RUSTC_WRAPPER: "sccache"
CARGO_INCREMENTAL: "0"
CARGO_TERM_COLOR: always
RUSTFLAGS: "-C linker=clang -C link-arg=-fuse-ld=mold"
SCCACHE_GHA_ENABLED: "true"
defaults:
run:
@ -35,7 +34,11 @@ jobs:
- uses: ./.github/workflows/actions/setup-env
with:
cache-key: "TEST"
install-deps: false # Self-hosted runners have deps pre-installed
install-deps: false
- name: Set build flags
run: echo "RUSTFLAGS=${{ env.RUSTFLAGS }} -C linker=clang -C link-arg=-fuse-ld=mold" >> $GITHUB_ENV
# Cleanup-runner skipped on self-hosted runners (bare-metal manages disk space externally)
- name: Install nextest
run: |

5143
operator/Cargo.lock generated

File diff suppressed because it is too large Load diff

View file

@ -39,6 +39,7 @@ alloy-core = { version = "0.8.15", default-features = false }
alloy-primitives = { version = "0.4.2", default-features = false }
alloy-sol-types = { version = "0.4.2", default-features = false }
array-bytes = { version = "6.2.2", default-features = false }
async-channel = "1.8.0"
async-trait = { version = "0.1.42" }
blake2-rfc = { version = "0.2.18", default-features = false }
byte-slice-cast = { version = "1.2.1", default-features = false }
@ -96,6 +97,7 @@ frame-system-rpc-runtime-api = { git = "https://github.com/paritytech/polkadot-s
frame-try-runtime = { git = "https://github.com/paritytech/polkadot-sdk", tag = "polkadot-stable2412-6", default-features = false }
mmr-rpc = { git = "https://github.com/paritytech/polkadot-sdk", tag = "polkadot-stable2412-6", default-features = false }
pallet-authorship = { git = "https://github.com/paritytech/polkadot-sdk", tag = "polkadot-stable2412-6", default-features = false }
pallet-assets = { git = "https://github.com/paritytech/polkadot-sdk", tag = "polkadot-stable2412-6", default-features = false }
pallet-babe = { git = "https://github.com/paritytech/polkadot-sdk", tag = "polkadot-stable2412-6", default-features = false }
pallet-balances = { git = "https://github.com/paritytech/polkadot-sdk", tag = "polkadot-stable2412-6", default-features = false }
pallet-beefy = { git = "https://github.com/paritytech/polkadot-sdk", tag = "polkadot-stable2412-6", default-features = false }
@ -109,6 +111,7 @@ pallet-multisig = { git = "https://github.com/paritytech/polkadot-sdk", tag = "p
pallet-offences = { git = "https://github.com/paritytech/polkadot-sdk", tag = "polkadot-stable2412-6", default-features = false }
pallet-parameters = { git = "https://github.com/paritytech/polkadot-sdk", tag = "polkadot-stable2412-6", default-features = false }
pallet-preimage = { git = "https://github.com/paritytech/polkadot-sdk", tag = "polkadot-stable2412-6", default-features = false }
pallet-collator-selection = { git = "https://github.com/paritytech/polkadot-sdk.git", tag = "polkadot-stable2412-6", default-features = false }
pallet-collective = { git = "https://github.com/paritytech/polkadot-sdk", tag = "polkadot-stable2412-6", default-features = false }
pallet-conviction-voting = { git = "https://github.com/paritytech/polkadot-sdk", tag = "polkadot-stable2412-6", default-features = false }
pallet-nfts = { git = "https://github.com/paritytech/polkadot-sdk", tag = "polkadot-stable2412-6", default-features = false }
@ -125,6 +128,8 @@ pallet-treasury = { git = "https://github.com/paritytech/polkadot-sdk", tag = "p
pallet-utility = { git = "https://github.com/paritytech/polkadot-sdk", tag = "polkadot-stable2412-6", default-features = false }
pallet-whitelist = { git = "https://github.com/paritytech/polkadot-sdk", tag = "polkadot-stable2412-6", default-features = false }
pallet-xcm = { git = "https://github.com/paritytech/polkadot-sdk", tag = "polkadot-stable2412-6", default-features = false }
parachain-info = { package = "staging-parachain-info", git = "https://github.com/paritytech/polkadot-sdk.git", tag = "polkadot-stable2412-6", default-features = false }
parachains-common = { git = "https://github.com/paritytech/polkadot-sdk.git", tag = "polkadot-stable2412-6", default-features = false }
polkadot-parachain-primitives = { git = "https://github.com/paritytech/polkadot-sdk", tag = "polkadot-stable2412-6", default-features = false }
polkadot-primitives = { git = "https://github.com/paritytech/polkadot-sdk", tag = "polkadot-stable2412-6", default-features = false }
polkadot-runtime-common = { git = "https://github.com/paritytech/polkadot-sdk", tag = "polkadot-stable2412-6", default-features = false }
@ -207,52 +212,69 @@ snowbridge-verification-primitives = { path = "primitives/snowbridge/verificatio
# Frontier (wasm)
evm = { git = "https://github.com/rust-ethereum/evm", rev = "6d86fe2d3bcc14887c2575f62958a67ac2d523db", default-features = false }
fp-account = { git = "https://github.com/polkadot-evm/frontier", rev="75329a2df49e2cc7981485392c31160929d1bd48", default-features = false }
fp-evm = { git = "https://github.com/polkadot-evm/frontier", rev="75329a2df49e2cc7981485392c31160929d1bd48", default-features = false }
fp-rpc = { git = "https://github.com/polkadot-evm/frontier", rev="75329a2df49e2cc7981485392c31160929d1bd48", default-features = false }
fp-self-contained = { git = "https://github.com/polkadot-evm/frontier", rev="75329a2df49e2cc7981485392c31160929d1bd48", default-features = false }
fp-storage = { git = "https://github.com/polkadot-evm/frontier", rev="75329a2df49e2cc7981485392c31160929d1bd48", default-features = false }
pallet-base-fee = { git = "https://github.com/polkadot-evm/frontier", rev="75329a2df49e2cc7981485392c31160929d1bd48", default-features = false }
pallet-dynamic-fee = { git = "https://github.com/polkadot-evm/frontier", rev="75329a2df49e2cc7981485392c31160929d1bd48", default-features = false }
pallet-ethereum = { git = "https://github.com/polkadot-evm/frontier/", rev="75329a2df49e2cc7981485392c31160929d1bd48", default-features = false }
pallet-evm = { git = "https://github.com/polkadot-evm/frontier/", rev="75329a2df49e2cc7981485392c31160929d1bd48", default-features = false }
pallet-evm-chain-id = { git = "https://github.com/polkadot-evm/frontier/", rev="75329a2df49e2cc7981485392c31160929d1bd48", default-features = false }
pallet-evm-precompile-blake2 = { git = "https://github.com/polkadot-evm/frontier", rev="75329a2df49e2cc7981485392c31160929d1bd48", default-features = false }
pallet-evm-precompile-bn128 = { git = "https://github.com/polkadot-evm/frontier", rev="75329a2df49e2cc7981485392c31160929d1bd48", default-features = false }
pallet-evm-precompile-modexp = { git = "https://github.com/polkadot-evm/frontier", rev="75329a2df49e2cc7981485392c31160929d1bd48", default-features = false }
pallet-evm-precompile-sha3fips = { git = "https://github.com/polkadot-evm/frontier", rev="75329a2df49e2cc7981485392c31160929d1bd48", default-features = false }
pallet-evm-precompile-simple = { git = "https://github.com/polkadot-evm/frontier", rev="75329a2df49e2cc7981485392c31160929d1bd48", default-features = false }
pallet-hotfix-sufficients = { git = "https://github.com/polkadot-evm/frontier", rev="75329a2df49e2cc7981485392c31160929d1bd48", default-features = false }
precompile-utils = { git = "https://github.com/polkadot-evm/frontier/", rev="75329a2df49e2cc7981485392c31160929d1bd48", default-features = false }
precompile-utils-macro = { git = "https://github.com/polkadot-evm/frontier", rev="75329a2df49e2cc7981485392c31160929d1bd48", default-features = false }
fp-account = { git = "https://github.com/polkadot-evm/frontier", branch = "stable2412", default-features = false }
fp-evm = { git = "https://github.com/polkadot-evm/frontier", branch = "stable2412", default-features = false }
fp-rpc = { git = "https://github.com/polkadot-evm/frontier", branch = "stable2412", default-features = false }
fp-self-contained = { git = "https://github.com/polkadot-evm/frontier", branch = "stable2412", default-features = false }
fp-storage = { git = "https://github.com/polkadot-evm/frontier", branch = "stable2412", default-features = false }
pallet-base-fee = { git = "https://github.com/polkadot-evm/frontier", branch = "stable2412", default-features = false }
pallet-dynamic-fee = { git = "https://github.com/polkadot-evm/frontier", branch = "stable2412", default-features = false }
pallet-ethereum = { git = "https://github.com/polkadot-evm/frontier/", branch = "stable2412", default-features = false }
pallet-evm = { git = "https://github.com/polkadot-evm/frontier/", branch = "stable2412", default-features = false }
pallet-evm-chain-id = { git = "https://github.com/polkadot-evm/frontier/", branch = "stable2412", default-features = false }
pallet-evm-precompile-blake2 = { git = "https://github.com/polkadot-evm/frontier", branch = "stable2412", default-features = false }
pallet-evm-precompile-bn128 = { git = "https://github.com/polkadot-evm/frontier", branch = "stable2412", default-features = false }
pallet-evm-precompile-modexp = { git = "https://github.com/polkadot-evm/frontier", branch = "stable2412", default-features = false }
pallet-evm-precompile-sha3fips = { git = "https://github.com/polkadot-evm/frontier", branch = "stable2412", default-features = false }
pallet-evm-precompile-simple = { git = "https://github.com/polkadot-evm/frontier", branch = "stable2412", default-features = false }
pallet-hotfix-sufficients = { git = "https://github.com/polkadot-evm/frontier", branch = "stable2412", default-features = false }
precompile-utils = { git = "https://github.com/polkadot-evm/frontier/", branch = "stable2412", default-features = false }
precompile-utils-macro = { git = "https://github.com/polkadot-evm/frontier", branch = "stable2412", default-features = false }
# Frontier (client)
fc-api = { git = "https://github.com/polkadot-evm/frontier", rev="75329a2df49e2cc7981485392c31160929d1bd48", default-features = false }
fc-cli = { git = "https://github.com/polkadot-evm/frontier", rev="75329a2df49e2cc7981485392c31160929d1bd48", default-features = false }
fc-consensus = { git = "https://github.com/polkadot-evm/frontier", rev="75329a2df49e2cc7981485392c31160929d1bd48", default-features = false }
fc-db = { git = "https://github.com/polkadot-evm/frontier", rev="75329a2df49e2cc7981485392c31160929d1bd48" }
fc-mapping-sync = { git = "https://github.com/polkadot-evm/frontier", rev="75329a2df49e2cc7981485392c31160929d1bd48", default-features = false }
fc-rpc = { git = "https://github.com/polkadot-evm/frontier", rev="75329a2df49e2cc7981485392c31160929d1bd48", default-features = false }
fc-rpc-core = { git = "https://github.com/polkadot-evm/frontier", rev="75329a2df49e2cc7981485392c31160929d1bd48", default-features = false }
fc-storage = { git = "https://github.com/polkadot-evm/frontier", rev="75329a2df49e2cc7981485392c31160929d1bd48", default-features = false }
fc-api = { git = "https://github.com/polkadot-evm/frontier", branch = "stable2412", default-features = false }
fc-cli = { git = "https://github.com/polkadot-evm/frontier", branch = "stable2412", default-features = false }
fc-consensus = { git = "https://github.com/polkadot-evm/frontier", branch = "stable2412", default-features = false }
fc-db = { git = "https://github.com/polkadot-evm/frontier", branch = "stable2412" }
fc-mapping-sync = { git = "https://github.com/polkadot-evm/frontier", branch = "stable2412", default-features = false }
fc-rpc = { git = "https://github.com/polkadot-evm/frontier", branch = "stable2412", default-features = false }
fc-rpc-core = { git = "https://github.com/polkadot-evm/frontier", branch = "stable2412", default-features = false }
fc-storage = { git = "https://github.com/polkadot-evm/frontier", branch = "stable2412", default-features = false }
# StorageHub
storage-hub-runtime = { git = "https://github.com/Moonsong-Labs/storage-hub", rev = "f8281283b6003a3009a32431ed0f3cd628561d6b", default-features = false }
pallet-bucket-nfts = { git = "https://github.com/Moonsong-Labs/storage-hub", rev = "f8281283b6003a3009a32431ed0f3cd628561d6b", default-features = false }
pallet-cr-randomness = { git = "https://github.com/Moonsong-Labs/storage-hub", rev = "f8281283b6003a3009a32431ed0f3cd628561d6b", default-features = false }
pallet-file-system = { git = "https://github.com/Moonsong-Labs/storage-hub", rev = "f8281283b6003a3009a32431ed0f3cd628561d6b", default-features = false }
pallet-file-system-runtime-api = { git = "https://github.com/Moonsong-Labs/storage-hub", rev = "f8281283b6003a3009a32431ed0f3cd628561d6b", default-features = false }
pallet-payment-streams = { git = "https://github.com/Moonsong-Labs/storage-hub", rev = "f8281283b6003a3009a32431ed0f3cd628561d6b", default-features = false }
pallet-payment-streams-runtime-api = { git = "https://github.com/Moonsong-Labs/storage-hub", rev = "f8281283b6003a3009a32431ed0f3cd628561d6b", default-features = false }
pallet-proofs-dealer = { git = "https://github.com/Moonsong-Labs/storage-hub", rev = "f8281283b6003a3009a32431ed0f3cd628561d6b", default-features = false }
pallet-proofs-dealer-runtime-api = { git = "https://github.com/Moonsong-Labs/storage-hub", rev = "f8281283b6003a3009a32431ed0f3cd628561d6b", default-features = false }
pallet-randomness = { git = "https://github.com/Moonsong-Labs/storage-hub", rev = "f8281283b6003a3009a32431ed0f3cd628561d6b", default-features = false }
pallet-storage-providers = { git = "https://github.com/Moonsong-Labs/storage-hub", rev = "f8281283b6003a3009a32431ed0f3cd628561d6b", default-features = false }
pallet-storage-providers-runtime-api = { git = "https://github.com/Moonsong-Labs/storage-hub", rev = "f8281283b6003a3009a32431ed0f3cd628561d6b", default-features = false }
shp-constants = { git = "https://github.com/Moonsong-Labs/storage-hub", rev = "f8281283b6003a3009a32431ed0f3cd628561d6b", default-features = false }
shp-file-metadata = { git = "https://github.com/Moonsong-Labs/storage-hub", rev = "f8281283b6003a3009a32431ed0f3cd628561d6b", default-features = false }
shp-traits = { git = "https://github.com/Moonsong-Labs/storage-hub", rev = "f8281283b6003a3009a32431ed0f3cd628561d6b", default-features = false }
shp-treasury-funding = { git = "https://github.com/Moonsong-Labs/storage-hub", rev = "f8281283b6003a3009a32431ed0f3cd628561d6b", default-features = false }
shp-forest-verifier = { git = "https://github.com/Moonsong-Labs/storage-hub", rev = "f8281283b6003a3009a32431ed0f3cd628561d6b", default-features = false }
shp-file-key-verifier = { git = "https://github.com/Moonsong-Labs/storage-hub", rev = "f8281283b6003a3009a32431ed0f3cd628561d6b", default-features = false }
shp-data-price-updater = { git = "https://github.com/Moonsong-Labs/storage-hub", rev = "f8281283b6003a3009a32431ed0f3cd628561d6b", default-features = false }
## Runtime
storage-hub-runtime = { git = "https://github.com/Moonsong-Labs/storage-hub.git", rev = "b78b5648a38849cee1a462a1b938d63d27e68547", default-features = false }
pallet-bucket-nfts = { git = "https://github.com/Moonsong-Labs/storage-hub.git", rev = "b78b5648a38849cee1a462a1b938d63d27e68547", default-features = false }
pallet-cr-randomness = { git = "https://github.com/Moonsong-Labs/storage-hub.git", rev = "b78b5648a38849cee1a462a1b938d63d27e68547", default-features = false }
pallet-file-system = { git = "https://github.com/Moonsong-Labs/storage-hub.git", rev = "b78b5648a38849cee1a462a1b938d63d27e68547", default-features = false }
pallet-file-system-runtime-api = { git = "https://github.com/Moonsong-Labs/storage-hub.git", rev = "b78b5648a38849cee1a462a1b938d63d27e68547", default-features = false }
pallet-payment-streams = { git = "https://github.com/Moonsong-Labs/storage-hub.git", rev = "b78b5648a38849cee1a462a1b938d63d27e68547", default-features = false }
pallet-payment-streams-runtime-api = { git = "https://github.com/Moonsong-Labs/storage-hub.git", rev = "b78b5648a38849cee1a462a1b938d63d27e68547", default-features = false }
pallet-proofs-dealer = { git = "https://github.com/Moonsong-Labs/storage-hub.git", rev = "b78b5648a38849cee1a462a1b938d63d27e68547", default-features = false }
pallet-proofs-dealer-runtime-api = { git = "https://github.com/Moonsong-Labs/storage-hub.git", rev = "b78b5648a38849cee1a462a1b938d63d27e68547", default-features = false }
pallet-randomness = { git = "https://github.com/Moonsong-Labs/storage-hub.git", rev = "b78b5648a38849cee1a462a1b938d63d27e68547", default-features = false }
pallet-storage-providers = { git = "https://github.com/Moonsong-Labs/storage-hub.git", rev = "b78b5648a38849cee1a462a1b938d63d27e68547", default-features = false }
pallet-storage-providers-runtime-api = { git = "https://github.com/Moonsong-Labs/storage-hub.git", rev = "b78b5648a38849cee1a462a1b938d63d27e68547", default-features = false }
shp-constants = { git = "https://github.com/Moonsong-Labs/storage-hub.git", rev = "b78b5648a38849cee1a462a1b938d63d27e68547", default-features = false }
shp-file-metadata = { git = "https://github.com/Moonsong-Labs/storage-hub.git", rev = "b78b5648a38849cee1a462a1b938d63d27e68547", default-features = false }
shp-traits = { git = "https://github.com/Moonsong-Labs/storage-hub.git", rev = "b78b5648a38849cee1a462a1b938d63d27e68547", default-features = false }
shp-treasury-funding = { git = "https://github.com/Moonsong-Labs/storage-hub.git", rev = "b78b5648a38849cee1a462a1b938d63d27e68547", default-features = false }
shp-forest-verifier = { git = "https://github.com/Moonsong-Labs/storage-hub.git", rev = "b78b5648a38849cee1a462a1b938d63d27e68547", default-features = false }
shp-file-key-verifier = { git = "https://github.com/Moonsong-Labs/storage-hub.git", rev = "b78b5648a38849cee1a462a1b938d63d27e68547", default-features = false }
shp-data-price-updater = { git = "https://github.com/Moonsong-Labs/storage-hub.git", rev = "b78b5648a38849cee1a462a1b938d63d27e68547", default-features = false }
## Client
shc-actors-framework = { git = "https://github.com/Moonsong-Labs/storage-hub.git", rev = "b78b5648a38849cee1a462a1b938d63d27e68547", default-features = false }
shc-actors-derive = { git = "https://github.com/Moonsong-Labs/storage-hub.git", rev = "b78b5648a38849cee1a462a1b938d63d27e68547", default-features = false }
shc-blockchain-service = { git = "https://github.com/Moonsong-Labs/storage-hub.git", rev = "b78b5648a38849cee1a462a1b938d63d27e68547", default-features = false }
shc-file-transfer-service = { git = "https://github.com/Moonsong-Labs/storage-hub.git", rev = "b78b5648a38849cee1a462a1b938d63d27e68547", default-features = false }
shc-indexer-service = { git = "https://github.com/Moonsong-Labs/storage-hub.git", rev = "b78b5648a38849cee1a462a1b938d63d27e68547", default-features = false }
shc-indexer-db = { git = "https://github.com/Moonsong-Labs/storage-hub.git", rev = "b78b5648a38849cee1a462a1b938d63d27e68547", default-features = false }
shc-common = { git = "https://github.com/Moonsong-Labs/storage-hub.git", rev = "b78b5648a38849cee1a462a1b938d63d27e68547", default-features = false }
shc-file-manager = { git = "https://github.com/Moonsong-Labs/storage-hub.git", rev = "b78b5648a38849cee1a462a1b938d63d27e68547", default-features = false }
shc-fisherman-service = { git = "https://github.com/Moonsong-Labs/storage-hub.git", rev = "b78b5648a38849cee1a462a1b938d63d27e68547", default-features = false }
shc-forest-manager = { git = "https://github.com/Moonsong-Labs/storage-hub.git", rev = "b78b5648a38849cee1a462a1b938d63d27e68547", default-features = false }
shc-rpc = { git = "https://github.com/Moonsong-Labs/storage-hub.git", rev = "b78b5648a38849cee1a462a1b938d63d27e68547", default-features = false }
shc-client = { git = "https://github.com/Moonsong-Labs/storage-hub.git", rev = "b78b5648a38849cee1a462a1b938d63d27e68547", default-features = false }
shp-opaque = { git = "https://github.com/Moonsong-Labs/storage-hub.git", rev = "b78b5648a38849cee1a462a1b938d63d27e68547", default-features = false }
shp-types = { git = "https://github.com/Moonsong-Labs/storage-hub.git", rev = "b78b5648a38849cee1a462a1b938d63d27e68547", default-features = false }
cumulus-client-service = { git = "https://github.com/paritytech/polkadot-sdk.git", tag = "polkadot-stable2412-6", default-features = false }

View file

@ -32,6 +32,7 @@ log = { workspace = true }
openssl-sys = { workspace = true }
serde_json = { workspace = true, default-features = true }
url = { workspace = true }
async-channel = { workspace = true }
#MMR
mmr-rpc = { workspace = true, default-features = true }
@ -99,6 +100,37 @@ fp-evm = { workspace = true }
fp-rpc = { workspace = true }
pallet-ethereum = { workspace = true }
# StorageHub
pallet-file-system = { workspace = true }
pallet-file-system-runtime-api = { workspace = true }
pallet-payment-streams = { workspace = true }
pallet-payment-streams-runtime-api = { workspace = true }
pallet-proofs-dealer = { workspace = true }
pallet-proofs-dealer-runtime-api = { workspace = true }
pallet-storage-providers = { workspace = true }
pallet-storage-providers-runtime-api = { workspace = true }
shc-actors-framework = { workspace = true }
shc-actors-derive = { workspace = true }
shc-blockchain-service = { workspace = true }
shc-file-transfer-service = { workspace = true }
shc-common = { workspace = true }
shc-file-manager = { workspace = true }
shc-fisherman-service = { workspace = true }
shc-forest-manager = { workspace = true }
shc-indexer-db = { workspace = true }
shc-indexer-service = { workspace = true }
shc-rpc = { workspace = true }
shc-client = { workspace = true }
shp-constants = { workspace = true }
shp-file-key-verifier = { workspace = true }
shp-file-metadata = { workspace = true }
shp-opaque = { workspace = true }
shp-traits = { workspace = true }
shp-types = { workspace = true }
sp-keystore = { workspace = true }
serde = { workspace = true, default-features = true }
cumulus-client-service = { workspace = true }
[build-dependencies]
substrate-build-script-utils = { workspace = true, default-features = true }
@ -109,6 +141,7 @@ std = [
"datahaven-stagenet-runtime/std",
"datahaven-mainnet-runtime/std",
"datahaven-testnet-runtime/std",
"shp-opaque/std"
]
# Dependencies that are only required if runtime benchmarking should be build.

View file

@ -1,7 +1,18 @@
use crate::command::ProviderOptions;
use crate::eth::EthConfiguration;
use clap::{Parser, ValueEnum};
use sc_cli::RunCmd;
use serde::{Deserialize, Deserializer};
use shc_client::builder::{
BlockchainServiceOptions, BspChargeFeesOptions, BspMoveBucketOptions, BspSubmitProofOptions,
BspUploadFileOptions, FishermanOptions, IndexerOptions, MspChargeFeesOptions,
MspMoveBucketOptions,
};
use shc_rpc::RpcConfig;
use shp_types::StorageDataUnit;
// Available Sealing methods.
#[derive(Copy, Clone, Debug, Default, clap::ValueEnum)]
#[derive(Copy, Clone, Debug, Default, ValueEnum)]
pub enum Sealing {
/// Seal using rpc method.
#[default]
@ -10,7 +21,7 @@ pub enum Sealing {
Instant,
}
#[derive(Debug, clap::Parser)]
#[derive(Debug, Parser)]
pub struct Cli {
#[command(subcommand)]
pub subcommand: Option<Subcommand>,
@ -25,6 +36,10 @@ pub struct Cli {
#[command(flatten)]
pub eth: EthConfiguration,
/// Provider configurations
#[command(flatten)]
pub provider_config: ProviderConfigurations,
}
#[derive(Debug, clap::Subcommand)]
@ -62,3 +77,446 @@ pub enum Subcommand {
/// Db meta columns information.
ChainInfo(sc_cli::ChainInfoCmd),
}
#[derive(ValueEnum, Clone, Debug, Eq, PartialEq)]
pub enum ProviderType {
/// Main Storage Provider
Msp,
/// Backup Storage Provider
Bsp,
/// User role
User,
}
impl<'de> serde::Deserialize<'de> for ProviderType {
fn deserialize<D: Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
let s = String::deserialize(d)?;
let provider_type = match s.as_str() {
"bsp" => ProviderType::Bsp,
"msp" => ProviderType::Msp,
"user" => ProviderType::User,
_ => {
return Err(serde::de::Error::custom(
"Cannot parse `provider_type`. Invalid value.",
))
}
};
Ok(provider_type)
}
}
#[derive(ValueEnum, Clone, Debug)]
pub enum StorageLayer {
/// RocksDB with path.
RocksDB,
/// In Memory
Memory,
}
impl<'de> serde::Deserialize<'de> for StorageLayer {
fn deserialize<D: Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
let s = String::deserialize(d)?;
let storage_layer = match s.as_str() {
"rocksdb" => StorageLayer::RocksDB,
"memory" => StorageLayer::Memory,
_ => {
return Err(serde::de::Error::custom(
"Cannot parse `storage_type`. Invalid value.",
))
}
};
Ok(storage_layer)
}
}
#[derive(Debug, Parser)]
#[group(skip)]
pub struct ProviderConfigurations {
/// Run node as a StorageHub provider.
#[arg(long)]
pub provider: bool,
/// Run the node in maintenance mode.
/// In this mode, the node will not import blocks or participate in consensus,
/// but will allow specific RPC calls for file and storage management.
#[arg(long, default_value = "false")]
pub maintenance_mode: bool,
/// Type of StorageHub provider.
#[arg(
long,
value_enum,
value_name = "PROVIDER_TYPE",
required_if_eq("provider", "true")
)]
pub provider_type: Option<ProviderType>,
/// Maximum storage capacity of the provider (bytes).
#[arg(long, required_if_eq_all([
("provider", "true"),
("provider_type", "msp"),
]), required_if_eq_all([
("provider", "true"),
("provider_type", "bsp"),
]))]
pub max_storage_capacity: Option<StorageDataUnit>,
/// Jump capacity (bytes).
#[arg(long, required_if_eq_all([
("provider", "true"),
("provider_type", "msp"),
]), required_if_eq_all([
("provider", "true"),
("provider_type", "bsp"),
]))]
pub jump_capacity: Option<StorageDataUnit>,
/// Type of StorageHub provider.
/// Currently: `memory` and `rocks-db`.
#[arg(
long,
value_enum,
value_name = "STORAGE_LAYER",
default_value = "memory"
)]
pub storage_layer: Option<StorageLayer>,
/// Storage location in the file system
#[arg(long, required_if_eq("storage_layer", "rocks-db"))]
pub storage_path: Option<String>,
/// Extrinsic retry timeout in seconds.
#[arg(long, default_value = "60")]
pub extrinsic_retry_timeout: Option<u64>,
/// The minimum number of blocks behind the current best block to consider the node out of sync.
#[arg(long, default_value = "5")]
pub sync_mode_min_blocks_behind: Option<u32>,
/// On blocks that are multiples of this number, the blockchain service will trigger the catch of proofs.
#[arg(long, default_value = "4")]
pub check_for_pending_proofs_period: Option<u32>,
/// The maximum number of blocks from the past that will be processed for catching up the root changes.
#[arg(long, default_value = "10")]
pub max_blocks_behind_to_catch_up_root_changes: Option<u32>,
// ============== Provider RPC options ==============
// ============== Remote file upload/download options ==============
/// Maximum file size in bytes (default: 10GB)
#[arg(
long,
value_name = "BYTES",
help_heading = "RPC - Remote File Options",
default_value = "10737418240"
)]
pub max_file_size: Option<u64>,
/// Connection timeout in seconds (default: 30)
#[arg(long, value_name = "SECONDS", default_value = "30")]
pub connection_timeout: Option<u64>,
/// Read timeout in seconds (default: 300)
#[arg(long, value_name = "SECONDS", default_value = "300")]
pub read_timeout: Option<u64>,
/// Whether to follow redirects (default: true)
#[arg(long, value_name = "BOOLEAN", default_value = "true")]
pub follow_redirects: Option<bool>,
/// Maximum number of redirects (default: 10)
#[arg(long, value_name = "COUNT", default_value = "10")]
pub max_redirects: Option<u64>,
/// User agent string (default: "StorageHub-Client/1.0")
#[arg(long, value_name = "STRING", default_value = "StorageHub-Client/1.0")]
pub user_agent: Option<String>,
/// Chunk size in bytes. This is different from the FILE_CHUNK_SIZE constant in the runtime, as it only affects file upload/download. (default: 8KB)
#[arg(long, value_name = "BYTES", default_value = "8192")]
pub chunk_size: Option<u64>,
/// Number of `chunk_size` chunks to buffer during upload/download. (default: 512)
#[arg(long, value_name = "COUNT", default_value = "512")]
pub chunks_buffer: Option<u64>,
// ============== MSP Charge Fees task options ==============
/// Enable and configure MSP Charge Fees task.
#[arg(long)]
pub msp_charge_fees_task: bool,
/// Minimum debt threshold for charging users.
#[arg(
long,
value_name = "AMOUNT",
help_heading = "MSP Charge Fees Options",
required_if_eq_all([
("msp_charge_fees_task", "true"),
("provider_type", "msp"),
])
)]
pub msp_charge_fees_min_debt: Option<u64>,
/// MSP charging fees period (in blocks).
/// Setting it to 600 with a block every 6 seconds will charge user every hour.
#[arg(long, required_if_eq_all([
("provider", "true"),
("provider_type", "msp"),
]))]
pub msp_charging_period: Option<u32>,
// ============== MSP Move Bucket task options ==============
/// Enable and configure MSP Move Bucket task.
#[arg(long)]
pub msp_move_bucket_task: bool,
/// Maximum number of times to retry a move bucket request.
#[arg(
long,
value_name = "COUNT",
help_heading = "MSP Move Bucket Options",
required_if_eq_all([
("msp_move_bucket_task", "true"),
("provider_type", "msp"),
])
)]
pub msp_move_bucket_max_try_count: Option<u32>,
/// Maximum tip amount to use when submitting a move bucket request extrinsic.
#[arg(
long,
value_name = "AMOUNT",
help_heading = "MSP Move Bucket Options",
required_if_eq_all([
("msp_move_bucket_task", "true"),
("provider_type", "msp"),
])
)]
pub msp_move_bucket_max_tip: Option<u128>,
// ============== BSP Upload File task options ==============
/// Enable and configure BSP Upload File task.
#[arg(long)]
pub bsp_upload_file_task: bool,
/// Maximum number of times to retry an upload file request.
#[arg(
long,
value_name = "COUNT",
help_heading = "BSP Upload File Options",
required_if_eq_all([
("bsp_upload_file_task", "true"),
("provider_type", "bsp"),
])
)]
pub bsp_upload_file_max_try_count: Option<u32>,
/// Maximum tip amount to use when submitting an upload file request extrinsic.
#[arg(
long,
value_name = "AMOUNT",
help_heading = "BSP Upload File Options",
required_if_eq_all([
("bsp_upload_file_task", "true"),
("provider_type", "bsp"),
])
)]
pub bsp_upload_file_max_tip: Option<u128>,
// ============== BSP Move Bucket task options ==============
/// Enable and configure BSP Move Bucket task.
#[arg(long)]
pub bsp_move_bucket_task: bool,
/// Grace period in seconds to accept download requests after a bucket move is accepted.
#[arg(
long,
value_name = "SECONDS",
help_heading = "BSP Move Bucket Options",
required_if_eq_all([
("bsp_move_bucket_task", "true"),
("provider_type", "bsp"),
])
)]
pub bsp_move_bucket_grace_period: Option<u64>,
// ============== BSP Charge Fees task options ==============
/// Enable and configure BSP Charge Fees task.
#[arg(long)]
pub bsp_charge_fees_task: bool,
/// Minimum debt threshold for charging users.
#[arg(
long,
value_name = "AMOUNT",
help_heading = "BSP Charge Fees Options",
required_if_eq_all([
("bsp_charge_fees_task", "true"),
("provider_type", "bsp"),
])
)]
pub bsp_charge_fees_min_debt: Option<u64>,
// ============== BSP Submit Proof task options ==============
/// Enable and configure BSP Submit Proof task.
#[arg(long)]
pub bsp_submit_proof_task: bool,
/// Maximum number of attempts to submit a proof.
#[arg(
long,
value_name = "COUNT",
help_heading = "BSP Submit Proof Options",
required_if_eq_all([
("bsp_submit_proof_task", "true"),
("provider_type", "bsp"),
])
)]
pub bsp_submit_proof_max_attempts: Option<u32>,
}
impl ProviderConfigurations {
pub fn provider_options(&self) -> ProviderOptions {
// Configure RPC options for Provider
let mut rpc_config = RpcConfig::default();
if let Some(max_file_size) = self.max_file_size {
rpc_config.remote_file.max_file_size = max_file_size;
}
if let Some(connection_timeout) = self.connection_timeout {
rpc_config.remote_file.connection_timeout = connection_timeout;
}
if let Some(read_timeout) = self.read_timeout {
rpc_config.remote_file.read_timeout = read_timeout;
}
if let Some(follow_redirects) = self.follow_redirects {
rpc_config.remote_file.follow_redirects = follow_redirects;
}
if let Some(max_redirects) = self.max_redirects {
rpc_config.remote_file.max_redirects = max_redirects;
}
if let Some(user_agent) = self.user_agent.clone() {
rpc_config.remote_file.user_agent = user_agent;
}
if let Some(chunk_size) = self.chunk_size {
if chunk_size > 0 {
rpc_config.remote_file.chunk_size = chunk_size as usize;
}
}
if let Some(chunks_buffer) = self.chunks_buffer {
if chunks_buffer > 0 {
rpc_config.remote_file.chunks_buffer = chunks_buffer as usize;
}
}
// Get provider type to conditionally apply options
let provider_type = self
.provider_type
.clone()
.expect("Provider type is required");
let mut msp_charge_fees = None;
let mut msp_move_bucket = None;
let mut bsp_upload_file = None;
let mut bsp_move_bucket = None;
let mut bsp_charge_fees = None;
let mut bsp_submit_proof = None;
// Only set MSP options if provider_type is MSP
if provider_type == ProviderType::Msp {
// If specific task flags are enabled, use the provided options
if self.msp_charge_fees_task {
let mut options = MspChargeFeesOptions::default();
options.min_debt = self.msp_charge_fees_min_debt;
msp_charge_fees = Some(options);
}
if self.msp_move_bucket_task {
let mut options = MspMoveBucketOptions::default();
options.max_try_count = self.msp_move_bucket_max_try_count;
options.max_tip = self.msp_move_bucket_max_tip;
msp_move_bucket = Some(options);
}
}
// Only set BSP options if provider_type is BSP
if provider_type == ProviderType::Bsp {
if self.bsp_upload_file_task {
let mut options = BspUploadFileOptions::default();
options.max_try_count = self.bsp_upload_file_max_try_count;
options.max_tip = self.bsp_upload_file_max_tip;
bsp_upload_file = Some(options);
}
if self.bsp_move_bucket_task {
let mut options = BspMoveBucketOptions::default();
options.move_bucket_accepted_grace_period = self.bsp_move_bucket_grace_period;
bsp_move_bucket = Some(options);
}
if self.bsp_charge_fees_task {
let mut options = BspChargeFeesOptions::default();
options.min_debt = self.bsp_charge_fees_min_debt;
bsp_charge_fees = Some(options);
}
if self.bsp_submit_proof_task {
let mut options = BspSubmitProofOptions::default();
options.max_submission_attempts = self.bsp_submit_proof_max_attempts;
bsp_submit_proof = Some(options);
}
}
let mut blockchain_service = None;
if let Some(extrinsic_retry_timeout) = self.extrinsic_retry_timeout {
let mut default_config = BlockchainServiceOptions::default();
default_config.extrinsic_retry_timeout = Some(extrinsic_retry_timeout);
blockchain_service = Some(default_config);
}
if let Some(sync_mode_min_blocks_behind) = self.sync_mode_min_blocks_behind {
let mut default_config = BlockchainServiceOptions::default();
default_config.sync_mode_min_blocks_behind = Some(sync_mode_min_blocks_behind);
blockchain_service = Some(default_config);
}
if let Some(check_for_pending_proofs_period) = self.check_for_pending_proofs_period {
let mut default_config = BlockchainServiceOptions::default();
default_config.check_for_pending_proofs_period = Some(check_for_pending_proofs_period);
blockchain_service = Some(default_config);
}
if let Some(max_blocks_behind_to_catch_up_root_changes) =
self.max_blocks_behind_to_catch_up_root_changes
{
let mut default_config = BlockchainServiceOptions::default();
default_config.max_blocks_behind_to_catch_up_root_changes =
Some(max_blocks_behind_to_catch_up_root_changes);
blockchain_service = Some(default_config);
}
ProviderOptions {
provider_type,
storage_layer: self
.storage_layer
.clone()
.expect("Storage layer is required"),
storage_path: self.storage_path.clone(),
max_storage_capacity: self.max_storage_capacity,
jump_capacity: self.jump_capacity,
rpc_config: rpc_config,
msp_charging_period: self.msp_charging_period,
msp_charge_fees,
msp_move_bucket,
bsp_upload_file,
bsp_move_bucket,
bsp_charge_fees,
bsp_submit_proof,
blockchain_service,
maintenance_mode: self.maintenance_mode,
}
}
}

View file

@ -4,13 +4,64 @@ use crate::service::frontier_database_dir;
use crate::{
benchmarking::{inherent_benchmark_data, RemarkBuilder, TransferKeepAliveBuilder},
chain_spec::{self, NetworkType},
cli::{Cli, Subcommand},
cli::{Cli, ProviderType, StorageLayer, Subcommand},
service,
};
use datahaven_runtime_common::Block;
use frame_benchmarking_cli::{BenchmarkCmd, ExtrinsicFactory, SUBSTRATE_REFERENCE_HARDWARE};
use sc_cli::SubstrateCli;
use sc_service::DatabaseSource;
use serde::Deserialize;
use shc_client::builder::{
BlockchainServiceOptions, BspChargeFeesOptions, BspMoveBucketOptions, BspSubmitProofOptions,
BspUploadFileOptions, MspChargeFeesOptions, MspMoveBucketOptions,
};
use shc_rpc::RpcConfig;
use shp_types::StorageDataUnit;
/// Configuration for the provider.
#[derive(Debug, Clone, Deserialize)]
pub struct ProviderOptions {
/// Provider type.
pub provider_type: ProviderType,
/// Storage layer.
pub storage_layer: StorageLayer,
/// RocksDB Path.
pub storage_path: Option<String>,
/// Maximum storage capacity of the Storage Provider (bytes).
pub max_storage_capacity: Option<StorageDataUnit>,
/// Jump capacity (bytes).
pub jump_capacity: Option<StorageDataUnit>,
/// RPC configuration options.
#[serde(default)]
pub rpc_config: RpcConfig,
/// MSP charging fees frequency.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub msp_charging_period: Option<u32>,
/// Configuration options for MSP charge fees task.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub msp_charge_fees: Option<MspChargeFeesOptions>,
/// Configuration options for MSP move bucket task.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub msp_move_bucket: Option<MspMoveBucketOptions>,
/// Configuration options for BSP upload file task.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub bsp_upload_file: Option<BspUploadFileOptions>,
/// Configuration options for BSP move bucket task.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub bsp_move_bucket: Option<BspMoveBucketOptions>,
/// Configuration options for BSP charge fees task.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub bsp_charge_fees: Option<BspChargeFeesOptions>,
/// Configuration options for BSP submit proof task.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub bsp_submit_proof: Option<BspSubmitProofOptions>,
/// Configuration options for blockchain service.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub blockchain_service: Option<BlockchainServiceOptions>,
/// Whether the node is running in maintenance mode.
pub maintenance_mode: bool,
}
impl SubstrateCli for Cli {
fn impl_name() -> String {
@ -58,7 +109,7 @@ macro_rules! construct_async_run {
match runner.config().chain_spec {
ref spec if spec.is_mainnet() => {
runner.async_run(|$config| {
let $components = service::new_partial::<datahaven_mainnet_runtime::RuntimeApi>(
let $components = service::new_partial::<datahaven_mainnet_runtime::Runtime, datahaven_mainnet_runtime::RuntimeApi>(
&$config,
&mut $cli.eth.clone()
)?;
@ -68,7 +119,7 @@ macro_rules! construct_async_run {
}
ref spec if spec.is_testnet() => {
runner.async_run(|$config| {
let $components = service::new_partial::<datahaven_testnet_runtime::RuntimeApi>(
let $components = service::new_partial::<datahaven_testnet_runtime::Runtime, datahaven_testnet_runtime::RuntimeApi>(
&$config,
&mut $cli.eth.clone()
)?;
@ -78,7 +129,7 @@ macro_rules! construct_async_run {
}
_ => {
runner.async_run(|$config| {
let $components = service::new_partial::<datahaven_stagenet_runtime::RuntimeApi>(
let $components = service::new_partial::<datahaven_stagenet_runtime::Runtime, datahaven_stagenet_runtime::RuntimeApi>(
&$config,
&mut $cli.eth.clone()
)?;
@ -94,24 +145,24 @@ macro_rules! construct_benchmark_partials {
($cli:expr, $config:expr, |$partials:ident| $code:expr) => {
match $config.chain_spec {
ref spec if spec.is_mainnet() => {
let $partials = service::new_partial::<datahaven_mainnet_runtime::RuntimeApi>(
&$config,
&mut $cli.eth.clone(),
)?;
let $partials = service::new_partial::<
datahaven_mainnet_runtime::Runtime,
datahaven_mainnet_runtime::RuntimeApi,
>(&$config, &mut $cli.eth.clone())?;
$code
}
ref spec if spec.is_testnet() => {
let $partials = service::new_partial::<datahaven_testnet_runtime::RuntimeApi>(
&$config,
&mut $cli.eth.clone(),
)?;
let $partials = service::new_partial::<
datahaven_testnet_runtime::Runtime,
datahaven_testnet_runtime::RuntimeApi,
>(&$config, &mut $cli.eth.clone())?;
$code
}
_ => {
let $partials = service::new_partial::<datahaven_stagenet_runtime::RuntimeApi>(
&$config,
&mut $cli.eth.clone(),
)?;
let $partials = service::new_partial::<
datahaven_stagenet_runtime::Runtime,
datahaven_stagenet_runtime::RuntimeApi,
>(&$config, &mut $cli.eth.clone())?;
$code
}
}
@ -261,7 +312,13 @@ pub fn run() -> sc_cli::Result<()> {
runner.sync_run(|config| cmd.run::<Block>(&config))
}
None => {
let mut provider_options: Option<ProviderOptions> = None;
let runner = cli.create_runner(&cli.run)?;
if cli.provider_config.provider {
provider_options = Some(cli.provider_config.provider_options());
};
runner.run_node_until_exit(|config| async move {
match config.network.network_backend {
// TODO: Litep2p becomes standard with Polkadot SDK stable2412-7 (should move None to other arm)
@ -270,23 +327,26 @@ pub fn run() -> sc_cli::Result<()> {
match config.chain_spec {
ref spec if spec.is_mainnet() => {
service::new_full::<
datahaven_mainnet_runtime::Runtime,
datahaven_mainnet_runtime::RuntimeApi,
sc_network::NetworkWorker<_, _>,
>(config, cli.eth)
>(config, cli.eth, provider_options)
.await
}
ref spec if spec.is_testnet() => {
service::new_full::<
datahaven_testnet_runtime::RuntimeApi,
datahaven_mainnet_runtime::Runtime,
datahaven_mainnet_runtime::RuntimeApi,
sc_network::NetworkWorker<_, _>,
>(config, cli.eth)
>(config, cli.eth, provider_options)
.await
}
_ => {
service::new_full::<
datahaven_stagenet_runtime::RuntimeApi,
datahaven_mainnet_runtime::Runtime,
datahaven_mainnet_runtime::RuntimeApi,
sc_network::NetworkWorker<_, _>,
>(config, cli.eth)
>(config, cli.eth, provider_options)
.await
}
}
@ -296,23 +356,26 @@ pub fn run() -> sc_cli::Result<()> {
match config.chain_spec {
ref spec if spec.is_mainnet() => {
service::new_full::<
datahaven_mainnet_runtime::Runtime,
datahaven_mainnet_runtime::RuntimeApi,
sc_network::Litep2pNetworkBackend,
>(config, cli.eth)
>(config, cli.eth, provider_options)
.await
}
ref spec if spec.is_testnet() => {
service::new_full::<
datahaven_testnet_runtime::Runtime,
datahaven_testnet_runtime::RuntimeApi,
sc_network::Litep2pNetworkBackend,
>(config, cli.eth)
>(config, cli.eth, provider_options)
.await
}
_ => {
service::new_full::<
datahaven_stagenet_runtime::Runtime,
datahaven_stagenet_runtime::RuntimeApi,
sc_network::Litep2pNetworkBackend,
>(config, cli.eth)
>(config, cli.eth, provider_options)
.await
}
}

View file

@ -1,11 +1,15 @@
//! Service and ServiceFactory implementation. Specialized wrapper over substrate service.
use crate::cli::ProviderType;
use crate::cli::StorageLayer;
use crate::command::ProviderOptions;
use crate::eth::{
new_frontier_partial, spawn_frontier_tasks, BackendType, FrontierBackend,
FrontierPartialComponents, FrontierTasksParams,
};
use crate::eth::{EthConfiguration, StorageOverrideHandler};
use crate::rpc::BeefyDeps;
use async_channel::Receiver;
use datahaven_runtime_common::{AccountId, Balance, Block, BlockNumber, Hash, Nonce};
use fc_consensus::FrontierBlockImport;
use fc_db::DatabaseSource;
@ -15,20 +19,46 @@ use sc_client_api::{AuxStore, Backend, BlockBackend, StateBackend, StorageProvid
use sc_consensus_babe::ImportQueueParams;
use sc_consensus_grandpa::SharedVoterState;
use sc_executor::{HeapAllocStrategy, WasmExecutor, DEFAULT_HEAP_ALLOC_STRATEGY};
use sc_network::config::FullNetworkConfiguration;
use sc_network::request_responses::IncomingRequest;
use sc_network::service::traits::NetworkService;
use sc_network::ProtocolName;
use sc_service::RpcHandlers;
use sc_service::{error::Error as ServiceError, Configuration, TaskManager, WarpSyncConfig};
use sc_telemetry::{Telemetry, TelemetryWorker};
use sc_transaction_pool::{BasicPool, FullChainApi};
use sc_transaction_pool_api::OffchainTransactionPoolFactory;
use shc_actors_framework::actor::TaskSpawner;
use shc_blockchain_service::capacity_manager::CapacityConfig;
use shc_client::builder::IndexerOptions;
use shc_client::{
builder::{Buildable, StorageHubBuilder, StorageLayerBuilder},
handler::{RunnableTasks, StorageHubHandler},
types::{
BspProvider, FishermanRole, InMemoryStorageLayer, MspProvider, NoStorageLayer,
RocksDbStorageLayer, ShNodeType, ShRole, ShStorageLayer, UserRole,
},
};
use shc_common::traits::StorageEnableRuntime;
use shc_common::types::BlockHash;
use shc_common::types::OpaqueBlock;
use shc_common::types::BCSV_KEY_TYPE;
use shc_indexer_db::DbPool;
use shc_rpc::StorageHubClientRpcConfig;
use sp_api::ProvideRuntimeApi;
use sp_blockchain::{Error as BlockChainError, HeaderBackend, HeaderMetadata};
use sp_consensus_beefy::ecdsa_crypto::AuthorityId as BeefyId;
use sp_core::H256;
use sp_keystore::KeystorePtr;
use sp_runtime::traits::BlakeTwo256;
use sp_runtime::SaturatedConversion;
use std::path::PathBuf;
use std::{default::Default, path::Path, sync::Arc, time::Duration};
pub(crate) type FullClient<RuntimeApi> = sc_service::TFullClient<
Block,
RuntimeApi,
sc_executor::WasmExecutor<sp_io::SubstrateHostFunctions>,
sc_executor::WasmExecutor<cumulus_client_service::ParachainHostFunctions>,
>;
type FullBackend = sc_service::TFullBackend<Block>;
@ -99,7 +129,10 @@ pub type Service<RuntimeApi> = sc_service::PartialComponents<
FullBackend,
FullSelectChain,
sc_consensus::DefaultImportQueue<Block>,
SingleStatePool<RuntimeApi>,
sc_transaction_pool::BasicPool<
sc_transaction_pool::FullChainApi<FullClient<RuntimeApi>, Block>,
Block,
>,
(
sc_consensus_babe::BabeBlockImport<
Block,
@ -124,6 +157,10 @@ pub type Service<RuntimeApi> = sc_service::PartialComponents<
),
>;
// StorageHub Enable client
pub(crate) type StorageEnableClient<Runtime> =
shc_common::types::ParachainClient<<Runtime as StorageEnableRuntime>::RuntimeApi>;
pub fn frontier_database_dir(config: &Configuration, path: &str) -> std::path::PathBuf {
config
.base_path
@ -199,11 +236,12 @@ where
Ok(frontier_backend)
}
pub fn new_partial<RuntimeApi>(
pub fn new_partial<Runtime, RuntimeApi>(
config: &Configuration,
eth_config: &mut EthConfiguration,
) -> Result<Service<RuntimeApi>, ServiceError>
where
Runtime: shc_common::traits::StorageEnableRuntime,
RuntimeApi: sp_api::ConstructRuntimeApi<Block, FullClient<RuntimeApi>> + Send + Sync + 'static,
RuntimeApi::RuntimeApi: FullRuntimeApi,
{
@ -340,16 +378,25 @@ where
}
/// Builds a new service for a full client.
pub async fn new_full<
// TODO: Find a way to remove `RuntimeApi` and to just keep `Runtime`
pub async fn new_full_impl<
R: ShRole,
S: ShStorageLayer,
Runtime,
RuntimeApi,
N: sc_network::NetworkBackend<Block, <Block as sp_runtime::traits::Block>::Hash>,
>(
config: Configuration,
mut eth_config: EthConfiguration,
provider_options: Option<ProviderOptions>,
) -> Result<TaskManager, ServiceError>
where
Runtime: shc_common::traits::StorageEnableRuntime<RuntimeApi = RuntimeApi>,
RuntimeApi: sp_api::ConstructRuntimeApi<Block, FullClient<RuntimeApi>> + Send + Sync + 'static,
RuntimeApi::RuntimeApi: FullRuntimeApi,
(R, S): ShNodeType<Runtime>,
StorageHubBuilder<R, S, Runtime>: StorageLayerBuilder + Buildable<(R, S), Runtime>,
StorageHubHandler<(R, S), Runtime>: RunnableTasks,
{
let sc_service::PartialComponents {
client,
@ -370,7 +417,7 @@ where
storage_override,
mut telemetry,
),
} = new_partial::<RuntimeApi>(&config, &mut eth_config)?;
} = new_partial::<Runtime, RuntimeApi>(&config, &mut eth_config)?;
let FrontierPartialComponents {
filter_pool,
@ -384,6 +431,23 @@ where
N,
>::new(&config.network, config.prometheus_registry().cloned());
// Starting StorageHub file transfer service.
// TODO: add fisherman
let mut file_transfer_request_protocol = None;
if provider_options.is_some() {
let genesis_hash = client
.block_hash(0u32.into())
.ok()
.flatten()
.expect("Genesis block exists; qed");
file_transfer_request_protocol = Some(configure_file_transfer_network::<_>(
genesis_hash,
&config,
&mut net_config,
));
}
let metrics = N::register_notification_metrics(config.prometheus_registry());
let peer_store_handle = net_config.peer_store_handle();
@ -470,6 +534,31 @@ where
);
}
let signing_dev_key = config
.dev_key_seed
.clone()
.expect("Dev key seed must be present in dev mode.");
let keystore = keystore_container.keystore();
// Initialise seed for signing transactions using blockchain service.
// In dev mode we use a well known dev account.
keystore
.sr25519_generate_new(BCSV_KEY_TYPE, Some(signing_dev_key.as_ref()))
.expect("Invalid dev signing key provided.");
// Storage Hub builder
let (sh_builder, maybe_storage_hub_client_rpc_config) = init_sh_builder::<R, S, Runtime>(
&provider_options,
&task_manager,
file_transfer_request_protocol,
network.clone(),
keystore.clone(),
client.clone(),
// indexer_options.clone(), FIXME
None,
)
.await?;
let role = config.role;
let force_authoring = config.force_authoring;
let backoff_authoring_blocks: Option<()> = None;
@ -513,6 +602,8 @@ where
)
.await;
let base_path = config.base_path.path().to_path_buf().clone();
let rpc_extensions_builder = {
let client = client.clone();
let pool = transaction_pool.clone();
@ -557,7 +648,7 @@ where
})
};
let _rpc_handlers = sc_service::spawn_tasks(sc_service::SpawnTasksParams {
let rpc_handlers = sc_service::spawn_tasks(sc_service::SpawnTasksParams {
network: Arc::new(network.clone()),
client: client.clone(),
keystore: keystore_container.keystore(),
@ -707,6 +798,306 @@ where
.spawn_blocking("beefy-gadget", None, gadget);
}
if let Some(_) = provider_options {
// Finishing building storage hub
finish_sh_builder_and_run_tasks(
sh_builder.unwrap(),
client.clone(),
rpc_handlers.clone(),
keystore_container.keystore(),
base_path.clone(),
false,
)
.await?;
}
network_starter.start_network();
Ok(task_manager)
}
pub async fn new_full<
Runtime,
RuntimeApi,
N: sc_network::NetworkBackend<Block, <Block as sp_runtime::traits::Block>::Hash>,
>(
config: Configuration,
mut eth_config: EthConfiguration,
provider_options: Option<ProviderOptions>,
) -> Result<TaskManager, ServiceError>
where
Runtime: shc_common::traits::StorageEnableRuntime<RuntimeApi = RuntimeApi>,
RuntimeApi: sp_api::ConstructRuntimeApi<Block, FullClient<RuntimeApi>> + Send + Sync + 'static,
RuntimeApi::RuntimeApi: FullRuntimeApi,
{
if let Some(provider_options) = provider_options {
match (
&provider_options.provider_type,
&provider_options.storage_layer,
) {
(&ProviderType::Bsp, &StorageLayer::Memory) => {
return new_full_impl::<BspProvider, InMemoryStorageLayer, Runtime, RuntimeApi, N>(
config,
eth_config,
Some(provider_options),
)
.await;
}
(&ProviderType::Bsp, &StorageLayer::RocksDB) => {
return new_full_impl::<BspProvider, RocksDbStorageLayer, Runtime, RuntimeApi, N>(
config,
eth_config,
Some(provider_options),
)
.await;
}
(&ProviderType::Msp, &StorageLayer::Memory) => {
return new_full_impl::<MspProvider, InMemoryStorageLayer, Runtime, RuntimeApi, N>(
config,
eth_config,
Some(provider_options),
)
.await;
}
(&ProviderType::Msp, &StorageLayer::RocksDB) => {
return new_full_impl::<MspProvider, RocksDbStorageLayer, Runtime, RuntimeApi, N>(
config,
eth_config,
Some(provider_options),
)
.await;
}
(&ProviderType::User, _) => {
return new_full_impl::<UserRole, NoStorageLayer, Runtime, RuntimeApi, N>(
config,
eth_config,
Some(provider_options),
)
.await;
}
};
} else {
return new_full_impl::<UserRole, NoStorageLayer, Runtime, RuntimeApi, N>(
config, eth_config, None,
)
.await;
};
}
/// Storage Hub
/// Maximum memory usage target for queued requests (8GB)
// TODO: Make this a configurable parameter
const MAX_QUEUED_REQUESTS_MEMORY_BYTES: u64 = 8 * 1024 * 1024 * 1024;
/// Max size of request packet. Calculated based on batch chunk size plus overhead percentage
const MAX_REQUEST_PACKET_SIZE_BYTES: u64 = {
let base_size = shc_common::types::BATCH_CHUNK_FILE_TRANSFER_MAX_SIZE as u64;
/// Percentage increase for packet overhead
///
/// This will cover any additional overhead required for the [`RemoteUploadDataRequest`](schema::v1::provider::request::Request::RemoteUploadDataRequest) payload.
// TODO: Make this a configurable parameter
const OVERHEAD_PERCENTILE: u64 = 100;
base_size.saturating_mul(100 + OVERHEAD_PERCENTILE) / 100
};
/// Max number of queued requests. Calculated to limit total memory usage
const MAX_FILE_TRANSFER_REQUESTS_QUEUE: usize = {
let max_requests = MAX_QUEUED_REQUESTS_MEMORY_BYTES / MAX_REQUEST_PACKET_SIZE_BYTES;
max_requests as usize
};
// TODO: Remove this once the `configure_file_transfer_network` from storage hub allow us to not pass the full client
pub fn configure_file_transfer_network<
Network: sc_network::NetworkBackend<OpaqueBlock, BlockHash>,
>(
genesis_hash: H256,
parachain_config: &Configuration,
net_config: &mut FullNetworkConfiguration<OpaqueBlock, BlockHash, Network>,
) -> (ProtocolName, async_channel::Receiver<IncomingRequest>) {
let (tx, request_receiver) = async_channel::bounded(MAX_FILE_TRANSFER_REQUESTS_QUEUE);
let mut protocol_config = shc_file_transfer_service::generate_protocol_config(
genesis_hash,
parachain_config.chain_spec.fork_id(),
);
protocol_config.inbound_queue = Some(tx);
let request_response_config = Network::request_response_config(
protocol_config.name.clone(),
protocol_config.fallback_names.clone(),
protocol_config.max_request_size,
protocol_config.max_response_size,
protocol_config.request_timeout,
protocol_config.inbound_queue,
);
net_config.add_request_response_protocol(request_response_config);
(protocol_config.name, request_receiver)
}
// Initialize the StorageHubBuilder for the StorageHub node.
async fn init_sh_builder<R, S, Runtime: StorageEnableRuntime>(
provider_options: &Option<ProviderOptions>,
task_manager: &TaskManager,
file_transfer_request_protocol: Option<(ProtocolName, Receiver<IncomingRequest>)>,
network: Arc<dyn NetworkService>,
keystore: KeystorePtr,
client: Arc<FullClient<Runtime::RuntimeApi>>,
indexer_options: Option<IndexerOptions>,
) -> Result<
(
Option<StorageHubBuilder<R, S, Runtime>>,
Option<
StorageHubClientRpcConfig<
<(R, S) as ShNodeType<Runtime>>::FL,
<(R, S) as ShNodeType<Runtime>>::FSH,
Runtime,
>,
>,
),
sc_service::Error,
>
where
R: ShRole,
S: ShStorageLayer,
(R, S): ShNodeType<Runtime>,
StorageHubBuilder<R, S, Runtime>: StorageLayerBuilder,
{
let maybe_indexer_db_pool =
configure_and_spawn_indexer::<Runtime>(&indexer_options, &task_manager, client.clone())
.await?;
if let Some(provider_options) = provider_options {
// Start building the StorageHubHandler, if running as a provider.
let task_spawner = TaskSpawner::new(task_manager.spawn_handle(), "sh-builder");
let mut storage_hub_builder = StorageHubBuilder::<R, S, Runtime>::new(task_spawner);
// Setup and spawn the File Transfer Service.
let (file_transfer_request_protocol_name, file_transfer_request_receiver) =
file_transfer_request_protocol
.expect("FileTransfer request protocol should already be initialised.");
storage_hub_builder
.with_file_transfer(
file_transfer_request_receiver,
file_transfer_request_protocol_name,
network.clone(),
)
.await;
// Setup the `ShStorageLayer` and additional configuration parameters.
storage_hub_builder
.setup_storage_layer(provider_options.storage_path.clone())
.with_capacity_config(Some(CapacityConfig::new(
provider_options
.max_storage_capacity
.unwrap_or_default()
.saturated_into(),
provider_options
.jump_capacity
.unwrap_or_default()
.saturated_into(),
)));
storage_hub_builder.with_msp_charge_fees_config(provider_options.msp_charge_fees.clone());
storage_hub_builder.with_msp_move_bucket_config(provider_options.msp_move_bucket.clone());
storage_hub_builder.with_bsp_upload_file_config(provider_options.bsp_upload_file.clone());
storage_hub_builder.with_bsp_move_bucket_config(provider_options.bsp_move_bucket.clone());
storage_hub_builder.with_bsp_charge_fees_config(provider_options.bsp_charge_fees.clone());
storage_hub_builder.with_bsp_submit_proof_config(provider_options.bsp_submit_proof.clone());
// Setup specific configuration for the MSP node.
if provider_options.provider_type == ProviderType::Msp {
storage_hub_builder
.with_notify_period(provider_options.msp_charging_period)
.with_indexer_db_pool(maybe_indexer_db_pool);
}
if let Some(c) = &provider_options.blockchain_service {
storage_hub_builder.with_blockchain_service_config(c.clone());
}
// Get the RPC configuration to use for this StorageHub node client.
let storage_hub_client_rpc_config =
storage_hub_builder.create_rpc_config(keystore, provider_options.rpc_config.clone());
return Ok((
Some(storage_hub_builder),
Some(storage_hub_client_rpc_config),
));
};
Ok((None, None))
}
/// Configure and spawn the indexer service.
async fn configure_and_spawn_indexer<Runtime: StorageEnableRuntime>(
indexer_options: &Option<IndexerOptions>,
task_manager: &TaskManager,
client: Arc<FullClient<<Runtime as StorageEnableRuntime>::RuntimeApi>>,
) -> Result<Option<DbPool>, sc_service::Error> {
let indexer_options = match indexer_options {
Some(config) => config,
None => return Ok(None),
};
// Setup database pool
let db_pool = shc_indexer_db::setup_db_pool(indexer_options.database_url.clone())
.await
.map_err(|e| sc_service::Error::Application(Box::new(e)))?;
let task_spawner = TaskSpawner::new(task_manager.spawn_handle(), "indexer-service");
shc_indexer_service::spawn_indexer_service::<Runtime>(
&task_spawner,
client.clone(),
db_pool.clone(),
indexer_options.indexer_mode,
)
.await;
Ok(Some(db_pool))
}
/// Finish the StorageHubBuilder and run the tasks.
async fn finish_sh_builder_and_run_tasks<R, S, Runtime: StorageEnableRuntime>(
mut sh_builder: StorageHubBuilder<R, S, Runtime>,
client: Arc<StorageEnableClient<Runtime>>,
rpc_handlers: RpcHandlers,
keystore: KeystorePtr,
rocksdb_root_path: impl Into<PathBuf>,
maintenance_mode: bool,
) -> Result<(), sc_service::Error>
where
R: ShRole,
S: ShStorageLayer,
(R, S): ShNodeType<Runtime>,
StorageHubBuilder<R, S, Runtime>: StorageLayerBuilder + Buildable<(R, S), Runtime>,
StorageHubHandler<(R, S), Runtime>: RunnableTasks,
{
let rocks_db_path = rocksdb_root_path.into();
// Spawn the Blockchain Service if node is running as a Storage Provider
sh_builder
.with_blockchain(
client.clone(),
keystore.clone(),
Arc::new(rpc_handlers),
rocks_db_path.clone(),
maintenance_mode,
)
.await;
// Initialize the BSP peer manager
sh_builder.with_peer_manager(rocks_db_path.clone());
// Build the StorageHubHandler
let mut sh_handler = sh_builder.build();
// Run StorageHub tasks according to the node role
sh_handler.run_tasks().await;
Ok(())
}

View file

@ -6,7 +6,7 @@ version = "0.1.0"
[dependencies]
codec = { workspace = true }
fp-account = { workspace = true }
fp-account = { workspace = true, features = ["serde"] }
frame-support = { workspace = true }
frame-system = { workspace = true }
pallet-authorship = { workspace = true }

View file

@ -137,6 +137,7 @@ pallet-proofs-dealer-runtime-api = { workspace = true }
pallet-randomness = { workspace = true }
pallet-storage-providers = { workspace = true }
pallet-storage-providers-runtime-api = { workspace = true }
shc-common = { workspace = true, optional = true }
shp-constants = { workspace = true }
shp-file-metadata = { workspace = true }
shp-traits = { workspace = true }
@ -266,6 +267,8 @@ std = [
"pallet-randomness/std",
"pallet-storage-providers/std",
"pallet-storage-providers-runtime-api/std",
"dep:shc-common",
"shc-common/std",
"shp-constants/std",
"shp-file-metadata/std",
"shp-forest-verifier/std",

View file

@ -0,0 +1,74 @@
// This module implements the StorageHub client traits for the runtime types.
// It is only compiled for native (std) builds to avoid pulling `shc-common` into the
// no_std Wasm runtime.
use shc_common::{
traits::{ExtensionOperations, StorageEnableRuntime},
types::{MinimalExtension, StorageEnableEvents},
};
use sp_core::H256;
// Implement the client-facing runtime trait for the concrete runtime.
impl StorageEnableRuntime for crate::Runtime {
type Address = crate::Address;
type Call = crate::RuntimeCall;
type Signature = crate::Signature;
type Extension = crate::SignedExtra;
type RuntimeApi = crate::RuntimeApi;
}
// Implement the transaction extension helpers for the concrete runtime's TxExtension.
impl ExtensionOperations<crate::RuntimeCall, crate::Runtime> for crate::SignedExtra {
type Hash = H256;
fn from_minimal_extension(minimal: MinimalExtension) -> Self {
(
frame_system::CheckNonZeroSender::<crate::Runtime>::new(),
frame_system::CheckSpecVersion::<crate::Runtime>::new(),
frame_system::CheckTxVersion::<crate::Runtime>::new(),
frame_system::CheckGenesis::<crate::Runtime>::new(),
frame_system::CheckEra::<crate::Runtime>::from(minimal.era),
frame_system::CheckNonce::<crate::Runtime>::from(minimal.nonce),
frame_system::CheckWeight::<crate::Runtime>::new(),
pallet_transaction_payment::ChargeTransactionPayment::<crate::Runtime>::from(
minimal.tip,
),
frame_metadata_hash_extension::CheckMetadataHash::new(false),
)
}
fn implicit(genesis_block_hash: Self::Hash, current_block_hash: Self::Hash) -> Self::Implicit {
(
(),
crate::VERSION.spec_version,
crate::VERSION.transaction_version,
genesis_block_hash,
current_block_hash,
(),
(),
(),
None,
)
}
}
// Map the runtime event into the client-facing storage events enum.
impl Into<StorageEnableEvents<crate::Runtime>> for crate::RuntimeEvent {
fn into(self) -> StorageEnableEvents<crate::Runtime> {
match self {
crate::RuntimeEvent::System(event) => StorageEnableEvents::System(event),
crate::RuntimeEvent::Providers(event) => StorageEnableEvents::StorageProviders(event),
crate::RuntimeEvent::ProofsDealer(event) => StorageEnableEvents::ProofsDealer(event),
crate::RuntimeEvent::PaymentStreams(event) => {
StorageEnableEvents::PaymentStreams(event)
}
crate::RuntimeEvent::FileSystem(event) => StorageEnableEvents::FileSystem(event),
crate::RuntimeEvent::TransactionPayment(event) => {
StorageEnableEvents::TransactionPayment(event)
}
crate::RuntimeEvent::Balances(event) => StorageEnableEvents::Balances(event),
crate::RuntimeEvent::BucketNfts(event) => StorageEnableEvents::BucketNfts(event),
crate::RuntimeEvent::Randomness(event) => StorageEnableEvents::Randomness(event),
_ => StorageEnableEvents::Other(self),
}
}
}

View file

@ -40,6 +40,9 @@ use sp_std::convert::{From, Into};
use sp_std::vec;
use sp_trie::{LayoutV1, TrieConfiguration, TrieLayout};
#[cfg(feature = "std")]
pub mod client; // StorageHub client trait only build for std build
/// Type representing the storage data units in StorageHub.
pub type StorageDataUnit = u64;
@ -302,6 +305,7 @@ impl pallet_proofs_dealer::Config for Runtime {
type ChallengesQueueLength = ChallengesQueueLength;
type CheckpointChallengePeriod = runtime_config::CheckpointChallengePeriod;
type ChallengesFee = ChallengesFee;
type PriorityChallengesFee = PriorityChallengesFee;
type Treasury = TreasuryAccount;
// TODO: Once the client logic to keep track of CR randomness deadlines and execute their submissions is implemented
// AND after the chain has been live for enough time to have enough providers to avoid the commit-reveal randomness being
@ -314,7 +318,6 @@ impl pallet_proofs_dealer::Config for Runtime {
type BlockFullnessHeadroom = BlockFullnessHeadroom;
type MinNotFullBlocksRatio = MinNotFullBlocksRatio;
type MaxSlashableProvidersPerTick = MaxSlashableProvidersPerTick;
type PriorityChallengesFee = PriorityChallengesFee;
type ChallengeOrigin = EnsureRoot<AccountId>;
type PriorityChallengeOrigin = EnsureRoot<AccountId>;
}

View file

@ -33,8 +33,21 @@ pub use pallet_balances::Call as BalancesCall;
use pallet_ethereum::{Call::transact, Transaction as EthereumTransaction};
use pallet_evm::{Account as EVMAccount, FeeCalculator, GasWeightMapping, Runner};
use pallet_external_validators::traits::EraIndex;
use pallet_file_system::types::StorageRequestMetadata;
use pallet_file_system_runtime_api::*;
use pallet_grandpa::{fg_primitives, AuthorityId as GrandpaId};
use pallet_payment_streams_runtime_api::*;
use pallet_proofs_dealer::types::{
CustomChallenge, KeyFor, ProviderIdFor as ProofsDealerProviderIdFor, RandomnessOutputFor,
};
use pallet_proofs_dealer_runtime_api::*;
use pallet_storage_providers::types::{
BackupStorageProvider, BackupStorageProviderId, BucketId, MainStorageProviderId,
Multiaddresses, ProviderIdFor, StorageDataUnit, StorageProviderId, ValuePropositionWithId,
};
use pallet_storage_providers_runtime_api::*;
pub use pallet_timestamp::Call as TimestampCall;
use shp_file_metadata::ChunkId;
use smallvec::smallvec;
use snowbridge_core::AgentId;
use snowbridge_merkle_tree::MerkleProof;
@ -52,6 +65,7 @@ use sp_runtime::{
transaction_validity::TransactionSource,
ApplyExtrinsicResult, Perbill, Permill,
};
use sp_std::collections::btree_map::BTreeMap;
#[cfg(feature = "std")]
use sp_version::NativeVersion;
use sp_version::RuntimeVersion;
@ -1197,6 +1211,155 @@ impl_runtime_apis! {
)
}
}
//╔═══════════════════════════════════════════════════════════════════════════════════════════════════════════════╗
//║ STORAGEHUB APIS ║
//╚═══════════════════════════════════════════════════════════════════════════════════════════════════════════════╝
impl pallet_file_system_runtime_api::FileSystemApi<Block, BackupStorageProviderId<Runtime>, MainStorageProviderId<Runtime>, H256, BlockNumber, ChunkId, BucketId<Runtime>, StorageRequestMetadata<Runtime>> for Runtime {
fn is_storage_request_open_to_volunteers(file_key: H256) -> Result<bool, IsStorageRequestOpenToVolunteersError> {
FileSystem::is_storage_request_open_to_volunteers(file_key)
}
fn query_earliest_file_volunteer_tick(bsp_id: BackupStorageProviderId<Runtime>, file_key: H256) -> Result<BlockNumber, QueryFileEarliestVolunteerTickError> {
FileSystem::query_earliest_file_volunteer_tick(bsp_id, file_key)
}
fn query_bsp_confirm_chunks_to_prove_for_file(bsp_id: BackupStorageProviderId<Runtime>, file_key: H256) -> Result<Vec<ChunkId>, QueryBspConfirmChunksToProveForFileError> {
FileSystem::query_bsp_confirm_chunks_to_prove_for_file(bsp_id, file_key)
}
fn query_msp_confirm_chunks_to_prove_for_file(msp_id: MainStorageProviderId<Runtime>, file_key: H256) -> Result<Vec<ChunkId>, QueryMspConfirmChunksToProveForFileError> {
FileSystem::query_msp_confirm_chunks_to_prove_for_file(msp_id, file_key)
}
fn decode_generic_apply_delta_event_info(encoded_event_info: Vec<u8>) -> Result<BucketId<Runtime>, GenericApplyDeltaEventInfoError> {
FileSystem::decode_generic_apply_delta_event_info(encoded_event_info)
}
fn pending_storage_requests_by_msp(msp_id: MainStorageProviderId<Runtime>) -> BTreeMap<H256, StorageRequestMetadata<Runtime>> {
FileSystem::pending_storage_requests_by_msp(msp_id)
}
}
impl pallet_payment_streams_runtime_api::PaymentStreamsApi<Block, ProviderIdFor<Runtime>, Balance, AccountId> for Runtime {
fn get_users_with_debt_over_threshold(provider_id: &ProviderIdFor<Runtime>, threshold: Balance) -> Result<Vec<AccountId>, GetUsersWithDebtOverThresholdError> {
PaymentStreams::get_users_with_debt_over_threshold(provider_id, threshold)
}
fn get_users_of_payment_streams_of_provider(provider_id: &ProviderIdFor<Runtime>) -> Vec<AccountId> {
PaymentStreams::get_users_of_payment_streams_of_provider(provider_id)
}
fn get_providers_with_payment_streams_with_user(user_account: &AccountId) -> Vec<ProviderIdFor<Runtime>> {
PaymentStreams::get_providers_with_payment_streams_with_user(user_account)
}
}
impl pallet_proofs_dealer_runtime_api::ProofsDealerApi<Block, ProofsDealerProviderIdFor<Runtime>, BlockNumber, KeyFor<Runtime>, RandomnessOutputFor<Runtime>, CustomChallenge<Runtime>> for Runtime {
fn get_last_tick_provider_submitted_proof(provider_id: &ProofsDealerProviderIdFor<Runtime>) -> Result<BlockNumber, GetProofSubmissionRecordError> {
ProofsDealer::get_last_tick_provider_submitted_proof(provider_id)
}
fn get_next_tick_to_submit_proof_for(provider_id: &ProofsDealerProviderIdFor<Runtime>) -> Result<BlockNumber, GetProofSubmissionRecordError> {
ProofsDealer::get_next_tick_to_submit_proof_for(provider_id)
}
fn get_last_checkpoint_challenge_tick() -> BlockNumber {
ProofsDealer::get_last_checkpoint_challenge_tick()
}
fn get_checkpoint_challenges(
tick: BlockNumber
) -> Result<Vec<CustomChallenge<Runtime>>, GetCheckpointChallengesError> {
ProofsDealer::get_checkpoint_challenges(tick)
}
fn get_challenge_seed(tick: BlockNumber) -> Result<RandomnessOutputFor<Runtime>, GetChallengeSeedError> {
ProofsDealer::get_challenge_seed(tick)
}
fn get_challenge_period(provider_id: &ProofsDealerProviderIdFor<Runtime>) -> Result<BlockNumber, GetChallengePeriodError> {
ProofsDealer::get_challenge_period(provider_id)
}
fn get_checkpoint_challenge_period() -> BlockNumber {
ProofsDealer::get_checkpoint_challenge_period()
}
fn get_challenges_from_seed(seed: &RandomnessOutputFor<Runtime>, provider_id: &ProofsDealerProviderIdFor<Runtime>, count: u32) -> Vec<KeyFor<Runtime>> {
ProofsDealer::get_challenges_from_seed(seed, provider_id, count)
}
fn get_forest_challenges_from_seed(seed: &RandomnessOutputFor<Runtime>, provider_id: &ProofsDealerProviderIdFor<Runtime>) -> Vec<KeyFor<Runtime>> {
ProofsDealer::get_forest_challenges_from_seed(seed, provider_id)
}
fn get_current_tick() -> BlockNumber {
ProofsDealer::get_current_tick()
}
fn get_next_deadline_tick(provider_id: &ProofsDealerProviderIdFor<Runtime>) -> Result<BlockNumber, GetNextDeadlineTickError> {
ProofsDealer::get_next_deadline_tick(provider_id)
}
}
impl pallet_storage_providers_runtime_api::StorageProvidersApi<Block, BlockNumber, BackupStorageProviderId<Runtime>, BackupStorageProvider<Runtime>, MainStorageProviderId<Runtime>, AccountId, ProviderIdFor<Runtime>, StorageProviderId<Runtime>, StorageDataUnit<Runtime>, Balance, BucketId<Runtime>, Multiaddresses<Runtime>, ValuePropositionWithId<Runtime>> for Runtime {
fn get_bsp_info(bsp_id: &BackupStorageProviderId<Runtime>) -> Result<BackupStorageProvider<Runtime>, GetBspInfoError> {
Providers::get_bsp_info(bsp_id)
}
fn get_storage_provider_id(who: &AccountId) -> Option<StorageProviderId<Runtime>> {
Providers::get_storage_provider_id(who)
}
fn query_msp_id_of_bucket_id(bucket_id: &BucketId<Runtime>) -> Result<Option<ProviderIdFor<Runtime>>, QueryMspIdOfBucketIdError> {
Providers::query_msp_id_of_bucket_id(bucket_id)
}
fn query_provider_multiaddresses(provider_id: &ProviderIdFor<Runtime>) -> Result<Multiaddresses<Runtime>, QueryProviderMultiaddressesError> {
Providers::query_provider_multiaddresses(provider_id)
}
fn query_storage_provider_capacity(provider_id: &ProviderIdFor<Runtime>) -> Result<StorageDataUnit<Runtime>, QueryStorageProviderCapacityError> {
Providers::query_storage_provider_capacity(provider_id)
}
fn query_available_storage_capacity(provider_id: &ProviderIdFor<Runtime>) -> Result<StorageDataUnit<Runtime>, QueryAvailableStorageCapacityError> {
Providers::query_available_storage_capacity(provider_id)
}
fn query_earliest_change_capacity_block(provider_id: &BackupStorageProviderId<Runtime>) -> Result<BlockNumber, QueryEarliestChangeCapacityBlockError> {
Providers::query_earliest_change_capacity_block(provider_id)
}
fn get_worst_case_scenario_slashable_amount(provider_id: ProviderIdFor<Runtime>) -> Option<Balance> {
Providers::get_worst_case_scenario_slashable_amount(&provider_id).ok()
}
fn get_slash_amount_per_max_file_size() -> Balance {
Providers::get_slash_amount_per_max_file_size()
}
fn query_value_propositions_for_msp(msp_id: &MainStorageProviderId<Runtime>) -> Vec<ValuePropositionWithId<Runtime>> {
Providers::query_value_propositions_for_msp(msp_id)
}
fn get_bsp_stake(bsp_id: &BackupStorageProviderId<Runtime>) -> Result<Balance, GetStakeError> {
Providers::get_bsp_stake(bsp_id)
}
fn can_delete_provider(provider_id: &ProviderIdFor<Runtime>) -> bool {
Providers::can_delete_provider(provider_id)
}
fn query_buckets_for_msp(msp_id: &MainStorageProviderId<Runtime>) -> Result<Vec<BucketId<Runtime>>, QueryBucketsForMspError> {
Providers::query_buckets_for_msp(msp_id)
}
fn query_buckets_of_user_stored_by_msp(msp_id: &ProviderIdFor<Runtime>, user: &AccountId) -> Result<sp_runtime::Vec<BucketId<Runtime>>, QueryBucketsOfUserStoredByMspError> {
Ok(sp_runtime::Vec::from_iter(Providers::query_buckets_of_user_stored_by_msp(msp_id, user)?))
}
}
}
// Shorthand for a Get field of a pallet Config.

View file

@ -17,7 +17,7 @@ bridge-hub-common = { workspace = true, optional = true }
codec = { workspace = true, features = ["derive"] }
datahaven-runtime-common = { workspace = true }
dhp-bridge = { workspace = true }
fp-account = { workspace = true, features = ["serde"] }
fp-account = { workspace = true }
fp-evm = { workspace = true, features = ["serde"] }
fp-rpc = { workspace = true }
fp-self-contained = { workspace = true, features = ["serde", "try-runtime"] }
@ -137,6 +137,7 @@ pallet-proofs-dealer-runtime-api = { workspace = true }
pallet-randomness = { workspace = true }
pallet-storage-providers = { workspace = true }
pallet-storage-providers-runtime-api = { workspace = true }
shc-common = { workspace = true, optional = true }
shp-constants = { workspace = true }
shp-file-metadata = { workspace = true }
shp-traits = { workspace = true }
@ -266,6 +267,8 @@ std = [
"pallet-randomness/std",
"pallet-storage-providers/std",
"pallet-storage-providers-runtime-api/std",
"dep:shc-common",
"shc-common/std",
"shp-constants/std",
"shp-file-metadata/std",
"shp-forest-verifier/std",

View file

@ -12,6 +12,7 @@ use datahaven_runtime_common::{Balance, BlockNumber};
#[dynamic_params(RuntimeParameters, pallet_parameters::Parameters::<Runtime>)]
pub mod dynamic_params {
use super::*;
#[dynamic_pallet_params]
#[codec(index = 0)]
pub mod runtime_config {

View file

@ -0,0 +1,74 @@
// This module implements the StorageHub client traits for the runtime types.
// It is only compiled for native (std) builds to avoid pulling `shc-common` into the
// no_std Wasm runtime.
use shc_common::{
traits::{ExtensionOperations, StorageEnableRuntime},
types::{MinimalExtension, StorageEnableEvents},
};
use sp_core::H256;
// Implement the client-facing runtime trait for the concrete runtime.
impl StorageEnableRuntime for crate::Runtime {
type Address = crate::Address;
type Call = crate::RuntimeCall;
type Signature = crate::Signature;
type Extension = crate::SignedExtra;
type RuntimeApi = crate::RuntimeApi;
}
// Implement the transaction extension helpers for the concrete runtime's TxExtension.
impl ExtensionOperations<crate::RuntimeCall, crate::Runtime> for crate::SignedExtra {
type Hash = H256;
fn from_minimal_extension(minimal: MinimalExtension) -> Self {
(
frame_system::CheckNonZeroSender::<crate::Runtime>::new(),
frame_system::CheckSpecVersion::<crate::Runtime>::new(),
frame_system::CheckTxVersion::<crate::Runtime>::new(),
frame_system::CheckGenesis::<crate::Runtime>::new(),
frame_system::CheckEra::<crate::Runtime>::from(minimal.era),
frame_system::CheckNonce::<crate::Runtime>::from(minimal.nonce),
frame_system::CheckWeight::<crate::Runtime>::new(),
pallet_transaction_payment::ChargeTransactionPayment::<crate::Runtime>::from(
minimal.tip,
),
frame_metadata_hash_extension::CheckMetadataHash::new(false),
)
}
fn implicit(genesis_block_hash: Self::Hash, current_block_hash: Self::Hash) -> Self::Implicit {
(
(),
crate::VERSION.spec_version,
crate::VERSION.transaction_version,
genesis_block_hash,
current_block_hash,
(),
(),
(),
None,
)
}
}
// Map the runtime event into the client-facing storage events enum.
impl Into<StorageEnableEvents<crate::Runtime>> for crate::RuntimeEvent {
fn into(self) -> StorageEnableEvents<crate::Runtime> {
match self {
crate::RuntimeEvent::System(event) => StorageEnableEvents::System(event),
crate::RuntimeEvent::Providers(event) => StorageEnableEvents::StorageProviders(event),
crate::RuntimeEvent::ProofsDealer(event) => StorageEnableEvents::ProofsDealer(event),
crate::RuntimeEvent::PaymentStreams(event) => {
StorageEnableEvents::PaymentStreams(event)
}
crate::RuntimeEvent::FileSystem(event) => StorageEnableEvents::FileSystem(event),
crate::RuntimeEvent::TransactionPayment(event) => {
StorageEnableEvents::TransactionPayment(event)
}
crate::RuntimeEvent::Balances(event) => StorageEnableEvents::Balances(event),
crate::RuntimeEvent::BucketNfts(event) => StorageEnableEvents::BucketNfts(event),
crate::RuntimeEvent::Randomness(event) => StorageEnableEvents::Randomness(event),
_ => StorageEnableEvents::Other(self),
}
}
}

View file

@ -40,6 +40,9 @@ use sp_std::convert::{From, Into};
use sp_std::vec;
use sp_trie::{LayoutV1, TrieConfiguration, TrieLayout};
#[cfg(feature = "std")]
pub mod client; // StorageHub client trait only build for std build
/// Type representing the storage data units in StorageHub.
pub type StorageDataUnit = u64;
@ -302,6 +305,7 @@ impl pallet_proofs_dealer::Config for Runtime {
type ChallengesQueueLength = ChallengesQueueLength;
type CheckpointChallengePeriod = runtime_config::CheckpointChallengePeriod;
type ChallengesFee = ChallengesFee;
type PriorityChallengesFee = PriorityChallengesFee;
type Treasury = TreasuryAccount;
// TODO: Once the client logic to keep track of CR randomness deadlines and execute their submissions is implemented
// AND after the chain has been live for enough time to have enough providers to avoid the commit-reveal randomness being
@ -314,7 +318,6 @@ impl pallet_proofs_dealer::Config for Runtime {
type BlockFullnessHeadroom = BlockFullnessHeadroom;
type MinNotFullBlocksRatio = MinNotFullBlocksRatio;
type MaxSlashableProvidersPerTick = MaxSlashableProvidersPerTick;
type PriorityChallengesFee = PriorityChallengesFee;
type ChallengeOrigin = EnsureRoot<AccountId>;
type PriorityChallengeOrigin = EnsureRoot<AccountId>;
}

View file

@ -30,8 +30,21 @@ pub use pallet_balances::Call as BalancesCall;
use pallet_ethereum::{Call::transact, Transaction as EthereumTransaction};
use pallet_evm::{Account as EVMAccount, FeeCalculator, GasWeightMapping, Runner};
use pallet_external_validators::traits::EraIndex;
use pallet_file_system::types::StorageRequestMetadata;
use pallet_file_system_runtime_api::*;
use pallet_grandpa::{fg_primitives, AuthorityId as GrandpaId};
use pallet_payment_streams_runtime_api::*;
use pallet_proofs_dealer::types::{
CustomChallenge, KeyFor, ProviderIdFor as ProofsDealerProviderIdFor, RandomnessOutputFor,
};
use pallet_proofs_dealer_runtime_api::*;
use pallet_storage_providers::types::{
BackupStorageProvider, BackupStorageProviderId, BucketId, MainStorageProviderId,
Multiaddresses, ProviderIdFor, StorageDataUnit, StorageProviderId, ValuePropositionWithId,
};
use pallet_storage_providers_runtime_api::*;
pub use pallet_timestamp::Call as TimestampCall;
use shp_file_metadata::ChunkId;
use smallvec::smallvec;
use snowbridge_core::AgentId;
use snowbridge_merkle_tree::MerkleProof;
@ -49,6 +62,7 @@ use sp_runtime::{
transaction_validity::TransactionSource,
ApplyExtrinsicResult, Perbill, Permill,
};
use sp_std::collections::btree_map::BTreeMap;
#[cfg(feature = "std")]
use sp_version::NativeVersion;
use sp_version::RuntimeVersion;
@ -1198,6 +1212,156 @@ impl_runtime_apis! {
)
}
}
//╔═══════════════════════════════════════════════════════════════════════════════════════════════════════════════╗
//║ STORAGEHUB APIS ║
//╚═══════════════════════════════════════════════════════════════════════════════════════════════════════════════╝
impl pallet_file_system_runtime_api::FileSystemApi<Block, BackupStorageProviderId<Runtime>, MainStorageProviderId<Runtime>, H256, BlockNumber, ChunkId, BucketId<Runtime>, StorageRequestMetadata<Runtime>> for Runtime {
fn is_storage_request_open_to_volunteers(file_key: H256) -> Result<bool, IsStorageRequestOpenToVolunteersError> {
FileSystem::is_storage_request_open_to_volunteers(file_key)
}
fn query_earliest_file_volunteer_tick(bsp_id: BackupStorageProviderId<Runtime>, file_key: H256) -> Result<BlockNumber, QueryFileEarliestVolunteerTickError> {
FileSystem::query_earliest_file_volunteer_tick(bsp_id, file_key)
}
fn query_bsp_confirm_chunks_to_prove_for_file(bsp_id: BackupStorageProviderId<Runtime>, file_key: H256) -> Result<Vec<ChunkId>, QueryBspConfirmChunksToProveForFileError> {
FileSystem::query_bsp_confirm_chunks_to_prove_for_file(bsp_id, file_key)
}
fn query_msp_confirm_chunks_to_prove_for_file(msp_id: MainStorageProviderId<Runtime>, file_key: H256) -> Result<Vec<ChunkId>, QueryMspConfirmChunksToProveForFileError> {
FileSystem::query_msp_confirm_chunks_to_prove_for_file(msp_id, file_key)
}
fn decode_generic_apply_delta_event_info(encoded_event_info: Vec<u8>) -> Result<BucketId<Runtime>, GenericApplyDeltaEventInfoError> {
FileSystem::decode_generic_apply_delta_event_info(encoded_event_info)
}
fn pending_storage_requests_by_msp(msp_id: MainStorageProviderId<Runtime>) -> BTreeMap<H256, StorageRequestMetadata<Runtime>> {
FileSystem::pending_storage_requests_by_msp(msp_id)
}
}
impl pallet_payment_streams_runtime_api::PaymentStreamsApi<Block, ProviderIdFor<Runtime>, Balance, AccountId> for Runtime {
fn get_users_with_debt_over_threshold(provider_id: &ProviderIdFor<Runtime>, threshold: Balance) -> Result<Vec<AccountId>, GetUsersWithDebtOverThresholdError> {
PaymentStreams::get_users_with_debt_over_threshold(provider_id, threshold)
}
fn get_users_of_payment_streams_of_provider(provider_id: &ProviderIdFor<Runtime>) -> Vec<AccountId> {
PaymentStreams::get_users_of_payment_streams_of_provider(provider_id)
}
fn get_providers_with_payment_streams_with_user(user_account: &AccountId) -> Vec<ProviderIdFor<Runtime>> {
PaymentStreams::get_providers_with_payment_streams_with_user(user_account)
}
}
impl pallet_proofs_dealer_runtime_api::ProofsDealerApi<Block, ProofsDealerProviderIdFor<Runtime>, BlockNumber, KeyFor<Runtime>, RandomnessOutputFor<Runtime>, CustomChallenge<Runtime>> for Runtime {
fn get_last_tick_provider_submitted_proof(provider_id: &ProofsDealerProviderIdFor<Runtime>) -> Result<BlockNumber, GetProofSubmissionRecordError> {
ProofsDealer::get_last_tick_provider_submitted_proof(provider_id)
}
fn get_next_tick_to_submit_proof_for(provider_id: &ProofsDealerProviderIdFor<Runtime>) -> Result<BlockNumber, GetProofSubmissionRecordError> {
ProofsDealer::get_next_tick_to_submit_proof_for(provider_id)
}
fn get_last_checkpoint_challenge_tick() -> BlockNumber {
ProofsDealer::get_last_checkpoint_challenge_tick()
}
fn get_checkpoint_challenges(
tick: BlockNumber
) -> Result<Vec<CustomChallenge<Runtime>>, GetCheckpointChallengesError> {
ProofsDealer::get_checkpoint_challenges(tick)
}
fn get_challenge_seed(tick: BlockNumber) -> Result<RandomnessOutputFor<Runtime>, GetChallengeSeedError> {
ProofsDealer::get_challenge_seed(tick)
}
fn get_challenge_period(provider_id: &ProofsDealerProviderIdFor<Runtime>) -> Result<BlockNumber, GetChallengePeriodError> {
ProofsDealer::get_challenge_period(provider_id)
}
fn get_checkpoint_challenge_period() -> BlockNumber {
ProofsDealer::get_checkpoint_challenge_period()
}
fn get_challenges_from_seed(seed: &RandomnessOutputFor<Runtime>, provider_id: &ProofsDealerProviderIdFor<Runtime>, count: u32) -> Vec<KeyFor<Runtime>> {
ProofsDealer::get_challenges_from_seed(seed, provider_id, count)
}
fn get_forest_challenges_from_seed(seed: &RandomnessOutputFor<Runtime>, provider_id: &ProofsDealerProviderIdFor<Runtime>) -> Vec<KeyFor<Runtime>> {
ProofsDealer::get_forest_challenges_from_seed(seed, provider_id)
}
fn get_current_tick() -> BlockNumber {
ProofsDealer::get_current_tick()
}
fn get_next_deadline_tick(provider_id: &ProofsDealerProviderIdFor<Runtime>) -> Result<BlockNumber, GetNextDeadlineTickError> {
ProofsDealer::get_next_deadline_tick(provider_id)
}
}
impl pallet_storage_providers_runtime_api::StorageProvidersApi<Block, BlockNumber, BackupStorageProviderId<Runtime>, BackupStorageProvider<Runtime>, MainStorageProviderId<Runtime>, AccountId, ProviderIdFor<Runtime>, StorageProviderId<Runtime>, StorageDataUnit<Runtime>, Balance, BucketId<Runtime>, Multiaddresses<Runtime>, ValuePropositionWithId<Runtime>> for Runtime {
fn get_bsp_info(bsp_id: &BackupStorageProviderId<Runtime>) -> Result<BackupStorageProvider<Runtime>, GetBspInfoError> {
Providers::get_bsp_info(bsp_id)
}
fn get_storage_provider_id(who: &AccountId) -> Option<StorageProviderId<Runtime>> {
Providers::get_storage_provider_id(who)
}
fn query_msp_id_of_bucket_id(bucket_id: &BucketId<Runtime>) -> Result<Option<ProviderIdFor<Runtime>>, QueryMspIdOfBucketIdError> {
Providers::query_msp_id_of_bucket_id(bucket_id)
}
fn query_provider_multiaddresses(provider_id: &ProviderIdFor<Runtime>) -> Result<Multiaddresses<Runtime>, QueryProviderMultiaddressesError> {
Providers::query_provider_multiaddresses(provider_id)
}
fn query_storage_provider_capacity(provider_id: &ProviderIdFor<Runtime>) -> Result<StorageDataUnit<Runtime>, QueryStorageProviderCapacityError> {
Providers::query_storage_provider_capacity(provider_id)
}
fn query_available_storage_capacity(provider_id: &ProviderIdFor<Runtime>) -> Result<StorageDataUnit<Runtime>, QueryAvailableStorageCapacityError> {
Providers::query_available_storage_capacity(provider_id)
}
fn query_earliest_change_capacity_block(provider_id: &BackupStorageProviderId<Runtime>) -> Result<BlockNumber, QueryEarliestChangeCapacityBlockError> {
Providers::query_earliest_change_capacity_block(provider_id)
}
fn get_worst_case_scenario_slashable_amount(provider_id: ProviderIdFor<Runtime>) -> Option<Balance> {
Providers::get_worst_case_scenario_slashable_amount(&provider_id).ok()
}
fn get_slash_amount_per_max_file_size() -> Balance {
Providers::get_slash_amount_per_max_file_size()
}
fn query_value_propositions_for_msp(msp_id: &MainStorageProviderId<Runtime>) -> Vec<ValuePropositionWithId<Runtime>> {
Providers::query_value_propositions_for_msp(msp_id)
}
fn get_bsp_stake(bsp_id: &BackupStorageProviderId<Runtime>) -> Result<Balance, GetStakeError> {
Providers::get_bsp_stake(bsp_id)
}
fn can_delete_provider(provider_id: &ProviderIdFor<Runtime>) -> bool {
Providers::can_delete_provider(provider_id)
}
fn query_buckets_for_msp(msp_id: &MainStorageProviderId<Runtime>) -> Result<Vec<BucketId<Runtime>>, QueryBucketsForMspError> {
Providers::query_buckets_for_msp(msp_id)
}
fn query_buckets_of_user_stored_by_msp(msp_id: &ProviderIdFor<Runtime>, user: &AccountId) -> Result<sp_runtime::Vec<BucketId<Runtime>>, QueryBucketsOfUserStoredByMspError> {
Ok(sp_runtime::Vec::from_iter(Providers::query_buckets_of_user_stored_by_msp(msp_id, user)?))
}
}
}
// Shorthand for a Get field of a pallet Config.

View file

@ -137,6 +137,7 @@ pallet-proofs-dealer-runtime-api = { workspace = true }
pallet-randomness = { workspace = true }
pallet-storage-providers = { workspace = true }
pallet-storage-providers-runtime-api = { workspace = true }
shc-common = { workspace = true, optional = true }
shp-constants = { workspace = true }
shp-file-metadata = { workspace = true }
shp-traits = { workspace = true }
@ -267,6 +268,8 @@ std = [
"pallet-randomness/std",
"pallet-storage-providers/std",
"pallet-storage-providers-runtime-api/std",
"dep:shc-common",
"shc-common/std",
"shp-constants/std",
"shp-file-metadata/std",
"shp-forest-verifier/std",

View file

@ -0,0 +1,74 @@
// This module implements the StorageHub client traits for the runtime types.
// It is only compiled for native (std) builds to avoid pulling `shc-common` into the
// no_std Wasm runtime.
use shc_common::{
traits::{ExtensionOperations, StorageEnableRuntime},
types::{MinimalExtension, StorageEnableEvents},
};
use sp_core::H256;
// Implement the client-facing runtime trait for the concrete runtime.
impl StorageEnableRuntime for crate::Runtime {
type Address = crate::Address;
type Call = crate::RuntimeCall;
type Signature = crate::Signature;
type Extension = crate::SignedExtra;
type RuntimeApi = crate::RuntimeApi;
}
// Implement the transaction extension helpers for the concrete runtime's TxExtension.
impl ExtensionOperations<crate::RuntimeCall, crate::Runtime> for crate::SignedExtra {
type Hash = H256;
fn from_minimal_extension(minimal: MinimalExtension) -> Self {
(
frame_system::CheckNonZeroSender::<crate::Runtime>::new(),
frame_system::CheckSpecVersion::<crate::Runtime>::new(),
frame_system::CheckTxVersion::<crate::Runtime>::new(),
frame_system::CheckGenesis::<crate::Runtime>::new(),
frame_system::CheckEra::<crate::Runtime>::from(minimal.era),
frame_system::CheckNonce::<crate::Runtime>::from(minimal.nonce),
frame_system::CheckWeight::<crate::Runtime>::new(),
pallet_transaction_payment::ChargeTransactionPayment::<crate::Runtime>::from(
minimal.tip,
),
frame_metadata_hash_extension::CheckMetadataHash::new(false),
)
}
fn implicit(genesis_block_hash: Self::Hash, current_block_hash: Self::Hash) -> Self::Implicit {
(
(),
crate::VERSION.spec_version,
crate::VERSION.transaction_version,
genesis_block_hash,
current_block_hash,
(),
(),
(),
None,
)
}
}
// Map the runtime event into the client-facing storage events enum.
impl Into<StorageEnableEvents<crate::Runtime>> for crate::RuntimeEvent {
fn into(self) -> StorageEnableEvents<crate::Runtime> {
match self {
crate::RuntimeEvent::System(event) => StorageEnableEvents::System(event),
crate::RuntimeEvent::Providers(event) => StorageEnableEvents::StorageProviders(event),
crate::RuntimeEvent::ProofsDealer(event) => StorageEnableEvents::ProofsDealer(event),
crate::RuntimeEvent::PaymentStreams(event) => {
StorageEnableEvents::PaymentStreams(event)
}
crate::RuntimeEvent::FileSystem(event) => StorageEnableEvents::FileSystem(event),
crate::RuntimeEvent::TransactionPayment(event) => {
StorageEnableEvents::TransactionPayment(event)
}
crate::RuntimeEvent::Balances(event) => StorageEnableEvents::Balances(event),
crate::RuntimeEvent::BucketNfts(event) => StorageEnableEvents::BucketNfts(event),
crate::RuntimeEvent::Randomness(event) => StorageEnableEvents::Randomness(event),
_ => StorageEnableEvents::Other(self),
}
}
}

View file

@ -40,6 +40,9 @@ use sp_std::convert::{From, Into};
use sp_std::vec;
use sp_trie::{LayoutV1, TrieConfiguration, TrieLayout};
#[cfg(feature = "std")]
pub mod client; // StorageHub client trait only build for std build
/// Type representing the storage data units in StorageHub.
pub type StorageDataUnit = u64;
@ -302,6 +305,7 @@ impl pallet_proofs_dealer::Config for Runtime {
type ChallengesQueueLength = ChallengesQueueLength;
type CheckpointChallengePeriod = runtime_config::CheckpointChallengePeriod;
type ChallengesFee = ChallengesFee;
type PriorityChallengesFee = PriorityChallengesFee;
type Treasury = TreasuryAccount;
// TODO: Once the client logic to keep track of CR randomness deadlines and execute their submissions is implemented
// AND after the chain has been live for enough time to have enough providers to avoid the commit-reveal randomness being
@ -314,7 +318,6 @@ impl pallet_proofs_dealer::Config for Runtime {
type BlockFullnessHeadroom = BlockFullnessHeadroom;
type MinNotFullBlocksRatio = MinNotFullBlocksRatio;
type MaxSlashableProvidersPerTick = MaxSlashableProvidersPerTick;
type PriorityChallengesFee = PriorityChallengesFee;
type ChallengeOrigin = EnsureRoot<AccountId>;
type PriorityChallengeOrigin = EnsureRoot<AccountId>;
}

View file

@ -32,8 +32,21 @@ pub use pallet_balances::Call as BalancesCall;
use pallet_ethereum::{Call::transact, Transaction as EthereumTransaction};
use pallet_evm::{Account as EVMAccount, FeeCalculator, GasWeightMapping, Runner};
use pallet_external_validators::traits::EraIndex;
use pallet_file_system::types::StorageRequestMetadata;
use pallet_file_system_runtime_api::*;
use pallet_grandpa::{fg_primitives, AuthorityId as GrandpaId};
use pallet_payment_streams_runtime_api::*;
use pallet_proofs_dealer::types::{
CustomChallenge, KeyFor, ProviderIdFor as ProofsDealerProviderIdFor, RandomnessOutputFor,
};
use pallet_proofs_dealer_runtime_api::*;
use pallet_storage_providers::types::{
BackupStorageProvider, BackupStorageProviderId, BucketId, MainStorageProviderId,
Multiaddresses, ProviderIdFor, StorageDataUnit, StorageProviderId, ValuePropositionWithId,
};
use pallet_storage_providers_runtime_api::*;
pub use pallet_timestamp::Call as TimestampCall;
use shp_file_metadata::ChunkId;
use smallvec::smallvec;
use snowbridge_core::AgentId;
use snowbridge_merkle_tree::MerkleProof;
@ -51,6 +64,7 @@ use sp_runtime::{
transaction_validity::TransactionSource,
ApplyExtrinsicResult, Perbill, Permill,
};
use sp_std::collections::btree_map::BTreeMap;
#[cfg(feature = "std")]
use sp_version::NativeVersion;
use sp_version::RuntimeVersion;
@ -1196,6 +1210,155 @@ impl_runtime_apis! {
)
}
}
//╔═══════════════════════════════════════════════════════════════════════════════════════════════════════════════╗
//║ STORAGEHUB APIS ║
//╚═══════════════════════════════════════════════════════════════════════════════════════════════════════════════╝
impl pallet_file_system_runtime_api::FileSystemApi<Block, BackupStorageProviderId<Runtime>, MainStorageProviderId<Runtime>, H256, BlockNumber, ChunkId, BucketId<Runtime>, StorageRequestMetadata<Runtime>> for Runtime {
fn is_storage_request_open_to_volunteers(file_key: H256) -> Result<bool, IsStorageRequestOpenToVolunteersError> {
FileSystem::is_storage_request_open_to_volunteers(file_key)
}
fn query_earliest_file_volunteer_tick(bsp_id: BackupStorageProviderId<Runtime>, file_key: H256) -> Result<BlockNumber, QueryFileEarliestVolunteerTickError> {
FileSystem::query_earliest_file_volunteer_tick(bsp_id, file_key)
}
fn query_bsp_confirm_chunks_to_prove_for_file(bsp_id: BackupStorageProviderId<Runtime>, file_key: H256) -> Result<Vec<ChunkId>, QueryBspConfirmChunksToProveForFileError> {
FileSystem::query_bsp_confirm_chunks_to_prove_for_file(bsp_id, file_key)
}
fn query_msp_confirm_chunks_to_prove_for_file(msp_id: MainStorageProviderId<Runtime>, file_key: H256) -> Result<Vec<ChunkId>, QueryMspConfirmChunksToProveForFileError> {
FileSystem::query_msp_confirm_chunks_to_prove_for_file(msp_id, file_key)
}
fn decode_generic_apply_delta_event_info(encoded_event_info: Vec<u8>) -> Result<BucketId<Runtime>, GenericApplyDeltaEventInfoError> {
FileSystem::decode_generic_apply_delta_event_info(encoded_event_info)
}
fn pending_storage_requests_by_msp(msp_id: MainStorageProviderId<Runtime>) -> BTreeMap<H256, StorageRequestMetadata<Runtime>> {
FileSystem::pending_storage_requests_by_msp(msp_id)
}
}
impl pallet_payment_streams_runtime_api::PaymentStreamsApi<Block, ProviderIdFor<Runtime>, Balance, AccountId> for Runtime {
fn get_users_with_debt_over_threshold(provider_id: &ProviderIdFor<Runtime>, threshold: Balance) -> Result<Vec<AccountId>, GetUsersWithDebtOverThresholdError> {
PaymentStreams::get_users_with_debt_over_threshold(provider_id, threshold)
}
fn get_users_of_payment_streams_of_provider(provider_id: &ProviderIdFor<Runtime>) -> Vec<AccountId> {
PaymentStreams::get_users_of_payment_streams_of_provider(provider_id)
}
fn get_providers_with_payment_streams_with_user(user_account: &AccountId) -> Vec<ProviderIdFor<Runtime>> {
PaymentStreams::get_providers_with_payment_streams_with_user(user_account)
}
}
impl pallet_proofs_dealer_runtime_api::ProofsDealerApi<Block, ProofsDealerProviderIdFor<Runtime>, BlockNumber, KeyFor<Runtime>, RandomnessOutputFor<Runtime>, CustomChallenge<Runtime>> for Runtime {
fn get_last_tick_provider_submitted_proof(provider_id: &ProofsDealerProviderIdFor<Runtime>) -> Result<BlockNumber, GetProofSubmissionRecordError> {
ProofsDealer::get_last_tick_provider_submitted_proof(provider_id)
}
fn get_next_tick_to_submit_proof_for(provider_id: &ProofsDealerProviderIdFor<Runtime>) -> Result<BlockNumber, GetProofSubmissionRecordError> {
ProofsDealer::get_next_tick_to_submit_proof_for(provider_id)
}
fn get_last_checkpoint_challenge_tick() -> BlockNumber {
ProofsDealer::get_last_checkpoint_challenge_tick()
}
fn get_checkpoint_challenges(
tick: BlockNumber
) -> Result<Vec<CustomChallenge<Runtime>>, GetCheckpointChallengesError> {
ProofsDealer::get_checkpoint_challenges(tick)
}
fn get_challenge_seed(tick: BlockNumber) -> Result<RandomnessOutputFor<Runtime>, GetChallengeSeedError> {
ProofsDealer::get_challenge_seed(tick)
}
fn get_challenge_period(provider_id: &ProofsDealerProviderIdFor<Runtime>) -> Result<BlockNumber, GetChallengePeriodError> {
ProofsDealer::get_challenge_period(provider_id)
}
fn get_checkpoint_challenge_period() -> BlockNumber {
ProofsDealer::get_checkpoint_challenge_period()
}
fn get_challenges_from_seed(seed: &RandomnessOutputFor<Runtime>, provider_id: &ProofsDealerProviderIdFor<Runtime>, count: u32) -> Vec<KeyFor<Runtime>> {
ProofsDealer::get_challenges_from_seed(seed, provider_id, count)
}
fn get_forest_challenges_from_seed(seed: &RandomnessOutputFor<Runtime>, provider_id: &ProofsDealerProviderIdFor<Runtime>) -> Vec<KeyFor<Runtime>> {
ProofsDealer::get_forest_challenges_from_seed(seed, provider_id)
}
fn get_current_tick() -> BlockNumber {
ProofsDealer::get_current_tick()
}
fn get_next_deadline_tick(provider_id: &ProofsDealerProviderIdFor<Runtime>) -> Result<BlockNumber, GetNextDeadlineTickError> {
ProofsDealer::get_next_deadline_tick(provider_id)
}
}
impl pallet_storage_providers_runtime_api::StorageProvidersApi<Block, BlockNumber, BackupStorageProviderId<Runtime>, BackupStorageProvider<Runtime>, MainStorageProviderId<Runtime>, AccountId, ProviderIdFor<Runtime>, StorageProviderId<Runtime>, StorageDataUnit<Runtime>, Balance, BucketId<Runtime>, Multiaddresses<Runtime>, ValuePropositionWithId<Runtime>> for Runtime {
fn get_bsp_info(bsp_id: &BackupStorageProviderId<Runtime>) -> Result<BackupStorageProvider<Runtime>, GetBspInfoError> {
Providers::get_bsp_info(bsp_id)
}
fn get_storage_provider_id(who: &AccountId) -> Option<StorageProviderId<Runtime>> {
Providers::get_storage_provider_id(who)
}
fn query_msp_id_of_bucket_id(bucket_id: &BucketId<Runtime>) -> Result<Option<ProviderIdFor<Runtime>>, QueryMspIdOfBucketIdError> {
Providers::query_msp_id_of_bucket_id(bucket_id)
}
fn query_provider_multiaddresses(provider_id: &ProviderIdFor<Runtime>) -> Result<Multiaddresses<Runtime>, QueryProviderMultiaddressesError> {
Providers::query_provider_multiaddresses(provider_id)
}
fn query_storage_provider_capacity(provider_id: &ProviderIdFor<Runtime>) -> Result<StorageDataUnit<Runtime>, QueryStorageProviderCapacityError> {
Providers::query_storage_provider_capacity(provider_id)
}
fn query_available_storage_capacity(provider_id: &ProviderIdFor<Runtime>) -> Result<StorageDataUnit<Runtime>, QueryAvailableStorageCapacityError> {
Providers::query_available_storage_capacity(provider_id)
}
fn query_earliest_change_capacity_block(provider_id: &BackupStorageProviderId<Runtime>) -> Result<BlockNumber, QueryEarliestChangeCapacityBlockError> {
Providers::query_earliest_change_capacity_block(provider_id)
}
fn get_worst_case_scenario_slashable_amount(provider_id: ProviderIdFor<Runtime>) -> Option<Balance> {
Providers::get_worst_case_scenario_slashable_amount(&provider_id).ok()
}
fn get_slash_amount_per_max_file_size() -> Balance {
Providers::get_slash_amount_per_max_file_size()
}
fn query_value_propositions_for_msp(msp_id: &MainStorageProviderId<Runtime>) -> Vec<ValuePropositionWithId<Runtime>> {
Providers::query_value_propositions_for_msp(msp_id)
}
fn get_bsp_stake(bsp_id: &BackupStorageProviderId<Runtime>) -> Result<Balance, GetStakeError> {
Providers::get_bsp_stake(bsp_id)
}
fn can_delete_provider(provider_id: &ProviderIdFor<Runtime>) -> bool {
Providers::can_delete_provider(provider_id)
}
fn query_buckets_for_msp(msp_id: &MainStorageProviderId<Runtime>) -> Result<Vec<BucketId<Runtime>>, QueryBucketsForMspError> {
Providers::query_buckets_for_msp(msp_id)
}
fn query_buckets_of_user_stored_by_msp(msp_id: &ProviderIdFor<Runtime>, user: &AccountId) -> Result<sp_runtime::Vec<BucketId<Runtime>>, QueryBucketsOfUserStoredByMspError> {
Ok(sp_runtime::Vec::from_iter(Providers::query_buckets_of_user_stored_by_msp(msp_id, user)?))
}
}
}
// Shorthand for a Get field of a pallet Config.

View file

@ -1,5 +1,5 @@
[toolchain]
channel = "1.85"
channel = "1.87"
components = [
"cargo",
"clippy",

View file

@ -1,5 +1,5 @@
{
"version": "0.1.0-autogenerated.7914682730988627992",
"version": "0.1.0-autogenerated.15314170487867117571",
"name": "@polkadot-api/descriptors",
"files": [
"dist"

Binary file not shown.