Skip to content

Commit

Permalink
monitor: use hash value comparison instead of signature comparison
Browse files Browse the repository at this point in the history
  • Loading branch information
j75689 committed Dec 16, 2022
1 parent bc44f29 commit 17a2fff
Show file tree
Hide file tree
Showing 7 changed files with 20 additions and 67 deletions.
5 changes: 0 additions & 5 deletions consensus/beacon/consensus.go
Original file line number Diff line number Diff line change
Expand Up @@ -338,11 +338,6 @@ func (beacon *Beacon) Close() error {
return beacon.ethone.Close()
}

// ExtraSeal returns fixed number of extra-data suffix bytes reserved for signer seal
func (beacon *Beacon) ExtraSeal() int {
return 0
}

// IsPoSHeader reports the header belongs to the PoS-stage with some special fields.
// This function is not suitable for a part of APIs like Prepare or CalcDifficulty
// because the header difficulty is not set yet.
Expand Down
5 changes: 0 additions & 5 deletions consensus/clique/clique.go
Original file line number Diff line number Diff line change
Expand Up @@ -595,11 +595,6 @@ func (c *Clique) Delay(chain consensus.ChainReader, header *types.Header, leftOv
return nil
}

// ExtraSeal returns fixed number of extra-data suffix bytes reserved for signer seal
func (c *Clique) ExtraSeal() int {
return extraSeal
}

// Seal implements consensus.Engine, attempting to create a sealed block using
// the local signing credentials.
func (c *Clique) Seal(chain consensus.ChainHeaderReader, block *types.Block, results chan<- *types.Block, stop <-chan struct{}) error {
Expand Down
3 changes: 0 additions & 3 deletions consensus/consensus.go
Original file line number Diff line number Diff line change
Expand Up @@ -118,9 +118,6 @@ type Engine interface {
// SealHash returns the hash of a block prior to it being sealed.
SealHash(header *types.Header) common.Hash

// ExtraSeal returns fixed number of extra-data suffix bytes reserved for signer seal
ExtraSeal() int

// CalcDifficulty is the difficulty adjustment algorithm. It returns the difficulty
// that a new block should have.
CalcDifficulty(chain ChainHeaderReader, time uint64, parent *types.Header) *big.Int
Expand Down
5 changes: 0 additions & 5 deletions consensus/ethash/consensus.go
Original file line number Diff line number Diff line change
Expand Up @@ -614,11 +614,6 @@ func (ethash *Ethash) Delay(_ consensus.ChainReader, _ *types.Header, _ *time.Du
return nil
}

// ExtraSeal returns fixed number of extra-data suffix bytes reserved for signer seal
func (ethash *Ethash) ExtraSeal() int {
return 0
}

// SealHash returns the hash of a block prior to it being sealed.
func (ethash *Ethash) SealHash(header *types.Header) (hash common.Hash) {
hasher := sha3.NewLegacyKeccak256()
Expand Down
5 changes: 0 additions & 5 deletions consensus/parlia/parlia.go
Original file line number Diff line number Diff line change
Expand Up @@ -820,11 +820,6 @@ func (p *Parlia) Delay(chain consensus.ChainReader, header *types.Header, leftOv
return &delay
}

// ExtraSeal returns fixed number of extra-data suffix bytes reserved for signer seal
func (p *Parlia) ExtraSeal() int {
return extraSeal
}

// Seal implements consensus.Engine, attempting to create a sealed block using
// the local signing credentials.
func (p *Parlia) Seal(chain consensus.ChainHeaderReader, block *types.Block, results chan<- *types.Block, stop <-chan struct{}) error {
Expand Down
2 changes: 1 addition & 1 deletion core/blockchain.go
Original file line number Diff line number Diff line change
Expand Up @@ -3010,7 +3010,7 @@ func EnableBlockValidator(chainConfig *params.ChainConfig, engine consensus.Engi
}

func EnableDoubleSignChecker(bc *BlockChain) (*BlockChain, error) {
bc.doubleSignMonitor = monitor.NewDoubleSignMonitor(bc.engine.ExtraSeal(), bc.engine.SealHash)
bc.doubleSignMonitor = monitor.NewDoubleSignMonitor()
return bc, nil
}

Expand Down
62 changes: 19 additions & 43 deletions core/monitor/double_sign_mointor.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,7 @@ package monitor

import (
"bytes"
"errors"

"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/prque"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/log"
Expand All @@ -14,62 +12,40 @@ const (
MaxCacheHeader = 100
)

func NewDoubleSignMonitor(
extraSeal int,
sealHash func(header *types.Header) (hash common.Hash),
) *DoubleSignMonitor {
func NewDoubleSignMonitor() *DoubleSignMonitor {
return &DoubleSignMonitor{
sealHash: sealHash,
extraSeal: extraSeal,
headerNumbers: prque.New(nil),
headers: make(map[uint64]*types.Header, MaxCacheHeader),
quit: make(chan struct{}),
}
}

type DoubleSignMonitor struct {
extraSeal int
sealHash func(header *types.Header) (hash common.Hash)
headerNumbers *prque.Prque
headers map[uint64]*types.Header
quit chan struct{}
}

func (m *DoubleSignMonitor) getSignature(h *types.Header) ([]byte, error) {
if len(h.Extra) < m.extraSeal {
return nil, errors.New("extra-data 65 byte signature suffix missing")
}
signature := h.Extra[len(h.Extra)-m.extraSeal:]
return signature, nil
}

func (m *DoubleSignMonitor) isDoubleSignHeaders(h1, h2 *types.Header) (bool, []byte, []byte, error) {
func (m *DoubleSignMonitor) isDoubleSignHeaders(h1, h2 *types.Header) (bool, error) {
if h1 == nil || h2 == nil {
return false, nil, nil, nil
return false, nil
}
if h1.Number.Cmp(h2.Number) != 0 {
return false, nil, nil, nil
return false, nil
}
if !bytes.Equal(h1.ParentHash[:], h2.ParentHash[:]) {
return false, nil, nil, nil
}
signature1, err := m.getSignature(h1)
if err != nil {
return false, nil, nil, err
}
signature2, err := m.getSignature(h2)
if err != nil {
return false, nil, nil, err
return false, nil
}
if bytes.Equal(signature1, signature2) {
return false, signature1, signature2, nil
// if the Hash is different the signature should not be equal
if bytes.Equal(h1.Hash().Bytes(), h2.Hash().Bytes()) {
return false, nil
}
// signer is already verified in sync program, we can trust coinbase.
if !bytes.Equal(h1.Coinbase.Bytes(), h2.Coinbase.Bytes()) {
return false, signature1, signature2, nil
return false, nil
}

return true, signature1, signature2, nil
return true, nil
}

func (m *DoubleSignMonitor) deleteOldHeader() {
Expand All @@ -78,42 +54,42 @@ func (m *DoubleSignMonitor) deleteOldHeader() {
delete(m.headers, h.Number.Uint64())
}

func (m *DoubleSignMonitor) checkHeader(h *types.Header) (bool, *types.Header, []byte, []byte, error) {
func (m *DoubleSignMonitor) checkHeader(h *types.Header) (bool, *types.Header, error) {
h2, exist := m.headers[h.Number.Uint64()]
if !exist {
if m.headerNumbers.Size() > MaxCacheHeader {
m.deleteOldHeader()
}
m.headers[h.Number.Uint64()] = h
m.headerNumbers.Push(h, -h.Number.Int64())
return false, nil, nil, nil, nil
return false, nil, nil
}

isDoubleSign, s1, s2, err := m.isDoubleSignHeaders(h, h2)
isDoubleSign, err := m.isDoubleSignHeaders(h, h2)
if err != nil {
return false, nil, s1, s2, err
return false, nil, err
}
if isDoubleSign {
return true, h2, s1, s2, nil
return true, h2, nil
}

return false, nil, s1, s2, nil
return false, nil, nil
}

func (m *DoubleSignMonitor) Start(ch <-chan *types.Header) {
for {
select {
case h := <-ch:
isDoubleSign, h2, s1, s2, err := m.checkHeader(h)
isDoubleSign, h2, err := m.checkHeader(h)
if err != nil {
log.Error("check double sign header error", "err", err)
continue
}
if isDoubleSign {
// found a double sign header
log.Error("found a double sign header", "number", h.Number.Uint64(),
"first_hash", h.Hash(), "first_miner", h.Coinbase, "first_signature", s1,
"second_hash", h2.Hash(), "second_miner", h2.Coinbase, "second_signature", s2)
"first_hash", h.Hash(), "first_miner", h.Coinbase,
"second_hash", h2.Hash(), "second_miner", h2.Coinbase)
}
case <-m.quit:
return
Expand Down

0 comments on commit 17a2fff

Please sign in to comment.