Skip to content

Conversation

@dmtrskv
Copy link
Contributor

@dmtrskv dmtrskv commented Jun 11, 2025

State accessor appears in profiles as an active creator of objects in memory.
Here I simplify the code of the accessor tailoring it to the current needs. The caching is reworked and improved (it wasn't happening at some places at all).

There are also some simplifications in the other code, especially improvements in the usage of accessors.

func GetFromShard(tx RoTx, shardId types.ShardId, table ShardedTableName, key prettyKey) ([]byte, error) {
data, err := tx.GetFromShard(shardId, table, key.Bytes())
if err != nil {
return nil, fmt.Errorf("%w: key=%s", err, key)
Copy link
Contributor

Choose a reason for hiding this comment

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

Perhaps shardId we also want to add to the error message?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Moved to #969

item, err := tx.tx.Get(MakeKey(tableName, key))
if errors.Is(err, badger.ErrKeyNotFound) {
return nil, ErrKeyNotFound
return nil, fmt.Errorf("%w: table %s", ErrKeyNotFound, tableName)
Copy link
Contributor

Choose a reason for hiding this comment

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

We have quite a few checks for errors.Is(err, db.ErrKeyNotFound). I think we might break some logic with such changes. If we want to add context to ErrrKeyNotFound, perhaps we should make it a full type and change the errors.Is checks to errors.As. Also, it might be better to make such changes as a separate PR.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Removed it here and added this to the Gets in accessors.
Wrapping errors this way doesn't affect errors.Is.

Moved these changes to another PR: #969

outTxCountsLRU *lru.Cache[common.Hash, [][]byte]
receiptsLRU *lru.Cache[common.Hash, [][]byte]
}
func newRawAccessorCache(blocksLRUSize, txnRLUSize int) *cache {
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
func newRawAccessorCache(blocksLRUSize, txnRLUSize int) *cache {
func newRawAccessorCache(blocksLRUSize, txnLRUSize int) *cache {

b.withDbTimestamp = true
return b
}
res, err := db.ReadBlockBytes(s.tx, s.shardId, hash)
Copy link
Contributor

Choose a reason for hiding this comment

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

We could also check s.cache.blocksLRU

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Reworked it a bit.

return nil, err
}
sa.cache.blocksLRU.Add(hash, block)
return &types.RawBlockWithExtractedData{
Copy link
Contributor

Choose a reason for hiding this comment

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

I don't really like this use of a type without filling in some of the fields. If Go were a normal language, we should use variant here, but since we have what we have, let's keep some form of rawBlockAccessorResult to represent the mandatory + optional part of the data fields.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I based it on the usages, but they actually could be improved/simplified. So, did that.

check.PanicIfErr(err)
type cache struct {
blocksLRU *lru.Cache[common.Hash, *types.Block]
fullBlocksLRU *lru.Cache[common.Hash, *types.RawBlockWithExtractedData]
Copy link
Contributor

Choose a reason for hiding this comment

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

Have you considered a more normalized way of storing data, where the ExtractedData part is stored separately, and rawBlocksLRU is used for both raw headers and full blocks?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Then I'll have to introduce ExtractedData, etc. Having an extra link to a block header is not a problem.
Instead, I merged raw and decoded headers, since they are unlikely to be used one without the other (it can only happen with the raw ones and only in a single rpc method).

withDbTimestamp bool
withConfig bool
}
func (s RawShardAccessor) decodeBlock(hash common.Hash, data []byte) (*types.Block, error) {
Copy link
Contributor

Choose a reason for hiding this comment

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

For some reason I really want to see in the function name the information that it is caching.

Suggested change
func (s RawShardAccessor) decodeBlock(hash common.Hash, data []byte) (*types.Block, error) {
func (s RawShardAccessor) decodeBlockCached(hash common.Hash, data []byte) (*types.Block, error) {

Probably because otherwise it's very easy to think from the name that it's pure, and make incorrect assumptions about behavior by reading the call locations.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Agree, but removed this method altogether.

if len(errMsg) > 0 {
result.Errors[txnHash] = errMsg
if len(errMsg) > 0 {
if result.Errors == nil {
Copy link
Contributor

Choose a reason for hiding this comment

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

How about building a temporary dictionary, and assigning it to result.Errors at the end if it's not empty? Or conversely, assigning nil to result.Errors if it's empty. By the way, why do we even want to maintain such an invariant?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I thought it would be nice not to touch the result, unless there are actual errors.

s.checkReceipt(shardId, m)
})

s.Run("CheckRefundsSeqno", func() {
Copy link
Contributor

Choose a reason for hiding this comment

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

Why did we delete this test?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It doesn't have anything to do with the proposer functionality.

@dmtrskv dmtrskv force-pushed the state-accessor-rework branch from 216db6c to f41374e Compare June 18, 2025 15:28
@dmtrskv dmtrskv force-pushed the state-accessor-rework branch from f41374e to 2bfd100 Compare June 18, 2025 16:13
@dmtrskv dmtrskv force-pushed the state-accessor-rework branch from 2bfd100 to ba582e6 Compare June 18, 2025 16:34
@dmtrskv dmtrskv marked this pull request as ready for review June 18, 2025 17:24
@dmtrskv dmtrskv requested a review from Un1oR June 18, 2025 17:28
@dmtrskv dmtrskv marked this pull request as draft June 18, 2025 19:20
@dmtrskv dmtrskv force-pushed the state-accessor-rework branch from ba582e6 to bc76ef8 Compare June 23, 2025 13:44
@dmtrskv dmtrskv force-pushed the state-accessor-rework branch from bc76ef8 to 0ffafe2 Compare June 23, 2025 17:04
@dmtrskv dmtrskv force-pushed the state-accessor-rework branch from 0ffafe2 to 200bbca Compare June 24, 2025 14:48
@dmtrskv dmtrskv force-pushed the state-accessor-rework branch from 200bbca to 528bc74 Compare June 24, 2025 16:16
@dmtrskv dmtrskv force-pushed the state-accessor-rework branch from 528bc74 to 0f8e20c Compare June 24, 2025 16:32
@dmtrskv dmtrskv force-pushed the state-accessor-rework branch from 0f8e20c to d4b066d Compare June 25, 2025 12:15
@dmtrskv dmtrskv force-pushed the state-accessor-rework branch from d4b066d to bf0abe8 Compare June 25, 2025 12:28
@dmtrskv dmtrskv force-pushed the state-accessor-rework branch from bf0abe8 to dffdbbb Compare June 25, 2025 17:22
@dmtrskv dmtrskv changed the base branch from main to block-accessor June 25, 2025 17:22
@dmtrskv dmtrskv marked this pull request as ready for review June 25, 2025 17:26
blockHashByNumber *BlockHashByNumberAccessor
}

func NewStateAccessor(blockLRUSize, txnLRUSize int) *StateAccessor {
Copy link
Collaborator

Choose a reason for hiding this comment

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

btw if you wanna improve cache it may make sense to implement slightly different algo than simple LRU

https://en.wikipedia.org/wiki/Adaptive_replacement_cache - this one seems to be quite efficient
https://github.com/alexanderGugel/arc - and here's some implementation in go

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.

5 participants