Skip to content

Commit

Permalink
feat!: passing operartor address to the RDK (#606)
Browse files Browse the repository at this point in the history
Co-authored-by: Daniel T <[email protected]>
  • Loading branch information
mtsitrin and danwt authored Mar 21, 2024
1 parent 8cd1a10 commit 74e7a92
Show file tree
Hide file tree
Showing 18 changed files with 332 additions and 112 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ on:
tags:
- v*
branches:
- main
- "main"
pull_request:

jobs:
Expand All @@ -18,7 +18,7 @@ jobs:
- uses: actions/checkout@v4
- uses: actions/setup-go@v4
with:
go-version: '1.20.5'
go-version: 1.22.1
- run: git config --global url.https://[email protected]/.insteadOf https://github.com/
- name: golangci-lint
uses: golangci/[email protected]
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ on:
tags:
- v*
branches:
- main
- "main"
pull_request:
jobs:

jobs:
build:
runs-on: ubuntu-latest
env:
Expand All @@ -19,7 +19,7 @@ jobs:
- name: Set up Go
uses: actions/setup-go@v4
with:
go-version: 1.20.5
go-version: 1.22.1
- run: git config --global url.https://[email protected]/.insteadOf https://github.com/

- name: Build
Expand Down
99 changes: 99 additions & 0 deletions block/initchain.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
package block

import (
"context"
"os"

"github.com/cosmos/cosmos-sdk/codec"

codectypes "github.com/cosmos/cosmos-sdk/codec/types"
cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec"
"github.com/cosmos/cosmos-sdk/crypto/keyring"
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
"github.com/evmos/evmos/v12/crypto/hd"
"github.com/ignite/cli/ignite/pkg/cosmosaccount"
tmtypes "github.com/tendermint/tendermint/types"
)

func (m *Manager) RunInitChain(ctx context.Context) error {

// We pass an initial val set which is actually the consensus and operator addresses of the proposer.
// This is a hack to make sure the chain can get both addresses without us needing to change comet signatures:
// The RDK will save a sequencer, and delete the extra validator after initChain, so we also delete it here
// to keep the state in sync.

//get the proposer's consensus pubkey
proposer := m.settlementClient.GetProposer()
tmPubKey, err := cryptocodec.ToTmPubKeyInterface(proposer.PublicKey)
if err != nil {
return err
}
consensusPubkey := tmtypes.NewValidator(tmPubKey, 1)

//get the operator's pubkey
pubkey, err := getOperatorPubkey(m.conf.OperatorKeyringHomeDir, m.conf.OperatorKeyringBackend, m.conf.OperatorAccountName)
if err != nil {
return err
}
tmPubKey, err = cryptocodec.ToTmPubKeyInterface(pubkey)
if err != nil {
return err
}
operatorPubkey := tmtypes.NewValidator(tmPubKey, 1)

//call initChain with both addresses
res, err := m.executor.InitChain(m.genesis, []*tmtypes.Validator{consensusPubkey, operatorPubkey})
if err != nil {
return err
}

//update the state with only the consensus pubkey
m.executor.UpdateStateAfterInitChain(&m.lastState, res, []*tmtypes.Validator{consensusPubkey})
if _, err := m.store.UpdateState(m.lastState, nil); err != nil {
return err
}

return nil
}

func getOperatorPubkey(keyDir, keyringBackend, accountName string) (cryptotypes.PubKey, error) {
// open keyring
c, err := cosmosaccount.New(
cosmosaccount.WithKeyringBackend(cosmosaccount.KeyringBackend(keyringBackend)),
cosmosaccount.WithHome(keyDir),
)
if err != nil {
return nil, err
}

interfaceRegistry := codectypes.NewInterfaceRegistry()
cryptocodec.RegisterInterfaces(interfaceRegistry)
cdc := codec.NewProtoCodec(interfaceRegistry)

customKeyring, err := keyring.New("operatorAddr", keyringBackend, keyDir, os.Stdin, cdc, hd.EthSecp256k1Option())
if err != nil {
return nil, err
}
c.Keyring = customKeyring

// If the keyring is in memory, ensure the default account exists to be used in tests
if keyringBackend == "memory" {
err := c.EnsureDefaultAccount()
if err != nil {
return nil, err
}
}

// Get account from the keyring
account, err := c.GetByName(accountName)
if err != nil {
return nil, err
}

pubkey, err := account.Record.GetPubKey()
if err != nil {
return nil, err
}

return pubkey, nil
}
100 changes: 19 additions & 81 deletions block/manager.go
Original file line number Diff line number Diff line change
@@ -1,23 +1,23 @@
package block

import (
"bytes"
"context"
"fmt"
"sync"
"sync/atomic"
"time"

// Importing the general purpose Cosmos blockchain client

"code.cloudfoundry.org/go-diodes"

"github.com/avast/retry-go/v4"
cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec"
"github.com/dymensionxyz/dymint/node/events"
"github.com/dymensionxyz/dymint/p2p"
"github.com/dymensionxyz/dymint/utils"
"github.com/libp2p/go-libp2p/core/crypto"
abci "github.com/tendermint/tendermint/abci/types"
tmcrypto "github.com/tendermint/tendermint/crypto"
"github.com/tendermint/tendermint/crypto/merkle"
"github.com/tendermint/tendermint/libs/pubsub"
tmtypes "github.com/tendermint/tendermint/types"

Expand Down Expand Up @@ -128,29 +128,6 @@ func NewManager(
return nil, fmt.Errorf("failed to get initial state: %w", err)
}

validators := []*tmtypes.Validator{}

if s.LastBlockHeight+1 == genesis.InitialHeight {
sequencersList := settlementClient.GetSequencersList()
for _, sequencer := range sequencersList {
tmPubKey, err := cryptocodec.ToTmPubKeyInterface(sequencer.PublicKey)
if err != nil {
return nil, err
}
validators = append(validators, tmtypes.NewValidator(tmPubKey, 1))
}

res, err := exec.InitChain(genesis, validators)
if err != nil {
return nil, err
}

updateInitChainState(&s, res, validators)
if _, err := store.UpdateState(s, nil); err != nil {
return nil, err
}
}

batchInProcess := atomic.Value{}
batchInProcess.Store(false)

Expand Down Expand Up @@ -192,12 +169,25 @@ func (m *Manager) Start(ctx context.Context, isAggregator bool) error {
}

if isAggregator {
//make sure local signing key is the registered on the hub
slProposerKey := m.settlementClient.GetProposer().PublicKey.Bytes()
localProposerKey, _ := m.proposerKey.GetPublic().Raw()
if !bytes.Equal(slProposerKey, localProposerKey) {
return fmt.Errorf("proposer key mismatch: settlement proposer key: %s, block manager proposer key: %s", slProposerKey, m.proposerKey.GetPublic())
}
m.logger.Info("Starting in aggregator mode")
// TODO(omritoptix): change to private methods

// Check if InitChain flow is needed
if m.lastState.LastBlockHeight+1 == m.genesis.InitialHeight {
err := m.RunInitChain(ctx)
if err != nil {
return err
}
}

go m.ProduceBlockLoop(ctx)
go m.SubmitLoop(ctx)
} else {
// TODO(omritoptix): change to private methods
go m.RetriveLoop(ctx)
go m.SyncTargetLoop(ctx)
}
Expand Down Expand Up @@ -234,7 +224,7 @@ func (m *Manager) syncBlockManager(ctx context.Context) error {

// updateSyncParams updates the sync target and state index if necessary
func (m *Manager) updateSyncParams(endHeight uint64) {
rollappHubHeightGauge.Set(float64(endHeight))
types.RollappHubHeightGauge.Set(float64(endHeight))
m.logger.Info("Received new syncTarget", "syncTarget", endHeight)
atomic.StoreUint64(&m.syncTarget, endHeight)
atomic.StoreInt64(&m.lastSubmissionTime, time.Now().UnixNano())
Expand Down Expand Up @@ -287,13 +277,6 @@ func (m *Manager) applyBlockCallback(event pubsub.Message) {
}
}

// SetDALC is used to set DataAvailabilityLayerClient used by Manager.
// TODO(omritoptix): Remove this from here as it's only being used for tests.
func (m *Manager) SetDALC(dalc da.DataAvailabilityLayerClient) {
m.dalc = dalc
m.retriever = dalc.(da.BatchRetriever)
}

// getLatestBatchFromSL gets the latest batch from the SL
func (m *Manager) getLatestBatchFromSL(ctx context.Context) (*settlement.ResultRetrieveBatch, error) {
var resultRetrieveBatch *settlement.ResultRetrieveBatch
Expand All @@ -315,49 +298,4 @@ func (m *Manager) getLatestBatchFromSL(ctx context.Context) (*settlement.ResultR
return resultRetrieveBatch, err
}
return resultRetrieveBatch, nil

}

// TODO(omritoptix): possible remove this method from the manager
func updateInitChainState(s *types.State, res *abci.ResponseInitChain, validators []*tmtypes.Validator) {
// If the app did not return an app hash, we keep the one set from the genesis doc in
// the state. We don't set appHash since we don't want the genesis doc app hash
// recorded in the genesis block. We should probably just remove GenesisDoc.AppHash.
if len(res.AppHash) > 0 {
copy(s.AppHash[:], res.AppHash)
}

//The validators after initChain must be greater than zero, otherwise this state is not loadable
if len(validators) <= 0 {
panic("Validators must be greater than zero")
}

if res.ConsensusParams != nil {
params := res.ConsensusParams
if params.Block != nil {
s.ConsensusParams.Block.MaxBytes = params.Block.MaxBytes
s.ConsensusParams.Block.MaxGas = params.Block.MaxGas
}
if params.Evidence != nil {
s.ConsensusParams.Evidence.MaxAgeNumBlocks = params.Evidence.MaxAgeNumBlocks
s.ConsensusParams.Evidence.MaxAgeDuration = params.Evidence.MaxAgeDuration
s.ConsensusParams.Evidence.MaxBytes = params.Evidence.MaxBytes
}
if params.Validator != nil {
// Copy params.Validator.PubkeyTypes, and set result's value to the copy.
// This avoids having to initialize the slice to 0 values, and then write to it again.
s.ConsensusParams.Validator.PubKeyTypes = append([]string{}, params.Validator.PubKeyTypes...)
}
if params.Version != nil {
s.ConsensusParams.Version.AppVersion = params.Version.AppVersion
}
s.Version.Consensus.App = s.ConsensusParams.Version.AppVersion
}
// We update the last results hash with the empty hash, to conform with RFC-6962.
copy(s.LastResultsHash[:], merkle.HashFromByteSlices(nil))

// Set the validators in the state
s.Validators = tmtypes.NewValidatorSet(validators).CopyIncrementProposerPriority(1)
s.NextValidators = s.Validators.Copy()
s.LastValidators = s.Validators.Copy()
}
11 changes: 4 additions & 7 deletions block/produce.go
Original file line number Diff line number Diff line change
Expand Up @@ -120,10 +120,7 @@ func (m *Manager) produceBlock(ctx context.Context, allowEmpty bool) error {
if err != nil {
return err
}
proposerAddress, err := getAddress(m.proposerKey)
if err != nil {
return err
}
proposerAddress := block.Header.ProposerAddress
sign, err := m.proposerKey.Sign(abciHeaderBytes)
if err != nil {
return err
Expand Down Expand Up @@ -157,9 +154,9 @@ func (m *Manager) produceBlock(ctx context.Context, allowEmpty bool) error {
}

m.logger.Info("block created", "height", newHeight, "num_tx", len(block.Data.Txs))
rollappBlockSizeBytesGauge.Set(float64(len(block.Data.Txs)))
rollappBlockSizeTxsGauge.Set(float64(len(block.Data.Txs)))
rollappHeightGauge.Set(float64(newHeight))
types.RollappBlockSizeBytesGauge.Set(float64(len(block.Data.Txs)))
types.RollappBlockSizeTxsGauge.Set(float64(len(block.Data.Txs)))
types.RollappHeightGauge.Set(float64(newHeight))
return nil
}

Expand Down
2 changes: 2 additions & 0 deletions block/testutil.go
Original file line number Diff line number Diff line change
Expand Up @@ -151,5 +151,7 @@ func getManagerConfig() config.BlockManagerConfig {
BatchSubmitMaxTime: 30 * time.Minute,
NamespaceID: "0102030405060708",
GossipedBlocksCacheSize: 50,
OperatorKeyringBackend: "memory",
OperatorAccountName: "default",
}
}
5 changes: 5 additions & 0 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,11 @@ type BlockManagerConfig struct {
BlockBatchMaxSizeBytes uint64 `mapstructure:"block_batch_max_size_bytes"`
// The number of messages cached by gossipsub protocol
GossipedBlocksCacheSize int `mapstructure:"gossiped_blocks_cache_size"`

// Parameters to get the sequencer's operator address
OperatorKeyringBackend string `mapstructure:"operator_keyring_backend"`
OperatorAccountName string `mapstructure:"operator_account_name"`
OperatorKeyringHomeDir string `mapstructure:"operator_keyring_home_dir"`
}

// GetViperConfig reads configuration parameters from Viper instance.
Expand Down
7 changes: 6 additions & 1 deletion config/defaults.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,11 +64,16 @@ func DefaultConfig(home, chainId string) *NodeConfig {
RollappID: chainId,
KeyringHomeDir: keyringDir,
DymAccountName: "sequencer",
GasPrices: "0.025udym",
GasPrices: "1000000000adym",
SLGrpc: defaultSlGrpcConfig,
}
cfg.SettlementConfig = defaultSLconfig

// set operator address
cfg.OperatorKeyringBackend = defaultSLconfig.KeyringBackend
cfg.OperatorKeyringHomeDir = defaultSLconfig.KeyringHomeDir
cfg.OperatorAccountName = defaultSLconfig.DymAccountName

//Setting default params for da grpc mock
defaultDAGrpc := grpc.Config{
Host: "127.0.0.1",
Expand Down
6 changes: 6 additions & 0 deletions config/toml.go
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,12 @@ keyring_backend = "{{ .SettlementConfig.KeyringBackend }}"
keyring_home_dir = "{{ .SettlementConfig.KeyringHomeDir }}"
dym_account_name = "{{ .SettlementConfig.DymAccountName }}"
#keyring and key name to be used as sequencer's operator address on the rollapp
operator_keyring_backend = "{{ .BlockManagerConfig.OperatorKeyringBackend }}"
operator_keyring_home_dir = "{{ .BlockManagerConfig.OperatorKeyringHomeDir }}"
operator_account_name = "{{ .BlockManagerConfig.OperatorAccountName }}"
#######################################################
### Instrumentation Configuration Options ###
#######################################################
Expand Down
Loading

0 comments on commit 74e7a92

Please sign in to comment.