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

Permissioned L1 stake table #2325

Merged
merged 37 commits into from
Dec 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
0e76651
Initial draft for minimal L1 stake table
sveitser Nov 25, 2024
0bb1514
Add Schnorr verifying key
sveitser Nov 25, 2024
0c4df9a
fix solhint error: named mapping keys and values
sveitser Nov 25, 2024
fdec50c
WIP: contract stake table types to rust types
sveitser Nov 27, 2024
4cfd276
rename: SimpleStakeTable -> PermissionedStakeTable
sveitser Nov 27, 2024
10d3d13
PermissionedStakeTable contract: add DA flag
sveitser Nov 27, 2024
beed539
Allow setting an initial stake table on deployment
sveitser Nov 27, 2024
c919dd1
deploy: load initial stake table from toml file
sveitser Nov 27, 2024
6b8d822
Use serde instead of unsafe rust
sveitser Nov 27, 2024
80dc00e
Update utils/src/deployer.rs
sveitser Dec 4, 2024
f1741e3
WIP: load initial stake table from file
sveitser Dec 4, 2024
99d7186
Merge remote-tracking branch 'origin/main' into ma/simple-stake-table
sveitser Dec 5, 2024
f926e84
Move solidity <-> jf code to contract adapter
sveitser Dec 5, 2024
0862ca7
Load initial stake table from file
sveitser Dec 5, 2024
1b2ccd5
remove unused imports
sveitser Dec 5, 2024
b2d5236
remove unused module
sveitser Dec 5, 2024
b642d06
dev-node: fix arguments to deploy function
sveitser Dec 5, 2024
2827cfa
fix clippy
sveitser Dec 5, 2024
0219c4a
Merge remote-tracking branch 'origin/main' into ma/simple-stake-table
sveitser Dec 5, 2024
e15c2b3
fix Cargo.toml for bindings generation
sveitser Dec 5, 2024
4982a2f
Merge remote-tracking branch 'origin/hotshot/0.5.82' into ma/simple-s…
tbro Dec 5, 2024
1120c7b
combine adding and removing into single event
sveitser Dec 6, 2024
b1179bf
update comment to match implementation (#2282)
alysiahuggins Dec 6, 2024
53274f2
update query-service
imabdulbasit Dec 5, 2024
6f68c0b
db max connections = 25 for dev node tests
imabdulbasit Dec 5, 2024
3be3606
update query-service
imabdulbasit Dec 5, 2024
66d1590
Fix no-storage decides
QuentinI Dec 6, 2024
4a2cd03
Branches -> tags
QuentinI Dec 6, 2024
53810bd
2368 stake table registration with fixed stake (#2365)
alysiahuggins Dec 6, 2024
27bf006
Merge branch 'main' into ma/simple-stake-table
imabdulbasit Dec 9, 2024
94a07a4
fix env var for permissioned_stake_table
imabdulbasit Dec 9, 2024
a55cfd6
Add test for jf / contract types conversions
sveitser Dec 9, 2024
e19186a
cleanup: pass rng
sveitser Dec 9, 2024
77ff146
load stake table from toml file (#2377)
imabdulbasit Dec 10, 2024
3f687e5
Merge branch 'main' into ma/simple-stake-table
sveitser Dec 10, 2024
fabe4af
remove unnecessary rand dependency
sveitser Dec 10, 2024
2ec9e1f
Merge branch 'main' into ma/simple-stake-table
sveitser Dec 10, 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
3 changes: 2 additions & 1 deletion .env
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,10 @@ ESPRESSO_BUILDER_ETH_ACCOUNT_INDEX=8
ESPRESSO_DEPLOYER_ACCOUNT_INDEX=9

# Contracts
ESPRESSO_SEQUENCER_LIGHT_CLIENT_PROXY_ADDRESS=0x0c8e79f3534b00d9a3d4a856b665bf4ebc22f2ba
ESPRESSO_SEQUENCER_LIGHT_CLIENT_PROXY_ADDRESS=0xf7cd8fa9b94db2aa972023b379c7f72c65e4de9d
ESPRESSO_SEQUENCER_LIGHTCLIENT_ADDRESS=$ESPRESSO_SEQUENCER_LIGHT_CLIENT_PROXY_ADDRESS
ESPRESSO_SEQUENCER_PERMISSIONED_PROVER=0x14dc79964da2c08b23698b3d3cc7ca32193d9955
SPRESSO_SEQUENCER_PERMISSIONED_STAKE_TABLE_ADDRESS=0x8ce361602b935680e8dec218b820ff5056beb7af

# Example sequencer demo private keys
ESPRESSO_DEMO_SEQUENCER_STAKING_PRIVATE_KEY_0=BLS_SIGNING_KEY~lNDh4Pn-pTAyzyprOAFdXHwhrKhEwqwtMtkD3CZF4x3o
Expand Down
2 changes: 2 additions & 0 deletions .typos.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
[files]
extend-exclude = [
"data/initial_stake_table.toml",
".env",
"*.json",
"**/*.pdf",
"doc/*.svg",
"doc/*.puml",
"contracts/lib",
Expand Down
9 changes: 9 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 contract-bindings/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ pub mod light_client;
pub mod light_client_mock;
pub mod light_client_state_update_vk;
pub mod light_client_state_update_vk_mock;
pub mod permissioned_stake_table;
pub mod plonk_verifier;
pub mod plonk_verifier_2;
pub mod shared_types;
1,169 changes: 1,169 additions & 0 deletions contract-bindings/src/permissioned_stake_table.rs

Large diffs are not rendered by default.

4 changes: 4 additions & 0 deletions contracts/rust/adapter/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,14 @@ edition = { workspace = true }
[dependencies]
anyhow = { workspace = true }
ark-bn254 = { workspace = true }
ark-ec = { workspace = true }
ark-ed-on-bn254 = { workspace = true }
ark-ff = { workspace = true }
ark-poly = { workspace = true }
ark-serialize = { workspace = true }
ark-std = { workspace = true }
contract-bindings = { path = "../../../contract-bindings" }
derive_more = { workspace = true }
diff-test-bn254 = { git = "https://github.com/EspressoSystems/solidity-bn254.git" }
ethers = { version = "2.0.4" }
hotshot-types = { workspace = true }
Expand All @@ -22,6 +25,7 @@ jf-utils = { workspace = true }
libp2p = { workspace = true, features = ["serde"] }
num-bigint = { version = "0.4", default-features = false }
num-traits = { version = "0.2", default-features = false }
serde = { workspace = true }

[[bin]]
name = "eval-domain"
Expand Down
1 change: 1 addition & 0 deletions contracts/rust/adapter/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

pub mod jellyfish;
pub mod light_client;
pub mod stake_table;

// Archived, legacy helpers and tests, to be removed soon. not included, reference/read only
// mod archived
224 changes: 224 additions & 0 deletions contracts/rust/adapter/src/stake_table.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,224 @@
use crate::jellyfish::u256_to_field;
use ark_ec::{
short_weierstrass,
twisted_edwards::{self, Affine, TECurveConfig},
AffineRepr,
};
use ark_ed_on_bn254::EdwardsConfig;
use ark_ff::{BigInteger, PrimeField};
use ark_serialize::{CanonicalDeserialize, CanonicalSerialize};
use contract_bindings::permissioned_stake_table::{self, EdOnBN254Point, NodeInfo};
use diff_test_bn254::ParsedG2Point;
use ethers::{
abi::AbiDecode,
prelude::{AbiError, EthAbiCodec, EthAbiType},
types::U256,
};
use hotshot_types::{light_client::StateVerKey, network::PeerConfigKeys, signature_key::BLSPubKey};
use serde::{Deserialize, Serialize};
use std::str::FromStr;

// TODO: (alex) maybe move these commonly shared util to a crate
/// convert a field element to U256, panic if field size is larger than 256 bit
pub fn field_to_u256<F: PrimeField>(f: F) -> U256 {
if F::MODULUS_BIT_SIZE > 256 {
panic!("Shouldn't convert a >256-bit field to U256");
}
U256::from_little_endian(&f.into_bigint().to_bytes_le())
}

/// an intermediate representation of `EdOnBN254Point` in solidity.
#[derive(Clone, PartialEq, Eq, Debug, EthAbiType, EthAbiCodec)]
pub struct ParsedEdOnBN254Point {
/// x coordinate of affine repr
pub x: U256,
/// y coordinate of affine repr
pub y: U256,
}

// this is convention from BN256 precompile
impl Default for ParsedEdOnBN254Point {
fn default() -> Self {
Self {
x: U256::from(0),
y: U256::from(0),
}
}
}

impl From<ParsedEdOnBN254Point> for EdOnBN254Point {
fn from(value: ParsedEdOnBN254Point) -> Self {
Self {
x: value.x,
y: value.y,
}
}
}

impl From<EdOnBN254Point> for ParsedEdOnBN254Point {
fn from(value: EdOnBN254Point) -> Self {
let EdOnBN254Point { x, y } = value;
Self { x, y }
}
}

impl FromStr for ParsedEdOnBN254Point {
type Err = AbiError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let parsed: (Self,) = AbiDecode::decode_hex(s)?;
Ok(parsed.0)
}
}

impl<P: TECurveConfig> From<Affine<P>> for ParsedEdOnBN254Point
where
P::BaseField: PrimeField,
{
fn from(p: Affine<P>) -> Self {
if p.is_zero() {
// this convention is from the BN precompile
Self {
x: U256::from(0),
y: U256::from(0),
}
} else {
Self {
x: field_to_u256::<P::BaseField>(*p.x().unwrap()),
y: field_to_u256::<P::BaseField>(*p.y().unwrap()),
}
}
}
}

impl<P: TECurveConfig> From<ParsedEdOnBN254Point> for Affine<P>
where
P::BaseField: PrimeField,
{
fn from(p: ParsedEdOnBN254Point) -> Self {
if p == ParsedEdOnBN254Point::default() {
Self::default()
} else {
Self::new_unchecked(
u256_to_field::<P::BaseField>(p.x),
u256_to_field::<P::BaseField>(p.y),
)
}
}
}

#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
pub struct NodeInfoJf {
pub stake_table_key: BLSPubKey,
pub state_ver_key: StateVerKey,
pub da: bool,
}

impl From<NodeInfoJf> for NodeInfo {
fn from(value: NodeInfoJf) -> Self {
let NodeInfoJf {
stake_table_key,
state_ver_key,
da,
} = value;
let ParsedG2Point { x0, x1, y0, y1 } = stake_table_key.to_affine().into();
let schnorr: ParsedEdOnBN254Point = state_ver_key.to_affine().into();
Self {
bls_vk: permissioned_stake_table::G2Point {
x_0: x0,
x_1: x1,
y_0: y0,
y_1: y1,
},
schnorr_vk: schnorr.into(),
is_da: da,
}
}
}

impl From<NodeInfo> for NodeInfoJf {
fn from(value: NodeInfo) -> Self {
let NodeInfo {
bls_vk,
schnorr_vk,
is_da,
} = value;
let stake_table_key = {
let g2 = diff_test_bn254::ParsedG2Point {
x0: bls_vk.x_0,
x1: bls_vk.x_1,
y0: bls_vk.y_0,
y1: bls_vk.y_1,
};
let g2_affine = short_weierstrass::Affine::<ark_bn254::g2::Config>::from(g2);
let mut bytes = vec![];
// TODO: remove serde round-trip once jellyfin provides a way to
// convert from Affine representation to VerKey.
//
// Serialization and de-serialization shouldn't fail.
g2_affine
.into_group()
.serialize_compressed(&mut bytes)
.unwrap();
BLSPubKey::deserialize_compressed(&bytes[..]).unwrap()
};
let state_ver_key = {
let g1_point: ParsedEdOnBN254Point = schnorr_vk.into();
let state_sk_affine = twisted_edwards::Affine::<EdwardsConfig>::from(g1_point);
StateVerKey::from(state_sk_affine)
};
Self {
stake_table_key,
state_ver_key,
da: is_da,
}
}
}

impl From<PeerConfigKeys<BLSPubKey>> for NodeInfoJf {
fn from(value: PeerConfigKeys<BLSPubKey>) -> Self {
let PeerConfigKeys {
stake_table_key,
state_ver_key,
da,
..
} = value;
Self {
stake_table_key,
state_ver_key,
da,
}
}
}

#[cfg(test)]
mod test {
use super::*;
use ark_std::rand::{Rng, RngCore};
use hotshot_types::{light_client::StateKeyPair, traits::signature_key::BuilderSignatureKey};

impl NodeInfoJf {
fn random(rng: &mut impl RngCore) -> Self {
let mut seed = [0u8; 32];
rng.fill_bytes(&mut seed);

let (stake_table_key, _) = BLSPubKey::generated_from_seed_indexed(seed, 0);
let state_key_pair = StateKeyPair::generate_from_seed_indexed(seed, 0);
Self {
stake_table_key,
state_ver_key: state_key_pair.ver_key(),
da: rng.gen(),
}
}
}

#[test]
fn test_node_info_round_trip() {
let mut rng = ark_std::rand::thread_rng();
for _ in 0..20 {
let jf = NodeInfoJf::random(&mut rng);
let sol: NodeInfo = jf.clone().into();
let jf2: NodeInfoJf = sol.into();
assert_eq!(jf2, jf);
}
}
}
Loading
Loading