Skip to content

Commit

Permalink
refactor(relayer): Store genesis config in .toml file (#102)
Browse files Browse the repository at this point in the history
  • Loading branch information
mertwole authored Aug 20, 2024
1 parent f7ca72f commit 14598d1
Show file tree
Hide file tree
Showing 15 changed files with 216 additions and 45 deletions.
8 changes: 4 additions & 4 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ _obj
cache/
out/

!/broadcast
**/broadcast/*/31337/
**/broadcast/**/dry-run/
ethereum/broadcast

.env
.env

GenesisConfig.toml
2 changes: 2 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 @@ -106,6 +106,7 @@ static_assertions = "1.1.0"
thiserror = "1.0.61"
tiny-keccak = { version = "2.0.2", features = ["keccak"] }
tokio = { version = "1.23.0", features = ["full"] }
toml = "0.8.19"
tree_hash = { git = "https://github.com/gear-tech/tree_hash.git", branch = "gear-v0.6.0", default-features = false }
tree_hash_derive = { git = "https://github.com/gear-tech/tree_hash.git", branch = "gear-v0.6.0" }
unroll = "0.1.5"
Expand Down
2 changes: 1 addition & 1 deletion gear-rpc-client/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ edition.workspace = true
[dependencies]
hex.workspace = true
futures-util.workspace = true

anyhow.workspace = true
blake2.workspace = true
gsdk.workspace = true
subxt.workspace = true
sc-consensus-grandpa.workspace = true
Expand Down
6 changes: 6 additions & 0 deletions gear-rpc-client/src/dto.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
const ED25519_PUBLIC_KEY_SIZE: usize = 32;
const ED25519_SIGNATURE_SIZE: usize = 64;
const KECCAK_HASH_SIZE: usize = 32;
const BLAKE2_HASH_SIZE: usize = 32;

pub struct PreCommit {
pub public_key: [u8; ED25519_PUBLIC_KEY_SIZE],
Expand Down Expand Up @@ -57,3 +58,8 @@ pub struct Message {
pub struct UserMessageSent {
pub payload: Vec<u8>,
}

pub struct AuthoritySetState {
pub authority_set_id: u64,
pub authority_set_hash: [u8; BLAKE2_HASH_SIZE],
}
48 changes: 42 additions & 6 deletions gear-rpc-client/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,11 @@
#![feature(generic_const_exprs)]

use anyhow::anyhow;
use dto::BranchNodeData;
use blake2::{
digest::{Update, VariableOutput},
Blake2bVar,
};
use dto::{AuthoritySetState, BranchNodeData};
use gsdk::{
metadata::{
gear::Event as GearEvent,
Expand Down Expand Up @@ -85,12 +89,44 @@ impl GearApi {
Ok(self.api.rpc().chain_get_finalized_head().await?)
}

/// Fetch authority set id for the given block.
pub async fn authority_set_id(&self, block: H256) -> anyhow::Result<u64> {
let block = (*self.api).blocks().at(block).await?;
let set_id_address = gsdk::Api::storage_root(GrandpaStorage::CurrentSetId);
Self::fetch_from_storage(&block, &set_id_address).await
}

/// Get authority set state for specified block. If block is not specified
/// the latest finalized block is taken.
pub async fn authority_set_state(
&self,
block: Option<H256>,
) -> anyhow::Result<AuthoritySetState> {
let block = match block {
Some(block) => block,
None => self.latest_finalized_block().await?,
};

let block = (*self.api).blocks().at(block).await?;
let set_id_address = gsdk::Api::storage_root(GrandpaStorage::CurrentSetId);
let set_id = Self::fetch_from_storage(&block, &set_id_address).await?;

let authority_set = self.fetch_authority_set(set_id).await?;
let authority_set_data: Vec<_> = authority_set.into_iter().flatten().collect();

let mut hasher = Blake2bVar::new(32).expect("Failed to instantiate Blake2bVar");
hasher.update(&authority_set_data);
let mut hash = [0; 32];
hasher
.finalize_variable(&mut hash)
.expect("Hash is of incorrect size");

Ok(AuthoritySetState {
authority_set_hash: hash,
authority_set_id: set_id,
})
}

/// Find authority set id that have signed given `block`.
pub async fn signed_by_authority_set_id(&self, block: H256) -> anyhow::Result<u64> {
let stored_set_id = self.authority_set_id(block).await?;
Expand Down Expand Up @@ -151,10 +187,10 @@ impl GearApi {

pub async fn fetch_finality_proof_for_session(
&self,
validator_set_id: u64,
authority_set_id: u64,
) -> anyhow::Result<(H256, dto::BlockFinalityProof)> {
let block = self
.search_for_authority_set_block(validator_set_id)
.search_for_authority_set_block(authority_set_id)
.await?;

self.fetch_finality_proof(block).await
Expand All @@ -166,7 +202,7 @@ impl GearApi {
&self,
after_block: H256,
) -> anyhow::Result<(H256, dto::BlockFinalityProof)> {
let required_validator_set_id = self.signed_by_authority_set_id(after_block).await?;
let required_authority_set_id = self.signed_by_authority_set_id(after_block).await?;

let after_block_number = self.block_hash_to_number(after_block).await?;
let finality: Option<String> = self
Expand All @@ -190,7 +226,7 @@ impl GearApi {

let signed_data = sp_consensus_grandpa::localized_payload(
justification.round,
required_validator_set_id,
required_authority_set_id,
&sp_consensus_grandpa::Message::<GearHeader>::Precommit(Precommit::<GearHeader>::new(
finality.block,
fetched_block_number,
Expand All @@ -202,7 +238,7 @@ impl GearApi {
assert!(pc.signature.verify(&signed_data[..], &pc.id));
}

let validator_set = self.fetch_authority_set(required_validator_set_id).await?;
let validator_set = self.fetch_authority_set(required_authority_set_id).await?;

let pre_commits: Vec<_> = justification
.commit
Expand Down
6 changes: 3 additions & 3 deletions prover/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,14 @@ edition.workspace = true
[dependencies]
anyhow.workspace = true
env_logger.workspace = true
ff.workspace = true
itertools.workspace = true
jemallocator.workspace = true
keccak-hash.workspace = true
lazy_static.workspace = true
log.workspace = true
num.workspace = true
paste.workspace = true
plonky2.workspace = true
plonky2_ed25519.workspace = true
plonky2_field.workspace = true
Expand All @@ -24,9 +27,6 @@ serde.workspace = true
serde_json.workspace = true
static_assertions.workspace = true
unroll.workspace = true
ff.workspace = true
lazy_static.workspace = true
paste.workspace = true

parity-scale-codec.workspace = true
sp-trie = { workspace = true, features = ["std"] }
Expand Down
2 changes: 1 addition & 1 deletion prover/src/final_proof/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ impl FinalProof {

let desired_genesis_validator_set_hash = Blake2TargetGoldilocks::parse_exact(
&mut genesis_config
.validator_set_hash
.authority_set_hash_goldilocks()
.iter()
.map(|el| builder.constant(F::from_noncanonical_u64(*el))),
);
Expand Down
2 changes: 1 addition & 1 deletion prover/src/latest_validator_set/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ impl Circuit {
) -> ProofWithCircuitData<LatestValidatorSetTarget> {
let genesis_data_pis = vec![config.authority_set_id]
.into_iter()
.chain(config.validator_set_hash)
.chain(config.authority_set_hash_goldilocks())
.map(F::from_noncanonical_u64)
.enumerate()
.collect();
Expand Down
19 changes: 18 additions & 1 deletion prover/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ pub mod proving {
LatestValidatorSet,
},
};
use consts::BLAKE2_DIGEST_SIZE;
use plonky2::{
plonk::{
circuit_data::{CommonCircuitData, VerifierCircuitData},
Expand Down Expand Up @@ -166,7 +167,23 @@ pub mod proving {
#[derive(Clone, Copy)]
pub struct GenesisConfig {
pub authority_set_id: u64,
pub validator_set_hash: [u64; BLAKE2_DIGEST_SIZE_IN_GOLDILOCKS_FIELD_ELEMENTS],
pub authority_set_hash: [u8; BLAKE2_DIGEST_SIZE],
}

impl GenesisConfig {
pub fn authority_set_hash_goldilocks(
&self,
) -> [u64; BLAKE2_DIGEST_SIZE_IN_GOLDILOCKS_FIELD_ELEMENTS] {
self.authority_set_hash
.chunks(4)
.map(|limb_bytes| {
u32::from_be_bytes(limb_bytes.try_into().expect("Expected 4 bytes per limb"))
as u64
})
.collect::<Vec<_>>()
.try_into()
.expect("Incorrect amount of limbs")
}
}

/// Prove very first transition from genesis authority set to the subsequent.
Expand Down
1 change: 1 addition & 0 deletions relayer/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ reqwest.workspace = true
serde.workspace = true
serde_json.workspace = true
thiserror.workspace = true
toml.workspace = true
tokio.workspace = true
utils-prometheus.workspace = true

Expand Down
73 changes: 73 additions & 0 deletions relayer/src/genesis_config.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
use gear_rpc_client::GearApi;
use prover::proving::GenesisConfig;
use serde::{Deserialize, Serialize};

pub async fn fetch_from_chain(
gear_api: GearApi,
block: Option<u32>,
write_to_file: bool,
) -> anyhow::Result<()> {
let block = match block {
Some(bn) => Some(
gear_api
.block_number_to_hash(bn)
.await
.expect("Failed to fetch block hash by number"),
),
None => None,
};

let state = gear_api.authority_set_state(block).await.unwrap();

println!("Authority set id: {}", state.authority_set_id);
println!(
"Authority set hash: {}",
hex::encode(state.authority_set_hash)
);

if write_to_file {
let config = GenesisConfig {
authority_set_id: state.authority_set_id,
authority_set_hash: state.authority_set_hash,
};

write_config_to_file(config);
}

Ok(())
}

#[derive(Deserialize, Serialize)]
struct GenesisConfigToml {
authority_set_id: u64,
authority_set_hash: String,
}

pub fn load_from_file() -> GenesisConfig {
let data =
std::fs::read_to_string("./GenesisConfig.toml").expect("Genesis config is not found");
let config: GenesisConfigToml =
toml::from_str(&data).expect("Wrong GenesisConfig.toml file structure");

let hash = hex::decode(&config.authority_set_hash)
.expect("Incorrect format for authority set hash: hex-encoded hash is expected");
let hash = hash
.try_into()
.expect("Incorrect format for authority set hash: wrong length");

GenesisConfig {
authority_set_id: config.authority_set_id,
authority_set_hash: hash,
}
}

fn write_config_to_file(config: GenesisConfig) {
let config = GenesisConfigToml {
authority_set_id: config.authority_set_id,
authority_set_hash: hex::encode(config.authority_set_hash),
};

let data = toml::to_string(&config).expect("Failed to serialize config");

std::fs::write("./GenesisConfig.toml", data).expect("Failed to write genesis config to file");
}
Loading

0 comments on commit 14598d1

Please sign in to comment.