github.com/core-coin/go-core/v2@v2.1.9/les/commons.go (about)

     1  // Copyright 2018 by the Authors
     2  // This file is part of the go-core library.
     3  //
     4  // The go-core library is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Lesser General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // The go-core library is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU Lesser General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Lesser General Public License
    15  // along with the go-core library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package les
    18  
    19  import (
    20  	"fmt"
    21  	"math/big"
    22  	"sync"
    23  
    24  	"github.com/core-coin/go-core/v2/xcbdb"
    25  
    26  	"github.com/core-coin/go-core/v2/common"
    27  	"github.com/core-coin/go-core/v2/core"
    28  	"github.com/core-coin/go-core/v2/core/rawdb"
    29  	"github.com/core-coin/go-core/v2/core/types"
    30  	"github.com/core-coin/go-core/v2/les/checkpointoracle"
    31  	"github.com/core-coin/go-core/v2/light"
    32  	"github.com/core-coin/go-core/v2/log"
    33  	"github.com/core-coin/go-core/v2/node"
    34  	"github.com/core-coin/go-core/v2/p2p"
    35  	"github.com/core-coin/go-core/v2/p2p/discv5"
    36  	"github.com/core-coin/go-core/v2/p2p/enode"
    37  	"github.com/core-coin/go-core/v2/params"
    38  	"github.com/core-coin/go-core/v2/xcb"
    39  	"github.com/core-coin/go-core/v2/xcbclient"
    40  )
    41  
    42  func errResp(code errCode, format string, v ...interface{}) error {
    43  	return fmt.Errorf("%v - %v", code, fmt.Sprintf(format, v...))
    44  }
    45  
    46  func lesTopic(genesisHash common.Hash, protocolVersion uint) discv5.Topic {
    47  	var name string
    48  	switch protocolVersion {
    49  	case lpv2:
    50  		name = "LES2"
    51  	default:
    52  		panic(nil)
    53  	}
    54  	return discv5.Topic(name + "@" + common.Bytes2Hex(genesisHash.Bytes()[0:8]))
    55  }
    56  
    57  type chainReader interface {
    58  	CurrentHeader() *types.Header
    59  }
    60  
    61  // lesCommons contains fields needed by both server and client.
    62  type lesCommons struct {
    63  	genesis                      common.Hash
    64  	config                       *xcb.Config
    65  	chainConfig                  *params.ChainConfig
    66  	iConfig                      *light.IndexerConfig
    67  	chainDb                      xcbdb.Database
    68  	chainReader                  chainReader
    69  	chtIndexer, bloomTrieIndexer *core.ChainIndexer
    70  	oracle                       *checkpointoracle.CheckpointOracle
    71  
    72  	closeCh chan struct{}
    73  	wg      sync.WaitGroup
    74  }
    75  
    76  // NodeInfo represents a short summary of the Core sub-protocol metadata
    77  // known about the host peer.
    78  type NodeInfo struct {
    79  	Network    uint64                   `json:"network"`    // Core network ID (Mainnet=1, Devin=3, Enterprise=4)
    80  	Difficulty *big.Int                 `json:"difficulty"` // Total difficulty of the host's blockchain
    81  	Genesis    common.Hash              `json:"genesis"`    // SHA3 hash of the host's genesis block
    82  	Config     *params.ChainConfig      `json:"config"`     // Chain configuration for the fork rules
    83  	Head       common.Hash              `json:"head"`       // SHA3 hash of the host's best owned block
    84  	CHT        params.TrustedCheckpoint `json:"cht"`        // Trused CHT checkpoint for fast catchup
    85  }
    86  
    87  // makeProtocols creates protocol descriptors for the given LES versions.
    88  func (c *lesCommons) makeProtocols(versions []uint, runPeer func(version uint, p *p2p.Peer, rw p2p.MsgReadWriter) error, peerInfo func(id enode.ID) interface{}, dialCandidates enode.Iterator) []p2p.Protocol {
    89  	protos := make([]p2p.Protocol, len(versions))
    90  	for i, version := range versions {
    91  		version := version
    92  		protos[i] = p2p.Protocol{
    93  			Name:     "les",
    94  			Version:  version,
    95  			Length:   ProtocolLengths[version],
    96  			NodeInfo: c.nodeInfo,
    97  			Run: func(peer *p2p.Peer, rw p2p.MsgReadWriter) error {
    98  				return runPeer(version, peer, rw)
    99  			},
   100  			PeerInfo:       peerInfo,
   101  			DialCandidates: dialCandidates,
   102  		}
   103  	}
   104  	return protos
   105  }
   106  
   107  // nodeInfo retrieves some protocol metadata about the running host node.
   108  func (c *lesCommons) nodeInfo() interface{} {
   109  	head := c.chainReader.CurrentHeader()
   110  	hash := head.Hash()
   111  	return &NodeInfo{
   112  		Network:    c.config.NetworkId,
   113  		Difficulty: rawdb.ReadTd(c.chainDb, hash, head.Number.Uint64()),
   114  		Genesis:    c.genesis,
   115  		Config:     c.chainConfig,
   116  		Head:       hash,
   117  		CHT:        c.latestLocalCheckpoint(),
   118  	}
   119  }
   120  
   121  // latestLocalCheckpoint finds the common stored section index and returns a set
   122  // of post-processed trie roots (CHT and BloomTrie) associated with the appropriate
   123  // section index and head hash as a local checkpoint package.
   124  func (c *lesCommons) latestLocalCheckpoint() params.TrustedCheckpoint {
   125  	sections, _, _ := c.chtIndexer.Sections()
   126  	sections2, _, _ := c.bloomTrieIndexer.Sections()
   127  	// Cap the section index if the two sections are not consistent.
   128  	if sections > sections2 {
   129  		sections = sections2
   130  	}
   131  	if sections == 0 {
   132  		// No checkpoint information can be provided.
   133  		return params.TrustedCheckpoint{}
   134  	}
   135  	return c.localCheckpoint(sections - 1)
   136  }
   137  
   138  // localCheckpoint returns a set of post-processed trie roots (CHT and BloomTrie)
   139  // associated with the appropriate head hash by specific section index.
   140  //
   141  // The returned checkpoint is only the checkpoint generated by the local indexers,
   142  // not the stable checkpoint registered in the registrar contract.
   143  func (c *lesCommons) localCheckpoint(index uint64) params.TrustedCheckpoint {
   144  	sectionHead := c.chtIndexer.SectionHead(index)
   145  	return params.TrustedCheckpoint{
   146  		SectionIndex: index,
   147  		SectionHead:  sectionHead,
   148  		CHTRoot:      light.GetChtRoot(c.chainDb, index, sectionHead),
   149  		BloomRoot:    light.GetBloomTrieRoot(c.chainDb, index, sectionHead),
   150  	}
   151  }
   152  
   153  // setupOracle sets up the checkpoint oracle contract client.
   154  func (c *lesCommons) setupOracle(node *node.Node, genesis common.Hash, xcbconfig *xcb.Config) *checkpointoracle.CheckpointOracle {
   155  	config := xcbconfig.CheckpointOracle
   156  	if config == nil {
   157  		// Try loading default config.
   158  		config = params.CheckpointOracles[genesis]
   159  	}
   160  	if config == nil {
   161  		log.Info("Checkpoint registrar is not enabled")
   162  		return nil
   163  	}
   164  	if config.Address == (common.Address{}) || uint64(len(config.Signers)) < config.Threshold {
   165  		log.Warn("Invalid checkpoint registrar config")
   166  		return nil
   167  	}
   168  	oracle := checkpointoracle.New(config, c.localCheckpoint)
   169  	rpcClient, _ := node.Attach()
   170  	client := xcbclient.NewClient(rpcClient)
   171  	oracle.Start(client)
   172  	log.Info("Configured checkpoint registrar", "address", config.Address, "signers", len(config.Signers), "threshold", config.Threshold)
   173  	return oracle
   174  }