Devnet-5: bug fixes for 7702 (#8148)

* * fix code hash for delegated accounts in ExtCodeHashOperation
* move common code to AbstractExtCodeOperation class

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

* * rename DelegatedCode -> CodeDelegation, for consistency

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

* * rename authorization -> CodeDelegation, for consistency

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

* rename method to start with lower case

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-22 21:59:27 +01:00
committed by GitHub
parent 519323f77e
commit e9a94f3682
23 changed files with 261 additions and 208 deletions

View File

@@ -87,7 +87,7 @@ public class CodeDelegationTransactionAcceptanceTest extends AcceptanceTestBase
public void shouldTransferAllEthOfAuthorizerToSponsor() throws IOException {
// 7702 transaction
final CodeDelegation authorization =
final CodeDelegation codeDelegation =
org.hyperledger.besu.ethereum.core.CodeDelegation.builder()
.chainId(BigInteger.valueOf(20211))
.address(SEND_ALL_ETH_CONTRACT_ADDRESS)
@@ -108,7 +108,7 @@ public class CodeDelegationTransactionAcceptanceTest extends AcceptanceTestBase
.value(Wei.ZERO)
.payload(Bytes32.leftPad(Bytes.fromHexString(transactionSponsor.getAddress())))
.accessList(List.of())
.codeDelegations(List.of(authorization))
.codeDelegations(List.of(codeDelegation))
.signAndBuild(
secp256k1.createKeyPair(
secp256k1.createPrivateKey(
@@ -143,7 +143,7 @@ public class CodeDelegationTransactionAcceptanceTest extends AcceptanceTestBase
final long GAS_LIMIT = 1_000_000L;
cluster.verify(authorizer.balanceEquals(Amount.ether(90_000)));
final CodeDelegation authorization =
final CodeDelegation codeDelegation =
org.hyperledger.besu.ethereum.core.CodeDelegation.builder()
.chainId(BigInteger.valueOf(20211))
.nonce(
@@ -166,7 +166,7 @@ public class CodeDelegationTransactionAcceptanceTest extends AcceptanceTestBase
.value(Wei.ZERO)
.payload(Bytes32.leftPad(Bytes.fromHexString(otherAccount.getAddress())))
.accessList(List.of())
.codeDelegations(List.of(authorization))
.codeDelegations(List.of(codeDelegation))
.signAndBuild(
secp256k1.createKeyPair(
secp256k1.createPrivateKey(AUTHORIZER_PRIVATE_KEY.toUnsignedBigInteger())));

View File

@@ -243,9 +243,9 @@ public interface Transaction {
Optional<List<CodeDelegation>> getCodeDelegationList();
/**
* Returns the size of the authorization list.
* Returns the size of the code delegation list.
*
* @return the size of the authorization list
* @return the size of the code delegation list
*/
int codeDelegationListSize();
}

View File

@@ -70,7 +70,7 @@ public class CodeDelegationProcessor {
.get()
.forEach(
codeDelegation ->
processAuthorization(
processCodeDelegation(
evmWorldUpdater,
(org.hyperledger.besu.ethereum.core.CodeDelegation) codeDelegation,
result));
@@ -78,7 +78,7 @@ public class CodeDelegationProcessor {
return result;
}
private void processAuthorization(
private void processCodeDelegation(
final EVMWorldUpdater evmWorldUpdater,
final CodeDelegation codeDelegation,
final CodeDelegationResult result) {
@@ -130,7 +130,7 @@ public class CodeDelegationProcessor {
} else {
authority = maybeAuthorityAccount.get();
if (!evmWorldUpdater.authorizedCodeService().canSetDelegatedCode(authority)) {
if (!evmWorldUpdater.codeDelegationService().canSetCodeDelegation(authority)) {
return;
}
@@ -150,8 +150,8 @@ public class CodeDelegationProcessor {
}
evmWorldUpdater
.authorizedCodeService()
.processDelegatedCodeAuthorization(authority, codeDelegation.address());
.codeDelegationService()
.processCodeDelegation(authority, codeDelegation.address());
authority.incrementNonce();
}
}

View File

@@ -427,8 +427,8 @@ public class MainnetTransactionProcessor {
final Address to = transaction.getTo().get();
final Optional<Account> maybeContract = Optional.ofNullable(evmWorldUpdater.get(to));
if (maybeContract.isPresent() && maybeContract.get().hasDelegatedCode()) {
warmAddressList.add(maybeContract.get().delegatedCodeAddress().get());
if (maybeContract.isPresent() && maybeContract.get().hasCodeDelegation()) {
warmAddressList.add(maybeContract.get().codeDelegationAddress().get());
}
initialFrame =
@@ -441,9 +441,10 @@ public class MainnetTransactionProcessor {
maybeContract
.map(
c -> {
if (c.hasDelegatedCode()) {
if (c.hasCodeDelegation()) {
return messageCallProcessor.getCodeFromEVM(
c.getDelegatedCodeHash().get(), c.getDelegatedCode().get());
c.getCodeDelegationTargetHash().get(),
c.getCodeDelegationTargetCode().get());
}
return messageCallProcessor.getCodeFromEVM(

View File

@@ -16,7 +16,7 @@ package org.hyperledger.besu.ethereum.mainnet;
import static org.hyperledger.besu.evm.account.Account.MAX_NONCE;
import static org.hyperledger.besu.evm.internal.Words.clampedAdd;
import static org.hyperledger.besu.evm.worldstate.DelegateCodeHelper.hasDelegatedCode;
import static org.hyperledger.besu.evm.worldstate.CodeDelegationHelper.hasCodeDelegation;
import org.hyperledger.besu.crypto.SECPSignature;
import org.hyperledger.besu.crypto.SignatureAlgorithmFactory;
@@ -333,7 +333,7 @@ public class MainnetTransactionValidator implements TransactionValidator {
}
private static boolean canSendTransaction(final Account sender, final Hash codeHash) {
return codeHash.equals(Hash.EMPTY) || hasDelegatedCode(sender.getCode());
return codeHash.equals(Hash.EMPTY) || hasCodeDelegation(sender.getCode());
}
private ValidationResult<TransactionInvalidReason> validateTransactionSignature(

View File

@@ -37,14 +37,15 @@ class CodeDelegationDecoderTest {
Bytes.fromHexString(
"0xf85a0194633688abc3ccf8b0c03088d2d1c6ae4958c2fa562a80a0840798fa67118e034c1eb7e42fe89e28d7cd5006dc813d5729e5f75b0d1a7ec5a03b1dbace38ceb862a65bf2eac0637693b5c3493bcb2a022dd614c0a74cce0b99"),
true);
final CodeDelegation authorization = CodeDelegationTransactionDecoder.decodeInnerPayload(input);
final CodeDelegation codeDelegation =
CodeDelegationTransactionDecoder.decodeInnerPayload(input);
assertThat(authorization.chainId()).isEqualTo(BigInteger.ONE);
assertThat(authorization.address())
assertThat(codeDelegation.chainId()).isEqualTo(BigInteger.ONE);
assertThat(codeDelegation.address())
.isEqualTo(Address.fromHexStringStrict("0x633688abc3cCf8B0C03088D2d1C6ae4958c2fA56"));
assertThat(authorization.nonce()).isEqualTo(42);
assertThat(codeDelegation.nonce()).isEqualTo(42);
final SECPSignature signature = authorization.signature();
final SECPSignature signature = codeDelegation.signature();
assertThat(signature.getRecId()).isEqualTo((byte) 0);
assertThat(signature.getR().toString(16))
.isEqualTo("840798fa67118e034c1eb7e42fe89e28d7cd5006dc813d5729e5f75b0d1a7ec5");
@@ -61,14 +62,15 @@ class CodeDelegationDecoderTest {
Bytes.fromHexString(
"0xf85a0194633688abc3ccf8b0c03088d2d1c6ae4958c2fa568001a0dd6b24048be1b7d7fe5bbbb73ffc37eb2ce1997ecb4ae5b6096532ef19363148a025b58a1ff8ad00bddbbfa1d5c2411961cbb6d08dcdc8ae88303db3c6cf983031"),
true);
final CodeDelegation authorization = CodeDelegationTransactionDecoder.decodeInnerPayload(input);
final CodeDelegation codeDelegation =
CodeDelegationTransactionDecoder.decodeInnerPayload(input);
assertThat(authorization.chainId()).isEqualTo(BigInteger.ONE);
assertThat(authorization.address())
assertThat(codeDelegation.chainId()).isEqualTo(BigInteger.ONE);
assertThat(codeDelegation.address())
.isEqualTo(Address.fromHexStringStrict("0x633688abc3cCf8B0C03088D2d1C6ae4958c2fA56"));
assertThat(authorization.nonce()).isEqualTo(0);
assertThat(codeDelegation.nonce()).isEqualTo(0);
final SECPSignature signature = authorization.signature();
final SECPSignature signature = codeDelegation.signature();
assertThat(signature.getRecId()).isEqualTo((byte) 1);
assertThat(signature.getR().toString(16))
.isEqualTo("dd6b24048be1b7d7fe5bbbb73ffc37eb2ce1997ecb4ae5b6096532ef19363148");
@@ -85,14 +87,15 @@ class CodeDelegationDecoderTest {
Bytes.fromHexString(
"0xf85a8094633688abc3ccf8b0c03088d2d1c6ae4958c2fa560501a0025c1240d7ffec0daeedb752d3357aff2e3cd58468f0c2d43ee0ee999e02ace2a03c8a25b2becd6e666f69803d1ae3322f2e137b7745c2c7f19da80f993ffde4df"),
true);
final CodeDelegation authorization = CodeDelegationTransactionDecoder.decodeInnerPayload(input);
final CodeDelegation codeDelegation =
CodeDelegationTransactionDecoder.decodeInnerPayload(input);
assertThat(authorization.chainId()).isEqualTo(BigInteger.ZERO);
assertThat(authorization.address())
assertThat(codeDelegation.chainId()).isEqualTo(BigInteger.ZERO);
assertThat(codeDelegation.address())
.isEqualTo(Address.fromHexStringStrict("0x633688abc3cCf8B0C03088D2d1C6ae4958c2fA56"));
assertThat(authorization.nonce()).isEqualTo(5);
assertThat(codeDelegation.nonce()).isEqualTo(5);
final SECPSignature signature = authorization.signature();
final SECPSignature signature = codeDelegation.signature();
assertThat(signature.getRecId()).isEqualTo((byte) 1);
assertThat(signature.getR().toString(16))
.isEqualTo("25c1240d7ffec0daeedb752d3357aff2e3cd58468f0c2d43ee0ee999e02ace2");
@@ -107,8 +110,9 @@ class CodeDelegationDecoderTest {
Bytes.fromHexString(
"0xdf8501a1f0ff5a947a40026a3b9a41754a95eec8c92c6b99886f440c5b808080"),
true);
final CodeDelegation authorization = CodeDelegationTransactionDecoder.decodeInnerPayload(input);
final CodeDelegation codeDelegation =
CodeDelegationTransactionDecoder.decodeInnerPayload(input);
assertThat(authorization.chainId()).isEqualTo(new BigInteger("01a1f0ff5a", 16));
assertThat(codeDelegation.chainId()).isEqualTo(new BigInteger("01a1f0ff5a", 16));
}
}

View File

@@ -27,7 +27,7 @@ import org.hyperledger.besu.datatypes.CodeDelegation;
import org.hyperledger.besu.ethereum.core.Transaction;
import org.hyperledger.besu.evm.account.Account;
import org.hyperledger.besu.evm.account.MutableAccount;
import org.hyperledger.besu.evm.worldstate.DelegatedCodeService;
import org.hyperledger.besu.evm.worldstate.CodeDelegationService;
import org.hyperledger.besu.evm.worldstate.EVMWorldUpdater;
import java.math.BigInteger;
@@ -47,7 +47,7 @@ class CodeDelegationProcessorTest {
@Mock private Transaction transaction;
@Mock private DelegatedCodeService authorizedCodeService;
@Mock private CodeDelegationService authorizedCodeService;
@Mock private MutableAccount authority;
@@ -95,7 +95,7 @@ class CodeDelegationProcessorTest {
@Test
void shouldProcessValidDelegationForNewAccount() {
// Arrange
when(worldUpdater.authorizedCodeService()).thenReturn(authorizedCodeService);
when(worldUpdater.codeDelegationService()).thenReturn(authorizedCodeService);
CodeDelegation codeDelegation = createCodeDelegation(CHAIN_ID, 0L);
when(transaction.getCodeDelegationList()).thenReturn(Optional.of(List.of(codeDelegation)));
when(worldUpdater.getAccount(any())).thenReturn(null);
@@ -109,18 +109,18 @@ class CodeDelegationProcessorTest {
assertThat(result.alreadyExistingDelegators()).isZero();
verify(worldUpdater).createAccount(any());
verify(authority).incrementNonce();
verify(authorizedCodeService).processDelegatedCodeAuthorization(authority, DELEGATE_ADDRESS);
verify(authorizedCodeService).processCodeDelegation(authority, DELEGATE_ADDRESS);
}
@Test
void shouldProcessValidDelegationForExistingAccount() {
// Arrange
when(worldUpdater.authorizedCodeService()).thenReturn(authorizedCodeService);
when(worldUpdater.codeDelegationService()).thenReturn(authorizedCodeService);
CodeDelegation codeDelegation = createCodeDelegation(CHAIN_ID, 1L);
when(transaction.getCodeDelegationList()).thenReturn(Optional.of(List.of(codeDelegation)));
when(worldUpdater.getAccount(any())).thenReturn(authority);
when(authority.getNonce()).thenReturn(1L);
when(authorizedCodeService.canSetDelegatedCode(any())).thenReturn(true);
when(authorizedCodeService.canSetCodeDelegation(any())).thenReturn(true);
// Act
CodeDelegationResult result = processor.process(worldUpdater, transaction);
@@ -129,17 +129,17 @@ class CodeDelegationProcessorTest {
assertThat(result.alreadyExistingDelegators()).isEqualTo(1);
verify(worldUpdater, never()).createAccount(any());
verify(authority).incrementNonce();
verify(authorizedCodeService).processDelegatedCodeAuthorization(authority, DELEGATE_ADDRESS);
verify(authorizedCodeService).processCodeDelegation(authority, DELEGATE_ADDRESS);
}
@Test
void shouldRejectDelegationWithInvalidNonce() {
// Arrange
when(worldUpdater.authorizedCodeService()).thenReturn(authorizedCodeService);
when(worldUpdater.codeDelegationService()).thenReturn(authorizedCodeService);
CodeDelegation codeDelegation = createCodeDelegation(CHAIN_ID, 2L);
when(transaction.getCodeDelegationList()).thenReturn(Optional.of(List.of(codeDelegation)));
when(worldUpdater.getAccount(any())).thenReturn(authority);
when(authorizedCodeService.canSetDelegatedCode(any())).thenReturn(true);
when(authorizedCodeService.canSetCodeDelegation(any())).thenReturn(true);
// Act
CodeDelegationResult result = processor.process(worldUpdater, transaction);
@@ -147,7 +147,7 @@ class CodeDelegationProcessorTest {
// Assert
assertThat(result.alreadyExistingDelegators()).isZero();
verify(authority, never()).incrementNonce();
verify(authorizedCodeService, never()).processDelegatedCodeAuthorization(any(), any());
verify(authorizedCodeService, never()).processCodeDelegation(any(), any());
}
@Test
@@ -163,7 +163,7 @@ class CodeDelegationProcessorTest {
// Assert
assertThat(result.alreadyExistingDelegators()).isZero();
verify(authority, never()).incrementNonce();
verify(authorizedCodeService, never()).processDelegatedCodeAuthorization(any(), any());
verify(authorizedCodeService, never()).processCodeDelegation(any(), any());
}
@Test
@@ -181,7 +181,7 @@ class CodeDelegationProcessorTest {
// Assert
assertThat(result.alreadyExistingDelegators()).isZero();
verify(authority, never()).incrementNonce();
verify(authorizedCodeService, never()).processDelegatedCodeAuthorization(any(), any());
verify(authorizedCodeService, never()).processCodeDelegation(any(), any());
}
@Test
@@ -201,17 +201,17 @@ class CodeDelegationProcessorTest {
// Assert
assertThat(result.alreadyExistingDelegators()).isZero();
verify(authority, never()).incrementNonce();
verify(authorizedCodeService, never()).processDelegatedCodeAuthorization(any(), any());
verify(authorizedCodeService, never()).processCodeDelegation(any(), any());
}
@Test
void shouldRejectDelegationWhenCannotSetDelegatedCode() {
void shouldRejectDelegationWhenCannotSetCodeDelegation() {
// Arrange
when(worldUpdater.authorizedCodeService()).thenReturn(authorizedCodeService);
when(worldUpdater.codeDelegationService()).thenReturn(authorizedCodeService);
CodeDelegation codeDelegation = createCodeDelegation(CHAIN_ID, 1L);
when(transaction.getCodeDelegationList()).thenReturn(Optional.of(List.of(codeDelegation)));
when(worldUpdater.getAccount(any())).thenReturn(authority);
when(authorizedCodeService.canSetDelegatedCode(any())).thenReturn(false);
when(authorizedCodeService.canSetCodeDelegation(any())).thenReturn(false);
// Act
CodeDelegationResult result = processor.process(worldUpdater, transaction);
@@ -219,7 +219,7 @@ class CodeDelegationProcessorTest {
// Assert
assertThat(result.alreadyExistingDelegators()).isZero();
verify(authority, never()).incrementNonce();
verify(authorizedCodeService, never()).processDelegatedCodeAuthorization(any(), any());
verify(authorizedCodeService, never()).processCodeDelegation(any(), any());
}
private CodeDelegation createCodeDelegation(final BigInteger chainId, final long nonce) {

View File

@@ -221,43 +221,44 @@ public class T8nExecutor {
continue;
}
List<CodeDelegation> authorizations = new ArrayList<>(authorizationList.size());
List<CodeDelegation> codeDelegations = new ArrayList<>(authorizationList.size());
for (JsonNode entryAsJson : authorizationList) {
final BigInteger authorizationChainId =
final BigInteger codeDelegationChainId =
Bytes.fromHexStringLenient(entryAsJson.get("chainId").textValue())
.toUnsignedBigInteger();
final Address authorizationAddress =
final Address codeDelegationAddress =
Address.fromHexString(entryAsJson.get("address").textValue());
final long authorizationNonce =
final long codeDelegationNonce =
Bytes.fromHexStringLenient(entryAsJson.get("nonce").textValue()).toLong();
final BigInteger authorizationV =
final BigInteger codeDelegationV =
Bytes.fromHexStringLenient(entryAsJson.get("v").textValue())
.toUnsignedBigInteger();
if (authorizationV.compareTo(BigInteger.valueOf(256)) >= 0) {
if (codeDelegationV.compareTo(BigInteger.valueOf(256)) >= 0) {
throw new IllegalArgumentException(
"Invalid authorizationV value. Must be less than 256");
"Invalid codeDelegationV value. Must be less than 256");
}
final BigInteger authorizationR =
final BigInteger codeDelegationR =
Bytes.fromHexStringLenient(entryAsJson.get("r").textValue())
.toUnsignedBigInteger();
final BigInteger authorizationS =
final BigInteger codeDelegationS =
Bytes.fromHexStringLenient(entryAsJson.get("s").textValue())
.toUnsignedBigInteger();
final SECPSignature authorizationSignature =
new SECPSignature(authorizationR, authorizationS, authorizationV.byteValue());
final SECPSignature codeDelegationSignature =
new SECPSignature(
codeDelegationR, codeDelegationS, codeDelegationV.byteValue());
authorizations.add(
codeDelegations.add(
new org.hyperledger.besu.ethereum.core.CodeDelegation(
authorizationChainId,
authorizationAddress,
authorizationNonce,
authorizationSignature));
codeDelegationChainId,
codeDelegationAddress,
codeDelegationNonce,
codeDelegationSignature));
}
builder.codeDelegations(authorizations);
builder.codeDelegations(codeDelegations);
}
if (txNode.has("blobVersionedHashes")) {

View File

@@ -23,20 +23,20 @@ import java.util.Optional;
import org.apache.tuweni.bytes.Bytes;
abstract class AbstractDelegatedCodeAccount implements Account {
abstract class AbstractCodeDelegationAccount 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 final Address codeDelegationAddress;
protected AbstractDelegatedCodeAccount(
protected AbstractCodeDelegationAccount(
final WorldUpdater worldUpdater,
final Address delegatedCodeAddress,
final Address codeDelegationAddress,
final GasCalculator gasCalculator) {
this.worldUpdater = worldUpdater;
this.gasCalculator = gasCalculator;
this.delegatedCodeAddress = delegatedCodeAddress;
this.codeDelegationAddress = codeDelegationAddress;
}
/**
@@ -45,8 +45,8 @@ abstract class AbstractDelegatedCodeAccount implements Account {
* @return the delegated code.
*/
@Override
public Optional<Bytes> getDelegatedCode() {
return resolveDelegatedCode();
public Optional<Bytes> getCodeDelegationTargetCode() {
return resolveCodeDelegationTargetCode();
}
/**
@@ -55,8 +55,8 @@ abstract class AbstractDelegatedCodeAccount implements Account {
* @return the hash of the delegated code.
*/
@Override
public Optional<Hash> getDelegatedCodeHash() {
return getDelegatedCode().map(Hash::hash);
public Optional<Hash> getCodeDelegationTargetHash() {
return getCodeDelegationTargetCode().map(Hash::hash);
}
/**
@@ -65,23 +65,23 @@ abstract class AbstractDelegatedCodeAccount implements Account {
* @return the address of the delegated code.
*/
@Override
public Optional<Address> delegatedCodeAddress() {
return Optional.of(delegatedCodeAddress);
public Optional<Address> codeDelegationAddress() {
return Optional.of(codeDelegationAddress);
}
@Override
public boolean hasDelegatedCode() {
public boolean hasCodeDelegation() {
return true;
}
private Optional<Account> getDelegatedAccount() {
return Optional.ofNullable(worldUpdater.getAccount(delegatedCodeAddress));
return Optional.ofNullable(worldUpdater.getAccount(codeDelegationAddress));
}
private Optional<Bytes> resolveDelegatedCode() {
private Optional<Bytes> resolveCodeDelegationTargetCode() {
final Optional<Account> maybeDelegatedAccount = getDelegatedAccount();
if (gasCalculator.isPrecompile(delegatedCodeAddress) || maybeDelegatedAccount.isEmpty()) {
if (gasCalculator.isPrecompile(codeDelegationAddress) || maybeDelegatedAccount.isEmpty()) {
return Optional.of(Bytes.EMPTY);
}

View File

@@ -57,7 +57,7 @@ public interface Account extends AccountState {
*
* @return the address of the delegated code account if it has one otherwise empty.
*/
default Optional<Address> delegatedCodeAddress() {
default Optional<Address> codeDelegationAddress() {
return Optional.empty();
}
@@ -66,7 +66,7 @@ public interface Account extends AccountState {
*
* @return true if the account has delegated code otherwise false.
*/
default boolean hasDelegatedCode() {
default boolean hasCodeDelegation() {
return false;
}
}

View File

@@ -78,9 +78,9 @@ public interface AccountState {
/**
* The optional EVM bytecode if the account has set a 7702 code delegation.
*
* @return the delegated code (which may be empty).
* @return the code of the target account (which may be empty).
*/
default Optional<Bytes> getDelegatedCode() {
default Optional<Bytes> getCodeDelegationTargetCode() {
return Optional.empty();
}
@@ -94,9 +94,9 @@ public interface AccountState {
/**
* 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).
* @return the hash of the code of the target account (which may be empty).
*/
default Optional<Hash> getDelegatedCodeHash() {
default Optional<Hash> getCodeDelegationTargetHash() {
return Optional.empty();
}

View File

@@ -28,19 +28,19 @@ 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 AbstractDelegatedCodeAccount implements Account {
public class CodeDelegationAccount extends AbstractCodeDelegationAccount implements Account {
private final Account wrappedAccount;
/**
* Creates a new AuthorizedCodeAccount.
* Creates a new CodeDelegationAccount.
*
* @param worldUpdater the world updater.
* @param wrappedAccount the account that has delegated code to be loaded into it.
* @param codeDelegationAddress the address of the delegated code.
* @param gasCalculator the gas calculator to check for precompiles.
*/
public DelegatedCodeAccount(
public CodeDelegationAccount(
final WorldUpdater worldUpdater,
final Account wrappedAccount,
final Address codeDelegationAddress,
@@ -60,8 +60,8 @@ public class DelegatedCodeAccount extends AbstractDelegatedCodeAccount implement
}
@Override
public Optional<Address> delegatedCodeAddress() {
return super.delegatedCodeAddress();
public Optional<Address> codeDelegationAddress() {
return super.codeDelegationAddress();
}
@Override

View File

@@ -29,20 +29,20 @@ 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 AbstractDelegatedCodeAccount
public class MutableCodeDelegationDelegationAccount extends AbstractCodeDelegationAccount
implements MutableAccount {
private final MutableAccount wrappedAccount;
/**
* Creates a new MutableAuthorizedCodeAccount.
* Creates a new MutableCodeDelegationDelegationAccount.
*
* @param worldUpdater the world updater.
* @param wrappedAccount the account that has delegated code to be loaded into it.
* @param codeDelegationAddress the address of the delegated code.
* @param gasCalculator the gas calculator to check for precompiles.
*/
public MutableDelegatedCodeAccount(
public MutableCodeDelegationDelegationAccount(
final WorldUpdater worldUpdater,
final MutableAccount wrappedAccount,
final Address codeDelegationAddress,
@@ -62,8 +62,8 @@ public class MutableDelegatedCodeAccount extends AbstractDelegatedCodeAccount
}
@Override
public Optional<Address> delegatedCodeAddress() {
return super.delegatedCodeAddress();
public Optional<Address> codeDelegationAddress() {
return super.codeDelegationAddress();
}
@Override

View File

@@ -26,7 +26,7 @@ import org.hyperledger.besu.evm.frame.ExceptionalHaltReason;
import org.hyperledger.besu.evm.frame.MessageFrame;
import org.hyperledger.besu.evm.frame.MessageFrame.State;
import org.hyperledger.besu.evm.gascalculator.GasCalculator;
import org.hyperledger.besu.evm.worldstate.DelegatedCodeGasCostHelper;
import org.hyperledger.besu.evm.worldstate.CodeDelegationGasCostHelper;
import org.apache.tuweni.bytes.Bytes;
@@ -191,24 +191,24 @@ public abstract class AbstractCallOperation extends AbstractOperation {
final Account contract = frame.getWorldUpdater().get(to);
if (contract != null && contract.hasDelegatedCode()) {
if (contract.getDelegatedCode().isEmpty()) {
if (contract != null && contract.hasCodeDelegation()) {
if (contract.getCodeDelegationTargetCode().isEmpty()) {
throw new RuntimeException("A delegated code account must have delegated code");
}
if (contract.getDelegatedCodeHash().isEmpty()) {
if (contract.getCodeDelegationTargetHash().isEmpty()) {
throw new RuntimeException("A delegated code account must have a delegated code hash");
}
final long delegatedCodeResolutionGas =
DelegatedCodeGasCostHelper.delegatedCodeGasCost(frame, gasCalculator(), contract);
final long codeDelegationResolutionGas =
CodeDelegationGasCostHelper.codeDelegationGasCost(frame, gasCalculator(), contract);
if (frame.getRemainingGas() < delegatedCodeResolutionGas) {
if (frame.getRemainingGas() < codeDelegationResolutionGas) {
return new Operation.OperationResult(
delegatedCodeResolutionGas, ExceptionalHaltReason.INSUFFICIENT_GAS);
codeDelegationResolutionGas, ExceptionalHaltReason.INSUFFICIENT_GAS);
}
frame.decrementRemainingGas(delegatedCodeResolutionGas);
frame.decrementRemainingGas(codeDelegationResolutionGas);
}
final Account account = frame.getWorldUpdater().get(frame.getRecipientAddress());
@@ -357,8 +357,9 @@ public abstract class AbstractCallOperation extends AbstractOperation {
return CodeV0.EMPTY_CODE;
}
if (account.hasDelegatedCode()) {
return evm.getCode(account.getDelegatedCodeHash().get(), account.getDelegatedCode().get());
if (account.hasCodeDelegation()) {
return evm.getCode(
account.getCodeDelegationTargetHash().get(), account.getCodeDelegationTargetCode().get());
}
return evm.getCode(account.getCodeHash(), account.getCode());

View File

@@ -25,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.CodeDelegationGasCostHelper;
import javax.annotation.Nonnull;
@@ -125,24 +125,24 @@ public abstract class AbstractExtCallOperation extends AbstractCallOperation {
Address to = Words.toAddress(toBytes);
final Account contract = frame.getWorldUpdater().get(to);
if (contract != null && contract.hasDelegatedCode()) {
if (contract.getDelegatedCode().isEmpty()) {
if (contract != null && contract.hasCodeDelegation()) {
if (contract.getCodeDelegationTargetCode().isEmpty()) {
throw new RuntimeException("A delegated code account must have delegated code");
}
if (contract.getDelegatedCodeHash().isEmpty()) {
if (contract.getCodeDelegationTargetHash().isEmpty()) {
throw new RuntimeException("A delegated code account must have a delegated code hash");
}
final long delegatedCodeResolutionGas =
DelegatedCodeGasCostHelper.delegatedCodeGasCost(frame, gasCalculator(), contract);
final long codeDelegationResolutionGas =
CodeDelegationGasCostHelper.codeDelegationGasCost(frame, gasCalculator(), contract);
if (frame.getRemainingGas() < delegatedCodeResolutionGas) {
if (frame.getRemainingGas() < codeDelegationResolutionGas) {
return new Operation.OperationResult(
delegatedCodeResolutionGas, ExceptionalHaltReason.INSUFFICIENT_GAS);
codeDelegationResolutionGas, ExceptionalHaltReason.INSUFFICIENT_GAS);
}
frame.decrementRemainingGas(delegatedCodeResolutionGas);
frame.decrementRemainingGas(codeDelegationResolutionGas);
}
boolean accountCreation = (contract == null || contract.isEmpty()) && !zeroValue;

View File

@@ -0,0 +1,77 @@
/*
* Copyright contributors to 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.operation;
import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.evm.account.Account;
import org.hyperledger.besu.evm.gascalculator.GasCalculator;
import org.hyperledger.besu.evm.worldstate.CodeDelegationHelper;
import org.apache.tuweni.bytes.Bytes;
/**
* ExtCode* operations treat EOAs with delegated code differently than other operations. This
* abstract class contains common methods for this behaviour.
*/
abstract class AbstractExtCodeOperation extends AbstractOperation {
/**
* Instantiates a new Abstract operation.
*
* @param opcode the opcode
* @param name the name
* @param stackItemsConsumed the stack items consumed
* @param stackItemsProduced the stack items produced
* @param gasCalculator the gas calculator
*/
protected AbstractExtCodeOperation(
final int opcode,
final String name,
final int stackItemsConsumed,
final int stackItemsProduced,
final GasCalculator gasCalculator) {
super(opcode, name, stackItemsConsumed, stackItemsProduced, gasCalculator);
}
/**
* Returns the code for standard accounts or a special designator for EOAs with delegated code
*
* @param account The account
* @return the code or the special 7702 designator
*/
protected Bytes getCode(final Account account) {
if (account == null) {
return Bytes.EMPTY;
}
return account.hasCodeDelegation()
? CodeDelegationHelper.getCodeDelegationForRead()
: account.getCode();
}
/**
* Returns the code hash for standard accounts or a special designator for EOAs with delegated
* code
*
* @param account The account
* @return the code hash or the hash of the special 7702 designator
*/
protected Hash getCodeHash(final Account account) {
if (account.hasCodeDelegation()) {
return Hash.hash(CodeDelegationHelper.getCodeDelegationForRead());
}
return account.getCodeHash();
}
}

View File

@@ -25,12 +25,11 @@ 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.DelegateCodeHelper;
import org.apache.tuweni.bytes.Bytes;
/** The Ext code copy operation. */
public class ExtCodeCopyOperation extends AbstractOperation {
public class ExtCodeCopyOperation extends AbstractExtCodeOperation {
/** This is the "code" legacy contracts see when copying code from an EOF contract. */
public static final Bytes EOF_REPLACEMENT_CODE = Bytes.fromHexString("0xef00");
@@ -108,14 +107,4 @@ 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

@@ -25,12 +25,11 @@ 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.DelegateCodeHelper;
import org.apache.tuweni.bytes.Bytes;
/** The Ext code hash operation. */
public class ExtCodeHashOperation extends AbstractOperation {
public class ExtCodeHashOperation extends AbstractExtCodeOperation {
// // 0x9dbf3648db8210552e9c4f75c6a1c3057c0ca432043bd648be15fe7be05646f5
static final Hash EOF_REPLACEMENT_HASH = Hash.hash(ExtCodeCopyOperation.EOF_REPLACEMENT_CODE);
@@ -93,7 +92,7 @@ public class ExtCodeHashOperation extends AbstractOperation {
&& code.get(1) == 0) {
frame.pushStackItem(EOF_REPLACEMENT_HASH);
} else {
frame.pushStackItem(account.getCodeHash());
frame.pushStackItem(getCodeHash(account));
}
}
return new OperationResult(cost, null);
@@ -104,12 +103,4 @@ 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

@@ -24,12 +24,11 @@ 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.DelegateCodeHelper;
import org.apache.tuweni.bytes.Bytes;
/** The Ext code size operation. */
public class ExtCodeSizeOperation extends AbstractOperation {
public class ExtCodeSizeOperation extends AbstractExtCodeOperation {
static final Bytes EOF_SIZE = Bytes.of(2);
@@ -103,14 +102,4 @@ 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

@@ -26,10 +26,10 @@ import org.hyperledger.besu.evm.gascalculator.GasCalculator;
* be executed when a contract has delegated code. This process is necessary to determine the
* contract that will be executed and to ensure that the contract is warm in the cache.
*/
public class DelegatedCodeGasCostHelper {
public class CodeDelegationGasCostHelper {
/** Private constructor to prevent instantiation. */
private DelegatedCodeGasCostHelper() {
private CodeDelegationGasCostHelper() {
// empty constructor
}
@@ -41,25 +41,25 @@ public class DelegatedCodeGasCostHelper {
* @param account the account
* @return the gas cost and result of the operation
*/
public static long delegatedCodeGasCost(
public static long codeDelegationGasCost(
final MessageFrame frame, final GasCalculator gasCalculator, final Account account) {
if (!account.hasDelegatedCode()) {
if (!account.hasCodeDelegation()) {
return 0;
}
if (account.delegatedCodeAddress().isEmpty()) {
if (account.codeDelegationAddress().isEmpty()) {
throw new RuntimeException("A delegated code account must have a delegated code address");
}
return calculateDelegatedCodeResolutionGas(
frame, gasCalculator, account.delegatedCodeAddress().get());
return calculateCodeDelegationResolutionGas(
frame, gasCalculator, account.codeDelegationAddress().get());
}
private static long calculateDelegatedCodeResolutionGas(
private static long calculateCodeDelegationResolutionGas(
final MessageFrame frame, final GasCalculator gasCalculator, final Address delegateeAddress) {
final boolean delegatedCodeIsWarm =
final boolean isWarm =
frame.warmUpAddress(delegateeAddress) || gasCalculator.isPrecompile(delegateeAddress);
return delegatedCodeIsWarm
return isWarm
? gasCalculator.getWarmStorageReadCost()
: gasCalculator.getColdAccountAccessCost();
}

View File

@@ -19,20 +19,20 @@ import org.hyperledger.besu.datatypes.Address;
import org.apache.tuweni.bytes.Bytes;
/** Helper class for 7702 delegated code interactions */
public class DelegateCodeHelper {
public class CodeDelegationHelper {
/**
* 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");
public static final Bytes CODE_DELEGATION_PREFIX = Bytes.fromHexString("ef0100");
/** The size of the delegated code */
public static final int DELEGATED_CODE_SIZE = DELEGATED_CODE_PREFIX.size() + Address.SIZE;
public static final int DELEGATED_CODE_SIZE = CODE_DELEGATION_PREFIX.size() + Address.SIZE;
/** create a new DelegateCodeHelper */
public DelegateCodeHelper() {
public CodeDelegationHelper() {
// empty
}
@@ -42,10 +42,10 @@ public class DelegateCodeHelper {
* @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) {
public static boolean hasCodeDelegation(final Bytes code) {
return code != null
&& code.size() == DELEGATED_CODE_SIZE
&& code.slice(0, DELEGATED_CODE_PREFIX.size()).equals(DELEGATED_CODE_PREFIX);
&& code.slice(0, CODE_DELEGATION_PREFIX.size()).equals(CODE_DELEGATION_PREFIX);
}
/**
@@ -53,7 +53,7 @@ public class DelegateCodeHelper {
*
* @return the hardcoded designator for delegated code: ef01
*/
public static Bytes getDelegatedCodeForRead() {
public static Bytes getCodeDelegationForRead() {
return DELEGATED_CODE_DESIGNATOR;
}
}

View File

@@ -14,29 +14,29 @@
*/
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 static org.hyperledger.besu.evm.worldstate.CodeDelegationHelper.CODE_DELEGATION_PREFIX;
import static org.hyperledger.besu.evm.worldstate.CodeDelegationHelper.hasCodeDelegation;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.evm.account.Account;
import org.hyperledger.besu.evm.account.DelegatedCodeAccount;
import org.hyperledger.besu.evm.account.CodeDelegationAccount;
import org.hyperledger.besu.evm.account.MutableAccount;
import org.hyperledger.besu.evm.account.MutableDelegatedCodeAccount;
import org.hyperledger.besu.evm.account.MutableCodeDelegationDelegationAccount;
import org.hyperledger.besu.evm.gascalculator.GasCalculator;
import org.apache.tuweni.bytes.Bytes;
/** A service that manages the code injection of delegated code. */
public class DelegatedCodeService {
public class CodeDelegationService {
private final GasCalculator gasCalculator;
/**
* Creates a new DelegatedCodeService.
* Creates a new CodeDelegationService.
*
* @param gasCalculator the gas calculator to check for pre compiles.
*/
public DelegatedCodeService(final GasCalculator gasCalculator) {
public CodeDelegationService(final GasCalculator gasCalculator) {
this.gasCalculator = gasCalculator;
}
@@ -45,17 +45,17 @@ public class DelegatedCodeService {
* address. If the address is 0, it will set the code to empty.
*
* @param account the account to which the delegated code is added.
* @param delegatedCodeAddress the address of the target of the authorization.
* @param codeDelegationAddress the address of the target of the authorization.
*/
public void processDelegatedCodeAuthorization(
final MutableAccount account, final Address delegatedCodeAddress) {
// authorization to zero address removes any delegated code
if (delegatedCodeAddress.equals(Address.ZERO)) {
public void processCodeDelegation(
final MutableAccount account, final Address codeDelegationAddress) {
// code delegation to zero address removes any delegated code
if (codeDelegationAddress.equals(Address.ZERO)) {
account.setCode(Bytes.EMPTY);
return;
}
account.setCode(Bytes.concatenate(DELEGATED_CODE_PREFIX, delegatedCodeAddress));
account.setCode(Bytes.concatenate(CODE_DELEGATION_PREFIX, codeDelegationAddress));
}
/**
@@ -64,8 +64,8 @@ public class DelegatedCodeService {
* @param account the account to check.
* @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.getCode());
public boolean canSetCodeDelegation(final Account account) {
return account.getCode().isEmpty() || hasCodeDelegation(account.getCode());
}
/**
@@ -77,11 +77,11 @@ public class DelegatedCodeService {
* otherwise.
*/
public Account processAccount(final WorldUpdater worldUpdater, final Account account) {
if (account == null || !hasDelegatedCode(account.getCode())) {
if (account == null || !hasCodeDelegation(account.getCode())) {
return account;
}
return new DelegatedCodeAccount(
return new CodeDelegationAccount(
worldUpdater, account, resolveDelegatedAddress(account.getCode()), gasCalculator);
}
@@ -95,15 +95,15 @@ public class DelegatedCodeService {
*/
public MutableAccount processMutableAccount(
final WorldUpdater worldUpdater, final MutableAccount account) {
if (account == null || !hasDelegatedCode(account.getCode())) {
if (account == null || !hasCodeDelegation(account.getCode())) {
return account;
}
return new MutableDelegatedCodeAccount(
return new MutableCodeDelegationDelegationAccount(
worldUpdater, account, resolveDelegatedAddress(account.getCode()), gasCalculator);
}
private Address resolveDelegatedAddress(final Bytes code) {
return Address.wrap(code.slice(DELEGATED_CODE_PREFIX.size()));
return Address.wrap(code.slice(CODE_DELEGATION_PREFIX.size()));
}
}

View File

@@ -26,11 +26,11 @@ import java.util.Optional;
/**
* The EVM world updater. This class is a wrapper around a WorldUpdater that provides an
* AuthorizedCodeService to manage the authorized code for accounts.
* CodeDelegationService to manage the code delegations for accounts.
*/
public class EVMWorldUpdater implements WorldUpdater {
private final WorldUpdater rootWorldUpdater;
private final DelegatedCodeService delegatedCodeService;
private final CodeDelegationService codeDelegationService;
/**
* Instantiates a new EVM world updater.
@@ -39,49 +39,49 @@ public class EVMWorldUpdater implements WorldUpdater {
* @param gasCalculator the gas calculator to check for precompiles.
*/
public EVMWorldUpdater(final WorldUpdater rootWorldUpdater, final GasCalculator gasCalculator) {
this(rootWorldUpdater, new DelegatedCodeService(gasCalculator));
this(rootWorldUpdater, new CodeDelegationService(gasCalculator));
}
private EVMWorldUpdater(
final WorldUpdater rootWorldUpdater, final DelegatedCodeService delegatedCodeService) {
final WorldUpdater rootWorldUpdater, final CodeDelegationService codeDelegationService) {
this.rootWorldUpdater = rootWorldUpdater;
this.delegatedCodeService = delegatedCodeService;
this.codeDelegationService = codeDelegationService;
}
/**
* Authorized code service.
* Code delegation service.
*
* @return the authorized code service
* @return the code delegation service
*/
public DelegatedCodeService authorizedCodeService() {
return delegatedCodeService;
public CodeDelegationService codeDelegationService() {
return codeDelegationService;
}
@Override
public MutableAccount createAccount(final Address address, final long nonce, final Wei balance) {
return delegatedCodeService.processMutableAccount(
return codeDelegationService.processMutableAccount(
this, rootWorldUpdater.createAccount(address, nonce, balance));
}
@Override
public MutableAccount getAccount(final Address address) {
return delegatedCodeService.processMutableAccount(this, rootWorldUpdater.getAccount(address));
return codeDelegationService.processMutableAccount(this, rootWorldUpdater.getAccount(address));
}
@Override
public MutableAccount getOrCreate(final Address address) {
return delegatedCodeService.processMutableAccount(this, rootWorldUpdater.getOrCreate(address));
return codeDelegationService.processMutableAccount(this, rootWorldUpdater.getOrCreate(address));
}
@Override
public MutableAccount getOrCreateSenderAccount(final Address address) {
return delegatedCodeService.processMutableAccount(
return codeDelegationService.processMutableAccount(
this, rootWorldUpdater.getOrCreateSenderAccount(address));
}
@Override
public MutableAccount getSenderAccount(final MessageFrame frame) {
return delegatedCodeService.processMutableAccount(
return codeDelegationService.processMutableAccount(
this, rootWorldUpdater.getSenderAccount(frame));
}
@@ -114,17 +114,17 @@ public class EVMWorldUpdater implements WorldUpdater {
public Optional<WorldUpdater> parentUpdater() {
return rootWorldUpdater.parentUpdater().isPresent()
? Optional.of(
new EVMWorldUpdater(rootWorldUpdater.parentUpdater().get(), delegatedCodeService))
new EVMWorldUpdater(rootWorldUpdater.parentUpdater().get(), codeDelegationService))
: Optional.empty();
}
@Override
public WorldUpdater updater() {
return new EVMWorldUpdater(rootWorldUpdater.updater(), delegatedCodeService);
return new EVMWorldUpdater(rootWorldUpdater.updater(), codeDelegationService);
}
@Override
public Account get(final Address address) {
return delegatedCodeService.processAccount(this, rootWorldUpdater.get(address));
return codeDelegationService.processAccount(this, rootWorldUpdater.get(address));
}
}