← Book map

Chapter 10 · Tabs

A data packet with a prologue

Two RPC calls, three wrappers: signdata produces an MMR descriptor and a signature, which become a VdxfUniValue inside a labelled DataDescriptor, then a data packet.

How an attestation is assembled signdata with createmmr returns an MMR descriptor and signature data, which are packed into a VdxfUniValue, wrapped in a labelled DataDescriptor, hashed, and then sent as a data packet request. TWO RPC CALLS, THREE WRAPPERS mmrdata[] label · mimetype · message signdata (createmmr) RPC, encrypttoaddress MMRDescriptor + SignatureData inside a VdxfUniValue DataDescriptor label + objectdata hex + sha256 pastebin payload data packet request → QR

FIGURE 10.1 · Attestation is a data packet with a two-call prologue.

Attestation is not a request type

There is no AttestationRequestOrdinalVDXFObject. An attestation tab produces a data packet whose signable object is a DataDescriptor containing a signed MMR payload. Once you see that, the 493 lines become approachable: half is building the descriptor, half is reusing the data-packet flow.

Step 1 — ask the daemon to sign the data

const sigRes = await verusId.interface.request({
  cmd: "signdata",
  getParams: () => [{
    address: signingId,
    createmmr: true,
    encrypttoaddress: encryptToAddress,
    mmrdata: mmrdata.map(e => ({ flags: e.flags ?? 0, label: e.label,
                                 mimetype: e.mimetype || "text/plain",
                                 message: e.message }))
  }]
});

The response contains mmrdescriptor and signaturedata. Those are parsed back into typed objects (MMRDescriptor.fromJson, SignatureData.fromJson) rather than passed through as opaque JSON — that is what lets them be re-serialised deterministically.

Step 2 — pack them into a VdxfUniValue

const innerUniValue = new VdxfUniValue({ values: [
  { [MMRDescriptorKey.vdxfid]: mmr },
  { [SignatureDataKey.vdxfid]: signaturedataObj }
]});

A VdxfUniValue is the library's "tagged union" container: each entry is keyed by its VDXF id so a reader knows what the payload is without being told. This is the same structure a content multimap value uses.

Step 3 — wrap in a labelled DataDescriptor

const containingDataDescriptor = new DataDescriptor({
  version: new BN(1), flags: new BN(0),
  label: attestationLabel,          // what the attestation is about
  objectdata: innerUniValue.toBuffer()
});
const pastebinHex  = containingDataDescriptor.toBuffer().toString("hex");
const pastebinHash = sha256(Buffer.from(pastebinHex, "hex")).toString("hex");

The label is the attestation's subject; the hash is what the eventual data packet should commit to. The tab returns pastebinHex, pastebinHash, pastebinJson and the raw signdata result, because the UI may need to upload the hex somewhere the URL descriptor can point at.

Step 4 — send it as a data packet

signAttestationPacket and generateAttestationQr build a DataPacketRequestDetails with the attestation flags:

FLAG_HAS_REQUEST_ID | FLAG_FOR_TRANSMITTAL_TO_USER | FLAG_HAS_URL_FOR_DOWNLOAD

Note FLAG_HAS_URL_FOR_DOWNLOAD: the attestation payload is expected to be reachable at a URL whose hash matches the descriptor. The request commits to both the URL and the hash, which is what makes the attestation verifiable later.

The interesting failure mode is a hash mismatch: if the pastebin hex changes after the descriptor is built, the data packet still points at the old hash and the attestation silently fails to verify. Rebuild the descriptor, not just the upload.

Reading the code

src/routes/requests/createAttestationTab.ts
  buildUrlDataDescriptor / parseSignableObjects / parseSignature
  getAttestationFlags / applyUserControlledFlags
  createAttestationForTab      # signdata → MMRDescriptor + SignatureData
  signAttestationPacket        # sign the packet
  generateAttestationQr        # final request
__tests__/dataPacket.test.js   # descriptor shapes