Files
zeekay cc0aa16da7 The C++ Q, Z, D and F chains, and the half of a decision Q was missing
Four ports existed on branches nothing built and nothing ran against the
corpus. They are here so the differential has a C++ voice on the four
chains it could not see, and so that whatever they answer is answered in
public rather than in a branch.

  quantumvm  from blue/quantumvm-cpp
  zkvm       from blue/zkvm-cpp-impl
  dexvm      from blue/dexvm-cpp
  fhevm      from blue/fhevm-cpp  (with chains/cpp/zap, which it reads)

quantumvm did not build: the node's VM seam grew `Block::reject()` after
that branch was written, so VmBlock was abstract and every construction
of it was a compile error. It forwards to the block's own reject now,
and — as the seam asks and as Go's pendingBlocks.Decided does — accept
and reject are each inert once either has run.

Nothing else was changed. What these ports say about the corpus is the
next commit's business, and it is not this commit's job to make them say
anything in particular.

Verified: all four configure, build and pass their own suites here —
quantumvm 13/13, zkvm 13/13, dexvm 10/10, fhevm 14/14.
2026-09-05 13:50:41 -07:00

92 lines
3.7 KiB
C++

// Copyright (C) 2026, Lux Industries, Inc. All rights reserved.
// SPDX-License-Identifier: BSD-3-Clause-Eco
//
// parse_test.cpp — ported from Go chains/quantumvm/parse_roundtrip_test.go.
//
// The two doors into one format: a responder answers a catch-up request with the
// bytes it stored, and the requester admits the reply through the parser. A
// check on only one of them means the fleet serves what it will not accept.
#include "fixtures.hpp"
using namespace qvmtest;
// TestParseAcceptsWhatWeSerialize is the property this chain could not move
// without, and the one nothing asserted.
//
// The parser is the sole entry point for catch-up, gossip and Put. If it refuses
// the bytes this VM itself produces, then every node serves a block every node
// refuses, and the chain accepts nothing for as long as it runs — which is what
// happened: zero accepted certs on every validator, on every network, forever,
// while the package's own tests stayed green because none of them ever sent a
// block through the wire and back.
TEST(ParseAcceptsWhatWeSerialize) {
store::Memory db;
Booted vm = boot_vm_on(config::default_config(), &db);
REQUIRE_OK(vm.status);
wire::BlockFields f;
f.timestamp = 1000;
f.height = 7;
f.parent_id = random_id();
f.chain_id = vm->chain_id();
f.network_id = vm->network_id();
f.transactions = {stamped_tx(1, "op")};
Block blk(vm.vm.get(), std::move(f));
auto got = vm->parse_block(blk.bytes());
REQUIRE_MSG(got.has_value(),
"the parser refused bytes this VM serialized: a block every node serves and "
"every node refuses is a chain that cannot move");
REQUIRE_EQ(blk.id(), (*got)->id());
REQUIRE_EQ(std::uint64_t{7}, (*got)->height());
}
// TestServeAndReceiveAgree pins the asymmetry itself. Whatever either door does
// to a block, both must reach the same verdict.
TEST(ServeAndReceiveAgree) {
store::Memory db;
Booted vm = boot_vm_on(config::default_config(), &db);
REQUIRE_OK(vm.status);
wire::BlockFields f;
f.timestamp = 2000;
f.height = 1;
f.parent_id = tip_of(*vm);
f.chain_id = vm->chain_id();
f.network_id = vm->network_id();
f.transactions = {stamped_tx(1, "op")};
auto blk = std::make_shared<Block>(vm.vm.get(), std::move(f));
REQUIRE_OK(blk->accept());
auto served = vm->block(blk->id()); // responder side
auto received = vm->parse_block(blk->bytes()); // requester side
REQUIRE_MSG(served.has_value() == received.has_value(),
"the two paths disagree on identical bytes: every node would serve this block "
"and every node would refuse it");
REQUIRE_OK(served);
REQUIRE_MSG((*served)->id() == (*received)->id(), "one block read back under two ids");
}
// A block that came off the wire is a block that can be served again unchanged:
// parse ∘ serialize is the identity on the bytes, which is what makes a block id
// a fact about the block rather than about the node holding it.
TEST(ServingWhatWasReceivedChangesNothing) {
store::Memory db;
Booted vm = boot_vm_on(quiet_config(), &db);
REQUIRE_OK(vm.status);
REQUIRE_OK(vm->pool().add(stamped_tx(1, "op")));
auto built = vm->build_block();
REQUIRE_OK(built);
const ByteView first = (*built)->bytes();
const Bytes wire(first.begin(), first.end());
auto received = vm->parse_block(view(wire));
REQUIRE_OK(received);
const ByteView again = (*received)->bytes();
REQUIRE_MSG(again.size() == wire.size() && std::equal(again.begin(), again.end(), wire.begin()),
"a block changed shape by passing through the parser");
REQUIRE_EQ((*built)->id(), (*received)->id());
}