From 390d54c3e09043d3e58e4f5de1096d2fee8c8027 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Sat, 10 Feb 2018 03:38:42 +0200 Subject: [PATCH] les, light: deterministic nodeset rlp, bloombits test skeleton --- les/handler.go | 3 +-- les/handler_test.go | 59 +++++++++++++++++++++++++++++---------------- les/helper_test.go | 6 ++++- les/odr_requests.go | 8 +++--- light/nodeset.go | 27 +++++++++++++-------- 5 files changed, 65 insertions(+), 38 deletions(-) diff --git a/les/handler.go b/les/handler.go index dc9bd12088..734befeeb2 100644 --- a/les/handler.go +++ b/les/handler.go @@ -790,10 +790,9 @@ func (pm *ProtocolManager) handleMsg(p *peer) error { break } } - proofs := nodes.NodeList() bv, rcost := p.fcClient.RequestProcessed(costs.baseCost + uint64(reqCnt)*costs.reqCost) pm.server.fcCostStats.update(msg.Code, uint64(reqCnt), rcost) - return p.SendProofsV2(req.ReqID, bv, proofs) + return p.SendProofsV2(req.ReqID, bv, nodes.NodeList()) case ProofsV1Msg: if pm.odr == nil { diff --git a/les/handler_test.go b/les/handler_test.go index df25f9097c..fa59fe66de 100644 --- a/les/handler_test.go +++ b/les/handler_test.go @@ -385,31 +385,13 @@ func testGetProofs(t *testing.T, protocol int) { case 2: cost := peer.GetRequestCost(GetProofsV2Msg, len(proofreqs)) sendRequest(peer.app, GetProofsV2Msg, 42, cost, proofreqs) - msg, err := peer.app.ReadMsg() - if err != nil { - t.Errorf("Message read error: %v", err) + if err := expectResponse(peer.app, ProofsV2Msg, 42, testBufLimit, proofsV2.NodeList()); err != nil { + t.Errorf("proofs mismatch: %v", err) } - var resp struct { - ReqID, BV uint64 - Data light.NodeList - } - if err := msg.Decode(&resp); err != nil { - t.Errorf("reply decode error: %v", err) - } - if msg.Code != ProofsV2Msg { - t.Errorf("Message code mismatch") - } - if resp.ReqID != 42 { - t.Errorf("ReqID mismatch") - } - if resp.BV != testBufLimit { - t.Errorf("BV mismatch") - } - testCheckProof(t, proofsV2, resp.Data) } } -// Tests that helper trie proofs can be correctly retrieved. +// Tests that CHT proofs can be correctly retrieved. func TestGetCHTProofsLes1(t *testing.T) { testGetCHTProofs(t, 1) } func TestGetCHTProofsLes2(t *testing.T) { testGetCHTProofs(t, 2) } @@ -485,6 +467,41 @@ func testGetCHTProofs(t *testing.T, protocol int) { } } +// Tests that bloombits proofs can be correctly retrieved. +func TestGetBloombitsProofs(t *testing.T) { + // Assemble the test environment + db, _ := ethdb.NewMemDatabase() + pm := newTestProtocolManagerMust(t, false, light.BloomTrieFrequency+256, testChainGen, nil, nil, db) + //bc := pm.blockchain.(*core.BlockChain) + peer, _ := newTestPeer(t, "peer", 2, pm, true) + defer peer.close() + + // Wait a while for the bloombits indexer to process the new headers + time.Sleep(100 * time.Millisecond * time.Duration(light.BloomTrieFrequency/4096)) // Chain indexer throttling + time.Sleep(250 * time.Millisecond) // CI tester slack + + // Assemble therequest and proofs for the bloombits + bit := rand.Intn(2048) + key := make([]byte, 10) + + binary.BigEndian.PutUint16(key[:2], uint16(bit)) + binary.BigEndian.PutUint64(key[2:], 0) + + requests := []HelperTrieReq{{ + Type: htBloomBits, + TrieIdx: 0, + Key: key, + }} + var proofs HelperTrieResps + + // Send the proof request and verify the response + cost := peer.GetRequestCost(GetHelperTrieProofsMsg, len(requests)) + sendRequest(peer.app, GetHelperTrieProofsMsg, 42, cost, requests) + if err := expectResponse(peer.app, HelperTrieProofsMsg, 42, testBufLimit, proofs); err != nil { + t.Errorf("proofs mismatch: %v", err) + } +} + func TestTransactionStatusLes2(t *testing.T) { db, _ := ethdb.NewMemDatabase() pm := newTestProtocolManagerMust(t, false, 0, nil, nil, nil, db) diff --git a/les/helper_test.go b/les/helper_test.go index a408d18609..e1e311b44b 100644 --- a/les/helper_test.go +++ b/les/helper_test.go @@ -31,6 +31,7 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/eth" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/les/flowcontrol" @@ -151,7 +152,10 @@ func newTestProtocolManager(lightSync bool, blocks int, generator func(int, *cor chtIndexer := light.NewChtIndexer(db, false) chtIndexer.Start(blockchain) - bloomIndexer := light.NewBloomTrieIndexer(db, false) + bbtIndexer := light.NewBloomTrieIndexer(db, false) + + bloomIndexer := eth.NewBloomIndexer(db, params.BloomBitsBlocks) + bloomIndexer.AddChildIndexer(bbtIndexer) bloomIndexer.Start(blockchain) gchain, _ := core.GenerateChain(gspec.Config, genesis, ethash.NewFaker(), db, blocks, generator) diff --git a/les/odr_requests.go b/les/odr_requests.go index a11d7b3965..34d759dd2a 100644 --- a/les/odr_requests.go +++ b/les/odr_requests.go @@ -493,10 +493,10 @@ func (r *BloomRequest) Request(reqID uint64, peer *peer) error { reqs := make([]HelperTrieReq, len(r.SectionIdxList)) var encNumber [10]byte - binary.BigEndian.PutUint16(encNumber[0:2], uint16(r.BitIdx)) + binary.BigEndian.PutUint16(encNumber[:2], uint16(r.BitIdx)) for i, sectionIdx := range r.SectionIdxList { - binary.BigEndian.PutUint64(encNumber[2:10], sectionIdx) + binary.BigEndian.PutUint64(encNumber[2:], sectionIdx) reqs[i] = HelperTrieReq{ Type: htBloomBits, TrieIdx: r.BloomTrieNum, @@ -525,10 +525,10 @@ func (r *BloomRequest) Validate(db ethdb.Database, msg *Msg) error { // Verify the proofs var encNumber [10]byte - binary.BigEndian.PutUint16(encNumber[0:2], uint16(r.BitIdx)) + binary.BigEndian.PutUint16(encNumber[:2], uint16(r.BitIdx)) for i, idx := range r.SectionIdxList { - binary.BigEndian.PutUint64(encNumber[2:10], idx) + binary.BigEndian.PutUint64(encNumber[2:], idx) value, err, _ := trie.VerifyProof(r.BloomTrieRoot, encNumber[:], reads) if err != nil { return err diff --git a/light/nodeset.go b/light/nodeset.go index ffdb71bb79..245b5eb766 100644 --- a/light/nodeset.go +++ b/light/nodeset.go @@ -29,7 +29,9 @@ import ( // NodeSet stores a set of trie nodes. It implements trie.Database and can also // act as a cache for another trie.Database. type NodeSet struct { - db map[string][]byte + nodes map[string][]byte + order []string + dataSize int lock sync.RWMutex } @@ -37,7 +39,7 @@ type NodeSet struct { // NewNodeSet creates an empty node set func NewNodeSet() *NodeSet { return &NodeSet{ - db: make(map[string][]byte), + nodes: make(map[string][]byte), } } @@ -46,10 +48,15 @@ func (db *NodeSet) Put(key []byte, value []byte) error { db.lock.Lock() defer db.lock.Unlock() - if _, ok := db.db[string(key)]; !ok { - db.db[string(key)] = common.CopyBytes(value) - db.dataSize += len(value) + if _, ok := db.nodes[string(key)]; ok { + return nil } + keystr := string(key) + + db.nodes[keystr] = common.CopyBytes(value) + db.order = append(db.order, keystr) + db.dataSize += len(value) + return nil } @@ -58,7 +65,7 @@ func (db *NodeSet) Get(key []byte) ([]byte, error) { db.lock.RLock() defer db.lock.RUnlock() - if entry, ok := db.db[string(key)]; ok { + if entry, ok := db.nodes[string(key)]; ok { return entry, nil } return nil, errors.New("not found") @@ -75,7 +82,7 @@ func (db *NodeSet) KeyCount() int { db.lock.RLock() defer db.lock.RUnlock() - return len(db.db) + return len(db.nodes) } // DataSize returns the aggregated data size of nodes in the set @@ -92,8 +99,8 @@ func (db *NodeSet) NodeList() NodeList { defer db.lock.RUnlock() var values NodeList - for _, value := range db.db { - values = append(values, value) + for _, key := range db.order { + values = append(values, db.nodes[key]) } return values } @@ -103,7 +110,7 @@ func (db *NodeSet) Store(target ethdb.Putter) { db.lock.RLock() defer db.lock.RUnlock() - for key, value := range db.db { + for key, value := range db.nodes { target.Put([]byte(key), value) } }