github.com/nnlgsakib/mind-dpos@v0.0.0-20230606105614-f3c8ca06f808/consensus/alien/custom_tx.go (about) 1 // Copyright 2018 The gttc Authors 2 // This file is part of the gttc library. 3 // 4 // The gttc library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The gttc library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the gttc library. If not, see <http://www.gnu.org/licenses/>. 16 17 // Package alien implements the delegated-proof-of-stake consensus engine. 18 19 package alien 20 21 import ( 22 "fmt" 23 "github.com/TTCECO/gttc/params" 24 "math/big" 25 "strconv" 26 "strings" 27 28 "github.com/TTCECO/gttc/common" 29 "github.com/TTCECO/gttc/consensus" 30 "github.com/TTCECO/gttc/core/state" 31 "github.com/TTCECO/gttc/core/types" 32 "github.com/TTCECO/gttc/log" 33 "github.com/TTCECO/gttc/rlp" 34 ) 35 36 const ( 37 /* 38 * ufo:version:category:action/data 39 */ 40 ufoPrefix = "ufo" 41 ufoVersion = "1" 42 ufoCategoryEvent = "event" 43 ufoCategoryLog = "oplog" 44 ufoCategorySC = "sc" 45 ufoEventVote = "vote" 46 ufoEventConfirm = "confirm" 47 ufoEventPorposal = "proposal" 48 ufoEventDeclare = "declare" 49 ufoEventSetCoinbase = "setcb" 50 ufoMinSplitLen = 3 51 posPrefix = 0 52 posVersion = 1 53 posCategory = 2 54 posEventVote = 3 55 posEventConfirm = 3 56 posEventProposal = 3 57 posEventDeclare = 3 58 posEventSetCoinbase = 3 59 posEventConfirmNumber = 4 60 61 /* 62 * proposal type 63 */ 64 proposalTypeCandidateAdd = 1 65 proposalTypeCandidateRemove = 2 66 proposalTypeMinerRewardDistributionModify = 3 // count in one thousand 67 proposalTypeSideChainAdd = 4 68 proposalTypeSideChainRemove = 5 69 proposalTypeMinVoterBalanceModify = 6 70 proposalTypeProposalDepositModify = 7 71 proposalTypeRentSideChain = 8 // use TTC to buy coin on side chain 72 73 /* 74 * proposal related 75 */ 76 maxValidationLoopCnt = 50000 // About one month if period = 3 & 21 super nodes 77 minValidationLoopCnt = 4 // just for test, Note: 12350 About three days if seal each block per second & 21 super nodes 78 defaultValidationLoopCnt = 10000 // About one week if period = 3 & 21 super nodes 79 maxProposalDeposit = 100000 // If no limit on max proposal deposit and 1 billion TTC deposit success passed, then no new proposal. 80 minSCRentFee = 100 // 100 TTC 81 minSCRentLength = 850000 // number of block about 1 month if period is 3 82 defaultSCRentLength = minSCRentLength * 3 // number of block about 3 month if period is 3 83 maxSCRentLength = defaultSCRentLength * 4 // number of block about 1 year if period is 3 84 85 /* 86 * notice related 87 */ 88 noticeTypeGasCharging = 1 89 ) 90 91 //side chain related 92 var minSCSetCoinbaseValue = big.NewInt(5e+18) 93 94 // RefundGas : 95 // refund gas to tx sender 96 type RefundGas map[common.Address]*big.Int 97 98 // RefundPair : 99 type RefundPair struct { 100 Sender common.Address 101 GasPrice *big.Int 102 } 103 104 // RefundHash : 105 type RefundHash map[common.Hash]RefundPair 106 107 // Vote : 108 // vote come from custom tx which data like "ufo:1:event:vote" 109 // Sender of tx is Voter, the tx.to is Candidate 110 // Stake is the balance of Voter when create this vote 111 type Vote struct { 112 Voter common.Address 113 Candidate common.Address 114 Stake *big.Int 115 } 116 117 // Confirmation : 118 // confirmation come from custom tx which data like "ufo:1:event:confirm:123" 119 // 123 is the block number be confirmed 120 // Sender of tx is Signer only if the signer in the SignerQueue for block number 123 121 type Confirmation struct { 122 Signer common.Address 123 BlockNumber *big.Int 124 } 125 126 // Proposal : 127 // proposal come from custom tx which data like "ufo:1:event:proposal:candidate:add:address" or "ufo:1:event:proposal:percentage:60" 128 // proposal only come from the current candidates 129 // not only candidate add/remove , current signer can proposal for params modify like percentage of reward distribution ... 130 type Proposal struct { 131 Hash common.Hash // tx hash 132 ReceivedNumber *big.Int // block number of proposal received 133 CurrentDeposit *big.Int // received deposit for this proposal 134 ValidationLoopCnt uint64 // validation block number length of this proposal from the received block number 135 ProposalType uint64 // type of proposal 1 - add candidate 2 - remove candidate ... 136 Proposer common.Address // proposer 137 TargetAddress common.Address // candidate need to add/remove if candidateNeedPD == true 138 MinerRewardPerThousand uint64 // reward of miner + side chain miner 139 SCHash common.Hash // side chain genesis parent hash need to add/remove 140 SCBlockCountPerPeriod uint64 // the number block sealed by this side chain per period, default 1 141 SCBlockRewardPerPeriod uint64 // the reward of this side chain per period if SCBlockCountPerPeriod reach, default 0. SCBlockRewardPerPeriod/1000 * MinerRewardPerThousand/1000 * BlockReward is the reward for this side chain 142 Declares []*Declare // Declare this proposal received (always empty in block header) 143 MinVoterBalance uint64 // value of minVoterBalance , need to mul big.Int(1e+18) 144 ProposalDeposit uint64 // The deposit need to be frozen during before the proposal get final conclusion. (TTC) 145 SCRentFee uint64 // number of TTC coin, not wei 146 SCRentRate uint64 // how many coin you want for 1 TTC on main chain 147 SCRentLength uint64 // minimize block number of main chain , the rent fee will be used as reward of side chain miner. 148 } 149 150 func (p *Proposal) copy() *Proposal { 151 cpy := &Proposal{ 152 Hash: p.Hash, 153 ReceivedNumber: new(big.Int).Set(p.ReceivedNumber), 154 CurrentDeposit: new(big.Int).Set(p.CurrentDeposit), 155 ValidationLoopCnt: p.ValidationLoopCnt, 156 ProposalType: p.ProposalType, 157 Proposer: p.Proposer, 158 TargetAddress: p.TargetAddress, 159 MinerRewardPerThousand: p.MinerRewardPerThousand, 160 SCHash: p.SCHash, 161 SCBlockCountPerPeriod: p.SCBlockCountPerPeriod, 162 SCBlockRewardPerPeriod: p.SCBlockRewardPerPeriod, 163 Declares: make([]*Declare, len(p.Declares)), 164 MinVoterBalance: p.MinVoterBalance, 165 ProposalDeposit: p.ProposalDeposit, 166 SCRentFee: p.SCRentFee, 167 SCRentRate: p.SCRentRate, 168 SCRentLength: p.SCRentLength, 169 } 170 171 copy(cpy.Declares, p.Declares) 172 return cpy 173 } 174 175 // Declare : 176 // declare come from custom tx which data like "ufo:1:event:declare:hash:yes" 177 // proposal only come from the current candidates 178 // hash is the hash of proposal tx 179 type Declare struct { 180 ProposalHash common.Hash 181 Declarer common.Address 182 Decision bool 183 } 184 185 // SCConfirmation is the confirmed tx send by side chain super node 186 type SCConfirmation struct { 187 Hash common.Hash 188 Coinbase common.Address // the side chain signer , may be diff from signer in main chain 189 Number uint64 190 LoopInfo []string 191 } 192 193 func (s *SCConfirmation) copy() *SCConfirmation { 194 cpy := &SCConfirmation{ 195 Hash: s.Hash, 196 Coinbase: s.Coinbase, 197 Number: s.Number, 198 LoopInfo: make([]string, len(s.LoopInfo)), 199 } 200 copy(cpy.LoopInfo, s.LoopInfo) 201 return cpy 202 } 203 204 // SCSetCoinbase is the tx send by main chain super node which can set coinbase for side chain 205 type SCSetCoinbase struct { 206 Hash common.Hash 207 Signer common.Address 208 Coinbase common.Address 209 } 210 211 type GasCharging struct { 212 Target common.Address // target address on side chain 213 Volume uint64 // volume of gas need charge (unit is ttc) 214 Hash common.Hash // the hash of proposal, use as id of this proposal 215 } 216 217 // HeaderExtra is the struct of info in header.Extra[extraVanity:len(header.extra)-extraSeal] 218 // HeaderExtra is the current struct 219 type HeaderExtra struct { 220 CurrentBlockConfirmations []Confirmation 221 CurrentBlockVotes []Vote 222 CurrentBlockProposals []Proposal 223 CurrentBlockDeclares []Declare 224 ModifyPredecessorVotes []Vote 225 LoopStartTime uint64 226 SignerQueue []common.Address 227 SignerMissing []common.Address 228 ConfirmedBlockNumber uint64 229 SideChainConfirmations []SCConfirmation 230 SideChainSetCoinbases []SCSetCoinbase 231 SideChainNoticeConfirmed []SCConfirmation 232 SideChainCharging []GasCharging //This only exist in side chain's header.Extra 233 } 234 235 // Encode HeaderExtra 236 func encodeHeaderExtra(config *params.AlienConfig, number *big.Int, val HeaderExtra) ([]byte, error) { 237 238 var headerExtra interface{} 239 switch { 240 //case config.IsTrantor(number): 241 242 default: 243 headerExtra = val 244 } 245 return rlp.EncodeToBytes(headerExtra) 246 247 } 248 249 // Decode HeaderExtra 250 func decodeHeaderExtra(config *params.AlienConfig, number *big.Int, b []byte, val *HeaderExtra) error { 251 var err error 252 switch { 253 //case config.IsTrantor(number): 254 default: 255 err = rlp.DecodeBytes(b, val) 256 } 257 return err 258 } 259 260 // Build side chain confirm data 261 func (a *Alien) buildSCEventConfirmData(scHash common.Hash, headerNumber *big.Int, headerTime *big.Int, lastLoopInfo string, chargingInfo string) []byte { 262 return []byte(fmt.Sprintf("%s:%s:%s:%s:%s:%d:%d:%s:%s", 263 ufoPrefix, ufoVersion, ufoCategorySC, ufoEventConfirm, 264 scHash.Hex(), headerNumber.Uint64(), headerTime.Uint64(), lastLoopInfo, chargingInfo)) 265 266 } 267 268 // Calculate Votes from transaction in this block, write into header.Extra 269 func (a *Alien) processCustomTx(headerExtra HeaderExtra, chain consensus.ChainReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, receipts []*types.Receipt) (HeaderExtra, RefundGas, error) { 270 // if predecessor voter make transaction and vote in this block, 271 // just process as vote, do it in snapshot.apply 272 var ( 273 snap *Snapshot 274 err error 275 number uint64 276 refundGas RefundGas 277 refundHash RefundHash 278 ) 279 refundGas = make(map[common.Address]*big.Int) 280 refundHash = make(map[common.Hash]RefundPair) 281 number = header.Number.Uint64() 282 if number > 1 { 283 snap, err = a.snapshot(chain, number-1, header.ParentHash, nil, nil, defaultLoopCntRecalculateSigners) 284 if err != nil { 285 return headerExtra, nil, err 286 } 287 } 288 289 for _, tx := range txs { 290 291 txSender, err := types.Sender(types.NewEIP155Signer(tx.ChainId()), tx) 292 if err != nil { 293 continue 294 } 295 296 if len(string(tx.Data())) >= len(ufoPrefix) { 297 txData := string(tx.Data()) 298 txDataInfo := strings.Split(txData, ":") 299 if len(txDataInfo) >= ufoMinSplitLen { 300 if txDataInfo[posPrefix] == ufoPrefix { 301 if txDataInfo[posVersion] == ufoVersion { 302 // process vote event 303 if txDataInfo[posCategory] == ufoCategoryEvent { 304 if len(txDataInfo) > ufoMinSplitLen { 305 // check is vote or not 306 if txDataInfo[posEventVote] == ufoEventVote && tx.To() != nil && (!candidateNeedPD || snap.isCandidate(*tx.To())) && state.GetBalance(txSender).Cmp(snap.MinVB) > 0 { 307 headerExtra.CurrentBlockVotes = a.processEventVote(headerExtra.CurrentBlockVotes, state, tx, txSender) 308 } else if txDataInfo[posEventConfirm] == ufoEventConfirm && snap.isCandidate(txSender) { 309 headerExtra.CurrentBlockConfirmations, refundHash = a.processEventConfirm(headerExtra.CurrentBlockConfirmations, chain, txDataInfo, number, tx, txSender, refundHash) 310 } else if txDataInfo[posEventProposal] == ufoEventPorposal { 311 headerExtra.CurrentBlockProposals = a.processEventProposal(headerExtra.CurrentBlockProposals, txDataInfo, state, tx, txSender, snap) 312 } else if txDataInfo[posEventDeclare] == ufoEventDeclare && snap.isCandidate(txSender) { 313 headerExtra.CurrentBlockDeclares = a.processEventDeclare(headerExtra.CurrentBlockDeclares, txDataInfo, tx, txSender) 314 } 315 } else { 316 // todo : something wrong, leave this transaction to process as normal transaction 317 } 318 } else if txDataInfo[posCategory] == ufoCategoryLog { 319 // todo : 320 } else if txDataInfo[posCategory] == ufoCategorySC { 321 if len(txDataInfo) > ufoMinSplitLen { 322 if txDataInfo[posEventConfirm] == ufoEventConfirm { 323 if len(txDataInfo) > ufoMinSplitLen+5 { 324 number := new(big.Int) 325 if err := number.UnmarshalText([]byte(txDataInfo[ufoMinSplitLen+2])); err != nil { 326 log.Trace("Side chain confirm info fail", "number", txDataInfo[ufoMinSplitLen+2]) 327 continue 328 } 329 if err := new(big.Int).UnmarshalText([]byte(txDataInfo[ufoMinSplitLen+3])); err != nil { 330 log.Trace("Side chain confirm info fail", "time", txDataInfo[ufoMinSplitLen+3]) 331 continue 332 } 333 loopInfo := txDataInfo[ufoMinSplitLen+4] 334 scHash := common.HexToHash(txDataInfo[ufoMinSplitLen+1]) 335 headerExtra.SideChainConfirmations, refundHash = a.processSCEventConfirm(headerExtra.SideChainConfirmations, 336 scHash, number.Uint64(), loopInfo, tx, txSender, refundHash) 337 338 chargingInfo := txDataInfo[ufoMinSplitLen+5] 339 headerExtra.SideChainNoticeConfirmed = a.processSCEventNoticeConfirm(headerExtra.SideChainNoticeConfirmed, 340 scHash, number.Uint64(), chargingInfo, txSender) 341 342 } 343 } else if txDataInfo[posEventSetCoinbase] == ufoEventSetCoinbase && snap.isCandidate(txSender) { 344 if len(txDataInfo) > ufoMinSplitLen+1 { 345 // the signer of main chain must send some value to coinbase of side chain for confirm tx of side chain 346 if tx.Value().Cmp(minSCSetCoinbaseValue) >= 0 && tx.To() != nil { 347 headerExtra.SideChainSetCoinbases = a.processSCEventSetCoinbase(headerExtra.SideChainSetCoinbases, 348 common.HexToHash(txDataInfo[ufoMinSplitLen+1]), txSender, *tx.To()) 349 } 350 } 351 } 352 } 353 } 354 } 355 } 356 } 357 } 358 // check each address 359 if number > 1 { 360 headerExtra.ModifyPredecessorVotes = a.processPredecessorVoter(headerExtra.ModifyPredecessorVotes, state, tx, txSender, snap) 361 } 362 363 } 364 365 for _, receipt := range receipts { 366 if pair, ok := refundHash[receipt.TxHash]; ok && receipt.Status == 1 { 367 pair.GasPrice.Mul(pair.GasPrice, big.NewInt(int64(receipt.GasUsed))) 368 refundGas = a.refundAddGas(refundGas, pair.Sender, pair.GasPrice) 369 } 370 } 371 return headerExtra, refundGas, nil 372 } 373 374 func (a *Alien) refundAddGas(refundGas RefundGas, address common.Address, value *big.Int) RefundGas { 375 if _, ok := refundGas[address]; ok { 376 refundGas[address].Add(refundGas[address], value) 377 } else { 378 refundGas[address] = value 379 } 380 381 return refundGas 382 } 383 384 func (a *Alien) processSCEventNoticeConfirm(scEventNoticeConfirm []SCConfirmation, hash common.Hash, number uint64, chargingInfo string, txSender common.Address) []SCConfirmation { 385 if chargingInfo != "" { 386 scEventNoticeConfirm = append(scEventNoticeConfirm, SCConfirmation{ 387 Hash: hash, 388 Coinbase: txSender, 389 Number: number, 390 LoopInfo: strings.Split(chargingInfo, "#"), 391 }) 392 } 393 return scEventNoticeConfirm 394 } 395 396 func (a *Alien) processSCEventConfirm(scEventConfirmaions []SCConfirmation, hash common.Hash, number uint64, loopInfo string, tx *types.Transaction, txSender common.Address, refundHash RefundHash) ([]SCConfirmation, RefundHash) { 397 scEventConfirmaions = append(scEventConfirmaions, SCConfirmation{ 398 Hash: hash, 399 Coinbase: txSender, 400 Number: number, 401 LoopInfo: strings.Split(loopInfo, "#"), 402 }) 403 refundHash[tx.Hash()] = RefundPair{txSender, tx.GasPrice()} 404 return scEventConfirmaions, refundHash 405 } 406 407 func (a *Alien) processSCEventSetCoinbase(scEventSetCoinbases []SCSetCoinbase, hash common.Hash, signer common.Address, coinbase common.Address) []SCSetCoinbase { 408 scEventSetCoinbases = append(scEventSetCoinbases, SCSetCoinbase{ 409 Hash: hash, 410 Signer: signer, 411 Coinbase: coinbase, 412 }) 413 return scEventSetCoinbases 414 } 415 416 func (a *Alien) processEventProposal(currentBlockProposals []Proposal, txDataInfo []string, state *state.StateDB, tx *types.Transaction, proposer common.Address, snap *Snapshot) []Proposal { 417 // sample for add side chain proposal 418 // eth.sendTransaction({from:eth.accounts[0],to:eth.accounts[0],value:0,data:web3.toHex("ufo:1:event:proposal:proposal_type:4:sccount:2:screward:50:schash:0x3210000000000000000000000000000000000000000000000000000000000000:vlcnt:4")}) 419 // sample for declare 420 // eth.sendTransaction({from:eth.accounts[0],to:eth.accounts[0],value:0,data:web3.toHex("ufo:1:event:declare:hash:0x853e10706e6b9d39c5f4719018aa2417e8b852dec8ad18f9c592d526db64c725:decision:yes")}) 421 if len(txDataInfo) <= posEventProposal+2 { 422 return currentBlockProposals 423 } 424 425 proposal := Proposal{ 426 Hash: tx.Hash(), 427 ReceivedNumber: big.NewInt(0), 428 CurrentDeposit: proposalDeposit, // for all type of deposit 429 ValidationLoopCnt: defaultValidationLoopCnt, 430 ProposalType: proposalTypeCandidateAdd, 431 Proposer: proposer, 432 TargetAddress: common.Address{}, 433 SCHash: common.Hash{}, 434 SCBlockCountPerPeriod: 1, 435 SCBlockRewardPerPeriod: 0, 436 MinerRewardPerThousand: minerRewardPerThousand, 437 Declares: []*Declare{}, 438 MinVoterBalance: new(big.Int).Div(minVoterBalance, big.NewInt(1e+18)).Uint64(), 439 ProposalDeposit: new(big.Int).Div(proposalDeposit, big.NewInt(1e+18)).Uint64(), // default value 440 SCRentFee: 0, 441 SCRentRate: 1, 442 SCRentLength: defaultSCRentLength, 443 } 444 445 for i := 0; i < len(txDataInfo[posEventProposal+1:])/2; i++ { 446 k, v := txDataInfo[posEventProposal+1+i*2], txDataInfo[posEventProposal+2+i*2] 447 switch k { 448 case "vlcnt": 449 // If vlcnt is missing then user default value, but if the vlcnt is beyond the min/max value then ignore this proposal 450 if validationLoopCnt, err := strconv.Atoi(v); err != nil || validationLoopCnt < minValidationLoopCnt || validationLoopCnt > maxValidationLoopCnt { 451 return currentBlockProposals 452 } else { 453 proposal.ValidationLoopCnt = uint64(validationLoopCnt) 454 } 455 case "schash": 456 proposal.SCHash.UnmarshalText([]byte(v)) 457 case "sccount": 458 if scBlockCountPerPeriod, err := strconv.Atoi(v); err != nil { 459 return currentBlockProposals 460 } else { 461 proposal.SCBlockCountPerPeriod = uint64(scBlockCountPerPeriod) 462 } 463 case "screward": 464 if scBlockRewardPerPeriod, err := strconv.Atoi(v); err != nil { 465 return currentBlockProposals 466 } else { 467 proposal.SCBlockRewardPerPeriod = uint64(scBlockRewardPerPeriod) 468 } 469 case "proposal_type": 470 if proposalType, err := strconv.Atoi(v); err != nil { 471 return currentBlockProposals 472 } else { 473 proposal.ProposalType = uint64(proposalType) 474 } 475 case "candidate": 476 // not check here 477 proposal.TargetAddress.UnmarshalText([]byte(v)) 478 case "mrpt": 479 // miner reward per thousand 480 if mrpt, err := strconv.Atoi(v); err != nil || mrpt <= 0 || mrpt > 1000 { 481 return currentBlockProposals 482 } else { 483 proposal.MinerRewardPerThousand = uint64(mrpt) 484 } 485 case "mvb": 486 // minVoterBalance 487 if mvb, err := strconv.Atoi(v); err != nil || mvb <= 0 { 488 return currentBlockProposals 489 } else { 490 proposal.MinVoterBalance = uint64(mvb) 491 } 492 case "mpd": 493 // proposalDeposit 494 if mpd, err := strconv.Atoi(v); err != nil || mpd <= 0 || mpd > maxProposalDeposit { 495 return currentBlockProposals 496 } else { 497 proposal.ProposalDeposit = uint64(mpd) 498 } 499 case "scrt": 500 // target address on side chain to charge gas 501 proposal.TargetAddress.UnmarshalText([]byte(v)) 502 case "scrf": 503 // side chain rent fee 504 if scrf, err := strconv.Atoi(v); err != nil || scrf < minSCRentFee { 505 return currentBlockProposals 506 } else { 507 proposal.SCRentFee = uint64(scrf) 508 } 509 case "scrr": 510 // side chain rent rate 511 if scrr, err := strconv.Atoi(v); err != nil || scrr <= 0 { 512 return currentBlockProposals 513 } else { 514 proposal.SCRentRate = uint64(scrr) 515 } 516 case "scrl": 517 // side chain rent length 518 if scrl, err := strconv.Atoi(v); err != nil || scrl < minSCRentLength || scrl > maxSCRentLength { 519 return currentBlockProposals 520 } else { 521 proposal.SCRentLength = uint64(scrl) 522 } 523 } 524 } 525 // now the proposal is built 526 currentProposalPay := new(big.Int).Set(proposalDeposit) 527 if proposal.ProposalType == proposalTypeRentSideChain { 528 // check if the proposal target side chain exist 529 if !snap.isSideChainExist(proposal.SCHash) { 530 return currentBlockProposals 531 } 532 if (proposal.TargetAddress == common.Address{}) { 533 return currentBlockProposals 534 } 535 currentProposalPay.Add(currentProposalPay, new(big.Int).Mul(new(big.Int).SetUint64(proposal.SCRentFee), big.NewInt(1e+18))) 536 } 537 // check enough balance for deposit 538 if state.GetBalance(proposer).Cmp(currentProposalPay) < 0 { 539 return currentBlockProposals 540 } 541 // collection the fee for this proposal (deposit and other fee , sc rent fee ...) 542 state.SetBalance(proposer, new(big.Int).Sub(state.GetBalance(proposer), currentProposalPay)) 543 544 return append(currentBlockProposals, proposal) 545 } 546 547 func (a *Alien) processEventDeclare(currentBlockDeclares []Declare, txDataInfo []string, tx *types.Transaction, declarer common.Address) []Declare { 548 if len(txDataInfo) <= posEventDeclare+2 { 549 return currentBlockDeclares 550 } 551 declare := Declare{ 552 ProposalHash: common.Hash{}, 553 Declarer: declarer, 554 Decision: true, 555 } 556 for i := 0; i < len(txDataInfo[posEventDeclare+1:])/2; i++ { 557 k, v := txDataInfo[posEventDeclare+1+i*2], txDataInfo[posEventDeclare+2+i*2] 558 switch k { 559 case "hash": 560 declare.ProposalHash.UnmarshalText([]byte(v)) 561 case "decision": 562 if v == "yes" { 563 declare.Decision = true 564 } else if v == "no" { 565 declare.Decision = false 566 } else { 567 return currentBlockDeclares 568 } 569 } 570 } 571 572 return append(currentBlockDeclares, declare) 573 } 574 575 func (a *Alien) processEventVote(currentBlockVotes []Vote, state *state.StateDB, tx *types.Transaction, voter common.Address) []Vote { 576 577 a.lock.RLock() 578 stake := state.GetBalance(voter) 579 a.lock.RUnlock() 580 581 currentBlockVotes = append(currentBlockVotes, Vote{ 582 Voter: voter, 583 Candidate: *tx.To(), 584 Stake: stake, 585 }) 586 587 return currentBlockVotes 588 } 589 590 func (a *Alien) processEventConfirm(currentBlockConfirmations []Confirmation, chain consensus.ChainReader, txDataInfo []string, number uint64, tx *types.Transaction, confirmer common.Address, refundHash RefundHash) ([]Confirmation, RefundHash) { 591 if len(txDataInfo) > posEventConfirmNumber { 592 confirmedBlockNumber := new(big.Int) 593 err := confirmedBlockNumber.UnmarshalText([]byte(txDataInfo[posEventConfirmNumber])) 594 if err != nil || number-confirmedBlockNumber.Uint64() > a.config.MaxSignerCount || number-confirmedBlockNumber.Uint64() < 0 { 595 return currentBlockConfirmations, refundHash 596 } 597 // check if the voter is in block 598 confirmedHeader := chain.GetHeaderByNumber(confirmedBlockNumber.Uint64()) 599 if confirmedHeader == nil { 600 //log.Info("Fail to get confirmedHeader") 601 return currentBlockConfirmations, refundHash 602 } 603 confirmedHeaderExtra := HeaderExtra{} 604 if extraVanity+extraSeal > len(confirmedHeader.Extra) { 605 return currentBlockConfirmations, refundHash 606 } 607 err = decodeHeaderExtra(a.config, confirmedBlockNumber, confirmedHeader.Extra[extraVanity:len(confirmedHeader.Extra)-extraSeal], &confirmedHeaderExtra) 608 if err != nil { 609 log.Info("Fail to decode parent header", "err", err) 610 return currentBlockConfirmations, refundHash 611 } 612 for _, s := range confirmedHeaderExtra.SignerQueue { 613 if s == confirmer { 614 currentBlockConfirmations = append(currentBlockConfirmations, Confirmation{ 615 Signer: confirmer, 616 BlockNumber: new(big.Int).Set(confirmedBlockNumber), 617 }) 618 refundHash[tx.Hash()] = RefundPair{confirmer, tx.GasPrice()} 619 break 620 } 621 } 622 } 623 624 return currentBlockConfirmations, refundHash 625 } 626 627 func (a *Alien) processPredecessorVoter(modifyPredecessorVotes []Vote, state *state.StateDB, tx *types.Transaction, voter common.Address, snap *Snapshot) []Vote { 628 // process normal transaction which relate to voter 629 if tx.Value().Cmp(big.NewInt(0)) > 0 && tx.To() != nil { 630 if snap.isVoter(voter) { 631 a.lock.RLock() 632 stake := state.GetBalance(voter) 633 a.lock.RUnlock() 634 modifyPredecessorVotes = append(modifyPredecessorVotes, Vote{ 635 Voter: voter, 636 Candidate: common.Address{}, 637 Stake: stake, 638 }) 639 } 640 if snap.isVoter(*tx.To()) { 641 a.lock.RLock() 642 stake := state.GetBalance(*tx.To()) 643 a.lock.RUnlock() 644 modifyPredecessorVotes = append(modifyPredecessorVotes, Vote{ 645 Voter: *tx.To(), 646 Candidate: common.Address{}, 647 Stake: stake, 648 }) 649 } 650 651 } 652 return modifyPredecessorVotes 653 }