Skip to content

Commit

Permalink
feat: address account nonce discrepancies mono (#11045)
Browse files Browse the repository at this point in the history
Signed-off-by: nikolay <n.atanasow94@gmail.com>
Signed-off-by: Ivo Yankov <ivo@devlabs.bg>
Co-authored-by: Ivo Yankov <ivo@devlabs.bg>
  • Loading branch information
natanasow and Ivo-Yankov committed Feb 8, 2024
1 parent a71e2fb commit 77d207f
Show file tree
Hide file tree
Showing 64 changed files with 1,283 additions and 46 deletions.
Expand Up @@ -117,7 +117,7 @@ protected TransactionProcessingResult execute(

super.setupFields(payload, contractCreation);

final var chargingResult = chargeForGas(
final var chargingResult = chargeForGasAndIncrementEthereumNonce(
gasCost,
upfrontCost,
value,
Expand Down Expand Up @@ -247,7 +247,7 @@ private void sendToCoinbase(
mutableCoinbase.incrementBalance(Wei.of(amount * gasPrice));
}

private ChargingResult chargeForGas(
private ChargingResult chargeForGasAndIncrementEthereumNonce(
final Wei gasCost,
final Wei upfrontCost,
final long value,
Expand Down Expand Up @@ -308,7 +308,14 @@ private ChargingResult chargeForGas(
final var senderCanAffordValue = senderAccount.getBalance().compareTo(Wei.of(value)) >= 0;
validateTrue(senderCanAffordValue, INSUFFICIENT_PAYER_BALANCE);
}

// increment sender's ethereum nonce right after all checks
// and before entering the evm for non-static calls
if (relayer != null) {
senderAccount.incrementNonce();
}
}

return new ChargingResult(senderAccount, mutableRelayer, allowanceCharged);
}

Expand All @@ -325,7 +332,7 @@ private void handleResourceLimitExceeded(
final Wei upfrontCost) {
// Consume all gas on resource exhaustion, using a clean updater
final var feesOnlyUpdater = (HederaWorldState.Updater) worldState.updater();
chargeForGas(
chargeForGasAndIncrementEthereumNonce(
gasCost,
upfrontCost,
value,
Expand Down
Expand Up @@ -43,6 +43,7 @@ public class TransactionProcessingResult extends HederaEvmTransactionProcessingR

private List<ContractID> createdContracts = Collections.emptyList();
private Map<ContractID, Long> contractNonces = new TreeMap<>();
private Long signerNonce;

public static TransactionProcessingResult failed(
final long gasUsed,
Expand Down Expand Up @@ -143,6 +144,14 @@ public void setActions(final List<SolidityAction> actions) {
this.actions = actions;
}

public Long getSignerNonce() {
return signerNonce;
}

public void setSignerNonce(Long signerNonce) {
this.signerNonce = signerNonce;
}

/**
* Converts the {@link TransactionProcessingResult} into {@link ContractFunctionResult} gRPC
* model.
Expand Down
Expand Up @@ -19,6 +19,7 @@
import com.hedera.node.app.service.mono.legacy.core.jproto.JKey;
import com.hedera.node.app.service.mono.legacy.core.jproto.JKeySerializer;
import com.swirlds.common.io.SelfSerializable;
import com.swirlds.common.io.streams.AugmentedDataInputStream;
import com.swirlds.common.io.streams.SerializableDataInputStream;
import com.swirlds.common.io.streams.SerializableDataOutputStream;
import edu.umd.cs.findbugs.annotations.Nullable;
Expand All @@ -41,6 +42,16 @@ public static void writeNullableString(@Nullable final String msg, final Seriali
writeNullable(msg, out, (msgVal, outVal) -> outVal.writeNormalisedString(msgVal));
}

@Nullable
public static Long readNullableLong(final SerializableDataInputStream in) throws IOException {
return readNullable(in, AugmentedDataInputStream::readLong);
}

public static void writeNullableLong(@Nullable final Long num, final SerializableDataOutputStream out)
throws IOException {
writeNullable(num, out, (numVal, outVal) -> outVal.writeLong(numVal));
}

@Nullable
public static <T> T readNullable(final SerializableDataInputStream in, final IoReadingFunction<T> reader)
throws IOException {
Expand Down
Expand Up @@ -17,8 +17,10 @@
package com.hedera.node.app.service.mono.state.submerkle;

import static com.hedera.node.app.service.evm.accounts.HederaEvmContractAliases.isMirror;
import static com.hedera.node.app.service.mono.state.serdes.IoUtils.readNullableLong;
import static com.hedera.node.app.service.mono.state.serdes.IoUtils.readNullableSerializable;
import static com.hedera.node.app.service.mono.state.serdes.IoUtils.readNullableString;
import static com.hedera.node.app.service.mono.state.serdes.IoUtils.writeNullableLong;
import static com.hedera.node.app.service.mono.state.serdes.IoUtils.writeNullableSerializable;
import static com.hedera.node.app.service.mono.state.serdes.IoUtils.writeNullableString;
import static com.swirlds.common.utility.CommonUtils.hex;
Expand All @@ -27,6 +29,7 @@
import com.google.common.base.MoreObjects;
import com.google.protobuf.ByteString;
import com.google.protobuf.BytesValue;
import com.google.protobuf.Int64Value;
import com.hedera.node.app.hapi.utils.ethereum.EthTxData;
import com.hedera.node.app.service.mono.contracts.execution.TransactionProcessingResult;
import com.hederahashgraph.api.proto.java.ContractFunctionResult;
Expand Down Expand Up @@ -54,7 +57,8 @@ public class EvmFnResult implements SelfSerializable {
static final int RELEASE_0260_VERSION = 5;
static final int RELEASE_0290_VERSION = 6;
static final int RELEASE_0400_VERSION = 7;
static final int CURRENT_VERSION = RELEASE_0400_VERSION;
static final int RELEASE_0470_VERSION = 8;
static final int CURRENT_VERSION = RELEASE_0470_VERSION;

static final long RUNTIME_CONSTRUCTABLE_ID = 0x2055c5c03ff84eb4L;

Expand All @@ -79,6 +83,7 @@ public class EvmFnResult implements SelfSerializable {
private long amount;
private byte[] functionParameters = EMPTY;
private EntityId senderId;
private Long signerNonce;

public EvmFnResult() {
// RuntimeConstructable
Expand All @@ -105,12 +110,13 @@ private static EvmFnResult from(final TransactionProcessingResult result, final
recipient,
serializableIdsFrom(result.getCreatedContracts()),
serializableContractNoncesFrom(result.getContractNonces()),
evmAddress);
evmAddress,
result.getSignerNonce());
} else {
final var error = result.getRevertReason()
.map(Object::toString)
.orElse(result.getHaltReason().map(Object::toString).orElse(null));
return failure(result.getGasUsed(), error);
return failure(result.getGasUsed(), error, result.getSignerNonce());
}
}

Expand All @@ -127,7 +133,8 @@ public EvmFnResult(
final long gas,
final long amount,
final byte[] functionParameters,
final EntityId senderId) {
final EntityId senderId,
final Long signerNonce) {
this.contractId = contractId;
this.result = result;
this.error = error;
Expand All @@ -141,6 +148,7 @@ public EvmFnResult(
this.amount = amount;
this.functionParameters = functionParameters;
this.senderId = senderId;
this.signerNonce = signerNonce;
}

/* --- SelfSerializable --- */
Expand Down Expand Up @@ -197,6 +205,9 @@ public void deserialize(final SerializableDataInputStream in, final int version)
if (version >= RELEASE_0400_VERSION) {
contractNonces = in.readSerializableList(MAX_CREATED_CONTRACT_NONCES, true, ContractNonceInfo::new);
}
if (version >= RELEASE_0470_VERSION) {
signerNonce = readNullableLong(in);
}
}

@Override
Expand All @@ -214,6 +225,7 @@ public void serialize(final SerializableDataOutputStream out) throws IOException
out.writeByteArray(functionParameters);
writeNullableSerializable(senderId, out);
out.writeSerializableList(contractNonces, true, true);
writeNullableLong(signerNonce, out);
}

/* --- Object --- */
Expand All @@ -238,7 +250,8 @@ public boolean equals(final Object o) {
&& gas == that.gas
&& amount == that.amount
&& Arrays.equals(functionParameters, that.functionParameters)
&& Objects.equals(senderId, that.senderId);
&& Objects.equals(senderId, that.senderId)
&& Objects.equals(signerNonce, that.signerNonce);
}

@Override
Expand All @@ -265,6 +278,7 @@ public String toString() {
.add("amount", amount)
.add("functionParameters", hex(functionParameters))
.add("senderId", senderId)
.add("signerNonce", signerNonce)
.toString();
}

Expand Down Expand Up @@ -325,6 +339,10 @@ public EntityId getSenderId() {
return senderId;
}

public Long getSignerNonce() {
return signerNonce;
}

public void setEvmAddress(final byte[] evmAddress) {
this.evmAddress = evmAddress;
}
Expand All @@ -345,6 +363,10 @@ public void setSenderId(final EntityId senderId) {
this.senderId = senderId;
}

public void setSignerNonce(Long signerNonce) {
this.signerNonce = signerNonce;
}

public void setContractNonces(List<ContractNonceInfo> contractNonces) {
this.contractNonces = contractNonces;
}
Expand Down Expand Up @@ -391,6 +413,9 @@ public ContractFunctionResult toGrpc() {
if (senderId != null) {
grpc.setSenderId(senderId.toGrpcAccountId());
}
if (signerNonce != null) {
grpc.setSignerNonce(Int64Value.newBuilder().setValue(signerNonce).build());
}
return grpc.build();
}

Expand Down Expand Up @@ -433,7 +458,8 @@ private static EvmFnResult success(
final Address recipient,
final List<EntityId> createdContractIds,
final List<ContractNonceInfo> contractNonces,
final byte[] evmAddress) {
final byte[] evmAddress,
final Long signerNonce) {
return new EvmFnResult(
isMirror(recipient.toArray()) ? EntityId.fromAddress(recipient) : null,
output.toArrayUnsafe(),
Expand All @@ -447,10 +473,11 @@ private static EvmFnResult success(
0L,
0L,
EMPTY,
null);
null,
signerNonce);
}

private static EvmFnResult failure(final long gasUsed, final String error) {
private static EvmFnResult failure(final long gasUsed, final String error, final Long signerNonce) {
return new EvmFnResult(
null,
EMPTY,
Expand All @@ -464,6 +491,7 @@ private static EvmFnResult failure(final long gasUsed, final String error) {
0L,
0L,
EMPTY,
null);
null,
signerNonce);
}
}
Expand Up @@ -78,7 +78,8 @@ public class ExpirableTxnRecord implements FastCopyable, SerializableHashable {
static final int RELEASE_0280_VERSION = 11;
// Debatable -- 0.33/0.34?
static final int RELEASE_0340_VERSION = 12;
static final int CURRENT_VERSION = RELEASE_0340_VERSION;
static final int RELEASE_0470_VERSION = 13;
static final int CURRENT_VERSION = RELEASE_0470_VERSION;
static final long RUNTIME_CONSTRUCTABLE_ID = 0x8b9ede7ca8d8db93L;

static final int MAX_MEMO_BYTES = 32 * 1_024;
Expand Down
Expand Up @@ -57,7 +57,8 @@ public static void addContractCallResultToRecord(
traceabilityOn ? messageFrame.getRemainingGas() : 0L,
traceabilityOn ? messageFrame.getValue().toLong() : 0L,
traceabilityOn ? messageFrame.getInputData().toArrayUnsafe() : EvmFnResult.EMPTY,
EntityId.fromAddress(senderAddress));
EntityId.fromAddress(senderAddress),
null);
childRecord.setContractCallResult(evmFnResult);
}
}
Expand Down
Expand Up @@ -158,9 +158,6 @@ public void doStateTransitionOperation(
result = evmTxProcessor.execute(
sender, receiver.canonicalAddress(), op.getGas(), op.getAmount(), callData, txnCtx.consensusTime());
} else {
sender.incrementEthereumNonce();
accountStore.commitAccount(sender);

result = evmTxProcessor.executeEth(
sender,
receiver.canonicalAddress(),
Expand All @@ -171,6 +168,7 @@ public void doStateTransitionOperation(
offeredGasPrice,
accountStore.loadAccount(relayerId),
maxGasAllowanceInTinybars);
result.setSignerNonce(worldState.get(senderId.asEvmAddress()).getNonce());
}

/* --- Externalise result --- */
Expand Down
Expand Up @@ -211,9 +211,6 @@ public void doStateTransitionOperation(
codeWithConstructorArgs,
consensusTime);
} else {
sender.incrementEthereumNonce();
accountStore.commitAccount(sender);

result = evmTxProcessor.executeEth(
sender,
newContractAddress,
Expand All @@ -224,6 +221,7 @@ public void doStateTransitionOperation(
accountStore.loadAccount(relayerId),
userOfferedGasPrice,
maxGasAllowance);
result.setSignerNonce(worldState.get(senderId.asEvmAddress()).getNonce());
}
} finally {
worldState.resetHapiSenderCustomizer();
Expand Down
Expand Up @@ -134,6 +134,7 @@ public void doStateTransition() {
} catch (InvalidTransactionException e) {
var result = TransactionProcessingResult.failed(
0, 0, 0, Optional.of(e.messageBytes()), Optional.empty(), Collections.emptyMap(), List.of());
result.setSignerNonce((Long) accountsLedger.get(callerNum.toGrpcAccountId(), ETHEREUM_NONCE));
recordService.externaliseEvmCallTransaction(result);
throw e;
} finally {
Expand Down
Expand Up @@ -54,6 +54,9 @@ protected EvmFnResult getExpectedObject(
// Always empty before 0.40
seeded.setContractNonces(Collections.emptyList());
}
if (version < EvmFnResult.RELEASE_0470_VERSION) {
seeded.setSignerNonce(null);
}
return seeded;
}

Expand Down

0 comments on commit 77d207f

Please sign in to comment.