Skip to content

Commit

Permalink
add a check for min hedgehog version and also cases where there are u…
Browse files Browse the repository at this point in the history
…nauthorized builds
  • Loading branch information
dekm committed Jun 18, 2024
1 parent e729f80 commit b7e9a0d
Showing 1 changed file with 57 additions and 47 deletions.
104 changes: 57 additions & 47 deletions x/pax/module/module.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"fmt"
"io"
"net/http"
"strings"
"time"

"cosmossdk.io/core/appmodule"
Expand Down Expand Up @@ -46,8 +47,6 @@ var (
// AppModuleBasic
// ----------------------------------------------------------------------------

// AppModuleBasic implements the AppModuleBasic interface that defines the
// independent methods a Cosmos SDK module needs to implement.
type AppModuleBasic struct {
cdc codec.BinaryCodec
}
Expand All @@ -56,27 +55,20 @@ func NewAppModuleBasic(cdc codec.BinaryCodec) AppModuleBasic {
return AppModuleBasic{cdc: cdc}
}

// Name returns the name of the module as a string.
func (AppModuleBasic) Name() string {
return types.ModuleName
}

// RegisterLegacyAminoCodec registers the amino codec for the module, which is used
// to marshal and unmarshal structs to/from []byte in order to persist them in the module's KVStore.
func (AppModuleBasic) RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) {}

// RegisterInterfaces registers a module's interface types and their concrete implementations as proto.Message.
func (a AppModuleBasic) RegisterInterfaces(reg cdctypes.InterfaceRegistry) {
types.RegisterInterfaces(reg)
}

// DefaultGenesis returns a default GenesisState for the module, marshalled to json.RawMessage.
// The default GenesisState need to be defined by the module developer and is primarily used for testing.
func (AppModuleBasic) DefaultGenesis(cdc codec.JSONCodec) json.RawMessage {
return cdc.MustMarshalJSON(types.DefaultGenesis())
}

// ValidateGenesis used to validate the GenesisState, given in its json.RawMessage form.
func (AppModuleBasic) ValidateGenesis(cdc codec.JSONCodec, config client.TxEncodingConfig, bz json.RawMessage) error {
var genState types.GenesisState
if err := cdc.UnmarshalJSON(bz, &genState); err != nil {
Expand All @@ -85,7 +77,6 @@ func (AppModuleBasic) ValidateGenesis(cdc codec.JSONCodec, config client.TxEncod
return genState.Validate()
}

// RegisterGRPCGatewayRoutes registers the gRPC Gateway routes for the module.
func (AppModuleBasic) RegisterGRPCGatewayRoutes(clientCtx client.Context, mux *runtime.ServeMux) {
if err := types.RegisterQueryHandlerClient(context.Background(), mux, types.NewQueryClient(clientCtx)); err != nil {
panic(err)
Expand All @@ -96,7 +87,6 @@ func (AppModuleBasic) RegisterGRPCGatewayRoutes(clientCtx client.Context, mux *r
// AppModule
// ----------------------------------------------------------------------------

// AppModule implements the AppModule interface that defines the inter-dependent methods that modules need to implement
type AppModule struct {
AppModuleBasic

Expand All @@ -119,83 +109,62 @@ func NewAppModule(
}
}

// RegisterServices registers a gRPC query service to respond to the module-specific gRPC queries
func (am AppModule) RegisterServices(cfg module.Configurator) {
types.RegisterMsgServer(cfg.MsgServer(), keeper.NewMsgServerImpl(am.keeper))
types.RegisterQueryServer(cfg.QueryServer(), keeper.NewQueryServerImpl(am.keeper))
}

// RegisterInvariants registers the invariants of the module. If an invariant deviates from its predicted value, the InvariantRegistry triggers appropriate logic (most often the chain will be halted)
func (am AppModule) RegisterInvariants(_ sdk.InvariantRegistry) {}

// InitGenesis performs the module's genesis initialization. It returns no validator updates.
func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONCodec, gs json.RawMessage) {
var genState types.GenesisState
// Initialize global index to index in genesis state
cdc.MustUnmarshalJSON(gs, &genState)

InitGenesis(ctx, am.keeper, genState)
}

// ExportGenesis returns the module's exported genesis state as raw JSON bytes.
func (am AppModule) ExportGenesis(ctx sdk.Context, cdc codec.JSONCodec) json.RawMessage {
genState := ExportGenesis(ctx, am.keeper)
return cdc.MustMarshalJSON(genState)
}

// ConsensusVersion is a sequence number for state-breaking change of the module.
// It should be incremented on each consensus-breaking change introduced by the module.
// To avoid wrong/empty versions, the initial version should be set to 1.
func (AppModule) ConsensusVersion() uint64 { return 1 }

// BeginBlock contains the logic that is automatically triggered at the beginning of each block.
// The begin block implementation is optional.
func (am AppModule) BeginBlock(_ context.Context) error {

hedgehogUrl := viper.GetString("hedgehog.hedgehog_url") + "/gridspork"
hedgehogUrl := viper.GetString("hedgehog.hedgehog_url") + "/minimum/version"
fmt.Println("Constructed Hedgehog URL:", hedgehogUrl)

hedgehogAvailable := isConnectedToHedgehog(hedgehogUrl)

if !hedgehogAvailable {
// Start a timer
timer := time.NewTimer(2 * time.Hour) // 2 hours until we panic and shutdown the node
timer := time.NewTimer(2 * time.Hour)

// Set up deferred panic handling
defer func() {
if r := recover(); r != nil {
// Wait for either the timer to expire or the server to become available
select {
case <-timer.C:
// Timer expired, re-panic
panic(r)
case available := <-checkHedgehogAvailability(hedgehogUrl, timer.C):
if available {
fmt.Println("Recovered from panic: Hedgehog server is now available.")
} else {
// Server did not become available in time, re-panic
panic(r)
}
}
}
}()

// Trigger panic
panic("Hedgehog is not available. Node is shutting down.")
}

fmt.Println("Hedgehog is available.")
return nil
}

// EndBlock contains the logic that is automatically triggered at the end of each block.
// The end block implementation is optional.
func (am AppModule) EndBlock(_ context.Context) error {
return nil
}

// checkHedgehogAvailability continuously checks if the Hedgehog server becomes available
// and returns a boolean value through a channel when the server is available or the timer expires.
func checkHedgehogAvailability(hedgehogUrl string, timerC <-chan time.Time) <-chan bool {
availabilityChan := make(chan bool)
go func() {
Expand All @@ -213,16 +182,14 @@ func checkHedgehogAvailability(hedgehogUrl string, timerC <-chan time.Time) <-ch
return
}
fmt.Println("Checking Hedgehog availability...")
time.Sleep(5 * time.Second) // check interval, adjust as needed
time.Sleep(5 * time.Second)
}
}
}()
return availabilityChan
}

// isConnectedToHedgehog performs an HTTP GET request to check the connectivity with the Hedgehog server.
func isConnectedToHedgehog(serverUrl string) bool {

response, err := httpclient.Client.Get(serverUrl)

if err != nil {
Expand All @@ -231,28 +198,72 @@ func isConnectedToHedgehog(serverUrl string) bool {
}
defer response.Body.Close()

// Read and discard the response body
_, err = io.ReadAll(response.Body)
body, err := io.ReadAll(response.Body)
if err != nil {
fmt.Println("Error reading response body:", err.Error())
return false
}

// Check if the HTTP status is 200 OK
if response.StatusCode == http.StatusOK {
fmt.Printf("Received OK response from hedgehog server: %d\n", response.StatusCode)
if response.StatusCode != http.StatusOK {
fmt.Printf("Received non-OK response from hedgehog server: %d\n", response.StatusCode)
return false
}

var versionInfo struct {
MinimumVersion struct {
Version string `json:"version"`
HedgehogProtocol string `json:"hedgehog_protocoll"`
GridsporkProtocol string `json:"gridspork_protocoll"`
} `json:"minimum_version"`
CurrentVersion struct {
Version string `json:"version"`
HedgehogProtocol string `json:"hedgehog_protocoll"`
GridsporkProtocol string `json:"gridspork_protocoll"`
} `json:"current_version"`
}

if err := json.Unmarshal(body, &versionInfo); err != nil {
fmt.Println("Error unmarshalling response body:", err.Error())
return false
}

if versionInfo.MinimumVersion.Version == "" {
fmt.Println("Minimum version not set, continuing...")
return true
}

fmt.Printf("Received non-OK response from hedgehog server: %d\n", response.StatusCode)
minVersion := strings.TrimSuffix(versionInfo.MinimumVersion.Version, "-SNAPSHOT")
currVersion := strings.TrimSuffix(versionInfo.CurrentVersion.Version, "-SNAPSHOT")
if strings.Contains(currVersion, "-BASTARD") {
fmt.Println("Current version contains -BASTARD suffix, rejecting version")
return false
}
currVersion = strings.TrimSuffix(currVersion, "-BASTARD")

if currVersion != minVersion {
fmt.Printf("Current version %s does not match minimum version %s\n", currVersion, minVersion)
return false
}

currHedgehogProtocol := strings.TrimPrefix(versionInfo.CurrentVersion.HedgehogProtocol, "hedgehog/")
currGridsporkProtocol := strings.TrimPrefix(versionInfo.CurrentVersion.GridsporkProtocol, "gridspork/")

if currHedgehogProtocol != versionInfo.MinimumVersion.HedgehogProtocol {
fmt.Printf("Current hedgehog protocol %s does not match minimum hedgehog protocol %s\n", currHedgehogProtocol, versionInfo.MinimumVersion.HedgehogProtocol)
return false
}

if currGridsporkProtocol != versionInfo.MinimumVersion.GridsporkProtocol {
fmt.Printf("Current gridspork protocol %s does not match minimum gridspork protocol %s\n", currGridsporkProtocol, versionInfo.MinimumVersion.GridsporkProtocol)
return false
}

return false
fmt.Println("Hedgehog server is running the correct version.")
return true
}

// IsOnePerModuleType implements the depinject.OnePerModuleType interface.
func (am AppModule) IsOnePerModuleType() {}

// IsAppModule implements the appmodule.AppModule interface.
func (am AppModule) IsAppModule() {}

// ----------------------------------------------------------------------------
Expand Down Expand Up @@ -286,7 +297,6 @@ type ModuleOutputs struct {
}

func ProvideModule(in ModuleInputs) ModuleOutputs {
// default to governance authority if not provided
authority := authtypes.NewModuleAddress(govtypes.ModuleName)
if in.Config.Authority != "" {
authority = authtypes.NewModuleAddressOrBech32Address(in.Config.Authority)
Expand Down

0 comments on commit b7e9a0d

Please sign in to comment.