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

Colin/plasma config #97

Merged
merged 6 commits into from
Dec 2, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 16 additions & 3 deletions app/app.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package app

import (
"crypto/ecdsa"
"encoding/binary"
"encoding/json"
auth "github.com/FourthState/plasma-mvp-sidechain/auth"
Expand Down Expand Up @@ -45,13 +46,22 @@ type ChildChain struct {
// Manage addition and deletion of utxo's
utxoMapper utxo.Mapper

metadataMapper metadata.MetadataMapper

/* Validator Information */
isValidator bool

// Address that validator uses to collect fees
validatorAddress ethcmn.Address

metadataMapper metadata.MetadataMapper
// Private key for submitting blocks to rootchain
validatorPrivKey *ecdsa.PrivateKey

// Rootchain contract address
rootchain ethcmn.Address
}

func NewChildChain(logger log.Logger, db dbm.DB, traceStore io.Writer) *ChildChain {
func NewChildChain(logger log.Logger, db dbm.DB, traceStore io.Writer, options ...func(*ChildChain)) *ChildChain {
cdc := MakeCodec()

bapp := bam.NewBaseApp(appName, logger, db, txDecoder)
Expand All @@ -66,6 +76,10 @@ func NewChildChain(logger log.Logger, db dbm.DB, traceStore io.Writer) *ChildCha
capKeyMetadataStore: sdk.NewKVStoreKey("metadata"),
}

for _, option := range options {
option(app)
}

// define the utxoMapper
app.utxoMapper = utxo.NewBaseMapper(
app.capKeyMainStore, // target store
Expand Down Expand Up @@ -150,7 +164,6 @@ func (app *ChildChain) endBlocker(ctx sdk.Context, req abci.RequestEndBlock) abc
if ctx.BlockHeader().DataHash != nil {
app.metadataMapper.StoreMetadata(ctx, blknumKey, ctx.BlockHeader().DataHash)
}

return abci.ResponseEndBlock{}
}

Expand Down
35 changes: 35 additions & 0 deletions app/options.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package app

import (
"crypto/ecdsa"
"fmt"
"path/filepath"

ethcmn "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
)

func SetEthConfig(isValidator bool, privkey_file string, rootchain_addr string) func(*ChildChain) {
var privkey *ecdsa.PrivateKey
var rootchain ethcmn.Address
if isValidator {
path, err := filepath.Abs(privkey_file)
if err != nil {
errMsg := fmt.Sprintf("Could not resolve provided private key file path: %v", err)
panic(errMsg)
}

privkey, err = crypto.LoadECDSA(path)
if err != nil {
errMsg := fmt.Sprintf("Could not load provided private key file to ecdsa private key: %v", err)
panic(errMsg)
}

rootchain = ethcmn.HexToAddress(rootchain_addr)
}
return func(cc *ChildChain) {
cc.validatorPrivKey = privkey
cc.isValidator = isValidator
cc.rootchain = rootchain
}
}
47 changes: 47 additions & 0 deletions app/options_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package app

import (
"github.com/stretchr/testify/require"
"io/ioutil"
"os"
"testing"

"github.com/FourthState/plasma-mvp-sidechain/utils"
ethcmn "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
dbm "github.com/tendermint/tendermint/libs/db"
"github.com/tendermint/tendermint/libs/log"
)

const (
privkey = "713bd18559e878e0fa3ee32c8ff3ef4393b82ff9f272a3d7de707882f9a3f7d7"
)

func TestSetPrivKey(t *testing.T) {
rootchain := utils.GenerateAddress()

// create a private key file
privkey_file, err := ioutil.TempFile("", "private_key")
require.NoError(t, err)

defer os.Remove(privkey_file.Name())

n, err := privkey_file.Write([]byte(privkey))
require.NoError(t, err)
require.Equal(t, n, len(privkey))

db := dbm.NewMemDB()
logger := log.NewTMLogger(log.NewSyncWriter(os.Stdout)).With("module", "main")
cc := NewChildChain(logger, db, nil,
SetEthConfig(true, privkey_file.Name(), rootchain.String()),
)

private_key, _ := crypto.LoadECDSA(privkey_file.Name())
privkey_file.Close()
require.EqualValues(t, private_key, cc.validatorPrivKey)
require.Equal(t, true, cc.isValidator)

var empty ethcmn.Address
require.NotEqual(t, empty, cc.rootchain)
require.Equal(t, rootchain, cc.rootchain)
}
4 changes: 4 additions & 0 deletions client/plasmad/cmd/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"path/filepath"

"github.com/FourthState/plasma-mvp-sidechain/app"
plasmacfg "github.com/FourthState/plasma-mvp-sidechain/client/plasmad/config"

"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/codec"
Expand Down Expand Up @@ -86,6 +87,9 @@ func InitCmd(ctx *server.Context, cdc *codec.Codec, appInit server.AppInit) *cob

cfg.WriteConfigFile(filepath.Join(config.RootDir, "config", "config.toml"), config)

plasmaConfig := plasmacfg.DefaultConfig()
plasmacfg.WriteConfigFile(filepath.Join(config.RootDir, "config", "plasma.toml"), plasmaConfig)

fmt.Printf("Add an ethereum address to 'fee_address' to collect fees as a validator\n\n")
return displayInfo(cdc, toPrint)
},
Expand Down
12 changes: 12 additions & 0 deletions client/plasmad/config/config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package config

// Defines basic configuration needed to interact with a rootchain contract
type Config struct {
IsValidator bool `mapstructure:"is_validator"`
EthPrivKeyFile string `mapstructure:"eth_privkey_file"`
EthRootchain string `mapstructure:"eth_rootchain"`
}

func DefaultConfig() *Config {
return &Config{false, "", ""}
}
52 changes: 52 additions & 0 deletions client/plasmad/config/toml.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package config

import (
"bytes"
"text/template"

"github.com/spf13/viper"
cmn "github.com/tendermint/tendermint/libs/common"
)

const defaultConfigTemplate = `# This is a TOML config file.
# For more information, see https://github.com/toml-lang/toml

##### ethereum config options #####
# Boolean specifying if this node is a validator
is_validator = "{{ .IsValidator }}"

# File containing unencrypted private key
# Used to sign eth transactions interacting with the rootchain
ethereum_privkey_file = "{{ .EthPrivKeyFile }}"

# Ethereum rootchain contract address
ethereum_rootchain = "{{.EthRootchain}}"`

var configTemplate *template.Template

func init() {
var err error
tmpl := template.New("plasmaConfigFileTemplate")
if configTemplate, err = tmpl.Parse(defaultConfigTemplate); err != nil {
panic(err)
}
}

// parses the plasma.toml file and unmarshals it into a Config struct
func ParseConfig() (*Config, error) {
config := DefaultConfig()
err := viper.Unmarshal(config)
return config, err
}

// WriteConfigFile renders config using the template and writes it to configFilePath.
func WriteConfigFile(configFilePath string, config *Config) {
var buffer bytes.Buffer

if err := configTemplate.Execute(&buffer, config); err != nil {
panic(err)
}

// 0600 for owner only read+write permissions
cmn.MustWriteFile(configFilePath, buffer.Bytes(), 0600)
}
11 changes: 9 additions & 2 deletions client/plasmad/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"os"

"github.com/spf13/cobra"
"github.com/spf13/viper"

"github.com/cosmos/cosmos-sdk/server"
abci "github.com/tendermint/tendermint/abci/types"
Expand All @@ -25,7 +26,7 @@ func main() {
rootCmd := &cobra.Command{
Use: "plasmad",
Short: "Plasma Daemon (server)",
PersistentPreRunE: server.PersistentPreRunEFn(ctx),
PersistentPreRunE: PersistentPreRunEFn(ctx),
}
rootCmd.AddCommand(cmd.InitCmd(ctx, cdc, app.PlasmaAppInit()))

Expand All @@ -40,7 +41,13 @@ func main() {
}

func newApp(logger log.Logger, db dbm.DB, traceStore io.Writer) abci.Application {
return app.NewChildChain(logger, db, traceStore)
key_file := viper.GetString("ethereum_privkey_file")
isValidator := viper.GetBool("is_validator")
rootchain := viper.GetString("rootchain")

return app.NewChildChain(logger, db, traceStore,
app.SetEthConfig(isValidator, key_file, rootchain),
)
}

// non-functional
Expand Down
102 changes: 102 additions & 0 deletions client/plasmad/utils.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
package main

import (
"errors"
"os"
"path/filepath"
"time"

"github.com/spf13/cobra"
"github.com/spf13/viper"

"github.com/FourthState/plasma-mvp-sidechain/client/plasmad/config"
"github.com/cosmos/cosmos-sdk/server"
tmcmd "github.com/tendermint/tendermint/cmd/tendermint/commands"
tmcfg "github.com/tendermint/tendermint/config"
"github.com/tendermint/tendermint/libs/cli"
tmflags "github.com/tendermint/tendermint/libs/cli/flags"
"github.com/tendermint/tendermint/libs/log"
)

// Returns a PresistentPreRunE function that initaillizes a config object
// using the config files stored locally. Parses plasma.toml, allowing access
// to the validators plasma configurations
func PersistentPreRunEFn(context *server.Context) func(*cobra.Command, []string) error {
return func(cmd *cobra.Command, args []string) error {
config, err := loadConfig()
if err != nil {
return err
}
err = validateConfig(config)
if err != nil {
return err
}
logger := log.NewTMLogger(log.NewSyncWriter(os.Stdout))
logger, err = tmflags.ParseLogLevel(config.LogLevel, logger, tmcfg.DefaultLogLevel())
if err != nil {
return err
}

if viper.GetBool(cli.TraceFlag) {
logger = log.NewTracingLogger(logger)
}
logger = logger.With("module", "main")
context.Config = config
context.Logger = logger
return nil
}
}

// update default tendermint and child chain settings if config is created
func loadConfig() (conf *tmcfg.Config, err error) {
// use a tmpConf to get root dir
tmpConf := tmcfg.DefaultConfig()
err = viper.Unmarshal(tmpConf)
if err != nil {
return nil, errors.New("error in unmarshalling default tendermint config object")
}
rootDir := tmpConf.RootDir
configFilePath := filepath.Join(rootDir, "config/config.toml")

// check if the config.toml exists
// if it does not exist, create a config file and set default configurations
if _, err := os.Stat(configFilePath); os.IsNotExist(err) {
conf, _ = tmcmd.ParseConfig()
conf.ProfListenAddress = "listenhost:6060"
conf.P2P.RecvRate = 5120000
conf.P2P.SendRate = 5120000
conf.TxIndex.IndexAllTags = true
conf.Consensus.TimeoutCommit = 5 * time.Nanosecond
tmcfg.WriteConfigFile(configFilePath, conf)
}

// parse existing file
if conf == nil {
conf, err = tmcmd.ParseConfig()
}

plasmaConfigFilePath := filepath.Join(rootDir, "config/plasma.toml")
viper.SetConfigName("plasma")
_ = viper.MergeInConfig()
var plasmaConf *config.Config

// check if plasma.toml exists
// if it does not exist, create the config file and set default configurations
if _, err := os.Stat(plasmaConfigFilePath); os.IsNotExist(err) {
plasmaConf, _ := config.ParseConfig()
config.WriteConfigFile(plasmaConfigFilePath, plasmaConf)
}

if plasmaConf == nil {
_, err = config.ParseConfig()
}

return
}

func validateConfig(conf *tmcfg.Config) error {
if conf.Consensus.CreateEmptyBlocks == false {
return errors.New("config option CreateEmptyBlocks = false is currently unsupported")
}
return nil
}