Skip to content

Commit

Permalink
Merge pull request irisnet#1080 from MrXJC/censorship2
Browse files Browse the repository at this point in the history
R4R: Censorship Slash
  • Loading branch information
wukongcheng authored Jan 17, 2019
2 parents 5d52a17 + c689419 commit 11c5756
Show file tree
Hide file tree
Showing 7 changed files with 171 additions and 28 deletions.
12 changes: 10 additions & 2 deletions app/baseapp.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,12 @@ import (
"github.com/gogo/protobuf/proto"
"github.com/irisnet/irishub/app/protocol"
"github.com/irisnet/irishub/codec"
"github.com/irisnet/irishub/modules/auth"
"github.com/irisnet/irishub/store"
sdk "github.com/irisnet/irishub/types"
"github.com/irisnet/irishub/version"
tmstate "github.com/tendermint/tendermint/state"
"strconv"
"github.com/irisnet/irishub/modules/auth"
)

// Key to store the consensus params in the main store.
Expand Down Expand Up @@ -482,7 +482,7 @@ func (app *BaseApp) BeginBlock(req abci.RequestBeginBlock) (res abci.ResponseBeg
// by InitChain. Context is now updated with Header information.
app.deliverState.ctx = app.deliverState.ctx.
WithBlockHeader(req.Header).
WithBlockHeight(req.Header.Height)
WithBlockHeight(req.Header.Height).WithCheckValidNum(0)
}

// add block gas meter
Expand All @@ -502,6 +502,7 @@ func (app *BaseApp) BeginBlock(req abci.RequestBeginBlock) (res abci.ResponseBeg
// set the signed validators for addition to context in deliverTx
// TODO: communicate this result to the address to pubkey map in slashing
app.voteInfos = req.LastCommitInfo.GetVotes()

return
}

Expand Down Expand Up @@ -539,7 +540,9 @@ func (app *BaseApp) DeliverTx(txBytes []byte) (res abci.ResponseDeliverTx) {
if err != nil {
result = err.Result()
} else {
// success pass txDecoder
result = app.runTx(RunTxModeDeliver, txBytes, tx)

}

// Even though the Result.Code is not OK, there are still effects,
Expand Down Expand Up @@ -702,6 +705,10 @@ func (app *BaseApp) runTx(mode RunTxMode, txBytes []byte, tx sdk.Tx) (result sdk
return err.Result()
}

if mode == RunTxModeDeliver {
app.deliverState.ctx = app.deliverState.ctx.WithCheckValidNum(app.deliverState.ctx.CheckValidNum() + 1)
}

defer func() {
if r := recover(); r != nil {
switch rType := r.(type) {
Expand Down Expand Up @@ -819,6 +826,7 @@ func (app *BaseApp) runTx(mode RunTxMode, txBytes []byte, tx sdk.Tx) (result sdk

// EndBlock implements the ABCI application interface.
func (app *BaseApp) EndBlock(req abci.RequestEndBlock) (res abci.ResponseEndBlock) {

if app.deliverState.ms.TracingEnabled() {
app.deliverState.ms = app.deliverState.ms.ResetTraceContext().(sdk.CacheMultiStore)
}
Expand Down
4 changes: 2 additions & 2 deletions app/v0/protocol_v0.go
Original file line number Diff line number Diff line change
Expand Up @@ -304,10 +304,10 @@ func (p *ProtocolV0) BeginBlocker(ctx sdk.Context, req abci.RequestBeginBlock) a
// application updates every end block
func (p *ProtocolV0) EndBlocker(ctx sdk.Context, req abci.RequestEndBlock) abci.ResponseEndBlock {
tags := gov.EndBlocker(ctx, p.govKeeper)
validatorUpdates := stake.EndBlocker(ctx, p.StakeKeeper)
tags = tags.AppendTags(slashing.EndBlocker(ctx, req, p.slashingKeeper))
tags = tags.AppendTags(service.EndBlocker(ctx, p.serviceKeeper))
tags = tags.AppendTags(upgrade.EndBlocker(ctx, p.upgradeKeeper))

validatorUpdates := stake.EndBlocker(ctx, p.StakeKeeper)
p.assertRuntimeInvariants(ctx)

return abci.ResponseEndBlock{
Expand Down
46 changes: 45 additions & 1 deletion modules/slashing/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ import (
"time"

"github.com/irisnet/irishub/codec"
sdk "github.com/irisnet/irishub/types"
"github.com/irisnet/irishub/modules/params"
stake "github.com/irisnet/irishub/modules/stake/types"
sdk "github.com/irisnet/irishub/types"
"github.com/tendermint/tendermint/crypto"
)

Expand Down Expand Up @@ -174,6 +174,50 @@ func (k Keeper) handleValidatorSignature(ctx sdk.Context, addr crypto.Address, p
return
}

// Punish proposer censorship by slashing malefactor's stake
func (k Keeper) handleProposerCensorship(ctx sdk.Context, addr crypto.Address, infractionHeight int64) (tags sdk.Tags) {
logger := ctx.Logger().With("module", "x/slashing")
time := ctx.BlockHeader().Time
consAddr := sdk.ConsAddress(addr)
pubkey, err := k.getPubkey(ctx, addr)
if err != nil {
panic(fmt.Sprintf("Validator consensus-address %v not found", consAddr))
}

// Get validator.
validator := k.validatorSet.ValidatorByConsAddr(ctx, consAddr)
if validator == nil || validator.GetStatus() == sdk.Unbonded {
// Defensive.
// Simulation doesn't take unbonding periods into account, and
// Tendermint might break this assumption at some point.
return
}
logger.Info(fmt.Sprintf("proposer censorship from %s at height %d", pubkey.Address(), infractionHeight))

distributionHeight := infractionHeight - stake.ValidatorUpdateDelay
// Slash validator
// `power` is the int64 power of the validator as provided to/by
// Tendermint. This value is validator.Tokens as sent to Tendermint via
// ABCI, and now received as evidence.
// The revisedFraction (which is the new fraction to be slashed) is passed
// in separately to separately slash unbonding and rebonding delegations.
tags = k.validatorSet.Slash(ctx, consAddr, distributionHeight, validator.GetPower().RoundInt64(), k.SlashFractionCensorship(ctx))

// Jail validator if not already jailed
if !validator.GetJailed() {
k.validatorSet.Jail(ctx, consAddr)
}

// Set or updated validator jail duration
signInfo, found := k.getValidatorSigningInfo(ctx, consAddr)
if !found {
panic(fmt.Sprintf("Expected signing info for validator %s but not found", consAddr))
}
signInfo.JailedUntil = time.Add(k.CensorshipUnbondDuration(ctx))
k.SetValidatorSigningInfo(ctx, consAddr, signInfo)
return
}

func (k Keeper) addPubkey(ctx sdk.Context, pubkey crypto.PubKey) {
addr := pubkey.Address()
k.setAddrPubkeyRelation(ctx, addr, pubkey)
Expand Down
97 changes: 81 additions & 16 deletions modules/slashing/params.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@ package slashing
import (
"time"

"fmt"
"github.com/irisnet/irishub/codec"
"github.com/irisnet/irishub/modules/params"
sdk "github.com/irisnet/irishub/types"
"fmt"
"strconv"
)

Expand All @@ -26,6 +26,8 @@ var (
KeyDowntimeJailDuration = []byte("DowntimeJailDuration")
KeySlashFractionDoubleSign = []byte("SlashFractionDoubleSign")
KeySlashFractionDowntime = []byte("SlashFractionDowntime")
keySlashFractionCensorship = []byte("SlashFractionCensorship")
keyCensorshipJailDuration = []byte("CensorshipJailDuration")
)

// ParamTypeTable for slashing module
Expand All @@ -42,6 +44,8 @@ type Params struct {
DowntimeJailDuration time.Duration `json:"downtime-unbond-duration"`
SlashFractionDoubleSign sdk.Dec `json:"slash-fraction-double-sign"`
SlashFractionDowntime sdk.Dec `json:"slash-fraction-downtime"`
SlashFractionCensorship sdk.Dec `json:"slash-fraction-censorship"`
CensorshipJailDuration time.Duration `json:"censorship-jail-duration"`
}

// Implements params.ParamStruct
Expand All @@ -54,6 +58,8 @@ func (p *Params) KeyValuePairs() params.KeyValuePairs {
{KeyDowntimeJailDuration, &p.DowntimeJailDuration},
{KeySlashFractionDoubleSign, &p.SlashFractionDoubleSign},
{KeySlashFractionDowntime, &p.SlashFractionDowntime},
{keySlashFractionCensorship, &p.SlashFractionCensorship},
{keyCensorshipJailDuration, &p.CensorshipJailDuration},
}
}

Expand Down Expand Up @@ -122,6 +128,24 @@ func (p *Params) Validate(key string, value string) (interface{}, sdk.Error) {
return nil, err
}
return slashFractionDowntime, nil
case string(keySlashFractionCensorship):
slashFractionCensorship, err := sdk.NewDecFromStr(value)
if err != nil {
return nil, params.ErrInvalidString(value)
}
if err := validateSlashFractionCensorship(slashFractionCensorship); err != nil {
return nil, err
}
return slashFractionCensorship, nil
case string(keyCensorshipJailDuration):
censorshipJailDuration, err := time.ParseDuration(value)
if err != nil {
return nil, params.ErrInvalidString(value)
}
if err := validateCensorshipJailDuration(censorshipJailDuration); err != nil {
return nil, err
}
return censorshipJailDuration, nil
default:
return nil, sdk.NewError(params.DefaultCodespace, params.CodeInvalidKey, fmt.Sprintf("%s is not found", key))
}
Expand Down Expand Up @@ -154,6 +178,12 @@ func (p *Params) StringFromBytes(cdc *codec.Codec, key string, bytes []byte) (st
case string(KeySlashFractionDowntime):
err := cdc.UnmarshalJSON(bytes, &p.SlashFractionDowntime)
return p.SlashFractionDowntime.String(), err
case string(keySlashFractionCensorship):
err := cdc.UnmarshalJSON(bytes, &p.SlashFractionCensorship)
return p.SlashFractionCensorship.String(), err
case string(keyCensorshipJailDuration):
err := cdc.UnmarshalJSON(bytes, &p.CensorshipJailDuration)
return p.CensorshipJailDuration.String(), err
default:
return "", fmt.Errorf("%s is not existed", key)
}
Expand All @@ -162,25 +192,29 @@ func (p *Params) StringFromBytes(cdc *codec.Codec, key string, bytes []byte) (st
// Default parameters used by Iris Hub
func DefaultParams() Params {
return Params{
MaxEvidenceAge: sdk.Day,
DoubleSignJailDuration: 5 * sdk.Day,
SignedBlocksWindow: 20000,
DowntimeJailDuration: 2 * sdk.Day,
MinSignedPerWindow: sdk.NewDecWithPrec(5, 1),
MaxEvidenceAge: sdk.Day,
DoubleSignJailDuration: 5 * sdk.Day,
SignedBlocksWindow: 20000,
DowntimeJailDuration: 2 * sdk.Day,
MinSignedPerWindow: sdk.NewDecWithPrec(5, 1),
SlashFractionDoubleSign: sdk.NewDecWithPrec(1, 2),
SlashFractionDowntime: sdk.NewDecWithPrec(5, 3),
SlashFractionDowntime: sdk.NewDecWithPrec(5, 3),
SlashFractionCensorship: sdk.NewDecWithPrec(2, 2),
CensorshipJailDuration: 7 * sdk.Day,
}
}

func DefaultParamsForTestnet() Params {
return Params{
MaxEvidenceAge: 10 * time.Minute,
DoubleSignJailDuration: 60 * 5 * time.Second,
SignedBlocksWindow: 100,
DowntimeJailDuration: 60 * 10 * time.Second,
MinSignedPerWindow: sdk.NewDecWithPrec(5, 1),
MaxEvidenceAge: 10 * time.Minute,
DoubleSignJailDuration: 60 * 5 * time.Second,
SignedBlocksWindow: 100,
DowntimeJailDuration: 60 * 10 * time.Second,
MinSignedPerWindow: sdk.NewDecWithPrec(5, 1),
SlashFractionDoubleSign: sdk.NewDec(1).Quo(sdk.NewDec(20)),
SlashFractionDowntime: sdk.NewDec(1).Quo(sdk.NewDec(100)),
SlashFractionDowntime: sdk.NewDec(1).Quo(sdk.NewDec(100)),
SlashFractionCensorship: sdk.NewDecWithPrec(2, 2),
CensorshipJailDuration: 60 * 7 * time.Second,
}
}

Expand Down Expand Up @@ -210,7 +244,12 @@ func validateParams(p Params) sdk.Error {
if err := validateSlashFractionDowntime(p.SlashFractionDowntime); err != nil {
return err
}

if err := validateSlashFractionCensorship(p.SlashFractionCensorship); err != nil {
return err
}
if err := validateCensorshipJailDuration(p.CensorshipJailDuration); err != nil {
return err
}
return nil
}

Expand All @@ -219,19 +258,26 @@ func validateMaxEvidenceAge(p time.Duration) sdk.Error {
if p < sdk.Day {
return sdk.NewError(params.DefaultCodespace, params.CodeInvalidSlashParams, fmt.Sprintf("Slash MaxEvidenceAge [%s] should be between [1day,) ", p.String()))
}
} else if p < 10 * time.Minute {
} else if p < 10*time.Minute {
return sdk.NewError(params.DefaultCodespace, params.CodeInvalidSlashParams, fmt.Sprintf("Slash MaxEvidenceAge [%s] should be between [10min,) ", p.String()))
}
return nil
}

func validateJailDuration(p time.Duration) sdk.Error {
if p <= 0 || p >= 4 * sdk.Week {
if p <= 0 || p >= 4*sdk.Week {
return sdk.NewError(params.DefaultCodespace, params.CodeInvalidSlashParams, fmt.Sprintf("Slash DoubleSignJailDuration and DowntimeJailDuration [%s] should be between (0, 4week) ", p.String()))
}
return nil
}

func validateCensorshipJailDuration(p time.Duration) sdk.Error {
if p <= 0 || p >= 4*sdk.Week {
return sdk.NewError(params.DefaultCodespace, params.CodeInvalidSlashParams, fmt.Sprintf("Slash CensorshipJailDuration should be between (0, 4week) ", p.String()))
}
return nil
}

func validateSignedBlocksWindow(p int64) sdk.Error {
if p < 100 || p > 140000 {
return sdk.NewError(params.DefaultCodespace, params.CodeInvalidSlashParams, fmt.Sprintf("Slash SignedBlocksWindow [%d] should be between [100, 140000] ", p))
Expand Down Expand Up @@ -260,6 +306,13 @@ func validateSlashFractionDowntime(p sdk.Dec) sdk.Error {
return nil
}

func validateSlashFractionCensorship(p sdk.Dec) sdk.Error {
if p.LT(sdk.NewDecWithPrec(5, 3)) || p.GT(sdk.NewDecWithPrec(1, 1)) {
return sdk.NewError(params.DefaultCodespace, params.CodeInvalidSlashParams, fmt.Sprintf("Slash SlashFractionCensorship [%s] should be between [0.005, 0.1] ", p.String()))
}
return nil
}

//______________________________________________________________________

// get inflation params from the global param store
Expand Down Expand Up @@ -317,3 +370,15 @@ func (k Keeper) SlashFractionDowntime(ctx sdk.Context) (res sdk.Dec) {
k.paramspace.Get(ctx, KeySlashFractionDowntime, &res)
return
}

// SlashFractionDowntime - currently default 1%
func (k Keeper) SlashFractionCensorship(ctx sdk.Context) (res sdk.Dec) {
k.paramspace.Get(ctx, keySlashFractionCensorship, &res)
return
}

// Downtime unbond duration
func (k Keeper) CensorshipUnbondDuration(ctx sdk.Context) (res time.Duration) {
k.paramspace.Get(ctx, keyCensorshipJailDuration, &res)
return
}
17 changes: 17 additions & 0 deletions modules/slashing/tick.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,3 +40,20 @@ func BeginBlocker(ctx sdk.Context, req abci.RequestBeginBlock, sk Keeper) (tags

return
}

// slashing end block functionality
func EndBlocker(ctx sdk.Context, req abci.RequestEndBlock, sk Keeper) (tags sdk.Tags) {

// Tag the height
heightBytes := make([]byte, 8)
binary.LittleEndian.PutUint64(heightBytes, uint64(req.Height))
tags = sdk.NewTags("height", heightBytes)

if int64(ctx.CheckValidNum()) < ctx.BlockHeader().NumTxs {
proposalCensorshipTag := sk.handleProposerCensorship(ctx,
ctx.BlockHeader().ProposerAddress,
ctx.BlockHeight())
tags = tags.AppendTags(proposalCensorshipTag)
}
return
}
Loading

0 comments on commit 11c5756

Please sign in to comment.