0
2022-08-02 18:53:10 〽️ Prometheus exporter started at 127.0.0.1:9616
2022-08-02 18:53:10 🥩 run BEEFY worker, best grandpa: #13709439.
2022-08-02 18:53:10 creating instance on iface 65.21.88.129
2022-08-02 18:53:10 failed to create `InterfaceState`: No such device (os error 19)
2022-08-02 18:53:10 creating instance on iface 172.17.0.1
2022-08-02 18:53:10 GRANDPA voter error: could not complete a round on disk: bad justification for header: invalid precommits for target commit
2022-08-02 18:53:10 Essential task `grandpa-voter` failed. Shutting down service.
2022-08-02 18:53:10 〽️ Prometheus exporter started at 127.0.0.1:9615
2022-08-02 18:53:10 creating instance on iface 65.21.88.129
2022-08-02 18:53:10 failed to create `InterfaceState`: No such device (os error 19)
2022-08-02 18:53:10 creating instance on iface 172.17.0.1
Error: Service(Other("Essential task failed."))

I have tried Google, but nothing useful founded.

What should I do? I have no idea how to debug this.

I think the Interface error can be ignored. I can run node with that error before. Or in a new -d path.


This would an issue. It's really hard to analyze. I'm going to close this.

What I do is clean the DB and resync. That works for me. But Kusama's state is 300GB now. we can not always do the resync.

1 Answer 1

1

Looks like the grandpa-voter failed.

The specific error Essential task failed is originating from here:

/// Return a future that will end with success if the signal to terminate was sent
/// (`self.terminate()`) or with an error if an essential task fails.
///
/// # Warning
///
/// This function will not wait until the end of the remaining task.
pub fn future<'a>(
    &'a mut self,
) -> Pin<Box<dyn Future<Output = Result<(), Error>> + Send + 'a>> {
    Box::pin(async move {
        let mut t1 = self.essential_failed_rx.next().fuse();
        let mut t2 = self.on_exit.clone().fuse();
        let mut t3 = try_join_all(
            self.children
                .iter_mut()
                .map(|x| x.future())
                // Never end this future if there is no error because if there is no children,
                // it must not stop
                .chain(std::iter::once(pending().boxed())),
        )
        .fuse();

        futures::select! {
            _ = t1 => Err(Error::Other("Essential task failed.".into())),
            _ = t2 => Ok(()),
            res = t3 => Err(res.map(|_| ()).expect_err("this future never ends; qed")),
        }
    })
}

Looks like the error: invalid precommits for target commit is coming from this logic:

/// Create a GRANDPA justification from the given commit. This method
/// assumes the commit is valid and well-formed.
pub fn from_commit<C>(
    client: &Arc<C>,
    round: u64,
    commit: Commit<Block>,
) -> Result<GrandpaJustification<Block>, Error>
where
    C: HeaderBackend<Block>,
{
    let mut votes_ancestries_hashes = HashSet::new();
    let mut votes_ancestries = Vec::new();

    let error = || {
        let msg = "invalid precommits for target commit".to_string();
        Err(Error::Client(ClientError::BadJustification(msg)))
    };

    // we pick the precommit for the lowest block as the base that
    // should serve as the root block for populating ancestry (i.e.
    // collect all headers from all precommit blocks to the base)
    let (base_hash, base_number) = match commit
        .precommits
        .iter()
        .map(|signed| &signed.precommit)
        .min_by_key(|precommit| precommit.target_number)
        .map(|precommit| (precommit.target_hash.clone(), precommit.target_number))
    {
        None => return error(),
        Some(base) => base,
    };

    for signed in commit.precommits.iter() {
        let mut current_hash = signed.precommit.target_hash;
        loop {
            if current_hash == base_hash {
                break
            }

            match client.header(BlockId::Hash(current_hash))? {
                Some(current_header) => {
                    // NOTE: this should never happen as we pick the lowest block
                    // as base and only traverse backwards from the other blocks
                    // in the commit. but better be safe to avoid an unbound loop.
                    if *current_header.number() <= base_number {
                        return error()
                    }

                    let parent_hash = *current_header.parent_hash();
                    if votes_ancestries_hashes.insert(current_hash) {
                        votes_ancestries.push(current_header);
                    }

                    current_hash = parent_hash;
                },
                _ => return error(),
            }
        }
    }

    Ok(GrandpaJustification { round, commit, votes_ancestries })
}

Also note this comment:

/// This is meant to be stored in the db and passed around the network to other
/// nodes, and are used by syncing nodes to prove authority set handoffs.

a little info on pre-commits:

Hope this is a little better than Google..

Not the answer you're looking for? Browse other questions tagged or ask your own question.