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

     1  package orgchain
     2  
     3  import (
     4  	"fmt"
     5  	"sort"
     6  	"sync"
     7  	"time"
     8  
     9  	"github.com/sixexorg/magnetic-ring/bactor"
    10  	orgcommon "github.com/sixexorg/magnetic-ring/p2pserver/common"
    11  
    12  	"github.com/ontio/ontology-eventbus/actor"
    13  	"github.com/sixexorg/magnetic-ring/log"
    14  
    15  	"github.com/sixexorg/magnetic-ring/config"
    16  	"github.com/sixexorg/magnetic-ring/store/orgchain/storages"
    17  
    18  	"github.com/sixexorg/magnetic-ring/common"
    19  	"github.com/sixexorg/magnetic-ring/core/orgchain/types"
    20  	"github.com/sixexorg/magnetic-ring/errors"
    21  	"github.com/sixexorg/magnetic-ring/store/orgchain/states"
    22  	"github.com/sixexorg/magnetic-ring/store/orgchain/validation"
    23  	"github.com/sixexorg/magnetic-ring/store/storelaw"
    24  )
    25  
    26  type SubPool struct {
    27  	pdmgr *PendingMgr //Maintain a collection of transactions that can be packaged
    28  	//queue *SubTxQueue //Maintain a collection of transactions transmitted over the network
    29  	txChan       chan *types.Transaction
    30  	maxPending   uint32
    31  	maxInPending uint32
    32  	maxInQueue   uint32
    33  	leagueId     common.Address
    34  
    35  	waitTxNum map[common.Hash]uint8
    36  	waitPool  types.Transactions
    37  
    38  	stateValidator *validation.StateValidate
    39  
    40  	txpoolPid   *actor.PID
    41  	mustPackTxs []*types.Transaction
    42  }
    43  
    44  func (pool *SubPool) Start() {
    45  	go func() {
    46  		for {
    47  			select {
    48  			case tx := <-pool.txChan:
    49  				fmt.Println("♦️ subTxpool add")
    50  				err := pool.AddTx(pool.leagueId, tx)
    51  				if err != nil {
    52  					log.Error("addtx error", "tx_pool", err)
    53  				}
    54  			}
    55  		}
    56  	}()
    57  }
    58  
    59  func startActor(obj interface{}, id string) (*actor.PID, error) {
    60  	props := actor.FromProducer(func() actor.Actor {
    61  		return obj.(actor.Actor)
    62  	})
    63  
    64  	pid, _ := actor.SpawnNamed(props, id)
    65  	if pid == nil {
    66  		return nil, fmt.Errorf("fail to start actor at props:%v id:%s", props, id)
    67  	}
    68  	return pid, nil
    69  }
    70  
    71  func NewSubPool(ledger *storages.LedgerStoreImp, leadgeId common.Address) *SubPool {
    72  	pool := new(SubPool)
    73  	pool.pdmgr = NewPendingMgr()
    74  	//pool.queue = NewSubTxQueue()
    75  	pool.maxPending = config.GlobalConfig.TxPoolCfg.MaxPending
    76  	pool.maxInPending = config.GlobalConfig.TxPoolCfg.MaxInPending
    77  	pool.maxInQueue = config.GlobalConfig.TxPoolCfg.MaxInQueue
    78  	pool.txChan = make(chan *types.Transaction, pool.maxInQueue)
    79  	pool.leagueId = leadgeId
    80  
    81  	pool.waitPool = make(types.Transactions, 0, 10000)
    82  	pool.waitTxNum = make(map[common.Hash]uint8, 10000)
    83  
    84  	pool.RefreshValidator(ledger, leadgeId)
    85  	pool.mustPackTxs = make([]*types.Transaction, 0)
    86  	poolActor := NewTxActor(pool)
    87  
    88  	pid, err := startActor(poolActor, "subtxpoolAcotor")
    89  	if err != nil {
    90  		return nil
    91  	}
    92  
    93  	pool.txpoolPid = pid
    94  
    95  	pool.Start()
    96  	return pool
    97  }
    98  
    99  func (pool *SubPool) AppendMustPackTx(txs ...*types.Transaction) {
   100  
   101  	for _, tx := range txs {
   102  		pool.mustPackTxs = append(pool.mustPackTxs, tx)
   103  	}
   104  
   105  }
   106  
   107  func (pool *SubPool) refreshWaitPool() {
   108  	if pool.waitPool.Len() > 0 {
   109  		for wp := range pool.waitPool {
   110  			pool.TxEnqueue(pool.waitPool[wp])
   111  		}
   112  	}
   113  	pool.waitPool = make(types.Transactions, 0, 10000)
   114  	pool.waitTxNum = make(map[common.Hash]uint8, 10000)
   115  }
   116  
   117  func (pool *SubPool) RefreshValidator(ledger *storages.LedgerStoreImp, leadgeId common.Address) {
   118  	if pool.stateValidator != nil {
   119  		fmt.Println("🚰 refreshValidator txlen", pool.stateValidator.GetTxLen())
   120  	}
   121  	oldSV := pool.stateValidator
   122  	pool.stateValidator = validation.NewStateValidate(ledger, leadgeId)
   123  	if oldSV != nil {
   124  		txch := oldSV.TxInheritance()
   125  		for ch := range txch {
   126  			pool.TxEnqueue(ch)
   127  		}
   128  	}
   129  	pool.refreshWaitPool()
   130  	//log.Info("func txpool RefreshValidator 02", "newTargetHeight", pool.stateValidator.TargetHeight, "txlen", pool.stateValidator.GetTxLen())
   131  	fmt.Println("func txpool RefreshValidator 02 ", "newTargetHeight=", pool.stateValidator.TargetHeight, " txlen=", pool.stateValidator.GetTxLen())
   132  }
   133  
   134  func (pool *SubPool) AddTx(leagueId common.Address, tx *types.Transaction) error {
   135  	fmt.Println("⭕️ txpool addtx 1 type:", tx.TxType)
   136  	result, err := pool.stateValidator.VerifyTx(tx)
   137  	txHash := tx.Hash()
   138  	fmt.Println("⭕️ txpool addtx 2", result, err)
   139  	if result == 1 || result == 0 {
   140  		orgTx := orgcommon.OrgTx{
   141  			OrgId: pool.leagueId,
   142  			Tx:    tx,
   143  		}
   144  		P2PPid, err := bactor.GetActorPid(bactor.P2PACTOR)
   145  		if err != nil {
   146  			log.Error("tx_pool.go get p2ppid error", "error", err)
   147  		} else {
   148  			P2PPid.Tell(orgTx)
   149  		}
   150  	}
   151  	fmt.Println("⭕️ txpool addtx 3", result, err)
   152  	switch result {
   153  	case -1:
   154  		return err
   155  	case 0:
   156  		if uint32(len(pool.txChan)) < pool.maxInQueue {
   157  
   158  			pool.waitTxNum[txHash]++
   159  			if uint32(pool.waitTxNum[txHash]) == config.GlobalConfig.TxPoolCfg.MaxTxInPool {
   160  				pool.waitPool = append(pool.waitPool, tx)
   161  			} else if uint32(pool.waitTxNum[txHash]) < config.GlobalConfig.TxPoolCfg.MaxTxInPool {
   162  				pool.TxEnqueue(tx)
   163  			}
   164  
   165  		} else {
   166  			return errors.ERR_TXPOOL_OUTOFMAX
   167  		}
   168  		return nil
   169  	case 1:
   170  		pool.pdmgr.addTx(tx, pool.maxPending)
   171  		return nil
   172  	}
   173  
   174  	return nil
   175  }
   176  
   177  /**
   178  generate block
   179  */
   180  func (pool *SubPool) GenerateBlock(leagueId common.Address, height uint64, packtx bool) *types.Block {
   181  
   182  	sts := states.AccountStates{}
   183  	var txs *types.Transactions
   184  	if packtx {
   185  		txs = pool.pdmgr.getTxs(pool.maxPending)
   186  		sort.Sort(txs)
   187  	}
   188  
   189  	block := &types.Block{
   190  		Header: &types.Header{
   191  			Height:        pool.stateValidator.TargetHeight,
   192  			Version:       types.TxVersion,
   193  			PrevBlockHash: common.Hash{},
   194  			ReceiptsRoot:  common.Hash{},
   195  			StateRoot:     sts.GetHashRoot(),
   196  			TxRoot:        txs.GetHashRoot(),
   197  			Timestamp:     uint64(time.Now().Unix()),
   198  		},
   199  		Transactions: *txs,
   200  	}
   201  
   202  	//reset validator
   203  	//pool.RefreshValidator()
   204  	return block
   205  }
   206  
   207  /**
   208  func (pool *SubPool) ValidateSyncTxs(leagueId common.Address, txhashes []*common.Hash) error {
   209  
   210  	if pool.pdmgr.pendingTxs == nil || len(pool.pdmgr.pendingTxs) < 1 {
   211  		return errors.ERR_TXPOOL_TXNOTFOUND
   212  	}
   213  
   214  	for _, v := range txhashes {
   215  		vtx := pool.queue.Remove(*v)
   216  
   217  		if vtx == nil {
   218  			return errors.ERR_TXPOOL_TXNOTFOUND
   219  		}
   220  
   221  		result, err := pool.stateValidator.VerifyTx(vtx)
   222  		switch result {
   223  		case -1:
   224  			return err
   225  		case 0:
   226  			if uint32(pool.queue.Size()) < pool.maxInQueue {
   227  				pool.queue.Enqueue(vtx)
   228  			} else {
   229  				return errors.ERR_TXPOOL_OUTOFMAX
   230  			}
   231  			return nil
   232  		case 1:
   233  			pool.pdmgr.addTx(vtx, pool.maxPending)
   234  			return nil
   235  		}
   236  	}
   237  	return nil
   238  }
   239  **/
   240  func (pool *SubPool) Execute() (blkInfo *storelaw.OrgBlockInfo) {
   241  	//fmt.Println("⭕️ subtxpool execute txlen", pool.stateValidator.GetTxLen())
   242  
   243  	for _, tx := range pool.mustPackTxs {
   244  		ret, err := pool.stateValidator.VerifyTx(tx)
   245  		if err != nil {
   246  			log.Error("range pool.mustPackTxs verifyTx error", "ret", ret, "error", err)
   247  		}
   248  	}
   249  
   250  	return pool.stateValidator.ExecuteOplogs()
   251  }
   252  
   253  type PendingMgr struct {
   254  	sync.RWMutex
   255  	pendingTxs map[common.Hash]*types.Transaction
   256  }
   257  
   258  func NewPendingMgr() *PendingMgr {
   259  	mgr := new(PendingMgr)
   260  	mgr.pendingTxs = make(map[common.Hash]*types.Transaction)
   261  	return mgr
   262  }
   263  
   264  /*
   265  	get txs from pending transaction list
   266  */
   267  func (pm *PendingMgr) getTxs(maxInblock uint32) *types.Transactions {
   268  
   269  	pm.Lock()
   270  	defer pm.Unlock()
   271  	if len(pm.pendingTxs) < 1 {
   272  		return nil
   273  	}
   274  
   275  	txs := make(types.Transactions, 0)
   276  
   277  	for _, v := range pm.pendingTxs {
   278  		txs = append(txs, v)
   279  	}
   280  
   281  	sort.Sort(txs)
   282  
   283  	le := uint32(len(txs))
   284  	if le > maxInblock {
   285  		le = maxInblock
   286  	}
   287  
   288  	ret := txs[0:le]
   289  
   290  	return &ret
   291  }
   292  
   293  func (pool *SubPool) RemovePendingTxs(hashes []common.Hash) {
   294  	pool.pdmgr.removePendingTxs(hashes)
   295  }
   296  
   297  /*
   298  	get txs from pending transaction list
   299  */
   300  func (pm *PendingMgr) removePendingTxs(txhashes []common.Hash) {
   301  
   302  	pm.Lock()
   303  	defer pm.Unlock()
   304  
   305  	if pm.pendingTxs == nil || len(pm.pendingTxs) < 1 {
   306  		return
   307  	}
   308  
   309  	for _, v := range txhashes {
   310  		delete(pm.pendingTxs, v)
   311  	}
   312  
   313  }
   314  
   315  /*
   316  	add tx to pending transaction list
   317  */
   318  func (pm *PendingMgr) addTx(tx *types.Transaction, maxPending uint32) error {
   319  
   320  	pm.Lock()
   321  	defer pm.Unlock()
   322  
   323  	if uint32(len(pm.pendingTxs)) > maxPending {
   324  		return errors.ERR_TXPOOL_OUTOFMAX
   325  	}
   326  
   327  	pm.pendingTxs[tx.Hash()] = tx
   328  	return nil
   329  }
   330  
   331  func (pool *SubPool) TxEnqueue(tx *types.Transaction) error {
   332  
   333  	if uint32(len(pool.txChan)) >= pool.maxInQueue {
   334  		return errors.ERR_TXPOOL_OUTOFMAX
   335  	}
   336  	fmt.Println("🌈 🌈  insert tx into subTxpool")
   337  	pool.txChan <- tx
   338  
   339  	return nil
   340  }
   341  
   342  func (pool *SubPool) GetTxpoolPID() *actor.PID {
   343  	return pool.txpoolPid
   344  }