Merge pull request #19288 from karalabe/les-verbose-errors
les, light: verbose errors on state retrieval issues
This commit is contained in:
		
							
								
								
									
										149
									
								
								les/handler.go
									
									
									
									
									
								
							
							
						
						
									
										149
									
								
								les/handler.go
									
									
									
									
									
								
							@@ -72,7 +72,7 @@ type BlockChain interface {
 | 
				
			|||||||
	GetHeaderByHash(hash common.Hash) *types.Header
 | 
						GetHeaderByHash(hash common.Hash) *types.Header
 | 
				
			||||||
	CurrentHeader() *types.Header
 | 
						CurrentHeader() *types.Header
 | 
				
			||||||
	GetTd(hash common.Hash, number uint64) *big.Int
 | 
						GetTd(hash common.Hash, number uint64) *big.Int
 | 
				
			||||||
	State() (*state.StateDB, error)
 | 
						StateCache() state.Database
 | 
				
			||||||
	InsertHeaderChain(chain []*types.Header, checkFreq int) (int, error)
 | 
						InsertHeaderChain(chain []*types.Header, checkFreq int) (int, error)
 | 
				
			||||||
	Rollback(chain []common.Hash)
 | 
						Rollback(chain []common.Hash)
 | 
				
			||||||
	GetHeaderByNumber(number uint64) *types.Header
 | 
						GetHeaderByNumber(number uint64) *types.Header
 | 
				
			||||||
@@ -642,26 +642,35 @@ func (pm *ProtocolManager) handleMsg(p *peer) error {
 | 
				
			|||||||
				if i != 0 && !task.waitOrStop() {
 | 
									if i != 0 && !task.waitOrStop() {
 | 
				
			||||||
					return
 | 
										return
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
				// Retrieve the requested state entry, stopping if enough was found
 | 
									// Look up the root hash belonging to the request
 | 
				
			||||||
				if number := rawdb.ReadHeaderNumber(pm.chainDb, req.BHash); number != nil {
 | 
									number := rawdb.ReadHeaderNumber(pm.chainDb, req.BHash)
 | 
				
			||||||
					if header := rawdb.ReadHeader(pm.chainDb, req.BHash, *number); header != nil {
 | 
									if number == nil {
 | 
				
			||||||
						statedb, err := pm.blockchain.State()
 | 
										p.Log().Warn("Failed to retrieve block num for code", "hash", req.BHash)
 | 
				
			||||||
						if err != nil {
 | 
					 | 
				
			||||||
					continue
 | 
										continue
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
						account, err := pm.getAccount(statedb, header.Root, common.BytesToHash(req.AccKey))
 | 
									header := rawdb.ReadHeader(pm.chainDb, req.BHash, *number)
 | 
				
			||||||
						if err != nil {
 | 
									if header == nil {
 | 
				
			||||||
 | 
										p.Log().Warn("Failed to retrieve header for code", "block", *number, "hash", req.BHash)
 | 
				
			||||||
					continue
 | 
										continue
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
						code, _ := statedb.Database().TrieDB().Node(common.BytesToHash(account.CodeHash))
 | 
									triedb := pm.blockchain.StateCache().TrieDB()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									account, err := pm.getAccount(triedb, header.Root, common.BytesToHash(req.AccKey))
 | 
				
			||||||
 | 
									if err != nil {
 | 
				
			||||||
 | 
										p.Log().Warn("Failed to retrieve account for code", "block", header.Number, "hash", header.Hash(), "account", common.BytesToHash(req.AccKey), "err", err)
 | 
				
			||||||
 | 
										continue
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									code, err := triedb.Node(common.BytesToHash(account.CodeHash))
 | 
				
			||||||
 | 
									if err != nil {
 | 
				
			||||||
 | 
										p.Log().Warn("Failed to retrieve account code", "block", header.Number, "hash", header.Hash(), "account", common.BytesToHash(req.AccKey), "codehash", common.BytesToHash(account.CodeHash), "err", err)
 | 
				
			||||||
 | 
										continue
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									// Accumulate the code and abort if enough data was retrieved
 | 
				
			||||||
				data = append(data, code)
 | 
									data = append(data, code)
 | 
				
			||||||
				if bytes += len(code); bytes >= softResponseLimit {
 | 
									if bytes += len(code); bytes >= softResponseLimit {
 | 
				
			||||||
					break
 | 
										break
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			sendResponse(req.ReqID, uint64(reqCnt), p.ReplyCode(req.ReqID, data), task.done())
 | 
								sendResponse(req.ReqID, uint64(reqCnt), p.ReplyCode(req.ReqID, data), task.done())
 | 
				
			||||||
		}()
 | 
							}()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -779,35 +788,53 @@ func (pm *ProtocolManager) handleMsg(p *peer) error {
 | 
				
			|||||||
				if i != 0 && !task.waitOrStop() {
 | 
									if i != 0 && !task.waitOrStop() {
 | 
				
			||||||
					return
 | 
										return
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
				// Retrieve the requested state entry, stopping if enough was found
 | 
									// Look up the root hash belonging to the request
 | 
				
			||||||
				if number := rawdb.ReadHeaderNumber(pm.chainDb, req.BHash); number != nil {
 | 
									number := rawdb.ReadHeaderNumber(pm.chainDb, req.BHash)
 | 
				
			||||||
					if header := rawdb.ReadHeader(pm.chainDb, req.BHash, *number); header != nil {
 | 
									if number == nil {
 | 
				
			||||||
						statedb, err := pm.blockchain.State()
 | 
										p.Log().Warn("Failed to retrieve block num for proof", "hash", req.BHash)
 | 
				
			||||||
						if err != nil {
 | 
					 | 
				
			||||||
					continue
 | 
										continue
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
						var trie state.Trie
 | 
									header := rawdb.ReadHeader(pm.chainDb, req.BHash, *number)
 | 
				
			||||||
						if len(req.AccKey) > 0 {
 | 
									if header == nil {
 | 
				
			||||||
							account, err := pm.getAccount(statedb, header.Root, common.BytesToHash(req.AccKey))
 | 
										p.Log().Warn("Failed to retrieve header for proof", "block", *number, "hash", req.BHash)
 | 
				
			||||||
							if err != nil {
 | 
					 | 
				
			||||||
					continue
 | 
										continue
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
							trie, _ = statedb.Database().OpenStorageTrie(common.BytesToHash(req.AccKey), account.Root)
 | 
									// Open the account or storage trie for the request
 | 
				
			||||||
						} else {
 | 
									statedb := pm.blockchain.StateCache()
 | 
				
			||||||
							trie, _ = statedb.Database().OpenTrie(header.Root)
 | 
					 | 
				
			||||||
						}
 | 
					 | 
				
			||||||
						if trie != nil {
 | 
					 | 
				
			||||||
							var proof light.NodeList
 | 
					 | 
				
			||||||
							trie.Prove(req.Key, 0, &proof)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									var trie state.Trie
 | 
				
			||||||
 | 
									switch len(req.AccKey) {
 | 
				
			||||||
 | 
									case 0:
 | 
				
			||||||
 | 
										// No account key specified, open an account trie
 | 
				
			||||||
 | 
										trie, err = statedb.OpenTrie(header.Root)
 | 
				
			||||||
 | 
										if trie == nil || err != nil {
 | 
				
			||||||
 | 
											p.Log().Warn("Failed to open storage trie for proof", "block", header.Number, "hash", header.Hash(), "root", header.Root, "err", err)
 | 
				
			||||||
 | 
											continue
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
									default:
 | 
				
			||||||
 | 
										// Account key specified, open a storage trie
 | 
				
			||||||
 | 
										account, err := pm.getAccount(statedb.TrieDB(), header.Root, common.BytesToHash(req.AccKey))
 | 
				
			||||||
 | 
										if err != nil {
 | 
				
			||||||
 | 
											p.Log().Warn("Failed to retrieve account for proof", "block", header.Number, "hash", header.Hash(), "account", common.BytesToHash(req.AccKey), "err", err)
 | 
				
			||||||
 | 
											continue
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
										trie, err = statedb.OpenStorageTrie(common.BytesToHash(req.AccKey), account.Root)
 | 
				
			||||||
 | 
										if trie == nil || err != nil {
 | 
				
			||||||
 | 
											p.Log().Warn("Failed to open storage trie for proof", "block", header.Number, "hash", header.Hash(), "account", common.BytesToHash(req.AccKey), "root", account.Root, "err", err)
 | 
				
			||||||
 | 
											continue
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									// Prove the user's request from the account or stroage trie
 | 
				
			||||||
 | 
									var proof light.NodeList
 | 
				
			||||||
 | 
									if err := trie.Prove(req.Key, 0, &proof); err != nil {
 | 
				
			||||||
 | 
										p.Log().Warn("Failed to prove state request", "block", header.Number, "hash", header.Hash(), "err", err)
 | 
				
			||||||
 | 
										continue
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
				proofs = append(proofs, proof)
 | 
									proofs = append(proofs, proof)
 | 
				
			||||||
				if bytes += proof.DataSize(); bytes >= softResponseLimit {
 | 
									if bytes += proof.DataSize(); bytes >= softResponseLimit {
 | 
				
			||||||
					break
 | 
										break
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
					}
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			sendResponse(req.ReqID, uint64(reqCnt), p.ReplyProofs(req.ReqID, proofs), task.done())
 | 
								sendResponse(req.ReqID, uint64(reqCnt), p.ReplyProofs(req.ReqID, proofs), task.done())
 | 
				
			||||||
		}()
 | 
							}()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -824,7 +851,6 @@ func (pm *ProtocolManager) handleMsg(p *peer) error {
 | 
				
			|||||||
		// Gather state data until the fetch or network limits is reached
 | 
							// Gather state data until the fetch or network limits is reached
 | 
				
			||||||
		var (
 | 
							var (
 | 
				
			||||||
			lastBHash common.Hash
 | 
								lastBHash common.Hash
 | 
				
			||||||
			statedb   *state.StateDB
 | 
					 | 
				
			||||||
			root      common.Hash
 | 
								root      common.Hash
 | 
				
			||||||
		)
 | 
							)
 | 
				
			||||||
		reqCnt := len(req.Reqs)
 | 
							reqCnt := len(req.Reqs)
 | 
				
			||||||
@@ -832,43 +858,60 @@ func (pm *ProtocolManager) handleMsg(p *peer) error {
 | 
				
			|||||||
			return errResp(ErrRequestRejected, "")
 | 
								return errResp(ErrRequestRejected, "")
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		go func() {
 | 
							go func() {
 | 
				
			||||||
 | 
					 | 
				
			||||||
			nodes := light.NewNodeSet()
 | 
								nodes := light.NewNodeSet()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			for i, req := range req.Reqs {
 | 
								for i, req := range req.Reqs {
 | 
				
			||||||
				if i != 0 && !task.waitOrStop() {
 | 
									if i != 0 && !task.waitOrStop() {
 | 
				
			||||||
					return
 | 
										return
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
				// Look up the state belonging to the request
 | 
									// Look up the root hash belonging to the request
 | 
				
			||||||
				if statedb == nil || req.BHash != lastBHash {
 | 
									var (
 | 
				
			||||||
					statedb, root, lastBHash = nil, common.Hash{}, req.BHash
 | 
										number *uint64
 | 
				
			||||||
 | 
										header *types.Header
 | 
				
			||||||
 | 
										trie   state.Trie
 | 
				
			||||||
 | 
									)
 | 
				
			||||||
 | 
									if req.BHash != lastBHash {
 | 
				
			||||||
 | 
										root, lastBHash = common.Hash{}, req.BHash
 | 
				
			||||||
 | 
					
 | 
				
			||||||
					if number := rawdb.ReadHeaderNumber(pm.chainDb, req.BHash); number != nil {
 | 
										if number = rawdb.ReadHeaderNumber(pm.chainDb, req.BHash); number == nil {
 | 
				
			||||||
						if header := rawdb.ReadHeader(pm.chainDb, req.BHash, *number); header != nil {
 | 
											p.Log().Warn("Failed to retrieve block num for proof", "hash", req.BHash)
 | 
				
			||||||
							statedb, _ = pm.blockchain.State()
 | 
											continue
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
										if header = rawdb.ReadHeader(pm.chainDb, req.BHash, *number); header == nil {
 | 
				
			||||||
 | 
											p.Log().Warn("Failed to retrieve header for proof", "block", *number, "hash", req.BHash)
 | 
				
			||||||
 | 
											continue
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
					root = header.Root
 | 
										root = header.Root
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
					}
 | 
									// Open the account or storage trie for the request
 | 
				
			||||||
				}
 | 
									statedb := pm.blockchain.StateCache()
 | 
				
			||||||
				if statedb == nil {
 | 
					
 | 
				
			||||||
 | 
									switch len(req.AccKey) {
 | 
				
			||||||
 | 
									case 0:
 | 
				
			||||||
 | 
										// No account key specified, open an account trie
 | 
				
			||||||
 | 
										trie, err = statedb.OpenTrie(root)
 | 
				
			||||||
 | 
										if trie == nil || err != nil {
 | 
				
			||||||
 | 
											p.Log().Warn("Failed to open storage trie for proof", "block", header.Number, "hash", header.Hash(), "root", root, "err", err)
 | 
				
			||||||
						continue
 | 
											continue
 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
				// Pull the account or storage trie of the request
 | 
									default:
 | 
				
			||||||
				var trie state.Trie
 | 
										// Account key specified, open a storage trie
 | 
				
			||||||
				if len(req.AccKey) > 0 {
 | 
										account, err := pm.getAccount(statedb.TrieDB(), root, common.BytesToHash(req.AccKey))
 | 
				
			||||||
					account, err := pm.getAccount(statedb, root, common.BytesToHash(req.AccKey))
 | 
					 | 
				
			||||||
					if err != nil {
 | 
										if err != nil {
 | 
				
			||||||
 | 
											p.Log().Warn("Failed to retrieve account for proof", "block", header.Number, "hash", header.Hash(), "account", common.BytesToHash(req.AccKey), "err", err)
 | 
				
			||||||
						continue
 | 
											continue
 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
					trie, _ = statedb.Database().OpenStorageTrie(common.BytesToHash(req.AccKey), account.Root)
 | 
										trie, err = statedb.OpenStorageTrie(common.BytesToHash(req.AccKey), account.Root)
 | 
				
			||||||
				} else {
 | 
										if trie == nil || err != nil {
 | 
				
			||||||
					trie, _ = statedb.Database().OpenTrie(root)
 | 
											p.Log().Warn("Failed to open storage trie for proof", "block", header.Number, "hash", header.Hash(), "account", common.BytesToHash(req.AccKey), "root", account.Root, "err", err)
 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
				if trie == nil {
 | 
					 | 
				
			||||||
						continue
 | 
											continue
 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
				// Prove the user's request from the account or stroage trie
 | 
									// Prove the user's request from the account or stroage trie
 | 
				
			||||||
				trie.Prove(req.Key, req.FromLevel, nodes)
 | 
									if err := trie.Prove(req.Key, req.FromLevel, nodes); err != nil {
 | 
				
			||||||
 | 
										p.Log().Warn("Failed to prove state request", "block", header.Number, "hash", header.Hash(), "err", err)
 | 
				
			||||||
 | 
										continue
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
				if nodes.DataSize() >= softResponseLimit {
 | 
									if nodes.DataSize() >= softResponseLimit {
 | 
				
			||||||
					break
 | 
										break
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
@@ -1190,8 +1233,8 @@ func (pm *ProtocolManager) handleMsg(p *peer) error {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// getAccount retrieves an account from the state based at root.
 | 
					// getAccount retrieves an account from the state based at root.
 | 
				
			||||||
func (pm *ProtocolManager) getAccount(statedb *state.StateDB, root, hash common.Hash) (state.Account, error) {
 | 
					func (pm *ProtocolManager) getAccount(triedb *trie.Database, root, hash common.Hash) (state.Account, error) {
 | 
				
			||||||
	trie, err := trie.New(root, statedb.Database().TrieDB())
 | 
						trie, err := trie.New(root, triedb)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return state.Account{}, err
 | 
							return state.Account{}, err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -211,9 +211,8 @@ func (lc *LightChain) Genesis() *types.Block {
 | 
				
			|||||||
	return lc.genesisBlock
 | 
						return lc.genesisBlock
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// State returns a new mutable state based on the current HEAD block.
 | 
					func (lc *LightChain) StateCache() state.Database {
 | 
				
			||||||
func (lc *LightChain) State() (*state.StateDB, error) {
 | 
						panic("not implemented")
 | 
				
			||||||
	return nil, errors.New("not implemented, needs client/server interface split")
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// GetBody retrieves a block body (transactions and uncles) from the database
 | 
					// GetBody retrieves a block body (transactions and uncles) from the database
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user