github.com/aergoio/aergo@v1.3.1/mempool/mempool.go (about)

     1  /**
     2   *  @file
     3   *  @copyright defined in aergo/LICENSE.txt
     4   */
     5  
     6  package mempool
     7  
     8  import (
     9  	"bufio"
    10  	"bytes"
    11  	"encoding/binary"
    12  	"io"
    13  	"math/big"
    14  	"os"
    15  	"sync"
    16  	"sync/atomic"
    17  	"time"
    18  
    19  	"github.com/aergoio/aergo-actor/actor"
    20  	"github.com/aergoio/aergo-actor/router"
    21  	"github.com/aergoio/aergo-lib/log"
    22  	"github.com/aergoio/aergo/account/key"
    23  	"github.com/aergoio/aergo/chain"
    24  	cfg "github.com/aergoio/aergo/config"
    25  	"github.com/aergoio/aergo/contract/enterprise"
    26  	"github.com/aergoio/aergo/contract/name"
    27  	"github.com/aergoio/aergo/contract/system"
    28  	"github.com/aergoio/aergo/fee"
    29  	"github.com/aergoio/aergo/internal/common"
    30  	"github.com/aergoio/aergo/internal/enc"
    31  	"github.com/aergoio/aergo/message"
    32  	"github.com/aergoio/aergo/pkg/component"
    33  	"github.com/aergoio/aergo/state"
    34  	"github.com/aergoio/aergo/types"
    35  	"github.com/golang/protobuf/proto"
    36  )
    37  
    38  const (
    39  	initial = iota
    40  	loading = iota
    41  	running = iota
    42  )
    43  
    44  var (
    45  	evictInterval  = time.Minute
    46  	evictPeriod    = time.Hour * types.DefaultEvictPeriod
    47  	metricInterval = time.Second
    48  )
    49  
    50  // MemPool is main structure of mempool service
    51  type MemPool struct {
    52  	*component.BaseComponent
    53  
    54  	sync.RWMutex
    55  	cfg *cfg.Config
    56  
    57  	sdb         *state.ChainStateDB
    58  	bestBlockID types.BlockID
    59  	bestBlockNo types.BlockNo
    60  	stateDB     *state.StateDB
    61  	verifier    *actor.PID
    62  	orphan      int
    63  	//cache       map[types.TxID]types.Transaction
    64  	cache       sync.Map
    65  	length      int
    66  	pool        map[types.AccountID]*TxList
    67  	dumpPath    string
    68  	status      int32
    69  	coinbasefee *big.Int
    70  	chainIdHash []byte
    71  	isPublic    bool
    72  	whitelist   *whitelistConf
    73  	// followings are for test
    74  	testConfig bool
    75  	deadtx     int
    76  
    77  	quit chan bool
    78  	wg   sync.WaitGroup // wait for internal loop
    79  }
    80  
    81  // NewMemPoolService create and return new MemPool
    82  func NewMemPoolService(cfg *cfg.Config, cs *chain.ChainService) *MemPool {
    83  
    84  	var sdb *state.ChainStateDB
    85  	if cs != nil {
    86  		sdb = cs.SDB()
    87  	} else { // Test
    88  		fee.EnableZeroFee()
    89  	}
    90  
    91  	actor := &MemPool{
    92  		cfg: cfg,
    93  		sdb: sdb,
    94  		//cache:    map[types.TxID]types.Transaction{},
    95  		cache:    sync.Map{},
    96  		pool:     map[types.AccountID]*TxList{},
    97  		dumpPath: cfg.Mempool.DumpFilePath,
    98  		status:   initial,
    99  		verifier: nil,
   100  		quit:     make(chan bool),
   101  	}
   102  	actor.BaseComponent = component.NewBaseComponent(message.MemPoolSvc, actor, log.NewLogger("mempool"))
   103  
   104  	if cfg.Mempool.FadeoutPeriod > 0 {
   105  		evictPeriod = time.Duration(cfg.Mempool.FadeoutPeriod) * time.Hour
   106  	}
   107  	return actor
   108  }
   109  
   110  // Start runs mempool servivce
   111  func (mp *MemPool) BeforeStart() {
   112  	if mp.testConfig {
   113  		initStubData()
   114  		mp.bestBlockID = getCurrentBestBlockNoMock()
   115  	}
   116  	//mp.Info("mempool start on: current Block :", mp.curBestBlockNo)
   117  }
   118  
   119  func (mp *MemPool) AfterStart() {
   120  
   121  	mp.Info().Bool("showmetric", mp.cfg.Mempool.ShowMetrics).
   122  		Bool("fadeout", mp.cfg.Mempool.EnableFadeout).
   123  		Str("evict period", evictPeriod.String()).
   124  		Int("number of verifier", mp.cfg.Mempool.VerifierNumber).
   125  		Msg("mempool init")
   126  
   127  	mp.verifier = actor.Spawn(router.NewRoundRobinPool(mp.cfg.Mempool.VerifierNumber).
   128  		WithInstance(NewTxVerifier(mp)))
   129  
   130  	rsp, err := mp.RequestToFuture(message.ChainSvc, &message.GetBestBlock{}, time.Second*2).Result()
   131  	if err != nil {
   132  		mp.Error().Err(err).Msg("failed to get best block")
   133  		panic("Mempool AfterStart Failed")
   134  	}
   135  	bestblock := rsp.(message.GetBestBlockRsp).Block
   136  	mp.setStateDB(bestblock) // nolint: errcheck
   137  
   138  	mp.wg.Add(1)
   139  	go mp.monitor()
   140  }
   141  
   142  // Stop handles clean-up for mempool service
   143  func (mp *MemPool) BeforeStop() {
   144  	if mp.verifier != nil {
   145  		mp.verifier.GracefulStop()
   146  	}
   147  	mp.dumpTxsToFile()
   148  	mp.quit <- true
   149  	mp.wg.Wait()
   150  }
   151  
   152  func (mp *MemPool) monitor() {
   153  	defer mp.wg.Done()
   154  
   155  	evict := time.NewTicker(evictInterval)
   156  	defer evict.Stop()
   157  
   158  	showmetric := time.NewTicker(metricInterval)
   159  	defer showmetric.Stop()
   160  
   161  	for {
   162  		select {
   163  		// Log current counts on mempool
   164  		case <-showmetric.C:
   165  			if mp.cfg.Mempool.ShowMetrics {
   166  				l, o := mp.Size()
   167  				mp.Info().Int("len", l).Int("orphan", o).Int("acc", len(mp.pool)).Msg("mempool metrics")
   168  			}
   169  			// Evict old enough transactions
   170  		case <-evict.C:
   171  			if mp.cfg.Mempool.EnableFadeout {
   172  				mp.evictTransactions()
   173  			}
   174  
   175  			// Graceful quit
   176  		case <-mp.quit:
   177  			return
   178  		}
   179  	}
   180  
   181  }
   182  
   183  func (mp *MemPool) evictTransactions() {
   184  	mp.Lock()
   185  	defer mp.Unlock()
   186  
   187  	total := 0
   188  	for acc, list := range mp.pool {
   189  		if time.Since(list.GetLastModifiedTime()) < evictPeriod {
   190  			continue
   191  		}
   192  		txs := list.GetAll()
   193  		total += len(txs)
   194  		orphan := len(txs) - list.Len()
   195  
   196  		for _, tx := range txs {
   197  			mp.cache.Delete(types.ToTxID(tx.GetHash()))
   198  			mp.length--
   199  		}
   200  
   201  		mp.orphan -= orphan
   202  		delete(mp.pool, acc)
   203  	}
   204  	if total > 0 {
   205  		mp.Info().Int("num", total).Msg("evict transactions")
   206  	}
   207  }
   208  
   209  // Size returns current maintaining number of transactions
   210  // and number of orphan transaction
   211  func (mp *MemPool) Size() (int, int) {
   212  	return mp.length, mp.orphan
   213  }
   214  
   215  // Receive handles requested messages from other services
   216  func (mp *MemPool) Receive(context actor.Context) {
   217  
   218  	switch msg := context.Message().(type) {
   219  	case *message.MemPoolPut:
   220  		mp.verifier.Request(msg.Tx, context.Sender())
   221  	case *message.MemPoolGet:
   222  		txs, err := mp.get(msg.MaxBlockBodySize)
   223  		context.Respond(&message.MemPoolGetRsp{
   224  			Txs: txs,
   225  			Err: err,
   226  		})
   227  	case *message.MemPoolDel:
   228  		errs := mp.removeOnBlockArrival(msg.Block)
   229  		context.Respond(&message.MemPoolDelRsp{
   230  			Err: errs,
   231  		})
   232  	case *message.MemPoolExist:
   233  		tx := mp.exist(msg.Hash)
   234  		context.Respond(&message.MemPoolExistRsp{
   235  			Tx: tx,
   236  		})
   237  	case *message.MemPoolExistEx:
   238  		txsnum, _ := mp.Size()
   239  		var bucketHash []types.TxHash
   240  		bucketHash = msg.Hashes
   241  		mp.Debug().Int("len", len(bucketHash)).Int("cached", txsnum).Msg("mempool existEx")
   242  
   243  		txs := mp.existEx(bucketHash)
   244  		context.Respond(&message.MemPoolExistExRsp{Txs: txs})
   245  
   246  	case *message.MemPoolSetWhitelist:
   247  		mp.whitelist.SetWhitelist(msg.Accounts)
   248  	case *message.MemPoolEnableWhitelist:
   249  		mp.whitelist.Enable(msg.On)
   250  
   251  	case *actor.Started:
   252  		mp.loadTxs() // FIXME :work-around for actor settled
   253  
   254  	default:
   255  		//mp.Debug().Str("type", reflect.TypeOf(msg).String()).Msg("unhandled message")
   256  	}
   257  }
   258  
   259  func (mp *MemPool) Statistics() *map[string]interface{} {
   260  	ret := map[string]interface{}{
   261  		"total":  mp.length,
   262  		"orphan": mp.orphan,
   263  		"dead":   mp.deadtx,
   264  		"config": mp.cfg.Mempool,
   265  	}
   266  	if !mp.isPublic {
   267  		ret["whitelist"] = mp.whitelist.GetWhitelist()
   268  		ret["whitelist_on"] = mp.whitelist.GetOn()
   269  	}
   270  	return &ret
   271  }
   272  
   273  func (mp *MemPool) get(maxBlockBodySize uint32) ([]types.Transaction, error) {
   274  	start := time.Now()
   275  	mp.RLock()
   276  	defer mp.RUnlock()
   277  	count := 0
   278  	size := 0
   279  	txs := make([]types.Transaction, 0)
   280  Gather:
   281  	for _, list := range mp.pool {
   282  		for _, tx := range list.Get() {
   283  			if size += proto.Size(tx.GetTx()); uint32(size) > maxBlockBodySize {
   284  				break Gather
   285  			}
   286  			txs = append(txs, tx)
   287  			count++
   288  		}
   289  	}
   290  	elapsed := time.Since(start)
   291  	mp.Debug().Str("elapsed", elapsed.String()).Int("len", mp.length).Int("orphan", mp.orphan).Int("count", count).Msg("total tx returned")
   292  	return txs, nil
   293  }
   294  
   295  // check existence.
   296  // validate
   297  // add pool if possible, else pendings
   298  func (mp *MemPool) put(tx types.Transaction) error {
   299  	id := types.ToTxID(tx.GetHash())
   300  	acc := tx.GetBody().GetAccount()
   301  	if tx.HasVerifedAccount() {
   302  		acc = tx.GetVerifedAccount()
   303  	}
   304  
   305  	if _, ok := mp.cache.Load(id); ok {
   306  		return types.ErrTxAlreadyInMempool
   307  	}
   308  	/*
   309  		err := mp.verifyTx(tx)
   310  		if err != nil {
   311  			return err
   312  		}
   313  	*/
   314  	err := mp.validateTx(tx, acc)
   315  	if err != nil && err != types.ErrTxNonceToohigh {
   316  		return err
   317  	}
   318  	mp.Lock()
   319  	defer mp.Unlock()
   320  
   321  	list, err := mp.acquireMemPoolList(acc)
   322  	if err != nil {
   323  		return err
   324  	}
   325  	defer mp.releaseMemPoolList(list)
   326  	diff, err := list.Put(tx)
   327  	if err != nil {
   328  		mp.Error().Err(err).Msg("fail to put at a mempool list")
   329  		return err
   330  	}
   331  
   332  	mp.orphan -= diff
   333  	mp.cache.Store(id, tx)
   334  	mp.length++
   335  	//mp.Debug().Str("tx_hash", enc.ToString(tx.GetHash())).Msgf("tx add-ed size(%d, %d)", len(mp.cache), mp.orphan)
   336  
   337  	if !mp.testConfig {
   338  		mp.notifyNewTx(tx)
   339  	}
   340  	return nil
   341  }
   342  func (mp *MemPool) puts(txs ...types.Transaction) []error {
   343  	errs := make([]error, len(txs))
   344  	for i, tx := range txs {
   345  		errs[i] = mp.put(tx)
   346  	}
   347  	return errs
   348  }
   349  
   350  func (mp *MemPool) setStateDB(block *types.Block) bool {
   351  	if mp.testConfig {
   352  		return true
   353  	}
   354  
   355  	newBlockID := types.ToBlockID(block.BlockHash())
   356  	parentBlockID := types.ToBlockID(block.GetHeader().GetPrevBlockHash())
   357  	normal := true
   358  
   359  	if types.HashID(newBlockID).Compare(types.HashID(mp.bestBlockID)) != 0 {
   360  		if types.HashID(parentBlockID).Compare(types.HashID(mp.bestBlockID)) != 0 {
   361  			normal = false
   362  		}
   363  		mp.bestBlockID = newBlockID
   364  		mp.bestBlockNo = block.GetHeader().GetBlockNo()
   365  		stateRoot := block.GetHeader().GetBlocksRootHash()
   366  		if mp.stateDB == nil {
   367  			mp.stateDB = mp.sdb.OpenNewStateDB(stateRoot)
   368  			cid := types.NewChainID()
   369  			if err := cid.Read(block.GetHeader().GetChainID()); err != nil {
   370  				mp.Error().Err(err).Msg("failed to read chain ID")
   371  			} else {
   372  				mp.isPublic = cid.PublicNet
   373  				if !mp.isPublic {
   374  					conf, err := enterprise.GetConf(mp.stateDB, enterprise.AccountWhite)
   375  					if err != nil {
   376  						mp.Warn().Err(err).Msg("failed to init whitelist")
   377  					}
   378  					mp.whitelist = newWhitelistConf(mp, conf.GetValues(), conf.GetOn())
   379  				}
   380  			}
   381  			mp.chainIdHash = common.Hasher(block.GetHeader().GetChainID())
   382  			mp.Debug().Str("Hash", newBlockID.String()).
   383  				Str("StateRoot", types.ToHashID(stateRoot).String()).
   384  				Str("chainidhash", enc.ToString(mp.chainIdHash)).
   385  				Msg("new StateDB opened")
   386  		} else if !bytes.Equal(mp.stateDB.GetRoot(), stateRoot) {
   387  			if err := mp.stateDB.SetRoot(stateRoot); err != nil {
   388  				mp.Error().Err(err).Msg("failed to set root of StateDB")
   389  			}
   390  		}
   391  	}
   392  	return normal
   393  }
   394  
   395  // input tx based ? or pool based?
   396  // concurrency consideration,
   397  func (mp *MemPool) removeOnBlockArrival(block *types.Block) error {
   398  	var ag [2]time.Duration
   399  	start := time.Now()
   400  	mp.Lock()
   401  	defer mp.Unlock()
   402  
   403  	check := 0
   404  	all := false
   405  	dirty := map[types.AccountID]bool{}
   406  
   407  	if !mp.setStateDB(block) {
   408  		all = true
   409  		mp.Debug().Int("cnt", len(mp.pool)).Msg("going to check all account's state")
   410  	} else {
   411  		for _, tx := range block.GetBody().GetTxs() {
   412  			account := tx.GetBody().GetAccount()
   413  			recipient := tx.GetBody().GetRecipient()
   414  			if tx.HasNameAccount() {
   415  				account = mp.getAddress(account)
   416  			}
   417  			if tx.HasNameRecipient() {
   418  				recipient = mp.getAddress(recipient)
   419  			}
   420  			dirty[types.ToAccountID(account)] = true
   421  			dirty[types.ToAccountID(recipient)] = true
   422  		}
   423  	}
   424  
   425  	ag[0] = time.Since(start)
   426  	start = time.Now()
   427  	for acc, list := range mp.pool {
   428  		if !all && dirty[acc] == false {
   429  			continue
   430  		}
   431  		ns, err := mp.getAccountState(list.GetAccount())
   432  		if err != nil {
   433  			mp.Error().Err(err).Msg("getting Account status failed during removal")
   434  			// TODO : ????
   435  			continue
   436  		}
   437  		diff, delTxs := list.FilterByState(ns)
   438  		mp.orphan -= diff
   439  		for _, tx := range delTxs {
   440  			mp.cache.Delete(types.ToTxID(tx.GetHash()))
   441  			mp.length--
   442  		}
   443  		mp.releaseMemPoolList(list)
   444  		check++
   445  	}
   446  
   447  	ag[1] = time.Since(start)
   448  	mp.Debug().Int("given", len(block.GetBody().GetTxs())).
   449  		Int("check", check).
   450  		Str("elapse1", ag[0].String()).
   451  		Str("elapse2", ag[1].String()).
   452  		Msg("delete txs on block")
   453  	return nil
   454  }
   455  
   456  // signiture verification
   457  func (mp *MemPool) verifyTx(tx types.Transaction) error {
   458  	err := tx.Validate(mp.chainIdHash, mp.isPublic)
   459  	if err != nil {
   460  		return err
   461  	}
   462  	if !tx.GetTx().NeedNameVerify() {
   463  		err = key.VerifyTx(tx.GetTx())
   464  		if err != nil {
   465  			return err
   466  		}
   467  	} else {
   468  		mp.RLock()
   469  		account := mp.getAddress(tx.GetBody().GetAccount())
   470  		mp.RUnlock()
   471  		err = key.VerifyTxWithAddress(tx.GetTx(), account)
   472  		if err != nil {
   473  			return err
   474  		}
   475  		if !tx.SetVerifedAccount(account) {
   476  			mp.Warn().Str("account", string(account)).Msg("could not set verifed account")
   477  		}
   478  	}
   479  	return nil
   480  }
   481  func (mp *MemPool) getAddress(account []byte) []byte {
   482  	if mp.testConfig {
   483  		return account
   484  	}
   485  
   486  	nameState, err := mp.getAccountState([]byte(types.AergoName))
   487  	if err != nil {
   488  		mp.Error().Str("for name", string(account)).Msgf("failed to get state %s", types.AergoName)
   489  		return nil
   490  	}
   491  	scs, err := mp.stateDB.OpenContractState(types.ToAccountID([]byte(types.AergoName)), nameState)
   492  	if err != nil {
   493  		mp.Error().Str("for name", string(account)).Msgf("failed to open contract %s", types.AergoName)
   494  		return nil
   495  	}
   496  	return name.GetOwner(scs, account)
   497  }
   498  
   499  // check tx sanity
   500  // check if sender has enough balance
   501  // check if recipient is valid name
   502  // check tx account is lower than known value
   503  func (mp *MemPool) validateTx(tx types.Transaction, account types.Address) error {
   504  	if !mp.whitelist.Check(types.EncodeAddress(account)) {
   505  		return types.ErrTxNotAllowedAccount
   506  	}
   507  	ns, err := mp.getAccountState(account)
   508  	if err != nil {
   509  		return err
   510  	}
   511  	err = tx.ValidateWithSenderState(ns)
   512  	if err != nil && err != types.ErrTxNonceToohigh {
   513  		return err
   514  	}
   515  
   516  	//NOTE: don't overwrite err, if err == ErrTxNonceToohigh
   517  	//because err should be ErrNonceToohigh if following validation has passed
   518  	//this will be refactored soon
   519  
   520  	switch tx.GetBody().GetType() {
   521  	case types.TxType_REDEPLOY:
   522  		if chain.IsPublic() {
   523  			return types.ErrTxInvalidType
   524  		}
   525  		if tx.GetBody().GetRecipient() == nil {
   526  			return types.ErrTxInvalidRecipient
   527  		}
   528  		fallthrough
   529  	case types.TxType_NORMAL:
   530  		if tx.GetTx().HasNameRecipient() {
   531  			recipient := tx.GetBody().GetRecipient()
   532  			recipientAddr := mp.getAddress(recipient)
   533  			if recipientAddr == nil {
   534  				return types.ErrTxInvalidRecipient
   535  			}
   536  		}
   537  	case types.TxType_GOVERNANCE:
   538  		aergoState, err := mp.getAccountState(tx.GetBody().GetRecipient())
   539  		if err != nil {
   540  			return err
   541  		}
   542  		aid := types.ToAccountID(tx.GetBody().GetRecipient())
   543  		scs, err := mp.stateDB.OpenContractState(aid, aergoState)
   544  		if err != nil {
   545  			return err
   546  		}
   547  		switch string(tx.GetBody().GetRecipient()) {
   548  		case types.AergoSystem:
   549  			sender, err := mp.stateDB.GetAccountStateV(account)
   550  			if err != nil {
   551  				return err
   552  			}
   553  			if _, err := system.ValidateSystemTx(account, tx.GetBody(),
   554  				sender, scs, mp.bestBlockNo+1); err != nil {
   555  				return err
   556  			}
   557  		case types.AergoName:
   558  			systemcs, err := mp.stateDB.OpenContractStateAccount(types.ToAccountID([]byte(types.AergoSystem)))
   559  			if err != nil {
   560  				return err
   561  			}
   562  			sender, err := mp.stateDB.GetAccountStateV(account)
   563  			if err != nil {
   564  				return err
   565  			}
   566  			if _, err := name.ValidateNameTx(tx.GetBody(), sender, scs, systemcs); err != nil {
   567  				return err
   568  			}
   569  		case types.AergoEnterprise:
   570  			enterprisecs, err := mp.stateDB.OpenContractStateAccount(types.ToAccountID([]byte(types.AergoEnterprise)))
   571  			if err != nil {
   572  				return err
   573  			}
   574  			sender, err := mp.stateDB.GetAccountStateV(account)
   575  			if err != nil {
   576  				return err
   577  			}
   578  			if _, err := enterprise.ValidateEnterpriseTx(tx.GetBody(), sender, enterprisecs, mp.bestBlockNo+1); err != nil {
   579  				return err
   580  			}
   581  		}
   582  
   583  	}
   584  	return err
   585  }
   586  
   587  func (mp *MemPool) exist(hash []byte) *types.Tx {
   588  	v := make([]types.TxHash, 1)
   589  	v[0] = hash
   590  	txs := mp.existEx(v)
   591  	return txs[0]
   592  }
   593  func (mp *MemPool) existEx(hashes []types.TxHash) []*types.Tx {
   594  
   595  	if len(hashes) > message.MaxReqestHashes {
   596  		mp.Error().Int("size", len(hashes)).
   597  			Msg("request exceeds max hash length")
   598  		return nil
   599  	}
   600  
   601  	ret := make([]*types.Tx, len(hashes))
   602  	for i, h := range hashes {
   603  		if v, ok := mp.cache.Load(types.ToTxID(h)); ok {
   604  			ret[i] = v.(types.Transaction).GetTx()
   605  		}
   606  	}
   607  	return ret
   608  }
   609  
   610  func (mp *MemPool) acquireMemPoolList(acc []byte) (*TxList, error) {
   611  	list := mp.getMemPoolList(acc)
   612  	if list != nil {
   613  		return list, nil
   614  	}
   615  	ns, err := mp.getAccountState(acc)
   616  	if err != nil {
   617  		return nil, err
   618  	}
   619  	id := types.ToAccountID(acc)
   620  	mp.pool[id] = NewTxList(acc, ns)
   621  	return mp.pool[id], nil
   622  }
   623  
   624  func (mp *MemPool) releaseMemPoolList(list *TxList) {
   625  	if list.Empty() {
   626  		id := types.ToAccountID(list.account)
   627  		delete(mp.pool, id)
   628  	}
   629  }
   630  
   631  func (mp *MemPool) getMemPoolList(acc []byte) *TxList {
   632  	id := types.ToAccountID(acc)
   633  	return mp.pool[id]
   634  }
   635  
   636  func (mp *MemPool) getAccountState(acc []byte) (*types.State, error) {
   637  	if mp.testConfig {
   638  		aid := types.ToAccountID(acc)
   639  		strAcc := aid.String()
   640  		bal := getBalanceByAccMock(strAcc)
   641  		nonce := getNonceByAccMock(strAcc)
   642  		//mp.Error().Str("acc:", strAcc).Int("nonce", int(nonce)).Msg("")
   643  		return &types.State{Balance: new(big.Int).SetUint64(bal).Bytes(), Nonce: nonce}, nil
   644  	}
   645  
   646  	state, err := mp.stateDB.GetAccountState(types.ToAccountID(acc))
   647  
   648  	if err != nil {
   649  		mp.Fatal().Err(err).Str("sroot", enc.ToString(mp.stateDB.GetRoot())).Msg("failed to get state")
   650  
   651  		//FIXME PANIC?
   652  		//mp.Fatal().Err(err).Msg("failed to get state")
   653  		return nil, err
   654  	}
   655  	/*
   656  		if state.Balance == 0 {
   657  			strAcc := types.EncodeAddress(acc)
   658  			mp.Info().Str("address", strAcc).Msg("w t f")
   659  
   660  		}
   661  	*/
   662  	return state, nil
   663  }
   664  
   665  func (mp *MemPool) notifyNewTx(tx types.Transaction) {
   666  	mp.RequestTo(message.P2PSvc, &message.NotifyNewTransactions{
   667  		Txs: []*types.Tx{tx.GetTx()},
   668  	})
   669  }
   670  
   671  func (mp *MemPool) isRunning() bool {
   672  	if atomic.LoadInt32(&mp.status) != running {
   673  		mp.Info().Msg("skip to dump txs because mempool is not running yet")
   674  		return false
   675  	}
   676  	return true
   677  }
   678  
   679  func (mp *MemPool) loadTxs() {
   680  	time.Sleep(time.Second) // FIXME
   681  	if !atomic.CompareAndSwapInt32(&mp.status, initial, loading) {
   682  		return
   683  	}
   684  	defer atomic.StoreInt32(&mp.status, running)
   685  
   686  	file, err := os.Open(mp.dumpPath)
   687  	if err != nil {
   688  		if !os.IsNotExist(err) {
   689  			mp.Error().Err(err).Msg("Unable to open dump file")
   690  		}
   691  		return
   692  	}
   693  
   694  	defer file.Close() // nolint: errcheck
   695  
   696  	reader := bufio.NewReader(file)
   697  
   698  	var count int
   699  
   700  	for {
   701  		buf := types.Tx{}
   702  		byteInt := make([]byte, 4)
   703  		_, err := io.ReadFull(reader, byteInt)
   704  		if err != nil {
   705  			if err != io.EOF {
   706  				mp.Error().Err(err).Msg("err on read file during loading")
   707  			}
   708  			break
   709  		}
   710  
   711  		reclen := binary.LittleEndian.Uint32(byteInt)
   712  		buffer := make([]byte, int(reclen))
   713  		_, err = io.ReadFull(reader, buffer)
   714  		if err != nil {
   715  			if err != io.EOF {
   716  				mp.Error().Err(err).Msg("err on read file during loading")
   717  			}
   718  			break
   719  		}
   720  
   721  		err = proto.Unmarshal(buffer, &buf)
   722  		if err != nil {
   723  			mp.Error().Err(err).Msg("errr on unmarshalling tx during loading")
   724  			continue
   725  		}
   726  		count++
   727  		mp.put(types.NewTransaction(&buf)) // nolint: errcheck
   728  	}
   729  
   730  	mp.Info().Int("try", count).
   731  		Int("drop", count-mp.length-mp.orphan).
   732  		Int("suceed", mp.length).
   733  		Int("orphan", mp.orphan).
   734  		Msg("loading mempool done")
   735  }
   736  
   737  func (mp *MemPool) dumpTxsToFile() {
   738  	if !mp.isRunning() {
   739  		return
   740  	}
   741  	mp.Info().Msg("start mempool dump")
   742  
   743  	file, err := os.Create(mp.dumpPath)
   744  	if err != nil {
   745  		mp.Error().Err(err).Msg("Unable to create file")
   746  		return
   747  	}
   748  	defer file.Close() // nolint: errcheck
   749  
   750  	writer := bufio.NewWriter(file)
   751  	defer writer.Flush() //nolint: errcheck
   752  	mp.Lock()
   753  	defer mp.Unlock()
   754  
   755  	var ag [2]time.Duration
   756  	count := 0
   757  
   758  Dump:
   759  	for _, list := range mp.pool {
   760  		for _, v := range list.GetAll() {
   761  
   762  			var total_data []byte
   763  			start := time.Now()
   764  			data, err := proto.Marshal(v.GetTx())
   765  			if err != nil {
   766  				mp.Error().Err(err).Msg("Marshal failed")
   767  				continue
   768  			}
   769  
   770  			byteInt := make([]byte, 4)
   771  			binary.LittleEndian.PutUint32(byteInt, uint32(len(data)))
   772  			total_data = append(total_data, byteInt...)
   773  			total_data = append(total_data, data...)
   774  
   775  			ag[0] += time.Since(start)
   776  			start = time.Now()
   777  
   778  			length := len(total_data)
   779  			for {
   780  				size, err := writer.Write(total_data)
   781  				if err != nil {
   782  					mp.Error().Err(err).Msg("writing encoded tx fail")
   783  					break Dump
   784  				}
   785  				if length != size {
   786  					total_data = total_data[size:]
   787  					length -= size
   788  				} else {
   789  					break
   790  				}
   791  			}
   792  			count++
   793  			ag[1] += time.Since(start)
   794  		}
   795  	}
   796  
   797  	mp.Info().Int("count", count).Str("path", mp.dumpPath).Str("marshal", ag[0].String()).
   798  		Str("write", ag[1].String()).Msg("dump txs")
   799  
   800  }