Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
1654323
genesis implementation poc
randygrok Mar 19, 2025
c095c58
use genesis interface
randygrok Mar 19, 2025
64d7ce7
temp commit
randygrok Mar 19, 2025
9f54416
more changes
randygrok Mar 19, 2025
cb8451b
make tests pass
randygrok Mar 19, 2025
6ac0053
fix lint
randygrok Mar 20, 2025
973c3ad
Merge remote-tracking branch 'origin/feature/exec_api' into feat/gene…
randygrok Mar 20, 2025
a6e16b7
Merge branch 'feature/exec_api' into feat/genesis-clean
randygrok Mar 20, 2025
1fcd875
temp commit
randygrok Mar 24, 2025
95cfadd
fix tests
randygrok Mar 24, 2025
54db65e
rename fields in config
randygrok Mar 24, 2025
cc57479
add ExtraData
randygrok Mar 24, 2025
00c4281
genesis load
randygrok Mar 24, 2025
2f4a20d
move genesis file to pkg
randygrok Mar 24, 2025
6667115
load genesis file
randygrok Mar 24, 2025
4038f62
add io test
randygrok Mar 24, 2025
8175afd
update block manager cmd
randygrok Mar 24, 2025
795bcd3
add message into execution core
randygrok Mar 24, 2025
af5ee7b
remove go.sum
randygrok Mar 24, 2025
e874a21
Merge remote-tracking branch 'origin/feature/exec_api' into feat/gene…
randygrok Mar 24, 2025
d561021
Fix lint problems
randygrok Mar 24, 2025
55c543e
use default genesis
randygrok Mar 24, 2025
66d60b3
clean markdown lint
randygrok Mar 24, 2025
dc510ad
bring back creation of genesis
randygrok Mar 24, 2025
3e5476e
revert
randygrok Mar 24, 2025
d342066
fix markdown lint
randygrok Mar 24, 2025
96afdf6
fix errors with markdown
randygrok Mar 24, 2025
a9ddcd4
fix markdown lint
randygrok Mar 24, 2025
8acbfb4
review changes
randygrok Mar 24, 2025
dd18f2d
remove commented code
randygrok Mar 24, 2025
4f1d4f2
fix md
randygrok Mar 24, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
fix lint
  • Loading branch information
randygrok committed Mar 20, 2025
commit 6ac0053ec0f95cbf383ad6f32f6774978455c3c1
2 changes: 1 addition & 1 deletion block/block-manager.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ The block manager is initialized using several parameters as defined below:
|-----|-----|-----|
signing key|crypto.PrivKey|used for signing a block after it is created
config|config.BlockManagerConfig|block manager configurations (see config options below)
genesis|*cmtypes.GenesisDoc|initialize the block manager with genesis state (genesis configuration defined in `config/genesis.json` file under the app directory)
genesis|coreexecutor.Genesis|initialize the block manager with genesis state (genesis configuration defined in `config/genesis.json` file under the app directory)
store|store.Store|local datastore for storing rollup blocks and states (default local store path is `$db_dir/rollkit` and `db_dir` specified in the `config.yaml` file under the app directory)
mempool, proxyapp, eventbus|mempool.Mempool, proxy.AppConnConsensus, *cmtypes.EventBus|for initializing the executor (state transition function). mempool is also used in the manager to check for availability of transactions for lazy block production
dalc|da.DAClient|the data availability light client used to submit and retrieve blocks to DA network
Expand Down
2 changes: 1 addition & 1 deletion block/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ type Manager struct {
bq *BatchQueue
}

// getInitialState tries to load lastState from Store, and if it's not available it reads GenesisDoc.
// getInitialState tries to load lastState from Store, and if it's not available it reads genesis.
func getInitialState(ctx context.Context, genesis coreexecutor.Genesis, store store.Store, exec coreexecutor.Executor, logger log.Logger) (types.State, error) {
// Load the state from store.
s, err := store.GetState(ctx)
Expand Down
40 changes: 2 additions & 38 deletions block/manager_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,8 @@ func TestInitialStateClean(t *testing.T) {
s, err := getInitialState(context.TODO(), genesisData, emptyStore, coreexecutor.NewDummyExecutor(), logger)
require.NoError(err)
initialHeight := genesisData.InitialHeight()
require.Equal(uint64(initialHeight-1), s.LastBlockHeight)
require.Equal(uint64(initialHeight), s.InitialHeight)
require.Equal(initialHeight-1, s.LastBlockHeight)
require.Equal(initialHeight, s.InitialHeight)
}

func TestInitialStateStored(t *testing.T) {
Expand Down Expand Up @@ -397,42 +397,6 @@ func Test_isProposer(t *testing.T) {
isProposer: true,
err: nil,
},
//{
// name: "Signing key does not match genesis proposer public key",
// args: func() args {
// genesisData, _ := types.GetGenesisWithPrivkey(types.DefaultSigningKeyType, "Test_isProposer")
// s, err := types.NewFromGenesisDoc(genesisData)
// require.NoError(err)

// randomPrivKey := ed25519.GenPrivKey()
// signingKey, err := types.PrivKeyToSigningKey(randomPrivKey)
// require.NoError(err)
// return args{
// s,
// signingKey,
// }
// }(),
// isProposer: false,
// err: nil,
//},
//{
// name: "No validators found in genesis",
// args: func() args {
// genesisData, privKey := types.GetGenesisWithPrivkey(types.DefaultSigningKeyType, "Test_isProposer")
// genesisData.Validators = nil
// s, err := types.NewFromGenesisDoc(genesisData)
// require.NoError(err)

// signingKey, err := types.PrivKeyToSigningKey(privKey)
// require.NoError(err)
// return args{
// s,
// signingKey,
// }
// }(),
// isProposer: false,
// err: ErrNoValidatorsInState,
//},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
Expand Down
4 changes: 2 additions & 2 deletions block/sync_service.go
Original file line number Diff line number Diff line change
Expand Up @@ -134,8 +134,8 @@ func (syncService *SyncService[H]) initStoreAndStartSyncer(ctx context.Context,
// WriteToStoreAndBroadcast initializes store if needed and broadcasts provided header or block.
// Note: Only returns an error in case store can't be initialized. Logs error if there's one while broadcasting.
func (syncService *SyncService[H]) WriteToStoreAndBroadcast(ctx context.Context, headerOrData H) error {
if syncService.genesis.InitialHeight() < 0 {
return fmt.Errorf("invalid initial height; cannot be negative")
if syncService.genesis.InitialHeight() == 0 {
return fmt.Errorf("invalid initial height; cannot be zero")
}
isGenesis := headerOrData.Height() == syncService.genesis.InitialHeight()
// For genesis header/block initialize the store and start the syncer
Expand Down
67 changes: 20 additions & 47 deletions cmd/rollkit/commands/run_node.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import (
"context"
"errors"
"fmt"
"math/rand"
"net"
"net/http"
"os"
Expand All @@ -15,7 +14,6 @@ import (

"cosmossdk.io/log"
cometprivval "github.com/cometbft/cometbft/privval"
comettypes "github.com/cometbft/cometbft/types"
"github.com/libp2p/go-libp2p/core/crypto"
"github.com/rs/zerolog"
"github.com/spf13/cobra"
Expand Down Expand Up @@ -61,10 +59,13 @@ func NewRunNodeCmd() *cobra.Command {
return initFiles()
},
RunE: func(cmd *cobra.Command, args []string) error {
genDocProvider := RollkitGenesisDocProviderFunc(nodeConfig)
genDoc, err := genDocProvider()
ctx, cancel := context.WithCancel(cmd.Context())
defer cancel() // Ensure context is cancelled when command exits

kvExecutor := createDirectKVExecutor(ctx)
genesis, err := kvExecutor.BuildGenesis(nodeConfig)
if err != nil {
return err
return fmt.Errorf("failed to build genesis: %w", err)
}

// TODO: this should be moved elsewhere
Expand All @@ -81,10 +82,11 @@ func NewRunNodeCmd() *cobra.Command {
metrics := node.DefaultMetricsProvider(rollconf.DefaultInstrumentationConfig())

// Determine which rollupID to use. If the flag has been set we want to use that value and ensure that the chainID in the genesis doc matches.
if cmd.Flags().Lookup(rollconf.FlagSequencerRollupID).Changed {
genDoc.ChainID = nodeConfig.Node.SequencerRollupID
}
sequencerRollupID := genDoc.ChainID
//if cmd.Flags().Lookup(rollconf.FlagSequencerRollupID).Changed {
Comment thread
randygrok marked this conversation as resolved.
Resolved
// genDoc.ChainID = nodeConfig.Node.SequencerRollupID
//}

sequencerRollupID := nodeConfig.Node.SequencerRollupID
// Try and launch a mock gRPC sequencer if there is no sequencer running.
// Only start mock Sequencer if the user did not provide --rollkit.sequencer_address
var seqSrv *grpc.Server = nil
Expand All @@ -104,17 +106,8 @@ func NewRunNodeCmd() *cobra.Command {
logger.Info("Executor address", "address", nodeConfig.Node.ExecutorAddress)

// Create a cancellable context for the node
ctx, cancel := context.WithCancel(cmd.Context())
defer cancel() // Ensure context is cancelled when command exits

kvExecutor := createDirectKVExecutor(ctx)
dummySequencer := coresequencer.NewDummySequencer()

genesis, err := kvExecutor.BuildGenesis(nodeConfig)
if err != nil {
return fmt.Errorf("failed to build genesis: %w", err)
}

dummyDA := coreda.NewDummyDA(100_000)
dummyDALC := da.NewDAClient(dummyDA, nodeConfig.DA.GasPrice, nodeConfig.DA.GasMultiplier, []byte(nodeConfig.DA.Namespace), []byte(nodeConfig.DA.SubmitOptions), logger)
// create the rollkit node
Expand Down Expand Up @@ -316,13 +309,11 @@ func initFiles() error {
// Generate the private validator config files
cometprivvalKeyFile := filepath.Join(configDir, "priv_validator_key.json")
cometprivvalStateFile := filepath.Join(dataDir, "priv_validator_state.json")
var pv *cometprivval.FilePV
if rollos.FileExists(cometprivvalKeyFile) {
pv = cometprivval.LoadFilePV(cometprivvalKeyFile, cometprivvalStateFile)
logger.Info("Found private validator", "keyFile", cometprivvalKeyFile,
"stateFile", cometprivvalStateFile)
} else {
pv = cometprivval.GenFilePV(cometprivvalKeyFile, cometprivvalStateFile)
pv := cometprivval.GenFilePV(cometprivvalKeyFile, cometprivvalStateFile)
pv.Save()
logger.Info("Generated private validator", "keyFile", cometprivvalKeyFile,
"stateFile", cometprivvalStateFile)
Expand All @@ -333,24 +324,16 @@ func initFiles() error {
if rollos.FileExists(genFile) {
logger.Info("Found genesis file", "path", genFile)
} else {
genDoc := comettypes.GenesisDoc{
ChainID: fmt.Sprintf("test-rollup-%08x", rand.Uint32()), //nolint:gosec
GenesisTime: time.Now().Round(0).UTC(),
ConsensusParams: comettypes.DefaultConsensusParams(),
}
pubKey, err := pv.GetPubKey()
// Create a KVExecutor to generate genesis
kvExecutor := testExecutor.NewKVExecutor()
genesis, err := kvExecutor.BuildGenesis(nodeConfig)
if err != nil {
return fmt.Errorf("can't get pubkey: %w", err)
return fmt.Errorf("failed to build genesis: %w", err)
}
genDoc.Validators = []comettypes.GenesisValidator{{
Address: pubKey.Address(),
PubKey: pubKey,
Power: 1000,
Name: "Rollkit Sequencer",
}}

if err := genDoc.SaveAs(genFile); err != nil {
return err

// Write genesis bytes directly to file
if err := os.WriteFile(genFile, genesis.Bytes(), 0600); err != nil {
return fmt.Errorf("failed to write genesis file: %w", err)
}
logger.Info("Generated genesis file", "path", genFile)
}
Expand Down Expand Up @@ -420,13 +403,3 @@ func setupLogger(config rollconf.Config) log.Logger {
// Add module to logger
return configuredLogger.With("module", "main")
}

// RollkitGenesisDocProviderFunc returns a function that loads the GenesisDoc from the filesystem
// using nodeConfig instead of config.
func RollkitGenesisDocProviderFunc(nodeConfig rollconf.Config) func() (*comettypes.GenesisDoc, error) {
return func() (*comettypes.GenesisDoc, error) {
// Construct the genesis file path using rootify
genFile := filepath.Join(nodeConfig.RootDir, nodeConfig.ConfigDir, "genesis.json")
return comettypes.GenesisDocFromFile(genFile)
}
}
55 changes: 0 additions & 55 deletions cmd/rollkit/commands/run_node_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -301,61 +301,6 @@ func TestStartMockSequencerServer(t *testing.T) {
}
}

func TestRollkitGenesisDocProviderFunc(t *testing.T) {
// Create a temporary directory for the test
tempDir, err := os.MkdirTemp("", "rollkit-test")
assert.NoError(t, err)
defer func() {
err := os.RemoveAll(tempDir)
assert.NoError(t, err)
}()

// Create the config directory
configDir := filepath.Join(tempDir, "config")
err = os.MkdirAll(configDir, rollconf.DefaultDirPerm)
assert.NoError(t, err)

// Create a simple test genesis file
testChainID := "test-chain-id"
genFileContent := fmt.Sprintf(`{
"chain_id": "%s",
"genesis_time": "2023-01-01T00:00:00Z",
"consensus_params": {
"block": {
"max_bytes": "22020096",
"max_gas": "-1"
},
"evidence": {
"max_age_num_blocks": "100000",
"max_age_duration": "172800000000000"
},
"validator": {
"pub_key_types": ["ed25519"]
}
}
}`, testChainID)

genFile := filepath.Join(configDir, "genesis.json")
err = os.WriteFile(genFile, []byte(genFileContent), 0600)
assert.NoError(t, err)

// Create a test node config
testNodeConfig := rollconf.Config{
RootDir: tempDir,
ConfigDir: "config",
}

// Get the genesis doc provider function
genDocProvider := RollkitGenesisDocProviderFunc(testNodeConfig)
assert.NotNil(t, genDocProvider)

// Call the provider function and verify the result
loadedGenDoc, err := genDocProvider()
assert.NoError(t, err)
assert.NotNil(t, loadedGenDoc)
assert.Equal(t, testChainID, loadedGenDoc.ChainID)
}

func TestInitFiles(t *testing.T) {
// Save the original nodeConfig
origNodeConfig := nodeConfig
Expand Down
2 changes: 1 addition & 1 deletion node/full_node.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ Note that unlike a light node which only syncs and stores block headers seen on

The Full Node mainly encapsulates and initializes/manages the following components:

### genesisDoc
### genesis

The [genesis] document contains information about the initial state of the rollup chain, in particular its validator set.

Expand Down
2 changes: 1 addition & 1 deletion node/full_node_integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -359,7 +359,7 @@ func (s *FullNodeTestSuite) TestGenesisInitialization() {

// Verify genesis state
state := s.node.blockManager.GetLastState()
require.Equal(uint64(s.node.genesis.InitialHeight()), state.InitialHeight)
require.Equal(s.node.genesis.InitialHeight(), state.InitialHeight)
require.Equal(s.node.genesis.ChainID(), state.ChainID)
}

Expand Down
18 changes: 17 additions & 1 deletion test/executors/kv/kvexecutor.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,23 @@ func (k *KVExecutor) computeStateRoot() []byte {

// BuildGenesis implements execution.Executor.
func (k *KVExecutor) BuildGenesis(config config.Config) (execution.Genesis, error) {
panic("unimplemented")
k.mu.Lock()
defer k.mu.Unlock()

// Compute initial state root from current store
stateRoot := k.computeStateRoot()

// Create a new genesis with a random chain ID if not provided
chainID := fmt.Sprintf("test-chain-%d", time.Now().UnixNano())

// Create genesis with initial height 1
return execution.NewBaseGenesis(
chainID,
1, // Initial height
time.Now().UTC(),
nil, // No proposer address for testing
stateRoot,
), nil
}

// InitChain initializes the chain state with genesis parameters.
Expand Down
5 changes: 3 additions & 2 deletions types/state.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
cmversion "github.com/cometbft/cometbft/proto/tendermint/version"
"github.com/cometbft/cometbft/types"
"github.com/cometbft/cometbft/version"

coreexecutor "github.com/rollkit/rollkit/core/execution"
)

Expand Down Expand Up @@ -76,7 +77,7 @@ func NewFromGenesisDoc(genDoc coreexecutor.Genesis) (State, error) {

DAHeight: 1,

LastBlockHeight: uint64(genDoc.InitialHeight()) - 1,
LastBlockHeight: genDoc.InitialHeight() - 1,
LastBlockID: types.BlockID{},
LastBlockTime: genDoc.GenesisTime(),

Expand All @@ -85,7 +86,7 @@ func NewFromGenesisDoc(genDoc coreexecutor.Genesis) (State, error) {
LastValidators: validatorSet,
LastHeightValidatorsChanged: int64(genDoc.InitialHeight()),

LastHeightConsensusParamsChanged: uint64(genDoc.InitialHeight()),
LastHeightConsensusParamsChanged: genDoc.InitialHeight(),
}

s.AppHash = genDoc.Bytes()
Expand Down
36 changes: 2 additions & 34 deletions types/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -272,44 +272,12 @@ func GetFirstSignedHeader(privkey cmEd25519.PrivKey, valSet *cmtypes.ValidatorSe
return &signedHeader, nil
}

// GetValidatorSetFromGenesis returns a ValidatorSet from a GenesisDoc, for usage with the centralized sequencer scheme.
func GetValidatorSetFromGenesis(g *cmtypes.GenesisDoc) cmtypes.ValidatorSet {
vals := []*cmtypes.Validator{
{
Address: g.Validators[0].Address,
PubKey: g.Validators[0].PubKey,
VotingPower: int64(1),
ProposerPriority: int64(1),
},
}
return cmtypes.ValidatorSet{
Validators: vals,
Proposer: vals[0],
}
}

// GetGenesisWithPrivkey returns a genesis doc with a single validator and a signing key
func GetGenesisWithPrivkey(chainID string) (coreexecutor.Genesis, crypto.PrivKey, cmEd25519.PubKey) {
// Generate Ed25519 key pair using CometBFT
cmtPrivKey := cmEd25519.GenPrivKey()
cmtPubKey := cmtPrivKey.PubKey().(cmEd25519.PubKey)

// Create genesis validator with CometBFT public key
genesisValidators := []cmtypes.GenesisValidator{{
Address: cmtPubKey.Address(),
PubKey: cmtPubKey,
Power: int64(1),
Name: "sequencer",
}}

// Create genesis document
genDoc := &cmtypes.GenesisDoc{
ChainID: chainID,
InitialHeight: 1,
Validators: genesisValidators,
GenesisTime: time.Now(),
}

// Convert CometBFT private key to libp2p format
privKeyBytes := cmtPrivKey.Bytes()
libp2pPrivKey, err := crypto.UnmarshalEd25519PrivateKey(privKeyBytes)
Expand All @@ -320,8 +288,8 @@ func GetGenesisWithPrivkey(chainID string) (coreexecutor.Genesis, crypto.PrivKey
// Create base genesis with validator's address
return coreexecutor.NewBaseGenesis(
chainID,
uint64(genDoc.InitialHeight),
genDoc.GenesisTime,
uint64(1),
time.Now(),
cmtPubKey.Address().Bytes(),
nil, // No raw bytes for now
), libp2pPrivKey, cmtPubKey
Expand Down