diff --git a/packages/proto/Taskfile.yml b/packages/proto/Taskfile.yml index 4c25de537..5776767be 100644 --- a/packages/proto/Taskfile.yml +++ b/packages/proto/Taskfile.yml @@ -30,6 +30,7 @@ tasks: - mv src/services/hapi/hedera-protobufs/services src/proto/ - rm -rf src/proto/streams - mv src/services/hapi/hedera-protobufs/streams src/proto/ + - mv src/services/hapi/hedera-protobufs/platform/event/* src/proto/services - echo "Protobufs moved successfully!" - task "delete:submodule" diff --git a/packages/proto/src/proto/services/basic_types.proto b/packages/proto/src/proto/services/basic_types.proto index 17c2f9106..0b3a4fe6c 100644 --- a/packages/proto/src/proto/services/basic_types.proto +++ b/packages/proto/src/proto/services/basic_types.proto @@ -1269,6 +1269,11 @@ enum HederaFunctionality { * Submit a node public tss encryption key as part of the Threshold Signature Scheme (TSS). */ TssEncryptionKey = 99; + + /** + * Submit a signature of a state root hash gossiped to other nodes + */ + StateSignatureTransaction = 100; } /** diff --git a/packages/proto/src/proto/services/event_consensus_data.proto b/packages/proto/src/proto/services/event_consensus_data.proto new file mode 100644 index 000000000..db9202f82 --- /dev/null +++ b/packages/proto/src/proto/services/event_consensus_data.proto @@ -0,0 +1,69 @@ +/** + * # Event Consensus Data + * A message that describes the consensus data for an event. + * + * The `EventConsensusData` contains two fields that are determined once an + * event reaches consensus, the `consensus_timestamp` and `consensus_order`. + * + * ### 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). + */ +syntax = "proto3"; + +package com.hedera.hapi.platform.event; + +/* + * Hedera Network Services Protobuf + * + * 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. + */ + +import "basic_types.proto"; +import "event/event_descriptor.proto"; +import "timestamp.proto"; + +option java_package = "com.hedera.hapi.platform.event.legacy"; +// <<>> This comment is special code for setting PBJ Compiler java package +option java_multiple_files = true; + +/** + * Event Consensus Data.
+ * This message records the critical values produced by consensus for an event. + */ +message EventConsensusData { + /** + * A consensus timestamp.
+ * The network's consensus agreement on a timestamp for this event. + *

+ * This timestamp MUST be strictly greater than the `consensus_timestamp` of + * the previous consensus event.
+ * This is a consensus value and MAY NOT match real-world "wall clock" time. + */ + proto.Timestamp consensus_timestamp = 1; + + /** + * A consensus order sequence number.
+ * A non-negative sequence number that identifies an event's consensus order + * since genesis. + *

+ * This SHALL be the unique for each consensus event.
+ * This SHALL always increase, and SHALL NOT decrease.
+ * This SHALL increment by one for each consensus event. + */ + uint64 consensus_order = 2; +} + diff --git a/packages/proto/src/proto/services/event_core.proto b/packages/proto/src/proto/services/event_core.proto new file mode 100644 index 000000000..86e565434 --- /dev/null +++ b/packages/proto/src/proto/services/event_core.proto @@ -0,0 +1,83 @@ +/** + * # Core Event Data + * A message that describes the metadata for an event. + * + * The `EventCore` contains a list of the event's parents, as well as the software + * version, an identifier for the node that created this event, the birth round, and + * the creation timestamp for the event. + * + * ### 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). + */ +syntax = "proto3"; + +package com.hedera.hapi.platform.event; + +/* + * Hedera Network Services Protobuf + * + * 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. + */ + +import "basic_types.proto"; +import "event/event_descriptor.proto"; +import "timestamp.proto"; + +option java_package = "com.hedera.hapi.platform.event.legacy"; +// <<>> This comment is special code for setting PBJ Compiler java package +option java_multiple_files = true; + +/** + * Contains information about an event and its parents. + */ +message EventCore { + /** + * The creator node identifier.
+ * This SHALL be the unique identifier for the node that created the event.
+ * This SHALL match the ID of the node as it appears in the address book. + */ + int64 creator_node_id = 1; + + /** + * The birth round of the event.
+ * The birth round SHALL be the pending consensus round at the time the event is created.
+ * The pending consensus round SHALL be **one greater** than the latest round to reach consensus. + */ + int64 birth_round = 2; + + /** + * The wall clock time at which the event was created, according to the node creating the event.
+ * If the event has a self parent, this timestamp MUST be strictly greater than the `time_created` of the self parent. + */ + proto.Timestamp time_created = 3; + + /** + * A list of EventDescriptors representing the parents of this event.
+ * The list of parents SHALL include zero or one self parents, and zero or more other parents.
+ * The first element of the list SHALL be the self parent, if one exists.
+ * The list of parents SHALL NOT include more than one parent from the same creator. + */ + repeated EventDescriptor parents = 4; + + /** + * The event specification version.
+ * The specification described by this version SHALL encompass the format of the `GossipEvent` message, and also the + * format of all contained messages.
+ * This SHALL exactly match the specification version passed into the platform at construction. + */ + proto.SemanticVersion version = 17; // This field is temporary until birth_round migration is complete. Field number 17 chosen to avoid polluting cheaper 1 byte field numbers 1-16 +} diff --git a/packages/proto/src/proto/services/event_descriptor.proto b/packages/proto/src/proto/services/event_descriptor.proto new file mode 100644 index 000000000..bb5690da6 --- /dev/null +++ b/packages/proto/src/proto/services/event_descriptor.proto @@ -0,0 +1,80 @@ +/** + * # Event Descriptor + * Unique identifier for an event. + * + * Contains the hash of the event, the creator identifier, the birth round, and the generation. + * + * An event's descriptor is constructed individually by each node that receives a `GossipEvent`, + * to uniquely identify that event. An event's descriptor isn't part of the `GossipEvent` itself, + * since the descriptor contains the fields `hash` and `generation`, which can be computed locally. + * Nodes receiving a `GossipEvent` have the required information to construct the event descriptor + * immediately upon receiving the event, without needing to wait for the event to reach consensus. + * + * Aside from being a unique identifier for events that have been received through gossip, + * the event descriptor contains the necessary information to describe an event's parents, + * in the `parents` field of `GossipEvent`. + * + * ### 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). + */ +syntax = "proto3"; + +package com.hedera.hapi.platform.event; + +/* + * Hedera Network Services Protobuf + * + * 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.platform.event.legacy"; +// <<>> This comment is special code for setting PBJ Compiler java package +option java_multiple_files = true; + +/** + * Unique identifier for an event. + */ +message EventDescriptor { + /** + * The hash of the event.
+ * The hash SHALL be a SHA-384 hash.
+ * The hash SHALL have the following inputs, in the specified order:
+ * 1. The bytes of the `EventCore` protobuf
+ * 2. The SHA-384 hash of each individual `EventTransaction`, in the order the transactions appear in the `event_transactions` field of the `GossipEvent` protobuf + */ + bytes hash = 1; + + /** + * The creator node identifier.
+ * This SHALL be the unique identifier for the node that created the event.
+ * This SHALL match the ID of the node as it appears in the address book. + */ + int64 creator_node_id = 2; + + /** + * The birth round of the event.
+ * The birth round SHALL be the pending consensus round at the time the event is created.
+ * The pending consensus round SHALL be **one greater** than the latest round to reach consensus. + */ + int64 birth_round = 3; + + /** + * The generation of the event.
+ * This value SHALL be **one greater** than the _maximum_ generation of all parents.
+ */ + int64 generation = 17; // This field is temporary until birth_round migration is complete. Field number 17 chosen to avoid polluting cheaper 1 byte field numbers 1-16 +} diff --git a/packages/proto/src/proto/services/event_transaction.proto b/packages/proto/src/proto/services/event_transaction.proto new file mode 100644 index 000000000..5081a1cdf --- /dev/null +++ b/packages/proto/src/proto/services/event_transaction.proto @@ -0,0 +1,65 @@ +/** + * # Event Transaction + * An Event Transaction gossiped between nodes as part of events. + * + * ### 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.platform.event; + +/* + * 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. + */ + +import "event/state_signature_transaction.proto"; + +option java_package = "com.hedera.hapi.platform.event.legacy"; +// <<>> This comment is special code for setting PBJ Compiler java package +option java_multiple_files = true; + +/** + * An Event Transaction gossiped between nodes as part of events. + * + * Each node MUST extract this transaction and process according to the type + * of transaction encoded.
+ * Both the platform and the application built on that platform MAY define event + * transactions.
+ * The encoded data MUST be a serialized protobuf message. + */ +message EventTransaction { + oneof transaction { + /** + * An application transaction. + *

+ * The contents of this transaction SHALL be defined by the application + * subsystem that created the event.
+ * The contents MUST be a serialized protobuf message. + */ + bytes application_transaction = 1; + /** + * A state signature. + *

+ * This transaction SHALL be a valid state signature for a state snapshot. + */ + StateSignatureTransaction state_signature_transaction = 2; + } + +} diff --git a/packages/proto/src/proto/services/gossip_event.proto b/packages/proto/src/proto/services/gossip_event.proto new file mode 100644 index 000000000..b0e16fd9b --- /dev/null +++ b/packages/proto/src/proto/services/gossip_event.proto @@ -0,0 +1,81 @@ +/** + * # Gossip Event + * An event that is sent and received via gossip + * + * ### 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). + */ +syntax = "proto3"; + +package com.hedera.hapi.platform.event; + +/* + * Hedera Network Services Protobuf + * + * 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. + */ + +import "event/event_transaction.proto"; +import "event/event_core.proto"; + +option java_package = "com.hedera.hapi.platform.event.legacy"; +// <<>> This comment is special code for setting PBJ Compiler java package +option java_multiple_files = true; + +/** + * An event that is sent and received via gossip + */ +message GossipEvent { + /** + * The core event data + */ + EventCore event_core = 1; + + /** + * A node signature on the event hash.
+ * The signature SHALL be created with the SHA384withRSA algorithm.
+ * The signature MUST verify using the public key belonging to the `event_creator`.
+ * The `event_creator` public key SHALL be read from the address book that corresponds to the event's birth round.
+ * The signed event hash SHALL be a SHA-384 hash.
+ * The signed event hash SHALL have the following inputs, in the specified order:
+ * 1. The bytes of the `event_core` field
+ * 2. The SHA-384 hash of each individual `EventTransaction`, in the order the transaction appear in the `event_transaction` field + */ + bytes signature = 2; + + /** + * The event transaction. + *

+ * This field MAY contain zero transactions.
+ * This field MUST NOT exceed `maxTransactionCountPerEvent` entries, initially `245760`.
+ * This total size of this field MUST NOT exceed `maxTransactionBytesPerEvent`, initially `245760` bytes.
+ * Deprecated in favor of the `transaction` field. The idea is to clean the design of event transactions.
+ * This is transitional state until 'transaction' field is fully adopted. + */ + repeated EventTransaction event_transaction = 3 [deprecated = true]; + + /** + * A list of serialized transactions. + *

+ * This field MAY contain zero transactions.
+ * Each transaction in this list SHALL be presented exactly as + * it was supplied to the consensus algorithm.
+ * This field MUST contain one entry for each transaction + * included in this gossip event. + */ + repeated bytes transactions = 4; +} diff --git a/packages/proto/src/proto/services/response_code.proto b/packages/proto/src/proto/services/response_code.proto index 6945f591b..38d1d5f94 100644 --- a/packages/proto/src/proto/services/response_code.proto +++ b/packages/proto/src/proto/services/response_code.proto @@ -1619,4 +1619,10 @@ enum ResponseCodeEnum { * The provided gRPC certificate hash is invalid. */ INVALID_GRPC_CERTIFICATE_HASH = 373; + + /** + * A scheduled transaction configured to wait for expiry to execute was not + * given an explicit expiration time. + */ + MISSING_EXPIRY_TIME = 374; } diff --git a/packages/proto/src/proto/services/state_signature_transaction.proto b/packages/proto/src/proto/services/state_signature_transaction.proto new file mode 100644 index 000000000..a8d55010b --- /dev/null +++ b/packages/proto/src/proto/services/state_signature_transaction.proto @@ -0,0 +1,64 @@ +/** + * # State Signature Transaction + * An signature of a state snapshot gossiped to other nodes. + * + * ### 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). + */ +syntax = "proto3"; + +package com.hedera.hapi.platform.event; + +/* + * Hedera Network Services Protobuf + * + * Copyright (C) 2018 - 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.platform.event.legacy"; +// <<>> This comment is special code for setting PBJ Compiler java package +option java_multiple_files = true; + +/** + * An signature of a state snapshot gossiped to other nodes. + * Each node SHALL hash the root of the merkle tree of a state snapshot every + * round. Once this hash is calculated, it SHOULD be signed with the nodes + * private signing key. This signature, together with the hash SHOULD be added + * to an event as a StateSignatureTransaction. + */ +message StateSignatureTransaction { + + /** + * The round number corresponding to the round number of the state snapshot + * being signed.
+ * This number MUST be greater than 0. + */ + int64 round = 1; + + /** + * The signature of state snapshot hash.
+ * This signature MUST be a RSA signature with a maximum length of 384 bytes.
+ * The signature algorithm used MUST be RSASSA-PKCS1-v1_5 with SHA-384. + */ + bytes signature = 2; + + /** + * The hash of the state snapshot being signed.
+ * This hash MUST be a SHA-384 hash. + */ + bytes hash = 3; +} diff --git a/packages/proto/src/proto/services/transaction_body.proto b/packages/proto/src/proto/services/transaction_body.proto index b34c1d9cd..8e63143d9 100644 --- a/packages/proto/src/proto/services/transaction_body.proto +++ b/packages/proto/src/proto/services/transaction_body.proto @@ -94,6 +94,8 @@ import "auxiliary/tss/tss_vote.proto"; import "auxiliary/tss/tss_share_signature.proto"; import "auxiliary/tss/tss_encryption_key.proto"; +import "event/state_signature_transaction.proto"; + /** * A single transaction. All transaction types are possible here. */ @@ -435,7 +437,7 @@ message TransactionBody { com.hedera.hapi.services.auxiliary.tss.TssVoteTransactionBody tssVote = 62; /** - * A transaction body for a 'tssShareSignature` request + * A transaction body for node signature as part of the Threshold Signature Scheme (TSS) processing. */ com.hedera.hapi.services.auxiliary.tss.TssShareSignatureTransactionBody tssShareSignature = 63; @@ -443,5 +445,10 @@ message TransactionBody { * A transaction body for a 'tssEncryptionKey` request */ com.hedera.hapi.services.auxiliary.tss.TssEncryptionKeyTransactionBody tssEncryptionKey = 64; + + /** + * A transaction body for signature of a state root hash gossiped to other nodes + */ + com.hedera.hapi.platform.event.StateSignatureTransaction state_signature_transaction = 65; } } diff --git a/src/RequestType.js b/src/RequestType.js index d4aa8cfd9..c52b929b5 100644 --- a/src/RequestType.js +++ b/src/RequestType.js @@ -213,6 +213,8 @@ export default class RequestType { return "TssShareSignature"; case RequestType.TssEncryptionKey: return "TssEncryptionKey"; + case RequestType.StateSignatureTransaction: + return "StateSignatureTransaction"; default: return `UNKNOWN (${this._code})`; } @@ -397,6 +399,8 @@ export default class RequestType { return RequestType.TssShareSignature; case 99: return RequestType.TssEncryptionKey; + case 100: + return RequestType.StateSignatureTransaction; } throw new Error( @@ -840,3 +844,8 @@ RequestType.TssShareSignature = new RequestType(98); * Submit a node public tss encryption key as part of the Threshold Signature Scheme (TSS). */ RequestType.TssEncryptionKey = new RequestType(99); + +/** + * Submit a signature of a state root hash gossiped to other nodes + */ +RequestType.StateSignatureTransaction = new RequestType(100); diff --git a/src/Status.js b/src/Status.js index 5f09f6745..8ca4f1b2b 100644 --- a/src/Status.js +++ b/src/Status.js @@ -705,6 +705,8 @@ export default class Status { return "SCHEDULE_EXPIRY_IS_BUSY"; case Status.InvalidGrpcCertificateHash: return "INVALID_GRPC_CERTIFICATE_HASH"; + case Status.MissingExpiryTime: + return "MISSING_EXPIRY_TIME"; default: return `UNKNOWN (${this._code})`; } @@ -1381,6 +1383,8 @@ export default class Status { return Status.ScheduleExpiryIsBusy; case 373: return Status.InvalidGrpcCertificateHash; + case 374: + return Status.MissingExpiryTime; default: throw new Error( `(BUG) Status.fromCode() does not handle code: ${code}`, @@ -3118,3 +3122,9 @@ Status.ScheduleExpiryIsBusy = new Status(372); * The provided gRPC certificate hash is invalid. */ Status.InvalidGrpcCertificateHash = new Status(373); + +/** + * A scheduled transaction configured to wait for expiry to execute was not + * given an explicit expiration time. + */ +Status.MissingExpiryTime = new Status(374); diff --git a/test/unit/Mocker.js b/test/unit/Mocker.js index 1b97d504f..6f1941be3 100644 --- a/test/unit/Mocker.js +++ b/test/unit/Mocker.js @@ -123,6 +123,12 @@ const PROTOS = [ "./packages/proto/src/proto/services/transaction_record.proto", "./packages/proto/src/proto/services/transaction_response.proto", "./packages/proto/src/proto/services/unchecked_submit.proto", + "./packages/proto/src/proto/services/event_consensus_data.proto", + "./packages/proto/src/proto/services/event_core.proto", + "./packages/proto/src/proto/services/event_descriptor.proto", + "./packages/proto/src/proto/services/event_transaction.proto", + "./packages/proto/src/proto/services/gossip_event.proto", + "./packages/proto/src/proto/services/state_signature_transaction.proto", ]; export const ABORTED = {