diff --git a/evm/src/main/java/org/hyperledger/besu/evm/MainnetEVMs.java b/evm/src/main/java/org/hyperledger/besu/evm/MainnetEVMs.java index 3afa09ee6e..adc26009ea 100644 --- a/evm/src/main/java/org/hyperledger/besu/evm/MainnetEVMs.java +++ b/evm/src/main/java/org/hyperledger/besu/evm/MainnetEVMs.java @@ -33,8 +33,6 @@ import org.hyperledger.besu.evm.operation.AddModOperation; import org.hyperledger.besu.evm.operation.AddOperation; import org.hyperledger.besu.evm.operation.AddressOperation; import org.hyperledger.besu.evm.operation.AndOperation; -import org.hyperledger.besu.evm.operation.AuthCallOperation; -import org.hyperledger.besu.evm.operation.AuthOperation; import org.hyperledger.besu.evm.operation.BalanceOperation; import org.hyperledger.besu.evm.operation.BaseFeeOperation; import org.hyperledger.besu.evm.operation.BlobBaseFeeOperation; @@ -951,9 +949,7 @@ public class MainnetEVMs { final BigInteger chainID) { registerCancunOperations(registry, gasCalculator, chainID); - // EIP-3074 AUTH and AUTHCALL - registry.put(new AuthOperation(gasCalculator)); - registry.put(new AuthCallOperation(gasCalculator)); + // TODO add EOF operations here once PragueEOF is collapsed into Prague } /** diff --git a/evm/src/main/java/org/hyperledger/besu/evm/frame/MessageFrame.java b/evm/src/main/java/org/hyperledger/besu/evm/frame/MessageFrame.java index 7ac0b4aaf4..d006c5de56 100644 --- a/evm/src/main/java/org/hyperledger/besu/evm/frame/MessageFrame.java +++ b/evm/src/main/java/org/hyperledger/besu/evm/frame/MessageFrame.java @@ -246,9 +246,6 @@ public class MessageFrame { /** The mark of the undoable collections at the creation of this message frame */ private final long undoMark; - /** mutated by AUTH operation */ - private Address authorizedBy = null; - /** * Builder builder. * @@ -1373,24 +1370,6 @@ public class MessageFrame { return txValues.versionedHashes(); } - /** - * Accessor for address that authorized future AUTHCALLs. - * - * @return the revert reason - */ - public Address getAuthorizedBy() { - return authorizedBy; - } - - /** - * Mutator for address that authorizes future AUTHCALLs, set by AUTH opcode - * - * @param authorizedBy the address that authorizes future AUTHCALLs - */ - public void setAuthorizedBy(final Address authorizedBy) { - this.authorizedBy = authorizedBy; - } - /** Reset. */ public void reset() { maybeUpdatedMemory = Optional.empty(); @@ -1428,7 +1407,9 @@ public class MessageFrame { private Optional> versionedHashes = Optional.empty(); /** Instantiates a new Builder. */ - public Builder() {} + public Builder() { + // constructor added to deal with JavaDoc linting rules. + } /** * The "parent" message frame. When present some fields will be populated from the parent and 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 7a3f57c81d..06f24c534e 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 @@ -210,35 +210,6 @@ public interface GasCalculator { Address contract, boolean accountIsWarm); - /** - * Returns the gas cost for AUTHCALL. - * - * @param frame The current frame - * @param stipend The gas stipend being provided by the CALL caller - * @param inputDataOffset The offset in memory to retrieve the CALL input data - * @param inputDataLength The CALL input data length - * @param outputDataOffset The offset in memory to place the CALL output data - * @param outputDataLength The CALL output data length - * @param transferValue The wei being transferred - * @param invoker The contract calling out on behalf of the authority - * @param invokee The address of the recipient (never null) - * @param accountIsWarm The address of the contract is "warm" as per EIP-2929 - * @return The gas cost for the CALL operation - */ - default long authCallOperationGasCost( - final MessageFrame frame, - final long stipend, - final long inputDataOffset, - final long inputDataLength, - final long outputDataOffset, - final long outputDataLength, - final Wei transferValue, - final Account invoker, - final Address invokee, - final boolean accountIsWarm) { - return 0L; - } - /** * Gets additional call stipend. * @@ -646,18 +617,4 @@ public interface GasCalculator { default long computeExcessBlobGas(final long parentExcessBlobGas, final long blobGasUsed) { return 0L; } - - /** - * Returns the gas cost of validating an auth commitment for an AUTHCALL - * - * @param frame the current frame, with memory to be read from - * @param offset start of memory read - * @param length amount of memory read - * @param authority address to check for warmup - * @return total gas cost for the operation - */ - default long authOperationGasCost( - final MessageFrame frame, final long offset, final long length, final Address authority) { - 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 9dde4bdb66..e2789bba33 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 @@ -16,11 +16,6 @@ package org.hyperledger.besu.evm.gascalculator; import static org.hyperledger.besu.datatypes.Address.BLS12_MAP_FP2_TO_G2; -import org.hyperledger.besu.datatypes.Address; -import org.hyperledger.besu.datatypes.Wei; -import org.hyperledger.besu.evm.account.Account; -import org.hyperledger.besu.evm.frame.MessageFrame; - /** * Gas Calculator for Prague * @@ -32,8 +27,6 @@ import org.hyperledger.besu.evm.frame.MessageFrame; * */ public class PragueGasCalculator extends CancunGasCalculator { - private static final int AUTH_OP_FIXED_FEE = 3100; - private static final long AUTH_CALL_VALUE_TRANSFER_GAS_COST = 6700; /** Instantiates a new Prague Gas Calculator. */ public PragueGasCalculator() { @@ -48,55 +41,4 @@ public class PragueGasCalculator extends CancunGasCalculator { protected PragueGasCalculator(final int maxPrecompile) { super(maxPrecompile); } - - @Override - public long authOperationGasCost( - final MessageFrame frame, final long offset, final long length, final Address authority) { - final long memoryExpansionGasCost = memoryExpansionGasCost(frame, offset, length); - final long accessFee = frame.isAddressWarm(authority) ? 100 : 2600; - final long gasCost = AUTH_OP_FIXED_FEE + memoryExpansionGasCost + accessFee; - return gasCost; - } - - /** - * Returns the gas cost to call another contract on behalf of an authority - * - * @return the gas cost to call another contract on behalf of an authority - */ - @Override - public long authCallOperationGasCost( - final MessageFrame frame, - final long stipend, - final long inputDataOffset, - final long inputDataLength, - final long outputDataOffset, - final long outputDataLength, - final Wei transferValue, - final Account invoker, - final Address invokee, - final boolean accountIsWarm) { - - final long inputDataMemoryExpansionCost = - memoryExpansionGasCost(frame, inputDataOffset, inputDataLength); - final long outputDataMemoryExpansionCost = - memoryExpansionGasCost(frame, outputDataOffset, outputDataLength); - final long memoryExpansionCost = - Math.max(inputDataMemoryExpansionCost, outputDataMemoryExpansionCost); - - final long staticGasCost = getWarmStorageReadCost(); - - long dynamicGasCost = accountIsWarm ? 0 : getColdAccountAccessCost() - getWarmStorageReadCost(); - - if (!transferValue.isZero()) { - dynamicGasCost += AUTH_CALL_VALUE_TRANSFER_GAS_COST; - } - - if ((invoker == null || invoker.isEmpty()) && !transferValue.isZero()) { - dynamicGasCost += newAccountGasCost(); - } - - long cost = staticGasCost + memoryExpansionCost + dynamicGasCost; - - return cost; - } } diff --git a/evm/src/main/java/org/hyperledger/besu/evm/operation/AuthCallOperation.java b/evm/src/main/java/org/hyperledger/besu/evm/operation/AuthCallOperation.java deleted file mode 100644 index 3d4fffffb3..0000000000 --- a/evm/src/main/java/org/hyperledger/besu/evm/operation/AuthCallOperation.java +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright contributors to Hyperledger Besu. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the - * specific language governing permissions and limitations under the License. - * - * SPDX-License-Identifier: Apache-2.0 - */ -package org.hyperledger.besu.evm.operation; - -import static org.hyperledger.besu.evm.internal.Words.clampedToLong; - -import org.hyperledger.besu.datatypes.Address; -import org.hyperledger.besu.datatypes.Wei; -import org.hyperledger.besu.evm.EVM; -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.apache.tuweni.bytes.Bytes32; - -/** Introduced via EIP-3074 to call another contract with a different authorization context. */ -public class AuthCallOperation extends AbstractCallOperation { - - /** - * Instantiates a new AuthCallOperation. - * - * @param gasCalculator a Prague or later gas calculator - */ - public AuthCallOperation(final GasCalculator gasCalculator) { - super(0xF7, "AUTHCALL", 7, 1, gasCalculator); - } - - @Override - protected Address to(final MessageFrame frame) { - return Words.toAddress(frame.getStackItem(1)); - } - - @Override - protected Wei value(final MessageFrame frame) { - return Wei.wrap(frame.getStackItem(2)); - } - - @Override - protected Wei apparentValue(final MessageFrame frame) { - return value(frame); - } - - @Override - protected long inputDataOffset(final MessageFrame frame) { - return clampedToLong(frame.getStackItem(3)); - } - - @Override - protected long inputDataLength(final MessageFrame frame) { - return clampedToLong(frame.getStackItem(4)); - } - - @Override - protected long outputDataOffset(final MessageFrame frame) { - return clampedToLong(frame.getStackItem(5)); - } - - @Override - protected long outputDataLength(final MessageFrame frame) { - return clampedToLong(frame.getStackItem(6)); - } - - @Override - protected Address address(final MessageFrame frame) { - return to(frame); - } - - @Override - protected Address sender(final MessageFrame frame) { - return frame.getAuthorizedBy(); - } - - @Override - public long gasAvailableForChildCall(final MessageFrame frame) { - return gasCalculator().gasAvailableForChildCall(frame, gas(frame), !value(frame).isZero()); - } - - @Override - public OperationResult execute(final MessageFrame frame, final EVM evm) { - if (frame.isStatic() && !value(frame).isZero()) { - return new OperationResult(cost(frame, true), ExceptionalHaltReason.ILLEGAL_STATE_CHANGE); - } else if (frame.getAuthorizedBy() != null) { - return super.execute(frame, evm); - } else { - frame.pushStackItem(Bytes32.ZERO); - return new OperationResult(cost(frame, true), null); - } - } -} diff --git a/evm/src/main/java/org/hyperledger/besu/evm/operation/AuthOperation.java b/evm/src/main/java/org/hyperledger/besu/evm/operation/AuthOperation.java deleted file mode 100644 index 2de52ab4a5..0000000000 --- a/evm/src/main/java/org/hyperledger/besu/evm/operation/AuthOperation.java +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Copyright contributors to Hyperledger Besu. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the - * specific language governing permissions and limitations under the License. - * - * SPDX-License-Identifier: Apache-2.0 - */ -package org.hyperledger.besu.evm.operation; - -import static org.hyperledger.besu.evm.internal.Words.clampedToLong; - -import org.hyperledger.besu.crypto.Hash; -import org.hyperledger.besu.crypto.SECPPublicKey; -import org.hyperledger.besu.crypto.SECPSignature; -import org.hyperledger.besu.crypto.SignatureAlgorithm; -import org.hyperledger.besu.crypto.SignatureAlgorithmFactory; -import org.hyperledger.besu.datatypes.Address; -import org.hyperledger.besu.evm.EVM; -import org.hyperledger.besu.evm.account.Account; -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 java.util.Optional; - -import org.apache.tuweni.bytes.Bytes; -import org.apache.tuweni.bytes.Bytes32; -import org.apache.tuweni.units.bigints.UInt256; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** The AUTH operation. */ -public class AuthOperation extends AbstractOperation { - - /** The constant MAGIC defined by EIP-3074 */ - public static final byte MAGIC = 0x4; - - private static final Logger LOG = LoggerFactory.getLogger(AuthOperation.class); - - private static final SignatureAlgorithm signatureAlgorithm = - SignatureAlgorithmFactory.getInstance(); - - /** - * Instantiates a new AuthOperation. - * - * @param gasCalculator a Prague or later gas calculator - */ - public AuthOperation(final GasCalculator gasCalculator) { - super(0xF6, "AUTH", 3, 1, gasCalculator); - } - - @Override - public OperationResult execute(final MessageFrame frame, final EVM evm) { - // create authority from stack - Address authority = Words.toAddress(frame.getStackItem(0)); - long offset = clampedToLong(frame.getStackItem(1)); - long length = clampedToLong(frame.getStackItem(2)); - - final long gasCost = - super.gasCalculator().authOperationGasCost(frame, offset, length, authority); - if (frame.getRemainingGas() < gasCost) { - return new OperationResult(gasCost, ExceptionalHaltReason.INSUFFICIENT_GAS); - } - - byte yParity = frame.readMemory(offset, 1).get(0); - Bytes32 r = Bytes32.wrap(frame.readMemory(offset + 1, 32)); - Bytes32 s = Bytes32.wrap(frame.readMemory(offset + 33, 32)); - Bytes32 commit = Bytes32.wrap(frame.readMemory(offset + 65, 32)); - Bytes32 invoker = Bytes32.leftPad(frame.getContractAddress()); - // TODO add test for getting sender nonce when account does not exist - Bytes32 senderNonce = - Bytes32.leftPad( - Bytes.ofUnsignedLong( - Optional.ofNullable(frame.getWorldUpdater().getAccount(authority)) - .map(Account::getNonce) - .orElse(0L))); - if (evm.getChainId().isEmpty()) { - frame.pushStackItem(UInt256.ZERO); - LOG.error("ChainId is not set"); - return new OperationResult(0, null); - } - Bytes authPreImage = - Bytes.concatenate( - Bytes.ofUnsignedShort(MAGIC), evm.getChainId().get(), senderNonce, invoker, commit); - Bytes32 messageHash = Hash.keccak256(authPreImage); - Optional publicKey; - try { - SECPSignature signature = - signatureAlgorithm.createSignature( - r.toUnsignedBigInteger(), s.toUnsignedBigInteger(), yParity); - publicKey = signatureAlgorithm.recoverPublicKeyFromSignature(messageHash, signature); - } catch (IllegalArgumentException e) { - - frame.pushStackItem(UInt256.ZERO); - return new OperationResult(gasCost, null); - } - if (publicKey.isPresent()) { - Address signerAddress = Address.extract(publicKey.get()); - if (signerAddress.equals(authority)) { - frame.setAuthorizedBy(authority); - frame.pushStackItem(UInt256.ONE); - } else { - frame.pushStackItem(UInt256.ZERO); - } - } else { - frame.pushStackItem(UInt256.ZERO); - } - return new OperationResult(gasCost, null); - } -} diff --git a/evm/src/test/java/org/hyperledger/besu/evm/gascalculator/PragueGasCalculatorTest.java b/evm/src/test/java/org/hyperledger/besu/evm/gascalculator/PragueGasCalculatorTest.java index 72cacd47cf..c528dab64f 100644 --- a/evm/src/test/java/org/hyperledger/besu/evm/gascalculator/PragueGasCalculatorTest.java +++ b/evm/src/test/java/org/hyperledger/besu/evm/gascalculator/PragueGasCalculatorTest.java @@ -14,61 +14,17 @@ */ package org.hyperledger.besu.evm.gascalculator; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; +import static org.assertj.core.api.Assertions.assertThat; import org.hyperledger.besu.datatypes.Address; -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.junit.jupiter.api.Test; -public class PragueGasCalculatorTest { +class PragueGasCalculatorTest { @Test - public void testAuthOperationGasCost() { - PragueGasCalculator pragueGasCalculator = new PragueGasCalculator(); - MessageFrame runningIn = mock(MessageFrame.class); - Address authority = Address.fromHexString("0xdeadbeef"); - when(runningIn.isAddressWarm(authority)).thenReturn(true); - long gasSpent = pragueGasCalculator.authOperationGasCost(runningIn, 0, 97, authority); - assertEquals( - 3100 + 100 + pragueGasCalculator.memoryExpansionGasCost(runningIn, 0, 97), gasSpent); - } - - @Test - public void testAuthCallOperationGasCostWithTransfer() { - PragueGasCalculator pragueGasCalculator = new PragueGasCalculator(); - MessageFrame runningIn = mock(MessageFrame.class); - Account invoker = mock(MutableAccount.class); - when(invoker.getAddress()).thenReturn(Address.fromHexString("0xCafeBabe")); - Address invokee = Address.fromHexString("0xdeadbeef"); - when(runningIn.isAddressWarm(invokee)).thenReturn(true); - long gasSpentInAuthCall = - pragueGasCalculator.authCallOperationGasCost( - runningIn, 63, 0, 97, 100, 97, Wei.ONE, invoker, invokee, true); - long gasSpentInCall = - pragueGasCalculator.callOperationGasCost( - runningIn, 63, 0, 97, 100, 97, Wei.ONE, invoker, invokee, true); - assertEquals(gasSpentInCall - 2300, gasSpentInAuthCall); - } - - @Test - public void testAuthCallOperationGasCostNoTransfer() { - PragueGasCalculator pragueGasCalculator = new PragueGasCalculator(); - MessageFrame runningIn = mock(MessageFrame.class); - Account invoker = mock(MutableAccount.class); - when(invoker.getAddress()).thenReturn(Address.fromHexString("0xCafeBabe")); - Address invokee = Address.fromHexString("0xdeadbeef"); - when(runningIn.isAddressWarm(invokee)).thenReturn(true); - long gasSpentInAuthCall = - pragueGasCalculator.authCallOperationGasCost( - runningIn, 63, 0, 97, 100, 97, Wei.ZERO, invoker, invokee, true); - long gasSpentInCall = - pragueGasCalculator.callOperationGasCost( - runningIn, 63, 0, 97, 100, 97, Wei.ZERO, invoker, invokee, true); - assertEquals(gasSpentInCall, gasSpentInAuthCall); + void testPrecompileSize() { + PragueGasCalculator subject = new PragueGasCalculator(); + assertThat(subject.isPrecompile(Address.precompiled(0x14))).isFalse(); + assertThat(subject.isPrecompile(Address.BLS12_MAP_FP2_TO_G2)).isTrue(); } } diff --git a/evm/src/test/java/org/hyperledger/besu/evm/operations/AuthOperationTest.java b/evm/src/test/java/org/hyperledger/besu/evm/operations/AuthOperationTest.java deleted file mode 100644 index be76e885b2..0000000000 --- a/evm/src/test/java/org/hyperledger/besu/evm/operations/AuthOperationTest.java +++ /dev/null @@ -1,153 +0,0 @@ -/* - * Copyright contributors to Hyperledger Besu. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the - * specific language governing permissions and limitations under the License. - * - * SPDX-License-Identifier: Apache-2.0 - */ -package org.hyperledger.besu.evm.operations; - -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.Hash; -import org.hyperledger.besu.crypto.KeyPair; -import org.hyperledger.besu.crypto.SECPSignature; -import org.hyperledger.besu.crypto.SignatureAlgorithm; -import org.hyperledger.besu.crypto.SignatureAlgorithmFactory; -import org.hyperledger.besu.datatypes.Address; -import org.hyperledger.besu.evm.EVM; -import org.hyperledger.besu.evm.account.MutableAccount; -import org.hyperledger.besu.evm.frame.MessageFrame; -import org.hyperledger.besu.evm.gascalculator.PragueGasCalculator; -import org.hyperledger.besu.evm.operation.AuthOperation; -import org.hyperledger.besu.evm.worldstate.WorldUpdater; - -import java.util.Optional; - -import org.apache.tuweni.bytes.Bytes; -import org.apache.tuweni.bytes.Bytes32; -import org.apache.tuweni.units.bigints.UInt256; -import org.junit.jupiter.api.Test; - -public class AuthOperationTest { - - @Test - public void testAuthOperation() { - SignatureAlgorithm algo = SignatureAlgorithmFactory.getInstance(); - KeyPair keys = algo.generateKeyPair(); - Address authingAddress = Address.extract(keys.getPublicKey()); - EVM fakeEVM = mock(EVM.class); - - Optional chainId = Optional.of(Bytes.of(1)); - when(fakeEVM.getChainId()).thenReturn(chainId); - long senderNonce = 0; - Address invokerAddress = Address.fromHexString("0xdeadbeef"); - Bytes32 invoker = Bytes32.leftPad(invokerAddress); - Bytes32 contractCommitment = Bytes32.leftPad(Bytes.fromHexString("0x1234")); - Bytes authPreImage = - Bytes.concatenate( - Bytes.ofUnsignedShort(AuthOperation.MAGIC), - chainId.get(), - Bytes32.leftPad(Bytes.ofUnsignedLong(senderNonce)), - invoker, - contractCommitment); - Bytes32 messageHash = Hash.keccak256(authPreImage); - SECPSignature signature = algo.sign(messageHash, keys); - - MessageFrame frame = mock(MessageFrame.class); - when(frame.getContractAddress()).thenReturn(invokerAddress); - MutableAccount authingAccount = mock(MutableAccount.class); - when(authingAccount.getAddress()).thenReturn(authingAddress); - when(authingAccount.getNonce()).thenReturn(senderNonce); - when(frame.getRemainingGas()).thenReturn(1000000L); - WorldUpdater state = mock(WorldUpdater.class); - - when(state.getAccount(authingAddress)).thenReturn(authingAccount); - - when(frame.getWorldUpdater()).thenReturn(state); - - when(frame.getSenderAddress()).thenReturn(authingAddress); - when(state.getSenderAccount(frame)).thenReturn(authingAccount); - when(frame.getStackItem(0)).thenReturn(authingAddress); - when(frame.getStackItem(1)).thenReturn(Bytes.of(0)); - when(frame.getStackItem(2)).thenReturn(Bytes.of(97)); - Bytes encodedSignature = signature.encodedBytes(); - when(frame.readMemory(0, 1)).thenReturn(encodedSignature.slice(64, 1)); - when(frame.readMemory(1, 32)).thenReturn(Bytes32.wrap(encodedSignature.slice(0, 32).toArray())); - when(frame.readMemory(33, 32)) - .thenReturn(Bytes32.wrap(encodedSignature.slice(32, 32).toArray())); - when(frame.readMemory(65, 32)).thenReturn(contractCommitment); - - AuthOperation authOperation = new AuthOperation(new PragueGasCalculator()); - authOperation.execute(frame, fakeEVM); - verify(frame).setAuthorizedBy(authingAddress); - verify(frame).pushStackItem(UInt256.ONE); - } - - @Test - public void testAuthOperationNegative() { - SignatureAlgorithm algo = SignatureAlgorithmFactory.getInstance(); - KeyPair keys = algo.generateKeyPair(); - Address authingAddress = Address.extract(keys.getPublicKey()); - EVM fakeEVM = mock(EVM.class); - - Optional chainId = Optional.of(Bytes.of(1)); - when(fakeEVM.getChainId()).thenReturn(chainId); - long senderNonce = 0; - Address invokerAddress = Address.fromHexString("0xdeadbeef"); - Bytes32 invoker = Bytes32.leftPad(invokerAddress); - Bytes32 contractCommitment = Bytes32.leftPad(Bytes.fromHexString("0x1234")); - Bytes authPreImage = - Bytes.concatenate( - Bytes.ofUnsignedShort(AuthOperation.MAGIC), - chainId.get(), - Bytes32.leftPad(Bytes.ofUnsignedLong(senderNonce)), - invoker, - contractCommitment); - Bytes32 messageHash = Hash.keccak256(authPreImage); - - // Generate a new key pair to create an incorrect signature - KeyPair wrongKeys = algo.generateKeyPair(); - SECPSignature wrongSignature = algo.sign(messageHash, wrongKeys); - - MessageFrame frame = mock(MessageFrame.class); - when(frame.getRemainingGas()).thenReturn(1000000L); - when(frame.getContractAddress()).thenReturn(invokerAddress); - MutableAccount authingAccount = mock(MutableAccount.class); - when(authingAccount.getAddress()).thenReturn(authingAddress); - when(authingAccount.getNonce()).thenReturn(senderNonce); - - WorldUpdater state = mock(WorldUpdater.class); - - when(state.getAccount(authingAddress)).thenReturn(authingAccount); - - when(frame.getWorldUpdater()).thenReturn(state); - - when(frame.getSenderAddress()).thenReturn(authingAddress); - when(state.getSenderAccount(frame)).thenReturn(authingAccount); - when(frame.getStackItem(0)).thenReturn(authingAddress); - when(frame.getStackItem(1)).thenReturn(Bytes.of(0)); - when(frame.getStackItem(2)).thenReturn(Bytes.of(97)); - Bytes encodedSignature = wrongSignature.encodedBytes(); // Use the wrong signature - when(frame.readMemory(0, 1)).thenReturn(encodedSignature.slice(64, 1)); - when(frame.readMemory(1, 32)).thenReturn(Bytes32.wrap(encodedSignature.slice(0, 32).toArray())); - when(frame.readMemory(33, 32)) - .thenReturn(Bytes32.wrap(encodedSignature.slice(32, 32).toArray())); - when(frame.readMemory(65, 32)).thenReturn(contractCommitment); - - AuthOperation authOperation = new AuthOperation(new PragueGasCalculator()); - authOperation.execute(frame, fakeEVM); - verify(frame, never()).setAuthorizedBy(authingAddress); // The address should not be authorized - verify(frame).pushStackItem(UInt256.ZERO); // The stack should contain UInt256.ZERO - } -} diff --git a/evm/src/test/java/org/hyperledger/besu/evm/processor/AuthCallProcessorTest.java b/evm/src/test/java/org/hyperledger/besu/evm/processor/AuthCallProcessorTest.java deleted file mode 100644 index 21144a4806..0000000000 --- a/evm/src/test/java/org/hyperledger/besu/evm/processor/AuthCallProcessorTest.java +++ /dev/null @@ -1,152 +0,0 @@ -/* - * Copyright contributors to Hyperledger Besu. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the - * specific language governing permissions and limitations under the License. - * - * SPDX-License-Identifier: Apache-2.0 - */ -package org.hyperledger.besu.evm.processor; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; - -import org.hyperledger.besu.crypto.Hash; -import org.hyperledger.besu.crypto.KeyPair; -import org.hyperledger.besu.crypto.SECPSignature; -import org.hyperledger.besu.crypto.SignatureAlgorithm; -import org.hyperledger.besu.crypto.SignatureAlgorithmFactory; -import org.hyperledger.besu.datatypes.Address; -import org.hyperledger.besu.datatypes.Wei; -import org.hyperledger.besu.evm.EVM; -import org.hyperledger.besu.evm.MainnetEVMs; -import org.hyperledger.besu.evm.fluent.EVMExecutor; -import org.hyperledger.besu.evm.frame.MessageFrame; -import org.hyperledger.besu.evm.gascalculator.PragueGasCalculator; -import org.hyperledger.besu.evm.internal.EvmConfiguration; -import org.hyperledger.besu.evm.operation.AuthOperation; -import org.hyperledger.besu.evm.toy.ToyWorld; -import org.hyperledger.besu.evm.worldstate.WorldUpdater; - -import java.math.BigInteger; -import java.util.List; -import java.util.Optional; - -import org.apache.tuweni.bytes.Bytes; -import org.apache.tuweni.bytes.Bytes32; -import org.junit.jupiter.api.Test; -import org.mockito.ArgumentCaptor; - -public class AuthCallProcessorTest extends MessageCallProcessorTest { - - MessageCallProcessor spyingMessageCallProcessor; - ArgumentCaptor frameCaptor = ArgumentCaptor.forClass(MessageFrame.class); - - WorldUpdater toyWorld = new ToyWorld(); - - @Test - public void authCallHappyPath() { - final EVM pragueEVM = - MainnetEVMs.prague(new PragueGasCalculator(), BigInteger.ONE, EvmConfiguration.DEFAULT); - final EVMExecutor executor = EVMExecutor.evm(pragueEVM); - this.spyingMessageCallProcessor = - spy(new MessageCallProcessor(pragueEVM, precompileContractRegistry)); - executor.messageCallProcessor(this.spyingMessageCallProcessor); - - executor.worldUpdater(toyWorld); - executor.gas(10_000_000_000L); - - SignatureAlgorithm algo = SignatureAlgorithmFactory.getInstance(); - KeyPair keys = algo.generateKeyPair(); - Optional chainId = Optional.of(Bytes.of(1)); - long senderNonce = 0; - Address invokerAddress = Address.fromHexString("0xdeadbeef"); - Bytes32 invoker = Bytes32.leftPad(invokerAddress); - Bytes32 contractCommitment = Bytes32.leftPad(Bytes.fromHexString("0x1234")); - Bytes authPreImage = - Bytes.concatenate( - Bytes.ofUnsignedShort(AuthOperation.MAGIC), - Bytes32.leftPad(chainId.get()), - Bytes32.leftPad(Bytes.ofUnsignedLong(senderNonce)), - invoker, - contractCommitment); - Bytes32 messageHash = Hash.keccak256(authPreImage); - SECPSignature signature = algo.sign(messageHash, keys); - Bytes encodedSignature = signature.encodedBytes(); - - Bytes authParam = - Bytes.concatenate( - encodedSignature.slice(64, 1), // y parity - encodedSignature.slice(0, 32), // r - encodedSignature.slice(32, 32), // s - contractCommitment); - - toyWorld.createAccount( - Address.extract(keys.getPublicKey()), 0, Wei.MAX_WEI); // initialize authority account - toyWorld.createAccount(invokerAddress, 0, Wei.MAX_WEI); // initialize invoker account - final Bytes codeBytes = - Bytes.fromHexString( - "0x" - + "6061" // push 97 the calldata length - + "6000" // push 0 the offset - + "6000" // push 0 the destination offset - + "37" // calldatacopy 97 bytes of the auth param to mem 0 - + "6061" // param is 97 bytes (0x61) - + "6000" // push 0 where in mem to find auth param - + "73" // push next 20 bytes for the authority address - + Address.extract(keys.getPublicKey()) - .toUnprefixedHexString() // push authority address - + "F6" // AUTH call, should work and set authorizedBy on the frame - + "6000" // push 0 for return length, we don't care about the return - + "6000" // push 0 for return offset, we don't care about the return - + "6000" // push 0 for input length - + "6000" // push 0 for input offset - + "60FF" // push 255 for the value being sent - + "73deadbeefdeadbeefdeadbeefdeadbeefdeadbeef" // push20 the invokee address - + "60FF" // push 255 gas - + "F7"); // AUTHCALL, should work - executor.contract(invokerAddress); - executor.execute(codeBytes, authParam, Wei.ZERO, invokerAddress); - verify(this.spyingMessageCallProcessor, times(2)) - .start(frameCaptor.capture(), any()); // one for parent frame, one for child - List frames = frameCaptor.getAllValues(); - assertThat(frames.get(0).getStackItem(0)).isEqualTo((Bytes.of(1))); - } - - @Test - public void unauthorizedAuthCall() { - final EVM pragueEVM = - MainnetEVMs.prague(new PragueGasCalculator(), BigInteger.ONE, EvmConfiguration.DEFAULT); - final EVMExecutor executor = EVMExecutor.evm(pragueEVM); - this.spyingMessageCallProcessor = - spy(new MessageCallProcessor(pragueEVM, precompileContractRegistry)); - executor.messageCallProcessor(this.spyingMessageCallProcessor); - - executor.gas(10_000_000_000L); - - final Bytes codeBytes = - Bytes.fromHexString( - "0x" - + "6000" // push 0 for return length - + "6000" // push 0 for return offset - + "6000" // push 0 for input length - + "6000" // push 0 for input offset - + "60FF" // push 255 for the value being sent - + "73deadbeefdeadbeefdeadbeefdeadbeefdeadbeef" // push20 the invokee address - + "60FF" // push 255 gas - + "F7"); // AUTHCALL without prior AUTH, should fail - - executor.execute(codeBytes, Bytes.EMPTY, Wei.ZERO, Address.ZERO); - verify(this.spyingMessageCallProcessor).start(frameCaptor.capture(), any()); - assertThat(frameCaptor.getValue().getStackItem(0)).isEqualTo(Bytes32.ZERO); - } -}