GitHub Logo HIP-1127: Transaction Cleanup

Author Michael Heinrichs, Michael Tinker
Working Group Richard Bair, Jasper Potts
Requested By Richard Bair <@rbair>
Status Last Call
Needs Hedera Approval Yes
Needs Hiero Review Yes
Review period ends Wed, 16 Jul 2025 07:00:00 +0000
Type Standards Track
Category Service
Created 2025-02-17
Updated 2025-07-02
Requires 1056

Abstract

The Transaction protobuf message in the legacy record stream supports two ways to represent a transaction.

  1. The Transaction.signedTransactionBytes field.
  2. Deprecated The Transaction.bodyBytes and Transaction.sigMap fields combination.

The definition of the transaction hash differs between the two representations. For (1), the transaction hash is the SHA-384 hash of the raw bytes in the signedTransactionBytes field. But for (2), the transaction hash is the SHA-384 hash of the protobuf serialization of the entire Transaction message; where this serialization must be done using ascending protobuf field order.

This HIP defines a single transaction representation for the block stream and preserves existing hash-based look-ups, so no client code changes are required.

This HIP does not propose any changes to the Hiero API (HAPI) or to the existing record stream. The consensus node will do all needed conversions from and to legacy Transaction messages for the foreseeable future.

Motivation

Unnecessary nesting in the Transaction message bloats the block stream and increases the serialization work done by consumers. The SignedTransaction message is a better, cleaner candidate for representing transactions in the block stream. This message is,

message SignedTransaction {
    /**
     * A byte array containing a serialized `TransactionBody`.
     * <p>
     * This content is what the signatures in `sigMap` MUST sign.
     */
    bytes bodyBytes = 1;

    /**
     * A set of cryptographic signatures.
     * <p>
     * This set MUST contain all signatures required to authenticate
     * and authorize the transaction.<br/>
     * This set MAY contain additional signatures.
     */
    SignatureMap sigMap = 2;
}

Rationale

We could specify the block stream’s representation with a TransactionBody body field instead of the serialized bodyBytes. But we feel it is important to make the block stream definition explicitly encode the signed bytes, as this is such a fundamental part of the protocol.

We could also extend HAPI to let clients submit SignedTransactions instead of Transactions. This would be nice, but does not offer a compelling return on investment at the current stage of the project.

User stories

  1. As a transaction sender, I want to be able to send transactions using both Transaction representations so that I am not forced to rewrite the calling code (which may be impossible).
  2. As a record stream/block stream consumer, I want a simple way to parse transactions and extract data.
  3. As a transaction signer, I want to be sure that my signatures can always be validated, even if transactions are modified to follow the normalized format.
  4. As a user of APIs that take transaction hashes as input, I want block stream consumers to preserve the current transaction hash definitions for both Transaction representations.

Specification

The protobuf definition of the Transaction object will not change. The SignedTransaction message will get one new field, a boolean that is true iff the transaction was originally submitted using the deprecated bodyBytes and sigMap combination,

message SignedTransaction {
    ...
    /**
     * If false then the hash of this transaction is the SHA-384 hash of the
     * serialization of this SignedTransaction message as it arrived on the wire. 
     * <p>
     * If true then the hash of this transaction is the SHA-384 hash of the
     * ascending field order serialization of the Transaction whose `bodyBytes`
     * and sigMap fields are deserialized from the contents of this message. 
     */
    boolean use_legacy_transaction_hash_algorithm = 3;
}

Modification of incoming transactions

When a node receives a Transaction using the signedTransactionBytes field, it will submit those signedTransactionBytes contents directly into consensus gossip.

When a node receives a Transaction using the bodyBytes and sigMap combination, it will repackage those two fields inside a SignedTransaction along with use_legacy_transaction_hash_algorithm=true, and submit the serialization of the repackaged message to consensus gossip.

Changes in record stream and block stream

Nothing will change in the record stream. The oneof item in the block stream’s BlockItem message will replace its EventTransaction choice with a SignedTransaction choice,

message BlockItem {
    ...
    oneof item {
        ...
        /**
         * A single logical transaction in the block stream.
         * <p>
         * If this item is not followed by a `state_changes` item
         * before the appearance of the next `signed_transaction`,
         * it MUST be taken as purely informational; that is, as a
         * "synthetic" transaction whose only purpose is to increase
         * the legibility of the block stream semantics to consumers
         * that do not themselves simulate consensus node logic.
         */
        proto.SignedTransaction signed_transaction = 4;
        ...
    }
}

Backwards Compatibility

A user can always find the original serialized bytes of their submitted Transaction in the record stream, even if they used the deprecated bodyBytes and sigMap combination. The block stream will not preserve this property for deprecated submissions.

But it will still let a user find their deprecated transactions by TransactionID or hash in the stream. So this is only a minor inconvenience, not a fundamentally breaking change.

Security Implications

This change has no known security implications.

How to Teach This

The block stream standardizes to a single transaction representation, the SignedTransaction. Users that look up transactions by hash can continue to do this as they do today.

Rejected Ideas

  • Keep EventTransaction in the block stream. (The parsing and wrapper overhead was deemed excessive.)
  • Use any of the other fields as the standard format.
  • Introduce a new transaction type.

Copyright/license

This document is licensed under the Apache License, Version 2.0 – see LICENSE or (https://www.apache.org/licenses/LICENSE-2.0)

Citation

Please cite this document as: