git.pirl.io/community/pirl@v0.0.0-20201111064343-9d3d31ff74be/core/pirlguard.go (about)

     1  package core
     2  
     3  import (
     4  	"errors"
     5  	"git.pirl.io/community/pirl/core/types"
     6  	"git.pirl.io/community/pirl/log"
     7  	"git.pirl.io/community/pirl/params"
     8  	"sort"
     9  )
    10  
    11  var syncStatus bool
    12  //var maxReorgValue = 5
    13  //var maxChangedHashes = 3
    14  
    15  func (bc *BlockChain) checkChainForAttack(blocks types.Blocks) error {
    16  	// Copyright 2014 The go-ethereum Authors
    17  	// Copyright 2018 Pirl Blockchain LTD
    18  	// This file is part of the go-ethereum library modified with Pirl Security Protocol.
    19  	//
    20  	// The go-ethereum library is free software: you can redistribute it and/or modify
    21  	// it under the terms of the GNU Lesser General Public License as published by
    22  	// the Free Software Foundation, either version 3 of the License, or
    23  	// (at your option) any later version.
    24  	//
    25  	// The go-ethereum library is distributed in the hope that it will be useful,
    26  	// but WITHOUT ANY WARRANTY; without even the implied warranty of
    27  	// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    28  	// GNU Lesser General Public License for more details.
    29  	//
    30  	// You should have received a copy of the GNU Lesser General Public License
    31  	// along with the go-ethereum library. If not, see http://www.gnu.org/licenses/.
    32  	// Package core implements the Ethereum consensus protocol modified with Pirl Security Protocol.
    33  
    34  	err := errors.New("")
    35  	err = nil
    36  	timeMap := make(map[uint64]int64)
    37  	tipOfTheMainChain := bc.CurrentBlock().NumberU64()
    38  
    39  
    40  
    41  	if !syncStatus {
    42  		if tipOfTheMainChain == blocks[0].NumberU64() - 1 {
    43  			//fmt.Println("We are synced")
    44  			syncStatus = true
    45  		} else {
    46  			//fmt.Println("Still syncing!")
    47  			syncStatus = false
    48  		}
    49  	}
    50  	//counter := 0
    51  
    52  	if len(blocks) > 0 && bc.CurrentBlock().NumberU64() > uint64(params.PirlGuardActivationBlock) {
    53  		//if syncStatus && len(blocks) < int(params.PirlGuardBlockLength) && len(blocks) > maxReorgValue {
    54  		//	//fmt.Println("We are in the condition here to check smaller block sizes...")
    55  		//	for _, b := range blocks {
    56  		//		//fmt.Println("This is the tx hash from incoming block : ",b.NumberU64()," with hash : " , b.Header().Hash().String())
    57  		//		block := bc.GetBlockByNumber(b.NumberU64())
    58  		//		if block != nil {
    59  		//			//fmt.Println("This is the tx hash from db block : ",block.NumberU64()," with hash : " , block.Header().Hash().String())
    60  		//			if b.Header().Hash().String() != block.Header().Hash().String() {
    61  		//				counter++
    62  		//				//fmt.Println("block tx hashes dont match for block : ", block.NumberU64())
    63  		//			}
    64  		//		} else {
    65  		//			fmt.Println("block not found in db : ", b.NumberU64())
    66  		//		}
    67  		//		fmt.Println("Matching blocks with changed hashes : ", counter)
    68  		//	}
    69  		//	if counter > maxChangedHashes {
    70  		//		fmt.Println("big reorg detected")
    71  		//		return ErrBigReorg
    72  		//	}
    73  		//}
    74  		if syncStatus && len(blocks) >= int(params.PirlGuardBlockLength) {
    75  			for _, b := range blocks {
    76  				timeMap[b.NumberU64()] = calculatePenaltyTimeForBlock(tipOfTheMainChain, b.NumberU64())
    77  			}
    78  		}
    79  	}
    80  
    81  	p := make(PairList, len(timeMap))
    82  	index := 0
    83  	for k, v := range timeMap {
    84  		p[index] = Pair {k, v}
    85  		index++
    86  	}
    87  	sort.Sort(p)
    88  	var penalty int64
    89  	for _, v := range p {
    90  		penalty += v.Value
    91  	}
    92  
    93  	multi := calculateMulti(bc.CurrentBlock().Difficulty().Uint64())
    94  	penalty = penalty * int64(multi)
    95  
    96  	if penalty < 0 {
    97  		penalty = 0
    98  	}
    99  	//fmt.Println("Penalty value for the chain :", penalty)
   100  	context := []interface{}{
   101  		"synced", syncStatus, "number", tipOfTheMainChain, "incoming_number", blocks[0].NumberU64() - 1, "penalty", penalty ,"implementation", "The Pirl Team",
   102  	}
   103  
   104  	log.Info("checking legitimity of the chain", context... )
   105  
   106  	if penalty > 0 {
   107  		context := []interface{}{
   108  			"penalty", penalty,
   109  		}
   110  		log.Error("Chain is a malicious and we should reject it", context... )
   111  		err = ErrDelayTooHigh
   112  
   113  	}
   114  
   115  	if penalty == 0 {
   116  		err = nil
   117  	}
   118  
   119  	return err
   120  }
   121  
   122  func calculatePenaltyTimeForBlock(tipOfTheMainChain , incomingBlock uint64) int64 {
   123  	if incomingBlock < tipOfTheMainChain {
   124  		return int64(tipOfTheMainChain - incomingBlock)
   125  	}
   126  	if incomingBlock == tipOfTheMainChain {
   127  		return 0
   128  	}
   129  	if incomingBlock > tipOfTheMainChain {
   130  		return -1
   131  	}
   132  	return 0
   133  }
   134  
   135  func calculateMulti(diff uint64) uint64 {
   136  
   137  	if diff <= 500000000 {
   138  		return 5
   139  	}
   140  	if diff >= 500000000 && diff < 20000000000 {
   141  		return 4
   142  	}
   143  	if diff >= 20000000000 && diff < 30000000000 {
   144  		return 3
   145  	}
   146  	if diff >= 30000000000 && diff < 50000000000 {
   147  		return 2
   148  	}
   149  	if diff >= 50000000000 {
   150  		return 1
   151  	}
   152  	return 1
   153  }
   154  
   155  // A data structure to hold key/value pairs
   156  type Pair struct {
   157  	Key   uint64
   158  	Value int64
   159  }
   160  
   161  // A slice of pairs that implements sort.Interface to sort by values
   162  type PairList []Pair
   163  
   164  func (p PairList) Len() int           { return len(p) }
   165  func (p PairList) Swap(i, j int)      { p[i], p[j] = p[j], p[i] }
   166  func (p PairList) Less(i, j int) bool { return p[i].Key < p[j].Key }