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  }