Skip to content

Canonical Transaction Envelope

The canonical transaction envelope is the authoritative consensus transaction representation in NOOSChain. It contains the exact consensus fields signed by the transaction signer:

  • nonce
  • createdAt
  • type
  • signerPublicKey
  • payload
  • optional protocolVersion

The signature is computed over deterministic canonical JSON for this consensus envelope. The transaction hash is then computed from { envelope, signature }. Database insertion timestamps are operational metadata only and must never be used to reconstruct a signed transaction.

ADD_ENCRYPTED_RECORD has one explicit availability-layer exception: encryptedPayload is not part of the canonical consensus envelope. It is not signed, not transaction-hashed, not Merkle-hashed, and not state-root hashed. The signed payload keeps payloadHash, encryption metadata, key-envelope metadata, public indexes, actor fields, and bucket key references. For per_record_key records, key-envelope metadata contains encrypted copies of the record DEK. For per_bucket_key records, record-level envelopes are normally empty and the signed payload instead references bucketKeyId and bucketKeyVersion. Ciphertext bytes move through permission-gated availability APIs such as /records/:recordId/payload.

This separation lets a node verify ordered blocks and replay deterministic state without receiving ciphertext it is not authorized to store.

Public API submission adds one local admission guard for this exception: ADD_ENCRYPTED_RECORD must include a valid preparedTransactionId. The prepared transaction table stores a short-lived hash of the full unsigned envelope, including encryptedPayload, so the node can reject altered ciphertext even though ciphertext remains outside the canonical signed/hash material used for consensus and replay.

Fresh transactions persist the exact envelope in transactions.envelope and copy envelope.createdAt into transactions.canonical_created_at. The older transactions.created_at column remains the database insertion timestamp and is not consensus-authoritative.

HTTP block sync sends the canonical consensus envelope in each block transaction DTO. For encrypted records the DTO marks encryptedPayload as omitted. A receiving node recomputes the transaction hash, verifies the signature, verifies Merkle inclusion from transaction hashes, executes the block locally, and compares the resulting state root and block hash. If the node is allowed by bucket replication policy and access rules to store ciphertext, it fetches those bytes separately as availability data. For per_bucket_key records, authorized node replication may also receive the bucket-key envelope metadata for the referenced key version; raw bucket DEKs are never returned.

Historical compatibility is nullable by design. Rows created before migration 014_transaction_envelope.sql may have envelope = null. Verifiers warn for those rows instead of fabricating envelopes, because silently rebuilding from DB timestamps would create a false sense of determinism. Fresh chains after this migration should be envelope-complete from genesis onward.

Replay uses transactions.envelope when present. This keeps replay independent from materialized DB timestamps and preserves protocol-versioned historical execution semantics.

Audience-first NOOSChain documentation.