bridgetracker

package
v0.11.0-rc3 Latest Latest
Warning

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

Go to latest
Published: Aug 5, 2026 License: Apache-2.0, MIT Imports: 15 Imported by: 0

Documentation

Index

Constants

View Source
const (
	// DefaultEnginePollInterval is the default period between engine resolution rounds
	DefaultEnginePollInterval = 10 * time.Second
	// DefaultEngineResolveTimeout is the default per-bridge budget for one resolution
	DefaultEngineResolveTimeout = 30 * time.Second
	// DefaultEngineUnresolvedTimeout is the default time a supervised tx is given to resolve
	// (FindBridge succeeding) before it is marked as terminally failed, regardless of why it
	// hasn't resolved (the tx may not be mined yet, or a source keeps failing transiently)
	DefaultEngineUnresolvedTimeout = 30 * time.Second
	// DefaultEngineRetentionPeriod is the default time a terminal bridge (Finished, or failed
	// to ever resolve) stays queryable before being forgotten. Clients polling or subscribed
	// observe the terminal TrackingStatus during this window; once forgotten, a new request
	// for the same tx re-registers it and tracking restarts from scratch — the retry path for
	// a tx the tracker gave up on
	DefaultEngineRetentionPeriod = 10 * time.Minute
)
View Source
const DefaultMaxTrackedBridges = 100_000

DefaultMaxTrackedBridges is the default Config.MaxTrackedBridges: how many distinct bridges the in-memory registry accepts before refusing new ones (see registry.go's memoryRegistry).

Variables

View Source
var DefaultL1BlockFinality = aggkittypes.LatestBlock

DefaultL1BlockFinality is the default Config.L1BlockFinality: an L1 bridge's creating tx is only accepted once its receipt reaches this finality, so a reorg cannot leave the tracker permanently following an orphaned deposit/block

View Source
var DefaultL2BlockFinality = aggkittypes.LatestBlock

DefaultL2BlockFinality is the default Config.L2BlockFinality: an L2 bridge's creating tx is only accepted once its receipt reaches this finality, so a reorg cannot leave the tracker permanently following an orphaned deposit/block

View Source
var DefaultRegisterResolveTimeout = types.Duration{Duration: defaultRegisterResolveTimeoutDuration}

DefaultRegisterResolveTimeout is the default Config.RegisterResolveTimeout (must stay in sync with the [Tracker] section of the proxy's default config)

View Source
var DefaultRetentionPeriod = types.Duration{Duration: DefaultEngineRetentionPeriod}

DefaultRetentionPeriod is the default Config.RetentionPeriod (see DefaultEngineRetentionPeriod for the semantics; both must stay in sync with the [Tracker] section of the proxy's default config)

View Source
var ErrBridgeTxNotABridge = domain.ErrBridgeTxNotABridge

ErrBridgeTxNotABridge is returned by BridgeEventSource.FindBridge when the transaction exists but is definitely not a bridge transaction (reverted, or mined without emitting a BridgeEvent log): unlike ErrBridgeTxNotFound, retrying cannot change this, so it is wrapped as domain.Permanent — the tracker marks the bridge as terminally failed immediately, with no retries

View Source
var ErrBridgeTxNotFound = domain.ErrBridgeTxNotFound

ErrBridgeTxNotFound is returned by BridgeEventSource.FindBridge when the transaction does not exist on the network yet. domain.ResolveBridgeTx keeps retrying for up to EngineConfig. UnresolvedTimeout (the tx may simply not be mined yet) before marking the bridge as terminally failed

View Source
var ErrSourceUnavailable = domain.ErrSourceUnavailable

ErrSourceUnavailable is returned by BridgeEventSource.FindBridge when the bridge's origin network has no source configured to resolve it (e.g. no JSON-RPC client for a statically-configured network): like ErrBridgeTxNotABridge, this is a permanent condition that retrying cannot change, so it is wrapped as domain.Permanent too

Functions

func Dependencies

func Dependencies() []proxytypes.Component

Types

type BridgeEventSource

type BridgeEventSource = domain.BridgeEventSource

BridgeEventSource is the driven port resolving the BridgeEvent behind a supervised tx on its origin network (RPC receipt or bridge service, resolved per network via the finder). domain.ResolveBridgeTx calls it directly — see its doc

type BridgeInfo

type BridgeInfo = domain.BridgeInfo

BridgeInfo holds the immutable facts of a bridge, resolved once from its creation tx

type BridgeStepPath

type BridgeStepPath = domain.BridgeStepPath

BridgeStepPath is the domain-internal representation of one step of the expected path of a bridge; see api.BridgeStepPath for the wire shape published to clients

type BridgeTracker

type BridgeTracker struct {
	// contains filtered or unexported fields
}

BridgeTracker is the bridge tracker component: it owns the supervised-bridges registry and the HTTP service implementing the tracker endpoints (API). The tracking engine is wired separately (see NewEngine) over the same registry passed in Config

func New

func New(cfg *Config) *BridgeTracker

New returns an instance of BridgeTracker

func (*BridgeTracker) API

func (b *BridgeTracker) API() *api.API

API returns the HTTP service of the tracker; register it on the shared HTTP server to expose the tracker REST/WS endpoints

func (*BridgeTracker) Publish

func (b *BridgeTracker) Publish(id TrackingID, info *BridgeInfo, allSteps []BridgeStepPath)

Publish stores the resolved bridge facts and expected path of a supervised bridge and pushes it to every subscriber (REST polls return it, WebSocket connections receive a "status" message); TrackingStatus and step index are derived from allSteps (see TrackingData), and the public BridgeStatus is derived from info (see api.BridgeStatus). It is a no-op if the bridge is not in the supervised list

func (*BridgeTracker) PublishError

func (b *BridgeTracker) PublishError(id TrackingID, errStep *types.ErrorStep)

PublishError marks a supervised bridge as terminally failed to resolve at all (e.g. the tx does not exist on the network or is not a bridge tx): TrackingStatus becomes Error and errStep is exposed as TrackingData.Error, both to REST polls and WebSocket connections (which then close normally). It is a no-op if the bridge is not in the supervised list

type CertificateSource

type CertificateSource interface {
	// CertificateFor returns the certificate that includes the bridge, or nil if the bridge
	// is not part of any certificate yet
	CertificateFor(ctx context.Context, bridge *BridgeInfo) (*types.CertificateInclusionData, error)
}

CertificateSource is the driven port to the agglayer: which certificate includes a bridge and in which state it is

type ClaimSource

type ClaimSource interface {
	// ClaimFor returns the claim transaction of the bridge on the destination network, or
	// nil if it has not been claimed yet
	ClaimFor(ctx context.Context, bridge *BridgeInfo) (*types.ClaimResult, error)
}

ClaimSource is the driven port to the claim state of a bridge on its destination network

type Config

type Config struct {
	// RetentionPeriod is how long a terminal bridge (Finished, or failed to ever resolve)
	// stays queryable before the tracker forgets it. Clients polling or subscribed observe
	// the terminal TrackingStatus during this window; once forgotten, a new request for the
	// same tx re-registers it and tracking restarts from scratch — the retry path for a tx
	// the tracker gave up on
	RetentionPeriod types.Duration `mapstructure:"RetentionPeriod"`

	// RegisterResolveTimeout is how long the GetTxStatus endpoint waits, the first time a tx is
	// registered, for the tracking engine's immediate resolution attempt (triggered right away
	// instead of on the next poll tick, see Registry.GetAndAwait) to produce an update before
	// answering. A value <= 0 disables the wait: the first response is always the bare
	// Registered snapshot, exactly as before this field existed. Looking up an already-registered
	// tx never waits, regardless of this setting.
	RegisterResolveTimeout types.Duration `mapstructure:"RegisterResolveTimeout"`

	// L1BlockFinality is the finality level a bridge's creating tx receipt must reach on L1
	// (network 0) before the tracker accepts it (see sources.BridgeEventSource): accepting
	// a receipt from a block that later gets reorged out would otherwise leave the tracker
	// permanently following an orphaned deposit count/block, since a resolved bridge is never
	// re-checked (see TrackingBridgeTx.IsDone)
	L1BlockFinality aggkittypes.BlockNumberFinality `` //nolint:lll
	/* 132-byte string literal not displayed */

	// L2BlockFinality is the finality level a bridge's creating tx receipt must reach on any
	// L2 (non-zero network) before the tracker accepts it; see L1BlockFinality for the reasoning
	L2BlockFinality aggkittypes.BlockNumberFinality `` //nolint:lll
	/* 132-byte string literal not displayed */

	// BridgeAddrs is the static networkID -> canonical bridge contract address map used to
	// reject a BridgeEvent log emitted by a contract other than the origin network's real
	// bridge (see sources.BridgeEventSource). A network absent from this map (the default,
	// empty map) still matches logs on the event signature alone.
	BridgeAddrs map[uint32]common.Address `mapstructure:"BridgeAddrs"`

	// L1GlobalExitRootAddress is the L1 GlobalExitRoot contract address (see sources.GERSource)
	L1GlobalExitRootAddress common.Address `mapstructure:"L1GlobalExitRootAddress"`

	// MaxTrackedBridges bounds how many distinct bridges the in-memory registry (see Registry)
	// accepts at once; a request that would exceed it fails instead of registering the bridge.
	// A value <= 0 falls back to DefaultMaxTrackedBridges. Only applies to the default in-memory
	// adapter — ignored when Registry is set to a custom implementation.
	MaxTrackedBridges int `mapstructure:"MaxTrackedBridges"`

	// AgglayerClient configures the client used to query the agglayer for a bridge's covering
	// certificate and that certificate's current status (see sources.CertificateSource)
	AgglayerClient agglayer.ClientConfig `mapstructure:"AgglayerClient"`

	Logger aggkitcommon.Logger `mapstructure:"-"`

	// ConfigSHA1 is the sha1sum (hex) of the configuration the binary was started with,
	// exposed by the health endpoint to check that all instances behind a proxy run the
	// same configuration
	ConfigSHA1 string `mapstructure:"-"`

	// Registry is the supervised-bridges subsystem to use. Leave nil to get the in-memory
	// adapter (single instance); inject a shared-store implementation so several tracker
	// instances behind a proxy answer for any registered tx
	Registry SupervisedRegistry `mapstructure:"-"`
}

Config holds the configuration of the bridge tracker service. Only the mapstructure-tagged fields come from the configuration file; the rest are wired programmatically by the binary (see proxy/cmd)

type Engine

type Engine struct {
	// contains filtered or unexported fields
}

Engine is the tracking engine: it watches the supervised list, resolves the status of every active bridge through the fact sources and stores each change (which the registry fans out to REST polls and WebSocket subscribers). All engine-private resolution state (resolved bridge facts, not-found counter, last published status/steps) lives in the store itself, as part of each bridge's TrackingData

func NewEngine

func NewEngine(
	cfg EngineConfig,
	logger aggkitcommon.Logger,
	store SupervisedStore,
	sources EngineSources,
) (*Engine, error)

NewEngine returns a tracking engine over the given store and fact sources

func (*Engine) Start

func (e *Engine) Start(ctx context.Context)

Start launches the resolution loop; it stops when ctx is cancelled. Besides the regular poll cadence, it also watches the store's Triggerable channel (if implemented) to resolve a freshly registered bridge right away instead of leaving it for the next tick — see resolveTriggered and SupervisedStore.GetAndAwait, which is what a caller actually waits on

type EngineConfig

type EngineConfig struct {
	// PollInterval is the period between resolution rounds over the supervised list
	PollInterval time.Duration
	// ResolveTimeout bounds the source calls of a single bridge resolution
	ResolveTimeout time.Duration
	// UnresolvedTimeout is how long a supervised tx is given, since first seen unresolved, to
	// have FindBridge succeed before it is marked terminally failed (TrackingStatus becomes
	// Error, with an exhausted ErrorStep explaining why)
	UnresolvedTimeout time.Duration
	// RetentionPeriod is how long a terminal bridge stays queryable before being forgotten
	// (see DefaultEngineRetentionPeriod)
	RetentionPeriod time.Duration
}

EngineConfig holds the tracking engine tunables. Zero values take the defaults above

type EngineSources

type EngineSources struct {
	Bridges                BridgeEventSource
	Certificates           CertificateSource
	GERs                   GERSource
	WaitingGERUpdateSource domain.WaitingGERUpdateSource
	LERs                   LERSource
	Claims                 ClaimSource
	Settlement             SettlementSource
}

EngineSources groups the driven ports the engine resolves bridge facts through. Each is handed directly to the one or two step resolvers that need it (see createResolvers) rather than adapted into one do-everything port

type GERSource

type GERSource interface {
	// OriginGER returns the GER update on the origin network that covers the bridge, or nil
	// if the bridge is not covered by any GER update yet. Only queried for L1-originated
	// bridges
	OriginGER(ctx context.Context, bridge *BridgeInfo) (*types.GERData, error)

	// InjectedGER returns the GER injected on the destination network that covers the
	// bridge, or nil if no covering GER has been injected yet. Only meaningful when the
	// destination is an L2 (injection does not apply to Mainnet)
	InjectedGER(ctx context.Context, bridge *BridgeInfo) (*types.GERData, error)

	// L1InfoTreeIndexForGER resolves the L1 info tree leaf index ger (produced by the bridge's
	// certificate settlement, see types.L1SettledGERResult) landed at, or nil if the L1 info
	// tree has not caught up with it yet. Only queried by StepWaitL1SettledGER, and only when
	// the settlement tx did not emit UpdateL1InfoTreeV2 (which already carries the index)
	L1InfoTreeIndexForGER(ctx context.Context, bridge *BridgeInfo, ger common.Hash) (*uint32, error)

	// InjectedGERAtIndex returns the GER injected at leafIndex on the bridge's destination
	// network, or nil if it has not been injected yet. Only queried for L2-originated bridges
	// arriving at an L2, right after StepWaitL1SettledGER
	InjectedGERAtIndex(ctx context.Context, bridge *BridgeInfo, leafIndex uint32) (*types.GERData, error)
}

GERSource is the driven port to the Global Exit Root state on both sides of a bridge

type LERSource

type LERSource interface {
	// OriginLER returns the LER update on the origin L2 network that covers the bridge, or
	// nil if the bridge is not covered yet
	OriginLER(ctx context.Context, bridge *BridgeInfo) (*types.LERUpdateResult, error)
}

LERSource is the driven port to the Local Exit Root state on an L2-originated bridge's origin network

type SettlementSource

type SettlementSource interface {
	// SettlementGERUpdate returns the evidence read off settlementTxHash's L1 receipt once it
	// reaches the configured L1 finality, or nil if it is not there yet
	SettlementGERUpdate(
		ctx context.Context, bridge *BridgeInfo, settlementTxHash common.Hash,
	) (*types.L1SettledGERResult, error)
}

SettlementSource is the driven port to the L1 evidence a certificate's settlement produces: the RollupManager/GlobalExitRoot events (VerifyBatchesTrustedAggregator, UpdateL1InfoTree[V2]) emitted by the settlement tx itself

type StatusNotifier

type StatusNotifier = domain.StatusNotifier

StatusNotifier is the driven port push consumers (the WebSocket handler) use to follow a supervised bridge.

Implementations must deliver every SetStatus / SetError of the same bridge as a TrackingData snapshot to all its active subscriptions: both ports are two views of one subsystem and are always implemented together (see SupervisedRegistry).

type SupervisedRegistry

type SupervisedRegistry = domain.SupervisedRegistry

SupervisedRegistry is the full supervised-bridges subsystem: state plus change notification. The in-memory adapter (NewMemoryRegistry) implements it for a single instance; a shared-store adapter can replace it so several tracker instances behind a proxy answer for any registered tx (see the statefulness note in the API doc)

func NewMemoryRegistry

func NewMemoryRegistry(maxEntries int) SupervisedRegistry

NewMemoryRegistry returns an in-memory SupervisedRegistry that refuses to register more than maxEntries distinct bridges at once (see memoryRegistry.maxEntries); maxEntries <= 0 falls back to DefaultMaxTrackedBridges.

type SupervisedStore

type SupervisedStore = domain.SupervisedStore

SupervisedStore is the driven port to the supervised-bridges state. The HTTP handlers use its read side (Register) and the tracking engine its write side (SetStatus / SetError).

Implementations must be safe for concurrent use.

type TrackingID

type TrackingID = domain.TrackingID

TrackingID identifies a supervised bridge: the network the creating tx was sent to plus its hash

Directories

Path Synopsis
api
docs
Package docs Code generated by swaggo/swag.
Package docs Code generated by swaggo/swag.
Package domain holds the pure business rules of the bridge tracker: decisions that depend only on bridge facts, with no I/O and no dependency on the ports or adapters.
Package domain holds the pure business rules of the bridge tracker: decisions that depend only on bridge facts, with no I/O and no dependency on the ports or adapters.
Package sources implements the driven fact ports of the bridge tracker engine (bridgetracker.BridgeEventSource, GERSource, LERSource, ClaimSource, CertificateSource) over the real backends: the per-network JSON-RPC endpoints and the aggkit bridge service REST API, both resolved per network through the bridgeservicefinder.
Package sources implements the driven fact ports of the bridge tracker engine (bridgetracker.BridgeEventSource, GERSource, LERSource, ClaimSource, CertificateSource) over the real backends: the per-network JSON-RPC endpoints and the aggkit bridge service REST API, both resolved per network through the bridgeservicefinder.

Jump to

Keyboard shortcuts

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