-
Notifications
You must be signed in to change notification settings - Fork 20
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
feat: add state dump and loading for the sequencer #159
Conversation
469bc32
to
5ca62c5
Compare
|
||
use super::program::SerializableProgram; | ||
|
||
#[derive(Debug, Clone, Serialize, Deserialize)] |
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 annotate which code is taken from katana? for credit but also to know which code is technically reviewed, tested and works in katana currently
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.
Makes sense, completed via this commit.
} | ||
|
||
#[derive(Debug, Clone, Serialize, Deserialize)] | ||
pub struct SerializableEntryPointOffset(pub usize); |
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 this needed?
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.
This has been taken from Katana directly.
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.
but can it be changed?
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.
This is required for the serialization.
fn from(value: SerializableEntryPointV1) -> Self { | ||
blockifier::execution::contract_class::EntryPointV1 { | ||
selector: value.selector, | ||
offset: value.offset.into(), |
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 looks like the only problem is offset!? that sounds cursed
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.
This has been taken from Katana directly.
@@ -143,6 +170,27 @@ impl BlockifierStateReader for &mut State { | |||
} | |||
} | |||
|
|||
impl From<&SerializableState> for State { |
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 are we implementing the trait on a reference?
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.
So that we want to create a State
from SerializableState
, we can do so without moving the value and rather than borrowing it.
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 don't really see the need for this, specially as the implementation itself just copies everything? So in the end we are copying values
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.
But if you will do it directly on type SerializableState
, then this copying will happen twice right?
Firstly you have to call this method on a clone, and then there will another copying inside the implementation. I think the reference approach is hence more optimizied.
Lemme know what you think.
nonces: serializable_state.nonces.clone(), | ||
}; | ||
|
||
serializable_state.classes.iter().for_each(|(class_hash, contract_class)|{ |
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 do we need to do 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.
crates/sequencer/src/state.rs
Outdated
serializable_state.classes.iter().for_each(|(class_hash, contract_class)|{ | ||
state.classes.insert( | ||
*class_hash, | ||
contract_class.class.clone().try_into().unwrap_or_else(|error| panic!("failed to convert SerializableClassRecord to ContractClass for class_hash {},\n error {}", class_hash, error)) |
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.
must we panic here?
can't we implement TryFrom and return a result?
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 think panic here is fine right? Because this situation is a bug, it means that there is an error in our serialisation for contract class { which is already tested by dojo! }, and from my understanding, panics are reserved for bugs, hence, from our assumption, this should never happen!
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 think we should never have a panic!
in our code, would make a lot more sense to rely the error upstream if we have one
crates/sequencer/src/state.rs
Outdated
let contract_class = get_contract_class(include_str!( | ||
"./test_data/contracts/compiled/universal_deployer.json" | ||
)); | ||
let compiled_class_hash = CompiledClassHash(stark_felt!("0x1")); |
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 use @greged93 's constants? I think he wrote a similar flow
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 constant.rs file
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 think we can, I have almost all values in there, and we can add if missing.
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.
makes sense, done via this commit.
crates/sequencer/src/state.rs
Outdated
|
||
/// This will read a dump from a file and initialize the state from it | ||
pub fn load_state_from_file(path: &PathBuf) -> Result<Self, SerializationError> { | ||
let serilizable_state = SerializableState::load_state(path)?; |
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 serilizable_state = SerializableState::load_state(path)?; | |
let serializable_state = SerializableState::load_state(path)?; |
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.
resolved via this commit.
crates/sequencer/src/state.rs
Outdated
pub fn load_state_from_file(path: &PathBuf) -> Result<Self, SerializationError> { | ||
let serilizable_state = SerializableState::load_state(path)?; | ||
|
||
Ok(Self::from(&serilizable_state)) |
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.
Ok(Self::from(&serilizable_state)) | |
Ok(Self::from(&serializable_state)) |
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.
resolved via this commit.
|
||
/// Converts `starknet-rs` RPC [FlattenedSierraClass] type to Cairo's | ||
/// [ContractClass](cairo_lang_starknet::contract_class::ContractClass) type. | ||
pub fn rpc_to_cairo_contract_class( |
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 do we need 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.
crates/sequencer/src/serde/utils.rs
Outdated
}) | ||
} | ||
|
||
pub fn get_contract_class(contract_class_str: &str) -> ContractClass { |
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.
this doesn't look like a getter but rather an into_contract_class
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.
Also we should avoid get
prefix
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.
This has been borrowed directly from katana and it is also used from the dojo borrowed file.
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 made a commit resolving it.
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.
Couple of comments, great work!
crates/sequencer/Cargo.toml
Outdated
# Starknet | ||
# TODO: remove the blockifier patch on the workspace once we can remove Katana. | ||
blockifier = { package = "blockifier", git = "https://github.com/starkware-libs/blockifier.git", tag = "v0.3.0-rc0" } | ||
cairo-lang-starknet = { workspace = true } | ||
cairo-vm = { workspace = true } | ||
serde.workspace = true |
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 use the same syntax here please? { workspace = true }
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.
resolved here.
crates/sequencer/Cargo.toml
Outdated
|
||
# Other | ||
rustc-hash = "1.1.0" | ||
|
||
[dev-dependencies] | ||
lazy_static = { workspace = true } | ||
starknet = { workspace = true } |
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.
no need to depend on it for dev, we have in the crate deps
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.
resolved here.
impl TryFrom<SerializableContractClass> for blockifier::execution::contract_class::ContractClass { | ||
type Error = anyhow::Error; | ||
|
||
fn try_from(value: SerializableContractClass) -> Result<Self, Self::Error> { |
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 rework this? You are using a TryFrom
trait but I don't see any error being thrown and I see an unwrap in the implementation.
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.
@greged93 this whole file is borrowed from Dojo, LamdbaClass said they are working on serialization for these types, if we still need this file in sometime even after merging this, then might be we can refactor this otherwise we will probably not need these serde types in sometime!
use starknet::core::types::contract::SierraClass; | ||
|
||
use super::*; | ||
use crate::serde::utils::{get_contract_class, rpc_to_inner_class}; |
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 added some cairo 0 and cairo 1 contracts already, can you use these instead? In order to avoid adding more and more test files.
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.
required by dojo tests, I don't think we should change this, in sometime we should not need it mostly as discussed once we have serialization enabled for ContractClass.
|
||
/// TODO: wrap the underlying errors in them | ||
#[derive(Error, Debug)] | ||
pub enum SerializationError { |
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 think we can rework this a little to use more the syntax from thiserror examples?
#[derive(Error, Debug)]
pub enum MyError {
Io {
#[from]
source: io::Error,
backtrace: Backtrace,
},
}
} | ||
|
||
impl SerializableState { | ||
pub fn dump_state(&self) -> Result<Vec<u8>, SerializationError> { |
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'm wondering: should we rename this? This converts the SerializableState
into a Vec, so naming it dump_state
sounds too specific.
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.
how about serialize_state
?
Ok(serialized_state_buffer) | ||
} | ||
|
||
pub fn load_state(path: &PathBuf) -> Result<Self, SerializationError> { |
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.
could we change this to new
? new
could take an Option and load the file if Option is not None.
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 think, from_file_path
is a better approach, it should be a static method and do one single thing!
We can see this pattern in other rust codebases as well, where there is options like from_str
, etc.
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.
Lemme know what you think about it.
crates/sequencer/src/state.rs
Outdated
let contract_class = get_contract_class(include_str!( | ||
"./test_data/contracts/compiled/universal_deployer.json" | ||
)); | ||
let compiled_class_hash = CompiledClassHash(stark_felt!("0x1")); |
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 think we can, I have almost all values in there, and we can add if missing.
crates/sequencer/src/state.rs
Outdated
assert_eq!( | ||
state.classes.get(&class_hash), | ||
loaded_state.classes.get(&class_hash) | ||
); | ||
assert_eq!( | ||
state.compiled_class_hashes.get(&class_hash), | ||
loaded_state.compiled_class_hashes.get(&class_hash) | ||
); | ||
assert_eq!( | ||
state.contracts.get(&contract_address), | ||
loaded_state.contracts.get(&contract_address) | ||
); | ||
assert_eq!( | ||
state.storage.get(&contract_storage_key), | ||
loaded_state.storage.get(&contract_storage_key) | ||
); | ||
assert_eq!( | ||
state.nonces.get(&contract_address), | ||
loaded_state.nonces.get(&contract_address) | ||
); |
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't we derive PartialEq
and just have one assert_eq!
?
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.
Great suggestion! Implemented via this commit.
@@ -0,0 +1,2534 @@ | |||
{ |
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.
You can remove both these contracts and use the ones I have added.
d7001aa
to
1f83daa
Compare
We will fork cairo-vm and blockifier in order to implement serialize on the necessary types. |
Resolves: #119
Pull Request type
Please check the type of change your PR introduces:
What is the new behavior?
This PR adds the ability to dump and load sequencer state, the serialisable types have been borrowed from dojo's katana.
Does this introduce a breaking change?