2016-11-09 04:01:56 +03:00
// Copyright 2016 The go-ethereum Authors
2016-10-14 06:51:29 +03:00
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
// Package les implements the Light Ethereum Subprotocol.
package les
import (
"fmt"
2017-06-21 13:27:38 +03:00
"sync"
2016-10-14 06:51:29 +03:00
"time"
"github.com/ethereum/go-ethereum/accounts"
"github.com/ethereum/go-ethereum/common"
2016-12-17 17:39:55 +03:00
"github.com/ethereum/go-ethereum/common/hexutil"
2019-02-26 14:32:48 +03:00
"github.com/ethereum/go-ethereum/common/mclock"
2017-04-05 01:16:29 +03:00
"github.com/ethereum/go-ethereum/consensus"
2016-10-14 06:51:29 +03:00
"github.com/ethereum/go-ethereum/core"
2017-10-24 16:19:09 +03:00
"github.com/ethereum/go-ethereum/core/bloombits"
2018-05-07 14:35:06 +03:00
"github.com/ethereum/go-ethereum/core/rawdb"
2016-10-14 06:51:29 +03:00
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/eth"
"github.com/ethereum/go-ethereum/eth/downloader"
"github.com/ethereum/go-ethereum/eth/filters"
"github.com/ethereum/go-ethereum/eth/gasprice"
"github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/internal/ethapi"
"github.com/ethereum/go-ethereum/light"
2017-02-22 15:10:07 +03:00
"github.com/ethereum/go-ethereum/log"
2016-10-14 06:51:29 +03:00
"github.com/ethereum/go-ethereum/node"
"github.com/ethereum/go-ethereum/p2p"
2017-06-21 13:27:38 +03:00
"github.com/ethereum/go-ethereum/p2p/discv5"
2016-10-20 14:36:29 +03:00
"github.com/ethereum/go-ethereum/params"
2016-10-14 06:51:29 +03:00
rpc "github.com/ethereum/go-ethereum/rpc"
)
type LightEthereum struct {
2018-08-17 13:21:53 +03:00
lesCommons
2018-02-05 16:41:53 +03:00
2016-10-14 06:51:29 +03:00
odr * LesOdr
relay * LesTxRelay
2016-10-20 14:36:29 +03:00
chainConfig * params . ChainConfig
2016-10-14 06:51:29 +03:00
// Channel for shutting down the service
shutdownChan chan bool
2018-08-17 13:21:53 +03:00
2016-10-14 06:51:29 +03:00
// Handlers
2018-08-17 13:21:53 +03:00
peers * peerSet
txPool * light . TxPool
blockchain * light . LightChain
serverPool * serverPool
reqDist * requestDistributor
retriever * retrieveManager
bloomRequests chan chan * bloombits . Retrieval // Channel receiving bloom data retrieval requests
bloomIndexer * core . ChainIndexer
2017-10-24 16:19:09 +03:00
2016-10-14 06:51:29 +03:00
ApiBackend * LesApiBackend
eventMux * event . TypeMux
2017-04-05 01:16:29 +03:00
engine consensus . Engine
2016-10-14 06:51:29 +03:00
accountManager * accounts . Manager
2017-04-25 14:31:15 +03:00
networkId uint64
2016-10-14 06:51:29 +03:00
netRPCService * ethapi . PublicNetAPI
2017-06-21 13:27:38 +03:00
2017-08-08 19:31:08 +03:00
wg sync . WaitGroup
2016-10-14 06:51:29 +03:00
}
func New ( ctx * node . ServiceContext , config * eth . Config ) ( * LightEthereum , error ) {
2018-09-24 15:57:49 +03:00
chainDb , err := ctx . OpenDatabase ( "lightchaindata" , config . DatabaseCache , config . DatabaseHandles , "eth/db/chaindata/" )
2016-10-14 06:51:29 +03:00
if err != nil {
return nil , err
}
2018-12-11 15:19:03 +03:00
chainConfig , genesisHash , genesisErr := core . SetupGenesisBlockWithOverride ( chainDb , config . Genesis , config . ConstantinopleOverride )
2017-03-02 16:03:33 +03:00
if _ , isCompat := genesisErr . ( * params . ConfigCompatError ) ; genesisErr != nil && ! isCompat {
return nil , genesisErr
2016-10-14 06:51:29 +03:00
}
2017-03-02 16:03:33 +03:00
log . Info ( "Initialised chain configuration" , "config" , chainConfig )
2017-06-21 13:27:38 +03:00
peers := newPeerSet ( )
quitSync := make ( chan struct { } )
2017-10-24 16:19:09 +03:00
leth := & LightEthereum {
2018-08-17 13:21:53 +03:00
lesCommons : lesCommons {
chainDb : chainDb ,
config : config ,
2018-08-28 10:08:16 +03:00
iConfig : light . DefaultClientIndexerConfig ,
2018-08-17 13:21:53 +03:00
} ,
2018-08-15 23:25:46 +03:00
chainConfig : chainConfig ,
eventMux : ctx . EventMux ,
peers : peers ,
2019-02-26 14:32:48 +03:00
reqDist : newRequestDistributor ( peers , quitSync , & mclock . System { } ) ,
2018-08-15 23:25:46 +03:00
accountManager : ctx . AccountManager ,
2018-08-28 16:59:05 +03:00
engine : eth . CreateConsensusEngine ( ctx , chainConfig , & config . Ethash , nil , false , chainDb ) ,
2018-08-15 23:25:46 +03:00
shutdownChan : make ( chan bool ) ,
networkId : config . NetworkId ,
bloomRequests : make ( chan chan * bloombits . Retrieval ) ,
2018-08-28 10:08:16 +03:00
bloomIndexer : eth . NewBloomIndexer ( chainDb , params . BloomBitsBlocksClient , params . HelperTrieConfirmations ) ,
2016-10-14 06:51:29 +03:00
}
2017-06-21 13:27:38 +03:00
2019-01-24 14:18:26 +03:00
var trustedNodes [ ] string
if leth . config . ULC != nil {
trustedNodes = leth . config . ULC . TrustedServers
}
2017-10-24 16:19:09 +03:00
leth . relay = NewLesTxRelay ( peers , leth . reqDist )
2019-01-24 14:18:26 +03:00
leth . serverPool = newServerPool ( chainDb , quitSync , & leth . wg , trustedNodes )
2017-10-24 16:19:09 +03:00
leth . retriever = newRetrieveManager ( peers , leth . reqDist , leth . serverPool )
2018-08-17 13:21:53 +03:00
2018-08-28 10:08:16 +03:00
leth . odr = NewLesOdr ( chainDb , light . DefaultClientIndexerConfig , leth . retriever )
2019-04-05 18:40:03 +03:00
leth . chtIndexer = light . NewChtIndexer ( chainDb , leth . odr , params . CHTFrequency , params . HelperTrieConfirmations )
2018-08-28 10:08:16 +03:00
leth . bloomTrieIndexer = light . NewBloomTrieIndexer ( chainDb , leth . odr , params . BloomBitsBlocksClient , params . BloomTrieFrequency )
2018-08-15 23:25:46 +03:00
leth . odr . SetIndexers ( leth . chtIndexer , leth . bloomTrieIndexer , leth . bloomIndexer )
2018-08-17 13:21:53 +03:00
2018-08-15 23:25:46 +03:00
// Note: NewLightChain adds the trusted checkpoint so it needs an ODR with
// indexers already set but not started yet
2017-10-24 16:19:09 +03:00
if leth . blockchain , err = light . NewLightChain ( leth . odr , leth . chainConfig , leth . engine ) ; err != nil {
2016-10-14 06:51:29 +03:00
return nil , err
}
2018-08-15 23:25:46 +03:00
// Note: AddChildIndexer starts the update process for the child
leth . bloomIndexer . AddChildIndexer ( leth . bloomTrieIndexer )
leth . chtIndexer . Start ( leth . blockchain )
2017-10-24 16:19:09 +03:00
leth . bloomIndexer . Start ( leth . blockchain )
2018-08-17 13:21:53 +03:00
2017-03-02 16:03:33 +03:00
// Rewind the chain in case of an incompatible config upgrade.
if compat , ok := genesisErr . ( * params . ConfigCompatError ) ; ok {
log . Warn ( "Rewinding chain to upgrade configuration" , "err" , compat )
2017-10-24 16:19:09 +03:00
leth . blockchain . SetHead ( compat . RewindTo )
2018-05-07 14:35:06 +03:00
rawdb . WriteChainConfig ( chainDb , genesisHash , chainConfig )
2017-03-02 16:03:33 +03:00
}
2016-10-14 06:51:29 +03:00
2017-10-24 16:19:09 +03:00
leth . txPool = light . NewTxPool ( leth . chainConfig , leth . blockchain , leth . relay )
2019-01-24 14:18:26 +03:00
if leth . protocolManager , err = NewProtocolManager (
leth . chainConfig ,
light . DefaultClientIndexerConfig ,
true ,
config . NetworkId ,
leth . eventMux ,
leth . engine ,
leth . peers ,
leth . blockchain ,
nil ,
chainDb ,
leth . odr ,
leth . relay ,
leth . serverPool ,
quitSync ,
& leth . wg ,
config . ULC ) ; err != nil {
2016-10-14 06:51:29 +03:00
return nil , err
}
2019-01-24 14:18:26 +03:00
if leth . protocolManager . isULCEnabled ( ) {
log . Warn ( "Ultra light client is enabled" , "trustedNodes" , len ( leth . protocolManager . ulc . trustedKeys ) , "minTrustedFraction" , leth . protocolManager . ulc . minTrustedFraction )
leth . blockchain . DisableCheckFreq ( )
}
2019-04-04 14:03:10 +03:00
leth . ApiBackend = & LesApiBackend { ctx . ExtRPCEnabled ( ) , leth , nil }
2019-01-24 14:18:26 +03:00
2017-04-12 17:27:23 +03:00
gpoParams := config . GPO
if gpoParams . Default == nil {
2018-08-21 22:56:54 +03:00
gpoParams . Default = config . MinerGasPrice
2017-04-06 17:20:42 +03:00
}
2017-10-24 16:19:09 +03:00
leth . ApiBackend . gpo = gasprice . NewOracle ( leth . ApiBackend , gpoParams )
return leth , nil
2016-10-14 06:51:29 +03:00
}
2017-10-24 16:19:09 +03:00
func lesTopic ( genesisHash common . Hash , protocolVersion uint ) discv5 . Topic {
var name string
switch protocolVersion {
case lpv2 :
name = "LES2"
default :
panic ( nil )
}
2017-10-27 17:18:53 +03:00
return discv5 . Topic ( name + "@" + common . Bytes2Hex ( genesisHash . Bytes ( ) [ 0 : 8 ] ) )
2017-06-21 13:27:38 +03:00
}
2016-10-14 06:51:29 +03:00
type LightDummyAPI struct { }
// Etherbase is the address that mining rewards will be send to
func ( s * LightDummyAPI ) Etherbase ( ) ( common . Address , error ) {
2019-04-03 10:15:15 +03:00
return common . Address { } , fmt . Errorf ( "mining is not supported in light mode" )
2016-10-14 06:51:29 +03:00
}
// Coinbase is the address that mining rewards will be send to (alias for Etherbase)
func ( s * LightDummyAPI ) Coinbase ( ) ( common . Address , error ) {
2019-04-03 10:15:15 +03:00
return common . Address { } , fmt . Errorf ( "mining is not supported in light mode" )
2016-10-14 06:51:29 +03:00
}
// Hashrate returns the POW hashrate
2016-12-17 17:39:55 +03:00
func ( s * LightDummyAPI ) Hashrate ( ) hexutil . Uint {
return 0
2016-10-14 06:51:29 +03:00
}
// Mining returns an indication if this node is currently mining.
func ( s * LightDummyAPI ) Mining ( ) bool {
return false
}
// APIs returns the collection of RPC services the ethereum package offers.
// NOTE, some of these services probably need to be moved to somewhere else.
func ( s * LightEthereum ) APIs ( ) [ ] rpc . API {
2017-04-13 00:04:14 +03:00
return append ( ethapi . GetAPIs ( s . ApiBackend ) , [ ] rpc . API {
2016-10-14 06:51:29 +03:00
{
Namespace : "eth" ,
Version : "1.0" ,
Service : & LightDummyAPI { } ,
Public : true ,
} , {
Namespace : "eth" ,
Version : "1.0" ,
Service : downloader . NewPublicDownloaderAPI ( s . protocolManager . downloader , s . eventMux ) ,
Public : true ,
} , {
Namespace : "eth" ,
Version : "1.0" ,
Service : filters . NewPublicFilterAPI ( s . ApiBackend , true ) ,
Public : true ,
} , {
Namespace : "net" ,
Version : "1.0" ,
Service : s . netRPCService ,
Public : true ,
} ,
} ... )
}
func ( s * LightEthereum ) ResetWithGenesisBlock ( gb * types . Block ) {
s . blockchain . ResetWithGenesisBlock ( gb )
}
func ( s * LightEthereum ) BlockChain ( ) * light . LightChain { return s . blockchain }
func ( s * LightEthereum ) TxPool ( ) * light . TxPool { return s . txPool }
2017-04-12 16:38:31 +03:00
func ( s * LightEthereum ) Engine ( ) consensus . Engine { return s . engine }
2018-08-17 13:21:53 +03:00
func ( s * LightEthereum ) LesVersion ( ) int { return int ( ClientProtocolVersions [ 0 ] ) }
2016-10-14 06:51:29 +03:00
func ( s * LightEthereum ) Downloader ( ) * downloader . Downloader { return s . protocolManager . downloader }
2016-11-25 18:55:06 +03:00
func ( s * LightEthereum ) EventMux ( ) * event . TypeMux { return s . eventMux }
2016-10-14 06:51:29 +03:00
// Protocols implements node.Service, returning all the currently configured
// network protocols to start.
func ( s * LightEthereum ) Protocols ( ) [ ] p2p . Protocol {
2018-08-17 13:21:53 +03:00
return s . makeProtocols ( ClientProtocolVersions )
2016-10-14 06:51:29 +03:00
}
// Start implements node.Service, starting all internal goroutines needed by the
// Ethereum protocol implementation.
func ( s * LightEthereum ) Start ( srvr * p2p . Server ) error {
2017-03-03 12:41:52 +03:00
log . Warn ( "Light client mode is an experimental feature" )
2018-08-28 10:08:16 +03:00
s . startBloomHandlers ( params . BloomBitsBlocksClient )
2017-04-25 14:31:15 +03:00
s . netRPCService = ethapi . NewPublicNetAPI ( srvr , s . networkId )
2018-01-22 15:38:34 +03:00
// clients are searching for the first advertised protocol in the list
protocolVersion := AdvertiseProtocolVersions [ 0 ]
2017-10-24 16:19:09 +03:00
s . serverPool . start ( srvr , lesTopic ( s . blockchain . Genesis ( ) . Hash ( ) , protocolVersion ) )
2018-02-05 16:41:53 +03:00
s . protocolManager . Start ( s . config . LightPeers )
2016-10-14 06:51:29 +03:00
return nil
}
// Stop implements node.Service, terminating all internal goroutines used by the
// Ethereum protocol.
func ( s * LightEthereum ) Stop ( ) error {
s . odr . Stop ( )
2018-08-17 13:21:53 +03:00
s . bloomIndexer . Close ( )
s . chtIndexer . Close ( )
2016-10-14 06:51:29 +03:00
s . blockchain . Stop ( )
s . protocolManager . Stop ( )
s . txPool . Stop ( )
2018-08-03 11:33:37 +03:00
s . engine . Close ( )
2016-10-14 06:51:29 +03:00
s . eventMux . Stop ( )
time . Sleep ( time . Millisecond * 200 )
s . chainDb . Close ( )
close ( s . shutdownChan )
return nil
}