Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

feat: Oracle pallet and precompile #853

Merged
merged 44 commits into from
Dec 20, 2024
Merged
Show file tree
Hide file tree
Changes from 42 commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
3f7dd29
Merge branch 'main' of github.com:tangle-network/tangle into feat/evm…
1xstj Dec 10, 2024
b7644b8
chore : switch to asset-id evm
1xstj Dec 10, 2024
ce7effe
cleanup
1xstj Dec 11, 2024
cf47bec
bump subxt
1xstj Dec 11, 2024
663f374
clean slate
1xstj Dec 12, 2024
f65f735
Merge branch 'main' of github.com:tangle-network/tangle into feat/evm…
1xstj Dec 12, 2024
5a677c8
use common exports
1xstj Dec 12, 2024
5e53247
use common exports
1xstj Dec 12, 2024
87181bb
wip
1xstj Dec 12, 2024
fadb9f6
wip
1xstj Dec 13, 2024
4d6b596
wip
1xstj Dec 13, 2024
c214aca
fix compile
1xstj Dec 13, 2024
a704da2
cleanup
1xstj Dec 13, 2024
6b51c97
compiling
1xstj Dec 14, 2024
4cc8780
precompiles fixes
1xstj Dec 16, 2024
b1719ee
Merge branch 'main' of github.com:tangle-network/tangle into feat/evm…
1xstj Dec 16, 2024
4a2a2a8
runtimes building
1xstj Dec 16, 2024
35f9394
update mocks
1xstj Dec 16, 2024
42a56fe
cleanup tests
1xstj Dec 16, 2024
145ff94
update js types
1xstj Dec 16, 2024
0c400ac
update subxt
1xstj Dec 16, 2024
c179e4c
cleanup clippy
1xstj Dec 16, 2024
8c58a05
use nightly fmt
1xstj Dec 16, 2024
130955c
use stable fmt
1xstj Dec 16, 2024
59b2375
cleanup clippy
1xstj Dec 16, 2024
f59c794
cleanup tests
1xstj Dec 16, 2024
0e72e74
cleanup tests
1xstj Dec 16, 2024
ec34241
cleanup fmt
1xstj Dec 16, 2024
99c6b08
more tests passing
1xstj Dec 17, 2024
eeb5487
cleanup clippy
1xstj Dec 17, 2024
44500a5
clipyy fixes
1xstj Dec 17, 2024
b2815d3
cleanup clippy
1xstj Dec 17, 2024
e7c6dbe
import oracle pallet
1xstj Dec 17, 2024
ebe8b6a
update traits
1xstj Dec 17, 2024
7adf9e6
update precompile
1xstj Dec 17, 2024
c9754bb
cleanup mock
1xstj Dec 17, 2024
6956d90
Merge branch 'main' of github.com:tangle-network/tangle into oracle-p…
1xstj Dec 18, 2024
fce9401
fix
1xstj Dec 18, 2024
eca9612
updates to tests
1xstj Dec 19, 2024
b265547
Merge branch 'main' of github.com:tangle-network/tangle into oracle-p…
1xstj Dec 20, 2024
4a1008b
update precompile
1xstj Dec 20, 2024
53fb139
update docs
1xstj Dec 20, 2024
8f58e92
update interface
1xstj Dec 20, 2024
5c48492
fix tests
1xstj Dec 20, 2024
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
19 changes: 19 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ pallet-services-rpc-runtime-api = { path = "pallets/services/rpc/runtime-api", d
pallet-services-rpc = { path = "pallets/services/rpc" }
pallet-multi-asset-delegation = { path = "pallets/multi-asset-delegation", default-features = false }
pallet-tangle-lst-benchmarking = { path = "pallets/tangle-lst/benchmarking", default-features = false }
pallet-oracle = { path = "pallets/oracle", default-features = false }

k256 = { version = "0.13.3", default-features = false }
p256 = { version = "0.13.2", default-features = false }
Expand Down
2 changes: 0 additions & 2 deletions client/evm-tracing/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,6 @@ ethereum-types = { workspace = true, features = [ "std" ] }
hex = { workspace = true, features = [ "serde" ] }
serde = { workspace = true, features = [ "derive", "std" ] }
serde_json = { workspace = true }

# Moonbeam
evm-tracing-events = { workspace = true, features = [ "std" ] }
rpc-primitives-debug = { workspace = true, features = [ "std" ] }

Expand Down
2 changes: 1 addition & 1 deletion client/rpc/debug/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ hex-literal = { workspace = true }
jsonrpsee = { workspace = true, features = ["macros", "server"] }
tokio = { workspace = true, features = ["sync", "time"] }

# Moonbeam

client-evm-tracing = { workspace = true }
rpc-core-debug = { workspace = true }
rpc-core-types = { workspace = true }
Expand Down
2 changes: 1 addition & 1 deletion client/rpc/trace/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ substrate-prometheus-endpoint = { workspace = true }
tokio = { workspace = true, features = ["sync", "time"] }
tracing = { workspace = true }

# Moonbeam

client-evm-tracing = { workspace = true }
rpc-core-trace = { workspace = true }
rpc-core-types = { workspace = true }
Expand Down
2 changes: 1 addition & 1 deletion client/rpc/txpool/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ jsonrpsee = { workspace = true, features = ["macros", "server"] }
serde = { workspace = true, features = ["derive"] }
sha3 = { workspace = true }

# Moonbeam

rpc-core-txpool = { workspace = true }
rpc-primitives-txpool = { workspace = true, features = ["std"] }

Expand Down
2 changes: 1 addition & 1 deletion evm-tracer/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ license = "GPL-3.0-only"
repository = { workspace = true }

[dependencies]
# Moonbeam

evm-tracing-events = { workspace = true, features = ["evm-tracing"] }
primitives-ext = { workspace = true }

Expand Down
3 changes: 2 additions & 1 deletion pallets/claims/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ use sp_io::{
crypto::{secp256k1_ecdsa_recover, sr25519_verify},
hashing::keccak_256,
};
use sp_runtime::Saturating;
use sp_runtime::{
traits::{CheckedSub, Zero},
transaction_validity::{InvalidTransaction, TransactionValidity, ValidTransaction},
Expand Down Expand Up @@ -334,7 +335,7 @@ pub mod pallet {
) -> DispatchResult {
ensure_root(origin)?;

<Total<T>>::mutate(|t| *t += value);
<Total<T>>::mutate(|t| *t = t.saturating_add(value));
<Claims<T>>::insert(who.clone(), value);
if let Some(vs) = vesting_schedule {
<Vesting<T>>::insert(who.clone(), vs);
Expand Down
52 changes: 52 additions & 0 deletions pallets/oracle/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
[package]
name = "pallet-oracle"
description = "Oracle module that makes off-chain data available on-chain."
repository = "https://github.com/open-web3-stack/open-runtime-module-library/tree/master/oracle"
license = "Apache-2.0"
version = "1.1.0"
authors = ["Laminar Developers <[email protected]>"]
edition = "2021"

[dependencies]
parity-scale-codec = { workspace = true }
scale-info = { workspace = true }
serde = { workspace = true, optional = true }

frame-support = { workspace = true }
frame-system = { workspace = true }
sp-application-crypto = { workspace = true }
sp-io = { workspace = true }
sp-runtime = { workspace = true }
sp-std = { workspace = true }
frame-benchmarking = { workspace = true, optional = true }
tangle-primitives = { workspace = true }

[dev-dependencies]
sp-core = { workspace = true }

[features]
default = [ "std" ]
std = [
"frame-benchmarking?/std",
"frame-support/std",
"frame-system/std",
"tangle-primitives/std",
"parity-scale-codec/std",
"scale-info/std",
"serde",
"sp-application-crypto/std",
"sp-io/std",
"sp-runtime/std",
"sp-std/std",
]
try-runtime = [
"frame-support/try-runtime",
"frame-system/try-runtime",
"sp-runtime/try-runtime",
]
runtime-benchmarks = [
"frame-benchmarking/runtime-benchmarks",
"frame-support/runtime-benchmarks",
"frame-system/runtime-benchmarks",
"sp-runtime/runtime-benchmarks",
]
103 changes: 103 additions & 0 deletions pallets/oracle/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
# Oracle Pallet

## Overview

The Oracle pallet provides a decentralized mechanism for feeding external off-chain data into the Tangle blockchain. It allows authorized oracle operators to submit data which can then be aggregated to provide reliable on-chain values.

## Features

- **Authorized Data Feeding**: Only authorized operators can submit data to the oracle
- **Timestamped Values**: All submitted values include timestamps for freshness verification
- **Data Aggregation**: Raw values from multiple operators can be combined using customizable aggregation logic
- **Flexible Key-Value Storage**: Supports arbitrary key types for versatile data storage
- **EVM Integration**: Includes precompile support for Ethereum compatibility

## Interface

### Extrinsics (Callable Functions)

- `feed_values(values: Vec<(OracleKey, OracleValue)>)`: Submit multiple key-value pairs to the oracle
- Requires sender to be an authorized operator
- Values are stored with current timestamp
- Limited by `MaxFeedValues` configuration

### Storage Queries

- `get(key)`: Retrieve the current combined value for a given key
- `get_all_values()`: Retrieve all stored key-value pairs
- `read_raw_values(key)`: Get all raw values submitted for a specific key

### EVM Precompile Interface

The pallet includes an EVM precompile that exposes the following functions:

```solidity
interface IOraclePrecompile {
// Feed multiple values into the oracle
function feedValues(uint256[] keys, uint256[] values) external;

// Read a value from the oracle
function getValue(uint256 key) external view returns (uint256 value, uint256 timestamp);
}
```

## Configuration

The pallet is configurable through the following types:

- `OracleKey`: The type used for oracle keys (e.g., `u32`)
- `OracleValue`: The type used for oracle values (e.g., `u64`)
- `MaxFeedValues`: Maximum number of values that can be fed in a single call
- `Members`: Source of oracle operator membership (typically using `pallet-membership`)

## Usage Examples

### Feeding Values

```rust
// Submit values through runtime call
Oracle::feed_values(
RuntimeOrigin::signed(operator_account),
vec![(key1, value1), (key2, value2)]
)?;

// Read values
if let Some(timestamped_value) = Oracle::get(&key) {
let value = timestamped_value.value;
let timestamp = timestamped_value.timestamp;
// Use the value...
}
```

### Through EVM

```solidity
// Assuming the precompile is deployed at ORACLE_ADDRESS
IOraclePrecompile oracle = IOraclePrecompile(ORACLE_ADDRESS);

// Feed values
uint256[] memory keys = new uint256[](2);
uint256[] memory values = new uint256[](2);
keys[0] = 1;
keys[1] = 2;
values[0] = 100;
values[1] = 200;
oracle.feedValues(keys, values);

// Read value
(uint256 value, uint256 timestamp) = oracle.getValue(1);
```

## Security

- Only authorized operators can feed values
- All values are timestamped to ensure data freshness
- Membership changes automatically clean up old operator data
- Gas costs are properly accounted for in EVM operations

## Dependencies

- `frame-support`: Core FRAME support library
- `frame-system`: Core Substrate system library
- `pallet-membership`: (optional) For managing oracle operators
- `pallet-evm`: For EVM precompile support
17 changes: 17 additions & 0 deletions pallets/oracle/runtime-api/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
[package]
name = "pallet-oracle-runtime-api"
version = "1.1.0"
authors = ["Laminar Developers <[email protected]>"]
edition = "2021"
license = "Apache-2.0"
description = "Runtime API module for pallet-oracle."
repository = "https://github.com/open-web3-stack/open-runtime-module-library"

[dependencies]
parity-scale-codec = { version = "3.0.0", default-features = false, features = ["derive"] }
sp-api = { workspace = true }
sp-std = { workspace = true }

[features]
default = [ "std" ]
std = [ "parity-scale-codec/std", "sp-api/std", "sp-std/std" ]
21 changes: 21 additions & 0 deletions pallets/oracle/runtime-api/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
//! Runtime API definition for oracle module.

#![cfg_attr(not(feature = "std"), no_std)]
// The `too_many_arguments` warning originates from `decl_runtime_apis` macro.
#![allow(clippy::too_many_arguments)]
// The `unnecessary_mut_passed` warning originates from `decl_runtime_apis` macro.
#![allow(clippy::unnecessary_mut_passed)]

use parity_scale_codec::Codec;
use sp_std::prelude::Vec;

sp_api::decl_runtime_apis! {
pub trait OracleApi<ProviderId, Key, Value> where
ProviderId: Codec,
Key: Codec,
Value: Codec,
{
fn get_value(provider_id: ProviderId, key: Key) -> Option<Value>;
fn get_all_values(provider_id: ProviderId) -> Vec<(Key, Option<Value>)>;
}
}
56 changes: 56 additions & 0 deletions pallets/oracle/src/benchmarking.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
use super::*;
use crate::Pallet as Oracle;

use frame_benchmarking::v2::*;

use frame_support::assert_ok;
use frame_system::{Pallet as System, RawOrigin};

#[instance_benchmarks]
mod benchmarks {
use super::*;

#[benchmark]
fn feed_values(
x: Linear<0, { T::BenchmarkHelper::get_currency_id_value_pairs().len() as u32 }>,
) {
// Register the caller
let caller: T::AccountId = whitelisted_caller();
T::Members::add(&caller);

let values = T::BenchmarkHelper::get_currency_id_value_pairs()[..x as usize]
.to_vec()
.try_into()
.expect("Must succeed since at worst the length remained the same.");

#[extrinsic_call]
_(RawOrigin::Signed(caller.clone()), values);

assert!(HasDispatched::<T, I>::get().contains(&caller));
}

#[benchmark]
fn on_finalize() {
// Register the caller
let caller: T::AccountId = whitelisted_caller();
T::Members::add(&caller);

// Feed some values before running `on_finalize` hook
System::<T>::set_block_number(1u32.into());
let values = T::BenchmarkHelper::get_currency_id_value_pairs();
assert_ok!(Oracle::<T, I>::feed_values(RawOrigin::Signed(caller).into(), values));

#[block]
{
Oracle::<T, I>::on_finalize(System::<T>::block_number());
}

assert!(!HasDispatched::<T, I>::exists());
}

impl_benchmark_test_suite! {
Oracle,
crate::mock::new_test_ext(),
crate::mock::Test,
}
}
Loading
Loading