github.com/turingchain2020/turingchain@v1.1.21/system/mempool/base.go (about) 1 // Copyright Turing Corp. 2018 All Rights Reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package mempool 6 7 import ( 8 "sync" 9 "sync/atomic" 10 "time" 11 12 "github.com/turingchain2020/turingchain/common" 13 log "github.com/turingchain2020/turingchain/common/log/log15" 14 "github.com/turingchain2020/turingchain/queue" 15 "github.com/turingchain2020/turingchain/types" 16 ) 17 18 var mlog = log.New("module", "mempool.base") 19 20 //Mempool mempool 基础类 21 type Mempool struct { 22 proxyMtx sync.Mutex 23 in chan *queue.Message 24 out <-chan *queue.Message 25 client queue.Client 26 header *types.Header 27 sync bool 28 cfg *types.Mempool 29 poolHeader chan struct{} 30 isclose int32 31 wg sync.WaitGroup 32 done chan struct{} 33 removeBlockTicket *time.Ticker 34 cache *txCache 35 } 36 37 //GetSync 判断是否mempool 同步 38 func (mem *Mempool) getSync() bool { 39 mem.proxyMtx.Lock() 40 defer mem.proxyMtx.Unlock() 41 return mem.sync 42 } 43 44 //NewMempool 新建mempool 实例 45 func NewMempool(cfg *types.Mempool) *Mempool { 46 pool := &Mempool{} 47 if cfg.MaxTxNumPerAccount == 0 { 48 cfg.MaxTxNumPerAccount = maxTxNumPerAccount 49 } 50 if cfg.MaxTxLast == 0 { 51 cfg.MaxTxLast = maxTxLast 52 } 53 if cfg.PoolCacheSize == 0 { 54 cfg.PoolCacheSize = poolCacheSize 55 } 56 pool.in = make(chan *queue.Message) 57 pool.out = make(<-chan *queue.Message) 58 pool.done = make(chan struct{}) 59 pool.cfg = cfg 60 pool.poolHeader = make(chan struct{}, 2) 61 pool.removeBlockTicket = time.NewTicker(time.Minute) 62 pool.cache = newCache(cfg.MaxTxNumPerAccount, cfg.MaxTxLast, cfg.PoolCacheSize) 63 return pool 64 } 65 66 //Close 关闭mempool 67 func (mem *Mempool) Close() { 68 if mem.isClose() { 69 return 70 } 71 atomic.StoreInt32(&mem.isclose, 1) 72 close(mem.done) 73 if mem.client != nil { 74 mem.client.Close() 75 } 76 mem.removeBlockTicket.Stop() 77 mlog.Info("mempool module closing") 78 mem.wg.Wait() 79 mlog.Info("mempool module closed") 80 } 81 82 //SetQueueClient 初始化mempool模块 83 func (mem *Mempool) SetQueueClient(client queue.Client) { 84 mem.client = client 85 mem.client.Sub("mempool") 86 mem.wg.Add(1) 87 go mem.pollLastHeader() 88 mem.wg.Add(1) 89 go mem.checkSync() 90 mem.wg.Add(1) 91 go mem.removeBlockedTxs() 92 93 mem.wg.Add(1) 94 go mem.eventProcess() 95 } 96 97 // Size 返回mempool中txCache大小 98 func (mem *Mempool) Size() int { 99 mem.proxyMtx.Lock() 100 defer mem.proxyMtx.Unlock() 101 return mem.cache.Size() 102 } 103 104 // SetMinFee 设置最小交易费用 105 func (mem *Mempool) SetMinFee(fee int64) { 106 mem.proxyMtx.Lock() 107 mem.cfg.MinTxFeeRate = fee 108 mem.proxyMtx.Unlock() 109 } 110 111 //SetQueueCache 设置排队策略 112 func (mem *Mempool) SetQueueCache(qcache QueueCache) { 113 mem.cache.SetQueueCache(qcache) 114 } 115 116 // GetTxList 从txCache中返回给定数目的tx 117 func (mem *Mempool) getTxList(filterList *types.TxHashList) (txs []*types.Transaction) { 118 mem.proxyMtx.Lock() 119 defer mem.proxyMtx.Unlock() 120 count := filterList.GetCount() 121 dupMap := make(map[string]bool) 122 for i := 0; i < len(filterList.GetHashes()); i++ { 123 dupMap[string(filterList.GetHashes()[i])] = true 124 } 125 return mem.filterTxList(count, dupMap, false) 126 } 127 128 func (mem *Mempool) filterTxList(count int64, dupMap map[string]bool, isAll bool) (txs []*types.Transaction) { 129 //mempool中的交易都是未打包的,需要用下一个区块的高度和时间作为交易过期判定 130 height := mem.header.GetHeight() + 1 131 blockTime := mem.header.GetBlockTime() 132 types.AssertConfig(mem.client) 133 cfg := mem.client.GetConfig() 134 //由于mempool可能存在过期交易,先遍历所有,满足目标交易数再退出,否则存在无法获取到实际交易情况 135 mem.cache.Walk(0, func(tx *Item) bool { 136 if len(dupMap) > 0 { 137 if _, ok := dupMap[string(tx.Value.Hash())]; ok { 138 return true 139 } 140 } 141 if isExpired(cfg, tx, height, blockTime) && !isAll { 142 return true 143 } 144 txs = append(txs, tx.Value) 145 //达到设定的交易数,退出循环, count为0获取所有 146 if count > 0 && len(txs) == int(count) { 147 return false 148 } 149 return true 150 }) 151 return txs 152 } 153 154 // RemoveTxs 从mempool中删除给定Hash的txs 155 func (mem *Mempool) RemoveTxs(hashList *types.TxHashList) error { 156 mem.proxyMtx.Lock() 157 defer mem.proxyMtx.Unlock() 158 mem.removeTxs(hashList.Hashes) 159 return nil 160 } 161 162 func (mem *Mempool) removeTxs(hashes [][]byte) { 163 164 for _, hash := range hashes { 165 exist := mem.cache.Exist(string(hash)) 166 if exist { 167 mem.cache.Remove(string(hash)) 168 } 169 } 170 } 171 172 // PushTx 将交易推入mempool,并返回结果(error) 173 func (mem *Mempool) PushTx(tx *types.Transaction) error { 174 mem.proxyMtx.Lock() 175 defer mem.proxyMtx.Unlock() 176 err := mem.cache.Push(tx) 177 return err 178 } 179 180 // setHeader设置mempool.header 181 func (mem *Mempool) setHeader(h *types.Header) { 182 mem.proxyMtx.Lock() 183 mem.header = h 184 mem.proxyMtx.Unlock() 185 } 186 187 // GetHeader 获取Mempool.header 188 func (mem *Mempool) GetHeader() *types.Header { 189 mem.proxyMtx.Lock() 190 defer mem.proxyMtx.Unlock() 191 return mem.header 192 } 193 194 //IsClose 判断是否mempool 关闭 195 func (mem *Mempool) isClose() bool { 196 return atomic.LoadInt32(&mem.isclose) == 1 197 } 198 199 // GetLastHeader 获取LastHeader的height和blockTime 200 func (mem *Mempool) GetLastHeader() (interface{}, error) { 201 if mem.client == nil { 202 panic("client not bind message queue.") 203 } 204 msg := mem.client.NewMessage("blockchain", types.EventGetLastHeader, nil) 205 err := mem.client.Send(msg, true) 206 if err != nil { 207 mlog.Error("blockchain closed", "err", err.Error()) 208 return nil, err 209 } 210 return mem.client.Wait(msg) 211 } 212 213 // GetAccTxs 用来获取对应账户地址(列表)中的全部交易详细信息 214 func (mem *Mempool) GetAccTxs(addrs *types.ReqAddrs) *types.TransactionDetails { 215 mem.proxyMtx.Lock() 216 defer mem.proxyMtx.Unlock() 217 return mem.cache.GetAccTxs(addrs) 218 } 219 220 // TxNumOfAccount 返回账户在mempool中交易数量 221 func (mem *Mempool) TxNumOfAccount(addr string) int64 { 222 mem.proxyMtx.Lock() 223 defer mem.proxyMtx.Unlock() 224 return int64(mem.cache.TxNumOfAccount(addr)) 225 } 226 227 // GetLatestTx 返回最新十条加入到mempool的交易 228 func (mem *Mempool) GetLatestTx() []*types.Transaction { 229 mem.proxyMtx.Lock() 230 defer mem.proxyMtx.Unlock() 231 return mem.cache.GetLatestTx() 232 } 233 234 // GetTotalCacheBytes 获取缓存交易的总占用空间 235 func (mem *Mempool) GetTotalCacheBytes() int64 { 236 mem.proxyMtx.Lock() 237 defer mem.proxyMtx.Unlock() 238 return mem.cache.qcache.GetCacheBytes() 239 } 240 241 // pollLastHeader 在初始化后循环获取LastHeader,直到获取成功后,返回 242 func (mem *Mempool) pollLastHeader() { 243 defer mem.wg.Done() 244 defer func() { 245 mlog.Info("pollLastHeader quit") 246 mem.poolHeader <- struct{}{} 247 }() 248 for { 249 if mem.isClose() { 250 return 251 } 252 lastHeader, err := mem.GetLastHeader() 253 if err != nil { 254 mlog.Error(err.Error()) 255 time.Sleep(time.Second) 256 continue 257 } 258 h := lastHeader.(*queue.Message).Data.(*types.Header) 259 mem.setHeader(h) 260 return 261 } 262 } 263 264 func (mem *Mempool) removeExpired() { 265 mem.proxyMtx.Lock() 266 defer mem.proxyMtx.Unlock() 267 types.AssertConfig(mem.client) 268 //mempool的header是当前高度,而交易将被下一个区块打包,过期判定采用下一个区块的高度和时间 269 mem.cache.removeExpiredTx(mem.client.GetConfig(), mem.header.GetHeight()+1, mem.header.GetBlockTime()) 270 } 271 272 // removeBlockedTxs 每隔1分钟清理一次已打包的交易 273 func (mem *Mempool) removeBlockedTxs() { 274 defer mem.wg.Done() 275 defer mlog.Info("RemoveBlockedTxs quit") 276 if mem.client == nil { 277 panic("client not bind message queue.") 278 } 279 for { 280 select { 281 case <-mem.removeBlockTicket.C: 282 if mem.isClose() { 283 return 284 } 285 mem.removeExpired() 286 case <-mem.done: 287 return 288 } 289 } 290 } 291 292 // RemoveTxsOfBlock 移除mempool中已被Blockchain打包的tx 293 func (mem *Mempool) RemoveTxsOfBlock(block *types.Block) bool { 294 mem.proxyMtx.Lock() 295 defer mem.proxyMtx.Unlock() 296 for _, tx := range block.Txs { 297 hash := tx.Hash() 298 exist := mem.cache.Exist(string(hash)) 299 if exist { 300 mem.cache.Remove(string(hash)) 301 } 302 } 303 return true 304 } 305 func (mem *Mempool) getCacheFeeRate() int64 { 306 if mem.cache.qcache == nil { 307 return 0 308 } 309 feeRate := mem.cache.qcache.GetProperFee() 310 311 //控制精度 312 unitFee := mem.cfg.MinTxFeeRate 313 if unitFee != 0 && feeRate%unitFee > 0 { 314 feeRate = (feeRate/unitFee + 1) * unitFee 315 } 316 if feeRate > mem.cfg.MaxTxFeeRate { 317 feeRate = mem.cfg.MaxTxFeeRate 318 } 319 return feeRate 320 } 321 322 // GetProperFeeRate 获取合适的手续费率 323 func (mem *Mempool) GetProperFeeRate(req *types.ReqProperFee) int64 { 324 if req == nil || req.TxCount == 0 { 325 req = &types.ReqProperFee{TxCount: 20} 326 } 327 if req.TxSize == 0 { 328 req.TxSize = 10240 329 } 330 feeRate := mem.getCacheFeeRate() 331 if mem.cfg.IsLevelFee { 332 levelFeeRate := mem.getLevelFeeRate(mem.cfg.MinTxFeeRate, req.TxCount, req.TxSize) 333 if levelFeeRate > feeRate { 334 feeRate = levelFeeRate 335 } 336 } 337 return feeRate 338 } 339 340 // getLevelFeeRate 获取合适的阶梯手续费率, 可以外部传入count, size进行前瞻性估计 341 func (mem *Mempool) getLevelFeeRate(baseFeeRate int64, appendCount, appendSize int32) int64 { 342 var feeRate int64 343 sumByte := mem.GetTotalCacheBytes() + int64(appendSize) 344 types.AssertConfig(mem.client) 345 cfg := mem.client.GetConfig() 346 maxTxNumber := cfg.GetP(mem.Height()).MaxTxNumber 347 memSize := mem.Size() 348 switch { 349 case sumByte >= int64(types.MaxBlockSize/20) || int64(memSize+int(appendCount)) >= maxTxNumber/2: 350 feeRate = 100 * baseFeeRate 351 case sumByte >= int64(types.MaxBlockSize/100) || int64(memSize+int(appendCount)) >= maxTxNumber/10: 352 feeRate = 10 * baseFeeRate 353 default: 354 feeRate = baseFeeRate 355 } 356 if feeRate > mem.cfg.MaxTxFeeRate { 357 feeRate = mem.cfg.MaxTxFeeRate 358 } 359 return feeRate 360 } 361 362 // Mempool.DelBlock将回退的区块内的交易重新加入mempool中 363 func (mem *Mempool) delBlock(block *types.Block) { 364 if len(block.Txs) <= 0 { 365 return 366 } 367 blkTxs := block.Txs 368 header := mem.GetHeader() 369 types.AssertConfig(mem.client) 370 cfg := mem.client.GetConfig() 371 for i := 0; i < len(blkTxs); i++ { 372 tx := blkTxs[i] 373 //当前包括ticket和平行链的第一笔挖矿交易,统一actionName为miner 374 if i == 0 && tx.ActionName() == types.MinerAction { 375 continue 376 } 377 groupCount := int(tx.GetGroupCount()) 378 if groupCount > 1 && i+groupCount <= len(blkTxs) { 379 group := types.Transactions{Txs: blkTxs[i : i+groupCount]} 380 tx = group.Tx() 381 i = i + groupCount - 1 382 } 383 err := tx.Check(cfg, header.GetHeight(), mem.cfg.MinTxFeeRate, mem.cfg.MaxTxFee) 384 if err != nil { 385 continue 386 } 387 if !mem.checkExpireValid(tx) { 388 continue 389 } 390 err = mem.PushTx(tx) 391 if err != nil { 392 mlog.Error("mem", "push tx err", err) 393 } 394 } 395 } 396 397 // Height 获取区块高度 398 func (mem *Mempool) Height() int64 { 399 mem.proxyMtx.Lock() 400 defer mem.proxyMtx.Unlock() 401 if mem.header == nil { 402 return -1 403 } 404 return mem.header.GetHeight() 405 } 406 407 // Wait wait mempool ready 408 func (mem *Mempool) Wait() { 409 <-mem.poolHeader 410 //wait sync 411 <-mem.poolHeader 412 } 413 414 // SendTxToP2P 向"p2p"发送消息 415 func (mem *Mempool) sendTxToP2P(tx *types.Transaction) { 416 if mem.client == nil { 417 panic("client not bind message queue.") 418 } 419 msg := mem.client.NewMessage("p2p", types.EventTxBroadcast, tx) 420 err := mem.client.Send(msg, false) 421 if err != nil { 422 mlog.Error("tx sent to p2p", "tx.Hash", common.ToHex(tx.Hash())) 423 return 424 } 425 //mlog.Debug("tx sent to p2p", "tx.Hash", common.ToHex(tx.Hash())) 426 } 427 428 // Mempool.checkSync检查并获取mempool同步状态 429 func (mem *Mempool) checkSync() { 430 defer func() { 431 mlog.Info("getsync quit") 432 mem.poolHeader <- struct{}{} 433 }() 434 defer mem.wg.Done() 435 if mem.getSync() { 436 return 437 } 438 if mem.cfg.ForceAccept { 439 mem.setSync(true) 440 } 441 for { 442 if mem.isClose() { 443 return 444 } 445 if mem.client == nil { 446 panic("client not bind message queue.") 447 } 448 msg := mem.client.NewMessage("blockchain", types.EventIsSync, nil) 449 err := mem.client.Send(msg, true) 450 if err != nil { 451 time.Sleep(time.Second) 452 continue 453 } 454 resp, err := mem.client.Wait(msg) 455 if err != nil { 456 time.Sleep(time.Second) 457 continue 458 } 459 if resp.GetData().(*types.IsCaughtUp).GetIscaughtup() { 460 mem.setSync(true) 461 return 462 } 463 time.Sleep(time.Second) 464 continue 465 } 466 } 467 468 func (mem *Mempool) setSync(status bool) { 469 mem.proxyMtx.Lock() 470 mem.sync = status 471 mem.proxyMtx.Unlock() 472 } 473 474 // getTxListByHash 从qcache或者SHashTxCache中获取hash对应的tx交易列表 475 func (mem *Mempool) getTxListByHash(hashList *types.ReqTxHashList) *types.ReplyTxList { 476 mem.proxyMtx.Lock() 477 defer mem.proxyMtx.Unlock() 478 479 var replyTxList types.ReplyTxList 480 481 //通过短hash来获取tx交易 482 if hashList.GetIsShortHash() { 483 for _, sHash := range hashList.GetHashes() { 484 tx := mem.cache.GetSHashTxCache(sHash) 485 replyTxList.Txs = append(replyTxList.Txs, tx) 486 } 487 return &replyTxList 488 } 489 //通过hash来获取tx交易 490 for _, hash := range hashList.GetHashes() { 491 tx := mem.cache.getTxByHash(hash) 492 replyTxList.Txs = append(replyTxList.Txs, tx) 493 } 494 return &replyTxList 495 }