Transaction & Merkle Helpers
The HCS-27 modules ship helper APIs for topic memo construction, transaction memo construction, checkpoint hashing, Merkle root calculation, and proof verification. These helpers are useful when you are building transparency logs off-ledger and only anchoring periodic checkpoints to Hedera.
Topic and Transaction MemosDirect link to Topic and Transaction Memos
- TypeScript
- Go
- Python
const topicMemo = client.buildTopicMemo(3600);
const parsedTopicMemo = client.parseTopicMemo(topicMemo);
const transactionMemo = client.buildTransactionMemo();
console.log(topicMemo); // hcs-27:0:3600:0
console.log(parsedTopicMemo);
console.log(transactionMemo); // hcs-27:op:0:0
import (
"fmt"
"log"
"github.com/hashgraph-online/standards-sdk-go/pkg/hcs27"
)
topicMemo := hcs27.BuildTopicMemo(3600)
parsedTopicMemo, ok := hcs27.ParseTopicMemo(topicMemo)
transactionMemo := hcs27.BuildTransactionMemo()
fmt.Println(topicMemo, ok, parsedTopicMemo, transactionMemo)
topic_memo = client.build_topic_memo({"ttl": 3600})
parsed_topic_memo = client.parse_topic_memo(topic_memo)
transaction_memo = client.build_transaction_memo()
print(topic_memo) # hcs-27:0:3600:0
print(parsed_topic_memo)
print(transaction_memo) # hcs-27:op:0:0
Leaf and Node HashingDirect link to Leaf and Node Hashing
HCS-27 uses the RFC 9162 Merkle profile in the current draft. Leaf hashes are computed from canonical JSON entries, and node hashes combine left and right child hashes.
- TypeScript
- Go
- Python
const leafHashHex = client.hashLeaf({
entry: { id: 'evt-1', action: 'append' },
});
const combinedHashHex = client.hashNode({
left: leafHashHex,
right: leafHashHex,
});
console.log(leafHashHex, combinedHashHex);
import (
"fmt"
"github.com/hashgraph-online/standards-sdk-go/pkg/hcs27"
)
leafHash, err := hcs27.MerkleRootFromEntries([]any{
map[string]any{"id": "evt-1", "action": "append"},
})
if err != nil {
log.Fatal(err)
}
nodeHash := hcs27.HashNode(leafHash, leafHash)
fmt.Printf("%x %x\n", leafHash, nodeHash)
leaf_hash_hex = client.hash_leaf(
{"entry": {"id": "evt-1", "action": "append"}}
)
combined_hash_hex = client.hash_node(
{"left": leaf_hash_hex, "right": leaf_hash_hex}
)
print(leaf_hash_hex, combined_hash_hex)
Merkle Roots from EntriesDirect link to Merkle Roots from Entries
- TypeScript
- Go
- Python
const rootHex = client.merkleRootFromEntries([
{ id: 'evt-1', action: 'append' },
{ id: 'evt-2', action: 'append' },
]);
const canonicalRootHex = client.merkleRootFromCanonicalEntries([
'{"action":"append","id":"evt-1"}',
'{"action":"append","id":"evt-2"}',
]);
import (
"log"
"github.com/hashgraph-online/standards-sdk-go/pkg/hcs27"
)
rootFromEntries, err := hcs27.MerkleRootFromEntries([]any{
map[string]any{"id": "evt-1", "action": "append"},
map[string]any{"id": "evt-2", "action": "append"},
})
if err != nil {
log.Fatal(err)
}
rootFromCanonical := hcs27.MerkleRootFromCanonicalEntries([][]byte{
[]byte(`{"action":"append","id":"evt-1"}`),
[]byte(`{"action":"append","id":"evt-2"}`),
})
root_from_entries = client.merkle_root_from_entries(
{
"entries": [
{"id": "evt-1", "action": "append"},
{"id": "evt-2", "action": "append"},
]
}
)
root_from_canonical = client.merkle_root_from_canonical_entries(
{
"entries": [
'{"action":"append","id":"evt-1"}',
'{"action":"append","id":"evt-2"}',
]
}
)
Proof VerificationDirect link to Proof Verification
You can verify inclusion and consistency proofs from external transparency-log services before publishing or accepting a checkpoint.
- TypeScript
- Go
- Python
const inclusionOk = client.verifyInclusionProof({
leafHash: '9f3d6b16d7f2c4b05678d91b5ee8aa2033f4dcb7dbf665a9a9f956c6882f5b9b',
leafIndex: '0',
treeSize: '1',
path: [],
rootHash: 'nz1rFtfyxLBWeNkbXuiqIDP03Lfb9mWpqflWxogvW5s=',
treeVersion: 1,
});
const consistencyOk = client.verifyConsistencyProof({
oldTreeSize: '1',
newTreeSize: '1',
oldRootHash: 'nz1rFtfyxLBWeNkbXuiqIDP03Lfb9mWpqflWxogvW5s=',
newRootHash: 'nz1rFtfyxLBWeNkbXuiqIDP03Lfb9mWpqflWxogvW5s=',
consistencyPath: [],
treeVersion: 1,
});
import (
"fmt"
"log"
"github.com/hashgraph-online/standards-sdk-go/pkg/hcs27"
)
ok, err := hcs27.VerifyInclusionProofObject(&hcs27.InclusionProof{
LeafHash: "9f3d6b16d7f2c4b05678d91b5ee8aa2033f4dcb7dbf665a9a9f956c6882f5b9b",
LeafIndex: "0",
TreeSize: "1",
Path: []string{},
RootHash: "nz1rFtfyxLBWeNkbXuiqIDP03Lfb9mWpqflWxogvW5s=",
TreeVersion: 1,
})
if err != nil {
log.Fatal(err)
}
fmt.Println(ok)
inclusion_ok = client.verify_inclusion_proof(
{
"proof": {
"leafHash": "9f3d6b16d7f2c4b05678d91b5ee8aa2033f4dcb7dbf665a9a9f956c6882f5b9b",
"leafIndex": "0",
"treeSize": "1",
"path": [],
"rootHash": "nz1rFtfyxLBWeNkbXuiqIDP03Lfb9mWpqflWxogvW5s=",
"treeVersion": 1,
}
}
)
consistency_ok = client.verify_consistency_proof(
{
"proof": {
"oldTreeSize": "1",
"newTreeSize": "1",
"oldRootHash": "nz1rFtfyxLBWeNkbXuiqIDP03Lfb9mWpqflWxogvW5s=",
"newRootHash": "nz1rFtfyxLBWeNkbXuiqIDP03Lfb9mWpqflWxogvW5s=",
"consistencyPath": [],
"treeVersion": 1,
}
}
)
NotesDirect link to Notes
treeSize,leafIndex,oldTreeSize, andnewTreeSizeare canonical base-10 strings in the draft-aligned object forms.rootHashB64uis base64url in checkpoint metadata, while proof helpers use the base64 shapes defined by the proof objects.- Proof helpers reject malformed base64 siblings (
path/consistencyPath) instead of treating invalid entries as empty bytes. - Overflow metadata inscription is automatic inside
publishCheckpoint(...); the Merkle helpers themselves only operate on the checkpoint data you pass in.