Skip to content

Commit

Permalink
EIP-7702: devnet-4 changes (#7809)
Browse files Browse the repository at this point in the history
* warm up to address at tx start if account is delegated, restrict auth nonce to 2**64-1

Signed-off-by: Daniel Lehrner <[email protected]>

* rename requestsRoot to requestsHash

Signed-off-by: Jason Frame <[email protected]>

* return no code if account has delegated code to precompile, treat precompile always as warm account when resolving code

Signed-off-by: Daniel Lehrner <[email protected]>

* make accessListWarmAddresses generic again

Signed-off-by: Daniel Lehrner <[email protected]>

* warm delegatee account if transaction destination has delegated code

Signed-off-by: Daniel Lehrner <[email protected]>

* * verify auth nonce less than 2**64-1 during auth processing
* auth to zero address deletes delegation
* auth to precompile returns empty code
* auth nonce < 2**8
* increase auth base cost to 12500

Signed-off-by: Daniel Lehrner <[email protected]>

* generalised requests flat encoding and engine api changes

Signed-off-by: Jason Frame <[email protected]>

* javadoc

Signed-off-by: Jason Frame <[email protected]>

* get tests passing

Signed-off-by: Jason Frame <[email protected]>

* get tests passing

Signed-off-by: Jason Frame <[email protected]>

* clean code

Signed-off-by: Jason Frame <[email protected]>

* change requests to single requestData for each requestType

Signed-off-by: Jason Frame <[email protected]>

* fix PoWBlockCreatorTest after requests data type change

Signed-off-by: Jason Frame <[email protected]>

* don't return request type in getPayload result

Signed-off-by: Jason Frame <[email protected]>

don't return request type in getPayload result

Signed-off-by: Jason Frame <[email protected]>

* include requests in t8n response

Signed-off-by: Jason Frame <[email protected]>

* update contract addresses for consolidation requests and withdrawal requests

Signed-off-by: Jason Frame <[email protected]>

* fix requestHash calculation

Signed-off-by: Jason Frame <[email protected]>

* Ensure that execution requests always return a response

Signed-off-by: Jason Frame <[email protected]>

* added and fixed bound checks, fixed some compilation errors after the rebase

Signed-off-by: Daniel Lehrner <[email protected]>

* revert changes to evm tool spec tests

Signed-off-by: Jason Frame <[email protected]>

* clean up

Signed-off-by: Jason Frame <[email protected]>

* replace AbstractSystemCallRequestProcessor to concrete class and remove specific processors

Signed-off-by: Jason Frame <[email protected]>

* spotless

Signed-off-by: Jason Frame <[email protected]>

* update evmtool tests for 7685 changes

Signed-off-by: Jason Frame <[email protected]>

* use empty requests hash prague fork at genesis

Signed-off-by: Jason Frame <[email protected]>

* review suggestions

Signed-off-by: Jason Frame <[email protected]>

* temporarily comment out osakaTime from Prague

Signed-off-by: Daniel Lehrner <[email protected]>

* engine API validation

Signed-off-by: Jason Frame <[email protected]>

* update plugin API hash

Signed-off-by: Jason Frame <[email protected]>

* fix GenesisStateTest

Signed-off-by: Jason Frame <[email protected]>

* comment out unused evmWorldUpdater.parentUpdater() check

Signed-off-by: Daniel Lehrner <[email protected]>

* added CodeDelegationProcessorTest

Signed-off-by: Daniel Lehrner <[email protected]>

* code clean up

Signed-off-by: Daniel Lehrner <[email protected]>

* spotless

Signed-off-by: Daniel Lehrner <[email protected]>

---------

Signed-off-by: Daniel Lehrner <[email protected]>
Signed-off-by: Jason Frame <[email protected]>
Co-authored-by: Jason Frame <[email protected]>
  • Loading branch information
daniellehrner and jframe authored Dec 3, 2024
1 parent 747a378 commit 07637cf
Show file tree
Hide file tree
Showing 28 changed files with 391 additions and 96 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,7 @@ public SECPSignature createSignature(final BigInteger r, final BigInteger s, fin

@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);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ public CodeDelegationSignature(final BigInteger r, final BigInteger s, final byt
* @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);

Expand All @@ -56,11 +56,6 @@ public static CodeDelegationSignature create(
"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);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,7 @@ Optional<SECPPublicKey> recoverPublicKeyFromSignature(
* @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.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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));
Expand All @@ -50,7 +50,7 @@ void testNullRValue() {
@Test
void testNullSValue() {
BigInteger r = BigInteger.ONE;
BigInteger yParity = BigInteger.ZERO;
byte yParity = (byte) 0;

assertThatExceptionOfType(NullPointerException.class)
.isThrownBy(() -> CodeDelegationSignature.create(r, null, yParity));
Expand All @@ -60,7 +60,7 @@ void testNullSValue() {
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))
Expand All @@ -71,34 +71,23 @@ void testRValueExceedsTwoPow256() {
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());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
*/
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.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ public JsonRpcResponse process(
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:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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"),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
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;
Expand Down Expand Up @@ -140,7 +140,7 @@ public BigInteger s() {

private Optional<Address> computeAuthority() {
BytesValueRLPOutput rlpOutput = new BytesValueRLPOutput();
CodeDelegationEncoder.encodeSingleCodeDelegationWithoutSignature(this, rlpOutput);
CodeDelegationTransactionEncoder.encodeSingleCodeDelegationWithoutSignature(this, rlpOutput);

final Hash hash = Hash.hash(Bytes.concatenate(MAGIC, rlpOutput.encoded()));

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
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;
Expand Down Expand Up @@ -937,7 +937,8 @@ private static Bytes codeDelegationPreimage(
chainId,
accessList,
rlpOutput);
CodeDelegationEncoder.encodeCodeDelegationInner(authorizationList, rlpOutput);
CodeDelegationTransactionEncoder.encodeCodeDelegationInner(
authorizationList, rlpOutput);
rlpOutput.endList();
});
return Bytes.concatenate(Bytes.of(TransactionType.DELEGATE_CODE.getSerializedType()), encoded);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ public static CodeDelegation decodeInnerPayload(final RLPInput input) {
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();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,9 @@

import org.apache.tuweni.bytes.Bytes;

public class CodeDelegationEncoder {
public class CodeDelegationTransactionEncoder {

private CodeDelegationEncoder() {
private CodeDelegationTransactionEncoder() {
// private constructor
}

Expand All @@ -49,7 +49,7 @@ public static void encodeSingleCodeDelegation(
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();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ interface Encoder {
TransactionType.BLOB,
BlobTransactionEncoder::encode,
TransactionType.DELEGATE_CODE,
CodeDelegationEncoder::encode);
CodeDelegationTransactionEncoder::encode);

private static final ImmutableMap<TransactionType, Encoder> POOLED_TRANSACTION_ENCODERS =
ImmutableMap.of(TransactionType.BLOB, BlobPooledTransactionEncoder::encode);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -30,9 +32,12 @@ public class CodeDelegationProcessor {
private static final Logger LOG = LoggerFactory.getLogger(CodeDelegationProcessor.class);

private final Optional<BigInteger> maybeChainId;
private final BigInteger halfCurveOrder;

public CodeDelegationProcessor(final Optional<BigInteger> maybeChainId) {
public CodeDelegationProcessor(
final Optional<BigInteger> maybeChainId, final BigInteger halfCurveOrder) {
this.maybeChainId = maybeChainId;
this.halfCurveOrder = halfCurveOrder;
}

/**
Expand Down Expand Up @@ -89,6 +94,22 @@ private void processAuthorization(
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<Address> authorizer = codeDelegation.authorizer();
if (authorizer.isEmpty()) {
LOG.trace("Invalid signature for code delegation");
Expand Down Expand Up @@ -128,7 +149,9 @@ private void processAuthorization(
result.incremenentAlreadyExistingDelegators();
}

evmWorldUpdater.authorizedCodeService().addDelegatedCode(authority, codeDelegation.address());
evmWorldUpdater
.authorizedCodeService()
.processDelegatedCodeAuthorization(authority, codeDelegation.address());
authority.incrementNonce();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@

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;
Expand Down Expand Up @@ -80,6 +82,8 @@
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;

Expand All @@ -89,6 +93,9 @@ public abstract class MainnetProtocolSpecs {
private static final Address RIPEMD160_PRECOMPILE =
Address.fromHexString("0x0000000000000000000000000000000000000003");

private static final Supplier<SignatureAlgorithm> 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.
Expand Down Expand Up @@ -714,7 +721,8 @@ static ProtocolSpecBuilder cancunDefinition(
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) ->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -286,7 +286,7 @@ public TransactionProcessingResult processTransaction(
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);
Expand Down Expand Up @@ -352,6 +352,8 @@ public TransactionProcessingResult processTransaction(
codeDelegationRefund =
gasCalculator.calculateDelegateCodeGasRefund(
(codeDelegationResult.alreadyExistingDelegators()));

evmWorldUpdater.commit();
}

final List<AccessListEntry> accessListEntries = transaction.getAccessList().orElse(List.of());
Expand Down Expand Up @@ -415,7 +417,6 @@ public TransactionProcessingResult processTransaction(
.miningBeneficiary(miningBeneficiary)
.blockHashLookup(blockHashLookup)
.contextVariables(contextVariablesBuilder.build())
.accessListWarmAddresses(warmAddressList)
.accessListWarmStorage(storageList);

if (transaction.getVersionedHashes().isPresent()) {
Expand All @@ -439,11 +440,17 @@ public TransactionProcessingResult processTransaction(
.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<Account> 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)
Expand All @@ -454,6 +461,7 @@ public TransactionProcessingResult processTransaction(
maybeContract
.map(c -> messageCallProcessor.getCodeFromEVM(c.getCodeHash(), c.getCode()))
.orElse(CodeV0.EMPTY_CODE))
.accessListWarmAddresses(warmAddressList)
.build();
}
Deque<MessageFrame> messageFrameStack = initialFrame.getMessageFrameStack();
Expand Down
Loading

0 comments on commit 07637cf

Please sign in to comment.