go-ethereum/params/config.go

1145 lines
41 KiB
Go

// Copyright 2016 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library 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 Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package params
import (
"fmt"
"maps"
"math/big"
"slices"
"strings"
"sync"
"github.com/XinFinOrg/XDPoSChain/common"
"github.com/XinFinOrg/XDPoSChain/log"
)
const (
ConsensusEngineVersion1 = "v1"
ConsensusEngineVersion2 = "v2"
Default = 0
)
var (
MainnetGenesisHash = common.HexToHash("0x4a9d748bd78a8d0385b67788c2435dcdb914f98a96250b68863a1f8b7642d6b1") // XDC Mainnet genesis hash to enforce below configs on
TestnetGenesisHash = common.HexToHash("0xbdea512b4f12ff1135ec92c00dc047ffb93890c2ea1aa0eefe9b013d80640075") // XDC Testnet genesis hash to enforce below configs on
DevnetGenesisHash = common.HexToHash("0x3c636c841ebee9121374fa76bd5480d17a23e1ba61d425dde21d7b3caba864f4") // XDC Devnet genesis hash to enforce below configs on
)
var (
MainnetV2Configs = map[uint64]*V2Config{
Default: {
MaxMasternodes: 108,
SwitchRound: 0,
CertThreshold: 0.667,
TimeoutSyncThreshold: 3,
TimeoutPeriod: 30,
MinePeriod: 2,
ExpTimeoutConfig: ExpTimeoutConfig{Base: 1.0, MaxExponent: 0},
},
2000: {
MaxMasternodes: 108,
SwitchRound: 2000,
CertThreshold: 0.667,
TimeoutSyncThreshold: 2,
TimeoutPeriod: 600,
MinePeriod: 2,
ExpTimeoutConfig: ExpTimeoutConfig{Base: 1.0, MaxExponent: 0},
},
8000: {
MaxMasternodes: 108,
SwitchRound: 8000,
CertThreshold: 0.667,
TimeoutSyncThreshold: 2,
TimeoutPeriod: 60,
MinePeriod: 2,
ExpTimeoutConfig: ExpTimeoutConfig{Base: 1.0, MaxExponent: 0},
},
220000: {
MaxMasternodes: 108,
SwitchRound: 220000,
CertThreshold: 0.667,
TimeoutSyncThreshold: 2,
TimeoutPeriod: 30,
MinePeriod: 2,
ExpTimeoutConfig: ExpTimeoutConfig{Base: 1.0, MaxExponent: 0},
},
460000: {
MaxMasternodes: 108,
SwitchRound: 460000,
CertThreshold: 0.667,
TimeoutSyncThreshold: 2,
TimeoutPeriod: 20,
MinePeriod: 2,
ExpTimeoutConfig: ExpTimeoutConfig{Base: 1.0, MaxExponent: 0},
},
3200000: {
MaxMasternodes: 108,
SwitchRound: 3200000,
CertThreshold: 0.667,
TimeoutSyncThreshold: 3,
TimeoutPeriod: 10,
MinePeriod: 2,
ExpTimeoutConfig: ExpTimeoutConfig{Base: 1.0, MaxExponent: 0},
},
}
TestnetV2Configs = map[uint64]*V2Config{
Default: {
MaxMasternodes: 15,
SwitchRound: 0,
CertThreshold: 0.45,
TimeoutSyncThreshold: 3,
TimeoutPeriod: 60,
MinePeriod: 2,
ExpTimeoutConfig: ExpTimeoutConfig{Base: 1.0, MaxExponent: 0},
},
900000: {
MaxMasternodes: 108,
SwitchRound: 900000,
CertThreshold: 0.667,
TimeoutSyncThreshold: 3,
TimeoutPeriod: 60,
MinePeriod: 2,
ExpTimeoutConfig: ExpTimeoutConfig{Base: 1.0, MaxExponent: 0},
},
15000000: {
MaxMasternodes: 108,
SwitchRound: 15000000,
CertThreshold: 0.667,
TimeoutSyncThreshold: 3,
TimeoutPeriod: 10,
MinePeriod: 2,
ExpTimeoutConfig: ExpTimeoutConfig{Base: 1.0, MaxExponent: 0},
},
}
DevnetV2Configs = map[uint64]*V2Config{
Default: {
SwitchRound: 0,
CertThreshold: 0.667,
TimeoutSyncThreshold: 3,
TimeoutPeriod: 5,
MinePeriod: 2,
ExpTimeoutConfig: ExpTimeoutConfig{Base: 2.0, MaxExponent: 5},
MaxMasternodes: 108,
MaxProtectorNodes: 100,
MaxObverserNodes: 1000,
MasternodeReward: 5000,
ProtectorReward: 4000,
ObserverReward: 1000,
},
252000: {
SwitchRound: 250000,
CertThreshold: 0.667,
TimeoutSyncThreshold: 3,
TimeoutPeriod: 5,
MinePeriod: 2,
ExpTimeoutConfig: ExpTimeoutConfig{Base: 2.0, MaxExponent: 5},
MaxMasternodes: 10,
MaxProtectorNodes: 3,
MaxObverserNodes: 1,
MasternodeReward: 57.06,
ProtectorReward: 45.25,
ObserverReward: 22.62,
},
261000: {
SwitchRound: 261000,
CertThreshold: 0.667,
TimeoutSyncThreshold: 3,
TimeoutPeriod: 5,
MinePeriod: 2,
ExpTimeoutConfig: ExpTimeoutConfig{Base: 2.0, MaxExponent: 5},
MaxMasternodes: 12,
MaxProtectorNodes: 0,
MaxObverserNodes: 1000,
MasternodeReward: 63.42, // 57.078 goes to node, 6.34 goes to foundation
ProtectorReward: 50.27, // 45.243 goes to node, 5.02 goes to foundation
ObserverReward: 25.13, // 22.671 goes to node, 2.51 goes to foundation
},
300000: {
SwitchRound: 300000,
CertThreshold: 0.667,
TimeoutSyncThreshold: 3,
TimeoutPeriod: 5,
MinePeriod: 2,
ExpTimeoutConfig: ExpTimeoutConfig{Base: 2.0, MaxExponent: 5},
MaxMasternodes: 12,
MaxProtectorNodes: 2,
MaxObverserNodes: 2,
MasternodeReward: 63.42, // 57.078 goes to node, 6.34 goes to foundation
ProtectorReward: 50.27, // 45.243 goes to node, 5.02 goes to foundation
ObserverReward: 25.13, // 22.671 goes to node, 2.51 goes to foundation
},
}
UnitTestV2Configs = map[uint64]*V2Config{
Default: {
MaxMasternodes: 18,
SwitchRound: 0,
CertThreshold: 0.667,
TimeoutSyncThreshold: 2,
TimeoutPeriod: 4,
MinePeriod: 2,
ExpTimeoutConfig: ExpTimeoutConfig{Base: 1.0, MaxExponent: 0},
},
10: {
MaxMasternodes: 18,
SwitchRound: 10,
CertThreshold: 0.667,
TimeoutSyncThreshold: 2,
TimeoutPeriod: 4,
MinePeriod: 3,
ExpTimeoutConfig: ExpTimeoutConfig{Base: 1.0, MaxExponent: 0},
},
900: {
MaxMasternodes: 20,
MaxProtectorNodes: 17,
MaxObverserNodes: 1,
SwitchRound: 900,
CertThreshold: 0.667,
TimeoutSyncThreshold: 4,
TimeoutPeriod: 5,
MinePeriod: 2,
ExpTimeoutConfig: ExpTimeoutConfig{Base: 1.0, MaxExponent: 0},
MasternodeReward: 500, // double as Reward
ProtectorReward: 400,
ObserverReward: 300.125,
LimitPenaltyEpoch: 2,
MinimumSigningTx: 2,
},
}
// XDPoSChain mainnet config
XDCMainnetChainConfig = &ChainConfig{
ChainID: big.NewInt(50),
HomesteadBlock: big.NewInt(1),
EIP150Block: big.NewInt(2),
EIP155Block: big.NewInt(3),
EIP158Block: big.NewInt(3),
ByzantiumBlock: big.NewInt(4),
XDPoS: &XDPoSConfig{
Period: 2,
Epoch: 900,
Reward: 5000,
RewardCheckpoint: 900,
Gap: 450,
FoudationWalletAddr: common.HexToAddress("xdc92a289fe95a85c53b8d0d113cbaef0c1ec98ac65"),
V2: &V2{
SwitchEpoch: common.MaintnetConstant.TIPV2SwitchBlock.Uint64() / 900,
SwitchBlock: common.MaintnetConstant.TIPV2SwitchBlock,
CurrentConfig: MainnetV2Configs[0],
AllConfigs: MainnetV2Configs,
},
},
}
// MainnetChainConfig is the chain parameters to run a node on the main network.
MainnetChainConfig = &ChainConfig{
ChainID: big.NewInt(1),
HomesteadBlock: big.NewInt(1150000),
DAOForkBlock: big.NewInt(1920000),
DAOForkSupport: true,
EIP150Block: big.NewInt(2463000),
EIP155Block: big.NewInt(2675000),
EIP158Block: big.NewInt(2675000),
ByzantiumBlock: big.NewInt(4370000),
ConstantinopleBlock: nil,
Ethash: new(EthashConfig),
}
// TestnetChainConfig contains the chain parameters to run a node on the Ropsten test network.
TestnetChainConfig = &ChainConfig{
ChainID: big.NewInt(51),
HomesteadBlock: big.NewInt(1),
DAOForkBlock: nil,
DAOForkSupport: false,
EIP150Block: big.NewInt(2),
EIP155Block: big.NewInt(3),
EIP158Block: big.NewInt(3),
ByzantiumBlock: big.NewInt(4),
ConstantinopleBlock: nil,
XDPoS: &XDPoSConfig{
Period: 2,
Epoch: 900,
Reward: 5000,
RewardCheckpoint: 900,
Gap: 450,
FoudationWalletAddr: common.HexToAddress("xdc746249c61f5832c5eed53172776b460491bdcd5c"),
V2: &V2{
SwitchEpoch: common.TestnetConstant.TIPV2SwitchBlock.Uint64() / 900,
SwitchBlock: common.TestnetConstant.TIPV2SwitchBlock,
CurrentConfig: TestnetV2Configs[0],
AllConfigs: TestnetV2Configs,
},
},
}
// DevnetChainConfig contains the chain parameters to run a node on the Ropsten test network.
DevnetChainConfig = &ChainConfig{
ChainID: big.NewInt(551),
HomesteadBlock: big.NewInt(0),
EIP150Block: big.NewInt(0),
EIP155Block: big.NewInt(0),
EIP158Block: big.NewInt(0),
ByzantiumBlock: big.NewInt(0),
XDPoS: &XDPoSConfig{
Period: 2,
Epoch: 900,
Reward: 10,
RewardCheckpoint: 900,
Gap: 450,
FoudationWalletAddr: common.HexToAddress("0xde5b54e8e7b585153add32f472e8d545e5d42a82"),
V2: &V2{
SwitchEpoch: common.DevnetConstant.TIPV2SwitchBlock.Uint64() / 900,
SwitchBlock: common.DevnetConstant.TIPV2SwitchBlock,
CurrentConfig: DevnetV2Configs[0],
AllConfigs: DevnetV2Configs,
},
},
}
// AllEthashProtocolChanges contains every protocol change (EIPs) introduced
// and accepted by the Ethereum core developers into the Ethash consensus.
//
// This configuration is intentionally not using keyed fields to force anyone
// adding flags to the config to also have to set these fields.
AllEthashProtocolChanges = &ChainConfig{
ChainID: big.NewInt(1337),
HomesteadBlock: big.NewInt(0),
DAOForkBlock: nil,
DAOForkSupport: false,
EIP150Block: big.NewInt(0),
EIP155Block: big.NewInt(0),
EIP158Block: big.NewInt(0),
ByzantiumBlock: big.NewInt(0),
ConstantinopleBlock: nil,
Ethash: new(EthashConfig),
Clique: nil,
XDPoS: nil,
}
// AllXDPoSProtocolChanges contains every protocol change (EIPs) introduced
// and accepted by the Ethereum core developers into the XDPoS consensus.
//
// This configuration is intentionally not using keyed fields to force anyone
// adding flags to the config to also have to set these fields.
AllXDPoSProtocolChanges = &ChainConfig{
ChainID: big.NewInt(89),
HomesteadBlock: big.NewInt(0),
DAOForkBlock: nil,
DAOForkSupport: false,
EIP150Block: big.NewInt(0),
EIP155Block: big.NewInt(0),
EIP158Block: big.NewInt(0),
ByzantiumBlock: big.NewInt(0),
ConstantinopleBlock: nil,
Ethash: nil,
Clique: nil,
XDPoS: &XDPoSConfig{Period: 0, Epoch: 900},
}
AllCliqueProtocolChanges = &ChainConfig{
ChainID: big.NewInt(1337),
HomesteadBlock: big.NewInt(0),
DAOForkBlock: nil,
DAOForkSupport: false,
EIP150Block: big.NewInt(0),
EIP155Block: big.NewInt(0),
EIP158Block: big.NewInt(0),
ByzantiumBlock: big.NewInt(0),
ConstantinopleBlock: nil,
Ethash: nil,
Clique: &CliqueConfig{Period: 0, Epoch: 900},
XDPoS: nil,
}
// XDPoS config with v2 engine after block 901
TestXDPoSMockChainConfig = &ChainConfig{
ChainID: big.NewInt(1337),
HomesteadBlock: big.NewInt(0),
DAOForkBlock: nil,
DAOForkSupport: false,
EIP150Block: big.NewInt(0),
EIP155Block: big.NewInt(0),
EIP158Block: big.NewInt(0),
ByzantiumBlock: big.NewInt(0),
ConstantinopleBlock: big.NewInt(0),
Ethash: new(EthashConfig),
Clique: nil,
XDPoS: &XDPoSConfig{
Epoch: 900,
Gap: 450,
SkipV1Validation: true,
FoudationWalletAddr: common.HexToAddress("0x0000000000000000000000000000000000000068"),
Reward: 250,
V2: &V2{
SwitchEpoch: 1,
SwitchBlock: big.NewInt(900),
CurrentConfig: UnitTestV2Configs[0],
AllConfigs: UnitTestV2Configs,
},
},
}
TestChainConfig = &ChainConfig{
ChainID: big.NewInt(1),
HomesteadBlock: big.NewInt(0),
DAOForkBlock: nil,
DAOForkSupport: false,
EIP150Block: big.NewInt(0),
EIP155Block: big.NewInt(0),
EIP158Block: big.NewInt(0),
ByzantiumBlock: big.NewInt(0),
ConstantinopleBlock: nil,
Ethash: new(EthashConfig),
Clique: nil,
XDPoS: nil,
}
TestRules = TestChainConfig.Rules(new(big.Int))
)
// ChainConfig is the core config which determines the blockchain settings.
//
// ChainConfig is stored in the database on a per block basis. This means
// that any network, identified by its genesis block, can have its own
// set of configuration options.
type ChainConfig struct {
ChainID *big.Int `json:"chainId"` // Chain id identifies the current chain and is used for replay protection
HomesteadBlock *big.Int `json:"homesteadBlock,omitempty"` // Homestead switch block (nil = no fork, 0 = already homestead)
DAOForkBlock *big.Int `json:"daoForkBlock,omitempty"` // TheDAO hard-fork switch block (nil = no fork)
DAOForkSupport bool `json:"daoForkSupport,omitempty"` // Whether the nodes supports or opposes the DAO hard-fork
// EIP150 implements the Gas price changes (https://github.com/ethereum/EIPs/issues/150)
EIP150Block *big.Int `json:"eip150Block,omitempty"` // EIP150 HF block (nil = no fork)
EIP155Block *big.Int `json:"eip155Block,omitempty"` // EIP155 HF block
EIP158Block *big.Int `json:"eip158Block,omitempty"` // EIP158 HF block
ByzantiumBlock *big.Int `json:"byzantiumBlock,omitempty"` // Byzantium switch block (nil = no fork, 0 = already on byzantium)
ConstantinopleBlock *big.Int `json:"constantinopleBlock,omitempty"` // Constantinople switch block (nil = no fork, 0 = already activated)
PetersburgBlock *big.Int `json:"petersburgBlock,omitempty"`
IstanbulBlock *big.Int `json:"istanbulBlock,omitempty"`
BerlinBlock *big.Int `json:"berlinBlock,omitempty"`
LondonBlock *big.Int `json:"londonBlock,omitempty"`
MergeBlock *big.Int `json:"mergeBlock,omitempty"`
ShanghaiBlock *big.Int `json:"shanghaiBlock,omitempty"`
Eip1559Block *big.Int `json:"eip1559Block,omitempty"`
CancunBlock *big.Int `json:"cancunBlock,omitempty"`
// Various consensus engines
Ethash *EthashConfig `json:"ethash,omitempty"`
Clique *CliqueConfig `json:"clique,omitempty"`
XDPoS *XDPoSConfig `json:"XDPoS,omitempty"`
}
// EthashConfig is the consensus engine configs for proof-of-work based sealing.
type EthashConfig struct{}
// String implements the stringer interface, returning the consensus engine details.
func (c *EthashConfig) String() string {
return "ethash"
}
// CliqueConfig is the consensus engine configs for proof-of-authority based sealing.
type CliqueConfig struct {
Period uint64 `json:"period"` // Number of seconds between blocks to enforce
Epoch uint64 `json:"epoch"` // Epoch length to reset votes and checkpoint
}
// String implements the stringer interface, returning the consensus engine details.
func (c *CliqueConfig) String() string {
return "clique"
}
// XDPoSConfig is the consensus engine configs for delegated-proof-of-stake based sealing.
type XDPoSConfig struct {
Period uint64 `json:"period"` // Number of seconds between blocks to enforce
Epoch uint64 `json:"epoch"` // Epoch length to reset votes and checkpoint
Reward uint64 `json:"reward"` // Block reward - unit Ether
RewardCheckpoint uint64 `json:"rewardCheckpoint"` // Checkpoint block for calculate rewards.
Gap uint64 `json:"gap"` // Gap time preparing for the next epoch
FoudationWalletAddr common.Address `json:"foudationWalletAddr"` // Foundation Address Wallet
SkipV1Validation bool //Skip Block Validation for testing purpose, V1 consensus only
V2 *V2 `json:"v2"`
}
type V2 struct {
lock sync.RWMutex // Protects the signer fields
SwitchEpoch uint64
SwitchBlock *big.Int `json:"switchBlock"`
CurrentConfig *V2Config `json:"config"`
AllConfigs map[uint64]*V2Config `json:"allConfigs"`
configIndex []uint64 //list of switch block of configs
SkipV2Validation bool //Skip Block Validation for testing purpose, V2 consensus only
}
type V2Config struct {
MaxMasternodes int `json:"maxMasternodes"` // v2 max masternodes
MaxProtectorNodes int `json:"maxProtectorNodes"` // v2 max ProtectorNodes
MaxObverserNodes int `json:"maxObserverNodes"` // v2 max ObserverNodes
SwitchRound uint64 `json:"switchRound"` // v1 to v2 switch block number
MinePeriod int `json:"minePeriod"` // Miner mine period to mine a block
TimeoutSyncThreshold int `json:"timeoutSyncThreshold"` // send syncInfo after number of timeout
TimeoutPeriod int `json:"timeoutPeriod"` // Duration in ms
CertThreshold float64 `json:"certificateThreshold"` // Necessary number of messages from master nodes to form a certificate
MasternodeReward float64 `json:"masternodeReward"` // Block reward per master node (core validator) - unit Ether
ProtectorReward float64 `json:"protectorReward"` // Block reward per protector - unit Ether
ObserverReward float64 `json:"observerReward"` // Block reward per observer - unit Ether
MinimumMinerBlockPerEpoch int `json:"minimumMinerBlockPerEpoch"` // Minimum block per epoch for a miner to not be penalized
LimitPenaltyEpoch int `json:"limitPenaltyEpoch"` // Epochs in a row that a penalty node needs to be penalized
MinimumSigningTx int `json:"minimumSigningTx"` // Signing txs that a node needs to produce to get out of penalty, after `LimitPenaltyEpoch`
ExpTimeoutConfig ExpTimeoutConfig `json:"expTimeoutConfig"`
}
type ExpTimeoutConfig struct {
Base float64 `json:"base"` // base in base^exponent
MaxExponent uint8 `json:"maxExponent"` // max exponent in base^exponent
}
func XDPoSConfigEqual(a, b *XDPoSConfig) bool {
if a == nil || b == nil {
return a == b
}
if a.Period != b.Period || a.Epoch != b.Epoch || a.Reward != b.Reward || a.RewardCheckpoint != b.RewardCheckpoint || a.Gap != b.Gap || a.FoudationWalletAddr != b.FoudationWalletAddr || a.SkipV1Validation != b.SkipV1Validation {
return false
}
return V2Equal(a.V2, b.V2)
}
func V2Equal(a, b *V2) bool {
if a == nil || b == nil {
return a == b
}
return a.SwitchEpoch == b.SwitchEpoch && configNumEqual(a.SwitchBlock, b.SwitchBlock) && slices.Equal(a.configIndex, b.configIndex) && maps.EqualFunc(a.AllConfigs, b.AllConfigs, V2ConfigEqual)
}
func V2ConfigEqual(a, b *V2Config) bool {
if a == nil || b == nil {
return a == b
}
return *a == *b
}
func (c *XDPoSConfig) String() string {
if c == nil {
return "XDPoSConfig: <nil>"
}
return fmt.Sprintf("XDPoSConfig{Period: %v, Epoch: %v, Reward: %v, RewardCheckpoint: %v, Gap: %v, FoudationWalletAddr: %v, SkipV1Validation: %v, V2: %s}", c.Period, c.Epoch, c.Reward, c.RewardCheckpoint, c.Gap, c.FoudationWalletAddr.String0x(), c.SkipV1Validation, c.V2.String())
}
func (c *XDPoSConfig) Description(indent int) string {
if c == nil {
return "XDPoS: <nil>"
}
banner := "XDPoS\n"
prefix := strings.Repeat(" ", indent)
banner += fmt.Sprintf("%s- Period: %v\n", prefix, c.Period)
banner += fmt.Sprintf("%s- Epoch: %v\n", prefix, c.Epoch)
banner += fmt.Sprintf("%s- Reward: %v\n", prefix, c.Reward)
banner += fmt.Sprintf("%s- RewardCheckpoint: %v\n", prefix, c.RewardCheckpoint)
banner += fmt.Sprintf("%s- Gap: %v\n", prefix, c.Gap)
banner += fmt.Sprintf("%s- FoudationWalletAddr: %v\n", prefix, c.FoudationWalletAddr.Hex())
banner += fmt.Sprintf("%s- SkipV1Validation: %v\n", prefix, c.SkipV1Validation)
banner += fmt.Sprintf("%s- %s", prefix, c.V2.Description(indent+2))
return banner
}
func (v2 *V2) String() string {
if v2 == nil {
return "V2: <nil>"
}
return fmt.Sprintf("V2{SwitchEpoch: %v, SwitchBlock: %v, SkipV2Validation: %v, %s}", v2.SwitchEpoch, v2.SwitchBlock, v2.SkipV2Validation, v2.CurrentConfig.String())
}
func (v2 *V2) Description(indent int) string {
if v2 == nil {
return "V2: <nil>"
}
banner := "V2:\n"
prefix := strings.Repeat(" ", indent)
banner += fmt.Sprintf("%s- SwitchEpoch: %v\n", prefix, v2.SwitchEpoch)
banner += fmt.Sprintf("%s- SwitchBlock: %v\n", prefix, v2.SwitchBlock)
banner += fmt.Sprintf("%s- SkipV2Validation: %v\n", prefix, v2.SkipV2Validation)
banner += fmt.Sprintf("%s- %s", prefix, v2.GetCurrentConfig().Description("CurrentConfig", indent+2))
return banner
}
func (c *V2Config) String() string {
if c == nil {
return "V2Config: <nil>"
}
return fmt.Sprintf("V2{MaxMasternodes: %v, MaxProtectorNodes: %v, MaxObverserNodes: %v, SwitchRound: %v, MinePeriod: %v, TimeoutSyncThreshold: %v, TimeoutPeriod: %v, CertThreshold: %v, MasternodeReward: %v, ProtectorReward: %v, ObserverReward: %v, MinimumMinerBlockPerEpoch: %v, LimitPenaltyEpoch: %v, MinimumSigningTx: %v, %s}", c.MaxMasternodes, c.MaxProtectorNodes, c.MaxObverserNodes, c.SwitchRound, c.MinePeriod, c.TimeoutSyncThreshold, c.TimeoutPeriod, c.CertThreshold, c.MasternodeReward, c.ProtectorReward, c.ObserverReward, c.MinimumMinerBlockPerEpoch, c.LimitPenaltyEpoch, c.MinimumSigningTx, c.ExpTimeoutConfig.String())
}
func (c *V2Config) Description(name string, indent int) string {
if c == nil {
return name + ": <nil>"
}
banner := name + ":\n"
prefix := strings.Repeat(" ", indent)
banner += fmt.Sprintf("%s- MaxMasternodes: %v\n", prefix, c.MaxMasternodes)
banner += fmt.Sprintf("%s- SwitchRound: %v\n", prefix, c.SwitchRound)
banner += fmt.Sprintf("%s- MinePeriod: %v\n", prefix, c.MinePeriod)
banner += fmt.Sprintf("%s- TimeoutSyncThreshold: %v\n", prefix, c.TimeoutSyncThreshold)
banner += fmt.Sprintf("%s- TimeoutPeriod: %v\n", prefix, c.TimeoutPeriod)
banner += fmt.Sprintf("%s- CertThreshold: %v\n", prefix, c.CertThreshold)
banner += fmt.Sprintf("%s- MasternodeReward: %v\n", prefix, c.MasternodeReward)
banner += fmt.Sprintf("%s- ProtectorReward: %v\n", prefix, c.ProtectorReward)
banner += fmt.Sprintf("%s- ObserverReward: %v\n", prefix, c.ObserverReward)
banner += fmt.Sprintf("%s- MinimumMinerBlockPerEpoch: %v\n", prefix, c.MinimumMinerBlockPerEpoch)
banner += fmt.Sprintf("%s- LimitPenaltyEpoch: %v\n", prefix, c.LimitPenaltyEpoch)
banner += fmt.Sprintf("%s- MinimumSigningTx: %v\n", prefix, c.MinimumSigningTx)
banner += fmt.Sprintf("%s- ExpTimeoutBase: %v\n", prefix, c.ExpTimeoutConfig.Base)
banner += fmt.Sprintf("%s- ExpTimeoutMaxExponent: %v", prefix, c.ExpTimeoutConfig.MaxExponent)
return banner
}
func (c ExpTimeoutConfig) String() string {
return fmt.Sprintf("ExpTimeoutConfig{Base: %v, MaxExponent: %v}", c.Base, c.MaxExponent)
}
func (c *XDPoSConfig) BlockConsensusVersion(num *big.Int) string {
if c.V2 != nil && c.V2.SwitchBlock != nil && num.Cmp(c.V2.SwitchBlock) > 0 {
return ConsensusEngineVersion2
}
return ConsensusEngineVersion1
}
func (v2 *V2) UpdateConfig(round uint64) {
v2.lock.Lock()
defer v2.lock.Unlock()
var index uint64
//find the right config
for i := range v2.configIndex {
if v2.configIndex[i] <= round {
index = v2.configIndex[i]
break
}
}
// update to current config
log.Info("[updateV2Config] Update config", "index", index, "round", round, "SwitchRound", v2.AllConfigs[index].SwitchRound)
v2.CurrentConfig = v2.AllConfigs[index]
}
// GetCurrentConfig returns a opy of the current config, it assumes v2 is not nil
func (v2 *V2) GetCurrentConfig() *V2Config {
v2.lock.RLock()
defer v2.lock.RUnlock()
if v2.CurrentConfig == nil {
return nil
}
// avoid CurrentConfig is changed by other goroutines
cpyConfig := *v2.CurrentConfig
return &cpyConfig
}
func (v2 *V2) Config(round uint64) *V2Config {
configRound := round
var index uint64
//find the right config
for i := range v2.configIndex {
if v2.configIndex[i] <= configRound {
index = v2.configIndex[i]
break
}
}
return v2.AllConfigs[index]
}
func (v2 *V2) BuildConfigIndex() {
var list []uint64
for i := range v2.AllConfigs {
list = append(list, i)
}
// sort, sort lib doesn't support type uint64, it's ok to have O(n^2) because only few items in the list
// Make it descending order
for i := 0; i < len(list)-1; i++ {
for j := i + 1; j < len(list); j++ {
if list[i] < list[j] {
list[i], list[j] = list[j], list[i]
}
}
}
log.Info("[BuildConfigIndex] config list", "list", list)
v2.configIndex = list
}
func (v2 *V2) ConfigIndex() []uint64 {
return v2.configIndex
}
// String implements the fmt.Stringer interface, returning a string representation
// of ChainConfig.
func (c *ChainConfig) String() string {
result := fmt.Sprintf("ChainConfig{ChainID: %v", c.ChainID)
// Add block-based forks
if c.HomesteadBlock != nil {
result += fmt.Sprintf(", HomesteadBlock: %v", c.HomesteadBlock)
}
if c.DAOForkBlock != nil {
result += fmt.Sprintf(", DAOForkBlock: %v", c.DAOForkBlock)
}
if c.EIP150Block != nil {
result += fmt.Sprintf(", EIP150Block: %v", c.EIP150Block)
}
if c.EIP155Block != nil {
result += fmt.Sprintf(", EIP155Block: %v", c.EIP155Block)
}
if c.EIP158Block != nil {
result += fmt.Sprintf(", EIP158Block: %v", c.EIP158Block)
}
if c.ByzantiumBlock != nil {
result += fmt.Sprintf(", ByzantiumBlock: %v", c.ByzantiumBlock)
}
if c.ConstantinopleBlock != nil {
result += fmt.Sprintf(", ConstantinopleBlock: %v", c.ConstantinopleBlock)
}
if c.PetersburgBlock != nil {
result += fmt.Sprintf(", PetersburgBlock: %v", c.PetersburgBlock)
}
if c.IstanbulBlock != nil {
result += fmt.Sprintf(", IstanbulBlock: %v", c.IstanbulBlock)
}
if c.BerlinBlock != nil {
result += fmt.Sprintf(", BerlinBlock: %v", c.BerlinBlock)
}
if c.LondonBlock != nil {
result += fmt.Sprintf(", LondonBlock: %v", c.LondonBlock)
}
if c.MergeBlock != nil {
result += fmt.Sprintf(", MergeBlock: %v", c.MergeBlock)
}
if c.ShanghaiBlock != nil {
result += fmt.Sprintf(", ShanghaiBlock: %v", c.ShanghaiBlock)
}
if c.CancunBlock != nil {
result += fmt.Sprintf(", CancunBlock: %v", c.CancunBlock)
}
if c.XDPoS != nil {
result += fmt.Sprintf(", %s", c.XDPoS.String())
}
result += "}"
return result
}
// Description returns a human-readable description of ChainConfig.
func (c *ChainConfig) Description() string {
var engine interface{}
switch {
case c.Ethash != nil:
engine = c.Ethash
case c.XDPoS != nil:
engine = c.XDPoS.Description(4)
default:
engine = "unknown"
}
berlinBlock := common.BerlinBlock
if c.BerlinBlock != nil {
berlinBlock = c.BerlinBlock
}
londonBlock := common.LondonBlock
if c.LondonBlock != nil {
londonBlock = c.LondonBlock
}
mergeBlock := common.MergeBlock
if c.MergeBlock != nil {
mergeBlock = c.MergeBlock
}
shanghaiBlock := common.ShanghaiBlock
if c.ShanghaiBlock != nil {
shanghaiBlock = c.ShanghaiBlock
}
eip1559Block := common.Eip1559Block
if c.Eip1559Block != nil {
eip1559Block = c.Eip1559Block
}
cancunBlock := common.CancunBlock
if c.CancunBlock != nil {
cancunBlock = c.CancunBlock
}
var banner = "Chain configuration:\n"
banner += fmt.Sprintf(" - ChainID: %-8v\n", c.ChainID)
banner += fmt.Sprintf(" - Homestead: %-8v\n", c.HomesteadBlock)
banner += fmt.Sprintf(" - DAO Fork: %-8v\n", c.DAOForkBlock)
banner += fmt.Sprintf(" - DAO Support: %-8v\n", c.DAOForkSupport)
banner += fmt.Sprintf(" - Tangerine Whistle (EIP 150): %-8v\n", c.EIP150Block)
banner += fmt.Sprintf(" - Spurious Dragon (EIP 155): %-8v\n", c.EIP155Block)
banner += fmt.Sprintf(" - Byzantium: %-8v\n", c.ByzantiumBlock)
banner += fmt.Sprintf(" - Constantinople: %-8v\n", c.ConstantinopleBlock)
banner += fmt.Sprintf(" - Petersburg: %-8v\n", c.PetersburgBlock)
banner += fmt.Sprintf(" - Istanbul: %-8v\n", c.IstanbulBlock)
banner += fmt.Sprintf(" - Berlin: %-8v\n", berlinBlock)
banner += fmt.Sprintf(" - London: %-8v\n", londonBlock)
banner += fmt.Sprintf(" - Merge: %-8v\n", mergeBlock)
banner += fmt.Sprintf(" - Shanghai: %-8v\n", shanghaiBlock)
banner += fmt.Sprintf(" - Eip1559: %-8v\n", eip1559Block)
banner += fmt.Sprintf(" - Cancun: %-8v\n", cancunBlock)
banner += fmt.Sprintf(" - TIPUpgradeReward: %-8v\n", common.TIPUpgradeReward)
banner += fmt.Sprintf(" - TIPEpochHalving: %-8v\n", common.TIPEpochHalving)
banner += fmt.Sprintf(" - Engine: %v", engine)
return banner
}
// IsHomestead returns whether num is either equal to the homestead block or greater.
func (c *ChainConfig) IsHomestead(num *big.Int) bool {
return isForked(c.HomesteadBlock, num)
}
// IsDAO returns whether num is either equal to the DAO fork block or greater.
func (c *ChainConfig) IsDAOFork(num *big.Int) bool {
return isForked(c.DAOForkBlock, num)
}
func (c *ChainConfig) IsEIP150(num *big.Int) bool {
return isForked(c.EIP150Block, num)
}
func (c *ChainConfig) IsEIP155(num *big.Int) bool {
return isForked(c.EIP155Block, num)
}
func (c *ChainConfig) IsEIP158(num *big.Int) bool {
return isForked(c.EIP158Block, num)
}
func (c *ChainConfig) IsByzantium(num *big.Int) bool {
return isForked(c.ByzantiumBlock, num)
}
func (c *ChainConfig) IsConstantinople(num *big.Int) bool {
return isForked(c.ConstantinopleBlock, num)
}
// IsPetersburg returns whether num is either
// - equal to or greater than the PetersburgBlock fork block,
// - OR is nil, and Constantinople is active
func (c *ChainConfig) IsPetersburg(num *big.Int) bool {
return isForked(common.TIPXDCXCancellationFee, num) || isForked(c.PetersburgBlock, num)
}
// IsIstanbul returns whether num is either equal to the Istanbul fork block or greater.
func (c *ChainConfig) IsIstanbul(num *big.Int) bool {
return isForked(common.TIPXDCXCancellationFee, num) || isForked(c.IstanbulBlock, num)
}
// IsBerlin returns whether num is either equal to the Berlin fork block or greater.
func (c *ChainConfig) IsBerlin(num *big.Int) bool {
return isForked(common.BerlinBlock, num) || isForked(c.BerlinBlock, num)
}
// IsLondon returns whether num is either equal to the London fork block or greater.
func (c *ChainConfig) IsLondon(num *big.Int) bool {
return isForked(common.LondonBlock, num) || isForked(c.LondonBlock, num)
}
// IsMerge returns whether num is either equal to the Merge fork block or greater.
// Different from Geth which uses `block.difficulty != nil`
func (c *ChainConfig) IsMerge(num *big.Int) bool {
return isForked(common.MergeBlock, num) || isForked(c.MergeBlock, num)
}
// IsShanghai returns whether num is either equal to the Shanghai fork block or greater.
func (c *ChainConfig) IsShanghai(num *big.Int) bool {
return isForked(common.ShanghaiBlock, num) || isForked(c.ShanghaiBlock, num)
}
func (c *ChainConfig) IsEIP1559(num *big.Int) bool {
return isForked(common.Eip1559Block, num) || isForked(c.Eip1559Block, num)
}
func (c *ChainConfig) IsCancun(num *big.Int) bool {
return isForked(common.CancunBlock, num) || isForked(c.CancunBlock, num)
}
func (c *ChainConfig) IsTIP2019(num *big.Int) bool {
return isForked(common.TIP2019Block, num)
}
func (c *ChainConfig) IsTIPSigning(num *big.Int) bool {
return isForked(common.TIPSigning, num)
}
func (c *ChainConfig) IsTIPRandomize(num *big.Int) bool {
return isForked(common.TIPRandomize, num)
}
// IsTIPIncreaseMasternodes using for increase masternodes from 18 to 40
// Time update: 23-07-2019
func (c *ChainConfig) IsTIPIncreaseMasternodes(num *big.Int) bool {
return isForked(common.TIPIncreaseMasternodes, num)
}
func (c *ChainConfig) IsTIPNoHalvingMNReward(num *big.Int) bool {
return isForked(common.TIPNoHalvingMNReward, num)
}
func (c *ChainConfig) IsTIPXDCX(num *big.Int) bool {
return isForked(common.TIPXDCX, num)
}
func (c *ChainConfig) IsTIPXDCXMiner(num *big.Int) bool {
return isForked(common.TIPXDCX, num) && !isForked(common.TIPXDCXMinerDisable, num)
}
func (c *ChainConfig) IsTIPXDCXReceiver(num *big.Int) bool {
return isForked(common.TIPXDCX, num) && !isForked(common.TIPXDCXReceiverDisable, num)
}
func (c *ChainConfig) IsXDCxDisable(num *big.Int) bool {
return isForked(common.TIPXDCXMinerDisable, num)
}
func (c *ChainConfig) IsTIPXDCXLending(num *big.Int) bool {
return isForked(common.TIPXDCXLending, num)
}
func (c *ChainConfig) IsTIPXDCXCancellationFee(num *big.Int) bool {
return isForked(common.TIPXDCXCancellationFee, num)
}
func (c *ChainConfig) IsTIPUpgradeReward(num *big.Int) bool {
return isForked(common.TIPUpgradeReward, num)
}
func (c *ChainConfig) IsTIPUpgradePenalty(num *big.Int) bool {
return isForked(common.TipUpgradePenalty, num)
}
func (c *ChainConfig) IsTIPEpochHalving(num *big.Int) bool {
return isForked(common.TIPEpochHalving, num)
}
// GasTable returns the gas table corresponding to the current phase (homestead or homestead reprice).
//
// The returned GasTable's fields shouldn't, under any circumstances, be changed.
func (c *ChainConfig) GasTable(num *big.Int) GasTable {
if num == nil {
return GasTableHomestead
}
switch {
case c.IsEIP158(num):
return GasTableEIP158
case c.IsEIP150(num):
return GasTableEIP150
default:
return GasTableHomestead
}
}
// CheckCompatible checks whether scheduled fork transitions have been imported
// with a mismatching chain configuration.
func (c *ChainConfig) CheckCompatible(newcfg *ChainConfig, height uint64) *ConfigCompatError {
bhead := new(big.Int).SetUint64(height)
// Iterate checkCompatible to find the lowest conflict.
var lasterr *ConfigCompatError
for {
err := c.checkCompatible(newcfg, bhead)
if err == nil || (lasterr != nil && err.RewindTo == lasterr.RewindTo) {
break
}
lasterr = err
bhead.SetUint64(err.RewindTo)
}
return lasterr
}
func (c *ChainConfig) checkCompatible(newcfg *ChainConfig, head *big.Int) *ConfigCompatError {
if isForkIncompatible(c.HomesteadBlock, newcfg.HomesteadBlock, head) {
return newCompatError("Homestead fork block", c.HomesteadBlock, newcfg.HomesteadBlock)
}
if isForkIncompatible(c.DAOForkBlock, newcfg.DAOForkBlock, head) {
return newCompatError("DAO fork block", c.DAOForkBlock, newcfg.DAOForkBlock)
}
if c.IsDAOFork(head) && c.DAOForkSupport != newcfg.DAOForkSupport {
return newCompatError("DAO fork support flag", c.DAOForkBlock, newcfg.DAOForkBlock)
}
if isForkIncompatible(c.EIP150Block, newcfg.EIP150Block, head) {
return newCompatError("EIP150 fork block", c.EIP150Block, newcfg.EIP150Block)
}
if isForkIncompatible(c.EIP155Block, newcfg.EIP155Block, head) {
return newCompatError("EIP155 fork block", c.EIP155Block, newcfg.EIP155Block)
}
if isForkIncompatible(c.EIP158Block, newcfg.EIP158Block, head) {
return newCompatError("EIP158 fork block", c.EIP158Block, newcfg.EIP158Block)
}
if c.IsEIP158(head) && !configNumEqual(c.ChainID, newcfg.ChainID) {
return newCompatError("EIP158 chain ID", c.EIP158Block, newcfg.EIP158Block)
}
if isForkIncompatible(c.ByzantiumBlock, newcfg.ByzantiumBlock, head) {
return newCompatError("Byzantium fork block", c.ByzantiumBlock, newcfg.ByzantiumBlock)
}
if isForkIncompatible(c.ConstantinopleBlock, newcfg.ConstantinopleBlock, head) {
return newCompatError("Constantinople fork block", c.ConstantinopleBlock, newcfg.ConstantinopleBlock)
}
if isForkIncompatible(c.PetersburgBlock, newcfg.PetersburgBlock, head) {
// the only case where we allow Petersburg to be set in the past is if it is equal to Constantinople
// mainly to satisfy fork ordering requirements which state that Petersburg fork be set if Constantinople fork is set
if isForkIncompatible(c.ConstantinopleBlock, newcfg.PetersburgBlock, head) {
return newCompatError("Petersburg fork block", c.PetersburgBlock, newcfg.PetersburgBlock)
}
}
if isForkIncompatible(c.IstanbulBlock, newcfg.IstanbulBlock, head) {
return newCompatError("Istanbul fork block", c.IstanbulBlock, newcfg.IstanbulBlock)
}
if isForkIncompatible(c.BerlinBlock, newcfg.BerlinBlock, head) {
return newCompatError("Berlin fork block", c.BerlinBlock, newcfg.BerlinBlock)
}
if isForkIncompatible(c.LondonBlock, newcfg.LondonBlock, head) {
return newCompatError("London fork block", c.LondonBlock, newcfg.LondonBlock)
}
if isForkIncompatible(c.ShanghaiBlock, newcfg.ShanghaiBlock, head) {
return newCompatError("Shanghai fork block", c.ShanghaiBlock, newcfg.ShanghaiBlock)
}
if isForkIncompatible(c.Eip1559Block, newcfg.Eip1559Block, head) {
return newCompatError("Eip1559 fork block", c.Eip1559Block, newcfg.Eip1559Block)
}
if isForkIncompatible(c.CancunBlock, newcfg.CancunBlock, head) {
return newCompatError("Cancun fork block", c.CancunBlock, newcfg.CancunBlock)
}
if !XDPoSConfigEqual(c.XDPoS, newcfg.XDPoS) {
storedblock := big.NewInt(1)
if c.XDPoS != nil && c.XDPoS.V2 != nil && c.XDPoS.V2.SwitchBlock != nil {
storedblock = c.XDPoS.V2.SwitchBlock
}
newblock := big.NewInt(1)
if newcfg.XDPoS != nil && newcfg.XDPoS.V2 != nil && newcfg.XDPoS.V2.SwitchBlock != nil {
newblock = newcfg.XDPoS.V2.SwitchBlock
}
return newCompatError("XDPoS not equal", storedblock, newblock)
}
if c.XDPoS != nil && newcfg.XDPoS != nil && c.XDPoS.V2 != nil && newcfg.XDPoS.V2 != nil && isForkIncompatible(c.XDPoS.V2.SwitchBlock, newcfg.XDPoS.V2.SwitchBlock, head) {
return newCompatError("XDPoS.V2.SwitchBlock", c.XDPoS.V2.SwitchBlock, newcfg.XDPoS.V2.SwitchBlock)
}
return nil
}
// isForkIncompatible returns true if a fork scheduled at s1 cannot be rescheduled to
// block s2 because head is already past the fork.
func isForkIncompatible(s1, s2, head *big.Int) bool {
return (isForked(s1, head) || isForked(s2, head)) && !configNumEqual(s1, s2)
}
// isForked returns whether a fork scheduled at block s is active at the given head block.
func isForked(s, head *big.Int) bool {
if s == nil || head == nil {
return false
}
return s.Cmp(head) <= 0
}
func configNumEqual(x, y *big.Int) bool {
if x == nil || y == nil {
return x == y
}
return x.Cmp(y) == 0
}
// ConfigCompatError is raised if the locally-stored blockchain is initialised with a
// ChainConfig that would alter the past.
type ConfigCompatError struct {
What string
// block numbers of the stored and new configurations
StoredConfig, NewConfig *big.Int
// the block number to which the local chain must be rewound to correct the error
RewindTo uint64
}
func newCompatError(what string, storedblock, newblock *big.Int) *ConfigCompatError {
var rew *big.Int
switch {
case storedblock == nil:
rew = newblock
case newblock == nil || storedblock.Cmp(newblock) < 0:
rew = storedblock
default:
rew = newblock
}
err := &ConfigCompatError{what, storedblock, newblock, 0}
if rew != nil && rew.Sign() > 0 {
err.RewindTo = rew.Uint64() - 1
}
return err
}
func (err *ConfigCompatError) Error() string {
return fmt.Sprintf("mismatching %s in database (have %d, want %d, rewindto %d)", err.What, err.StoredConfig, err.NewConfig, err.RewindTo)
}
// Rules wraps ChainConfig and is merely syntatic sugar or can be used for functions
// that do not have or require information about the block.
//
// Rules is a one time interface meaning that it shouldn't be used in between transition
// phases.
type Rules struct {
ChainId *big.Int
IsHomestead, IsEIP150, IsEIP155, IsEIP158 bool
IsByzantium, IsConstantinople, IsPetersburg, IsIstanbul bool
IsBerlin, IsLondon bool
IsMerge, IsShanghai bool
IsXDCxDisable bool
IsEIP1559 bool
IsCancun bool
}
func (c *ChainConfig) Rules(num *big.Int) Rules {
chainId := c.ChainID
if chainId == nil {
chainId = new(big.Int)
}
return Rules{
ChainId: new(big.Int).Set(chainId),
IsHomestead: c.IsHomestead(num),
IsEIP150: c.IsEIP150(num),
IsEIP155: c.IsEIP155(num),
IsEIP158: c.IsEIP158(num),
IsByzantium: c.IsByzantium(num),
IsConstantinople: c.IsConstantinople(num),
IsPetersburg: c.IsPetersburg(num),
IsIstanbul: c.IsIstanbul(num),
IsBerlin: c.IsBerlin(num),
IsLondon: c.IsLondon(num),
IsMerge: c.IsMerge(num),
IsShanghai: c.IsShanghai(num),
IsXDCxDisable: c.IsXDCxDisable(num),
IsEIP1559: c.IsEIP1559(num),
IsCancun: c.IsCancun(num),
}
}