Skip to content

Commit

Permalink
Fix tx validation if sender has delegated it's code via 7702 transact…
Browse files Browse the repository at this point in the history
…ion (hyperledger#7593)

Signed-off-by: Daniel Lehrner <daniel.lehrner@consensys.net>
  • Loading branch information
daniellehrner authored Sep 10, 2024
1 parent 36454b4 commit 01fcc7f
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 18 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -175,29 +175,61 @@ public void shouldCheckNonceAfterNonceIncreaseOfSender() throws IOException {
besuNode.execute(ethTransactions.sendRawTransaction(tx.encoded().toHexString()));
testHelper.buildNewBlock();

Optional<TransactionReceipt> maybeTransactionReceipt =
final Optional<TransactionReceipt> maybeFirstTransactionReceipt =
besuNode.execute(ethTransactions.getTransactionReceipt(txHash));
assertThat(maybeTransactionReceipt).isPresent();
assertThat(maybeFirstTransactionReceipt).isPresent();

final String gasPriceWithout0x =
maybeTransactionReceipt.get().getEffectiveGasPrice().substring(2);
maybeFirstTransactionReceipt.get().getEffectiveGasPrice().substring(2);
final BigInteger gasPrice = new BigInteger(gasPriceWithout0x, 16);
final BigInteger txCost = maybeTransactionReceipt.get().getGasUsed().multiply(gasPrice);
final BigInteger txCost = maybeFirstTransactionReceipt.get().getGasUsed().multiply(gasPrice);

final BigInteger authorizerBalance = besuNode.execute(ethTransactions.getBalance(authorizer));
final BigInteger authorizerBalanceAfterFirstTx =
besuNode.execute(ethTransactions.getBalance(authorizer));

// The remaining balance of the authorizer should the gas limit multiplied by the gas price
// minus the transaction cost.
// The following executes this calculation in reverse.
assertThat(GAS_LIMIT).isEqualTo(authorizerBalance.add(txCost).divide(gasPrice).longValue());
assertThat(GAS_LIMIT)
.isEqualTo(authorizerBalanceAfterFirstTx.add(txCost).divide(gasPrice).longValue());

// The other accounts balance should be the initial 9000 ETH balance from the authorizer minus
// the remaining balance of the authorizer and minus the transaction cost
cluster.verify(
otherAccount.balanceEquals(
Amount.wei(
new BigInteger("90000000000000000000000")
.subtract(authorizerBalance)
.subtract(txCost))));
final BigInteger otherAccountBalanceAfterFirstTx =
new BigInteger("90000000000000000000000")
.subtract(authorizerBalanceAfterFirstTx)
.subtract(txCost);

cluster.verify(otherAccount.balanceEquals(Amount.wei(otherAccountBalanceAfterFirstTx)));

final Transaction txSendEthToOtherAccount =
Transaction.builder()
.type(TransactionType.EIP1559)
.chainId(BigInteger.valueOf(20211))
.nonce(2)
.maxPriorityFeePerGas(Wei.of(10))
.maxFeePerGas(Wei.of(100))
.gasLimit(21000)
.to(Address.fromHexStringStrict(otherAccount.getAddress()))
.value(Wei.ONE)
.payload(Bytes.EMPTY)
.signAndBuild(
secp256k1.createKeyPair(
secp256k1.createPrivateKey(AUTHORIZER_PRIVATE_KEY.toUnsignedBigInteger())));

final String txSendEthToOtherAccountHash =
besuNode.execute(
ethTransactions.sendRawTransaction(txSendEthToOtherAccount.encoded().toHexString()));
testHelper.buildNewBlock();

final Optional<TransactionReceipt> maybeSecondTransactionReceipt =
besuNode.execute(ethTransactions.getTransactionReceipt(txSendEthToOtherAccountHash));
assertThat(maybeSecondTransactionReceipt).isPresent();

// the balance of the other account should be the previous balance plus the value of the 1 Wei
final BigInteger otherAccountBalanceAfterSecondTx =
besuNode.execute(ethTransactions.getBalance(otherAccount));
assertThat(otherAccountBalanceAfterFirstTx.add(BigInteger.ONE))
.isEqualTo(otherAccountBalanceAfterSecondTx);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
import org.hyperledger.besu.ethereum.transaction.TransactionInvalidReason;
import org.hyperledger.besu.evm.account.Account;
import org.hyperledger.besu.evm.gascalculator.GasCalculator;
import org.hyperledger.besu.evm.worldstate.DelegatedCodeService;

import java.math.BigInteger;
import java.util.List;
Expand Down Expand Up @@ -305,7 +306,8 @@ public ValidationResult<TransactionInvalidReason> validateForSender(
}

private static boolean canSendTransaction(final Account sender, final Hash codeHash) {
return codeHash.equals(Hash.EMPTY) || sender.hasDelegatedCode();
return codeHash.equals(Hash.EMPTY)
|| DelegatedCodeService.hasDelegatedCode(sender.getUnprocessedCode());
}

private ValidationResult<TransactionInvalidReason> validateTransactionSignature(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,13 +85,19 @@ public MutableAccount processMutableAccount(
worldUpdater, account, resolveDelegatedAddress(account.getCode()));
}

private Address resolveDelegatedAddress(final Bytes code) {
return Address.wrap(code.slice(DELEGATED_CODE_PREFIX.size()));
}

private boolean hasDelegatedCode(final Bytes code) {
/**
* Returns if the provided code is delegated code.
*
* @param code the code to check.
* @return {@code true} if the code is delegated code, {@code false} otherwise.
*/
public static boolean hasDelegatedCode(final Bytes code) {
return code != null
&& code.size() == DELEGATED_CODE_SIZE
&& code.slice(0, DELEGATED_CODE_PREFIX.size()).equals(DELEGATED_CODE_PREFIX);
}

private Address resolveDelegatedAddress(final Bytes code) {
return Address.wrap(code.slice(DELEGATED_CODE_PREFIX.size()));
}
}

0 comments on commit 01fcc7f

Please sign in to comment.