Renumber EOF and Transient storage (#5550)

As per a recent EIP update the opcode numbers for Transient Storage
have been updated.  EOF opcodes were also updated.
Update the code and test cases for the new numbers.

Signed-off-by: Danno Ferrin <danno.ferrin@swirldslabs.com>
pull/5585/head
Danno Ferrin 1 year ago committed by GitHub
parent cb12a2c410
commit 9913a5aa11
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 42
      ethereum/evmtool/src/test/java/org/hyperledger/besu/evmtool/CodeValidationSubCommandTest.java
  2. 46
      evm/src/main/java/org/hyperledger/besu/evm/code/CodeV1Validation.java
  3. 2
      evm/src/main/java/org/hyperledger/besu/evm/operation/CallFOperation.java
  4. 2
      evm/src/main/java/org/hyperledger/besu/evm/operation/JumpFOperation.java
  5. 2
      evm/src/main/java/org/hyperledger/besu/evm/operation/RelativeJumpIfOperation.java
  6. 2
      evm/src/main/java/org/hyperledger/besu/evm/operation/RelativeJumpOperation.java
  7. 2
      evm/src/main/java/org/hyperledger/besu/evm/operation/RelativeJumpVectorOperation.java
  8. 2
      evm/src/main/java/org/hyperledger/besu/evm/operation/RetFOperation.java
  9. 2
      evm/src/main/java/org/hyperledger/besu/evm/operation/TLoadOperation.java
  10. 2
      evm/src/main/java/org/hyperledger/besu/evm/operation/TStoreOperation.java
  11. 337
      evm/src/test/java/org/hyperledger/besu/evm/code/CodeV1Test.java
  12. 4
      evm/src/test/java/org/hyperledger/besu/evm/processor/ContractCreationProcessorTest.java
  13. 63
      evm/src/test/java/org/hyperledger/besu/evm/testutils/ByteCodeBuilder.java

@ -27,15 +27,16 @@ import picocli.CommandLine;
public class CodeValidationSubCommandTest {
static final String CODE_STOP_ONLY = "0xef0001 010004 020001-0001 030000 00 00000000 00";
static final String CODE_RETF_ONLY = "0xef0001 010004 020001-0001 030000 00 00000000 b1";
static final String CODE_BAD_MAGIC = "0xefffff 010004 020001-0001 030000 00 00000000 b1";
static final String CODE_RETF_ONLY = "0xef0001 010004 020001-0001 030000 00 00000000 e4";
static final String CODE_BAD_MAGIC = "0xefffff 010004 020001-0001 030000 00 00000000 e4";
static final String CODE_INTERIOR_COMMENTS =
"0xef0001 010008 020002-000c-0002 030000 00 \n"
+ "# 7 inputs 1 output,\n"
+ "00000007-07010007 \n"
+ "59-59-59-59-59-59-59-b00001-50-b1\n"
+ "# No immediate data\n"
+ "f1-b1";
"""
0xef0001 010008 020002-000c-0002 030000 00
# 7 inputs 1 output,
00000007-07010007
59-59-59-59-59-59-59-e30001-50-e4
# No immediate data
f1-e4""";
static final String CODE_MULTIPLE =
CODE_STOP_ONLY + "\n" + CODE_BAD_MAGIC + "\n" + CODE_RETF_ONLY + "\n";
@ -67,7 +68,12 @@ public class CodeValidationSubCommandTest {
new CodeValidateSubCommand(bais, new PrintStream(baos));
codeValidateSubCommand.run();
assertThat(baos.toString(UTF_8))
.contains("OK 00\n" + "err: layout - EOF header byte 1 incorrect\n" + "OK b1\n");
.contains(
"""
OK 00
err: layout - EOF header byte 1 incorrect
OK e4
""");
}
@Test
@ -104,7 +110,12 @@ public class CodeValidationSubCommandTest {
cmd.parseArgs(CODE_STOP_ONLY, CODE_BAD_MAGIC, CODE_RETF_ONLY);
codeValidateSubCommand.run();
assertThat(baos.toString(UTF_8))
.contains("OK 00\n" + "err: layout - EOF header byte 1 incorrect\n" + "OK b1\n");
.contains(
"""
OK 00
err: layout - EOF header byte 1 incorrect
OK e4
""");
}
@Test
@ -116,7 +127,7 @@ public class CodeValidationSubCommandTest {
final CommandLine cmd = new CommandLine(codeValidateSubCommand);
cmd.parseArgs(CODE_RETF_ONLY);
codeValidateSubCommand.run();
assertThat(baos.toString(UTF_8)).contains("OK b1\n");
assertThat(baos.toString(UTF_8)).contains("OK e4\n");
}
@Test
@ -128,7 +139,7 @@ public class CodeValidationSubCommandTest {
final CommandLine cmd = new CommandLine(codeValidateSubCommand);
cmd.parseArgs(CODE_INTERIOR_COMMENTS);
codeValidateSubCommand.run();
assertThat(baos.toString(UTF_8)).contains("OK 59595959595959b0000150b1,f1b1\n");
assertThat(baos.toString(UTF_8)).contains("OK 59595959595959e3000150e4,f1e4\n");
}
@Test
@ -140,6 +151,11 @@ public class CodeValidationSubCommandTest {
new CodeValidateSubCommand(bais, new PrintStream(baos));
codeValidateSubCommand.run();
assertThat(baos.toString(UTF_8))
.isEqualTo("OK 00\n" + "err: layout - EOF header byte 1 incorrect\n" + "OK b1\n");
.isEqualTo(
"""
OK 00
err: layout - EOF header byte 1 incorrect
OK e4
""");
}
}

@ -135,9 +135,9 @@ public final class CodeV1Validation {
VALID, // 0x59 - MSIZE
VALID, // 0x5a - GAS
VALID, // 0x5b - NOOOP (née JUMPDEST)
VALID_AND_TERMINAL, // 0X5c - RJUMP
VALID, // 0X5d - RJUMPI
VALID, // 0X5e - RJUMPV
VALID, // 0X5c - TLOAD
VALID, // 0X5d - TSTORE
VALID, // 0X5e - MCOPY
VALID, // 0X5f - PUSH0
VALID, // 0x60 - PUSH1
VALID, // 0x61 - PUSH2
@ -219,9 +219,9 @@ public final class CodeV1Validation {
INVALID, // 0xad
INVALID, // 0xae
INVALID, // 0xaf
VALID, // 0xb0 - CALLF
VALID_AND_TERMINAL, // 0xb1 - RETF
INVALID, // 0xb2 - JUMPF
INVALID, // 0xb0
INVALID, // 0xb1
INVALID, // 0xb2
INVALID, // 0xb3
INVALID, // 0xb4
INVALID, // 0xb5
@ -267,11 +267,11 @@ public final class CodeV1Validation {
INVALID, // 0xdd
INVALID, // 0xde
INVALID, // 0xef
INVALID, // 0xe0
INVALID, // 0xe1
INVALID, // 0xe2
INVALID, // 0xe3
INVALID, // 0xe4
VALID_AND_TERMINAL, // 0xe0 - RJUMP
VALID, // 0xe1 - RJUMPI
VALID, // 0xe2 - RJUMPV
VALID, // 0xe3 - CALLF
VALID_AND_TERMINAL, // 0xe4 - RETF
INVALID, // 0xe5
INVALID, // 0xe6
INVALID, // 0xe7
@ -398,9 +398,9 @@ public final class CodeV1Validation {
{0, 1, 1}, // 0x59 - MSIZE
{0, 1, 1}, // 0x5a - GAS
{0, 0, 1}, // 0x5b - NOOP (née JUMPDEST)
{0, 0, -3}, // 0x5c - RJUMP
{1, 0, 3}, // 0x5d - RJUMPI
{1, 0, 2}, // 0x5e - RJUMPV
{1, 1, 1}, // 0x5c - TLOAD
{2, 0, 1}, // 0x5d - TSTORE
{4, 0, 1}, // 0x5e - MCOPY
{0, 1, 1}, // 0x5f - PUSH0
{0, 1, 2}, // 0x60 - PUSH1
{0, 1, 3}, // 0x61 - PUSH2
@ -482,9 +482,9 @@ public final class CodeV1Validation {
{0, 0, 0}, // 0xad
{0, 0, 0}, // 0xae
{0, 0, 0}, // 0xaf
{0, 0, 3}, // 0xb0 - CALLF
{0, 0, -1}, // 0xb1 - RETF
{0, 0, 0}, // 0xb2 - JUMPF
{0, 0, 0}, // 0xb0
{0, 0, 0}, // 0xb1
{0, 0, 0}, // 0xb2
{0, 0, 0}, // 0xb3
{0, 0, 0}, // 0xb4
{0, 0, 0}, // 0xb5
@ -530,12 +530,12 @@ public final class CodeV1Validation {
{0, 0, 0}, // 0xdd
{0, 0, 0}, // 0xde
{0, 0, 0}, // 0xef
{0, 0, 0}, // 0xe0
{0, 0, 0}, // 0xe1
{0, 0, 0}, // 0xe2
{0, 0, 0}, // 0xe3
{0, 0, 0}, // 0xe4
{0, 0, 0}, // 0xe5
{0, 0, -3}, // 0xe0 - RJUMP
{1, 0, 3}, // 0xe1 - RJUMPI
{1, 0, 2}, // 0xe2 - RJUMPV
{0, 0, 3}, // 0xe3 - CALLF
{0, 0, -1}, // 0xe4 - RETF
{0, 0, 0}, // 0xe5 - JUMPF
{0, 0, 0}, // 0xe6
{0, 0, 0}, // 0xe7
{0, 0, 0}, // 0xe8

@ -24,7 +24,7 @@ import org.hyperledger.besu.evm.gascalculator.GasCalculator;
public class CallFOperation extends AbstractOperation {
/** The constant OPCODE. */
public static final int OPCODE = 0xb0;
public static final int OPCODE = 0xe3;
/** The Call F success. */
static final OperationResult callfSuccess = new OperationResult(5, null);

@ -24,7 +24,7 @@ import org.hyperledger.besu.evm.gascalculator.GasCalculator;
public class JumpFOperation extends AbstractOperation {
/** The constant OPCODE. */
public static final int OPCODE = 0xb2;
public static final int OPCODE = 0xe5;
/** The Jump F success operation result. */
static final OperationResult jumpfSuccess = new OperationResult(3, null);

@ -25,7 +25,7 @@ import org.apache.tuweni.bytes.Bytes;
public class RelativeJumpIfOperation extends RelativeJumpOperation {
/** The constant OPCODE. */
public static final int OPCODE = 0x5d;
public static final int OPCODE = 0xe1;
/**
* Instantiates a new Relative jump If operation.

@ -26,7 +26,7 @@ import org.apache.tuweni.bytes.Bytes;
public class RelativeJumpOperation extends AbstractFixedCostOperation {
/** The constant OPCODE. */
public static final int OPCODE = 0x5c;
public static final int OPCODE = 0xe0;
/**
* Instantiates a new Relative jump operation.

@ -27,7 +27,7 @@ import org.apache.tuweni.bytes.Bytes;
public class RelativeJumpVectorOperation extends AbstractFixedCostOperation {
/** The constant OPCODE. */
public static final int OPCODE = 0x5e;
public static final int OPCODE = 0xe2;
/**
* Instantiates a new Relative jump vector operation.

@ -22,7 +22,7 @@ import org.hyperledger.besu.evm.gascalculator.GasCalculator;
public class RetFOperation extends AbstractOperation {
/** The Opcode. */
public static final int OPCODE = 0xb1;
public static final int OPCODE = 0xe4;
/** The Ret F success. */
static final OperationResult retfSuccess = new OperationResult(4, null);

@ -33,7 +33,7 @@ public class TLoadOperation extends AbstractOperation {
* @param gasCalculator gas calculator for costing
*/
public TLoadOperation(final GasCalculator gasCalculator) {
super(0xb3, "TLOAD", 1, 1, gasCalculator);
super(0x5C, "TLOAD", 1, 1, gasCalculator);
}
@Override

@ -30,7 +30,7 @@ public class TStoreOperation extends AbstractOperation {
* @param gasCalculator gas calculator for costing
*/
public TStoreOperation(final GasCalculator gasCalculator) {
super(0xb4, "TSTORE", 2, 0, gasCalculator);
super(0x5D, "TSTORE", 2, 0, gasCalculator);
}
@Override

@ -44,7 +44,7 @@ class CodeV1Test {
@Test
void validCode() {
String codeHex =
"0xEF0001 01000C 020003 000b 0002 0008 030000 00 00000000 02010001 01000002 60016002b00001b00002b1 01b1 60005360106000f3";
"0xEF0001 01000C 020003 000b 0002 0008 030000 00 00000000 02010001 01000002 60016002e30001e30002e4 01e4 60005360106000f3";
final EOFLayout layout = EOFLayout.parseEOF(Bytes.fromHexString(codeHex.replace(" ", "")));
String validationError = validateCode(layout);
@ -54,7 +54,7 @@ class CodeV1Test {
@ParameterizedTest
@ValueSource(
strings = {"3000", "5000", "5c000000", "60005d000000", "60005e01000000", "fe00", "0000"})
strings = {"3000", "5000", "e0000000", "6000e1000000", "6000e201000000", "fe00", "0000"})
void testValidOpcodes(final String code) {
final String validationError = validateCode(Bytes.fromHexString(code), 1);
assertThat(validationError).isNull();
@ -90,15 +90,15 @@ class CodeV1Test {
private static Stream<Arguments> testRjumpValidImmediateArguments() {
return Stream.of(
"5c000000",
"5c00010000",
"5c00010000000000",
"5c0100" + NOOP_HEX.repeat(256) + ZERO_HEX,
"5c7fff" + NOOP_HEX.repeat(32767) + ZERO_HEX,
"5cfffd0000",
"005cfffc00",
NOOP_HEX.repeat(253) + "5cff0000",
NOOP_HEX.repeat(32765) + "5c800000")
"e0000000",
"e000010000",
"e000010000000000",
"e00100" + NOOP_HEX.repeat(256) + ZERO_HEX,
"e07fff" + NOOP_HEX.repeat(32767) + ZERO_HEX,
"e0fffd0000",
"00e0fffc00",
NOOP_HEX.repeat(253) + "e0ff0000",
NOOP_HEX.repeat(32765) + "e0800000")
.map(Arguments::arguments);
}
@ -111,16 +111,16 @@ class CodeV1Test {
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",
NOOP_HEX.repeat(252) + "60015dff0000",
NOOP_HEX.repeat(32763) + "60015d800000",
"5d000000")
"6001e1000000",
"6001e100010000",
"6001e100010000000000",
"6001e10100" + "5b".repeat(256) + ZERO_HEX,
"6001e17fff" + "5b".repeat(32767) + ZERO_HEX,
"6001e1fffd0000",
"6001e1fffb00",
NOOP_HEX.repeat(252) + "6001e1ff0000",
NOOP_HEX.repeat(32763) + "6001e1800000",
"e1000000")
.map(Arguments::arguments);
}
@ -133,14 +133,14 @@ class CodeV1Test {
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")
"6001e201000000",
"6001e202000000010000",
"6001e203000000040100" + "5b".repeat(256) + ZERO_HEX,
"6001e2040000000401007fff" + "5b".repeat(32767) + ZERO_HEX,
"6001e201fffc0000",
"5b".repeat(248) + "6001e202fffaff0000",
"5b".repeat(32760) + "6001e202fffa800000",
"e201000000")
.map(Arguments::arguments);
}
@ -157,12 +157,11 @@ class CodeV1Test {
IntStream.of(0x1e, 0x1f),
IntStream.rangeClosed(0x21, 0x2f),
IntStream.rangeClosed(0x49, 0x4f),
// IntStream.of(0x5f), // PUSH0
IntStream.rangeClosed(0xa5, 0xaf),
IntStream.rangeClosed(0xb3, 0xbf),
IntStream.rangeClosed(0xb0, 0xbf),
IntStream.rangeClosed(0xc0, 0xcf),
IntStream.rangeClosed(0xd0, 0xdf),
IntStream.rangeClosed(0xe0, 0xef),
IntStream.rangeClosed(0xe5, 0xef),
IntStream.of(0xf6, 0xf7, 0xf8, 0xf9, 0xfb, 0xfc))
.flatMapToInt(i -> i)
.mapToObj(i -> String.format("%02x", i) + ZERO_HEX)
@ -185,14 +184,14 @@ class CodeV1Test {
}
@ParameterizedTest
@ValueSource(strings = {"5c", "5c00"})
@ValueSource(strings = {"e0", "e000"})
void testRjumpTruncatedImmediate(final String code) {
final String validationError = validateCode(Bytes.fromHexString(code), 1);
assertThat(validationError).isEqualTo("Truncated relative jump offset");
}
@ParameterizedTest
@ValueSource(strings = {"60015d", "60015d00"})
@ValueSource(strings = {"6001e1", "6001e100"})
void testRjumpiTruncatedImmediate(final String code) {
final String validationError = validateCode(Bytes.fromHexString(code), 1);
assertThat(validationError).isEqualTo("Truncated relative jump offset");
@ -201,12 +200,12 @@ class CodeV1Test {
@ParameterizedTest
@ValueSource(
strings = {
"60015e",
"60015e01",
"60015e0100",
"60015e030000",
"60015e0300000001",
"60015e030000000100"
"6001e2",
"6001e201",
"6001e20100",
"6001e2030000",
"6001e20300000001",
"6001e2030000000100"
})
void testRjumpvTruncatedImmediate(final String code) {
final String validationError = validateCode(Bytes.fromHexString(code), 1);
@ -216,14 +215,14 @@ class CodeV1Test {
@ParameterizedTest
@ValueSource(
strings = {
"5c0000",
"5c000100",
"5cfffc00",
"60015d0000",
"60015d000100",
"60015dfffa00",
"60015e01000100",
"60015e01fff900"
"e00000",
"e0000100",
"e0fffc00",
"6001e10000",
"6001e1000100",
"6001e1fffa00",
"6001e201000100",
"6001e201fff900"
})
void testRjumpsOutOfBounds(final String code) {
final String validationError = validateCode(Bytes.fromHexString(code), 1);
@ -235,47 +234,47 @@ class CodeV1Test {
@ValueSource(
strings = {
// RJUMP into RJUMP immediate
"5cffff00",
"5cfffe00",
"5c00015c000000",
"5c00025c000000",
"e0ffff00",
"e0fffe00",
"e00001e0000000",
"e00002e0000000",
// RJUMPI into RJUMP immediate
"60015d00015c000000",
"60015d00025c000000",
"6001e10001e0000000",
"6001e10002e0000000",
// RJUMPV into RJUMP immediate
"60015e0100015c000000",
"60015e0100025c000000",
"6001e2010001e0000000",
"6001e2010002e0000000",
// RJUMP into RJUMPI immediate
"5c000360015d000000",
"5c000460015d000000",
"e000036001e1000000",
"e000046001e1000000",
// RJUMPI into RJUMPI immediate
"60015dffff00",
"60015dfffe00",
"60015d000360015d000000",
"60015d000460015d000000",
"6001e1ffff00",
"6001e1fffe00",
"6001e100036001e1000000",
"6001e100046001e1000000",
// RJUMPV into RJUMPI immediate
"60015e01000360015d000000",
"60015e01000460015d000000",
"6001e20100036001e1000000",
"6001e20100046001e1000000",
// RJUMP into RJUMPV immediate
"5c00015e01000000",
"5c00025e01000000",
"5c00035e01000000",
"e00001e201000000",
"e00002e201000000",
"e00003e201000000",
// RJUMPI into RJUMPV immediate
"60015d00015e01000000",
"60015d00025e01000000",
"60015d00035e01000000",
"6001e10001e201000000",
"6001e10002e201000000",
"6001e10003e201000000",
// RJUMPV into RJUMPV immediate
"60015e01ffff00",
"60015e01fffe00",
"60015e01fffd00",
"60015e0100015e01000000",
"60015e0100025e01000000",
"60015e0100035e01000000",
"60015e0100015e020000fff400",
"60015e0100025e020000fff400",
"60015e0100035e020000fff400",
"60015e0100045e020000fff400",
"60015e0100055e020000fff400"
"6001e201ffff00",
"6001e201fffe00",
"6001e201fffd00",
"6001e2010001e201000000",
"6001e2010002e201000000",
"6001e2010003e201000000",
"6001e2010001e2020000fff400",
"6001e2010002e2020000fff400",
"6001e2010003e2020000fff400",
"6001e2010004e2020000fff400",
"6001e2010005e2020000fff400"
})
void testRjumpsIntoImmediate(final String code) {
final String validationError = validateCode(Bytes.fromHexString(code), 1);
@ -291,21 +290,21 @@ class CodeV1Test {
.mapToObj(
offset ->
Stream.of(
String.format("5c00%02x", offset)
String.format("e000%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)
String.format("6001e100%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("6001e20100%02x", offset)
+ String.format("%02x", 0x60 + n - 1)
+ // PUSHn
ZERO_HEX.repeat(n)
@ -318,21 +317,21 @@ class CodeV1Test {
}
@ParameterizedTest
@ValueSource(strings = {"60015e0000"})
@ValueSource(strings = {"6001e20000"})
void testRjumpvEmptyTable(final String code) {
final String validationError = validateCode(Bytes.fromHexString(code), 1);
assertThat(validationError).isEqualTo("Empty jump table");
}
@ParameterizedTest
@ValueSource(strings = {"b0", "b000"})
@ValueSource(strings = {"e3", "e300"})
void testCallFTruncated(final String code) {
final String validationError = validateCode(Bytes.fromHexString(code), 1);
assertThat(validationError).isEqualTo("Truncated CALLF");
}
@ParameterizedTest
@ValueSource(strings = {"b2", "b200"})
@ValueSource(strings = {"e5", "e500"})
@Disabled("Out of Shahghai, will likely return in Cancun or Prague")
void testJumpCallFTruncated(final String code) {
final String validationError = validateCode(Bytes.fromHexString(code), 1);
@ -340,14 +339,14 @@ class CodeV1Test {
}
@ParameterizedTest
@ValueSource(strings = {"b00004", "b003ff", "b0ffff"})
@ValueSource(strings = {"e30004", "e303ff", "e3ffff"})
void testCallFWrongSection(final String code) {
final String validationError = validateCode(Bytes.fromHexString(code), 3);
assertThat(validationError).startsWith("CALLF to non-existent section -");
}
@ParameterizedTest
@ValueSource(strings = {"b20004", "b203ff", "b2ffff"})
@ValueSource(strings = {"e50004", "e503ff", "e5ffff"})
@Disabled("Out of Shahghai, will likely return in Cancun or Prague")
void testJumpFWrongSection(final String code) {
final String validationError = validateCode(Bytes.fromHexString(code), 3);
@ -355,14 +354,14 @@ class CodeV1Test {
}
@ParameterizedTest
@ValueSource(strings = {"b0000100", "b0000200", "b0000000"})
@ValueSource(strings = {"e3000100", "e3000200", "e3000000"})
void testCallFValid(final String code) {
final String validationError = validateCode(Bytes.fromHexString(code), 3);
assertThat(validationError).isNull();
}
@ParameterizedTest
@ValueSource(strings = {"b20001", "b20002", "b20000"})
@ValueSource(strings = {"e50001", "e50002", "e50000"})
@Disabled("Out of Shahghai, will likely return in Cancun or Prague")
void testJumpFValid(final String code) {
final String validationError = validateCode(Bytes.fromHexString(code), 3);
@ -378,26 +377,26 @@ class CodeV1Test {
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",
// 0xe0 byte which could be interpreted a RJUMP, but it's not because it's in PUSH data
"60e0001000",
"6100e0001000",
// 0xe1 byte which could be interpreted a RJUMPI, but it's not because it's in PUSH data
"60e1001000",
"6100e1001000",
// 0xe2 byte which could be interpreted a RJUMPV, but it's not because it's in PUSH data
"60e201000000",
"6100e201000000",
// 0x60 byte which could be interpreted as PUSH, but it's not because it's in RJUMP data
// offset = -160
"5b".repeat(160) + "5cff6000",
"5b".repeat(160) + "e0ff6000",
// 0x60 byte which could be interpreted as PUSH, but it's not because it's in RJUMPI
// data
// offset = -160
"5b".repeat(160) + "5dff6000",
"5b".repeat(160) + "e1ff6000",
// 0x60 byte which could be interpreted as PUSH, but it's not because it's in RJUMPV
// data
// offset = -160
"5b".repeat(160) + "5e01ff6000")
"5b".repeat(160) + "e201ff6000")
.map(Arguments::arguments);
}
@ -497,48 +496,48 @@ class CodeV1Test {
static Stream<Arguments> stackRJumpForward() {
return Stream.of(
Arguments.of("RJUMP 0", null, 0, List.of(List.of("5C0000 00", 0, 0, 0))),
Arguments.of("RJUMP 0", null, 0, List.of(List.of("e00000 00", 0, 0, 0))),
Arguments.of(
"RJUMP 1 w/ dead code",
"Dead code detected in section 0",
0,
List.of(List.of("5C0001 43 00", 0, 0, 0))),
List.of(List.of("e00001 43 00", 0, 0, 0))),
Arguments.of(
"RJUMP 2 w/ dead code",
"Dead code detected in section 0",
0,
List.of(List.of("5C0002 43 50 00", 0, 0, 0))),
List.of(List.of("e00002 43 50 00", 0, 0, 0))),
Arguments.of(
"RJUMP 3 and -10",
null,
0,
List.of(List.of("5C0003 01 50 00 6001 6001 5Cfff6", 0, 0, 2))));
List.of(List.of("e00003 01 50 00 6001 6001 e0fff6", 0, 0, 2))));
}
static Stream<Arguments> stackRJumpBackward() {
return Stream.of(
Arguments.of("RJUMP -3", null, 0, List.of(List.of("5Cfffd", 0, 0, 0))),
Arguments.of("RJUMP -4", null, 0, List.of(List.of("5B 5Cfffc", 0, 0, 0))),
Arguments.of("RJUMP -3", null, 0, List.of(List.of("e0fffd", 0, 0, 0))),
Arguments.of("RJUMP -4", null, 0, List.of(List.of("5B e0fffc", 0, 0, 0))),
Arguments.of(
"RJUMP -4 unmatched stack",
"Jump into code stack height (0) does not match previous value (1)",
0,
List.of(List.of("43 5Cfffc", 0, 0, 0))),
List.of(List.of("43 e0fffc", 0, 0, 0))),
Arguments.of(
"RJUMP -4 unmatched stack",
"Jump into code stack height (1) does not match previous value (0)",
0,
List.of(List.of("43 50 5Cfffc 00", 0, 0, 0))),
Arguments.of("RJUMP -3 matched stack", null, 0, List.of(List.of("43 50 5Cfffd", 0, 0, 1))),
List.of(List.of("43 50 e0fffc 00", 0, 0, 0))),
Arguments.of("RJUMP -3 matched stack", null, 0, List.of(List.of("43 50 e0fffd", 0, 0, 1))),
Arguments.of(
"RJUMP -4 matched stack", null, 0, List.of(List.of("43 50 5B 5Cfffc", 0, 0, 1))),
"RJUMP -4 matched stack", null, 0, List.of(List.of("43 50 5B e0fffc", 0, 0, 1))),
Arguments.of(
"RJUMP -5 matched stack", null, 0, List.of(List.of("43 50 43 5Cfffb", 0, 0, 1))),
"RJUMP -5 matched stack", null, 0, List.of(List.of("43 50 43 e0fffb", 0, 0, 1))),
Arguments.of(
"RJUMP -4 unmatched stack",
"Jump into code stack height (0) does not match previous value (1)",
0,
List.of(List.of("43 50 43 5Cfffc 50 00", 0, 0, 0))));
List.of(List.of("43 50 43 e0fffc 50 00", 0, 0, 0))));
}
static Stream<Arguments> stackRJumpI() {
@ -547,61 +546,61 @@ class CodeV1Test {
"RJUMPI Each branch ending with STOP",
null,
0,
List.of(List.of("60ff 6001 5D0002 50 00 50 00", 0, 0, 2))),
List.of(List.of("60ff 6001 e10002 50 00 50 00", 0, 0, 2))),
Arguments.of(
"RJUMPI One branch ending with RJUMP",
null,
0,
List.of(List.of("60ff 6001 5D0004 50 5C0001 50 00", 0, 0, 2))),
List.of(List.of("60ff 6001 e10004 50 e00001 50 00", 0, 0, 2))),
Arguments.of(
"RJUMPI Fallthrough",
null,
0,
List.of(List.of("60ff 6001 5D0004 80 80 50 50 50 00", 0, 0, 3))),
List.of(List.of("60ff 6001 e10004 80 80 50 50 50 00", 0, 0, 3))),
Arguments.of(
"RJUMPI Offset 0", null, 0, List.of(List.of("60ff 6001 5D0000 50 00", 0, 0, 2))),
"RJUMPI Offset 0", null, 0, List.of(List.of("60ff 6001 e10000 50 00", 0, 0, 2))),
Arguments.of(
"Simple loop (RJUMPI offset = -5)",
null,
0,
List.of(List.of("6001 60ff 81 02 80 5Dfffa 50 50 00", 0, 0, 3))),
List.of(List.of("6001 60ff 81 02 80 e1fffa 50 50 00", 0, 0, 3))),
Arguments.of(
"RJUMPI One branch increasing max stack more stack than another",
null,
0,
List.of(List.of("6001 5D0007 30 30 30 50 50 50 00 30 50 00", 0, 0, 3))),
List.of(List.of("6001 e10007 30 30 30 50 50 50 00 30 50 00", 0, 0, 3))),
Arguments.of(
"RJUMPI One branch increasing max stack more stack than another II",
null,
0,
List.of(List.of("6001 5D0003 30 50 00 30 30 30 50 50 50 00", 0, 0, 3))),
List.of(List.of("6001 e10003 30 50 00 30 30 30 50 50 50 00", 0, 0, 3))),
Arguments.of(
"RJUMPI Missing stack argument",
"Operation 0x5D requires stack of 1 but only has 0 items",
"Operation 0xE1 requires stack of 1 but only has 0 items",
0,
List.of(List.of("5D0000 00", 0, 0, 0))),
List.of(List.of("e10000 00", 0, 0, 0))),
Arguments.of(
"Stack underflow one branch",
"Operation 0x02 requires stack of 2 but only has 1 items",
0,
List.of(List.of("60ff 6001 5D0002 50 00 02 50 00", 0, 0, 0))),
List.of(List.of("60ff 6001 e10002 50 00 02 50 00", 0, 0, 0))),
Arguments.of(
"Stack underflow another branch",
"Operation 0x02 requires stack of 2 but only has 1 items",
0,
List.of(List.of("60ff 6001 5D0002 02 00 19 50 00", 0, 0, 0))),
List.of(List.of("60ff 6001 e10002 02 00 19 50 00", 0, 0, 0))),
// this depends on requiring stacks to be "clean" returns
Arguments.of(
"RJUMPI Stack not empty in the end of one branch",
null,
0,
List.of(List.of("60ff 6001 5D0002 50 00 19 00", 0, 0, 2))),
List.of(List.of("60ff 6001 e10002 50 00 19 00", 0, 0, 2))),
// this depends on requiring stacks to be "clean" returns
Arguments.of(
"RJUMPI Stack not empty in the end of one branch II",
null,
0,
List.of(List.of("60ff 6001 5D0002 19 00 50 00", 0, 0, 2))));
List.of(List.of("60ff 6001 e10002 19 00 50 00", 0, 0, 2))));
}
static Stream<Arguments> stackCallF() {
@ -610,99 +609,99 @@ class CodeV1Test {
"0 input 0 output",
null,
0,
List.of(List.of("B00001 00", 0, 0, 0), List.of("b1", 0, 0, 0))),
List.of(List.of("e30001 00", 0, 0, 0), List.of("e4", 0, 0, 0))),
Arguments.of(
"0 inputs, 0 output 3 sections",
null,
0,
List.of(List.of("B00002 00", 0, 0, 0), List.of("b1", 1, 1, 1), List.of("b1", 0, 0, 0))),
List.of(List.of("e30002 00", 0, 0, 0), List.of("e4", 1, 1, 1), List.of("e4", 0, 0, 0))),
Arguments.of(
"more than 0 inputs",
null,
0,
List.of(List.of("30 B00001 00", 0, 0, 1), List.of("00", 1, 0, 1))),
List.of(List.of("30 e30001 00", 0, 0, 1), List.of("00", 1, 0, 1))),
Arguments.of(
"forwarding an argument",
null,
1,
List.of(List.of("00", 0, 0, 0), List.of("B00002 00", 1, 0, 1), List.of("00", 1, 0, 1))),
List.of(List.of("00", 0, 0, 0), List.of("e30002 00", 1, 0, 1), List.of("00", 1, 0, 1))),
Arguments.of(
"more than 1 inputs",
null,
0,
List.of(List.of("30 80 B00001 00", 0, 0, 2), List.of("00", 2, 0, 2))),
List.of(List.of("30 80 e30001 00", 0, 0, 2), List.of("00", 2, 0, 2))),
Arguments.of(
"more than 0 outputs",
null,
0,
List.of(List.of("B00001 50 00", 0, 0, 1), List.of("3000", 0, 1, 1))),
List.of(List.of("e30001 50 00", 0, 0, 1), List.of("3000", 0, 1, 1))),
Arguments.of(
"more than 0 outputs 3 sections",
null,
0,
List.of(
List.of("B00002 50 00", 0, 0, 1),
List.of("e30002 50 00", 0, 0, 1),
List.of("00", 0, 0, 0),
List.of("30305000", 0, 1, 2))),
Arguments.of(
"more than 1 outputs",
null,
0,
List.of(List.of("B00001 50 50 00", 0, 0, 2), List.of("303000", 0, 2, 2))),
List.of(List.of("e30001 50 50 00", 0, 0, 2), List.of("303000", 0, 2, 2))),
Arguments.of(
"more than 0 inputs, more than 0 outputs",
null,
0,
List.of(
List.of("30 30 B00001 50 50 50 00", 0, 0, 3),
List.of("30 30 B00001 50 50 00", 2, 3, 5))),
Arguments.of("recursion", null, 0, List.of(List.of("B00000 00", 0, 0, 0))),
List.of("30 30 e30001 50 50 50 00", 0, 0, 3),
List.of("30 30 e30001 50 50 00", 2, 3, 5))),
Arguments.of("recursion", null, 0, List.of(List.of("e30000 00", 0, 0, 0))),
Arguments.of(
"recursion 2 inputs",
null,
1,
List.of(List.of("00", 0, 0, 0), List.of("B00000 00", 2, 0, 2))),
List.of(List.of("00", 0, 0, 0), List.of("e30000 00", 2, 0, 2))),
Arguments.of(
"recursion 2 inputs 2 outputs",
null,
1,
List.of(List.of("00", 0, 0, 0), List.of("B00000 50 50 00", 2, 2, 2))),
List.of(List.of("00", 0, 0, 0), List.of("e30000 50 50 00", 2, 2, 2))),
Arguments.of(
"recursion 2 inputs 1 output",
null,
1,
List.of(List.of("00", 0, 0, 0), List.of("30 30 B00001 50 50 50 00", 2, 1, 4))),
List.of(List.of("00", 0, 0, 0), List.of("30 30 e30001 50 50 50 00", 2, 1, 4))),
Arguments.of(
"multiple CALLFs with different types",
null,
1,
List.of(
List.of("00", 0, 0, 0),
List.of("44 B00002 80 80 B00003 44 80 B00004 50 50 00", 0, 0, 3),
List.of("44 e30002 80 80 e30003 44 80 e30004 50 50 00", 0, 0, 3),
List.of("3030505000", 1, 1, 3),
List.of("50505000", 3, 0, 3),
List.of("00", 2, 2, 2))),
Arguments.of(
"underflow",
"Operation 0xB0 requires stack of 1 but only has 0 items",
"Operation 0xE3 requires stack of 1 but only has 0 items",
0,
List.of(List.of("B00001 00", 0, 0, 0), List.of("00", 1, 0, 0))),
List.of(List.of("e30001 00", 0, 0, 0), List.of("00", 1, 0, 0))),
Arguments.of(
"underflow 2",
"Operation 0xB0 requires stack of 2 but only has 1 items",
"Operation 0xE3 requires stack of 2 but only has 1 items",
0,
List.of(List.of("30 B00001 00", 0, 0, 0), List.of("00", 2, 0, 2))),
List.of(List.of("30 e30001 00", 0, 0, 0), List.of("00", 2, 0, 2))),
Arguments.of(
"underflow 3",
"Operation 0xB0 requires stack of 1 but only has 0 items",
"Operation 0xE3 requires stack of 1 but only has 0 items",
1,
List.of(List.of("00", 0, 0, 0), List.of("50 B00001 00", 1, 0, 1))),
List.of(List.of("00", 0, 0, 0), List.of("50 e30001 00", 1, 0, 1))),
Arguments.of(
"underflow 4",
"Operation 0xB0 requires stack of 3 but only has 2 items",
"Operation 0xE3 requires stack of 3 but only has 2 items",
0,
List.of(
List.of("44 B00001 80 B00002 00", 0, 0, 0),
List.of("44 e30001 80 e30002 00", 0, 0, 0),
List.of("00", 1, 1, 1),
List.of("00", 3, 0, 3))));
}
@ -713,63 +712,63 @@ class CodeV1Test {
"0 outputs at section 0",
null,
0,
List.of(List.of("B1", 0, 0, 0), List.of("00", 0, 0, 0))),
List.of(List.of("e4", 0, 0, 0), List.of("00", 0, 0, 0))),
Arguments.of(
"0 outputs at section 1",
null,
1,
List.of(List.of("00", 0, 0, 0), List.of("B1", 0, 0, 0))),
List.of(List.of("00", 0, 0, 0), List.of("e4", 0, 0, 0))),
Arguments.of(
"0 outputs at section 2",
null,
2,
List.of(List.of("00", 0, 0, 0), List.of("00", 1, 1, 1), List.of("B1", 0, 0, 0))),
List.of(List.of("00", 0, 0, 0), List.of("00", 1, 1, 1), List.of("e4", 0, 0, 0))),
Arguments.of(
"more than 0 outputs section 0",
null,
0,
List.of(List.of("44 50 B1", 0, 0, 1), List.of("4400", 0, 1, 1))),
List.of(List.of("44 50 e4", 0, 0, 1), List.of("4400", 0, 1, 1))),
Arguments.of(
"more than 0 outputs section 0",
null,
1,
List.of(List.of("00", 0, 0, 0), List.of("44 B1", 0, 1, 1))),
List.of(List.of("00", 0, 0, 0), List.of("44 e4", 0, 1, 1))),
Arguments.of(
"more than 1 outputs section 1",
null,
1,
List.of(List.of("00", 0, 0, 0), List.of("44 80 B1", 0, 2, 2))),
List.of(List.of("00", 0, 0, 0), List.of("44 80 e4", 0, 2, 2))),
Arguments.of(
"Forwarding return values",
null,
1,
List.of(List.of("00", 0, 0, 0), List.of("B1", 1, 1, 1))),
List.of(List.of("00", 0, 0, 0), List.of("e4", 1, 1, 1))),
Arguments.of(
"Forwarding of return values 2",
null,
1,
List.of(
List.of("00", 0, 0, 0), List.of("B00002 B1", 0, 1, 1), List.of("3000", 0, 1, 1))),
List.of("00", 0, 0, 0), List.of("e30002 e4", 0, 1, 1), List.of("3000", 0, 1, 1))),
Arguments.of(
"Multiple RETFs",
null,
1,
List.of(List.of("00", 0, 0, 0), List.of("5D0003 44 80 B1 30 80 B1", 1, 2, 2))),
List.of(List.of("00", 0, 0, 0), List.of("e10003 44 80 e4 30 80 e4", 1, 2, 2))),
Arguments.of(
"underflow 1",
"Section return (RETF) calculated height 0x0 does not match configured height 0x1",
1,
List.of(List.of("00", 0, 0, 0), List.of("B1", 0, 1, 0))),
List.of(List.of("00", 0, 0, 0), List.of("e4", 0, 1, 0))),
Arguments.of(
"underflow 2",
"Section return (RETF) calculated height 0x1 does not match configured height 0x2",
1,
List.of(List.of("00", 0, 0, 0), List.of("44 B1", 0, 2, 1))),
List.of(List.of("00", 0, 0, 0), List.of("44 e4", 0, 2, 1))),
Arguments.of(
"underflow 3",
"Section return (RETF) calculated height 0x1 does not match configured height 0x2",
1,
List.of(List.of("00", 0, 0, 0), List.of("5D0003 44 80 B1 30 B1", 1, 2, 2))));
List.of(List.of("00", 0, 0, 0), List.of("e10003 44 80 e4 30 e4", 1, 2, 2))));
}
static Stream<Arguments> stackUnreachable() {
@ -783,12 +782,12 @@ class CodeV1Test {
"Max stack not changed by unreachable code RETf",
"Dead code detected in section 0",
0,
List.of(List.of("30 50 B1 30 30 30 50 50 50 00", 0, 0, 1))),
List.of(List.of("30 50 e4 30 30 30 50 50 50 00", 0, 0, 1))),
Arguments.of(
"Max stack not changed by unreachable code RJUMP",
"Dead code detected in section 0",
0,
List.of(List.of("30 50 5C0006 30 30 30 50 50 50 00", 0, 0, 1))),
List.of(List.of("30 50 e00006 30 30 30 50 50 50 00", 0, 0, 1))),
Arguments.of(
"Stack underflow in unreachable code",
"Dead code detected in section 0",
@ -798,12 +797,12 @@ class CodeV1Test {
"Stack underflow in unreachable code RETF",
"Dead code detected in section 0",
0,
List.of(List.of("30 50 B1 50 00", 0, 0, 1))),
List.of(List.of("30 50 e4 50 00", 0, 0, 1))),
Arguments.of(
"Stack underflow in unreachable code RJUMP",
"Dead code detected in section 0",
0,
List.of(List.of("30 50 5C0001 50 00", 0, 0, 1))));
List.of(List.of("30 50 e00001 50 00", 0, 0, 1))));
}
static Stream<Arguments> stackHeight() {
@ -812,12 +811,12 @@ class CodeV1Test {
"Stack height mismatch backwards",
"Jump into code stack height (0) does not match previous value (1)",
0,
List.of(List.of("30 5Cfffc00", 0, 0, 1))),
List.of(List.of("30 e0fffc00", 0, 0, 1))),
Arguments.of(
"Stack height mismatch forwards",
"Jump into code stack height (3) does not match previous value (0)",
0,
List.of(List.of("305D0003303030303000", 0, 0, 2))));
List.of(List.of("30e10003303030303000", 0, 0, 2))));
}
static Stream<Arguments> invalidInstructions() {

@ -159,7 +159,7 @@ class ContractCreationProcessorTest {
Collections.emptyList());
final Bytes contractCode =
Bytes.fromHexString(
"0xEF000101000C020003000b000200080300000000000002020100020100000260016002b00001b00002b101b160005360106000f3");
"0xEF000101000C020003000b000200080300000000000002020100020100000260016002e30001e30002e401e460005360106000f3");
final MessageFrame messageFrame = new TestMessageFrameBuilder().build();
messageFrame.setOutputData(contractCode);
messageFrame.setGasRemaining(100L);
@ -182,7 +182,7 @@ class ContractCreationProcessorTest {
final Bytes contractCode = Bytes.fromHexString("6030602001");
final Bytes initCode =
Bytes.fromHexString(
"0xEF000101000C020003000b000200080300000000000002020100020100000260016002b00001b00002b101b160005360106000f3");
"0xEF000101000C020003000b000200080300000000000002020100020100000260016002e30001e30002e401e460005360106000f3");
final MessageFrame messageFrame =
new TestMessageFrameBuilder().code(CodeFactory.createCode(initCode, 1, true)).build();
messageFrame.setOutputData(contractCode);

@ -38,8 +38,8 @@ public class ByteCodeBuilder {
RETURNDATACOPY("3e"),
REVERT("fd"),
STATICCALL("fa"),
TLOAD("b3"),
TSTORE("b4");
TLOAD("5c"),
TSTORE("5d");
private final String value;
@ -53,20 +53,13 @@ public class ByteCodeBuilder {
}
}
StringBuilder byteCode = new StringBuilder("0x");
final StringBuilder byteCode = new StringBuilder("0x");
@Override
public String toString() {
return byteCode.toString();
}
/**
* @return Bytecode as Bytes
*/
public Bytes toBytes() {
return Bytes.fromHexString(byteCode.toString());
}
/**
* Operation to push the value to the EVM stack
*
@ -106,8 +99,10 @@ public class ByteCodeBuilder {
private String standardizeByteString(final UInt256 value) {
String byteString = value.toMinimalBytes().toUnprefixedHexString();
while (byteString.length() < 2) {
if (byteString.length() % 2 == 1) {
byteString = "0" + byteString;
} else if (byteString.length() == 0) {
byteString = "00";
}
return byteString;
}
@ -120,8 +115,7 @@ public class ByteCodeBuilder {
* @return this
*/
public ByteCodeBuilder tstore(final int key, final int value) {
this.push(value);
this.push(key);
this.push(value).push(key);
byteCode.append(Operation.TSTORE);
return this;
}
@ -145,8 +139,7 @@ public class ByteCodeBuilder {
* @return this
*/
public ByteCodeBuilder dataOnStackToMemory(final int key) {
this.push(key);
this.op(Operation.MSTORE);
this.push(key).op(Operation.MSTORE);
return this;
}
@ -158,9 +151,7 @@ public class ByteCodeBuilder {
* @return this
*/
public ByteCodeBuilder returnValueAtMemory(final int size, final int key) {
this.push(size);
this.push(key);
this.op(Operation.RETURN);
this.push(size).push(key).op(Operation.RETURN);
return this;
}
@ -175,14 +166,14 @@ public class ByteCodeBuilder {
public ByteCodeBuilder call(
final Operation callType, final Address address, final UInt256 gasLimit) {
callTypeCheck(callType);
this.push(0);
this.push(0);
this.push(0);
this.push(0);
this.push(0);
this.push(Bytes.fromHexString(address.toHexString()));
this.push(gasLimit.toMinimalBytes());
this.op(callType);
this.push(0)
.push(0)
.push(0)
.push(0)
.push(0)
.push(Bytes.fromHexString(address.toHexString()))
.push(gasLimit.toMinimalBytes())
.op(callType);
return this;
}
@ -233,14 +224,14 @@ public class ByteCodeBuilder {
dataOnStackToMemory(0);
}
this.push(0);
this.push(0);
this.push(32);
this.push(0);
this.push(0);
this.push(Bytes.fromHexString(address.toHexString()));
this.push(gasLimit.toMinimalBytes());
this.op(callType);
this.push(0)
.push(0)
.push(32)
.push(0)
.push(0)
.push(Bytes.fromHexString(address.toHexString()))
.push(gasLimit.toMinimalBytes())
.op(callType);
return this;
}
@ -250,9 +241,7 @@ public class ByteCodeBuilder {
* @return this
*/
public ByteCodeBuilder returnInnerCallResults() {
this.push(32);
this.push(0);
this.push(0);
this.push(32).push(0).push(0);
byteCode.append(Operation.RETURNDATACOPY);
this.returnValueAtMemory(32, 0);
return this;

Loading…
Cancel
Save