#![cfg(feature = "unstable-store")]
use content_addressable::store::{
AddressedBytes, MemoryStore, NodeStore, NodeStoreExt, StoreError, StoreOperation, VerifiedStore,
};
use content_addressable::{canonical, ContentAddressable, ContentError, ContentId};
fn canonical_map(n: u64) -> Vec<u8> {
let ipld: ipld_core::ipld::Ipld =
serde_json::from_value(serde_json::json!({"n": n, "name": "node"})).expect("json -> ipld");
canonical::to_canonical_dagcbor(&ipld).expect("encode canonical")
}
const NON_CANONICAL: [u8; 8] = [0xa2, 0x62, 0x62, 0x62, 0x01, 0x61, 0x61, 0x02];
#[test]
fn put_derives_the_address() {
let mut store = MemoryStore::new();
for n in 0..8 {
let bytes = canonical_map(n);
let id = store.put(&bytes).expect("put succeeds");
assert_eq!(
id,
ContentId::from_canonical_bytes(&bytes),
"put must return exactly the content-derived id"
);
}
}
#[test]
fn put_node_equals_content_id() {
#[derive(serde::Serialize)]
struct Rec {
k: String,
}
impl ContentAddressable for Rec {
fn canonical_form(&self) -> Result<Vec<u8>, ContentError> {
canonical::to_canonical_dagcbor(self)
}
}
let mut store = MemoryStore::new();
let rec = Rec { k: "value".into() };
let via_store = store.put_node(&rec).expect("put_node succeeds");
let via_trait = rec.content_id().expect("content_id succeeds");
assert_eq!(
via_store, via_trait,
"put_node(n) must equal n.content_id()"
);
}
#[derive(Default)]
struct DroppingStore;
impl NodeStore for DroppingStore {
fn get_unverified(&self, id: &ContentId) -> Result<Vec<u8>, StoreError> {
Err(StoreError::NotFound(*id))
}
fn insert(&mut self, _item: AddressedBytes<'_>) -> Result<(), StoreError> {
Ok(())
}
}
#[test]
fn put_id_is_seam_derived_not_backend_minted() {
let mut store = DroppingStore;
let bytes = canonical_map(1);
let id = store.put(&bytes).expect("put succeeds");
assert_eq!(
id,
ContentId::from_canonical_bytes(&bytes),
"the id must be the seam's derivation, regardless of the backend"
);
assert!(matches!(store.get(&id), Err(StoreError::NotFound(_))));
}
#[test]
fn get_returns_exactly_what_was_put() {
let mut store = MemoryStore::new();
let bytes = canonical_map(1);
let id = store.put(&bytes).expect("put succeeds");
let back = store.get(&id).expect("verified get succeeds");
assert_eq!(back, bytes, "get must return the exact stored bytes");
}
#[test]
fn decode_verified_bytes_round_trips_a_value() {
let mut store = MemoryStore::new();
let ipld: ipld_core::ipld::Ipld =
serde_json::from_value(serde_json::json!({"alpha": 1, "zeta": 26})).expect("json -> ipld");
let bytes = canonical::to_canonical_dagcbor(&ipld).expect("encode");
let id = store.put(&bytes).expect("put succeeds");
let back: ipld_core::ipld::Ipld = store
.decode_verified_bytes(&id)
.expect("decode_verified_bytes succeeds");
assert_eq!(back, ipld, "must decode the stored value");
}
#[test]
fn decode_verified_bytes_surfaces_decode_failure_for_wrong_type() {
let mut store = MemoryStore::new();
let id = store.put(&canonical_map(1)).expect("put succeeds");
let err = store
.decode_verified_bytes::<u64>(&id)
.expect_err("wrong type must fail to decode");
assert!(
matches!(err, StoreError::Content(ContentError::DecodingError { .. })),
"wrong-type decode must surface as Content(DecodingError), got {err:?}"
);
}
#[derive(Debug, PartialEq, serde::Serialize, serde::Deserialize)]
struct OnlyAlpha {
alpha: u64,
}
impl ContentAddressable for OnlyAlpha {
fn canonical_form(&self) -> Result<Vec<u8>, ContentError> {
canonical::to_canonical_dagcbor(self)
}
}
#[test]
fn get_node_rejects_a_lossy_decode_that_decode_verified_bytes_would_admit() {
let mut store = MemoryStore::new();
let ipld: ipld_core::ipld::Ipld =
serde_json::from_value(serde_json::json!({"alpha": 1, "zeta": 26})).expect("json -> ipld");
let bytes = canonical::to_canonical_dagcbor(&ipld).expect("encode");
let id = store.put(&bytes).expect("put succeeds");
let lossy: OnlyAlpha = store
.decode_verified_bytes(&id)
.expect("lenient decode admits the lossy value");
assert_eq!(lossy, OnlyAlpha { alpha: 1 });
assert_ne!(
lossy.content_id().expect("cid"),
id,
"the decoded value's own CID differs from the id it was read under"
);
let err = store
.get_node::<OnlyAlpha>(&id)
.expect_err("a lossy round-trip must be rejected by the identity-preserving read");
assert!(
matches!(err, StoreError::RepresentationMismatch { id: got } if got == id),
"get_node must reject a lossy re-encode with RepresentationMismatch, got {err:?}"
);
}
#[test]
fn get_node_round_trips_an_identity_preserving_value() {
let mut store = MemoryStore::new();
let v = OnlyAlpha { alpha: 7 };
let id = store.put_node(&v).expect("put_node");
let back: OnlyAlpha = store.get_node(&id).expect("get_node succeeds");
assert_eq!(back, v);
}
#[test]
fn get_missing_is_not_found_carrying_the_id() {
let store = MemoryStore::new();
let id = ContentId::from_canonical_bytes(&canonical_map(42));
let err = store.get(&id).expect_err("missing id must be NotFound");
match err {
StoreError::NotFound(missing) => {
assert_eq!(missing, id, "NotFound must carry the requested id")
}
other => panic!("expected NotFound, got {other:?}"),
}
}
struct SubstitutingStore {
wrong_bytes: Vec<u8>,
}
impl NodeStore for SubstitutingStore {
fn get_unverified(&self, _id: &ContentId) -> Result<Vec<u8>, StoreError> {
Ok(self.wrong_bytes.clone())
}
fn insert(&mut self, _item: AddressedBytes<'_>) -> Result<(), StoreError> {
Ok(())
}
}
struct CorruptingStore {
inner: MemoryStore,
}
impl NodeStore for CorruptingStore {
fn get_unverified(&self, id: &ContentId) -> Result<Vec<u8>, StoreError> {
let mut bytes = self.inner.get_unverified(id)?;
*bytes.last_mut().expect("stored nodes are non-empty") ^= 0x01;
Ok(bytes)
}
fn insert(&mut self, item: AddressedBytes<'_>) -> Result<(), StoreError> {
self.inner.insert(item)
}
}
#[test]
fn verified_get_rejects_substituted_bytes() {
let wrong = canonical_map(999);
let store = SubstitutingStore {
wrong_bytes: wrong.clone(),
};
let requested = ContentId::from_canonical_bytes(&canonical_map(1));
let err = store
.get(&requested)
.expect_err("substituted bytes must fail verification");
match err {
StoreError::Content(ContentError::VerificationFailed { expected, computed }) => {
assert_eq!(expected, requested.to_string(), "expected = requested id");
assert_eq!(
computed,
ContentId::from_canonical_bytes(&wrong).to_string(),
"computed = the substituted bytes' real id"
);
}
other => panic!("expected Content(VerificationFailed), got {other:?}"),
}
}
#[test]
fn verified_get_rejects_corrupted_bytes() {
let mut store = CorruptingStore {
inner: MemoryStore::new(),
};
let bytes = canonical_map(7);
let id = store.put(&bytes).expect("put succeeds");
let err = store
.get(&id)
.expect_err("corrupted bytes must fail verification");
assert!(
matches!(
err,
StoreError::Content(ContentError::VerificationFailed { .. })
),
"corruption must surface as Content(VerificationFailed), got {err:?}"
);
}
#[test]
fn put_checked_accepts_canonical_and_matches_put() {
let bytes = canonical_map(3);
let mut a = MemoryStore::new();
let mut b = MemoryStore::new();
let via_checked = a.put_checked(&bytes).expect("canonical bytes accepted");
let via_unchecked = b.put(&bytes).expect("put succeeds");
assert_eq!(
via_checked, via_unchecked,
"put_checked(canonical) must equal put(canonical)"
);
assert_eq!(a, b, "both stores must hold identical state");
}
#[test]
fn put_checked_rejects_non_canonical_cbor() {
let mut store = MemoryStore::new();
let err = store
.put_checked(&NON_CANONICAL)
.expect_err("non-canonical CBOR must be rejected");
assert!(
matches!(err, StoreError::Content(ContentError::NonCanonical)),
"non-canonical valid CBOR must map to Content(NonCanonical), got {err:?}"
);
assert!(store.is_empty(), "rejected bytes must not be stored");
}
#[test]
fn put_checked_rejects_non_cbor_garbage() {
let mut store = MemoryStore::new();
let err = store
.put_checked(&[0xff, 0xff, 0xff, 0xff])
.expect_err("garbage must be rejected");
assert!(
matches!(err, StoreError::Content(ContentError::DecodingError { .. })),
"garbage must map to Content(DecodingError), got {err:?}"
);
assert!(store.is_empty(), "rejected bytes must not be stored");
}
#[test]
fn put_is_idempotent_and_grow_only() {
let mut store = MemoryStore::new();
let bytes = canonical_map(5);
let first = store.put(&bytes).expect("first put");
let snapshot = store.clone();
let second = store.put(&bytes).expect("second put");
assert_eq!(first, second, "same bytes must yield the same id");
assert_eq!(store, snapshot, "idempotent put must not change state");
assert_eq!(store.len(), 1, "one distinct node stored once");
assert_eq!(
store.get(&first).expect("get succeeds"),
bytes,
"the mapping is never rebound"
);
}
#[test]
fn a_mismatched_insert_is_unrepresentable_and_repeat_writes_are_idempotent() {
let mut store = MemoryStore::new();
let a = canonical_map(1);
let id = store.put(&a).expect("put A");
assert_eq!(
id,
ContentId::from_canonical_bytes(&a),
"put files under the derived id"
);
store.put(&a).expect("idempotent re-put");
let other = store.put(&canonical_map(2)).expect("put B");
assert_ne!(other, id);
assert_eq!(store.len(), 2, "grow-only: two distinct nodes");
assert_eq!(store.get(&id).expect("A resolves"), a);
}
struct ShadowingStore {
served: Vec<u8>,
}
impl ShadowingStore {
fn get(&self, _id: &ContentId) -> Result<Vec<u8>, StoreError> {
Ok(self.served.clone())
}
}
impl NodeStore for ShadowingStore {
fn get_unverified(&self, _id: &ContentId) -> Result<Vec<u8>, StoreError> {
Ok(self.served.clone())
}
fn insert(&mut self, _item: AddressedBytes<'_>) -> Result<(), StoreError> {
Ok(())
}
}
#[test]
fn verified_store_defeats_inherent_method_shadowing() {
let honest = canonical_map(1);
let id = ContentId::from_canonical_bytes(&honest);
let hostile = canonical_map(2);
assert_ne!(honest, hostile);
let store = ShadowingStore { served: hostile };
assert_eq!(store.get(&id).expect("inherent get"), canonical_map(2));
let verified = VerifiedStore::new(ShadowingStore {
served: canonical_map(2),
});
assert!(
matches!(
verified.get(&id),
Err(StoreError::Content(ContentError::VerificationFailed { .. }))
),
"VerifiedStore::get must verify and reject the substituted bytes"
);
assert!(
matches!(
NodeStoreExt::get(&store, &id),
Err(StoreError::Content(ContentError::VerificationFailed { .. }))
),
"NodeStoreExt::get (UFCS) must verify and reject the substituted bytes"
);
}
struct BadNode;
impl ContentAddressable for BadNode {
fn canonical_form(&self) -> Result<Vec<u8>, ContentError> {
Ok(b"deterministic, but not dag-cbor".to_vec())
}
}
#[test]
fn put_node_rejects_a_non_canonical_content_addressable() {
let mut store = MemoryStore::new();
let err = store
.put_node(&BadNode)
.expect_err("a non-canonical node must be rejected at write");
assert!(
matches!(
err,
StoreError::Content(ContentError::DecodingError { .. } | ContentError::NonCanonical)
),
"put_node must reject non-canonical bytes, got {err:?}"
);
assert_eq!(store.len(), 0, "nothing was stored");
}
#[test]
fn get_node_rejects_non_canonical_stored_bytes_before_trusting_t() {
let mut store = MemoryStore::new();
let id = store
.put(&NON_CANONICAL)
.expect("raw put accepts any bytes");
let err = store
.get_node::<OnlyAlpha>(&id)
.expect_err("non-canonical stored bytes must be rejected");
assert!(
matches!(
err,
StoreError::Content(ContentError::NonCanonical | ContentError::DecodingError { .. })
),
"get_node must reject non-canonical bytes, got {err:?}"
);
}
#[test]
fn verified_store_wraps_boxed_and_borrowed_backends() {
let boxed: Box<dyn NodeStore> = Box::new(MemoryStore::new());
let mut v = VerifiedStore::new(boxed);
let id = v
.put(&canonical_map(1))
.expect("put through a boxed dyn backend");
assert_eq!(
v.get(&id).expect("get through the facade"),
canonical_map(1)
);
let mut backing = MemoryStore::new();
{
let mut vb = VerifiedStore::new(&mut backing);
let id2 = vb
.put(&canonical_map(2))
.expect("put through a &mut backend");
assert_eq!(vb.get(&id2).expect("get"), canonical_map(2));
}
assert_eq!(backing.len(), 1, "the borrowed backend received the write");
}
#[test]
fn store_error_has_backend_and_collision_representations() {
let io = std::io::Error::new(std::io::ErrorKind::PermissionDenied, "disk offline");
let backend = StoreError::Backend {
operation: StoreOperation::Insert,
source: Box::new(io),
};
assert!(
backend.to_string().contains("insert"),
"a backend error names the operation that failed"
);
assert!(
std::error::Error::source(&backend).is_some(),
"a backend error preserves its underlying source"
);
let id = ContentId::from_canonical_bytes(&canonical_map(1));
let collision = StoreError::Collision { id };
assert!(collision.to_string().contains(&id.to_string()));
}
#[test]
fn store_state_is_insertion_order_independent() {
let blobs: Vec<Vec<u8>> = (0..6).map(canonical_map).collect();
let mut forward = MemoryStore::new();
for b in &blobs {
forward.put(b).expect("put succeeds");
}
let mut reverse = MemoryStore::new();
for b in blobs.iter().rev() {
reverse.put(b).expect("put succeeds");
}
assert_eq!(
forward, reverse,
"insertion order must not affect store state"
);
}
#[test]
fn hand_rolled_value_sweep_holds_the_laws() {
let values = [
serde_json::json!({}),
serde_json::json!([]),
serde_json::json!(null),
serde_json::json!(0),
serde_json::json!(-1),
serde_json::json!(u64::from(u32::MAX)),
serde_json::json!("ütf-8 ünïcödé"),
serde_json::json!({"nested": {"deep": [1, 2, {"deeper": null}]}}),
serde_json::json!([1, "two", [3.5], {"four": 4}]),
];
let mut store = MemoryStore::new();
for v in &values {
let ipld: ipld_core::ipld::Ipld = serde_json::from_value(v.clone()).expect("json -> ipld");
let bytes = canonical::to_canonical_dagcbor(&ipld).expect("encode");
let id = store.put(&bytes).expect("put succeeds");
assert_eq!(id, ContentId::from_canonical_bytes(&bytes), "PO-STORE-1");
assert_eq!(store.get(&id).expect("get succeeds"), bytes, "round-trip");
assert_eq!(store.put(&bytes).expect("re-put"), id, "idempotence");
}
assert_eq!(store.len(), values.len(), "each distinct value stored once");
}
#[test]
fn node_store_is_dyn_compatible_and_gets_ext_methods() {
let mut boxed: Box<dyn NodeStore> = Box::new(MemoryStore::new());
let bytes = canonical_map(11);
let id = boxed.put(&bytes).expect("put through dyn");
assert_eq!(
boxed.get(&id).expect("verified get through dyn"),
bytes,
"NodeStoreExt::get must work on dyn NodeStore"
);
let back: ipld_core::ipld::Ipld = boxed
.decode_verified_bytes(&id)
.expect("decode_verified_bytes over dyn NodeStore");
let reencoded = canonical::to_canonical_dagcbor(&back).expect("re-encode");
assert_eq!(reencoded, bytes, "typed read round-trips through dyn");
boxed
.put_checked(&bytes)
.expect("put_checked must work on dyn NodeStore");
let hostile: Box<dyn NodeStore> = Box::new(SubstitutingStore {
wrong_bytes: canonical_map(999),
});
let err = hostile
.get(&id)
.expect_err("substitution through dyn must fail verification");
assert!(
matches!(
err,
StoreError::Content(ContentError::VerificationFailed { .. })
),
"dyn-dispatched get must verify-on-read, got {err:?}"
);
}
#[test]
fn store_error_is_send_sync_static() {
fn assert_send_sync_static<T: Send + Sync + 'static>() {}
assert_send_sync_static::<StoreError>();
}
#[cfg(feature = "unstable-merkle")]
mod merkle_integration {
use std::collections::BTreeMap;
use super::*;
use content_addressable::merkle::MerkleNode;
fn reconstruct(
store: &impl NodeStore,
root: &ContentId,
out: &mut BTreeMap<ContentId, MerkleNode<String>>,
visiting: &mut std::collections::BTreeSet<ContentId>,
) -> Result<(), StoreError> {
if out.contains_key(root) {
return Ok(());
}
assert!(
visiting.insert(*root),
"back-edge: a content-addressed DAG is acyclic"
);
let node: MerkleNode<String> = store.get_node(root)?;
for parent in node.parents().clone() {
reconstruct(store, &parent, out, visiting)?;
}
visiting.remove(root);
out.insert(*root, node);
Ok(())
}
#[test]
fn a_dag_is_fully_determined_by_root_cid_plus_store() {
let mut store = MemoryStore::new();
let a = MerkleNode::genesis("a".to_string());
let a_id = store.put_node(&a).expect("put a");
let b = MerkleNode::new("b".to_string(), [a_id]);
let b_id = store.put_node(&b).expect("put b");
let c = MerkleNode::new("c".to_string(), [a_id]);
let c_id = store.put_node(&c).expect("put c");
let d = MerkleNode::new("d".to_string(), [b_id, c_id]);
let d_id = store.put_node(&d).expect("put d");
let mut recovered = BTreeMap::new();
let mut visiting = std::collections::BTreeSet::new();
reconstruct(&store, &d_id, &mut recovered, &mut visiting).expect("reconstruct from root");
assert_eq!(recovered.len(), 4, "all four nodes reachable from the root");
assert_eq!(recovered[&a_id], a);
assert_eq!(recovered[&b_id], b);
assert_eq!(recovered[&c_id], c);
assert_eq!(recovered[&d_id], d);
}
#[test]
fn a_missing_interior_node_fails_loudly_not_partially() {
let mut full = MemoryStore::new();
let a = MerkleNode::genesis("a".to_string());
let a_id = full.put_node(&a).expect("put a");
let b = MerkleNode::new("b".to_string(), [a_id]);
let b_id = full.put_node(&b).expect("put b");
let mut partial = MemoryStore::new();
let b_bytes = b.canonical_form().expect("encode b");
partial.put(&b_bytes).expect("put only b");
let mut recovered = BTreeMap::new();
let mut visiting = std::collections::BTreeSet::new();
let err = reconstruct(&partial, &b_id, &mut recovered, &mut visiting)
.expect_err("missing parent must fail reconstruction");
assert!(
matches!(err, StoreError::NotFound(missing) if missing == a_id),
"the failure must name exactly the missing node, got {err:?}"
);
}
}
#[test]
fn put_node_propagates_encoding_failure() {
struct Unencodable;
impl ContentAddressable for Unencodable {
fn canonical_form(&self) -> Result<Vec<u8>, ContentError> {
canonical::to_canonical_dagcbor(&f64::NAN)
}
}
let mut store = MemoryStore::new();
let err = store
.put_node(&Unencodable)
.expect_err("NaN must fail to encode");
assert!(
matches!(err, StoreError::Content(ContentError::EncodingError { .. })),
"encoding failure must surface as Content(EncodingError), got {err:?}"
);
assert!(store.is_empty(), "nothing may be stored on failure");
}
#[test]
fn store_error_display_is_legible() {
let id = ContentId::from_canonical_bytes(&[0xa0]);
assert_eq!(
StoreError::NotFound(id).to_string(),
format!("node not found: {id}"),
);
let inner = ContentError::NonCanonical;
let expected = inner.to_string();
assert_eq!(
StoreError::Content(inner).to_string(),
expected,
"Content must display transparently as the inner error"
);
}
const NON_CANONICAL_ALPHA: [u8; 10] = [0xa1, 0x65, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x19, 0x00, 0x01];
#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq)]
struct SneakyAlpha {
alpha: u64,
}
impl ContentAddressable for SneakyAlpha {
fn canonical_form(&self) -> Result<Vec<u8>, ContentError> {
canonical::to_canonical_dagcbor(self)
}
#[allow(deprecated)]
fn from_canonical_form(bytes: &[u8]) -> Result<Self, ContentError> {
canonical::from_canonical_dagcbor(bytes)
}
}
#[test]
fn get_node_cannot_be_weakened_by_a_type_that_overrides_from_canonical_form() {
let mut store = MemoryStore::new();
let id = store
.put(&NON_CANONICAL_ALPHA)
.expect("raw put accepts any bytes");
let direct = SneakyAlpha::from_canonical_form(&NON_CANONICAL_ALPHA)
.expect("the override must accept the non-canonical bytes");
assert_eq!(direct, SneakyAlpha { alpha: 1 });
assert_ne!(
direct.content_id().expect("content_id"),
id,
"and the value it returns is NOT the one the stored id names — that is the hazard"
);
let err = store
.get_node::<SneakyAlpha>(&id)
.expect_err("get_node must reject the non-canonical stored bytes regardless of T");
assert!(
matches!(err, StoreError::Content(ContentError::NonCanonical)),
"an overriding T must not be able to turn the seam's check off, got {err:?}"
);
}
#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq)]
struct EncoderSaysLossy;
impl ContentAddressable for EncoderSaysLossy {
fn canonical_form(&self) -> Result<Vec<u8>, ContentError> {
Err(ContentError::LossyDecode)
}
}
#[test]
fn get_node_does_not_blame_the_bytes_for_an_error_inside_the_types_encoder() {
let mut store = MemoryStore::new();
let bytes = canonical::to_canonical_dagcbor(&EncoderSaysLossy).expect("encode null");
let id = store.put(&bytes).expect("put succeeds");
let err = store
.get_node::<EncoderSaysLossy>(&id)
.expect_err("the encoder fails, so the read must fail");
assert!(
matches!(err, StoreError::Content(ContentError::LossyDecode)),
"an encoder-originated error must propagate verbatim, not be blamed on the \
stored bytes as RepresentationMismatch, got {err:?}"
);
}
static SPY_DECODED: std::sync::atomic::AtomicBool = std::sync::atomic::AtomicBool::new(false);
#[derive(serde::Serialize, Debug, PartialEq)]
struct Spy {
alpha: u64,
}
impl<'de> serde::Deserialize<'de> for Spy {
fn deserialize<D: serde::Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
SPY_DECODED.store(true, std::sync::atomic::Ordering::SeqCst);
#[derive(serde::Deserialize)]
struct Inner {
alpha: u64,
}
Ok(Spy {
alpha: Inner::deserialize(d)?.alpha,
})
}
}
impl ContentAddressable for Spy {
fn canonical_form(&self) -> Result<Vec<u8>, ContentError> {
canonical::to_canonical_dagcbor(self)
}
}
#[test]
fn get_node_proves_canonicality_before_it_constructs_any_t() {
use std::sync::atomic::Ordering::SeqCst;
let mut store = MemoryStore::new();
let bad = store
.put(&NON_CANONICAL_ALPHA)
.expect("raw put accepts any bytes");
SPY_DECODED.store(false, SeqCst);
let err = store
.get_node::<Spy>(&bad)
.expect_err("non-canonical stored bytes must be rejected");
assert!(matches!(
err,
StoreError::Content(ContentError::NonCanonical)
));
assert!(
!SPY_DECODED.load(SeqCst),
"the canonicality gate must run BEFORE any T is constructed"
);
let good = store
.put_node(&Spy { alpha: 1 })
.expect("a canonical node stores");
SPY_DECODED.store(false, SeqCst);
let back: Spy = store.get_node(&good).expect("get_node succeeds");
assert_eq!(back, Spy { alpha: 1 });
assert!(
SPY_DECODED.load(SeqCst),
"the spy must actually be the decode path, or the ordering check is vacuous"
);
}