Help us shape the future of Go! Take the 2026 Go Developer Survey

cache

package
v0.7.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 8, 2026 License: MIT Imports: 26 Imported by: 0

Documentation

Overview

Package cache mirrors the name contracts in Mongo (see "Name cache" in the README).

Index

Constants

View Source
const CName = "any-ns.cache"

Variables

View Source
var ErrDuplicateNames = errors.New("the cache has duplicates of a name: resolve them by hand, then create the unique index (-dedupe-cache -refresh-apply)")

ErrDuplicateNames is returned by VerifyNameIndex when the unique index is missing and the cache has more than one record of a name: they must be resolved by hand before it can be created

View Source
var ErrNameDataIncomplete = errors.New("name is registered, but its owner could not be read")

ErrNameDataIncomplete is returned by UpdateInCache when the registry confirmed the name (it is registered and not lapsed), but its owner could not be read. the confirmed part is cached and the record is marked refresh_needed, so lookups keep reporting the name as taken

View Source
var ErrNameIndexNotUnique = fmt.Errorf("the name cache has a non-unique index on {name: 1}: drop it by hand, " +
	"resolve the duplicates, then run -dedupe-cache -refresh-apply")

ErrNameIndexNotUnique is returned when there is an index on exactly {name: 1}, but it is not unique. it is never dropped automatically (an operator decides)

View Source
var ErrNameNotCached = errors.New("the name is not in the cache")

ErrNameNotCached is returned by ReleaseName when the cache has no record of the name

View Source
var ErrNameNotRegistered = errors.New("name is not registered")

ErrNameNotRegistered is returned by UpdateInCache when the chain does not have the name and the cache has no record of it: "not registered (yet)". it is not a transport error: callers should treat it as "not registered (yet)", never as "the cache is up to date"

View Source
var ErrNameReserved = errors.New("the name is reserved for another identity")

ErrNameReserved is returned by CheckReservation for a registration of a name that the cache has for another identity

View Source
var ErrRecordChanged = errors.New("the record changed, run again")

ErrRecordChanged is returned by ReleaseName when the record changed between the read and the delete: nothing was deleted

Functions

func CheckReservation added in v0.7.2

func CheckReservation(ctx context.Context, cs CacheService, fullName, ownerAnyID string, ensip15 bool) error

CheckReservation checks that the identity ownerAnyID may register the name: a name stays reserved to the identity that registered it, even after it lapsed on chain: the cache is the record of who holds a name (every registration goes through an operation of ours), so any record of the name (a lapsed one, a 0.7.1 tombstone, one under another spelling) reserves it. no record, or the same owner (a re-registration after a lapse, the payment node's renew-past-grace fallback): nil. a record without an owner (a tombstone, an incomplete read): ErrNameReserved. a cache that can not be read: an error too (fail closed, the caller retries). moving a name to another identity is a support action (-release-name)

func New

func New() app.Component

func NewMaintainer added in v0.7.0

func NewMaintainer() app.Component

NewMaintainer is the cache for a one-off maintenance run (a Maintainer): it does not touch the indexes at start (VerifyNameIndex reports them) and runs no background refresh

Types

type AliasStats added in v0.7.0

type AliasStats struct {
	// records under a non-canonical spelling
	Aliases int
	// renamed to the canonical name (there was no canonical record), kept as they are, marked
	// for a refresh
	Renamed int
	// deleted: the canonical record has its block, is live, complete and at least as new
	Deleted int
	// records given their canonical spelling (canon), aliases and canonical records alike
	Canon int
	// left as they are (the canonical record has no block, is a tombstone, incomplete or older),
	// the canonical record marked for a refresh: for an operator, or a later run
	Kept []string
}

AliasStats is what MigrateAliases did (or would do, in a dry run)

type CacheService

type CacheService interface {
	// call it before you want to check in smart contracts
	// it will look up data in Mongo.
	// a cached name is always reported as taken, whatever its expiry: a name stays reserved
	// to the identity that registered it. only an operator removes a record (-release-name)
	IsNameAvailable(ctx context.Context, in *nsp.NameAvailableRequest) (out *nsp.NameAvailableResponse, err error)
	GetNameByAddress(ctx context.Context, in *nsp.NameByAddressRequest) (out *nsp.NameByAddressResponse, err error)
	GetNameByAnyId(ctx context.Context, in *nsp.NameByAnyIdRequest) (out *nsp.NameByAddressResponse, err error)

	// call it when you need to read REAL data: smart contracts -> cache
	// will return no error if name is found and data was updated
	// will return ErrNameNotRegistered if the chain does not have the name (never registered, or
	// lapsed) and the cache has no record of it. a cached record is never removed or wiped by a
	// read: a lapse is stored on the record (lapsed), "never registered" leaves it as it is (the
	// error then wraps ErrNameNotRegistered too). callers must never treat it as "the cache is
	// up to date"
	// will return ErrNameDataIncomplete if the name is registered, but its owner could not be
	// read: the cache has it as taken, without the owner (see ErrNameDataIncomplete)
	// will return any other error if something went wrong
	UpdateInCache(ctx context.Context, in *nsp.NameAvailableRequest) (err error)
	// UpdateInCacheAfterOperation is UpdateInCache for a name that a completed operation changed:
	// the same refresh at the latest block, and it schedules re-reads of the name (see
	// rereadDelays) in the same write, to pick up a lagging provider or a reorg
	UpdateInCacheAfterOperation(ctx context.Context, in *nsp.NameAvailableRequest) (err error)
	// RefreshAfterOperation hands a name that a completed operation changed to the background:
	// its re-reads are stored on its record (durable: a dropped request or a restart does not lose
	// them), and a refresh at the latest block runs (if it fails, the record is marked
	// refresh_needed). it never blocks and never waits for a write
	RefreshAfterOperation(fullName string)

	app.Component
}

type Maintainer added in v0.7.0

type Maintainer interface {
	// RefreshAll re-reads every cached name from the contracts, with the same decisions as the
	// node (a lapse is stored on the record, nothing is ever removed, the order of the records).
	// apply == false is a dry run: it decides the same, but writes nothing.
	// interval is the delay between two names, every name costs several contract calls
	RefreshAll(ctx context.Context, apply bool, interval time.Duration) (RefreshStats, error)

	// VerifyNameIndex checks the unique index on {name: 1}: any unique one is accepted whatever
	// its name (prod has name_1). a missing one is created with apply (it fails if the cache has
	// duplicates of a name: they are never resolved automatically). a non-unique one is an error
	// (ErrNameIndexNotUnique), it is never dropped
	VerifyNameIndex(ctx context.Context, apply bool) (NameIndexStats, error)

	// MigrateAliases resolves the records cached under a non-canonical spelling (see alias.go),
	// one transaction per record: no canonical record -> the alias is renamed to the canonical
	// name (its data kept, marked for a refresh); the canonical record is live, complete and at
	// least as new -> the alias is deleted; otherwise both stay (Kept). apply == false is a dry run
	MigrateAliases(ctx context.Context, apply bool) (AliasStats, error)

	// ReleaseName is the support transfer of a name: a name stays reserved to its identity until
	// an operator releases it. it finds the record of the name (normalized) and, with apply,
	// deletes exactly that record (ErrRecordChanged if it changed since it was read: nothing is
	// deleted); the records under other spellings (aliases) are listed, never deleted.
	// ErrNameNotCached if there is no record. apply == false is a dry run
	ReleaseName(ctx context.Context, fullName string, apply bool) (ReleaseStats, error)

	// RestoreTombstones brings back the owners of the 0.7.1 tombstones (removed records, their
	// owner fields wiped) from a mongoexport of the cache (JSON lines, MongoDB Extended JSON).
	// one transaction per record, only while it is still removed; the later expiry of the export
	// and the tombstone. a tombstone that the export has no owner for (Missing), or records with
	// different owners for (Conflicts), is left as it is (served as taken, without an owner).
	// records that are not removed but have another owner than the export's are reported
	// (OwnerDiffers), never written. apply == false is a dry run
	RestoreTombstones(ctx context.Context, export io.Reader, apply bool) (RestoreStats, error)
}

Maintainer holds the cache maintenance tools (the -refresh-cache, -dedupe-cache, -release-name and -restore-tombstones flags of the node). it is not a part of CacheService

type NameDataItem

type NameDataItem struct {
	ID       primitive.ObjectID `bson:"_id,omitempty"`
	FullName string             `bson:"name"`
	// always store in LOWER CASE!
	OwnerEthAddress    string `bson:"owner_eth_address"`
	OwnerScwEthAddress string `bson:"owner_scw_eth_address"`
	OwnerAnyAddress    string `bson:"owner_any_address"`
	SpaceId            string `bson:"space_id"`
	NameExpires        int64  `bson:"name_expires"`

	// the block the contracts were read at (all the reads of a refresh by its hash).
	// 0 for records written before it was added
	ObservedBlock     int64  `bson:"observed_block,omitempty"`
	ObservedBlockHash string `bson:"observed_block_hash,omitempty"`
	// that block's timestamp (unix seconds): lapse decisions use it, not the local clock
	ObservedBlockTime int64 `bson:"observed_block_time,omitempty"`
	// the local time of the read (unix ms)
	ObservedAt int64 `bson:"observed_at,omitempty"`
	// the latest read (unix ms) of this record's fork (block and hash), if a later one than
	// ObservedAt: a read that lost to this record (e.g. an incomplete one) still counts for
	// which fork was read last (see newer)
	ForkReadAt int64 `bson:"fork_read_at,omitempty"`

	// no background refresh takes the record before this (unix ms): a refresh in progress (a
	// lease) or a failed one (a backoff)
	RefreshNextAt int64 `bson:"refresh_next_at,omitempty"`
	// when the periodic scan takes the record (unix ms, see repairAt). indexed
	RepairAt int64 `bson:"repair_at,omitempty"`
	// scheduled re-reads of the record (unix ms, sorted): after a completed operation, see
	// rereadDelays. a read after one of them is done with it
	Rereads []int64 `bson:"rereads,omitempty"`

	// a tombstone written by 0.7.1 (the name lapsed, its owner fields were wiped). never written
	// any more: such a record is served as taken (with whatever owner fields it has), reverse
	// lookups skip it. -restore-tombstones brings the owner back and clears it
	Removed bool `bson:"removed,omitempty"`

	// the chain lets this name lapse (expired and past the grace period) at ObservedBlock; the
	// cache keeps it reserved for its owner: the owner fields stay, it is served as taken
	Lapsed bool `bson:"lapsed,omitempty"`

	// failed background refreshes in a row: the backoff of the next one grows with it (see
	// failureBackoff). reset by a successful write of the record
	RefreshFailures int `bson:"refresh_failures,omitempty"`

	// the registry confirmed the name, but the enrichment (owner, AnyID, space ID) failed: the
	// record holds what was confirmed, and what it could carry over from the previous record
	// (see carryOver). this is what orders two records of one block (see newer)
	Incomplete bool `bson:"incomplete,omitempty"`
	// the record is retried by the background (an incomplete read, or a failed refresh after an
	// operation): scheduling only, its data can be complete
	RefreshNeeded bool `bson:"refresh_needed,omitempty"`

	// the registry owner at ObservedBlock (lower case; the NameWrapper for a wrapped name, zero
	// for a reserved name without a registry owner). "" for records written before it was added
	RegistryOwner string `bson:"registry_owner,omitempty"`
	// the canonical spelling of the name (the normalizer's output), written with every record:
	// the alias check finds records under another spelling by it (see alias.go). indexed
	Canon string `bson:"canon,omitempty"`
	// contains filtered or unexported fields
}

type NameIndexStats added in v0.7.0

type NameIndexStats struct {
	// "exists" (a unique index on exactly {name: 1}, whatever its name), "created", or
	// "missing" (a dry run: it would be created)
	NameIndex string
	// names with more than one record (only counted when the index is missing): the index can
	// not be created until they are resolved by hand
	DuplicateNames int
}

NameIndexStats is what VerifyNameIndex found (or did)

type RefreshStats added in v0.7.0

type RefreshStats struct {
	Total     int
	Unchanged int
	Updated   int
	// lapsed on chain (expired and past the grace period): marked lapsed, or kept so; the
	// record and its owner stay
	Lapsed int
	// the chain says that a cached name was never registered: the record is kept as it is, for
	// an operator to look at
	NotOnChain int
	// nothing decided (e.g. a contract read failed), or the owner could not be read (the
	// confirmed part is stored, marked): run it again
	Failed int
	// cached under a spelling that is not the canonical one (e.g. "Foo.any"): the canonical
	// name was refreshed, the record under this spelling is left as it is (taken), for an
	// operator to look at
	NonCanonical int
	// cached under a name that can not be normalized (e.g. a leading "_", see STD3): not read,
	// left as it is (taken). not a failure: a re-run can not change it
	Unnormalizable int
}

RefreshStats counts what RefreshAll did (or would do, in a dry run)

type ReleaseStats added in v0.7.2

type ReleaseStats struct {
	// the normalized name
	Name string
	// the record of the name, nil if there is none
	Record *NameDataItem
	// the records of the name under other spellings: listed, never deleted
	Aliases []string
	// the record was deleted (apply)
	Deleted bool
}

ReleaseStats is what ReleaseName found (and did)

type RestoreStats added in v0.7.2

type RestoreStats struct {
	// the removed records of the cache
	Tombstones int
	// given their owner back from the export
	Restored int
	// not removed any more when they were written (a registration read in between): not touched
	Skipped int
	// the export has no owner for them: left as they are (taken, without an owner)
	Missing []string
	// the export has records of the name with different owners: left as they are, for an operator
	Conflicts []string
	// records that are not removed, but whose owner differs from the export's (a name taken by
	// another identity while 0.7.1 had freed it?): nothing is written, for support to review
	OwnerDiffers []string
}

RestoreStats is what RestoreTombstones did (or would do, in a dry run). Tombstones = Restored + Skipped + len(Missing) + len(Conflicts)

Directories

Path Synopsis
Package mock_cache is a generated GoMock package.
Package mock_cache is a generated GoMock package.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL