stream.output.state_changes.proto Maven / Gradle / Ivy
/**
* # State Changes
* Serialization of change records which describe the mutation of state
* during a block.
*
* The _ordered_ application of all `StateChanges` in a block to an initial
* state that matches network state at the beginning of that block MUST produce
* a resultant state that matches the network state at the end of that block.
*
* ### Keywords
* The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
* "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
* document are to be interpreted as described in
* [RFC2119](https://www.ietf.org/rfc/rfc2119) and clarified in
* [RFC8174](https://www.ietf.org/rfc/rfc8174).
*/
syntax = "proto3";
package com.hedera.hapi.block.stream.output;
/*
* Copyright (C) 2024 Hedera Hashgraph, LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
option java_package = "com.hedera.hapi.block.stream.output.protoc";
// <<>> This comment is special code for setting PBJ Compiler java package
option java_multiple_files = true;
import "google/protobuf/wrappers.proto";
import "basic_types.proto";
import "exchange_rate.proto";
import "state/addressbook/node.proto";
import "state/blockrecords/block_info.proto";
import "state/blockrecords/running_hashes.proto";
import "state/blockstream/block_stream_info.proto";
import "state/congestion/congestion_level_starts.proto";
import "state/consensus/topic.proto";
import "state/contract/bytecode.proto";
import "state/contract/storage_slot.proto";
import "state/file/file.proto";
import "state/recordcache/recordcache.proto";
import "state/roster/roster.proto";
import "state/roster/roster_state.proto";
import "state/schedule/schedule.proto";
import "state/throttles/throttle_usage_snapshots.proto";
import "state/token/account.proto";
import "state/token/account_pending_airdrop.proto";
import "state/token/network_staking_rewards.proto";
import "state/token/nft.proto";
import "state/token/staking_node_info.proto";
import "state/token/token.proto";
import "state/token/token_relation.proto";
import "state/platform_state.proto";
import "timestamp.proto";
/**
* A set of state changes.
*
* Each set of changes in the network deterministically mutates the
* current state to a new state, and all nodes MUST apply the same
* changes in the same order.
* Each change set described in the block stream SHALL describe an
* ordered set of mutations which mutate the previous valid state to
* produce a new valid state.
* The order of state change sets SHALL be determined by the
* `consensus_timestamp`, which is a strictly ascending value
* determined by network consensus.
*
* ### Consensus Timestamp
* This value enables a consumer of the block stream to order state
* changes by a consistent ascending value that is determined by network
* consensus. A primary use case would be to enter state changes in a
* time-series database.
* This value depends on the cause of the state change.
* 1. For transactions, this is the transaction consensus timestamp.
* 1. For events without transactions, this is the consensus timestamp of
* the event (round?).
* 1. For changes that are not the result of a transaction, but still follow
* a transaction within an event, this is the consensus timestamp of the
* preceding transaction.
*/
message StateChanges {
/**
* The consensus timestamp of this set of changes.
*
* This value SHALL be deterministic with the cause of the state change.
*/
proto.Timestamp consensus_timestamp = 1;
/**
* An ordered list of individual changes.
*
* These changes MUST be applied in the order listed to produce
* a correct modified state.
*/
repeated StateChange state_changes = 2;
}
/**
* A change to any item in the merkle tree.
*
* A State change SHALL represent one mutation of the network state merkle
* tree. The state changes published in the block stream MAY be combined
* into an ordered set of state mutations that transform the tree from any
* initial state to a destination state.
* When the full set of state change items from the block stream for a round
* is applied to the network state at the start of that round the result
* SHALL match the network state at the end of the round.
* TODO: Need documentation for how the merkle tree is constructed.
* Need to reference that document, stored in platform docs?, here.
*/
message StateChange {
/**
* A state identifier.
* The reason we use an integer field here, and not an enum field is to
* better support forward compatibility. There will be many cases when a
* block node or other client (such as a dApp) with HAPI version N wants
* to process blocks from HAPI version N+1, for example. If we use a
* protobuf enum then when that is mapped Java or Rust it would not be
* parsed as an enum value because those languages do not support unknown
* enum values. ProtoC has a workaround for this but it is complex and
* requires non-deterministic parsing. Our solution to create an integer
* field and provide an enumeration for mapping that integer is intended
* as an acceptable compromise solution.
*
* This number SHALL identify the merkle subtree "state" to be modified and
* often corresponds to a `VirtualMap` identifier.
* This number SHALL be a valid value for the `StateIdentifier` enum.
*/
uint32 state_id = 1;
oneof change_operation {
/**
* Addition of a new state.
* This may be a singleton, virtual map, or queue state.
*/
NewStateChange state_add = 2;
/**
* Removal of an existing state.
* The entire singleton, virtual map, or queue state is removed,
* and not just the contents.
*/
RemovedStateChange state_remove = 3;
/**
* An add or update to a `Singleton` state.
*/
SingletonUpdateChange singleton_update = 4;
/**
* An add or update to a single item in a `VirtualMap`.
*/
MapUpdateChange map_update = 5;
/**
* A removal of a single item from a `VirtualMap`.
*/
MapDeleteChange map_delete = 6;
/**
* Addition of an item to a `Queue` state.
*/
QueuePushChange queue_push = 7;
/**
* Removal of an item from a `Queue` state.
*/
QueuePopChange queue_pop = 8;
}
}
/**
* An informational enumeration of all known states.
* This enumeration is included here So that people know the mapping from
* integer to state "name".
*
* State changes are expressed in terms of changes to named states at the
* high level conceptual model of the state type like map key/values or
* queue appends. To say which state the change is on we will include an
* `integer` number for the state name. This is done for performance and
* efficiency as there will be 10s of thousands of state changes in a block.
*
* We use an integer, and provide this enumeration, for the following reasons.
* - If we have a extra 8-10 bytes per state change at 40-50K state changes
* per second then that is an extra 2.5-4 megabits of bandwidth. Compression
* should help a lot but that is not guaranteed.
* - When the state name is used as part of complex key in the big state
* merkle map. The smaller the key is, in bytes, the more efficient the
* database is, because more keys can fit in a single disk page.
* - When parsing keys, parsing a UTF-8 string to a Java String is a many
* times more expensive than parsing a VARINT to an integer.
*
* Note: This enumeration is never transmitted directly in the block stream.
* This enumeration is provided for clients to _interpret_ the value
* of the `StateChange`.`state_id` field.
*/
enum StateIdentifier {
/**
* A state identifier for the Topics state.
*/
STATE_ID_TOPICS = 0;
/**
* A state identifier for the next entity Identifier.
*/
STATE_ID_ENTITY_ID = 1;
/**
* A state identifier for the Accounts state.
*/
STATE_ID_ACCOUNTS = 2;
/**
* A state identifier for account aliases.
*/
STATE_ID_ALIASES = 3;
/**
* A state identifier for contract storage slots.
*/
STATE_ID_CONTRACT_STORAGE = 4;
/**
* A state identifier for contract bytecode.
*/
STATE_ID_CONTRACT_BYTECODE = 5;
/**
* A state identifier for Hedera File Service (HFS).
*/
STATE_ID_FILES = 6;
/**
* A state identifier for Hedera Token Service (HTS).
*/
STATE_ID_TOKENS = 7;
/**
* A state identifier for non-fungible/unique tokens.
*/
STATE_ID_NFTS = 8;
/**
* A state identifier for token relationships.
*/
STATE_ID_TOKEN_RELATIONS = 9;
/**
* A state identifier for network staking information.
*/
STATE_ID_STAKING_INFO = 10;
/**
* A state identifier for network staking rewards.
*/
STATE_ID_NETWORK_REWARDS = 11;
/**
* A state identifier for throttle usage.
*/
STATE_ID_THROTTLE_USAGE = 12;
/**
* A state identifier for network congestion start times.
*/
STATE_ID_CONGESTION_STARTS = 13;
/**
* A state identifier for scheduled transactions.
*/
STATE_ID_SCHEDULES_BY_ID = 14;
/**
* A state identifier for scheduled transaction expiration.
*/
STATE_ID_SCHEDULES_BY_EXPIRY = 15;
/**
* A state identifier for scheduled transaction deduplication.
*/
STATE_ID_SCHEDULES_BY_EQUALITY = 16;
/**
* A state identifier for conversion rate updates.
*/
STATE_ID_MIDNIGHT_RATES = 17;
/**
* A state identifier for the network running hash(es).
*/
STATE_ID_RUNNING_HASHES = 18;
/**
* A state identifier for network block information.
*/
STATE_ID_BLOCK_INFO = 19;
/**
* A state identifier for address book nodes.
*/
STATE_ID_NODES = 20;
/**
* A state identifier for the next "upgrade" file.
*/
STATE_ID_UPGRADE_FILE = 21;
/**
* A state identifier for the hash of the next "upgrade" file.
*/
STATE_ID_UPGRADE_FILE_HASH = 22;
/**
* A state identifier for the next network freeze time.
*/
STATE_ID_FREEZE_TIME = 23;
/**
* A state identifier for the block stream status singleton.
*/
STATE_ID_BLOCK_STREAM_INFO = 24;
/**
* A state identifier for pending airdrops.
*/
STATE_ID_PENDING_AIRDROPS = 25;
/**
* A state identifier for the platform state singleton.
*/
STATE_ID_PLATFORM_STATE = 26;
/**
* A state identifier for the roster state singleton.
*/
STATE_ID_ROSTER_STATE = 27;
/**
* A state identifier for the rosters key/value map.
*/
STATE_ID_ROSTERS = 28;
/**
* A state identifier for the round receipts queue.
*/
STATE_ID_TRANSACTION_RECEIPTS_QUEUE = 126;
/**
* A state for the `150` upgrade file data
*/
STATE_ID_UPGRADE_DATA_150 = 10001;
/**
* A state for the `151` upgrade file data
*/
STATE_ID_UPGRADE_DATA_151 = 10002;
/**
* A state for the `152` upgrade file data
*/
STATE_ID_UPGRADE_DATA_152 = 10003;
/**
* A state for the `153` upgrade file data
*/
STATE_ID_UPGRADE_DATA_153 = 10004;
/**
* A state for the `154` upgrade file data
*/
STATE_ID_UPGRADE_DATA_154 = 10005;
/**
* A state for the `155` upgrade file data
*/
STATE_ID_UPGRADE_DATA_155 = 10006;
/**
* A state for the `156` upgrade file data
*/
STATE_ID_UPGRADE_DATA_156 = 10007;
/**
* A state for the `157` upgrade file data
*/
STATE_ID_UPGRADE_DATA_157 = 10008;
/**
* A state for the `158` upgrade file data
*/
STATE_ID_UPGRADE_DATA_158 = 10009;
/**
* A state for the `159` upgrade file data
*/
STATE_ID_UPGRADE_DATA_159 = 10010;
}
/**
* An addition of a new named state.
*
* Adding a new named state SHALL only require the name and type.
* The content of the new state SHALL be filled in via subsequent
* state change items specific to the type of state
* (e.g. SingletonUpdateChange or MapUpdateChange).
*/
message NewStateChange {
/**
* The type (e.g. Singleton, Virtual Map, Queue) of state to add.
*/
NewStateType state_type = 1;
}
/**
* An enumeration of the types of named states.
* The default, Singleton, is the type of state most frequently
* added and removed.
*/
enum NewStateType {
SINGLETON = 0;
VIRTUAL_MAP = 1;
QUEUE = 2;
}
/**
* A removal of a named state.
*
* Removing a named state does not, currently, require additional
* information beyond the state name common to all state changes.
* A named state, other than a singleton, SHOULD be empty before it is removed.
*/
message RemovedStateChange {
}
/**
* An update to a `Singleton` state.
*/
message SingletonUpdateChange {
oneof new_value {
/**
* A change to the block info singleton.
*
* The `BlockInfo` SHALL be updated at the end of every block and
* SHALL store, among other fields, the last 256 block hash values.
*
REVIEW NOTE
* The full BlockInfo will be in the state proof, and may not be
* necessary here.
*/
proto.BlockInfo block_info_value = 1;
/**
* A change to the congestion level starts singleton.
*
* This change SHALL be present if congestion level pricing for
* general fees or gas fees started during the current block.
*/
proto.CongestionLevelStarts congestion_level_starts_value = 2;
/**
* A change to the Entity Identifier singleton.
*
* The Entity Identifier singleton SHALL track the highest entity
* identifier used for the current shard and realm and SHALL be used
* to issue new entity numbers.
*/
google.protobuf.UInt64Value entity_number_value = 3;
/**
* A change to the exchange rates singleton.
*
* This change SHALL be present if the HBAR<=>USD exchange
* rate, as stored in the "midnight rates" singleton changed
* during the current block.
*/
proto.ExchangeRateSet exchange_rate_set_value = 4;
/**
* A change to the network staking rewards singleton.
*
* Network staking rewards SHALL be updated for every non-empty block.
*/
proto.NetworkStakingRewards network_staking_rewards_value = 5;
/**
* A change to a raw byte array singleton.
*
* This change SHALL present a change made to a raw byte array
* singleton.
* The "upgrade file hash" state is an example of a raw byte
* array singleton.
*/
google.protobuf.BytesValue bytes_value = 6;
/**
* A change to a raw string singleton.
*
*
- Note
- There are no current examples of a raw string
* singleton state.
*/
google.protobuf.StringValue string_value = 7;
/**
* A change to the running hashes singleton.
*
* Running hashes SHALL be updated for each transaction.
*
*
REVIEW NOTE
* Running hashes is a record stream item. Can it be elided from
* the block stream? It's not written to the record stream, as far
* as I can tell. If we do write this it's adding over 144 bytes
* for every transaction. It's also not clear how we'll calculate
* this, as it's a hash of the records currently, so it would have
* to be a hash of the block items, including this one...
*
*/
proto.RunningHashes running_hashes_value = 8;
/**
* A change to the throttle usage snapshots singleton.
*
* Throttle usage snapshots SHALL be updated for _every transaction_
* to reflect the amount used for each tps throttle and
* for the gas throttle.
*/
proto.ThrottleUsageSnapshots throttle_usage_snapshots_value = 9;
/**
* A change to a raw `Timestamp` singleton.
* An example of a raw `Timestamp` singleton is the
* "network freeze time" singleton state, which, if set, stores
* the time for the next scheduled freeze.
*/
proto.Timestamp timestamp_value = 10;
/**
* A change to the block stream status singleton.
*
* This MUST be updated at the beginning of a block, with the
* information for the immediately prior block.
*/
com.hedera.hapi.node.state.blockstream.BlockStreamInfo block_stream_info_value = 11;
/**
* A change to the platform state singleton.
*/
com.hedera.hapi.platform.state.PlatformState platform_state_value = 12;
/**
* A change to the roster state singleton.
*/
com.hedera.hapi.node.state.roster.RosterState roster_state_value = 13;
}
}
/**
* An update to a single item in a `VirtualMap`.
* Each update consists of a "key" and a "value".
* Keys are often identifiers or scalar values.
* Values are generally full messages or byte arrays.
*
* The key presented here is not mutable, we do not update map keys.
* The value associated to the key provided is updated, or the value is
* added and associated with that key.
* A change of key would be expressed as removal of the prior key and
* an addition for the new key.
*/
message MapUpdateChange {
/**
* A key in a virtual map.
*
* This key MUST be mapped to the value added or updated.
* This field is REQUIRED.
*/
MapChangeKey key = 1;
/**
* A value in a virtual map.
*
* This value MUST correctly represent the state of the map entry
* _after_ the asserted update.
* This value MAY be reduced to only transmit fields that differ
* from the prior state.
* This field is REQUIRED.
*/
MapChangeValue value = 2;
}
/**
* A removal of a single item from a `VirtualMap`.
*/
message MapDeleteChange {
/**
* A key in a virtual map.
*
* This key SHALL be removed.
* The mapped value SHALL also be removed.
* This field is REQUIRED.
*/
MapChangeKey key = 1;
}
/**
* A key identifying a specific entry in a key-value "virtual map".
*/
message MapChangeKey {
oneof key_choice {
/**
* A key for a change affecting a map keyed by an Account identifier.
*/
proto.AccountID account_id_key = 1;
/**
* A change to the token relationships virtual map.
* This map is keyed by the pair of account identifier and
* token identifier.
*/
proto.TokenAssociation token_relationship_key = 2;
/**
* A change to a map keyed by an EntityNumber (which is a whole number).
*
* This SHOULD NOT be used. Virtual maps SHOULD be keyed to
* full identifiers that include shard and realm information.
*/
google.protobuf.UInt64Value entity_number_key = 3;
/**
* A change to a virtual map keyed by File identifier.
*/
proto.FileID file_id_key = 4;
/**
* A change to a virtual map keyed by NFT identifier.
*/
proto.NftID nft_id_key = 5;
/**
* A change to a virtual map keyed by a byte array.
*/
google.protobuf.BytesValue proto_bytes_key = 6;
/**
* A change to a virtual map keyed by an int64 value.
*/
google.protobuf.Int64Value proto_long_key = 7;
/**
* A change to a virtual map keyed by a string value.
*/
google.protobuf.StringValue proto_string_key = 8;
/**
* A change to a virtual map keyed by a Schedule identifier.
*/
proto.ScheduleID schedule_id_key = 9;
/**
* A change to the EVM storage "slot" virtual map.
*/
proto.SlotKey slot_key_key = 10;
/**
* A change to a virtual map keyed by a Token identifier.
*/
proto.TokenID token_id_key = 11;
/**
* A change to a virtual map keyed by a Topic identifier.
*/
proto.TopicID topic_id_key = 12;
/**
* A change to a virtual map keyed by contract id identifier.
*/
proto.ContractID contract_id_key = 13;
/**
* A change to a virtual map keyed by pending airdrop id identifier.
*/
proto.PendingAirdropId pending_airdrop_id_key = 14;
}
}
/**
* A value updated in, or added to, a virtual map.
*
*/
message MapChangeValue {
oneof value_choice {
/**
* An account value.
*/
proto.Account account_value = 1;
/**
* An account identifier.
* In some cases a map is used to connect a value or identifier
* to another identifier.
*/
proto.AccountID account_id_value = 2;
/**
* Compiled EVM bytecode.
*/
proto.Bytecode bytecode_value = 3;
/**
* An Hedera "file" value.
*
*
REVIEW NOTE
* A file can become quite large (up to 1048576 bytes).
* Do we want to structure file changes separately?
* Perhaps a file metadata update and a separate byte array for
* just the bytes appended (or initial bytes on create). We only
* allow create/append/delete, so the separate byte array would work
* and keep the size below 6K per state change.
*
*/
proto.File file_value = 4;
/**
* A non-fungible/unique token value.
*/
proto.Nft nft_value = 5;
/**
* A string value.
*/
google.protobuf.StringValue proto_string_value = 6;
/**
* A scheduled transaction value.
*/
proto.Schedule schedule_value = 7;
/**
* A list of scheduled transactions.
* An example for this value is the map of consensus second to
* scheduled transactions that expire at that consensus time.
*/
proto.ScheduleList schedule_list_value = 8;
/**
* An EVM storage slot value.
*/
proto.SlotValue slot_value_value = 9;
/**
* An updated set of staking information for all nodes in
* the address book.
*/
proto.StakingNodeInfo staking_node_info_value = 10;
/**
* An HTS token value.
*/
proto.Token token_value = 11;
/**
* A token relationship value.
* These values track which accounts are willing to transact
* in specific HTS tokens.
*/
proto.TokenRelation token_relation_value = 12;
/**
* An HCS topic value.
*/
proto.Topic topic_value = 13;
/**
* An network node value.
*/
com.hedera.hapi.node.state.addressbook.Node node_value = 14;
/**
* A pending airdrop value.
*/
proto.AccountPendingAirdrop account_pending_airdrop_value = 15;
/**
* A roster value.
*/
com.hedera.hapi.node.state.roster.Roster roster_value = 16;
}
}
/**
* Addition of an item to a `Queue` state.
*
* The new item SHALL be added after the current "last" element in the
* queue.
* The new item MUST be the same type of value as all other items in the queue.
*/
message QueuePushChange {
oneof value {
/**
* A byte array added to the queue state.
*/
google.protobuf.BytesValue proto_bytes_element = 1;
/**
* A string added to the queue state.
*/
google.protobuf.StringValue proto_string_element = 2;
/**
* All transaction receipts for a round added to queue state.
*/
proto.TransactionReceiptEntries transaction_receipt_entries_element = 3;
}
}
/**
* Removal of an item from a `Queue` state.
*
* The item removed SHALL be the current "front" (or "head") of the queue.
* Removing from a queue "head" does not, currently, require additional
* information beyond the state name common to all state changes.
*/
message QueuePopChange {
}