diff --git a/ledger/state.go b/ledger/state.go index ad42f07a..9b46b3a9 100644 --- a/ledger/state.go +++ b/ledger/state.go @@ -32,7 +32,9 @@ import ( ouroboros "github.com/blinklabs-io/gouroboros" "github.com/blinklabs-io/gouroboros/cbor" "github.com/blinklabs-io/gouroboros/ledger" + "github.com/blinklabs-io/gouroboros/ledger/babbage" lcommon "github.com/blinklabs-io/gouroboros/ledger/common" + "github.com/blinklabs-io/gouroboros/ledger/conway" ochainsync "github.com/blinklabs-io/gouroboros/protocol/chainsync" ocommon "github.com/blinklabs-io/gouroboros/protocol/common" "github.com/prometheus/client_golang/prometheus" @@ -61,6 +63,7 @@ type LedgerStateConfig struct { CardanoNodeConfig *cardano.CardanoNodeConfig PromRegistry prometheus.Registerer ValidateHistorical bool + ForgeBlocks bool // Callback(s) BlockfetchRequestRangeFunc BlockfetchRequestRangeFunc } @@ -152,6 +155,28 @@ func (ls *LedgerState) Start() error { interval := time.Duration(durationNs) ls.Scheduler = NewScheduler(interval) ls.Scheduler.Start() + + // Schedule block forging if dev mode is enabled + if ls.config.ForgeBlocks { + // Calculate block interval from ActiveSlotsCoeff + shelleyGenesis := ls.config.CardanoNodeConfig.ShelleyGenesis() + if shelleyGenesis != nil { + // Calculate block interval (1 / ActiveSlotsCoeff) + activeSlotsCoeff := shelleyGenesis.ActiveSlotsCoeff + if activeSlotsCoeff.Rat != nil && activeSlotsCoeff.Rat.Num().Int64() > 0 { + blockInterval := int((1 * activeSlotsCoeff.Rat.Denom().Int64()) / activeSlotsCoeff.Rat.Num().Int64()) + // Scheduled forgeBlock to run at the calculated block interval + ls.Scheduler.Register(blockInterval, ls.forgeBlock) + + ls.config.Logger.Info( + "dev mode block forging enabled", + "component", "ledger", + "block_interval", blockInterval, + "active_slots_coeff", activeSlotsCoeff.String(), + ) + } + } + } } // Start goroutine to process new blocks go ls.ledgerProcessBlocks() @@ -917,3 +942,76 @@ func (ls *LedgerState) ValidateTx( } return nil } + +// forgeBlock creates an empty conway block and logs its CBOR representation +func (ls *LedgerState) forgeBlock() { + // Get current chain tip + currentTip := ls.chain.Tip() + + // Calculate next slot and block number + nextSlot, err := ls.TimeToSlot(time.Now()) + if err != nil { + ls.config.Logger.Error( + "failed to calculate slot from current time", + "component", "ledger", + "error", err, + ) + return + } + nextBlockNumber := currentTip.BlockNumber + 1 + + // Create empty Babbage block header body + headerBody := babbage.BabbageBlockHeaderBody{ + BlockNumber: nextBlockNumber, + Slot: nextSlot, + PrevHash: lcommon.NewBlake2b256(currentTip.Point.Hash), + IssuerVkey: lcommon.IssuerVkey{}, + VrfKey: []byte{}, + VrfResult: lcommon.VrfResult{}, + BlockBodySize: 0, + BlockBodyHash: lcommon.Blake2b256{}, + OpCert: babbage.BabbageOpCert{}, + ProtoVersion: babbage.BabbageProtoVersion{ + Major: 2, + Minor: 0, + }, + } + + // Create Conway block header + conwayHeader := &conway.ConwayBlockHeader{ + BabbageBlockHeader: babbage.BabbageBlockHeader{ + Body: headerBody, + Signature: []byte{}, + }, + } + + // Create a conway block + conwayBlock := &conway.ConwayBlock{ + BlockHeader: conwayHeader, + TransactionBodies: []conway.ConwayTransactionBody{}, + TransactionWitnessSets: []conway.ConwayTransactionWitnessSet{}, + TransactionMetadataSet: map[uint]*cbor.LazyValue{}, + InvalidTransactions: []uint{}, + } + + // Marshal the conway block to CBOR + blockCbor, err := cbor.Encode(conwayBlock) + if err != nil { + ls.config.Logger.Error( + "failed to marshal forged conway block to CBOR", + "component", "ledger", + "error", err, + ) + return + } + + // Log the generated block CBOR (DEBUG level) + ls.config.Logger.Debug( + "forged empty conway block", + "component", "ledger", + "slot", nextSlot, + "block_number", nextBlockNumber, + "prev_hash", hex.EncodeToString(currentTip.Point.Hash), + "block_cbor", hex.EncodeToString(blockCbor), + ) +} diff --git a/node.go b/node.go index 280bd9e2..27d7711a 100644 --- a/node.go +++ b/node.go @@ -123,6 +123,7 @@ func (n *Node) Run() error { Logger: n.config.logger, CardanoNodeConfig: n.config.cardanoNodeConfig, PromRegistry: n.config.promRegistry, + ForgeBlocks: n.config.devMode, BlockfetchRequestRangeFunc: n.blockfetchClientRequestRange, }, )