Documentation
¶
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func NewChainReader ¶
func NewChainReader( ctx context.Context, lgr logger.Logger, ptbClient *client.PTBClient, configs sui.ChainReaderConfig, db sqlutil.DataSource, indexer indexer.IndexerApi, readerCache *Cache, ) (pkgtypes.ContractReader, error)
Types ¶
type Cache ¶
type Cache struct {
// contains filtered or unexported fields
}
Cache de-duplicates and caches the read-path RPCs that dominate Sui CCIP config polling:
- object reference metadata (GetObject) for shared/immutable objects, and
- optionally, decoded read-call (devInspect) results.
Concurrent identical loads are collapsed via singleflight — this is what relieves the cold-start storm where every node polls config simultaneously with empty caches — and successful loads are retained for a configurable TTL. The cache is process-local, which is sufficient because the redundancy it removes lives within a single relayer instance (each node re-reads the same shared objects on every poll); it does not need to be shared across nodes.
All methods are safe to call on a nil *Cache: they degrade to invoking the loader directly, so callers can hold an optional cache without nil checks.
func NewCache ¶
func NewCache(lggr logger.Logger, cfg CacheConfig) *Cache
NewCache builds a Cache from cfg (missing durations are defaulted).
func (*Cache) GetObjectMetadata ¶
func (rc *Cache) GetObjectMetadata( ctx context.Context, objectID string, loader func(context.Context) (*suirpcv2.Object, error), ) (*suirpcv2.Object, error)
GetObjectMetadata returns the object's reference metadata, serving it from cache when possible and otherwise invoking loader exactly once across concurrent callers for the same objectID. Only version-stable objects (SHARED/IMMUTABLE) are cached; address-owned objects, whose version changes on mutation, always go to loader so a stale ref is never served. This method satisfies the client.ObjectMetadataCache interface used by the gRPC client.
func (*Cache) GetReadResults ¶
func (rc *Cache) GetReadResults( ctx context.Context, key string, loader func(context.Context) ([]any, error), ) ([]any, error)
GetReadResults returns the decoded results of a read call, serving them from cache when enabled and otherwise invoking loader exactly once across concurrent callers for the same key. Disabled by default — see CacheConfig.ReadCacheEnabled.
Every cache hit returns a deep copy of the cached value. This is required for correctness: callers (GetLatestValue -> prepareFunctionReadResult -> applyResultFieldRenames/MaybeRenameFields, and the NormalizeReturnValuesToHex path) mutate the decoded result in place — e.g. renaming the OffRamp OCR config's `big_f` field to `f`. Handing out the cached reference would let the first read mutate the shared value, so a later cache hit would see an already-transformed object (e.g. `big_f` missing) and fail. Copying on the way out keeps the cached value pristine and each caller's result independent.
type CacheConfig ¶
type CacheConfig struct {
// ObjectCacheEnabled caches version-stable object reference metadata (owner/version/digest). The Sui
// read hot path resolves the same shared CCIP config objects (the CCIPObjectRef, OffRamp state, fee
// quoter, ...) on every read; caching their refs removes that redundant GetObject fan-out so it does
// not hit the node on every read across every config-poll cycle.
ObjectCacheEnabled bool
// ObjectTTL is how long object metadata is retained. Only SHARED/IMMUTABLE objects are cached (their
// refs are version-stable), so this can be minutes without serving a stale ref.
ObjectTTL time.Duration
// ReadCacheEnabled caches decoded read-call (devInspect) results keyed by read identifier + params.
// Config reads (OffRamp OCR config, source-chain configs, static/dynamic config, price seq number)
// change rarely, so caching them for a short ReadTTL cuts the redundant devInspect fan-out that
// otherwise floods the node every config-poll cycle. Combined with StaleReadTTL below, it also makes
// reads resilient to transient RPC cancellation (the EVM->Sui commit blocker).
ReadCacheEnabled bool
// ReadTTL bounds how long a cached read result is served as fresh before it is re-fetched.
ReadTTL time.Duration
// StaleReadTTL bounds how long the last successfully-read value may be served as a fallback when a
// fresh read fails (see GetReadResults). This turns a transient read failure — e.g. a context
// cancellation while a slow config poll is in flight — into "serve the last known-good config"
// instead of "return a zero/empty config", which is what makes the Sui commit plugin reject every
// EVM->Sui report. Only consulted when ReadCacheEnabled is true; a zero value falls back to the
// default via withDefaults.
StaleReadTTL time.Duration
// CleanupInterval is how often expired entries are purged from the underlying caches.
CleanupInterval time.Duration
}
CacheConfig tunes the Cache. Zero-value durations fall back to the values in DefaultCacheConfig via withDefaults(), so a partially-populated config is always valid.
func DefaultCacheConfig ¶
func DefaultCacheConfig() CacheConfig
DefaultCacheConfig returns safe defaults: object caching ON (high value, no staleness risk for version-stable objects) and read-call caching ON with a short freshness TTL plus a bounded serve-stale fallback (config reads change rarely, and serving a slightly-stale config is far safer than serving a zero config on a transient read failure).
type ExtendedContractReader ¶
type ExtendedContractReader interface {
pkgtypes.ContractReader
QueryKeyWithMetadata(ctx context.Context, contract pkgtypes.BoundContract, filter query.KeyFilter, limitAndSort query.LimitAndSort, sequenceDataType any) ([]aptosCRConfig.SequenceWithMetadata, error)
}
type SequenceWithRecord ¶
type SequenceWithRecord struct {
Sequence pkgtypes.Sequence
Record *database.EventRecord
}