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 }