fix penalty calculation bug (#189)

This commit is contained in:
Liam 2022-10-09 14:06:04 +08:00 committed by GitHub
parent 73a6b1626d
commit a75c315eb5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 61 additions and 37 deletions

View file

@ -68,7 +68,7 @@ func (x *XDPoS_v2) onTimeoutPoolThresholdReached(blockChainReader consensus.Chai
syncInfo := x.getSyncInfo()
x.broadcastToBftChannel(syncInfo)
log.Info("Successfully processed the timeout message and produced TC & SyncInfo!", "TcRound", timeoutCert.Round, "NumberOfTcSig", len(timeoutCert.Signatures))
log.Info("Successfully processed the timeout message and produced TC & SyncInfo!", "QcRound", syncInfo.HighestQuorumCert.ProposedBlockInfo.Round, "QcBlockNum", syncInfo.HighestQuorumCert.ProposedBlockInfo.Number, "TcRound", timeoutCert.Round, "NumberOfTcSig", len(timeoutCert.Signatures))
return nil
}

View file

@ -53,9 +53,10 @@ func TestHookPenaltyV2Mining(t *testing.T) {
Coinbase: acc1Addr,
}
// Force to make the node to be at its round to mine, otherwise won't pass the yourturn masternodes check
// We have 19 nodes in total (20 candidates in snapshot - 1 penalty) and the fake signer is always at the 18th(last) in the list. Hence int(config.XDPoS.Epoch)*3+18-900, the +18 means is to force to next 18 round and -900 is the relative round number to block number int(config.XDPoS.Epoch)*3
// We have 19 nodes in total (20 candidates in snapshot - 1 penalty) and the fake signer is always at the 18th(last) in the list.
// Hence int(config.XDPoS.Epoch)*3+18-900, the +18 means is to force to next 18 round and -900 is the relative round number to block number int(config.XDPoS.Epoch)*3
adaptor.EngineV2.SetNewRoundFaker(blockchain, types.Round(int(config.XDPoS.Epoch)*3+18-900), false)
// The test default signer is not in the msaternodes, so we set the faker signer
// The test default signer is not in the masternodes, so we set the faker signer
adaptor.EngineV2.AuthorizeFaker(acc1Addr)
err = adaptor.Prepare(blockchain, headerMining)
assert.Nil(t, err)
@ -106,10 +107,32 @@ func TestHookPenaltyV2Jump(t *testing.T) {
assert.Nil(t, err)
masternodes := adaptor.GetMasternodesFromCheckpointHeader(header901)
assert.Equal(t, 5, len(masternodes))
header2085 := blockchain.GetHeaderByNumber(uint64(end))
header2685 := blockchain.GetHeaderByNumber(uint64(end))
adaptor.EngineV2.SetNewRoundFaker(blockchain, types.Round(config.XDPoS.Epoch*3), false)
// round 2085-2100 miss blocks, penalty should work as usual
penalty, err := adaptor.EngineV2.HookPenalty(blockchain, header2085.Number, header2085.ParentHash, masternodes)
// round 2685-2700 miss blocks, penalty should work as usual
penalty, err := adaptor.EngineV2.HookPenalty(blockchain, header2685.Number, header2685.ParentHash, masternodes)
assert.Nil(t, err)
assert.Equal(t, 2, len(penalty))
}
// Test calculate penalty under startRange blocks, currently is 150
func TestHookPenaltyV2LessThen150Blocks(t *testing.T) {
config := params.TestXDPoSMockChainConfig
blockchain, _, _, _, _ := PrepareXDCTestBlockChainWithPenaltyForV2Engine(t, int(config.XDPoS.Epoch)*3, 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))
header1900 := blockchain.GetHeaderByNumber(1900)
adaptor.EngineV2.SetNewRoundFaker(blockchain, types.Round(config.XDPoS.Epoch*3), false)
// penalty count from 1900
penalty, err := adaptor.EngineV2.HookPenalty(blockchain, header1900.Number, header1900.ParentHash, masternodes)
assert.Nil(t, err)
assert.Equal(t, 2, len(penalty))
}

View file

@ -174,9 +174,11 @@ func (b *Bfter) Stop() {
close(b.quit)
}
func (b *Bfter) loop() {
log.Info("BFT Loop Start")
for {
select {
case <-b.quit:
log.Warn("BFT Loop Close")
return
case obj := <-b.broadcastCh:
switch v := obj.(type) {

View file

@ -22,11 +22,10 @@ func AttachConsensusV2Hooks(adaptor *XDPoS.XDPoS, bc *core.BlockChain, chainConf
// Hook scans for bad masternodes and decide to penalty them
adaptor.EngineV2.HookPenalty = func(chain consensus.ChainReader, number *big.Int, currentHash common.Hash, candidates []common.Address) ([]common.Address, error) {
start := time.Now()
listBlockHash := make([]common.Hash, chain.Config().XDPoS.Epoch)
listBlockHash := []common.Hash{}
// get list block hash & stats total created block
statMiners := make(map[common.Address]int)
listBlockHash[0] = currentHash
listBlockHash = append(listBlockHash, currentHash)
parentNumber := number.Uint64() - 1
parentHash := currentHash
@ -63,9 +62,10 @@ func AttachConsensusV2Hooks(adaptor *XDPoS.XDPoS, bc *core.BlockChain, chainConf
} else {
statMiners[miner] = 1
}
parentHash = parentHeader.ParentHash
listBlockHash[i] = parentHash
parentNumber--
parentHash = parentHeader.ParentHash
listBlockHash = append(listBlockHash, parentHash)
log.Debug("[HookPenalty] listBlockHash", "i", i, "len", len(listBlockHash), "parentHash", parentHash, "parentNumber", parentNumber)
}
// add list not miner to penalties
@ -109,35 +109,34 @@ func AttachConsensusV2Hooks(adaptor *XDPoS.XDPoS, bc *core.BlockChain, chainConf
startRange = len(listBlockHash) - 1
}
for i := startRange; i >= 0; i-- {
if len(penComebacks) > 0 {
blockNumber := number.Uint64() - uint64(i) - 1
bhash := listBlockHash[i]
if blockNumber%common.MergeSignRange == 0 {
mapBlockHash[bhash] = true
}
signData, ok := adaptor.GetCachedSigningTxs(bhash)
if !ok {
block := chain.GetBlock(bhash, blockNumber)
txs := block.Transactions()
signData = adaptor.CacheSigningTxs(bhash, txs)
}
txs := signData.([]*types.Transaction)
// Check signer signed?
for _, tx := range txs {
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
}
if len(penComebacks) == 0 {
break
}
blockNumber := number.Uint64() - uint64(i) - 1
bhash := listBlockHash[i]
if blockNumber%common.MergeSignRange == 0 {
mapBlockHash[bhash] = true
}
signData, ok := adaptor.GetCachedSigningTxs(bhash)
if !ok {
block := chain.GetBlock(bhash, blockNumber)
txs := block.Transactions()
signData = adaptor.CacheSigningTxs(bhash, txs)
}
txs := signData.([]*types.Transaction)
// Check signer signed?
for _, tx := range txs {
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
}
}
}
} else {
break
}
}