diff --git a/crypto/algorithms/src/main/java/org/hyperledger/besu/crypto/AbstractSECP256.java b/crypto/algorithms/src/main/java/org/hyperledger/besu/crypto/AbstractSECP256.java
index bd450b206e..4e228441cc 100644
--- a/crypto/algorithms/src/main/java/org/hyperledger/besu/crypto/AbstractSECP256.java
+++ b/crypto/algorithms/src/main/java/org/hyperledger/besu/crypto/AbstractSECP256.java
@@ -214,7 +214,7 @@ public abstract class AbstractSECP256 implements SignatureAlgorithm {
@Override
public CodeDelegationSignature createCodeDelegationSignature(
- final BigInteger r, final BigInteger s, final BigInteger yParity) {
+ final BigInteger r, final BigInteger s, final byte yParity) {
return CodeDelegationSignature.create(r, s, yParity);
}
diff --git a/crypto/algorithms/src/main/java/org/hyperledger/besu/crypto/CodeDelegationSignature.java b/crypto/algorithms/src/main/java/org/hyperledger/besu/crypto/CodeDelegationSignature.java
index 06ec72bf0a..e68f30727c 100644
--- a/crypto/algorithms/src/main/java/org/hyperledger/besu/crypto/CodeDelegationSignature.java
+++ b/crypto/algorithms/src/main/java/org/hyperledger/besu/crypto/CodeDelegationSignature.java
@@ -42,7 +42,7 @@ public class CodeDelegationSignature extends SECPSignature {
* @return the new CodeDelegationSignature
*/
public static CodeDelegationSignature create(
- final BigInteger r, final BigInteger s, final BigInteger yParity) {
+ final BigInteger r, final BigInteger s, final byte yParity) {
checkNotNull(r);
checkNotNull(s);
@@ -56,11 +56,6 @@ public class CodeDelegationSignature extends SECPSignature {
"Invalid 's' value, should be < 2^256 but got " + s.toString(16));
}
- if (yParity.compareTo(TWO_POW_256) >= 0) {
- throw new IllegalArgumentException(
- "Invalid 'yParity' value, should be < 2^256 but got " + yParity.toString(16));
- }
-
- return new CodeDelegationSignature(r, s, yParity.byteValue());
+ return new CodeDelegationSignature(r, s, yParity);
}
}
diff --git a/crypto/algorithms/src/main/java/org/hyperledger/besu/crypto/SignatureAlgorithm.java b/crypto/algorithms/src/main/java/org/hyperledger/besu/crypto/SignatureAlgorithm.java
index 4bf8d89c82..a1a79d057a 100644
--- a/crypto/algorithms/src/main/java/org/hyperledger/besu/crypto/SignatureAlgorithm.java
+++ b/crypto/algorithms/src/main/java/org/hyperledger/besu/crypto/SignatureAlgorithm.java
@@ -224,7 +224,7 @@ public interface SignatureAlgorithm {
* @return the code delegation signature
*/
CodeDelegationSignature createCodeDelegationSignature(
- final BigInteger r, final BigInteger s, final BigInteger yParity);
+ final BigInteger r, final BigInteger s, final byte yParity);
/**
* Decode secp signature.
diff --git a/crypto/algorithms/src/test/java/org/hyperledger/besu/crypto/CodeDelegationSignatureTest.java b/crypto/algorithms/src/test/java/org/hyperledger/besu/crypto/CodeDelegationSignatureTest.java
index 332aa14893..1c0cc95ffd 100644
--- a/crypto/algorithms/src/test/java/org/hyperledger/besu/crypto/CodeDelegationSignatureTest.java
+++ b/crypto/algorithms/src/test/java/org/hyperledger/besu/crypto/CodeDelegationSignatureTest.java
@@ -29,19 +29,19 @@ class CodeDelegationSignatureTest {
void testValidInputs() {
BigInteger r = BigInteger.ONE;
BigInteger s = BigInteger.TEN;
- BigInteger yParity = BigInteger.ONE;
+ byte yParity = (byte) 1;
CodeDelegationSignature result = CodeDelegationSignature.create(r, s, yParity);
assertThat(r).isEqualTo(result.getR());
assertThat(s).isEqualTo(result.getS());
- assertThat(yParity.byteValue()).isEqualTo(result.getRecId());
+ assertThat(yParity).isEqualTo(result.getRecId());
}
@Test
void testNullRValue() {
BigInteger s = BigInteger.TEN;
- BigInteger yParity = BigInteger.ZERO;
+ byte yParity = (byte) 0;
assertThatExceptionOfType(NullPointerException.class)
.isThrownBy(() -> CodeDelegationSignature.create(null, s, yParity));
@@ -50,7 +50,7 @@ class CodeDelegationSignatureTest {
@Test
void testNullSValue() {
BigInteger r = BigInteger.ONE;
- BigInteger yParity = BigInteger.ZERO;
+ byte yParity = (byte) 0;
assertThatExceptionOfType(NullPointerException.class)
.isThrownBy(() -> CodeDelegationSignature.create(r, null, yParity));
@@ -60,7 +60,7 @@ class CodeDelegationSignatureTest {
void testRValueExceedsTwoPow256() {
BigInteger r = TWO_POW_256;
BigInteger s = BigInteger.TEN;
- BigInteger yParity = BigInteger.ZERO;
+ byte yParity = (byte) 0;
assertThatExceptionOfType(IllegalArgumentException.class)
.isThrownBy(() -> CodeDelegationSignature.create(r, s, yParity))
@@ -71,34 +71,23 @@ class CodeDelegationSignatureTest {
void testSValueExceedsTwoPow256() {
BigInteger r = BigInteger.ONE;
BigInteger s = TWO_POW_256;
- BigInteger yParity = BigInteger.ZERO;
+ byte yParity = (byte) 0;
assertThatExceptionOfType(IllegalArgumentException.class)
.isThrownBy(() -> CodeDelegationSignature.create(r, s, yParity))
.withMessageContainingAll("Invalid 's' value, should be < 2^256");
}
- @Test
- void testYParityExceedsTwoPow256() {
- BigInteger r = BigInteger.ONE;
- BigInteger s = BigInteger.TWO;
- BigInteger yParity = TWO_POW_256;
-
- assertThatExceptionOfType(IllegalArgumentException.class)
- .isThrownBy(() -> CodeDelegationSignature.create(r, s, yParity))
- .withMessageContainingAll("Invalid 'yParity' value, should be < 2^256");
- }
-
@Test
void testValidYParityZero() {
BigInteger r = BigInteger.ONE;
BigInteger s = BigInteger.TEN;
- BigInteger yParity = BigInteger.ZERO;
+ byte yParity = (byte) 0;
CodeDelegationSignature result = CodeDelegationSignature.create(r, s, yParity);
assertThat(r).isEqualTo(result.getR());
assertThat(s).isEqualTo(result.getS());
- assertThat(yParity.byteValue()).isEqualTo(result.getRecId());
+ assertThat(yParity).isEqualTo(result.getRecId());
}
}
diff --git a/datatypes/src/main/java/org/hyperledger/besu/datatypes/CodeDelegation.java b/datatypes/src/main/java/org/hyperledger/besu/datatypes/CodeDelegation.java
index 7b9e3d7d44..aab8203e29 100644
--- a/datatypes/src/main/java/org/hyperledger/besu/datatypes/CodeDelegation.java
+++ b/datatypes/src/main/java/org/hyperledger/besu/datatypes/CodeDelegation.java
@@ -25,7 +25,7 @@ import java.util.Optional;
*/
public interface CodeDelegation {
/** The cost of delegating code on an existing account. */
- long PER_AUTH_BASE_COST = 2_500L;
+ long PER_AUTH_BASE_COST = 12_500L;
/**
* Return the chain id.
diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/execution/TracedJsonRpcProcessor.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/execution/TracedJsonRpcProcessor.java
index 2a38afd630..4ac790617f 100644
--- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/execution/TracedJsonRpcProcessor.java
+++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/execution/TracedJsonRpcProcessor.java
@@ -107,6 +107,7 @@ public class TracedJsonRpcProcessor implements JsonRpcProcessor {
case INVALID_PROPOSAL_PARAMS:
case INVALID_REMOTE_CAPABILITIES_PARAMS:
case INVALID_REWARD_PERCENTILES_PARAMS:
+ case INVALID_REQUESTS_PARAMS:
case INVALID_SEALER_ID_PARAMS:
case INVALID_STORAGE_KEYS_PARAMS:
case INVALID_SUBSCRIPTION_PARAMS:
diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/response/RpcErrorType.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/response/RpcErrorType.java
index a2b7d17591..fa67fce15b 100644
--- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/response/RpcErrorType.java
+++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/response/RpcErrorType.java
@@ -95,6 +95,7 @@ public enum RpcErrorType implements RpcMethodError {
INVALID_REMOTE_CAPABILITIES_PARAMS(
INVALID_PARAMS_ERROR_CODE, "Invalid remote capabilities params"),
INVALID_REWARD_PERCENTILES_PARAMS(INVALID_PARAMS_ERROR_CODE, "Invalid reward percentiles params"),
+ INVALID_REQUESTS_PARAMS(INVALID_PARAMS_ERROR_CODE, "Invalid requests params"),
INVALID_SEALER_ID_PARAMS(INVALID_PARAMS_ERROR_CODE, "Invalid sealer ID params"),
INVALID_STORAGE_KEYS_PARAMS(INVALID_PARAMS_ERROR_CODE, "Invalid storage keys params"),
INVALID_SUBSCRIPTION_PARAMS(INVALID_PARAMS_ERROR_CODE, "Invalid subscription params"),
diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/CodeDelegation.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/CodeDelegation.java
index 68fa958a8d..ef38a98222 100644
--- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/CodeDelegation.java
+++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/CodeDelegation.java
@@ -20,7 +20,7 @@ import org.hyperledger.besu.crypto.SignatureAlgorithm;
import org.hyperledger.besu.crypto.SignatureAlgorithmFactory;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.Hash;
-import org.hyperledger.besu.ethereum.core.encoding.CodeDelegationEncoder;
+import org.hyperledger.besu.ethereum.core.encoding.CodeDelegationTransactionEncoder;
import org.hyperledger.besu.ethereum.rlp.BytesValueRLPOutput;
import java.math.BigInteger;
@@ -140,7 +140,7 @@ public class CodeDelegation implements org.hyperledger.besu.datatypes.CodeDelega
private Optional
computeAuthority() {
BytesValueRLPOutput rlpOutput = new BytesValueRLPOutput();
- CodeDelegationEncoder.encodeSingleCodeDelegationWithoutSignature(this, rlpOutput);
+ CodeDelegationTransactionEncoder.encodeSingleCodeDelegationWithoutSignature(this, rlpOutput);
final Hash hash = Hash.hash(Bytes.concatenate(MAGIC, rlpOutput.encoded()));
diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/Transaction.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/Transaction.java
index 0da8f8f28a..1926fa8a7d 100644
--- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/Transaction.java
+++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/Transaction.java
@@ -38,7 +38,7 @@ import org.hyperledger.besu.datatypes.VersionedHash;
import org.hyperledger.besu.datatypes.Wei;
import org.hyperledger.besu.ethereum.core.encoding.AccessListTransactionEncoder;
import org.hyperledger.besu.ethereum.core.encoding.BlobTransactionEncoder;
-import org.hyperledger.besu.ethereum.core.encoding.CodeDelegationEncoder;
+import org.hyperledger.besu.ethereum.core.encoding.CodeDelegationTransactionEncoder;
import org.hyperledger.besu.ethereum.core.encoding.EncodingContext;
import org.hyperledger.besu.ethereum.core.encoding.TransactionDecoder;
import org.hyperledger.besu.ethereum.core.encoding.TransactionEncoder;
@@ -937,7 +937,8 @@ public class Transaction
chainId,
accessList,
rlpOutput);
- CodeDelegationEncoder.encodeCodeDelegationInner(authorizationList, rlpOutput);
+ CodeDelegationTransactionEncoder.encodeCodeDelegationInner(
+ authorizationList, rlpOutput);
rlpOutput.endList();
});
return Bytes.concatenate(Bytes.of(TransactionType.DELEGATE_CODE.getSerializedType()), encoded);
diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/CodeDelegationTransactionDecoder.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/CodeDelegationTransactionDecoder.java
index 6448940d8d..88d502f7a1 100644
--- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/CodeDelegationTransactionDecoder.java
+++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/CodeDelegationTransactionDecoder.java
@@ -81,7 +81,7 @@ public class CodeDelegationTransactionDecoder {
final Address address = Address.wrap(input.readBytes());
final long nonce = input.readLongScalar();
- final BigInteger yParity = input.readUInt256Scalar().toUnsignedBigInteger();
+ final byte yParity = (byte) input.readUnsignedByteScalar();
final BigInteger r = input.readUInt256Scalar().toUnsignedBigInteger();
final BigInteger s = input.readUInt256Scalar().toUnsignedBigInteger();
diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/CodeDelegationEncoder.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/CodeDelegationTransactionEncoder.java
similarity index 95%
rename from ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/CodeDelegationEncoder.java
rename to ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/CodeDelegationTransactionEncoder.java
index 4cedf93adc..c34de12925 100644
--- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/CodeDelegationEncoder.java
+++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/CodeDelegationTransactionEncoder.java
@@ -25,9 +25,9 @@ import java.util.List;
import org.apache.tuweni.bytes.Bytes;
-public class CodeDelegationEncoder {
+public class CodeDelegationTransactionEncoder {
- private CodeDelegationEncoder() {
+ private CodeDelegationTransactionEncoder() {
// private constructor
}
@@ -49,7 +49,7 @@ public class CodeDelegationEncoder {
final CodeDelegation payload, final RLPOutput rlpOutput) {
rlpOutput.startList();
encodeAuthorizationDetails(payload, rlpOutput);
- rlpOutput.writeIntScalar(payload.signature().getRecId());
+ rlpOutput.writeUnsignedByte(payload.signature().getRecId() & 0xFF);
rlpOutput.writeBigIntegerScalar(payload.signature().getR());
rlpOutput.writeBigIntegerScalar(payload.signature().getS());
rlpOutput.endList();
diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/TransactionEncoder.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/TransactionEncoder.java
index 26bad56c6d..a97f24cbd0 100644
--- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/TransactionEncoder.java
+++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/TransactionEncoder.java
@@ -41,7 +41,7 @@ public class TransactionEncoder {
TransactionType.BLOB,
BlobTransactionEncoder::encode,
TransactionType.DELEGATE_CODE,
- CodeDelegationEncoder::encode);
+ CodeDelegationTransactionEncoder::encode);
private static final ImmutableMap POOLED_TRANSACTION_ENCODERS =
ImmutableMap.of(TransactionType.BLOB, BlobPooledTransactionEncoder::encode);
diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/CodeDelegationProcessor.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/CodeDelegationProcessor.java
index 58f66b6afb..977b503193 100644
--- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/CodeDelegationProcessor.java
+++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/CodeDelegationProcessor.java
@@ -14,6 +14,8 @@
*/
package org.hyperledger.besu.ethereum.mainnet;
+import static org.hyperledger.besu.evm.account.Account.MAX_NONCE;
+
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.ethereum.core.CodeDelegation;
import org.hyperledger.besu.ethereum.core.Transaction;
@@ -30,9 +32,12 @@ public class CodeDelegationProcessor {
private static final Logger LOG = LoggerFactory.getLogger(CodeDelegationProcessor.class);
private final Optional maybeChainId;
+ private final BigInteger halfCurveOrder;
- public CodeDelegationProcessor(final Optional maybeChainId) {
+ public CodeDelegationProcessor(
+ final Optional maybeChainId, final BigInteger halfCurveOrder) {
this.maybeChainId = maybeChainId;
+ this.halfCurveOrder = halfCurveOrder;
}
/**
@@ -89,6 +94,22 @@ public class CodeDelegationProcessor {
return;
}
+ if (codeDelegation.nonce() == MAX_NONCE) {
+ LOG.trace("Nonce of code delegation must be less than 2^64-1");
+ return;
+ }
+
+ if (codeDelegation.signature().getS().compareTo(halfCurveOrder) > 0) {
+ LOG.trace(
+ "Invalid signature for code delegation. S value must be less or equal than the half curve order.");
+ return;
+ }
+
+ if (codeDelegation.signature().getRecId() != 0 && codeDelegation.signature().getRecId() != 1) {
+ LOG.trace("Invalid signature for code delegation. RecId must be 0 or 1.");
+ return;
+ }
+
final Optional authorizer = codeDelegation.authorizer();
if (authorizer.isEmpty()) {
LOG.trace("Invalid signature for code delegation");
@@ -128,7 +149,9 @@ public class CodeDelegationProcessor {
result.incremenentAlreadyExistingDelegators();
}
- evmWorldUpdater.authorizedCodeService().addDelegatedCode(authority, codeDelegation.address());
+ evmWorldUpdater
+ .authorizedCodeService()
+ .processDelegatedCodeAuthorization(authority, codeDelegation.address());
authority.incrementNonce();
}
}
diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetProtocolSpecs.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetProtocolSpecs.java
index 87396bff3e..26c9e69c8f 100644
--- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetProtocolSpecs.java
+++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetProtocolSpecs.java
@@ -18,6 +18,8 @@ import static org.hyperledger.besu.ethereum.mainnet.requests.MainnetRequestsProc
import org.hyperledger.besu.config.GenesisConfigOptions;
import org.hyperledger.besu.config.PowAlgorithm;
+import org.hyperledger.besu.crypto.SignatureAlgorithm;
+import org.hyperledger.besu.crypto.SignatureAlgorithmFactory;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.TransactionType;
import org.hyperledger.besu.datatypes.Wei;
@@ -80,6 +82,8 @@ import java.util.Optional;
import java.util.Set;
import java.util.stream.IntStream;
+import com.google.common.base.Supplier;
+import com.google.common.base.Suppliers;
import com.google.common.io.Resources;
import io.vertx.core.json.JsonArray;
@@ -89,6 +93,9 @@ public abstract class MainnetProtocolSpecs {
private static final Address RIPEMD160_PRECOMPILE =
Address.fromHexString("0x0000000000000000000000000000000000000003");
+ private static final Supplier SIGNATURE_ALGORITHM =
+ Suppliers.memoize(SignatureAlgorithmFactory::getInstance);
+
// A consensus bug at Ethereum mainnet transaction 0xcf416c53
// deleted an empty account even when the message execution scope
// failed, but the transaction itself succeeded.
@@ -714,7 +721,8 @@ public abstract class MainnetProtocolSpecs {
evmConfiguration.evmStackSize(),
feeMarket,
CoinbaseFeePriceCalculator.eip1559(),
- new CodeDelegationProcessor(chainId)))
+ new CodeDelegationProcessor(
+ chainId, SIGNATURE_ALGORITHM.get().getHalfCurveOrder())))
// change to check for max blob gas per block for EIP-4844
.transactionValidatorFactoryBuilder(
(evm, gasLimitCalculator, feeMarket) ->
diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionProcessor.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionProcessor.java
index c662c18864..3425708247 100644
--- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionProcessor.java
+++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionProcessor.java
@@ -286,7 +286,7 @@ public class MainnetTransactionProcessor {
final TransactionValidationParams transactionValidationParams,
final PrivateMetadataUpdater privateMetadataUpdater,
final Wei blobGasPrice) {
- final EVMWorldUpdater evmWorldUpdater = new EVMWorldUpdater(worldState);
+ final EVMWorldUpdater evmWorldUpdater = new EVMWorldUpdater(worldState, gasCalculator);
try {
final var transactionValidator = transactionValidatorFactory.get();
LOG.trace("Starting execution of {}", transaction);
@@ -352,6 +352,8 @@ public class MainnetTransactionProcessor {
codeDelegationRefund =
gasCalculator.calculateDelegateCodeGasRefund(
(codeDelegationResult.alreadyExistingDelegators()));
+
+ evmWorldUpdater.commit();
}
final List accessListEntries = transaction.getAccessList().orElse(List.of());
@@ -415,7 +417,6 @@ public class MainnetTransactionProcessor {
.miningBeneficiary(miningBeneficiary)
.blockHashLookup(blockHashLookup)
.contextVariables(contextVariablesBuilder.build())
- .accessListWarmAddresses(warmAddressList)
.accessListWarmStorage(storageList);
if (transaction.getVersionedHashes().isPresent()) {
@@ -439,11 +440,17 @@ public class MainnetTransactionProcessor {
.contract(contractAddress)
.inputData(initCodeBytes.slice(code.getSize()))
.code(code)
+ .accessListWarmAddresses(warmAddressList)
.build();
} else {
@SuppressWarnings("OptionalGetWithoutIsPresent") // isContractCall tests isPresent
final Address to = transaction.getTo().get();
final Optional maybeContract = Optional.ofNullable(evmWorldUpdater.get(to));
+
+ if (maybeContract.isPresent() && maybeContract.get().hasDelegatedCode()) {
+ warmAddressList.add(maybeContract.get().delegatedCodeAddress().get());
+ }
+
initialFrame =
commonMessageFrameBuilder
.type(MessageFrame.Type.MESSAGE_CALL)
@@ -454,6 +461,7 @@ public class MainnetTransactionProcessor {
maybeContract
.map(c -> messageCallProcessor.getCodeFromEVM(c.getCodeHash(), c.getCode()))
.orElse(CodeV0.EMPTY_CODE))
+ .accessListWarmAddresses(warmAddressList)
.build();
}
Deque messageFrameStack = initialFrame.getMessageFrameStack();
diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionValidator.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionValidator.java
index 0e86b6b878..2b9fea0f3d 100644
--- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionValidator.java
+++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionValidator.java
@@ -52,6 +52,8 @@ import org.bouncycastle.crypto.digests.SHA256Digest;
*/
public class MainnetTransactionValidator implements TransactionValidator {
+ public static final BigInteger TWO_POW_8 = BigInteger.TWO.pow(8);
+ public static final BigInteger TWO_POW_64 = BigInteger.TWO.pow(64);
public static final BigInteger TWO_POW_256 = BigInteger.TWO.pow(256);
private final GasCalculator gasCalculator;
@@ -158,30 +160,26 @@ public class MainnetTransactionValidator implements TransactionValidator {
"transaction code delegation transactions must have a to address");
}
- final BigInteger halfCurveOrder = SignatureAlgorithmFactory.getInstance().getHalfCurveOrder();
final Optional> validationResult =
transaction
.getCodeDelegationList()
.map(
codeDelegations -> {
for (CodeDelegation codeDelegation : codeDelegations) {
- if (codeDelegation.chainId().compareTo(TWO_POW_256) >= 0) {
+ if (codeDelegation.chainId().compareTo(TWO_POW_64) >= 0) {
throw new IllegalArgumentException(
- "Invalid 'chainId' value, should be < 2^256 but got "
+ "Invalid 'chainId' value, should be < 2^64 but got "
+ codeDelegation.chainId());
}
- if (codeDelegation.signature().getS().compareTo(halfCurveOrder) > 0) {
- return ValidationResult.invalid(
- TransactionInvalidReason.INVALID_SIGNATURE,
- "Invalid signature for code delegation. S value must be less or equal than the half curve order.");
+ if (codeDelegation.r().compareTo(TWO_POW_256) >= 0) {
+ throw new IllegalArgumentException(
+ "Invalid 'r' value, should be < 2^256 but got " + codeDelegation.r());
}
- if (codeDelegation.signature().getRecId() != 0
- && codeDelegation.signature().getRecId() != 1) {
- return ValidationResult.invalid(
- TransactionInvalidReason.INVALID_SIGNATURE,
- "Invalid signature for code delegation. RecId value must be 0 or 1.");
+ if (codeDelegation.s().compareTo(TWO_POW_256) >= 0) {
+ throw new IllegalArgumentException(
+ "Invalid 's' value, should be < 2^256 but got " + codeDelegation.s());
}
}
diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/encoding/CodeDelegationEncoderTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/encoding/CodeDelegationTransactionEncoderTest.java
similarity index 93%
rename from ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/encoding/CodeDelegationEncoderTest.java
rename to ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/encoding/CodeDelegationTransactionEncoderTest.java
index 34b7c6d449..b09fde48dd 100644
--- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/encoding/CodeDelegationEncoderTest.java
+++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/encoding/CodeDelegationTransactionEncoderTest.java
@@ -30,7 +30,7 @@ import org.apache.tuweni.bytes.Bytes;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
-class CodeDelegationEncoderTest {
+class CodeDelegationTransactionEncoderTest {
private static final Supplier SIGNATURE_ALGORITHM =
Suppliers.memoize(SignatureAlgorithmFactory::getInstance);
@@ -59,7 +59,7 @@ class CodeDelegationEncoderTest {
"3b1dbace38ceb862a65bf2eac0637693b5c3493bcb2a022dd614c0a74cce0b99", 16),
(byte) 0));
- CodeDelegationEncoder.encodeSingleCodeDelegation(authorization, output);
+ CodeDelegationTransactionEncoder.encodeSingleCodeDelegation(authorization, output);
assertThat(output.encoded())
.isEqualTo(
@@ -85,7 +85,7 @@ class CodeDelegationEncoderTest {
"25b58a1ff8ad00bddbbfa1d5c2411961cbb6d08dcdc8ae88303db3c6cf983031", 16),
(byte) 1));
- CodeDelegationEncoder.encodeSingleCodeDelegation(authorization, output);
+ CodeDelegationTransactionEncoder.encodeSingleCodeDelegation(authorization, output);
assertThat(output.encoded())
.isEqualTo(
@@ -111,7 +111,7 @@ class CodeDelegationEncoderTest {
"3c8a25b2becd6e666f69803d1ae3322f2e137b7745c2c7f19da80f993ffde4df", 16),
(byte) 1));
- CodeDelegationEncoder.encodeSingleCodeDelegation(authorization, output);
+ CodeDelegationTransactionEncoder.encodeSingleCodeDelegation(authorization, output);
assertThat(output.encoded())
.isEqualTo(
diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/CodeDelegationProcessorTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/CodeDelegationProcessorTest.java
new file mode 100644
index 0000000000..c4b45f9e08
--- /dev/null
+++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/CodeDelegationProcessorTest.java
@@ -0,0 +1,236 @@
+/*
+ * 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.ethereum.mainnet;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import org.hyperledger.besu.crypto.SECPSignature;
+import org.hyperledger.besu.datatypes.Address;
+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.EVMWorldUpdater;
+
+import java.math.BigInteger;
+import java.util.List;
+import java.util.Optional;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.Mock;
+import org.mockito.junit.jupiter.MockitoExtension;
+
+@ExtendWith(MockitoExtension.class)
+class CodeDelegationProcessorTest {
+
+ @Mock private EVMWorldUpdater worldUpdater;
+
+ @Mock private Transaction transaction;
+
+ @Mock private DelegatedCodeService authorizedCodeService;
+
+ @Mock private MutableAccount authority;
+
+ private CodeDelegationProcessor processor;
+ private static final BigInteger CHAIN_ID = BigInteger.valueOf(1);
+ private static final BigInteger HALF_CURVE_ORDER = BigInteger.valueOf(1000);
+ private static final Address DELEGATE_ADDRESS =
+ Address.fromHexString("0x9876543210987654321098765432109876543210");
+
+ @BeforeEach
+ void setUp() {
+ processor = new CodeDelegationProcessor(Optional.of(CHAIN_ID), HALF_CURVE_ORDER);
+ }
+
+ @Test
+ void shouldRejectInvalidChainId() {
+ // Arrange
+ CodeDelegation codeDelegation = createCodeDelegation(BigInteger.valueOf(2), 0L);
+ when(transaction.getCodeDelegationList()).thenReturn(Optional.of(List.of(codeDelegation)));
+
+ // Act
+ CodeDelegationResult result = processor.process(worldUpdater, transaction);
+
+ // Assert
+ assertThat(result.alreadyExistingDelegators()).isZero();
+ verify(worldUpdater, never()).createAccount(any());
+ verify(worldUpdater, never()).getAccount(any());
+ }
+
+ @Test
+ void shouldRejectMaxNonce() {
+ // Arrange
+ CodeDelegation codeDelegation = createCodeDelegation(CHAIN_ID, Account.MAX_NONCE);
+ when(transaction.getCodeDelegationList()).thenReturn(Optional.of(List.of(codeDelegation)));
+
+ // Act
+ CodeDelegationResult result = processor.process(worldUpdater, transaction);
+
+ // Assert
+ assertThat(result.alreadyExistingDelegators()).isZero();
+ verify(worldUpdater, never()).createAccount(any());
+ verify(worldUpdater, never()).getAccount(any());
+ }
+
+ @Test
+ void shouldProcessValidDelegationForNewAccount() {
+ // Arrange
+ when(worldUpdater.authorizedCodeService()).thenReturn(authorizedCodeService);
+ CodeDelegation codeDelegation = createCodeDelegation(CHAIN_ID, 0L);
+ when(transaction.getCodeDelegationList()).thenReturn(Optional.of(List.of(codeDelegation)));
+ when(worldUpdater.getAccount(any())).thenReturn(null);
+ when(worldUpdater.createAccount(any())).thenReturn(authority);
+ when(authority.getNonce()).thenReturn(0L);
+
+ // Act
+ CodeDelegationResult result = processor.process(worldUpdater, transaction);
+
+ // Assert
+ assertThat(result.alreadyExistingDelegators()).isZero();
+ verify(worldUpdater).createAccount(any());
+ verify(authority).incrementNonce();
+ verify(authorizedCodeService).processDelegatedCodeAuthorization(authority, DELEGATE_ADDRESS);
+ }
+
+ @Test
+ void shouldProcessValidDelegationForExistingAccount() {
+ // Arrange
+ when(worldUpdater.authorizedCodeService()).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);
+
+ // Act
+ CodeDelegationResult result = processor.process(worldUpdater, transaction);
+
+ // Assert
+ assertThat(result.alreadyExistingDelegators()).isEqualTo(1);
+ verify(worldUpdater, never()).createAccount(any());
+ verify(authority).incrementNonce();
+ verify(authorizedCodeService).processDelegatedCodeAuthorization(authority, DELEGATE_ADDRESS);
+ }
+
+ @Test
+ void shouldRejectDelegationWithInvalidNonce() {
+ // Arrange
+ when(worldUpdater.authorizedCodeService()).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);
+
+ // Act
+ CodeDelegationResult result = processor.process(worldUpdater, transaction);
+
+ // Assert
+ assertThat(result.alreadyExistingDelegators()).isZero();
+ verify(authority, never()).incrementNonce();
+ verify(authorizedCodeService, never()).processDelegatedCodeAuthorization(any(), any());
+ }
+
+ @Test
+ void shouldRejectDelegationWithSGreaterThanHalfCurveOrder() {
+ // Arrange
+ CodeDelegation codeDelegation =
+ createCodeDelegation(CHAIN_ID, 1L, HALF_CURVE_ORDER.add(BigInteger.ONE));
+ when(transaction.getCodeDelegationList()).thenReturn(Optional.of(List.of(codeDelegation)));
+
+ // Act
+ CodeDelegationResult result = processor.process(worldUpdater, transaction);
+
+ // Assert
+ assertThat(result.alreadyExistingDelegators()).isZero();
+ verify(authority, never()).incrementNonce();
+ verify(authorizedCodeService, never()).processDelegatedCodeAuthorization(any(), any());
+ }
+
+ @Test
+ void shouldRejectDelegationWithRecIdNeitherZeroNorOne() {
+ // Arrange
+ final SECPSignature signature = new SECPSignature(BigInteger.ONE, BigInteger.ONE, (byte) 2);
+ CodeDelegation codeDelegation =
+ new org.hyperledger.besu.ethereum.core.CodeDelegation(
+ CHAIN_ID, CodeDelegationProcessorTest.DELEGATE_ADDRESS, 1L, signature);
+ when(transaction.getCodeDelegationList()).thenReturn(Optional.of(List.of(codeDelegation)));
+
+ // Act
+ CodeDelegationResult result = processor.process(worldUpdater, transaction);
+
+ // Assert
+ assertThat(result.alreadyExistingDelegators()).isZero();
+ verify(authority, never()).incrementNonce();
+ verify(authorizedCodeService, never()).processDelegatedCodeAuthorization(any(), any());
+ }
+
+ @Test
+ void shouldRejectDelegationWithInvalidSignature() {
+ // Arrange
+ CodeDelegation codeDelegation = mock(org.hyperledger.besu.ethereum.core.CodeDelegation.class);
+ when(codeDelegation.chainId()).thenReturn(CHAIN_ID);
+ when(codeDelegation.nonce()).thenReturn(1L);
+ when(codeDelegation.signature())
+ .thenReturn(new SECPSignature(BigInteger.ONE, BigInteger.ONE, (byte) 0));
+ when(codeDelegation.authorizer()).thenReturn(Optional.empty());
+ when(transaction.getCodeDelegationList()).thenReturn(Optional.of(List.of(codeDelegation)));
+
+ // Act
+ CodeDelegationResult result = processor.process(worldUpdater, transaction);
+
+ // Assert
+ assertThat(result.alreadyExistingDelegators()).isZero();
+ verify(authority, never()).incrementNonce();
+ verify(authorizedCodeService, never()).processDelegatedCodeAuthorization(any(), any());
+ }
+
+ @Test
+ void shouldRejectDelegationWhenCannotSetDelegatedCode() {
+ // Arrange
+ when(worldUpdater.authorizedCodeService()).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);
+
+ // Act
+ CodeDelegationResult result = processor.process(worldUpdater, transaction);
+
+ // Assert
+ assertThat(result.alreadyExistingDelegators()).isZero();
+ verify(authority, never()).incrementNonce();
+ verify(authorizedCodeService, never()).processDelegatedCodeAuthorization(any(), any());
+ }
+
+ private CodeDelegation createCodeDelegation(final BigInteger chainId, final long nonce) {
+ return createCodeDelegation(chainId, nonce, BigInteger.ONE);
+ }
+
+ private CodeDelegation createCodeDelegation(
+ final BigInteger chainId, final long nonce, final BigInteger s) {
+ final SECPSignature signature = new SECPSignature(BigInteger.ONE, s, (byte) 0);
+
+ return new org.hyperledger.besu.ethereum.core.CodeDelegation(
+ chainId, CodeDelegationProcessorTest.DELEGATE_ADDRESS, nonce, signature);
+ }
+}
diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionProcessorTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionProcessorTest.java
index c40da7210e..3403dc0b39 100644
--- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionProcessorTest.java
+++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionProcessorTest.java
@@ -89,7 +89,7 @@ class MainnetTransactionProcessorTest {
MAX_STACK_SIZE,
FeeMarket.legacy(),
CoinbaseFeePriceCalculator.frontier(),
- new CodeDelegationProcessor(Optional.of(BigInteger.ONE)));
+ new CodeDelegationProcessor(Optional.of(BigInteger.ONE), BigInteger.TEN));
}
@Test
diff --git a/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/T8nExecutor.java b/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/T8nExecutor.java
index ba55fdf29e..8c64a031b3 100644
--- a/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/T8nExecutor.java
+++ b/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/T8nExecutor.java
@@ -231,10 +231,14 @@ public class T8nExecutor {
final long authorizationNonce =
Bytes.fromHexStringLenient(entryAsJson.get("nonce").textValue()).toLong();
- final byte authorizationV =
+ final BigInteger authorizationV =
Bytes.fromHexStringLenient(entryAsJson.get("v").textValue())
- .toUnsignedBigInteger()
- .byteValueExact();
+ .toUnsignedBigInteger();
+ if (authorizationV.compareTo(BigInteger.valueOf(256)) >= 0) {
+ throw new IllegalArgumentException(
+ "Invalid authorizationV value. Must be less than 256");
+ }
+
final BigInteger authorizationR =
Bytes.fromHexStringLenient(entryAsJson.get("r").textValue())
.toUnsignedBigInteger();
@@ -243,7 +247,7 @@ public class T8nExecutor {
.toUnsignedBigInteger();
final SECPSignature authorizationSignature =
- new SECPSignature(authorizationR, authorizationS, authorizationV);
+ new SECPSignature(authorizationR, authorizationS, authorizationV.byteValue());
authorizations.add(
new org.hyperledger.besu.ethereum.core.CodeDelegation(
diff --git a/evm/src/main/java/org/hyperledger/besu/evm/account/BaseDelegatedCodeAccount.java b/evm/src/main/java/org/hyperledger/besu/evm/account/BaseDelegatedCodeAccount.java
index 0e5219d835..4ee28145de 100644
--- a/evm/src/main/java/org/hyperledger/besu/evm/account/BaseDelegatedCodeAccount.java
+++ b/evm/src/main/java/org/hyperledger/besu/evm/account/BaseDelegatedCodeAccount.java
@@ -17,6 +17,7 @@ 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;
import java.util.Optional;
@@ -25,13 +26,17 @@ import org.apache.tuweni.bytes.Bytes;
class BaseDelegatedCodeAccount {
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(
- final WorldUpdater worldUpdater, final Address delegatedCodeAddress) {
+ final WorldUpdater worldUpdater,
+ final Address delegatedCodeAddress,
+ final GasCalculator gasCalculator) {
this.worldUpdater = worldUpdater;
+ this.gasCalculator = gasCalculator;
this.delegatedCodeAddress = delegatedCodeAddress;
}
@@ -86,6 +91,9 @@ class BaseDelegatedCodeAccount {
}
private Bytes resolveDelegatedCode() {
+ if (gasCalculator.isPrecompile(delegatedCodeAddress)) {
+ return Bytes.EMPTY;
+ }
return getDelegatedAccount().map(Account::getUnprocessedCode).orElse(Bytes.EMPTY);
}
diff --git a/evm/src/main/java/org/hyperledger/besu/evm/account/DelegatedCodeAccount.java b/evm/src/main/java/org/hyperledger/besu/evm/account/DelegatedCodeAccount.java
index 1eba364c19..0ac969abad 100644
--- a/evm/src/main/java/org/hyperledger/besu/evm/account/DelegatedCodeAccount.java
+++ b/evm/src/main/java/org/hyperledger/besu/evm/account/DelegatedCodeAccount.java
@@ -17,6 +17,7 @@ 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;
import java.util.NavigableMap;
@@ -37,12 +38,14 @@ public class DelegatedCodeAccount extends BaseDelegatedCodeAccount implements Ac
* @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(
final WorldUpdater worldUpdater,
final Account wrappedAccount,
- final Address codeDelegationAddress) {
- super(worldUpdater, codeDelegationAddress);
+ final Address codeDelegationAddress,
+ final GasCalculator gasCalculator) {
+ super(worldUpdater, codeDelegationAddress, gasCalculator);
this.wrappedAccount = wrappedAccount;
}
diff --git a/evm/src/main/java/org/hyperledger/besu/evm/account/MutableDelegatedCodeAccount.java b/evm/src/main/java/org/hyperledger/besu/evm/account/MutableDelegatedCodeAccount.java
index 0e1e1145dd..20894b4f28 100644
--- a/evm/src/main/java/org/hyperledger/besu/evm/account/MutableDelegatedCodeAccount.java
+++ b/evm/src/main/java/org/hyperledger/besu/evm/account/MutableDelegatedCodeAccount.java
@@ -17,6 +17,7 @@ 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;
import java.util.Map;
@@ -39,12 +40,14 @@ public class MutableDelegatedCodeAccount extends BaseDelegatedCodeAccount
* @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(
final WorldUpdater worldUpdater,
final MutableAccount wrappedAccount,
- final Address codeDelegationAddress) {
- super(worldUpdater, codeDelegationAddress);
+ final Address codeDelegationAddress,
+ final GasCalculator gasCalculator) {
+ super(worldUpdater, codeDelegationAddress, gasCalculator);
this.wrappedAccount = wrappedAccount;
}
diff --git a/evm/src/main/java/org/hyperledger/besu/evm/gascalculator/GasCalculator.java b/evm/src/main/java/org/hyperledger/besu/evm/gascalculator/GasCalculator.java
index fd453deac5..4c6770e70d 100644
--- a/evm/src/main/java/org/hyperledger/besu/evm/gascalculator/GasCalculator.java
+++ b/evm/src/main/java/org/hyperledger/besu/evm/gascalculator/GasCalculator.java
@@ -666,14 +666,4 @@ public interface GasCalculator {
default long calculateDelegateCodeGasRefund(final long alreadyExistingAccountSize) {
return 0L;
}
-
- /**
- * Returns the gas cost for resolving the code of a delegate account.
- *
- * @param isWarm whether the account is warm
- * @return the gas cost
- */
- default long delegatedCodeResolutionGasCost(final boolean isWarm) {
- return 0L;
- }
}
diff --git a/evm/src/main/java/org/hyperledger/besu/evm/gascalculator/PragueGasCalculator.java b/evm/src/main/java/org/hyperledger/besu/evm/gascalculator/PragueGasCalculator.java
index 33fe98b996..666292e9e1 100644
--- a/evm/src/main/java/org/hyperledger/besu/evm/gascalculator/PragueGasCalculator.java
+++ b/evm/src/main/java/org/hyperledger/besu/evm/gascalculator/PragueGasCalculator.java
@@ -52,9 +52,4 @@ public class PragueGasCalculator extends CancunGasCalculator {
public long calculateDelegateCodeGasRefund(final long alreadyExistingAccounts) {
return existingAccountGasRefund * alreadyExistingAccounts;
}
-
- @Override
- public long delegatedCodeResolutionGasCost(final boolean isWarm) {
- return isWarm ? getWarmStorageReadCost() : getColdAccountAccessCost();
- }
}
diff --git a/evm/src/main/java/org/hyperledger/besu/evm/worldstate/DelegatedCodeGasCostHelper.java b/evm/src/main/java/org/hyperledger/besu/evm/worldstate/DelegatedCodeGasCostHelper.java
index fc67770314..3cdd2dc205 100644
--- a/evm/src/main/java/org/hyperledger/besu/evm/worldstate/DelegatedCodeGasCostHelper.java
+++ b/evm/src/main/java/org/hyperledger/besu/evm/worldstate/DelegatedCodeGasCostHelper.java
@@ -14,6 +14,7 @@
*/
package org.hyperledger.besu.evm.worldstate;
+import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.evm.account.Account;
import org.hyperledger.besu.evm.frame.MessageFrame;
import org.hyperledger.besu.evm.gascalculator.GasCalculator;
@@ -66,9 +67,9 @@ public class DelegatedCodeGasCostHelper {
throw new RuntimeException("A delegated code account must have a delegated code address");
}
- final boolean delegatedCodeIsWarm = frame.warmUpAddress(account.delegatedCodeAddress().get());
final long delegatedCodeResolutionGas =
- gasCalculator.delegatedCodeResolutionGasCost(delegatedCodeIsWarm);
+ calculateDelegatedCodeResolutionGas(
+ frame, gasCalculator, account.delegatedCodeAddress().get());
if (frame.getRemainingGas() < delegatedCodeResolutionGas) {
return new Result(delegatedCodeResolutionGas, Status.INSUFFICIENT_GAS);
@@ -77,4 +78,13 @@ public class DelegatedCodeGasCostHelper {
frame.decrementRemainingGas(delegatedCodeResolutionGas);
return new Result(delegatedCodeResolutionGas, Status.SUCCESS);
}
+
+ private static long calculateDelegatedCodeResolutionGas(
+ final MessageFrame frame, final GasCalculator gasCalculator, final Address delegateeAddress) {
+ final boolean delegatedCodeIsWarm =
+ frame.warmUpAddress(delegateeAddress) || gasCalculator.isPrecompile(delegateeAddress);
+ return delegatedCodeIsWarm
+ ? gasCalculator.getWarmStorageReadCost()
+ : gasCalculator.getColdAccountAccessCost();
+ }
}
diff --git a/evm/src/main/java/org/hyperledger/besu/evm/worldstate/DelegatedCodeService.java b/evm/src/main/java/org/hyperledger/besu/evm/worldstate/DelegatedCodeService.java
index 885324b10b..770d0b79dd 100644
--- a/evm/src/main/java/org/hyperledger/besu/evm/worldstate/DelegatedCodeService.java
+++ b/evm/src/main/java/org/hyperledger/besu/evm/worldstate/DelegatedCodeService.java
@@ -19,6 +19,7 @@ import org.hyperledger.besu.evm.account.Account;
import org.hyperledger.besu.evm.account.DelegatedCodeAccount;
import org.hyperledger.besu.evm.account.MutableAccount;
import org.hyperledger.besu.evm.account.MutableDelegatedCodeAccount;
+import org.hyperledger.besu.evm.gascalculator.GasCalculator;
import org.apache.tuweni.bytes.Bytes;
@@ -27,16 +28,32 @@ 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;
- /** Creates a new DelegatedCodeService. */
- public DelegatedCodeService() {}
+ private final GasCalculator gasCalculator;
/**
- * Add the delegated code to the given account.
+ * Creates a new DelegatedCodeService.
+ *
+ * @param gasCalculator the gas calculator to check for pre compiles.
+ */
+ public DelegatedCodeService(final GasCalculator gasCalculator) {
+ this.gasCalculator = gasCalculator;
+ }
+
+ /**
+ * Process the delegated code authorization. It will set the code to 0x ef0100 + delegated code
+ * 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 delegated code.
+ * @param delegatedCodeAddress the address of the target of the authorization.
*/
- public void addDelegatedCode(final MutableAccount account, final Address delegatedCodeAddress) {
+ public void processDelegatedCodeAuthorization(
+ final MutableAccount account, final Address delegatedCodeAddress) {
+ // authorization to zero address removes any delegated code
+ if (delegatedCodeAddress.equals(Address.ZERO)) {
+ account.setCode(Bytes.EMPTY);
+ return;
+ }
+
account.setCode(Bytes.concatenate(DELEGATED_CODE_PREFIX, delegatedCodeAddress));
}
@@ -64,7 +81,7 @@ public class DelegatedCodeService {
}
return new DelegatedCodeAccount(
- worldUpdater, account, resolveDelegatedAddress(account.getCode()));
+ worldUpdater, account, resolveDelegatedAddress(account.getCode()), gasCalculator);
}
/**
@@ -82,7 +99,7 @@ public class DelegatedCodeService {
}
return new MutableDelegatedCodeAccount(
- worldUpdater, account, resolveDelegatedAddress(account.getCode()));
+ worldUpdater, account, resolveDelegatedAddress(account.getCode()), gasCalculator);
}
/**
diff --git a/evm/src/main/java/org/hyperledger/besu/evm/worldstate/EVMWorldUpdater.java b/evm/src/main/java/org/hyperledger/besu/evm/worldstate/EVMWorldUpdater.java
index 928118acfe..f6e45f4555 100644
--- a/evm/src/main/java/org/hyperledger/besu/evm/worldstate/EVMWorldUpdater.java
+++ b/evm/src/main/java/org/hyperledger/besu/evm/worldstate/EVMWorldUpdater.java
@@ -19,6 +19,7 @@ import org.hyperledger.besu.datatypes.Wei;
import org.hyperledger.besu.evm.account.Account;
import org.hyperledger.besu.evm.account.MutableAccount;
import org.hyperledger.besu.evm.frame.MessageFrame;
+import org.hyperledger.besu.evm.gascalculator.GasCalculator;
import java.util.Collection;
import java.util.Optional;
@@ -35,9 +36,10 @@ public class EVMWorldUpdater implements WorldUpdater {
* Instantiates a new EVM world updater.
*
* @param rootWorldUpdater the root world updater
+ * @param gasCalculator the gas calculator to check for precompiles.
*/
- public EVMWorldUpdater(final WorldUpdater rootWorldUpdater) {
- this(rootWorldUpdater, new DelegatedCodeService());
+ public EVMWorldUpdater(final WorldUpdater rootWorldUpdater, final GasCalculator gasCalculator) {
+ this(rootWorldUpdater, new DelegatedCodeService(gasCalculator));
}
private EVMWorldUpdater(
@@ -110,7 +112,10 @@ public class EVMWorldUpdater implements WorldUpdater {
@Override
public Optional parentUpdater() {
- return rootWorldUpdater.parentUpdater();
+ return rootWorldUpdater.parentUpdater().isPresent()
+ ? Optional.of(
+ new EVMWorldUpdater(rootWorldUpdater.parentUpdater().get(), delegatedCodeService))
+ : Optional.empty();
}
@Override