diff options
author | Felföldi Zsolt <zsfelfoldi@gmail.com> | 2017-10-24 21:19:09 +0800 |
---|---|---|
committer | Felix Lange <fjl@users.noreply.github.com> | 2017-10-24 21:19:09 +0800 |
commit | ca376ead88a5a26626a90abdb62f4de7f6313822 (patch) | |
tree | 71d11e3b6cd40d2bf29033b7e23d30d04e086558 /light/odr_util.go | |
parent | 6d6a5a93370371a33fb815d7ae47b60c7021c86a (diff) | |
download | dexon-ca376ead88a5a26626a90abdb62f4de7f6313822.tar dexon-ca376ead88a5a26626a90abdb62f4de7f6313822.tar.gz dexon-ca376ead88a5a26626a90abdb62f4de7f6313822.tar.bz2 dexon-ca376ead88a5a26626a90abdb62f4de7f6313822.tar.lz dexon-ca376ead88a5a26626a90abdb62f4de7f6313822.tar.xz dexon-ca376ead88a5a26626a90abdb62f4de7f6313822.tar.zst dexon-ca376ead88a5a26626a90abdb62f4de7f6313822.zip |
les, light: LES/2 protocol version (#14970)
This PR implements the new LES protocol version extensions:
* new and more efficient Merkle proofs reply format (when replying to
a multiple Merkle proofs request, we just send a single set of trie
nodes containing all necessary nodes)
* BBT (BloomBitsTrie) works similarly to the existing CHT and contains
the bloombits search data to speed up log searches
* GetTxStatusMsg returns the inclusion position or the
pending/queued/unknown state of a transaction referenced by hash
* an optional signature of new block data (number/hash/td) can be
included in AnnounceMsg to provide an option for "very light
clients" (mobile/embedded devices) to skip expensive Ethash check
and accept multiple signatures of somewhat trusted servers (still a
lot better than trusting a single server completely and retrieving
everything through RPC). The new client mode is not implemented in
this PR, just the protocol extension.
Diffstat (limited to 'light/odr_util.go')
-rw-r--r-- | light/odr_util.go | 121 |
1 files changed, 78 insertions, 43 deletions
diff --git a/light/odr_util.go b/light/odr_util.go index fcdfdb82c..a0eb6303d 100644 --- a/light/odr_util.go +++ b/light/odr_util.go @@ -19,56 +19,16 @@ package light import ( "bytes" "context" - "errors" - "math/big" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/rlp" ) var sha3_nil = crypto.Keccak256Hash(nil) -var ( - ErrNoTrustedCht = errors.New("No trusted canonical hash trie") - ErrNoHeader = errors.New("Header not found") - - ChtFrequency = uint64(4096) - ChtConfirmations = uint64(2048) - trustedChtKey = []byte("TrustedCHT") -) - -type ChtNode struct { - Hash common.Hash - Td *big.Int -} - -type TrustedCht struct { - Number uint64 - Root common.Hash -} - -func GetTrustedCht(db ethdb.Database) TrustedCht { - data, _ := db.Get(trustedChtKey) - var res TrustedCht - if err := rlp.DecodeBytes(data, &res); err != nil { - return TrustedCht{0, common.Hash{}} - } - return res -} - -func WriteTrustedCht(db ethdb.Database, cht TrustedCht) { - data, _ := rlp.EncodeToBytes(cht) - db.Put(trustedChtKey, data) -} - -func DeleteTrustedCht(db ethdb.Database) { - db.Delete(trustedChtKey) -} - func GetHeaderByNumber(ctx context.Context, odr OdrBackend, number uint64) (*types.Header, error) { db := odr.Database() hash := core.GetCanonicalHash(db, number) @@ -81,12 +41,29 @@ func GetHeaderByNumber(ctx context.Context, odr OdrBackend, number uint64) (*typ return header, nil } - cht := GetTrustedCht(db) - if number >= cht.Number*ChtFrequency { + var ( + chtCount, sectionHeadNum uint64 + sectionHead common.Hash + ) + if odr.ChtIndexer() != nil { + chtCount, sectionHeadNum, sectionHead = odr.ChtIndexer().Sections() + canonicalHash := core.GetCanonicalHash(db, sectionHeadNum) + // if the CHT was injected as a trusted checkpoint, we have no canonical hash yet so we accept zero hash too + for chtCount > 0 && canonicalHash != sectionHead && canonicalHash != (common.Hash{}) { + chtCount-- + if chtCount > 0 { + sectionHeadNum = chtCount*ChtFrequency - 1 + sectionHead = odr.ChtIndexer().SectionHead(chtCount - 1) + canonicalHash = core.GetCanonicalHash(db, sectionHeadNum) + } + } + } + + if number >= chtCount*ChtFrequency { return nil, ErrNoTrustedCht } - r := &ChtRequest{ChtRoot: cht.Root, ChtNum: cht.Number, BlockNum: number} + r := &ChtRequest{ChtRoot: GetChtRoot(db, chtCount-1, sectionHead), ChtNum: chtCount - 1, BlockNum: number} if err := odr.Retrieve(ctx, r); err != nil { return nil, err } else { @@ -162,3 +139,61 @@ func GetBlockReceipts(ctx context.Context, odr OdrBackend, hash common.Hash, num } return r.Receipts, nil } + +// GetBloomBits retrieves a batch of compressed bloomBits vectors belonging to the given bit index and section indexes +func GetBloomBits(ctx context.Context, odr OdrBackend, bitIdx uint, sectionIdxList []uint64) ([][]byte, error) { + db := odr.Database() + result := make([][]byte, len(sectionIdxList)) + var ( + reqList []uint64 + reqIdx []int + ) + + var ( + bloomTrieCount, sectionHeadNum uint64 + sectionHead common.Hash + ) + if odr.BloomTrieIndexer() != nil { + bloomTrieCount, sectionHeadNum, sectionHead = odr.BloomTrieIndexer().Sections() + canonicalHash := core.GetCanonicalHash(db, sectionHeadNum) + // if the BloomTrie was injected as a trusted checkpoint, we have no canonical hash yet so we accept zero hash too + for bloomTrieCount > 0 && canonicalHash != sectionHead && canonicalHash != (common.Hash{}) { + bloomTrieCount-- + if bloomTrieCount > 0 { + sectionHeadNum = bloomTrieCount*BloomTrieFrequency - 1 + sectionHead = odr.BloomTrieIndexer().SectionHead(bloomTrieCount - 1) + canonicalHash = core.GetCanonicalHash(db, sectionHeadNum) + } + } + } + + for i, sectionIdx := range sectionIdxList { + sectionHead := core.GetCanonicalHash(db, (sectionIdx+1)*BloomTrieFrequency-1) + // if we don't have the canonical hash stored for this section head number, we'll still look for + // an entry with a zero sectionHead (we store it with zero section head too if we don't know it + // at the time of the retrieval) + bloomBits, err := core.GetBloomBits(db, bitIdx, sectionIdx, sectionHead) + if err == nil { + result[i] = bloomBits + } else { + if sectionIdx >= bloomTrieCount { + return nil, ErrNoTrustedBloomTrie + } + reqList = append(reqList, sectionIdx) + reqIdx = append(reqIdx, i) + } + } + if reqList == nil { + return result, nil + } + + r := &BloomRequest{BloomTrieRoot: GetBloomTrieRoot(db, bloomTrieCount-1, sectionHead), BloomTrieNum: bloomTrieCount - 1, BitIdx: bitIdx, SectionIdxList: reqList} + if err := odr.Retrieve(ctx, r); err != nil { + return nil, err + } else { + for i, idx := range reqIdx { + result[idx] = r.BloomBits[i] + } + return result, nil + } +} |