-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
8da9ce3
commit 34a1ebf
Showing
9 changed files
with
356 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -24,7 +24,7 @@ RUN apt-get update && \ | |
ENV SHUTTER_GNOSIS_SM_BLOCKTIME=10 \ | ||
SHUTTER_GNOSIS_GENESIS_KEYPER=0x440Dc6F164e9241F04d282215ceF2780cd0B755e \ | ||
SHUTTER_GNOSIS_MAXTXPOINTERAGE=5 \ | ||
SHUTTER_DATABASEURL=postgres://[email protected]${NETWORK}.dappnode:5432/keyper \ | ||
SHUTTER_DATABASE_URL=postgres://[email protected]${NETWORK}.dappnode:5432/keyper \ | ||
SHUTTER_SHUTTERMINT_SHUTTERMINTURL=http://localhost:26657 \ | ||
CHAIN_LISTEN_PORT=26657 \ | ||
SHUTTER_BIN=/rolling-shutter \ | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
module go-dappnode-shutter | ||
|
||
go 1.22.2 | ||
|
||
require github.com/joho/godotenv v1.5.1 | ||
|
||
require github.com/pelletier/go-toml/v2 v2.2.3 // indirect |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= | ||
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= | ||
github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8= | ||
github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= | ||
github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M= | ||
github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc= |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
package main | ||
|
||
import ( | ||
"flag" | ||
"fmt" | ||
"go-dappnode-shutter/settings" | ||
"log" | ||
"os" | ||
|
||
"github.com/joho/godotenv" | ||
) | ||
|
||
func main() { | ||
// Define flags for the template, config, and output paths | ||
templateFilePath := flag.String("template", "", "Path to the template file where settings will be included") | ||
configFilePath := flag.String("config", "", "Path to the config file where the settings will be read") | ||
outputFilePath := flag.String("output", "", "Path where the modified settings will be saved") | ||
|
||
// Parse the flags | ||
flag.Parse() | ||
|
||
// Load environment variables from the .env file | ||
err := godotenv.Load(os.Getenv("ASSETS_DIR") + "/variables.env") | ||
if err != nil { | ||
log.Fatalf("Error loading .env file: %v", err) | ||
} | ||
|
||
// Check for additional arguments, e.g., keyper or chain | ||
if len(flag.Args()) < 1 { | ||
fmt.Println("Error: missing argument. Use 'include-keyper-settings' or 'include-chain-settings'.") | ||
os.Exit(1) | ||
} | ||
|
||
// Read the argument passed to the program | ||
argument := flag.Arg(0) | ||
|
||
// Call appropriate function based on the command | ||
switch argument { | ||
case "include-keyper-settings": | ||
// Ensure template, config, and output paths are provided | ||
if *templateFilePath == "" || *configFilePath == "" || *outputFilePath == "" { | ||
fmt.Println("Error: --template, --config, and --output flags must be provided for keyper settings.") | ||
flag.Usage() | ||
os.Exit(1) | ||
} | ||
|
||
// Call the function to configure keyper | ||
err := settings.AddSettingsToKeyper(*templateFilePath, *configFilePath, *outputFilePath) | ||
if err != nil { | ||
log.Fatalf("Failed to configure keyper: %v", err) | ||
} | ||
|
||
case "include-chain-settings": | ||
// Ensure config and output paths are provided | ||
if *configFilePath == "" || *outputFilePath == "" { | ||
fmt.Println("Error: --config and --output flags must be provided for chain settings.") | ||
flag.Usage() | ||
os.Exit(1) | ||
} | ||
|
||
// Call the function to configure chain | ||
err := settings.AddSettingsToChain(*configFilePath, *outputFilePath) | ||
if err != nil { | ||
log.Fatalf("Failed to configure chain: %v", err) | ||
} | ||
|
||
default: | ||
fmt.Println("Invalid argument. Use 'include-keyper-settings' or 'include-chain-settings'.") | ||
os.Exit(1) | ||
} | ||
|
||
fmt.Println("Configuration completed successfully!") | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
package settings | ||
|
||
import ( | ||
"fmt" | ||
"os" | ||
|
||
"github.com/pelletier/go-toml/v2" | ||
) | ||
|
||
type ChainConfig struct { | ||
PrivateKey string | ||
InstanceID string | ||
} | ||
|
||
/** | ||
* This function should: | ||
* - Read all the values from the template configuration file | ||
* - Read the values defined in ChainConfig from the chain configuration file | ||
* - Read the environment variables | ||
* - Copy all the values from the template configuration file to the output configuration file | ||
* - Modify the values using the chain configuration file and environment variables (these have more priority) | ||
* - Save the modified configuration file | ||
* - Return an error if any | ||
*/ | ||
func AddSettingsToChain(templateFilePath, outputFilePath string) error { | ||
|
||
var chainConfig ChainConfig | ||
|
||
chainConfigPath := os.Getenv("SHUTTER_CHAIN_CONFIG_FILE") | ||
|
||
// Check that the chain configuration file exists | ||
if _, err := os.Stat(chainConfigPath); os.IsNotExist(err) { | ||
fmt.Println("Chain configuration file does not exist:", chainConfigPath) | ||
os.Exit(1) | ||
} | ||
|
||
|
||
chainConfigFile, err := os.ReadFile(chainConfigPath) | ||
if err != nil { | ||
fmt.Println("Error reading TOML file:", err) | ||
os.Exit(1) | ||
} | ||
|
||
err = toml.Unmarshal(chainConfigFile, &chainConfig) | ||
if err != nil { | ||
fmt.Println("Error unmarshalling TOML file:", err) | ||
os.Exit(1) | ||
} | ||
|
||
// Read the template configuration file | ||
templateFile, err := os.ReadFile(templateFilePath) | ||
if err != nil { | ||
return fmt.Errorf("error reading template TOML file: %v", err) | ||
} | ||
|
||
// Create a map to hold the template configuration | ||
var templateConfig map[string]interface{} | ||
err = toml.Unmarshal(templateFile, &templateConfig) | ||
if err != nil { | ||
return fmt.Errorf("error unmarshalling template TOML file: %v", err) | ||
} | ||
|
||
// Modify the template configuration based on ChainConfig and environment variables | ||
// ChainConfig values take priority over the template values | ||
applyChainConfig(&templateConfig, chainConfig) | ||
|
||
// Apply environment variables, which have even higher priority than the ChainConfig | ||
applyEnvOverrides(&templateConfig) | ||
|
||
// Marshal the modified configuration to TOML format | ||
modifiedConfig, err := toml.Marshal(templateConfig) | ||
if err != nil { | ||
return fmt.Errorf("error marshalling modified config to TOML: %v", err) | ||
} | ||
|
||
// Write the modified configuration to the output file | ||
err = os.WriteFile(outputFilePath, modifiedConfig, 0644) | ||
if err != nil { | ||
return fmt.Errorf("error writing modified TOML file: %v", err) | ||
} | ||
|
||
fmt.Println("TOML file modified successfully and saved to", outputFilePath) | ||
return nil | ||
} | ||
|
||
// applyChainConfig modifies the template configuration based on the values from ChainConfig | ||
func applyChainConfig(templateConfig *map[string]interface{}, chainConfig ChainConfig) { | ||
if chainConfig.PrivateKey != "" { | ||
(*templateConfig)["PrivateKey"] = chainConfig.PrivateKey | ||
} | ||
if chainConfig.InstanceID != "" { | ||
(*templateConfig)["InstanceID"] = chainConfig.InstanceID | ||
} | ||
} | ||
|
||
// applyEnvOverrides applies environment variables to the template configuration, giving them the highest priority | ||
func applyEnvOverrides(templateConfig *map[string]interface{}) { | ||
// Example: Check for environment variables and override values if they exist | ||
if privateKey := os.Getenv("PRIVATE_KEY"); privateKey != "" { | ||
(*templateConfig)["PrivateKey"] = privateKey | ||
} | ||
if instanceID := os.Getenv("INSTANCE_ID"); instanceID != "" { | ||
(*templateConfig)["InstanceID"] = instanceID | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,152 @@ | ||
package settings | ||
|
||
import ( | ||
"fmt" | ||
"os" | ||
"reflect" | ||
"strconv" | ||
"strings" | ||
|
||
"github.com/pelletier/go-toml/v2" | ||
) | ||
|
||
type KeyperConfig struct { | ||
InstanceID int `env:"_ASSETS_INSTANCE_ID"` | ||
MaxNumKeysPerMessage int `env:"_ASSETS_MAX_NUM_KEYS_PER_MESSAGE"` | ||
EncryptedGasLimit int `env:"_ASSETS_ENCRYPTED_GAS_LIMIT"` | ||
GenesisSlotTimestamp int `env:"_ASSETS_GENESIS_SLOT_TIMESTAMP"` | ||
SyncStartBlockNumber int `env:"_ASSETS_SYNC_START_BLOCK_NUMBER"` | ||
KeyperSetManager string `env:"_ASSETS_KEYPER_SET_MANAGER"` | ||
KeyBroadcastContract string `env:"_ASSETS_KEY_BROADCAST_CONTRACT"` | ||
Sequencer string `env:"_ASSETS_SEQUENCER"` | ||
ValidatorRegistry string `env:"_ASSETS_VALIDATOR_REGISTRY"` | ||
DiscoveryNamespace string `env:"_ASSETS_DISCOVERY_NAME_PREFIX"` | ||
CustomBootstrapAddresses []string `env:"_ASSETS_CUSTOM_BOOTSTRAP_ADDRESSES"` | ||
DKGPhaseLength int `env:"_ASSETS_DKG_PHASE_LENGTH"` | ||
DKGStartBlockDelta int `env:"_ASSETS_DKG_START_BLOCK_DELTA"` | ||
|
||
DatabaseURL string `env:"SHUTTER_DATABASE_URL"` | ||
BeaconAPIURL string `env:"SHUTTER_BEACONAPIURL"` | ||
ContractsURL string `env:"SHUTTER_GNOSIS_NODE_CONTRACTSURL"` | ||
MaxTxPointerAge int `env:"SHUTTER_GNOSIS_MAXTXPOINTERAGE"` | ||
DeploymentDir string `env:"SHUTTER_DEPLOYMENT_DIR"` // Unused, but you can still add an env if needed | ||
EthereumURL string `env:"SHUTTER_GNOSIS_NODE_ETHEREUMURL"` | ||
ShuttermintURL string `env:"SHUTTER_SHUTTERMINT_SHUTTERMINTURL"` | ||
ListenAddresses string `env:"SHUTTER_P2P_LISTENADDRESSES"` | ||
AdvertiseAddresses string `env:"SHUTTER_P2P_ADVERTISEADDRESSES"` | ||
ValidatorPublicKey string `env:"VALIDATOR_PUBLIC_KEY"` | ||
Enabled bool `env:"SHUTTER_ENABLED"` | ||
} | ||
|
||
// AddSettingsToKeyper modifies the keyper settings by combining the template, config, and environment variables. | ||
func AddSettingsToKeyper(templateFilePath, configFilePath, outputFilePath string) error { | ||
var keyperConfig KeyperConfig | ||
|
||
fmt.Println("Adding user settings to keyper...") | ||
|
||
// Read the keyper config file | ||
configFile, err := os.ReadFile(configFilePath) | ||
if err != nil { | ||
return fmt.Errorf("error reading chain config TOML file: %v", err) | ||
} | ||
|
||
// Unmarshal the chain config TOML into the chainConfig struct | ||
err = toml.Unmarshal(configFile, &keyperConfig) | ||
if err != nil { | ||
return fmt.Errorf("error unmarshalling chain config TOML file: %v", err) | ||
} | ||
|
||
// Read the template file | ||
templateFile, err := os.ReadFile(templateFilePath) | ||
if err != nil { | ||
return fmt.Errorf("error reading template TOML file: %v", err) | ||
} | ||
|
||
// Create a map to hold the template configuration | ||
var templateConfig map[string]interface{} | ||
err = toml.Unmarshal(templateFile, &templateConfig) | ||
if err != nil { | ||
return fmt.Errorf("error unmarshalling template TOML file: %v", err) | ||
} | ||
|
||
// Modify the template configuration based on ChainConfig and environment variables | ||
applyKeyperConfig(&templateConfig, keyperConfig) | ||
applyEnvOverrides(&templateConfig) | ||
|
||
// Marshal the modified configuration to TOML format | ||
modifiedConfig, err := toml.Marshal(templateConfig) | ||
if err != nil { | ||
return fmt.Errorf("error marshalling modified config to TOML: %v", err) | ||
} | ||
|
||
// Write the modified configuration to the output file | ||
err = os.WriteFile(outputFilePath, modifiedConfig, 0644) | ||
if err != nil { | ||
return fmt.Errorf("error writing modified TOML file: %v", err) | ||
} | ||
|
||
fmt.Println("Keyper TOML file modified successfully and saved to", outputFilePath) | ||
return nil | ||
} | ||
|
||
// applyKeyperConfig modifies the template based on environment variables, config, and default template values | ||
func applyKeyperConfig(templateConfig *map[string]interface{}, keyperConfig KeyperConfig) { | ||
v := reflect.ValueOf(keyperConfig) | ||
t := reflect.TypeOf(keyperConfig) | ||
|
||
for i := 0; i < v.NumField(); i++ { | ||
fieldValue := v.Field(i) | ||
fieldType := t.Field(i) | ||
|
||
// Get the environment variable tag | ||
envVar := fieldType.Tag.Get("env") | ||
|
||
// Get the corresponding field value based on the priority (env > config > template) | ||
fieldName := fieldType.Name | ||
|
||
var finalValue interface{} | ||
|
||
// 1. Check environment variable | ||
envValue := os.Getenv(envVar) | ||
if envValue != "" { | ||
finalValue = parseEnvValue(envValue, fieldType.Type) | ||
} else if !isZeroValue(fieldValue.Interface()) { | ||
// 2. Use config value if it exists and is non-zero | ||
finalValue = fieldValue.Interface() | ||
} else { | ||
// 3. Fallback to template value (do nothing as it's already in template) | ||
finalValue = (*templateConfig)[fieldName] | ||
} | ||
|
||
setTemplateField(templateConfig, fieldName, finalValue) | ||
} | ||
} | ||
|
||
// Helper function to update template configuration | ||
func setTemplateField(templateConfig *map[string]interface{}, key string, value interface{}) { | ||
if !isZeroValue(value) { | ||
(*templateConfig)[key] = value | ||
} | ||
} | ||
|
||
// Parse environment variable value into the correct type | ||
func parseEnvValue(value string, valueType reflect.Type) interface{} { | ||
switch valueType.Kind() { | ||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: | ||
intValue, _ := strconv.ParseInt(value, 10, 64) | ||
return intValue | ||
case reflect.Bool: | ||
boolValue, _ := strconv.ParseBool(value) | ||
return boolValue | ||
case reflect.Slice: | ||
// Assume comma-separated values for slice | ||
return strings.Split(value, ",") | ||
default: | ||
return value | ||
} | ||
} | ||
|
||
// Check if a value is the zero value of its type | ||
func isZeroValue(value interface{}) bool { | ||
return reflect.DeepEqual(value, reflect.Zero(reflect.TypeOf(value)).Interface()) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.