Further LES cleanup

This commit is contained in:
Frank Szendzielarz 2019-05-30 10:41:03 +02:00
parent a7eaf583eb
commit 3712581a00
18 changed files with 319 additions and 184 deletions

View file

@ -20,6 +20,7 @@ package utils
import ( import (
"crypto/ecdsa" "crypto/ecdsa"
"encoding/json" "encoding/json"
"errors"
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"math/big" "math/big"
@ -1470,27 +1471,52 @@ func SetDashboardConfig(ctx *cli.Context, cfg *dashboard.Config) {
cfg.Refresh = ctx.GlobalDuration(DashboardRefreshFlag.Name) cfg.Refresh = ctx.GlobalDuration(DashboardRefreshFlag.Name)
} }
// RegisterEthService adds an Ethereum client to the stack. // RegisterLesClientService adds a Light Client service to the stack if the config permits
func RegisterEthService(stack *node.Node, cfg *eth.Config) { func RegisterLesClientService(stack *node.Node, cfg *eth.Config) {
var err error
//if the light client is requested
if cfg.SyncMode == downloader.LightSync { if cfg.SyncMode == downloader.LightSync {
err = stack.Register(func(ctx *node.ServiceContext) (node.Service, error) { //register a light client
if err := stack.Register(func(ctx *node.ServiceContext) (node.Service, error) {
return les.New(ctx, cfg) return les.New(ctx, cfg)
}) }); err != nil {
} else { Fatalf("Failed to register the Light Client service: %v", err)
err = stack.Register(func(ctx *node.ServiceContext) (node.Service, error) {
fullNode, err := eth.New(ctx, cfg)
if fullNode != nil && cfg.LightServ > 0 {
ls, _ := les.NewLesServer(fullNode, cfg)
fullNode.AddLesServer(ls)
} }
return fullNode, err
})
} }
if err != nil { }
// RegisterLesServerService adds a Light Server service to the stack if the config permits
func RegisterLesServerService(stack *node.Node, cfg *eth.Config) {
//if the light client is not requested and the light server is requested
if cfg.SyncMode != downloader.LightSync && cfg.LightServ > 0 {
//register a light server service
if err := stack.Register(func(ctx *node.ServiceContext) (node.Service, error) {
//check if the main Eth protocol service is running
var ethService *eth.Ethereum
if ctx.Service(&ethService) != nil {
return nil, errors.New("Failed to start the Les Server service because Ethereum service is not running")
}
return les.NewLesServer(ethService, cfg)
}); err != nil {
Fatalf("Failed to register the Light Server service: %v", err)
}
}
}
// RegisterEthService adds an Ethereum client to the stack if the config permits
func RegisterEthService(stack *node.Node, cfg *eth.Config) {
//if the light client is not requested
if cfg.SyncMode != downloader.LightSync {
//register a service for the Eth protocol
if err := stack.Register(func(ctx *node.ServiceContext) (node.Service, error) {
return eth.New(ctx, cfg)
}); err != nil {
Fatalf("Failed to register the Ethereum service: %v", err) Fatalf("Failed to register the Ethereum service: %v", err)
} }
} }
}
// RegisterDashboardService adds a dashboard to the stack. // RegisterDashboardService adds a dashboard to the stack.
func RegisterDashboardService(stack *node.Node, cfg *dashboard.Config, commit string) { func RegisterDashboardService(stack *node.Node, cfg *dashboard.Config, commit string) {

View file

@ -51,14 +51,6 @@ import (
"github.com/ethereum/go-ethereum/rpc" "github.com/ethereum/go-ethereum/rpc"
) )
type LesServer interface {
Start(srvr *p2p.Server)
Stop()
APIs() []rpc.API
Protocols() []p2p.Protocol
SetBloomBitsIndexer(bbIndexer *core.ChainIndexer)
}
// Ethereum implements the Ethereum full node service. // Ethereum implements the Ethereum full node service.
type Ethereum struct { type Ethereum struct {
config *Config config *Config
@ -70,7 +62,6 @@ type Ethereum struct {
txPool *core.TxPool txPool *core.TxPool
blockchain *core.BlockChain blockchain *core.BlockChain
protocolManager *ProtocolManager protocolManager *ProtocolManager
lesServer LesServer
// DB interfaces // DB interfaces
chainDb ethdb.Database // Block chain database chainDb ethdb.Database // Block chain database
@ -94,11 +85,6 @@ type Ethereum struct {
lock sync.RWMutex // Protects the variadic fields (e.g. gas price and etherbase) lock sync.RWMutex // Protects the variadic fields (e.g. gas price and etherbase)
} }
func (s *Ethereum) AddLesServer(ls LesServer) {
s.lesServer = ls
ls.SetBloomBitsIndexer(s.bloomIndexer)
}
// New creates a new Ethereum object (including the // New creates a new Ethereum object (including the
// initialisation of the common Ethereum object) // initialisation of the common Ethereum object)
func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) { func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) {
@ -256,15 +242,13 @@ func CreateConsensusEngine(ctx *node.ServiceContext, chainConfig *params.ChainCo
} }
} }
// APIs return the collection of RPC services the ethereum package offers. // APIs return the collection of RPC services the ethereum package offers.
// NOTE, some of these services probably need to be moved to somewhere else. // NOTE, some of these services probably need to be moved to somewhere else.
func (s *Ethereum) APIs() []rpc.API { func (s *Ethereum) APIs() []rpc.API {
apis := ethapi.GetAPIs(s.APIBackend) apis := ethapi.GetAPIs(s.APIBackend)
// Append any APIs exposed explicitly by the les server
if s.lesServer != nil {
apis = append(apis, s.lesServer.APIs()...)
}
// Append any APIs exposed explicitly by the consensus engine // Append any APIs exposed explicitly by the consensus engine
apis = append(apis, s.engine.APIs(s.BlockChain())...) apis = append(apis, s.engine.APIs(s.BlockChain())...)
@ -316,6 +300,11 @@ func (s *Ethereum) APIs() []rpc.API {
}, },
}...) }...)
} }
// GetBloomIndexer returns the bloombits indexer, primarily
// so that the Les Server service can re-use it
func (s *Ethereum) GetBloomIndexer() *core.ChainIndexer {
return s.bloomIndexer
}
func (s *Ethereum) ResetWithGenesisBlock(gb *types.Block) { func (s *Ethereum) ResetWithGenesisBlock(gb *types.Block) {
s.blockchain.ResetWithGenesisBlock(gb) s.blockchain.ResetWithGenesisBlock(gb)
@ -485,11 +474,8 @@ func (s *Ethereum) Synced() bool { return atomic.LoadUint3
// Protocols implements node.Service, returning all the currently configured // Protocols implements node.Service, returning all the currently configured
// network protocols to start. // network protocols to start.
func (s *Ethereum) Protocols() []p2p.Protocol { func (s *Ethereum) Protocols() []p2p.Protocol {
if s.lesServer == nil {
return s.protocolManager.SubProtocols return s.protocolManager.SubProtocols
} }
return append(s.protocolManager.SubProtocols, s.lesServer.Protocols()...)
}
// Start implements node.Service, starting all internal goroutines needed by the // Start implements node.Service, starting all internal goroutines needed by the
// Ethereum protocol implementation. // Ethereum protocol implementation.
@ -508,11 +494,10 @@ func (s *Ethereum) Start(srvr *p2p.Server) error {
} }
maxPeers -= s.config.LightPeers maxPeers -= s.config.LightPeers
} }
// Start the networking layer and the light server if requested // Start the networking layer and the light server if requested
s.protocolManager.Start(maxPeers) s.protocolManager.Start(maxPeers)
if s.lesServer != nil {
s.lesServer.Start(srvr)
}
return nil return nil
} }
@ -523,13 +508,9 @@ func (s *Ethereum) Stop() error {
s.blockchain.Stop() s.blockchain.Stop()
s.engine.Close() s.engine.Close()
s.protocolManager.Stop() s.protocolManager.Stop()
if s.lesServer != nil {
s.lesServer.Stop()
}
s.txPool.Stop() s.txPool.Stop()
s.miner.Stop() s.miner.Stop()
s.eventMux.Stop() s.eventMux.Stop()
s.chainDb.Close() s.chainDb.Close()
close(s.shutdownChan) close(s.shutdownChan)
return nil return nil

View file

@ -0,0 +1,8 @@
{
"folders": [
{
"path": "."
}
],
"settings": {}
}

View file

@ -29,8 +29,11 @@ import (
) )
var ( var (
// ErrMinCap capacity too small
ErrMinCap = errors.New("capacity too small") ErrMinCap = errors.New("capacity too small")
// ErrTotalCap total capacity exceeded
ErrTotalCap = errors.New("total capacity exceeded") ErrTotalCap = errors.New("total capacity exceeded")
// ErrUnknownBenchmarkType unknown benchmark type
ErrUnknownBenchmarkType = errors.New("unknown benchmark type") ErrUnknownBenchmarkType = errors.New("unknown benchmark type")
dropCapacityDelay = time.Second // delay applied to decreasing capacity changes dropCapacityDelay = time.Second // delay applied to decreasing capacity changes

View file

@ -39,37 +39,44 @@ import (
"github.com/ethereum/go-ethereum/rpc" "github.com/ethereum/go-ethereum/rpc"
) )
type LesApiBackend struct { // ClientBackend is a backend implementation for the light Client only
type ClientBackend struct {
extRPCEnabled bool extRPCEnabled bool
eth *LightEthereum eth *LightEthereum
gpo *gasprice.Oracle gpo *gasprice.Oracle
} }
func (b *LesApiBackend) ChainConfig() *params.ChainConfig { // ChainConfig returns the LightEthereum service config
func (b *ClientBackend) ChainConfig() *params.ChainConfig {
return b.eth.chainConfig return b.eth.chainConfig
} }
func (b *LesApiBackend) CurrentBlock() *types.Block { // CurrentBlock returns the LightEthereum service chain current header block
func (b *ClientBackend) CurrentBlock() *types.Block {
return types.NewBlockWithHeader(b.eth.BlockChain().CurrentHeader()) return types.NewBlockWithHeader(b.eth.BlockChain().CurrentHeader())
} }
func (b *LesApiBackend) SetHead(number uint64) { // SetHead cancels the downloader and sets the head to a certain number
func (b *ClientBackend) SetHead(number uint64) {
b.eth.protocolManager.downloader.Cancel() b.eth.protocolManager.downloader.Cancel()
b.eth.blockchain.SetHead(number) b.eth.blockchain.SetHead(number)
} }
func (b *LesApiBackend) HeaderByNumber(ctx context.Context, blockNr rpc.BlockNumber) (*types.Header, error) { // HeaderByNumber returns either the chain's current header or an on-demand-requested header, given a block number
func (b *ClientBackend) HeaderByNumber(ctx context.Context, blockNr rpc.BlockNumber) (*types.Header, error) {
if blockNr == rpc.LatestBlockNumber || blockNr == rpc.PendingBlockNumber { if blockNr == rpc.LatestBlockNumber || blockNr == rpc.PendingBlockNumber {
return b.eth.blockchain.CurrentHeader(), nil return b.eth.blockchain.CurrentHeader(), nil
} }
return b.eth.blockchain.GetHeaderByNumberOdr(ctx, uint64(blockNr)) return b.eth.blockchain.GetHeaderByNumberOdr(ctx, uint64(blockNr))
} }
func (b *LesApiBackend) HeaderByHash(ctx context.Context, hash common.Hash) (*types.Header, error) { // HeaderByHash returns a block header for the given block hash
func (b *ClientBackend) HeaderByHash(ctx context.Context, hash common.Hash) (*types.Header, error) {
return b.eth.blockchain.GetHeaderByHash(hash), nil return b.eth.blockchain.GetHeaderByHash(hash), nil
} }
func (b *LesApiBackend) BlockByNumber(ctx context.Context, blockNr rpc.BlockNumber) (*types.Block, error) { // BlockByNumber identifies a header by number and then returns the block with the corresponding block hash
func (b *ClientBackend) BlockByNumber(ctx context.Context, blockNr rpc.BlockNumber) (*types.Block, error) {
header, err := b.HeaderByNumber(ctx, blockNr) header, err := b.HeaderByNumber(ctx, blockNr)
if header == nil || err != nil { if header == nil || err != nil {
return nil, err return nil, err
@ -77,7 +84,8 @@ func (b *LesApiBackend) BlockByNumber(ctx context.Context, blockNr rpc.BlockNumb
return b.GetBlock(ctx, header.Hash()) return b.GetBlock(ctx, header.Hash())
} }
func (b *LesApiBackend) StateAndHeaderByNumber(ctx context.Context, blockNr rpc.BlockNumber) (*state.StateDB, *types.Header, error) { // StateAndHeaderByNumber identifies a block header by the supplied number, then returns that header's associated state and the header itself
func (b *ClientBackend) StateAndHeaderByNumber(ctx context.Context, blockNr rpc.BlockNumber) (*state.StateDB, *types.Header, error) {
header, err := b.HeaderByNumber(ctx, blockNr) header, err := b.HeaderByNumber(ctx, blockNr)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
@ -88,123 +96,157 @@ func (b *LesApiBackend) StateAndHeaderByNumber(ctx context.Context, blockNr rpc.
return light.NewState(ctx, header, b.eth.odr), header, nil return light.NewState(ctx, header, b.eth.odr), header, nil
} }
func (b *LesApiBackend) GetBlock(ctx context.Context, blockHash common.Hash) (*types.Block, error) { // GetBlock returns a block identified by block hash
func (b *ClientBackend) GetBlock(ctx context.Context, blockHash common.Hash) (*types.Block, error) {
return b.eth.blockchain.GetBlockByHash(ctx, blockHash) return b.eth.blockchain.GetBlockByHash(ctx, blockHash)
} }
func (b *LesApiBackend) GetReceipts(ctx context.Context, hash common.Hash) (types.Receipts, error) { // GetReceipts returns a set of receipts for a block, identified by the supplied hash
func (b *ClientBackend) GetReceipts(ctx context.Context, hash common.Hash) (types.Receipts, error) {
if number := rawdb.ReadHeaderNumber(b.eth.chainDb, hash); number != nil { if number := rawdb.ReadHeaderNumber(b.eth.chainDb, hash); number != nil {
return light.GetBlockReceipts(ctx, b.eth.odr, hash, *number) return light.GetBlockReceipts(ctx, b.eth.odr, hash, *number)
} }
return nil, nil return nil, nil
} }
func (b *LesApiBackend) GetLogs(ctx context.Context, hash common.Hash) ([][]*types.Log, error) { // GetLogs identifies the block header number given the supplied hash and then returns the block logs
func (b *ClientBackend) GetLogs(ctx context.Context, hash common.Hash) ([][]*types.Log, error) {
if number := rawdb.ReadHeaderNumber(b.eth.chainDb, hash); number != nil { if number := rawdb.ReadHeaderNumber(b.eth.chainDb, hash); number != nil {
return light.GetBlockLogs(ctx, b.eth.odr, hash, *number) return light.GetBlockLogs(ctx, b.eth.odr, hash, *number)
} }
return nil, nil return nil, nil
} }
func (b *LesApiBackend) GetTd(hash common.Hash) *big.Int { // GetTd retrieves a block's total difficulty in the canonical chain by hash
func (b *ClientBackend) GetTd(hash common.Hash) *big.Int {
return b.eth.blockchain.GetTdByHash(hash) return b.eth.blockchain.GetTdByHash(hash)
} }
func (b *LesApiBackend) GetEVM(ctx context.Context, msg core.Message, state *state.StateDB, header *types.Header) (*vm.EVM, func() error, error) { // GetEVM creates an EVM initialised with an account and balance from the supplied message
func (b *ClientBackend) GetEVM(ctx context.Context, msg core.Message, state *state.StateDB, header *types.Header) (*vm.EVM, func() error, error) {
state.SetBalance(msg.From(), math.MaxBig256) state.SetBalance(msg.From(), math.MaxBig256)
context := core.NewEVMContext(msg, header, b.eth.blockchain, nil) context := core.NewEVMContext(msg, header, b.eth.blockchain, nil)
return vm.NewEVM(context, state, b.eth.chainConfig, vm.Config{}), state.Error, nil return vm.NewEVM(context, state, b.eth.chainConfig, vm.Config{}), state.Error, nil
} }
func (b *LesApiBackend) SendTx(ctx context.Context, signedTx *types.Transaction) error { // SendTx add the transaction to the local transaction pool
func (b *ClientBackend) SendTx(ctx context.Context, signedTx *types.Transaction) error {
return b.eth.txPool.Add(ctx, signedTx) return b.eth.txPool.Add(ctx, signedTx)
} }
func (b *LesApiBackend) RemoveTx(txHash common.Hash) { // RemoveTx removes a transaction from the local transaction pool
func (b *ClientBackend) RemoveTx(txHash common.Hash) {
b.eth.txPool.RemoveTx(txHash) b.eth.txPool.RemoveTx(txHash)
} }
func (b *LesApiBackend) GetPoolTransactions() (types.Transactions, error) { // GetPoolTransactions returns all currently processable transactions.
func (b *ClientBackend) GetPoolTransactions() (types.Transactions, error) {
return b.eth.txPool.GetTransactions() return b.eth.txPool.GetTransactions()
} }
func (b *LesApiBackend) GetPoolTransaction(txHash common.Hash) *types.Transaction { // GetPoolTransaction returns a transaction if it is contained in the pool and nil otherwise.
func (b *ClientBackend) GetPoolTransaction(txHash common.Hash) *types.Transaction {
return b.eth.txPool.GetTransaction(txHash) return b.eth.txPool.GetTransaction(txHash)
} }
func (b *LesApiBackend) GetTransaction(ctx context.Context, txHash common.Hash) (*types.Transaction, common.Hash, uint64, uint64, error) { // GetTransaction retrieves a canonical transaction by hash and also returns its position in the chain
func (b *ClientBackend) GetTransaction(ctx context.Context, txHash common.Hash) (*types.Transaction, common.Hash, uint64, uint64, error) {
return light.GetTransaction(ctx, b.eth.odr, txHash) return light.GetTransaction(ctx, b.eth.odr, txHash)
} }
func (b *LesApiBackend) GetPoolNonce(ctx context.Context, addr common.Address) (uint64, error) { // GetPoolNonce returns the "pending" nonce of a given address. It always queries
// the nonce belonging to the latest header too in order to detect if another
// client using the same key sent a transaction.
func (b *ClientBackend) GetPoolNonce(ctx context.Context, addr common.Address) (uint64, error) {
return b.eth.txPool.GetNonce(ctx, addr) return b.eth.txPool.GetNonce(ctx, addr)
} }
func (b *LesApiBackend) Stats() (pending int, queued int) { // Stats returns the number of currently pending (locally created) transactions
func (b *ClientBackend) Stats() (pending int, queued int) {
return b.eth.txPool.Stats(), 0 return b.eth.txPool.Stats(), 0
} }
func (b *LesApiBackend) TxPoolContent() (map[common.Address]types.Transactions, map[common.Address]types.Transactions) { // TxPoolContent retrieves the data content of the transaction pool, returning all the
// pending as well as queued transactions, grouped by account and nonce.
func (b *ClientBackend) TxPoolContent() (map[common.Address]types.Transactions, map[common.Address]types.Transactions) {
return b.eth.txPool.Content() return b.eth.txPool.Content()
} }
func (b *LesApiBackend) SubscribeNewTxsEvent(ch chan<- core.NewTxsEvent) event.Subscription { // SubscribeNewTxsEvent registers a subscription of core.NewTxsEvent and
// starts sending event to the given channel.
func (b *ClientBackend) SubscribeNewTxsEvent(ch chan<- core.NewTxsEvent) event.Subscription {
return b.eth.txPool.SubscribeNewTxsEvent(ch) return b.eth.txPool.SubscribeNewTxsEvent(ch)
} }
func (b *LesApiBackend) SubscribeChainEvent(ch chan<- core.ChainEvent) event.Subscription { // SubscribeChainEvent registers a subscription of ChainEvent.
func (b *ClientBackend) SubscribeChainEvent(ch chan<- core.ChainEvent) event.Subscription {
return b.eth.blockchain.SubscribeChainEvent(ch) return b.eth.blockchain.SubscribeChainEvent(ch)
} }
func (b *LesApiBackend) SubscribeChainHeadEvent(ch chan<- core.ChainHeadEvent) event.Subscription { // SubscribeChainHeadEvent registers a subscription of ChainHeadEvent.
func (b *ClientBackend) SubscribeChainHeadEvent(ch chan<- core.ChainHeadEvent) event.Subscription {
return b.eth.blockchain.SubscribeChainHeadEvent(ch) return b.eth.blockchain.SubscribeChainHeadEvent(ch)
} }
func (b *LesApiBackend) SubscribeChainSideEvent(ch chan<- core.ChainSideEvent) event.Subscription { // SubscribeChainSideEvent registers a subscription of ChainSideEvent.
func (b *ClientBackend) SubscribeChainSideEvent(ch chan<- core.ChainSideEvent) event.Subscription {
return b.eth.blockchain.SubscribeChainSideEvent(ch) return b.eth.blockchain.SubscribeChainSideEvent(ch)
} }
func (b *LesApiBackend) SubscribeLogsEvent(ch chan<- []*types.Log) event.Subscription { // SubscribeLogsEvent implements the interface of filters.Backend
// LightChain does not send logs events, so return an empty subscription.
func (b *ClientBackend) SubscribeLogsEvent(ch chan<- []*types.Log) event.Subscription {
return b.eth.blockchain.SubscribeLogsEvent(ch) return b.eth.blockchain.SubscribeLogsEvent(ch)
} }
func (b *LesApiBackend) SubscribeRemovedLogsEvent(ch chan<- core.RemovedLogsEvent) event.Subscription { // SubscribeRemovedLogsEvent implements the interface of filters.Backend
// LightChain does not send core.RemovedLogsEvent, so return an empty subscription.
func (b *ClientBackend) SubscribeRemovedLogsEvent(ch chan<- core.RemovedLogsEvent) event.Subscription {
return b.eth.blockchain.SubscribeRemovedLogsEvent(ch) return b.eth.blockchain.SubscribeRemovedLogsEvent(ch)
} }
func (b *LesApiBackend) Downloader() *downloader.Downloader { // Downloader returns the LightEthereum downloader
func (b *ClientBackend) Downloader() *downloader.Downloader {
return b.eth.Downloader() return b.eth.Downloader()
} }
func (b *LesApiBackend) ProtocolVersion() int { // ProtocolVersion return the Les version number offset by 10000
func (b *ClientBackend) ProtocolVersion() int {
return b.eth.LesVersion() + 10000 return b.eth.LesVersion() + 10000
} }
func (b *LesApiBackend) SuggestPrice(ctx context.Context) (*big.Int, error) { // SuggestPrice returns the gas price oracle price suggestion
func (b *ClientBackend) SuggestPrice(ctx context.Context) (*big.Int, error) {
return b.gpo.SuggestPrice(ctx) return b.gpo.SuggestPrice(ctx)
} }
func (b *LesApiBackend) ChainDb() ethdb.Database { // ChainDb returns the ClientBackend db representation
func (b *ClientBackend) ChainDb() ethdb.Database {
return b.eth.chainDb return b.eth.chainDb
} }
func (b *LesApiBackend) EventMux() *event.TypeMux { // EventMux ...
func (b *ClientBackend) EventMux() *event.TypeMux {
return b.eth.eventMux return b.eth.eventMux
} }
func (b *LesApiBackend) AccountManager() *accounts.Manager { // AccountManager returns an overarching account manager needed for signing transactions
func (b *ClientBackend) AccountManager() *accounts.Manager {
return b.eth.accountManager return b.eth.accountManager
} }
func (b *LesApiBackend) ExtRPCEnabled() bool { // ExtRPCEnabled indicates if the external RPC API is enabled
func (b *ClientBackend) ExtRPCEnabled() bool {
return b.extRPCEnabled return b.extRPCEnabled
} }
func (b *LesApiBackend) RPCGasCap() *big.Int { // RPCGasCap - return the global gas cap for eth_call over rpc (DoS protection)
func (b *ClientBackend) RPCGasCap() *big.Int {
return b.eth.config.RPCGasCap return b.eth.config.RPCGasCap
} }
func (b *LesApiBackend) BloomStatus() (uint64, uint64) { // BloomStatus ..
func (b *ClientBackend) BloomStatus() (uint64, uint64) {
if b.eth.bloomIndexer == nil { if b.eth.bloomIndexer == nil {
return 0, 0 return 0, 0
} }
@ -212,7 +254,8 @@ func (b *LesApiBackend) BloomStatus() (uint64, uint64) {
return params.BloomBitsBlocksClient, sections return params.BloomBitsBlocksClient, sections
} }
func (b *LesApiBackend) ServiceFilter(ctx context.Context, session *bloombits.MatcherSession) { // ServiceFilter ...
func (b *ClientBackend) ServiceFilter(ctx context.Context, session *bloombits.MatcherSession) {
for i := 0; i < bloomFilterThreads; i++ { for i := 0; i < bloomFilterThreads; i++ {
go session.Multiplex(bloomRetrievalBatch, bloomRetrievalWait, b.eth.bloomRequests) go session.Multiplex(bloomRetrievalBatch, bloomRetrievalWait, b.eth.bloomRequests)
} }

View file

@ -90,15 +90,15 @@ func testCapacityAPI(t *testing.T, clientCount int) {
} }
server := servers[0] server := servers[0]
clientRpcClients := make([]*rpc.Client, len(clients)) clientRPCClients := make([]*rpc.Client, len(clients))
serverRpcClient, err := server.Client() serverRPCClient, err := server.Client()
if err != nil { if err != nil {
t.Fatalf("Failed to obtain rpc client: %v", err) t.Fatalf("Failed to obtain rpc client: %v", err)
} }
headNum, headHash := getHead(ctx, t, serverRpcClient) headNum, headHash := getHead(ctx, t, serverRPCClient)
totalCap := getTotalCap(ctx, t, serverRpcClient) totalCap := getTotalCap(ctx, t, serverRPCClient)
minCap := getMinCap(ctx, t, serverRpcClient) minCap := getMinCap(ctx, t, serverRPCClient)
testCap := totalCap * 3 / 4 testCap := totalCap * 3 / 4
fmt.Printf("Server testCap: %d minCap: %d head number: %d head hash: %064x\n", testCap, minCap, headNum, headHash) fmt.Printf("Server testCap: %d minCap: %d head number: %d head hash: %064x\n", testCap, minCap, headNum, headHash)
reqMinCap := uint64(float64(testCap) * minRelCap / (minRelCap + float64(len(clients)-1))) reqMinCap := uint64(float64(testCap) * minRelCap / (minRelCap + float64(len(clients)-1)))
@ -107,18 +107,18 @@ func testCapacityAPI(t *testing.T, clientCount int) {
} }
freeIdx := rand.Intn(len(clients)) freeIdx := rand.Intn(len(clients))
freeCap := getFreeCap(ctx, t, serverRpcClient) freeCap := getFreeCap(ctx, t, serverRPCClient)
for i, client := range clients { for i, client := range clients {
var err error var err error
clientRpcClients[i], err = client.Client() clientRPCClients[i], err = client.Client()
if err != nil { if err != nil {
t.Fatalf("Failed to obtain rpc client: %v", err) t.Fatalf("Failed to obtain rpc client: %v", err)
} }
fmt.Println("connecting client", i) fmt.Println("connecting client", i)
if i != freeIdx { if i != freeIdx {
setCapacity(ctx, t, serverRpcClient, client.ID(), testCap/uint64(len(clients))) setCapacity(ctx, t, serverRPCClient, client.ID(), testCap/uint64(len(clients)))
} }
net.Connect(client.ID(), server.ID()) net.Connect(client.ID(), server.ID())
@ -128,7 +128,7 @@ func testCapacityAPI(t *testing.T, clientCount int) {
t.Fatalf("Timeout") t.Fatalf("Timeout")
default: default:
} }
num, hash := getHead(ctx, t, clientRpcClients[i]) num, hash := getHead(ctx, t, clientRPCClients[i])
if num == headNum && hash == headHash { if num == headNum && hash == headHash {
fmt.Println("client", i, "synced") fmt.Println("client", i, "synced")
break break
@ -140,9 +140,9 @@ func testCapacityAPI(t *testing.T, clientCount int) {
var wg sync.WaitGroup var wg sync.WaitGroup
stop := make(chan struct{}) stop := make(chan struct{})
reqCount := make([]uint64, len(clientRpcClients)) reqCount := make([]uint64, len(clientRPCClients))
for i, c := range clientRpcClients { for i, c := range clientRPCClients {
wg.Add(1) wg.Add(1)
i, c := i, c i, c := i, c
go func() { go func() {
@ -194,7 +194,7 @@ func testCapacityAPI(t *testing.T, clientCount int) {
weights := make([]float64, len(clients)) weights := make([]float64, len(clients))
for c := 0; c < 5; c++ { for c := 0; c < 5; c++ {
setCapacity(ctx, t, serverRpcClient, clients[freeIdx].ID(), freeCap) setCapacity(ctx, t, serverRPCClient, clients[freeIdx].ID(), freeCap)
freeIdx = rand.Intn(len(clients)) freeIdx = rand.Intn(len(clients))
var sum float64 var sum float64
for i := range clients { for i := range clients {
@ -208,15 +208,15 @@ func testCapacityAPI(t *testing.T, clientCount int) {
for i, client := range clients { for i, client := range clients {
weights[i] *= float64(testCap-freeCap-100) / sum weights[i] *= float64(testCap-freeCap-100) / sum
capacity := uint64(weights[i]) capacity := uint64(weights[i])
if i != freeIdx && capacity < getCapacity(ctx, t, serverRpcClient, client.ID()) { if i != freeIdx && capacity < getCapacity(ctx, t, serverRPCClient, client.ID()) {
setCapacity(ctx, t, serverRpcClient, client.ID(), capacity) setCapacity(ctx, t, serverRPCClient, client.ID(), capacity)
} }
} }
setCapacity(ctx, t, serverRpcClient, clients[freeIdx].ID(), 0) setCapacity(ctx, t, serverRPCClient, clients[freeIdx].ID(), 0)
for i, client := range clients { for i, client := range clients {
capacity := uint64(weights[i]) capacity := uint64(weights[i])
if i != freeIdx && capacity > getCapacity(ctx, t, serverRpcClient, client.ID()) { if i != freeIdx && capacity > getCapacity(ctx, t, serverRPCClient, client.ID()) {
setCapacity(ctx, t, serverRpcClient, client.ID(), capacity) setCapacity(ctx, t, serverRPCClient, client.ID(), capacity)
} }
} }
weights[freeIdx] = float64(freeCap) weights[freeIdx] = float64(freeCap)
@ -239,7 +239,7 @@ func testCapacityAPI(t *testing.T, clientCount int) {
default: default:
} }
totalCap = getTotalCap(ctx, t, serverRpcClient) totalCap = getTotalCap(ctx, t, serverRPCClient)
if totalCap < testCap { if totalCap < testCap {
fmt.Println("Total capacity underrun") fmt.Println("Total capacity underrun")
close(stop) close(stop)
@ -520,6 +520,6 @@ func newLesServerService(ctx *adapters.ServiceContext) (node.Service, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
ethereum.AddLesServer(server)
return ethereum, nil return server, nil
} }

View file

@ -46,6 +46,7 @@ import (
rpc "github.com/ethereum/go-ethereum/rpc" rpc "github.com/ethereum/go-ethereum/rpc"
) )
// LightEthereum is a light client service
type LightEthereum struct { type LightEthereum struct {
lesCommons lesCommons
@ -66,18 +67,19 @@ type LightEthereum struct {
bloomRequests chan chan *bloombits.Retrieval // Channel receiving bloom data retrieval requests bloomRequests chan chan *bloombits.Retrieval // Channel receiving bloom data retrieval requests
bloomIndexer *core.ChainIndexer bloomIndexer *core.ChainIndexer
ApiBackend *LesApiBackend APIBackend *ClientBackend
eventMux *event.TypeMux eventMux *event.TypeMux
engine consensus.Engine engine consensus.Engine
accountManager *accounts.Manager accountManager *accounts.Manager
networkId uint64 networkID uint64
netRPCService *ethapi.PublicNetAPI netRPCService *ethapi.PublicNetAPI
wg sync.WaitGroup wg sync.WaitGroup
} }
// New constructs a LightEthereum client
func New(ctx *node.ServiceContext, config *eth.Config) (*LightEthereum, error) { func New(ctx *node.ServiceContext, config *eth.Config) (*LightEthereum, error) {
chainDb, err := ctx.OpenDatabase("lightchaindata", config.DatabaseCache, config.DatabaseHandles, "eth/db/chaindata/") chainDb, err := ctx.OpenDatabase("lightchaindata", config.DatabaseCache, config.DatabaseHandles, "eth/db/chaindata/")
if err != nil { if err != nil {
@ -105,7 +107,7 @@ func New(ctx *node.ServiceContext, config *eth.Config) (*LightEthereum, error) {
accountManager: ctx.AccountManager, accountManager: ctx.AccountManager,
engine: eth.CreateConsensusEngine(ctx, chainConfig, &config.Ethash, nil, false, chainDb), engine: eth.CreateConsensusEngine(ctx, chainConfig, &config.Ethash, nil, false, chainDb),
shutdownChan: make(chan bool), shutdownChan: make(chan bool),
networkId: config.NetworkId, networkID: config.NetworkId,
bloomRequests: make(chan chan *bloombits.Retrieval), bloomRequests: make(chan chan *bloombits.Retrieval),
bloomIndexer: eth.NewBloomIndexer(chainDb, params.BloomBitsBlocksClient, params.HelperTrieConfirmations), bloomIndexer: eth.NewBloomIndexer(chainDb, params.BloomBitsBlocksClient, params.HelperTrieConfirmations),
} }
@ -167,13 +169,13 @@ func New(ctx *node.ServiceContext, config *eth.Config) (*LightEthereum, error) {
log.Warn("Ultra light client is enabled", "trustedNodes", len(leth.protocolManager.ulc.trustedKeys), "minTrustedFraction", leth.protocolManager.ulc.minTrustedFraction) log.Warn("Ultra light client is enabled", "trustedNodes", len(leth.protocolManager.ulc.trustedKeys), "minTrustedFraction", leth.protocolManager.ulc.minTrustedFraction)
leth.blockchain.DisableCheckFreq() leth.blockchain.DisableCheckFreq()
} }
leth.ApiBackend = &LesApiBackend{ctx.ExtRPCEnabled(), leth, nil} leth.APIBackend = &ClientBackend{ctx.ExtRPCEnabled(), leth, nil}
gpoParams := config.GPO gpoParams := config.GPO
if gpoParams.Default == nil { if gpoParams.Default == nil {
gpoParams.Default = config.Miner.GasPrice gpoParams.Default = config.Miner.GasPrice
} }
leth.ApiBackend.gpo = gasprice.NewOracle(leth.ApiBackend, gpoParams) leth.APIBackend.gpo = gasprice.NewOracle(leth.APIBackend, gpoParams)
return leth, nil return leth, nil
} }
@ -188,6 +190,7 @@ func lesTopic(genesisHash common.Hash, protocolVersion uint) discv5.Topic {
return discv5.Topic(name + "@" + common.Bytes2Hex(genesisHash.Bytes()[0:8])) return discv5.Topic(name + "@" + common.Bytes2Hex(genesisHash.Bytes()[0:8]))
} }
// LightDummyAPI is a fake api that serves default values in the role of a light client
type LightDummyAPI struct{} type LightDummyAPI struct{}
// Etherbase is the address that mining rewards will be send to // Etherbase is the address that mining rewards will be send to
@ -213,7 +216,7 @@ func (s *LightDummyAPI) Mining() bool {
// APIs returns the collection of RPC services the ethereum package offers. // APIs returns the collection of RPC services the ethereum package offers.
// NOTE, some of these services probably need to be moved to somewhere else. // NOTE, some of these services probably need to be moved to somewhere else.
func (s *LightEthereum) APIs() []rpc.API { func (s *LightEthereum) APIs() []rpc.API {
return append(ethapi.GetAPIs(s.ApiBackend), []rpc.API{ return append(ethapi.GetAPIs(s.APIBackend), []rpc.API{
{ {
Namespace: "eth", Namespace: "eth",
Version: "1.0", Version: "1.0",
@ -227,7 +230,7 @@ func (s *LightEthereum) APIs() []rpc.API {
}, { }, {
Namespace: "eth", Namespace: "eth",
Version: "1.0", Version: "1.0",
Service: filters.NewPublicFilterAPI(s.ApiBackend, true), Service: filters.NewPublicFilterAPI(s.APIBackend, true),
Public: true, Public: true,
}, { }, {
Namespace: "net", Namespace: "net",
@ -238,15 +241,28 @@ func (s *LightEthereum) APIs() []rpc.API {
}...) }...)
} }
// ResetWithGenesisBlock purges the entire blockchain, restoring it to the
// specified genesis state.
func (s *LightEthereum) ResetWithGenesisBlock(gb *types.Block) { func (s *LightEthereum) ResetWithGenesisBlock(gb *types.Block) {
s.blockchain.ResetWithGenesisBlock(gb) s.blockchain.ResetWithGenesisBlock(gb)
} }
// BlockChain returns the light client's blockchain
func (s *LightEthereum) BlockChain() *light.LightChain { return s.blockchain } func (s *LightEthereum) BlockChain() *light.LightChain { return s.blockchain }
// TxPool the pool of locally created transactions
func (s *LightEthereum) TxPool() *light.TxPool { return s.txPool } func (s *LightEthereum) TxPool() *light.TxPool { return s.txPool }
// Engine is the employed consensus engine
func (s *LightEthereum) Engine() consensus.Engine { return s.engine } func (s *LightEthereum) Engine() consensus.Engine { return s.engine }
// LesVersion is the current version of Les used by this light client
func (s *LightEthereum) LesVersion() int { return int(ClientProtocolVersions[0]) } func (s *LightEthereum) LesVersion() int { return int(ClientProtocolVersions[0]) }
// Downloader is the employed downloader
func (s *LightEthereum) Downloader() *downloader.Downloader { return s.protocolManager.downloader } func (s *LightEthereum) Downloader() *downloader.Downloader { return s.protocolManager.downloader }
// EventMux is an event subscription notifier
func (s *LightEthereum) EventMux() *event.TypeMux { return s.eventMux } func (s *LightEthereum) EventMux() *event.TypeMux { return s.eventMux }
// Protocols implements node.Service, returning all the currently configured // Protocols implements node.Service, returning all the currently configured
@ -260,7 +276,7 @@ func (s *LightEthereum) Protocols() []p2p.Protocol {
func (s *LightEthereum) Start(srvr *p2p.Server) error { func (s *LightEthereum) Start(srvr *p2p.Server) error {
log.Warn("Light client mode is an experimental feature") log.Warn("Light client mode is an experimental feature")
s.startBloomHandlers(params.BloomBitsBlocksClient) s.startBloomHandlers(params.BloomBitsBlocksClient)
s.netRPCService = ethapi.NewPublicNetAPI(srvr, s.networkId) s.netRPCService = ethapi.NewPublicNetAPI(srvr, s.networkID)
// clients are searching for the first advertised protocol in the list // clients are searching for the first advertised protocol in the list
protocolVersion := AdvertiseProtocolVersions[0] protocolVersion := AdvertiseProtocolVersions[0]
s.serverPool.start(srvr, lesTopic(s.blockchain.Genesis().Hash(), protocolVersion)) s.serverPool.start(srvr, lesTopic(s.blockchain.Genesis().Hash(), protocolVersion))

View file

@ -74,9 +74,9 @@ func (b *benchmarkBlockHeaders) init(pm *ProtocolManager, count int) error {
func (b *benchmarkBlockHeaders) request(peer *peer, index int) error { func (b *benchmarkBlockHeaders) request(peer *peer, index int) error {
if b.byHash { if b.byHash {
return peer.RequestHeadersByHash(0, 0, b.hashes[index], b.amount, b.skip, b.reverse) return peer.RequestHeadersByHash(0, 0, b.hashes[index], b.amount, b.skip, b.reverse)
} else {
return peer.RequestHeadersByNumber(0, 0, uint64(b.offset+rand.Int63n(b.randMax)), b.amount, b.skip, b.reverse)
} }
return peer.RequestHeadersByNumber(0, 0, uint64(b.offset+rand.Int63n(b.randMax)), b.amount, b.skip, b.reverse)
} }
// benchmarkBodiesOrReceipts implements requestBenchmark // benchmarkBodiesOrReceipts implements requestBenchmark
@ -97,9 +97,9 @@ func (b *benchmarkBodiesOrReceipts) init(pm *ProtocolManager, count int) error {
func (b *benchmarkBodiesOrReceipts) request(peer *peer, index int) error { func (b *benchmarkBodiesOrReceipts) request(peer *peer, index int) error {
if b.receipts { if b.receipts {
return peer.RequestReceipts(0, 0, []common.Hash{b.hashes[index]}) return peer.RequestReceipts(0, 0, []common.Hash{b.hashes[index]})
} else {
return peer.RequestBodies(0, 0, []common.Hash{b.hashes[index]})
} }
return peer.RequestBodies(0, 0, []common.Hash{b.hashes[index]})
} }
// benchmarkProofsOrCode implements requestBenchmark // benchmarkProofsOrCode implements requestBenchmark
@ -118,9 +118,9 @@ func (b *benchmarkProofsOrCode) request(peer *peer, index int) error {
rand.Read(key) rand.Read(key)
if b.code { if b.code {
return peer.RequestCode(0, 0, []CodeReq{{BHash: b.headHash, AccKey: key}}) return peer.RequestCode(0, 0, []CodeReq{{BHash: b.headHash, AccKey: key}})
} else {
return peer.RequestProofs(0, 0, []ProofReq{{BHash: b.headHash, Key: key}})
} }
return peer.RequestProofs(0, 0, []ProofReq{{BHash: b.headHash, Key: key}})
} }
// benchmarkHelperTrie implements requestBenchmark // benchmarkHelperTrie implements requestBenchmark
@ -281,8 +281,8 @@ func (pm *ProtocolManager) measure(setup *benchmarkSetup, count int) error {
serverMeteredPipe := &meteredPipe{rw: serverPipe} serverMeteredPipe := &meteredPipe{rw: serverPipe}
var id enode.ID var id enode.ID
rand.Read(id[:]) rand.Read(id[:])
clientPeer := pm.newPeer(lpv2, NetworkId, p2p.NewPeer(id, "client", nil), clientMeteredPipe) clientPeer := pm.newPeer(lpv2, NetworkID, p2p.NewPeer(id, "client", nil), clientMeteredPipe)
serverPeer := pm.newPeer(lpv2, NetworkId, p2p.NewPeer(id, "server", nil), serverMeteredPipe) serverPeer := pm.newPeer(lpv2, NetworkID, p2p.NewPeer(id, "server", nil), serverMeteredPipe)
serverPeer.sendQueue = newExecQueue(count) serverPeer.sendQueue = newExecQueue(count)
serverPeer.announceType = announceTypeNone serverPeer.announceType = announceTypeNone
serverPeer.fcCosts = make(requestCostTable) serverPeer.fcCosts = make(requestCostTable)

View file

@ -51,7 +51,7 @@ func testFreeClientPool(t *testing.T, connLimit, clientCount int) {
peerAddress = func(i int) string { peerAddress = func(i int) string {
return fmt.Sprintf("addr #%d", i) return fmt.Sprintf("addr #%d", i)
} }
peerId = func(i int) string { peerID = func(i int) string {
return fmt.Sprintf("id #%d", i) return fmt.Sprintf("id #%d", i)
} }
disconnFn = func(id string) { disconnFn = func(id string) {
@ -67,14 +67,14 @@ func testFreeClientPool(t *testing.T, connLimit, clientCount int) {
// pool should accept new peers up to its connected limit // pool should accept new peers up to its connected limit
for i := 0; i < connLimit; i++ { for i := 0; i < connLimit; i++ {
if pool.connect(peerAddress(i), peerId(i)) { if pool.connect(peerAddress(i), peerID(i)) {
connected[i] = true connected[i] = true
} else { } else {
t.Fatalf("Test peer #%d rejected", i) t.Fatalf("Test peer #%d rejected", i)
} }
} }
// since all accepted peers are new and should not be kicked out, the next one should be rejected // since all accepted peers are new and should not be kicked out, the next one should be rejected
if pool.connect(peerAddress(connLimit), peerId(connLimit)) { if pool.connect(peerAddress(connLimit), peerID(connLimit)) {
connected[connLimit] = true connected[connLimit] = true
t.Fatalf("Peer accepted over connected limit") t.Fatalf("Peer accepted over connected limit")
} }
@ -89,7 +89,7 @@ func testFreeClientPool(t *testing.T, connLimit, clientCount int) {
connected[i] = false connected[i] = false
connTicks[i] += tickCounter connTicks[i] += tickCounter
} else { } else {
if pool.connect(peerAddress(i), peerId(i)) { if pool.connect(peerAddress(i), peerID(i)) {
connected[i] = true connected[i] = true
connTicks[i] -= tickCounter connTicks[i] -= tickCounter
} }
@ -135,7 +135,7 @@ func testFreeClientPool(t *testing.T, connLimit, clientCount int) {
// try connecting all known peers (connLimit should be filled up) // try connecting all known peers (connLimit should be filled up)
for i := 0; i < clientCount; i++ { for i := 0; i < clientCount; i++ {
pool.connect(peerAddress(i), peerId(i)) pool.connect(peerAddress(i), peerID(i))
} }
// expect pool to remember known nodes and kick out one of them to accept a new one // expect pool to remember known nodes and kick out one of them to accept a new one
if !pool.connect("newAddr2", "newId2") { if !pool.connect("newAddr2", "newId2") {

View file

@ -49,14 +49,22 @@ const (
ethVersion = 63 // equivalent eth version for the downloader ethVersion = 63 // equivalent eth version for the downloader
MaxHeaderFetch = 192 // Amount of block headers to be fetched per retrieval request // MaxHeaderFetch - Amount of block headers to be fetched per retrieval request
MaxBodyFetch = 32 // Amount of block bodies to be fetched per retrieval request MaxHeaderFetch = 192
MaxReceiptFetch = 128 // Amount of transaction receipts to allow fetching per request // MaxBodyFetch - Amount of block bodies to be fetched per retrieval request
MaxCodeFetch = 64 // Amount of contract codes to allow fetching per request MaxBodyFetch = 32
MaxProofsFetch = 64 // Amount of merkle proofs to be fetched per retrieval request // MaxReceiptFetch - Amount of transaction receipts to allow fetching per request
MaxHelperTrieProofsFetch = 64 // Amount of merkle proofs to be fetched per retrieval request MaxReceiptFetch = 128
MaxTxSend = 64 // Amount of transactions to be send per request // MaxCodeFetch - Amount of contract codes to allow fetching per request
MaxTxStatus = 256 // Amount of transactions to queried per request MaxCodeFetch = 64
// MaxProofsFetch - Amount of merkle proofs to be fetched per retrieval request
MaxProofsFetch = 64
// MaxHelperTrieProofsFetch - Amount of merkle proofs to be fetched per retrieval request
MaxHelperTrieProofsFetch = 64
// MaxTxSend - Amount of transactions to be send per request
MaxTxSend = 64
// MaxTxStatus - Amount of transactions to queried per request
MaxTxStatus = 256
disableClientRemovePeer = false disableClientRemovePeer = false
) )
@ -65,6 +73,7 @@ func errResp(code errCode, format string, v ...interface{}) error {
return fmt.Errorf("%v - %v", code, fmt.Sprintf(format, v...)) return fmt.Errorf("%v - %v", code, fmt.Sprintf(format, v...))
} }
// BlockChain - a blockchain
type BlockChain interface { type BlockChain interface {
Config() *params.ChainConfig Config() *params.ChainConfig
HasHeader(hash common.Hash, number uint64) bool HasHeader(hash common.Hash, number uint64) bool
@ -86,6 +95,7 @@ type txPool interface {
Status(hashes []common.Hash) []core.TxStatus Status(hashes []common.Hash) []core.TxStatus
} }
// ProtocolManager handles protocol messages and other protocol-specific tasks
type ProtocolManager struct { type ProtocolManager struct {
// Configs // Configs
chainConfig *params.ChainConfig chainConfig *params.ChainConfig
@ -93,7 +103,7 @@ type ProtocolManager struct {
client bool // The indicator whether the node is light client client bool // The indicator whether the node is light client
maxPeers int // The maximum number peers allowed to connect. maxPeers int // The maximum number peers allowed to connect.
networkId uint64 // The identity of network. networkID uint64 // The identity of network.
txpool txPool txpool txPool
txrelay *LesTxRelay txrelay *LesTxRelay
@ -129,7 +139,7 @@ func NewProtocolManager(
chainConfig *params.ChainConfig, chainConfig *params.ChainConfig,
indexerConfig *light.IndexerConfig, indexerConfig *light.IndexerConfig,
client bool, client bool,
networkId uint64, networkID uint64,
mux *event.TypeMux, mux *event.TypeMux,
engine consensus.Engine, engine consensus.Engine,
peers *peerSet, peers *peerSet,
@ -151,7 +161,7 @@ func NewProtocolManager(
iConfig: indexerConfig, iConfig: indexerConfig,
chainDb: chainDb, chainDb: chainDb,
odr: odr, odr: odr,
networkId: networkId, networkID: networkID,
txpool: txpool, txpool: txpool,
txrelay: txrelay, txrelay: txrelay,
serverPool: serverPool, serverPool: serverPool,
@ -194,6 +204,7 @@ func (pm *ProtocolManager) removePeer(id string) {
pm.peers.Unregister(id) pm.peers.Unregister(id)
} }
// Start starts the protocol manager and is called during node startup only
func (pm *ProtocolManager) Start(maxPeers int) { func (pm *ProtocolManager) Start(maxPeers int) {
pm.maxPeers = maxPeers pm.maxPeers = maxPeers
if pm.client { if pm.client {
@ -206,6 +217,7 @@ func (pm *ProtocolManager) Start(maxPeers int) {
} }
} }
// Stop stops the protocol manager and is called during node shutdown only
func (pm *ProtocolManager) Stop() { func (pm *ProtocolManager) Stop() {
// Showing a log message. During download / process this could actually // Showing a log message. During download / process this could actually
// take between 5 to 10 seconds and therefor feedback is required. // take between 5 to 10 seconds and therefor feedback is required.
@ -236,7 +248,7 @@ func (pm *ProtocolManager) Stop() {
// runPeer is the p2p protocol run function for the given version. // runPeer is the p2p protocol run function for the given version.
func (pm *ProtocolManager) runPeer(version uint, p *p2p.Peer, rw p2p.MsgReadWriter) error { func (pm *ProtocolManager) runPeer(version uint, p *p2p.Peer, rw p2p.MsgReadWriter) error {
var entry *poolEntry var entry *poolEntry
peer := pm.newPeer(int(version), pm.networkId, p, rw) peer := pm.newPeer(int(version), pm.networkID, p, rw)
if pm.serverPool != nil { if pm.serverPool != nil {
entry = pm.serverPool.connect(peer, peer.Node()) entry = pm.serverPool.connect(peer, peer.Node())
} }

View file

@ -170,7 +170,7 @@ func newTestProtocolManager(lightSync bool, blocks int, generator func(int, *cor
if lightSync { if lightSync {
indexConfig = light.TestClientIndexerConfig indexConfig = light.TestClientIndexerConfig
} }
pm, err := NewProtocolManager(gspec.Config, indexConfig, lightSync, NetworkId, evmux, engine, peers, chain, pool, db, odr, nil, nil, make(chan struct{}), new(sync.WaitGroup), ulcConfig, func() bool { return true }) pm, err := NewProtocolManager(gspec.Config, indexConfig, lightSync, NetworkID, evmux, engine, peers, chain, pool, db, odr, nil, nil, make(chan struct{}), new(sync.WaitGroup), ulcConfig, func() bool { return true })
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -218,7 +218,7 @@ func newTestPeer(t *testing.T, name string, version int, pm *ProtocolManager, sh
var id enode.ID var id enode.ID
rand.Read(id[:]) rand.Read(id[:])
peer := pm.newPeer(version, NetworkId, p2p.NewPeer(id, name, nil), net) peer := pm.newPeer(version, NetworkID, p2p.NewPeer(id, name, nil), net)
// Start the peer on a new thread // Start the peer on a new thread
errc := make(chan error, 1) errc := make(chan error, 1)
@ -255,8 +255,8 @@ func newTestPeerPair(name string, version int, pm, pm2 *ProtocolManager) (*peer,
var id enode.ID var id enode.ID
rand.Read(id[:]) rand.Read(id[:])
peer := pm.newPeer(version, NetworkId, p2p.NewPeer(id, name, nil), net) peer := pm.newPeer(version, NetworkID, p2p.NewPeer(id, name, nil), net)
peer2 := pm2.newPeer(version, NetworkId, p2p.NewPeer(id, name, nil), app) peer2 := pm2.newPeer(version, NetworkID, p2p.NewPeer(id, name, nil), app)
// Start the peer on a new thread // Start the peer on a new thread
errc := make(chan error, 1) errc := make(chan error, 1)
@ -285,7 +285,7 @@ func newTestPeerPair(name string, version int, pm, pm2 *ProtocolManager) (*peer,
func (p *testPeer) handshake(t *testing.T, td *big.Int, head common.Hash, headNum uint64, genesis common.Hash) { func (p *testPeer) handshake(t *testing.T, td *big.Int, head common.Hash, headNum uint64, genesis common.Hash) {
var expList keyValueList var expList keyValueList
expList = expList.add("protocolVersion", uint64(p.version)) expList = expList.add("protocolVersion", uint64(p.version))
expList = expList.add("networkId", uint64(NetworkId)) expList = expList.add("networkId", uint64(NetworkID))
expList = expList.add("headTd", td) expList = expList.add("headTd", td)
expList = expList.add("headHash", head) expList = expList.add("headHash", head)
expList = expList.add("headNum", headNum) expList = expList.add("headNum", headNum)

View file

@ -34,6 +34,7 @@ type LesOdr struct {
stop chan struct{} stop chan struct{}
} }
// NewLesOdr - construct a new LES on demand request
func NewLesOdr(db ethdb.Database, config *light.IndexerConfig, retriever *retrieveManager) *LesOdr { func NewLesOdr(db ethdb.Database, config *light.IndexerConfig, retriever *retrieveManager) *LesOdr {
return &LesOdr{ return &LesOdr{
db: db, db: db,
@ -81,11 +82,17 @@ func (odr *LesOdr) IndexerConfig() *light.IndexerConfig {
} }
const ( const (
// MsgBlockBodies - block bodies request
MsgBlockBodies = iota MsgBlockBodies = iota
// MsgCode - code request
MsgCode MsgCode
// MsgReceipts - receipts request
MsgReceipts MsgReceipts
// MsgProofsV2 - proofs request
MsgProofsV2 MsgProofsV2
// MsgHelperTrieProofs - helper trie proofs request
MsgHelperTrieProofs MsgHelperTrieProofs
// MsgTxStatus - transaction status request
MsgTxStatus MsgTxStatus
) )

View file

@ -45,6 +45,7 @@ var (
errUselessNodes = errors.New("useless nodes in merkle proof nodeset") errUselessNodes = errors.New("useless nodes in merkle proof nodeset")
) )
// LesOdrRequest - an on-demand request
type LesOdrRequest interface { type LesOdrRequest interface {
GetCost(*peer) uint64 GetCost(*peer) uint64
CanSend(*peer) bool CanSend(*peer) bool
@ -52,6 +53,7 @@ type LesOdrRequest interface {
Validate(ethdb.Database, *Msg) error Validate(ethdb.Database, *Msg) error
} }
// LesRequest - generate a LES on demand request from a light one
func LesRequest(req light.OdrRequest) LesOdrRequest { func LesRequest(req light.OdrRequest) LesOdrRequest {
switch r := req.(type) { switch r := req.(type) {
case *light.BlockRequest: case *light.BlockRequest:
@ -93,7 +95,7 @@ func (r *BlockRequest) Request(reqID uint64, peer *peer) error {
return peer.RequestBodies(reqID, r.GetCost(peer), []common.Hash{r.Hash}) return peer.RequestBodies(reqID, r.GetCost(peer), []common.Hash{r.Hash})
} }
// Valid processes an ODR request reply message from the LES network // Validate processes an ODR request reply message from the LES network
// returns true and stores results in memory if the message was a valid reply // returns true and stores results in memory if the message was a valid reply
// to the request (implementation of LesOdrRequest) // to the request (implementation of LesOdrRequest)
func (r *BlockRequest) Validate(db ethdb.Database, msg *Msg) error { func (r *BlockRequest) Validate(db ethdb.Database, msg *Msg) error {
@ -149,7 +151,7 @@ func (r *ReceiptsRequest) Request(reqID uint64, peer *peer) error {
return peer.RequestReceipts(reqID, r.GetCost(peer), []common.Hash{r.Hash}) return peer.RequestReceipts(reqID, r.GetCost(peer), []common.Hash{r.Hash})
} }
// Valid processes an ODR request reply message from the LES network // Validate processes an ODR request reply message from the LES network
// returns true and stores results in memory if the message was a valid reply // returns true and stores results in memory if the message was a valid reply
// to the request (implementation of LesOdrRequest) // to the request (implementation of LesOdrRequest)
func (r *ReceiptsRequest) Validate(db ethdb.Database, msg *Msg) error { func (r *ReceiptsRequest) Validate(db ethdb.Database, msg *Msg) error {
@ -178,13 +180,14 @@ func (r *ReceiptsRequest) Validate(db ethdb.Database, msg *Msg) error {
return nil return nil
} }
// ProofReq - a request for a proof
type ProofReq struct { type ProofReq struct {
BHash common.Hash BHash common.Hash
AccKey, Key []byte AccKey, Key []byte
FromLevel uint FromLevel uint
} }
// ODR request type for state/storage trie entries, see LesOdrRequest interface // TrieRequest - ODR request type for state/storage trie entries, see LesOdrRequest interface
type TrieRequest light.TrieRequest type TrieRequest light.TrieRequest
// GetCost returns the cost of the given ODR request according to the serving // GetCost returns the cost of the given ODR request according to the serving
@ -209,7 +212,7 @@ func (r *TrieRequest) Request(reqID uint64, peer *peer) error {
return peer.RequestProofs(reqID, r.GetCost(peer), []ProofReq{req}) return peer.RequestProofs(reqID, r.GetCost(peer), []ProofReq{req})
} }
// Valid processes an ODR request reply message from the LES network // Validate processes an ODR request reply message from the LES network
// returns true and stores results in memory if the message was a valid reply // returns true and stores results in memory if the message was a valid reply
// to the request (implementation of LesOdrRequest) // to the request (implementation of LesOdrRequest)
func (r *TrieRequest) Validate(db ethdb.Database, msg *Msg) error { func (r *TrieRequest) Validate(db ethdb.Database, msg *Msg) error {
@ -233,12 +236,13 @@ func (r *TrieRequest) Validate(db ethdb.Database, msg *Msg) error {
return nil return nil
} }
// CodeReq - a request for contract code
type CodeReq struct { type CodeReq struct {
BHash common.Hash BHash common.Hash
AccKey []byte AccKey []byte
} }
// ODR request type for node data (used for retrieving contract code), see LesOdrRequest interface // CodeRequest - ODR request type for node data (used for retrieving contract code), see LesOdrRequest interface
type CodeRequest light.CodeRequest type CodeRequest light.CodeRequest
// GetCost returns the cost of the given ODR request according to the serving // GetCost returns the cost of the given ODR request according to the serving
@ -262,7 +266,7 @@ func (r *CodeRequest) Request(reqID uint64, peer *peer) error {
return peer.RequestCode(reqID, r.GetCost(peer), []CodeReq{req}) return peer.RequestCode(reqID, r.GetCost(peer), []CodeReq{req})
} }
// Valid processes an ODR request reply message from the LES network // Validate processes an ODR request reply message from the LES network
// returns true and stores results in memory if the message was a valid reply // returns true and stores results in memory if the message was a valid reply
// to the request (implementation of LesOdrRequest) // to the request (implementation of LesOdrRequest)
func (r *CodeRequest) Validate(db ethdb.Database, msg *Msg) error { func (r *CodeRequest) Validate(db ethdb.Database, msg *Msg) error {
@ -297,6 +301,7 @@ const (
auxHeader = 2 auxHeader = 2
) )
// HelperTrieReq - a request for part of a trie
type HelperTrieReq struct { type HelperTrieReq struct {
Type uint Type uint
TrieIdx uint64 TrieIdx uint64
@ -304,12 +309,13 @@ type HelperTrieReq struct {
FromLevel, AuxReq uint FromLevel, AuxReq uint
} }
// HelperTrieResps - response to HelperTrieReq, providing merkle proofs
type HelperTrieResps struct { // describes all responses, not just a single one type HelperTrieResps struct { // describes all responses, not just a single one
Proofs light.NodeList Proofs light.NodeList
AuxData [][]byte AuxData [][]byte
} }
// ODR request type for requesting headers by Canonical Hash Trie, see LesOdrRequest interface // ChtRequest - ODR request type for requesting headers by Canonical Hash Trie, see LesOdrRequest interface
type ChtRequest light.ChtRequest type ChtRequest light.ChtRequest
// GetCost returns the cost of the given ODR request according to the serving // GetCost returns the cost of the given ODR request according to the serving
@ -340,7 +346,7 @@ func (r *ChtRequest) Request(reqID uint64, peer *peer) error {
return peer.RequestHelperTrieProofs(reqID, r.GetCost(peer), []HelperTrieReq{req}) return peer.RequestHelperTrieProofs(reqID, r.GetCost(peer), []HelperTrieReq{req})
} }
// Valid processes an ODR request reply message from the LES network // Validate processes an ODR request reply message from the LES network
// returns true and stores results in memory if the message was a valid reply // returns true and stores results in memory if the message was a valid reply
// to the request (implementation of LesOdrRequest) // to the request (implementation of LesOdrRequest)
func (r *ChtRequest) Validate(db ethdb.Database, msg *Msg) error { func (r *ChtRequest) Validate(db ethdb.Database, msg *Msg) error {
@ -393,11 +399,12 @@ func (r *ChtRequest) Validate(db ethdb.Database, msg *Msg) error {
return nil return nil
} }
// BloomReq -
type BloomReq struct { type BloomReq struct {
BloomTrieNum, BitIdx, SectionIndex, FromLevel uint64 BloomTrieNum, BitIdx, SectionIndex, FromLevel uint64
} }
// ODR request type for requesting headers by Canonical Hash Trie, see LesOdrRequest interface // BloomRequest - ODR request type for requesting headers by Canonical Hash Trie, see LesOdrRequest interface
type BloomRequest light.BloomRequest type BloomRequest light.BloomRequest
// GetCost returns the cost of the given ODR request according to the serving // GetCost returns the cost of the given ODR request according to the serving
@ -436,7 +443,7 @@ func (r *BloomRequest) Request(reqID uint64, peer *peer) error {
return peer.RequestHelperTrieProofs(reqID, r.GetCost(peer), reqs) return peer.RequestHelperTrieProofs(reqID, r.GetCost(peer), reqs)
} }
// Valid processes an ODR request reply message from the LES network // Validate processes an ODR request reply message from the LES network
// returns true and stores results in memory if the message was a valid reply // returns true and stores results in memory if the message was a valid reply
// to the request (implementation of LesOdrRequest) // to the request (implementation of LesOdrRequest)
func (r *BloomRequest) Validate(db ethdb.Database, msg *Msg) error { func (r *BloomRequest) Validate(db ethdb.Database, msg *Msg) error {
@ -493,7 +500,7 @@ func (r *TxStatusRequest) Request(reqID uint64, peer *peer) error {
return peer.RequestTxStatus(reqID, r.GetCost(peer), r.Hashes) return peer.RequestTxStatus(reqID, r.GetCost(peer), r.Hashes)
} }
// Valid processes an ODR request reply message from the LES network // Validate processes an ODR request reply message from the LES network
// returns true and stores results in memory if the message was a valid reply // returns true and stores results in memory if the message was a valid reply
// to the request (implementation of LesOdrRequest) // to the request (implementation of LesOdrRequest)
func (r *TxStatusRequest) Validate(db ethdb.Database, msg *Msg) error { func (r *TxStatusRequest) Validate(db ethdb.Database, msg *Msg) error {

View file

@ -526,7 +526,7 @@ func (p *peer) Handshake(td *big.Int, head common.Hash, headNum uint64, genesis
return errResp(ErrGenesisBlockMismatch, "%x (!= %x)", rGenesis[:8], genesis[:8]) return errResp(ErrGenesisBlockMismatch, "%x (!= %x)", rGenesis[:8], genesis[:8])
} }
if rNetwork != p.network { if rNetwork != p.network {
return errResp(ErrNetworkIdMismatch, "%d (!= %d)", rNetwork, p.network) return errResp(ErrNetworkIDMismatch, "%d (!= %d)", rNetwork, p.network)
} }
if int(rVersion) != p.version { if int(rVersion) != p.version {
return errResp(ErrProtocolVersionMismatch, "%d (!= %d)", rVersion, p.version) return errResp(ErrProtocolVersionMismatch, "%d (!= %d)", rVersion, p.version)

View file

@ -12,8 +12,8 @@ import (
) )
const ( const (
test_networkid = 10 testNetworkID = 10
protocol_version = lpv2 protocolVersion = lpv2
) )
var ( var (
@ -30,7 +30,7 @@ func TestPeerHandshakeSetAnnounceTypeToAnnounceTypeSignedForTrustedPeer(t *testi
//peer to connect(on ulc side) //peer to connect(on ulc side)
p := peer{ p := peer{
Peer: p2p.NewPeer(id, "test peer", []p2p.Cap{}), Peer: p2p.NewPeer(id, "test peer", []p2p.Cap{}),
version: protocol_version, version: protocolVersion,
isTrusted: true, isTrusted: true,
rw: &rwStub{ rw: &rwStub{
WriteHook: func(recvList keyValueList) { WriteHook: func(recvList keyValueList) {
@ -59,7 +59,7 @@ func TestPeerHandshakeSetAnnounceTypeToAnnounceTypeSignedForTrustedPeer(t *testi
return l return l
}, },
}, },
network: test_networkid, network: testNetworkID,
} }
err := p.Handshake(td, hash, headNum, genesis, nil) err := p.Handshake(td, hash, headNum, genesis, nil)
@ -76,7 +76,7 @@ func TestPeerHandshakeAnnounceTypeSignedForTrustedPeersPeerNotInTrusted(t *testi
id := newNodeID(t).ID() id := newNodeID(t).ID()
p := peer{ p := peer{
Peer: p2p.NewPeer(id, "test peer", []p2p.Cap{}), Peer: p2p.NewPeer(id, "test peer", []p2p.Cap{}),
version: protocol_version, version: protocolVersion,
rw: &rwStub{ rw: &rwStub{
WriteHook: func(recvList keyValueList) { WriteHook: func(recvList keyValueList) {
//checking that ulc sends to peer allowedRequests=noRequests and announceType != announceTypeSigned //checking that ulc sends to peer allowedRequests=noRequests and announceType != announceTypeSigned
@ -104,7 +104,7 @@ func TestPeerHandshakeAnnounceTypeSignedForTrustedPeersPeerNotInTrusted(t *testi
return l return l
}, },
}, },
network: test_networkid, network: testNetworkID,
} }
err := p.Handshake(td, hash, headNum, genesis, nil) err := p.Handshake(td, hash, headNum, genesis, nil)
@ -123,7 +123,7 @@ func TestPeerHandshakeDefaultAllRequests(t *testing.T) {
p := peer{ p := peer{
Peer: p2p.NewPeer(id, "test peer", []p2p.Cap{}), Peer: p2p.NewPeer(id, "test peer", []p2p.Cap{}),
version: protocol_version, version: protocolVersion,
rw: &rwStub{ rw: &rwStub{
ReadHook: func(l keyValueList) keyValueList { ReadHook: func(l keyValueList) keyValueList {
l = l.add("announceType", uint64(announceTypeSigned)) l = l.add("announceType", uint64(announceTypeSigned))
@ -132,7 +132,7 @@ func TestPeerHandshakeDefaultAllRequests(t *testing.T) {
return l return l
}, },
}, },
network: test_networkid, network: testNetworkID,
} }
err := p.Handshake(td, hash, headNum, genesis, s) err := p.Handshake(td, hash, headNum, genesis, s)
@ -153,7 +153,7 @@ func TestPeerHandshakeServerSendOnlyAnnounceRequestsHeaders(t *testing.T) {
p := peer{ p := peer{
Peer: p2p.NewPeer(id, "test peer", []p2p.Cap{}), Peer: p2p.NewPeer(id, "test peer", []p2p.Cap{}),
version: protocol_version, version: protocolVersion,
rw: &rwStub{ rw: &rwStub{
ReadHook: func(l keyValueList) keyValueList { ReadHook: func(l keyValueList) keyValueList {
l = l.add("announceType", uint64(announceTypeSigned)) l = l.add("announceType", uint64(announceTypeSigned))
@ -171,7 +171,7 @@ func TestPeerHandshakeServerSendOnlyAnnounceRequestsHeaders(t *testing.T) {
} }
}, },
}, },
network: test_networkid, network: testNetworkID,
} }
err := p.Handshake(td, hash, headNum, genesis, s) err := p.Handshake(td, hash, headNum, genesis, s)
@ -184,7 +184,7 @@ func TestPeerHandshakeClientReceiveOnlyAnnounceRequestsHeaders(t *testing.T) {
p := peer{ p := peer{
Peer: p2p.NewPeer(id, "test peer", []p2p.Cap{}), Peer: p2p.NewPeer(id, "test peer", []p2p.Cap{}),
version: protocol_version, version: protocolVersion,
rw: &rwStub{ rw: &rwStub{
ReadHook: func(l keyValueList) keyValueList { ReadHook: func(l keyValueList) keyValueList {
l = l.add("flowControl/BL", uint64(0)) l = l.add("flowControl/BL", uint64(0))
@ -196,7 +196,7 @@ func TestPeerHandshakeClientReceiveOnlyAnnounceRequestsHeaders(t *testing.T) {
return l return l
}, },
}, },
network: test_networkid, network: testNetworkID,
isTrusted: true, isTrusted: true,
} }
@ -215,7 +215,7 @@ func TestPeerHandshakeClientReturnErrorOnUselessPeer(t *testing.T) {
p := peer{ p := peer{
Peer: p2p.NewPeer(id, "test peer", []p2p.Cap{}), Peer: p2p.NewPeer(id, "test peer", []p2p.Cap{}),
version: protocol_version, version: protocolVersion,
rw: &rwStub{ rw: &rwStub{
ReadHook: func(l keyValueList) keyValueList { ReadHook: func(l keyValueList) keyValueList {
l = l.add("flowControl/BL", uint64(0)) l = l.add("flowControl/BL", uint64(0))
@ -227,7 +227,7 @@ func TestPeerHandshakeClientReturnErrorOnUselessPeer(t *testing.T) {
return l return l
}, },
}, },
network: test_networkid, network: testNetworkID,
} }
err := p.Handshake(td, hash, headNum, genesis, nil) err := p.Handshake(td, hash, headNum, genesis, nil)
@ -254,8 +254,8 @@ type rwStub struct {
func (s *rwStub) ReadMsg() (p2p.Msg, error) { func (s *rwStub) ReadMsg() (p2p.Msg, error) {
payload := keyValueList{} payload := keyValueList{}
payload = payload.add("protocolVersion", uint64(protocol_version)) payload = payload.add("protocolVersion", uint64(protocolVersion))
payload = payload.add("networkId", uint64(test_networkid)) payload = payload.add("networkId", uint64(testNetworkID))
payload = payload.add("headTd", td) payload = payload.add("headTd", td)
payload = payload.add("headHash", hash) payload = payload.add("headHash", hash)
payload = payload.add("headNum", headNum) payload = payload.add("headNum", headNum)

View file

@ -41,12 +41,14 @@ var (
AdvertiseProtocolVersions = []uint{lpv2} // clients are searching for the first advertised protocol in the list AdvertiseProtocolVersions = []uint{lpv2} // clients are searching for the first advertised protocol in the list
) )
// Number of implemented message corresponding to different protocol versions. // ProtocolLengths - Number of implemented message corresponding to different protocol versions.
var ProtocolLengths = map[uint]uint64{lpv2: 22} var ProtocolLengths = map[uint]uint64{lpv2: 22}
const ( const (
NetworkId = 1 // NetworkID - the network id
ProtocolMaxMsgSize = 10 * 1024 * 1024 // Maximum cap on the size of a protocol message NetworkID = 1
// ProtocolMaxMsgSize - Maximum cap on the size of a protocol message
ProtocolMaxMsgSize = 10 * 1024 * 1024
) )
// les protocol message codes // les protocol message codes
@ -91,20 +93,35 @@ var requests = map[uint64]requestInfo{
type errCode int type errCode int
const ( const (
// ErrMsgTooLarge - message too large
ErrMsgTooLarge = iota ErrMsgTooLarge = iota
// ErrDecode - decode error
ErrDecode ErrDecode
// ErrInvalidMsgCode - invalid message error
ErrInvalidMsgCode ErrInvalidMsgCode
// ErrProtocolVersionMismatch - mismatched protocol version
ErrProtocolVersionMismatch ErrProtocolVersionMismatch
ErrNetworkIdMismatch // ErrNetworkIDMismatch - wrong network id
ErrNetworkIDMismatch
// ErrGenesisBlockMismatch - incompatible genesis blocks
ErrGenesisBlockMismatch ErrGenesisBlockMismatch
// ErrNoStatusMsg -
ErrNoStatusMsg ErrNoStatusMsg
// ErrExtraStatusMsg -
ErrExtraStatusMsg ErrExtraStatusMsg
// ErrSuspendedPeer -
ErrSuspendedPeer ErrSuspendedPeer
// ErrUselessPeer -
ErrUselessPeer ErrUselessPeer
// ErrRequestRejected -
ErrRequestRejected ErrRequestRejected
// ErrUnexpectedResponse -
ErrUnexpectedResponse ErrUnexpectedResponse
// ErrInvalidResponse -
ErrInvalidResponse ErrInvalidResponse
// ErrTooManyTimeouts -
ErrTooManyTimeouts ErrTooManyTimeouts
// ErrMissingKey -
ErrMissingKey ErrMissingKey
) )
@ -118,7 +135,7 @@ var errorToString = map[int]string{
ErrDecode: "Invalid message", ErrDecode: "Invalid message",
ErrInvalidMsgCode: "Invalid message code", ErrInvalidMsgCode: "Invalid message code",
ErrProtocolVersionMismatch: "Protocol version mismatch", ErrProtocolVersionMismatch: "Protocol version mismatch",
ErrNetworkIdMismatch: "NetworkId mismatch", ErrNetworkIDMismatch: "NetworkId mismatch",
ErrGenesisBlockMismatch: "Genesis block mismatch", ErrGenesisBlockMismatch: "Genesis block mismatch",
ErrNoStatusMsg: "No status message", ErrNoStatusMsg: "No status message",
ErrExtraStatusMsg: "Extra status message", ErrExtraStatusMsg: "Extra status message",

View file

@ -37,6 +37,7 @@ import (
const bufLimitRatio = 6000 // fixed bufLimit/MRR ratio const bufLimitRatio = 6000 // fixed bufLimit/MRR ratio
// LesServer - a node service running a LES server
type LesServer struct { type LesServer struct {
lesCommons lesCommons
@ -56,6 +57,7 @@ type LesServer struct {
priorityClientPool *priorityClientPool priorityClientPool *priorityClientPool
} }
// NewLesServer - ctor creating a LES server node service
func NewLesServer(eth *eth.Ethereum, config *eth.Config) (*LesServer, error) { func NewLesServer(eth *eth.Ethereum, config *eth.Config) (*LesServer, error) {
quitSync := make(chan struct{}) quitSync := make(chan struct{})
pm, err := NewProtocolManager( pm, err := NewProtocolManager(
@ -124,9 +126,13 @@ func NewLesServer(eth *eth.Ethereum, config *eth.Config) (*LesServer, error) {
} }
srv.chtIndexer.Start(eth.BlockChain()) srv.chtIndexer.Start(eth.BlockChain())
eth.GetBloomIndexer().AddChildIndexer(srv.bloomTrieIndexer)
return srv, nil return srv, nil
} }
// APIs - the RPC APIs offered by this server
func (s *LesServer) APIs() []rpc.API { func (s *LesServer) APIs() []rpc.API {
return []rpc.API{ return []rpc.API{
{ {
@ -180,12 +186,13 @@ func (s *LesServer) startEventLoop() {
}() }()
} }
// Protocols - rlpx capabilities offered by this LES server
func (s *LesServer) Protocols() []p2p.Protocol { func (s *LesServer) Protocols() []p2p.Protocol {
return s.makeProtocols(ServerProtocolVersions) return s.makeProtocols(ServerProtocolVersions)
} }
// Start starts the LES server // Start starts the LES server
func (s *LesServer) Start(srvr *p2p.Server) { func (s *LesServer) Start(srvr *p2p.Server) error {
s.maxPeers = s.config.LightPeers s.maxPeers = s.config.LightPeers
totalRecharge := s.costTracker.totalRecharge() totalRecharge := s.costTracker.totalRecharge()
if s.maxPeers > 0 { if s.maxPeers > 0 {
@ -225,22 +232,30 @@ func (s *LesServer) Start(srvr *p2p.Server) {
} }
s.privateKey = srvr.PrivateKey s.privateKey = srvr.PrivateKey
s.protocolManager.blockLoop() s.protocolManager.blockLoop()
return nil
} }
// SetBloomBitsIndexer - adds the bloombits indexer as a child indexer to the bloomtrie indexer
func (s *LesServer) SetBloomBitsIndexer(bloomIndexer *core.ChainIndexer) { func (s *LesServer) SetBloomBitsIndexer(bloomIndexer *core.ChainIndexer) {
bloomIndexer.AddChildIndexer(s.bloomTrieIndexer) bloomIndexer.AddChildIndexer(s.bloomTrieIndexer)
} }
// Stop stops the LES service // Stop stops the LES service
func (s *LesServer) Stop() { func (s *LesServer) Stop() error {
s.chtIndexer.Close()
err := s.chtIndexer.Close()
// bloom trie indexer is closed by parent bloombits indexer // bloom trie indexer is closed by parent bloombits indexer
go func() { go func() {
<-s.protocolManager.noMorePeers <-s.protocolManager.noMorePeers
}() }()
s.freeClientPool.stop() s.freeClientPool.stop()
s.costTracker.stop() s.costTracker.stop()
s.protocolManager.Stop() s.protocolManager.Stop()
return err
} }
// todo(rjl493456442) separate client and server implementation. // todo(rjl493456442) separate client and server implementation.

View file

@ -176,8 +176,8 @@ func connectPeers(full, light pairPeer, version int) (*peer, *peer, error) {
// Create a message pipe to communicate through // Create a message pipe to communicate through
app, net := p2p.MsgPipe() app, net := p2p.MsgPipe()
peerLight := full.PM.newPeer(version, NetworkId, p2p.NewPeer(light.Node.ID(), light.Name, nil), net) peerLight := full.PM.newPeer(version, NetworkID, p2p.NewPeer(light.Node.ID(), light.Name, nil), net)
peerFull := light.PM.newPeer(version, NetworkId, p2p.NewPeer(full.Node.ID(), full.Name, nil), app) peerFull := light.PM.newPeer(version, NetworkID, p2p.NewPeer(full.Node.ID(), full.Name, nil), app)
// Start the peerLight on a new thread // Start the peerLight on a new thread
errc1 := make(chan error, 1) errc1 := make(chan error, 1)