mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-06-19 21:31:37 +00:00
1386 lines
50 KiB
Go
1386 lines
50 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 (
|
|
"cmp"
|
|
"encoding/json"
|
|
"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,
|
|
FoundationWalletAddr: common.HexToAddress("xdc92a289fe95a85c53b8d0d113cbaef0c1ec98ac65"),
|
|
V2: &V2{
|
|
SwitchEpoch: common.MainnetConstant.TIPV2SwitchBlock.Uint64() / 900,
|
|
SwitchBlock: common.MainnetConstant.TIPV2SwitchBlock,
|
|
CurrentConfig: MainnetV2Configs[0],
|
|
AllConfigs: MainnetV2Configs,
|
|
},
|
|
},
|
|
}
|
|
|
|
// MainnetChainConfig is the chain parameters to run a node on the ethereum 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 Apothem testnet.
|
|
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,
|
|
FoundationWalletAddr: 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 devnet.
|
|
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,
|
|
FoundationWalletAddr: 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.
|
|
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: big.NewInt(0),
|
|
PetersburgBlock: big.NewInt(0),
|
|
IstanbulBlock: big.NewInt(0),
|
|
BerlinBlock: big.NewInt(0),
|
|
LondonBlock: big.NewInt(0),
|
|
ShanghaiBlock: big.NewInt(0),
|
|
Eip1559Block: nil,
|
|
CancunBlock: nil,
|
|
PragueBlock: nil,
|
|
OsakaBlock: nil,
|
|
Ethash: new(EthashConfig),
|
|
Clique: nil,
|
|
XDPoS: nil,
|
|
}
|
|
|
|
// AllDevChainProtocolChanges 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.
|
|
AllDevChainProtocolChanges = &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),
|
|
PetersburgBlock: big.NewInt(0),
|
|
IstanbulBlock: big.NewInt(0),
|
|
BerlinBlock: big.NewInt(0),
|
|
LondonBlock: big.NewInt(0),
|
|
ShanghaiBlock: big.NewInt(0),
|
|
Eip1559Block: big.NewInt(0),
|
|
CancunBlock: big.NewInt(0),
|
|
PragueBlock: big.NewInt(0),
|
|
OsakaBlock: big.NewInt(0),
|
|
Ethash: nil,
|
|
Clique: nil,
|
|
XDPoS: &XDPoSConfig{
|
|
Epoch: 900,
|
|
Gap: 450,
|
|
SkipV1Validation: true,
|
|
FoundationWalletAddr: common.HexToAddress("0x0000000000000000000000000000000000000068"),
|
|
Reward: 250,
|
|
V2: &V2{
|
|
SwitchEpoch: 1,
|
|
SwitchBlock: big.NewInt(900),
|
|
CurrentConfig: UnitTestV2Configs[0],
|
|
AllConfigs: UnitTestV2Configs,
|
|
},
|
|
},
|
|
}
|
|
|
|
// AllCliqueProtocolChanges contains every protocol change (EIPs) introduced
|
|
// and accepted by the Ethereum core developers into the Clique consensus.
|
|
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: big.NewInt(0),
|
|
PetersburgBlock: big.NewInt(0),
|
|
IstanbulBlock: big.NewInt(0),
|
|
BerlinBlock: big.NewInt(0),
|
|
LondonBlock: big.NewInt(0),
|
|
ShanghaiBlock: big.NewInt(0),
|
|
Eip1559Block: big.NewInt(0),
|
|
CancunBlock: nil,
|
|
PragueBlock: nil,
|
|
OsakaBlock: 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,
|
|
FoundationWalletAddr: common.HexToAddress("0x0000000000000000000000000000000000000068"),
|
|
Reward: 250,
|
|
V2: &V2{
|
|
SwitchEpoch: 1,
|
|
SwitchBlock: big.NewInt(900),
|
|
CurrentConfig: UnitTestV2Configs[0],
|
|
AllConfigs: UnitTestV2Configs,
|
|
},
|
|
},
|
|
}
|
|
|
|
// TestChainConfig contains every protocol change (EIPs) introduced
|
|
// and accepted by the Ethereum core developers for testing purposes.
|
|
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: big.NewInt(0),
|
|
PetersburgBlock: big.NewInt(0),
|
|
IstanbulBlock: big.NewInt(0),
|
|
BerlinBlock: big.NewInt(0),
|
|
LondonBlock: big.NewInt(0),
|
|
ShanghaiBlock: big.NewInt(0),
|
|
Eip1559Block: nil,
|
|
CancunBlock: nil,
|
|
PragueBlock: nil,
|
|
OsakaBlock: nil,
|
|
Ethash: new(EthashConfig),
|
|
Clique: nil,
|
|
XDPoS: nil,
|
|
}
|
|
|
|
// MergedTestChainConfig contains every protocol change (EIPs) introduced
|
|
// and accepted by the Ethereum core developers for testing purposes.
|
|
MergedTestChainConfig = &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: big.NewInt(0),
|
|
PetersburgBlock: big.NewInt(0),
|
|
IstanbulBlock: big.NewInt(0),
|
|
BerlinBlock: big.NewInt(0),
|
|
LondonBlock: big.NewInt(0),
|
|
ShanghaiBlock: big.NewInt(0),
|
|
Eip1559Block: big.NewInt(0),
|
|
CancunBlock: big.NewInt(0),
|
|
PragueBlock: big.NewInt(0),
|
|
OsakaBlock: big.NewInt(0),
|
|
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"`
|
|
PragueBlock *big.Int `json:"pragueBlock,omitempty"`
|
|
OsakaBlock *big.Int `json:"osakaBlock,omitempty"`
|
|
|
|
DynamicGasLimitBlock *big.Int `json:"dynamicGasLimitBlock,omitempty"` // Dynamic gas limit adjustment algorithm activation block (nil = no fork)
|
|
|
|
// 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
|
|
FoundationWalletAddr common.Address `json:"foundationWalletAddr"` // Foundation Address Wallet
|
|
SkipV1Validation bool //Skip Block Validation for testing purpose, V1 consensus only
|
|
V2 *V2 `json:"v2"`
|
|
}
|
|
|
|
// UnmarshalJSON supports both the current and legacy typo-ed JSON key for
|
|
// foundation wallet address to keep old on-disk chain configs compatible.
|
|
func (c *XDPoSConfig) UnmarshalJSON(data []byte) error {
|
|
type xdpJSON struct {
|
|
Period uint64 `json:"period"`
|
|
Epoch uint64 `json:"epoch"`
|
|
Reward uint64 `json:"reward"`
|
|
RewardCheckpoint uint64 `json:"rewardCheckpoint"`
|
|
Gap uint64 `json:"gap"`
|
|
FoundationWalletAddr common.Address `json:"foundationWalletAddr"`
|
|
LegacyFoudationWalletAddr common.Address `json:"foudationWalletAddr"`
|
|
SkipV1Validation bool `json:"SkipV1Validation"`
|
|
V2 *V2 `json:"v2"`
|
|
}
|
|
var decoded xdpJSON
|
|
if err := json.Unmarshal(data, &decoded); err != nil {
|
|
return err
|
|
}
|
|
|
|
c.Period = decoded.Period
|
|
c.Epoch = decoded.Epoch
|
|
c.Reward = decoded.Reward
|
|
c.RewardCheckpoint = decoded.RewardCheckpoint
|
|
c.Gap = decoded.Gap
|
|
c.FoundationWalletAddr = decoded.FoundationWalletAddr
|
|
if c.FoundationWalletAddr == (common.Address{}) && decoded.LegacyFoudationWalletAddr != (common.Address{}) {
|
|
c.FoundationWalletAddr = decoded.LegacyFoudationWalletAddr
|
|
}
|
|
c.SkipV1Validation = decoded.SkipV1Validation
|
|
c.V2 = decoded.V2
|
|
|
|
return nil
|
|
}
|
|
|
|
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
|
|
}
|
|
|
|
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 {
|
|
if a != b {
|
|
log.Warn("[XDPoSConfigEqual] One of the configs is nil", "a", a, "b", b)
|
|
return false
|
|
}
|
|
return true
|
|
}
|
|
if a.Period != b.Period {
|
|
log.Warn("[XDPoSConfigEqual] Period mismatch", "a.Period", a.Period, "b.Period", b.Period)
|
|
return false
|
|
}
|
|
if a.Epoch != b.Epoch {
|
|
log.Warn("[XDPoSConfigEqual] Epoch mismatch", "a.Epoch", a.Epoch, "b.Epoch", b.Epoch)
|
|
return false
|
|
}
|
|
if a.Reward != b.Reward {
|
|
log.Warn("[XDPoSConfigEqual] Reward mismatch", "a.Reward", a.Reward, "b.Reward", b.Reward)
|
|
return false
|
|
}
|
|
if a.RewardCheckpoint != b.RewardCheckpoint {
|
|
log.Warn("[XDPoSConfigEqual] RewardCheckpoint mismatch", "a.RewardCheckpoint", a.RewardCheckpoint, "b.RewardCheckpoint", b.RewardCheckpoint)
|
|
return false
|
|
}
|
|
if a.Gap != b.Gap {
|
|
log.Warn("[XDPoSConfigEqual] Gap mismatch", "a.Gap", a.Gap, "b.Gap", b.Gap)
|
|
return false
|
|
}
|
|
if a.FoundationWalletAddr != b.FoundationWalletAddr {
|
|
log.Warn("[XDPoSConfigEqual] FoundationWalletAddr mismatch", "a.FoundationWalletAddr", a.FoundationWalletAddr.Hex(), "b.FoundationWalletAddr", b.FoundationWalletAddr.Hex())
|
|
return false
|
|
}
|
|
if a.SkipV1Validation != b.SkipV1Validation {
|
|
log.Warn("[XDPoSConfigEqual] SkipV1Validation mismatch", "a.SkipV1Validation", a.SkipV1Validation, "b.SkipV1Validation", b.SkipV1Validation)
|
|
return false
|
|
}
|
|
return V2Equal(a.V2, b.V2)
|
|
}
|
|
|
|
func V2Equal(a, b *V2) bool {
|
|
if a == nil || b == nil {
|
|
if a != b {
|
|
log.Warn("[V2Equal] One of the configs is nil", "a", a, "b", b)
|
|
return false
|
|
}
|
|
return true
|
|
}
|
|
if !configNumEqual(a.SwitchBlock, b.SwitchBlock) {
|
|
log.Warn("[V2Equal] SwitchBlock mismatch", "a.SwitchBlock", a.SwitchBlock, "b.SwitchBlock", b.SwitchBlock)
|
|
return false
|
|
}
|
|
// Only check configs in both of AllConfigs
|
|
for k1, cfg1 := range a.AllConfigs {
|
|
if cfg2, ok := b.AllConfigs[k1]; ok {
|
|
if !V2ConfigEqual(cfg1, cfg2) {
|
|
return false
|
|
}
|
|
}
|
|
}
|
|
return true
|
|
}
|
|
|
|
func V2ConfigEqual(a, b *V2Config) bool {
|
|
if a == nil || b == nil {
|
|
if a != b {
|
|
log.Warn("[V2ConfigEqual] One of the configs is nil", "a", a, "b", b)
|
|
return false
|
|
}
|
|
return true
|
|
}
|
|
if a.MaxMasternodes != b.MaxMasternodes {
|
|
log.Warn("[V2ConfigEqual] MaxMasternodes mismatch", "a.MaxMasternodes", a.MaxMasternodes, "b.MaxMasternodes", b.MaxMasternodes)
|
|
return false
|
|
}
|
|
if a.SwitchRound != b.SwitchRound {
|
|
log.Warn("[V2ConfigEqual] SwitchRound mismatch", "a.SwitchRound", a.SwitchRound, "b.SwitchRound", b.SwitchRound)
|
|
return false
|
|
}
|
|
if a.CertThreshold != b.CertThreshold {
|
|
log.Warn("[V2ConfigEqual] CertThreshold mismatch", "a.CertThreshold", a.CertThreshold, "b.CertThreshold", b.CertThreshold)
|
|
return false
|
|
}
|
|
return true
|
|
}
|
|
|
|
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, FoundationWalletAddr: %v, SkipV1Validation: %v, V2: %s}", c.Period, c.Epoch, c.Reward, c.RewardCheckpoint, c.Gap, c.FoundationWalletAddr.String0x(), c.SkipV1Validation, c.V2.String())
|
|
}
|
|
|
|
// Description returns a human-readable description of XDPoSConfig
|
|
// NOTE: don't append "\n" to end
|
|
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- FoundationWalletAddr: %v\n", prefix, c.FoundationWalletAddr.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, %s}", v2.SwitchEpoch, v2.SwitchBlock, v2.CurrentConfig.String())
|
|
}
|
|
|
|
// Description returns a human-readable description of V2
|
|
// NOTE: don't append "\n" to end
|
|
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- %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())
|
|
}
|
|
|
|
// Description returns a human-readable description of V2Config
|
|
// NOTE: don't append "\n" to end
|
|
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() {
|
|
list := slices.Collect(maps.Keys(v2.AllConfigs))
|
|
// Make it descending order
|
|
slices.SortFunc(list, func(a, b uint64) int {
|
|
return cmp.Compare(b, a)
|
|
})
|
|
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.PragueBlock != nil {
|
|
result += fmt.Sprintf(", PragueBlock: %v", c.PragueBlock)
|
|
}
|
|
if c.DynamicGasLimitBlock != nil {
|
|
result += fmt.Sprintf(", DynamicGasLimitBlock: %v", c.DynamicGasLimitBlock)
|
|
}
|
|
if c.XDPoS != nil {
|
|
result += fmt.Sprintf(", %s", c.XDPoS.String())
|
|
}
|
|
result += "}"
|
|
return result
|
|
}
|
|
|
|
// Description returns a human-readable description of ChainConfig.
|
|
// NOTE: don't append "\n" to end
|
|
func (c *ChainConfig) Description() string {
|
|
var engine string
|
|
switch {
|
|
case c.Ethash != nil:
|
|
engine = c.Ethash.String()
|
|
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
|
|
}
|
|
pragueBlock := common.PragueBlock
|
|
if c.PragueBlock != nil {
|
|
pragueBlock = c.PragueBlock
|
|
}
|
|
osakaBlock := common.OsakaBlock
|
|
if c.OsakaBlock != nil {
|
|
osakaBlock = c.OsakaBlock
|
|
}
|
|
dynamicGasLimitBlock := common.DynamicGasLimitBlock
|
|
if c.DynamicGasLimitBlock != nil {
|
|
dynamicGasLimitBlock = c.DynamicGasLimitBlock
|
|
}
|
|
|
|
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(" - TIP2019Block: %-8v\n", common.TIP2019Block)
|
|
banner += fmt.Sprintf(" - TIPSigning: %-8v\n", common.TIPSigning)
|
|
banner += fmt.Sprintf(" - TIPRandomize: %-8v\n", common.TIPRandomize)
|
|
banner += fmt.Sprintf(" - TIPIncreaseMasternodes: %-8v\n", common.TIPIncreaseMasternodes)
|
|
banner += fmt.Sprintf(" - DenylistHFNumber: %-8v\n", common.DenylistHFNumber)
|
|
banner += fmt.Sprintf(" - TIPNoHalvingMNReward: %-8v\n", common.TIPNoHalvingMNReward)
|
|
banner += fmt.Sprintf(" - TIPXDCX: %-8v\n", common.TIPXDCX)
|
|
banner += fmt.Sprintf(" - TIPXDCXLending: %-8v\n", common.TIPXDCXLending)
|
|
banner += fmt.Sprintf(" - TIPXDCXCancellationFee: %-8v\n", common.TIPXDCXCancellationFee)
|
|
banner += fmt.Sprintf(" - TIPTRC21Fee: %-8v\n", common.TIPTRC21Fee)
|
|
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(" - BlockNumberGas50x: %-8v\n", common.BlockNumberGas50x)
|
|
banner += fmt.Sprintf(" - TIPXDCXMinerDisable: %-8v\n", common.TIPXDCXMinerDisable)
|
|
banner += fmt.Sprintf(" - TIPXDCXReceiverDisable: %-8v\n", common.TIPXDCXReceiverDisable)
|
|
banner += fmt.Sprintf(" - Eip1559: %-8v\n", eip1559Block)
|
|
banner += fmt.Sprintf(" - Cancun: %-8v\n", cancunBlock)
|
|
banner += fmt.Sprintf(" - Prague: %-8v\n", pragueBlock)
|
|
banner += fmt.Sprintf(" - Osaka: %-8v\n", osakaBlock)
|
|
banner += fmt.Sprintf(" - DynamicGasLimitBlock: %-8v\n", dynamicGasLimitBlock)
|
|
banner += fmt.Sprintf(" - TIPUpgradeReward: %-8v\n", common.TIPUpgradeReward)
|
|
banner += fmt.Sprintf(" - TipUpgradePenalty: %-8v\n", common.TipUpgradePenalty)
|
|
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)
|
|
}
|
|
|
|
// IsEIP1559 returns whether num is either equal to the EIP1559 fork block or greater.
|
|
func (c *ChainConfig) IsEIP1559(num *big.Int) bool {
|
|
return isForked(common.Eip1559Block, num) || isForked(c.Eip1559Block, num)
|
|
}
|
|
|
|
// IsCancun returns whether num is either equal to the Cancun fork block or greater.
|
|
func (c *ChainConfig) IsCancun(num *big.Int) bool {
|
|
return isForked(common.CancunBlock, num) || isForked(c.CancunBlock, num)
|
|
}
|
|
|
|
// IsPrague returns whether num is either equal to the Prague fork block or greater.
|
|
func (c *ChainConfig) IsPrague(num *big.Int) bool {
|
|
return isForked(common.PragueBlock, num) || isForked(c.PragueBlock, num)
|
|
}
|
|
|
|
// IsOsaka returns whether num is either equal to the Osaka fork block or greater.
|
|
func (c *ChainConfig) IsOsaka(num *big.Int) bool {
|
|
return isForked(common.OsakaBlock, num) || isForked(c.OsakaBlock, num)
|
|
}
|
|
|
|
// IsDynamicGasLimitBlock returns whether num is either equal to the DynamicGasLimitBlock fork block or greater.
|
|
func (c *ChainConfig) IsDynamicGasLimitBlock(num *big.Int) bool {
|
|
return isForked(common.DynamicGasLimitBlock, num) || isForked(c.DynamicGasLimitBlock, 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 isForkIncompatible(c.PragueBlock, newcfg.PragueBlock, head) {
|
|
return newCompatError("Prague fork block", c.PragueBlock, newcfg.PragueBlock)
|
|
}
|
|
if isForkIncompatible(c.OsakaBlock, newcfg.OsakaBlock, head) {
|
|
return newCompatError("Osaka fork block", c.OsakaBlock, newcfg.OsakaBlock)
|
|
}
|
|
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 bool
|
|
IsEIP150 bool
|
|
IsEIP155 bool
|
|
IsEIP158 bool
|
|
IsByzantium bool
|
|
IsConstantinople bool
|
|
IsPetersburg bool
|
|
IsIstanbul bool
|
|
IsBerlin bool
|
|
IsLondon bool
|
|
IsMerge bool
|
|
IsShanghai bool
|
|
IsXDCxDisable bool
|
|
IsEIP1559 bool
|
|
IsCancun bool
|
|
IsPrague bool
|
|
IsOsaka 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),
|
|
IsPrague: c.IsPrague(num),
|
|
IsOsaka: c.IsOsaka(num),
|
|
}
|
|
}
|