github.com/intfoundation/intchain@v0.0.0-20220727031208-4316ad31ca73/intprotocol/backend.go (about)

     1  // Copyright 2014 The go-ethereum Authors
     2  // This file is part of the go-ethereum library.
     3  //
     4  // The go-ethereum library is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Lesser General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // The go-ethereum library is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU Lesser General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Lesser General Public License
    15  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  // Package intprotocol implements the Ethereum protocol.
    18  package intprotocol
    19  
    20  import (
    21  	"errors"
    22  	"fmt"
    23  	"github.com/intfoundation/intchain/accounts"
    24  	"github.com/intfoundation/intchain/common"
    25  	"github.com/intfoundation/intchain/common/hexutil"
    26  	"github.com/intfoundation/intchain/consensus"
    27  	"github.com/intfoundation/intchain/consensus/ipbft"
    28  	tendermintBackend "github.com/intfoundation/intchain/consensus/ipbft"
    29  	"github.com/intfoundation/intchain/core"
    30  	"github.com/intfoundation/intchain/core/bloombits"
    31  	"github.com/intfoundation/intchain/core/datareduction"
    32  	"github.com/intfoundation/intchain/core/rawdb"
    33  	"github.com/intfoundation/intchain/core/types"
    34  	"github.com/intfoundation/intchain/core/vm"
    35  	"github.com/intfoundation/intchain/event"
    36  	"github.com/intfoundation/intchain/intdb"
    37  	"github.com/intfoundation/intchain/internal/intapi"
    38  	"github.com/intfoundation/intchain/intprotocol/downloader"
    39  	"github.com/intfoundation/intchain/intprotocol/filters"
    40  	"github.com/intfoundation/intchain/intprotocol/gasprice"
    41  	"github.com/intfoundation/intchain/log"
    42  	"github.com/intfoundation/intchain/miner"
    43  	"github.com/intfoundation/intchain/node"
    44  	"github.com/intfoundation/intchain/p2p"
    45  	"github.com/intfoundation/intchain/params"
    46  	"github.com/intfoundation/intchain/rlp"
    47  	"github.com/intfoundation/intchain/rpc"
    48  	"gopkg.in/urfave/cli.v1"
    49  	"math/big"
    50  	"runtime"
    51  	"sync"
    52  	"sync/atomic"
    53  )
    54  
    55  type LesServer interface {
    56  	Start(srvr *p2p.Server)
    57  	Stop()
    58  	Protocols() []p2p.Protocol
    59  	SetBloomBitsIndexer(bbIndexer *core.ChainIndexer)
    60  }
    61  
    62  // IntChain implements the INT Chain full node service.
    63  type IntChain struct {
    64  	config      *Config
    65  	chainConfig *params.ChainConfig
    66  
    67  	// Channel for shutting down the service
    68  	shutdownChan chan bool // Channel for shutting down the intChain
    69  
    70  	// Handlers
    71  	txPool          *core.TxPool
    72  	blockchain      *core.BlockChain
    73  	protocolManager *ProtocolManager
    74  
    75  	// DB interfaces
    76  	chainDb intdb.Database // Block chain database
    77  	pruneDb intdb.Database // Prune data database
    78  
    79  	eventMux       *event.TypeMux
    80  	engine         consensus.IPBFT
    81  	accountManager *accounts.Manager
    82  
    83  	bloomRequests chan chan *bloombits.Retrieval // Channel receiving bloom data retrieval requests
    84  	bloomIndexer  *core.ChainIndexer             // Bloom indexer operating during block imports
    85  
    86  	ApiBackend *EthApiBackend
    87  
    88  	miner    *miner.Miner
    89  	gasPrice *big.Int
    90  	coinbase common.Address
    91  	solcPath string
    92  
    93  	networkId     uint64
    94  	netRPCService *intapi.PublicNetAPI
    95  
    96  	lock sync.RWMutex // Protects the variadic fields (e.g. gas price and etherbase)
    97  }
    98  
    99  // New creates a new INT Chain object (including the
   100  // initialisation of the common INT Chain object)
   101  func New(ctx *node.ServiceContext, config *Config, cliCtx *cli.Context,
   102  	cch core.CrossChainHelper, logger log.Logger, isTestnet bool) (*IntChain, error) {
   103  
   104  	if !config.SyncMode.IsValid() {
   105  		return nil, fmt.Errorf("invalid sync mode %d", config.SyncMode)
   106  	}
   107  	chainDb, err := ctx.OpenDatabase("chaindata", config.DatabaseCache, config.DatabaseHandles, "intchain/db/chaindata/")
   108  	if err != nil {
   109  		return nil, err
   110  	}
   111  	pruneDb, err := ctx.OpenDatabase("prunedata", config.DatabaseCache, config.DatabaseHandles, "intchain/db/prune/")
   112  	if err != nil {
   113  		return nil, err
   114  	}
   115  
   116  	isMainChain := params.IsMainChain(ctx.ChainId())
   117  
   118  	chainConfig, genesisHash, genesisErr := core.SetupGenesisBlockWithDefault(chainDb, config.Genesis, isMainChain, isTestnet)
   119  	if _, ok := genesisErr.(*params.ConfigCompatError); genesisErr != nil && !ok {
   120  		return nil, genesisErr
   121  	}
   122  
   123  	//directly support corresponding instruction set
   124  	chainConfig.ConstantinopleBlock = big.NewInt(0)
   125  	chainConfig.PetersburgBlock = big.NewInt(0)
   126  	chainConfig.IstanbulBlock = big.NewInt(0)
   127  
   128  	chainConfig.ChainLogger = logger
   129  	logger.Info("Initialised chain configuration", "config", chainConfig)
   130  
   131  	intChain := &IntChain{
   132  		config:         config,
   133  		chainDb:        chainDb,
   134  		pruneDb:        pruneDb,
   135  		chainConfig:    chainConfig,
   136  		eventMux:       ctx.EventMux,
   137  		accountManager: ctx.AccountManager,
   138  		engine:         CreateConsensusEngine(ctx, config, chainConfig, chainDb, cliCtx, cch),
   139  		shutdownChan:   make(chan bool),
   140  		networkId:      config.NetworkId,
   141  		gasPrice:       config.MinerGasPrice,
   142  		coinbase:       config.Coinbase,
   143  		solcPath:       config.SolcPath,
   144  		bloomRequests:  make(chan chan *bloombits.Retrieval),
   145  		bloomIndexer:   NewBloomIndexer(chainDb, params.BloomBitsBlocks),
   146  	}
   147  
   148  	bcVersion := rawdb.ReadDatabaseVersion(chainDb)
   149  	var dbVer = "<nil>"
   150  	if bcVersion != nil {
   151  		dbVer = fmt.Sprintf("%d", *bcVersion)
   152  	}
   153  	logger.Info("Initialising IntChain protocol", "versions", intChain.engine.Protocol().Versions, "network", config.NetworkId, "dbversion", dbVer)
   154  	//logger.Info("Initialising intchain protocol", "network", config.NetworkId, "dbversion", dbVer)
   155  
   156  	if !config.SkipBcVersionCheck {
   157  		if bcVersion != nil && *bcVersion > core.BlockChainVersion {
   158  			return nil, fmt.Errorf("database version is v%d, Geth %s only supports v%d", *bcVersion, params.VersionWithMeta, core.BlockChainVersion)
   159  		} else if bcVersion == nil || *bcVersion < core.BlockChainVersion {
   160  			logger.Warn("Upgrade blockchain database version", "from", dbVer, "to", core.BlockChainVersion)
   161  			rawdb.WriteDatabaseVersion(chainDb, core.BlockChainVersion)
   162  		}
   163  	}
   164  	var (
   165  		vmConfig    = vm.Config{EnablePreimageRecording: config.EnablePreimageRecording}
   166  		cacheConfig = &core.CacheConfig{
   167  			TrieCleanLimit: config.TrieCleanCache,
   168  
   169  			TrieDirtyLimit:    config.TrieDirtyCache,
   170  			TrieDirtyDisabled: config.NoPruning,
   171  			TrieTimeLimit:     config.TrieTimeout,
   172  		}
   173  	)
   174  	//eth.engine = CreateConsensusEngine(ctx, config, chainConfig, chainDb, cliCtx, cch)
   175  
   176  	intChain.blockchain, err = core.NewBlockChain(chainDb, cacheConfig, intChain.chainConfig, intChain.engine, vmConfig, cch)
   177  	if err != nil {
   178  		return nil, err
   179  	}
   180  
   181  	// Rewind the chain in case of an incompatible config upgrade.
   182  	if compat, ok := genesisErr.(*params.ConfigCompatError); ok {
   183  		logger.Warn("Rewinding chain to upgrade configuration", "err", compat)
   184  		intChain.blockchain.SetHead(compat.RewindTo)
   185  		rawdb.WriteChainConfig(chainDb, genesisHash, chainConfig)
   186  	}
   187  	intChain.bloomIndexer.Start(intChain.blockchain)
   188  
   189  	if config.TxPool.Journal != "" {
   190  		config.TxPool.Journal = ctx.ResolvePath(config.TxPool.Journal)
   191  	}
   192  	intChain.txPool = core.NewTxPool(config.TxPool, intChain.chainConfig, intChain.blockchain, cch)
   193  
   194  	if intChain.protocolManager, err = NewProtocolManager(intChain.chainConfig, config.SyncMode, config.NetworkId, intChain.eventMux, intChain.txPool, intChain.engine, intChain.blockchain, chainDb, cch); err != nil {
   195  		return nil, err
   196  	}
   197  	intChain.miner = miner.New(intChain, intChain.chainConfig, intChain.EventMux(), intChain.engine, config.MinerGasFloor, config.MinerGasCeil, cch)
   198  	intChain.miner.SetExtra(makeExtraData(config.ExtraData))
   199  
   200  	intChain.ApiBackend = &EthApiBackend{intChain, nil, cch}
   201  	gpoParams := config.GPO
   202  	if gpoParams.Default == nil {
   203  		gpoParams.Default = config.MinerGasPrice
   204  	}
   205  	intChain.ApiBackend.gpo = gasprice.NewOracle(intChain.ApiBackend, gpoParams)
   206  
   207  	return intChain, nil
   208  }
   209  
   210  func makeExtraData(extra []byte) []byte {
   211  	if len(extra) == 0 {
   212  		// create default extradata
   213  		extra, _ = rlp.EncodeToBytes([]interface{}{
   214  			uint(params.VersionMajor<<16 | params.VersionMinor<<8 | params.VersionPatch),
   215  			"intchain",
   216  			runtime.Version(),
   217  			runtime.GOOS,
   218  		})
   219  	}
   220  	if uint64(len(extra)) > params.MaximumExtraDataSize {
   221  		log.Warn("Miner extra data exceed limit", "extra", hexutil.Bytes(extra), "limit", params.MaximumExtraDataSize)
   222  		extra = nil
   223  	}
   224  	return extra
   225  }
   226  
   227  // CreateConsensusEngine creates the required type of consensus engine instance for an IntChain service
   228  func CreateConsensusEngine(ctx *node.ServiceContext, config *Config, chainConfig *params.ChainConfig, db intdb.Database,
   229  	cliCtx *cli.Context, cch core.CrossChainHelper) consensus.IPBFT {
   230  	// If IPBFT is requested, set it up
   231  	if chainConfig.IPBFT.Epoch != 0 {
   232  		config.IPBFT.Epoch = chainConfig.IPBFT.Epoch
   233  	}
   234  	config.IPBFT.ProposerPolicy = ipbft.ProposerPolicy(chainConfig.IPBFT.ProposerPolicy)
   235  	return tendermintBackend.New(chainConfig, cliCtx, ctx.NodeKey(), cch)
   236  }
   237  
   238  // APIs returns the collection of RPC services the IntChain package offers.
   239  // NOTE, some of these services probably need to be moved to somewhere else.
   240  func (s *IntChain) APIs() []rpc.API {
   241  
   242  	apis := intapi.GetAPIs(s.ApiBackend, s.solcPath)
   243  	// Append any APIs exposed explicitly by the consensus engine
   244  	apis = append(apis, s.engine.APIs(s.BlockChain())...)
   245  	// Append all the local APIs and return
   246  	apis = append(apis, []rpc.API{
   247  		{
   248  			Namespace: "eth",
   249  			Version:   "1.0",
   250  			Service:   NewPublicEthereumAPI(s),
   251  			Public:    true,
   252  		}, {
   253  			Namespace: "eth",
   254  			Version:   "1.0",
   255  			Service:   NewPublicMinerAPI(s),
   256  			Public:    true,
   257  		}, {
   258  			Namespace: "eth",
   259  			Version:   "1.0",
   260  			Service:   downloader.NewPublicDownloaderAPI(s.protocolManager.downloader, s.eventMux),
   261  			Public:    true,
   262  		}, {
   263  			Namespace: "int",
   264  			Version:   "1.0",
   265  			Service:   NewPublicEthereumAPI(s),
   266  			Public:    true,
   267  		}, {
   268  			Namespace: "int",
   269  			Version:   "1.0",
   270  			Service:   NewPublicMinerAPI(s),
   271  			Public:    true,
   272  		}, {
   273  			Namespace: "int",
   274  			Version:   "1.0",
   275  			Service:   downloader.NewPublicDownloaderAPI(s.protocolManager.downloader, s.eventMux),
   276  			Public:    true,
   277  		}, {
   278  			Namespace: "miner",
   279  			Version:   "1.0",
   280  			Service:   NewPrivateMinerAPI(s),
   281  			Public:    false,
   282  		}, {
   283  			Namespace: "eth",
   284  			Version:   "1.0",
   285  			Service:   filters.NewPublicFilterAPI(s.ApiBackend, false),
   286  			Public:    true,
   287  		}, {
   288  			Namespace: "int",
   289  			Version:   "1.0",
   290  			Service:   filters.NewPublicFilterAPI(s.ApiBackend, false),
   291  			Public:    true,
   292  		}, {
   293  			Namespace: "admin",
   294  			Version:   "1.0",
   295  			Service:   NewPrivateAdminAPI(s),
   296  		}, {
   297  			Namespace: "debug",
   298  			Version:   "1.0",
   299  			Service:   NewPublicDebugAPI(s),
   300  			Public:    true,
   301  		}, {
   302  			Namespace: "debug",
   303  			Version:   "1.0",
   304  			Service:   NewPrivateDebugAPI(s.chainConfig, s),
   305  		}, {
   306  			Namespace: "net",
   307  			Version:   "1.0",
   308  			Service:   s.netRPCService,
   309  			Public:    true,
   310  		},
   311  	}...)
   312  	return apis
   313  }
   314  
   315  func (s *IntChain) ResetWithGenesisBlock(gb *types.Block) {
   316  	s.blockchain.ResetWithGenesisBlock(gb)
   317  }
   318  
   319  func (s *IntChain) Coinbase() (eb common.Address, err error) {
   320  	if ipbft, ok := s.engine.(consensus.IPBFT); ok {
   321  		eb = ipbft.PrivateValidator()
   322  		if eb != (common.Address{}) {
   323  			return eb, nil
   324  		} else {
   325  			return eb, errors.New("private validator missing")
   326  		}
   327  	} else {
   328  		s.lock.RLock()
   329  		coinbase := s.coinbase
   330  		s.lock.RUnlock()
   331  
   332  		if coinbase != (common.Address{}) {
   333  			return coinbase, nil
   334  		}
   335  		if wallets := s.AccountManager().Wallets(); len(wallets) > 0 {
   336  			if accounts := wallets[0].Accounts(); len(accounts) > 0 {
   337  				coinbase := accounts[0].Address
   338  
   339  				s.lock.Lock()
   340  				s.coinbase = coinbase
   341  				s.lock.Unlock()
   342  
   343  				log.Info("Coinbase automatically configured", "address", coinbase)
   344  				return coinbase, nil
   345  			}
   346  		}
   347  	}
   348  	return common.Address{}, fmt.Errorf("etherbase must be explicitly specified")
   349  }
   350  
   351  // set in js console via admin interface or wrapper from cli flags
   352  func (self *IntChain) SetCoinbase(coinbase common.Address) {
   353  
   354  	if _, ok := self.engine.(consensus.IPBFT); ok {
   355  		log.Error("Cannot set etherbase in IPBFT consensus")
   356  		return
   357  	}
   358  
   359  	self.lock.Lock()
   360  	self.coinbase = coinbase
   361  	self.lock.Unlock()
   362  
   363  	self.miner.SetCoinbase(coinbase)
   364  }
   365  
   366  func (s *IntChain) StartMining(local bool) error {
   367  	var eb common.Address
   368  	if ipbft, ok := s.engine.(consensus.IPBFT); ok {
   369  		eb = ipbft.PrivateValidator()
   370  		if (eb == common.Address{}) {
   371  			log.Error("Cannot start mining without private validator")
   372  			return errors.New("private validator missing")
   373  		}
   374  	} else {
   375  		_, err := s.Coinbase()
   376  		if err != nil {
   377  			log.Error("Cannot start mining without etherbase", "err", err)
   378  			return fmt.Errorf("etherbase missing: %v", err)
   379  		}
   380  	}
   381  
   382  	if local {
   383  		// If local (CPU) mining is started, we can disable the transaction rejection
   384  		// mechanism introduced to speed sync times. CPU mining on mainnet is ludicrous
   385  		// so noone will ever hit this path, whereas marking sync done on CPU mining
   386  		// will ensure that private networks work in single miner mode too.
   387  		atomic.StoreUint32(&s.protocolManager.acceptTxs, 1)
   388  	}
   389  	go s.miner.Start(eb)
   390  	return nil
   391  }
   392  
   393  func (s *IntChain) StopMining()         { s.miner.Stop() }
   394  func (s *IntChain) IsMining() bool      { return s.miner.Mining() }
   395  func (s *IntChain) Miner() *miner.Miner { return s.miner }
   396  
   397  func (s *IntChain) ChainConfig() *params.ChainConfig   { return s.chainConfig }
   398  func (s *IntChain) AccountManager() *accounts.Manager  { return s.accountManager }
   399  func (s *IntChain) BlockChain() *core.BlockChain       { return s.blockchain }
   400  func (s *IntChain) TxPool() *core.TxPool               { return s.txPool }
   401  func (s *IntChain) EventMux() *event.TypeMux           { return s.eventMux }
   402  func (s *IntChain) Engine() consensus.IPBFT            { return s.engine }
   403  func (s *IntChain) ChainDb() intdb.Database            { return s.chainDb }
   404  func (s *IntChain) IsListening() bool                  { return true } // Always listening
   405  func (s *IntChain) EthVersion() int                    { return int(s.protocolManager.SubProtocols[0].Version) }
   406  func (s *IntChain) NetVersion() uint64                 { return s.networkId }
   407  func (s *IntChain) Downloader() *downloader.Downloader { return s.protocolManager.downloader }
   408  
   409  // Protocols implements node.Service, returning all the currently configured
   410  // network protocols to start.
   411  func (s *IntChain) Protocols() []p2p.Protocol {
   412  	return s.protocolManager.SubProtocols
   413  }
   414  
   415  // Start implements node.Service, starting all internal goroutines needed by the
   416  // INT Chain protocol implementation.
   417  func (s *IntChain) Start(srvr *p2p.Server) error {
   418  	// Start the bloom bits servicing goroutines
   419  	s.startBloomHandlers()
   420  
   421  	// Start the RPC service
   422  	s.netRPCService = intapi.NewPublicNetAPI(srvr, s.NetVersion())
   423  
   424  	// Figure out a max peers count based on the server limits
   425  	maxPeers := srvr.MaxPeers
   426  
   427  	// Start the networking layer and the light server if requested
   428  	s.protocolManager.Start(maxPeers)
   429  
   430  	// Start the Auto Mining Loop
   431  	go s.loopForMiningEvent()
   432  
   433  	// Start the Data Reduction
   434  	if s.config.PruneStateData && s.chainConfig.IntChainId == "child_0" {
   435  		go s.StartScanAndPrune(0)
   436  	}
   437  
   438  	return nil
   439  }
   440  
   441  // Stop implements node.Service, terminating all internal goroutines used by the
   442  // IntChain protocol.
   443  func (s *IntChain) Stop() error {
   444  	s.bloomIndexer.Close()
   445  	s.blockchain.Stop()
   446  	s.protocolManager.Stop()
   447  	s.txPool.Stop()
   448  	s.miner.Stop()
   449  	s.engine.Close()
   450  	s.miner.Close()
   451  	s.eventMux.Stop()
   452  
   453  	s.chainDb.Close()
   454  	s.pruneDb.Close()
   455  	close(s.shutdownChan)
   456  
   457  	return nil
   458  }
   459  
   460  func (s *IntChain) loopForMiningEvent() {
   461  	// Start/Stop mining Feed
   462  	startMiningCh := make(chan core.StartMiningEvent, 1)
   463  	startMiningSub := s.blockchain.SubscribeStartMiningEvent(startMiningCh)
   464  
   465  	stopMiningCh := make(chan core.StopMiningEvent, 1)
   466  	stopMiningSub := s.blockchain.SubscribeStopMiningEvent(stopMiningCh)
   467  
   468  	defer startMiningSub.Unsubscribe()
   469  	defer stopMiningSub.Unsubscribe()
   470  
   471  	for {
   472  		select {
   473  		case <-startMiningCh:
   474  			if !s.IsMining() {
   475  				s.lock.RLock()
   476  				price := s.gasPrice
   477  				s.lock.RUnlock()
   478  				s.txPool.SetGasPrice(price)
   479  				s.chainConfig.ChainLogger.Info("IPBFT Consensus Engine will be start shortly")
   480  				s.engine.(consensus.IPBFT).ForceStart()
   481  				s.StartMining(true)
   482  			} else {
   483  				s.chainConfig.ChainLogger.Info("IPBFT Consensus Engine already started")
   484  			}
   485  		case <-stopMiningCh:
   486  			if s.IsMining() {
   487  				s.chainConfig.ChainLogger.Info("IPBFT Consensus Engine will be stop shortly")
   488  				s.StopMining()
   489  			} else {
   490  				s.chainConfig.ChainLogger.Info("IPBFT Consensus Engine already stopped")
   491  			}
   492  		case <-startMiningSub.Err():
   493  			return
   494  		case <-stopMiningSub.Err():
   495  			return
   496  		}
   497  	}
   498  }
   499  
   500  func (s *IntChain) StartScanAndPrune(blockNumber uint64) {
   501  
   502  	if datareduction.StartPruning() {
   503  		log.Info("Data Reduction - Start")
   504  	} else {
   505  		log.Info("Data Reduction - Pruning is already running")
   506  		return
   507  	}
   508  
   509  	latestBlockNumber := s.blockchain.CurrentHeader().Number.Uint64()
   510  	if blockNumber == 0 || blockNumber >= latestBlockNumber {
   511  		blockNumber = latestBlockNumber
   512  		log.Infof("Data Reduction - Last block number %v", blockNumber)
   513  	} else {
   514  		log.Infof("Data Reduction - User defined Last block number %v", blockNumber)
   515  	}
   516  
   517  	ps := rawdb.ReadHeadScanNumber(s.pruneDb)
   518  	var scanNumber uint64
   519  	if ps != nil {
   520  		scanNumber = *ps
   521  	}
   522  
   523  	pp := rawdb.ReadHeadPruneNumber(s.pruneDb)
   524  	var pruneNumber uint64
   525  	if pp != nil {
   526  		pruneNumber = *pp
   527  	}
   528  	log.Infof("Data Reduction - Last scan number %v, prune number %v", scanNumber, pruneNumber)
   529  
   530  	pruneProcessor := datareduction.NewPruneProcessor(s.chainDb, s.pruneDb, s.blockchain, s.config.PruneBlockData)
   531  
   532  	lastScanNumber, lastPruneNumber := pruneProcessor.Process(blockNumber, scanNumber, pruneNumber)
   533  	log.Infof("Data Reduction - After prune, last number scan %v, prune number %v", lastScanNumber, lastPruneNumber)
   534  	if s.config.PruneBlockData {
   535  		for i := uint64(1); i < lastPruneNumber; i++ {
   536  			rawdb.DeleteBody(s.chainDb, rawdb.ReadCanonicalHash(s.chainDb, i), i)
   537  		}
   538  		log.Infof("deleted block from 1 to %v", lastPruneNumber)
   539  	}
   540  	log.Info("Data Reduction - Completed")
   541  
   542  	datareduction.StopPruning()
   543  }