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

Init Cache Manager #223

Merged
merged 26 commits into from
Apr 15, 2024
Merged

Init Cache Manager #223

merged 26 commits into from
Apr 15, 2024

Conversation

rachel-bousfield
Copy link
Contributor

@rachel-bousfield rachel-bousfield commented Apr 8, 2024

This PR introduces the concept of an "init cache manager" contract, which can be a Stylus program or EVM smart contract. Init cache managers can cache programs and slots, and are configurable via ArbOwner. This allows the design of expresive auction mechanisms for Stylus-enabled chains.

Additionally, this PR

  • refactors log parsing via Go generics, simplifying system tests and ArbOS log processing.
  • shrinks program records several bytes, even with caching data
  • fixes an bug in the data fee mechanism

Resolves STY-2

@cla-bot cla-bot bot added the s label Apr 8, 2024
}

// Caches all programs with the given codehash. Caller must be a cache manager or chain owner.
func (con ArbWasmCache) CacheCodehash(c ctx, evm mech, codehash hash) error {
Copy link
Contributor

Choose a reason for hiding this comment

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

There is no explicit connection between caching and eviction, and not limit here on number of total contracts hashed.
I understand why - but it makes the existence of multiple cache managers more risky than helpful IMHO. This level should only have one cacheManager (+possibly chain owner). If multiple contracts are needed - let them all request caching from the single cachemanager. Then the single cachemanager could e.g. give different sub-managers allowance or something..

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 like having multiple only in that it keeps our storage format the same in future ArbOS upgrades should we extend the affordances of these actors. Back when we were initially designing the chain owner system in Nitro and before that 3rd party aggregators (throwback) we had a similar convo.

arbos/programs/programs.go Outdated Show resolved Hide resolved
initGas uint24
asmEstimateKb uint24 // Predicted size of the asm
initGas uint16
cachedInitGas uint16
Copy link
Contributor

Choose a reason for hiding this comment

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

do we really want initGas + cachedInitGas per program?
it both complicates code and makes some changes harder.
I think we only want an initGas per contract, and a general param(s?) for discount. That'll give owner an easy handle that changes how much discount is given for being in cache (which it'll make sense to change while changing cache policy - you can give a larger discount if you cache 16 contracts vs if you cache 1024 of them)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The reason for having both initGas and cachedInitGas is that programs vary in their initialization timings. I ran some benchmarks and found that it's not as simple as "cached is 8x cheaper" or "uncached pays an extra Y gas". So basically the variability of the savings motivates recording both during program activation.


import "github.com/ethereum/go-ethereum/common"

type RecentPrograms struct {
Copy link
Contributor

Choose a reason for hiding this comment

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

worth documenting somewhere that this is only inside transaction.

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 and documented in geth!

p.queue = append(p.queue, item)
p.items[item] = struct{}{}

if len(p.queue) > int(params.TxCacheSize) {
Copy link
Contributor

Choose a reason for hiding this comment

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

If access pattern is (A,B,A,C,A,D,A,E....) first to be evicted will be A.

  1. since this is inside a transaction - can't we have a reasonable upper-limit that means we don't really need to worry about eviction at all? (+possibly put some hardcoded upper limit that can't be reached)
  2. since this is inside memory - if we do care about eviction we can probably have something a little more complicated that will be more LRU

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sure we can do the sequence number idea in memory. I'm about to push a commit to make the scoping per-block too, and then have Rust maintain a super-set :)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Switched to an LRU cache in Geth :)

@rachel-bousfield rachel-bousfield merged commit c3bff9e into stylus Apr 15, 2024
8 checks passed
@rachel-bousfield rachel-bousfield deleted the init-cache branch April 15, 2024 05:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants