Skip to content

Commit

Permalink
bug fixes, added first tests
Browse files Browse the repository at this point in the history
Signed-off-by: Daniel Lehrner <[email protected]>
  • Loading branch information
daniellehrner committed Jul 16, 2024
1 parent 6420df0 commit 73bd969
Show file tree
Hide file tree
Showing 14 changed files with 385 additions and 20 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -236,5 +236,8 @@ default Optional<? extends Quantity> getMaxFeePerBlobGas() {
int getSize();

/** Returns the set code transaction payload if this transaction is a 7702 transaction. */
Optional<List<SetCodeAuthorization>> getSetCodeTransactionPayloads();
Optional<List<SetCodeAuthorization>> setCodeTransactionPayloads();

/** Returns the size of the set code transaction payload list. */
int setCodeTransactionPayloadSize();
}
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ public TransactionCompleteResult(final TransactionWithMetadata tx) {
this.r = Quantity.create(transaction.getR());
this.s = Quantity.create(transaction.getS());
this.versionedHashes = transaction.getVersionedHashes().orElse(null);
this.setCodeAuthorizationList = transaction.getSetCodeTransactionPayloads().orElse(null);
this.setCodeAuthorizationList = transaction.setCodeTransactionPayloads().orElse(null);
}

@JsonGetter(value = "accessList")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -681,10 +681,15 @@ public Optional<BlobsWithCommitments> getBlobsWithCommitments() {
}

@Override
public Optional<List<SetCodeAuthorization>> getSetCodeTransactionPayloads() {
public Optional<List<SetCodeAuthorization>> setCodeTransactionPayloads() {
return maybeSetCodeTransactionPayloads;
}

@Override
public int setCodeTransactionPayloadSize() {
return maybeSetCodeTransactionPayloads.map(List::size).orElse(0);
}

/**
* Return the list of transaction hashes extracted from the collection of Transaction passed as
* argument
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,8 @@ public static Transaction decode(final RLPInput input) {
return transaction;
}

private static SetCodeAuthorization decodeInnerPayload(final RLPInput input) {
public static SetCodeAuthorization decodeInnerPayload(final RLPInput input) {
input.enterList();
final BigInteger chainId = input.readBigIntegerScalar();
final Address address = Address.wrap(input.readBytes());

Expand All @@ -99,19 +100,29 @@ private static SetCodeAuthorization decodeInnerPayload(final RLPInput input) {
throw new IllegalArgumentException("Optional nonce must be an empty list, but isn't");
}

if (!input.nextIsList()) {
throw new IllegalArgumentException("Optional nonce must be an list, but isn't");
}

final long noncesSize = input.nextSize();

input.enterList();
while (input.nextSize() != 0) {
for (int i = 0; i < noncesSize; i++) {
nonces.add(input.readLongScalar());
}
input.leaveList();

final byte yParity = (byte) input.readUnsignedByteScalar();

final SECPSignature signature =
SIGNATURE_ALGORITHM
.get()
.createSignature(
input.readUInt256Scalar().toUnsignedBigInteger(),
input.readUInt256Scalar().toUnsignedBigInteger(),
(byte) input.readUnsignedByteScalar());
yParity);

input.leaveList();

return new SetCodeAuthorization(chainId, address, nonces, signature);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ public static void encode(final Transaction transaction, final RLPOutput out) {
writeAccessList(out, transaction.getAccessList());
encodeSetCodeInner(
transaction
.getSetCodeTransactionPayloads()
.setCodeTransactionPayloads()
.orElseThrow(
() ->
new IllegalStateException(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
import org.hyperledger.besu.evm.worldstate.WorldUpdater;

import java.util.Deque;
import java.util.HashSet;
import java.util.List;
import java.util.Optional;
import java.util.Set;
Expand Down Expand Up @@ -264,6 +265,7 @@ public TransactionProcessingResult processTransaction(
final Wei blobGasPrice) {
try {
final var transactionValidator = transactionValidatorFactory.get();
final Set<Address> setCodeAuthorities = new HashSet<>();
LOG.trace("Starting execution of {}", transaction);
ValidationResult<TransactionInvalidReason> validationResult =
transactionValidator.validate(
Expand Down Expand Up @@ -336,13 +338,17 @@ public TransactionProcessingResult processTransaction(
transaction.getPayload(), transaction.isContractCreation());
final long accessListGas =
gasCalculator.accessListGasCost(accessListEntries.size(), accessListStorageCount);
final long gasAvailable = transaction.getGasLimit() - intrinsicGas - accessListGas;
final long setCodeGas =
gasCalculator.setCodeListGasCost(transaction.setCodeTransactionPayloadSize());
final long gasAvailable =
transaction.getGasLimit() - intrinsicGas - accessListGas - setCodeGas;
LOG.trace(
"Gas available for execution {} = {} - {} - {} (limit - intrinsic - accessList)",
"Gas available for execution {} = {} - {} - {} - {} (limit - intrinsic - accessList - setCode)",
gasAvailable,
transaction.getGasLimit(),
intrinsicGas,
accessListGas);
accessListGas,
setCodeGas);

final WorldUpdater worldUpdater = worldState.updater();
final ImmutableMap.Builder<String, Object> contextVariablesBuilder =
Expand Down Expand Up @@ -378,9 +384,10 @@ public TransactionProcessingResult processTransaction(
if (transaction.getVersionedHashes().isPresent()) {
commonMessageFrameBuilder.versionedHashes(
Optional.of(transaction.getVersionedHashes().get().stream().toList()));
} else if (transaction.getSetCodeTransactionPayloads().isPresent()) {
addressList.addAll(
} else if (transaction.setCodeTransactionPayloads().isPresent()) {
setCodeAuthorities.addAll(
setCodeTransactionProcessor.addContractToAuthority(worldUpdater, transaction));
addressList.addAll(setCodeAuthorities);
} else {
commonMessageFrameBuilder.versionedHashes(Optional.empty());
}
Expand Down Expand Up @@ -492,6 +499,7 @@ public TransactionProcessingResult processTransaction(
coinbaseCalculator.price(usedGas, transactionGasPrice, blockHeader.getBaseFee());

coinbase.incrementBalance(coinbaseWeiDelta);
setCodeTransactionProcessor.removeCodeFromAuthorities(worldUpdater, setCodeAuthorities);

operationTracer.traceEndTransaction(
worldUpdater,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ public Set<Address> addContractToAuthority(
final Set<Address> authorityList = new HashSet<>();

transaction
.getSetCodeTransactionPayloads()
.setCodeTransactionPayloads()
.get()
.forEach(
payload -> {
Expand All @@ -71,11 +71,8 @@ public Set<Address> addContractToAuthority(
return;
}

if (!account.getCode().isEmpty()) {
return;
}

account.setCode(worldUpdater.getAccount(payload.address()).getCode());
worldUpdater.addCodeToEOA(
authorityAddress, worldUpdater.getAccount(payload.address()).getCode());
authorityList.add(authorityAddress);
});
});
Expand All @@ -94,4 +91,9 @@ private Optional<Address> recoverAuthority(final SetCodeAuthorization authorizat
.recoverPublicKeyFromSignature(hash, authorization.signature())
.map(Address::extract);
}

public void removeCodeFromAuthorities(
final WorldUpdater worldUpdater, final Set<Address> authorities) {
authorities.forEach(worldUpdater::removeCodeFromEOAs);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
/*
* 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.core.encoding;

import static org.assertj.core.api.AssertionsForClassTypes.assertThat;

import org.hyperledger.besu.crypto.SECPSignature;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.SetCodeAuthorization;
import org.hyperledger.besu.ethereum.rlp.BytesValueRLPInput;

import java.math.BigInteger;

import org.apache.tuweni.bytes.Bytes;
import org.junit.jupiter.api.Test;

class SetCodeTransactionDecoderTest {

@Test
void shouldDecodeInnerPayloadWithNonce() {
// "0xd80194633688abc3ccf8b0c03088d2d1c6ae4958c2fa56c105"

final BytesValueRLPInput input =
new BytesValueRLPInput(
Bytes.fromHexString(
"0xf85b0194633688abc3ccf8b0c03088d2d1c6ae4958c2fa56c18080a0840798fa67118e034c1eb7e42fe89e28d7cd5006dc813d5729e5f75b0d1a7ec5a03b1dbace38ceb862a65bf2eac0637693b5c3493bcb2a022dd614c0a74cce0b99"),
true);
final SetCodeAuthorization authorization = SetCodeTransactionDecoder.decodeInnerPayload(input);

assertThat(authorization.chainId()).isEqualTo(BigInteger.ONE);
assertThat(authorization.address())
.isEqualTo(Address.fromHexStringStrict("0x633688abc3cCf8B0C03088D2d1C6ae4958c2fA56"));
assertThat(authorization.nonces().size()).isEqualTo(1);
assertThat(authorization.nonces().getFirst()).isEqualTo(0L);

final SECPSignature signature = authorization.signature();
assertThat(signature.getRecId()).isEqualTo((byte) 0);
assertThat(signature.getR().toString(16))
.isEqualTo("840798fa67118e034c1eb7e42fe89e28d7cd5006dc813d5729e5f75b0d1a7ec5");
assertThat(signature.getS().toString(16))
.isEqualTo("3b1dbace38ceb862a65bf2eac0637693b5c3493bcb2a022dd614c0a74cce0b99");
}

@Test
void shouldDecodeInnerPayloadWithoutNonce() {
// "0xd70194633688abc3ccf8b0c03088d2d1c6ae4958c2fa56c5"

final BytesValueRLPInput input =
new BytesValueRLPInput(
Bytes.fromHexString(
"0xf85a0194633688abc3ccf8b0c03088d2d1c6ae4958c2fa56c001a0dd6b24048be1b7d7fe5bbbb73ffc37eb2ce1997ecb4ae5b6096532ef19363148a025b58a1ff8ad00bddbbfa1d5c2411961cbb6d08dcdc8ae88303db3c6cf983031"),
true);
final SetCodeAuthorization authorization = SetCodeTransactionDecoder.decodeInnerPayload(input);

assertThat(authorization.chainId()).isEqualTo(BigInteger.ONE);
assertThat(authorization.address())
.isEqualTo(Address.fromHexStringStrict("0x633688abc3cCf8B0C03088D2d1C6ae4958c2fA56"));
assertThat(authorization.nonces().size()).isEqualTo(0);

final SECPSignature signature = authorization.signature();
assertThat(signature.getRecId()).isEqualTo((byte) 1);
assertThat(signature.getR().toString(16))
.isEqualTo("dd6b24048be1b7d7fe5bbbb73ffc37eb2ce1997ecb4ae5b6096532ef19363148");
assertThat(signature.getS().toString(16))
.isEqualTo("25b58a1ff8ad00bddbbfa1d5c2411961cbb6d08dcdc8ae88303db3c6cf983031");
}

@Test
void shouldDecodeInnerPayloadWithMultipleNonces() {
// "d90194633688abc3ccf8b0c03088d2d1c6ae4958c2fa56c20107"

final BytesValueRLPInput input =
new BytesValueRLPInput(
Bytes.fromHexString(
"0xf85c0194633688abc3ccf8b0c03088d2d1c6ae4958c2fa56c2010201a0401b5d4ebe88306448115d1a46a30e5ad1136f2818b4ebb0733d9c4efffd135aa0753ff1dbce6db504ecb9635a64d8c4506ff887e2d2a0d2b7175baf94c849eccc"),
true);
final SetCodeAuthorization authorization = SetCodeTransactionDecoder.decodeInnerPayload(input);

assertThat(authorization.chainId()).isEqualTo(BigInteger.ONE);
assertThat(authorization.address())
.isEqualTo(Address.fromHexStringStrict("0x633688abc3cCf8B0C03088D2d1C6ae4958c2fA56"));
assertThat(authorization.nonces().size()).isEqualTo(2);
assertThat(authorization.nonces().getFirst()).isEqualTo(1L);
assertThat(authorization.nonces().get(1)).isEqualTo(2L);

final SECPSignature signature = authorization.signature();
assertThat(signature.getRecId()).isEqualTo((byte) 1);
assertThat(signature.getR().toString(16))
.isEqualTo("401b5d4ebe88306448115d1a46a30e5ad1136f2818b4ebb0733d9c4efffd135a");
assertThat(signature.getS().toString(16))
.isEqualTo("753ff1dbce6db504ecb9635a64d8c4506ff887e2d2a0d2b7175baf94c849eccc");
}

@Test
void shouldDecodeInnerPayloadWithoutNonceAndChainIdZero() {
// "d70094633688abc3ccf8b0c03088d2d1c6ae4958c2fa56c5"

final BytesValueRLPInput input =
new BytesValueRLPInput(
Bytes.fromHexString(
"0xf85a0094633688abc3ccf8b0c03088d2d1c6ae4958c2fa56c001a0025c1240d7ffec0daeedb752d3357aff2e3cd58468f0c2d43ee0ee999e02ace2a03c8a25b2becd6e666f69803d1ae3322f2e137b7745c2c7f19da80f993ffde4df"),
true);
final SetCodeAuthorization authorization = SetCodeTransactionDecoder.decodeInnerPayload(input);

assertThat(authorization.chainId()).isEqualTo(BigInteger.ZERO);
assertThat(authorization.address())
.isEqualTo(Address.fromHexStringStrict("0x633688abc3cCf8B0C03088D2d1C6ae4958c2fA56"));
assertThat(authorization.nonces().isEmpty()).isTrue();

final SECPSignature signature = authorization.signature();
assertThat(signature.getRecId()).isEqualTo((byte) 1);
assertThat(signature.getR().toString(16))
.isEqualTo("25c1240d7ffec0daeedb752d3357aff2e3cd58468f0c2d43ee0ee999e02ace2");
assertThat(signature.getS().toString(16))
.isEqualTo("3c8a25b2becd6e666f69803d1ae3322f2e137b7745c2c7f19da80f993ffde4df");
}
}
Loading

0 comments on commit 73bd969

Please sign in to comment.