Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

(wip) Drand #951

Draft
wants to merge 26 commits into
base: devnet-ready
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
696 changes: 545 additions & 151 deletions Cargo.lock

Large diffs are not rendered by default.

26 changes: 22 additions & 4 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ members = [
"support/macros",
"support/linting",
"support/procedural-fork",
"pallets/drand",
]
exclude = ["support/procedural-fork"]
resolver = "2"
Expand All @@ -49,7 +50,7 @@ manual_inspect = "allow"
async-trait = "0.1"
cargo-husky = { version = "1", default-features = false }
clap = "4.5.4"
codec = { version = "3.2.2", default-features = false }
codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] }
ed25519-dalek = { version = "2.1.0", default-features = false, features = ["alloc"] }
enumflags2 = "0.7.9"
futures = "0.3.30"
Expand All @@ -63,14 +64,14 @@ parity-util-mem = "0.12.0"
rand = "0.8.5"
scale-codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] }
scale-info = { version = "2.11.2", default-features = false }
serde = { version = "1.0.199", default-features = false }
serde = { version = "1.0.214", default-features = false }
serde-tuple-vec-map = { version = "1.0.1", default-features = false }
serde_bytes = { version = "0.11.14", default-features = false }
serde_json = { version = "1.0.121", default-features = false }
serde_with = { version = "=2.0.0", default-features = false }
smallvec = "1.13.2"
litep2p = { git = "https://github.com/paritytech/litep2p", tag = "v0.7.0" }
syn = { version = "2", features = [
syn = { version = "2.0.87", features = [
"full",
"visit-mut",
"visit",
Expand Down Expand Up @@ -141,7 +142,7 @@ sp-genesis-builder = { git = "https://github.com/paritytech/polkadot-sdk.git", t
sp-core = { git = "https://github.com/paritytech/polkadot-sdk.git", tag = "polkadot-stable2409", default-features = false }
sp-inherents = { git = "https://github.com/paritytech/polkadot-sdk.git", tag = "polkadot-stable2409", default-features = false }
sp-io = { git = "https://github.com/paritytech/polkadot-sdk.git", tag = "polkadot-stable2409", default-features = false }
sp-keyring = { git = "https://github.com/paritytech/polkadot-sdk.git", tag = "polkadot-stable2409" }
sp-keyring = { git = "https://github.com/paritytech/polkadot-sdk.git", tag = "polkadot-stable2409", default-features = false }
sp-offchain = { git = "https://github.com/paritytech/polkadot-sdk.git", tag = "polkadot-stable2409", default-features = false }
sp-rpc = { git = "https://github.com/paritytech/polkadot-sdk.git", tag = "polkadot-stable2409", default-features = false }
sp-runtime = { git = "https://github.com/paritytech/polkadot-sdk.git", tag = "polkadot-stable2409", default-features = false }
Expand Down Expand Up @@ -190,6 +191,23 @@ pallet-evm-precompile-sha3fips = { git = "https://github.com/gztensor/frontier",
pallet-evm-precompile-simple = { git = "https://github.com/gztensor/frontier", rev = "b8e3025", default-features = false }
pallet-hotfix-sufficients = { git = "https://github.com/gztensor/frontier", rev = "b8e3025", default-features = false }

#DRAND
pallet-drand = { path = "pallets/drand", default-features = false }
sp-crypto-ec-utils = { git = "https://github.com/paritytech/polkadot-sdk.git", tag = "polkadot-stable2409", features = ["bls12-381"] }
getrandom = { version = "0.2.15", features = ["custom"], default-features = false }
sp-keystore = { git = "https://github.com/paritytech/polkadot-sdk.git", tag = "polkadot-stable2409", default-features = false }
w3f-bls = { version = "=0.1.3", default-features = false }
ark-crypto-primitives = { version = "0.4.0", default-features = false, features = [ "r1cs", "snark" ] }
ark-scale = { version = "0.0.11", default-features = false, features = ["hazmat"] }
sp-ark-bls12-381 = { git = "https://github.com/paritytech/substrate-curves", default-features = false }
ark-bls12-381 = { version = "0.4.0", features = ["curve"], default-features = false }
ark-serialize = { version = "0.4.0", features = [ "derive" ], default-features = false }
ark-ff = { version = "0.4.0", default-features = false }
ark-ec = { version = "0.4.0", default-features = false }
ark-std = { version = "0.4.0", default-features = false }
anyhow = "1.0.81"
sha2 = { version = "0.10.8", default-features = false }

frame-metadata = "16"

[profile.release]
Expand Down
6 changes: 6 additions & 0 deletions node/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,10 @@ frame-metadata-hash-extension = { workspace = true }
frame-system = { workspace = true }
pallet-transaction-payment = { workspace = true }
pallet-commitments = { path = "../pallets/commitments" }
pallet-drand = { workspace = true }
sp-crypto-ec-utils = { workspace = true }
sp-keystore = { workspace = true, default-features = false }


# These dependencies are used for the subtensor's RPCs
jsonrpsee = { workspace = true, features = ["server"] }
Expand Down Expand Up @@ -135,6 +139,7 @@ runtime-benchmarks = [
"sc-service/runtime-benchmarks",
"sp-runtime/runtime-benchmarks",
"pallet-commitments/runtime-benchmarks",
"pallet-drand/runtime-benchmarks"
]
pow-faucet = []

Expand All @@ -146,6 +151,7 @@ try-runtime = [
"pallet-transaction-payment/try-runtime",
"sp-runtime/try-runtime",
"pallet-commitments/try-runtime",
"pallet-drand/try-runtime"
]

metadata-hash = ["node-subtensor-runtime/metadata-hash"]
6 changes: 4 additions & 2 deletions node/src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,15 @@ use sc_executor::WasmExecutor;
/// Full backend.
pub type FullBackend = sc_service::TFullBackend<Block>;
/// Full client.
pub type FullClient = sc_service::TFullClient<Block, RuntimeApi, WasmExecutor<HostFunctions>>;
pub type FullClient = sc_service::TFullClient<Block, RuntimeApi, RuntimeExecutor>;
/// Always enable runtime benchmark host functions, the genesis state
/// was built with them so we're stuck with them forever.
///
/// They're just a noop, never actually get used if the runtime was not compiled with
/// `runtime-benchmarks`.
type HostFunctions = (
pub type HostFunctions = (
sp_io::SubstrateHostFunctions,
sp_crypto_ec_utils::bls12_381::host_calls::HostFunctions,
frame_benchmarking::benchmarking::HostFunctions,
);
pub type RuntimeExecutor = WasmExecutor<HostFunctions>;
57 changes: 36 additions & 21 deletions node/src/service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ use std::{sync::Arc, time::Duration};
use substrate_prometheus_endpoint::Registry;

use crate::cli::Sealing;
use crate::client::{FullBackend, FullClient};
use crate::client::{FullBackend, FullClient, HostFunctions, RuntimeExecutor};
use crate::ethereum::{
db_config_dir, new_frontier_partial, spawn_frontier_tasks, BackendType, EthConfiguration,
FrontierBackend, FrontierBlockImport, FrontierPartialComponents, StorageOverride,
Expand Down Expand Up @@ -77,13 +77,14 @@ where
})
.transpose()?;

let executor = sc_service::new_wasm_executor(&config.executor);
let executor = sc_service::new_wasm_executor::<HostFunctions>(&config.executor);
let (client, backend, keystore_container, task_manager) =
sc_service::new_full_parts::<Block, RuntimeApi, _>(
sc_service::new_full_parts::<Block, RuntimeApi, RuntimeExecutor>(
config,
telemetry.as_ref().map(|(_, telemetry)| telemetry.handle()),
executor,
)?;

let client = Arc::new(client);

let telemetry = telemetry.map(|(worker, telemetry)| {
Expand Down Expand Up @@ -314,24 +315,38 @@ where
})?;

if config.offchain_worker.enabled {
task_manager.spawn_handle().spawn(
"offchain-workers-runner",
"offchain-worker",
sc_offchain::OffchainWorkers::new(sc_offchain::OffchainWorkerOptions {
runtime_api_provider: client.clone(),
is_validator: config.role.is_authority(),
keystore: Some(keystore_container.keystore()),
offchain_db: backend.offchain_storage(),
transaction_pool: Some(OffchainTransactionPoolFactory::new(
transaction_pool.clone(),
)),
network_provider: Arc::new(network.clone()),
enable_http_requests: true,
custom_extensions: |_| vec![],
})
.run(client.clone(), task_manager.spawn_handle())
.boxed(),
);
match sp_keystore::Keystore::sr25519_generate_new(
&*keystore_container.keystore(),
pallet_drand::KEY_TYPE,
Some("//Alice"),
) {
Ok(_) => {
task_manager.spawn_handle().spawn(
"offchain-workers-runner",
"offchain-worker",
sc_offchain::OffchainWorkers::new(sc_offchain::OffchainWorkerOptions {
runtime_api_provider: client.clone(),
is_validator: config.role.is_authority(),
keystore: Some(keystore_container.keystore()),
offchain_db: backend.offchain_storage(),
transaction_pool: Some(OffchainTransactionPoolFactory::new(
transaction_pool.clone(),
)),
network_provider: Arc::new(network.clone()),
enable_http_requests: true,
custom_extensions: |_| vec![],
})
.run(client.clone(), task_manager.spawn_handle())
.boxed(),
);
}
Err(e) => {
log::error!(
"Failed to create SR25519 key for offchain worker with account Alice: {:?}",
e
);
}
}
}

let role = config.role;
Expand Down
91 changes: 91 additions & 0 deletions pallets/drand/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
[package]
name = "pallet-drand"
description = "FRAME pallet for briding to drand."
authors = ["Tony Riemer <[email protected]>"]
version = "0.0.1"
license = "MIT-0"
edition = "2021"
homepage = "https://www.idealabs.network"
publish = false

[package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"]

[dependencies]
codec = { workspace = true, default-features = false, features = [
"derive",
] }
scale-info = { workspace = true, default-features = false, features = [
"derive",
] }
serde = { workspace = true, features = ["derive"], default-features = false }
serde_json = { workspace = true, default-features = false }
log = { workspace = true, default-features = false }
hex = { workspace = true, features = ["serde"], default-features = false }
sha2 = { workspace = true }
anyhow = { workspace = true }
# frame deps
frame-benchmarking = { workspace = true, default-features = false, optional = true }
frame-support = { workspace = true, default-features = false }
frame-system = { workspace = true, default-features = false }
sp-core = { workspace = true, default-features = false }
sp-io = { workspace = true, default-features = false}
sp-runtime = { workspace = true, default-features = false}
# arkworks dependencies
sp-ark-bls12-381 = { workspace = true, default-features = false }
ark-bls12-381 = { workspace = true, features = ["curve"], default-features = false }
ark-serialize = { workspace = true, features = [ "derive" ], default-features = false }
ark-ff = { workspace = true, default-features = false }
ark-ec = { workspace = true, default-features = false }
ark-std = { workspace = true, default-features = false }
ark-crypto-primitives = { workspace = true, default-features = false, features = [ "r1cs", "snark" ] }
ark-scale = { workspace = true, default-features = false, features = ["hazmat"] }
w3f-bls = { workspace = true, default-features = false }
sp-keyring = { workspace = true, default-features = false }
subtensor-macros.workspace = true

[dev-dependencies]
sp-keystore = { workspace = true, default-features = false }

[features]
default = ["std"]
std = [
"codec/std",
"log/std",
"sha2/std",
"frame-benchmarking?/std",
"frame-support/std",
"frame-system/std",
"scale-info/std",
"sp-core/std",
"sp-io/std",
"sp-keystore/std",
"sp-keyring/std",
"sp-runtime/std",
"serde/std",
"serde_json/std",
"hex/std",
"sp-ark-bls12-381/std",
"ark-bls12-381/std",
"ark-serialize/std",
"ark-ff/std",
"ark-ec/std",
"ark-std/std",
"ark-crypto-primitives/std",
"ark-scale/std",
"w3f-bls/std",
]
runtime-benchmarks = [
"frame-benchmarking/runtime-benchmarks",
"frame-support/runtime-benchmarks",
"frame-system/runtime-benchmarks",
"sp-runtime/runtime-benchmarks",
]
try-runtime = [
"frame-support/try-runtime",
"frame-system/try-runtime",
"sp-runtime/try-runtime",
]

# use the drand mainnet configuration
mainnet = []
83 changes: 83 additions & 0 deletions pallets/drand/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
# Drand Bridge Pallet

This is a [FRAME](https://docs.substrate.io/reference/frame-pallets/) pallet that allows Substrate-based chains to bridge to drand. It only supports bridging to drand's [Quicknet](https://drand.love/blog/quicknet-is-live-on-the-league-of-entropy-mainnet), which provides fresh randomness every 3 seconds. Adding this pallet to a runtime allows it to acquire verifiable on-chain randomness which can be used in runtime modules or ink! smart contracts.

Read [here](https://github.com/ideal-lab5/pallet-drand/blob/main/docs/how_it_works.md) for a deep-dive into the pallet.

## Usage

Use this pallet in a Substrate runtime to acquire verifiable randomness from drand's quicknet.

### Node Requirements

Usage of this pallet requires that the node support:
- arkworks host functions
- offchain workers
- (optional - in case of smart contracts) Contracts pallet and drand chain extension enabled

We have included a node in this repo, [substrate-node-template](https://github.com/ideal-lab5/pallet-drand/tree/main/substrate-node-template), that meets these requirements that you can use to get started.

See [here](https://github.com/ideal-lab5/pallet-drand/blob/main/docs/integration.md) for a detailed guide on integrating this pallet into a runtime.

### For Pallets
This pallet implements the [Randomness](https://paritytech.github.io/polkadot-sdk/master/frame_support/traits/trait.Randomness.html) trait. FRAME pallets can use it by configuring their runtimes

``` rust
impl pallet_with_randomness for Runtime {
type Randomness = Drand;
}
```

Subsequently in your pallet, fetch the latest round randomness with:

``` rust
let latest_randomness = T::Randomness::random(b"ctx");
```

For example, the [lottery pallet](https://github.com/paritytech/polkadot-sdk/blob/d3d1542c1d387408c141f9a1a8168e32435a4be9/substrate/frame/lottery/src/lib.rs#L518)

### For Smart Contracts

Add a [chain extension](https://use.ink/macros-attributes/chain-extension/) to your runtime to expose the drand pallet's randomness. An example can be found in the template [here](https://github.com/ideal-lab5/pallet-drand/blob/f00598d961a484fc3c47d1d7f3fa74e5a9f4d38a/substrate-node-template/runtime/src/lib.rs#L854). and then follow the guide [here](https://github.com/ideal-lab5/contracts). The [template contract](https://github.com/ideal-lab5/contracts/tree/main/template) provides a minimal working example.

## Building

``` shell
cargo build
```

## Testing

We maintain a minimum of 85% coverage on all new code. You can check coverage with tarpauling by running

``` shell
cargo tarpaulin --rustflags="-C opt-level=0"
```

### Unit Tests

``` shell
cargo test
```

### Benchmarks

The pallet can be benchmarked with a substrate node that adds the pallet to it's runtime, such as the substrate-node-template example included in this repo.

``` shell
cd substrate-node-template
# build the node with benchmarks enables
cargo build --release --features runtime-benchmarks
# run the pallet benchmarks
./target/release/node-template benchmark pallet \
--chain dev \
--wasm-execution=compiled \
--pallet pallet_drand \
--extrinsic "*" \
--steps 50 \
--repeat 20 \
--output ../src/new_weight.rs \
--allow-missing-host-functions
```

License: MIT-0
Loading
Loading