style:Refactoring slashfilter
This commit is contained in:
parent
99c98b5de0
commit
425661772d
@ -27,24 +27,24 @@ func New(dstore ds.Batching) *SlashFilter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *SlashFilter) MinedBlock(ctx context.Context, bh *types.BlockHeader, parentEpoch abi.ChainEpoch) error {
|
func (f *SlashFilter) CheckBlock(ctx context.Context, bh *types.BlockHeader, parentEpoch abi.ChainEpoch) (cid.Cid, error) {
|
||||||
if build.IsNearUpgrade(bh.Height, build.UpgradeOrangeHeight) {
|
if build.IsNearUpgrade(bh.Height, build.UpgradeOrangeHeight) {
|
||||||
return nil
|
return cid.Undef, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
epochKey := ds.NewKey(fmt.Sprintf("/%s/%d", bh.Miner, bh.Height))
|
epochKey := ds.NewKey(fmt.Sprintf("/%s/%d", bh.Miner, bh.Height))
|
||||||
{
|
{
|
||||||
// double-fork mining (2 blocks at one epoch)
|
// double-fork mining (2 blocks at one epoch)
|
||||||
if err := checkFault(ctx, f.byEpoch, epochKey, bh, "double-fork mining faults"); err != nil {
|
if witness, err := checkFault(ctx, f.byEpoch, epochKey, bh, "double-fork mining faults"); err != nil {
|
||||||
return err
|
return witness, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
parentsKey := ds.NewKey(fmt.Sprintf("/%s/%x", bh.Miner, types.NewTipSetKey(bh.Parents...).Bytes()))
|
parentsKey := ds.NewKey(fmt.Sprintf("/%s/%x", bh.Miner, types.NewTipSetKey(bh.Parents...).Bytes()))
|
||||||
{
|
{
|
||||||
// time-offset mining faults (2 blocks with the same parents)
|
// time-offset mining faults (2 blocks with the same parents)
|
||||||
if err := checkFault(ctx, f.byParents, parentsKey, bh, "time-offset mining faults"); err != nil {
|
if witness, err := checkFault(ctx, f.byParents, parentsKey, bh, "time-offset mining faults"); err != nil {
|
||||||
return err
|
return witness, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -55,19 +55,19 @@ func (f *SlashFilter) MinedBlock(ctx context.Context, bh *types.BlockHeader, par
|
|||||||
parentEpochKey := ds.NewKey(fmt.Sprintf("/%s/%d", bh.Miner, parentEpoch))
|
parentEpochKey := ds.NewKey(fmt.Sprintf("/%s/%d", bh.Miner, parentEpoch))
|
||||||
have, err := f.byEpoch.Has(ctx, parentEpochKey)
|
have, err := f.byEpoch.Has(ctx, parentEpochKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return cid.Undef, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if have {
|
if have {
|
||||||
// If we had, make sure it's in our parent tipset
|
// If we had, make sure it's in our parent tipset
|
||||||
cidb, err := f.byEpoch.Get(ctx, parentEpochKey)
|
cidb, err := f.byEpoch.Get(ctx, parentEpochKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return xerrors.Errorf("getting other block cid: %w", err)
|
return cid.Undef, xerrors.Errorf("getting other block cid: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
_, parent, err := cid.CidFromBytes(cidb)
|
_, parent, err := cid.CidFromBytes(cidb)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return cid.Undef, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var found bool
|
var found bool
|
||||||
@ -78,45 +78,50 @@ func (f *SlashFilter) MinedBlock(ctx context.Context, bh *types.BlockHeader, par
|
|||||||
}
|
}
|
||||||
|
|
||||||
if !found {
|
if !found {
|
||||||
return xerrors.Errorf("produced block would trigger 'parent-grinding fault' consensus fault; miner: %s; bh: %s, expected parent: %s", bh.Miner, bh.Cid(), parent)
|
return cid.Undef, xerrors.Errorf("produced block would trigger 'parent-grinding fault' consensus fault; miner: %s; bh: %s, expected parent: %s", bh.Miner, bh.Cid(), parent)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := f.byParents.Put(ctx, parentsKey, bh.Cid().Bytes()); err != nil {
|
if err := f.byParents.Put(ctx, parentsKey, bh.Cid().Bytes()); err != nil {
|
||||||
return xerrors.Errorf("putting byEpoch entry: %w", err)
|
return cid.Undef, xerrors.Errorf("putting byEpoch entry: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := f.byEpoch.Put(ctx, epochKey, bh.Cid().Bytes()); err != nil {
|
if err := f.byEpoch.Put(ctx, epochKey, bh.Cid().Bytes()); err != nil {
|
||||||
return xerrors.Errorf("putting byEpoch entry: %w", err)
|
return cid.Undef, xerrors.Errorf("putting byEpoch entry: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return cid.Undef, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func checkFault(ctx context.Context, t ds.Datastore, key ds.Key, bh *types.BlockHeader, faultType string) error {
|
func (f *SlashFilter) MinedBlock(ctx context.Context, bh *types.BlockHeader, parentEpoch abi.ChainEpoch) error {
|
||||||
|
_, err := f.CheckBlock(ctx, bh, parentEpoch)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkFault(ctx context.Context, t ds.Datastore, key ds.Key, bh *types.BlockHeader, faultType string) (cid.Cid, error) {
|
||||||
fault, err := t.Has(ctx, key)
|
fault, err := t.Has(ctx, key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return cid.Undef, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if fault {
|
if fault {
|
||||||
cidb, err := t.Get(ctx, key)
|
cidb, err := t.Get(ctx, key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return xerrors.Errorf("getting other block cid: %w", err)
|
return cid.Undef, xerrors.Errorf("getting other block cid: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
_, other, err := cid.CidFromBytes(cidb)
|
_, other, err := cid.CidFromBytes(cidb)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return cid.Undef, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if other == bh.Cid() {
|
if other == bh.Cid() {
|
||||||
return nil
|
return cid.Undef, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return xerrors.Errorf("produced block would trigger '%s' consensus fault; miner: %s; bh: %s, other: %s", faultType, bh.Miner, bh.Cid(), other)
|
return other, xerrors.Errorf("produced block would trigger '%s' consensus fault; miner: %s; bh: %s, other: %s", faultType, bh.Miner, bh.Cid(), other)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return cid.Undef, nil
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,15 @@ import (
|
|||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/filecoin-project/go-address"
|
||||||
|
cborutil "github.com/filecoin-project/go-cbor-util"
|
||||||
|
"github.com/filecoin-project/go-state-types/builtin"
|
||||||
|
"github.com/filecoin-project/lotus/chain/actors"
|
||||||
|
"github.com/filecoin-project/lotus/chain/gen/slashfilter"
|
||||||
|
"github.com/filecoin-project/specs-actors/actors/builtin/miner"
|
||||||
|
"github.com/ipfs/go-cid"
|
||||||
|
levelds "github.com/ipfs/go-ds-leveldb"
|
||||||
|
ldbopts "github.com/syndtr/goleveldb/leveldb/opt"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
@ -29,7 +38,6 @@ import (
|
|||||||
|
|
||||||
"github.com/filecoin-project/go-jsonrpc"
|
"github.com/filecoin-project/go-jsonrpc"
|
||||||
"github.com/filecoin-project/go-paramfetch"
|
"github.com/filecoin-project/go-paramfetch"
|
||||||
|
|
||||||
lapi "github.com/filecoin-project/lotus/api"
|
lapi "github.com/filecoin-project/lotus/api"
|
||||||
"github.com/filecoin-project/lotus/build"
|
"github.com/filecoin-project/lotus/build"
|
||||||
"github.com/filecoin-project/lotus/chain/consensus"
|
"github.com/filecoin-project/lotus/chain/consensus"
|
||||||
@ -160,6 +168,19 @@ var DaemonCmd = &cli.Command{
|
|||||||
Name: "restore-config",
|
Name: "restore-config",
|
||||||
Usage: "config file to use when restoring from backup",
|
Usage: "config file to use when restoring from backup",
|
||||||
},
|
},
|
||||||
|
&cli.BoolFlag{
|
||||||
|
Name: "slash-consensus",
|
||||||
|
Usage: "Report consensus fault",
|
||||||
|
Value: false,
|
||||||
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "slasher-sender",
|
||||||
|
Usage: "optionally specify the account to report consensus from",
|
||||||
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "slashdb-dir",
|
||||||
|
Value: "slash watch db dir path",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
Action: func(cctx *cli.Context) error {
|
Action: func(cctx *cli.Context) error {
|
||||||
isLite := cctx.Bool("lite")
|
isLite := cctx.Bool("lite")
|
||||||
@ -380,7 +401,14 @@ var DaemonCmd = &cli.Command{
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to start json-rpc endpoint: %s", err)
|
return fmt.Errorf("failed to start json-rpc endpoint: %s", err)
|
||||||
}
|
}
|
||||||
|
if cctx.IsSet("slash-consensus") && cctx.IsSet("slashdb-dir") {
|
||||||
|
go func() {
|
||||||
|
err := slashConsensus(api, cctx.String("slashdb-dir"), cctx.String("slasher-sender"))
|
||||||
|
if err != nil {
|
||||||
|
panic("slashConsensus error")
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
// Monitor for shutdown.
|
// Monitor for shutdown.
|
||||||
finishCh := node.MonitorShutdown(shutdownChan,
|
finishCh := node.MonitorShutdown(shutdownChan,
|
||||||
node.ShutdownHandler{Component: "rpc server", StopFunc: rpcStopper},
|
node.ShutdownHandler{Component: "rpc server", StopFunc: rpcStopper},
|
||||||
@ -574,3 +602,99 @@ func ImportChain(ctx context.Context, r repo.Repo, fname string, snapshot bool)
|
|||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func slashConsensus(a lapi.FullNode, p string, from string) error {
|
||||||
|
ctx := context.Background()
|
||||||
|
var fromAddr address.Address
|
||||||
|
|
||||||
|
ds, err := levelds.NewDatastore(p, &levelds.Options{
|
||||||
|
Compression: ldbopts.NoCompression,
|
||||||
|
NoSync: false,
|
||||||
|
Strict: ldbopts.StrictAll,
|
||||||
|
ReadOnly: false,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return xerrors.Errorf("open leveldb: %w", err)
|
||||||
|
}
|
||||||
|
sf := slashfilter.New(ds)
|
||||||
|
if from == "" {
|
||||||
|
defaddr, err := a.WalletDefaultAddress(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
fromAddr = defaddr
|
||||||
|
} else {
|
||||||
|
addr, err := address.NewFromString(from)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
fromAddr = addr
|
||||||
|
}
|
||||||
|
|
||||||
|
blocks, err := a.SyncIncomingBlocks(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return xerrors.Errorf("sync incoming blocks failed: %w", err)
|
||||||
|
}
|
||||||
|
for block := range blocks {
|
||||||
|
log.Infof("deal with block: %d, %v, %s", block.Height, block.Miner, block.Cid())
|
||||||
|
if otherBlock, err := slashFilterMinedBlock(ctx, sf, a, block); err != nil {
|
||||||
|
if otherBlock == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
log.Errorf("<!!> SLASH FILTER ERROR: %s", err)
|
||||||
|
bh1, err := cborutil.Dump(otherBlock)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("could not dump otherblock:%s, err:%s", otherBlock.Cid(), err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
bh2, err := cborutil.Dump(block)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("could not dump block:%s, err:%s", block.Cid(), err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
params := miner.ReportConsensusFaultParams{
|
||||||
|
BlockHeader1: bh1,
|
||||||
|
BlockHeader2: bh2,
|
||||||
|
}
|
||||||
|
|
||||||
|
enc, err := actors.SerializeParams(¶ms)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("could not serialize declare faults parameters: %s", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
message, err := a.MpoolPushMessage(ctx, &types.Message{
|
||||||
|
To: block.Miner,
|
||||||
|
From: fromAddr,
|
||||||
|
Value: types.NewInt(0),
|
||||||
|
Method: builtin.MethodsMiner.ReportConsensusFault,
|
||||||
|
Params: enc,
|
||||||
|
}, nil)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("ReportConsensusFault to messagepool error:%s", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
log.Infof("ReportConsensusFault message CID:%s", message.Cid())
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func slashFilterMinedBlock(ctx context.Context, sf *slashfilter.SlashFilter, a lapi.FullNode, bh *types.BlockHeader) (*types.BlockHeader, error) {
|
||||||
|
parent, err := a.ChainGetBlock(ctx, bh.Parents[0])
|
||||||
|
if err != nil {
|
||||||
|
return nil, xerrors.Errorf("chain get block error:%s", err)
|
||||||
|
}
|
||||||
|
otherCid, err := sf.CheckBlock(ctx, bh, parent.Height)
|
||||||
|
if err != nil {
|
||||||
|
return nil, xerrors.Errorf("slash filter check block error:%s", err)
|
||||||
|
}
|
||||||
|
if otherCid != cid.Undef {
|
||||||
|
otherHeader, err := a.ChainGetBlock(ctx, otherCid)
|
||||||
|
return otherHeader, xerrors.Errorf("chain get other block error:%s", err)
|
||||||
|
}
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user