Tenant isolation
The guarantee
Section titled “The guarantee”At the ledger boundary, a tenant can neither read, overwrite, nor enumerate another tenant’s anchored Merkle batches. The tenant is derived from the signed client identity of the transacting party, never from a function argument — so it cannot be forged by a caller.
This replaces a weaker earlier reality where a “tenant” was only a string prefix on a batch id sharing one channel and one identity, which enforced nothing at the ledger.
Where it is enforced
Section titled “Where it is enforced”In the chaincode, the one place a client cannot bypass:
clientTenant()derives the tenant from the client identity — the CA-signedtenantcertificate attribute when present (multi-tenant within one org), otherwise the MSP ID (org-per-tenant). It never reads a tenant argument.- Merkle-batch state is stored under a composite key
(tenant, batchID). Store/query resolve that key from the caller’s identity; listing ranges only over the caller’s partition.
By construction:
- a batch id that looks like another tenant’s is still keyed under the caller’s own identity — the argument cannot widen scope;
- a cross-tenant read resolves to a key that does not exist → reported as non-existent (no metadata leak);
- a cross-tenant “overwrite” writes to a different partition → the original anchor is untouched; write-once still holds within a tenant.
Proven under test
Section titled “Proven under test”The chaincode is tested against a fake stub + client identity asserting: scoped store/query, no foreign read, no cross-tenant overwrite, listing returns only the caller’s batches, the tenant is not spoofable via a batch id, and isolation also holds by MSP ID without an attribute.
Operational requirement
Section titled “Operational requirement”For real tenants, each must transact with its own identity carrying its
tenant attribute — a credential-provisioning step
(register-tenant-identity.sh) plus a fabric.tenant_identities mapping. Until
then, anchors use the default identity and fall back to the MSP-ID partition
(org-level isolation) — still enforced, never the old shared keyspace.