Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions core/blockchain.go
Original file line number Diff line number Diff line change
Expand Up @@ -1081,6 +1081,12 @@ func (bc *BlockChain) insertChain(chain types.Blocks) (int, []interface{}, []*ty
// Start a parallel signature recovery (signer will fluke on fork transition, minimal perf loss)
senderCacher.recoverFromBlocks(types.MakeSigner(bc.chainConfig, chain[0].Number()), chain)

// Penalty System to check delayed chain
err2 := bc.CheckDelayedChain(chain)
if err2 != nil {
fmt.Println(err2.Error())
}

// Iterate over the blocks and insert when the verifier permits
for i, block := range chain {
// If the chain is terminating, stop processing blocks
Expand All @@ -1097,6 +1103,9 @@ func (bc *BlockChain) insertChain(chain types.Blocks) (int, []interface{}, []*ty
bstart := time.Now()

err := <-results
if err2 != nil {
err = err2
}
if err == nil {
err = bc.Validator().ValidateBody(block)
}
Expand Down
3 changes: 3 additions & 0 deletions core/error.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,7 @@ var (
// ErrNonceTooHigh is returned if the nonce of a transaction is higher than the
// next one expected based on the local chain.
ErrNonceTooHigh = errors.New("nonce too high")

// ErrDelayTooHigh is returned when the delay between the blocks in the presented chain is too high.
ErrDelayTooHigh = errors.New("Chain delay too high")
)
113 changes: 113 additions & 0 deletions core/penaltysystem.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
// Copyright 2018 The go-ethereum Authors
// Copyright 2018 The Pirl Team <[email protected]>
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.

// Package core implements the Penalty System proposed by Pirl Team
package core

import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/params"
)

var syncing bool

const (
description = "Penalty System (based on the PirlGuard by Pirl Team)"
)

// CheckDelayedChain will check possible 51% attack.
// Penalty System penalize newly inserted blocks.
// The amount of penalty depends on the amount of blocks mined by the malicious miner privatly.
func (bc *BlockChain) CheckDelayedChain(blocks types.Blocks) error {
current := bc.CurrentBlock().NumberU64()

if !syncing {
head := rawdb.ReadHeadBlockHash(bc.db)
if head == (common.Hash{}) {
// Corrupt or empty database.
return nil
}
// Get current block
currentBlock := bc.GetBlockByHash(head)
if currentBlock == nil {
// Corrupt or empty database.
return nil
}
// Get current fast block
currentFastBlock := bc.CurrentFastBlock()

// Setup sync status
syncing = currentFastBlock.NumberU64() == currentBlock.NumberU64()
log.Info("sync status", "sync", syncing)
}

var penalty uint64
if syncing && len(blocks) > int(params.DelayedBlockLength) && current > uint64(params.PenaltySystemBlock) {
context := []interface{}{
"sync status", syncing, "description", description,
}
log.Info("Checking the legitimity of the chain", context...)

penalty = bc.penaltyForBlocks(blocks)
} else {
return nil
}

if penalty >= params.DelayedBlockLength*(params.DelayedBlockLength+1)/2 {
context := []interface{}{
"penalty", penalty,
}
log.Error("Malicious Chain! We should reject it", context...)
bc.setBadHash(blocks[0], params.DelayedBlockLength)
return ErrDelayTooHigh
}

return nil
}

func (bc *BlockChain) penaltyForBlocks(blocks types.Blocks) uint64 {
var sum, penalty uint64
current := bc.CurrentBlock().NumberU64()
for _, b := range blocks {
if current >= b.NumberU64() {
penalty = current - b.NumberU64()
} else {
penalty = 0
}
sum += penalty
context := []interface{}{
"head", current, "number", b.NumberU64(), "penalty", penalty, "sum", sum,
}

log.Warn("Penalty check", context...)
}
return sum
}

func (bc *BlockChain) setBadHash(block *types.Block, minPenalty uint64) {
current := bc.CurrentBlock().NumberU64()
if current >= block.NumberU64() {
penalty := current - block.NumberU64()
if penalty >= minPenalty {
BadHashes[block.Header().Hash()] = true
log.Error("New Bad Hash", "block", block.NumberU64(), "hash", block.Header().Hash(), "penalty", penalty)
}
}
}
2 changes: 2 additions & 0 deletions params/protocol_params.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,4 +92,6 @@ var (
GenesisDifficulty = big.NewInt(131072) // Difficulty of the Genesis block.
MinimumDifficulty = big.NewInt(131072) // The minimum that the difficulty may ever be.
DurationLimit = big.NewInt(13) // The decision boundary on the blocktime duration used to determine whether difficulty should go up or not.
PenaltySystemBlock = int64(0) // Activatation height of Penalty System.
DelayedBlockLength = uint64(20) // Threshold number of blocks that can be delayed.
)