Pectra devnet 5: 7702 changes (#8118)

* first draft for 7702 changes for pectra-devnet5

Signed-off-by: Daniel Lehrner <daniel.lehrner@consensys.net>

* spotless, javadoc

Signed-off-by: Daniel Lehrner <daniel.lehrner@consensys.net>

* fixed get code in call operations

Signed-off-by: Daniel Lehrner <daniel.lehrner@consensys.net>

* allow code delegation chain id to be up to 2^256-1

Signed-off-by: Daniel Lehrner <daniel.lehrner@consensys.net>

* set code for delegated accounts correctly in the initialFrame of the tx processing

Signed-off-by: Daniel Lehrner <daniel.lehrner@consensys.net>

* delegated accounts return empty bytes for the code if the target does not exist

Signed-off-by: Daniel Lehrner <daniel.lehrner@consensys.net>

---------

Signed-off-by: Daniel Lehrner <daniel.lehrner@consensys.net>
Co-authored-by: Simon Dudley <simon.dudley@consensys.net>
This commit is contained in:
daniellehrner
2025-01-16 07:20:20 +01:00
committed by GitHub
parent 479bec0310
commit b5fdcc096f
15 changed files with 215 additions and 179 deletions

View File

@@ -16,7 +16,6 @@ package org.hyperledger.besu.evm.account;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.datatypes.Wei;
import org.hyperledger.besu.evm.gascalculator.GasCalculator;
import org.hyperledger.besu.evm.worldstate.WorldUpdater;
@@ -24,14 +23,14 @@ import java.util.Optional;
import org.apache.tuweni.bytes.Bytes;
class BaseDelegatedCodeAccount {
abstract class AbstractDelegatedCodeAccount implements Account {
private final WorldUpdater worldUpdater;
private final GasCalculator gasCalculator;
/** The address of the account that has delegated code to be loaded into it. */
protected final Address delegatedCodeAddress;
protected BaseDelegatedCodeAccount(
protected AbstractDelegatedCodeAccount(
final WorldUpdater worldUpdater,
final Address delegatedCodeAddress,
final GasCalculator gasCalculator) {
@@ -45,7 +44,8 @@ class BaseDelegatedCodeAccount {
*
* @return the delegated code.
*/
protected Bytes getCode() {
@Override
public Optional<Bytes> getDelegatedCode() {
return resolveDelegatedCode();
}
@@ -54,27 +54,9 @@ class BaseDelegatedCodeAccount {
*
* @return the hash of the delegated code.
*/
protected Hash getCodeHash() {
final Bytes code = getCode();
return (code == null || code.isEmpty()) ? Hash.EMPTY : Hash.hash(code);
}
/**
* Returns the balance of the delegated account.
*
* @return the balance of the delegated account.
*/
protected Wei getDelegatedBalance() {
return getDelegatedAccount().map(Account::getBalance).orElse(Wei.ZERO);
}
/**
* Returns the nonce of the delegated account.
*
* @return the nonce of the delegated account.
*/
protected long getDelegatedNonce() {
return getDelegatedAccount().map(Account::getNonce).orElse(Account.DEFAULT_NONCE);
@Override
public Optional<Hash> getDelegatedCodeHash() {
return getDelegatedCode().map(Hash::hash);
}
/**
@@ -82,19 +64,27 @@ class BaseDelegatedCodeAccount {
*
* @return the address of the delegated code.
*/
protected Optional<Address> delegatedCodeAddress() {
@Override
public Optional<Address> delegatedCodeAddress() {
return Optional.of(delegatedCodeAddress);
}
@Override
public boolean hasDelegatedCode() {
return true;
}
private Optional<Account> getDelegatedAccount() {
return Optional.ofNullable(worldUpdater.getAccount(delegatedCodeAddress));
}
private Bytes resolveDelegatedCode() {
if (gasCalculator.isPrecompile(delegatedCodeAddress)) {
return Bytes.EMPTY;
private Optional<Bytes> resolveDelegatedCode() {
final Optional<Account> maybeDelegatedAccount = getDelegatedAccount();
if (gasCalculator.isPrecompile(delegatedCodeAddress) || maybeDelegatedAccount.isEmpty()) {
return Optional.of(Bytes.EMPTY);
}
return getDelegatedAccount().map(Account::getUnprocessedCode).orElse(Bytes.EMPTY);
return Optional.of(maybeDelegatedAccount.get().getCode());
}
}

View File

@@ -19,8 +19,6 @@ import org.hyperledger.besu.datatypes.Wei;
import java.util.Optional;
import org.apache.tuweni.bytes.Bytes;
/**
* A world state account.
*
@@ -71,13 +69,4 @@ public interface Account extends AccountState {
default boolean hasDelegatedCode() {
return false;
}
/**
* Returns the code as it is stored in the trie even if it's a delegated code account.
*
* @return the code as it is stored in the trie.
*/
default Bytes getUnprocessedCode() {
return getCode();
}
}

View File

@@ -18,6 +18,7 @@ import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.datatypes.Wei;
import java.util.NavigableMap;
import java.util.Optional;
import org.apache.tuweni.bytes.Bytes;
import org.apache.tuweni.bytes.Bytes32;
@@ -74,6 +75,15 @@ public interface AccountState {
*/
Bytes getCode();
/**
* The optional EVM bytecode if the account has set a 7702 code delegation.
*
* @return the delegated code (which may be empty).
*/
default Optional<Bytes> getDelegatedCode() {
return Optional.empty();
}
/**
* The hash of the EVM bytecode associated with this account.
*
@@ -81,6 +91,15 @@ public interface AccountState {
*/
Hash getCodeHash();
/**
* The optional hash of the delegated EVM bytecode if the account has set a 7702 code delegation.
*
* @return the hash of the delegated code (which may be empty).
*/
default Optional<Hash> getDelegatedCodeHash() {
return Optional.empty();
}
/**
* Whether the account has (non empty) EVM bytecode associated to it.
*

View File

@@ -28,7 +28,7 @@ import org.apache.tuweni.bytes.Bytes32;
import org.apache.tuweni.units.bigints.UInt256;
/** Wraps an EOA account and includes delegated code to be run on behalf of it. */
public class DelegatedCodeAccount extends BaseDelegatedCodeAccount implements Account {
public class DelegatedCodeAccount extends AbstractDelegatedCodeAccount implements Account {
private final Account wrappedAccount;
@@ -81,17 +81,12 @@ public class DelegatedCodeAccount extends BaseDelegatedCodeAccount implements Ac
@Override
public Bytes getCode() {
return super.getCode();
}
@Override
public Bytes getUnprocessedCode() {
return wrappedAccount.getCode();
}
@Override
public Hash getCodeHash() {
return super.getCodeHash();
return wrappedAccount.getCodeHash();
}
@Override
@@ -106,7 +101,7 @@ public class DelegatedCodeAccount extends BaseDelegatedCodeAccount implements Ac
@Override
public boolean isEmpty() {
return getDelegatedNonce() == 0 && getDelegatedBalance().isZero() && !hasCode();
return wrappedAccount.isEmpty();
}
@Override
@@ -119,9 +114,4 @@ public class DelegatedCodeAccount extends BaseDelegatedCodeAccount implements Ac
final Bytes32 startKeyHash, final int limit) {
return wrappedAccount.storageEntriesFrom(startKeyHash, limit);
}
@Override
public boolean hasDelegatedCode() {
return true;
}
}

View File

@@ -29,7 +29,7 @@ import org.apache.tuweni.bytes.Bytes32;
import org.apache.tuweni.units.bigints.UInt256;
/** Wraps an EOA account and includes delegated code to be run on behalf of it. */
public class MutableDelegatedCodeAccount extends BaseDelegatedCodeAccount
public class MutableDelegatedCodeAccount extends AbstractDelegatedCodeAccount
implements MutableAccount {
private final MutableAccount wrappedAccount;
@@ -83,17 +83,12 @@ public class MutableDelegatedCodeAccount extends BaseDelegatedCodeAccount
@Override
public Bytes getCode() {
return super.getCode();
}
@Override
public Bytes getUnprocessedCode() {
return wrappedAccount.getCode();
}
@Override
public Hash getCodeHash() {
return super.getCodeHash();
return wrappedAccount.getCodeHash();
}
@Override
@@ -108,7 +103,7 @@ public class MutableDelegatedCodeAccount extends BaseDelegatedCodeAccount
@Override
public boolean isEmpty() {
return getDelegatedNonce() == 0 && getDelegatedBalance().isZero() && !hasCode();
return wrappedAccount.isEmpty();
}
@Override
@@ -156,9 +151,4 @@ public class MutableDelegatedCodeAccount extends BaseDelegatedCodeAccount
public void becomeImmutable() {
wrappedAccount.becomeImmutable();
}
@Override
public boolean hasDelegatedCode() {
return true;
}
}

View File

@@ -15,7 +15,6 @@
package org.hyperledger.besu.evm.operation;
import static org.hyperledger.besu.evm.internal.Words.clampedToLong;
import static org.hyperledger.besu.evm.worldstate.DelegatedCodeGasCostHelper.deductDelegatedCodeGasCost;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.Wei;
@@ -192,13 +191,24 @@ public abstract class AbstractCallOperation extends AbstractOperation {
final Account contract = frame.getWorldUpdater().get(to);
if (contract != null) {
final DelegatedCodeGasCostHelper.Result result =
deductDelegatedCodeGasCost(frame, gasCalculator(), contract);
if (result.status() != DelegatedCodeGasCostHelper.Status.SUCCESS) {
return new Operation.OperationResult(
result.gasCost(), ExceptionalHaltReason.INSUFFICIENT_GAS);
if (contract != null && contract.hasDelegatedCode()) {
if (contract.getDelegatedCode().isEmpty()) {
throw new RuntimeException("A delegated code account must have delegated code");
}
if (contract.getDelegatedCodeHash().isEmpty()) {
throw new RuntimeException("A delegated code account must have a delegated code hash");
}
final long delegatedCodeResolutionGas =
DelegatedCodeGasCostHelper.delegatedCodeGasCost(frame, gasCalculator(), contract);
if (frame.getRemainingGas() < delegatedCodeResolutionGas) {
return new Operation.OperationResult(
delegatedCodeResolutionGas, ExceptionalHaltReason.INSUFFICIENT_GAS);
}
frame.decrementRemainingGas(delegatedCodeResolutionGas);
}
final Account account = frame.getWorldUpdater().get(frame.getRecipientAddress());
@@ -218,10 +228,7 @@ public abstract class AbstractCallOperation extends AbstractOperation {
final Bytes inputData = frame.readMutableMemory(inputDataOffset(frame), inputDataLength(frame));
final Code code =
contract == null
? CodeV0.EMPTY_CODE
: evm.getCode(contract.getCodeHash(), contract.getCode());
final Code code = getCode(evm, contract);
// invalid code results in a quick exit
if (!code.isValid()) {
@@ -337,4 +344,23 @@ public abstract class AbstractCallOperation extends AbstractOperation {
return LEGACY_FAILURE_STACK_ITEM;
}
}
/**
* Gets the code from the contract or EOA with delegated code.
*
* @param evm the evm
* @param account the account which needs to be retrieved
* @return the code
*/
protected static Code getCode(final EVM evm, final Account account) {
if (account == null) {
return CodeV0.EMPTY_CODE;
}
if (account.hasDelegatedCode()) {
return evm.getCode(account.getDelegatedCodeHash().get(), account.getDelegatedCode().get());
}
return evm.getCode(account.getCodeHash(), account.getCode());
}
}

View File

@@ -15,14 +15,12 @@
package org.hyperledger.besu.evm.operation;
import static org.hyperledger.besu.evm.internal.Words.clampedAdd;
import static org.hyperledger.besu.evm.worldstate.DelegatedCodeGasCostHelper.deductDelegatedCodeGasCost;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.Wei;
import org.hyperledger.besu.evm.Code;
import org.hyperledger.besu.evm.EVM;
import org.hyperledger.besu.evm.account.Account;
import org.hyperledger.besu.evm.code.CodeV0;
import org.hyperledger.besu.evm.frame.ExceptionalHaltReason;
import org.hyperledger.besu.evm.frame.MessageFrame;
import org.hyperledger.besu.evm.gascalculator.GasCalculator;
@@ -127,13 +125,24 @@ public abstract class AbstractExtCallOperation extends AbstractCallOperation {
Address to = Words.toAddress(toBytes);
final Account contract = frame.getWorldUpdater().get(to);
if (contract != null) {
final DelegatedCodeGasCostHelper.Result result =
deductDelegatedCodeGasCost(frame, gasCalculator, contract);
if (result.status() != DelegatedCodeGasCostHelper.Status.SUCCESS) {
return new Operation.OperationResult(
result.gasCost(), ExceptionalHaltReason.INSUFFICIENT_GAS);
if (contract != null && contract.hasDelegatedCode()) {
if (contract.getDelegatedCode().isEmpty()) {
throw new RuntimeException("A delegated code account must have delegated code");
}
if (contract.getDelegatedCodeHash().isEmpty()) {
throw new RuntimeException("A delegated code account must have a delegated code hash");
}
final long delegatedCodeResolutionGas =
DelegatedCodeGasCostHelper.delegatedCodeGasCost(frame, gasCalculator(), contract);
if (frame.getRemainingGas() < delegatedCodeResolutionGas) {
return new Operation.OperationResult(
delegatedCodeResolutionGas, ExceptionalHaltReason.INSUFFICIENT_GAS);
}
frame.decrementRemainingGas(delegatedCodeResolutionGas);
}
boolean accountCreation = (contract == null || contract.isEmpty()) && !zeroValue;
@@ -154,10 +163,7 @@ public abstract class AbstractExtCallOperation extends AbstractCallOperation {
currentGas -= cost;
frame.expandMemory(inputOffset, inputLength);
final Code code =
contract == null
? CodeV0.EMPTY_CODE
: evm.getCode(contract.getCodeHash(), contract.getCode());
final Code code = getCode(evm, contract);
// invalid code results in a quick exit
if (!code.isValid()) {

View File

@@ -16,7 +16,6 @@ package org.hyperledger.besu.evm.operation;
import static org.hyperledger.besu.evm.internal.Words.clampedAdd;
import static org.hyperledger.besu.evm.internal.Words.clampedToLong;
import static org.hyperledger.besu.evm.worldstate.DelegatedCodeGasCostHelper.deductDelegatedCodeGasCost;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.evm.EVM;
@@ -26,7 +25,7 @@ import org.hyperledger.besu.evm.frame.ExceptionalHaltReason;
import org.hyperledger.besu.evm.frame.MessageFrame;
import org.hyperledger.besu.evm.gascalculator.GasCalculator;
import org.hyperledger.besu.evm.internal.Words;
import org.hyperledger.besu.evm.worldstate.DelegatedCodeGasCostHelper;
import org.hyperledger.besu.evm.worldstate.DelegateCodeHelper;
import org.apache.tuweni.bytes.Bytes;
@@ -96,16 +95,7 @@ public class ExtCodeCopyOperation extends AbstractOperation {
final Account account = frame.getWorldUpdater().get(address);
if (account != null) {
final DelegatedCodeGasCostHelper.Result result =
deductDelegatedCodeGasCost(frame, gasCalculator(), account);
if (result.status() != DelegatedCodeGasCostHelper.Status.SUCCESS) {
return new Operation.OperationResult(
result.gasCost(), ExceptionalHaltReason.INSUFFICIENT_GAS);
}
}
final Bytes code = account != null ? account.getCode() : Bytes.EMPTY;
final Bytes code = getCode(account);
if (enableEIP3540
&& code.size() >= 2
@@ -118,4 +108,14 @@ public class ExtCodeCopyOperation extends AbstractOperation {
return new OperationResult(cost, null);
}
private static Bytes getCode(final Account account) {
if (account == null) {
return Bytes.EMPTY;
}
return account.hasDelegatedCode()
? DelegateCodeHelper.getDelegatedCodeForRead()
: account.getCode();
}
}

View File

@@ -14,8 +14,6 @@
*/
package org.hyperledger.besu.evm.operation;
import static org.hyperledger.besu.evm.worldstate.DelegatedCodeGasCostHelper.deductDelegatedCodeGasCost;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.evm.EVM;
@@ -27,7 +25,7 @@ import org.hyperledger.besu.evm.gascalculator.GasCalculator;
import org.hyperledger.besu.evm.internal.OverflowException;
import org.hyperledger.besu.evm.internal.UnderflowException;
import org.hyperledger.besu.evm.internal.Words;
import org.hyperledger.besu.evm.worldstate.DelegatedCodeGasCostHelper;
import org.hyperledger.besu.evm.worldstate.DelegateCodeHelper;
import org.apache.tuweni.bytes.Bytes;
@@ -85,19 +83,10 @@ public class ExtCodeHashOperation extends AbstractOperation {
final Account account = frame.getWorldUpdater().get(address);
if (account != null) {
final DelegatedCodeGasCostHelper.Result result =
deductDelegatedCodeGasCost(frame, gasCalculator(), account);
if (result.status() != DelegatedCodeGasCostHelper.Status.SUCCESS) {
return new Operation.OperationResult(
result.gasCost(), ExceptionalHaltReason.INSUFFICIENT_GAS);
}
}
if (account == null || account.isEmpty()) {
frame.pushStackItem(Bytes.EMPTY);
} else {
final Bytes code = account.getCode();
final Bytes code = getCode(account);
if (enableEIP3540
&& code.size() >= 2
&& code.get(0) == EOFLayout.EOF_PREFIX_BYTE
@@ -115,4 +104,12 @@ public class ExtCodeHashOperation extends AbstractOperation {
return new OperationResult(cost(true), ExceptionalHaltReason.TOO_MANY_STACK_ITEMS);
}
}
private static Bytes getCode(final Account account) {
if (!account.hasDelegatedCode()) {
return account.getCode();
}
return DelegateCodeHelper.getDelegatedCodeForRead();
}
}

View File

@@ -14,8 +14,6 @@
*/
package org.hyperledger.besu.evm.operation;
import static org.hyperledger.besu.evm.worldstate.DelegatedCodeGasCostHelper.deductDelegatedCodeGasCost;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.evm.EVM;
import org.hyperledger.besu.evm.account.Account;
@@ -26,7 +24,7 @@ import org.hyperledger.besu.evm.gascalculator.GasCalculator;
import org.hyperledger.besu.evm.internal.OverflowException;
import org.hyperledger.besu.evm.internal.UnderflowException;
import org.hyperledger.besu.evm.internal.Words;
import org.hyperledger.besu.evm.worldstate.DelegatedCodeGasCostHelper;
import org.hyperledger.besu.evm.worldstate.DelegateCodeHelper;
import org.apache.tuweni.bytes.Bytes;
@@ -82,20 +80,11 @@ public class ExtCodeSizeOperation extends AbstractOperation {
} else {
final Account account = frame.getWorldUpdater().get(address);
if (account != null) {
final DelegatedCodeGasCostHelper.Result result =
deductDelegatedCodeGasCost(frame, gasCalculator(), account);
if (result.status() != DelegatedCodeGasCostHelper.Status.SUCCESS) {
return new Operation.OperationResult(
result.gasCost(), ExceptionalHaltReason.INSUFFICIENT_GAS);
}
}
Bytes codeSize;
if (account == null) {
codeSize = Bytes.EMPTY;
} else {
final Bytes code = account.getCode();
final Bytes code = getCode(account);
if (enableEIP3540
&& code.size() >= 2
&& code.get(0) == EOFLayout.EOF_PREFIX_BYTE
@@ -114,4 +103,14 @@ public class ExtCodeSizeOperation extends AbstractOperation {
return new OperationResult(cost(true), ExceptionalHaltReason.TOO_MANY_STACK_ITEMS);
}
}
private static Bytes getCode(final Account account) {
if (account == null) {
return Bytes.EMPTY;
}
return account.hasDelegatedCode()
? DelegateCodeHelper.getDelegatedCodeForRead()
: account.getCode();
}
}

View File

@@ -0,0 +1,59 @@
/*
* Copyright contributors to Hyperledger Besu.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.evm.worldstate;
import org.hyperledger.besu.datatypes.Address;
import org.apache.tuweni.bytes.Bytes;
/** Helper class for 7702 delegated code interactions */
public class DelegateCodeHelper {
/**
* The designator that is returned when a ExtCode* operation calls a contract with delegated code
*/
public static final Bytes DELEGATED_CODE_DESIGNATOR = Bytes.fromHexString("ef01");
/** The prefix that is used to identify delegated code */
public static final Bytes DELEGATED_CODE_PREFIX = Bytes.fromHexString("ef0100");
/** The size of the delegated code */
public static final int DELEGATED_CODE_SIZE = DELEGATED_CODE_PREFIX.size() + Address.SIZE;
/** create a new DelegateCodeHelper */
public DelegateCodeHelper() {
// empty
}
/**
* 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);
}
/**
* Returns the delegated code designator
*
* @return the hardcoded designator for delegated code: ef01
*/
public static Bytes getDelegatedCodeForRead() {
return DELEGATED_CODE_DESIGNATOR;
}
}

View File

@@ -33,22 +33,6 @@ public class DelegatedCodeGasCostHelper {
// empty constructor
}
/** The status of the operation. */
public enum Status {
/** The operation failed due to insufficient gas. */
INSUFFICIENT_GAS,
/** The operation was successful. */
SUCCESS
}
/**
* The result of the operation.
*
* @param gasCost the gas cost
* @param status of the operation
*/
public record Result(long gasCost, Status status) {}
/**
* Deducts the gas cost for delegated code resolution.
*
@@ -57,26 +41,18 @@ public class DelegatedCodeGasCostHelper {
* @param account the account
* @return the gas cost and result of the operation
*/
public static Result deductDelegatedCodeGasCost(
public static long delegatedCodeGasCost(
final MessageFrame frame, final GasCalculator gasCalculator, final Account account) {
if (!account.hasDelegatedCode()) {
return new Result(0, Status.SUCCESS);
return 0;
}
if (account.delegatedCodeAddress().isEmpty()) {
throw new RuntimeException("A delegated code account must have a delegated code address");
}
final long delegatedCodeResolutionGas =
calculateDelegatedCodeResolutionGas(
frame, gasCalculator, account.delegatedCodeAddress().get());
if (frame.getRemainingGas() < delegatedCodeResolutionGas) {
return new Result(delegatedCodeResolutionGas, Status.INSUFFICIENT_GAS);
}
frame.decrementRemainingGas(delegatedCodeResolutionGas);
return new Result(delegatedCodeResolutionGas, Status.SUCCESS);
return calculateDelegatedCodeResolutionGas(
frame, gasCalculator, account.delegatedCodeAddress().get());
}
private static long calculateDelegatedCodeResolutionGas(

View File

@@ -14,6 +14,9 @@
*/
package org.hyperledger.besu.evm.worldstate;
import static org.hyperledger.besu.evm.worldstate.DelegateCodeHelper.DELEGATED_CODE_PREFIX;
import static org.hyperledger.besu.evm.worldstate.DelegateCodeHelper.hasDelegatedCode;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.evm.account.Account;
import org.hyperledger.besu.evm.account.DelegatedCodeAccount;
@@ -25,8 +28,6 @@ import org.apache.tuweni.bytes.Bytes;
/** A service that manages the code injection of delegated code. */
public class DelegatedCodeService {
private static final Bytes DELEGATED_CODE_PREFIX = Bytes.fromHexString("ef0100");
private static final int DELEGATED_CODE_SIZE = DELEGATED_CODE_PREFIX.size() + Address.SIZE;
private final GasCalculator gasCalculator;
@@ -64,7 +65,7 @@ public class DelegatedCodeService {
* @return {@code true} if the account can set delegated code, {@code false} otherwise.
*/
public boolean canSetDelegatedCode(final Account account) {
return account.getCode().isEmpty() || hasDelegatedCode(account.getUnprocessedCode());
return account.getCode().isEmpty() || hasDelegatedCode(account.getCode());
}
/**
@@ -102,18 +103,6 @@ public class DelegatedCodeService {
worldUpdater, account, resolveDelegatedAddress(account.getCode()), gasCalculator);
}
/**
* 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()));
}