func (self *XEth) doSign(from common.Address, hash common.Hash, didUnlock bool) ([]byte, error) { sig, err := self.backend.AccountManager().Sign(accounts.Account{Address: from}, hash.Bytes()) if err == accounts.ErrLocked { if didUnlock { return nil, fmt.Errorf("signer account still locked after successful unlock") } if !self.frontend.UnlockAccount(from.Bytes()) { return nil, fmt.Errorf("could not unlock signer account") } // retry signing, the account should now be unlocked. return self.doSign(from, hash, true) } else if err != nil { return nil, err } return sig, nil }
// banBlocks retrieves a batch of blocks from a peer feeding us invalid hashes, // and bans the head of the retrieved batch. // // This method only fetches one single batch as the goal is not ban an entire // (potentially long) invalid chain - wasting a lot of time in the meanwhile -, // but rather to gradually build up a blacklist if the peer keeps reconnecting. func (d *Downloader) banBlocks(peerId string, head common.Hash) error { glog.V(logger.Debug).Infof("Banning a batch out of %d blocks from %s", d.queue.Pending(), peerId) // Ask the peer being banned for a batch of blocks from the banning point peer := d.peers.Peer(peerId) if peer == nil { return nil } request := d.queue.Reserve(peer, MaxBlockFetch) if request == nil { return nil } if err := peer.Fetch(request); err != nil { return err } // Wait a bit for the reply to arrive, and ban if done so timeout := time.After(blockHardTTL) for { select { case <-d.cancelCh: return errCancelBlockFetch case <-timeout: return errTimeout case <-d.hashCh: // Out of bounds hashes received, ignore them case blockPack := <-d.blockCh: blocks := blockPack.blocks // Short circuit if it's a stale cross check if len(blocks) == 1 { block := blocks[0] if _, ok := d.checks[block.Hash()]; ok { delete(d.checks, block.Hash()) break } } // Short circuit if it's not from the peer being banned if blockPack.peerId != peerId { break } // Short circuit if no blocks were returned if len(blocks) == 0 { return errors.New("no blocks returned to ban") } // Reconstruct the original chain order and ensure we're banning the correct blocks types.BlockBy(types.Number).Sort(blocks) if bytes.Compare(blocks[0].Hash().Bytes(), head.Bytes()) != 0 { return errors.New("head block not the banned one") } index := 0 for _, block := range blocks[1:] { if bytes.Compare(block.ParentHash().Bytes(), blocks[index].Hash().Bytes()) != 0 { break } index++ } // Ban the head hash and phase out any excess d.banned.Add(blocks[index].Hash()) for d.banned.Size() > maxBannedHashes { var evacuate common.Hash d.banned.Each(func(item interface{}) bool { // Skip any hard coded bans if core.BadHashes[item.(common.Hash)] { return true } evacuate = item.(common.Hash) return false }) d.banned.Remove(evacuate) } glog.V(logger.Debug).Infof("Banned %d blocks from: %s", index+1, peerId) return nil } } }