Skip to content

Commit

Permalink
Merge branch 'develop' into 13001-stale-event-detector
Browse files Browse the repository at this point in the history
Signed-off-by: Cody Littley <cody@swirldslabs.com>
  • Loading branch information
cody-littley committed May 7, 2024
2 parents b27a286 + a73ebaf commit 1b79c32
Show file tree
Hide file tree
Showing 137 changed files with 5,580 additions and 1,973 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import org.gradle.api.DefaultTask
import org.gradle.api.file.DirectoryProperty
import org.gradle.api.provider.Property
import org.gradle.api.tasks.Input
import org.gradle.api.tasks.Optional
import org.gradle.api.tasks.OutputDirectory
import org.gradle.api.tasks.TaskAction
import org.gradle.process.ExecOperations
Expand All @@ -15,7 +16,12 @@ abstract class GitClone : DefaultTask() {
abstract val url: Property<String>

@get:Input
abstract val branchOrTag: Property<String>
@get:Optional
abstract val tag: Property<String>

@get:Input
@get:Optional
abstract val branch: Property<String>

@get:Input
abstract val offline: Property<Boolean>
Expand All @@ -26,8 +32,17 @@ abstract class GitClone : DefaultTask() {
@get:Inject
protected abstract val exec: ExecOperations

init {
// If a 'branch' is configured, the task is never up-to-date as it may change
outputs.upToDateWhen { !branch.isPresent }
}

@TaskAction
fun cloneOrUpdate() {
if (!tag.isPresent && !branch.isPresent || tag.isPresent && branch.isPresent) {
throw RuntimeException("Define either 'tag' or 'branch'")
}

val localClone = localCloneDirectory.get()
if (!offline.get()) {
exec.exec {
Expand All @@ -45,13 +60,24 @@ abstract class GitClone : DefaultTask() {
}
}
}
exec.exec {
workingDir = localClone.asFile
commandLine("git", "checkout", branchOrTag.get(), "-q")
}
exec.exec {
workingDir = localClone.asFile
commandLine("git", "reset", "--hard", "origin/${branchOrTag.get()}", "-q")
if (tag.isPresent) {
exec.exec {
workingDir = localClone.asFile
commandLine("git", "checkout", tag.get(), "-q")
}
exec.exec {
workingDir = localClone.asFile
commandLine("git", "reset", "--hard", tag.get(), "-q")
}
} else {
exec.exec {
workingDir = localClone.asFile
commandLine("git", "checkout", branch.get(), "-q")
}
exec.exec {
workingDir = localClone.asFile
commandLine("git", "reset", "--hard", "origin/${branch.get()}", "-q")
}
}
}
}
5 changes: 2 additions & 3 deletions hapi/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,8 @@ description = "Hedera API"

// Add downloaded HAPI repo protobuf files into build directory and add to sources to build them
tasks.cloneHederaProtobufs {
branchOrTag = "v0.50.0-release"
// As long as the 'branchOrTag' above is not stable, run always:
outputs.upToDateWhen { false }
tag = "v0.50.0-release"
// branch = "main"
}

sourceSets {
Expand Down
2 changes: 1 addition & 1 deletion hedera-dependency-versions/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ moduleInfo {
version("javax.inject", "1")
version("lazysodium.java", "5.1.1")
version("net.i2p.crypto.eddsa", "0.3.0")
version("org.antlr.antlr4.runtime", "4.11.1")
version("org.antlr.antlr4.runtime", "4.13.1")
version("org.apache.commons.codec", "1.15")
version("org.apache.commons.collections4", "4.4")
version("org.apache.commons.io", "2.15.1")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@

package com.hedera.node.app.spi.fees;

import com.hederahashgraph.api.proto.java.FeeComponents;
import com.hederahashgraph.api.proto.java.FeeData;

/**
* Represents the combination of node, network, and service fees.
*
Expand All @@ -36,6 +39,15 @@
public record Fees(long nodeFee, long networkFee, long serviceFee) {
/** A constant representing zero fees. */
public static final Fees FREE = new Fees(0, 0, 0);
/**
* A constant representing fees of 1 constant resource usage for each of the node, network, and service components.
* This is useful when a fee is required, but the entity is not present in state to determine the actual fee.
*/
public static final FeeData CONSTANT_FEE_DATA = FeeData.newBuilder()
.setNodedata(FeeComponents.newBuilder().setConstant(1).build())
.setNetworkdata(FeeComponents.newBuilder().setConstant(1).build())
.setServicedata(FeeComponents.newBuilder().setConstant(1).build())
.build();

public Fees {
// Validate the fee components are never negative.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ public class KeyUtils {

public static final Key IMMUTABILITY_SENTINEL_KEY =
Key.newBuilder().keyList(KeyList.DEFAULT).build();

public static final int EVM_ADDRESS_BYTE_LENGTH = 20;
public static final int ED25519_BYTE_LENGTH = 32;
private static final byte ODD_PARITY = (byte) 0x03;
Expand All @@ -43,10 +44,6 @@ private KeyUtils() {
throw new UnsupportedOperationException("Utility Class");
}

public static boolean isEmptyAndNotImmutable(@Nullable final Key pbjKey) {
return isEmptyInternal(pbjKey, true);
}

/**
* Checks if the given key is empty.
* For a KeyList type checks if the list is empty.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -726,10 +726,7 @@ private void unmarkMigrationRecordsStreamed(HederaState state) {
final var nextBlockInfo =
currentBlockInfo.copyBuilder().migrationRecordsStreamed(false).build();
blockInfoState.put(nextBlockInfo);
logger.info(
"Unmarked migration records streamed with block info {} with hash {}",
nextBlockInfo,
blockInfoState.hashCode());
logger.info("Unmarked migration records streamed");
((WritableSingletonStateBase<BlockInfo>) blockInfoState).commit();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@
import com.hedera.node.config.data.HederaConfig;
import com.hedera.node.config.data.RatesConfig;
import com.hedera.pbj.runtime.ParseException;
import com.hedera.pbj.runtime.UncheckedParseException;
import com.hedera.pbj.runtime.io.buffer.Bytes;
import edu.umd.cs.findbugs.annotations.NonNull;
import edu.umd.cs.findbugs.annotations.Nullable;
Expand All @@ -43,6 +42,8 @@
import java.util.stream.LongStream;
import javax.inject.Inject;
import javax.inject.Singleton;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

/**
* Parses the exchange rate information and makes it available to the workflows.
Expand All @@ -63,6 +64,7 @@
*/
@Singleton
public final class ExchangeRateManager {
private static final Logger log = LogManager.getLogger(ExchangeRateManager.class);

private static final BigInteger ONE_HUNDRED = BigInteger.valueOf(100);

Expand All @@ -80,31 +82,29 @@ public void init(@NonNull final HederaState state, @NonNull final Bytes bytes) {
requireNonNull(state, "state must not be null");
requireNonNull(bytes, "bytes must not be null");

// First we try to read midnightRates from state
// Re-use the same code path to set the active rates as does the SystemFileUpdateFacility
// IMPORTANT - if we first initialized the midnight rates, we couldn't reuse this code path
// because it overwrites the midnight rates with the current rates
systemUpdate(bytes);

// Now fix the midnight rates to what is in state (note that all post-initialization
// Services states must have a non-null midnight rates set, even at genesis, as
// FeeService schema migrate() creates them in that case)
midnightRates = state.getReadableStates(FeeService.NAME)
.<ExchangeRateSet>getSingleton(FeeService.MIDNIGHT_RATES_STATE_KEY)
.get();
if (midnightRates != ExchangeRateSet.DEFAULT) {
// midnightRates were found in state, a regular update is sufficient
//
systemUpdate(bytes);
}

// If midnightRates were not found in state, we initialize them from the file
try {
midnightRates = ExchangeRateSet.PROTOBUF.parse(bytes.toReadableSequentialData());
} catch (ParseException e) {
// an error here is fatal and needs to be handled by the general initialization code
throw new UncheckedParseException(e);
}
this.currentExchangeRateInfo = new ExchangeRateInfoImpl(midnightRates);
requireNonNull(midnightRates, "an initialized state must have a midnight rates set");
log.info(
"Initializing exchange rates with midnight rates {} and active rates {}",
midnightRates,
currentExchangeRateInfo.exchangeRates());
}

/**
* Updates the exchange rate information. MUST BE CALLED on the handle thread!
*
* @param bytes The protobuf encoded {@link ExchangeRateSet}.
* @param payerId The payer of the transaction that triggered this update.
* @param bytes The protobuf encoded {@link ExchangeRateSet}.
* @param payerId The payer of the transaction that triggered this update.
*/
public void update(@NonNull final Bytes bytes, @NonNull AccountID payerId) {
requireNonNull(payerId, "payerId must not be null");
Expand Down Expand Up @@ -147,7 +147,6 @@ private void internalUpdate(@NonNull final Bytes bytes, @Nullable AccountID paye

// Update the current ExchangeRateInfo and eventually the midnightRates
this.currentExchangeRateInfo = new ExchangeRateInfoImpl(proposedRates);
// TODO: save the mignightRates in state only
if (isAdminUser(payerId, accountsConfig)) {
midnightRates = proposedRates;
}
Expand All @@ -167,15 +166,22 @@ private boolean isAdminUser(@NonNull final AccountID accountID, AccountsConfig a
return num == accountsConfig.systemAdmin();
}

/**
* Updates the midnight rates to the current exchange rates, both internally and in the given state.
*
* @param state the {@link HederaState} to update the midnight rates in
*/
public void updateMidnightRates(@NonNull final HederaState state) {
midnightRates = currentExchangeRateInfo.exchangeRates();
final var singleton = state.getWritableStates(FeeService.NAME)
.<ExchangeRateSet>getSingleton(FeeService.MIDNIGHT_RATES_STATE_KEY);
singleton.put(midnightRates);
log.info("Updated midnight rates to {}", midnightRates);
}

/**
* Gets the current {@link ExchangeRateSet}. MUST BE CALLED ON THE HANDLE THREAD!!
*
* @return The current {@link ExchangeRateSet}.
*/
@NonNull
Expand All @@ -188,7 +194,7 @@ public ExchangeRateSet exchangeRates() {
* THREAD!!
*
* @param consensusTime The consensus time. If after the expiration time of the current rate, the next rate will
* be returned. Otherwise, the current rate will be returned.
* be returned. Otherwise, the current rate will be returned.
* @return The {@link ExchangeRate} that should be used as of the given consensus time.
*/
@NonNull
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,17 +109,20 @@ public abstract class MethodBase implements ServerCalls.UnaryMethod<BufferedData
@Override
public void invoke(
@NonNull final BufferedData requestBuffer, @NonNull final StreamObserver<BufferedData> responseObserver) {
try {
// Track the number of times this method has been called
callsReceivedCounter.increment();
callsReceivedSpeedometer.cycle();
// Track the number of times this method has been called
callsReceivedCounter.increment();
callsReceivedSpeedometer.cycle();

// Fail-fast if the request is too large (Note that the request buffer is sized to allow exactly
// 1 more byte than MAX_MESSAGE_SIZE, so we can detect this case).
if (requestBuffer.length() > MAX_MESSAGE_SIZE) {
throw new RuntimeException("More than " + MAX_MESSAGE_SIZE + " received");
}
// Fail-fast if the request is too large (Note that the request buffer is sized to allow exactly
// 1 more byte than MAX_MESSAGE_SIZE, so we can detect this case).
if (requestBuffer.length() > MAX_MESSAGE_SIZE) {
callsFailedCounter.increment();
final var exception = new RuntimeException("More than " + MAX_MESSAGE_SIZE + " received");
responseObserver.onError(exception);
return;
}

try {
// Prepare the response buffer
final var responseBuffer = BUFFER_THREAD_LOCAL.get();
responseBuffer.reset();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ static NodeId selfId(@NonNull final Platform platform) {
@Provides
@Singleton
static Signer signer(@NonNull final Platform platform) {
return platform;
return platform::sign;
}

@Provides
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@
import static com.hedera.hapi.node.base.ResponseCodeEnum.BUSY;
import static com.hedera.hapi.node.base.ResponseCodeEnum.DUPLICATE_TRANSACTION;
import static com.hedera.hapi.node.base.ResponseCodeEnum.INSUFFICIENT_GAS;
import static com.hedera.hapi.node.base.ResponseCodeEnum.INSUFFICIENT_TX_FEE;
import static com.hedera.hapi.node.base.ResponseCodeEnum.INVALID_ETHEREUM_TRANSACTION;
import static com.hedera.hapi.node.base.ResponseCodeEnum.INVALID_NODE_ACCOUNT;
import static com.hedera.hapi.node.base.ResponseCodeEnum.INVALID_SIGNATURE;
Expand Down Expand Up @@ -189,9 +188,9 @@ public TransactionInfo runAllChecks(

// If the fee offered does not cover the gas cost of the transaction, then
// we would again end up with uncompensated work
final var gasCost = solvencyPreCheck.estimateAdditionalCosts(txBody, CONTRACT_CALL, consensusTime)
- txBody.contractCallOrThrow().amount();
validateTruePreCheck(txBody.transactionFee() >= gasCost, INSUFFICIENT_TX_FEE);
// final var gasCost = solvencyPreCheck.estimateAdditionalCosts(txBody, CONTRACT_CALL, consensusTime)
// - txBody.contractCallOrThrow().amount();
// validateTruePreCheck(txBody.transactionFee() >= gasCost, INSUFFICIENT_TX_FEE);
} else if (functionality == ETHEREUM_TRANSACTION) {
final var ethTxData = populateEthTxData(
requireNonNull(txBody.ethereumTransactionOrThrow().ethereumData())
Expand Down
14 changes: 14 additions & 0 deletions hedera-node/hedera-app/src/xtest/java/common/AbstractXTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@
import com.hedera.node.app.spi.metrics.StoreMetricsService;
import com.hedera.node.app.spi.state.ReadableKVState;
import com.hedera.node.app.spi.workflows.HandleException;
import com.hedera.node.app.spi.workflows.PreCheckException;
import com.hedera.node.app.spi.workflows.QueryHandler;
import com.hedera.node.app.spi.workflows.TransactionHandler;
import com.hedera.node.app.spi.workflows.record.SingleTransactionRecordBuilder;
Expand Down Expand Up @@ -127,6 +128,7 @@ void scenarioPasses() {

doScenarioOperations();

assertExpectedTokens(finalTokens());
assertExpectedNfts(finalNfts());
assertExpectedAliases(finalAliases());
assertExpectedAccounts(finalAccounts());
Expand Down Expand Up @@ -159,13 +161,18 @@ protected SingleTransactionRecordBuilderImpl handleAndCommitSingleTransaction(
@NonNull final TransactionBody txn,
@NonNull final ResponseCodeEnum expectedStatus) {
final var context = component().txnContextFactory().apply(txn);
final var preContext = component().txnPreHandleContextFactory().apply(txn);
var impliedStatus = OK;
try {
handler.preHandle(preContext);
handler.handle(context);
((SavepointStackImpl) context.savepointStack()).commitFullStack();
} catch (HandleException e) {
impliedStatus = e.getStatus();
((SavepointStackImpl) context.savepointStack()).rollbackFullStack();
} catch (PreCheckException e) {
impliedStatus = e.responseCode();
((SavepointStackImpl) context.savepointStack()).rollbackFullStack();
}
assertEquals(expectedStatus, impliedStatus);
return (SingleTransactionRecordBuilderImpl) context.recordBuilder(SingleTransactionRecordBuilder.class);
Expand Down Expand Up @@ -326,6 +333,13 @@ protected void assertExpectedBytecodes(@NonNull ReadableKVState<EntityNumber, By

protected void assertExpectedTokens(@NonNull ReadableKVState<TokenID, Token> tokens) {}

private ReadableKVState<TokenID, Token> finalTokens() {
return component()
.hederaState()
.getReadableStates(TokenServiceImpl.NAME)
.get(TokenServiceImpl.TOKENS_KEY);
}

private ReadableKVState<NftID, Nft> finalNfts() {
return component()
.hederaState()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import com.hedera.node.app.fees.ExchangeRateManager;
import com.hedera.node.app.fees.FeeManager;
import com.hedera.node.app.spi.workflows.HandleContext;
import com.hedera.node.app.spi.workflows.PreHandleContext;
import com.hedera.node.app.spi.workflows.QueryContext;
import com.hedera.node.app.state.HederaState;
import com.hedera.node.app.state.WorkingStateAccessor;
Expand All @@ -41,6 +42,8 @@ public interface BaseScaffoldingComponent {

Function<TransactionBody, HandleContext> txnContextFactory();

Function<TransactionBody, PreHandleContext> txnPreHandleContextFactory();

BiFunction<Query, AccountID, QueryContext> queryContextFactory();

FeeManager feeManager();
Expand Down

0 comments on commit 1b79c32

Please sign in to comment.