Skip to content

Commit

Permalink
Merge pull request #4 from commonprefix/blocks
Browse files Browse the repository at this point in the history
Blocks
  • Loading branch information
pkakelas authored Oct 27, 2023
2 parents 752f369 + ae22ba8 commit acaa0c4
Show file tree
Hide file tree
Showing 12 changed files with 7,897 additions and 36 deletions.
2 changes: 1 addition & 1 deletion artifacts/checksums.txt
Original file line number Diff line number Diff line change
@@ -1 +1 @@
57a8138a7cd9101d50563b369f315901c37e690b02bae1f7c6e6ba9b6045a539 light_client.wasm
b5cd6870b6985f11c835058b8dba620011bc0fc96240947da3ba837572ab7a27 light_client.wasm
2 changes: 1 addition & 1 deletion artifacts/checksums_intermediate.txt
Original file line number Diff line number Diff line change
@@ -1 +1 @@
be37a5795dea73b28305eddaf42f318acfc8d4ee1c52c782e5d6ec67c286394f ./target/wasm32-unknown-unknown/release/light_client.wasm
3aee800182bbd5651181db7fdf0240d9e3afc55f33913ffd012661820622425d /target/wasm32-unknown-unknown/release/light_client.wasm
38 changes: 35 additions & 3 deletions src/contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,11 +47,12 @@ pub fn execute(
}
// TODO: only admin should do that
UpdateForks { forks } => execute::update_forks(deps, forks),
VerifyBlock { verification_data } => execute::verify_block(&deps, &env, verification_data),
}
}

mod execute {
use crate::lightclient::types::{Forks, Update};
use crate::lightclient::types::{BlockVerificationData, Forks, Update};

use super::*;

Expand Down Expand Up @@ -88,6 +89,37 @@ mod execute {
})?;
Ok(Response::new())
}

pub fn verify_block(
deps: &DepsMut,
env: &Env,
ver_data: BlockVerificationData,
) -> Result<Response, ContractError> {
let state = LIGHT_CLIENT_STATE.load(deps.storage)?;
let config = CONFIG.load(deps.storage)?;
let lc = LightClient::new(&config, Some(state), env);

let sync_committee = SYNC_COMMITTEES.load(deps.storage, ver_data.sig_slot.into());
if sync_committee.is_err() {
return Err(ContractError::NoSyncCommittee {
period: calc_sync_period(ver_data.sig_slot.into()),
});
}

let res = lc.verify_block(
&sync_committee.unwrap(),
&ver_data.target_block,
&ver_data.intermediate_chain,
&ver_data.sync_aggregate,
ver_data.sig_slot.into(),
);

if res {
Ok(Response::new().add_attribute("result", "ok"))
} else {
Ok(Response::new().add_attribute("result", "err"))
}
}
}

#[cfg_attr(not(feature = "library"), entry_point)]
Expand Down Expand Up @@ -173,7 +205,7 @@ mod tests {
)
.unwrap();

return (app, addr);
(app, addr)
}

#[test]
Expand All @@ -184,7 +216,7 @@ mod tests {

let resp: LightClientState = app
.wrap()
.query_wasm_smart(&addr, &QueryMsg::LightClientState {})
.query_wasm_smart(addr, &QueryMsg::LightClientState {})
.unwrap();

let mut lc = LightClient::new(&get_config(), None, &env);
Expand Down
3 changes: 3 additions & 0 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ pub enum ContractError {
#[error("Update for this period already exists")]
UpdateAlreadyExists {},

#[error("No sync committee for this period")]
NoSyncCommittee { period: u64 },

#[error("Consensus error: {:?}", error)]
ConsensusError { error: ConsensusError },
// Add any other custom errors you like here.
Expand Down
16 changes: 8 additions & 8 deletions src/lightclient/helpers.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
use eyre::Result;
use ssz_rs::prelude::*;

use crate::lightclient::types::{Bytes32, Header};
use crate::lightclient::types::{BeaconBlockHeader, Bytes32};

pub fn is_proof_valid<L: Merkleized>(
attested_header: &Header,
attested_header: &BeaconBlockHeader,
leaf_object: &mut L,
branch: &[Bytes32],
depth: usize,
Expand Down Expand Up @@ -59,7 +59,7 @@ pub mod test_helpers {
let file = File::open("testdata/bootstrap.json").unwrap();
let bootstrap: Bootstrap = serde_json::from_reader(file).unwrap();

return bootstrap;
bootstrap
}

// Currently have in testdata: 767, 862, 863
Expand All @@ -68,23 +68,23 @@ pub mod test_helpers {
let file = File::open(path).unwrap();
let update: Update = serde_json::from_reader(file).unwrap();

return update;
update
}

pub fn get_config() -> ChainConfig {
return ChainConfig {
ChainConfig {
chain_id: 1,
genesis_time: 1606824023,
genesis_root: hex_str_to_bytes(
"0x4b363db94e286120d76eb905340fdd4e54bfe9f06bf33ff6cf5ad27f511bfe95",
)
.unwrap(),
forks: get_forks(),
};
}
}

pub fn get_forks() -> Forks {
return Forks {
Forks {
genesis: Fork {
epoch: 0,
fork_version: hex_str_to_bytes("0x00000000").unwrap(),
Expand All @@ -101,6 +101,6 @@ pub mod test_helpers {
epoch: 194048,
fork_version: hex_str_to_bytes("0x03000000").unwrap(),
},
};
}
}
}
112 changes: 102 additions & 10 deletions src/lightclient/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ impl LightClient {
let pks = self
.get_participating_keys(&sync_committee, &update.sync_aggregate.sync_committee_bits);

let is_valid_sig = self.verify_sync_committee_signture(
let is_valid_sig = self.verify_sync_committee_signature(
&self.config,
&pks,
&update.attested_header.beacon,
Expand Down Expand Up @@ -190,7 +190,7 @@ impl LightClient {

fn is_current_committee_proof_valid(
&self,
attested_header: &Header,
attested_header: &BeaconBlockHeader,
current_committee: &mut SyncCommittee,
current_committee_branch: &[Bytes32],
) -> bool {
Expand Down Expand Up @@ -222,16 +222,16 @@ impl LightClient {

fn is_finality_proof_valid(
&self,
attested_header: &Header,
finality_header: &mut Header,
attested_header: &BeaconBlockHeader,
finality_header: &mut BeaconBlockHeader,
finality_branch: &[Bytes32],
) -> bool {
is_proof_valid(attested_header, finality_header, finality_branch, 6, 41)
}

fn is_next_committee_proof_valid(
&self,
attested_header: &Header,
attested_header: &BeaconBlockHeader,
next_committee: &mut SyncCommittee,
next_committee_branch: &[Bytes32],
) -> bool {
Expand All @@ -244,6 +244,48 @@ impl LightClient {
)
}

/**
* Accepts a chain of blocks [T, .., L, SigBlock] where
* SigBlock: The block that contains the sync aggregate signature of L
* L: A block that can be attested with enough participation by the sync commmittee
* T: The block that we want to verify.
*
* Given those blocks, this function verifies that:
* 1. SigBlock contains a valid signature to L
* 2. The chain of blocks from T to L is valid. ie the hash_tree root
* of n block equals the parent root of n + 1 block
*
* Note that the chain of blocks from T..L should contain blocks that are
* subsequent to each other but the sigBlock just need to be more recent
* than the L block
*
* TODO: Accept block headers instead of full blocks
* TODO: Make sure that the SigBlock is finalized
* TODO: Change input structure from an array of blocks to a meaningful struct
*/
pub fn verify_block(
&self,
sync_committee: &SyncCommittee,
target_block: &BeaconBlock,
intermediate_chain: &[BeaconBlockHeader],
sync_aggregate: &SyncAggregate,
sig_slot: u64,
) -> bool {
if intermediate_chain.is_empty() {
return self.verify_attestation(target_block, sync_aggregate, sync_committee, sig_slot);
}

let is_valid_chain = self.verify_chain_of_blocks(target_block, intermediate_chain);
let is_valid_attestation = self.verify_attestation(
&intermediate_chain[intermediate_chain.len() - 1],
sync_aggregate,
sync_committee,
sig_slot,
);

is_valid_chain && is_valid_attestation
}

/**
* Returns the fork version for a given slot.
*/
Expand Down Expand Up @@ -281,18 +323,46 @@ impl LightClient {
pks
}

fn verify_sync_committee_signture(
pub fn verify_attestation<T>(
&self,
attest_block: &T,
sync_aggregate: &SyncAggregate,
sync_committee: &SyncCommittee,
sig_slot: u64,
) -> bool
where
T: ssz_rs::Merkleized + Clone,
{
let pks = self.get_participating_keys(sync_committee, &sync_aggregate.sync_committee_bits);

if (pks.len() as u64) * 3 < 512 * 2 {
// Not enough participation
return false;
}

self.verify_sync_committee_signature(
&self.config,
&pks,
attest_block,
&sync_aggregate.sync_committee_signature,
sig_slot,
)
}

fn verify_sync_committee_signature<T>(
&self,
config: &ChainConfig,
pks: &[PublicKey],
attested_header: &Header,
attested_block: &T,
signature: &SignatureBytes,
signature_slot: u64,
) -> bool {
) -> bool
where
T: ssz_rs::Merkleized + Clone,
{
let res: Result<bool> = (move || {
let pks: Vec<&PublicKey> = pks.iter().collect();
let header_root =
Bytes32::try_from(attested_header.clone().hash_tree_root()?.as_ref())?;
let header_root = Bytes32::try_from(attested_block.clone().hash_tree_root()?.as_ref())?;
let signing_root =
self.compute_committee_sign_root(config, header_root, signature_slot)?;

Expand All @@ -306,6 +376,28 @@ impl LightClient {
}
}

pub fn verify_chain_of_blocks(
&self,
interested_block: &BeaconBlock,
chain: &[BeaconBlockHeader],
) -> bool {
if chain.is_empty() {
return true;
}

for window in chain.windows(2) {
if let [prev, next] = window {
let hash = prev.clone().hash_tree_root().unwrap();
let next_hash = next.parent_root.as_ref();
if hash != next_hash {
return false;
}
}
}

return interested_block.clone().hash_tree_root().unwrap() == chain[0].parent_root.as_ref();
}

pub fn is_aggregate_valid(
&self,
sig_bytes: &SignatureBytes,
Expand Down
Loading

0 comments on commit acaa0c4

Please sign in to comment.