github.com/sixexorg/magnetic-ring@v0.0.0-20191119090307-31705a21e419/store/orgchain/validation/state_validate.go (about)

     1  package validation
     2  
     3  import (
     4  	"math/big"
     5  	"sync"
     6  
     7  	"fmt"
     8  
     9  	"github.com/sixexorg/magnetic-ring/common"
    10  	"github.com/sixexorg/magnetic-ring/core/orgchain/types"
    11  	"github.com/sixexorg/magnetic-ring/errors"
    12  	"github.com/sixexorg/magnetic-ring/store/storelaw"
    13  )
    14  
    15  var (
    16  	ratU = big.NewRat(1e8, 1)
    17  	bigU = big.NewInt(1e8)
    18  )
    19  
    20  // todo how to do with the nonce
    21  type StateValidate struct {
    22  	TargetHeight       uint64
    23  	currentBlockHeight uint64
    24  	currentBlockHash   common.Hash
    25  	MemoAccountState   map[common.Address]storelaw.AccountStater
    26  	//for one tx ,Take the lower limit,only the subtraction
    27  	DirtyAccountState map[common.Address]storelaw.AccountStater
    28  
    29  	//vote instant state
    30  	MemoVoteState map[common.Hash]*storelaw.VoteState
    31  
    32  	DirtyVote map[common.Hash]map[common.Address]struct{}
    33  	Blacklist map[common.Address]bool
    34  
    35  	receipts          types.Receipts
    36  	txs               types.Transactions
    37  	ParentBonusHeight uint64
    38  	WaitOplogs        []*OpLog //Transactional submission
    39  
    40  	//the ut amount when the vote start
    41  	voteUT map[common.Hash]*TxUT
    42  	//new vote pool
    43  	voteNew       []*storelaw.VoteState
    44  	accountVoteds map[common.Hash]map[common.Address]struct{}
    45  	ledgeror      storelaw.Ledger4Validation
    46  	leagueId      common.Address
    47  
    48  	m sync.Mutex
    49  }
    50  
    51  func NewStateValidate(ledgeror storelaw.Ledger4Validation, leadgeId common.Address) *StateValidate {
    52  
    53  	curHeight := ledgeror.GetCurrentBlockHeight4V(leadgeId)
    54  	s := &StateValidate{
    55  		TargetHeight:       curHeight + 1,
    56  		currentBlockHash:   ledgeror.GetCurrentHeaderHash4V(leadgeId),
    57  		currentBlockHeight: curHeight,
    58  		MemoAccountState:   make(map[common.Address]storelaw.AccountStater),
    59  		DirtyAccountState:  make(map[common.Address]storelaw.AccountStater),
    60  		Blacklist:          make(map[common.Address]bool),
    61  		MemoVoteState:      make(map[common.Hash]*storelaw.VoteState),
    62  		voteUT:             make(map[common.Hash]*TxUT),
    63  		accountVoteds:      make(map[common.Hash]map[common.Address]struct{}),
    64  		DirtyVote:          make(map[common.Hash]map[common.Address]struct{}),
    65  		WaitOplogs:         []*OpLog{}, //Transactional submission
    66  		ledgeror:           ledgeror,
    67  		leagueId:           leadgeId,
    68  	}
    69  	return s
    70  }
    71  
    72  func (s *StateValidate) TxInheritance() <-chan *types.Transaction {
    73  	ch := make(chan *types.Transaction, 20)
    74  	for k, _ := range s.txs {
    75  		if !s.ledgeror.ContainTx4V(s.txs[k].Hash()) {
    76  			ch <- s.txs[k]
    77  		}
    78  	}
    79  	close(ch)
    80  	return ch
    81  }
    82  
    83  //ExecuteOplogs is perform the verified transaction calculation and generate the status data
    84  func (s *StateValidate) ExecuteOplogs() *storelaw.OrgBlockInfo {
    85  	s.m.Lock()
    86  	defer s.m.Unlock()
    87  	{
    88  		//fmt.Println("⛏ ⛏  ExecuteOplogs txlen", s.txs.Len())
    89  		var (
    90  			aa *OPAddressBigInt
    91  			an *OPAddressUint64
    92  			ha *OPHashAddress
    93  			//ad *OPAddressAdress
    94  			fee = big.NewInt(0)
    95  		)
    96  		ut := s.ledgeror.GetUTByHeight(s.currentBlockHeight, s.leagueId)
    97  		//the vote hasn't passed
    98  		afterVote := make(map[common.Hash]struct{})
    99  		for k, v := range s.MemoVoteState {
   100  			//fmt.Println("⭕️ ExecuteOplogs vote hash ", k.String(), len(s.MemoVoteState))
   101  			if !v.GetResult(s.voteUT[k].UT, 67) {
   102  				//fmt.Println("⭕️ ExecuteOplogs vote result ", s.voteUT[k].UT)
   103  				afterVote[k] = struct{}{}
   104  			}
   105  		}
   106  		for _, v := range s.WaitOplogs {
   107  			switch v.method {
   108  			case Account_ut_add:
   109  				aa = v.data.(*OPAddressBigInt)
   110  				s.MemoAccountState[aa.Address].BalanceAdd(aa.Num)
   111  				break
   112  			case Account_energy_add:
   113  				aa = v.data.(*OPAddressBigInt)
   114  				//fmt.Println("func ExecuteOplogs address:", aa.Address.ToString())
   115  				s.MemoAccountState[aa.Address].EnergyAdd(aa.Num)
   116  				break
   117  			case Account_ut_sub:
   118  				aa = v.data.(*OPAddressBigInt)
   119  				s.MemoAccountState[aa.Address].BalanceSub(aa.Num)
   120  				break
   121  			case Account_energy_sub, Account_energy_consume:
   122  				aa = v.data.(*OPAddressBigInt)
   123  				s.MemoAccountState[aa.Address].EnergySub(aa.Num)
   124  				if v.method == Account_energy_consume {
   125  					fee.Add(fee, aa.Num)
   126  				}
   127  				break
   128  			case Account_bonus_left:
   129  				an = v.data.(*OPAddressUint64)
   130  				s.MemoAccountState[an.Address].BonusHSet(an.Num)
   131  				break
   132  			case Account_nonce_add:
   133  				an = v.data.(*OPAddressUint64)
   134  				s.MemoAccountState[an.Address].NonceSet(an.Num)
   135  				break
   136  			case Vote_abstention:
   137  				ha = v.data.(*OPHashAddress)
   138  				h := s.MemoVoteState[ha.Hash].Height
   139  				as := s.GetPrevAccountState(ha.Address, h)
   140  				s.MemoVoteState[ha.Hash].AddAbstention(as.Balance())
   141  			case Vote_against:
   142  				ha = v.data.(*OPHashAddress)
   143  				h := s.MemoVoteState[ha.Hash].Height
   144  				as := s.GetPrevAccountState(ha.Address, h)
   145  				s.MemoVoteState[ha.Hash].AddAgainst(as.Balance())
   146  			case Vote_agree:
   147  				ha = v.data.(*OPHashAddress)
   148  				h := s.MemoVoteState[ha.Hash].Height
   149  				as := s.GetPrevAccountState(ha.Address, h)
   150  				s.MemoVoteState[ha.Hash].AddAgree(as.Balance())
   151  			case League_Raise_ut:
   152  				aa = v.data.(*OPAddressBigInt)
   153  				ut.Add(ut, aa.Num)
   154  			}
   155  		}
   156  		accountStates := storelaw.AccountStaters{}
   157  		for _, v := range s.MemoAccountState {
   158  			accountStates = append(accountStates, v)
   159  		}
   160  
   161  		//todo calculate memberRoot and fill it into memoLeagueState
   162  		block := &types.Block{
   163  			Transactions: s.txs,
   164  			Header: &types.Header{
   165  				Height:        s.TargetHeight,
   166  				PrevBlockHash: s.currentBlockHash,
   167  				Version:       0x01,
   168  				TxRoot:        s.txs.GetHashRoot(),
   169  				StateRoot:     accountStates.GetHashRoot(),
   170  				ReceiptsRoot:  s.receipts.GetHashRoot(),
   171  				LeagueId:      s.leagueId,
   172  			},
   173  		}
   174  
   175  		//fmt.Println("♌️ ♌️ ♌️ ♌️ ♌️ ut️:", ut, " leagueId:", s.leagueId.ToString())
   176  		if s.TargetHeight%types.HWidth == 0 {
   177  			energyUsed := s.ledgeror.GetHeaderBonus(s.leagueId)
   178  			//fmt.Printf("♐️ ♐️ league ExecuteOplogs destroyEnergy:%d ut:%d\n ", energyUsed.Uint64(), ut.Uint64())
   179  			rat1 := new(big.Rat).SetInt(ut)
   180  			rat2 := new(big.Rat).SetInt(energyUsed)
   181  			rat1.Inv(rat1)
   182  			rat1.Mul(rat1, rat2)
   183  			rat1.Mul(rat1, ratU)
   184  			rfTmp := big.NewFloat(0).SetRat(rat1)
   185  			integer, _ := rfTmp.Uint64()
   186  			block.Header.Bonus = integer
   187  			//fmt.Println("♐️ ♐️ league ExecuteOplogs bonus ", integer)
   188  
   189  		}
   190  		feeSum := big.NewInt(0)
   191  		for _, v := range s.receipts {
   192  			feeSum.Add(feeSum, big.NewInt(0).SetUint64(v.GasUsed))
   193  		}
   194  		blkInfo := &storelaw.OrgBlockInfo{
   195  			Block:         block,
   196  			Receipts:      s.receipts,
   197  			AccStates:     accountStates,
   198  			FeeSum:        feeSum,
   199  			VoteStates:    make([]*storelaw.VoteState, 0, len(s.voteNew)+len(s.MemoVoteState)),
   200  			AccountVoteds: make([]*storelaw.AccountVoted, 0, len(s.DirtyVote)),
   201  		}
   202  		//put new vote into votestates
   203  		blkInfo.VoteStates = append(blkInfo.VoteStates, s.voteNew...)
   204  		if len(s.MemoVoteState) > 0 {
   205  			for k, v := range s.MemoVoteState {
   206  				blkInfo.VoteStates = append(blkInfo.VoteStates, v)
   207  
   208  				if v.GetResult(s.voteUT[k].UT, 67) {
   209  					if _, ok := afterVote[k]; ok {
   210  						fmt.Println("⭕️ vote first pass ", s.voteUT[k].Tx.Hash())
   211  						blkInfo.VoteFirstPass = append(blkInfo.VoteFirstPass, s.voteUT[k].Tx)
   212  					}
   213  				}
   214  			}
   215  		}
   216  		for k, v := range s.DirtyVote {
   217  			av := &storelaw.AccountVoted{
   218  				VoteId:   k,
   219  				Height:   s.TargetHeight,
   220  				Accounts: make([]common.Address, 0, len(v)),
   221  			}
   222  			for ki, _ := range v {
   223  				av.Accounts = append(av.Accounts, ki)
   224  			}
   225  			blkInfo.AccountVoteds = append(blkInfo.AccountVoteds, av)
   226  		}
   227  		//UT TODO if the tx causes a change in the ut amount,it needs to be calculated on ut.
   228  		blkInfo.UT = ut
   229  		return blkInfo
   230  	}
   231  }
   232  func (s *StateValidate) GetTxLen() int {
   233  	return s.txs.Len()
   234  }
   235  
   236  //VerifyTx is verify that the transaction is valid and return the processing plan
   237  //returns:
   238  // 	int   ------   -1: throw tx,0: back to queue, 1: efficient transaction
   239  //  error ------   Existing warning
   240  // if verify pass,tx is going to change StateValidate,append WaitOplogs,to affect dirtyState
   241  func (s *StateValidate) VerifyTx(tx *types.Transaction) (int, error) {
   242  	s.m.Lock()
   243  	defer s.m.Unlock()
   244  	//fmt.Println("🔍 verifytx start")
   245  	err := s.CheckSign(tx)
   246  	if err != nil {
   247  		return -1, err
   248  	}
   249  	err = s.CheckFee(tx)
   250  	if err != nil {
   251  		return -1, err
   252  
   253  	}
   254  	oplogs := HandleTransaction(tx)
   255  	//route oplogs to its homestate
   256  	accountOps := make([]*OpLog, 0, len(oplogs))
   257  	bonusOps := make([]*OpLog, 0, 3)
   258  	var (
   259  		voteOp  *OpLog
   260  		raiseOp *OpLog
   261  	)
   262  	//feeOp := &OpLog{}
   263  	//check exits in dirtystate,if not then get
   264  	for k, v := range oplogs {
   265  		if v.method < AccountMaxLine {
   266  			accountOps = append(accountOps, oplogs[k])
   267  			/*if v.method == Account_energy_consume {
   268  				feeOp = oplogs[k]
   269  			}*/
   270  		} else if v.method == Account_bonus_fee {
   271  			bonusOps = append(bonusOps, v)
   272  		} else if v.method == League_Raise_ut {
   273  			raiseOp = v
   274  		} else {
   275  			voteOp = v
   276  		}
   277  	}
   278  	fee := uint64(0)
   279  	if tx.TxData.Fee != nil {
   280  		fee = tx.TxData.Fee.Uint64()
   281  	}
   282  	receipt := &types.Receipt{
   283  		TxHash:  tx.Hash(),
   284  		GasUsed: fee,
   285  	}
   286  	//fill oplogs into WaitOplogs and FeeOplogs (group by)
   287  	opIndes1, err := s.VerifyAccount(accountOps)
   288  	if err != nil {
   289  		s.RollbackAccount(accountOps, opIndes1)
   290  		if err == errors.ERR_STATE_ACCOUNT_NONCE_DISCONTINUITY {
   291  			return 0, err
   292  		} else {
   293  			return -1, err
   294  		}
   295  		/*err = s.verifyAccount(feeOp)
   296  		if err != nil {
   297  			return 0, err
   298  		}
   299  		s.appendWaitOplog(feeOp)
   300  		s.appendTx(tx)
   301  		s.appendReceipt(receipt)
   302  		return 1, nil*/
   303  	}
   304  	if len(bonusOps) > 0 {
   305  		ops, err := s.verifyBonus(bonusOps[0])
   306  		if err != nil {
   307  			s.RollbackAccount(accountOps, opIndes1)
   308  			return -1, err
   309  		}
   310  		bonusOps = append(bonusOps, ops...)
   311  	}
   312  	if voteOp != nil {
   313  		err = s.verifyVote(voteOp)
   314  		if err != nil {
   315  			s.RollbackAccount(accountOps, opIndes1)
   316  			return -1, err
   317  		}
   318  	}
   319  
   320  	receipt.Status = true
   321  	s.appendReceipt(receipt)
   322  	s.appendWaitOplogs(accountOps)
   323  	s.appendWaitOplog(voteOp)
   324  	s.appendWaitOplogs(bonusOps)
   325  	s.appendWaitOplog(raiseOp)
   326  	s.appendTx(tx)
   327  	return 1, nil
   328  }
   329  
   330  func (s *StateValidate) appendWaitOplogs(oplogs []*OpLog) {
   331  	s.WaitOplogs = append(s.WaitOplogs, oplogs...)
   332  }
   333  func (s *StateValidate) appendWaitOplog(oplog *OpLog) {
   334  	if oplog != nil {
   335  		s.WaitOplogs = append(s.WaitOplogs, oplog)
   336  	}
   337  }
   338  func (s *StateValidate) appendTx(tx *types.Transaction) {
   339  	s.txs = append(s.txs, tx)
   340  	s.appendVoteNew(tx)
   341  }
   342  func (s *StateValidate) appendVoteNew(tx *types.Transaction) {
   343  	if voteTypeContains(tx.TxType) {
   344  		vs := &storelaw.VoteState{
   345  			VoteId:     tx.Hash(),
   346  			Height:     s.TargetHeight,
   347  			Agree:      big.NewInt(0),
   348  			Against:    big.NewInt(0),
   349  			Abstention: big.NewInt(0),
   350  		}
   351  		s.voteNew = append(s.voteNew, vs)
   352  	}
   353  }
   354  
   355  func (s *StateValidate) appendReceipt(receipt *types.Receipt) {
   356  	s.receipts = append(s.receipts, receipt)
   357  }
   358  
   359  //
   360  func (s *StateValidate) CheckSign(tx *types.Transaction) error {
   361  	return nil
   362  }
   363  
   364  //todo
   365  func (s *StateValidate) CheckFee(tx *types.Transaction) error {
   366  	return nil
   367  }
   368  func (s *StateValidate) CheckNodeId(nodeId common.Address) error {
   369  	return nil
   370  }
   371  
   372  //TODO get data from leder_store
   373  func (s *StateValidate) checkMemberState(address, leagueId common.Address) error {
   374  	return nil
   375  }