Add EIP-4200: EOF - Static relative jumps (#4760)

* Remove opSize field from Operation

With the introduction of RJUMPV, operations don't have fixed size anymore. This field isn't used anyware in the code so it's safe to delete it

Signed-off-by: Diego López León <dieguitoll@gmail.com>

* Add comments

Signed-off-by: Diego López León <dieguitoll@gmail.com>

* Add some EIP-3670 and EIP-3540 tests

Signed-off-by: Diego López León <dieguitoll@gmail.com>

* Replace jumpdest bitmap with BitSet

Signed-off-by: Diego López León <dieguitoll@gmail.com>

* Implement EIP-4200: EOF - Static relative jumps

Signed-off-by: Diego López León <dieguitoll@gmail.com>

Signed-off-by: Diego López León <dieguitoll@gmail.com>
pull/4843/head
Diego López León 2 years ago committed by GitHub
parent 8b46caf019
commit c3c934d706
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      ethereum/core/src/test/java/org/hyperledger/besu/ethereum/vm/DebugOperationTracerTest.java
  2. 97
      ethereum/core/src/test/java/org/hyperledger/besu/ethereum/vm/operations/RelativeJumpOperationTest.java
  3. 6
      evm/src/main/java/org/hyperledger/besu/evm/MainnetEVMs.java
  4. 88
      evm/src/main/java/org/hyperledger/besu/evm/code/OpcodesV1.java
  5. 3
      evm/src/main/java/org/hyperledger/besu/evm/operation/AbstractCallOperation.java
  6. 3
      evm/src/main/java/org/hyperledger/besu/evm/operation/AbstractCreateOperation.java
  7. 3
      evm/src/main/java/org/hyperledger/besu/evm/operation/AbstractFixedCostOperation.java
  8. 8
      evm/src/main/java/org/hyperledger/besu/evm/operation/AbstractOperation.java
  9. 2
      evm/src/main/java/org/hyperledger/besu/evm/operation/AddModOperation.java
  10. 2
      evm/src/main/java/org/hyperledger/besu/evm/operation/AddOperation.java
  11. 2
      evm/src/main/java/org/hyperledger/besu/evm/operation/AddressOperation.java
  12. 2
      evm/src/main/java/org/hyperledger/besu/evm/operation/AndOperation.java
  13. 2
      evm/src/main/java/org/hyperledger/besu/evm/operation/BalanceOperation.java
  14. 2
      evm/src/main/java/org/hyperledger/besu/evm/operation/BaseFeeOperation.java
  15. 2
      evm/src/main/java/org/hyperledger/besu/evm/operation/BlockHashOperation.java
  16. 2
      evm/src/main/java/org/hyperledger/besu/evm/operation/ByteOperation.java
  17. 2
      evm/src/main/java/org/hyperledger/besu/evm/operation/CallCodeOperation.java
  18. 2
      evm/src/main/java/org/hyperledger/besu/evm/operation/CallDataCopyOperation.java
  19. 2
      evm/src/main/java/org/hyperledger/besu/evm/operation/CallDataLoadOperation.java
  20. 2
      evm/src/main/java/org/hyperledger/besu/evm/operation/CallDataSizeOperation.java
  21. 2
      evm/src/main/java/org/hyperledger/besu/evm/operation/CallOperation.java
  22. 2
      evm/src/main/java/org/hyperledger/besu/evm/operation/CallValueOperation.java
  23. 2
      evm/src/main/java/org/hyperledger/besu/evm/operation/CallerOperation.java
  24. 2
      evm/src/main/java/org/hyperledger/besu/evm/operation/ChainIdOperation.java
  25. 2
      evm/src/main/java/org/hyperledger/besu/evm/operation/CodeCopyOperation.java
  26. 2
      evm/src/main/java/org/hyperledger/besu/evm/operation/CodeSizeOperation.java
  27. 2
      evm/src/main/java/org/hyperledger/besu/evm/operation/CoinbaseOperation.java
  28. 2
      evm/src/main/java/org/hyperledger/besu/evm/operation/Create2Operation.java
  29. 2
      evm/src/main/java/org/hyperledger/besu/evm/operation/CreateOperation.java
  30. 2
      evm/src/main/java/org/hyperledger/besu/evm/operation/DelegateCallOperation.java
  31. 2
      evm/src/main/java/org/hyperledger/besu/evm/operation/DifficultyOperation.java
  32. 2
      evm/src/main/java/org/hyperledger/besu/evm/operation/DivOperation.java
  33. 1
      evm/src/main/java/org/hyperledger/besu/evm/operation/DupOperation.java
  34. 2
      evm/src/main/java/org/hyperledger/besu/evm/operation/EqOperation.java
  35. 2
      evm/src/main/java/org/hyperledger/besu/evm/operation/ExpOperation.java
  36. 2
      evm/src/main/java/org/hyperledger/besu/evm/operation/ExtCodeCopyOperation.java
  37. 2
      evm/src/main/java/org/hyperledger/besu/evm/operation/ExtCodeHashOperation.java
  38. 2
      evm/src/main/java/org/hyperledger/besu/evm/operation/ExtCodeSizeOperation.java
  39. 2
      evm/src/main/java/org/hyperledger/besu/evm/operation/GasLimitOperation.java
  40. 2
      evm/src/main/java/org/hyperledger/besu/evm/operation/GasOperation.java
  41. 2
      evm/src/main/java/org/hyperledger/besu/evm/operation/GasPriceOperation.java
  42. 2
      evm/src/main/java/org/hyperledger/besu/evm/operation/GtOperation.java
  43. 2
      evm/src/main/java/org/hyperledger/besu/evm/operation/InvalidOperation.java
  44. 2
      evm/src/main/java/org/hyperledger/besu/evm/operation/IsZeroOperation.java
  45. 2
      evm/src/main/java/org/hyperledger/besu/evm/operation/JumpDestOperation.java
  46. 2
      evm/src/main/java/org/hyperledger/besu/evm/operation/JumpOperation.java
  47. 2
      evm/src/main/java/org/hyperledger/besu/evm/operation/JumpiOperation.java
  48. 2
      evm/src/main/java/org/hyperledger/besu/evm/operation/Keccak256Operation.java
  49. 2
      evm/src/main/java/org/hyperledger/besu/evm/operation/LogOperation.java
  50. 2
      evm/src/main/java/org/hyperledger/besu/evm/operation/LtOperation.java
  51. 2
      evm/src/main/java/org/hyperledger/besu/evm/operation/MLoadOperation.java
  52. 2
      evm/src/main/java/org/hyperledger/besu/evm/operation/MSizeOperation.java
  53. 2
      evm/src/main/java/org/hyperledger/besu/evm/operation/MStore8Operation.java
  54. 2
      evm/src/main/java/org/hyperledger/besu/evm/operation/MStoreOperation.java
  55. 2
      evm/src/main/java/org/hyperledger/besu/evm/operation/ModOperation.java
  56. 2
      evm/src/main/java/org/hyperledger/besu/evm/operation/MulModOperation.java
  57. 2
      evm/src/main/java/org/hyperledger/besu/evm/operation/MulOperation.java
  58. 2
      evm/src/main/java/org/hyperledger/besu/evm/operation/NotOperation.java
  59. 2
      evm/src/main/java/org/hyperledger/besu/evm/operation/NumberOperation.java
  60. 2
      evm/src/main/java/org/hyperledger/besu/evm/operation/Operation.java
  61. 2
      evm/src/main/java/org/hyperledger/besu/evm/operation/OrOperation.java
  62. 2
      evm/src/main/java/org/hyperledger/besu/evm/operation/OriginOperation.java
  63. 2
      evm/src/main/java/org/hyperledger/besu/evm/operation/PCOperation.java
  64. 2
      evm/src/main/java/org/hyperledger/besu/evm/operation/PopOperation.java
  65. 2
      evm/src/main/java/org/hyperledger/besu/evm/operation/PrevRanDaoOperation.java
  66. 2
      evm/src/main/java/org/hyperledger/besu/evm/operation/Push0Operation.java
  67. 1
      evm/src/main/java/org/hyperledger/besu/evm/operation/PushOperation.java
  68. 41
      evm/src/main/java/org/hyperledger/besu/evm/operation/RelativeJumpIfOperation.java
  69. 65
      evm/src/main/java/org/hyperledger/besu/evm/operation/RelativeJumpOperation.java
  70. 53
      evm/src/main/java/org/hyperledger/besu/evm/operation/RelativeJumpVectorOperation.java
  71. 2
      evm/src/main/java/org/hyperledger/besu/evm/operation/ReturnDataCopyOperation.java
  72. 2
      evm/src/main/java/org/hyperledger/besu/evm/operation/ReturnDataSizeOperation.java
  73. 2
      evm/src/main/java/org/hyperledger/besu/evm/operation/ReturnOperation.java
  74. 2
      evm/src/main/java/org/hyperledger/besu/evm/operation/RevertOperation.java
  75. 2
      evm/src/main/java/org/hyperledger/besu/evm/operation/SDivOperation.java
  76. 2
      evm/src/main/java/org/hyperledger/besu/evm/operation/SGtOperation.java
  77. 2
      evm/src/main/java/org/hyperledger/besu/evm/operation/SLoadOperation.java
  78. 2
      evm/src/main/java/org/hyperledger/besu/evm/operation/SLtOperation.java
  79. 2
      evm/src/main/java/org/hyperledger/besu/evm/operation/SModOperation.java
  80. 2
      evm/src/main/java/org/hyperledger/besu/evm/operation/SStoreOperation.java
  81. 2
      evm/src/main/java/org/hyperledger/besu/evm/operation/SarOperation.java
  82. 2
      evm/src/main/java/org/hyperledger/besu/evm/operation/SelfBalanceOperation.java
  83. 2
      evm/src/main/java/org/hyperledger/besu/evm/operation/SelfDestructOperation.java
  84. 2
      evm/src/main/java/org/hyperledger/besu/evm/operation/ShlOperation.java
  85. 2
      evm/src/main/java/org/hyperledger/besu/evm/operation/ShrOperation.java
  86. 2
      evm/src/main/java/org/hyperledger/besu/evm/operation/SignExtendOperation.java
  87. 2
      evm/src/main/java/org/hyperledger/besu/evm/operation/StaticCallOperation.java
  88. 2
      evm/src/main/java/org/hyperledger/besu/evm/operation/StopOperation.java
  89. 2
      evm/src/main/java/org/hyperledger/besu/evm/operation/SubOperation.java
  90. 1
      evm/src/main/java/org/hyperledger/besu/evm/operation/SwapOperation.java
  91. 2
      evm/src/main/java/org/hyperledger/besu/evm/operation/TimestampOperation.java
  92. 5
      evm/src/main/java/org/hyperledger/besu/evm/operation/VirtualOperation.java
  93. 2
      evm/src/main/java/org/hyperledger/besu/evm/operation/XorOperation.java
  94. 187
      evm/src/test/java/org/hyperledger/besu/evm/code/CodeFactoryTest.java
  95. 310
      evm/src/test/java/org/hyperledger/besu/evm/code/CodeV1Test.java

@ -57,7 +57,7 @@ public class DebugOperationTracerTest {
// @Mock private OperationTracer.ExecuteOperation executeOperationAction;
private final Operation anOperation =
new AbstractOperation(0x02, "MUL", 2, 1, 1, null) {
new AbstractOperation(0x02, "MUL", 2, 1, null) {
@Override
public OperationResult execute(final MessageFrame frame, final EVM evm) {
return new OperationResult(20L, null);

@ -0,0 +1,97 @@
/*
* 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.vm.operations;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import org.hyperledger.besu.evm.frame.MessageFrame;
import org.hyperledger.besu.evm.gascalculator.GasCalculator;
import org.hyperledger.besu.evm.operation.Operation;
import org.hyperledger.besu.evm.operation.RelativeJumpIfOperation;
import org.hyperledger.besu.evm.operation.RelativeJumpOperation;
import org.hyperledger.besu.evm.operation.RelativeJumpVectorOperation;
import org.apache.tuweni.bytes.Bytes;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
import org.mockito.Mockito;
public class RelativeJumpOperationTest {
@ParameterizedTest
@ValueSource(ints = {1, 0, 9, -4, -5})
void rjumpOperation(final int jumpLength) {
final GasCalculator gasCalculator = mock(GasCalculator.class);
final MessageFrame messageFrame = mock(MessageFrame.class, Mockito.RETURNS_DEEP_STUBS);
final String twosComplementJump = String.format("%08x", jumpLength).substring(4);
final int rjumpOperationIndex = 3;
final Bytes code = Bytes.fromHexString("00".repeat(3) + "5c" + twosComplementJump);
when(messageFrame.getCode().getCodeBytes()).thenReturn(code);
when(messageFrame.getRemainingGas()).thenReturn(3L);
when(messageFrame.getPC()).thenReturn(rjumpOperationIndex);
RelativeJumpOperation rjump = new RelativeJumpOperation(gasCalculator);
Operation.OperationResult rjumpResult = rjump.execute(messageFrame, null);
Assertions.assertThat(rjumpResult.getPcIncrement())
.isEqualTo(code.size() - rjumpOperationIndex + jumpLength);
}
@Test
void rjumpiOperation() {
final GasCalculator gasCalculator = mock(GasCalculator.class);
final MessageFrame messageFrame = mock(MessageFrame.class, Mockito.RETURNS_DEEP_STUBS);
final int rjumpOperationIndex = 3;
final Bytes code = Bytes.fromHexString("00".repeat(rjumpOperationIndex) + "5d0004");
when(messageFrame.getCode().getCodeBytes()).thenReturn(code);
when(messageFrame.getPC()).thenReturn(rjumpOperationIndex);
when(messageFrame.getRemainingGas()).thenReturn(5L);
when(messageFrame.popStackItem()).thenReturn(Bytes.EMPTY);
RelativeJumpIfOperation rjumpi = new RelativeJumpIfOperation(gasCalculator);
Operation.OperationResult rjumpResult = rjumpi.execute(messageFrame, null);
Assertions.assertThat(rjumpResult.getPcIncrement()).isEqualTo(2 + 1);
}
@Test
void rjumpvOperation() {
final GasCalculator gasCalculator = mock(GasCalculator.class);
final MessageFrame messageFrame = mock(MessageFrame.class, Mockito.RETURNS_DEEP_STUBS);
final int rjumpOperationIndex = 3;
final int jumpVectorSize = 1;
final int jumpLength = 4;
final Bytes code =
Bytes.fromHexString(
"00".repeat(rjumpOperationIndex)
+ String.format("5e%02x%04x", jumpVectorSize, jumpLength));
when(messageFrame.getCode().getCodeBytes()).thenReturn(code);
when(messageFrame.getPC()).thenReturn(rjumpOperationIndex);
when(messageFrame.getRemainingGas()).thenReturn(5L);
when(messageFrame.popStackItem()).thenReturn(Bytes.of(jumpVectorSize));
RelativeJumpVectorOperation rjumpv = new RelativeJumpVectorOperation(gasCalculator);
Operation.OperationResult rjumpResult = rjumpv.execute(messageFrame, null);
Assertions.assertThat(rjumpResult.getPcIncrement()).isEqualTo(1 + 2 * jumpVectorSize + 1);
}
}

@ -84,6 +84,9 @@ import org.hyperledger.besu.evm.operation.PopOperation;
import org.hyperledger.besu.evm.operation.PrevRanDaoOperation;
import org.hyperledger.besu.evm.operation.Push0Operation;
import org.hyperledger.besu.evm.operation.PushOperation;
import org.hyperledger.besu.evm.operation.RelativeJumpIfOperation;
import org.hyperledger.besu.evm.operation.RelativeJumpOperation;
import org.hyperledger.besu.evm.operation.RelativeJumpVectorOperation;
import org.hyperledger.besu.evm.operation.ReturnDataCopyOperation;
import org.hyperledger.besu.evm.operation.ReturnDataSizeOperation;
import org.hyperledger.besu.evm.operation.ReturnOperation;
@ -456,5 +459,8 @@ public class MainnetEVMs {
registerParisOperations(registry, gasCalculator, chainID);
// Register the PUSH0 operation.
registry.put(new Push0Operation(gasCalculator));
registry.put(new RelativeJumpOperation(gasCalculator));
registry.put(new RelativeJumpIfOperation(gasCalculator));
registry.put(new RelativeJumpVectorOperation(gasCalculator));
}
}

@ -17,6 +17,11 @@
package org.hyperledger.besu.evm.code;
import org.hyperledger.besu.evm.operation.PushOperation;
import org.hyperledger.besu.evm.operation.RelativeJumpIfOperation;
import org.hyperledger.besu.evm.operation.RelativeJumpOperation;
import org.hyperledger.besu.evm.operation.RelativeJumpVectorOperation;
import java.util.BitSet;
import org.apache.tuweni.bytes.Bytes;
@ -122,9 +127,9 @@ class OpcodesV1 {
VALID, // 0x59 - MSIZE
VALID, // 0x5a - GAS
VALID_AND_JUMPDEST, // 0x5b - JUMPDEST
INVALID, // 0X5c
INVALID, // 0X5d
INVALID, // 0X5e
VALID, // 0X5c - RJUMP
VALID, // 0X5d - RJUMPI
VALID, // 0X5e - RJUMPV
VALID, // 0X5f - PUSH0
VALID, // 0x60 - PUSH1
VALID, // 0x61 - PUSH2
@ -294,34 +299,77 @@ class OpcodesV1 {
static long[] validateAndCalculateJumpDests(final Bytes code) {
final int size = code.size();
final long[] bitmap = new long[(size >> 6) + 1];
final BitSet bitmap = new BitSet(size);
final BitSet rjumpdests = new BitSet(size);
final BitSet immediates = new BitSet(size);
final byte[] rawCode = code.toArrayUnsafe();
final int length = rawCode.length;
int attribute = INVALID;
for (int i = 0; i < length; ) {
long thisEntry = 0L;
final int entryPos = i >> 6;
final int max = Math.min(64, length - (entryPos << 6));
int j = i & 0x3f;
for (; j < max; i++, j++) {
final int operationNum = rawCode[i] & 0xff;
int pos = 0;
while (pos < size) {
final int operationNum = rawCode[pos] & 0xff;
attribute = opcodeAttributes[operationNum];
if ((attribute & INVALID) == INVALID) {
// undefined instruction
return null;
} else if ((attribute & JUMPDEST) == JUMPDEST) {
thisEntry |= 1L << j;
} else if (operationNum > PushOperation.PUSH_BASE
&& operationNum <= PushOperation.PUSH_MAX) {
}
if ((attribute & JUMPDEST) == JUMPDEST) {
bitmap.set(pos);
}
pos += 1;
int pcPostInstruction = pos;
if (operationNum > PushOperation.PUSH_BASE && operationNum <= PushOperation.PUSH_MAX) {
final int multiByteDataLen = operationNum - PushOperation.PUSH_BASE;
j += multiByteDataLen;
i += multiByteDataLen;
pcPostInstruction += multiByteDataLen;
} else if (operationNum == RelativeJumpOperation.OPCODE
|| operationNum == RelativeJumpIfOperation.OPCODE) {
if (pos + 2 > size) {
// truncated relative jump offset
return null;
}
pcPostInstruction += 2;
final int offset = RelativeJumpOperation.getRelativeOffset(code, pos);
final int rjumpdest = pcPostInstruction + offset;
if (rjumpdest < 0 || rjumpdest >= size) {
// relative jump destination out of bounds
return null;
}
bitmap[entryPos] = thisEntry;
rjumpdests.set(rjumpdest);
} else if (operationNum == RelativeJumpVectorOperation.OPCODE) {
if (pos + 1 > size) {
// truncated jump table
return null;
}
final int jumpTableSize = RelativeJumpVectorOperation.getVectorSize(code, pos);
if (jumpTableSize == 0) {
// empty jump table
return null;
}
pcPostInstruction += 1 + 2 * jumpTableSize;
if (pcPostInstruction > size) {
// truncated jump table
return null;
}
for (int offsetPos = pos + 1; offsetPos < pcPostInstruction; offsetPos += 2) {
final int offset = RelativeJumpOperation.getRelativeOffset(code, offsetPos);
final int rjumpdest = pcPostInstruction + offset;
if (rjumpdest < 0 || rjumpdest >= size) {
// relative jump destination out of bounds
return null;
}
rjumpdests.set(rjumpdest);
}
}
immediates.set(pos, pcPostInstruction);
pos = pcPostInstruction;
}
if ((attribute & TERMINAL) != TERMINAL) {
// no terminating instruction
return null;
}
if (rjumpdests.intersects(immediates)) {
// Ensure relative jump destinations don't target immediates
return null;
}
return bitmap;
return bitmap.toLongArray();
}
}

@ -45,9 +45,8 @@ public abstract class AbstractCallOperation extends AbstractOperation {
final String name,
final int stackItemsConsumed,
final int stackItemsProduced,
final int opSize,
final GasCalculator gasCalculator) {
super(opcode, name, stackItemsConsumed, stackItemsProduced, opSize, gasCalculator);
super(opcode, name, stackItemsConsumed, stackItemsProduced, gasCalculator);
}
/**

@ -41,9 +41,8 @@ public abstract class AbstractCreateOperation extends AbstractOperation {
final String name,
final int stackItemsConsumed,
final int stackItemsProduced,
final int opSize,
final GasCalculator gasCalculator) {
super(opcode, name, stackItemsConsumed, stackItemsProduced, opSize, gasCalculator);
super(opcode, name, stackItemsConsumed, stackItemsProduced, gasCalculator);
}
@Override

@ -36,10 +36,9 @@ abstract class AbstractFixedCostOperation extends AbstractOperation {
final String name,
final int stackItemsConsumed,
final int stackItemsProduced,
final int opSize,
final GasCalculator gasCalculator,
final long fixedCost) {
super(opcode, name, stackItemsConsumed, stackItemsProduced, opSize, gasCalculator);
super(opcode, name, stackItemsConsumed, stackItemsProduced, gasCalculator);
gasCost = fixedCost;
successResponse = new OperationResult(gasCost, null);
outOfGasResponse = new OperationResult(gasCost, ExceptionalHaltReason.INSUFFICIENT_GAS);

@ -26,7 +26,6 @@ public abstract class AbstractOperation implements Operation {
private final String name;
private final int stackItemsConsumed;
private final int stackItemsProduced;
private final int opSize;
private final GasCalculator gasCalculator;
protected AbstractOperation(
@ -34,13 +33,11 @@ public abstract class AbstractOperation implements Operation {
final String name,
final int stackItemsConsumed,
final int stackItemsProduced,
final int opSize,
final GasCalculator gasCalculator) {
this.opcode = opcode & 0xff;
this.name = name;
this.stackItemsConsumed = stackItemsConsumed;
this.stackItemsProduced = stackItemsProduced;
this.opSize = opSize;
this.gasCalculator = gasCalculator;
}
@ -67,9 +64,4 @@ public abstract class AbstractOperation implements Operation {
public int getStackItemsProduced() {
return stackItemsProduced;
}
@Override
public int getOpSize() {
return opSize;
}
}

@ -29,7 +29,7 @@ public class AddModOperation extends AbstractFixedCostOperation {
private static final OperationResult addModSuccess = new OperationResult(8, null);
public AddModOperation(final GasCalculator gasCalculator) {
super(0x08, "ADDMOD", 3, 1, 1, gasCalculator, gasCalculator.getMidTierGasCost());
super(0x08, "ADDMOD", 3, 1, gasCalculator, gasCalculator.getMidTierGasCost());
}
@Override

@ -27,7 +27,7 @@ public class AddOperation extends AbstractFixedCostOperation {
static final OperationResult addSuccess = new OperationResult(3, null);
public AddOperation(final GasCalculator gasCalculator) {
super(0x01, "ADD", 2, 1, 1, gasCalculator, gasCalculator.getVeryLowTierGasCost());
super(0x01, "ADD", 2, 1, gasCalculator, gasCalculator.getVeryLowTierGasCost());
}
@Override

@ -21,7 +21,7 @@ import org.hyperledger.besu.evm.gascalculator.GasCalculator;
public class AddressOperation extends AbstractFixedCostOperation {
public AddressOperation(final GasCalculator gasCalculator) {
super(0x30, "ADDRESS", 0, 1, 1, gasCalculator, gasCalculator.getBaseTierGasCost());
super(0x30, "ADDRESS", 0, 1, gasCalculator, gasCalculator.getBaseTierGasCost());
}
@Override

@ -25,7 +25,7 @@ public class AndOperation extends AbstractFixedCostOperation {
static final OperationResult andSuccess = new OperationResult(3, null);
public AndOperation(final GasCalculator gasCalculator) {
super(0x16, "AND", 2, 1, 1, gasCalculator, gasCalculator.getVeryLowTierGasCost());
super(0x16, "AND", 2, 1, gasCalculator, gasCalculator.getVeryLowTierGasCost());
}
@Override

@ -29,7 +29,7 @@ import org.apache.tuweni.units.bigints.UInt256;
public class BalanceOperation extends AbstractOperation {
public BalanceOperation(final GasCalculator gasCalculator) {
super(0x31, "BALANCE", 1, 1, 1, gasCalculator);
super(0x31, "BALANCE", 1, 1, gasCalculator);
}
protected long cost(final boolean accountIsWarm) {

@ -25,7 +25,7 @@ import java.util.Optional;
public class BaseFeeOperation extends AbstractFixedCostOperation {
public BaseFeeOperation(final GasCalculator gasCalculator) {
super(0x48, "BASEFEE", 0, 1, 1, gasCalculator, gasCalculator.getBaseTierGasCost());
super(0x48, "BASEFEE", 0, 1, gasCalculator, gasCalculator.getBaseTierGasCost());
}
@Override

@ -29,7 +29,7 @@ public class BlockHashOperation extends AbstractFixedCostOperation {
private static final int MAX_RELATIVE_BLOCK = 255;
public BlockHashOperation(final GasCalculator gasCalculator) {
super(0x40, "BLOCKHASH", 1, 1, 1, gasCalculator, gasCalculator.getBlockHashOperationGasCost());
super(0x40, "BLOCKHASH", 1, 1, gasCalculator, gasCalculator.getBlockHashOperationGasCost());
}
@Override

@ -26,7 +26,7 @@ public class ByteOperation extends AbstractFixedCostOperation {
static final OperationResult byteSuccess = new OperationResult(3, null);
public ByteOperation(final GasCalculator gasCalculator) {
super(0x1A, "BYTE", 2, 1, 1, gasCalculator, gasCalculator.getVeryLowTierGasCost());
super(0x1A, "BYTE", 2, 1, gasCalculator, gasCalculator.getVeryLowTierGasCost());
}
private static UInt256 getByte(final UInt256 seq, final UInt256 offset) {

@ -26,7 +26,7 @@ import org.hyperledger.besu.evm.internal.Words;
public class CallCodeOperation extends AbstractCallOperation {
public CallCodeOperation(final GasCalculator gasCalculator) {
super(0xF2, "CALLCODE", 7, 1, 1, gasCalculator);
super(0xF2, "CALLCODE", 7, 1, gasCalculator);
}
@Override

@ -26,7 +26,7 @@ import org.apache.tuweni.bytes.Bytes;
public class CallDataCopyOperation extends AbstractOperation {
public CallDataCopyOperation(final GasCalculator gasCalculator) {
super(0x37, "CALLDATACOPY", 3, 0, 1, gasCalculator);
super(0x37, "CALLDATACOPY", 3, 0, gasCalculator);
}
@Override

@ -26,7 +26,7 @@ import org.apache.tuweni.units.bigints.UInt256;
public class CallDataLoadOperation extends AbstractFixedCostOperation {
public CallDataLoadOperation(final GasCalculator gasCalculator) {
super(0x35, "CALLDATALOAD", 1, 1, 1, gasCalculator, gasCalculator.getVeryLowTierGasCost());
super(0x35, "CALLDATALOAD", 1, 1, gasCalculator, gasCalculator.getVeryLowTierGasCost());
}
@Override

@ -24,7 +24,7 @@ import org.apache.tuweni.units.bigints.UInt256;
public class CallDataSizeOperation extends AbstractFixedCostOperation {
public CallDataSizeOperation(final GasCalculator gasCalculator) {
super(0x36, "CALLDATASIZE", 0, 1, 1, gasCalculator, gasCalculator.getBaseTierGasCost());
super(0x36, "CALLDATASIZE", 0, 1, gasCalculator, gasCalculator.getBaseTierGasCost());
}
@Override

@ -28,7 +28,7 @@ import org.hyperledger.besu.evm.internal.Words;
public class CallOperation extends AbstractCallOperation {
public CallOperation(final GasCalculator gasCalculator) {
super(0xF1, "CALL", 7, 1, 1, gasCalculator);
super(0xF1, "CALL", 7, 1, gasCalculator);
}
@Override

@ -22,7 +22,7 @@ import org.hyperledger.besu.evm.gascalculator.GasCalculator;
public class CallValueOperation extends AbstractFixedCostOperation {
public CallValueOperation(final GasCalculator gasCalculator) {
super(0x34, "CALLVALUE", 0, 1, 1, gasCalculator, gasCalculator.getBaseTierGasCost());
super(0x34, "CALLVALUE", 0, 1, gasCalculator, gasCalculator.getBaseTierGasCost());
}
@Override

@ -21,7 +21,7 @@ import org.hyperledger.besu.evm.gascalculator.GasCalculator;
public class CallerOperation extends AbstractFixedCostOperation {
public CallerOperation(final GasCalculator gasCalculator) {
super(0x33, "CALLER", 0, 1, 1, gasCalculator, gasCalculator.getBaseTierGasCost());
super(0x33, "CALLER", 0, 1, gasCalculator, gasCalculator.getBaseTierGasCost());
}
@Override

@ -26,7 +26,7 @@ public class ChainIdOperation extends AbstractFixedCostOperation {
private final UInt256 chainId;
public ChainIdOperation(final GasCalculator gasCalculator, final Bytes32 chainId) {
super(0x46, "CHAINID", 0, 1, 1, gasCalculator, gasCalculator.getBaseTierGasCost());
super(0x46, "CHAINID", 0, 1, gasCalculator, gasCalculator.getBaseTierGasCost());
this.chainId = UInt256.fromBytes(chainId);
}

@ -25,7 +25,7 @@ import org.hyperledger.besu.evm.gascalculator.GasCalculator;
public class CodeCopyOperation extends AbstractOperation {
public CodeCopyOperation(final GasCalculator gasCalculator) {
super(0x39, "CODECOPY", 3, 0, 1, gasCalculator);
super(0x39, "CODECOPY", 3, 0, gasCalculator);
}
@Override

@ -24,7 +24,7 @@ import org.apache.tuweni.units.bigints.UInt256;
public class CodeSizeOperation extends AbstractFixedCostOperation {
public CodeSizeOperation(final GasCalculator gasCalculator) {
super(0x38, "CODESIZE", 0, 1, 1, gasCalculator, gasCalculator.getBaseTierGasCost());
super(0x38, "CODESIZE", 0, 1, gasCalculator, gasCalculator.getBaseTierGasCost());
}
@Override

@ -22,7 +22,7 @@ import org.hyperledger.besu.evm.gascalculator.GasCalculator;
public class CoinbaseOperation extends AbstractFixedCostOperation {
public CoinbaseOperation(final GasCalculator gasCalculator) {
super(0x41, "COINBASE", 0, 1, 1, gasCalculator, gasCalculator.getBaseTierGasCost());
super(0x41, "COINBASE", 0, 1, gasCalculator, gasCalculator.getBaseTierGasCost());
}
@Override

@ -30,7 +30,7 @@ public class Create2Operation extends AbstractCreateOperation {
private static final Bytes PREFIX = Bytes.fromHexString("0xFF");
public Create2Operation(final GasCalculator gasCalculator) {
super(0xF5, "CREATE2", 4, 1, 1, gasCalculator);
super(0xF5, "CREATE2", 4, 1, gasCalculator);
}
@Override

@ -22,7 +22,7 @@ import org.hyperledger.besu.evm.gascalculator.GasCalculator;
public class CreateOperation extends AbstractCreateOperation {
public CreateOperation(final GasCalculator gasCalculator) {
super(0xF0, "CREATE", 3, 1, 1, gasCalculator);
super(0xF0, "CREATE", 3, 1, gasCalculator);
}
@Override

@ -26,7 +26,7 @@ import org.hyperledger.besu.evm.internal.Words;
public class DelegateCallOperation extends AbstractCallOperation {
public DelegateCallOperation(final GasCalculator gasCalculator) {
super(0xF4, "DELEGATECALL", 6, 1, 1, gasCalculator);
super(0xF4, "DELEGATECALL", 6, 1, gasCalculator);
}
@Override

@ -21,7 +21,7 @@ import org.hyperledger.besu.evm.gascalculator.GasCalculator;
public class DifficultyOperation extends AbstractFixedCostOperation {
public DifficultyOperation(final GasCalculator gasCalculator) {
super(0x44, "DIFFICULTY", 0, 1, 1, gasCalculator, gasCalculator.getBaseTierGasCost());
super(0x44, "DIFFICULTY", 0, 1, gasCalculator, gasCalculator.getBaseTierGasCost());
}
@Override

@ -28,7 +28,7 @@ public class DivOperation extends AbstractFixedCostOperation {
static final OperationResult divSuccess = new OperationResult(5, null);
public DivOperation(final GasCalculator gasCalculator) {
super(0x04, "DIV", 2, 1, 1, gasCalculator, gasCalculator.getLowTierGasCost());
super(0x04, "DIV", 2, 1, gasCalculator, gasCalculator.getLowTierGasCost());
}
@Override

@ -33,7 +33,6 @@ public class DupOperation extends AbstractFixedCostOperation {
"DUP" + index,
index,
index + 1,
1,
gasCalculator,
gasCalculator.getVeryLowTierGasCost());
this.index = index;

@ -25,7 +25,7 @@ public class EqOperation extends AbstractFixedCostOperation {
static final OperationResult eqSuccess = new OperationResult(3, null);
public EqOperation(final GasCalculator gasCalculator) {
super(0x14, "EQ", 2, 1, 1, gasCalculator, gasCalculator.getVeryLowTierGasCost());
super(0x14, "EQ", 2, 1, gasCalculator, gasCalculator.getVeryLowTierGasCost());
}
@Override

@ -24,7 +24,7 @@ import org.apache.tuweni.units.bigints.UInt256;
public class ExpOperation extends AbstractOperation {
public ExpOperation(final GasCalculator gasCalculator) {
super(0x0A, "EXP", 2, 1, 1, gasCalculator);
super(0x0A, "EXP", 2, 1, gasCalculator);
}
@Override

@ -30,7 +30,7 @@ import org.apache.tuweni.bytes.Bytes;
public class ExtCodeCopyOperation extends AbstractOperation {
public ExtCodeCopyOperation(final GasCalculator gasCalculator) {
super(0x3C, "EXTCODECOPY", 4, 0, 1, gasCalculator);
super(0x3C, "EXTCODECOPY", 4, 0, gasCalculator);
}
protected long cost(

@ -29,7 +29,7 @@ import org.apache.tuweni.units.bigints.UInt256;
public class ExtCodeHashOperation extends AbstractOperation {
public ExtCodeHashOperation(final GasCalculator gasCalculator) {
super(0x3F, "EXTCODEHASH", 1, 1, 1, gasCalculator);
super(0x3F, "EXTCODEHASH", 1, 1, gasCalculator);
}
protected long cost(final boolean accountIsWarm) {

@ -29,7 +29,7 @@ import org.apache.tuweni.units.bigints.UInt256;
public class ExtCodeSizeOperation extends AbstractOperation {
public ExtCodeSizeOperation(final GasCalculator gasCalculator) {
super(0x3B, "EXTCODESIZE", 1, 1, 1, gasCalculator);
super(0x3B, "EXTCODESIZE", 1, 1, gasCalculator);
}
protected long cost(final boolean accountIsWarm) {

@ -23,7 +23,7 @@ import org.apache.tuweni.bytes.Bytes;
public class GasLimitOperation extends AbstractFixedCostOperation {
public GasLimitOperation(final GasCalculator gasCalculator) {
super(0x45, "GASLIMIT", 0, 1, 1, gasCalculator, gasCalculator.getBaseTierGasCost());
super(0x45, "GASLIMIT", 0, 1, gasCalculator, gasCalculator.getBaseTierGasCost());
}
@Override

@ -23,7 +23,7 @@ import org.apache.tuweni.bytes.Bytes;
public class GasOperation extends AbstractFixedCostOperation {
public GasOperation(final GasCalculator gasCalculator) {
super(0x5A, "GAS", 0, 1, 1, gasCalculator, gasCalculator.getBaseTierGasCost());
super(0x5A, "GAS", 0, 1, gasCalculator, gasCalculator.getBaseTierGasCost());
}
@Override

@ -22,7 +22,7 @@ import org.hyperledger.besu.evm.gascalculator.GasCalculator;
public class GasPriceOperation extends AbstractFixedCostOperation {
public GasPriceOperation(final GasCalculator gasCalculator) {
super(0x3A, "GASPRICE", 0, 1, 1, gasCalculator, gasCalculator.getBaseTierGasCost());
super(0x3A, "GASPRICE", 0, 1, gasCalculator, gasCalculator.getBaseTierGasCost());
}
@Override

@ -25,7 +25,7 @@ public class GtOperation extends AbstractFixedCostOperation {
static final OperationResult gtSuccess = new OperationResult(3, null);
public GtOperation(final GasCalculator gasCalculator) {
super(0x11, "GT", 2, 1, 1, gasCalculator, gasCalculator.getVeryLowTierGasCost());
super(0x11, "GT", 2, 1, gasCalculator, gasCalculator.getVeryLowTierGasCost());
}
@Override

@ -31,7 +31,7 @@ public class InvalidOperation extends AbstractOperation {
}
public InvalidOperation(final int opcode, final GasCalculator gasCalculator) {
super(opcode, "INVALID", -1, -1, 1, gasCalculator);
super(opcode, "INVALID", -1, -1, gasCalculator);
invalidResult = new OperationResult(0L, ExceptionalHaltReason.INVALID_OPERATION);
}

@ -25,7 +25,7 @@ public class IsZeroOperation extends AbstractFixedCostOperation {
static final OperationResult isZeroSuccess = new OperationResult(3, null);
public IsZeroOperation(final GasCalculator gasCalculator) {
super(0x15, "ISZERO", 1, 1, 1, gasCalculator, gasCalculator.getVeryLowTierGasCost());
super(0x15, "ISZERO", 1, 1, gasCalculator, gasCalculator.getVeryLowTierGasCost());
}
@Override

@ -23,7 +23,7 @@ public class JumpDestOperation extends AbstractFixedCostOperation {
public static final int OPCODE = 0x5B;
public JumpDestOperation(final GasCalculator gasCalculator) {
super(OPCODE, "JUMPDEST", 0, 0, 1, gasCalculator, gasCalculator.getJumpDestOperationGasCost());
super(OPCODE, "JUMPDEST", 0, 0, gasCalculator, gasCalculator.getJumpDestOperationGasCost());
}
@Override

@ -28,7 +28,7 @@ public class JumpOperation extends AbstractFixedCostOperation {
private final OperationResult jumpResponse;
public JumpOperation(final GasCalculator gasCalculator) {
super(0x56, "JUMP", 2, 0, 1, gasCalculator, gasCalculator.getMidTierGasCost());
super(0x56, "JUMP", 2, 0, gasCalculator, gasCalculator.getMidTierGasCost());
invalidJumpResponse =
new Operation.OperationResult(gasCost, ExceptionalHaltReason.INVALID_JUMP_DESTINATION);
jumpResponse = new OperationResult(gasCost, null, 0);

@ -28,7 +28,7 @@ public class JumpiOperation extends AbstractFixedCostOperation {
private final OperationResult jumpResponse;
public JumpiOperation(final GasCalculator gasCalculator) {
super(0x57, "JUMPI", 2, 0, 1, gasCalculator, gasCalculator.getHighTierGasCost());
super(0x57, "JUMPI", 2, 0, gasCalculator, gasCalculator.getHighTierGasCost());
invalidJumpResponse =
new Operation.OperationResult(gasCost, ExceptionalHaltReason.INVALID_JUMP_DESTINATION);
jumpResponse = new OperationResult(gasCost, null, 0);

@ -28,7 +28,7 @@ import org.apache.tuweni.units.bigints.UInt256;
public class Keccak256Operation extends AbstractOperation {
public Keccak256Operation(final GasCalculator gasCalculator) {
super(0x20, "KECCAK256", 2, 1, 1, gasCalculator);
super(0x20, "KECCAK256", 2, 1, gasCalculator);
}
@Override

@ -33,7 +33,7 @@ public class LogOperation extends AbstractOperation {
private final int numTopics;
public LogOperation(final int numTopics, final GasCalculator gasCalculator) {
super(0xA0 + numTopics, "LOG" + numTopics, numTopics + 2, 0, 1, gasCalculator);
super(0xA0 + numTopics, "LOG" + numTopics, numTopics + 2, 0, gasCalculator);
this.numTopics = numTopics;
}

@ -25,7 +25,7 @@ public class LtOperation extends AbstractFixedCostOperation {
static final OperationResult ltSuccess = new OperationResult(3, null);
public LtOperation(final GasCalculator gasCalculator) {
super(0x10, "LT", 2, 1, 1, gasCalculator, gasCalculator.getVeryLowTierGasCost());
super(0x10, "LT", 2, 1, gasCalculator, gasCalculator.getVeryLowTierGasCost());
}
@Override

@ -26,7 +26,7 @@ import org.apache.tuweni.bytes.Bytes;
public class MLoadOperation extends AbstractOperation {
public MLoadOperation(final GasCalculator gasCalculator) {
super(0x51, "MLOAD", 1, 1, 1, gasCalculator);
super(0x51, "MLOAD", 1, 1, gasCalculator);
}
@Override

@ -23,7 +23,7 @@ import org.apache.tuweni.units.bigints.UInt256;
public class MSizeOperation extends AbstractFixedCostOperation {
public MSizeOperation(final GasCalculator gasCalculator) {
super(0x59, "MSIZE", 0, 1, 1, gasCalculator, gasCalculator.getBaseTierGasCost());
super(0x59, "MSIZE", 0, 1, gasCalculator, gasCalculator.getBaseTierGasCost());
}
@Override

@ -26,7 +26,7 @@ import org.apache.tuweni.bytes.Bytes;
public class MStore8Operation extends AbstractOperation {
public MStore8Operation(final GasCalculator gasCalculator) {
super(0x53, "MSTORE8", 2, 0, 1, gasCalculator);
super(0x53, "MSTORE8", 2, 0, gasCalculator);
}
@Override

@ -26,7 +26,7 @@ import org.apache.tuweni.bytes.Bytes;
public class MStoreOperation extends AbstractOperation {
public MStoreOperation(final GasCalculator gasCalculator) {
super(0x52, "MSTORE", 2, 0, 1, gasCalculator);
super(0x52, "MSTORE", 2, 0, gasCalculator);
}
@Override

@ -29,7 +29,7 @@ public class ModOperation extends AbstractFixedCostOperation {
private static final OperationResult modSuccess = new OperationResult(5, null);
public ModOperation(final GasCalculator gasCalculator) {
super(0x06, "MOD", 2, 1, 1, gasCalculator, gasCalculator.getLowTierGasCost());
super(0x06, "MOD", 2, 1, gasCalculator, gasCalculator.getLowTierGasCost());
}
@Override

@ -29,7 +29,7 @@ public class MulModOperation extends AbstractFixedCostOperation {
private static final OperationResult mulModSuccess = new OperationResult(8, null);
public MulModOperation(final GasCalculator gasCalculator) {
super(0x09, "MULMOD", 3, 1, 1, gasCalculator, gasCalculator.getMidTierGasCost());
super(0x09, "MULMOD", 3, 1, gasCalculator, gasCalculator.getMidTierGasCost());
}
@Override

@ -27,7 +27,7 @@ public class MulOperation extends AbstractFixedCostOperation {
static final OperationResult mulSuccess = new OperationResult(5, null);
public MulOperation(final GasCalculator gasCalculator) {
super(0x02, "MUL", 2, 1, 1, gasCalculator, gasCalculator.getLowTierGasCost());
super(0x02, "MUL", 2, 1, gasCalculator, gasCalculator.getLowTierGasCost());
}
@Override

@ -25,7 +25,7 @@ public class NotOperation extends AbstractFixedCostOperation {
static final OperationResult notSuccess = new OperationResult(3, null);
public NotOperation(final GasCalculator gasCalculator) {
super(0x19, "NOT", 1, 1, 1, gasCalculator, gasCalculator.getVeryLowTierGasCost());
super(0x19, "NOT", 1, 1, gasCalculator, gasCalculator.getVeryLowTierGasCost());
}
@Override

@ -23,7 +23,7 @@ import org.apache.tuweni.bytes.Bytes;
public class NumberOperation extends AbstractFixedCostOperation {
public NumberOperation(final GasCalculator gasCalculator) {
super(0x43, "NUMBER", 0, 1, 1, gasCalculator, gasCalculator.getBaseTierGasCost());
super(0x43, "NUMBER", 0, 1, gasCalculator, gasCalculator.getBaseTierGasCost());
}
@Override

@ -71,8 +71,6 @@ public interface Operation {
int getStackItemsProduced();
int getOpSize();
/**
* Determines whether this operation has been virtually added to the contract code. For instance
* if the contract is not ended by a STOP opcode the {@link EVM} adds an explicit end of script

@ -25,7 +25,7 @@ public class OrOperation extends AbstractFixedCostOperation {
static final OperationResult orSuccess = new OperationResult(3, null);
public OrOperation(final GasCalculator gasCalculator) {
super(0x17, "OR", 2, 1, 1, gasCalculator, gasCalculator.getVeryLowTierGasCost());
super(0x17, "OR", 2, 1, gasCalculator, gasCalculator.getVeryLowTierGasCost());
}
@Override

@ -21,7 +21,7 @@ import org.hyperledger.besu.evm.gascalculator.GasCalculator;
public class OriginOperation extends AbstractFixedCostOperation {
public OriginOperation(final GasCalculator gasCalculator) {
super(0x32, "ORIGIN", 0, 1, 1, gasCalculator, gasCalculator.getBaseTierGasCost());
super(0x32, "ORIGIN", 0, 1, gasCalculator, gasCalculator.getBaseTierGasCost());
}
@Override

@ -23,7 +23,7 @@ import org.apache.tuweni.units.bigints.UInt256;
public class PCOperation extends AbstractFixedCostOperation {
public PCOperation(final GasCalculator gasCalculator) {
super(0x58, "PC", 0, 1, 1, gasCalculator, gasCalculator.getBaseTierGasCost());
super(0x58, "PC", 0, 1, gasCalculator, gasCalculator.getBaseTierGasCost());
}
@Override

@ -23,7 +23,7 @@ public class PopOperation extends AbstractFixedCostOperation {
static final OperationResult popSuccess = new OperationResult(2, null);
public PopOperation(final GasCalculator gasCalculator) {
super(0x50, "POP", 1, 0, 1, gasCalculator, gasCalculator.getBaseTierGasCost());
super(0x50, "POP", 1, 0, gasCalculator, gasCalculator.getBaseTierGasCost());
}
@Override

@ -21,7 +21,7 @@ import org.hyperledger.besu.evm.gascalculator.GasCalculator;
public class PrevRanDaoOperation extends AbstractFixedCostOperation {
public PrevRanDaoOperation(final GasCalculator gasCalculator) {
super(0x44, "PREVRANDAO", 0, 1, 1, gasCalculator, gasCalculator.getBaseTierGasCost());
super(0x44, "PREVRANDAO", 0, 1, gasCalculator, gasCalculator.getBaseTierGasCost());
}
@Override

@ -27,7 +27,7 @@ public class Push0Operation extends AbstractFixedCostOperation {
static final OperationResult push0Success = new OperationResult(2, null);
public Push0Operation(final GasCalculator gasCalculator) {
super(PUSH_BASE, "PUSH0", 0, 1, 1, gasCalculator, gasCalculator.getBaseTierGasCost());
super(PUSH_BASE, "PUSH0", 0, 1, gasCalculator, gasCalculator.getBaseTierGasCost());
}
@Override

@ -35,7 +35,6 @@ public class PushOperation extends AbstractFixedCostOperation {
"PUSH" + length,
0,
1,
length + 1,
gasCalculator,
gasCalculator.getVeryLowTierGasCost());
this.length = length;

@ -0,0 +1,41 @@
/*
* 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 org.hyperledger.besu.evm.EVM;
import org.hyperledger.besu.evm.frame.MessageFrame;
import org.hyperledger.besu.evm.gascalculator.GasCalculator;
import org.apache.tuweni.bytes.Bytes;
public class RelativeJumpIfOperation extends RelativeJumpOperation {
public static final int OPCODE = 0x5d;
public RelativeJumpIfOperation(final GasCalculator gasCalculator) {
super(OPCODE, "RJUMPI", 0, 0, gasCalculator, 4L);
}
@Override
protected OperationResult executeFixedCostOperation(final MessageFrame frame, final EVM evm) {
final Bytes condition = frame.popStackItem();
// If condition is zero (false), no jump is will be performed. Therefore, skip the rest.
if (!condition.isZero()) {
return super.executeFixedCostOperation(frame, evm);
}
return new OperationResult(gasCost, null, 2 + 1);
}
}

@ -0,0 +1,65 @@
/*
* 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 org.hyperledger.besu.evm.EVM;
import org.hyperledger.besu.evm.frame.MessageFrame;
import org.hyperledger.besu.evm.gascalculator.GasCalculator;
import org.apache.tuweni.bytes.Bytes;
public class RelativeJumpOperation extends AbstractFixedCostOperation {
public static final int OPCODE = 0x5c;
public RelativeJumpOperation(final GasCalculator gasCalculator) {
this(OPCODE, "RJUMP", 0, 0, gasCalculator, gasCalculator.getBaseTierGasCost());
}
protected RelativeJumpOperation(
final int opcode,
final String name,
final int stackItemsConsumed,
final int stackItemsProduced,
final GasCalculator gasCalculator,
final long fixedCost) {
super(opcode, name, stackItemsConsumed, stackItemsProduced, gasCalculator, fixedCost);
}
@Override
protected OperationResult executeFixedCostOperation(final MessageFrame frame, final EVM evm) {
final Bytes code = frame.getCode().getCodeBytes();
final int pcPostInstruction = frame.getPC() + 1;
return new OperationResult(gasCost, null, 2 + getRelativeOffset(code, pcPostInstruction) + 1);
}
/**
* Extracts the relative offset from the 16 bits after the RJUMP[I] opcode. This value is encoded
* as a 16-bit signed (twos-complement) big-endian value
*
* @param code the source
* @param relativeOffsetBegin offset within the code where the immediate offset begins
* @return code immediate offset
*/
public static int getRelativeOffset(final Bytes code, final int relativeOffsetBegin) {
int relativeOffset =
(code.get(relativeOffsetBegin) << 8) | (code.get(relativeOffsetBegin + 1) & 0xff);
if ((relativeOffset & 0x8000) != 0) {
relativeOffset = -((~relativeOffset & 0xffff) + 1);
}
return relativeOffset;
}
}

@ -0,0 +1,53 @@
/*
* 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.operation.RelativeJumpOperation.getRelativeOffset;
import org.hyperledger.besu.evm.EVM;
import org.hyperledger.besu.evm.frame.MessageFrame;
import org.hyperledger.besu.evm.gascalculator.GasCalculator;
import org.apache.tuweni.bytes.Bytes;
public class RelativeJumpVectorOperation extends AbstractFixedCostOperation {
public static final int OPCODE = 0x5e;
public RelativeJumpVectorOperation(final GasCalculator gasCalculator) {
super(OPCODE, "RJUMPV", 0, 0, gasCalculator, 4L);
}
@Override
protected OperationResult executeFixedCostOperation(final MessageFrame frame, final EVM evm) {
final Bytes code = frame.getCode().getCodeBytes();
final int offsetCase = frame.popStackItem().toInt();
final int vectorSize = getVectorSize(code, frame.getPC() + 1);
return new OperationResult(
gasCost,
null,
1
+ 2 * vectorSize
+ ((offsetCase >= vectorSize)
? 0
: getRelativeOffset(code, frame.getPC() + 1 + offsetCase * 2))
+ 1);
}
public static int getVectorSize(final Bytes code, final int offsetCountByteIndex) {
return code.get(offsetCountByteIndex) & 0xff;
}
}

@ -31,7 +31,7 @@ public class ReturnDataCopyOperation extends AbstractOperation {
new OperationResult(0L, ExceptionalHaltReason.OUT_OF_BOUNDS);
public ReturnDataCopyOperation(final GasCalculator gasCalculator) {
super(0x3E, "RETURNDATACOPY", 3, 0, 1, gasCalculator);
super(0x3E, "RETURNDATACOPY", 3, 0, gasCalculator);
}
@Override

@ -24,7 +24,7 @@ import org.apache.tuweni.units.bigints.UInt256;
public class ReturnDataSizeOperation extends AbstractFixedCostOperation {
public ReturnDataSizeOperation(final GasCalculator gasCalculator) {
super(0x3D, "RETURNDATASIZE", 0, 1, 1, gasCalculator, gasCalculator.getBaseTierGasCost());
super(0x3D, "RETURNDATASIZE", 0, 1, gasCalculator, gasCalculator.getBaseTierGasCost());
}
@Override

@ -24,7 +24,7 @@ import org.hyperledger.besu.evm.gascalculator.GasCalculator;
public class ReturnOperation extends AbstractOperation {
public ReturnOperation(final GasCalculator gasCalculator) {
super(0xF3, "RETURN", 2, 0, 1, gasCalculator);
super(0xF3, "RETURN", 2, 0, gasCalculator);
}
@Override

@ -26,7 +26,7 @@ import org.apache.tuweni.bytes.Bytes;
public class RevertOperation extends AbstractOperation {
public RevertOperation(final GasCalculator gasCalculator) {
super(0xFD, "REVERT", 2, 0, 1, gasCalculator);
super(0xFD, "REVERT", 2, 0, gasCalculator);
}
@Override

@ -29,7 +29,7 @@ public class SDivOperation extends AbstractFixedCostOperation {
private static final OperationResult sdivSuccess = new OperationResult(5, null);
public SDivOperation(final GasCalculator gasCalculator) {
super(0x05, "SDIV", 2, 1, 1, gasCalculator, gasCalculator.getLowTierGasCost());
super(0x05, "SDIV", 2, 1, gasCalculator, gasCalculator.getLowTierGasCost());
}
@Override

@ -28,7 +28,7 @@ public class SGtOperation extends AbstractFixedCostOperation {
static final OperationResult sgtSuccess = new OperationResult(3, null);
public SGtOperation(final GasCalculator gasCalculator) {
super(0x13, "SGT", 2, 1, 1, gasCalculator, gasCalculator.getVeryLowTierGasCost());
super(0x13, "SGT", 2, 1, gasCalculator, gasCalculator.getVeryLowTierGasCost());
}
@Override

@ -35,7 +35,7 @@ public class SLoadOperation extends AbstractOperation {
private final OperationResult coldSuccess;
public SLoadOperation(final GasCalculator gasCalculator) {
super(0x54, "SLOAD", 1, 1, 1, gasCalculator);
super(0x54, "SLOAD", 1, 1, gasCalculator);
final long baseCost = gasCalculator.getSloadOperationGasCost();
warmCost = baseCost + gasCalculator.getWarmStorageReadCost();
coldCost = baseCost + gasCalculator.getColdSloadCost();

@ -28,7 +28,7 @@ public class SLtOperation extends AbstractFixedCostOperation {
static final OperationResult sltSuccess = new OperationResult(3, null);
public SLtOperation(final GasCalculator gasCalculator) {
super(0x12, "SLT", 2, 1, 1, gasCalculator, gasCalculator.getVeryLowTierGasCost());
super(0x12, "SLT", 2, 1, gasCalculator, gasCalculator.getVeryLowTierGasCost());
}
@Override

@ -29,7 +29,7 @@ public class SModOperation extends AbstractFixedCostOperation {
private static final OperationResult smodSuccess = new OperationResult(5, null);
public SModOperation(final GasCalculator gasCalculator) {
super(0x07, "SMOD", 2, 1, 1, gasCalculator, gasCalculator.getLowTierGasCost());
super(0x07, "SMOD", 2, 1, gasCalculator, gasCalculator.getLowTierGasCost());
}
@Override

@ -34,7 +34,7 @@ public class SStoreOperation extends AbstractOperation {
private final long minimumGasRemaining;
public SStoreOperation(final GasCalculator gasCalculator, final long minimumGasRemaining) {
super(0x55, "SSTORE", 2, 0, 1, gasCalculator);
super(0x55, "SSTORE", 2, 0, gasCalculator);
this.minimumGasRemaining = minimumGasRemaining;
}

@ -31,7 +31,7 @@ public class SarOperation extends AbstractFixedCostOperation {
private static final UInt256 ALL_BITS = UInt256.MAX_VALUE;
public SarOperation(final GasCalculator gasCalculator) {
super(0x1d, "SAR", 2, 1, 1, gasCalculator, gasCalculator.getVeryLowTierGasCost());
super(0x1d, "SAR", 2, 1, gasCalculator, gasCalculator.getVeryLowTierGasCost());
}
@Override

@ -25,7 +25,7 @@ import org.apache.tuweni.units.bigints.UInt256;
public class SelfBalanceOperation extends AbstractFixedCostOperation {
public SelfBalanceOperation(final GasCalculator gasCalculator) {
super(0x47, "SELFBALANCE", 0, 1, 1, gasCalculator, gasCalculator.getLowTierGasCost());
super(0x47, "SELFBALANCE", 0, 1, gasCalculator, gasCalculator.getLowTierGasCost());
}
@Override

@ -27,7 +27,7 @@ import org.hyperledger.besu.evm.internal.Words;
public class SelfDestructOperation extends AbstractOperation {
public SelfDestructOperation(final GasCalculator gasCalculator) {
super(0xFF, "SELFDESTRUCT", 1, 0, 1, gasCalculator);
super(0xFF, "SELFDESTRUCT", 1, 0, gasCalculator);
}
@Override

@ -28,7 +28,7 @@ public class ShlOperation extends AbstractFixedCostOperation {
static final OperationResult shlSuccess = new OperationResult(3, null);
public ShlOperation(final GasCalculator gasCalculator) {
super(0x1b, "SHL", 2, 1, 1, gasCalculator, gasCalculator.getVeryLowTierGasCost());
super(0x1b, "SHL", 2, 1, gasCalculator, gasCalculator.getVeryLowTierGasCost());
}
@Override

@ -28,7 +28,7 @@ public class ShrOperation extends AbstractFixedCostOperation {
static final OperationResult shrSuccess = new OperationResult(3, null);
public ShrOperation(final GasCalculator gasCalculator) {
super(0x1c, "SHR", 2, 1, 1, gasCalculator, gasCalculator.getVeryLowTierGasCost());
super(0x1c, "SHR", 2, 1, gasCalculator, gasCalculator.getVeryLowTierGasCost());
}
@Override

@ -26,7 +26,7 @@ public class SignExtendOperation extends AbstractFixedCostOperation {
private static final OperationResult signExtendSuccess = new OperationResult(5, null);
public SignExtendOperation(final GasCalculator gasCalculator) {
super(0x0B, "SIGNEXTEND", 2, 1, 1, gasCalculator, gasCalculator.getLowTierGasCost());
super(0x0B, "SIGNEXTEND", 2, 1, gasCalculator, gasCalculator.getLowTierGasCost());
}
@Override

@ -26,7 +26,7 @@ import org.hyperledger.besu.evm.internal.Words;
public class StaticCallOperation extends AbstractCallOperation {
public StaticCallOperation(final GasCalculator gasCalculator) {
super(0xFA, "STATICCALL", 6, 1, 1, gasCalculator);
super(0xFA, "STATICCALL", 6, 1, gasCalculator);
}
@Override

@ -25,7 +25,7 @@ public class StopOperation extends AbstractFixedCostOperation {
static final OperationResult stopSuccess = new OperationResult(0, null);
public StopOperation(final GasCalculator gasCalculator) {
super(0x00, "STOP", 0, 0, 1, gasCalculator, gasCalculator.getZeroTierGasCost());
super(0x00, "STOP", 0, 0, gasCalculator, gasCalculator.getZeroTierGasCost());
}
@Override

@ -25,7 +25,7 @@ public class SubOperation extends AbstractFixedCostOperation {
static final OperationResult subSuccess = new OperationResult(3, null);
public SubOperation(final GasCalculator gasCalculator) {
super(0x03, "SUB", 2, 1, 1, gasCalculator, gasCalculator.getVeryLowTierGasCost());
super(0x03, "SUB", 2, 1, gasCalculator, gasCalculator.getVeryLowTierGasCost());
}
@Override

@ -35,7 +35,6 @@ public class SwapOperation extends AbstractFixedCostOperation {
"SWAP" + index,
index + 1,
index + 1,
1,
gasCalculator,
gasCalculator.getVeryLowTierGasCost());
this.index = index;

@ -23,7 +23,7 @@ import org.apache.tuweni.units.bigints.UInt256;
public class TimestampOperation extends AbstractFixedCostOperation {
public TimestampOperation(final GasCalculator gasCalculator) {
super(0x42, "TIMESTAMP", 0, 1, 1, gasCalculator, gasCalculator.getBaseTierGasCost());
super(0x42, "TIMESTAMP", 0, 1, gasCalculator, gasCalculator.getBaseTierGasCost());
}
@Override

@ -52,11 +52,6 @@ public class VirtualOperation implements Operation {
return delegate.getStackItemsProduced();
}
@Override
public int getOpSize() {
return delegate.getOpSize();
}
@Override
public boolean isVirtualOperation() {
return true;

@ -25,7 +25,7 @@ public class XorOperation extends AbstractFixedCostOperation {
static final OperationResult xorSuccess = new OperationResult(3, null);
public XorOperation(final GasCalculator gasCalculator) {
super(0x18, "XOR", 2, 1, 1, gasCalculator, gasCalculator.getVeryLowTierGasCost());
super(0x18, "XOR", 2, 1, gasCalculator, gasCalculator.getVeryLowTierGasCost());
}
@Override

@ -0,0 +1,187 @@
/*
* 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.code;
import static org.assertj.core.api.Assertions.assertThat;
import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.evm.Code;
import org.apache.tuweni.bytes.Bytes;
import org.junit.jupiter.api.Test;
class CodeFactoryTest {
@Test
void invalidCodeIncompleteMagic() {
invalidCode("0xEF");
}
@Test
void invalidCodeInvalidMagic() {
invalidCode("0xEFFF0101000302000400600000AABBCCDD");
}
@Test
void invalidCodeNoVersion() {
invalidCode("0xEF00");
}
@Test
void invalidCodeInvalidVersion0x00() {
invalidCode("EF000001000302000400600000AABBCCDD");
}
@Test
void invalidCodeInvalidVersion0x02() {
invalidCode("EF000201000302000400600000AABBCCDD");
}
@Test
void invalidCodeInvalidVersion0xFF() {
invalidCode("EF00FF01000302000400600000AABBCCDD");
}
@Test
void invalidCodeNoHeader() {
invalidCode("0xEF0001");
}
@Test
void invalidCodeNoCodeSection() {
invalidCode("0xEF000100");
}
@Test
void invalidCodeNoCodeSectionSize() {
invalidCode("0xEF000101");
}
@Test
void invalidCodeCodeSectionSizeIncomplete() {
invalidCode("0xEF00010100");
}
@Test
void invalidCodeNoSectionTerminator0x03() {
invalidCode("0xEF0001010003");
}
@Test
void invalidCodeNoSectionTerminator0x03600000() {
invalidCode("0xEF0001010003600000");
}
@Test
void invalidCodeNoCodeSectionContents() {
invalidCode("0xEF000101000200");
}
@Test
void invalidCodeCodeSectionContentsIncomplete() {
invalidCode("0xEF00010100020060");
}
@Test
void invalidCodeTrailingBytesAfterCodeSection() {
invalidCode("0xEF000101000300600000DEADBEEF");
}
@Test
void invalidCodeMultipleCodeSections() {
invalidCode("0xEF000101000301000300600000600000");
}
@Test
void invalidCodeEmptyCodeSection() {
invalidCode("0xEF000101000000");
}
@Test
void invalidCodeEmptyCodeSectionWithNonEmptyDataSection() {
invalidCode("0xEF000101000002000200AABB");
}
@Test
void invalidCodeDataSectionPrecedingCodeSection() {
invalidCode("0xEF000102000401000300AABBCCDD600000");
}
@Test
void invalidCodeDataSectionWithoutCodeSection() {
invalidCode("0xEF000102000400AABBCCDD");
}
@Test
void invalidCodeNoDataSectionSize() {
invalidCode("0xEF000101000202");
}
@Test
void invalidCodeDataSectionSizeIncomplete() {
invalidCode("0xEF00010100020200");
}
@Test
void invalidCodeNoSectionTerminator0x03020004() {
invalidCode("0xEF0001010003020004");
}
@Test
void invalidCodeNoSectionTerminator0x03020004600000AABBCCDD() {
invalidCode("0xEF0001010003020004600000AABBCCDD");
}
@Test
void invalidCodeNoDataSectionContents() {
invalidCode("0xEF000101000302000400600000");
}
@Test
void invalidCodeDataSectionContentsIncomplete() {
invalidCode("0xEF000101000302000400600000AABBCC");
}
@Test
void invalidCodeTrailingBytesAfterDataSection() {
invalidCode("0xEF000101000302000400600000AABBCCDDEE");
}
@Test
void invalidCodeMultipleDataSections() {
invalidCode("0xEF000101000302000402000400600000AABBCCDDAABBCCDD");
}
@Test
void invalidCodeMultipleCodeAndDataSections() {
invalidCode("0xEF000101000101000102000102000100FEFEAABB");
}
@Test
void invalidCodeEmptyDataSection() {
invalidCode("0xEF000101000302000000600000");
}
@Test
void invalidCodeUnknownSectionId3() {
invalidCode("0xEF0001010002030004006000AABBCCDD");
}
private static void invalidCode(final String str) {
Code code = CodeFactory.createCode(Bytes.fromHexString(str), Hash.EMPTY, 1, true);
assertThat(code.isValid()).isFalse();
}
}

@ -18,11 +18,20 @@ package org.hyperledger.besu.evm.code;
import static org.assertj.core.api.Assertions.assertThat;
import java.util.stream.IntStream;
import java.util.stream.Stream;
import org.apache.tuweni.bytes.Bytes;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import org.junit.jupiter.params.provider.ValueSource;
class CodeV1Test {
public static final String ZERO_HEX = String.format("%02x", 0);
@Test
void calculatesJumpDestMap() {
String codeHex = "0xEF000101000F006001600055600D5660026000555B00";
@ -32,4 +41,305 @@ class CodeV1Test {
assertThat(jumpDest).containsExactly(0x2000);
}
@ParameterizedTest
@ValueSource(
strings = {"3000", "5000", "5c000000", "60005d000000", "60005e01000000", "fe00", "0000"})
void testValidOpcodes(final String code) {
final long[] jumpDest = OpcodesV1.validateAndCalculateJumpDests(Bytes.fromHexString(code));
assertThat(jumpDest).isNotNull();
}
@ParameterizedTest
@ValueSource(strings = {"00", "f3", "fd", "fe"})
void testValidCodeTerminator(final String code) {
final long[] jumpDest = OpcodesV1.validateAndCalculateJumpDests(Bytes.fromHexString(code));
assertThat(jumpDest).isNotNull();
}
@ParameterizedTest
@MethodSource("testPushValidImmediateArguments")
void testPushValidImmediate(final String code) {
final long[] jumpDest = OpcodesV1.validateAndCalculateJumpDests(Bytes.fromHexString(code));
assertThat(jumpDest).isNotNull();
}
private static Stream<Arguments> testPushValidImmediateArguments() {
final int codeBegin = 96;
return IntStream.range(0, 32)
.mapToObj(i -> String.format("%02x", codeBegin + i) + ZERO_HEX.repeat(i + 1) + ZERO_HEX)
.map(Arguments::arguments);
}
@ParameterizedTest
@MethodSource("testRjumpValidImmediateArguments")
void testRjumpValidImmediate(final String code) {
final long[] jumpDest = OpcodesV1.validateAndCalculateJumpDests(Bytes.fromHexString(code));
assertThat(jumpDest).isNotNull();
}
private static Stream<Arguments> testRjumpValidImmediateArguments() {
return Stream.of(
"5c000000",
"5c00010000",
"5c00010000000000",
"5c0100" + ZERO_HEX.repeat(256) + ZERO_HEX,
"5c7fff" + ZERO_HEX.repeat(32767) + ZERO_HEX,
"5cfffd0000",
"005cfffc00",
ZERO_HEX.repeat(253) + "5cff0000",
ZERO_HEX.repeat(32765) + "5c800000")
.map(Arguments::arguments);
}
@ParameterizedTest
@MethodSource("testRjumpiValidImmediateArguments")
void testRjumpiValidImmediate(final String code) {
final long[] jumpDest = OpcodesV1.validateAndCalculateJumpDests(Bytes.fromHexString(code));
assertThat(jumpDest).isNotNull();
}
private static Stream<Arguments> testRjumpiValidImmediateArguments() {
return Stream.of(
"60015d000000",
"60015d00010000",
"60015d00010000000000",
"60015d0100" + "5b".repeat(256) + ZERO_HEX,
"60015d7fff" + "5b".repeat(32767) + ZERO_HEX,
"60015dfffd0000",
"60015dfffb00",
ZERO_HEX.repeat(252) + "60015dff0000",
ZERO_HEX.repeat(32763) + "60015d800000",
"5d000000")
.map(Arguments::arguments);
}
@ParameterizedTest
@MethodSource("rjumptableValidImmediateArguments")
void testRjumptableValidImmediate(final String code) {
final long[] jumpDest = OpcodesV1.validateAndCalculateJumpDests(Bytes.fromHexString(code));
assertThat(jumpDest).isNotNull();
}
private static Stream<Arguments> rjumptableValidImmediateArguments() {
return Stream.of(
"60015e01000000",
"60015e02000000010000",
"60015e03000000040100" + "5b".repeat(256) + ZERO_HEX,
"60015e040000000401007fff" + "5b".repeat(32767) + ZERO_HEX,
"60015e01fffc0000",
"5b".repeat(248) + "60015e02fffaff0000",
"5b".repeat(32760) + "60015e02fffa800000",
"5e01000000")
.map(Arguments::arguments);
}
@ParameterizedTest
@MethodSource("invalidCodeArguments")
void testInvalidCode(final String code) {
final long[] jumpDest = OpcodesV1.validateAndCalculateJumpDests(Bytes.fromHexString(code));
assertThat(jumpDest).isNull();
}
private static Stream<Arguments> invalidCodeArguments() {
return Stream.of(
IntStream.rangeClosed(0x0c, 0x0f),
IntStream.of(0x1e, 0x1f),
IntStream.rangeClosed(0x21, 0x2f),
IntStream.rangeClosed(0x49, 0x4f),
// IntStream.of(0x5f), // PUSH0
IntStream.rangeClosed(0xa5, 0xaf),
IntStream.rangeClosed(0xb0, 0xbf),
IntStream.rangeClosed(0xc0, 0xcf),
IntStream.rangeClosed(0xd0, 0xdf),
IntStream.rangeClosed(0xe0, 0xef),
IntStream.of(0xf6, 0xf7, 0xf8, 0xf9, 0xfb, 0xfc))
.flatMapToInt(i -> i)
.mapToObj(i -> String.format("%02x", i) + ZERO_HEX)
.map(Arguments::arguments);
}
@ParameterizedTest
@MethodSource("pushTruncatedImmediateArguments")
void testPushTruncatedImmediate(final String code) {
final long[] jumpDest = OpcodesV1.validateAndCalculateJumpDests(Bytes.fromHexString(code));
assertThat(jumpDest).isNull();
}
private static Stream<Arguments> pushTruncatedImmediateArguments() {
return Stream.concat(
Stream.of("60"),
IntStream.range(0, 31)
.mapToObj(i -> String.format("%02x", 0x61 + i) + ZERO_HEX.repeat(i + 1)))
.map(Arguments::arguments);
}
@ParameterizedTest
@ValueSource(strings = {"5c", "5c00", "5c0000"})
void testRjumpTruncatedImmediate(final String code) {
final long[] jumpDest = OpcodesV1.validateAndCalculateJumpDests(Bytes.fromHexString(code));
assertThat(jumpDest).isNull();
}
@ParameterizedTest
@ValueSource(strings = {"60015d", "60015d00", "60015d0000"})
void testRjumpiTruncatedImmediate(final String code) {
final long[] jumpDest = OpcodesV1.validateAndCalculateJumpDests(Bytes.fromHexString(code));
assertThat(jumpDest).isNull();
}
@ParameterizedTest
@ValueSource(
strings = {
"60015e",
"60015e01",
"60015e0100",
"60015e030000",
"60015e0300000001",
"60015e030000000100"
})
void testRjumpvTruncatedImmediate(final String code) {
final long[] jumpDest = OpcodesV1.validateAndCalculateJumpDests(Bytes.fromHexString(code));
assertThat(jumpDest).isNull();
}
@ParameterizedTest
@ValueSource(
strings = {
"5c000100",
"5cfffc00",
"60015d000100",
"60015dfffa00",
"60015e01000100",
"60015e01fff900"
})
void testRjumpsOutOfBounds(final String code) {
final long[] jumpDest = OpcodesV1.validateAndCalculateJumpDests(Bytes.fromHexString(code));
assertThat(jumpDest).isNull();
}
@ParameterizedTest
@MethodSource("rjumpsIntoImmediateExtraArguments")
@ValueSource(
strings = {
// RJUMP into RJUMP immediate
"5cffff00",
"5cfffe00",
"5c00015c000000",
"5c00025c000000",
// RJUMPI into RJUMP immediate
"60015d00015c000000",
"60015d00025c000000",
// RJUMPV into RJUMP immediate
"60015e0100015c000000",
"60015e0100025c000000",
// RJUMP into RJUMPI immediate
"5c000360015d000000",
"5c000460015d000000",
// RJUMPI into RJUMPI immediate
"60015dffff00",
"60015dfffe00",
"60015d000360015d000000",
"60015d000460015d000000",
// RJUMPV into RJUMPI immediate
"60015e01000360015d000000",
"60015e01000460015d000000",
// RJUMP into RJUMPV immediate
"5c00015e01000000",
"5c00025e01000000",
"5c00035e01000000",
// RJUMPI into RJUMPV immediate
"60015d00015e01000000",
"60015d00025e01000000",
"60015d00035e01000000",
// RJUMPV into RJUMPV immediate
"60015e01ffff00",
"60015e01fffe00",
"60015e01fffd00",
"60015e0100015e01000000",
"60015e0100025e01000000",
"60015e0100035e01000000",
"60015e0100015e020000fff400",
"60015e0100025e020000fff400",
"60015e0100035e020000fff400",
"60015e0100045e020000fff400",
"60015e0100055e020000fff400"
})
void testRjumpsIntoImmediate(final String code) {
final long[] jumpDest = OpcodesV1.validateAndCalculateJumpDests(Bytes.fromHexString(code));
assertThat(jumpDest).isNull();
}
private static Stream<Arguments> rjumpsIntoImmediateExtraArguments() {
return IntStream.range(1, 33)
.mapToObj(
n ->
IntStream.range(1, n + 1)
.mapToObj(
offset ->
Stream.of(
String.format("5c00%02x", offset)
+ // RJUMP offset
String.format("%02x", 0x60 + n - 1)
+ // PUSHn
ZERO_HEX.repeat(n)
+ // push data
ZERO_HEX, // STOP
String.format("60015d00%02x", offset)
+ // PUSH1 1 RJUMI offset
String.format("%02x", 0x60 + n - 1)
+ // PUSHn
ZERO_HEX.repeat(n)
+ // push data
ZERO_HEX, // STOP
String.format("60015e0100%02x", offset)
+ String.format("%02x", 0x60 + n - 1)
+ // PUSHn
ZERO_HEX.repeat(n)
+ // push data
ZERO_HEX // STOP
)))
.flatMap(i -> i)
.flatMap(i -> i)
.map(Arguments::arguments);
}
@ParameterizedTest
@ValueSource(strings = {"60015e0000"})
void testRjumpvEmptyTable(final String code) {
final long[] jumpDest = OpcodesV1.validateAndCalculateJumpDests(Bytes.fromHexString(code));
assertThat(jumpDest).isNull();
}
@ParameterizedTest
@MethodSource("immediateContainsOpcodeArguments")
void testImmediateContainsOpcode(final String code) {
final long[] jumpDest = OpcodesV1.validateAndCalculateJumpDests(Bytes.fromHexString(code));
assertThat(jumpDest).isNotNull();
}
private static Stream<Arguments> immediateContainsOpcodeArguments() {
return Stream.of(
// 0x5c byte which could be interpreted a RJUMP, but it's not because it's in PUSH data
"605c001000",
"61005c001000",
// 0x5d byte which could be interpreted a RJUMPI, but it's not because it's in PUSH data
"605d001000",
"61005d001000",
// 0x5e byte which could be interpreted a RJUMPV, but it's not because it's in PUSH data
"605e01000000",
"61005e01000000",
// 0x60 byte which could be interpreted as PUSH, but it's not because it's in RJUMP data
// offset = -160
"5b".repeat(160) + "5cff6000",
// 0x60 byte which could be interpreted as PUSH, but it's not because it's in RJUMPI
// data
// offset = -160
"5b".repeat(160) + "5dff6000",
// 0x60 byte which could be interpreted as PUSH, but it's not because it's in RJUMPV
// data
// offset = -160
"5b".repeat(160) + "5e01ff6000")
.map(Arguments::arguments);
}
}

Loading…
Cancel
Save