Skip to content

Commit

Permalink
Merge branch 'develop' into 15492-fake-tss-library-for-testing
Browse files Browse the repository at this point in the history
  • Loading branch information
MiroslavGatsanoga committed Oct 18, 2024
2 parents 4136248 + 373935a commit 6f17c87
Show file tree
Hide file tree
Showing 138 changed files with 6,308 additions and 1,399 deletions.
29 changes: 12 additions & 17 deletions hapi/hedera-protobufs/services/address_book_service.proto
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ import "transaction.proto";
* but each node operator may update their own operational attributes without
* additional approval, reducing overhead for routine operations.
*
* Most operations are `privileged operations` and require governing council
* All operations are `privileged operations` and require governing council
* approval.
*
* ### For a node creation transaction.
Expand Down Expand Up @@ -91,22 +91,18 @@ import "transaction.proto";
* - If the transaction changes the value of the "node account" the
* node operator MUST _also_ sign this transaction with the active `key`
* for the account to be assigned as the new "node account".
* - The node operator SHALL submit the transaction to the
* network. Hedera council approval SHALL NOT be sought for this
* transaction
* - If the Hedera council representative creates the transaction
* - The Hedera council representative SHALL arrange for council members
* to review and sign the transaction.
* - Once sufficient council members have signed the transaction, the
* Hedera council representative SHALL submit the transaction to the
* network.
* - The node operator MUST deliver the signed transaction to the Hedera
* council representative.
* - The Hedera council representative SHALL arrange for council members to
* review and sign the transaction.
* - Once sufficient council members have signed the transaction, the
* Hedera council representative SHALL submit the transaction to the
* network.
* - Upon receipt of a valid and signed node update transaction the network
* software SHALL
* - If the transaction is signed by the Hedera governing council
* - Validate the threshold signature for the Hedera governing council
* - If the transaction is signed by the active `key` for the node account
* - Validate the signature of the active `key` for the account assigned
* as the "node account".
* - Validate the threshold signature for the Hedera governing council
* - Validate the signature of the active `key` for the account to be
* assigned as the "node account".
* - If the transaction modifies the value of the "node account",
* - Validate the signature of the _new_ `key` for the account to be
* assigned as the new "node account".
Expand Down Expand Up @@ -151,8 +147,7 @@ service AddressBookService {
* This transaction, once complete, SHALL modify the identified consensus
* node state as requested.
* <p>
* This transaction MAY be authorized by either the node operator OR the
* Hedera governing council.
* Hedera governing council authorization is REQUIRED for this transaction.
*/
rpc updateNode (proto.Transaction) returns (proto.TransactionResponse);
}
7 changes: 4 additions & 3 deletions hapi/hedera-protobufs/services/node_update.proto
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,10 @@ import "basic_types.proto";
/**
* Transaction body to modify address book node attributes.
*
* - This transaction SHALL enable the node operator, as identified by the
* `admin_key`, to modify operational attributes of the node.
* - This transaction MUST be signed by the active `admin_key` for the node.
* This transaction body SHALL be considered a "privileged transaction".
*
* - This transaction MUST be signed by the governing council and
* - the active `admin_key` for the node.
* - If this transaction sets a new value for the `admin_key`, then both the
* current `admin_key`, and the new `admin_key` MUST sign this transaction.
* - This transaction SHALL NOT change any field that is not set (is null) in
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ package com.hedera.hapi.node.state.blockstream;
*/

import "timestamp.proto";
import "basic_types.proto";

option java_package = "com.hederahashgraph.api.proto.java";
// <<<pbj.java_package = "com.hedera.hapi.node.state.blockstream">>> This comment is special code for setting PBJ Compiler java package
Expand Down Expand Up @@ -73,7 +74,7 @@ message BlockStreamInfo {
* A concatenation of hash values.<br/>
* This combines several trailing output block item hashes and
* is used as a seed value for a pseudo-random number generator.<br/>
* This is also requiried to implement the EVM `PREVRANDAO` opcode.
* This is also required to implement the EVM `PREVRANDAO` opcode.
* This MUST contain at least 256 bits of entropy.
*/
bytes trailing_output_hashes = 3;
Expand Down Expand Up @@ -131,4 +132,27 @@ message BlockStreamInfo {
* the current block.
*/
proto.Timestamp block_end_time = 9;

/**
* Whether the post-upgrade work has been done.
* <p>
* This MUST be false if and only if the network just restarted
* after an upgrade and has not yet done the post-upgrade work.
*/
bool post_upgrade_work_done = 10;

/**
* A version describing the version of application software.
* <p>
* This SHALL be the software version that created this block.
*/
proto.SemanticVersion creation_software_version = 11;

/**
* The time stamp at which the last interval process was done.
* <p>
* This field SHALL hold the consensus time for the last time
* at which an interval of time-dependent events were processed.
*/
proto.Timestamp last_interval_process_time = 12;
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,14 @@
import com.google.protobuf.InvalidProtocolBufferException;
import com.hedera.hapi.util.HapiUtils;
import com.hedera.hapi.util.UnknownHederaFunctionality;
import com.hedera.pbj.runtime.io.buffer.Bytes;
import com.hederahashgraph.api.proto.java.HederaFunctionality;
import com.hederahashgraph.api.proto.java.SignatureMap;
import com.hederahashgraph.api.proto.java.SignedTransaction;
import com.hederahashgraph.api.proto.java.Timestamp;
import com.hederahashgraph.api.proto.java.TransactionBody;
import com.hederahashgraph.api.proto.java.TransactionOrBuilder;
import com.swirlds.common.crypto.DigestType;
import edu.umd.cs.findbugs.annotations.NonNull;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
Expand Down Expand Up @@ -94,6 +96,23 @@ public static SignatureMap extractSignatureMap(final TransactionOrBuilder transa
return transaction.getSigMap();
}

/**
* Returns a {@link MessageDigest} instance for the SHA-384 algorithm, throwing an unchecked exception if the
* algorithm is not found.
* @return a {@link MessageDigest} instance for the SHA-384 algorithm
*/
public static MessageDigest sha384DigestOrThrow() {
try {
return MessageDigest.getInstance(DigestType.SHA_384.algorithmName());
} catch (final NoSuchAlgorithmException fatal) {
throw new IllegalStateException(fatal);
}
}

public static Bytes noThrowSha384HashOf(final Bytes bytes) {
return Bytes.wrap(noThrowSha384HashOf(bytes.toByteArray()));
}

public static byte[] noThrowSha384HashOf(final byte[] byteArray) {
try {
return MessageDigest.getInstance(sha384HashTag).digest(byteArray);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ public NodeCreateHandler(@NonNull final AddressBookValidator addressBookValidato
@Override
public void pureChecks(@NonNull final TransactionBody txn) throws PreCheckException {
requireNonNull(txn);
final var op = txn.nodeCreate();
final var op = txn.nodeCreateOrThrow();
addressBookValidator.validateAccountId(op.accountId());
validateFalsePreCheck(op.gossipEndpoint().isEmpty(), INVALID_GOSSIP_ENDPOINT);
validateFalsePreCheck(op.serviceEndpoint().isEmpty(), INVALID_SERVICE_ENDPOINT);
Expand All @@ -95,7 +95,7 @@ public void preHandle(@NonNull final PreHandleContext context) throws PreCheckEx
@Override
public void handle(@NonNull final HandleContext handleContext) {
requireNonNull(handleContext);
final var op = handleContext.body().nodeCreate();
final var op = handleContext.body().nodeCreateOrThrow();
final var nodeConfig = handleContext.configuration().getConfigData(NodesConfig.class);
final var storeFactory = handleContext.storeFactory();
final var nodeStore = storeFactory.writableStore(WritableNodeStore.class);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ public NodeUpdateHandler(@NonNull final AddressBookValidator addressBookValidato
@Override
public void pureChecks(@NonNull final TransactionBody txn) throws PreCheckException {
requireNonNull(txn);
final var op = txn.nodeUpdate();
final var op = txn.nodeUpdateOrThrow();
validateFalsePreCheck(op.nodeId() < 0, INVALID_NODE_ID);
if (op.hasGossipCaCertificate()) {
validateFalsePreCheck(op.gossipCaCertificate().equals(Bytes.EMPTY), INVALID_GOSSIP_CA_CERTIFICATE);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,14 @@ void migrateAsExpected4() {
writableNodes.get(EntityNumber.newBuilder().number(3).build()));
}

@Test
void failedNullNetworkinfo() {
given(migrationContext.genesisNetworkInfo()).willReturn(null);
assertThatCode(() -> subject.migrate(migrationContext))
.isInstanceOf(IllegalStateException.class)
.hasMessage("Genesis network info is not found");
}

private void setupMigrationContext() {
writableStates = MapWritableStates.builder().state(writableNodes).build();
given(migrationContext.newStates()).willReturn(writableStates);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import static com.hedera.hapi.node.base.ResponseCodeEnum.UNKNOWN;
import static com.hedera.hapi.util.HapiUtils.TIMESTAMP_COMPARATOR;
import static java.util.Collections.emptyList;
import static java.util.Objects.requireNonNull;

import com.hedera.hapi.node.base.AccountID;
import com.hedera.hapi.node.base.ResponseCodeEnum;
Expand Down Expand Up @@ -53,7 +54,8 @@ public interface RecordCache {
* For mono-service fidelity, records with these statuses do not prevent valid transactions with
* the same id from reaching consensus and being handled.
*/
Set<ResponseCodeEnum> DUE_DILIGENCE_FAILURES = EnumSet.of(INVALID_NODE_ACCOUNT, INVALID_PAYER_SIGNATURE);
Set<ResponseCodeEnum> NODE_FAILURES = EnumSet.of(INVALID_NODE_ACCOUNT, INVALID_PAYER_SIGNATURE);

/**
* And when ordering records for queries, we treat records with unclassifiable statuses as the
* lowest "priority"; so that e.g. if a transaction with id {@code X} resolves to {@link ResponseCodeEnum#SUCCESS}
Expand All @@ -65,11 +67,82 @@ public interface RecordCache {
@SuppressWarnings("java:S3358")
Comparator<TransactionRecord> RECORD_COMPARATOR = Comparator.<TransactionRecord, ResponseCodeEnum>comparing(
rec -> rec.receiptOrThrow().status(),
(a, b) -> DUE_DILIGENCE_FAILURES.contains(a) == DUE_DILIGENCE_FAILURES.contains(b)
(a, b) -> NODE_FAILURES.contains(a) == NODE_FAILURES.contains(b)
? 0
: (DUE_DILIGENCE_FAILURES.contains(b) ? -1 : 1))
: (NODE_FAILURES.contains(b) ? -1 : 1))
.thenComparing(rec -> rec.consensusTimestampOrElse(Timestamp.DEFAULT), TIMESTAMP_COMPARATOR);

/**
* Returns true if the two transaction IDs are equal in all fields except for the nonce.
* @param aTxnId the first transaction ID
* @param bTxnId the second transaction ID
* @return true if the two transaction IDs are equal in all fields except for the nonce
*/
static boolean matchesExceptNonce(@NonNull final TransactionID aTxnId, @NonNull final TransactionID bTxnId) {
requireNonNull(aTxnId);
requireNonNull(bTxnId);
return aTxnId.accountIDOrElse(AccountID.DEFAULT).equals(bTxnId.accountIDOrElse(AccountID.DEFAULT))
&& aTxnId.transactionValidStartOrElse(Timestamp.DEFAULT)
.equals(bTxnId.transactionValidStartOrElse(Timestamp.DEFAULT))
&& aTxnId.scheduled() == bTxnId.scheduled();
}

/**
* Returns true if the second transaction ID is a child of the first.
* @param aTxnId the first transaction ID
* @param bTxnId the second transaction ID
* @return true if the second transaction ID is a child of the first
*/
static boolean isChild(@NonNull final TransactionID aTxnId, @NonNull final TransactionID bTxnId) {
requireNonNull(aTxnId);
requireNonNull(bTxnId);
return aTxnId.nonce() == 0 && bTxnId.nonce() != 0 && matchesExceptNonce(aTxnId, bTxnId);
}

/**
* Just the receipts for a source of one or more {@link TransactionID}s instead of the full records.
*/
interface ReceiptSource {
/**
* This receipt is returned whenever we know there is a transaction pending (i.e. we have a history for a
* transaction ID), but we do not yet have a record for it.
*/
TransactionReceipt PENDING_RECEIPT =
TransactionReceipt.newBuilder().status(UNKNOWN).build();

/**
* The "priority" receipt for the transaction id, if known; or {@link ReceiptSource#PENDING_RECEIPT} if there are no
* consensus receipts with this id. (The priority receipt is the first receipt in the id's history that had a
* status not in {@link RecordCache#NODE_FAILURES}; or if all its receipts have such statuses, the first
* one to have reached consensus.)
* @return the priority receipt, if known
*/
@NonNull
TransactionReceipt priorityReceipt(@NonNull TransactionID txnId);

/**
* The child receipt with this transaction id, if any; or null otherwise.
* @return the child receipt, if known
*/
@Nullable
TransactionReceipt childReceipt(@NonNull TransactionID txnId);

/**
* All the duplicate receipts for the transaction id, if any, with the statuses in
* {@link RecordCache#NODE_FAILURES} coming last. The list is otherwise ordered by consensus timestamp.
* @return the duplicate receipts, if any
*/
@NonNull
List<TransactionReceipt> duplicateReceipts(@NonNull TransactionID txnId);

/**
* All the child receipts for the transaction id, if any. The list is ordered by consensus timestamp.
* @return the child receipts, if any
*/
@NonNull
List<TransactionReceipt> childReceipts(@NonNull TransactionID txnId);
}

/**
* An item stored in the cache.
*
Expand All @@ -92,13 +165,6 @@ record History(
@NonNull List<TransactionRecord> records,
@NonNull List<TransactionRecord> childRecords) {

/**
* This receipt is returned whenever we know there is a transaction pending (i.e. we have a history for a
* transaction ID), but we do not yet have a record for it.
*/
private static final TransactionReceipt PENDING_RECEIPT =
TransactionReceipt.newBuilder().status(UNKNOWN).build();

/**
* Create a new {@link History} instance with empty lists.
*/
Expand All @@ -117,17 +183,10 @@ public TransactionRecord userTransactionRecord() {
return records.isEmpty() ? null : sortedRecords().getFirst();
}

/**
* Gets the primary receipt, that is, the receipt associated with the user transaction itself. This receipt will
* be null if there is no such record.
*
* @return The primary receipt, if there is one.
*/
@Nullable
public TransactionReceipt userTransactionReceipt() {
public @NonNull TransactionReceipt priorityReceipt() {
return records.isEmpty()
? PENDING_RECEIPT
: sortedRecords().getFirst().receipt();
? ReceiptSource.PENDING_RECEIPT
: sortedRecords().getFirst().receiptOrThrow();
}

/**
Expand Down Expand Up @@ -181,6 +240,14 @@ private List<TransactionRecord> sortedRecords() {
@Nullable
History getHistory(@NonNull TransactionID transactionID);

/**
* Gets the receipts for the given {@link TransactionID}, if known.
* @param transactionID The transaction ID to look up
* @return the receipts, if any, stored in this cache for the given transaction ID
*/
@Nullable
ReceiptSource getReceipts(@NonNull TransactionID transactionID);

/**
* Gets a list of all records for the given {@link AccountID}. The {@link AccountID} is the account of the Payer of
* the transaction.
Expand Down
Loading

0 comments on commit 6f17c87

Please sign in to comment.