feat: improvements to the consensus slasher
This commit is contained in:
parent
a413a53be2
commit
50a86f2161
@ -16,7 +16,6 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/DataDog/zstd"
|
"github.com/DataDog/zstd"
|
||||||
"github.com/ipfs/go-cid"
|
|
||||||
levelds "github.com/ipfs/go-ds-leveldb"
|
levelds "github.com/ipfs/go-ds-leveldb"
|
||||||
metricsprom "github.com/ipfs/go-metrics-prometheus"
|
metricsprom "github.com/ipfs/go-metrics-prometheus"
|
||||||
"github.com/mitchellh/go-homedir"
|
"github.com/mitchellh/go-homedir"
|
||||||
@ -639,11 +638,13 @@ func slashConsensus(a lapi.FullNode, p string, from string) error {
|
|||||||
}
|
}
|
||||||
for block := range blocks {
|
for block := range blocks {
|
||||||
log.Infof("deal with block: %d, %v, %s", block.Height, block.Miner, block.Cid())
|
log.Infof("deal with block: %d, %v, %s", block.Height, block.Miner, block.Cid())
|
||||||
if otherBlock, extraBlock, err := slashFilterMinedBlock(ctx, sf, a, block); err != nil {
|
otherBlock, extraBlock, fault, err := slashFilterMinedBlock(ctx, sf, a, block)
|
||||||
if otherBlock == nil {
|
if err != nil {
|
||||||
continue
|
log.Errorf("slash detector errored: %s", err)
|
||||||
}
|
continue
|
||||||
log.Errorf("<!!> SLASH FILTER ERROR: %s", err)
|
}
|
||||||
|
if fault {
|
||||||
|
log.Errorf("<!!> SLASH FILTER DETECTED FAULT DUE TO BLOCKS %s and %s", otherBlock.Cid(), block.Cid())
|
||||||
bh1, err := cborutil.Dump(otherBlock)
|
bh1, err := cborutil.Dump(otherBlock)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("could not dump otherblock:%s, err:%s", otherBlock.Cid(), err)
|
log.Errorf("could not dump otherblock:%s, err:%s", otherBlock.Cid(), err)
|
||||||
@ -682,7 +683,7 @@ func slashConsensus(a lapi.FullNode, p string, from string) error {
|
|||||||
Params: enc,
|
Params: enc,
|
||||||
}, nil)
|
}, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("ReportConsensusFault to messagepool error:%w", err)
|
log.Errorf("ReportConsensusFault to messagepool error:%s", err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
log.Infof("ReportConsensusFault message CID:%s", message.Cid())
|
log.Infof("ReportConsensusFault message CID:%s", message.Cid())
|
||||||
@ -692,24 +693,35 @@ func slashConsensus(a lapi.FullNode, p string, from string) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func slashFilterMinedBlock(ctx context.Context, sf *slashfilter.SlashFilter, a lapi.FullNode, blockB *types.BlockHeader) (*types.BlockHeader, *types.BlockHeader, error) {
|
func slashFilterMinedBlock(ctx context.Context, sf *slashfilter.SlashFilter, a lapi.FullNode, blockB *types.BlockHeader) (*types.BlockHeader, *types.BlockHeader, bool, error) {
|
||||||
blockC, err := a.ChainGetBlock(ctx, blockB.Parents[0])
|
blockC, err := a.ChainGetBlock(ctx, blockB.Parents[0])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, xerrors.Errorf("chain get block error:%s", err)
|
return nil, nil, false, xerrors.Errorf("chain get block error:%s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
otherCid, err := sf.MinedBlock(ctx, blockB, blockC.Height)
|
blockACid, fault, err := sf.MinedBlock(ctx, blockB, blockC.Height)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, xerrors.Errorf("slash filter check block error:%s", err)
|
return nil, nil, false, xerrors.Errorf("slash filter check block error:%s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if otherCid != cid.Undef {
|
if !fault {
|
||||||
otherHeader, err := a.ChainGetBlock(ctx, otherCid)
|
return nil, nil, false, nil
|
||||||
return otherHeader, nil, xerrors.Errorf("chain get other block error:%s", err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
blockA, err := a.ChainGetBlock(ctx, otherCid)
|
blockA, err := a.ChainGetBlock(ctx, blockACid)
|
||||||
if
|
if err != nil {
|
||||||
|
return nil, nil, false, xerrors.Errorf("failed to get blockA: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// (a) double-fork mining (2 blocks at one epoch)
|
||||||
|
if blockA.Height == blockB.Height {
|
||||||
|
return blockA, nil, true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// (b) time-offset mining faults (2 blocks with the same parents)
|
||||||
|
if types.CidArrsEqual(blockB.Parents, blockA.Parents) {
|
||||||
|
return blockA, nil, true, nil
|
||||||
|
}
|
||||||
|
|
||||||
// (c) parent-grinding fault
|
// (c) parent-grinding fault
|
||||||
// Here extra is the "witness", a third block that shows the connection between A and B as
|
// Here extra is the "witness", a third block that shows the connection between A and B as
|
||||||
@ -721,8 +733,9 @@ func slashFilterMinedBlock(ctx context.Context, sf *slashfilter.SlashFilter, a l
|
|||||||
// [A, C]
|
// [A, C]
|
||||||
if types.CidArrsEqual(blockA.Parents, blockC.Parents) && blockA.Height == blockC.Height &&
|
if types.CidArrsEqual(blockA.Parents, blockC.Parents) && blockA.Height == blockC.Height &&
|
||||||
types.CidArrsContains(blockB.Parents, blockC.Cid()) && !types.CidArrsContains(blockB.Parents, blockA.Cid()) {
|
types.CidArrsContains(blockB.Parents, blockC.Cid()) && !types.CidArrsContains(blockB.Parents, blockA.Cid()) {
|
||||||
return blockA, blockC, xerrors.Errorf("chain get other block error:%s", err)
|
return blockA, blockC, true, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, nil, nil
|
log.Error("unexpectedly reached end of slashFilterMinedBlock despite fault being reported!")
|
||||||
|
return nil, nil, false, nil
|
||||||
}
|
}
|
||||||
|
@ -333,7 +333,7 @@ minerLoop:
|
|||||||
}
|
}
|
||||||
|
|
||||||
if fault {
|
if fault {
|
||||||
log.Errorf("<!!> SLASH FILTER DETECTED FAULT due to witness %s", witness)
|
log.Errorf("<!!> SLASH FILTER DETECTED FAULT due to blocks %s and %s", b.Header.Cid(), witness)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user