Skip to content
This repository has been archived by the owner on Dec 4, 2024. It is now read-only.

Commit

Permalink
[Feature] Adding new flag which enables custom block time value (#384)
Browse files Browse the repository at this point in the history
* block time configurable via block_time flag

* changed block time unit to milliseconds

* changed block headers timestamp to msec

* changed input flag default to 2000; changed description

* changed log output to milliseconds

* changed Prometheus metric for block time to milliseconds

* fix block_interval metric

* fix consensus_rounds metric to correspond to log output

* fix helper config merge BlockTime value

 * added comments to indicate milliseconds

* changed time.UnixMili to custom time functions for go backward compatibility

* set default block time as const
  • Loading branch information
ZeljkoBenovic authored Jan 27, 2022
1 parent dea5094 commit a5313a9
Show file tree
Hide file tree
Showing 10 changed files with 67 additions and 19 deletions.
2 changes: 1 addition & 1 deletion blockchain/blockchain.go
Original file line number Diff line number Diff line change
Expand Up @@ -646,7 +646,7 @@ func (b *Blockchain) WriteBlock(block *types.Block) error {

if prevHeader, ok := b.GetHeaderByNumber(header.Number - 1); ok {
diff := header.Timestamp - prevHeader.Timestamp
logArgs = append(logArgs, "generation_time_in_sec", diff)
logArgs = append(logArgs, "generation_time_in_miliseconds", diff)
}

b.logger.Info("new block", logArgs...)
Expand Down
15 changes: 15 additions & 0 deletions command/helper/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ type Config struct {
Join string `json:"join_addr"`
Consensus map[string]interface{} `json:"consensus"`
RestoreFile string `json:"restore_file"`
BlockTime uint64 `json:"block_time_ms"` // block time im miliseconds
}

// Telemetry holds the config details for metric services.
Expand All @@ -59,6 +60,9 @@ type TxPool struct {
MaxSlots uint64 `json:"max_slots"`
}

// variable defining default BlockTime parameter in miliseconds
const defaultBlockTime uint64 = 2000

// DefaultConfig returns the default server configuration
func DefaultConfig() *Config {
return &Config{
Expand All @@ -80,6 +84,7 @@ func DefaultConfig() *Config {
Consensus: map[string]interface{}{},
LogLevel: "INFO",
RestoreFile: "",
BlockTime: defaultBlockTime, // default block time in miliseconds
}
}

Expand Down Expand Up @@ -177,6 +182,11 @@ func (c *Config) BuildConfig() (*server.Config, error) {
conf.RestoreFile = &c.RestoreFile
}

// set block time if not default
if c.BlockTime != defaultBlockTime {
conf.BlockTime = c.BlockTime
}

// if we are in dev mode, change the consensus protocol with 'dev'
// and disable discovery of other nodes
// TODO: Disable networking altogether.
Expand Down Expand Up @@ -311,6 +321,11 @@ func (c *Config) mergeConfigWith(otherConfig *Config) error {
c.RestoreFile = otherConfig.RestoreFile
}

// if block time not default, set to new value
if otherConfig.BlockTime != defaultBlockTime {
c.BlockTime = otherConfig.BlockTime
}

if err := mergo.Merge(&c.Consensus, otherConfig.Consensus, mergo.WithOverride); err != nil {
return err
}
Expand Down
1 change: 1 addition & 0 deletions command/helper/helper.go
Original file line number Diff line number Diff line change
Expand Up @@ -472,6 +472,7 @@ func ReadConfig(baseCommand string, args []string) (*Config, error) {
flags.StringVar(&cliConfig.BlockGasTarget, "block-gas-target", strconv.FormatUint(0, 10), "")
flags.StringVar(&cliConfig.Secrets, "secrets-config", "", "")
flags.StringVar(&cliConfig.RestoreFile, "restore", "", "")
flags.Uint64Var(&cliConfig.BlockTime, "block-time", config.BlockTime, "")

if err := flags.Parse(args); err != nil {
return nil, err
Expand Down
8 changes: 8 additions & 0 deletions command/server/server_command.go
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,14 @@ func (c *ServerCommand) DefineFlags() {
},
FlagOptional: true,
}

c.FlagMap["block-time"] = helper.FlagDescriptor{
Description: fmt.Sprintf("Sets block time in miliseconds. Default: %d", helper.DefaultConfig().BlockTime),
Arguments: []string{
"BLOCK_TIME",
},
FlagOptional: true,
}
}

// GetHelperText returns a simple description of the command
Expand Down
1 change: 1 addition & 0 deletions consensus/consensus.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ type ConsensusParams struct {
Logger hclog.Logger
Metrics *Metrics
SecretsManager secrets.SecretsManager
BlockTime uint64 // block time im miliseconds
}

// Factory is the factory function to create a discovery backend
Expand Down
35 changes: 21 additions & 14 deletions consensus/ibft/ibft.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,8 @@ type Ibft struct {
secretsManager secrets.SecretsManager

mechanism ConsensusMechanism // IBFT ConsensusMechanism used (PoA / PoS)

blockTime uint64 // Configurable consensus blocktime in miliseconds
}

// Define the type of the IBFT consensus
Expand Down Expand Up @@ -245,6 +247,7 @@ func Factory(
sealing: params.Seal,
metrics: params.Metrics,
secretsManager: params.SecretsManager,
blockTime: params.BlockTime,
}

// Initialize the mechanism
Expand Down Expand Up @@ -576,8 +579,6 @@ func (i *Ibft) runSyncState() {
}
}

var defaultBlockPeriod = 2 * time.Second

// buildBlock builds the block, based on the passed in snapshot and parent header
func (i *Ibft) buildBlock(snap *Snapshot, parent *types.Header) (*types.Block, error) {
header := &types.Header{
Expand Down Expand Up @@ -608,15 +609,18 @@ func (i *Ibft) buildBlock(snap *Snapshot, parent *types.Header) (*types.Block, e
i.logger.Error(fmt.Sprintf("Unable to run hook %s, %v", CandidateVoteHook, hookErr))
}

// calculate millisecond values from consensus custom functions in utils.go file
// to preserve go backward compatibility as time.UnixMili is available as of go 17

// set the timestamp
parentTime := time.Unix(int64(parent.Timestamp), 0)
headerTime := parentTime.Add(defaultBlockPeriod)
parentTime := consensus.MilliToUnix(parent.Timestamp)
headerTime := parentTime.Add(time.Duration(i.blockTime) * time.Millisecond)

if headerTime.Before(time.Now()) {
headerTime = time.Now()
}

header.Timestamp = uint64(headerTime.Unix())
header.Timestamp = consensus.UnixToMilli(headerTime)

// we need to include in the extra field the current set of validators
putIbftExtraValidators(header, snap.Set)
Expand Down Expand Up @@ -732,8 +736,11 @@ func (i *Ibft) writeTransactions(gasLimit uint64, transition transitionInterface
// If it turns out that the current node is the proposer, it builds a block,
// and sends preprepare and then prepare messages.
func (i *Ibft) runAcceptState() { // start new round
// set log output
logger := i.logger.Named("acceptState")
logger.Info("Accept state", "sequence", i.state.view.Sequence, "round", i.state.view.Round+1)
// set consensus_rounds metric output
i.metrics.Rounds.Set(float64(i.state.view.Round + 1))

// This is the state in which we either propose a block or wait for the pre-prepare message
parent := i.blockchain.Header()
Expand Down Expand Up @@ -798,7 +805,7 @@ func (i *Ibft) runAcceptState() { // start new round
}

// calculate how much time do we have to wait to mine the block
delay := time.Until(time.Unix(int64(i.state.block.Header.Timestamp), 0))
delay := time.Until(consensus.MilliToUnix(i.state.block.Header.Timestamp))

select {
case <-time.After(delay):
Expand Down Expand Up @@ -970,15 +977,15 @@ func (i *Ibft) runValidateState() {
// updateMetrics will update various metrics based on the given block
// currently we capture No.of Txs and block interval metrics using this function
func (i *Ibft) updateMetrics(block *types.Block) {
// get previous header
prvHeader, _ := i.blockchain.GetHeaderByNumber(block.Number() - 1)
parentTime := time.Unix(int64(prvHeader.Timestamp), 0)
headerTime := time.Unix(int64(block.Header.Timestamp), 0)
//Update the block interval metric
if block.Number() > 1 {
i.metrics.BlockInterval.Observe(
headerTime.Sub(parentTime).Seconds(),
)
}
// calculate difference between previous and current header timestamps
// diff := time.Unix(int64(block.Header.Timestamp),0).Sub(time.Unix(int64(prvHeader.Timestamp),0))
diff := consensus.MilliToUnix(block.Header.Timestamp).Sub(consensus.MilliToUnix(prvHeader.Timestamp))

// update block_interval metric
i.metrics.BlockInterval.Set(float64(diff.Milliseconds()))

//Update the Number of transactions in the block metric
i.metrics.NumTxs.Set(float64(len(block.Body().Transactions)))
}
Expand Down
8 changes: 4 additions & 4 deletions consensus/metrics.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ type Metrics struct {
NumTxs metrics.Gauge

//Time between current block and the previous block in seconds
BlockInterval metrics.Histogram
BlockInterval metrics.Gauge
}

// GetPrometheusMetrics return the consensus metrics instance
Expand Down Expand Up @@ -48,11 +48,11 @@ func GetPrometheusMetrics(namespace string, labelsWithValues ...string) *Metrics
Help: "Number of transactions.",
}, labels).With(labelsWithValues...),

BlockInterval: prometheus.NewHistogramFrom(stdprometheus.HistogramOpts{
BlockInterval: prometheus.NewGaugeFrom(stdprometheus.GaugeOpts{
Namespace: namespace,
Subsystem: "consensus",
Name: "block_interval",
Help: "Time between current block and the previous block in seconds.",
Help: "Time between current block and the previous block in miliseconds.",
}, labels).With(labelsWithValues...),
}
}
Expand All @@ -63,6 +63,6 @@ func NilMetrics() *Metrics {
Validators: discard.NewGauge(),
Rounds: discard.NewGauge(),
NumTxs: discard.NewGauge(),
BlockInterval: discard.NewHistogram(),
BlockInterval: discard.NewGauge(),
}
}
12 changes: 12 additions & 0 deletions consensus/utils.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package consensus

import (
"time"

"github.com/0xPolygon/polygon-edge/types"
"github.com/0xPolygon/polygon-edge/types/buildroot"
)
Expand Down Expand Up @@ -38,3 +40,13 @@ func BuildBlock(params BuildBlockParams) *types.Block {
Transactions: txs,
}
}

// MilliToUnix returns the local Time corresponding to the given Unix time m milliseconds since January 1, 1970 UTC.
func MilliToUnix(m uint64) time.Time {
return time.Unix(0, int64(m)*1e6)
}

// UnixToMilli returns uint64 value for miliseconds
func UnixToMilli(t time.Time) uint64 {
return uint64(t.UnixNano() / 1e6)
}
3 changes: 3 additions & 0 deletions server/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (

const DefaultGRPCPort int = 9632
const DefaultJSONRPCPort int = 8545
const DefaultBlockTime = 2000 // in milliseconds

// Config is used to parametrize the minimal client
type Config struct {
Expand All @@ -26,6 +27,7 @@ type Config struct {
MaxSlots uint64
SecretsManager *secrets.SecretsManagerConfig
RestoreFile *string
BlockTime uint64
}

// DefaultConfig returns the default config for JSON-RPC, GRPC (ports) and Networking
Expand All @@ -36,6 +38,7 @@ func DefaultConfig() *Config {
Network: network.DefaultConfig(),
Telemetry: &Telemetry{PrometheusAddr: nil},
SecretsManager: nil,
BlockTime: DefaultBlockTime, // default block time in milliseconds
}
}

Expand Down
1 change: 1 addition & 0 deletions server/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -362,6 +362,7 @@ func (s *Server) setupConsensus() error {
Logger: s.logger.Named("consensus"),
Metrics: s.serverMetrics.consensus,
SecretsManager: s.secretsManager,
BlockTime: s.config.BlockTime,
},
)

Expand Down

0 comments on commit a5313a9

Please sign in to comment.