mirror of
https://github.com/zap-proto/go.git
synced 2026-10-30 15:05:00 +00:00
Generating C++ is a claim. This runs it. Both probes build the same cases from the same inputs — every type the dialect has, plus the request and response envelopes the generated client and dispatch produce — and print the hex; the two outputs are the same file. Then each probe reads both probes' bytes with its own generated accessors, four crossings, all agreeing. Then both read a corpus of real P-chain transactions produced by the Go chain implementation, 134 vectors of which 44 are truncated or malformed on purpose, and answer the same fields in the same places. Neither probe decides anything: every value printed comes from a generated accessor or a generated builder, so a disagreement between the probes is a disagreement between the backends and nowhere else. It earned its keep immediately. Five corpus vectors separated a Go [N]byte accessor answering zeros from a C++ span answering empty, and the round trip found the zero Object panicking in the Go runtime where C++ answered zero. Both are fixed; neither was visible by reading. list<T> carries a pointer and a count and nothing about elements — the dialect cannot state a stride — so both languages agree on the count, which is all either can say. That gap is in the dialect, in both backends at once.
115 lines
4.4 KiB
C++
115 lines
4.4 KiB
C++
// Code generated by zapgen; DO NOT EDIT.
|
|
// source: pchain.zap
|
|
// SPDX-License-Identifier: BSD-3-Clause-Eco
|
|
|
|
#pragma once
|
|
|
|
#include <array>
|
|
#include <cstdint>
|
|
#include <expected>
|
|
#include <span>
|
|
#include <vector>
|
|
|
|
#include <zap/zap.hpp>
|
|
|
|
namespace pchain {
|
|
|
|
class Spend;
|
|
|
|
// Field byte offsets for Spend, and the size of its fixed section.
|
|
inline constexpr std::int64_t kSpendKindOff = 0;
|
|
inline constexpr std::int64_t kSpendNetworkIDOff = 1;
|
|
inline constexpr std::int64_t kSpendBlockchainIDOff = 5;
|
|
inline constexpr std::int64_t kSpendOutsOff = 37;
|
|
inline constexpr std::int64_t kSpendOwnerAddrsOff = 45;
|
|
inline constexpr std::int64_t kSpendInsOff = 53;
|
|
inline constexpr std::int64_t kSpendSigIndicesOff = 61;
|
|
inline constexpr std::int64_t kSpendMemoOff = 69;
|
|
inline constexpr std::int64_t kSpendSize = 77;
|
|
|
|
// Spend is a zero-copy view into a ZAP-encoded Spend message. It borrows the
|
|
// bytes it was built over, which must outlive it, and copies no field.
|
|
class Spend {
|
|
public:
|
|
Spend() = default;
|
|
explicit Spend(zap::Object o) : o_(o) {}
|
|
|
|
bool is_null() const { return o_.is_null(); }
|
|
zap::Object object() const { return o_; }
|
|
|
|
std::uint8_t Kind() const { return o_.u8(kSpendKindOff); }
|
|
std::uint32_t NetworkID() const { return o_.u32(kSpendNetworkIDOff); }
|
|
std::span<const std::uint8_t> BlockchainID() const {
|
|
static constexpr std::array<std::uint8_t, 32> zero{};
|
|
const auto b = o_.bytes_fixed(kSpendBlockchainIDOff, 32);
|
|
return b.size() == 32 ? b : std::span<const std::uint8_t>(zero);
|
|
}
|
|
zap::List Outs() const { return o_.list(kSpendOutsOff); }
|
|
zap::List OwnerAddrs() const { return o_.list(kSpendOwnerAddrsOff); }
|
|
zap::List Ins() const { return o_.list(kSpendInsOff); }
|
|
zap::List SigIndices() const { return o_.list(kSpendSigIndicesOff); }
|
|
std::span<const std::uint8_t> Memo() const { return o_.bytes(kSpendMemoOff); }
|
|
|
|
private:
|
|
zap::Object o_;
|
|
};
|
|
|
|
// WrapSpend parses b and returns a typed view over it, or says why b is not a
|
|
// message. The view borrows b.
|
|
inline std::expected<Spend, zap::Error> WrapSpend(std::span<const std::uint8_t> b) {
|
|
auto m = zap::Message::parse(b);
|
|
if (!m) return std::unexpected(m.error());
|
|
return Spend(m->root());
|
|
}
|
|
|
|
// SpendInput collects the field values for NewSpend. A borrowed field is a view:
|
|
// it must outlive the call, not the buffer the call returns.
|
|
struct SpendInput {
|
|
std::uint8_t Kind{};
|
|
std::uint32_t NetworkID{};
|
|
std::array<std::uint8_t, 32> BlockchainID{};
|
|
std::vector<std::span<const std::uint8_t>> Outs{};
|
|
std::vector<std::span<const std::uint8_t>> OwnerAddrs{};
|
|
std::vector<std::span<const std::uint8_t>> Ins{};
|
|
std::vector<std::span<const std::uint8_t>> SigIndices{};
|
|
std::span<const std::uint8_t> Memo{};
|
|
};
|
|
|
|
// NewSpend writes a ZAP-encoded Spend message into a fresh buffer and returns it.
|
|
inline std::vector<std::uint8_t> NewSpend(const SpendInput& in) {
|
|
zap::Builder b(256, zap::kVersion1);
|
|
auto ob = b.start_object(kSpendSize);
|
|
ob.set_u8(kSpendKindOff, in.Kind);
|
|
ob.set_u32(kSpendNetworkIDOff, in.NetworkID);
|
|
ob.set_bytes_fixed(kSpendBlockchainIDOff, std::span<const std::uint8_t>(in.BlockchainID));
|
|
auto outs_list = b.start_list(0);
|
|
for (const auto& elem : in.Outs) {
|
|
outs_list.add_u32(static_cast<std::uint32_t>(elem.size()));
|
|
outs_list.add_bytes(elem);
|
|
}
|
|
ob.set_list(kSpendOutsOff, outs_list.finish().first, static_cast<std::int64_t>(in.Outs.size()));
|
|
auto ownerAddrs_list = b.start_list(0);
|
|
for (const auto& elem : in.OwnerAddrs) {
|
|
ownerAddrs_list.add_u32(static_cast<std::uint32_t>(elem.size()));
|
|
ownerAddrs_list.add_bytes(elem);
|
|
}
|
|
ob.set_list(kSpendOwnerAddrsOff, ownerAddrs_list.finish().first, static_cast<std::int64_t>(in.OwnerAddrs.size()));
|
|
auto ins_list = b.start_list(0);
|
|
for (const auto& elem : in.Ins) {
|
|
ins_list.add_u32(static_cast<std::uint32_t>(elem.size()));
|
|
ins_list.add_bytes(elem);
|
|
}
|
|
ob.set_list(kSpendInsOff, ins_list.finish().first, static_cast<std::int64_t>(in.Ins.size()));
|
|
auto sigIndices_list = b.start_list(0);
|
|
for (const auto& elem : in.SigIndices) {
|
|
sigIndices_list.add_u32(static_cast<std::uint32_t>(elem.size()));
|
|
sigIndices_list.add_bytes(elem);
|
|
}
|
|
ob.set_list(kSpendSigIndicesOff, sigIndices_list.finish().first, static_cast<std::int64_t>(in.SigIndices.size()));
|
|
ob.set_bytes(kSpendMemoOff, in.Memo);
|
|
ob.finish_as_root();
|
|
return b.finish();
|
|
}
|
|
|
|
} // namespace pchain
|