github.com/aquanetwork/aquachain@v1.7.8/aqua/backend.go (about)

     1  // Copyright 2014 The aquachain Authors
     2  // This file is part of the aquachain library.
     3  //
     4  // The aquachain 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 aquachain 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 aquachain library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  // Package aqua implements the AquaChain protocol.
    18  package aqua
    19  
    20  import (
    21  	"fmt"
    22  	"math/big"
    23  	"runtime"
    24  	"sync"
    25  	"sync/atomic"
    26  
    27  	"gitlab.com/aquachain/aquachain/aqua/accounts"
    28  	"gitlab.com/aquachain/aquachain/aqua/downloader"
    29  	"gitlab.com/aquachain/aquachain/aqua/event"
    30  	"gitlab.com/aquachain/aquachain/aqua/filters"
    31  	"gitlab.com/aquachain/aquachain/aqua/gasprice"
    32  	"gitlab.com/aquachain/aquachain/aquadb"
    33  	"gitlab.com/aquachain/aquachain/common"
    34  	"gitlab.com/aquachain/aquachain/common/hexutil"
    35  	"gitlab.com/aquachain/aquachain/common/log"
    36  	"gitlab.com/aquachain/aquachain/consensus"
    37  	"gitlab.com/aquachain/aquachain/consensus/aquahash"
    38  	"gitlab.com/aquachain/aquachain/core"
    39  	"gitlab.com/aquachain/aquachain/core/bloombits"
    40  	"gitlab.com/aquachain/aquachain/core/types"
    41  	"gitlab.com/aquachain/aquachain/core/vm"
    42  	"gitlab.com/aquachain/aquachain/internal/aquaapi"
    43  	"gitlab.com/aquachain/aquachain/node"
    44  	"gitlab.com/aquachain/aquachain/opt/miner"
    45  	"gitlab.com/aquachain/aquachain/p2p"
    46  	"gitlab.com/aquachain/aquachain/params"
    47  	"gitlab.com/aquachain/aquachain/rlp"
    48  	"gitlab.com/aquachain/aquachain/rpc"
    49  )
    50  
    51  // AquaChain implements the AquaChain full node service.
    52  type AquaChain struct {
    53  	config      *Config
    54  	chainConfig *params.ChainConfig
    55  
    56  	// Channel for shutting down the service
    57  	shutdownChan  chan bool    // Channel for shutting down the aquachain
    58  	stopDbUpgrade func() error // stop chain db sequential key upgrade
    59  
    60  	// Handlers
    61  	txPool          *core.TxPool
    62  	blockchain      *core.BlockChain
    63  	protocolManager *ProtocolManager
    64  
    65  	// DB interfaces
    66  	chainDb aquadb.Database // Block chain database
    67  
    68  	eventMux       *event.TypeMux
    69  	engine         consensus.Engine
    70  	accountManager *accounts.Manager
    71  
    72  	bloomRequests chan chan *bloombits.Retrieval // Channel receiving bloom data retrieval requests
    73  	bloomIndexer  *core.ChainIndexer             // Bloom indexer operating during block imports
    74  
    75  	ApiBackend *AquaApiBackend
    76  
    77  	miner    *miner.Miner
    78  	gasPrice *big.Int
    79  	aquabase common.Address
    80  
    81  	networkId     uint64
    82  	netRPCService *aquaapi.PublicNetAPI
    83  
    84  	lock sync.RWMutex // Protects the variadic fields (e.g. gas price and aquabase)
    85  }
    86  
    87  // New creates a new AquaChain object (including the
    88  // initialisation of the common AquaChain object)
    89  func New(ctx *node.ServiceContext, config *Config) (*AquaChain, error) {
    90  	if !config.SyncMode.IsValid() {
    91  		return nil, fmt.Errorf("invalid sync mode %d", config.SyncMode)
    92  	}
    93  	chainDb, err := CreateDB(ctx, config, "chaindata")
    94  	if err != nil {
    95  		return nil, err
    96  	}
    97  	stopDbUpgrade := upgradeDeduplicateData(chainDb)
    98  	chainConfig, genesisHash, genesisErr := core.SetupGenesisBlock(chainDb, config.Genesis)
    99  	if _, ok := genesisErr.(*params.ConfigCompatError); genesisErr != nil && !ok {
   100  		return nil, genesisErr
   101  	}
   102  	log.Info("Initialised chain configuration", "HF-Ready", chainConfig.HF, "config", chainConfig)
   103  
   104  	aqua := &AquaChain{
   105  		config:         config,
   106  		chainDb:        chainDb,
   107  		chainConfig:    chainConfig,
   108  		eventMux:       ctx.EventMux,
   109  		accountManager: ctx.AccountManager,
   110  		engine:         CreateConsensusEngine(ctx, &config.Aquahash, chainConfig, chainDb),
   111  		shutdownChan:   make(chan bool),
   112  		stopDbUpgrade:  stopDbUpgrade,
   113  		networkId:      config.NetworkId,
   114  		gasPrice:       config.GasPrice,
   115  		aquabase:       config.Aquabase,
   116  		bloomRequests:  make(chan chan *bloombits.Retrieval),
   117  		bloomIndexer:   NewBloomIndexer(chainConfig, chainDb, params.BloomBitsBlocks),
   118  	}
   119  
   120  	log.Info("Initialising AquaChain protocol", "versions", ProtocolVersions, "network", config.NetworkId)
   121  
   122  	//if !config.SkipBcVersionCheck {
   123  	bcVersion := core.GetBlockChainVersion(chainDb)
   124  	if bcVersion != core.BlockChainVersion && bcVersion != 0 {
   125  		return nil, fmt.Errorf("Blockchain DB version mismatch (%d / %d). Run aquachain upgradedb.\n", bcVersion, core.BlockChainVersion)
   126  	}
   127  	core.WriteBlockChainVersion(chainDb, core.BlockChainVersion)
   128  	//}
   129  	var (
   130  		vmConfig    = vm.Config{EnablePreimageRecording: config.EnablePreimageRecording}
   131  		cacheConfig = &core.CacheConfig{Disabled: config.NoPruning, TrieNodeLimit: config.TrieCache, TrieTimeLimit: config.TrieTimeout}
   132  	)
   133  	aqua.blockchain, err = core.NewBlockChain(chainDb, cacheConfig, aqua.chainConfig, aqua.engine, vmConfig)
   134  	if err != nil {
   135  		return nil, err
   136  	}
   137  	// Rewind the chain in case of an incompatible config upgrade.
   138  	if compat, ok := genesisErr.(*params.ConfigCompatError); ok {
   139  		log.Warn("Rewinding chain to upgrade configuration", "err", compat)
   140  		aqua.blockchain.SetHead(compat.RewindTo)
   141  		core.WriteChainConfig(chainDb, genesisHash, chainConfig)
   142  	}
   143  	aqua.bloomIndexer.Start(aqua.blockchain)
   144  
   145  	if config.TxPool.Journal != "" {
   146  		config.TxPool.Journal = ctx.ResolvePath(config.TxPool.Journal)
   147  	}
   148  	aqua.txPool = core.NewTxPool(config.TxPool, aqua.chainConfig, aqua.blockchain)
   149  
   150  	if aqua.protocolManager, err = NewProtocolManager(aqua.chainConfig, config.SyncMode, config.NetworkId, aqua.eventMux, aqua.txPool, aqua.engine, aqua.blockchain, chainDb); err != nil {
   151  		return nil, err
   152  	}
   153  	aqua.miner = miner.New(aqua, aqua.chainConfig, aqua.EventMux(), aqua.engine)
   154  	aqua.miner.SetExtra(makeExtraData(config.ExtraData))
   155  
   156  	aqua.ApiBackend = &AquaApiBackend{aqua, nil}
   157  	gpoParams := config.GPO
   158  	if gpoParams.Default == nil {
   159  		gpoParams.Default = config.GasPrice
   160  	}
   161  	aqua.ApiBackend.gpo = gasprice.NewOracle(aqua.ApiBackend, gpoParams)
   162  
   163  	return aqua, nil
   164  }
   165  
   166  func makeExtraData(extra []byte) []byte {
   167  	// create default extradata
   168  	defaultExtra, _ := rlp.EncodeToBytes([]interface{}{
   169  		uint(params.VersionMajor<<16 | params.VersionMinor<<8 | params.VersionPatch),
   170  		"aquachain",
   171  		runtime.GOOS,
   172  		runtime.Version(), // go version
   173  	})
   174  	if len(extra) == 0 {
   175  		extra = defaultExtra
   176  	}
   177  	if uint64(len(extra)) > params.MaximumExtraDataSize {
   178  		extra = extra[:params.MaximumExtraDataSize-1]
   179  		log.Warn("Miner extra data exceed limit, truncating!", "extra", hexutil.Bytes(extra), "limit", params.MaximumExtraDataSize)
   180  	}
   181  	return extra
   182  }
   183  
   184  func DecodeExtraData(extra []byte) (version [3]uint8, osname string, extradata []byte, err error) {
   185  	var (
   186  		v                   []interface{}
   187  		major, minor, patch uint8
   188  	)
   189  
   190  	err = rlp.DecodeBytes(extra, &v)
   191  	if err != nil {
   192  		return version, osname, extra, err
   193  	}
   194  
   195  	// extract version
   196  	vr, ok := v[0].([]uint8)
   197  	if !ok || len(vr) != 3 {
   198  		fmt.Printf("%T type, len %v\n", v[0], len(vr))
   199  		err = fmt.Errorf("could not decode version")
   200  		return version, osname, extra, err
   201  	}
   202  	major, minor, patch = vr[0], vr[1], vr[2]
   203  
   204  	// check "aquachain"
   205  	if aq, ok := v[1].([]byte); !ok {
   206  		return version, osname, extra, nil
   207  	} else if string(aq) != "aquachain" {
   208  		return version, osname, extra, nil
   209  	}
   210  
   211  	// get OS
   212  	if osnameBytes, ok := v[2].([]byte); !ok {
   213  		fmt.Printf("%T type\n", v[2])
   214  		return version, osname, extra, fmt.Errorf("osname")
   215  	} else {
   216  		osname = string(osnameBytes)
   217  	}
   218  
   219  	return [3]uint8{major, minor, patch}, osname, extra, nil
   220  }
   221  
   222  // CreateDB creates the chain database.
   223  func CreateDB(ctx *node.ServiceContext, config *Config, name string) (aquadb.Database, error) {
   224  	db, err := ctx.OpenDatabase(name, config.DatabaseCache, config.DatabaseHandles)
   225  	if err != nil {
   226  		return nil, err
   227  	}
   228  	if db, ok := db.(*aquadb.LDBDatabase); ok {
   229  		db.Meter("aqua/db/chaindata/")
   230  	}
   231  	return db, nil
   232  }
   233  
   234  // CreateConsensusEngine creates the required type of consensus engine instance for an AquaChain service
   235  func CreateConsensusEngine(ctx *node.ServiceContext, config *aquahash.Config, chainConfig *params.ChainConfig, db aquadb.Database) consensus.Engine {
   236  	startVersion := func() byte {
   237  		big0 := big.NewInt(0)
   238  		if chainConfig == nil {
   239  			return 0
   240  		}
   241  		if chainConfig.IsHF(8, big0) {
   242  			return 3
   243  		}
   244  		if chainConfig.IsHF(5, big0) {
   245  			return 2
   246  		}
   247  		return 0
   248  	}()
   249  	switch {
   250  	case config.PowMode == aquahash.ModeFake:
   251  		log.Warn("Aquahash used in fake mode")
   252  		return aquahash.NewFaker()
   253  	case config.PowMode == aquahash.ModeTest:
   254  		log.Warn("Aquahash used in test mode")
   255  		return aquahash.NewTester()
   256  	case config.PowMode == aquahash.ModeShared:
   257  		log.Warn("Aquahash used in shared mode")
   258  		return aquahash.NewShared()
   259  	default:
   260  		if startVersion > 1 {
   261  			engine := aquahash.New(aquahash.Config{StartVersion: startVersion})
   262  			engine.SetThreads(-1)
   263  			return engine
   264  		}
   265  		engine := aquahash.New(aquahash.Config{
   266  			CacheDir:       ctx.ResolvePath(config.CacheDir),
   267  			CachesInMem:    config.CachesInMem,
   268  			CachesOnDisk:   config.CachesOnDisk,
   269  			DatasetDir:     config.DatasetDir,
   270  			DatasetsInMem:  config.DatasetsInMem,
   271  			DatasetsOnDisk: config.DatasetsOnDisk,
   272  			StartVersion:   startVersion,
   273  		})
   274  		engine.SetThreads(-1) // Disable CPU mining
   275  		return engine
   276  	}
   277  }
   278  
   279  // APIs returns the collection of RPC services the aquachain package offers.
   280  // NOTE, some of these services probably need to be moved to somewhere else.
   281  func (s *AquaChain) APIs() []rpc.API {
   282  	apis := aquaapi.GetAPIs(s.ApiBackend)
   283  
   284  	// Append any APIs exposed explicitly by the consensus engine
   285  	apis = append(apis, s.engine.APIs(s.BlockChain())...)
   286  
   287  	// Append all the local APIs and return
   288  	return append(apis, []rpc.API{
   289  		{
   290  			Namespace: "aqua",
   291  			Version:   "1.0",
   292  			Service:   NewPublicAquaChainAPI(s),
   293  			Public:    true,
   294  		}, {
   295  			Namespace: "aqua",
   296  			Version:   "1.0",
   297  			Service:   NewPublicMinerAPI(s),
   298  			Public:    true,
   299  		}, {
   300  			Namespace: "aqua",
   301  			Version:   "1.0",
   302  			Service:   downloader.NewPublicDownloaderAPI(s.protocolManager.downloader, s.eventMux),
   303  			Public:    true,
   304  		}, {
   305  			Namespace: "miner",
   306  			Version:   "1.0",
   307  			Service:   NewPrivateMinerAPI(s),
   308  			Public:    false,
   309  		}, {
   310  			Namespace: "aqua",
   311  			Version:   "1.0",
   312  			Service:   filters.NewPublicFilterAPI(s.ApiBackend, false),
   313  			Public:    true,
   314  		}, {
   315  			Namespace: "admin",
   316  			Version:   "1.0",
   317  			Service:   NewPrivateAdminAPI(s),
   318  		}, {
   319  			Namespace: "debug",
   320  			Version:   "1.0",
   321  			Service:   NewPublicDebugAPI(s),
   322  			Public:    true,
   323  		}, {
   324  			Namespace: "debug",
   325  			Version:   "1.0",
   326  			Service:   NewPrivateDebugAPI(s.chainConfig, s),
   327  		}, {
   328  			Namespace: "testing",
   329  			Version:   "1.0",
   330  			Service:   NewPublicTestingAPI(s.chainConfig, s),
   331  		}, {
   332  			Namespace: "net",
   333  			Version:   "1.0",
   334  			Service:   s.netRPCService,
   335  			Public:    true,
   336  		},
   337  	}...)
   338  }
   339  
   340  func (s *AquaChain) ResetWithGenesisBlock(gb *types.Block) {
   341  	s.blockchain.ResetWithGenesisBlock(gb)
   342  }
   343  
   344  func (s *AquaChain) Aquabase() (eb common.Address, err error) {
   345  	s.lock.RLock()
   346  	aquabase := s.aquabase
   347  	s.lock.RUnlock()
   348  
   349  	if aquabase != (common.Address{}) {
   350  		return aquabase, nil
   351  	}
   352  	if wallets := s.AccountManager().Wallets(); len(wallets) > 0 {
   353  		if accounts := wallets[0].Accounts(); len(accounts) > 0 {
   354  			aquabase := accounts[0].Address
   355  
   356  			s.lock.Lock()
   357  			s.aquabase = aquabase
   358  			s.lock.Unlock()
   359  
   360  			log.Info("Aquabase automatically configured", "address", aquabase)
   361  			return aquabase, nil
   362  		}
   363  	}
   364  	return common.Address{}, fmt.Errorf("aquabase must be explicitly specified")
   365  }
   366  
   367  // set in js console via admin interface or wrapper from cli flags
   368  func (self *AquaChain) SetAquabase(aquabase common.Address) {
   369  	self.lock.Lock()
   370  	self.aquabase = aquabase
   371  	self.lock.Unlock()
   372  
   373  	self.miner.SetAquabase(aquabase)
   374  }
   375  
   376  func (s *AquaChain) StartMining(local bool) error {
   377  	eb, err := s.Aquabase()
   378  	if err != nil {
   379  		log.Error("Cannot start mining without aquabase", "err", err)
   380  		return fmt.Errorf("aquabase missing: %v", err)
   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 *AquaChain) StopMining()         { s.miner.Stop() }
   394  func (s *AquaChain) IsMining() bool      { return s.miner.Mining() }
   395  func (s *AquaChain) Miner() *miner.Miner { return s.miner }
   396  
   397  func (s *AquaChain) AccountManager() *accounts.Manager  { return s.accountManager }
   398  func (s *AquaChain) BlockChain() *core.BlockChain       { return s.blockchain }
   399  func (s *AquaChain) TxPool() *core.TxPool               { return s.txPool }
   400  func (s *AquaChain) EventMux() *event.TypeMux           { return s.eventMux }
   401  func (s *AquaChain) Engine() consensus.Engine           { return s.engine }
   402  func (s *AquaChain) ChainDb() aquadb.Database           { return s.chainDb }
   403  func (s *AquaChain) IsListening() bool                  { return true } // Always listening
   404  func (s *AquaChain) AquaVersion() int                   { return int(s.protocolManager.SubProtocols[0].Version) }
   405  func (s *AquaChain) NetVersion() uint64                 { return s.networkId }
   406  func (s *AquaChain) Downloader() *downloader.Downloader { return s.protocolManager.downloader }
   407  
   408  // Protocols implements node.Service, returning all the currently configured
   409  // network protocols to start.
   410  func (s *AquaChain) Protocols() []p2p.Protocol {
   411  	return s.protocolManager.SubProtocols
   412  }
   413  
   414  // Start implements node.Service, starting all internal goroutines needed by the
   415  // AquaChain protocol implementation.
   416  func (s *AquaChain) Start(srvr *p2p.Server) error {
   417  	// Start the bloom bits servicing goroutines
   418  	s.startBloomHandlers()
   419  
   420  	// Start the RPC service
   421  	s.netRPCService = aquaapi.NewPublicNetAPI(srvr, s.NetVersion())
   422  
   423  	// Figure out a max peers count based on the server limits
   424  	maxPeers := srvr.MaxPeers
   425  	// Start the networking layer
   426  	s.protocolManager.Start(maxPeers)
   427  
   428  	return nil
   429  }
   430  
   431  // Stop implements node.Service, terminating all internal goroutines used by the
   432  // AquaChain protocol.
   433  func (s *AquaChain) Stop() error {
   434  	if s.stopDbUpgrade != nil {
   435  		s.stopDbUpgrade()
   436  	}
   437  	s.bloomIndexer.Close()
   438  	s.blockchain.Stop()
   439  	s.protocolManager.Stop()
   440  	s.txPool.Stop()
   441  	s.miner.Stop()
   442  	s.eventMux.Stop()
   443  
   444  	s.chainDb.Close()
   445  	close(s.shutdownChan)
   446  
   447  	return nil
   448  }