Skip to content
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

fix(katana-provider): temporarily invalidate cache if nonce or class hash is default value #1850

Merged
merged 3 commits into from
Apr 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 23 additions & 2 deletions crates/katana/storage/provider/src/providers/fork/backend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -353,7 +353,25 @@ impl ContractInfoProvider for SharedStateProvider {

impl StateProvider for SharedStateProvider {
fn nonce(&self, address: ContractAddress) -> ProviderResult<Option<Nonce>> {
if let nonce @ Some(_) = self.contract(address)?.map(|i| i.nonce) {
// TEMP:
//
// The nonce and class hash are stored in the same struct, so if we call either `nonce` or
// `class_hash_of_contract` first, the other would be filled with the default value.
// Currently, the data types that we're using doesn't allow us to distinguish between
// 'not fetched' vs the actual value.
//
// Right now, if the nonce value is 0, we couldn't distinguish whether that is the actual
// value or just the default value. So this filter is a pessimistic approach to always
// invalidate 0 nonce value in the cache.
//
// Meaning, if the nonce is 0, we always fetch the nonce from the forked provider, even if
// we already fetched it before.
//
// Similar story with `class_hash_of_contract`
//
if let nonce @ Some(_) =
self.contract(address)?.map(|i| i.nonce).filter(|n| n != &Nonce::ZERO)
{
return Ok(nonce);
}

Expand Down Expand Up @@ -413,7 +431,10 @@ impl StateProvider for SharedStateProvider {
&self,
address: ContractAddress,
) -> ProviderResult<Option<ClassHash>> {
if let hash @ Some(_) = self.contract(address)?.map(|i| i.class_hash) {
// See comment at `nonce` for the explanation of this filter.
if let hash @ Some(_) =
self.contract(address)?.map(|i| i.class_hash).filter(|h| h != &ClassHash::ZERO)
{
return Ok(hash);
}

Expand Down
28 changes: 23 additions & 5 deletions crates/katana/storage/provider/src/providers/fork/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,14 +38,22 @@ impl StateProvider for ForkedStateDb {
&self,
address: ContractAddress,
) -> ProviderResult<Option<ClassHash>> {
if let hash @ Some(_) = self.contract_state.read().get(&address).map(|i| i.class_hash) {
if let hash @ Some(_) = self
.contract_state
.read()
.get(&address)
.map(|i| i.class_hash)
.filter(|h| h != &ClassHash::ZERO)
{
return Ok(hash);
}
StateProvider::class_hash_of_contract(&self.db, address)
}

fn nonce(&self, address: ContractAddress) -> ProviderResult<Option<Nonce>> {
if let nonce @ Some(_) = self.contract_state.read().get(&address).map(|i| i.nonce) {
if let nonce @ Some(_) =
self.contract_state.read().get(&address).map(|i| i.nonce).filter(|n| n != &Nonce::ZERO)
{
return Ok(nonce);
}
StateProvider::nonce(&self.db, address)
Expand Down Expand Up @@ -148,7 +156,13 @@ impl ContractInfoProvider for ForkedSnapshot {

impl StateProvider for ForkedSnapshot {
fn nonce(&self, address: ContractAddress) -> ProviderResult<Option<Nonce>> {
if let nonce @ Some(_) = self.inner.contract_state.get(&address).map(|info| info.nonce) {
if let nonce @ Some(_) = self
.inner
.contract_state
.get(&address)
.map(|info| info.nonce)
.filter(|n| n != &Nonce::ZERO)
{
return Ok(nonce);
}
StateProvider::nonce(&self.inner.db, address)
Expand All @@ -171,8 +185,12 @@ impl StateProvider for ForkedSnapshot {
&self,
address: ContractAddress,
) -> ProviderResult<Option<ClassHash>> {
if let class_hash @ Some(_) =
self.inner.contract_state.get(&address).map(|info| info.class_hash)
if let class_hash @ Some(_) = self
.inner
.contract_state
.get(&address)
.map(|info| info.class_hash)
.filter(|h| h != &ClassHash::ZERO)
{
return Ok(class_hash);
}
Expand Down
Loading