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 { public class CodeValidationSubCommandTest {
static final String CODE_STOP_ONLY = "0xef0001 010004 020001-0001 030000 00 00000000 00"; 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_RETF_ONLY = "0xef0001 010004 020001-0001 030000 00 00000000 e4";
static final String CODE_BAD_MAGIC = "0xefffff 010004 020001-0001 030000 00 00000000 b1"; static final String CODE_BAD_MAGIC = "0xefffff 010004 020001-0001 030000 00 00000000 e4";
static final String CODE_INTERIOR_COMMENTS = static final String CODE_INTERIOR_COMMENTS =
"0xef0001 010008 020002-000c-0002 030000 00 \n" """
+ "# 7 inputs 1 output,\n" 0xef0001 010008 020002-000c-0002 030000 00
+ "00000007-07010007 \n" # 7 inputs 1 output,
+ "59-59-59-59-59-59-59-b00001-50-b1\n" 00000007-07010007
+ "# No immediate data\n" 59-59-59-59-59-59-59-e30001-50-e4
+ "f1-b1"; # No immediate data
f1-e4""";
static final String CODE_MULTIPLE = static final String CODE_MULTIPLE =
CODE_STOP_ONLY + "\n" + CODE_BAD_MAGIC + "\n" + CODE_RETF_ONLY + "\n"; 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)); new CodeValidateSubCommand(bais, new PrintStream(baos));
codeValidateSubCommand.run(); codeValidateSubCommand.run();
assertThat(baos.toString(UTF_8)) 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 @Test
@ -104,7 +110,12 @@ public class CodeValidationSubCommandTest {
cmd.parseArgs(CODE_STOP_ONLY, CODE_BAD_MAGIC, CODE_RETF_ONLY); cmd.parseArgs(CODE_STOP_ONLY, CODE_BAD_MAGIC, CODE_RETF_ONLY);
codeValidateSubCommand.run(); codeValidateSubCommand.run();
assertThat(baos.toString(UTF_8)) 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 @Test
@ -116,7 +127,7 @@ public class CodeValidationSubCommandTest {
final CommandLine cmd = new CommandLine(codeValidateSubCommand); final CommandLine cmd = new CommandLine(codeValidateSubCommand);
cmd.parseArgs(CODE_RETF_ONLY); cmd.parseArgs(CODE_RETF_ONLY);
codeValidateSubCommand.run(); codeValidateSubCommand.run();
assertThat(baos.toString(UTF_8)).contains("OK b1\n"); assertThat(baos.toString(UTF_8)).contains("OK e4\n");
} }
@Test @Test
@ -128,7 +139,7 @@ public class CodeValidationSubCommandTest {
final CommandLine cmd = new CommandLine(codeValidateSubCommand); final CommandLine cmd = new CommandLine(codeValidateSubCommand);
cmd.parseArgs(CODE_INTERIOR_COMMENTS); cmd.parseArgs(CODE_INTERIOR_COMMENTS);
codeValidateSubCommand.run(); codeValidateSubCommand.run();
assertThat(baos.toString(UTF_8)).contains("OK 59595959595959b0000150b1,f1b1\n"); assertThat(baos.toString(UTF_8)).contains("OK 59595959595959e3000150e4,f1e4\n");
} }
@Test @Test
@ -140,6 +151,11 @@ public class CodeValidationSubCommandTest {
new CodeValidateSubCommand(bais, new PrintStream(baos)); new CodeValidateSubCommand(bais, new PrintStream(baos));
codeValidateSubCommand.run(); codeValidateSubCommand.run();
assertThat(baos.toString(UTF_8)) 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, // 0x59 - MSIZE
VALID, // 0x5a - GAS VALID, // 0x5a - GAS
VALID, // 0x5b - NOOOP (née JUMPDEST) VALID, // 0x5b - NOOOP (née JUMPDEST)
VALID_AND_TERMINAL, // 0X5c - RJUMP VALID, // 0X5c - TLOAD
VALID, // 0X5d - RJUMPI VALID, // 0X5d - TSTORE
VALID, // 0X5e - RJUMPV VALID, // 0X5e - MCOPY
VALID, // 0X5f - PUSH0 VALID, // 0X5f - PUSH0
VALID, // 0x60 - PUSH1 VALID, // 0x60 - PUSH1
VALID, // 0x61 - PUSH2 VALID, // 0x61 - PUSH2
@ -219,9 +219,9 @@ public final class CodeV1Validation {
INVALID, // 0xad INVALID, // 0xad
INVALID, // 0xae INVALID, // 0xae
INVALID, // 0xaf INVALID, // 0xaf
VALID, // 0xb0 - CALLF INVALID, // 0xb0
VALID_AND_TERMINAL, // 0xb1 - RETF INVALID, // 0xb1
INVALID, // 0xb2 - JUMPF INVALID, // 0xb2
INVALID, // 0xb3 INVALID, // 0xb3
INVALID, // 0xb4 INVALID, // 0xb4
INVALID, // 0xb5 INVALID, // 0xb5
@ -267,11 +267,11 @@ public final class CodeV1Validation {
INVALID, // 0xdd INVALID, // 0xdd
INVALID, // 0xde INVALID, // 0xde
INVALID, // 0xef INVALID, // 0xef
INVALID, // 0xe0 VALID_AND_TERMINAL, // 0xe0 - RJUMP
INVALID, // 0xe1 VALID, // 0xe1 - RJUMPI
INVALID, // 0xe2 VALID, // 0xe2 - RJUMPV
INVALID, // 0xe3 VALID, // 0xe3 - CALLF
INVALID, // 0xe4 VALID_AND_TERMINAL, // 0xe4 - RETF
INVALID, // 0xe5 INVALID, // 0xe5
INVALID, // 0xe6 INVALID, // 0xe6
INVALID, // 0xe7 INVALID, // 0xe7
@ -398,9 +398,9 @@ public final class CodeV1Validation {
{0, 1, 1}, // 0x59 - MSIZE {0, 1, 1}, // 0x59 - MSIZE
{0, 1, 1}, // 0x5a - GAS {0, 1, 1}, // 0x5a - GAS
{0, 0, 1}, // 0x5b - NOOP (née JUMPDEST) {0, 0, 1}, // 0x5b - NOOP (née JUMPDEST)
{0, 0, -3}, // 0x5c - RJUMP {1, 1, 1}, // 0x5c - TLOAD
{1, 0, 3}, // 0x5d - RJUMPI {2, 0, 1}, // 0x5d - TSTORE
{1, 0, 2}, // 0x5e - RJUMPV {4, 0, 1}, // 0x5e - MCOPY
{0, 1, 1}, // 0x5f - PUSH0 {0, 1, 1}, // 0x5f - PUSH0
{0, 1, 2}, // 0x60 - PUSH1 {0, 1, 2}, // 0x60 - PUSH1
{0, 1, 3}, // 0x61 - PUSH2 {0, 1, 3}, // 0x61 - PUSH2
@ -482,9 +482,9 @@ public final class CodeV1Validation {
{0, 0, 0}, // 0xad {0, 0, 0}, // 0xad
{0, 0, 0}, // 0xae {0, 0, 0}, // 0xae
{0, 0, 0}, // 0xaf {0, 0, 0}, // 0xaf
{0, 0, 3}, // 0xb0 - CALLF {0, 0, 0}, // 0xb0
{0, 0, -1}, // 0xb1 - RETF {0, 0, 0}, // 0xb1
{0, 0, 0}, // 0xb2 - JUMPF {0, 0, 0}, // 0xb2
{0, 0, 0}, // 0xb3 {0, 0, 0}, // 0xb3
{0, 0, 0}, // 0xb4 {0, 0, 0}, // 0xb4
{0, 0, 0}, // 0xb5 {0, 0, 0}, // 0xb5
@ -530,12 +530,12 @@ public final class CodeV1Validation {
{0, 0, 0}, // 0xdd {0, 0, 0}, // 0xdd
{0, 0, 0}, // 0xde {0, 0, 0}, // 0xde
{0, 0, 0}, // 0xef {0, 0, 0}, // 0xef
{0, 0, 0}, // 0xe0 {0, 0, -3}, // 0xe0 - RJUMP
{0, 0, 0}, // 0xe1 {1, 0, 3}, // 0xe1 - RJUMPI
{0, 0, 0}, // 0xe2 {1, 0, 2}, // 0xe2 - RJUMPV
{0, 0, 0}, // 0xe3 {0, 0, 3}, // 0xe3 - CALLF
{0, 0, 0}, // 0xe4 {0, 0, -1}, // 0xe4 - RETF
{0, 0, 0}, // 0xe5 {0, 0, 0}, // 0xe5 - JUMPF
{0, 0, 0}, // 0xe6 {0, 0, 0}, // 0xe6
{0, 0, 0}, // 0xe7 {0, 0, 0}, // 0xe7
{0, 0, 0}, // 0xe8 {0, 0, 0}, // 0xe8

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

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

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

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

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

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

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

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

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

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

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

Loading…
Cancel
Save