mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-17 18:30:45 +00:00
Xin 181 178 (#80)
* add skeleton forensics * remove duplicated penalty check in verify header
This commit is contained in:
parent
92857e50e5
commit
6c48d5be6c
5 changed files with 70 additions and 27 deletions
|
|
@ -57,6 +57,8 @@ type XDPoS_v2 struct {
|
||||||
|
|
||||||
HookReward func(chain consensus.ChainReader, state *state.StateDB, parentState *state.StateDB, header *types.Header) (map[string]interface{}, error)
|
HookReward func(chain consensus.ChainReader, state *state.StateDB, parentState *state.StateDB, header *types.Header) (map[string]interface{}, error)
|
||||||
HookPenalty func(chain consensus.ChainReader, number *big.Int, parentHash common.Hash, candidates []common.Address) ([]common.Address, error)
|
HookPenalty func(chain consensus.ChainReader, number *big.Int, parentHash common.Hash, candidates []common.Address) ([]common.Address, error)
|
||||||
|
|
||||||
|
forensics *Forensics
|
||||||
}
|
}
|
||||||
|
|
||||||
func New(config *params.XDPoSConfig, db ethdb.Database, waitPeriodCh chan int) *XDPoS_v2 {
|
func New(config *params.XDPoSConfig, db ethdb.Database, waitPeriodCh chan int) *XDPoS_v2 {
|
||||||
|
|
@ -110,6 +112,8 @@ func New(config *params.XDPoSConfig, db ethdb.Database, waitPeriodCh chan int) *
|
||||||
timeoutTimer.OnTimeoutFn = engine.OnCountdownTimeout
|
timeoutTimer.OnTimeoutFn = engine.OnCountdownTimeout
|
||||||
|
|
||||||
engine.periodicJob()
|
engine.periodicJob()
|
||||||
|
|
||||||
|
engine.AttachForensics()
|
||||||
return engine
|
return engine
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
52
consensus/XDPoS/engines/engine_v2/forensics.go
Normal file
52
consensus/XDPoS/engines/engine_v2/forensics.go
Normal file
|
|
@ -0,0 +1,52 @@
|
||||||
|
package engine_v2
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/XinFinOrg/XDPoSChain/common"
|
||||||
|
"github.com/XinFinOrg/XDPoSChain/consensus/XDPoS/utils"
|
||||||
|
"github.com/XinFinOrg/XDPoSChain/log"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ForensicProof struct {
|
||||||
|
QcWithSmallerRound utils.QuorumCert
|
||||||
|
QcWithLargerRound utils.QuorumCert
|
||||||
|
DivergingHash common.Hash
|
||||||
|
HashesTillSmallerRoundQc []common.Hash
|
||||||
|
HashesTillLargerRoundQc []common.Hash
|
||||||
|
AcrossEpochs bool
|
||||||
|
QcWithSmallerRoundAddresses []common.Address
|
||||||
|
QcWithLargerRoundAddresses []common.Address
|
||||||
|
}
|
||||||
|
|
||||||
|
type Forensics struct {
|
||||||
|
ReceiverCh <-chan utils.QuorumCert
|
||||||
|
Abort chan<- struct{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initiate a forensics process
|
||||||
|
func (x *XDPoS_v2) AttachForensics() {
|
||||||
|
receiver := make(chan utils.QuorumCert)
|
||||||
|
abort := make(chan struct{})
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
for {
|
||||||
|
// A real event arrived, process interesting content
|
||||||
|
select {
|
||||||
|
case quorumCert := <-receiver:
|
||||||
|
x.ProcessForensics(quorumCert)
|
||||||
|
case <-abort:
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
x.forensics = &Forensics{
|
||||||
|
ReceiverCh: receiver,
|
||||||
|
Abort: abort,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *XDPoS_v2) SendForensicProof() {
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *XDPoS_v2) ProcessForensics(quorumCert utils.QuorumCert) {
|
||||||
|
log.Info("Received a QC in forensics", "QC", quorumCert)
|
||||||
|
}
|
||||||
|
|
@ -101,7 +101,14 @@ func (x *XDPoS_v2) verifyHeader(chain consensus.ChainReader, header *types.Heade
|
||||||
if len(header.Validators)%common.AddressLength != 0 {
|
if len(header.Validators)%common.AddressLength != 0 {
|
||||||
return utils.ErrInvalidCheckpointSigners
|
return utils.ErrInvalidCheckpointSigners
|
||||||
}
|
}
|
||||||
isLegit, err := x.isValidatorsLegit(chain, header)
|
|
||||||
|
_, localPenalties, err := x.calcMasternodes(chain, header.Number, header.ParentHash)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("[verifyHeader] Fail to calculate master nodes list with penalty", "Number", header.Number, "Hash", header.Hash())
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
isLegit, err := x.isValidatorsLegit(chain, header, localPenalties)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("[verifyHeader] Error while trying to check if the validators are legit", "Hash", header.Hash(), "Number", header.Number, "ValidatorsLength", len(header.Validators))
|
log.Error("[verifyHeader] Error while trying to check if the validators are legit", "Hash", header.Hash(), "Number", header.Number, "ValidatorsLength", len(header.Validators))
|
||||||
return err
|
return err
|
||||||
|
|
@ -109,17 +116,6 @@ func (x *XDPoS_v2) verifyHeader(chain consensus.ChainReader, header *types.Heade
|
||||||
if !isLegit {
|
if !isLegit {
|
||||||
return utils.ErrValidatorsNotLegit
|
return utils.ErrValidatorsNotLegit
|
||||||
}
|
}
|
||||||
|
|
||||||
_, penalties, err := x.calcMasternodes(chain, header.Number, header.ParentHash)
|
|
||||||
if err != nil {
|
|
||||||
log.Error("[verifyHeader] Fail to calculate master nodes list with penalty", "Number", header.Number, "Hash", header.Hash())
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if !utils.CompareSignersLists(common.ExtractAddressFromBytes(header.Penalties), penalties) {
|
|
||||||
return utils.ErrPenaltyListDoesNotMatch
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
if len(header.Validators) != 0 {
|
if len(header.Validators) != 0 {
|
||||||
log.Warn("[verifyHeader] Validators shall not have values in non-epochSwitch block", "Hash", header.Hash(), "Number", header.Number, "header.Validators", header.Validators)
|
log.Warn("[verifyHeader] Validators shall not have values in non-epochSwitch block", "Hash", header.Hash(), "Number", header.Number, "header.Validators", header.Validators)
|
||||||
|
|
@ -167,16 +163,15 @@ func (x *XDPoS_v2) verifyHeader(chain consensus.ChainReader, header *types.Heade
|
||||||
}
|
}
|
||||||
|
|
||||||
// Verify the header validators address is legit by checking against its snapshot masternode list minutes the penalty list, we also ensure the order matches
|
// Verify the header validators address is legit by checking against its snapshot masternode list minutes the penalty list, we also ensure the order matches
|
||||||
func (x *XDPoS_v2) isValidatorsLegit(chain consensus.ChainReader, header *types.Header) (bool, error) {
|
func (x *XDPoS_v2) isValidatorsLegit(chain consensus.ChainReader, header *types.Header, penalties []common.Address) (bool, error) {
|
||||||
snap, err := x.getSnapshot(chain, header.Number.Uint64(), false)
|
snap, err := x.getSnapshot(chain, header.Number.Uint64(), false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("[isValidatorsLegit] Error while trying to get snapshot", "BlockNumber", header.Number.Int64(), "Hash", header.Hash().Hex(), "error", err)
|
log.Error("[isValidatorsLegit] Error while trying to get snapshot", "BlockNumber", header.Number.Int64(), "Hash", header.Hash().Hex(), "error", err)
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
// snap.NextEpochMasterNodes
|
// snap.NextEpochMasterNodes
|
||||||
penaltyList := common.ExtractAddressFromBytes(header.Penalties)
|
|
||||||
penaltyMap := make(map[common.Address]bool)
|
penaltyMap := make(map[common.Address]bool)
|
||||||
for _, item := range penaltyList {
|
for _, item := range penalties {
|
||||||
penaltyMap[item] = true
|
penaltyMap[item] = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -91,8 +91,7 @@ var (
|
||||||
ErrCoinbaseAndValidatorMismatch = errors.New("Validaotor and coinbase address in header does not match")
|
ErrCoinbaseAndValidatorMismatch = errors.New("Validaotor and coinbase address in header does not match")
|
||||||
ErrNotItsTurn = errors.New("Not validator's turn to mine this block")
|
ErrNotItsTurn = errors.New("Not validator's turn to mine this block")
|
||||||
|
|
||||||
ErrPenaltyListDoesNotMatch = errors.New("Incoming block penalty list does not match")
|
ErrRoundInvalid = errors.New("Invalid Round, it shall be bigger than QC round")
|
||||||
ErrRoundInvalid = errors.New("Invalid Round, it shall be bigger than QC round")
|
|
||||||
|
|
||||||
ErrAlreadyMined = errors.New("Already mined")
|
ErrAlreadyMined = errors.New("Already mined")
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -80,18 +80,13 @@ func TestShouldVerifyBlock(t *testing.T) {
|
||||||
err = adaptor.VerifyHeader(blockchain, invalidValidatorsSignerBlock, true)
|
err = adaptor.VerifyHeader(blockchain, invalidValidatorsSignerBlock, true)
|
||||||
assert.Equal(t, utils.ErrInvalidCheckpointSigners, err)
|
assert.Equal(t, utils.ErrInvalidCheckpointSigners, err)
|
||||||
|
|
||||||
invalidPenaltiesExistBlock := blockchain.GetBlockByNumber(901).Header()
|
|
||||||
invalidPenaltiesExistBlock.Penalties = common.Hex2BytesFixed("123131231", 20)
|
|
||||||
err = adaptor.VerifyHeader(blockchain, invalidPenaltiesExistBlock, true)
|
|
||||||
assert.Equal(t, utils.ErrPenaltyListDoesNotMatch, err)
|
|
||||||
|
|
||||||
// non-epoch switch
|
// non-epoch switch
|
||||||
invalidValidatorsExistBlock := blockchain.GetBlockByNumber(902).Header()
|
invalidValidatorsExistBlock := blockchain.GetBlockByNumber(902).Header()
|
||||||
invalidValidatorsExistBlock.Validators = []byte{123}
|
invalidValidatorsExistBlock.Validators = []byte{123}
|
||||||
err = adaptor.VerifyHeader(blockchain, invalidValidatorsExistBlock, true)
|
err = adaptor.VerifyHeader(blockchain, invalidValidatorsExistBlock, true)
|
||||||
assert.Equal(t, utils.ErrInvalidFieldInNonEpochSwitch, err)
|
assert.Equal(t, utils.ErrInvalidFieldInNonEpochSwitch, err)
|
||||||
|
|
||||||
invalidPenaltiesExistBlock = blockchain.GetBlockByNumber(902).Header()
|
invalidPenaltiesExistBlock := blockchain.GetBlockByNumber(902).Header()
|
||||||
invalidPenaltiesExistBlock.Penalties = common.Hex2BytesFixed("123131231", 20)
|
invalidPenaltiesExistBlock.Penalties = common.Hex2BytesFixed("123131231", 20)
|
||||||
err = adaptor.VerifyHeader(blockchain, invalidPenaltiesExistBlock, true)
|
err = adaptor.VerifyHeader(blockchain, invalidPenaltiesExistBlock, true)
|
||||||
assert.Equal(t, utils.ErrInvalidFieldInNonEpochSwitch, err)
|
assert.Equal(t, utils.ErrInvalidFieldInNonEpochSwitch, err)
|
||||||
|
|
@ -163,10 +158,8 @@ func TestShouldVerifyBlock(t *testing.T) {
|
||||||
|
|
||||||
// Make the validators not legit by adding something to the penalty
|
// Make the validators not legit by adding something to the penalty
|
||||||
validatorsNotLegit := blockchain.GetBlockByNumber(901).Header()
|
validatorsNotLegit := blockchain.GetBlockByNumber(901).Header()
|
||||||
penalties := []common.Address{acc1Addr}
|
|
||||||
for _, v := range penalties {
|
validatorsNotLegit.Validators = append(validatorsNotLegit.Validators, acc1Addr[:]...)
|
||||||
validatorsNotLegit.Penalties = append(validatorsNotLegit.Penalties, v[:]...)
|
|
||||||
}
|
|
||||||
err = adaptor.VerifyHeader(blockchain, validatorsNotLegit, true)
|
err = adaptor.VerifyHeader(blockchain, validatorsNotLegit, true)
|
||||||
assert.Equal(t, utils.ErrValidatorsNotLegit, err)
|
assert.Equal(t, utils.ErrValidatorsNotLegit, err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue