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

     1  package validation
     2  
     3  import (
     4  	"sync"
     5  
     6  	"math/big"
     7  
     8  	"fmt"
     9  
    10  	"github.com/sixexorg/magnetic-ring/common"
    11  	"github.com/sixexorg/magnetic-ring/core/mainchain/types"
    12  	"github.com/sixexorg/magnetic-ring/errors"
    13  	"github.com/sixexorg/magnetic-ring/log"
    14  	"github.com/sixexorg/magnetic-ring/store/mainchain/states"
    15  	"github.com/sixexorg/magnetic-ring/store/mainchain/storages"
    16  )
    17  
    18  var (
    19  	feeLimit = big.NewInt(0)
    20  	objTypes = make(map[types.TransactionType]struct{})
    21  )
    22  
    23  func init() {
    24  	objTypes[types.ConsensusLeague] = struct{}{}
    25  	objTypes[types.LockLeague] = struct{}{}
    26  	objTypes[types.RaiseUT] = struct{}{}
    27  }
    28  func containObjTypes(key types.TransactionType) bool {
    29  	_, ok := objTypes[key]
    30  	return ok
    31  }
    32  
    33  // todo how to do with the nonce
    34  type StateValidate struct {
    35  	TargetHeight       uint64
    36  	currentBlockHeight uint64
    37  	currentBlockHash   common.Hash
    38  	//Only contain changes state
    39  	CacheLMemberState map[common.Address]map[common.Address]*states.LeagueMember
    40  
    41  	MemoAccountState map[common.Address]*states.AccountState
    42  	MemoLeagueState  map[common.Address]*states.LeagueState
    43  
    44  	TargetLMemberState map[common.Address]map[common.Address]*states.LeagueMember
    45  
    46  	//for one tx ,Take the lower limit,only the subtraction
    47  	DirtyAccountState map[common.Address]*states.AccountState
    48  	DirtyLeagueState  map[common.Address]*states.LeagueState
    49  	//one by one,an account can only perform one operation about add or exit
    50  	DirtyLMemberState map[common.Address]map[common.Address]*states.LeagueMember
    51  
    52  	//if league is newly created,it can't accept anything else
    53  	LeagueForCreate []*storages.LeagueKV
    54  	SymbolForCreate map[common.Symbol]struct{}
    55  	Blacklist       map[common.Address]bool
    56  
    57  	ParentBonusHeight uint64
    58  	WaitOplogs        []*OpLog //Transactional submission
    59  
    60  	objTxs      types.Transactions
    61  	receipts    types.Receipts
    62  	txs         types.Transactions
    63  	ledgerStore *storages.LedgerStoreImp
    64  
    65  	LeagueGas *big.Int
    66  	M         *sync.Mutex
    67  }
    68  
    69  func NewStateValidate(ledgerStore *storages.LedgerStoreImp) *StateValidate {
    70  	log.Info("func validation NewStateValidate")
    71  
    72  	curHeight, curHash := ledgerStore.GetCurrentBlock()
    73  	AccountNonceInstance.reset(curHeight)
    74  	s := &StateValidate{
    75  		TargetHeight:       curHeight + 1,
    76  		currentBlockHash:   curHash,
    77  		currentBlockHeight: curHeight,
    78  		MemoAccountState:   make(map[common.Address]*states.AccountState),
    79  		MemoLeagueState:    make(map[common.Address]*states.LeagueState),
    80  		DirtyAccountState:  make(map[common.Address]*states.AccountState),
    81  		DirtyLeagueState:   make(map[common.Address]*states.LeagueState),
    82  		LeagueForCreate:    make([]*storages.LeagueKV, 0),
    83  		TargetLMemberState: make(map[common.Address]map[common.Address]*states.LeagueMember), //league account
    84  		CacheLMemberState:  make(map[common.Address]map[common.Address]*states.LeagueMember),
    85  		DirtyLMemberState:  make(map[common.Address]map[common.Address]*states.LeagueMember),
    86  		Blacklist:          make(map[common.Address]bool),
    87  		SymbolForCreate:    make(map[common.Symbol]struct{}),
    88  		ledgerStore:        ledgerStore,
    89  		WaitOplogs:         []*OpLog{}, //Transactional submission
    90  		LeagueGas:          new(big.Int),
    91  		M:                  new(sync.Mutex),
    92  	}
    93  
    94  	return s
    95  }
    96  func (s *StateValidate) GetTxLen() int {
    97  	if s == nil {
    98  		return -1
    99  	}
   100  	return s.txs.Len()
   101  }
   102  func (s *StateValidate) TxInheritance() <-chan *types.Transaction {
   103  	ch := make(chan *types.Transaction, 20)
   104  	for k, _ := range s.txs {
   105  		if !s.ledgerStore.ContainTx(s.txs[k].Hash()) {
   106  			ch <- s.txs[k]
   107  		}
   108  	}
   109  	close(ch)
   110  	return ch
   111  }
   112  
   113  //ExecuteOplogs is perform the verified transaction calculation and generate the status data
   114  func (s *StateValidate) ExecuteOplogs() (
   115  	blockInfo *storages.BlockInfo) {
   116  	s.M.Lock()
   117  	defer s.M.Unlock()
   118  	{
   119  		log.Info("func ExecuteOplogs", "blockTargetHeight", s.TargetHeight, "txlen", s.txs.Len())
   120  		var (
   121  			aa  *OPAddressBigInt
   122  			an  *OPAddressUint64
   123  			ad  *OPAddressAdress
   124  			fee = big.NewInt(0)
   125  		)
   126  		/*for k, v := range s.MemoAccountState {
   127  			fmt.Println("ex  you know", k.ToString(), v.Address.ToString(), v.Data.Nonce)
   128  
   129  		}*/
   130  		for _, optmp := range s.WaitOplogs {
   131  			v := optmp
   132  			switch v.method {
   133  			case Account_box_add:
   134  				aa = v.data.(*OPAddressBigInt)
   135  				s.MemoAccountState[aa.Address].Data.Balance.Add(s.MemoAccountState[aa.Address].Data.Balance, aa.Num)
   136  				break
   137  			case Account_energy_add:
   138  				aa = v.data.(*OPAddressBigInt)
   139  				s.MemoAccountState[aa.Address].Data.EnergyBalance.Add(s.MemoAccountState[aa.Address].Data.EnergyBalance, aa.Num)
   140  				break
   141  			case Account_box_sub:
   142  				aa = v.data.(*OPAddressBigInt)
   143  				s.MemoAccountState[aa.Address].Data.Balance.Sub(s.MemoAccountState[aa.Address].Data.Balance, aa.Num)
   144  				break
   145  			case Account_energy_sub, Account_energy_consume:
   146  				aa = v.data.(*OPAddressBigInt)
   147  				s.MemoAccountState[aa.Address].Data.EnergyBalance.Sub(s.MemoAccountState[aa.Address].Data.EnergyBalance, aa.Num)
   148  				if v.method == Account_energy_consume {
   149  					fee.Add(fee, aa.Num)
   150  				}
   151  				break
   152  			case Account_bonus_left:
   153  				an = v.data.(*OPAddressUint64)
   154  				s.MemoAccountState[an.Address].Data.BonusHeight = an.Num
   155  				break
   156  			case Account_nonce_add:
   157  				an = v.data.(*OPAddressUint64)
   158  				s.MemoAccountState[an.Address].Data.Nonce = an.Num
   159  				break
   160  			case League_create:
   161  				modelCreate := v.data.(*OPCreateLeague)
   162  				leagueState := &states.LeagueState{
   163  					Address: modelCreate.League,
   164  					Height:  s.TargetHeight,
   165  					MinBox:  modelCreate.Minbox,
   166  					Creator: modelCreate.Creator,
   167  					Rate:    modelCreate.Rate,
   168  					Private: modelCreate.Private,
   169  					Data: &states.League{
   170  						Nonce:      1,
   171  						FrozenBox:  modelCreate.FrozenBox,
   172  						MemberRoot: common.Hash{}, //todo merkle root
   173  						Name:       common.Hash{},
   174  					},
   175  				}
   176  				s.MemoLeagueState[leagueState.Address] = leagueState
   177  				break
   178  			case League_member_add, League_member_apply:
   179  				ad = v.data.(*OPAddressAdress)
   180  				if s.TargetLMemberState[ad.Second] == nil {
   181  					s.TargetLMemberState[ad.Second] = make(map[common.Address]*states.LeagueMember)
   182  				}
   183  				s.TargetLMemberState[ad.Second][ad.First] = s.DirtyLMemberState[ad.Second][ad.First]
   184  				fmt.Printf("🔆 ExecuteOplogs dirtyLMemberState %v\n", s.DirtyLMemberState[ad.Second][ad.First])
   185  				break
   186  			case League_member_remove:
   187  				ad = v.data.(*OPAddressAdress)
   188  				if s.TargetLMemberState[ad.Second] == nil {
   189  					s.TargetLMemberState[ad.Second] = make(map[common.Address]*states.LeagueMember)
   190  				}
   191  				s.TargetLMemberState[ad.Second][ad.First] = s.DirtyLMemberState[ad.Second][ad.First]
   192  				fmt.Printf("🔆 ExecuteOplogs dirtyLMemberState %v\n", s.DirtyLMemberState[ad.Second][ad.First])
   193  			case League_nonce_add:
   194  				an = v.data.(*OPAddressUint64)
   195  				s.MemoLeagueState[an.Address].Data.Nonce = an.Num
   196  				//fmt.Println("execute 2", an.Address.ToString(), an.Num)
   197  				break
   198  			case League_gas_destroy:
   199  				aa = v.data.(*OPAddressBigInt)
   200  				s.LeagueGas.Add(s.LeagueGas, aa.Num)
   201  				break
   202  			case League_raise:
   203  				aa = v.data.(*OPAddressBigInt)
   204  				s.MemoLeagueState[aa.Address].AddMetaBox(aa.Num)
   205  				break
   206  			}
   207  		}
   208  		accountStates := make(states.AccountStates, 0, len(s.MemoAccountState))
   209  		for _, v := range s.MemoAccountState {
   210  			/*	log.Info("--------------------------accountState------------start--------------")
   211  				fmt.Printf("energy:%d,crystal:%d,nonce:%d,height:%d,address:%s\n", v.Data.EnergyBalance.Uint64(), v.Data.Balance.Uint64(), v.Data.Nonce, v.Height, v.Address.ToString())
   212  				as, _ := s.ledgerStore.GetAccountByHeight(v.Height, v.Address)
   213  				if as != nil {
   214  
   215  					fmt.Printf("accountState ====> address :%s,nonce:%d,crystal:%d,energy:%d,height:%d \n", as.Address.ToString(), as.Data.Nonce, as.Data.Balance.Uint64(), as.Data.EnergyBalance.Uint64(), as.Height)
   216  					log.Info("--------------------------accountState------------end--------------")
   217  				}*/
   218  			as := v
   219  			accountStates = append(accountStates, as)
   220  			//fmt.Println("execute state rennbon", as.Address.ToString(), as.Data.Nonce)
   221  			/*
   222  				fmt.Println("key", k.ToString())*/
   223  		}
   224  
   225  		//todo calculate memberRoot and fill it into memoLeagueState
   226  		leagueMembers := make(states.LeagueMembers, 0)
   227  		for k, v := range s.TargetLMemberState {
   228  			lms := make(states.LeagueMembers, 0)
   229  			for _, vi := range v {
   230  				member := vi
   231  				lms = append(lms, member)
   232  				hashRoot := lms.GetHashRoot()
   233  				s.MemoLeagueState[k].Data.MemberRoot = hashRoot
   234  				leagueMembers = append(leagueMembers, member)
   235  			}
   236  		}
   237  		leagueStates := make(states.LeagueStates, 0, len(s.MemoLeagueState))
   238  		for k, _ := range s.MemoLeagueState {
   239  			leagueStates = append(leagueStates, s.MemoLeagueState[k])
   240  		}
   241  		//todo calculate memberRoot and fill it into memoLeagueState
   242  		fmt.Println("🔨 🔧  ExecuteOplogs txlen:", s.txs.Len())
   243  		txs := make(types.Transactions, 0, len(s.txs)+len(s.objTxs))
   244  		txs = append(txs, s.txs...)
   245  		txs = append(txs, s.objTxs...)
   246  		block := &types.Block{
   247  			Transactions: txs,
   248  			Header: &types.Header{
   249  				Height:        s.TargetHeight,
   250  				PrevBlockHash: s.currentBlockHash,
   251  				Version:       0x01,
   252  				TxRoot:        txs.GetHashRoot(),
   253  				StateRoot:     accountStates.GetHashRoot(),
   254  				LeagueRoot:    leagueStates.GetHashRoot(),
   255  				ReceiptsRoot:  s.receipts.GetHashRoot(),
   256  			},
   257  			Sigs: &types.SigData{},
   258  		}
   259  		// Temporary cancellation, account recovery system is not designed
   260  		//if s.TargetHeight%types.HWidth == 0 {
   261  		//	lvs, err := s.ledgerStore.GetNextHeaderProperty(s.TargetHeight)
   262  		//	if err != nil {
   263  		//		panic(err)
   264  		//	}
   265  		//	fmt.Println("🔨 🔧  ExecuteOplogs pack block head bonus ", lvs)
   266  		//	for k, v := range lvs {
   267  		//		switch k {
   268  		//		case 0:
   269  		//			block.Header.Lv1 = v
   270  		//			break
   271  		//		case 1:
   272  		//			block.Header.Lv2 = v
   273  		//			break
   274  		//		case 2:
   275  		//			block.Header.Lv3 = v
   276  		//			break
   277  		//		case 3:
   278  		//			block.Header.Lv4 = v
   279  		//			break
   280  		//		case 4:
   281  		//			block.Header.Lv5 = v
   282  		//			break
   283  		//		case 5:
   284  		//			block.Header.Lv6 = v
   285  		//			break
   286  		//		case 6:
   287  		//			block.Header.Lv7 = v
   288  		//			break
   289  		//		case 7:
   290  		//			block.Header.Lv8 = v
   291  		//			break
   292  		//		case 8:
   293  		//			block.Header.Lv9 = v
   294  		//			break
   295  		//		}
   296  		//	}
   297  		//}
   298  		feeSum := big.NewInt(0)
   299  		for _, v := range s.receipts {
   300  			feeSum.Add(feeSum, big.NewInt(0).SetUint64(v.GasUsed))
   301  		}
   302  
   303  		/*gasDestroy1 := new(big.Int)
   304  		hundred := big.NewInt(100)
   305  		gasDestroy1.Mul(feeSum, hundred)
   306  		gasDestroy1.Div(gasDestroy1, big.NewInt(75))
   307  
   308  		gasDestroy2 := new(big.Int)
   309  		gasDestroy2.Mul(s.LeagueGas, hundred)
   310  		gasDestroy2.Div(gasDestroy2, big.NewInt(30))
   311  
   312  		gasDestroy1.Add(gasDestroy1, gasDestroy2)*/
   313  		blockkInfo := &storages.BlockInfo{
   314  			Block:         block,
   315  			Receipts:      s.receipts,
   316  			AccountStates: accountStates,
   317  			LeagueStates:  leagueStates,
   318  			Members:       leagueMembers,
   319  			FeeSum:        feeSum,
   320  			LeagueKVs:     s.LeagueForCreate,
   321  			ObjTxs:        s.objTxs,
   322  			//GasDestroy:    gasDestroy1,
   323  		}
   324  		//return block, s.receipts, accountStates, leagueStates, leagueMembers, fee
   325  		return blockkInfo
   326  	}
   327  }
   328  
   329  //VerifyTx is verify that the transaction is valid and return the processing plan
   330  //returns:
   331  // 	int   ------   -1: throw tx,0: back to queue, 1: efficient transaction
   332  //  error ------   Existing warning
   333  // if verify pass,tx is going to change StateValidate,append WaitOplogs,to affect dirtyState
   334  func (s *StateValidate) VerifyTx(tx *types.Transaction) (int, error) {
   335  	//log.Info("func VerifyTx 01", "tx.Hash", tx.Hash().String())
   336  	//log.Info("func VerifyTx 02", "txlen", s.txs.Len())
   337  	//fmt.Println("bbbb", tx.TxData.Froms.Tis[0].Nonce)
   338  	err := s.CheckSign(tx)
   339  	if err != nil {
   340  		return -1, err
   341  	}
   342  
   343  	err = s.CheckFee(tx)
   344  	if err != nil {
   345  		return -1, err
   346  
   347  	}
   348  	//fmt.Println("---------tx start--------")
   349  	//defer fmt.Println("---------tx end--------")
   350  	oplogs := HandleTransaction(tx)
   351  	l := len(oplogs)
   352  	//route oplogs to its homestate
   353  	accountOps := make([]*OpLog, 0, l)
   354  	leagueOps := make([]*OpLog, 0, l)
   355  	bonusOps := make([]*OpLog, 0, 3)
   356  	//feeOp := &OpLog{}
   357  	gused := uint64(0)
   358  	if tx.TxData.Fee != nil {
   359  		gused = tx.TxData.Fee.Uint64()
   360  	}
   361  	receipt := &types.Receipt{
   362  		GasUsed: gused,
   363  		TxHash:  tx.Hash(),
   364  	}
   365  	//check exits in dirtystate,if not then get
   366  	for _, v := range oplogs {
   367  		opTmp := v
   368  		if v.method < AccountMaxLine {
   369  			accountOps = append(accountOps, opTmp)
   370  			/*if v.method == Account_energy_consume {
   371  				feeOp = opTmp
   372  			}*/
   373  		} else if v.method > LeagueMinLine && v.method < LeagueMaxLine {
   374  			leagueOps = append(leagueOps, opTmp)
   375  		} else if v.method == Account_bonus_fee {
   376  			bonusOps = append(bonusOps, opTmp)
   377  		}
   378  	}
   379  
   380  	//fill oplogs into WaitOplogs and FeeOplogs (group by)
   381  	opIndes1, err := s.VerifyAccount(accountOps)
   382  	if err != nil {
   383  		s.RollbackAccount(accountOps, opIndes1)
   384  		if err == errors.ERR_STATE_ACCOUNT_NONCE_DISCONTINUITY {
   385  			return 0, err
   386  		} else {
   387  			return -1, err
   388  		}
   389  		/*	err = s.verifyAccount(feeOp)
   390  			if err != nil {
   391  				return 0, err
   392  			}
   393  			s.appendWaitOplogs(feeOp)
   394  			s.appendReceipt(receipt)
   395  			s.appendTx(tx)
   396  			return 1, nil*/
   397  	}
   398  	if len(bonusOps) > 0 {
   399  		ops, err := s.verifyBonus(bonusOps[0])
   400  		if err != nil {
   401  			s.RollbackAccount(accountOps, opIndes1)
   402  			return -1, err
   403  		}
   404  		bonusOps = append(bonusOps, ops...)
   405  	}
   406  	opIndes2, err := s.VerifyLeague(leagueOps)
   407  	if err != nil {
   408  		//TODO if league has something that has to be done
   409  		s.RollbackAccount(accountOps, opIndes1)
   410  		s.RollbackLeague(leagueOps, opIndes2)
   411  		return -1, err
   412  		/*if err == errors.ERR_STATE_LEAGUE_NONCE_BIGGER {
   413  			return 0, err
   414  		} else {*/
   415  
   416  		//}
   417  		/*	err = s.verifyAccount(feeOp)
   418  			s.appendWaitOplogs(feeOp)
   419  			s.appendReceipt(receipt)
   420  			s.appendTx(tx)
   421  			return 1, nil*/
   422  	}
   423  
   424  	receipt.Status = true
   425  
   426  	s.appendReceipt(receipt)
   427  	s.appendWaitOplogs(accountOps...)
   428  	s.appendWaitOplogs(leagueOps...)
   429  	s.appendWaitOplogs(bonusOps...)
   430  	s.appendTx(tx)
   431  
   432  	//log.Info("func VerifyTx 03", "appendTx", tx.Hash().String())
   433  
   434  	if tx.TxType == types.EnergyToLeague {
   435  		fmt.Println("转energy到圈子")
   436  	}
   437  	return 1, nil
   438  }
   439  
   440  func (s *StateValidate) appendWaitOplogs(oplogs ...*OpLog) {
   441  	s.WaitOplogs = append(s.WaitOplogs, oplogs...)
   442  }
   443  
   444  func (s *StateValidate) appendReceipt(receipt *types.Receipt) {
   445  	s.receipts = append(s.receipts, receipt)
   446  }
   447  func (s *StateValidate) appendTx(tx *types.Transaction) {
   448  	if containObjTypes(tx.TxType) {
   449  		s.objTxs = append(s.objTxs, tx)
   450  	} else {
   451  		s.txs = append(s.txs, tx)
   452  	}
   453  }
   454  
   455  func (s *StateValidate) CheckSign(tx *types.Transaction) error {
   456  	if !containObjTypes(tx.TxType) {
   457  		b, err := tx.VerifySignature()
   458  		if err != nil {
   459  			return err
   460  		}
   461  		if !b {
   462  			return errors.ERR_TX_SIGN
   463  		}
   464  	}
   465  	return nil
   466  }
   467  
   468  //todo
   469  func (s *StateValidate) CheckFee(tx *types.Transaction) error {
   470  	return nil
   471  	/*	if containObjTypes(tx.TxType) {
   472  			return nil
   473  		} else {
   474  			feeLimit.SetUint64(2)
   475  			if tx.TxData.Fee.Cmp(feeLimit) == -1 {
   476  				return errors.NewErr("fee not enought")
   477  			}
   478  			return nil
   479  		}*/
   480  }
   481  func (s *StateValidate) CheckNodeId(nodeId common.Address) error {
   482  	return nil
   483  }
   484  
   485  func (s *StateValidate) RemoveElementInLeagueForCreate(address common.Address) {
   486  	index := -1
   487  	for k, v := range s.LeagueForCreate {
   488  		if address == v.K {
   489  			index = k
   490  		}
   491  	}
   492  	if index != -1 {
   493  		if index == len(s.LeagueForCreate) {
   494  			s.LeagueForCreate = s.LeagueForCreate[:index]
   495  		} else {
   496  			s.LeagueForCreate = append(s.LeagueForCreate[:index], s.LeagueForCreate[index+1:]...)
   497  		}
   498  	}
   499  }