Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(SELFDESTRUCT): deloyment number #1336

Merged
merged 10 commits into from
Oct 1, 2024
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,12 @@

package net.consensys.linea.zktracer.module.hub;

import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkState;
import static net.consensys.linea.zktracer.types.AddressUtils.isAddressWarm;

import java.util.Optional;

import com.google.common.base.Preconditions;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Setter;
Expand Down Expand Up @@ -141,9 +142,17 @@ public AccountSnapshot deepCopy() {
address, nonce, balance, isWarm, code, deploymentNumber, deploymentStatus);
}

public AccountSnapshot wipe() {
public AccountSnapshot wipe(DeploymentInfo deploymentInfo) {
final boolean deploymentStatus = deploymentInfo.getDeploymentStatus(address);
checkArgument(!deploymentStatus);
return new AccountSnapshot(
address, 0, Wei.of(0), isWarm, Bytecode.EMPTY, deploymentNumber + 1, false);
address,
0,
Wei.of(0),
isWarm,
Bytecode.EMPTY,
deploymentInfo.deploymentNumber(address),
deploymentStatus);
}

/**
Expand All @@ -154,7 +163,7 @@ public AccountSnapshot wipe() {
* @return {@code this} with decremented balance
*/
public AccountSnapshot decrementBalanceBy(Wei quantity) {
Preconditions.checkState(
checkState(
balance.greaterOrEqualThan(quantity),
"Insufficient balance"
+ String.format("\n\t\tAddress: %s", address)
Expand Down Expand Up @@ -223,14 +232,13 @@ public AccountSnapshot raiseNonceByOne() {
}

public AccountSnapshot setDeploymentInfo(DeploymentInfo deploymentInfo) {
this.deploymentNumber(deploymentInfo.deploymentNumber(address));
this.deploymentStatus(deploymentInfo.getDeploymentStatus(address));
deploymentNumber(deploymentInfo.deploymentNumber(address));
deploymentStatus(deploymentInfo.getDeploymentStatus(address));
return this;
}

public AccountSnapshot deployByteCode(Bytecode code) {
Preconditions.checkState(
deploymentStatus, "Deployment status should be true before deploying byte code.");
checkState(deploymentStatus, "Deployment status should be true before deploying byte code.");

return new AccountSnapshot(address, nonce, balance, true, code, deploymentNumber, false);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -502,20 +502,27 @@ public void traceStartTransaction(final WorldView world, final Transaction tx) {
state.enter();
txStack.enterTransaction(world, tx, transients.block());

final TransactionProcessingMetadata transactionProcessingMetadata = txStack.current();

this.enterTransaction();

if (!txStack.current().requiresEvmExecution()) {
if (!transactionProcessingMetadata.requiresEvmExecution()) {
state.setProcessingPhase(TX_SKIP);
new TxSkippedSection(this, world, txStack.current(), transients);
new TxSkippedSection(this, world, transactionProcessingMetadata, transients);
} else {
if (txStack.current().requiresPrewarming()) {
if (transactionProcessingMetadata.requiresPrewarming()) {
state.setProcessingPhase(TX_WARM);
new TxPreWarmingMacroSection(world, this);
}
state.setProcessingPhase(TX_INIT);
new TxInitializationSection(this, world);
}

// Note: for deployment transactions the deployment number / status were updated during the
OlivierBBB marked this conversation as resolved.
Show resolved Hide resolved
// initialization phase. We are thus capturing the respective XXX_NEW's
transactionProcessingMetadata
.captureUpdatedInitialRecipientAddressDeploymentInfoAtTransactionStart(this);

/*
* TODO: the ID = 0 (universal parent context) context should
* 1. be shared by all transactions in a conflation (OK)
Expand All @@ -525,7 +532,7 @@ public void traceStartTransaction(final WorldView world, final Transaction tx) {
callStack.getById(0).universalParentReturnDataContextNumber(this.stamp() + 1);

for (Module m : modules) {
m.traceStartTx(world, txStack.current());
m.traceStartTx(world, transactionProcessingMetadata);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,22 +27,22 @@

@Getter
public class TransactionStack implements StackedContainer {
private final List<TransactionProcessingMetadata> txs =
private final List<TransactionProcessingMetadata> transactions =
new ArrayList<>(200); // TODO: write the allocated memory from .toml file
private int currentAbsNumber;
private int relativeTransactionNumber;

public TransactionProcessingMetadata current() {
return txs.getLast();
return transactions.getLast();
}

/* WARN: can't be called if currentAbsNumber == 1*/
public TransactionProcessingMetadata previous() {
return this.txs.get(this.txs.size() - 2);
return this.transactions.get(this.transactions.size() - 2);
}

public TransactionProcessingMetadata getByAbsoluteTransactionNumber(final int id) {
return this.txs.get(id - 1);
return this.transactions.get(id - 1);
}

@Override
Expand All @@ -53,7 +53,7 @@ public void enter() {

@Override
public void pop() {
this.txs.remove(this.current());
this.transactions.remove(this.current());
this.currentAbsNumber -= 1;
this.relativeTransactionNumber -= 1;
}
Expand All @@ -69,13 +69,19 @@ public void enterTransaction(final WorldView world, final Transaction tx, Block
new TransactionProcessingMetadata(
world, tx, block, relativeTransactionNumber, currentAbsNumber);

this.txs.add(newTx);
transactions.add(newTx);
}

// @françois what replaces this for message calls to smart contracts ?
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand your question. Why do you want to store the CFI of the smart contract recipient of the tx ? We compute it in the recipient AccountFragment. For the moment, the only place where we read the CFI of a deployment transaction is in TXN_DATA, this is strange ...

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do you want to store the CFI of the smart contract recipient of the tx ?

Because the traces require it. The question is when/where does it get computed.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we do it at traceStartTx in the RomLex so this is ok, already done. We can delete the comment, as this method just set the CFI of the initCode in the TransactionProcessingMetadata. It is read only by TXN_DATA for the moment.

public void setCodeFragmentIndex(Hub hub) {
for (TransactionProcessingMetadata tx : this.txs) {
for (TransactionProcessingMetadata tx : transactions) {
final int cfi =
tx.requiresCfiUpdate() ? hub.getCfiByMetaData(tx.getEffectiveRecipient(), 1, true) : 0;
tx.requiresCfiUpdate()
? hub.getCfiByMetaData(
tx.getEffectiveRecipient(),
tx.getUpdatedRecipientAddressDeploymentNumberAtTransactionStart(),
tx.isUpdatedRecipientAddressDeploymentStatusAtTransactionStart())
: 0;
tx.setCodeFragmentIndex(cfi);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@
import net.consensys.linea.zktracer.module.hub.fragment.scenario.SelfdestructScenarioFragment;
import net.consensys.linea.zktracer.module.hub.section.TraceSection;
import net.consensys.linea.zktracer.module.hub.signals.Exceptions;
import net.consensys.linea.zktracer.module.hub.transients.DeploymentInfo;
import net.consensys.linea.zktracer.runtime.callstack.CallFrame;
import net.consensys.linea.zktracer.types.TransactionProcessingMetadata;
import net.consensys.linea.zktracer.types.TransactionProcessingMetadata.AttemptedSelfDestruct;
Expand Down Expand Up @@ -246,9 +245,9 @@ public void resolvePostTransaction(
return;
}

Map<EphemeralAccount, Integer> effectiveSelfDestructMap =
final Map<EphemeralAccount, Integer> effectiveSelfDestructMap =
transactionProcessingMetadata.getEffectiveSelfDestructMap();
EphemeralAccount ephemeralAccount =
final EphemeralAccount ephemeralAccount =
new EphemeralAccount(
addressWhichMaySelfDestruct, selfdestructorAccountAfter.deploymentNumber());

Expand All @@ -260,7 +259,7 @@ public void resolvePostTransaction(

checkArgument(hubStamp >= selfDestructTime);

AccountSnapshot accountBeforeSelfDestruct =
final AccountSnapshot accountBeforeSelfDestruct =
transactionProcessingMetadata.getDestructedAccountsSnapshot().stream()
.filter(
accountSnapshot -> accountSnapshot.address().equals(addressWhichMaySelfDestruct))
Expand All @@ -272,17 +271,18 @@ public void resolvePostTransaction(
SelfdestructScenarioFragment.SelfdestructScenario
.SELFDESTRUCT_WONT_REVERT_NOT_YET_MARKED);

AccountFragment accountWipingFragment =
// the hub's defers.resolvePostTransaction() gets called after the
// hub's completeLineaTransaction which in turn calls
// freshDeploymentNumberFinishingSelfdestruct()
// which raises the deployment number and sets the deployment status to false
final AccountFragment accountWipingFragment =
hub.factories()
.accountFragment()
.make(
accountBeforeSelfDestruct,
selfdestructorAccountAfter.wipe(),
selfdestructorAccountAfter.wipe(hub.transients().conflation().deploymentInfo()),
DomSubStampsSubFragment.selfdestructDomSubStamps(hub));

final DeploymentInfo deploymentInfo = hub.transients().conflation().deploymentInfo();
deploymentInfo.freshDeploymentNumberFinishingSelfdestruct(addressWhichMaySelfDestruct);

this.addFragment(accountWipingFragment);
} else {
selfdestructScenarioFragment.setScenario(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import static com.google.common.base.Preconditions.*;
import static net.consensys.linea.zktracer.module.constants.GlobalConstants.LLARGE;
import static net.consensys.linea.zktracer.opcode.OpCode.*;
import static net.consensys.linea.zktracer.runtime.callstack.CallFrame.getOpCode;
import static net.consensys.linea.zktracer.types.AddressUtils.getDeploymentAddress;
import static net.consensys.linea.zktracer.types.AddressUtils.highPart;
import static net.consensys.linea.zktracer.types.AddressUtils.lowPart;
Expand Down Expand Up @@ -130,7 +131,7 @@ public void traceStartTx(WorldView worldView, TransactionProcessingMetadata txMe
final Address deploymentAddress = Address.contractAddress(tx.getSender(), tx.getNonce());
final RomOperation operation =
new RomOperation(
ContractMetadata.make(deploymentAddress, 1, true), false, false, tx.getInit().get());
ContractMetadata.canonical(hub, deploymentAddress), false, false, tx.getInit().get());

operations.add(operation);
}
Expand Down Expand Up @@ -238,6 +239,9 @@ public void callRomLex(final MessageFrame frame) {
}
});
}

default -> throw new RuntimeException(
String.format("%s does not trigger the creation of ROM_LEX", getOpCode(frame)));
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ public class TransactionProcessingMetadata {
final long baseFee;

final boolean isDeployment;
int updatedRecipientAddressDeploymentNumberAtTransactionStart;
boolean updatedRecipientAddressDeploymentStatusAtTransactionStart;

@Accessors(fluent = true)
final boolean requiresEvmExecution;
Expand Down Expand Up @@ -132,32 +134,32 @@ public TransactionProcessingMetadata(
final int relativeTransactionNumber,
final int absoluteTransactionNumber) {
this.absoluteTransactionNumber = absoluteTransactionNumber;
this.relativeBlockNumber = block.blockNumber();
this.coinbase = block.coinbaseAddress();
this.baseFee = block.baseFee().toLong();
relativeBlockNumber = block.blockNumber();
coinbase = block.coinbaseAddress();
baseFee = block.baseFee().toLong();

this.besuTransaction = transaction;
besuTransaction = transaction;
this.relativeTransactionNumber = relativeTransactionNumber;

this.isDeployment = transaction.getTo().isEmpty();
this.requiresEvmExecution = computeRequiresEvmExecution(world);
this.copyTransactionCallData = computeCopyCallData();
isDeployment = transaction.getTo().isEmpty();
requiresEvmExecution = computeRequiresEvmExecution(world);
copyTransactionCallData = computeCopyCallData();

this.initialBalance = getInitialBalance(world);
initialBalance = getInitialBalance(world);

// Note: Besu's dataCost computation contains
// - the 21_000 transaction cost (we deduce it)
// - the contract creation cost in case of deployment (we set deployment to false to not add it)
this.dataCost =
dataCost =
ZkTracer.gasCalculator.transactionIntrinsicGasCost(besuTransaction.getPayload(), false)
- GAS_CONST_G_TRANSACTION;
this.accessListCost =
accessListCost =
besuTransaction.getAccessList().map(ZkTracer.gasCalculator::accessListGasCost).orElse(0L);
this.initiallyAvailableGas = getInitiallyAvailableGas();
initiallyAvailableGas = getInitiallyAvailableGas();

this.effectiveRecipient = effectiveToAddress(besuTransaction);
effectiveRecipient = effectiveToAddress(besuTransaction);

this.effectiveGasPrice = computeEffectiveGasPrice();
effectiveGasPrice = computeEffectiveGasPrice();
}

public void setPreFinalisationValues(
Expand Down Expand Up @@ -324,4 +326,11 @@ private void determineSelfDestructTimeStamp() {
}
}
}

public void captureUpdatedInitialRecipientAddressDeploymentInfoAtTransactionStart(Hub hub) {
updatedRecipientAddressDeploymentNumberAtTransactionStart =
hub.deploymentNumberOf(effectiveRecipient);
updatedRecipientAddressDeploymentStatusAtTransactionStart =
hub.deploymentStatusOf(effectiveRecipient);
}
}
Loading