HCS-27: Transparency Log Checkpoints
HCS-27 anchors append-only transparency logs to Hedera by publishing signed or unsigned checkpoint commitments. The Standards SDK now exposes draft-aligned HCS-27 clients in TypeScript, Go, and Python, including topic creation, checkpoint publication, mirror-node reads, Merkle helpers, proof verification, and automatic overflow metadata inscription when a checkpoint payload exceeds the Hedera message size limit.
What the SDK CoversDirect link to What the SDK Covers
- Draft-aligned checkpoint message and metadata shapes.
- Topic memo and transaction memo helpers for HCS-27 topics.
- Checkpoint publication with
root.treeSize,rootHashB64u, and optionalprevlinkage. - Mirror-node checkpoint reads with resolved effective metadata.
- Inclusion and consistency proof verification helpers.
- Automatic HCS-1 metadata references plus
metadata_digestwhen the serialized checkpoint exceeds 1024 bytes.
InstallationDirect link to Installation
- TypeScript
- Go
- Python
pnpm add @hashgraphonline/standards-sdk
# npm install @hashgraphonline/standards-sdk
go get github.com/hashgraph-online/standards-sdk-go@latest
pip install standards-sdk-py
QuickstartDirect link to Quickstart
- TypeScript
- Go
- Python
import { createHash } from 'node:crypto';
import { HCS27Client } from '@hashgraphonline/standards-sdk';
const rootHash = (value: string): string =>
createHash('sha256').update(value).digest('base64url');
const client = new HCS27Client({
operatorId: process.env.HEDERA_ACCOUNT_ID!,
operatorKey: process.env.HEDERA_PRIVATE_KEY!,
network: 'testnet',
});
const topic = await client.createCheckpointTopic({
ttl: 3600,
adminKey: true,
submitKey: true,
});
await client.publishCheckpoint(
topic.topicId,
{
type: 'ans-checkpoint-v1',
stream: { registry: 'ans', log_id: 'typescript-example' },
log: {
alg: 'sha-256',
leaf: 'sha256(jcs(event))',
merkle: 'rfc9162',
},
root: {
treeSize: '1',
rootHashB64u: rootHash('ts-sdk-hcs27-root-1'),
},
},
'typescript checkpoint 1',
);
const checkpoints = await client.getCheckpoints(topic.topicId);
client.validateCheckpointChain(checkpoints);
console.log(checkpoints[0]?.effectiveMetadata.root.rootHashB64u);
import (
"context"
"crypto/sha256"
"encoding/base64"
"log"
"os"
"github.com/hashgraph-online/standards-sdk-go/pkg/hcs27"
)
rootHash := func(value string) string {
sum := sha256.Sum256([]byte(value))
return base64.RawURLEncoding.EncodeToString(sum[:])
}
client, err := hcs27.NewClient(hcs27.ClientConfig{
OperatorAccountID: os.Getenv("HEDERA_ACCOUNT_ID"),
OperatorPrivateKey: os.Getenv("HEDERA_PRIVATE_KEY"),
Network: "testnet",
})
if err != nil {
log.Fatal(err)
}
topicID, _, err := client.CreateCheckpointTopic(context.Background(), hcs27.CreateTopicOptions{
TTLSeconds: 3600,
UseOperatorAsAdmin: true,
UseOperatorAsSubmit: true,
})
if err != nil {
log.Fatal(err)
}
_, err = client.PublishCheckpoint(context.Background(), topicID, hcs27.CheckpointMetadata{
Type: "ans-checkpoint-v1",
Stream: hcs27.StreamID{Registry: "ans", LogID: "go-example"},
Log: &hcs27.LogProfile{
Algorithm: "sha-256",
Leaf: "sha256(jcs(event))",
Merkle: "rfc9162",
},
Root: hcs27.RootCommitment{
TreeSize: "1",
RootHashB64u: rootHash("go-sdk-hcs27-root-1"),
},
}, "go checkpoint 1", "")
if err != nil {
log.Fatal(err)
}
import base64
import hashlib
import os
from standards_sdk_py.hcs27 import HCS27Client
def root_hash(value: str) -> str:
digest = hashlib.sha256(value.encode("utf-8")).digest()
return base64.urlsafe_b64encode(digest).decode("utf-8").rstrip("=")
client = HCS27Client(
operator_id=os.environ["HEDERA_ACCOUNT_ID"],
operator_key=os.environ["HEDERA_PRIVATE_KEY"],
network="testnet",
)
topic = client.create_checkpoint_topic(
{
"ttl": 3600,
"useOperatorAsAdmin": True,
"useOperatorAsSubmit": True,
}
)
client.publish_checkpoint(
topic["topicId"],
{
"type": "ans-checkpoint-v1",
"stream": {"registry": "ans", "log_id": "python-example"},
"log": {
"alg": "sha-256",
"leaf": "sha256(jcs(event))",
"merkle": "rfc9162",
},
"root": {
"treeSize": "1",
"rootHashB64u": root_hash("py-sdk-hcs27-root-1"),
},
},
"python checkpoint 1",
)
checkpoints = client.get_checkpoints(topic["topicId"])
client.validate_checkpoint_chain(checkpoints)
print(checkpoints[0]["effectiveMetadata"]["root"]["rootHashB64u"])
Automatic Overflow InscriptionDirect link to Automatic Overflow Inscription
When a serialized checkpoint message would exceed the Hedera TopicMessageSubmitTransaction payload limit, the SDK automatically stores the full metadata as an inscription and publishes an HCS-27 message with:
metadata: "hcs://1/<topicId>"metadata_digest: { alg: "sha-256", b64u: "..." }
You do not need to chunk or assemble the HCS-1 payload manually. getCheckpoints(...) resolves the effective metadata for you, and resolveHCS1Reference(...) is available if you want the raw bytes directly.