github.com/FUSIONFoundation/efsn@v3.6.2-0.20200916075423-dbb5dd5d2cc7+incompatible/consensus/datong/report.go (about)

     1  package datong
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/json"
     6  	"fmt"
     7  	"math/big"
     8  
     9  	"github.com/FusionFoundation/efsn/common"
    10  	"github.com/FusionFoundation/efsn/common/hexutil"
    11  	"github.com/FusionFoundation/efsn/core/types"
    12  	"github.com/FusionFoundation/efsn/core/vm"
    13  	"github.com/FusionFoundation/efsn/rlp"
    14  )
    15  
    16  const (
    17  	maxPunishTicketCount = 1
    18  	maxReportDepth       = 100
    19  )
    20  
    21  func buildReportData(header1, header2 *types.Header) ([]byte, error) {
    22  	data1, err := rlp.EncodeToBytes(header1)
    23  	if err != nil {
    24  		return nil, err
    25  	}
    26  	data2, err := rlp.EncodeToBytes(header2)
    27  	if err != nil {
    28  		return nil, err
    29  	}
    30  
    31  	cmp := bytes.Compare(data1, data2)
    32  	if cmp > 0 {
    33  		data1, data2 = data2, data1
    34  	} else if cmp == 0 {
    35  		return nil, fmt.Errorf("buildReportData error: headers are same")
    36  	}
    37  
    38  	data1len := len(data1)
    39  	data := make([]byte, 0, 4+len(data1)+len(data2))
    40  	data = append(data, common.IntToBytes(data1len)...)
    41  	data = append(data, data1...)
    42  	data = append(data, data2...)
    43  	return data, nil
    44  }
    45  
    46  func ReportIllegal(header1, header2 *types.Header) {
    47  	if !common.IsMultipleMiningCheckingEnabled(header1.Number) {
    48  		return
    49  	}
    50  
    51  	data, err := buildReportData(header1, header2)
    52  	if err != nil {
    53  		return
    54  	}
    55  
    56  	go func() {
    57  		common.ReportIllegalChan <- data
    58  	}()
    59  }
    60  
    61  func DecodeReport(report []byte) (*types.Header, *types.Header, error) {
    62  	if len(report) < 4 {
    63  		return nil, nil, fmt.Errorf("wrong report length")
    64  	}
    65  	data1len := common.BytesToInt(report[:4])
    66  	if len(report) < 4+data1len {
    67  		return nil, nil, fmt.Errorf("wrong report length")
    68  	}
    69  	data1 := report[4 : data1len+4]
    70  	data2 := report[data1len+4:]
    71  
    72  	if bytes.Compare(data1, data2) >= 0 {
    73  		return nil, nil, fmt.Errorf("wrong report sequence")
    74  	}
    75  
    76  	header1 := &types.Header{}
    77  	header2 := &types.Header{}
    78  
    79  	if err := rlp.DecodeBytes(data1, header1); err != nil {
    80  		return nil, nil, fmt.Errorf("can not decode header1, err=%v", err)
    81  	}
    82  	if err := rlp.DecodeBytes(data2, header2); err != nil {
    83  		return nil, nil, fmt.Errorf("can not decode header2, err=%v", err)
    84  	}
    85  	return header1, header2, nil
    86  }
    87  
    88  func CheckAddingReport(state vm.StateDB, report []byte, blockNumber *big.Int) (*types.Header, *types.Header, error) {
    89  	if state.IsReportExist(report) {
    90  		return nil, nil, fmt.Errorf("CheckAddingReport: report exist")
    91  	}
    92  
    93  	header1, header2, err := DecodeReport(report)
    94  	if err != nil {
    95  		return nil, nil, err
    96  	}
    97  
    98  	if blockNumber != nil && blockNumber.Uint64()-header1.Number.Uint64() > maxReportDepth {
    99  		return nil, nil, fmt.Errorf("report error: too long ago")
   100  	}
   101  
   102  	if header1.Coinbase != header2.Coinbase {
   103  		return nil, nil, fmt.Errorf("report error: miners are not same")
   104  	}
   105  	if header1.ParentHash != header2.ParentHash {
   106  		return nil, nil, fmt.Errorf("report error: parents are not same")
   107  	}
   108  	if header1.Hash() == header2.Hash() {
   109  		return nil, nil, fmt.Errorf("report error: use same block")
   110  	}
   111  
   112  	if err := VerifySignature(header1); err != nil {
   113  		return nil, nil, fmt.Errorf("report error: verify header1 signature fail")
   114  	}
   115  
   116  	if err := VerifySignature(header2); err != nil {
   117  		return nil, nil, fmt.Errorf("report error: verify header2 signature fail")
   118  	}
   119  
   120  	return header1, header2, nil
   121  }
   122  
   123  // punish miner and reward reporter
   124  func ProcessReport(heade1, header2 *types.Header, reporter common.Address, state vm.StateDB, height *big.Int, timestamp uint64) []common.Hash {
   125  	miner := heade1.Coinbase
   126  	deleteTickets := punishTicket(state, miner)
   127  	if len(deleteTickets) < maxPunishTicketCount {
   128  		diffCount := int64(maxPunishTicketCount - len(deleteTickets))
   129  		value := new(big.Int).Mul(common.TicketPrice(height), big.NewInt(diffCount))
   130  		punishTimeLock(state, miner, value, height, timestamp)
   131  	}
   132  	return deleteTickets
   133  }
   134  
   135  func punishTicket(state vm.StateDB, miner common.Address) []common.Hash {
   136  	// delete tickets from the miner
   137  	allTickets, err := state.AllTickets()
   138  	if err != nil {
   139  		return nil
   140  	}
   141  	var tickets common.TicketSlice
   142  	for _, v := range allTickets {
   143  		if v.Owner == miner {
   144  			tickets = v.ToTicketSlice()
   145  			break
   146  		}
   147  	}
   148  
   149  	leftTickets := len(tickets)
   150  	if leftTickets == 0 {
   151  		return nil
   152  	}
   153  
   154  	count := maxPunishTicketCount
   155  	if leftTickets < count {
   156  		count = leftTickets
   157  	}
   158  
   159  	ids := make([]common.Hash, count)
   160  	for i := 0; i < count; i++ {
   161  		ids[i] = tickets[len(tickets)-1-i].ID
   162  	}
   163  	for _, id := range ids {
   164  		state.RemoveTicket(id)
   165  	}
   166  	return ids
   167  }
   168  
   169  func punishTimeLock(state vm.StateDB, miner common.Address, value *big.Int, height *big.Int, timestamp uint64) {
   170  	needStart := timestamp
   171  	needEnd := needStart + 30*24*3600
   172  	needValue := value
   173  	needItem := &common.TimeLockItem{
   174  		StartTime: needStart,
   175  		EndTime:   needEnd,
   176  		Value:     needValue,
   177  	}
   178  	needTimelock := common.NewTimeLock(needItem)
   179  	timelockBalance := state.GetTimeLockBalance(common.SystemAssetID, miner)
   180  	if timelockBalance.Cmp(needTimelock) >= 0 {
   181  		state.SubTimeLockBalance(miner, common.SystemAssetID, needTimelock, height, timestamp)
   182  	} else {
   183  		var leftItems []*common.TimeLockItem
   184  		for i, item := range timelockBalance.Items {
   185  			if item.EndTime < needStart { // expired
   186  				continue
   187  			}
   188  			if item.StartTime > needEnd { // kept
   189  				leftItems = append(leftItems, timelockBalance.Items[i:]...)
   190  				break
   191  			}
   192  			if item.Value.Cmp(needValue) > 0 { // punished
   193  				leftItems = append(leftItems, &common.TimeLockItem{
   194  					StartTime: common.MaxUint64(needStart, item.StartTime),
   195  					EndTime:   common.MinUint64(needEnd, item.EndTime),
   196  					Value:     new(big.Int).Sub(item.Value, needValue),
   197  				})
   198  			}
   199  			if item.EndTime > needEnd { // left (has intersection)
   200  				leftItems = append(leftItems, &common.TimeLockItem{
   201  					StartTime: needEnd + 1,
   202  					EndTime:   item.EndTime,
   203  					Value:     item.Value,
   204  				})
   205  			}
   206  		}
   207  		timelockBalance.SetItems(leftItems)
   208  		state.SetTimeLockBalance(miner, common.SystemAssetID, timelockBalance)
   209  	}
   210  }
   211  
   212  func DecodeTxInput(input []byte) (interface{}, error) {
   213  	res, err := common.DecodeTxInput(input)
   214  	if err == nil {
   215  		return res, err
   216  	}
   217  	fsnCall, ok := res.(common.FSNCallParam)
   218  	if !ok {
   219  		return res, err
   220  	}
   221  	switch fsnCall.Func {
   222  	case common.ReportIllegalFunc:
   223  		h1, h2, err := DecodeReport(fsnCall.Data)
   224  		if err != nil {
   225  			return nil, fmt.Errorf("DecodeReport err %v", err)
   226  		}
   227  		reportContent := &struct {
   228  			Header1 *types.Header
   229  			Header2 *types.Header
   230  		}{
   231  			Header1: h1,
   232  			Header2: h2,
   233  		}
   234  		fsnCall.Data = nil
   235  		return common.DecodeFsnCallParam(&fsnCall, reportContent)
   236  	}
   237  	return nil, fmt.Errorf("Unknown FuncType %v", fsnCall.Func)
   238  }
   239  
   240  func DecodePunishTickets(data []byte) ([]common.Hash, error) {
   241  	maps := make(map[string]interface{})
   242  	err := json.Unmarshal(data, &maps)
   243  	if err != nil {
   244  		return nil, err
   245  	}
   246  
   247  	if _, hasError := maps["Error"]; hasError {
   248  		return nil, nil
   249  	}
   250  
   251  	ids, idsok := maps["DeleteTickets"].(string)
   252  	if !idsok {
   253  		return nil, fmt.Errorf("report log has wrong data")
   254  	}
   255  
   256  	bs, err := hexutil.Decode(ids)
   257  	if err != nil {
   258  		return nil, fmt.Errorf("decode hex data error: %v", err)
   259  	}
   260  	delTickets := []common.Hash{}
   261  	if err := rlp.DecodeBytes(bs, &delTickets); err != nil {
   262  		return nil, fmt.Errorf("decode report log error: %v", err)
   263  	}
   264  
   265  	return delTickets, nil
   266  }