Skip to content

Conversation

@AnnaShaleva
Copy link
Member

Close #4049.

As an alternative, we may consider attaching a full serialized stateroot instead of just witness (right now stateroot version is missing from the state object which may be a problem in future if stateroot version will be changed).

@codecov
Copy link

codecov bot commented Nov 25, 2025

Codecov Report

❌ Patch coverage is 37.93103% with 54 lines in your changes missing coverage. Please review.
✅ Project coverage is 83.38%. Comparing base (e249080) to head (a26d6a8).
⚠️ Report is 2 commits behind head on master.

Files with missing lines Patch % Lines
pkg/services/statefetcher/statefetcher.go 0.00% 21 Missing ⚠️
pkg/services/helpers/neofs/neofs.go 0.00% 13 Missing ⚠️
pkg/core/blockchain.go 64.70% 3 Missing and 3 partials ⚠️
pkg/core/statesync/module.go 25.00% 6 Missing ⚠️
pkg/core/stateroot/module.go 33.33% 3 Missing and 1 partial ⚠️
cli/util/upload_state.go 0.00% 2 Missing ⚠️
pkg/core/transaction/witness.go 80.00% 1 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master    #4099      +/-   ##
==========================================
- Coverage   83.51%   83.38%   -0.13%     
==========================================
  Files         351      351              
  Lines       42390    42458      +68     
==========================================
+ Hits        35401    35405       +4     
- Misses       5251     5317      +66     
+ Partials     1738     1736       -2     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@AnnaShaleva
Copy link
Member Author

AnnaShaleva commented Nov 26, 2025

I'll test this code on real network once we finalize the PR.

// NotifyServices notifies dependent services about node roles. It does not
// check whether roles were updated in the last block. It expects the cache to
// be initialized and RW.
func (s *Designate) NotifyServices(dao *dao.Simple, force bool) {
Copy link
Member

Choose a reason for hiding this comment

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

You can hide the force from public method if all callers use it this way (and postpersist can handle deal with caches internally).

}

lastFoundIdx, err := strconv.ParseUint(lastItem.Attributes[0], 10, 32)
lastItemH, err := neofs.ObjectHead(ctx, s.Pool, s.Account.PrivateKey(), s.ContainerID, lastItem.ID)
Copy link
Member

Choose a reason for hiding this comment

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

Why an additional Head? You can request the attribute from ObjectSearch directly.

Copy link
Member Author

Choose a reason for hiding this comment

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

How exactly?

From what I understood, we need to include attribute to a search filter. The problem is that this attribute is optional, and there's no such filter like "check attribute if it's present".

Copy link
Member

Choose a reason for hiding this comment

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

No, just add it to the list of requested attributes, you'll get it if it's present.

continue
}
if err = s.chain.AddContractStorageItems(batch, syncHeight, expectedRoot); err != nil {
if err = s.chain.AddContractStorageItems(batch, syncHeight, expectedRoot, witness); err != nil {
Copy link
Member

Choose a reason for hiding this comment

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

I'm not sure why you're passing it always when processing batches of KVs. Intermediate roots will never be correct, only the final one can be, so to me you should be:

  • checking stateroot witness once before performing any state changes
  • adding sets of KVs as usual
  • checking the resulting stateroot to be equal to the one we proved to be correct at the first step

Copy link
Member Author

@AnnaShaleva AnnaShaleva Nov 27, 2025

Choose a reason for hiding this comment

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

I'm not sure why you're passing it always when processing batches of KVs

I'm just following the current implementation since we're passing expectedRoot every time as far. It was like that since #3844, let's refactor this code.

checking stateroot witness once before performing any state changes

It was an initial implementation, but then I discovered stateroot verification functions bound to the state service and decided to reuse this code (and it can be done only after state service cache initialization on the proper height). Fail-fast strategy is good, but we'll be sure that the whole state is correct only after full MPT recovery at the third step.

So are we OK with the stateroot witness checking code duplication?

Copy link
Member Author

Choose a reason for hiding this comment

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

Implemented in a separate commit.

// TODO: @roman-khimov, we need to notify NeoFS nodes about chain state reset so that they update
// NeoFSAlphabet-dependent services accordingly (the current code won't work because it's based
// on notifications, and there are no notifications during state sync). I suggest to add a callback
// to the Blockchain that will be called once state reset is finished.
Copy link
Member

Choose a reason for hiding this comment

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

It only happens on a new node normally and this can happen with non-local RPC as well, so callbacks can't solve the problem.

A part of #4049.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
Oracle, StateRoot and Notary services should properly react to state
jump (either occured after state reset or after statesync finalization).
Otherwise, these services use an out-of-date roles information retrieved
from the previous node state.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
@AnnaShaleva AnnaShaleva force-pushed the witnessed-root branch 2 times, most recently from e0fdcb0 to a26d6a8 Compare November 28, 2025 10:48
@AnnaShaleva AnnaShaleva marked this pull request as draft November 28, 2025 10:54
A part of #4049.

1. Check the stateroot witness.
2. Ensure witness' public keys match block's validators at the state
   sync height.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
This callback is set when module is not active yet, no locking required.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
(*Module).syncStage is a subject of change, it may be updated by every
Module's callback called concurrently.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
@AnnaShaleva
Copy link
Member Author

TestStateSyncModule_Init is the last one that failing, so I'm still in progress of fixing it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Attach verified stateroot to NeoFS state objects

3 participants