mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-17 18:30:45 +00:00
Consecutive penalty upgrade (#1053)
* feat: penalty upgrade, consecutive epochs penalty can be unpenalized * feat: use binary search inside penalty hook * style: modification on style * feat: in penaltyHook change startRange * fix: add lastPenalty condition in HookPenalty V2
This commit is contained in:
parent
217a01e927
commit
4ec4a5390f
11 changed files with 389 additions and 109 deletions
|
|
@ -42,27 +42,28 @@ type constant struct {
|
||||||
blackListHFNumber uint64
|
blackListHFNumber uint64
|
||||||
maxMasternodesV2 int // Last v1 masternodes
|
maxMasternodesV2 int // Last v1 masternodes
|
||||||
|
|
||||||
tip2019Block *big.Int
|
tip2019Block *big.Int
|
||||||
tipSigning *big.Int
|
tipSigning *big.Int
|
||||||
tipRandomize *big.Int
|
tipRandomize *big.Int
|
||||||
tipNoHalvingMNReward *big.Int // hard fork no halving masternodes reward
|
tipNoHalvingMNReward *big.Int // hard fork no halving masternodes reward
|
||||||
tipXDCX *big.Int
|
tipXDCX *big.Int
|
||||||
tipXDCXLending *big.Int
|
tipXDCXLending *big.Int
|
||||||
tipXDCXCancellationFee *big.Int
|
tipXDCXCancellationFee *big.Int
|
||||||
tipTRC21Fee *big.Int
|
tipTRC21Fee *big.Int
|
||||||
tipIncreaseMasternodes *big.Int // Upgrade MN Count at Block.
|
tipIncreaseMasternodes *big.Int // Upgrade MN Count at Block.
|
||||||
berlinBlock *big.Int
|
berlinBlock *big.Int
|
||||||
londonBlock *big.Int
|
londonBlock *big.Int
|
||||||
mergeBlock *big.Int
|
mergeBlock *big.Int
|
||||||
shanghaiBlock *big.Int
|
shanghaiBlock *big.Int
|
||||||
blockNumberGas50x *big.Int
|
blockNumberGas50x *big.Int
|
||||||
TIPV2SwitchBlock *big.Int
|
TIPV2SwitchBlock *big.Int
|
||||||
tipXDCXMinerDisable *big.Int
|
tipXDCXMinerDisable *big.Int
|
||||||
tipXDCXReceiverDisable *big.Int
|
tipXDCXReceiverDisable *big.Int
|
||||||
tipUpgradeReward *big.Int
|
tipUpgradeReward *big.Int
|
||||||
tipEpochHalving *big.Int
|
tipUpgradePenalty *big.Int
|
||||||
eip1559Block *big.Int
|
tipEpochHalving *big.Int
|
||||||
cancunBlock *big.Int
|
eip1559Block *big.Int
|
||||||
|
cancunBlock *big.Int
|
||||||
|
|
||||||
trc21IssuerSMC Address
|
trc21IssuerSMC Address
|
||||||
xdcxListingSMC Address
|
xdcxListingSMC Address
|
||||||
|
|
@ -79,26 +80,27 @@ var (
|
||||||
BlackListHFNumber = MaintnetConstant.blackListHFNumber
|
BlackListHFNumber = MaintnetConstant.blackListHFNumber
|
||||||
MaxMasternodesV2 = MaintnetConstant.maxMasternodesV2 // Last v1 masternodes
|
MaxMasternodesV2 = MaintnetConstant.maxMasternodesV2 // Last v1 masternodes
|
||||||
|
|
||||||
TIP2019Block = MaintnetConstant.tip2019Block
|
TIP2019Block = MaintnetConstant.tip2019Block
|
||||||
TIPSigning = MaintnetConstant.tipSigning
|
TIPSigning = MaintnetConstant.tipSigning
|
||||||
TIPRandomize = MaintnetConstant.tipRandomize
|
TIPRandomize = MaintnetConstant.tipRandomize
|
||||||
TIPNoHalvingMNReward = MaintnetConstant.tipNoHalvingMNReward
|
TIPNoHalvingMNReward = MaintnetConstant.tipNoHalvingMNReward
|
||||||
TIPXDCX = MaintnetConstant.tipXDCX
|
TIPXDCX = MaintnetConstant.tipXDCX
|
||||||
TIPXDCXLending = MaintnetConstant.tipXDCXLending
|
TIPXDCXLending = MaintnetConstant.tipXDCXLending
|
||||||
TIPXDCXCancellationFee = MaintnetConstant.tipXDCXCancellationFee
|
TIPXDCXCancellationFee = MaintnetConstant.tipXDCXCancellationFee
|
||||||
TIPTRC21Fee = MaintnetConstant.tipTRC21Fee
|
TIPTRC21Fee = MaintnetConstant.tipTRC21Fee
|
||||||
TIPIncreaseMasternodes = MaintnetConstant.tipIncreaseMasternodes
|
TIPIncreaseMasternodes = MaintnetConstant.tipIncreaseMasternodes
|
||||||
BerlinBlock = MaintnetConstant.berlinBlock
|
BerlinBlock = MaintnetConstant.berlinBlock
|
||||||
LondonBlock = MaintnetConstant.londonBlock
|
LondonBlock = MaintnetConstant.londonBlock
|
||||||
MergeBlock = MaintnetConstant.mergeBlock
|
MergeBlock = MaintnetConstant.mergeBlock
|
||||||
ShanghaiBlock = MaintnetConstant.shanghaiBlock
|
ShanghaiBlock = MaintnetConstant.shanghaiBlock
|
||||||
BlockNumberGas50x = MaintnetConstant.blockNumberGas50x
|
BlockNumberGas50x = MaintnetConstant.blockNumberGas50x
|
||||||
TIPXDCXMinerDisable = MaintnetConstant.tipXDCXMinerDisable
|
TIPXDCXMinerDisable = MaintnetConstant.tipXDCXMinerDisable
|
||||||
TIPXDCXReceiverDisable = MaintnetConstant.tipXDCXReceiverDisable
|
TIPXDCXReceiverDisable = MaintnetConstant.tipXDCXReceiverDisable
|
||||||
Eip1559Block = MaintnetConstant.eip1559Block
|
Eip1559Block = MaintnetConstant.eip1559Block
|
||||||
CancunBlock = MaintnetConstant.cancunBlock
|
CancunBlock = MaintnetConstant.cancunBlock
|
||||||
TIPUpgradeReward = MaintnetConstant.tipUpgradeReward
|
TIPUpgradeReward = MaintnetConstant.tipUpgradeReward
|
||||||
TIPEpochHalving = MaintnetConstant.tipEpochHalving
|
TipUpgradePenalty = MaintnetConstant.tipUpgradePenalty
|
||||||
|
TIPEpochHalving = MaintnetConstant.tipEpochHalving
|
||||||
|
|
||||||
TRC21IssuerSMC = MaintnetConstant.trc21IssuerSMC
|
TRC21IssuerSMC = MaintnetConstant.trc21IssuerSMC
|
||||||
XDCXListingSMC = MaintnetConstant.xdcxListingSMC
|
XDCXListingSMC = MaintnetConstant.xdcxListingSMC
|
||||||
|
|
@ -158,6 +160,7 @@ func CopyConstants(chainID uint64) {
|
||||||
Eip1559Block = c.eip1559Block
|
Eip1559Block = c.eip1559Block
|
||||||
CancunBlock = c.cancunBlock
|
CancunBlock = c.cancunBlock
|
||||||
TIPUpgradeReward = c.tipUpgradeReward
|
TIPUpgradeReward = c.tipUpgradeReward
|
||||||
|
TipUpgradePenalty = c.tipUpgradePenalty
|
||||||
TIPEpochHalving = c.tipEpochHalving
|
TIPEpochHalving = c.tipEpochHalving
|
||||||
|
|
||||||
TRC21IssuerSMC = c.trc21IssuerSMC
|
TRC21IssuerSMC = c.trc21IssuerSMC
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,7 @@ var DevnetConstant = constant{
|
||||||
eip1559Block: big.NewInt(32400),
|
eip1559Block: big.NewInt(32400),
|
||||||
cancunBlock: big.NewInt(43200),
|
cancunBlock: big.NewInt(43200),
|
||||||
tipUpgradeReward: big.NewInt(243000),
|
tipUpgradeReward: big.NewInt(243000),
|
||||||
|
tipUpgradePenalty: big.NewInt(9999999999),
|
||||||
tipEpochHalving: big.NewInt(9999999999),
|
tipEpochHalving: big.NewInt(9999999999),
|
||||||
|
|
||||||
trc21IssuerSMC: HexToAddress("0x8c0faeb5C6bEd2129b8674F262Fd45c4e9468bee"),
|
trc21IssuerSMC: HexToAddress("0x8c0faeb5C6bEd2129b8674F262Fd45c4e9468bee"),
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,7 @@ var localConstant = constant{
|
||||||
eip1559Block: big.NewInt(0),
|
eip1559Block: big.NewInt(0),
|
||||||
cancunBlock: big.NewInt(0),
|
cancunBlock: big.NewInt(0),
|
||||||
tipUpgradeReward: big.NewInt(0),
|
tipUpgradeReward: big.NewInt(0),
|
||||||
|
tipUpgradePenalty: big.NewInt(0),
|
||||||
tipEpochHalving: big.NewInt(0),
|
tipEpochHalving: big.NewInt(0),
|
||||||
|
|
||||||
trc21IssuerSMC: HexToAddress("0x8c0faeb5C6bEd2129b8674F262Fd45c4e9468bee"),
|
trc21IssuerSMC: HexToAddress("0x8c0faeb5C6bEd2129b8674F262Fd45c4e9468bee"),
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,7 @@ var MaintnetConstant = constant{
|
||||||
eip1559Block: big.NewInt(9999999999),
|
eip1559Block: big.NewInt(9999999999),
|
||||||
cancunBlock: big.NewInt(9999999999),
|
cancunBlock: big.NewInt(9999999999),
|
||||||
tipUpgradeReward: big.NewInt(9999999999),
|
tipUpgradeReward: big.NewInt(9999999999),
|
||||||
|
tipUpgradePenalty: big.NewInt(9999999999),
|
||||||
tipEpochHalving: big.NewInt(9999999999),
|
tipEpochHalving: big.NewInt(9999999999),
|
||||||
|
|
||||||
trc21IssuerSMC: HexToAddress("0x8c0faeb5C6bEd2129b8674F262Fd45c4e9468bee"),
|
trc21IssuerSMC: HexToAddress("0x8c0faeb5C6bEd2129b8674F262Fd45c4e9468bee"),
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,7 @@ var TestnetConstant = constant{
|
||||||
eip1559Block: big.NewInt(71550000), // Target 14th Feb 2025
|
eip1559Block: big.NewInt(71550000), // Target 14th Feb 2025
|
||||||
cancunBlock: big.NewInt(71551800),
|
cancunBlock: big.NewInt(71551800),
|
||||||
tipUpgradeReward: big.NewInt(9999999999),
|
tipUpgradeReward: big.NewInt(9999999999),
|
||||||
|
tipUpgradePenalty: big.NewInt(9999999999),
|
||||||
tipEpochHalving: big.NewInt(9999999999),
|
tipEpochHalving: big.NewInt(9999999999),
|
||||||
|
|
||||||
trc21IssuerSMC: HexToAddress("0x0E2C88753131CE01c7551B726b28BFD04e44003F"),
|
trc21IssuerSMC: HexToAddress("0x0E2C88753131CE01c7551B726b28BFD04e44003F"),
|
||||||
|
|
|
||||||
|
|
@ -1089,12 +1089,25 @@ func (x *XDPoS_v2) GetMasternodesByHash(chain consensus.ChainReader, hash common
|
||||||
|
|
||||||
// Given hash, get master node from the epoch switch block of the previous `limit` epoch
|
// Given hash, get master node from the epoch switch block of the previous `limit` epoch
|
||||||
func (x *XDPoS_v2) GetPreviousPenaltyByHash(chain consensus.ChainReader, hash common.Hash, limit int) []common.Address {
|
func (x *XDPoS_v2) GetPreviousPenaltyByHash(chain consensus.ChainReader, hash common.Hash, limit int) []common.Address {
|
||||||
epochSwitchInfo, err := x.getPreviousEpochSwitchInfoByHash(chain, hash, limit)
|
currentEpochSwitchInfo, err := x.getEpochSwitchInfo(chain, nil, hash)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("[GetPreviousPenaltyByHash] Adaptor v2 getPreviousEpochSwitchInfoByHash has error, potentially bug", "err", err)
|
||||||
|
return []common.Address{}
|
||||||
|
}
|
||||||
|
if limit == 0 {
|
||||||
|
return currentEpochSwitchInfo.Penalties
|
||||||
|
}
|
||||||
|
epochNum := x.config.V2.SwitchEpoch + uint64(currentEpochSwitchInfo.EpochSwitchBlockInfo.Round)/x.config.Epoch
|
||||||
|
if epochNum < uint64(limit) {
|
||||||
|
// avoid negative number
|
||||||
|
log.Error("[GetPreviousPenaltyByHash] Adaptor v2 getPreviousEpochSwitchInfoByHash has error, too large limit", "limit", limit)
|
||||||
|
return []common.Address{}
|
||||||
|
}
|
||||||
|
_, header, err := x.binarySearchBlockByEpochNumber(chain, epochNum-uint64(limit), currentEpochSwitchInfo.EpochSwitchBlockInfo.Number.Uint64()-x.config.Epoch*uint64(limit), currentEpochSwitchInfo.EpochSwitchParentBlockInfo.Number.Uint64())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("[GetPreviousPenaltyByHash] Adaptor v2 getPreviousEpochSwitchInfoByHash has error, potentially bug", "err", err)
|
log.Error("[GetPreviousPenaltyByHash] Adaptor v2 getPreviousEpochSwitchInfoByHash has error, potentially bug", "err", err)
|
||||||
return []common.Address{}
|
return []common.Address{}
|
||||||
}
|
}
|
||||||
header := chain.GetHeaderByHash(epochSwitchInfo.EpochSwitchBlockInfo.Hash)
|
|
||||||
return common.ExtractAddressFromBytes(header.Penalties)
|
return common.ExtractAddressFromBytes(header.Penalties)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -246,28 +246,28 @@ func (x *XDPoS_v2) getBlockByEpochNumberInCache(chain consensus.ChainReader, est
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *XDPoS_v2) binarySearchBlockByEpochNumber(chain consensus.ChainReader, targetEpochNum uint64, start, end uint64) (*types.BlockInfo, error) {
|
func (x *XDPoS_v2) binarySearchBlockByEpochNumber(chain consensus.ChainReader, targetEpochNum uint64, start, end uint64) (*types.BlockInfo, *types.Header, error) {
|
||||||
// `end` must be larger than the target and `start` could be the target
|
// `end` must be larger than the target and `start` could be the target
|
||||||
for start < end {
|
for start < end {
|
||||||
header := chain.GetHeaderByNumber((start + end) / 2)
|
header := chain.GetHeaderByNumber((start + end) / 2)
|
||||||
if header == nil {
|
if header == nil {
|
||||||
return nil, errors.New("header nil in binary search")
|
return nil, nil, errors.New("header nil in binary search")
|
||||||
}
|
}
|
||||||
isEpochSwitch, epochNum, err := x.IsEpochSwitch(header)
|
isEpochSwitch, epochNum, err := x.IsEpochSwitch(header)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
if epochNum == targetEpochNum {
|
if epochNum == targetEpochNum {
|
||||||
_, round, _, err := x.getExtraFields(header)
|
_, round, _, err := x.getExtraFields(header)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
if isEpochSwitch {
|
if isEpochSwitch {
|
||||||
return &types.BlockInfo{
|
return &types.BlockInfo{
|
||||||
Hash: header.Hash(),
|
Hash: header.Hash(),
|
||||||
Round: round,
|
Round: round,
|
||||||
Number: header.Number,
|
Number: header.Number,
|
||||||
}, nil
|
}, header, nil
|
||||||
} else {
|
} else {
|
||||||
end = header.Number.Uint64()
|
end = header.Number.Uint64()
|
||||||
// trick to shorten the search
|
// trick to shorten the search
|
||||||
|
|
@ -287,7 +287,7 @@ func (x *XDPoS_v2) binarySearchBlockByEpochNumber(chain consensus.ChainReader, t
|
||||||
start = nextStart
|
start = nextStart
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil, errors.New("no epoch switch header in binary search (all rounds in this epoch are missed, which is very rare)")
|
return nil, nil, errors.New("no epoch switch header in binary search (all rounds in this epoch are missed, which is very rare)")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *XDPoS_v2) GetBlockByEpochNumber(chain consensus.ChainReader, targetEpochNum uint64) (*types.BlockInfo, error) {
|
func (x *XDPoS_v2) GetBlockByEpochNumber(chain consensus.ChainReader, targetEpochNum uint64) (*types.BlockInfo, error) {
|
||||||
|
|
@ -337,5 +337,6 @@ func (x *XDPoS_v2) GetBlockByEpochNumber(chain consensus.ChainReader, targetEpoc
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// else, we use binary search
|
// else, we use binary search
|
||||||
return x.binarySearchBlockByEpochNumber(chain, targetEpochNum, estBlockNum.Uint64(), epochSwitchInfo.EpochSwitchBlockInfo.Number.Uint64())
|
blockInfo, _, err = x.binarySearchBlockByEpochNumber(chain, targetEpochNum, estBlockNum.Uint64(), epochSwitchInfo.EpochSwitchBlockInfo.Number.Uint64())
|
||||||
|
return blockInfo, err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -578,6 +578,68 @@ func PrepareXDCTestBlockChainWithPenaltyForV2Engine(t *testing.T, numOfBlocks in
|
||||||
return blockchain, backend, currentBlock, signer, signFn
|
return blockchain, backend, currentBlock, signer, signFn
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// V2 concensus engine, compared to PrepareXDCTestBlockChainForV2Engine: (1) no forking (2) add penalty
|
||||||
|
func PrepareXDCTestBlockChainWithPenaltyCustomized(t *testing.T, numOfBlocks int, chainConfig *params.ChainConfig, penaltyOrNot []bool) (*core.BlockChain, *backends.SimulatedBackend, *types.Block, common.Address, func(account accounts.Account, hash []byte) ([]byte, error)) {
|
||||||
|
// Preparation
|
||||||
|
var err error
|
||||||
|
signer, signFn, err := backends.SimulateWalletAddressAndSignFn()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("Error while creating simulated wallet for generating singer address and signer fn: ", err)
|
||||||
|
}
|
||||||
|
backend := getCommonBackend(t, chainConfig)
|
||||||
|
blockchain := backend.BlockChain()
|
||||||
|
blockchain.Client = backend
|
||||||
|
|
||||||
|
// Authorise
|
||||||
|
blockchain.Engine().(*XDPoS.XDPoS).Authorize(signer, signFn)
|
||||||
|
|
||||||
|
currentBlock := blockchain.Genesis()
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
for range core.CheckpointCh {
|
||||||
|
checkpointChanMsg := <-core.CheckpointCh
|
||||||
|
log.Info("[V2] Got a message from core CheckpointChan!", "msg", checkpointChanMsg)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
penaltyCnt := 0
|
||||||
|
// Insert initial blocks
|
||||||
|
for i := 1; i <= numOfBlocks; i++ {
|
||||||
|
blockCoinBase := fmt.Sprintf("0x111000000000000000000000000000000%03d", i)
|
||||||
|
// for v2 blocks, fill in correct coinbase
|
||||||
|
if int64(i) > chainConfig.XDPoS.V2.SwitchBlock.Int64() {
|
||||||
|
blockCoinBase = signer.Hex()
|
||||||
|
}
|
||||||
|
roundNumber := int64(i) - chainConfig.XDPoS.V2.SwitchBlock.Int64()
|
||||||
|
// use signer itself as penalty
|
||||||
|
penalty := signer[:]
|
||||||
|
if roundNumber%int64(chainConfig.XDPoS.Epoch) != 0 {
|
||||||
|
penalty = nil
|
||||||
|
} else {
|
||||||
|
if len(penaltyOrNot) > penaltyCnt && !penaltyOrNot[penaltyCnt] {
|
||||||
|
penalty = nil
|
||||||
|
t.Log("nilnil penalty for block", i)
|
||||||
|
}
|
||||||
|
penaltyCnt++
|
||||||
|
}
|
||||||
|
block := CreateBlock(blockchain, chainConfig, currentBlock, i, roundNumber, blockCoinBase, signer, signFn, penalty, nil, "")
|
||||||
|
|
||||||
|
err = blockchain.InsertBlock(block)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
currentBlock = block
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update Signer as there is no previous signer assigned
|
||||||
|
err = UpdateSigner(blockchain)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return blockchain, backend, currentBlock, signer, signFn
|
||||||
|
}
|
||||||
|
|
||||||
// V2 concensus engine, compared to PrepareXDCTestBlockChainForV2Engine: (1) no forking (2) 128 masternode candidates
|
// V2 concensus engine, compared to PrepareXDCTestBlockChainForV2Engine: (1) no forking (2) 128 masternode candidates
|
||||||
func PrepareXDCTestBlockChainWith128Candidates(t *testing.T, numOfBlocks int, chainConfig *params.ChainConfig) (*core.BlockChain, *backends.SimulatedBackend, *types.Block, common.Address, func(account accounts.Account, hash []byte) ([]byte, error)) {
|
func PrepareXDCTestBlockChainWith128Candidates(t *testing.T, numOfBlocks int, chainConfig *params.ChainConfig) (*core.BlockChain, *backends.SimulatedBackend, *types.Block, common.Address, func(account accounts.Account, hash []byte) ([]byte, error)) {
|
||||||
// Preparation
|
// Preparation
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
package engine_v2_tests
|
package engine_v2_tests
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"math/big"
|
"math/big"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
|
@ -39,7 +40,7 @@ func TestHookPenaltyV2Mining(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
assert.True(t, contains)
|
assert.True(t, contains)
|
||||||
// set adaptor round/qc to that of 6299
|
// set adaptor round/qc to that of 2099
|
||||||
err = utils.DecodeBytesExtraFields(header2100.Extra, &extraField)
|
err = utils.DecodeBytesExtraFields(header2100.Extra, &extraField)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
err = adaptor.EngineV2.ProcessQCFaker(blockchain, extraField.QuorumCert)
|
err = adaptor.EngineV2.ProcessQCFaker(blockchain, extraField.QuorumCert)
|
||||||
|
|
@ -84,7 +85,7 @@ func TestHookPenaltyV2Comeback(t *testing.T) {
|
||||||
// miner (coinbase) is in comeback. so all addresses are in penalty
|
// miner (coinbase) is in comeback. so all addresses are in penalty
|
||||||
assert.Equal(t, 2, len(penalty))
|
assert.Equal(t, 2, len(penalty))
|
||||||
header2085 := blockchain.GetHeaderByNumber(config.XDPoS.Epoch*3 - common.MergeSignRange)
|
header2085 := blockchain.GetHeaderByNumber(config.XDPoS.Epoch*3 - common.MergeSignRange)
|
||||||
// forcely insert signing tx into cache, to cancel comeback. since no comeback, penalty is 3
|
// forcely insert signing tx into cache, to cancel comeback. since no comeback, penalty is 1
|
||||||
tx, err := signingTxWithSignerFn(header2085, 0, signer, signFn)
|
tx, err := signingTxWithSignerFn(header2085, 0, signer, signFn)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
adaptor.CacheSigningTxs(header2085.Hash(), []*types.Transaction{tx})
|
adaptor.CacheSigningTxs(header2085.Hash(), []*types.Transaction{tx})
|
||||||
|
|
@ -151,3 +152,107 @@ func TestGetPenalties(t *testing.T) {
|
||||||
assert.Equal(t, 1, len(penalty2699))
|
assert.Equal(t, 1, len(penalty2699))
|
||||||
assert.Equal(t, 1, len(penalty1801))
|
assert.Equal(t, 1, len(penalty1801))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestHookPenaltyParolee tests that a penalty stays enough epoch, it will not be penalty.
|
||||||
|
// but if it does not stays enough, it will still be penalty.
|
||||||
|
func TestHookPenaltyParolee(t *testing.T) {
|
||||||
|
// set upgrade number to 0
|
||||||
|
backup := common.TipUpgradePenalty
|
||||||
|
common.TipUpgradePenalty = big.NewInt(0)
|
||||||
|
|
||||||
|
config := params.TestXDPoSMockChainConfig
|
||||||
|
blockchain, _, _, signer, signFn := PrepareXDCTestBlockChainWithPenaltyForV2Engine(t, int(config.XDPoS.Epoch)*4, config)
|
||||||
|
adaptor := blockchain.Engine().(*XDPoS.XDPoS)
|
||||||
|
hooks.AttachConsensusV2Hooks(adaptor, blockchain, config)
|
||||||
|
assert.NotNil(t, adaptor.EngineV2.HookPenalty)
|
||||||
|
var extraField types.ExtraFields_v2
|
||||||
|
// 901 is the first v2 block
|
||||||
|
header901 := blockchain.GetHeaderByNumber(config.XDPoS.Epoch + 1)
|
||||||
|
err := utils.DecodeBytesExtraFields(header901.Extra, &extraField)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
masternodes := adaptor.GetMasternodesFromCheckpointHeader(header901)
|
||||||
|
assert.Equal(t, 5, len(masternodes))
|
||||||
|
header2700 := blockchain.GetHeaderByNumber(config.XDPoS.Epoch * 3)
|
||||||
|
header2685 := blockchain.GetHeaderByNumber(config.XDPoS.Epoch*3 - common.MergeSignRange)
|
||||||
|
// forcely insert signing tx into cache, to cancel comeback. since no comeback, penalty is 1
|
||||||
|
tx, err := signingTxWithSignerFn(header2685, 0, signer, signFn)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
adaptor.CacheSigningTxs(header2685.Hash(), []*types.Transaction{tx})
|
||||||
|
penalty, err := adaptor.EngineV2.HookPenalty(blockchain, big.NewInt(int64(config.XDPoS.Epoch*3)), header2700.ParentHash, masternodes)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
// 2700 not trigger parole yet
|
||||||
|
assert.Equal(t, 1, len(penalty))
|
||||||
|
header3600 := blockchain.GetHeaderByNumber(config.XDPoS.Epoch * 4)
|
||||||
|
penalty, err = adaptor.EngineV2.HookPenalty(blockchain, big.NewInt(int64(config.XDPoS.Epoch*4)), header3600.ParentHash, masternodes)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
// miner (coinbase) is in comeback. so all addresses are in penalty
|
||||||
|
assert.Equal(t, 2, len(penalty))
|
||||||
|
header3585 := blockchain.GetHeaderByNumber(config.XDPoS.Epoch*4 - common.MergeSignRange)
|
||||||
|
// forcely insert signing tx into cache, to cancel comeback
|
||||||
|
tx, err = signingTxWithSignerFn(header3585, 0, signer, signFn)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
adaptor.CacheSigningTxs(header3585.Hash(), []*types.Transaction{tx})
|
||||||
|
penalty, err = adaptor.EngineV2.HookPenalty(blockchain, big.NewInt(int64(config.XDPoS.Epoch*4)), header3600.ParentHash, masternodes)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assert.Equal(t, 2, len(penalty))
|
||||||
|
|
||||||
|
header3570 := blockchain.GetHeaderByNumber(config.XDPoS.Epoch*4 - common.MergeSignRange*2)
|
||||||
|
// forcely insert signing tx into cache, to cancel comeback. since no comeback, penalty is 1
|
||||||
|
tx, err = signingTxWithSignerFn(header3570, 0, signer, signFn)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
adaptor.CacheSigningTxs(header3570.Hash(), []*types.Transaction{tx})
|
||||||
|
penalty, err = adaptor.EngineV2.HookPenalty(blockchain, big.NewInt(int64(config.XDPoS.Epoch*4)), header3600.ParentHash, masternodes)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assert.Equal(t, 1, len(penalty))
|
||||||
|
|
||||||
|
common.TipUpgradePenalty = backup
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestHookPenaltyParoleePerformance tests penalty hook performance
|
||||||
|
func TestHookPenaltyParoleePerformance(t *testing.T) {
|
||||||
|
b, err := json.Marshal(params.TestXDPoSMockChainConfig)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
configString := string(b)
|
||||||
|
|
||||||
|
var config params.ChainConfig
|
||||||
|
err = json.Unmarshal([]byte(configString), &config)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
config.XDPoS.V2.AllConfigs[900].LimitPenaltyEpoch = 4
|
||||||
|
|
||||||
|
// set upgrade number to 0
|
||||||
|
backup := common.TipUpgradePenalty
|
||||||
|
common.TipUpgradePenalty = big.NewInt(0)
|
||||||
|
|
||||||
|
// 900 1800 2700 3600(not) 4500 5400 has penalty except 3600
|
||||||
|
penaltyOrNot := []bool{true, true, true, false, true, true}
|
||||||
|
blockchain, _, _, signer, signFn := PrepareXDCTestBlockChainWithPenaltyCustomized(t, int(config.XDPoS.Epoch)*7, &config, penaltyOrNot)
|
||||||
|
adaptor := blockchain.Engine().(*XDPoS.XDPoS)
|
||||||
|
hooks.AttachConsensusV2Hooks(adaptor, blockchain, &config)
|
||||||
|
assert.NotNil(t, adaptor.EngineV2.HookPenalty)
|
||||||
|
var extraField types.ExtraFields_v2
|
||||||
|
// 901 is the first v2 block
|
||||||
|
header901 := blockchain.GetHeaderByNumber(config.XDPoS.Epoch + 1)
|
||||||
|
err = utils.DecodeBytesExtraFields(header901.Extra, &extraField)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
masternodes := adaptor.GetMasternodesFromCheckpointHeader(header901)
|
||||||
|
assert.Equal(t, 5, len(masternodes))
|
||||||
|
|
||||||
|
header6285 := blockchain.GetHeaderByNumber(config.XDPoS.Epoch*7 - common.MergeSignRange)
|
||||||
|
// forcely insert signing tx into cache, to cancel comeback
|
||||||
|
tx, err := signingTxWithSignerFn(header6285, 0, signer, signFn)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
adaptor.CacheSigningTxs(header6285.Hash(), []*types.Transaction{tx})
|
||||||
|
header6270 := blockchain.GetHeaderByNumber(config.XDPoS.Epoch*7 - common.MergeSignRange*2)
|
||||||
|
// forcely insert signing tx into cache, to cancel comeback
|
||||||
|
tx, err = signingTxWithSignerFn(header6270, 0, signer, signFn)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
adaptor.CacheSigningTxs(header6270.Hash(), []*types.Transaction{tx})
|
||||||
|
|
||||||
|
header6300 := blockchain.GetHeaderByNumber(config.XDPoS.Epoch * 7)
|
||||||
|
penalty, err := adaptor.EngineV2.HookPenalty(blockchain, big.NewInt(int64(config.XDPoS.Epoch*7)), header6300.ParentHash, masternodes)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
// miner (coinbase) is not parolee since one epoch it is not penalty. so it is in penalty. plus another one, total 2.
|
||||||
|
assert.Equal(t, 2, len(penalty))
|
||||||
|
|
||||||
|
common.TipUpgradePenalty = backup
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -45,11 +45,19 @@ func AttachConsensusV2Hooks(adaptor *XDPoS.XDPoS, bc *core.BlockChain, chainConf
|
||||||
parentNumber := number.Uint64() - 1
|
parentNumber := number.Uint64() - 1
|
||||||
parentHash := currentHash
|
parentHash := currentHash
|
||||||
|
|
||||||
|
var round types.Round
|
||||||
// check and wait the latest block is already in the disk
|
// check and wait the latest block is already in the disk
|
||||||
// sometimes blocks are yet inserted into block
|
// sometimes blocks are yet inserted into block
|
||||||
for timeout := 0; ; timeout++ {
|
for timeout := 0; ; timeout++ {
|
||||||
parentHeader := chain.GetHeader(parentHash, parentNumber)
|
parentHeader := chain.GetHeader(parentHash, parentNumber)
|
||||||
if parentHeader != nil { // found the latest block in the disk
|
if parentHeader != nil { // found the latest block in the disk
|
||||||
|
// extract round number from the lastest block
|
||||||
|
r, err := adaptor.EngineV2.GetRoundNumber(parentHeader)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("[V2 Hook Penalty] Fail to get round", "error", err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
round = r
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
log.Info("[V2 Hook Penalty] parentHeader is nil, wait block to be writen in disk", "parentNumber", parentNumber)
|
log.Info("[V2 Hook Penalty] parentHeader is nil, wait block to be writen in disk", "parentNumber", parentNumber)
|
||||||
|
|
@ -83,12 +91,17 @@ func AttachConsensusV2Hooks(adaptor *XDPoS.XDPoS, bc *core.BlockChain, chainConf
|
||||||
listBlockHash = append(listBlockHash, parentHash)
|
listBlockHash = append(listBlockHash, parentHash)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
currentConfig := chain.Config().XDPoS.V2.Config(uint64(round))
|
||||||
// add list not miner to penalties
|
// add list not miner to penalties
|
||||||
preMasternodes := adaptor.EngineV2.GetMasternodesByHash(chain, currentHash)
|
preMasternodes := adaptor.EngineV2.GetMasternodesByHash(chain, currentHash)
|
||||||
penalties := []common.Address{}
|
penalties := []common.Address{}
|
||||||
|
minimunMinerBlockPerEpoch := common.MinimunMinerBlockPerEpoch
|
||||||
|
if chain.Config().IsTIPUpgradePenalty(number) {
|
||||||
|
minimunMinerBlockPerEpoch = currentConfig.MinimumMinerBlockPerEpoch
|
||||||
|
}
|
||||||
for miner, total := range statMiners {
|
for miner, total := range statMiners {
|
||||||
if total < common.MinimunMinerBlockPerEpoch {
|
if total < minimunMinerBlockPerEpoch {
|
||||||
log.Info("[HookPenalty] Find a node does not create enough block", "addr", miner.Hex(), "total", total, "require", common.MinimunMinerBlockPerEpoch)
|
log.Info("[HookPenalty] Find a node does not create enough block", "addr", miner.Hex(), "total", total, "require", minimunMinerBlockPerEpoch)
|
||||||
penalties = append(penalties, miner)
|
penalties = append(penalties, miner)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -101,69 +114,130 @@ func AttachConsensusV2Hooks(adaptor *XDPoS.XDPoS, bc *core.BlockChain, chainConf
|
||||||
|
|
||||||
// get list check penalties signing block & list master nodes wil comeback
|
// get list check penalties signing block & list master nodes wil comeback
|
||||||
// start to calc comeback at v2 block + limitPenaltyEpochV2 to avoid reading v1 blocks
|
// start to calc comeback at v2 block + limitPenaltyEpochV2 to avoid reading v1 blocks
|
||||||
comebackHeight := (common.LimitPenaltyEpochV2+1)*chain.Config().XDPoS.Epoch + chain.Config().XDPoS.V2.SwitchBlock.Uint64()
|
|
||||||
penComebacks := []common.Address{}
|
|
||||||
if number.Uint64() > comebackHeight {
|
|
||||||
pens := adaptor.EngineV2.GetPreviousPenaltyByHash(chain, currentHash, common.LimitPenaltyEpochV2)
|
|
||||||
for _, p := range pens {
|
|
||||||
for _, addr := range candidates {
|
|
||||||
if p == addr {
|
|
||||||
log.Info("[HookPenalty] get previous penalty node and add into comeback list", "addr", addr)
|
|
||||||
penComebacks = append(penComebacks, p)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Loop for each block to check missing sign. with comeback nodes
|
if !chain.Config().IsTIPUpgradePenalty(number) {
|
||||||
mapBlockHash := map[common.Hash]bool{}
|
comebackHeight := (common.LimitPenaltyEpochV2+1)*chain.Config().XDPoS.Epoch + chain.Config().XDPoS.V2.SwitchBlock.Uint64()
|
||||||
startRange := common.RangeReturnSigner - 1
|
penComebacks := []common.Address{}
|
||||||
// to prevent visiting outside index of listBlockHash
|
if number.Uint64() > comebackHeight {
|
||||||
if startRange >= len(listBlockHash) {
|
pens := adaptor.EngineV2.GetPreviousPenaltyByHash(chain, currentHash, common.LimitPenaltyEpochV2)
|
||||||
startRange = len(listBlockHash) - 1
|
for _, p := range pens {
|
||||||
}
|
for _, addr := range candidates {
|
||||||
for i := startRange; i >= 0; i-- {
|
if p == addr {
|
||||||
if len(penComebacks) == 0 {
|
log.Info("[HookPenalty] get previous penalty node and add into comeback list", "addr", addr)
|
||||||
break
|
penComebacks = append(penComebacks, p)
|
||||||
}
|
|
||||||
blockNumber := number.Uint64() - uint64(i) - 1
|
|
||||||
bhash := listBlockHash[i]
|
|
||||||
if blockNumber%common.MergeSignRange == 0 {
|
|
||||||
mapBlockHash[bhash] = true
|
|
||||||
}
|
|
||||||
signingTxs, ok := adaptor.GetCachedSigningTxs(bhash)
|
|
||||||
if !ok {
|
|
||||||
block := chain.GetBlock(bhash, blockNumber)
|
|
||||||
txs := block.Transactions()
|
|
||||||
signingTxs = adaptor.CacheSigningTxs(bhash, txs)
|
|
||||||
}
|
|
||||||
// Check signer signed?
|
|
||||||
for _, tx := range signingTxs {
|
|
||||||
blkHash := common.BytesToHash(tx.Data()[len(tx.Data())-32:])
|
|
||||||
from := *tx.From()
|
|
||||||
if mapBlockHash[blkHash] {
|
|
||||||
for j, addr := range penComebacks {
|
|
||||||
if from == addr {
|
|
||||||
// Remove it from dupSigners.
|
|
||||||
penComebacks = append(penComebacks[:j], penComebacks[j+1:]...)
|
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
// Loop for each block to check missing sign. with comeback nodes
|
||||||
}
|
mapBlockHash := map[common.Hash]bool{}
|
||||||
|
startRange := common.RangeReturnSigner - 1
|
||||||
|
// to prevent visiting outside index of listBlockHash
|
||||||
|
if startRange >= len(listBlockHash) {
|
||||||
|
startRange = len(listBlockHash) - 1
|
||||||
|
}
|
||||||
|
for i := startRange; i >= 0; i-- {
|
||||||
|
if len(penComebacks) == 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
blockNumber := number.Uint64() - uint64(i) - 1
|
||||||
|
bhash := listBlockHash[i]
|
||||||
|
if blockNumber%common.MergeSignRange == 0 {
|
||||||
|
mapBlockHash[bhash] = true
|
||||||
|
}
|
||||||
|
signingTxs, ok := adaptor.GetCachedSigningTxs(bhash)
|
||||||
|
if !ok {
|
||||||
|
block := chain.GetBlock(bhash, blockNumber)
|
||||||
|
txs := block.Transactions()
|
||||||
|
signingTxs = adaptor.CacheSigningTxs(bhash, txs)
|
||||||
|
}
|
||||||
|
// Check signer signed?
|
||||||
|
for _, tx := range signingTxs {
|
||||||
|
blkHash := common.BytesToHash(tx.Data()[len(tx.Data())-32:])
|
||||||
|
from := *tx.From()
|
||||||
|
if mapBlockHash[blkHash] {
|
||||||
|
for j, addr := range penComebacks {
|
||||||
|
if from == addr {
|
||||||
|
// Remove it from dupSigners.
|
||||||
|
penComebacks = append(penComebacks[:j], penComebacks[j+1:]...)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for _, comeback := range penComebacks {
|
for _, comeback := range penComebacks {
|
||||||
ok := true
|
ok := true
|
||||||
for _, p := range penalties {
|
for _, p := range penalties {
|
||||||
if p == comeback {
|
if p == comeback {
|
||||||
ok = false
|
ok = false
|
||||||
break
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ok {
|
||||||
|
penalties = append(penalties, comeback)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ok {
|
} else { // after penalty upgrade
|
||||||
penalties = append(penalties, comeback)
|
comebackHeight := (uint64(currentConfig.LimitPenaltyEpoch)+1)*chain.Config().XDPoS.Epoch + chain.Config().XDPoS.V2.SwitchBlock.Uint64()
|
||||||
|
if number.Uint64() > comebackHeight {
|
||||||
|
// penParolees record those who stayed enough epoch of LimitPenaltyEpoch
|
||||||
|
penParoleeMap := map[common.Address]int{}
|
||||||
|
// lastPenalty record the last epoch penalties
|
||||||
|
lastPenalty := []common.Address{}
|
||||||
|
for i := 0; i <= currentConfig.LimitPenaltyEpoch; i++ {
|
||||||
|
pens := adaptor.EngineV2.GetPreviousPenaltyByHash(chain, currentHash, i)
|
||||||
|
for _, p := range pens {
|
||||||
|
penParoleeMap[p]++
|
||||||
|
}
|
||||||
|
if i == 0 {
|
||||||
|
// record the last epoch penalties
|
||||||
|
lastPenalty = pens
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Loop for each block to check missing sign. with comeback nodes
|
||||||
|
mapBlockHash := map[common.Hash]bool{}
|
||||||
|
txSignerMap := map[common.Address]int{}
|
||||||
|
startRange := int(chain.Config().XDPoS.Epoch) - 1
|
||||||
|
// to prevent visiting outside index of listBlockHash
|
||||||
|
if startRange >= len(listBlockHash) {
|
||||||
|
startRange = len(listBlockHash) - 1
|
||||||
|
}
|
||||||
|
for i := startRange; i >= 0; i-- {
|
||||||
|
blockNumber := number.Uint64() - uint64(i) - 1
|
||||||
|
bhash := listBlockHash[i]
|
||||||
|
if blockNumber%common.MergeSignRange == 0 {
|
||||||
|
mapBlockHash[bhash] = true
|
||||||
|
}
|
||||||
|
signingTxs, ok := adaptor.GetCachedSigningTxs(bhash)
|
||||||
|
if !ok {
|
||||||
|
block := chain.GetBlock(bhash, blockNumber)
|
||||||
|
txs := block.Transactions()
|
||||||
|
signingTxs = adaptor.CacheSigningTxs(bhash, txs)
|
||||||
|
}
|
||||||
|
// Check signer signed?
|
||||||
|
for _, tx := range signingTxs {
|
||||||
|
blkHash := common.BytesToHash(tx.Data()[len(tx.Data())-32:])
|
||||||
|
from := *tx.From()
|
||||||
|
if mapBlockHash[blkHash] {
|
||||||
|
txSignerMap[from]++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// check addr in lastPenalty, and if they does not meet condition, add them to penalty
|
||||||
|
for _, p := range lastPenalty {
|
||||||
|
if penParoleeMap[p] == currentConfig.LimitPenaltyEpoch+1 {
|
||||||
|
// check if this node signs enough
|
||||||
|
if txSignerMap[p] >= currentConfig.MinimumSigningTx {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// reaches here means that the node should still stays in penalty list
|
||||||
|
penalties = append(penalties, p)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -199,6 +199,8 @@ var (
|
||||||
MasternodeReward: 500, // double as Reward
|
MasternodeReward: 500, // double as Reward
|
||||||
ProtectorReward: 400,
|
ProtectorReward: 400,
|
||||||
ObserverReward: 300.125,
|
ObserverReward: 300.125,
|
||||||
|
LimitPenaltyEpoch: 1,
|
||||||
|
MinimumSigningTx: 2,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -484,6 +486,10 @@ type V2Config struct {
|
||||||
ProtectorReward float64 `json:"protectorReward"` // Block reward per protector - unit Ether
|
ProtectorReward float64 `json:"protectorReward"` // Block reward per protector - unit Ether
|
||||||
ObserverReward float64 `json:"observerReward"` // Block reward per observer - 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"`
|
ExpTimeoutConfig ExpTimeoutConfig `json:"expTimeoutConfig"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -541,6 +547,14 @@ func (c *V2Config) Description(name string, indent int) string {
|
||||||
banner += fmt.Sprintf("%s- TimeoutSyncThreshold: %v\n", prefix, c.TimeoutSyncThreshold)
|
banner += fmt.Sprintf("%s- TimeoutSyncThreshold: %v\n", prefix, c.TimeoutSyncThreshold)
|
||||||
banner += fmt.Sprintf("%s- TimeoutPeriod: %v\n", prefix, c.TimeoutPeriod)
|
banner += fmt.Sprintf("%s- TimeoutPeriod: %v\n", prefix, c.TimeoutPeriod)
|
||||||
banner += fmt.Sprintf("%s- CertThreshold: %v", prefix, c.CertThreshold)
|
banner += fmt.Sprintf("%s- CertThreshold: %v", prefix, c.CertThreshold)
|
||||||
|
banner += fmt.Sprintf("%s- MasternodeReward: %v", prefix, c.MasternodeReward)
|
||||||
|
banner += fmt.Sprintf("%s- ProtectorReward: %v", prefix, c.ProtectorReward)
|
||||||
|
banner += fmt.Sprintf("%s- ObserverReward: %v", prefix, c.ObserverReward)
|
||||||
|
banner += fmt.Sprintf("%s- MinimumMinerBlockPerEpoch: %v", prefix, c.MinimumMinerBlockPerEpoch)
|
||||||
|
banner += fmt.Sprintf("%s- LimitPenaltyEpoch: %v", prefix, c.LimitPenaltyEpoch)
|
||||||
|
banner += fmt.Sprintf("%s- MinimumSigningTx: %v", prefix, c.MinimumSigningTx)
|
||||||
|
banner += fmt.Sprintf("%s- ExpTimeoutBase: %v", prefix, c.ExpTimeoutConfig.Base)
|
||||||
|
banner += fmt.Sprintf("%s- ExpTimeoutMaxExponent: %v", prefix, c.ExpTimeoutConfig.MaxExponent)
|
||||||
return banner
|
return banner
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -786,6 +800,10 @@ func (c *ChainConfig) IsTIPUpgradeReward(num *big.Int) bool {
|
||||||
return isForked(common.TIPUpgradeReward, num)
|
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 {
|
func (c *ChainConfig) IsTIPEpochHalving(num *big.Int) bool {
|
||||||
return isForked(common.TIPEpochHalving, num)
|
return isForked(common.TIPEpochHalving, num)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue