codechain icon indicating copy to clipboard operation
codechain copied to clipboard

OnChain invalid timestamp block propagation fail

Open posgnu opened this issue 7 years ago • 1 comments

There are some issues in sending invalid timestamp onChain blocks.

Below is a test scenario.

  1. Make block1 and block2.
  2. The timestamp in Block2's header should be invalid. Simply make it smaller than block1.
  3. Send a status message with block2's hash as the bestHash.
  4. Send a header response message which is [genesisHeader, block1Header, block2Header].
  5. Send a body response message == [[], []], which is correspond to block1's body and block2's body.
  6. Block is accepted from the target node only for block1. So the target node should send a status message with block1's hash as bestHash.(This is normal behaviour but it didn't)

And here are problems

  1. The target node does not send status message if in the above situation. However, if I inserted info!("55"); then the status message come properly.
  2. In below verify() function in /core/verification/queue/mod.rs, Ok(verified) is returned twice although the block2 is invalid.

    fn verify(
        verification: Arc<Verification<K>>,
        engine: Arc<CodeChainEngine>,
        ready_signal: Arc<QueueSignal>,
        empty: Arc<SCondvar>,
        more_to_verify: Arc<SCondvar>,
        _id: usize,
    ) {
        loop {
            // wait for work if empty.
            {
                let mut more_to_verify_mutex = verification.more_to_verify_mutex.lock().unwrap();

                if verification.unverified.lock().is_empty() && verification.verifying.lock().is_empty() {
                    empty.notify_all();
                }

                while verification.unverified.lock().is_empty() {
                    more_to_verify_mutex = more_to_verify.wait(more_to_verify_mutex).unwrap();
                }
            }

            // do work.
            let item = {
                // acquire these locks before getting the item to verify.
                let mut unverified = verification.unverified.lock();
                let mut verifying = verification.verifying.lock();

                let item = match unverified.pop_front() {
                    Some(item) => item,
                    None => continue,
                };

                verification.sizes.unverified.fetch_sub(item.heap_size_of_children(), AtomicOrdering::SeqCst);
                verifying.push_back(Verifying {
                    hash: item.hash(),
                    output: None,
                });
                item
            };

            let hash = item.hash();
            let is_ready = match K::verify(item, &*engine, verification.check_seal) {
                Ok(verified) => {
                    let mut verifying = verification.verifying.lock();
                    let mut idx = None;
                    for (i, e) in verifying.iter_mut().enumerate() {
                        if e.hash == hash {
                            idx = Some(i);

                            verification
                                .sizes
                                .verifying
                                .fetch_add(verified.heap_size_of_children(), AtomicOrdering::SeqCst);
                            e.output = Some(verified);
                            break
                        }
                    }

                    if idx == Some(0) {
                        // we're next!
                        let mut verified = verification.verified.lock();
                        let mut bad = verification.bad.lock();
                        VerificationQueue::drain_verifying(
                            &mut verifying,
                            &mut verified,
                            &mut bad,
                            &verification.sizes,
                        );
                        info!("111");
                        true
                    } else {
                        info!("222");
                        false
                    }
                }
                Err(_) => {
                    let mut verifying = verification.verifying.lock();
                    let mut verified = verification.verified.lock();
                    let mut bad = verification.bad.lock();

                    bad.insert(hash.clone());
                    verifying.retain(|e| e.hash != hash);

                    if verifying.front().map_or(false, |x| x.output.is_some()) {
                        VerificationQueue::drain_verifying(
                            &mut verifying,
                            &mut verified,
                            &mut bad,
                            &verification.sizes,
                        );
                        info!("33");
                        true
                    } else {
                        info!("44");
                        false
                    }
                }
            };
            if is_ready {
                info!("55");
                // Import the block immediately
                ready_signal.set_sync();
            }
        }
    }

posgnu avatar Oct 12 '18 02:10 posgnu

The verification queue cannot check the error with the parent block. It only checks the error of a block like an invalid signature. The error that can be checked with the parent status is checked when executing the transactions in the block.

sgkim126 avatar May 18 '19 21:05 sgkim126