-
Notifications
You must be signed in to change notification settings - Fork 292
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
State sync from l1 #1296
base: main
Are you sure you want to change the base?
State sync from l1 #1296
Conversation
Hey thanks for the good work. I think it can be used as a way to finalize the l2 state, but it needs something build on top of it. Did you had other stuffs in mind? |
Also, are you aware of this PR: #1282 |
Based on this issue #1224, we developed the code in this pull request (PR). This feature can be used to rapidly rebuild the state of L2 from L1. |
I've read the code, and there are no redundant with my PR. This PR (#1282) is about retrieving and applying messages from L1 to L2, whereas mine is about fetching L2 state from L1 and applying it locally. |
crates/node/src/commands/run.rs
Outdated
|
||
/// When enable, the node will sync state from l1, | ||
#[clap(long)] | ||
pub sync_from_l1: Option<String>, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In ExtendedRunCommand
pub base: RunCmd,
pub network_params: NetworkParams,
pub sync: SyncMode,` we find this, provided by substrate:
/// Syncing mode.
#[derive(Debug, Clone, Copy, ValueEnum, PartialEq)]
#[value(rename_all = "kebab-case")]
pub enum SyncMode {
/// Full sync. Download end verify all blocks.
Full,
/// Download blocks without executing them. Download latest state with proofs.
Fast,
/// Download blocks without executing them. Download latest state without proofs.
FastUnsafe,
/// Prove finality and download the latest state.
Warp,
}
Do you think we can reuse those already defined modes? They look a bit similar to what we offer.
What is the list of the different sync mode we aim to support? I think we should define them.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What you said makes a lot of sense. I think we can expand this enumeration. Currently, pub sync_from_l1: Option<String>
, actually refers to a configuration file path, and the content of this configuration file at present is like this:
{
"l1_start": 5854324,
"core_contract": "0xde29d060D45901Fb19ED6C6e959EB22d8626708e",
"verifier_contract": "0x5EF3C980Bf970FcE5BbC217835743ea9f0388f4F",
"memory_page_contract": "0x743789ff2fF82Bfb907009C9911a7dA636D34FA7",
"l2_start": 0,
"l1_url_list": ["https://eth-goerli.g.alchemy.com/v2/nMMxqPTld6cj0DUO-4Qj2cg88Dd1MUhH","https://eth-goerli.g.alchemy.com/v2/AktNdFZZplqKaD2NrEfowmeYAwmEn4db"],
"v011_diff_format_height": 28566,
"constructor_args_diff_height": 4873
}
So, we can extend this enumeration to:
/// Syncing mode.
#[derive(Debug, Clone, Copy, ValueEnum, PartialEq)]
#[value(rename_all = "kebab-case")]
pub enum SyncMode {
/// Full sync. Download end verify all blocks.
Full,
/// Download blocks without executing them. Download latest state with proofs.
Fast,
/// Download blocks without executing them. Download latest state without proofs.
FastUnsafe,
/// Prove finality and download the latest state.
Warp,
/// Sync state from L1
FromL1(String),
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Has this made it into the codebase in the end?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The SyncMode
defined in substrate specifies the synchronization method between nodes within the same network. However, sync from l1
is another type of synchronization that only exists within the rollup chain. Therefore, we cannot reuse the substrate SyncMode
. Additionally, extending Substrate SyncMode
is not quite suitable since substrate does not provide rollup functionality. Therefore, it is more appropriate to continue placing this command parameter in the ExtendedRunCommand
.
thanks for this impl! finishing some stuff on the rpc side and I'll deep dive here 👍 |
Reviewing it now, my apologies for the delays I've been busy bumping madara specs. |
@jerrybaoo could you please sync with upstream when you have time so I can test it locally? |
Okay, I'll start syncing with upstream now. |
Thanks! |
Sync with upstream has been completed. Additionally, we have a quick start guide that we hope will be helpful to you. Alternatively, we can include it in the Readme. |
bf1e5e6
to
450c695
Compare
crates/client/db/src/meta_db.rs
Outdated
pub struct L1L2BlockMapping { | ||
pub l1_block_hash: H256, | ||
pub l1_block_number: u64, | ||
pub l2_block_hash: U256, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We are talking starknet hash here, not substrate hash.
Can we add a comment to make it explicit?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is it a U256
and not a H256
? We are talking about a hash
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is it a
U256
and not aH256
? We are talking about a hash
You are right, this is a mistake.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We are talking starknet hash here, not substrate hash. Can we add a comment to make it explicit?
Indeed, it is necessary to provide detailed comments explaining the mapping between L1 block hash and starknet block hash.
pub struct EthOrigin { | ||
block_hash: H256, | ||
block_number: u64, | ||
_transaction_hash: H256, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is it here if it's never used?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Indeed, it is not being used and has already been removed.
eth_origin: EthOrigin, | ||
update: LogStateUpdate, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Both field contains block_hash
and block_number
. It looks like duplicated data, is it? Or is there a good reason to this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is no duplicate data; they have different meanings. eth_origin
represents the L2 rollup data to L1, including the block and transaction information for this transaction. On the other hand, update
conveys information about the L2 state update.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is misleading for something called EthOrigin
to be about l2, which is not eth.
Can you figure out a way to make it more understandable (changing names or adding more doc)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have indeed renamed it to avoid confusion and added comments for clarity.
pub block_hash: U256, | ||
} | ||
|
||
/// Ethereum contract event representing a log state update in old contract. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you add a bit more background on that, please? When was the update from old to new done (at which block) and link the code of both
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In the testnet, we noticed an upgrade in the Starknet Core contract, leading to an additional field in the LogStateUpdate event. This adjustment is made solely for forward compatibility with the older events. If there is no need to maintain consistency with the Starknet mainnet and testnet, you may safely ignore LogStateUpdateOld.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add it to the doc. I think it's interesting for people to understand that
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some comment documentation has been added.
return Ok(LogStateUpdate { | ||
global_root: update.global_root, | ||
block_number: update.block_number, | ||
block_hash: Default::default(), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this safe?
Wouldnt' it be better to have an enum
pub enum LogStateUpdate {
Old(..),
New(..)
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In the current processing logic, if the L2 block hash cannot be obtained from the chain, a local l2 block hash will be computed. culcualte l2 block hash.
During the calculation of the local block hash, we are unable to retrieve all the information of the L2 block header. Therefore, this block hash cannot be computed correctly. To ensure security, it is crucial to find a method to obtain the correct block hash.
Do you have any good ideas about this? Is it possible for us not to consider compatibility with such changes in Starknet? In fact, we haven't found any documentation explaining these changes; we've only observed the changes in contract events from the chain explorer.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@antiyro how did you manage that? When getting data from l1, before some contract update the l2 block hash wasn't part of the payload. How to you manage to still retrieve the blockhash?
|
||
let state_updates = self.query_state_update(l1_from, l2_start).await?; | ||
let tasks = state_updates.iter().map(|updates| { | ||
debug!(target: LOG_TARGET, "crate task fro update l1:{} l2: {}", updates.eth_origin.block_number, updates.update.block_number); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
typo fro
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed
let mut states_res = Vec::new(); | ||
for fetched_state in fetched_states { | ||
match fetched_state { | ||
Ok(state) => states_res.push(state), | ||
Err(e) => return Err(e), | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
let states_res: Result<Vec<_>> = fetched_states.into_iter().collect();
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed
crates/client/state-sync/src/lib.rs
Outdated
/// Error occurring during transaction construction with a specific message. | ||
ConstructTransaction(String), | ||
/// Error while committing data to storage with a specific message. | ||
CommitStorage(String), | ||
/// Error related to connection issues with L1 chain with a specific message. | ||
L1Connection(String), | ||
/// Error decoding an event from L1. | ||
L1EventDecode, | ||
/// Error related to state handling on L1 with a specific message. | ||
L1StateError(String), | ||
/// Error due to a type mismatch or inconsistency with a specific message. | ||
TypeError(String), | ||
/// Any other unspecified error with a specific message. | ||
Other(String), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't use a String
as a way to represent the original error.
Use the error type itself.
You can achieve this easily with thiserror
and their #[from]
macro
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have rewritten the Error
enum using thiserror
.
remove unused code
add comments
replace std::sync::mutex with use parking_lot::Mutex
There hasn't been any activity on this pull request recently, and in order to prioritize active work, it has been marked as stale. |
Add sync state from L1 feature
Pull Request type
What is the current behavior?
Currently, there is no functionality to synchronize data from L1.
What is the new behavior?
Does this introduce a breaking change?
No