Skip to content
This repository has been archived by the owner on Nov 9, 2022. It is now read-only.

Commit

Permalink
feat: apply new finality rule
Browse files Browse the repository at this point in the history
  • Loading branch information
keroro520 committed Oct 13, 2022
1 parent 8e0a3fe commit 0b45e20
Show file tree
Hide file tree
Showing 7 changed files with 143 additions and 48 deletions.
17 changes: 12 additions & 5 deletions contracts/custodian-lock/src/entry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,14 @@ use crate::ckb_std::{
high_level::load_script, high_level::load_witness_args,
};
use gw_types::{
core::ScriptHashType,
core::{ScriptHashType, Timepoint},
packed::{
CustodianLockArgs, CustodianLockArgsReader, UnlockCustodianViaRevertWitness,
UnlockCustodianViaRevertWitnessReader,
},
prelude::*,
};
use gw_utils::finality::{is_block_number_finalized, is_timestamp_finalized};
use gw_utils::gw_types;

use crate::error::Error;
Expand Down Expand Up @@ -58,11 +59,17 @@ pub fn main() -> Result<(), Error> {
Some(state) => state,
None => return Err(Error::RollupCellNotFound),
};
let config = load_rollup_config(&global_state.rollup_config_hash().unpack())?;

let deposit_block_number: u64 = lock_args.deposit_block_number().unpack();
let last_finalized_block_number: u64 = global_state.last_finalized_block_number().unpack();

if deposit_block_number <= last_finalized_block_number {
let is_finalized = match Timepoint::from_full_value(lock_args.deposit_block_number().unpack()) {
Timepoint::BlockNumber(block_number) => {
is_block_number_finalized(&config, &global_state, block_number)
}
Timepoint::Timestamp(timestamp) => {
is_timestamp_finalized(&config, &global_state, timestamp)?
}
};
if is_finalized {
// this custodian lock is already finalized, rollup will handle the logic
return Ok(());
}
Expand Down
19 changes: 14 additions & 5 deletions contracts/stake-lock/src/entry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,14 @@ use crate::ckb_std::{
};

use gw_utils::cells::{
rollup::{search_rollup_cell, search_rollup_state},
rollup::{load_rollup_config, search_rollup_cell, search_rollup_state},
utils::search_lock_hash,
};
use gw_utils::finality::{is_block_number_finalized, is_timestamp_finalized};
use gw_utils::gw_types;

use gw_types::{
core::Timepoint,
packed::{StakeLockArgs, StakeLockArgsReader},
prelude::*,
};
Expand Down Expand Up @@ -52,12 +54,19 @@ pub fn main() -> Result<(), Error> {
// Unlock by User
// read global state from rollup cell in deps
if let Some(global_state) = search_rollup_state(&rollup_type_hash, Source::CellDep)? {
let stake_block_number: u64 = lock_args.stake_block_number().unpack();
let last_finalized_block_number: u64 = global_state.last_finalized_block_number().unpack();

// 1. check if stake_block_number is finalized
// 2. check if owner_lock_hash exists in input cells
if stake_block_number <= last_finalized_block_number
let config = load_rollup_config(&global_state.rollup_config_hash().unpack())?;
let is_finalized = match Timepoint::from_full_value(lock_args.stake_block_number().unpack())
{
Timepoint::BlockNumber(block_number) => {
is_block_number_finalized(&config, &global_state, block_number)
}
Timepoint::Timestamp(timestamp) => {
is_timestamp_finalized(&config, &global_state, timestamp)?
}
};
if is_finalized
&& search_lock_hash(&lock_args.owner_lock_hash().unpack(), Source::Input).is_some()
{
return Ok(());
Expand Down
2 changes: 1 addition & 1 deletion contracts/state-validator/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,9 @@ pub struct WithdrawalRequest {
}
pub struct BlockContext {
pub number: u64,
pub finalized_number: u64,
pub timestamp: u64,
pub block_hash: H256,
pub rollup_type_hash: H256,
pub prev_account_root: H256,
pub post_version: u8,
}
23 changes: 19 additions & 4 deletions contracts/state-validator/src/verifications/challenge.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use gw_types::{
packed::{GlobalState, RollupConfig},
prelude::*,
};
use gw_utils::finality::{is_block_number_finalized, is_timestamp_finalized};
use gw_utils::{
cells::lock_cells::{collect_burn_cells, find_challenge_cell},
ckb_std::{ckb_constants::Source, debug},
Expand Down Expand Up @@ -38,13 +39,27 @@ pub fn verify_enter_challenge(
// check that challenge target is exists
let witness = args.witness();
let challenged_block = witness.raw_l2block();

// check challenged block isn't finazlied
if prev_global_state.last_finalized_block_number().unpack()
>= challenged_block.number().unpack()
{
debug!("enter challenge finalized block error");
let post_version: u8 = post_global_state.version().into();
let is_block_finalized = if post_version < 2 {
is_block_number_finalized(
config,
post_global_state,
challenged_block.number().unpack(),
)
} else {
is_timestamp_finalized(
config,
post_global_state,
challenged_block.timestamp().unpack(),
)?
};
if is_block_finalized {
debug!("cannot challenge a finalized block");
return Err(Error::InvalidChallengeTarget);
}

let valid = {
let merkle_proof = CompiledMerkleProof(witness.block_proof().unpack());
let leaves = vec![(
Expand Down
25 changes: 19 additions & 6 deletions contracts/state-validator/src/verifications/revert.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,13 @@ use gw_common::{
H256,
};
use gw_types::{
core::Status,
core::{Status, Timepoint},
packed::{BlockMerkleState, Byte32, GlobalState, RawL2Block, RollupConfig},
prelude::*,
};
use gw_utils::finality::{
finality_as_blocks, finality_as_duration, obtain_max_timestamp_of_header_deps,
};
use gw_utils::gw_types;
use gw_utils::{
cells::{
Expand Down Expand Up @@ -247,12 +250,22 @@ fn check_reverted_blocks(
};
let account_merkle_state = reverted_blocks[0].prev_account();
let tip_block_hash = reverted_blocks[0].parent_block_hash();
let last_finalized_block_number = {
let number: u64 = reverted_blocks[0].number().unpack();
number
let version: u8 = prev_global_state.version().into();
let last_finalized = if version < 2 {
let tip_number: u64 = reverted_blocks[0].number().unpack();
let finalized_number = tip_number
.saturating_sub(1)
.saturating_sub(config.finality_blocks().unpack())
.saturating_sub(finality_as_blocks(&config));
Timepoint::from_block_number(finalized_number)
} else {
let l1_timestamp = match obtain_max_timestamp_of_header_deps() {
Some(timestamp) => timestamp,
None => return Err(Error::HeaderDepsNotFound),
};
let finalized_timestamp = l1_timestamp.saturating_sub(finality_as_duration(&config));
Timepoint::from_timestamp(finalized_timestamp)
};

let new_tip_block = revert_args.new_tip_block();
if new_tip_block.hash() != tip_block_hash.as_slice() {
debug!("[verify revert] reverted new_tip_block doesn't match");
Expand All @@ -269,7 +282,7 @@ fn check_reverted_blocks(
.block(block_merkle_state)
.tip_block_hash(tip_block_hash.to_entity())
.tip_block_timestamp(tip_block_timestamp.to_entity())
.last_finalized_block_number(last_finalized_block_number.pack())
.last_finalized_block_number(last_finalized.full_value().pack())
.reverted_block_root(reverted_block_root)
.status(status.into())
.build()
Expand Down
79 changes: 60 additions & 19 deletions contracts/state-validator/src/verifications/submit_block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ use gw_utils::gw_types::packed::{L2BlockReader, WithdrawalRequestReader};
// https://nervosnetwork.github.io/ckb-std/riscv64imac-unknown-none-elf/doc/ckb_std/index.html
use crate::ckb_std::{ckb_constants::Source, debug};
use gw_state::kv_state::KVState;
use gw_utils::finality::{
finality_as_blocks, finality_as_duration, is_block_number_finalized, is_timestamp_finalized,
obtain_max_timestamp_of_header_deps,
};
use gw_utils::gw_common::{self, ckb_decimal::CKBCapacity};
use gw_utils::gw_types::{self, U256};

Expand Down Expand Up @@ -42,7 +46,7 @@ use gw_common::{
};
use gw_types::{
bytes::Bytes,
core::{ScriptHashType, Status},
core::{ScriptHashType, Status, Timepoint},
packed::{Byte32, GlobalState, RawL2Block, RollupConfig},
prelude::*,
};
Expand Down Expand Up @@ -73,13 +77,21 @@ fn check_withdrawal_cells<'a>(
for cell in withdrawal_cells {
// check withdrawal cell block info
let withdrawal_block_hash: H256 = cell.args.withdrawal_block_hash().unpack();
if withdrawal_block_hash != context.block_hash
|| cell.args.withdrawal_block_number().unpack() != context.number
{
if withdrawal_block_hash != context.block_hash {
debug!("withdrawal cell mismatch block_hash");
return Err(Error::InvalidWithdrawalCell);
}

let expected_timepoint = if context.post_version < 2 {
Timepoint::from_block_number(context.number)
} else {
Timepoint::from_timestamp(context.timestamp)
};
if cell.args.withdrawal_block_number().unpack() != expected_timepoint.full_value() {
debug!("withdrawal cell mismatch timepoint");
return Err(Error::InvalidWithdrawalCell);
}

let cell_account_script_hash: H256 = cell.args.account_script_hash().unpack();
// check that there is a corresponded withdrawal request
match withdrawal_requests.iter().position(|request| {
Expand Down Expand Up @@ -116,6 +128,7 @@ fn check_withdrawal_cells<'a>(

fn check_input_custodian_cells(
config: &RollupConfig,
global_state: &GlobalState,
context: &BlockContext,
output_withdrawal_cells: Vec<WithdrawalCell>,
) -> Result<BTreeMap<H256, u128>, Error> {
Expand All @@ -124,8 +137,14 @@ fn check_input_custodian_cells(
collect_custodian_locks(&context.rollup_type_hash, config, Source::Input)?
.into_iter()
.partition(|cell| {
let number: u64 = cell.args.deposit_block_number().unpack();
number <= context.finalized_number
match Timepoint::from_full_value(cell.args.deposit_block_number().unpack()) {
Timepoint::BlockNumber(block_number) => {
is_block_number_finalized(config, global_state, block_number)
}
Timepoint::Timestamp(timestamp) => {
is_timestamp_finalized(config, global_state, timestamp).unwrap_or(false)
}
}
});
// check unfinalized custodian cells == reverted deposit requests
let mut reverted_deposit_cells =
Expand Down Expand Up @@ -160,6 +179,7 @@ fn check_input_custodian_cells(

fn check_output_custodian_cells(
config: &RollupConfig,
global_state: &GlobalState,
context: &BlockContext,
mut deposit_cells: Vec<DepositRequestCell>,
input_finalized_assets: BTreeMap<H256, u128>,
Expand All @@ -169,8 +189,14 @@ fn check_output_custodian_cells(
collect_custodian_locks(&context.rollup_type_hash, config, Source::Output)?
.into_iter()
.partition(|cell| {
let number: u64 = cell.args.deposit_block_number().unpack();
number <= context.finalized_number
match Timepoint::from_full_value(cell.args.deposit_block_number().unpack()) {
Timepoint::BlockNumber(block_number) => {
is_block_number_finalized(config, global_state, block_number)
}
Timepoint::Timestamp(timestamp) => {
is_timestamp_finalized(config, global_state, timestamp).unwrap_or(false)
}
}
});
// check deposits request cells == unfinalized custodian cells
for custodian_cell in unfinalized_custodian_cells {
Expand Down Expand Up @@ -375,7 +401,6 @@ fn check_layer2_withdrawal(

fn load_block_context_and_state<'a>(
rollup_type_hash: H256,
config: &RollupConfig,
tree_buffer: &'a mut [Pair],
kv_state_proof: &'a Bytes,
l2block: &L2BlockReader,
Expand Down Expand Up @@ -465,9 +490,9 @@ fn load_block_context_and_state<'a>(
}

// Generate context
let post_version: u8 = post_global_state.version().into();
let account_count: u32 = prev_global_state.account().count().unpack();
let prev_account_root = prev_global_state.account().merkle_root().unpack();
let finalized_number = number.saturating_sub(config.finality_blocks().unpack());

// Check pre account merkle proof
let kv_state = KVState::build(
Expand All @@ -484,11 +509,11 @@ fn load_block_context_and_state<'a>(

let context = BlockContext {
number,
finalized_number,
timestamp,
rollup_type_hash,
block_hash,
prev_account_root,
post_version,
};

Ok((context, kv_state))
Expand Down Expand Up @@ -525,10 +550,15 @@ fn verify_block_producer(
Source::Input,
&owner_lock_hash,
)? {
let expected_timepoint = if context.post_version < 2 {
Timepoint::from_block_number(context.number)
} else {
Timepoint::from_timestamp(context.timestamp)
};
let expected_stake_lock_args = input_stake_cell
.args
.as_builder()
.stake_block_number(raw_block.number().to_entity())
.stake_block_number(expected_timepoint.full_value().pack())
.build();
if expected_stake_lock_args != output_stake_cell.args
|| input_stake_cell.capacity > output_stake_cell.capacity
Expand Down Expand Up @@ -760,7 +790,6 @@ pub fn verify(

let (context, mut kv_state) = load_block_context_and_state(
rollup_type_hash,
config,
&mut tree_buffer,
&kv_state_proof,
block,
Expand All @@ -778,9 +807,11 @@ pub fn verify(
let withdrawal_requests_vec = block.withdrawals();
let withdrawal_requests = withdrawal_requests_vec.iter().collect();
check_withdrawal_cells(&context, withdrawal_requests, &withdrawal_cells)?;
let input_finalized_assets = check_input_custodian_cells(config, &context, withdrawal_cells)?;
let input_finalized_assets =
check_input_custodian_cells(config, post_global_state, &context, withdrawal_cells)?;
check_output_custodian_cells(
config,
post_global_state,
&context,
deposit_cells.clone(),
input_finalized_assets,
Expand All @@ -807,9 +838,19 @@ pub fn verify(
let account_merkle_state = block.raw().post_account();
// we have verified the post block merkle state
let block_merkle_state = post_global_state.block();
// last finalized block number
let last_finalized_block_number = context.finalized_number;
let version = post_global_state.version();

let version: u8 = post_global_state.version().into();
let last_finalized = if version < 2 {
let finalized_number = context.number.saturating_sub(finality_as_blocks(&config));
Timepoint::from_block_number(finalized_number)
} else {
let l1_timestamp = match obtain_max_timestamp_of_header_deps() {
Some(timestamp) => timestamp,
None => return Err(Error::HeaderDepsNotFound),
};
let finalized_timestamp = l1_timestamp.saturating_sub(finality_as_duration(&config));
Timepoint::from_timestamp(finalized_timestamp)
};
let tip_block_timestamp = if version == 0.into() {
0
} else {
Expand All @@ -823,8 +864,8 @@ pub fn verify(
.block(block_merkle_state)
.tip_block_hash(context.block_hash.pack())
.tip_block_timestamp(tip_block_timestamp.pack())
.last_finalized_block_number(last_finalized_block_number.pack())
.version(version)
.last_finalized_block_number(last_finalized.full_value().pack())
.version(version.into())
.build()
};

Expand Down
Loading

0 comments on commit 0b45e20

Please sign in to comment.