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 }