cfg.EnsureRoot(config.RootDir, "solonet")
}
+ //generate the federation config file
+ fedFilePath := config.FederationFile()
+ if _, err := os.Stat(fedFilePath); os.IsNotExist(err) {
+ if err := cfg.ExportFederationFile(fedFilePath, config); err != nil {
+ log.WithFields(log.Fields{"module": logModule, "config": fedFilePath, "error": err}).Fatal("fail on export federation file")
+ }
+ }
+
//generate the node private key
keyFilePath := path.Join(config.RootDir, config.PrivateKeyFile)
if _, err := os.Stat(keyFilePath); os.IsNotExist(err) {
// Top level options use an anonymous struct
BaseConfig `mapstructure:",squash"`
// Options for services
- P2P *P2PConfig `mapstructure:"p2p"`
- Wallet *WalletConfig `mapstructure:"wallet"`
- Auth *RPCAuthConfig `mapstructure:"auth"`
- Web *WebConfig `mapstructure:"web"`
- Simd *SimdConfig `mapstructure:"simd"`
- Websocket *WebsocketConfig `mapstructure:"ws"`
+ P2P *P2PConfig `mapstructure:"p2p"`
+ Wallet *WalletConfig `mapstructure:"wallet"`
+ Auth *RPCAuthConfig `mapstructure:"auth"`
+ Web *WebConfig `mapstructure:"web"`
+ Simd *SimdConfig `mapstructure:"simd"`
+ Websocket *WebsocketConfig `mapstructure:"ws"`
+ Federation *FederationConfig `mapstructure:"federation"`
}
// Default configurable parameters.
Web: DefaultWebConfig(),
Simd: DefaultSimdConfig(),
Websocket: DefaultWebsocketConfig(),
+ Federation: DefaultFederationConfig(),
}
}
return cfg.XPrv
}
-//-----------------------------------------------------------------------------
+// -----------------------------------------------------------------------------
// BaseConfig
type BaseConfig struct {
// The root directory for all data.
// This should be set in viper so it can unmarshal into this struct
RootDir string `mapstructure:"home"`
- //The alias of the node
+ // The alias of the node
NodeAlias string `mapstructure:"node_alias"`
- //The ID of the network to json
+ // The ID of the network to json
ChainID string `mapstructure:"chain_id"`
- //log level to set
+ // log level to set
LogLevel string `mapstructure:"log_level"`
// A custom human readable name for this node
PrivateKeyFile string `mapstructure:"private_key_file"`
XPrv *chainkd.XPrv
XPub *chainkd.XPub
+
+ FederationFileName string `mapstructure:"federation_file"`
}
// Default configurable base parameters.
func DefaultBaseConfig() BaseConfig {
return BaseConfig{
- Moniker: "anonymous",
- ProfListenAddress: "",
- Mining: false,
- DBBackend: "leveldb",
- DBPath: "data",
- KeysPath: "keystore",
- NodeAlias: "",
- LogFile: "log",
- PrivateKeyFile: "node_key.txt",
+ Moniker: "anonymous",
+ ProfListenAddress: "",
+ Mining: false,
+ DBBackend: "leveldb",
+ DBPath: "data",
+ KeysPath: "keystore",
+ NodeAlias: "",
+ LogFile: "log",
+ PrivateKeyFile: "node_key.txt",
+ FederationFileName: "federation.json",
}
}
return rootify(b.KeysPath, b.RootDir)
}
+func (b BaseConfig) FederationFile() string {
+ return rootify(b.FederationFileName, b.RootDir)
+}
+
// P2PConfig
type P2PConfig struct {
ListenAddress string `mapstructure:"laddr"`
}
}
-//-----------------------------------------------------------------------------
+// -----------------------------------------------------------------------------
type WalletConfig struct {
Disable bool `mapstructure:"disable"`
Rescan bool `mapstructure:"rescan"`
MaxNumConcurrentReqs int `mapstructure:"max_num_concurrent_reqs"`
}
+type FederationConfig struct {
+ Xpubs []chainkd.XPub `json:"xpubs"`
+ Quorum int `json:"quorum"`
+}
+
// Default configurable rpc's auth parameters.
func DefaultRPCAuthConfig() *RPCAuthConfig {
return &RPCAuthConfig{
}
}
-//-----------------------------------------------------------------------------
+// Default configurable federation parameters.
+func DefaultFederationConfig() *FederationConfig {
+ return &FederationConfig{
+ Xpubs: []chainkd.XPub{
+ xpub("580daf48fa8962100047cb1391da890bb7f2c849fdbc9b368cb4394a4c7cbb0977e2e7ebbf055dc0ef90af6a0d2af01ce7ec56b735d016aab597815ec48552e5"),
+ xpub("f3f6bcf61b65fa9d1566455a5688ca8b395efdc22e654963134b5e5cb0a45d8be522d21abc384a73177a7b9d64eba915fcfe2862d86a508a3c46dc410bdd72ad"),
+ xpub("53559612f2b7bcada18948b7de39d63947a0e2bd7336d07db1350c54ba5743996b84bf9d18ff7a2457e1a5c70ce5013e4a3b62666ddb03294c53051d5f5c70c0"),
+ xpub("7c88cc58adfc71818b08308d43c29de22460b0ea6895449cbec6e458d7dc09e0aea243fa5075ee6621da0d805bd047f6bb207329c5bd2ca3253b172fb323b512"),
+ },
+ Quorum: 2,
+ }
+}
+
+func xpub(str string) (xpub chainkd.XPub) {
+ if err := xpub.UnmarshalText([]byte(str)); err != nil {
+ log.Panicf("Fail converts a string to xpub")
+ }
+ return xpub
+}
+
+// -----------------------------------------------------------------------------
// Utils
// helper function to make config creation independent of root dir
--- /dev/null
+package config
+
+import (
+ "bytes"
+ "encoding/json"
+ "io/ioutil"
+ "os"
+)
+
+func ExportFederationFile(fedFile string, config *Config) error {
+ buf := new(bytes.Buffer)
+
+ encoder := json.NewEncoder(buf)
+ encoder.SetIndent("", " ")
+ if err := encoder.Encode(config.Federation); err != nil {
+ return err
+ }
+
+ return ioutil.WriteFile(fedFile, buf.Bytes(), 0644)
+}
+
+func LoadFederationFile(fedFile string, config *Config) error {
+ file, err := os.Open(fedFile)
+ if err != nil {
+ return err
+ }
+ defer file.Close()
+
+ return json.NewDecoder(file).Decode(config.Federation)
+}
// consensus variables
const (
// Max gas that one block contains
- MaxBlockGas = uint64(10000000)
- VMGasRate = int64(200)
- StorageGasRate = int64(1)
- MaxGasAmount = int64(200000)
- DefaultGasCredit = int64(30000)
- NumOfValidators = int(10)
+ MaxBlockGas = uint64(10000000)
+ VMGasRate = int64(200)
+ StorageGasRate = int64(1)
+ MaxGasAmount = int64(200000)
+ DefaultGasCredit = int64(30000)
+ MaxNumOfValidators = int(10)
// config parameter for coinbase reward
CoinbasePendingBlockNumber = uint64(100)
func setSupLinkToCheckpoint(c *state.Checkpoint, supLinks types.SupLinks) {
for _, supLink := range supLinks {
- var signatures [consensus.NumOfValidators]string
+ var signatures [consensus.MaxNumOfValidators]string
for i, signature := range supLink.Signatures {
signatures[i] = hex.EncodeToString(signature)
}
log "github.com/sirupsen/logrus"
cmn "github.com/tendermint/tmlibs/common"
browser "github.com/toqueteos/webbrowser"
+
"github.com/bytom/bytom/proposal/blockproposer"
"github.com/prometheus/prometheus/util/flock"
// NewNode create bytom node
func NewNode(config *cfg.Config) *Node {
- ctx := context.Background()
- if err := lockDataDirectory(config); err != nil {
- cmn.Exit("Error: " + err.Error())
- }
-
- if err := bytomLog.InitLogFile(config); err != nil {
- log.WithField("err", err).Fatalln("InitLogFile failed")
+ if err := initNodeConfig(config); err != nil {
+ cmn.Exit(cmn.Fmt("Failed to init config: %v", err))
}
- initActiveNetParams(config)
- initCommonConfig(config)
-
// Get store
if config.DBBackend != "memdb" && config.DBBackend != "leveldb" {
cmn.Exit(cmn.Fmt("Param db_backend [%v] is invalid, use leveldb or memdb", config.DBBackend))
txFeedDB := dbm.NewDB("txfeeds", config.DBBackend, config.DBDir())
txFeed = txfeed.NewTracker(txFeedDB, chain)
- if err = txFeed.Prepare(ctx); err != nil {
+ if err = txFeed.Prepare(context.Background()); err != nil {
log.WithFields(log.Fields{"module": logModule, "error": err}).Error("start txfeed")
return nil
}
return node
}
+func initNodeConfig(config *cfg.Config) error {
+ if err := lockDataDirectory(config); err != nil {
+ cmn.Exit("Error: " + err.Error())
+ }
+
+ if err := bytomLog.InitLogFile(config); err != nil {
+ log.WithField("err", err).Fatalln("InitLogFile failed")
+ }
+
+ if err := cfg.LoadFederationFile(config.FederationFile(), config); err != nil {
+ log.WithField("err", err).Info("Failed to load federated information")
+ return err
+ }
+
+ initActiveNetParams(config)
+ initCommonConfig(config)
+ return nil
+}
+
// Lock data directory after daemonization
func lockDataDirectory(config *cfg.Config) error {
_, _, err := flock.New(filepath.Join(config.RootDir, "LOCK"))
}
supLink := target.AddVerification(v.SourceHash, v.SourceHeight, validators[v.PubKey].Order, v.Signature)
- if target.Status != state.Unjustified || !supLink.IsMajority() || source.Status == state.Finalized {
+ if target.Status != state.Unjustified || !supLink.IsMajority(len(validators)) || source.Status == state.Finalized {
continue
}
type SupLink struct {
SourceHeight uint64
SourceHash bc.Hash
- Signatures [consensus.NumOfValidators][]byte
+ Signatures [consensus.MaxNumOfValidators][]byte
}
func (s *SupLink) readFrom(r *blockchain.Reader) (err error) {
return err
}
- for i := 0; i < consensus.NumOfValidators; i++ {
+ for i := 0; i < consensus.MaxNumOfValidators; i++ {
if s.Signatures[i], err = blockchain.ReadVarstr31(r); err != nil {
return err
}
{
SourceHeight: 100,
SourceHash: testutil.MustDecodeHash("0a3cd1175e295a35c2b63054969c3fe54eeaa3eb68258227b28d8daa6cf4c50c"),
- Signatures: [consensus.NumOfValidators][]byte{
+ Signatures: [consensus.MaxNumOfValidators][]byte{
testutil.MustDecodeHexString("750318156e8c913c378a8d31294fca1084df3be3967035425f470f81e00cd824d1f12bf8e1c3b308f4b1a916438b9ce630722bc8d92ef0feebbbaf987dd7a60e"),
testutil.MustDecodeHexString("be7c7e0ba54109c8c457cdbba4691d7aaae32eb4b8ac63755f2494be406027ce66c7b4730bfd2506fa2caaba12a7bbbea2faca5f07bb64fe06a568b6415e7506"),
},
{
SourceHeight: 105,
SourceHash: testutil.MustDecodeHash("546c91cefc6a06f9b7a0aaa4d69db9a7f229af27928304a44ecd48e33ba2ba91"),
- Signatures: [consensus.NumOfValidators][]byte{
+ Signatures: [consensus.MaxNumOfValidators][]byte{
testutil.MustDecodeHexString("38c9a6a48eeea993b2d4137e73b17e4743ce3935636fcce957ae2291c691491525f39509a1c21fec3c7f78403ae88e375b796fa9dcc4cac0af8a987994f62c07"),
testutil.MustDecodeHexString("4fe5646b2b669aaef0dd74a090e150de676218d0a6e693bb2d1cc791282517669d7903c60a909a5d9c5a996e5797ea9dded20b52dc4b8ec272e86e5fc4e8a008"),
nil,
{
SourceHeight: 200,
SourceHash: testutil.MustDecodeHash("0a3cd1175e295a35c2b63054969c3fe54eeaa3eb68258227b28d8daa6cf4c50c"),
- Signatures: [consensus.NumOfValidators][]byte{
+ Signatures: [consensus.MaxNumOfValidators][]byte{
testutil.MustDecodeHexString("750318156e8c913c378a8d31294fca1084df3be3967035425f470f81e00cd824d1f12bf8e1c3b308f4b1a916438b9ce630722bc8d92ef0feebbbaf987dd7a60e"),
testutil.MustDecodeHexString("be7c7e0ba54109c8c457cdbba4691d7aaae32eb4b8ac63755f2494be406027ce66c7b4730bfd2506fa2caaba12a7bbbea2faca5f07bb64fe06a568b6415e7506"),
testutil.MustDecodeHexString("9938ea16d6caae68b7e9318f1aed387ef9767dc0d80db807e0d0a77065229ceffef7a8b6407882f5d6e29b2edf1c6373bb1c47188138068e2baa4851c04c6f0e"),
import (
"sort"
+ "github.com/bytom/bytom/config"
"github.com/bytom/bytom/consensus"
"github.com/bytom/bytom/protocol/bc"
)
type SupLink struct {
SourceHeight uint64
SourceHash bc.Hash
- Signatures [consensus.NumOfValidators]string
+ Signatures [consensus.MaxNumOfValidators]string
}
// IsMajority if at least 2/3 of validators have published votes with sup link
-func (s *SupLink) IsMajority() bool {
+func (s *SupLink) IsMajority(numOfValidators int) bool {
numOfSignatures := 0
for _, signature := range s.Signatures {
if signature != "" {
numOfSignatures++
}
}
- return numOfSignatures > consensus.NumOfValidators*2/3
+ return numOfSignatures > numOfValidators*2/3
}
// Checkpoint represent the block/hash under consideration for finality for a given epoch.
}
}
+ if len(validators) == 0 {
+ return federationValidators()
+ }
+
sort.Slice(validators, func(i, j int) bool {
return validators[i].Guaranty+validators[i].Vote > validators[j].Guaranty+validators[j].Vote
})
result := make(map[string]*Validator)
- for i := 0; i < len(validators) && i < consensus.NumOfValidators; i++ {
+ for i := 0; i < len(validators) && i < consensus.MaxNumOfValidators; i++ {
validator := validators[i]
validator.Order = i
result[validator.PubKey] = validator
}
-
return result
}
+
+func federationValidators() map[string]*Validator {
+ validators := map[string]*Validator{}
+ for i, xPub := range config.CommonConfig.Federation.Xpubs {
+ validators[xPub.String()] = &Validator{PubKey: xPub.String(), Order: i}
+ }
+ return validators
+}