Merge pull request #255 from cosmos/feature/staking

Feature/staking
This commit is contained in:
Ethan Buchman 2017-10-11 16:53:16 -04:00 committed by GitHub
commit f6513738cf
6 changed files with 143 additions and 51 deletions

View File

@ -28,12 +28,16 @@ type Basecoin struct {
state *Store
handler sdk.Handler
tick Ticker
pending []*abci.Validator
height uint64
logger log.Logger
}
// Ticker - tick function
type Ticker func(sm.SimpleDB) ([]*abci.Validator, error)
var _ abci.Application = &Basecoin{}
// NewBasecoin - create a new instance of the basecoin application
@ -46,6 +50,17 @@ func NewBasecoin(handler sdk.Handler, store *Store, logger log.Logger) *Basecoin
}
}
// NewBasecoinTick - create a new instance of the basecoin application with tick functionality
func NewBasecoinTick(handler sdk.Handler, store *Store, logger log.Logger, tick Ticker) *Basecoin {
return &Basecoin{
handler: handler,
info: sm.NewChainState(),
state: store,
logger: logger,
tick: tick,
}
}
// GetChainID returns the currently stored chain
func (app *Basecoin) GetChainID() string {
return app.info.GetChainID(app.state.Committed())
@ -168,9 +183,18 @@ func (app *Basecoin) InitChain(req abci.RequestInitChain) {
// BeginBlock - ABCI
func (app *Basecoin) BeginBlock(req abci.RequestBeginBlock) {
app.height++
// for _, plugin := range app.plugins.GetList() {
// plugin.BeginBlock(app.state, hash, header)
// }
if app.tick != nil {
diff, err := app.tick(app.state.Append())
if err != nil {
panic(err)
}
app.addValChange(diff)
}
}
// EndBlock - ABCI

View File

@ -35,7 +35,7 @@ func initCmd(cmd *cobra.Command, args []string) error {
}
genesis := getGenesisJSON(viper.GetString(commands.FlagChainID))
return commands.CreateGenesisValidatorFiles(cfg, genesis, cmd.Root().Name())
return commands.CreateGenesisValidatorFiles(cfg, genesis, commands.StaticPrivValJSON, cmd.Root().Name())
}
// TODO: better, auto-generate validator...

View File

@ -2,6 +2,7 @@ package commands
import (
"encoding/hex"
"encoding/json"
"fmt"
"io/ioutil"
"os"
@ -13,25 +14,33 @@ import (
tcmd "github.com/tendermint/tendermint/cmd/tendermint/commands"
"github.com/tendermint/tendermint/config"
"github.com/tendermint/tendermint/types"
cmn "github.com/tendermint/tmlibs/common"
)
// InitCmd - node initialization command
var InitCmd = &cobra.Command{
Use: "init [address]",
Short: "Initialize genesis files for a blockchain",
RunE: initCmd,
}
//nolint - flags
var (
// InitCmd - node initialization command
InitCmd = GetInitCmd("mycoin")
//nolint - flags
FlagChainID = "chain-id" //TODO group with other flags or remove? is this already a flag here?
FlagDenom = "denom" //TODO group with other flags or remove? is this already a flag here?
FlagOption = "option"
FlagStatic = "static"
)
func init() {
InitCmd.Flags().String(FlagChainID, "test_chain_id", "Chain ID")
InitCmd.Flags().StringSliceP(FlagOption, "p", []string{}, "Genesis option in the format <app>/<option>/<value>")
// GetInitCmd - get the node initialization command, with a custom genesis account denom
func GetInitCmd(defaultDenom string) *cobra.Command {
initCmd := &cobra.Command{
Use: "init [address]",
Short: "Initialize genesis files for a blockchain",
RunE: initCmd,
}
initCmd.Flags().String(FlagChainID, "test_chain_id", "Chain ID")
initCmd.Flags().String(FlagDenom, defaultDenom, "Coin denomination for genesis account")
initCmd.Flags().StringSliceP(FlagOption, "p", []string{}, "Genesis option in the format <app>/<option>/<value>")
initCmd.Flags().Bool(FlagStatic, false, "use a static private validator")
return initCmd
}
// returns 1 iff it set a file, otherwise 0 (so we can add them)
@ -91,37 +100,31 @@ func initCmd(cmd *cobra.Command, args []string) error {
optionsStr = sep + strings.Join(options[:], sep)
}
genesis := GetGenesisJSON(viper.GetString(FlagChainID), userAddr, optionsStr)
return CreateGenesisValidatorFiles(cfg, genesis, cmd.Root().Name())
}
// CreateGenesisValidatorFiles creates a genesis file with these
// contents and a private validator file
func CreateGenesisValidatorFiles(cfg *config.Config, genesis, appName string) error {
genesisFile := cfg.GenesisFile()
privValFile := cfg.PrivValidatorFile()
mod1, err := setupFile(genesisFile, genesis, 0644)
if err != nil {
return err
}
mod2, err := setupFile(privValFile, PrivValJSON, 0400)
if err != nil {
return err
}
if (mod1 + mod2) > 0 {
msg := fmt.Sprintf("Initialized %s", appName)
logger.Info(msg, "genesis", genesisFile, "priv_validator", privValFile)
var privValJSON, pubkey string
if viper.GetBool(FlagStatic) {
privValJSON = StaticPrivValJSON
pubkey = StaticPK
} else {
logger.Info("Already initialized", "priv_validator", privValFile)
privVal := types.GenPrivValidatorFS("")
pubkey = strings.ToUpper(hex.EncodeToString(privVal.PubKey.Bytes()[1:]))
pvBytes, err := json.Marshal(privVal)
if err != nil {
return err
}
privValJSON = string(pvBytes)
}
return nil
genesis := GetGenesisJSON(pubkey, viper.GetString(FlagChainID), viper.GetString(FlagDenom),
userAddr, optionsStr)
return CreateGenesisValidatorFiles(cfg, genesis, privValJSON, cmd.Root().Name())
}
// PrivValJSON - validator private key file contents in json
var PrivValJSON = `{
// StaticPK - static public key for test cases
var StaticPK = "7B90EA87E7DC0C7145C8C48C08992BE271C7234134343E8A8E8008E617DE7B30"
// StaticPrivValJSON - static validator private key file contents in json
var StaticPrivValJSON = `{
"address": "7A956FADD20D3A5B2375042B2959F8AB172A058F",
"last_height": 0,
"last_round": 0,
@ -138,10 +141,35 @@ var PrivValJSON = `{
}
}`
// CreateGenesisValidatorFiles creates a genesis file with these
// contents and a private validator file
func CreateGenesisValidatorFiles(cfg *config.Config, genesis, privVal, appName string) error {
privValFile := cfg.PrivValidatorFile()
genesisFile := cfg.GenesisFile()
mod1, err := setupFile(genesisFile, genesis, 0644)
if err != nil {
return err
}
mod2, err := setupFile(privValFile, privVal, 0400)
if err != nil {
return err
}
if (mod1 + mod2) > 0 {
msg := fmt.Sprintf("Initialized %s", appName)
logger.Info(msg, "genesis", genesisFile, "priv_validator", privValFile)
} else {
logger.Info("Already initialized", "priv_validator", privValFile)
}
return nil
}
// GetGenesisJSON returns a new tendermint genesis with Basecoin app_options
// that grant a large amount of "mycoin" to a single address
// TODO: A better UX for generating genesis files
func GetGenesisJSON(chainID, addr string, options string) string {
func GetGenesisJSON(pubkey, chainID, denom, addr string, options string) string {
return fmt.Sprintf(`{
"app_hash": "",
"chain_id": "%s",
@ -152,7 +180,7 @@ func GetGenesisJSON(chainID, addr string, options string) string {
"name": "",
"pub_key": {
"type": "ed25519",
"data": "7B90EA87E7DC0C7145C8C48C08992BE271C7234134343E8A8E8008E617DE7B30"
"data": "%s"
}
}
],
@ -161,7 +189,7 @@ func GetGenesisJSON(chainID, addr string, options string) string {
"address": "%s",
"coins": [
{
"denom": "mycoin",
"denom": "%s",
"amount": 9007199254740992
}
]
@ -170,5 +198,5 @@ func GetGenesisJSON(chainID, addr string, options string) string {
"coin/issuer", {"app": "sigs", "addr": "%s"}%s
]
}
}`, chainID, addr, addr, options)
}`, chainID, pubkey, addr, denom, addr, options)
}

View File

@ -9,8 +9,8 @@ import (
"github.com/spf13/cobra"
"github.com/spf13/viper"
sdk "github.com/cosmos/cosmos-sdk"
"github.com/tendermint/abci/server"
abci "github.com/tendermint/abci/types"
"github.com/tendermint/tmlibs/cli"
cmn "github.com/tendermint/tmlibs/common"
@ -19,6 +19,7 @@ import (
"github.com/tendermint/tendermint/proxy"
"github.com/tendermint/tendermint/types"
sdk "github.com/cosmos/cosmos-sdk"
"github.com/cosmos/cosmos-sdk/app"
)
@ -29,6 +30,18 @@ var StartCmd = &cobra.Command{
RunE: startCmd,
}
// GetTickStartCmd - initialize a command as the start command with tick
func GetTickStartCmd(tick app.Ticker) *cobra.Command {
startCmd := &cobra.Command{
Use: "start",
Short: "Start this full node",
RunE: startCmd,
}
startCmd.RunE = tickStartCmd(tick)
addStartFlag(startCmd)
return startCmd
}
// nolint TODO: move to config file
const EyesCacheSize = 10000
@ -45,11 +58,35 @@ var (
)
func init() {
flags := StartCmd.Flags()
addStartFlag(StartCmd)
}
func addStartFlag(startCmd *cobra.Command) {
flags := startCmd.Flags()
flags.String(FlagAddress, "tcp://0.0.0.0:46658", "Listen address")
flags.Bool(FlagWithoutTendermint, false, "Only run abci app, assume external tendermint process")
// add all standard 'tendermint node' flags
tcmd.AddNodeFlags(StartCmd)
tcmd.AddNodeFlags(startCmd)
}
//returns the start command which uses the tick
func tickStartCmd(tick app.Ticker) func(cmd *cobra.Command, args []string) error {
return func(cmd *cobra.Command, args []string) error {
rootDir := viper.GetString(cli.HomeFlag)
store, err := app.NewStore(
path.Join(rootDir, "data", "merkleeyes.db"),
EyesCacheSize,
logger.With("module", "store"),
)
if err != nil {
return err
}
// Create Basecoin app
basecoinApp := app.NewBasecoinTick(Handler, store, logger.With("module", "app"), tick)
return start(rootDir, store, basecoinApp)
}
}
func startCmd(cmd *cobra.Command, args []string) error {
@ -63,9 +100,12 @@ func startCmd(cmd *cobra.Command, args []string) error {
if err != nil {
return err
}
// Create Basecoin app
basecoinApp := app.NewBasecoin(Handler, store, logger.With("module", "app"))
return start(rootDir, store, basecoinApp)
}
func start(rootDir string, store *app.Store, basecoinApp *app.Basecoin) error {
// if chain_id has not been set yet, load the genesis.
// else, assume it's been loaded
@ -93,7 +133,7 @@ func startCmd(cmd *cobra.Command, args []string) error {
return startTendermint(rootDir, basecoinApp)
}
func startBasecoinABCI(basecoinApp *app.Basecoin) error {
func startBasecoinABCI(basecoinApp abci.Application) error {
// Start the ABCI listener
addr := viper.GetString(FlagAddress)
svr, err := server.NewServer(addr, "socket", basecoinApp)
@ -111,7 +151,7 @@ func startBasecoinABCI(basecoinApp *app.Basecoin) error {
return nil
}
func startTendermint(dir string, basecoinApp *app.Basecoin) error {
func startTendermint(dir string, basecoinApp abci.Application) error {
cfg, err := tcmd.ParseConfig()
if err != nil {
return err

View File

@ -34,7 +34,7 @@ var _ sdk.Context = secureContext{}
func (c secureContext) WithPermissions(perms ...sdk.Actor) sdk.Context {
// the guard makes sure you only set permissions for the app you are inside
for _, p := range perms {
if !c.validPermisison(p) {
if !c.validPermission(p) {
err := errors.Errorf("Cannot set permission for %s/%s on (app=%s, ibc=%b)",
p.ChainID, p.App, c.app, c.ibc)
panic(err)
@ -48,7 +48,7 @@ func (c secureContext) WithPermissions(perms ...sdk.Actor) sdk.Context {
}
}
func (c secureContext) validPermisison(p sdk.Actor) bool {
func (c secureContext) validPermission(p sdk.Actor) bool {
// if app is set, then it must match
if c.app != "" && c.app != p.App {
return false

View File

@ -65,7 +65,7 @@ initServer() {
SERVER_LOG=$1/${SERVER_EXE}.log
GENKEY=$(${CLIENT_EXE} keys get ${RICH} | awk '{print $2}')
${SERVER_EXE} init --chain-id $CHAIN $GENKEY --home=$SERVE_DIR >>$SERVER_LOG
${SERVER_EXE} init --static --chain-id $CHAIN $GENKEY --home=$SERVE_DIR >>$SERVER_LOG
# optionally set the port
if [ -n "$3" ]; then