Documentation
¶
Overview ¶
Package forging contains types and utilities for block production.
Block Propagation ¶
Block propagation to peers is handled automatically by the chain package. When a forged block is added via chain.AddBlock(), the method closes the chain's waitingChan (see chain/chain.go lines 174-180), which signals any blocking ChainIterators. The ouroboros chainsync server (see ouroboros/chainsync.go chainsyncServerRequestNext) waits on these iterators via ChainIterator.Next(true), which blocks on waitingChan when at chain tip. When the channel is closed, iterators wake up and deliver the new block to connected peers via RollForward messages.
This means there is no need for explicit propagation logic when forging blocks - adding the block to the chain automatically triggers delivery to all subscribed chainsync clients.
Package forging provides block production functionality for Cardano SPOs.
Index ¶
- Constants
- Variables
- func CurrentKESPeriod(genesis *shelley.ShelleyGenesis, now time.Time) (uint64, error)
- type BlockBroadcaster
- type BlockBuilder
- type BlockBuilderConfig
- type BlockForgedObserver
- type BlockForger
- func (f *BlockForger) IsRunning() bool
- func (f *BlockForger) RecordSlotBattle()
- func (f *BlockForger) SignBlockHeader(kesPeriod uint64, headerBytes []byte) ([]byte, error)
- func (f *BlockForger) SlotTracker() *SlotTracker
- func (f *BlockForger) Start(ctx context.Context) error
- func (f *BlockForger) Stop()
- func (f *BlockForger) VRFProofForSlot(slot uint64, epochNonce []byte) ([]byte, []byte, error)
- type ChainTipProvider
- type DefaultBlockBuilder
- type EpochNonceProvider
- type ForgedBlockRecord
- type ForgerConfig
- type LeaderChecker
- type LedgerView
- type MempoolProvider
- type MempoolTransaction
- type Mode
- type OpCert
- type PoolCredentials
- func (pc *PoolCredentials) GetKESPeriod() uint64
- func (pc *PoolCredentials) GetKESVKey() []byte
- func (pc *PoolCredentials) GetOpCert() *OpCert
- func (pc *PoolCredentials) GetPoolID() lcommon.PoolId
- func (pc *PoolCredentials) GetVRFSKey() []byte
- func (pc *PoolCredentials) GetVRFVKey() []byte
- func (pc *PoolCredentials) IsLoaded() bool
- func (pc *PoolCredentials) KESSign(period uint64, message []byte) ([]byte, error)
- func (pc *PoolCredentials) LoadFromFiles(vrfSKeyPath string, kesSKeyPath string, opCertPath string) error
- func (pc *PoolCredentials) OpCertExpiryPeriod() uint64
- func (pc *PoolCredentials) PeriodsRemaining(currentPeriod uint64) uint64
- func (pc *PoolCredentials) UpdateKESPeriod(period uint64) error
- func (pc *PoolCredentials) VRFProve(alpha []byte) ([]byte, []byte, error)
- func (pc *PoolCredentials) ValidateAgainstLedger(view LedgerView) (registered, vrfMatched bool, err error)
- func (pc *PoolCredentials) ValidateKESPeriod(genesis *shelley.ShelleyGenesis, now time.Time) error
- func (pc *PoolCredentials) ValidateOpCert() error
- type ProtocolParamsProvider
- type SlotBattleEvent
- type SlotClockProvider
- type SlotTracker
- type TxValidator
Constants ¶
const SlotBattleEventType = event.EventType("forging.slot_battle")
SlotBattleEventType is the event type for slot battles (competing blocks)
Variables ¶
var ErrVRFKeyHashMismatch = errors.New("VRF key hash mismatch")
Functions ¶
func CurrentKESPeriod ¶ added in v0.43.0
CurrentKESPeriod returns the KES period that wall-clock time `now` falls in, given the chain's Shelley genesis. It is a pure function so callers can drive it with synthetic genesis and timestamps in tests.
Semantics:
- Before SystemStart, period is 0 (the chain has not begun).
- SlotLength is a rational number of seconds per slot; the math is done in big.Rat to avoid losing precision on chains where slot length is a fraction (e.g. 1/20s on devnets).
- Returns an error if SlotsPerKESPeriod is non-positive, SlotLength is non-positive, or the computed period overflows uint64.
Types ¶
type BlockBroadcaster ¶
type BlockBroadcaster interface {
// AddBlock adds a block to the local chain and propagates to peers.
AddBlock(block ledger.Block, cbor []byte) error
}
BlockBroadcaster submits built blocks to the chain.
type BlockBuilder ¶
type BlockBuilder interface {
// BuildBlock creates a new block for the given slot.
// Returns the block and its CBOR encoding.
BuildBlock(slot uint64, kesPeriod uint64) (ledger.Block, []byte, error)
}
BlockBuilder constructs blocks from mempool transactions.
type BlockBuilderConfig ¶
type BlockBuilderConfig struct {
Logger *slog.Logger
Mempool MempoolProvider
PParamsProvider ProtocolParamsProvider
ChainTip ChainTipProvider
EpochNonce EpochNonceProvider
Credentials *PoolCredentials
// TxValidator optionally re-validates each transaction against
// the current ledger state before including it in a block.
// When nil, ledger-level re-validation is skipped (but
// intra-block double-spend detection still applies).
TxValidator TxValidator
}
BlockBuilderConfig holds configuration for the DefaultBlockBuilder.
type BlockForgedObserver ¶ added in v0.46.2
BlockForgedObserver observes blocks after they are successfully built, before chain adoption is attempted.
type BlockForger ¶
type BlockForger struct {
// contains filtered or unexported fields
}
BlockForger coordinates block production for a stake pool.
func NewBlockForger ¶
func NewBlockForger(cfg ForgerConfig) (*BlockForger, error)
NewBlockForger creates a new block forger.
func (*BlockForger) IsRunning ¶
func (f *BlockForger) IsRunning() bool
IsRunning returns true if the forger is currently running.
func (*BlockForger) RecordSlotBattle ¶
func (f *BlockForger) RecordSlotBattle()
RecordSlotBattle increments the slot battles counter. This is called from external components (e.g., LedgerState) when a slot battle is detected.
func (*BlockForger) SignBlockHeader ¶
func (f *BlockForger) SignBlockHeader( kesPeriod uint64, headerBytes []byte, ) ([]byte, error)
SignBlockHeader signs a block header with KES.
func (*BlockForger) SlotTracker ¶
func (f *BlockForger) SlotTracker() *SlotTracker
SlotTracker returns the forger's slot tracker, which can be used by other components (e.g., chainsync) to detect slot battles.
func (*BlockForger) Start ¶
func (f *BlockForger) Start(ctx context.Context) error
Start begins the block forging process. The provided context controls the forger's lifecycle.
func (*BlockForger) Stop ¶
func (f *BlockForger) Stop()
Stop stops the block forging process. It blocks until the runLoop goroutine has exited.
func (*BlockForger) VRFProofForSlot ¶
VRFProofForSlot generates a VRF proof for leader election at the given slot. Returns (proof, output, error).
type ChainTipProvider ¶
type ChainTipProvider interface {
Tip() ochainsync.Tip
}
ChainTipProvider provides access to the current chain tip.
type DefaultBlockBuilder ¶
type DefaultBlockBuilder struct {
// contains filtered or unexported fields
}
DefaultBlockBuilder implements BlockBuilder using LedgerState components.
func NewDefaultBlockBuilder ¶
func NewDefaultBlockBuilder(cfg BlockBuilderConfig) (*DefaultBlockBuilder, error)
NewDefaultBlockBuilder creates a new DefaultBlockBuilder.
func (*DefaultBlockBuilder) BuildBlock ¶
func (b *DefaultBlockBuilder) BuildBlock( slot uint64, kesPeriod uint64, ) (ledger.Block, []byte, error)
BuildBlock creates a new block for the given slot. Returns the block and its CBOR encoding.
type EpochNonceProvider ¶
type EpochNonceProvider interface {
// CurrentEpoch returns the current epoch number.
CurrentEpoch() uint64
// EpochForSlot returns the epoch containing the given slot.
EpochForSlot(slot uint64) (uint64, error)
// EpochNonce returns the nonce for the given epoch.
EpochNonce(epoch uint64) []byte
}
EpochNonceProvider provides the epoch nonce for VRF proof generation.
type ForgedBlockRecord ¶
type ForgedBlockRecord struct {
BlockHash []byte
}
ForgedBlockRecord stores the hash of a block we forged for a given slot.
type ForgerConfig ¶
type ForgerConfig struct {
Mode Mode
Logger *slog.Logger
SlotDuration time.Duration
// Production mode configuration
Credentials *PoolCredentials
LeaderChecker LeaderChecker
BlockBuilder BlockBuilder
BlockBroadcaster BlockBroadcaster
BlockForged BlockForgedObserver
SlotClock SlotClockProvider
// ForgeSyncToleranceSlots controls how far the local chain can lag the
// upstream tip before forging is skipped. Zero uses the default.
ForgeSyncToleranceSlots uint64
// ForgeStaleGapThresholdSlots controls when to log an error if the
// chain tip is far ahead of the slot clock. Zero uses the default.
ForgeStaleGapThresholdSlots uint64
// Prometheus metrics registry (optional)
PromRegistry prometheus.Registerer
}
ForgerConfig holds configuration for the block forger.
type LeaderChecker ¶
type LeaderChecker interface {
// ShouldProduceBlock returns true if this pool is the leader for the slot.
ShouldProduceBlock(slot uint64) bool
// NextLeaderSlot returns the next slot where this pool is leader.
NextLeaderSlot(fromSlot uint64) (uint64, bool)
}
LeaderChecker determines if the pool should produce a block for a given slot.
type LedgerView ¶ added in v0.43.0
type LedgerView interface {
// PoolRegistrationVRFKeyHash returns the VRF key hash recorded on
// the most recent active pool registration certificate for poolID.
// found is false when the pool has no on-chain registration yet.
PoolRegistrationVRFKeyHash(poolID [28]byte) (vrfKeyHash [32]byte, found bool, err error)
// LatestOpCertSequence returns the highest opcert IssueNumber
// observed on chain for poolID. found is false when on-chain
// counter tracking is not implemented or this pool has never
// minted a block.
LatestOpCertSequence(poolID [28]byte) (sequence uint64, found bool, err error)
}
LedgerView is the subset of ledger state the post-startup credential cross-check needs. The forging package depends on it as a small interface so the package itself stays free of a ledger dependency, and tests can drive the logic with a fake.
type MempoolProvider ¶
type MempoolProvider interface {
Transactions() []MempoolTransaction
}
MempoolProvider provides access to mempool transactions.
type MempoolTransaction ¶
MempoolTransaction represents a transaction in the mempool.
type OpCert ¶
type OpCert struct {
KESVKey []byte // KES verification key (32 bytes)
IssueNumber uint64 // Certificate sequence number
KESPeriod uint64 // KES period when certificate was created
Signature []byte // Cold key signature (64 bytes)
ColdVKey []byte // Cold verification key (32 bytes)
}
OpCert represents an operational certificate that binds a KES key to a pool.
type PoolCredentials ¶
type PoolCredentials struct {
// contains filtered or unexported fields
}
PoolCredentials holds the cryptographic keys required for block production. All keys are loaded using Bursa from standard cardano-cli format files. Fields are unexported to enforce thread-safe access via the mutex.
func NewPoolCredentials ¶
func NewPoolCredentials() *PoolCredentials
NewPoolCredentials creates an empty PoolCredentials instance.
func (*PoolCredentials) GetKESPeriod ¶
func (pc *PoolCredentials) GetKESPeriod() uint64
GetKESPeriod returns the current KES period of the loaded key. Returns 0 if the KES key is not loaded.
func (*PoolCredentials) GetKESVKey ¶
func (pc *PoolCredentials) GetKESVKey() []byte
GetKESVKey returns a copy of the KES verification key.
func (*PoolCredentials) GetOpCert ¶
func (pc *PoolCredentials) GetOpCert() *OpCert
GetOpCert returns a copy of the operational certificate. Returns nil if no certificate is loaded.
func (*PoolCredentials) GetPoolID ¶
func (pc *PoolCredentials) GetPoolID() lcommon.PoolId
GetPoolID returns the pool ID (Blake2b-224 of cold vkey).
func (*PoolCredentials) GetVRFSKey ¶
func (pc *PoolCredentials) GetVRFSKey() []byte
GetVRFSKey returns a copy of the VRF secret key (seed).
func (*PoolCredentials) GetVRFVKey ¶
func (pc *PoolCredentials) GetVRFVKey() []byte
GetVRFVKey returns a copy of the VRF verification key.
func (*PoolCredentials) IsLoaded ¶
func (pc *PoolCredentials) IsLoaded() bool
IsLoaded returns true if all credentials have been loaded.
func (*PoolCredentials) KESSign ¶
func (pc *PoolCredentials) KESSign(period uint64, message []byte) ([]byte, error)
KESSign signs a message with the KES key at the specified ABSOLUTE period.
IMPORTANT: Callers must ensure UpdateKESPeriod(period) was called before KESSign to evolve the key to the correct period. The kes.Sign function expects the key to already be at the relative period within the opcert window when an opcert is loaded.
func (*PoolCredentials) LoadFromFiles ¶
func (pc *PoolCredentials) LoadFromFiles( vrfSKeyPath string, kesSKeyPath string, opCertPath string, ) error
LoadFromFiles loads all pool credentials from the specified file paths. Uses Bursa to parse cardano-cli format key files.
func (*PoolCredentials) OpCertExpiryPeriod ¶
func (pc *PoolCredentials) OpCertExpiryPeriod() uint64
OpCertExpiryPeriod returns the KES period at which the OpCert expires. For depth 6, max periods = 2^6 = 64, so expiry = startPeriod + 64.
func (*PoolCredentials) PeriodsRemaining ¶
func (pc *PoolCredentials) PeriodsRemaining(currentPeriod uint64) uint64
PeriodsRemaining returns how many KES periods remain before expiry.
func (*PoolCredentials) UpdateKESPeriod ¶
func (pc *PoolCredentials) UpdateKESPeriod(period uint64) error
UpdateKESPeriod evolves the KES key to the specified ABSOLUTE period. The secret key itself tracks the relative period within the opcert window, so we translate chain KES periods by subtracting the opcert start period when an opcert is loaded.
func (*PoolCredentials) VRFProve ¶
func (pc *PoolCredentials) VRFProve(alpha []byte) ([]byte, []byte, error)
VRFProve generates a VRF proof for leader election. alpha should be MkInputVrf(slot, epochNonce).
func (*PoolCredentials) ValidateAgainstLedger ¶ added in v0.43.0
func (pc *PoolCredentials) ValidateAgainstLedger( view LedgerView, ) (registered, vrfMatched bool, err error)
ValidateAgainstLedger cross-checks the loaded credentials against ledger state once it is available. It is best-effort: a missing pool registration is not fatal because operators commonly stage their keys before submitting the registration certificate.
Three return values describe the outcome:
- registered: true if the pool registration was found on chain.
- vrfMatched: true if registered AND the on-chain VRF key hash matched our loaded VRF verification key. False otherwise (also false when registered is false or the VRF verification key is unavailable, e.g. for a seed-only VRF skey).
- err: a non-nil error means the ledger view disagrees with the loaded credentials. Normal networks refuse startup for these; devnet callers may choose to warn on ErrVRFKeyHashMismatch.
func (*PoolCredentials) ValidateKESPeriod ¶ added in v0.43.0
func (pc *PoolCredentials) ValidateKESPeriod( genesis *shelley.ShelleyGenesis, now time.Time, ) error
ValidateKESPeriod checks that the loaded operational certificate's KES period is plausible at wall-clock time `now`, given the chain's Shelley genesis. A non-nil result means the node should refuse to start: either the opcert claims a period that hasn't started yet (rotated key staged too early, or wrong network) or the opcert has expired and needs to be rotated.
The protocol-level expiry uses MaxKESEvolutions from genesis rather than the raw 2^depth ceiling, so this matches the chain's view of when an opcert stops being valid.
func (*PoolCredentials) ValidateOpCert ¶
func (pc *PoolCredentials) ValidateOpCert() error
ValidateOpCert validates that the operational certificate matches the KES key and that the cold key signature over the certificate body is valid.
type ProtocolParamsProvider ¶
type ProtocolParamsProvider interface {
GetCurrentPParams() lcommon.ProtocolParameters
// ProtocolParamsForSlot returns the pparams that should govern a
// block forged at the given slot. When the slot is in an epoch
// beyond a scheduled fork that has not yet been applied to the
// in-memory ledger state, the returned pparams are the
// post-fork pparams. The forger uses this to produce
// era-correct blocks at fork boundaries.
ProtocolParamsForSlot(slot uint64) lcommon.ProtocolParameters
}
ProtocolParamsProvider provides access to protocol parameters.
type SlotBattleEvent ¶
type SlotBattleEvent struct {
// Slot is the slot number where the battle occurred
Slot uint64
// LocalBlockHash is the hash of our locally forged block (if any)
LocalBlockHash []byte
// RemoteBlockHash is the hash of the competing block from peers
RemoteBlockHash []byte
// Won indicates whether our local block was selected for the chain
Won bool
}
SlotBattleEvent is emitted when the node detects competing blocks for the same slot, either from receiving an external block while preparing to forge or when detecting a fork at the same slot height.
type SlotClockProvider ¶
type SlotClockProvider interface {
// CurrentSlot returns the current slot number based on wall-clock time.
CurrentSlot() (uint64, error)
// SlotsPerKESPeriod returns the number of slots in a KES period.
SlotsPerKESPeriod() uint64
// ChainTipSlot returns the slot number of the current chain tip.
ChainTipSlot() uint64
// NextSlotTime returns the wall-clock time when the next slot begins.
NextSlotTime() (time.Time, error)
// UpstreamTipSlot returns the latest known tip slot from upstream peers.
// Returns 0 if no upstream tip is known.
UpstreamTipSlot() uint64
}
SlotClockProvider provides current slot information from the slot clock.
type SlotTracker ¶
type SlotTracker struct {
// contains filtered or unexported fields
}
SlotTracker is a thread-safe tracker for recently forged block slots and their hashes. It allows chainsync to detect slot battles when an incoming block from a peer occupies a slot for which the local node has already forged a block.
func NewSlotTracker ¶
func NewSlotTracker() *SlotTracker
NewSlotTracker creates a new SlotTracker with the default capacity.
func NewSlotTrackerWithCapacity ¶
func NewSlotTrackerWithCapacity(maxSlots int) *SlotTracker
NewSlotTrackerWithCapacity creates a new SlotTracker with the given maximum capacity.
func (*SlotTracker) Len ¶
func (st *SlotTracker) Len() int
Len returns the number of tracked forged slots.
func (*SlotTracker) RecordForgedBlock ¶
func (st *SlotTracker) RecordForgedBlock(slot uint64, blockHash []byte)
RecordForgedBlock records that the local node forged a block with the given hash at the given slot. If the tracker is at capacity, the oldest entry is evicted.
func (*SlotTracker) WasForgedByUs ¶
func (st *SlotTracker) WasForgedByUs( slot uint64, ) (blockHash []byte, ok bool)
WasForgedByUs checks whether the local node forged a block for the given slot. If so, it returns the block hash and true. Otherwise it returns nil, false.
type TxValidator ¶
type TxValidator interface {
ValidateTx(tx ledger.Transaction) error
}
TxValidator re-validates a transaction against the current ledger state at block assembly time. This catches transactions whose inputs have been consumed since they entered the mempool, protocol parameter changes, or other state mutations that invalidate previously-accepted transactions.