Skip to content

Conversation

@SmaGMan
Copy link
Contributor

@SmaGMan SmaGMan commented Dec 27, 2025

RATIONALE

Support local state data sharding on parts - shard accounts cells tree is split into parts by shards at the configured split_depth. The top of the state tree is stored in the main cells db, and parts subtrees are stored each in separate physical databases that can be placed on separate disks.


Pull Request Checklist

NODE CONFIGURATION MODEL CHANGES

[Yes]

Added core_storage.state_parts

...
"core_storage": {
  ...
  "state_parts": {
    "split_depth": N, // depth of the state split on 2^N parts
    "part_dirs" : {
      // key - hex representation of part shard prefix; value - path to the part database
      "a000000000000000": "path/to/cells-part-a000000000000000",
      ...
    }
  }
  ...
}
...
  • when split_depth: 0 - no parts used;
  • we can set a custom database path, even only for one part, so we can move only one database to a separate disk if required;
  • if the path to part database is not specified, then the relative path used "cells-parts/cells-part-{shard prefix hex}".

Default value is state_parts: null that means no parts configured.

BLOCKCHAIN CONFIGURATION MODEL CHANGES

[None]


COMPATIBILITY

Affected features:

  • [State]
  • [Storage. Blocks]
  • [Storage. States]

Fully compatible.

State will be saved with parts if they are specified in config. If state was saved with parts it will be read with parts. If it was saved without parts (e.g. before update) it will be read without.

Parts map {key - cell hash: value - shard prefix} will be saved to CellsDB.shard_states right after root cell hash. If no parts used nothing will be added to ShardStates value. So existing values in ShardStates table will be treated as "no parts used".

A new flag HAS_STATE_PARTS = 1 << 13 added to the BlockHandle bit flags. It means that no parts were used / or all required state parts were successfully stored in separate storages. Now BlockHandle.has_state() returns true only when both new flag and old one HAS_STATE_MAIN = 1 << 3 are set. The migration script (0.0.4 -> 0.0.5) set HAS_STATE_PARTS for all existing block handles.

BUT parts configuration changes (e.g. from 4 to 8 partitions, or from 8 to 2 or 0) are not auto compatible. Will be implemented in a separate task.

Manual compatibility tests were passed:

  • set core_storage.state_parts = null or remove param from config
  • build last master version
  • gen local network
just gen_network 1 --force
  • run node
 just node 1
  • run 20k transfers test
 ./transfers-20k.sh
  • stop node
  • build feat/split-state-storage barch version
  • run node without reset
 just node 1
  • see successful core db migration to 0.0.5 in logs
  • continue 20k transfers test, ensure all is going well
 ./transfers-20k.sh --continue
  • stop node
  • set up 4 parts in .temp/config1.json
...
  "state_parts" : {
    "split_depth": 2
  }
...
  • run node without reset
 just node 1
  • continue 20k transfers test, ensure all is going well
 ./transfers-20k.sh --continue
  • stop node
  • move some parts databases
 mkdir .temp/db1/cells-parts-moved
 mv .temp/db1/cells-parts/cells-part-a000000000000000 .temp/db1/cells-parts-moved/
 mv .temp/db1/cells-parts/cells-part-6000000000000000 .temp/db1/cells-parts-moved/
  • set up paths to moved databases in .temp/config1.json
...
  "state_parts" : {
    "split_depth": 2,
	"part_dirs": {
	  "a000000000000000": "/workspace/tycho/.temp/db1/cells-parts-moved/cells-part-a000000000000000",
      "6000000000000000": "cells-parts-moved/cells-part-6000000000000000"
	}
  }
...
  • run node without reset
 just node 1
  • continue 20k transfers test, ensure all is going well
 ./transfers-20k.sh --continue

SPECIAL DEPLOYMENT ACTIONS

[Not Required]

Without additional changes in the node config it works with a single part without split.


PERFORMANCE IMPACT

[Expected impact]

  • Better perfomance of non-zero states (~20-30%)
    • master: degradation on 20k transfers from empty to 30kk state: from ~35k tps to ~15-20k tps
image image
  • 4 local parts: degradation on 20k transfers from empty to 30kk state: from ~35k tps to ~20-30k tps
image image
  • No states GC lag growth
  • Faster state store

TESTS

Unit Tests

[No coverage]

Network Tests

[No coverage]

Manual Tests

Performance testing:

  • 20k transfers
  • 30k transfers
  • deploy 30kk accounts
  • 20k transfers
  • 30k transfers

(metrics are in the PERFORMANCE IMPACT block)

@github-actions
Copy link

github-actions bot commented Dec 27, 2025

🧪 Network Tests

To run network tests for this PR, use:

gh workflow run network-tests.yml -f pr_number=989

Available test options:

  • Run all tests: gh workflow run network-tests.yml -f pr_number=989
  • Run specific test: gh workflow run network-tests.yml -f pr_number=989 -f test_selection=ping-pong

Test types: destroyable, ping-pong, one-to-many-internal-messages, fq-deploy, nft-index, persistent-sync

Results will be posted as workflow runs in the Actions tab.

@SmaGMan SmaGMan linked an issue Dec 27, 2025 that may be closed by this pull request
@SmaGMan SmaGMan self-assigned this Dec 27, 2025
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.

Implement shard accounts state sharding into local partitions

2 participants