From 8d355d572b3c24a8349642069a6be7a43cafcaec Mon Sep 17 00:00:00 2001
From: Silas Davis <silas@erisindustries.com>
Date: Tue, 6 Dec 2016 15:47:21 +0000
Subject: [PATCH] Pull in configuration templating from eris-cm

---
 config/config.go      | 176 +++++++++++++++++++++++
 config/config_test.go |  29 ++++
 config/templates.go   | 318 ++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 523 insertions(+)
 create mode 100644 config/config.go
 create mode 100644 config/config_test.go
 create mode 100644 config/templates.go

diff --git a/config/config.go b/config/config.go
new file mode 100644
index 00000000..a37cf96f
--- /dev/null
+++ b/config/config.go
@@ -0,0 +1,176 @@
+// Copyright 2015, 2016 Monax Industries (UK) Ltd.
+// This file is part of Eris-RT
+
+// Eris-RT is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Eris-RT is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Eris-RT.  If not, see <http://www.gnu.org/licenses/>.
+
+package config
+
+import (
+	"bytes"
+	"fmt"
+	"text/template"
+)
+
+type ConfigServiceGeneral struct {
+	ChainImageName      string
+	UseDataContainer    bool
+	ExportedPorts       string
+	ContainerEntrypoint string
+}
+
+// TODO: [ben] increase the configurability upon need
+type ConfigChainGeneral struct {
+	AssertChainId       string
+	ErisdbMajorVersion  uint8
+	ErisdbMinorVersion  uint8
+	GenesisRelativePath string
+}
+
+type ConfigChainModule struct {
+	Name               string
+	MajorVersion       uint8
+	MinorVersion       uint8
+	ModuleRelativeRoot string
+}
+
+type ConfigTendermint struct {
+	Moniker  string
+	Seeds    string
+	FastSync bool
+}
+
+var serviceGeneralTemplate *template.Template
+var chainGeneralTemplate *template.Template
+var chainConsensusTemplate *template.Template
+var chainApplicationManagerTemplate *template.Template
+var tendermintTemplate *template.Template
+
+func init() {
+	var err error
+	if serviceGeneralTemplate, err = template.New("serviceGeneral").Parse(sectionServiceGeneral); err != nil {
+		panic(err)
+	}
+	if chainGeneralTemplate, err = template.New("chainGeneral").Parse(sectionChainGeneral); err != nil {
+		panic(err)
+	}
+	if chainConsensusTemplate, err = template.New("chainConsensus").Parse(sectionChainConsensus); err != nil {
+		panic(err)
+	}
+	if chainApplicationManagerTemplate, err = template.New("chainApplicationManager").Parse(sectionChainApplicationManager); err != nil {
+		panic(err)
+	}
+	if tendermintTemplate, err = template.New("tendermint").Parse(sectionTendermint); err != nil {
+		panic(err)
+	}
+}
+
+// NOTE: [ben] for 0.12.0-rc3 we only have a single configuration path
+// with Tendermint in-process as the consensus engine and ErisMint
+// in-process as the application manager, so we hard-code the few
+// parameters that are already templated.
+// Let's learn to walk before we can run.
+func GetConfigurationFileBytes(chainId, moniker, seeds string, chainImageName string,
+	useDataContainer bool, exportedPortsString, containerEntrypoint string) ([]byte, error) {
+
+	erisdbService := &ConfigServiceGeneral{
+		ChainImageName:      chainImageName,
+		UseDataContainer:    useDataContainer,
+		ExportedPorts:       exportedPortsString,
+		ContainerEntrypoint: containerEntrypoint,
+	}
+	erisdbChain := &ConfigChainGeneral{
+		AssertChainId:       chainId,
+		ErisdbMajorVersion:  uint8(0),
+		ErisdbMinorVersion:  uint8(12),
+		GenesisRelativePath: "genesis.json",
+	}
+	chainConsensusModule := &ConfigChainModule{
+		Name:               "tendermint",
+		MajorVersion:       uint8(0),
+		MinorVersion:       uint8(6),
+		ModuleRelativeRoot: "tendermint",
+	}
+	chainApplicationManagerModule := &ConfigChainModule{
+		Name:               "erismint",
+		MajorVersion:       uint8(0),
+		MinorVersion:       uint8(12),
+		ModuleRelativeRoot: "erismint",
+	}
+	tendermintModule := &ConfigTendermint{
+		Moniker:  moniker,
+		Seeds:    seeds,
+		FastSync: false,
+	}
+
+	// NOTE: [ben] according to StackOverflow appending strings with copy is
+	// more efficient than bytes.WriteString, but for readability and because
+	// this is not performance critical code we opt for bytes, which is
+	// still more efficient than + concatentation operator.
+	var buffer bytes.Buffer
+
+	// write copyright header
+	buffer.WriteString(headerCopyright)
+
+	// write section [service]
+	if err := serviceGeneralTemplate.Execute(&buffer, erisdbService); err != nil {
+		return nil, fmt.Errorf("Failed to write template service general for %s: %s",
+			chainId, err)
+	}
+	// write section for service dependencies; this is currently a static section
+	// with a fixed dependency on eris-keys
+	buffer.WriteString(sectionServiceDependencies)
+
+	// write section [chain]
+	if err := chainGeneralTemplate.Execute(&buffer, erisdbChain); err != nil {
+		return nil, fmt.Errorf("Failed to write template chain general for %s: %s",
+			chainId, err)
+	}
+
+	// write separator chain consensus
+	buffer.WriteString(separatorChainConsensus)
+	// write section [chain.consensus]
+	if err := chainConsensusTemplate.Execute(&buffer, chainConsensusModule); err != nil {
+		return nil, fmt.Errorf("Failed to write template chain consensus for %s: %s",
+			chainId, err)
+	}
+
+	// write separator chain application manager
+	buffer.WriteString(separatorChainApplicationManager)
+	// write section [chain.consensus]
+	if err := chainApplicationManagerTemplate.Execute(&buffer,
+		chainApplicationManagerModule); err != nil {
+		return nil, fmt.Errorf("Failed to write template chain application manager for %s: %s",
+			chainId, err)
+	}
+
+	// write separator servers
+	buffer.WriteString(separatorServerConfiguration)
+	// TODO: [ben] upon necessity replace this with template too
+	// write static section servers
+	buffer.WriteString(sectionServers)
+
+	// write separator modules
+	buffer.WriteString(separatorModules)
+
+	// write section module Tendermint
+	if err := tendermintTemplate.Execute(&buffer, tendermintModule); err != nil {
+		return nil, fmt.Errorf("Failed to write template tendermint for %s, moniker %s: %s",
+			chainId, moniker, err)
+	}
+
+	// write static section erismint
+	buffer.WriteString(sectionErisMint)
+
+	return buffer.Bytes(), nil
+}
diff --git a/config/config_test.go b/config/config_test.go
new file mode 100644
index 00000000..79286f35
--- /dev/null
+++ b/config/config_test.go
@@ -0,0 +1,29 @@
+// Copyright 2015, 2016 Monax Industries (UK) Ltd.
+// This file is part of Eris-RT
+
+// Eris-RT is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Eris-RT is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Eris-RT.  If not, see <http://www.gnu.org/licenses/>.
+
+package config
+
+import (
+	"testing"
+)
+
+func TestConfigurationFileBytes(t *testing.T) {
+	// TODO: [ben] parse written bytes for comparison with expected parameters
+	if _, err := GetConfigurationFileBytes("simplechain", "marmot", "noseeds", "db:latest",
+		true, "", "eris-db"); err != nil {
+		t.Errorf("Error writing configuration file bytes: %s", err)
+	}
+}
diff --git a/config/templates.go b/config/templates.go
new file mode 100644
index 00000000..cead77d9
--- /dev/null
+++ b/config/templates.go
@@ -0,0 +1,318 @@
+// Copyright 2015, 2016 Monax Industries (UK) Ltd.
+// This file is part of Eris-RT
+
+// Eris-RT is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Eris-RT is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Eris-RT.  If not, see <http://www.gnu.org/licenses/>.
+
+package config
+
+const headerCopyright = `# Copyright 2015, 2016 Eris Industries (UK) Ltd.
+# This file is part of Eris-RT
+# Eris-RT is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Eris-RT is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Eris-RT.  If not, see <http://www.gnu.org/licenses/>.
+
+# This is a TOML configuration for Eris-DB chains generated by Eris-CM
+
+`
+
+const sectionServiceGeneral = `[service]
+# NOTE: this section is read by Eris tooling, and ignored by eris-db.
+# Image specifies the image name eris-cli needs to pull 
+# for running the chain.
+image = "{{.ChainImageName}}"
+# Define whether eris-cli needs to attach the data container
+# for the chain.
+data_container = {{.UseDataContainer}}
+# Specify a list of ports that need to be exported on the container.
+ports = {{.ExportedPorts}}
+{{ if ne .ContainerEntrypoint "" }}# Entrypoint points to the default action to execute
+# in the chain container.
+entry_point = "{{.ContainerEntrypoint}}"{{ end }}
+
+`
+
+const sectionServiceDependencies = `[dependencies]
+# NOTE: this section is read by Eris tooling, and ignored by eris-db.
+# Eris-db expects these services to be available; eric-cli tooling will
+# automatically set these services up for you.
+# Services to boot with/required by the chain
+services = [ "keys" ]
+
+`
+
+const sectionChainGeneral = `[chain]
+
+# ChainId is a human-readable name to identify the chain.
+# This must correspond to the chain_id defined in the genesis file
+# and the assertion here provides a safe-guard on misconfiguring chains.
+assert_chain_id = "{{.AssertChainId}}"
+# semantic major and minor version
+major_version = {{.ErisdbMajorVersion}}
+minor_version = {{.ErisdbMinorVersion}}
+# genesis file, relative path is to eris-db working directory
+genesis_file = "{{.GenesisRelativePath}}"
+
+`
+
+const separatorChainConsensus = `
+################################################################################
+##
+##  consensus
+##
+################################################################################
+
+`
+
+const sectionChainConsensus = `  [chain.consensus]
+  # consensus defines the module to use for consensus and
+  # this will define the peer-to-peer consensus network;
+  # accepted values are ("noops", "tmsp",) "tendermint"
+  name = "{{.Name}}"
+  # version is the major and minor semantic version;
+  # the version will be asserted on
+  major_version = {{.MajorVersion}}
+  minor_version = {{.MinorVersion}}
+  # relative path to consensus' module root folder
+  relative_root = "{{.ModuleRelativeRoot}}"
+
+  `
+
+const separatorChainApplicationManager = `
+################################################################################
+##
+##  application manager
+##
+################################################################################
+
+`
+
+const sectionChainApplicationManager = `  [chain.manager]
+  # application manager name defines the module to use for handling
+  # the transactions.  Supported names are "erismint"
+  name = "{{.Name}}"
+  # version is the major and minor semantic version;
+  # the version will be asserted on
+  major_version = {{.MajorVersion}}
+  minor_version = {{.MinorVersion}}
+  # relative path to application manager root folder
+  relative_root = "{{.ModuleRelativeRoot}}"
+
+  `
+
+const separatorServerConfiguration = `
+################################################################################
+################################################################################
+##
+## Server configurations
+##
+################################################################################
+################################################################################
+
+`
+
+// TODO: [ben] map entries to structure defined in eris-db
+const sectionServers = `[servers]
+
+  [servers.bind]
+  address = ""
+  port = 1337
+
+  [servers.tls]
+  tls = false
+  cert_path = ""
+  key_path = ""
+
+  [servers.cors]
+  enable = false
+  allow_origins = []
+  allow_credentials = false
+  allow_methods = []
+  allow_headers = []
+  expose_headers = []
+  max_age = 0
+
+  [servers.http]
+  json_rpc_endpoint = "/rpc"
+
+  [servers.websocket]
+  endpoint = "/socketrpc"
+  max_sessions = 50
+  read_buffer_size = 4096
+  write_buffer_size = 4096
+
+	[servers.tendermint]
+	# Multiple listeners can be separated with a comma
+	rpc_local_address = "0.0.0.0:46657"
+	endpoint = "/websocket"
+
+  [servers.logging]
+  console_log_level = "info"
+  file_log_level = "warn"
+  log_file = ""
+
+  `
+
+const separatorModules = `
+################################################################################
+################################################################################
+##
+## Module configurations - dynamically loaded based on chain configuration
+##
+################################################################################
+################################################################################
+
+`
+
+// TODO: [ben] make configurable
+const sectionTmsp = `
+################################################################################
+##
+## Tendermint Socket Protocol (TMSP)
+## version 0.6.0
+##
+## TMSP expects a tendermint consensus process to run and connect to Eris-DB
+##
+################################################################################
+
+[tmsp]
+# listener address for accepting tendermint socket protocol connections
+listener = "tcp://0.0.0.0:46658"
+
+`
+
+// TODO: [ben] minimal fields have been made configurable; expand where needed
+const sectionTendermint = `
+################################################################################
+##
+## Tendermint
+## version 0.6.0
+##
+## in-process execution of Tendermint consensus engine
+##
+################################################################################
+
+[tendermint]
+# private validator file is used by tendermint to keep the status
+# of the private validator, but also (currently) holds the private key
+# for the private vaildator to sign with.  This private key needs to be moved
+# out and directly managed by eris-keys
+# This file needs to be in the root directory
+private_validator_file = "priv_validator.json"
+
+  # Tendermint requires additional configuration parameters.
+  # Eris-DB's tendermint consensus module will load [tendermint.configuration]
+  # as the configuration for Tendermint.
+  # Eris-DB will respect the configurations set in this file where applicable,
+  # but reserves the option to override or block conflicting settings.
+  [tendermint.configuration]
+  # moniker is the name of the node on the tendermint p2p network
+  moniker = "{{.Moniker}}"
+  # seeds lists the peers tendermint can connect to join the network
+  seeds = "{{.Seeds}}"
+  # fast_sync allows a tendermint node to catch up faster when joining
+  # the network.
+  # NOTE: Tendermint has reported potential issues with fast_sync enabled.
+  # The recommended setting is for keeping it disabled.
+  fast_sync = {{.FastSync}}
+  # database backend to use for Tendermint. Supported "leveldb" and "memdb".
+  db_backend = "leveldb"
+  # logging level. Supported "error" < "warn" < "notice" < "info" < "debug"
+  log_level = "info"
+  # node local address
+  node_laddr = "0.0.0.0:46656"
+  # rpc local address
+	# NOTE: value is ignored when run in-process as RPC is
+	# handled by [servers.tendermint]
+  rpc_laddr = "0.0.0.0:46657"
+  # proxy application address - used for tmsp connections,
+  # and this port should not be exposed for in-process Tendermint
+  proxy_app = "tcp://127.0.0.1:46658"
+
+  # Extended Tendermint configuration settings
+  # for reference to Tendermint see https://github.com/tendermint/tendermint/blob/master/config/tendermint/config.go
+
+  # genesis_file = "./data/tendermint/genesis.json"
+  # skip_upnp = false
+  # addrbook_file = "./data/tendermint/addrbook.json"
+  # priv_validator_file = "./data/tendermint/priv_validator.json"
+  # db_dir = "./data/tendermint/data"
+  # prof_laddr = ""
+  # revision_file = "./data/tendermint/revision"
+  # cswal = "./data/tendermint/data/cswal"
+  # cswal_light = false
+
+  # block_size = 10000
+  # disable_data_hash = false
+  # timeout_propose = 3000
+  # timeout_propose_delta = 500
+  # timeout_prevote = 1000
+  # timeout_prevote_delta = 500
+  # timeout_precommit = 1000
+  # timeout_precommit_delta = 500
+  # timeout_commit = 1000
+  # mempool_recheck = true
+  # mempool_recheck_empty = true
+  # mempool_broadcast = true
+
+		[tendermint.configuration.p2p]
+		# Switch config keys
+		dial_timeout_seconds = 3
+		handshake_timeout_seconds = 20
+		max_num_peers = 20
+		authenticated_encryption = true
+
+		# MConnection config keys
+		send_rate = 512000
+		recv_rate = 512000
+
+		# Fuzz params
+		fuzz_enable = false # use the fuzz wrapped conn
+		fuzz_active = false # toggle fuzzing
+		fuzz_mode = "drop"  # eg. drop, delay
+		fuzz_max_delay_milliseconds = 3000
+		fuzz_prob_drop_rw = 0.2
+		fuzz_prob_drop_conn = 0.00
+		fuzz_prob_sleep = 0.00
+
+`
+
+const sectionErisMint = `
+################################################################################
+##
+## Eris-Mint
+## version 0.12.0
+##
+## The original Ethereum virtual machine with IAVL merkle trees
+## and tendermint/go-wire encoding
+##
+################################################################################
+
+[erismint]
+# Database backend to use for ErisMint state database.
+# Supported "leveldb" and "memdb".
+db_backend = "leveldb"
+# tendermint host address needs to correspond to tendermints configuration
+# of the rpc local address
+tendermint_host = "0.0.0.0:46657"
+
+`
-- 
GitLab