@@ -3,7 +3,7 @@ hip: 1056
33title : Block Streams
44author : >-
55 Jasper Potts <@jasperpotts>, Richard Bair <@rbair23>, Nana Essilfie-Conduah <@Nana-EC>,
6- Mark Blackman <mark@swirldslabs.com>, Edward Wertz<@edward-swirldslabs>
6+ Mark Blackman <mark@swirldslabs.com>, Edward Wertz<@edward-swirldslabs>, Michael Tinker <@tinker-michaelj>
77working-group : >-
88 Jasper Potts <@jasperpotts>, Richard Bair <@rbair23>, Nana Essilfie-Conduah <@Nana-EC>,
99 Mark Blackman <mark@swirldslabs.com>, Leemon Baird, Joseph Sinclair <@jsync-swirlds>, Nick Poorman <@nickpoorman>,
@@ -17,7 +17,7 @@ status: Approved
1717last-call-date-time : 2025-06-03T07:00:00Z
1818created : 2023-06-04
1919discussions-to : https://github.com/hiero-ledger/hiero-improvement-proposals/discussions/1055
20- updated : 2025-07-15
20+ updated : 2025-07-28
2121requires : 1183, 1127, cutover
2222---
2323
@@ -503,16 +503,34 @@ in. Block items removed from a filtered stream are represented by one or more
503503` FilteredItemHash ` ’s which provide the missing hashes required to validate the
504504filtered stream with the same block proof as the full stream.
505505
506- > The parent-child relationship of some transactions is preserved in the Block
507- > Streams and will see the appropriate ` BlockItem ` s for each level. For example,
508- > a ` CryptoTransfer ` transaction to a non existing EVM address results in the
509- > auto creation of a new Account with the said EVM address. In the Block Streams
510- > the ` CryptoTransfer ` transaction will be described by its ` EventTransaction ` ,
511- > ` TransactionResult ` , ` TransactionOutput ` and ` StateChange ` ` BlockItem ` s. The
512- > ` CryptoCreate ` transaction will also be described by its own
513- > ` EventTransaction ` , ` TransactionResult ` , ` TransactionOutput and ` StateChange`
514- > ` BlockItem ` s. In this way a transactions input, output and impacts on the
515- > network are clearly described.
506+ The parent-child relationship of some transactions is preserved in the Block
507+ Streams and will see the appropriate ` BlockItem ` s for each level. For example,
508+ a ` CryptoTransfer ` transaction to a non existing EVM address results in the
509+ auto creation of a new Account with the said EVM address. In the Block Streams
510+ the ` CryptoTransfer ` transaction will be described by its ` SignedTransaction ` ,
511+ ` TransactionResult ` , and ` TransactionOutput ` and ` BlockItem ` s. The ` CryptoCreate `
512+ transaction will also be described by its own ` SignedTransaction ` ,
513+ ` TransactionResult ` , and ` TransactionOutput and ` BlockItem`s. However, because
514+ both logical transactions are in the same Hiero transactional unit, only
515+ the parent ` CryptoTransfer ` will have a ` StateChanges ` item; and that item will
516+ include all changes for the entire transactional unit. In this way a transactions
517+ input, output and impacts on the network are clearly described.
518+
519+ The distinction between a ** logical transaction** in the block stream and its
520+ ** Hiero transactional unit** is especially significant for
521+ [ batch transactions] ( https://hips.hedera.com/hip/hip-551 ) . The ` AtomicBatch `
522+ transaction lets a Hiero user group arbitrary HAPI transactions into an
523+ all-or-nothing unit. None of the HAPI transactions in the group have their own
524+ ` StateChanges ` block item---only the ` AtomicBatch ` has a ` StateChanges ` item.
525+ This item includes _ either_ the effects of executing every transaction in
526+ the group with final status ` SUCCESS ` ; _ or_ just the effects of paying fees for
527+ whatever transactions in the group were attempted before getting a status other
528+ than ` SUCCESS ` . The logical transactions inside the batch are legible in the
529+ block stream because their "input" appears as a ` SignedTransaction ` item in the
530+ batch and their "output" appears as a ` TransactionResult ` item along with any
531+ ` TransactionOutput ` or ` TraceData ` needed for extra detail. But a ` StateChanges `
532+ item always represents the boundary of a Hiero transactional unit, and never the
533+ boundary of a logical transaction.
516534
517535##### Forward Compatibility
518536
@@ -547,7 +565,6 @@ and a new "BridgeTransform" which is in Trace Data.
547565 * The "ConsensusTransform" is field 20 (20 modulo 10 is 0, so it is a Consensus Header).
548566 * The "BridgeTransform" field is 24 (24 modulo 10 is 4, so it is Trace Data).
549567
550-
551568#### BlockHeader
552569
553570A ` BlockHeader ` is one type of ` output ` BlockItem and will always be the first element in a Block. It contains Block
@@ -867,20 +884,22 @@ message TransactionOutput {
867884```
868885
869886``` protobuf
870- message ContractCallOutput {
887+ message CallContractOutput {
871888 /**
872- * Result details for an EVM transaction execution
889+ * An EVM transaction result. Contains just the information not already
890+ * externalized in the matching transaction body.
873891 */
874- EVMTransactionResult evm_transaction_result = 1;
892+ proto.EvmTransactionResult evm_transaction_result = 1;
875893}
876894```
877895
878896``` protobuf
879- message ContractCreateOutput {
897+ message CreateContractOutput {
880898 /**
881- * Result details for an EVM transaction execution
899+ * An EVM transaction result. Contains just the information not already
900+ * externalized in the matching transaction body.
882901 */
883- EVMTransactionResult evm_transaction_result = 1;
902+ proto.EvmTransactionResult evm_transaction_result = 1;
884903}
885904```
886905
@@ -895,10 +914,21 @@ message CreateAccountOutput {
895914
896915``` protobuf
897916message EthereumOutput {
898- /**
899- * Result details for an EVM transaction execution
900- */
901- EVMTransactionResult evm_transaction_result = 1;
917+ oneof transaction_result {
918+ /**
919+ * An EVM transaction result for an Ethereum transaction executed as a
920+ * call. Contains just the information not already externalized in the
921+ * matching transaction body.
922+ */
923+ proto.EvmTransactionResult evm_call_transaction_result = 1;
924+
925+ /**
926+ * An EVM transaction result for an Ethereum transaction executed as a
927+ * create. Contains just the information not already externalized in the
928+ * matching transaction body.
929+ */
930+ proto.EvmTransactionResult evm_create_transaction_result = 2;
931+ }
902932}
903933```
904934
@@ -1783,118 +1813,194 @@ A `TraceData` block item is added to contain all information that could be cosni
17831813The consensus node will export all necessary and important data for a transactions execution in the block streams,
17841814however every byte of information is stored fore er and needed in the proof of the network data. As such it's important
17851815to ensure that data is required but also laid out in a way that makes it easier for filtering by downstream clients.
1786- To this point the ` TraceData ` would initially contain smart contracts ` EVMTraceData ` that support traceability information (e.g.
1816+ To this point the ` TraceData ` would initially contain smart contracts ` EvmTraceData ` that support traceability information (e.g.
17871817contract actions, read values etc). Future trace like data can be added to ` TraceData ` and Block Nodes, Mirror Nodes and
1788- other block stream parsign clients can decided to store or filter it out based on their needs.
1818+ other block stream clients can decided to store or filter it out based on their needs.
17891819
17901820``` protobuf
1791- message ContractSlotReads {
1792-
1793- message SlotRead {
1794- oneof identifier {
1795- /**
1796- * The contract storage slot counter in this block
1797- * This is populated in place of the 256 bit word when the given slot is written to in state changes
1798- */
1799- int32 index = 1;
1800-
1801- /**
1802- * The key of this contratc storage slot, may be left-padded with zeros to form a 256-bit word.
1803- * This is populated when the slot was not written and only read
1804- */
1805- bytes key = 2;
1806- }
1807-
1808- /**
1809- * The storage value in this slot, may be left-padded with zeros to form a 256-bit word.
1810- */
1811- bytes read_value = 3;
1812- }
1813-
1814- /**
1815- * The contract associated with the storage slots this slot belongs to.
1816- */
1817- ContractID contract_id = 1;
1818-
1819- /**
1820- * The storage slots that were read in this EVM exectuion. They may or may not have assocaited slot writes
1821- */
1822- repeated SlotRead slot_reads = 2;
1823- }
1824-
18251821/**
1826- * EVM transaction execution log storage details
1827- * Details maps to the log object in eth_getTransactionReceipt response without repeating info already available in the input transaction
1828- * Log bloom logic is removed as it may be calculated by block parser for both transactions and block level
1822+ * EVM trace data, including:
1823+ * 1. Contract actions executed during the transaction (i.e., the call trace)
1824+ * 2. Contract slot usages, including reads and writes.
1825+ * 3. Full error message, if any, produced by the contract call.
1826+ * 4. Initcode used for any internal contract creations.
1827+ * 5. Events logged during the transaction.
18291828 */
1830- message EVMTransactionLog {
1831- /**
1832- * The contract emitting the log. ContractID vs 20 bye address is used to preserve space
1833- */
1834- ContractID contract_id = 1;
1829+ message EvmTraceData {
1830+ /**
1831+ * All contract actions executed during the transaction.
1832+ */
1833+ repeated proto.ContractAction contract_actions = 1;
18351834
1836- /**
1837- * The Log data
1838- */
1839- bytes data = 2;
1835+ /**
1836+ * Contract slot usages in the transaction, by contract id.
1837+ */
1838+ repeated ContractSlotUsage contract_slot_usages = 2;
18401839
1841- /**
1842- * The logc topics left padding of 0's by EVM is stripped to save space.
1843- * Indexers should left-pad with zeros to form a 256-bit word.
1844- */
1845- repeated bytes topics = 3;
1840+ /**
1841+ * Additional details of any error message in the EVM transaction result.
1842+ * <p>
1843+ * This SHALL be unset if the contract call succeeded.
1844+ */
1845+ string error_details = 3;
1846+
1847+ /**
1848+ * The initcode executed for an internal contract creation.
1849+ */
1850+ ExecutedInitcode executed_initcode = 4;
1851+
1852+ /**
1853+ * Log events produced during the transaction, by contract id.
1854+ */
1855+ repeated EvmTransactionLog logs = 5;
18461856}
18471857
18481858/**
1849- * The init bytecode components for child contracts created as part of the contract execution.
1850- * init_bytecode = deploy_bytecode + runtime_byteode + metadata_bytecode
1859+ * Usage of a contract's storage slots in an EVM transaction.<br/>
1860+ * In the common case that a contract operation is the only EVM
1861+ * transaction in its Hiero transactional unit, this message simply
1862+ * sets `written_keys_are_non_identical_state_changes` to true;
1863+ * meaning a stream consumer should extract the written keys from
1864+ * the Hiero unit's SlotKey state changes that match this message's
1865+ * `contract_id` (but ignoring any* MapUpdateChange with
1866+ * `identical` set to true).
1867+ * <p>
1868+ * In the less common case that an EVM transaction is one of
1869+ * several in its Hiero transactional unit (e.g., because it is
1870+ * one of several ContractCalls in an AtomicBatch); this message
1871+ * explicitly traces the storage slots that were written during
1872+ * its transaction's execution.
18511873 */
1852- message ContractInitByteCode {
1874+ message ContractSlotUsage {
1875+ /**
1876+ * The contract using the storage slots.
1877+ */
1878+ proto.ContractID contract_id = 1;
1879+
18531880 /**
1854- * The bytecode that predeces and deploys the runtime bytecode in a contracts deployment
1881+ * When this EVM transaction was one of several within its Hiero
1882+ * transactional unit, the storage slots that it wrote.
1883+ * <p>
1884+ * The written value can be unambiguously derived from the block items
1885+ * in this EVM transaction's Hiero transactional unit. In particular,
1886+ * 1. If a following EVM trace modifies the same slot, the value written
1887+ * in this EVM transaction was whatever value the following trace read.
1888+ * 2. If the slot was not modified in a following EVM trace, the value
1889+ * is whatever value was committed to the Merkle state for the slot.
18551890 */
1856- google.protobuf.BytesValue deploy_bytecode = 1 ;
1891+ WrittenSlotKeys written_slot_keys = 3 ;
18571892
18581893 /**
1859- * The bytecode that follows the runtime bytecode (found in contract state) in a contracts deployment.
1894+ * The storage slots that were read in this EVM execution. They may or
1895+ * may not have associated slot writes.
18601896 */
1861- google.protobuf.BytesValue metadata_bytecode = 2;
1897+ repeated SlotRead slot_reads = 4;
1898+ }
1899+
1900+ message WrittenSlotKeys {
1901+ repeated bytes keys = 1;
1902+ }
1903+
1904+ /**
1905+ * A slot read in a contract's storage, as used in an EVM transaction.<br/>
1906+ */
1907+ message SlotRead {
1908+ oneof identifier {
1909+ /**
1910+ * If this slot was also written, the index of the written key in a
1911+ * an explicit or implicit list of written keys in the stream.
1912+ * <p>
1913+ * The case of the explicit list is when this SlotRead appears in a
1914+ * ContractSlotUsage with `written_slot_keys` set to a non-empty list
1915+ * of keys. In this case, the index is into that list.
1916+ * <p>
1917+ * The case of the implicit list is when this SlotRead appears in a
1918+ * ContractSlotUsage with `written_slot_keys` unset. In this case,
1919+ * the list is implicit---it is the list of all SlotKey state changes
1920+ * in the Hiero transactional unit that match this ContractSlotUsage's
1921+ * `contract_id` and have `identical` set to false.
1922+ */
1923+ int32 index = 1;
1924+
1925+ /**
1926+ * If this slot was only read, its key represented with minimal bytes
1927+ * (no leading zeros); a stream consumer can left-pad this field with
1928+ * zeros to form a 32-byte EVM slot key.
1929+ */
1930+ bytes key = 2;
1931+ }
18621932
18631933 /**
1864- * The bytecode that defines a deployed contracts logic. Only present if not in state.
1934+ * The storage value in this slot, represented with minimal bytes (no
1935+ * leading zeros); a stream consumer can left-pad this field with zeros.
1936+ * to form a 32-byte EVM slot value.
1937+ */
1938+ bytes read_value = 3;
1939+ }
1940+
1941+ /**
1942+ * Information about the initcode executed to create a contract.
1943+ */
1944+ message ExecutedInitcode {
1945+ /**
1946+ * The id of the contract created by the initcode.
18651947 */
1866- google.protobuf.BytesValue runtime_bytecode = 3;
1948+ proto.ContractID contract_id = 1;
1949+
1950+ oneof initcode {
1951+ /**
1952+ * If the runtime bytecode follows the common convention of appearing as a subsequence
1953+ * of the initcode, the initcode pieces that surround the runtime bytecode (which is
1954+ * necessarily in the Hiero transactional unit's state changes).
1955+ */
1956+ InitcodeBookends initcode_bookends = 2;
1957+
1958+ /**
1959+ * If the runtime bytecode is not a subsequence of the initcode, the explicit initcode.
1960+ */
1961+ bytes explicit_initcode = 3;
1962+ }
18671963}
18681964
18691965/**
1870- * EVM tranaction execution trace details
1871- * Details maps to the variable needed for debugging executions
1966+ * The initcode bookends of a contract, which are the deploy bytecode and metadata
1967+ * bytecode that surround the runtime bytecode in a contract's deployment.
1968+ * <p>
1969+ * The runtime bytecode is not included here, as it is externalized via a state change
1970+ * with the matching contract id in the Hiero transactional unit.
18721971 */
1873- message EVMTraceData {
1972+ message InitcodeBookends {
18741973 /**
1875- * The init bytecode component for this child contract created as part of the contract execution .
1974+ * The bytecode that precedes the runtime bytecode of a contract in initcode .
18761975 */
1877- ContractInitByteCode init_bytecode = 1;
1976+ bytes deploy_bytecode = 1;
18781977
18791978 /**
1880- * The inter contract interaction details. This represents the internal EVM message frames .
1979+ * The bytecode that follows the runtime bytecode of a contract in initcode .
18811980 */
1882- repeated ContractAction contract_actions = 2;
1883-
1981+ bytes metadata_bytecode = 2;
1982+ }
1983+
1984+ /**
1985+ * A EVM transaction log; c.f. eth_getTransactionReceipt.<br/>
1986+ * Stream consumers may compute bloom values from topics and data if desired.
1987+ */
1988+ message EvmTransactionLog {
18841989 /**
1885- * Contract slot values that were read during the execution of the EVM transaction. Associated written values will be in state changes
1990+ * The contract emitting the log.
18861991 */
1887- repeated ContractSlotReads contract_slot_reads = 3 ;
1992+ proto.ContractID contract_id = 1 ;
18881993
18891994 /**
1890- * Any error message produced by the contract call .
1995+ * The logged data .
18911996 */
1892- string full_error_message = 4 ;
1997+ bytes data = 2 ;
18931998
18941999 /**
1895- * Any Log events produced by this contract call.
2000+ * The log's topics represented with minimal bytes (no leading zeros);
2001+ * a stream consumer can left-pad with zeros to form a 256-bit words.
18962002 */
1897- repeated EVMTransactionLog logs = 5 ;
2003+ repeated bytes topics = 3 ;
18982004}
18992005```
19002006
0 commit comments