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

(wip) (fix) Fix Storage Usage #4247

Closed
wants to merge 40 commits into from
Closed

Conversation

EgorKulikov
Copy link
Contributor

@EgorKulikov EgorKulikov commented Apr 21, 2021

Storage usage is incorrect for some accounts on mainnet due to oversubtracting storage usage on access key deletion. Bug itself was already fixed. Delta between actual and expected storage usage was calculated on mainnet dump. Next time storage usage will be changed for such accounts they will be migrated to V2 and storage usage will be adjusted

Test plan

See test_storage_usage_delta

Moving Account to primitives
chain/rosetta-rpc/src/lib.rs Outdated Show resolved Hide resolved
core/primitives/src/account.rs Outdated Show resolved Hide resolved
core/primitives/src/account.rs Show resolved Hide resolved
core/primitives/src/account.rs Show resolved Hide resolved
EgorKulikov and others added 4 commits April 21, 2021 17:16
Co-authored-by: Aleksey Kladov <aleksey.kladov@gmail.com>
Co-authored-by: Aleksey Kladov <aleksey.kladov@gmail.com>
Copy link
Collaborator

@bowenwang1996 bowenwang1996 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

where did you fix storage usage?

@@ -128,6 +145,16 @@ struct LegacyAccount {
storage_usage: StorageUsage,
}

#[cfg(feature = "protocol_feature_add_account_versions")]
#[derive(BorshSerialize, BorshDeserialize)]
struct SerializableAccount {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should we implement From<SerializableAccount> for Account?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Considering it should ever be used only once I am not sure we need this

@EgorKulikov
Copy link
Contributor Author

where did you fix storage usage?

It is not in yet, safely stashed until this builds, that's why is added wip to it

@EgorKulikov EgorKulikov added the S-donotmerge Status: do not merge this PR label Apr 21, 2021
@EgorKulikov EgorKulikov linked an issue Apr 26, 2021 that may be closed by this pull request
@EgorKulikov
Copy link
Contributor Author

  • How do you plan to test this change?

I've introduced test, see test_storage_usage_delta

Copy link
Collaborator

@bowenwang1996 bowenwang1996 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we add at least an integration test to test that this protocol feature works fine with upgrades? You can do it in client/tests/process_blocks.rs

@@ -644,6 +673,13 @@ pub(crate) fn action_add_key(
}
);
let storage_config = &apply_state.config.transaction_costs.storage_usage_config;
#[cfg(feature = "protocol_feature_add_account_versions")]
migrate_account(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it seems that you try to do this in every action. I wonder whether we can do it in apply_action or some higher level function to avoid code duplication

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not in every action, only in those that change storage usage

@EgorKulikov
Copy link
Contributor Author

Can we add at least an integration test to test that this protocol feature works fine with upgrades? You can do it in client/tests/process_blocks.rs

Will do

@bowenwang1996 bowenwang1996 requested a review from frol April 27, 2021 16:11
Copy link
Collaborator

@frol frol left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it possible to avoid the hardcoded CSV file and instead reproduce it on the fly? How long will it take? If that is not the way to go, how about generating .rs file instead of .csv? (I really don't like having more dependencies than necessary, and csv in runtime looks completely odd)

Comment on lines +44 to +46
/// True iff this ApplyState is on mainnet
#[cfg(feature = "protocol_feature_add_account_versions")]
pub is_mainnet: bool,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We introduce so many hacks right into our core primitives that it makes me uneasy. Why do we need to know if it is mainnet here? Let's just have the STORAGE_USAGE_DELTA_FROM_FILE empty on non-mainnet networks, and thus we won't need this ugly is_mainnet everywhere since the lookup for a given account in the STORAGE_USAGE_DELTA_FROM_FILE will never succeed on non-mainnet networks given the map is going to be empty.

runtime/runtime/src/actions.rs Outdated Show resolved Hide resolved
fn main() -> Result<(), Error> {
println!("Start");

let genesis = Genesis::from_file("output.json");
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I feel like you expect to have a state dump in this output.json, but it is not clear. Please, provide more details in the doc comments as to how to use it.

Comment on lines +16 to +19
let storage_usage =
Runtime::compute_storage_usage(&genesis.records.0[..], &RuntimeConfig::default());
println!("Storage usage calculated");
for record in genesis.records.0 {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe this should work:

Suggested change
let storage_usage =
Runtime::compute_storage_usage(&genesis.records.0[..], &RuntimeConfig::default());
println!("Storage usage calculated");
for record in genesis.records.0 {
let storage_usage =
Runtime::compute_storage_usage(genesis.records.as_ref(), &RuntimeConfig::default());
println!("Storage usage calculated");
for record in genesis.records.into() {

P.S. GenesisRecords needs one more derive DeriveMore::Into to support .into()


#[cfg(feature = "protocol_feature_add_account_versions")]
lazy_static::lazy_static! {
static ref STORAGE_USAGE_DELTA_FROM_FILE: HashMap<AccountId, u64> = read_storage_usage_delta();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We already did enough hacks around by pulling a random CSV file right into the binary, let's at least have the HashMap properly propagated through the configuration. neard should be the single source of configuration, we should not hijack runtime and get changed its operation due to some random global variable. Let neard hold the file, parse it conditionally when the chain id is mainnet, and pass it through the runtime configs down here if necessary.

Co-authored-by: Vlad Frolov <frolvlad@gmail.com>
@EgorKulikov
Copy link
Contributor Author

Is it possible to avoid the hardcoded CSV file and instead reproduce it on the fly? How long will it take? If that is not the way to go, how about generating .rs file instead of .csv? (I really don't like having more dependencies than necessary, and csv in runtime looks completely odd)

I'd rather parse csv manually than put more than 3k lines of data directly into rs file

@matklad
Copy link
Contributor

matklad commented Apr 28, 2021

I'd rather parse csv manually than put more than 3k lines of data directly into rs file

Another option is to convert CSV to borsh once, and then, at/in runtime, include!(data.borsh) and deserialize that. Does conceptually the same thing as embedding & parsing CSV, but re-usese existing deps

@frol
Copy link
Collaborator

frol commented Apr 28, 2021

Another option is to convert CSV to borsh

Well, it will be even more magical and impossible to review, so I would not go with it

@EgorKulikov
Copy link
Contributor Author

Well, it will be even more magical and impossible to review, so I would not go with it

We can go with serde, I guess

@bowenwang1996
Copy link
Collaborator

Is it possible to avoid the hardcoded CSV file and instead reproduce it on the fly? How long will it take? If that is not the way to go, how about generating .rs file instead of .csv? (I really don't like having more dependencies than necessary, and csv in runtime looks completely odd)

@frol it is impossible to reproduce it while the node is running as it is prohibitively expensive to iterate over the state. More complex solutions are possible, but I don't think it is worth the effort here.

@frol
Copy link
Collaborator

frol commented Apr 29, 2021

We can go with serde, I guess

JSON or manual CSV parsing is fine. Let's move the preparation logic and the artifact file to neard crate and pass the adjustment delta-table to runtime through configuration.

@EgorKulikov EgorKulikov changed the title (wip)(fix) Fix Storage Usage (fix) Fix Storage Usage May 6, 2021
@EgorKulikov EgorKulikov changed the title (fix) Fix Storage Usage (wip) (fix) Fix Storage Usage May 6, 2021
@EgorKulikov EgorKulikov marked this pull request as draft May 6, 2021 16:33
@Ekleog-NEAR Ekleog-NEAR deleted the fix-account-storage-usage branch March 29, 2024 14:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
S-donotmerge Status: do not merge this PR
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Recalculate storage usage based on the actual state
5 participants