From 50a86f2161c6a88dc2d1b6b70a6e01e9cb88b46b Mon Sep 17 00:00:00 2001 From: Aayush Date: Tue, 13 Jun 2023 10:51:03 -0400 Subject: [PATCH] feat: improvements to the consensus slasher --- cmd/lotus/daemon.go | 49 ++++++++++++++++++++++++++++----------------- miner/miner.go | 2 +- 2 files changed, 32 insertions(+), 19 deletions(-) diff --git a/cmd/lotus/daemon.go b/cmd/lotus/daemon.go index 44082e058..9fa1d42ae 100644 --- a/cmd/lotus/daemon.go +++ b/cmd/lotus/daemon.go @@ -16,7 +16,6 @@ import ( "strings" "github.com/DataDog/zstd" - "github.com/ipfs/go-cid" levelds "github.com/ipfs/go-ds-leveldb" metricsprom "github.com/ipfs/go-metrics-prometheus" "github.com/mitchellh/go-homedir" @@ -639,11 +638,13 @@ func slashConsensus(a lapi.FullNode, p string, from string) error { } for block := range blocks { 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 { - if otherBlock == nil { - continue - } - log.Errorf(" SLASH FILTER ERROR: %s", err) + otherBlock, extraBlock, fault, err := slashFilterMinedBlock(ctx, sf, a, block) + if err != nil { + log.Errorf("slash detector errored: %s", err) + continue + } + if fault { + log.Errorf(" SLASH FILTER DETECTED FAULT DUE TO BLOCKS %s and %s", otherBlock.Cid(), block.Cid()) bh1, err := cborutil.Dump(otherBlock) if err != nil { 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, }, nil) if err != nil { - log.Errorf("ReportConsensusFault to messagepool error:%w", err) + log.Errorf("ReportConsensusFault to messagepool error:%s", err) continue } log.Infof("ReportConsensusFault message CID:%s", message.Cid()) @@ -692,24 +693,35 @@ func slashConsensus(a lapi.FullNode, p string, from string) error { 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]) 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 { - 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 { - otherHeader, err := a.ChainGetBlock(ctx, otherCid) - return otherHeader, nil, xerrors.Errorf("chain get other block error:%s", err) + if !fault { + return nil, nil, false, nil } - blockA, err := a.ChainGetBlock(ctx, otherCid) - if + blockA, err := a.ChainGetBlock(ctx, blockACid) + 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 // 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] if types.CidArrsEqual(blockA.Parents, blockC.Parents) && blockA.Height == blockC.Height && 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 } diff --git a/miner/miner.go b/miner/miner.go index 1caaade96..9281854d7 100644 --- a/miner/miner.go +++ b/miner/miner.go @@ -333,7 +333,7 @@ minerLoop: } 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 } }