Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(pubkey): Pubkey module #342

Merged
merged 9 commits into from
Oct 1, 2024
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ Ref: https://keepachangelog.com/en/1.0.0/
* (docs) [#326](https://github.com/sedaprotocol/seda-chain/pull/326) Swagger API documentation
* (x/tally) [#311](https://github.com/sedaprotocol/seda-chain/pull/311) New module `x/tally`
* (x/data-proxy) [#339](https://github.com/sedaprotocol/seda-chain/pull/339) New module `x/data-proxy`
* (x/pkr) [#299](https://github.com/sedaprotocol/seda-chain/pull/299) New module `x/pkr`

### Bug Fixes
* (build) [#321](https://github.com/sedaprotocol/seda-chain/pull/321) Rosetta build tag (not to be used with static compilation)
Expand Down
18 changes: 17 additions & 1 deletion app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,9 @@ import (
dataproxy "github.com/sedaprotocol/seda-chain/x/data-proxy"
dataproxykeeper "github.com/sedaprotocol/seda-chain/x/data-proxy/keeper"
dataproxytypes "github.com/sedaprotocol/seda-chain/x/data-proxy/types"
"github.com/sedaprotocol/seda-chain/x/pubkey"
pubkeykeeper "github.com/sedaprotocol/seda-chain/x/pubkey/keeper"
pubkeytypes "github.com/sedaprotocol/seda-chain/x/pubkey/types"
"github.com/sedaprotocol/seda-chain/x/staking"
stakingkeeper "github.com/sedaprotocol/seda-chain/x/staking/keeper"
"github.com/sedaprotocol/seda-chain/x/tally"
Expand Down Expand Up @@ -181,6 +184,8 @@ var (
ibctm.AppModuleBasic{},
ibcfee.AppModuleBasic{},
transfer.AppModuleBasic{},
wasmstorage.AppModuleBasic{},
pubkey.AppModuleBasic{},
ica.AppModuleBasic{},
crisis.AppModuleBasic{},
packetforward.AppModuleBasic{},
Expand Down Expand Up @@ -244,6 +249,7 @@ type App struct {
WasmStorageKeeper wasmstoragekeeper.Keeper
TallyKeeper tallykeeper.Keeper
DataProxyKeeper dataproxykeeper.Keeper
PubKeyKeeper pubkeykeeper.Keeper

mm *module.Manager
bmm module.BasicManager
Expand Down Expand Up @@ -308,7 +314,7 @@ func NewApp(
feegrant.StoreKey, evidencetypes.StoreKey, circuittypes.StoreKey, authzkeeper.StoreKey, group.StoreKey,
capabilitytypes.StoreKey, ibcexported.StoreKey, ibctransfertypes.StoreKey, ibcfeetypes.StoreKey,
wasmtypes.StoreKey, icahosttypes.StoreKey, icacontrollertypes.StoreKey, packetforwardtypes.StoreKey,
crisistypes.StoreKey, wasmstoragetypes.StoreKey, dataproxytypes.StoreKey,
crisistypes.StoreKey, wasmstoragetypes.StoreKey, dataproxytypes.StoreKey, pubkeytypes.StoreKey,
)

memKeys := storetypes.NewMemoryStoreKeys(capabilitytypes.MemStoreKey)
Expand Down Expand Up @@ -628,6 +634,12 @@ func NewApp(
app.TallyKeeper = tallykeeper.NewKeeper(app.WasmStorageKeeper, contractKeeper, app.WasmKeeper)

app.DataProxyKeeper = *dataproxykeeper.NewKeeper(appCodec, runtime.NewKVStoreService(keys[dataproxytypes.StoreKey]), authtypes.NewModuleAddress(govtypes.ModuleName).String())
app.PubKeyKeeper = *pubkeykeeper.NewKeeper(
appCodec,
runtime.NewKVStoreService(keys[pubkeytypes.StoreKey]),
app.StakingKeeper,
authcodec.NewBech32Codec(sdk.GetConfig().GetBech32ValidatorAddrPrefix()),
)

/* =================================================== */
/* TRANSFER STACK */
Expand Down Expand Up @@ -743,6 +755,7 @@ func NewApp(
wasmstorage.NewAppModule(appCodec, app.WasmStorageKeeper),
tally.NewAppModule(app.TallyKeeper),
dataproxy.NewAppModule(appCodec, app.DataProxyKeeper),
pubkey.NewAppModule(appCodec, app.PubKeyKeeper),
crisis.NewAppModule(app.CrisisKeeper, skipGenesisInvariants, nil), // always be last to make sure that it checks for all invariants and not only part of them
)

Expand Down Expand Up @@ -800,6 +813,7 @@ func NewApp(
wasmstoragetypes.ModuleName,
tallytypes.ModuleName,
dataproxytypes.ModuleName,
pubkeytypes.ModuleName,
)

app.mm.SetOrderEndBlockers(
Expand Down Expand Up @@ -831,6 +845,7 @@ func NewApp(
wasmstoragetypes.ModuleName,
tallytypes.ModuleName,
dataproxytypes.ModuleName,
pubkeytypes.ModuleName,
)

// NOTE: The genutils module must occur after sdkstaking so that pools are
Expand Down Expand Up @@ -868,6 +883,7 @@ func NewApp(
wasmstoragetypes.ModuleName,
tallytypes.ModuleName,
dataproxytypes.ModuleName,
pubkeytypes.ModuleName,
}
app.mm.SetOrderInitGenesis(genesisModuleOrder...)
app.mm.SetOrderExportGenesis(genesisModuleOrder...)
Expand Down
71 changes: 32 additions & 39 deletions app/utils/vrf_key.go
Original file line number Diff line number Diff line change
Expand Up @@ -180,29 +180,6 @@ func NewVRFKey(privKey crypto.PrivKey, keyFilePath string) (*VRFKey, error) {
}, nil
}

// LoadOrGenVRFKey loads a VRFKey from the given file path
// or else generates a new one and saves it to the file path.
func LoadOrGenVRFKey(keyFilePath string) (*VRFKey, error) {
var vrfKey *VRFKey
var err error
if cmtos.FileExists(keyFilePath) {
vrfKey, err = LoadVRFKey(keyFilePath)
if err != nil {
return nil, err
}
} else {
vrfKey, err = NewVRFKey(secp256k1.GenPrivKey(), keyFilePath)
if err != nil {
return nil, err
}
err = vrfKey.Save()
if err != nil {
return nil, err
}
}
return vrfKey, nil
}

func LoadVRFKey(keyFilePath string) (*VRFKey, error) {
keyJSONBytes, err := os.ReadFile(keyFilePath)
if err != nil {
Expand All @@ -225,23 +202,39 @@ func LoadVRFKey(keyFilePath string) (*VRFKey, error) {
return vrfKey, nil
}

func InitializeVRFKey(config *cfg.Config) (vrfPubKey sdkcrypto.PubKey, err error) {
pvKeyFile := config.PrivValidatorKeyFile()
if err := os.MkdirAll(filepath.Dir(pvKeyFile), 0o700); err != nil {
return nil, fmt.Errorf("could not create directory %q: %w", filepath.Dir(pvKeyFile), err)
}
// LoadOrGenVRFKey initializes a VRF key and returns its public key.
// If loadPath is specified, it loads the VRF key file at the specified
// path. Otherwise, it generates a new VRF key, whose entropy is randomly
// generated or obtained from the mnemonic, if provided.
func LoadOrGenVRFKey(config *cfg.Config, loadPath string) (vrfPubKey sdkcrypto.PubKey, err error) {
var vrfKey *VRFKey
if loadPath != "" {
vrfKey, err = LoadVRFKey(loadPath)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this standard for cosmos? I'd say it's a risk to store a private key as plain text in a file. So we should additionally have the option to do it as an ENV var.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

created an issue based on what we discussed: #368

if err != nil {
return nil, err
}
} else {
privKey := secp256k1.GenPrivKey()

vrfKeyFile := PrivValidatorKeyFileToVRFKeyFile(config.PrivValidatorKeyFile())
vrfKey, err := LoadOrGenVRFKey(vrfKeyFile)
if err != nil {
return nil, err
// VRF key file is placed in the same directory as the validator key file.
pvKeyFile := config.PrivValidatorKeyFile()
savePath := filepath.Join(filepath.Dir(pvKeyFile), VRFKeyFileName)
if cmtos.FileExists(savePath) {
return nil, fmt.Errorf("vrf key file already exists at %s", savePath)
}
err := cmtos.EnsureDir(filepath.Dir(pvKeyFile), 0o700)
if err != nil {
return nil, err
}

vrfKey, err = NewVRFKey(privKey, savePath)
if err != nil {
return nil, err
}
err = vrfKey.Save()
if err != nil {
return nil, err
}
}
return vrfKey.PubKey, nil
}

// PrivValidatorKeyFileToVRFKeyFile returns the path to the VRF key file
// given a path to the private validator key file. The two files should
// be placed in the same directory.
func PrivValidatorKeyFileToVRFKeyFile(pvFile string) string {
return filepath.Join(filepath.Dir(pvFile), VRFKeyFileName)
}
2 changes: 1 addition & 1 deletion cmd/sedad/gentx/gentx.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ $ %s gentx my-key-name 1000000seda --home=/path/to/home/dir --keyring-backend=os
if err != nil {
return errors.Wrap(err, "failed to initialize node validator files")
}
vrfPubKey, err := utils.InitializeVRFKey(serverCtx.Config)
vrfPubKey, err := utils.LoadOrGenVRFKey(serverCtx.Config, "") // TODO (#314)
if err != nil {
return errors.Wrap(err, "failed to initialize VRF key")
}
Expand Down
8 changes: 5 additions & 3 deletions e2e/validator.go
Original file line number Diff line number Diff line change
Expand Up @@ -131,13 +131,15 @@ func (v *validator) createConsensusKey() error {

v.consensusKey = filePV.Key

vrfKeyFile := utils.PrivValidatorKeyFileToVRFKeyFile(config.PrivValidatorKeyFile())
vrfKey, err := utils.LoadOrGenVRFKey(vrfKeyFile)
_, err := utils.LoadOrGenVRFKey(config, "")
if err != nil {
return err
}
vrfKey, err := utils.LoadVRFKey(filepath.Join(filepath.Dir(config.PrivValidatorKeyFile()), utils.VRFKeyFileName))
if err != nil {
return err
}
v.vrfKey = vrfKey

return nil
}

Expand Down
1 change: 0 additions & 1 deletion interchaintest/chain_core_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -489,7 +489,6 @@ func testStaking(ctx context.Context, t *testing.T, chain *cosmos.CosmosChain, u
height, err := chain.Height(ctx)
require.NoError(t, err)

//nolint:gosec // G115: Test will fail if conversion overflows
searchHeight := int64(height - 1)

hi, err := chain.StakingQueryHistoricalInfo(ctx, searchHeight)
Expand Down
4 changes: 2 additions & 2 deletions interchaintest/chain_upgrade_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ func ValidatorVoting(t *testing.T, ctx context.Context, chain *cosmos.CosmosChai
require.NoError(t, err, "error fetching height before upgrade")

// this should timeout due to chain halt at upgrade height
//nolint:gosec // G115: Test will fail if conversion overflows

_ = testutil.WaitForBlocks(timeoutCtx, int(haltHeight-currentHeight), chain)

currentHeight, err = chain.Height(ctx)
Expand All @@ -227,7 +227,7 @@ func SubmitUpgradeProposal(t *testing.T, ctx context.Context, chain *cosmos.Cosm
Authority: "seda10d07y265gmmuvt4z0w9aw880jnsr700jvvla4j", // gov module account; sedad q auth module-account gov
Plan: upgradetypes.Plan{
Name: upgradeName,
//nolint:gosec // G115: Test will fail if conversion overflows

Height: int64(haltHeight),
},
}
Expand Down
1 change: 0 additions & 1 deletion interchaintest/state_sync_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@ func TestStateSync(t *testing.T) {
latestHeight, err := chain.Height(ctx)
require.NoError(t, err, "failed to fetch latest chain height")

//nolint:gosec // G115: Test will fail if conversion overflows
trustHeight := int64(latestHeight) - stateSyncSnapshotInterval

firstFullNode := chain.FullNodes[0]
Expand Down
22 changes: 22 additions & 0 deletions proto/sedachain/pubkey/v1/genesis.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
syntax = "proto3";
package sedachain.pubkey.v1;

import "gogoproto/gogo.proto";
import "cosmos_proto/cosmos.proto";
import "sedachain/pubkey/v1/pubkey.proto";

option go_package = "github.com/sedaprotocol/seda-chain/x/pubkey/types";

// GenesisState defines pubkey module's genesis state.
message GenesisState {
repeated ValidatorPubKeys validator_pub_keys = 1
[ (gogoproto.nullable) = false ];
}

// ValidatorPubKeys defines a validator's list of registered public keys
// primarily used in the x/pubkey genesis state.
message ValidatorPubKeys {
string validator_addr = 1
[ (cosmos_proto.scalar) = "cosmos.ValidatorAddressString" ];
repeated IndexedPubKey indexed_pub_keys = 2 [ (gogoproto.nullable) = false ];
}
14 changes: 14 additions & 0 deletions proto/sedachain/pubkey/v1/pubkey.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
syntax = "proto3";
package sedachain.pubkey.v1;

import "google/protobuf/any.proto";
import "cosmos_proto/cosmos.proto";

option go_package = "github.com/sedaprotocol/seda-chain/x/pubkey/types";

// IndexPubKeyPair defines an index - public key pair.
message IndexedPubKey {
uint32 index = 1;
google.protobuf.Any pub_key = 2
[ (cosmos_proto.accepts_interface) = "cosmos.crypto.PubKey" ];
}
32 changes: 32 additions & 0 deletions proto/sedachain/pubkey/v1/query.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
syntax = "proto3";
package sedachain.pubkey.v1;

import "google/api/annotations.proto";
import "gogoproto/gogo.proto";
import "cosmos_proto/cosmos.proto";
import "sedachain/pubkey/v1/genesis.proto";

option go_package = "github.com/sedaprotocol/seda-chain/x/pubkey/types";

// Query defines the gRPC querier service.
service Query {
// ValidatorKeys returns a given validator's registered keys.
rpc ValidatorKeys(QueryValidatorKeysRequest)
returns (QueryValidatorKeysResponse) {
option (google.api.http).get =
"/seda-chain/pubkey/validator_keys/{validator_addr}";
}
}

// QueryValidatorKeysRequest is request type for the Query/ValidatorKeys RPC
// method.
message QueryValidatorKeysRequest {
string validator_addr = 1
[ (cosmos_proto.scalar) = "cosmos.ValidatorAddressString" ];
}

// QueryValidatorKeysResponse is response type for the Query/ValidatorKeys RPC
// method.
message QueryValidatorKeysResponse {
ValidatorPubKeys validator_pub_keys = 1 [ (gogoproto.nullable) = false ];
}
29 changes: 29 additions & 0 deletions proto/sedachain/pubkey/v1/tx.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
syntax = "proto3";
package sedachain.pubkey.v1;

import "gogoproto/gogo.proto";
import "cosmos_proto/cosmos.proto";
import "cosmos/msg/v1/msg.proto";
import "sedachain/pubkey/v1/pubkey.proto";

option go_package = "github.com/sedaprotocol/seda-chain/x/pubkey/types";

// Msg defines the pubkey Msg service.
service Msg {
option (cosmos.msg.v1.service) = true;

// AddKey defines a method for registering a new public key.
rpc AddKey(MsgAddKey) returns (MsgAddKeyResponse);
}

// MsgAddKey defines a message for registering a new public key.
message MsgAddKey {
option (cosmos.msg.v1.signer) = "validator_addr";

string validator_addr = 1
[ (cosmos_proto.scalar) = "cosmos.ValidatorAddressString" ];
repeated IndexedPubKey indexed_pub_keys = 2 [ (gogoproto.nullable) = false ];
}

// MsgAddKeyResponse defines the Msg/MsgAddKey response type.
message MsgAddKeyResponse {}
3 changes: 1 addition & 2 deletions proto/sedachain/wasm_storage/v1/genesis.proto
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,7 @@ import "sedachain/wasm_storage/v1/wasm_storage.proto";

option go_package = "github.com/sedaprotocol/seda-chain/x/wasm-storage/types";

// GenesisState defines the wasm module's genesis state(i.e wasms stored at
// genesis.)
// GenesisState defines wasm-storage module's genesis state.
message GenesisState {
Params params = 1 [ (gogoproto.nullable) = false ];
repeated DataRequestWasm data_request_wasms = 2
Expand Down
1 change: 1 addition & 0 deletions scripts/mockgen.sh
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,4 @@ fi
# Generate mocks for the given package
$mockgen_cmd -source=$GOPATH/pkg/mod/github.com/\!cosm\!wasm/wasmd@v0.50.0/x/wasm/types/exported_keepers.go -package testutil -destination x/wasm-storage/keeper/testutil/wasm_keepers_mock.go
$mockgen_cmd -source=x/wasm-storage/types/expected_keepers.go -package testutil -destination x/wasm-storage/keeper/testutil/expected_keepers_mock.go
$mockgen_cmd -source=x/pubkey/types/expected_keepers.go -package testutil -destination x/pubkey/keeper/testutil/expected_keepers_mock.go
1 change: 0 additions & 1 deletion x/data-proxy/types/query.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion x/data-proxy/types/tx.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading