diff --git a/les/commons.go b/les/commons.go index a97687993..0b6cf3711 100644 --- a/les/commons.go +++ b/les/commons.go @@ -42,12 +42,12 @@ type lesCommons struct { // NodeInfo represents a short summary of the Ethereum sub-protocol metadata // known about the host peer. type NodeInfo struct { - Network uint64 `json:"network"` // Ethereum network ID (1=Frontier, 2=Morden, Ropsten=3, Rinkeby=4) - Difficulty *big.Int `json:"difficulty"` // Total difficulty of the host's blockchain - Genesis common.Hash `json:"genesis"` // SHA3 hash of the host's genesis block - Config *params.ChainConfig `json:"config"` // Chain configuration for the fork rules - Head common.Hash `json:"head"` // SHA3 hash of the host's best owned block - CHT light.TrustedCheckpoint `json:"cht"` // Trused CHT checkpoint for fast catchup + Network uint64 `json:"network"` // Ethereum network ID (1=Frontier, 2=Morden, Ropsten=3, Rinkeby=4) + Difficulty *big.Int `json:"difficulty"` // Total difficulty of the host's blockchain + Genesis common.Hash `json:"genesis"` // SHA3 hash of the host's genesis block + Config *params.ChainConfig `json:"config"` // Chain configuration for the fork rules + Head common.Hash `json:"head"` // SHA3 hash of the host's best owned block + CHT params.TrustedCheckpoint `json:"cht"` // Trused CHT checkpoint for fast catchup } // makeProtocols creates protocol descriptors for the given LES versions. @@ -76,7 +76,7 @@ func (c *lesCommons) makeProtocols(versions []uint) []p2p.Protocol { // nodeInfo retrieves some protocol metadata about the running host node. func (c *lesCommons) nodeInfo() interface{} { - var cht light.TrustedCheckpoint + var cht params.TrustedCheckpoint sections, _, _ := c.chtIndexer.Sections() sections2, _, _ := c.bloomTrieIndexer.Sections() @@ -98,11 +98,11 @@ func (c *lesCommons) nodeInfo() interface{} { idxV2 := (sectionIndex+1)*c.iConfig.PairChtSize/c.iConfig.ChtSize - 1 chtRoot = light.GetChtRoot(c.chainDb, idxV2, sectionHead) } - cht = light.TrustedCheckpoint{ - SectionIdx: sectionIndex, - SectionHead: sectionHead, - CHTRoot: chtRoot, - BloomRoot: light.GetBloomTrieRoot(c.chainDb, sectionIndex, sectionHead), + cht = params.TrustedCheckpoint{ + SectionIndex: sectionIndex, + SectionHead: sectionHead, + CHTRoot: chtRoot, + BloomRoot: light.GetBloomTrieRoot(c.chainDb, sectionIndex, sectionHead), } } diff --git a/les/odr_requests.go b/les/odr_requests.go index 9e9b2673f..77b1b6d0c 100644 --- a/les/odr_requests.go +++ b/les/odr_requests.go @@ -478,7 +478,7 @@ func (r *ChtRequest) Validate(db ethdb.Database, msg *Msg) error { } type BloomReq struct { - BloomTrieNum, BitIdx, SectionIdx, FromLevel uint64 + BloomTrieNum, BitIdx, SectionIndex, FromLevel uint64 } // ODR request type for requesting headers by Canonical Hash Trie, see LesOdrRequest interface @@ -487,7 +487,7 @@ type BloomRequest light.BloomRequest // GetCost returns the cost of the given ODR request according to the serving // peer's cost table (implementation of LesOdrRequest) func (r *BloomRequest) GetCost(peer *peer) uint64 { - return peer.GetRequestCost(GetHelperTrieProofsMsg, len(r.SectionIdxList)) + return peer.GetRequestCost(GetHelperTrieProofsMsg, len(r.SectionIndexList)) } // CanSend tells if a certain peer is suitable for serving the given request @@ -503,13 +503,13 @@ func (r *BloomRequest) CanSend(peer *peer) bool { // Request sends an ODR request to the LES network (implementation of LesOdrRequest) func (r *BloomRequest) Request(reqID uint64, peer *peer) error { - peer.Log().Debug("Requesting BloomBits", "bloomTrie", r.BloomTrieNum, "bitIdx", r.BitIdx, "sections", r.SectionIdxList) - reqs := make([]HelperTrieReq, len(r.SectionIdxList)) + peer.Log().Debug("Requesting BloomBits", "bloomTrie", r.BloomTrieNum, "bitIdx", r.BitIdx, "sections", r.SectionIndexList) + reqs := make([]HelperTrieReq, len(r.SectionIndexList)) var encNumber [10]byte binary.BigEndian.PutUint16(encNumber[:2], uint16(r.BitIdx)) - for i, sectionIdx := range r.SectionIdxList { + for i, sectionIdx := range r.SectionIndexList { binary.BigEndian.PutUint64(encNumber[2:], sectionIdx) reqs[i] = HelperTrieReq{ Type: htBloomBits, @@ -524,7 +524,7 @@ func (r *BloomRequest) Request(reqID uint64, peer *peer) error { // returns true and stores results in memory if the message was a valid reply // to the request (implementation of LesOdrRequest) func (r *BloomRequest) Validate(db ethdb.Database, msg *Msg) error { - log.Debug("Validating BloomBits", "bloomTrie", r.BloomTrieNum, "bitIdx", r.BitIdx, "sections", r.SectionIdxList) + log.Debug("Validating BloomBits", "bloomTrie", r.BloomTrieNum, "bitIdx", r.BitIdx, "sections", r.SectionIndexList) // Ensure we have a correct message with a single proof element if msg.MsgType != MsgHelperTrieProofs { @@ -535,13 +535,13 @@ func (r *BloomRequest) Validate(db ethdb.Database, msg *Msg) error { nodeSet := proofs.NodeSet() reads := &readTraceDB{db: nodeSet} - r.BloomBits = make([][]byte, len(r.SectionIdxList)) + r.BloomBits = make([][]byte, len(r.SectionIndexList)) // Verify the proofs var encNumber [10]byte binary.BigEndian.PutUint16(encNumber[:2], uint16(r.BitIdx)) - for i, idx := range r.SectionIdxList { + for i, idx := range r.SectionIndexList { binary.BigEndian.PutUint64(encNumber[2:], idx) value, _, err := trie.VerifyProof(r.BloomTrieRoot, encNumber[:], reads) if err != nil { diff --git a/light/lightchain.go b/light/lightchain.go index 81bdaad75..8e2734c2d 100644 --- a/light/lightchain.go +++ b/light/lightchain.go @@ -118,19 +118,19 @@ func NewLightChain(odr OdrBackend, config *params.ChainConfig, engine consensus. } // addTrustedCheckpoint adds a trusted checkpoint to the blockchain -func (self *LightChain) addTrustedCheckpoint(cp TrustedCheckpoint) { +func (self *LightChain) addTrustedCheckpoint(cp *params.TrustedCheckpoint) { if self.odr.ChtIndexer() != nil { - StoreChtRoot(self.chainDb, cp.SectionIdx, cp.SectionHead, cp.CHTRoot) - self.odr.ChtIndexer().AddCheckpoint(cp.SectionIdx, cp.SectionHead) + StoreChtRoot(self.chainDb, cp.SectionIndex, cp.SectionHead, cp.CHTRoot) + self.odr.ChtIndexer().AddCheckpoint(cp.SectionIndex, cp.SectionHead) } if self.odr.BloomTrieIndexer() != nil { - StoreBloomTrieRoot(self.chainDb, cp.SectionIdx, cp.SectionHead, cp.BloomRoot) - self.odr.BloomTrieIndexer().AddCheckpoint(cp.SectionIdx, cp.SectionHead) + StoreBloomTrieRoot(self.chainDb, cp.SectionIndex, cp.SectionHead, cp.BloomRoot) + self.odr.BloomTrieIndexer().AddCheckpoint(cp.SectionIndex, cp.SectionHead) } if self.odr.BloomIndexer() != nil { - self.odr.BloomIndexer().AddCheckpoint(cp.SectionIdx, cp.SectionHead) + self.odr.BloomIndexer().AddCheckpoint(cp.SectionIndex, cp.SectionHead) } - log.Info("Added trusted checkpoint", "chain", cp.name, "block", (cp.SectionIdx+1)*self.indexerConfig.ChtSize-1, "hash", cp.SectionHead) + log.Info("Added trusted checkpoint", "chain", cp.Name, "block", (cp.SectionIndex+1)*self.indexerConfig.ChtSize-1, "hash", cp.SectionHead) } func (self *LightChain) getProcInterrupt() bool { diff --git a/light/odr.go b/light/odr.go index 3cd8b2c04..900be0544 100644 --- a/light/odr.go +++ b/light/odr.go @@ -157,18 +157,18 @@ func (req *ChtRequest) StoreResult(db ethdb.Database) { // BloomRequest is the ODR request type for retrieving bloom filters from a CHT structure type BloomRequest struct { OdrRequest - Config *IndexerConfig - BloomTrieNum uint64 - BitIdx uint - SectionIdxList []uint64 - BloomTrieRoot common.Hash - BloomBits [][]byte - Proofs *NodeSet + Config *IndexerConfig + BloomTrieNum uint64 + BitIdx uint + SectionIndexList []uint64 + BloomTrieRoot common.Hash + BloomBits [][]byte + Proofs *NodeSet } // StoreResult stores the retrieved data in local database func (req *BloomRequest) StoreResult(db ethdb.Database) { - for i, sectionIdx := range req.SectionIdxList { + for i, sectionIdx := range req.SectionIndexList { sectionHead := rawdb.ReadCanonicalHash(db, (sectionIdx+1)*req.Config.BloomTrieSize-1) // if we don't have the canonical hash stored for this section head number, we'll still store it under // a key with a zero sectionHead. GetBloomBits will look there too if we still don't have the canonical diff --git a/light/odr_util.go b/light/odr_util.go index 9bc0f604b..073f0d642 100644 --- a/light/odr_util.go +++ b/light/odr_util.go @@ -222,7 +222,7 @@ func GetBloomBits(ctx context.Context, odr OdrBackend, bitIdx uint, sectionIdxLi } r := &BloomRequest{BloomTrieRoot: GetBloomTrieRoot(db, bloomTrieCount-1, sectionHead), BloomTrieNum: bloomTrieCount - 1, - BitIdx: bitIdx, SectionIdxList: reqList, Config: odr.IndexerConfig()} + BitIdx: bitIdx, SectionIndexList: reqList, Config: odr.IndexerConfig()} if err := odr.Retrieve(ctx, r); err != nil { return nil, err } else { diff --git a/light/postprocess.go b/light/postprocess.go index 7b23e48b5..2f8cb73ab 100644 --- a/light/postprocess.go +++ b/light/postprocess.go @@ -104,38 +104,11 @@ var ( } ) -// trustedCheckpoint represents a set of post-processed trie roots (CHT and BloomTrie) associated with -// the appropriate section index and head hash. It is used to start light syncing from this checkpoint -// and avoid downloading the entire header chain while still being able to securely access old headers/logs. -type TrustedCheckpoint struct { - name string - SectionIdx uint64 - SectionHead, CHTRoot, BloomRoot common.Hash -} - // trustedCheckpoints associates each known checkpoint with the genesis hash of the chain it belongs to -var trustedCheckpoints = map[common.Hash]TrustedCheckpoint{ - params.MainnetGenesisHash: { - name: "mainnet", - SectionIdx: 187, - SectionHead: common.HexToHash("e6baa034efa31562d71ff23676512dec6562c1ad0301e08843b907e81958c696"), - CHTRoot: common.HexToHash("28001955219719cf06de1b08648969139d123a9835fc760547a1e4dabdabc15a"), - BloomRoot: common.HexToHash("395ca2373fc662720ac6b58b3bbe71f68aa0f38b63b2d3553dd32ff3c51eebc4"), - }, - params.TestnetGenesisHash: { - name: "ropsten", - SectionIdx: 117, - SectionHead: common.HexToHash("9529b38631ae30783f56cbe4c3b9f07575b770ecba4f6e20a274b1e2f40fede1"), - CHTRoot: common.HexToHash("6f48e9f101f1fac98e7d74fbbcc4fda138358271ffd974d40d2506f0308bb363"), - BloomRoot: common.HexToHash("8242342e66e942c0cd893484e6736b9862ceb88b43ca344bb06a8285ac1b6d64"), - }, - params.RinkebyGenesisHash: { - name: "rinkeby", - SectionIdx: 85, - SectionHead: common.HexToHash("92cfa67afc4ad8ab0dcbc6fa49efd14b5b19402442e7317e6bc879d85f89d64d"), - CHTRoot: common.HexToHash("2802ec92cd7a54a75bca96afdc666ae7b99e5d96cf8192dcfb09588812f51564"), - BloomRoot: common.HexToHash("ebefeb31a9a42866d8cf2d2477704b4c3d7c20d0e4e9b5aaa77f396e016a1263"), - }, +var trustedCheckpoints = map[common.Hash]*params.TrustedCheckpoint{ + params.MainnetGenesisHash: params.MainnetTrustedCheckpoint, + params.TestnetGenesisHash: params.TestnetTrustedCheckpoint, + params.RinkebyGenesisHash: params.RinkebyTrustedCheckpoint, } var ( @@ -329,7 +302,7 @@ func (b *BloomTrieIndexerBackend) fetchMissingNodes(ctx context.Context, section for i := 0; i < 20; i++ { go func() { for bitIndex := range indexCh { - r := &BloomRequest{BloomTrieRoot: root, BloomTrieNum: section - 1, BitIdx: bitIndex, SectionIdxList: []uint64{section - 1}, Config: b.odr.IndexerConfig()} + r := &BloomRequest{BloomTrieRoot: root, BloomTrieNum: section - 1, BitIdx: bitIndex, SectionIndexList: []uint64{section - 1}, Config: b.odr.IndexerConfig()} for { if err := b.odr.Retrieve(ctx, r); err == ErrNoPeers { // if there are no peers to serve, retry later diff --git a/params/config.go b/params/config.go index c4dfa8b4b..b0f6b7df1 100644 --- a/params/config.go +++ b/params/config.go @@ -46,6 +46,15 @@ var ( Ethash: new(EthashConfig), } + // MainnetTrustedCheckpoint contains the light client trusted checkpoint for the main network. + MainnetTrustedCheckpoint = &TrustedCheckpoint{ + Name: "mainnet", + SectionIndex: 193, + SectionHead: common.HexToHash("0xc2d574295ecedc4d58530ae24c31a5a98be7d2b3327fba0dd0f4ed3913828a55"), + CHTRoot: common.HexToHash("0x5d1027dfae688c77376e842679ceada87fd94738feb9b32ef165473bfbbb317b"), + BloomRoot: common.HexToHash("0xd38be1a06aabd568e10957fee4fcc523bc64996bcf31bae3f55f86e0a583919f"), + } + // TestnetChainConfig contains the chain parameters to run a node on the Ropsten test network. TestnetChainConfig = &ChainConfig{ ChainID: big.NewInt(3), @@ -61,6 +70,15 @@ var ( Ethash: new(EthashConfig), } + // TestnetTrustedCheckpoint contains the light client trusted checkpoint for the Ropsten test network. + TestnetTrustedCheckpoint = &TrustedCheckpoint{ + Name: "testnet", + SectionIndex: 123, + SectionHead: common.HexToHash("0xa372a53decb68ce453da12bea1c8ee7b568b276aa2aab94d9060aa7c81fc3dee"), + CHTRoot: common.HexToHash("0x6b02e7fada79cd2a80d4b3623df9c44384d6647fc127462e1c188ccd09ece87b"), + BloomRoot: common.HexToHash("0xf2d27490914968279d6377d42868928632573e823b5d1d4a944cba6009e16259"), + } + // RinkebyChainConfig contains the chain parameters to run a node on the Rinkeby test network. RinkebyChainConfig = &ChainConfig{ ChainID: big.NewInt(4), @@ -79,6 +97,15 @@ var ( }, } + // RinkebyTrustedCheckpoint contains the light client trusted checkpoint for the Rinkeby test network. + RinkebyTrustedCheckpoint = &TrustedCheckpoint{ + Name: "rinkeby", + SectionIndex: 91, + SectionHead: common.HexToHash("0x435b7b2d8a7922f3b9a522f2fb02730e95e0e1782f0f5443894d5415bba37154"), + CHTRoot: common.HexToHash("0x0664bf7ecccfb6775c4eca6f0f264fb5282a22754a2135a1ac4bff2ef02898dd"), + BloomRoot: common.HexToHash("0x2a64df2400c3a2cb6400639bb6ed29389abdb4d93e2e525aa7c21f38767cd96f"), + } + // AllEthashProtocolChanges contains every protocol change (EIPs) introduced // and accepted by the Ethereum core developers into the Ethash consensus. // @@ -97,6 +124,18 @@ var ( TestRules = TestChainConfig.Rules(new(big.Int)) ) +// TrustedCheckpoint represents a set of post-processed trie roots (CHT and +// BloomTrie) associated with the appropriate section index and head hash. It is +// used to start light syncing from this checkpoint and avoid downloading the +// entire header chain while still being able to securely access old headers/logs. +type TrustedCheckpoint struct { + Name string `json:"-"` + SectionIndex uint64 `json:"sectionIndex"` + SectionHead common.Hash `json:"sectionHead"` + CHTRoot common.Hash `json:"chtRoot"` + BloomRoot common.Hash `json:"bloomRoot"` +} + // ChainConfig is the core config which determines the blockchain settings. // // ChainConfig is stored in the database on a per block basis. This means