github.com/sixexorg/magnetic-ring@v0.0.0-20191119090307-31705a21e419/txpool/mainchain/tx_pool.go (about)

     1  package mainchain
     2  
     3  import (
     4  	"fmt"
     5  	"sort"
     6  	"sync"
     7  	"time"
     8  
     9  	"github.com/sixexorg/magnetic-ring/bactor"
    10  	"github.com/sixexorg/magnetic-ring/config"
    11  
    12  	"github.com/sixexorg/magnetic-ring/log"
    13  
    14  	"github.com/ontio/ontology-eventbus/actor"
    15  	"github.com/sixexorg/magnetic-ring/common"
    16  	"github.com/sixexorg/magnetic-ring/core/mainchain/types"
    17  	"github.com/sixexorg/magnetic-ring/errors"
    18  	"github.com/sixexorg/magnetic-ring/radar/mainchain"
    19  	"github.com/sixexorg/magnetic-ring/store/mainchain/states"
    20  	"github.com/sixexorg/magnetic-ring/store/mainchain/storages"
    21  	"github.com/sixexorg/magnetic-ring/store/mainchain/validation"
    22  )
    23  
    24  var (
    25  	mainTxPool *TxPool
    26  )
    27  
    28  type TxPool struct {
    29  	pdmgr *PendingMgr
    30  	//queue     *TxQueue
    31  	waitTxNum map[common.Hash]uint8
    32  	waitPool  types.Transactions
    33  	txChan    chan *types.Transaction
    34  
    35  	maxPending   uint32
    36  	maxInPending uint32
    37  	maxInQueue   uint32
    38  
    39  	stateValidator *validation.StateValidate
    40  
    41  	ticker *time.Ticker
    42  
    43  	txpoolPid *actor.PID
    44  
    45  	mustPackTxs []*types.Transaction
    46  	mainRadar   *mainchain.LeagueConsumers
    47  }
    48  
    49  func NewTxPool() *TxPool {
    50  	pool := new(TxPool)
    51  	pool.pdmgr = NewPendingMgr()
    52  	//pool.queue = NewTxQueue()
    53  	pool.maxPending = config.GlobalConfig.TxPoolCfg.MaxPending
    54  	pool.maxInPending = config.GlobalConfig.TxPoolCfg.MaxInPending
    55  	pool.maxInQueue = config.GlobalConfig.TxPoolCfg.MaxInQueue
    56  	pool.txChan = make(chan *types.Transaction, pool.maxInQueue)
    57  
    58  	pool.RefreshValidator()
    59  	pool.waitPool = make(types.Transactions, 0, 10000)
    60  	pool.waitTxNum = make(map[common.Hash]uint8, 10000)
    61  	pool.mustPackTxs = make([]*types.Transaction, 0)
    62  	return pool
    63  }
    64  func (pool *TxPool) SetMainRadar(mainRadar *mainchain.LeagueConsumers) {
    65  	pool.mainRadar = mainRadar
    66  }
    67  
    68  func (pool *TxPool) AppendMustPackTx(txs ...*types.Transaction) {
    69  
    70  	for _, tx := range txs {
    71  		pool.mustPackTxs = append(pool.mustPackTxs, tx)
    72  	}
    73  
    74  }
    75  
    76  type PendingMgr struct {
    77  	sync.RWMutex
    78  	pendingTxs map[common.Hash]*types.Transaction
    79  }
    80  
    81  func InitPool() (*TxPool, error) {
    82  	var err error
    83  	mainTxPool, err = InitTxPool()
    84  
    85  	if err != nil {
    86  		return nil, err
    87  	}
    88  
    89  	mainTxPool.Start()
    90  	return mainTxPool, nil
    91  }
    92  
    93  func GetPool() (*TxPool, error) {
    94  	if mainTxPool == nil {
    95  		return nil, errors.ERR_TXPOOL_UNINIT
    96  	}
    97  	return mainTxPool, nil
    98  }
    99  
   100  func (pool *TxPool) Start() {
   101  	pool.RefreshValidator()
   102  	go func() {
   103  		for {
   104  			select {
   105  			case tx := <-pool.txChan:
   106  
   107  				//if !pool.queue.IsEmpty() {
   108  				//tx = pool.queue.Dequeue()
   109  
   110  				err := pool.AddTx(tx)
   111  				if err != nil {
   112  					fmt.Printf("addtx and validate error=%v\n", err)
   113  					log.Info("addtx error", "error", err, "targetBlockHeight", pool.stateValidator.TargetHeight, "errors.ERR_TXPOOL_OUTOFMAX", pool.maxInQueue, "len(pool.txChan)", len(pool.txChan))
   114  				}
   115  				//}
   116  			}
   117  		}
   118  	}()
   119  }
   120  
   121  func startActor(obj interface{}, id string) (*actor.PID, error) {
   122  	props := actor.FromProducer(func() actor.Actor {
   123  		return obj.(actor.Actor)
   124  	})
   125  
   126  	pid, _ := actor.SpawnNamed(props, id)
   127  	if pid == nil {
   128  		return nil, fmt.Errorf("fail to start actor at props:%v id:%s", props, id)
   129  	}
   130  	return pid, nil
   131  }
   132  
   133  func InitTxPool() (*TxPool, error) {
   134  	pool := NewTxPool()
   135  
   136  	poolActor := NewTxActor(pool)
   137  
   138  	pid, err := startActor(poolActor, "txpoolAcotor")
   139  	if err != nil {
   140  		return nil, err
   141  	}
   142  
   143  	bactor.RegistActorPid(bactor.TXPOOLACTOR, pid)
   144  	pool.txpoolPid = pid
   145  
   146  	return pool, nil
   147  
   148  }
   149  
   150  func (pool *TxPool) refreshWaitPool() {
   151  	if pool.waitPool.Len() > 0 {
   152  		for k, _ := range pool.waitPool {
   153  			pool.TxEnqueue(pool.waitPool[k])
   154  		}
   155  	}
   156  	pool.waitPool = make(types.Transactions, 0, 10000)
   157  	pool.waitTxNum = make(map[common.Hash]uint8, 10000)
   158  }
   159  func (pool *TxPool) RefreshValidator() {
   160  	if pool != nil && pool.stateValidator != nil {
   161  		//log.Info("func txpool RefreshValidator 01", "oldTargetHeight", pool.stateValidator.TargetHeight, "txlen", pool.stateValidator.GetTxLen())
   162  		fmt.Println("func txpool RefreshValidator 01 ", "oldTargetHeight=", pool.stateValidator.TargetHeight, " txlen=", pool.stateValidator.GetTxLen())
   163  	}
   164  	ledgerStore := storages.GetLedgerStore()
   165  	if ledgerStore == nil {
   166  		return
   167  	}
   168  	oldSV := pool.stateValidator
   169  	pool.stateValidator = validation.NewStateValidate(ledgerStore)
   170  	if oldSV != nil {
   171  		txch := oldSV.TxInheritance()
   172  		for ch := range txch {
   173  			pool.TxEnqueue(ch)
   174  		}
   175  	}
   176  	pool.refreshWaitPool()
   177  	//log.Info("func txpool RefreshValidator 02", "newTargetHeight", pool.stateValidator.TargetHeight, "txlen", pool.stateValidator.GetTxLen())
   178  	fmt.Println("func txpool RefreshValidator 02 ", "newTargetHeight=", pool.stateValidator.TargetHeight, " txlen=", pool.stateValidator.GetTxLen())
   179  }
   180  
   181  func (pool *TxPool) AddTx(tx *types.Transaction) error {
   182  	result, err := pool.stateValidator.VerifyTx(tx)
   183  
   184  	if err != nil {
   185  		return err
   186  	}
   187  
   188  	txHash := tx.Hash()
   189  
   190  	switch result {
   191  	case -1:
   192  		return err
   193  	case 0: //
   194  		if uint32(len(pool.txChan)) < pool.maxInQueue {
   195  			pool.waitTxNum[txHash]++
   196  			if uint32(pool.waitTxNum[txHash]) == config.GlobalConfig.TxPoolCfg.MaxTxInPool { // 下一个块在考虑  尝试四次都失败后执行
   197  				pool.waitPool = append(pool.waitPool, tx)
   198  			} else if uint32(pool.waitTxNum[txHash]) < config.GlobalConfig.TxPoolCfg.MaxTxInPool {
   199  				pool.txChan <- tx
   200  			}
   201  		} else {
   202  			return errors.ERR_TXPOOL_OUTOFMAX
   203  		}
   204  
   205  		return nil
   206  	case 1: //
   207  		fmt.Printf("validate tx success,txhash=%s\n", txHash.String())
   208  		p2ppid, err := bactor.GetActorPid(bactor.P2PACTOR)
   209  		if err != nil {
   210  			log.Error("tx_pool.go get p2ppid error", "error", err)
   211  		} else {
   212  			p2ppid.Tell(tx)
   213  		}
   214  		pool.pdmgr.addTx(tx, pool.maxPending)
   215  		return nil
   216  	}
   217  	return nil
   218  }
   219  
   220  func (pool *TxPool) GetTxpoolPID() *actor.PID {
   221  	return pool.txpoolPid
   222  }
   223  
   224  func (pool *TxPool) TxEnqueue(tx *types.Transaction) error {
   225  	log.Info("magnetic try to enqueue", "tx", tx, "queue.size", len(pool.txChan))
   226  	//if uint32(pool.queue.Size()) >= pool.maxInQueue {
   227  	//	return errors.ERR_TXPOOL_OUTOFMAX
   228  	//}
   229  	if uint32(len(pool.txChan)) >= pool.maxInQueue {
   230  		return errors.ERR_TXPOOL_OUTOFMAX
   231  	}
   232  	log.Info("magnetic enqueue success", "tx", tx, "queue.size", len(pool.txChan))
   233  	//pool.queue.Enqueue(tx)
   234  	pool.txChan <- tx
   235  	return nil
   236  }
   237  
   238  /**
   239  	generate block
   240  */
   241  func (pool *TxPool) GenerateBlock(height uint64, packtx bool) *types.Block {
   242  	//pool.ticker.Stop()
   243  
   244  	sts := states.AccountStates{}
   245  	var txs *types.Transactions
   246  	if packtx {
   247  		txs = pool.pdmgr.getTxs(pool.maxPending)
   248  		if txs != nil && txs.Len() > 0 {
   249  			sort.Sort(txs)
   250  		}
   251  	}
   252  	var txsroot common.Hash
   253  	var txns types.Transactions
   254  
   255  	if txs != nil {
   256  		txsroot = txs.GetHashRoot()
   257  		txns = *txs
   258  	}
   259  
   260  	block := &types.Block{
   261  		Header: &types.Header{
   262  			Height:        height + 1,
   263  			Version:       types.TxVersion,
   264  			PrevBlockHash: storages.GetLedgerStore().GetCurrentBlockHash(),
   265  			LeagueRoot:    common.Hash{},
   266  			ReceiptsRoot:  common.Hash{},
   267  			TxRoot:        txsroot,
   268  			StateRoot:     sts.GetHashRoot(),
   269  			Timestamp:     uint64(time.Now().Unix()),
   270  		},
   271  		Transactions: txns,
   272  	}
   273  
   274  	return block
   275  }
   276  
   277  func (pool *TxPool) ValidateSyncTxs(txhashes []*common.Hash) error {
   278  
   279  	if pool.pdmgr.pendingTxs == nil || len(pool.pdmgr.pendingTxs) < 1 {
   280  		return errors.ERR_TXPOOL_TXNOTFOUND
   281  	}
   282  
   283  	//for _, v := range txhashes {
   284  	//vtx := pool.queue.Remove(*v)
   285  
   286  	//if vtx == nil {
   287  	//	return errors.ERR_TXPOOL_TXNOTFOUND
   288  	//}
   289  
   290  	//result, err := pool.stateValidator.VerifyTx(vtx)
   291  	//
   292  	//switch result {
   293  	//case -1:
   294  	//	return err
   295  	//case 0:
   296  	//	if uint32(pool.queue.Size()) < pool.maxInQueue {
   297  	//		pool.queue.Enqueue(vtx)
   298  	//	} else {
   299  	//		return errors.ERR_TXPOOL_OUTOFMAX
   300  	//	}
   301  	//	return nil
   302  	//case 1:
   303  	//	pool.pdmgr.addTx(vtx, pool.maxPending)
   304  	//	return nil
   305  	//}
   306  	//}
   307  	return nil
   308  }
   309  
   310  func (pool *TxPool) Execute() *storages.BlockInfo {
   311  	log.Info("func txpool Execute", "targetHeight", pool.stateValidator.TargetHeight)
   312  
   313  	/*for _, tx := range pool.mustPackTxs {
   314  		ret, err := pool.stateValidator.VerifyTx(tx)
   315  		if err != nil {
   316  			log.Error("range pool.mustPackTxs verifyTx error", "ret", ret, "error", err)
   317  		}
   318  	}*/
   319  	objectiveTxs, err := pool.mainRadar.GenerateMainTxs()
   320  	if err != nil {
   321  		log.Error("GenerateMainTxs  failed", "error", err)
   322  	}
   323  	for _, tx := range objectiveTxs {
   324  		if validation.AutoNonceContains(tx.TxType) {
   325  			nonce := validation.AccountNonceInstance.GetAccountNonce(tx.TxData.From)
   326  			tx.TxData.Nonce = nonce + 1
   327  			validation.AccountNonceInstance.SetNonce(tx.TxData.From, nonce+1)
   328  			fmt.Println("🚰 Execute txhash", tx.TxData.LeagueId.ToString())
   329  		}
   330  		ret, err := pool.stateValidator.VerifyTx(tx)
   331  		if err != nil {
   332  			log.Error("range pool.mustPackTxs verifyTx error", "ret", ret, "error", err)
   333  		}
   334  		if ret != 1 {
   335  			fmt.Println("🚰 🚰 🚰 objTx verify failed!!! result:", ret, tx.TxType)
   336  		}
   337  		if tx.TxType == types.ConsensusLeague {
   338  			fmt.Printf("🚰 🚰 🚰  ♋️ leagueId:%s startheight:%d endheight:%d energy:%s blockroot:%s\n",
   339  				tx.TxData.LeagueId.ToString(),
   340  				tx.TxData.StartHeight,
   341  				tx.TxData.EndHeight,
   342  				tx.TxData.Energy.String(),
   343  				tx.TxData.BlockRoot.String())
   344  		}
   345  	}
   346  	return pool.stateValidator.ExecuteOplogs()
   347  
   348  }
   349  
   350  func (pool *TxPool) RemovePendingTxs(hashes []common.Hash) {
   351  	pool.pdmgr.removePendingTxs(hashes)
   352  }
   353  
   354  func NewPendingMgr() *PendingMgr {
   355  	mgr := new(PendingMgr)
   356  	mgr.pendingTxs = make(map[common.Hash]*types.Transaction)
   357  	return mgr
   358  }
   359  
   360  /*
   361  	get txs from pending transaction list
   362  */
   363  func (pm *PendingMgr) getTxs(maxInblock uint32) *types.Transactions {
   364  
   365  	pm.Lock()
   366  	defer pm.Unlock()
   367  	if len(pm.pendingTxs) < 1 {
   368  		return nil
   369  	}
   370  
   371  	txs := make(types.Transactions, 0)
   372  
   373  	for _, v := range pm.pendingTxs {
   374  		txs = append(txs, v)
   375  	}
   376  
   377  	sort.Sort(txs)
   378  
   379  	le := uint32(len(txs))
   380  	if le > maxInblock {
   381  		le = maxInblock
   382  	}
   383  
   384  	ret := txs[0:le]
   385  
   386  	return &ret
   387  }
   388  
   389  /*
   390  	get txs from pending transaction list
   391  */
   392  func (pm *PendingMgr) removePendingTxs(txhashes []common.Hash) {
   393  
   394  	pm.RLock()
   395  	defer pm.RUnlock()
   396  
   397  	if pm.pendingTxs == nil || len(pm.pendingTxs) < 1 {
   398  		return
   399  	}
   400  
   401  	for _, v := range txhashes {
   402  		delete(pm.pendingTxs, v)
   403  	}
   404  
   405  }
   406  
   407  /*
   408  	add tx to pending transaction list
   409  */
   410  func (pm *PendingMgr)   addTx(tx *types.Transaction, maxPending uint32) error {
   411  
   412  	pm.Lock()
   413  	defer pm.Unlock()
   414  
   415  	if uint32(len(pm.pendingTxs)) > maxPending {
   416  		return errors.ERR_TXPOOL_OUTOFMAX
   417  	}
   418  
   419  	pm.pendingTxs[tx.Hash()] = tx
   420  	return nil
   421  }