Skip to content

Commit

Permalink
fix: set active ExchangeRateSet on triggered txn receipts (#15396)
Browse files Browse the repository at this point in the history
Signed-off-by: Michael Tinker <[email protected]>
  • Loading branch information
tinker-michaelj authored Sep 10, 2024
1 parent eba7d69 commit 33a84b1
Show file tree
Hide file tree
Showing 6 changed files with 28 additions and 11 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -363,7 +363,8 @@ private HandleOutput execute(@NonNull final UserTxn userTxn) {
dispatchProcessor.processDispatch(dispatch);
updateWorkflowMetrics(userTxn);
}
final var handleOutput = userTxn.stack().buildHandleOutput(userTxn.consensusNow());
final var handleOutput =
userTxn.stack().buildHandleOutput(userTxn.consensusNow(), exchangeRateManager.exchangeRates());
// Note that we don't yet support producing ONLY blocks, because we haven't integrated
// translators from block items to records for answering queries
if (blockStreamConfig.streamRecords()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@

import com.hedera.hapi.block.stream.BlockItem;
import com.hedera.hapi.node.base.TransactionID;
import com.hedera.hapi.node.transaction.ExchangeRateSet;
import com.hedera.node.app.blocks.impl.BoundaryStateChangeListener;
import com.hedera.node.app.blocks.impl.KVStateChangeListener;
import com.hedera.node.app.blocks.impl.PairedStreamBuilder;
Expand Down Expand Up @@ -59,16 +60,13 @@
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

/**
* A stack of savepoints scoped to a dispatch. Each savepoint captures the state of the {@link State} at the time
* the savepoint was created and all the changes made to the state from the time savepoint was created, along with all
* the stream builders created in the savepoint.
*/
public class SavepointStackImpl implements HandleContext.SavepointStack, State {
private static final Logger log = LogManager.getLogger(SavepointStackImpl.class);
private final State state;
private final Deque<Savepoint> stack = new ArrayDeque<>();
private final Map<String, WritableStatesStack> writableStatesMap = new HashMap<>();
Expand Down Expand Up @@ -444,9 +442,11 @@ Savepoint peek() {
* Builds all the records for the user transaction.
*
* @param consensusTime consensus time of the transaction
* @param exchangeRates the active exchange rates
* @return the stream of records
*/
public HandleOutput buildHandleOutput(@NonNull final Instant consensusTime) {
public HandleOutput buildHandleOutput(
@NonNull final Instant consensusTime, @NonNull final ExchangeRateSet exchangeRates) {
final List<BlockItem> blockItems;
Instant lastAssignedConsenusTime = consensusTime;
if (streamMode == RECORDS) {
Expand Down Expand Up @@ -481,10 +481,16 @@ public HandleOutput buildHandleOutput(@NonNull final Instant consensusTime) {
final var consensusNow = consensusTime.plusNanos((long) i - indexOfUserRecord);
lastAssignedConsenusTime = consensusNow;
builder.consensusTimestamp(consensusNow);
if (i > indexOfUserRecord && builder.category() != SCHEDULED) {
// Only set exchange rates on transactions preceding the user transaction, since
// no subsequent child can change the exchange rate
builder.parentConsensus(consensusTime).exchangeRate(null);
if (i > indexOfUserRecord) {
if (builder.category() != SCHEDULED) {
// Only set exchange rates on transactions preceding the user transaction, since
// no subsequent child can change the exchange rate
builder.parentConsensus(consensusTime).exchangeRate(null);
} else {
// But for backward compatibility keep setting rates on scheduled receipts, c.f.
// https://github.com/hashgraph/hedera-services/issues/15393
builder.exchangeRate(exchangeRates);
}
}
switch (streamMode) {
case RECORDS -> records.add(((RecordStreamBuilder) builder).build());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import com.hedera.node.app.authorization.AuthorizerInjectionModule;
import com.hedera.node.app.config.BootstrapConfigProviderImpl;
import com.hedera.node.app.config.ConfigProviderImpl;
import com.hedera.node.app.fees.ExchangeRateManager;
import com.hedera.node.app.service.contract.impl.ContractServiceImpl;
import com.hedera.node.app.service.file.impl.FileServiceImpl;
import com.hedera.node.app.services.ServicesInjectionModule;
Expand Down Expand Up @@ -81,5 +82,7 @@ interface Builder {

StateNetworkInfo stateNetworkInfo();

ExchangeRateManager exchangeRateManager();

StandaloneDispatchFactory standaloneDispatchFactory();
}
Original file line number Diff line number Diff line change
Expand Up @@ -52,11 +52,14 @@ public TransactionExecutor newExecutor(@NonNull final State state, @NonNull fina
final var executor = newExecutorComponent(properties);
executor.initializer().accept(state);
executor.stateNetworkInfo().initFrom(state);
final var exchangeRateManager = executor.exchangeRateManager();
return (transactionBody, consensusNow, operationTracers) -> {
final var dispatch = executor.standaloneDispatchFactory().newDispatch(state, transactionBody, consensusNow);
OPERATION_TRACERS.set(List.of(operationTracers));
executor.dispatchProcessor().processDispatch(dispatch);
return dispatch.stack().buildHandleOutput(consensusNow).recordsOrThrow();
return dispatch.stack()
.buildHandleOutput(consensusNow, exchangeRateManager.exchangeRates())
.recordsOrThrow();
};
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -329,7 +329,7 @@ public SingleTransactionRecord recordFrom(@NonNull final BlockTransactionParts p
if (followsUserRecord && !parts.transactionIdOrThrow().scheduled()) {
recordBuilder.parentConsensusTimestamp(asTimestamp(userTimestamp));
}
if (!followsUserRecord) {
if (!followsUserRecord || parts.transactionIdOrThrow().scheduled()) {
// Only preceding and user transactions get exchange rates in their receipts; note that
// auto-account creations are always preceding dispatches and so get exchange rates
receiptBuilder.exchangeRate(activeRates);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
import static java.util.Objects.requireNonNull;
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;

import com.esaulpaugh.headlong.abi.Function;
import com.hedera.node.app.spi.workflows.HandleContext.TransactionCategory;
Expand Down Expand Up @@ -455,6 +456,9 @@ private static void assertParentChildStructure(
withNonce(userTransactionID, nextExpectedNonce++ - postTriggeredOffset), following.txnId());
assertEquals(userConsensusTime, following.parentConsensusTimestamp());
}
if (following.txnId().getScheduled()) {
assertTrue(following.txnRecord().getReceipt().hasExchangeRate());
}
}
}

Expand Down

0 comments on commit 33a84b1

Please sign in to comment.