gitlab.com/aquachain/aquachain@v1.17.16-rc3.0.20221018032414-e3ddf1e1c055/aqua/backend.go (about)

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