mirror of https://github.com/hyperledger/besu
EIP-7692 "Mega" EOF Implementation (#7169)
A complete and up to date implementation of EIP-7692 EOF v.1. For genesis file activation use "PragueEOFTime", for references tests it activates as part of Prague. Signed-off-by: Danno Ferrin <danno@numisight.com>revert-7203-patch-1
parent
365737c2eb
commit
85d286aa85
@ -0,0 +1,226 @@ |
|||||||
|
/* |
||||||
|
* 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.evmtool; |
||||||
|
|
||||||
|
import static java.nio.charset.StandardCharsets.UTF_8; |
||||||
|
import static org.hyperledger.besu.ethereum.referencetests.EOFTestCaseSpec.TestResult.failed; |
||||||
|
import static org.hyperledger.besu.ethereum.referencetests.EOFTestCaseSpec.TestResult.passed; |
||||||
|
import static org.hyperledger.besu.evmtool.EOFTestSubCommand.COMMAND_NAME; |
||||||
|
|
||||||
|
import org.hyperledger.besu.crypto.SignatureAlgorithmFactory; |
||||||
|
import org.hyperledger.besu.ethereum.referencetests.EOFTestCaseSpec; |
||||||
|
import org.hyperledger.besu.ethereum.referencetests.EOFTestCaseSpec.TestResult; |
||||||
|
import org.hyperledger.besu.evm.EvmSpecVersion; |
||||||
|
import org.hyperledger.besu.evm.code.CodeFactory; |
||||||
|
import org.hyperledger.besu.evm.code.CodeInvalid; |
||||||
|
import org.hyperledger.besu.evm.code.CodeV1; |
||||||
|
import org.hyperledger.besu.evm.code.CodeV1Validation; |
||||||
|
import org.hyperledger.besu.evm.code.EOFLayout; |
||||||
|
import org.hyperledger.besu.util.LogConfigurator; |
||||||
|
|
||||||
|
import java.io.BufferedReader; |
||||||
|
import java.io.File; |
||||||
|
import java.io.IOException; |
||||||
|
import java.io.InputStreamReader; |
||||||
|
import java.nio.file.Path; |
||||||
|
import java.util.ArrayList; |
||||||
|
import java.util.List; |
||||||
|
import java.util.Map; |
||||||
|
|
||||||
|
import com.fasterxml.jackson.core.JsonProcessingException; |
||||||
|
import com.fasterxml.jackson.databind.JavaType; |
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper; |
||||||
|
import org.apache.tuweni.bytes.Bytes; |
||||||
|
import picocli.CommandLine; |
||||||
|
|
||||||
|
@CommandLine.Command( |
||||||
|
name = COMMAND_NAME, |
||||||
|
description = "Runs EOF validation reference tests", |
||||||
|
mixinStandardHelpOptions = true, |
||||||
|
versionProvider = VersionProvider.class) |
||||||
|
public class EOFTestSubCommand implements Runnable { |
||||||
|
public static final String COMMAND_NAME = "eof-test"; |
||||||
|
@CommandLine.ParentCommand private final EvmToolCommand parentCommand; |
||||||
|
|
||||||
|
// picocli does it magically
|
||||||
|
@CommandLine.Parameters private final List<Path> eofTestFiles = new ArrayList<>(); |
||||||
|
|
||||||
|
@CommandLine.Option( |
||||||
|
names = {"--fork-name"}, |
||||||
|
description = "Limit execution to one fork.") |
||||||
|
private String forkName = null; |
||||||
|
|
||||||
|
@CommandLine.Option( |
||||||
|
names = {"--test-name"}, |
||||||
|
description = "Limit execution to one test.") |
||||||
|
private String testVectorName = null; |
||||||
|
|
||||||
|
public EOFTestSubCommand() { |
||||||
|
this(null); |
||||||
|
} |
||||||
|
|
||||||
|
public EOFTestSubCommand(final EvmToolCommand parentCommand) { |
||||||
|
this.parentCommand = parentCommand; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void run() { |
||||||
|
LogConfigurator.setLevel("", "OFF"); |
||||||
|
// presume ethereum mainnet for reference and EOF tests
|
||||||
|
SignatureAlgorithmFactory.setDefaultInstance(); |
||||||
|
final ObjectMapper eofTestMapper = JsonUtils.createObjectMapper(); |
||||||
|
|
||||||
|
final JavaType javaType = |
||||||
|
eofTestMapper |
||||||
|
.getTypeFactory() |
||||||
|
.constructParametricType(Map.class, String.class, EOFTestCaseSpec.class); |
||||||
|
try { |
||||||
|
if (eofTestFiles.isEmpty()) { |
||||||
|
// if no EOF tests were specified use standard input to get filenames
|
||||||
|
final BufferedReader in = |
||||||
|
new BufferedReader(new InputStreamReader(parentCommand.in, UTF_8)); |
||||||
|
while (true) { |
||||||
|
final String fileName = in.readLine(); |
||||||
|
if (fileName == null) { |
||||||
|
// reached end of file. Stop the loop.
|
||||||
|
break; |
||||||
|
} |
||||||
|
final File file = new File(fileName); |
||||||
|
if (file.isFile()) { |
||||||
|
final Map<String, EOFTestCaseSpec> eofTests = eofTestMapper.readValue(file, javaType); |
||||||
|
executeEOFTest(file.toString(), eofTests); |
||||||
|
} else { |
||||||
|
parentCommand.out.println("File not found: " + fileName); |
||||||
|
} |
||||||
|
} |
||||||
|
} else { |
||||||
|
for (final Path eofTestFile : eofTestFiles) { |
||||||
|
final Map<String, EOFTestCaseSpec> eofTests; |
||||||
|
if ("stdin".equals(eofTestFile.toString())) { |
||||||
|
eofTests = eofTestMapper.readValue(parentCommand.in, javaType); |
||||||
|
} else { |
||||||
|
eofTests = eofTestMapper.readValue(eofTestFile.toFile(), javaType); |
||||||
|
} |
||||||
|
executeEOFTest(eofTestFile.toString(), eofTests); |
||||||
|
} |
||||||
|
} |
||||||
|
} catch (final JsonProcessingException jpe) { |
||||||
|
parentCommand.out.println("File content error: " + jpe); |
||||||
|
} catch (final IOException e) { |
||||||
|
System.err.println("Unable to read EOF test file"); |
||||||
|
e.printStackTrace(System.err); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
record TestExecutionResult( |
||||||
|
String fileName, |
||||||
|
String group, |
||||||
|
String name, |
||||||
|
String fork, |
||||||
|
boolean pass, |
||||||
|
String expectedError, |
||||||
|
String actualError) {} |
||||||
|
|
||||||
|
private void executeEOFTest(final String fileName, final Map<String, EOFTestCaseSpec> eofTests) { |
||||||
|
List<TestExecutionResult> results = new ArrayList<>(); |
||||||
|
|
||||||
|
for (var testGroup : eofTests.entrySet()) { |
||||||
|
String groupName = testGroup.getKey(); |
||||||
|
for (var testVector : testGroup.getValue().getVector().entrySet()) { |
||||||
|
String testName = testVector.getKey(); |
||||||
|
if (testVectorName != null && !testVectorName.equals(testName)) { |
||||||
|
continue; |
||||||
|
} |
||||||
|
String code = testVector.getValue().code(); |
||||||
|
for (var testResult : testVector.getValue().results().entrySet()) { |
||||||
|
String expectedForkName = testResult.getKey(); |
||||||
|
if (forkName != null && !forkName.equals(expectedForkName)) { |
||||||
|
continue; |
||||||
|
} |
||||||
|
TestResult expectedResult = testResult.getValue(); |
||||||
|
EvmSpecVersion evmVersion = EvmSpecVersion.fromName(expectedForkName); |
||||||
|
if (evmVersion == null) { |
||||||
|
results.add( |
||||||
|
new TestExecutionResult( |
||||||
|
fileName, |
||||||
|
groupName, |
||||||
|
testName, |
||||||
|
expectedForkName, |
||||||
|
false, |
||||||
|
"Valid fork name", |
||||||
|
"Unknown fork: " + expectedForkName)); |
||||||
|
|
||||||
|
continue; |
||||||
|
} |
||||||
|
TestResult actualResult; |
||||||
|
if (evmVersion.ordinal() < EvmSpecVersion.PRAGUE_EOF.ordinal()) { |
||||||
|
actualResult = failed("EOF_InvalidCode"); |
||||||
|
} else { |
||||||
|
actualResult = considerCode(code); |
||||||
|
} |
||||||
|
results.add( |
||||||
|
new TestExecutionResult( |
||||||
|
fileName, |
||||||
|
groupName, |
||||||
|
testName, |
||||||
|
expectedForkName, |
||||||
|
actualResult.result() == expectedResult.result(), |
||||||
|
expectedResult.exception(), |
||||||
|
actualResult.exception())); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
for (TestExecutionResult result : results) { |
||||||
|
try { |
||||||
|
parentCommand.out.println(JsonUtils.createObjectMapper().writeValueAsString(result)); |
||||||
|
} catch (JsonProcessingException e) { |
||||||
|
e.printStackTrace(parentCommand.out); |
||||||
|
throw new RuntimeException(e); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public TestResult considerCode(final String hexCode) { |
||||||
|
Bytes codeBytes; |
||||||
|
try { |
||||||
|
codeBytes = |
||||||
|
Bytes.fromHexString( |
||||||
|
hexCode.replaceAll("(^|\n)#[^\n]*($|\n)", "").replaceAll("[^0-9A-Za-z]", "")); |
||||||
|
} catch (RuntimeException re) { |
||||||
|
return failed(re.getMessage()); |
||||||
|
} |
||||||
|
if (codeBytes.isEmpty()) { |
||||||
|
return passed(); |
||||||
|
} |
||||||
|
|
||||||
|
var layout = EOFLayout.parseEOF(codeBytes); |
||||||
|
if (!layout.isValid()) { |
||||||
|
return failed("layout - " + layout.invalidReason()); |
||||||
|
} |
||||||
|
|
||||||
|
var code = CodeFactory.createCode(codeBytes, 1); |
||||||
|
if (!code.isValid()) { |
||||||
|
return failed("validate " + ((CodeInvalid) code).getInvalidReason()); |
||||||
|
} |
||||||
|
if (code instanceof CodeV1 codeV1) { |
||||||
|
var result = CodeV1Validation.validate(codeV1.getEofLayout()); |
||||||
|
if (result != null) { |
||||||
|
return (failed("deep validate error: " + result)); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return passed(); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,81 @@ |
|||||||
|
/* |
||||||
|
* 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.evmtool; |
||||||
|
|
||||||
|
import static org.hyperledger.besu.evmtool.PrettyPrintSubCommand.COMMAND_NAME; |
||||||
|
|
||||||
|
import org.hyperledger.besu.evm.code.CodeV1Validation; |
||||||
|
import org.hyperledger.besu.evm.code.EOFLayout; |
||||||
|
import org.hyperledger.besu.util.LogConfigurator; |
||||||
|
|
||||||
|
import java.util.ArrayList; |
||||||
|
import java.util.List; |
||||||
|
|
||||||
|
import org.apache.tuweni.bytes.Bytes; |
||||||
|
import picocli.CommandLine; |
||||||
|
|
||||||
|
@CommandLine.Command( |
||||||
|
name = COMMAND_NAME, |
||||||
|
description = "Pretty Prints EOF Code", |
||||||
|
mixinStandardHelpOptions = true, |
||||||
|
versionProvider = VersionProvider.class) |
||||||
|
public class PrettyPrintSubCommand implements Runnable { |
||||||
|
public static final String COMMAND_NAME = "pretty-print"; |
||||||
|
@CommandLine.ParentCommand private final EvmToolCommand parentCommand; |
||||||
|
|
||||||
|
@CommandLine.Option( |
||||||
|
names = {"-f", "--force"}, |
||||||
|
description = "Always print well formated code, even if there is an error", |
||||||
|
paramLabel = "<boolean>") |
||||||
|
private final Boolean force = false; |
||||||
|
|
||||||
|
// picocli does it magically
|
||||||
|
@CommandLine.Parameters private final List<String> codeList = new ArrayList<>(); |
||||||
|
|
||||||
|
public PrettyPrintSubCommand() { |
||||||
|
this(null); |
||||||
|
} |
||||||
|
|
||||||
|
public PrettyPrintSubCommand(final EvmToolCommand parentCommand) { |
||||||
|
this.parentCommand = parentCommand; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void run() { |
||||||
|
LogConfigurator.setLevel("", "OFF"); |
||||||
|
|
||||||
|
for (var hexCode : codeList) { |
||||||
|
Bytes container = Bytes.fromHexString(hexCode); |
||||||
|
if (container.get(0) != ((byte) 0xef) && container.get(1) != 0) { |
||||||
|
parentCommand.out.println( |
||||||
|
"Pretty printing of legacy EVM is not supported. Patches welcome!"); |
||||||
|
|
||||||
|
} else { |
||||||
|
EOFLayout layout = EOFLayout.parseEOF(container); |
||||||
|
if (layout.isValid()) { |
||||||
|
String validation = CodeV1Validation.validate(layout); |
||||||
|
if (validation == null || force) { |
||||||
|
layout.prettyPrint(parentCommand.out); |
||||||
|
} |
||||||
|
if (validation != null) { |
||||||
|
parentCommand.out.println("EOF code is invalid - " + validation); |
||||||
|
} |
||||||
|
} else { |
||||||
|
parentCommand.out.println("EOF layout is invalid - " + layout.invalidReason()); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
File diff suppressed because one or more lines are too long
@ -0,0 +1,8 @@ |
|||||||
|
{ |
||||||
|
"cli": [ |
||||||
|
"pretty-print", |
||||||
|
"0xEF0001010004020001001304000000008000026000e20200030000fff65b5b00600160015500" |
||||||
|
], |
||||||
|
"stdin": "", |
||||||
|
"stdout": "0x # EOF\nef0001 # Magic and Version ( 1 )\n010004 # Types length ( 4 )\n020001 # Total code sections ( 1 )\n 0013 # Code section 0 , 19 bytes\n040000 # Data section length( 0 )\n 00 # Terminator (end of header)\n # Code section 0 types\n 00 # 0 inputs \n 80 # 0 outputs (Non-returning function)\n 0002 # max stack: 2\n # Code section 0 - in=0 out=non-returning height=2\n 6000 # [0] PUSH1(0)\ne20200030000fff6 # [2] RJUMPV(3,0,-10)\n 5b # [10] NOOP\n 5b # [11] NOOP\n 00 # [12] STOP\n 6001 # [13] PUSH1(1)\n 6001 # [15] PUSH1(1)\n 55 # [17] SSTORE\n 00 # [18] STOP\n # Data section (empty)\n" |
||||||
|
} |
@ -0,0 +1,8 @@ |
|||||||
|
{ |
||||||
|
"cli": [ |
||||||
|
"pretty-print", |
||||||
|
"0xef000101000402000100130300010043040000000080000436600060003736600060006000ec0060005500ef0001010004020001000b03000100200400000000800003366000600037366000ee00ef0001010004020001000d0400400000800002d10000600055d1002060015500" |
||||||
|
], |
||||||
|
"stdin": "", |
||||||
|
"stdout": "0x # EOF\nef0001 # Magic and Version ( 1 )\n010004 # Types length ( 4 )\n020001 # Total code sections ( 1 )\n 0013 # Code section 0 , 19 bytes\n030001 # Total subcontainers ( 1 )\n 0043 # Sub container 0, 67 byte\n040000 # Data section length( 0 )\n 00 # Terminator (end of header)\n # Code section 0 types\n 00 # 0 inputs \n 80 # 0 outputs (Non-returning function)\n 0004 # max stack: 4\n # Code section 0 - in=0 out=non-returning height=4\n 36 # [0] CALLDATASIZE\n 6000 # [1] PUSH1(0)\n 6000 # [3] PUSH1(0)\n 37 # [5] CALLDATACOPY\n 36 # [6] CALLDATASIZE\n 6000 # [7] PUSH1(0)\n 6000 # [9] PUSH1(0)\n 6000 # [11] PUSH1(0)\n ec00 # [13] EOFCREATE(0)\n 6000 # [15] PUSH1(0)\n 55 # [17] SSTORE\n 00 # [18] STOP\n # Subcontainer 0 starts here\n ef0001 # Magic and Version ( 1 )\n 010004 # Types length ( 4 )\n 020001 # Total code sections ( 1 )\n 000b # Code section 0 , 11 bytes\n 030001 # Total subcontainers ( 1 )\n 0020 # Sub container 0, 32 byte\n 040000 # Data section length( 0 ) \n 00 # Terminator (end of header)\n # Code section 0 types\n 00 # 0 inputs \n 80 # 0 outputs (Non-returning function)\n 0003 # max stack: 3\n # Code section 0 - in=0 out=non-returning height=3\n 36 # [0] CALLDATASIZE\n 6000 # [1] PUSH1(0)\n 6000 # [3] PUSH1(0)\n 37 # [5] CALLDATACOPY\n 36 # [6] CALLDATASIZE\n 6000 # [7] PUSH1(0)\n ee00 # [9] RETURNCONTRACT(0)\n # Subcontainer 0.0 starts here\n ef0001 # Magic and Version ( 1 )\n 010004 # Types length ( 4 )\n 020001 # Total code sections ( 1 )\n 000d # Code section 0 , 13 bytes\n 040040 # Data section length( 64 ) (actual size 0) \n 00 # Terminator (end of header)\n # Code section 0 types\n 00 # 0 inputs \n 80 # 0 outputs (Non-returning function)\n 0002 # max stack: 2\n # Code section 0 - in=0 out=non-returning height=2\n d10000 # [0] DATALOADN(0x0000)\n 6000 # [3] PUSH1(0)\n 55 # [5] SSTORE\n d10020 # [6] DATALOADN(0x0020)\n 6001 # [9] PUSH1(1)\n 55 # [11] SSTORE\n 00 # [12] STOP\n # Data section (empty)\n # Subcontainer 0.0 ends\n # Data section (empty)\n # Subcontainer 0 ends\n # Data section (empty)\n" |
||||||
|
} |
@ -0,0 +1,86 @@ |
|||||||
|
{ |
||||||
|
"cli": [ |
||||||
|
"state-test", |
||||||
|
"stdin", |
||||||
|
"--trace", |
||||||
|
"--trace.memory", |
||||||
|
"--trace.stack", |
||||||
|
"--trace.returndata", |
||||||
|
"--notime" |
||||||
|
], |
||||||
|
"stdin": { |
||||||
|
"create-eof": { |
||||||
|
"env": { |
||||||
|
"currentCoinbase": "b94f5374fce5edbc8e2a8697c15331677e6ebf0b", |
||||||
|
"currentDifficulty": "0x20000", |
||||||
|
"currentRandom": "0x0000000000000000000000000000000000000000000000000000000000020000", |
||||||
|
"currentGasLimit": "0x26e1f476fe1e22", |
||||||
|
"currentNumber": "0x2", |
||||||
|
"currentTimestamp": "0x3e8", |
||||||
|
"previousHash": "0x0000000000000000000000000000000000000000000000000000000000000000", |
||||||
|
"currentBaseFee": "0x10" |
||||||
|
}, |
||||||
|
"pre": { |
||||||
|
"0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b": { |
||||||
|
"code": "0x", |
||||||
|
"storage": {}, |
||||||
|
"balance": "0xffffffffff", |
||||||
|
"nonce": "0x0" |
||||||
|
} |
||||||
|
}, |
||||||
|
"transaction": { |
||||||
|
"gasPrice": "0x10", |
||||||
|
"nonce": "0x0", |
||||||
|
"to": null, |
||||||
|
"data": [ |
||||||
|
"ef00010100040200010009030001001404000000008000035f355f5fa15f5fee00ef00010100040200010001040000000080000000c0de471fe5" |
||||||
|
], |
||||||
|
"gasLimit": [ |
||||||
|
"0x7a1200" |
||||||
|
], |
||||||
|
"value": [ |
||||||
|
"0xdbbe" |
||||||
|
], |
||||||
|
"secretKey": "0x45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8" |
||||||
|
}, |
||||||
|
"out": "0x", |
||||||
|
"post": { |
||||||
|
"Prague": [ |
||||||
|
{ |
||||||
|
"hash": "0x1a8642a04dae90535f00f53d3a30284c4db051d508a653db89eb100ba9aecbf3", |
||||||
|
"logs": "0xf48b954a6a6f4ce6b28e4950b7027413f4bdc8f459df6003b6e8d7a1567c8940", |
||||||
|
"indexes": { |
||||||
|
"data": 0, |
||||||
|
"gas": 0, |
||||||
|
"value": 0 |
||||||
|
} |
||||||
|
} |
||||||
|
], |
||||||
|
"Cancun": [ |
||||||
|
{ |
||||||
|
"hash": "0xaa80d89bc89f58da8de41d3894bd1a241896ff91f7a5964edaefb39e8e3a4a98", |
||||||
|
"logs": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", |
||||||
|
"indexes": { |
||||||
|
"data": 0, |
||||||
|
"gas": 0, |
||||||
|
"value": 0 |
||||||
|
} |
||||||
|
} |
||||||
|
] |
||||||
|
} |
||||||
|
} |
||||||
|
}, |
||||||
|
"stdout": [ |
||||||
|
{"pc":0,"section":0,"op":95,"gas":"0x794068","gasCost":"0x2","memSize":0,"stack":[],"depth":1,"refund":0,"opName":"PUSH0"}, |
||||||
|
{"pc":1,"section":0,"op":53,"gas":"0x794066","gasCost":"0x3","memSize":0,"stack":["0x0"],"depth":1,"refund":0,"opName":"CALLDATALOAD"}, |
||||||
|
{"pc":2,"section":0,"op":95,"gas":"0x794063","gasCost":"0x2","memSize":0,"stack":["0xc0de471fe5000000000000000000000000000000000000000000000000000000"],"depth":1,"refund":0,"opName":"PUSH0"}, |
||||||
|
{"pc":3,"section":0,"op":95,"gas":"0x794061","gasCost":"0x2","memSize":0,"stack":["0xc0de471fe5000000000000000000000000000000000000000000000000000000","0x0"],"depth":1,"refund":0,"opName":"PUSH0"}, |
||||||
|
{"pc":4,"section":0,"op":161,"gas":"0x79405f","gasCost":"0x2ee","memSize":0,"stack":["0xc0de471fe5000000000000000000000000000000000000000000000000000000","0x0","0x0"],"depth":1,"refund":0,"opName":"LOG1"}, |
||||||
|
{"pc":5,"section":0,"op":95,"gas":"0x793d71","gasCost":"0x2","memSize":0,"stack":[],"depth":1,"refund":0,"opName":"PUSH0"}, |
||||||
|
{"pc":6,"section":0,"op":95,"gas":"0x793d6f","gasCost":"0x2","memSize":0,"stack":["0x0"],"depth":1,"refund":0,"opName":"PUSH0"}, |
||||||
|
{"pc":7,"section":0,"op":238,"immediate":"0x00","gas":"0x793d6d","gasCost":"0x0","memSize":0,"stack":["0x0","0x0"],"depth":1,"refund":0,"opName":"RETURNCONTRACT"}, |
||||||
|
{"output":"","gasUsed":"0xe433","test":"create-eof","fork":"Prague","d":0,"g":0,"v":0,"postHash":"0x1a8642a04dae90535f00f53d3a30284c4db051d508a653db89eb100ba9aecbf3","postLogsHash":"0xf48b954a6a6f4ce6b28e4950b7027413f4bdc8f459df6003b6e8d7a1567c8940","pass":true}, |
||||||
|
{"pc":0,"op":239,"gas":"0x794068","gasCost":"0x0","memSize":0,"stack":[],"depth":1,"refund":0,"opName":"INVALID","error":"Bad instruction"}, |
||||||
|
{"output":"","gasUsed":"0x7a1200","test":"create-eof","fork":"Cancun","d":0,"g":0,"v":0,"postHash":"0xaa80d89bc89f58da8de41d3894bd1a241896ff91f7a5964edaefb39e8e3a4a98","postLogsHash":"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","pass":true,"error":"INVALID_OPERATION"} |
||||||
|
] |
||||||
|
} |
@ -0,0 +1,78 @@ |
|||||||
|
{ |
||||||
|
"cli": [ |
||||||
|
"state-test", |
||||||
|
"stdin", |
||||||
|
"--trace", |
||||||
|
"--trace.memory", |
||||||
|
"--trace.stack", |
||||||
|
"--trace.returndata", |
||||||
|
"--notime" |
||||||
|
], |
||||||
|
"stdin": { |
||||||
|
"create-eof": { |
||||||
|
"env": { |
||||||
|
"currentCoinbase": "b94f5374fce5edbc8e2a8697c15331677e6ebf0b", |
||||||
|
"currentDifficulty": "0x20000", |
||||||
|
"currentRandom": "0x0000000000000000000000000000000000000000000000000000000000020000", |
||||||
|
"currentGasLimit": "0x26e1f476fe1e22", |
||||||
|
"currentNumber": "0x2", |
||||||
|
"currentTimestamp": "0x3e8", |
||||||
|
"previousHash": "0x0000000000000000000000000000000000000000000000000000000000000000", |
||||||
|
"currentBaseFee": "0x10" |
||||||
|
}, |
||||||
|
"pre": { |
||||||
|
"0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b": { |
||||||
|
"code": "0x", |
||||||
|
"storage": {}, |
||||||
|
"balance": "0xffffffffff", |
||||||
|
"nonce": "0x0" |
||||||
|
} |
||||||
|
}, |
||||||
|
"transaction": { |
||||||
|
"gasPrice": "0x10", |
||||||
|
"nonce": "0x0", |
||||||
|
"to": null, |
||||||
|
"data": [ |
||||||
|
"ef00011100040200010009030001001404000000008000035f355f5fa15f5fee00ef00010100040200010001040000000080000000c0de471fe5" |
||||||
|
], |
||||||
|
"gasLimit": [ |
||||||
|
"0x7a1200" |
||||||
|
], |
||||||
|
"value": [ |
||||||
|
"0xdbbe" |
||||||
|
], |
||||||
|
"secretKey": "0x45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8" |
||||||
|
}, |
||||||
|
"out": "0x", |
||||||
|
"post": { |
||||||
|
"Prague": [ |
||||||
|
{ |
||||||
|
"hash": "0x1a8642a04dae90535f00f53d3a30284c4db051d508a653db89eb100ba9aecbf3", |
||||||
|
"logs": "0xf48b954a6a6f4ce6b28e4950b7027413f4bdc8f459df6003b6e8d7a1567c8940", |
||||||
|
"indexes": { |
||||||
|
"data": 0, |
||||||
|
"gas": 0, |
||||||
|
"value": 0 |
||||||
|
} |
||||||
|
} |
||||||
|
], |
||||||
|
"Cancun": [ |
||||||
|
{ |
||||||
|
"hash": "0xaa80d89bc89f58da8de41d3894bd1a241896ff91f7a5964edaefb39e8e3a4a98", |
||||||
|
"logs": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", |
||||||
|
"indexes": { |
||||||
|
"data": 0, |
||||||
|
"gas": 0, |
||||||
|
"value": 0 |
||||||
|
} |
||||||
|
} |
||||||
|
] |
||||||
|
} |
||||||
|
} |
||||||
|
}, |
||||||
|
"stdout": [ |
||||||
|
{"output":"","gasUsed":"0xd198","test":"create-eof","fork":"Prague","d":0,"g":0,"v":0,"postHash":"0x2a9c58298ba5d4ec86ca682b9fcc9ff67c3fc44dbd39f85a2f9b74bfe4e5178e","postLogsHash":"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","pass":false,"error":"Invalid EOF Layout: Expected kind 1 but read kind 17"}, |
||||||
|
{"pc":0,"op":239,"gas":"0x794068","gasCost":"0x0","memSize":0,"stack":[],"depth":1,"refund":0,"opName":"INVALID","error":"Bad instruction"}, |
||||||
|
{"output":"","gasUsed":"0x7a1200","test":"create-eof","fork":"Cancun","d":0,"g":0,"v":0,"postHash":"0xaa80d89bc89f58da8de41d3894bd1a241896ff91f7a5964edaefb39e8e3a4a98","postLogsHash":"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","pass":true,"error":"INVALID_OPERATION"} |
||||||
|
] |
||||||
|
} |
@ -0,0 +1,25 @@ |
|||||||
|
{ |
||||||
|
"cli": [ |
||||||
|
"--notime", |
||||||
|
"--json", |
||||||
|
"--create", |
||||||
|
"--code", |
||||||
|
"ef00010100040200010009030001001404000000008000035f355f5fa15f5fee00ef00010100040200010001040000000080000000c0de471fe5", |
||||||
|
"--coinbase", |
||||||
|
"4444588443C3A91288C5002483449ABA1054192B", |
||||||
|
"--fork", |
||||||
|
"pragueeof" |
||||||
|
], |
||||||
|
"stdin": "", |
||||||
|
"stdout": [ |
||||||
|
{"pc":0,"section":0,"op":95,"gas":"0x2540be400","gasCost":"0x2","memSize":0,"stack":[],"depth":1,"refund":0,"opName":"PUSH0"}, |
||||||
|
{"pc":1,"section":0,"op":53,"gas":"0x2540be3fe","gasCost":"0x3","memSize":0,"stack":["0x0"],"depth":1,"refund":0,"opName":"CALLDATALOAD"}, |
||||||
|
{"pc":2,"section":0,"op":95,"gas":"0x2540be3fb","gasCost":"0x2","memSize":0,"stack":["0xc0de471fe5000000000000000000000000000000000000000000000000000000"],"depth":1,"refund":0,"opName":"PUSH0"}, |
||||||
|
{"pc":3,"section":0,"op":95,"gas":"0x2540be3f9","gasCost":"0x2","memSize":0,"stack":["0xc0de471fe5000000000000000000000000000000000000000000000000000000","0x0"],"depth":1,"refund":0,"opName":"PUSH0"}, |
||||||
|
{"pc":4,"section":0,"op":161,"gas":"0x2540be3f7","gasCost":"0x2ee","memSize":0,"stack":["0xc0de471fe5000000000000000000000000000000000000000000000000000000","0x0","0x0"],"depth":1,"refund":0,"opName":"LOG1"}, |
||||||
|
{"pc":5,"section":0,"op":95,"gas":"0x2540be109","gasCost":"0x2","memSize":0,"stack":[],"depth":1,"refund":0,"opName":"PUSH0"}, |
||||||
|
{"pc":6,"section":0,"op":95,"gas":"0x2540be107","gasCost":"0x2","memSize":0,"stack":["0x0"],"depth":1,"refund":0,"opName":"PUSH0"}, |
||||||
|
{"pc":7,"section":0,"op":238,"immediate":"0x00","gas":"0x2540be105","gasCost":"0x0","memSize":0,"stack":["0x0","0x0"],"depth":1,"refund":0,"opName":"RETURNCONTRACT"}, |
||||||
|
{"gasUser":"0x129b","gasTotal":"0x129b","output":"0x"} |
||||||
|
] |
||||||
|
} |
@ -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.ethereum.referencetests; |
||||||
|
|
||||||
|
import java.util.NavigableMap; |
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonCreator; |
||||||
|
import com.fasterxml.jackson.annotation.JsonIgnoreProperties; |
||||||
|
import com.fasterxml.jackson.annotation.JsonProperty; |
||||||
|
|
||||||
|
@JsonIgnoreProperties(ignoreUnknown = true) |
||||||
|
public class EOFTestCaseSpec { |
||||||
|
|
||||||
|
public record TestVector( |
||||||
|
@JsonProperty("code") String code, |
||||||
|
@JsonProperty("results") NavigableMap<String, TestResult> results) {} |
||||||
|
|
||||||
|
public record TestResult( |
||||||
|
@JsonProperty("exception") String exception, @JsonProperty("result") boolean result) { |
||||||
|
public static TestResult TEST_RESULT_PASSED = new TestResult(null, true); |
||||||
|
|
||||||
|
public static TestResult failed(final String exception) { |
||||||
|
return new TestResult(exception, false); |
||||||
|
} |
||||||
|
|
||||||
|
public static TestResult passed() { |
||||||
|
return TEST_RESULT_PASSED; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
NavigableMap<String, TestVector> vector; |
||||||
|
|
||||||
|
@JsonCreator |
||||||
|
public EOFTestCaseSpec(@JsonProperty("vectors") final NavigableMap<String, TestVector> vector) { |
||||||
|
this.vector = vector; |
||||||
|
} |
||||||
|
|
||||||
|
public NavigableMap<String, TestVector> getVector() { |
||||||
|
return vector; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,142 @@ |
|||||||
|
/* |
||||||
|
* 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.eof; |
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat; |
||||||
|
|
||||||
|
import java.nio.file.Path; |
||||||
|
import java.util.Arrays; |
||||||
|
import java.util.Collection; |
||||||
|
import java.util.List; |
||||||
|
import java.util.Map; |
||||||
|
import org.apache.tuweni.bytes.Bytes; |
||||||
|
import org.hyperledger.besu.ethereum.referencetests.EOFTestCaseSpec; |
||||||
|
import org.hyperledger.besu.evm.Code; |
||||||
|
import org.hyperledger.besu.evm.EvmSpecVersion; |
||||||
|
import org.hyperledger.besu.evm.code.CodeFactory; |
||||||
|
import org.hyperledger.besu.evm.code.CodeInvalid; |
||||||
|
import org.hyperledger.besu.evm.code.CodeV1; |
||||||
|
import org.hyperledger.besu.evm.code.CodeV1Validation; |
||||||
|
import org.hyperledger.besu.evm.code.EOFLayout; |
||||||
|
import org.hyperledger.besu.testutil.JsonTestParameters; |
||||||
|
|
||||||
|
public class EOFReferenceTestTools { |
||||||
|
private static final List<String> EIPS_TO_RUN; |
||||||
|
|
||||||
|
static { |
||||||
|
final String eips = |
||||||
|
System.getProperty("test.ethereum.eof.eips", "Prague,Osaka,Amsterdam,Bogota,Polis,Bangkok"); |
||||||
|
EIPS_TO_RUN = Arrays.asList(eips.split(",")); |
||||||
|
} |
||||||
|
|
||||||
|
private static final JsonTestParameters<?, ?> params = |
||||||
|
JsonTestParameters.create(EOFTestCaseSpec.class, EOFTestCaseSpec.TestResult.class) |
||||||
|
.generator( |
||||||
|
(testName, fullPath, eofSpec, collector) -> { |
||||||
|
final Path path = Path.of(fullPath).getParent().getFileName(); |
||||||
|
final String prefix = path + "/" + testName + "-"; |
||||||
|
for (final Map.Entry<String, EOFTestCaseSpec.TestVector> entry : |
||||||
|
eofSpec.getVector().entrySet()) { |
||||||
|
final String name = entry.getKey(); |
||||||
|
final Bytes code = Bytes.fromHexString(entry.getValue().code()); |
||||||
|
for (final var result : entry.getValue().results().entrySet()) { |
||||||
|
final String eip = result.getKey(); |
||||||
|
final boolean runTest = EIPS_TO_RUN.contains(eip); |
||||||
|
collector.add( |
||||||
|
prefix + eip + '[' + name + ']', |
||||||
|
fullPath, |
||||||
|
eip, |
||||||
|
code, |
||||||
|
result.getValue(), |
||||||
|
runTest); |
||||||
|
} |
||||||
|
} |
||||||
|
}); |
||||||
|
|
||||||
|
static { |
||||||
|
if (EIPS_TO_RUN.isEmpty()) { |
||||||
|
params.ignoreAll(); |
||||||
|
} |
||||||
|
|
||||||
|
// TXCREATE still in tests, but has been removed
|
||||||
|
params.ignore("EOF1_undefined_opcodes_186"); |
||||||
|
} |
||||||
|
|
||||||
|
private EOFReferenceTestTools() { |
||||||
|
// utility class
|
||||||
|
} |
||||||
|
|
||||||
|
//
|
||||||
|
public static Collection<Object[]> generateTestParametersForConfig(final String[] filePath) { |
||||||
|
return params.generate(filePath); |
||||||
|
} |
||||||
|
|
||||||
|
public static void executeTest( |
||||||
|
final String fork, final Bytes code, final EOFTestCaseSpec.TestResult expected) { |
||||||
|
EvmSpecVersion evmVersion = EvmSpecVersion.fromName(fork); |
||||||
|
assertThat(evmVersion).isNotNull(); |
||||||
|
|
||||||
|
// hardwire in the magic byte transaction checks
|
||||||
|
if (evmVersion.getMaxEofVersion() < 1) { |
||||||
|
assertThat(expected.exception()).isEqualTo("EOF_InvalidCode"); |
||||||
|
} else { |
||||||
|
EOFLayout layout = EOFLayout.parseEOF(code); |
||||||
|
|
||||||
|
if (layout.isValid()) { |
||||||
|
Code parsedCode = CodeFactory.createCode(code, evmVersion.getMaxEofVersion()); |
||||||
|
assertThat(parsedCode.isValid()) |
||||||
|
.withFailMessage( |
||||||
|
() -> |
||||||
|
EOFLayout.parseEOF(code).prettyPrint() |
||||||
|
+ "\nExpected exception :" |
||||||
|
+ expected.exception() |
||||||
|
+ " actual exception :" |
||||||
|
+ (parsedCode.isValid() |
||||||
|
? null |
||||||
|
: ((CodeInvalid) parsedCode).getInvalidReason())) |
||||||
|
.isEqualTo(expected.result()); |
||||||
|
if (parsedCode instanceof CodeV1 codeV1) { |
||||||
|
var deepValidate = CodeV1Validation.validate(codeV1.getEofLayout()); |
||||||
|
assertThat(deepValidate) |
||||||
|
.withFailMessage( |
||||||
|
() -> |
||||||
|
codeV1.prettyPrint() |
||||||
|
+ "\nExpected exception :" |
||||||
|
+ expected.exception() |
||||||
|
+ " actual exception :" |
||||||
|
+ (parsedCode.isValid() ? null : deepValidate)) |
||||||
|
.isNull(); |
||||||
|
} |
||||||
|
|
||||||
|
if (expected.result()) { |
||||||
|
System.out.println(code); |
||||||
|
System.out.println(layout.writeContainer(null)); |
||||||
|
assertThat(code) |
||||||
|
.withFailMessage("Container round trip failed") |
||||||
|
.isEqualTo(layout.writeContainer(null)); |
||||||
|
} |
||||||
|
} else { |
||||||
|
assertThat(layout.isValid()) |
||||||
|
.withFailMessage( |
||||||
|
() -> |
||||||
|
"Expected exception - " |
||||||
|
+ expected.exception() |
||||||
|
+ " actual exception - " |
||||||
|
+ (layout.isValid() ? null : layout.invalidReason())) |
||||||
|
.isEqualTo(expected.result()); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,42 @@ |
|||||||
|
package org.hyperledger.besu.ethereum.vm.eof; |
||||||
|
|
||||||
|
import static org.hyperledger.besu.ethereum.eof.EOFReferenceTestTools.executeTest; |
||||||
|
import static org.hyperledger.besu.ethereum.eof.EOFReferenceTestTools.generateTestParametersForConfig; |
||||||
|
import static org.junit.jupiter.api.Assumptions.assumeTrue; |
||||||
|
|
||||||
|
import org.hyperledger.besu.ethereum.referencetests.EOFTestCaseSpec; |
||||||
|
|
||||||
|
import java.util.Arrays; |
||||||
|
import java.util.stream.Stream; |
||||||
|
|
||||||
|
import org.apache.tuweni.bytes.Bytes; |
||||||
|
import org.junit.jupiter.params.ParameterizedTest; |
||||||
|
import org.junit.jupiter.params.provider.Arguments; |
||||||
|
import org.junit.jupiter.params.provider.MethodSource; |
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assumptions.assumeTrue; |
||||||
|
|
||||||
|
/** The general state test operation testing framework entry point. */ |
||||||
|
public class %%TESTS_NAME%% { |
||||||
|
|
||||||
|
private static final String[] TEST_CONFIG_FILE_DIR_PATH = |
||||||
|
new String[] { |
||||||
|
%%TESTS_FILE%% |
||||||
|
}; |
||||||
|
|
||||||
|
public static Stream<Arguments> getTestParametersForConfig() { |
||||||
|
return generateTestParametersForConfig(TEST_CONFIG_FILE_DIR_PATH).stream().map(Arguments::of); |
||||||
|
} |
||||||
|
|
||||||
|
@ParameterizedTest(name = "Name: {0}") |
||||||
|
@MethodSource("getTestParametersForConfig") |
||||||
|
public void execution( |
||||||
|
final String name, |
||||||
|
final String fork, |
||||||
|
final Bytes code, |
||||||
|
final EOFTestCaseSpec.TestResult results, |
||||||
|
final boolean runTest) { |
||||||
|
assumeTrue(runTest, "Test " + name + " was ignored"); |
||||||
|
executeTest(fork, code, results); |
||||||
|
} |
||||||
|
} |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,336 @@ |
|||||||
|
/* |
||||||
|
* 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 com.google.common.base.Preconditions; |
||||||
|
|
||||||
|
/** |
||||||
|
* Information about opcodes. Currently merges Legacy and EOFv1 |
||||||
|
* |
||||||
|
* @param name formal name of the opcode, such as STOP |
||||||
|
* @param opcode the number of the opcode |
||||||
|
* @param valid Is this a valid opcode (from an EOFV1 perspective) |
||||||
|
* @param terminal Is this opcode terminal? (i.e. can it end a code section) |
||||||
|
* @param inputs How many stack inputs are required/consumed? |
||||||
|
* @param outputs How many stack items will be output? |
||||||
|
* @param stackDelta What is the net difference in stack height from this operation |
||||||
|
* @param pcAdvance How far should the PC advance (0 for terminal only, 1 for most, 2+ for opcodes |
||||||
|
* with immediates) |
||||||
|
*/ |
||||||
|
public record OpcodeInfo( |
||||||
|
String name, |
||||||
|
int opcode, |
||||||
|
boolean valid, |
||||||
|
boolean terminal, |
||||||
|
int inputs, |
||||||
|
int outputs, |
||||||
|
int stackDelta, |
||||||
|
int pcAdvance) { |
||||||
|
static OpcodeInfo unallocatedOpcode(final int opcode) { |
||||||
|
return new OpcodeInfo("-", opcode, false, false, 0, 0, 0, 1); |
||||||
|
} |
||||||
|
|
||||||
|
static OpcodeInfo invalidOpcode(final String name, final int opcode) { |
||||||
|
return new OpcodeInfo(name, opcode, false, false, 0, 0, 0, 1); |
||||||
|
} |
||||||
|
|
||||||
|
static OpcodeInfo terminalOpcode( |
||||||
|
final String name, |
||||||
|
final int opcode, |
||||||
|
final int inputs, |
||||||
|
final int outputs, |
||||||
|
final int pcAdvance) { |
||||||
|
return new OpcodeInfo(name, opcode, true, true, inputs, outputs, outputs - inputs, pcAdvance); |
||||||
|
} |
||||||
|
|
||||||
|
static OpcodeInfo validOpcode( |
||||||
|
final String name, |
||||||
|
final int opcode, |
||||||
|
final int inputs, |
||||||
|
final int outputs, |
||||||
|
final int pcAdvance) { |
||||||
|
return new OpcodeInfo(name, opcode, true, false, inputs, outputs, outputs - inputs, pcAdvance); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Gets the opcode info for a specific opcode |
||||||
|
* |
||||||
|
* @param i opcode |
||||||
|
* @return the OpcodeInfo object describing that opcode |
||||||
|
*/ |
||||||
|
public static OpcodeInfo getOpcode(final int i) { |
||||||
|
Preconditions.checkArgument(i >= 0 && i <= 255); |
||||||
|
return V1_OPCODES[i]; |
||||||
|
} |
||||||
|
|
||||||
|
static final OpcodeInfo[] V1_OPCODES = { |
||||||
|
OpcodeInfo.terminalOpcode("STOP", 0x00, 0, 0, 1), |
||||||
|
OpcodeInfo.validOpcode("ADD", 0x01, 2, 1, 1), |
||||||
|
OpcodeInfo.validOpcode("MUL", 0x02, 2, 1, 1), |
||||||
|
OpcodeInfo.validOpcode("SUB", 0x03, 2, 1, 1), |
||||||
|
OpcodeInfo.validOpcode("DIV", 0x04, 2, 1, 1), |
||||||
|
OpcodeInfo.validOpcode("SDIV", 0x05, 2, 1, 1), |
||||||
|
OpcodeInfo.validOpcode("MOD", 0x06, 2, 1, 1), |
||||||
|
OpcodeInfo.validOpcode("SMOD", 0x07, 2, 1, 1), |
||||||
|
OpcodeInfo.validOpcode("ADDMOD", 0x08, 3, 1, 1), |
||||||
|
OpcodeInfo.validOpcode("MULMOD", 0x09, 3, 1, 1), |
||||||
|
OpcodeInfo.validOpcode("EXP", 0x0a, 2, 1, 1), |
||||||
|
OpcodeInfo.validOpcode("SIGNEXTEND", 0x0b, 2, 1, 1), |
||||||
|
OpcodeInfo.unallocatedOpcode(0x0c), |
||||||
|
OpcodeInfo.unallocatedOpcode(0x0d), |
||||||
|
OpcodeInfo.unallocatedOpcode(0x0e), |
||||||
|
OpcodeInfo.unallocatedOpcode(0x0f), |
||||||
|
OpcodeInfo.validOpcode("LT", 0x10, 2, 1, 1), |
||||||
|
OpcodeInfo.validOpcode("GT", 0x11, 2, 1, 1), |
||||||
|
OpcodeInfo.validOpcode("SLT", 0x12, 2, 1, 1), |
||||||
|
OpcodeInfo.validOpcode("SGT", 0x13, 2, 1, 1), |
||||||
|
OpcodeInfo.validOpcode("EQ", 0x14, 2, 1, 1), |
||||||
|
OpcodeInfo.validOpcode("ISZERO", 0x15, 1, 1, 1), |
||||||
|
OpcodeInfo.validOpcode("AND", 0x16, 2, 1, 1), |
||||||
|
OpcodeInfo.validOpcode("OR", 0x17, 2, 1, 1), |
||||||
|
OpcodeInfo.validOpcode("XOR", 0x18, 2, 1, 1), |
||||||
|
OpcodeInfo.validOpcode("NOT", 0x19, 1, 1, 1), |
||||||
|
OpcodeInfo.validOpcode("BYTE", 0x1a, 2, 1, 1), |
||||||
|
OpcodeInfo.validOpcode("SHL", 0x1b, 2, 1, 1), |
||||||
|
OpcodeInfo.validOpcode("SHR", 0x1c, 2, 1, 1), |
||||||
|
OpcodeInfo.validOpcode("SAR", 0x1d, 2, 1, 1), |
||||||
|
OpcodeInfo.unallocatedOpcode(0x1e), |
||||||
|
OpcodeInfo.unallocatedOpcode(0x1f), |
||||||
|
OpcodeInfo.validOpcode("SHA3", 0x20, 2, 1, 1), |
||||||
|
OpcodeInfo.unallocatedOpcode(0x21), |
||||||
|
OpcodeInfo.unallocatedOpcode(0x22), |
||||||
|
OpcodeInfo.unallocatedOpcode(0x23), |
||||||
|
OpcodeInfo.unallocatedOpcode(0x24), |
||||||
|
OpcodeInfo.unallocatedOpcode(0x25), |
||||||
|
OpcodeInfo.unallocatedOpcode(0x26), |
||||||
|
OpcodeInfo.unallocatedOpcode(0x27), |
||||||
|
OpcodeInfo.unallocatedOpcode(0x28), |
||||||
|
OpcodeInfo.unallocatedOpcode(0x29), |
||||||
|
OpcodeInfo.unallocatedOpcode(0x2a), |
||||||
|
OpcodeInfo.unallocatedOpcode(0x2b), |
||||||
|
OpcodeInfo.unallocatedOpcode(0x2c), |
||||||
|
OpcodeInfo.unallocatedOpcode(0x2d), |
||||||
|
OpcodeInfo.unallocatedOpcode(0x2e), |
||||||
|
OpcodeInfo.unallocatedOpcode(0x2f), |
||||||
|
OpcodeInfo.validOpcode("ADDRESS", 0x30, 0, 1, 1), |
||||||
|
OpcodeInfo.validOpcode("BALANCE", 0x31, 1, 1, 1), |
||||||
|
OpcodeInfo.validOpcode("ORIGIN", 0x32, 0, 1, 1), |
||||||
|
OpcodeInfo.validOpcode("CALLER", 0x33, 0, 1, 1), |
||||||
|
OpcodeInfo.validOpcode("CALLVALUE", 0x34, 0, 1, 1), |
||||||
|
OpcodeInfo.validOpcode("CALLDATALOAD", 0x35, 1, 1, 1), |
||||||
|
OpcodeInfo.validOpcode("CALLDATASIZE", 0x36, 0, 1, 1), |
||||||
|
OpcodeInfo.validOpcode("CALLDATACOPY", 0x37, 3, 0, 1), |
||||||
|
OpcodeInfo.invalidOpcode("CODESIZE", 0x38), |
||||||
|
OpcodeInfo.invalidOpcode("CODECOPY", 0x39), |
||||||
|
OpcodeInfo.validOpcode("GASPRICE", 0x3a, 0, 1, 1), |
||||||
|
OpcodeInfo.invalidOpcode("EXTCODESIZE", 0x3b), |
||||||
|
OpcodeInfo.invalidOpcode("EXTCODECOPY", 0x3c), |
||||||
|
OpcodeInfo.validOpcode("RETURNDATASIZE", 0x3d, 0, 1, 1), |
||||||
|
OpcodeInfo.validOpcode("RETURNDATACOPY", 0x3e, 3, 0, 1), |
||||||
|
OpcodeInfo.invalidOpcode("EXTCODEHASH", 0x3f), |
||||||
|
OpcodeInfo.validOpcode("BLOCKHASH", 0x40, 1, 1, 1), |
||||||
|
OpcodeInfo.validOpcode("COINBASE", 0x41, 0, 1, 1), |
||||||
|
OpcodeInfo.validOpcode("TIMESTAMP", 0x42, 0, 1, 1), |
||||||
|
OpcodeInfo.validOpcode("NUMBER", 0x43, 0, 1, 1), |
||||||
|
OpcodeInfo.validOpcode("PREVRANDAO", 0x44, 0, 1, 1), // was DIFFICULTY
|
||||||
|
OpcodeInfo.validOpcode("GASLIMIT", 0x45, 0, 1, 1), |
||||||
|
OpcodeInfo.validOpcode("CHAINID", 0x46, 0, 1, 1), |
||||||
|
OpcodeInfo.validOpcode("SELFBALANCE", 0x47, 0, 1, 1), |
||||||
|
OpcodeInfo.validOpcode("BASEFEE", 0x48, 0, 1, 1), |
||||||
|
OpcodeInfo.validOpcode("BLOBAHASH", 0x49, 1, 1, 1), |
||||||
|
OpcodeInfo.validOpcode("BLOBBASEFEE", 0x4a, 0, 1, 1), |
||||||
|
OpcodeInfo.unallocatedOpcode(0x4b), |
||||||
|
OpcodeInfo.unallocatedOpcode(0x4c), |
||||||
|
OpcodeInfo.unallocatedOpcode(0x4d), |
||||||
|
OpcodeInfo.unallocatedOpcode(0x4e), |
||||||
|
OpcodeInfo.unallocatedOpcode(0x4f), |
||||||
|
OpcodeInfo.validOpcode("POP", 0x50, 1, 0, 1), |
||||||
|
OpcodeInfo.validOpcode("MLOAD", 0x51, 1, 1, 1), |
||||||
|
OpcodeInfo.validOpcode("MSTORE", 0x52, 2, 0, 1), |
||||||
|
OpcodeInfo.validOpcode("MSTORE8", 0x53, 2, 0, 1), |
||||||
|
OpcodeInfo.validOpcode("SLOAD", 0x54, 1, 1, 1), |
||||||
|
OpcodeInfo.validOpcode("SSTORE", 0x55, 2, 0, 1), |
||||||
|
OpcodeInfo.invalidOpcode("JUMP", 0x56), |
||||||
|
OpcodeInfo.invalidOpcode("JUMPI", 0x57), |
||||||
|
OpcodeInfo.invalidOpcode("PC", 0x58), |
||||||
|
OpcodeInfo.validOpcode("MSIZE", 0x59, 0, 1, 1), |
||||||
|
OpcodeInfo.invalidOpcode("GAS", 0x5a), |
||||||
|
OpcodeInfo.validOpcode("NOOP", 0x5b, 0, 0, 1), // was JUMPDEST
|
||||||
|
OpcodeInfo.validOpcode("TLOAD", 0x5c, 1, 1, 1), |
||||||
|
OpcodeInfo.validOpcode("TSTORE", 0x5d, 2, 0, 1), |
||||||
|
OpcodeInfo.validOpcode("MCOPY", 0x5e, 3, 0, 1), |
||||||
|
OpcodeInfo.validOpcode("PUSH0", 0x5f, 0, 1, 1), |
||||||
|
OpcodeInfo.validOpcode("PUSH1", 0x60, 0, 1, 2), |
||||||
|
OpcodeInfo.validOpcode("PUSH2", 0x61, 0, 1, 3), |
||||||
|
OpcodeInfo.validOpcode("PUSH3", 0x62, 0, 1, 4), |
||||||
|
OpcodeInfo.validOpcode("PUSH4", 0x63, 0, 1, 5), |
||||||
|
OpcodeInfo.validOpcode("PUSH5", 0x64, 0, 1, 6), |
||||||
|
OpcodeInfo.validOpcode("PUSH6", 0x65, 0, 1, 7), |
||||||
|
OpcodeInfo.validOpcode("PUSH7", 0x66, 0, 1, 8), |
||||||
|
OpcodeInfo.validOpcode("PUSH8", 0x67, 0, 1, 9), |
||||||
|
OpcodeInfo.validOpcode("PUSH9", 0x68, 0, 1, 10), |
||||||
|
OpcodeInfo.validOpcode("PUSH10", 0x69, 0, 1, 11), |
||||||
|
OpcodeInfo.validOpcode("PUSH11", 0x6a, 0, 1, 12), |
||||||
|
OpcodeInfo.validOpcode("PUSH12", 0x6b, 0, 1, 13), |
||||||
|
OpcodeInfo.validOpcode("PUSH13", 0x6c, 0, 1, 14), |
||||||
|
OpcodeInfo.validOpcode("PUSH14", 0x6d, 0, 1, 15), |
||||||
|
OpcodeInfo.validOpcode("PUSH15", 0x6e, 0, 1, 16), |
||||||
|
OpcodeInfo.validOpcode("PUSH16", 0x6f, 0, 1, 17), |
||||||
|
OpcodeInfo.validOpcode("PUSH17", 0x70, 0, 1, 18), |
||||||
|
OpcodeInfo.validOpcode("PUSH18", 0x71, 0, 1, 19), |
||||||
|
OpcodeInfo.validOpcode("PUSH19", 0x72, 0, 1, 20), |
||||||
|
OpcodeInfo.validOpcode("PUSH20", 0x73, 0, 1, 21), |
||||||
|
OpcodeInfo.validOpcode("PUSH21", 0x74, 0, 1, 22), |
||||||
|
OpcodeInfo.validOpcode("PUSH22", 0x75, 0, 1, 23), |
||||||
|
OpcodeInfo.validOpcode("PUSH23", 0x76, 0, 1, 24), |
||||||
|
OpcodeInfo.validOpcode("PUSH24", 0x77, 0, 1, 25), |
||||||
|
OpcodeInfo.validOpcode("PUSH25", 0x78, 0, 1, 26), |
||||||
|
OpcodeInfo.validOpcode("PUSH26", 0x79, 0, 1, 27), |
||||||
|
OpcodeInfo.validOpcode("PUSH27", 0x7a, 0, 1, 28), |
||||||
|
OpcodeInfo.validOpcode("PUSH28", 0x7b, 0, 1, 29), |
||||||
|
OpcodeInfo.validOpcode("PUSH29", 0x7c, 0, 1, 30), |
||||||
|
OpcodeInfo.validOpcode("PUSH30", 0x7d, 0, 1, 31), |
||||||
|
OpcodeInfo.validOpcode("PUSH31", 0x7e, 0, 1, 32), |
||||||
|
OpcodeInfo.validOpcode("PUSH32", 0x7f, 0, 1, 33), |
||||||
|
OpcodeInfo.validOpcode("DUP1", 0x80, 1, 2, 1), |
||||||
|
OpcodeInfo.validOpcode("DUP2", 0x81, 2, 3, 1), |
||||||
|
OpcodeInfo.validOpcode("DUP3", 0x82, 3, 4, 1), |
||||||
|
OpcodeInfo.validOpcode("DUP4", 0x83, 4, 5, 1), |
||||||
|
OpcodeInfo.validOpcode("DUP5", 0x84, 5, 6, 1), |
||||||
|
OpcodeInfo.validOpcode("DUP6", 0x85, 6, 7, 1), |
||||||
|
OpcodeInfo.validOpcode("DUP7", 0x86, 7, 8, 1), |
||||||
|
OpcodeInfo.validOpcode("DUP8", 0x87, 8, 9, 1), |
||||||
|
OpcodeInfo.validOpcode("DUP9", 0x88, 9, 10, 1), |
||||||
|
OpcodeInfo.validOpcode("DUP10", 0x89, 10, 11, 1), |
||||||
|
OpcodeInfo.validOpcode("DUP11", 0x8a, 11, 12, 1), |
||||||
|
OpcodeInfo.validOpcode("DUP12", 0x8b, 12, 13, 1), |
||||||
|
OpcodeInfo.validOpcode("DUP13", 0x8c, 13, 14, 1), |
||||||
|
OpcodeInfo.validOpcode("DUP14", 0x8d, 14, 15, 1), |
||||||
|
OpcodeInfo.validOpcode("DUP15", 0x8e, 15, 16, 1), |
||||||
|
OpcodeInfo.validOpcode("DUP16", 0x8f, 16, 17, 1), |
||||||
|
OpcodeInfo.validOpcode("SWAP1", 0x90, 2, 2, 1), |
||||||
|
OpcodeInfo.validOpcode("SWAP2", 0x91, 3, 3, 1), |
||||||
|
OpcodeInfo.validOpcode("SWAP3", 0x92, 4, 4, 1), |
||||||
|
OpcodeInfo.validOpcode("SWAP4", 0x93, 5, 5, 1), |
||||||
|
OpcodeInfo.validOpcode("SWAP5", 0x94, 6, 6, 1), |
||||||
|
OpcodeInfo.validOpcode("SWAP6", 0x95, 7, 7, 1), |
||||||
|
OpcodeInfo.validOpcode("SWAP7", 0x96, 8, 8, 1), |
||||||
|
OpcodeInfo.validOpcode("SWAP8", 0x97, 9, 9, 1), |
||||||
|
OpcodeInfo.validOpcode("SWAP9", 0x98, 10, 10, 1), |
||||||
|
OpcodeInfo.validOpcode("SWAP10", 0x99, 11, 11, 1), |
||||||
|
OpcodeInfo.validOpcode("SWAP11", 0x9a, 12, 12, 1), |
||||||
|
OpcodeInfo.validOpcode("SWAP12", 0x9b, 13, 13, 1), |
||||||
|
OpcodeInfo.validOpcode("SWAP13", 0x9c, 14, 14, 1), |
||||||
|
OpcodeInfo.validOpcode("SWAP14", 0x9d, 15, 15, 1), |
||||||
|
OpcodeInfo.validOpcode("SWAP15", 0x9e, 16, 16, 1), |
||||||
|
OpcodeInfo.validOpcode("SWAP16", 0x9f, 17, 17, 1), |
||||||
|
OpcodeInfo.validOpcode("LOG0", 0xa0, 2, 0, 1), |
||||||
|
OpcodeInfo.validOpcode("LOG1", 0xa1, 3, 0, 1), |
||||||
|
OpcodeInfo.validOpcode("LOG2", 0xa2, 4, 0, 1), |
||||||
|
OpcodeInfo.validOpcode("LOG3", 0xa3, 5, 0, 1), |
||||||
|
OpcodeInfo.validOpcode("LOG4", 0xa4, 6, 0, 1), |
||||||
|
OpcodeInfo.unallocatedOpcode(0xa5), |
||||||
|
OpcodeInfo.unallocatedOpcode(0xa6), |
||||||
|
OpcodeInfo.unallocatedOpcode(0xa7), |
||||||
|
OpcodeInfo.unallocatedOpcode(0xa8), |
||||||
|
OpcodeInfo.unallocatedOpcode(0xa9), |
||||||
|
OpcodeInfo.unallocatedOpcode(0xaa), |
||||||
|
OpcodeInfo.unallocatedOpcode(0xab), |
||||||
|
OpcodeInfo.unallocatedOpcode(0xac), |
||||||
|
OpcodeInfo.unallocatedOpcode(0xad), |
||||||
|
OpcodeInfo.unallocatedOpcode(0xae), |
||||||
|
OpcodeInfo.unallocatedOpcode(0xaf), |
||||||
|
OpcodeInfo.unallocatedOpcode(0xb0), |
||||||
|
OpcodeInfo.unallocatedOpcode(0xb1), |
||||||
|
OpcodeInfo.unallocatedOpcode(0xb2), |
||||||
|
OpcodeInfo.unallocatedOpcode(0xb3), |
||||||
|
OpcodeInfo.unallocatedOpcode(0xb4), |
||||||
|
OpcodeInfo.unallocatedOpcode(0xb5), |
||||||
|
OpcodeInfo.unallocatedOpcode(0xb6), |
||||||
|
OpcodeInfo.unallocatedOpcode(0xb7), |
||||||
|
OpcodeInfo.unallocatedOpcode(0xb8), |
||||||
|
OpcodeInfo.unallocatedOpcode(0xb9), |
||||||
|
OpcodeInfo.unallocatedOpcode(0xba), |
||||||
|
OpcodeInfo.unallocatedOpcode(0xbb), |
||||||
|
OpcodeInfo.unallocatedOpcode(0xbc), |
||||||
|
OpcodeInfo.unallocatedOpcode(0xbd), |
||||||
|
OpcodeInfo.unallocatedOpcode(0xbe), |
||||||
|
OpcodeInfo.unallocatedOpcode(0xbf), |
||||||
|
OpcodeInfo.unallocatedOpcode(0xc0), |
||||||
|
OpcodeInfo.unallocatedOpcode(0xc1), |
||||||
|
OpcodeInfo.unallocatedOpcode(0xc2), |
||||||
|
OpcodeInfo.unallocatedOpcode(0xc3), |
||||||
|
OpcodeInfo.unallocatedOpcode(0xc4), |
||||||
|
OpcodeInfo.unallocatedOpcode(0xc5), |
||||||
|
OpcodeInfo.unallocatedOpcode(0xc6), |
||||||
|
OpcodeInfo.unallocatedOpcode(0xc7), |
||||||
|
OpcodeInfo.unallocatedOpcode(0xc8), |
||||||
|
OpcodeInfo.unallocatedOpcode(0xc9), |
||||||
|
OpcodeInfo.unallocatedOpcode(0xca), |
||||||
|
OpcodeInfo.unallocatedOpcode(0xcb), |
||||||
|
OpcodeInfo.unallocatedOpcode(0xcc), |
||||||
|
OpcodeInfo.unallocatedOpcode(0xcd), |
||||||
|
OpcodeInfo.unallocatedOpcode(0xce), |
||||||
|
OpcodeInfo.unallocatedOpcode(0xcf), |
||||||
|
OpcodeInfo.validOpcode("DATALOAD", 0xd0, 1, 1, 1), |
||||||
|
OpcodeInfo.validOpcode("DATALOADN", 0xd1, 0, 1, 3), |
||||||
|
OpcodeInfo.validOpcode("DATASIZE", 0xd2, 0, 1, 1), |
||||||
|
OpcodeInfo.validOpcode("DATACOPY", 0xd3, 3, 0, 1), |
||||||
|
OpcodeInfo.unallocatedOpcode(0xd4), |
||||||
|
OpcodeInfo.unallocatedOpcode(0xd5), |
||||||
|
OpcodeInfo.unallocatedOpcode(0xd6), |
||||||
|
OpcodeInfo.unallocatedOpcode(0xd7), |
||||||
|
OpcodeInfo.unallocatedOpcode(0xd8), |
||||||
|
OpcodeInfo.unallocatedOpcode(0xd9), |
||||||
|
OpcodeInfo.unallocatedOpcode(0xda), |
||||||
|
OpcodeInfo.unallocatedOpcode(0xdb), |
||||||
|
OpcodeInfo.unallocatedOpcode(0xdc), |
||||||
|
OpcodeInfo.unallocatedOpcode(0xdd), |
||||||
|
OpcodeInfo.unallocatedOpcode(0xde), |
||||||
|
OpcodeInfo.unallocatedOpcode(0xdf), |
||||||
|
OpcodeInfo.terminalOpcode("RJUMP", 0xe0, 0, 0, 3), |
||||||
|
OpcodeInfo.validOpcode("RJUMPI", 0xe1, 1, 0, 3), |
||||||
|
OpcodeInfo.validOpcode("RJUMPV", 0xe2, 1, 0, 2), |
||||||
|
OpcodeInfo.validOpcode("CALLF", 0xe3, 0, 0, 3), |
||||||
|
OpcodeInfo.terminalOpcode("RETF", 0xe4, 0, 0, 1), |
||||||
|
OpcodeInfo.terminalOpcode("JUMPF", 0xe5, 0, 0, 3), |
||||||
|
OpcodeInfo.validOpcode("DUPN", 0xe6, 0, 1, 2), |
||||||
|
OpcodeInfo.validOpcode("SWAPN", 0xe7, 0, 0, 2), |
||||||
|
OpcodeInfo.validOpcode("EXCHANGE", 0xe8, 0, 0, 2), |
||||||
|
OpcodeInfo.unallocatedOpcode(0xe9), |
||||||
|
OpcodeInfo.unallocatedOpcode(0xea), |
||||||
|
OpcodeInfo.unallocatedOpcode(0xeb), |
||||||
|
OpcodeInfo.validOpcode("EOFCREATE", 0xec, 4, 1, 2), |
||||||
|
OpcodeInfo.unallocatedOpcode(0xed), |
||||||
|
OpcodeInfo.terminalOpcode("RETURNCONTRACT", 0xee, 2, 1, 2), |
||||||
|
OpcodeInfo.unallocatedOpcode(0xef), |
||||||
|
OpcodeInfo.invalidOpcode("CREATE", 0xf0), |
||||||
|
OpcodeInfo.invalidOpcode("CALL", 0xf1), |
||||||
|
OpcodeInfo.invalidOpcode("CALLCODE", 0xf2), |
||||||
|
OpcodeInfo.terminalOpcode("RETURN", 0xf3, 2, 0, 1), |
||||||
|
OpcodeInfo.invalidOpcode("DELEGATECALL", 0xf4), |
||||||
|
OpcodeInfo.invalidOpcode("CREATE2", 0xf5), |
||||||
|
OpcodeInfo.unallocatedOpcode(0xf6), |
||||||
|
OpcodeInfo.validOpcode("RETURNDATALOAD", 0xf7, 1, 1, 1), |
||||||
|
OpcodeInfo.validOpcode("EXTCALL", 0xf8, 4, 1, 1), |
||||||
|
OpcodeInfo.validOpcode("EXTDELEGATECALL", 0xf9, 3, 1, 1), |
||||||
|
OpcodeInfo.invalidOpcode("STATICCALL", 0xfa), |
||||||
|
OpcodeInfo.validOpcode("EXTSTATICCALL", 0xfb, 3, 1, 1), |
||||||
|
OpcodeInfo.unallocatedOpcode(0xfc), |
||||||
|
OpcodeInfo.terminalOpcode("REVERT", 0xfd, 2, 0, 1), |
||||||
|
OpcodeInfo.terminalOpcode("INVALID", 0xfe, 0, 0, 1), |
||||||
|
OpcodeInfo.invalidOpcode("SELFDESTRUCT", 0xff), |
||||||
|
}; |
||||||
|
} |
@ -0,0 +1,95 @@ |
|||||||
|
/* |
||||||
|
* 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; |
||||||
|
|
||||||
|
/** |
||||||
|
* A work list, allowing a DAG to be evaluated while detecting disconnected sections. |
||||||
|
* |
||||||
|
* <p>When an item is marked if it has not been marked it is added to the work list. `take()` |
||||||
|
* returns the fist item that has not yet been returned from a take, or `-1` if no items are |
||||||
|
* available. Items are added by calling `put(int)`, which is idempotent. Items can be put several |
||||||
|
* times but will only be taken once. |
||||||
|
* |
||||||
|
* <p>`isComplete()` checks if all items have been taken. `getFirstUnmarkedItem()` is used when |
||||||
|
* reporting errors to identify an unconnected item. |
||||||
|
*/ |
||||||
|
class WorkList { |
||||||
|
boolean[] marked; |
||||||
|
int[] items; |
||||||
|
int nextIndex; |
||||||
|
int listEnd; |
||||||
|
|
||||||
|
/** |
||||||
|
* Create a work list of the appropriate size. The list is empty. |
||||||
|
* |
||||||
|
* @param size number of possible items |
||||||
|
*/ |
||||||
|
WorkList(final int size) { |
||||||
|
marked = new boolean[size]; |
||||||
|
items = new int[size]; |
||||||
|
nextIndex = 0; |
||||||
|
listEnd = -1; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Take the next item, if available |
||||||
|
* |
||||||
|
* @return the item number, or -1 if no items are available. |
||||||
|
*/ |
||||||
|
int take() { |
||||||
|
if (nextIndex > listEnd) { |
||||||
|
return -1; |
||||||
|
} |
||||||
|
int result = items[nextIndex]; |
||||||
|
nextIndex++; |
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Have all items been taken? |
||||||
|
* |
||||||
|
* @return true if all items were marked and then taken |
||||||
|
*/ |
||||||
|
boolean isComplete() { |
||||||
|
return nextIndex >= items.length; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Put an item in the work list. This is idempotent, an item will only be added on the first call. |
||||||
|
* |
||||||
|
* @param item the item to add to the list. |
||||||
|
*/ |
||||||
|
void put(final int item) { |
||||||
|
if (!marked[item]) { |
||||||
|
listEnd++; |
||||||
|
items[listEnd] = item; |
||||||
|
marked[item] = true; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Walks the taken list and returns the first unmarked item |
||||||
|
* |
||||||
|
* @return the first unmarked item, or -1 if all items are marked. |
||||||
|
*/ |
||||||
|
int getFirstUnmarkedItem() { |
||||||
|
for (int i = 0; i < marked.length; i++) { |
||||||
|
if (!marked[i]) { |
||||||
|
return i; |
||||||
|
} |
||||||
|
} |
||||||
|
return -1; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,57 @@ |
|||||||
|
/* |
||||||
|
* 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.gascalculator; |
||||||
|
|
||||||
|
import static org.hyperledger.besu.datatypes.Address.BLS12_MAP_FP2_TO_G2; |
||||||
|
|
||||||
|
/** |
||||||
|
* Gas Calculator for Prague |
||||||
|
* |
||||||
|
* <p>Placeholder for new gas schedule items. If Prague finalzies without changes this can be |
||||||
|
* removed |
||||||
|
* |
||||||
|
* <UL> |
||||||
|
* <LI>TBD |
||||||
|
* </UL> |
||||||
|
*/ |
||||||
|
public class PragueEOFGasCalculator extends PragueGasCalculator { |
||||||
|
|
||||||
|
static final long MIN_RETAINED_GAS = 5_000; |
||||||
|
static final long MIN_CALLEE_GAS = 2300; |
||||||
|
|
||||||
|
/** Instantiates a new Prague Gas Calculator. */ |
||||||
|
public PragueEOFGasCalculator() { |
||||||
|
this(BLS12_MAP_FP2_TO_G2.toArrayUnsafe()[19]); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Instantiates a new Prague Gas Calculator |
||||||
|
* |
||||||
|
* @param maxPrecompile the max precompile |
||||||
|
*/ |
||||||
|
protected PragueEOFGasCalculator(final int maxPrecompile) { |
||||||
|
super(maxPrecompile); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public long getMinRetainedGas() { |
||||||
|
return MIN_RETAINED_GAS; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public long getMinCalleeGas() { |
||||||
|
return MIN_CALLEE_GAS; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,201 @@ |
|||||||
|
/* |
||||||
|
* 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.datatypes.Address; |
||||||
|
import org.hyperledger.besu.datatypes.Wei; |
||||||
|
import org.hyperledger.besu.evm.Code; |
||||||
|
import org.hyperledger.besu.evm.EVM; |
||||||
|
import org.hyperledger.besu.evm.account.Account; |
||||||
|
import org.hyperledger.besu.evm.code.CodeV0; |
||||||
|
import org.hyperledger.besu.evm.frame.ExceptionalHaltReason; |
||||||
|
import org.hyperledger.besu.evm.frame.MessageFrame; |
||||||
|
import org.hyperledger.besu.evm.gascalculator.GasCalculator; |
||||||
|
import org.hyperledger.besu.evm.internal.Words; |
||||||
|
|
||||||
|
import javax.annotation.Nonnull; |
||||||
|
|
||||||
|
import org.apache.tuweni.bytes.Bytes; |
||||||
|
|
||||||
|
/** |
||||||
|
* A skeleton class for implementing call operations. |
||||||
|
* |
||||||
|
* <p>A call operation creates a child message call from the current message context, allows it to |
||||||
|
* execute, and then updates the current message context based on its execution. |
||||||
|
*/ |
||||||
|
public abstract class AbstractExtCallOperation extends AbstractCallOperation { |
||||||
|
|
||||||
|
static final int STACK_TO = 0; |
||||||
|
|
||||||
|
/** EXT*CALL response indicating success */ |
||||||
|
public static final Bytes EOF1_SUCCESS_STACK_ITEM = Bytes.EMPTY; |
||||||
|
|
||||||
|
/** EXT*CALL response indicating a "soft failure" */ |
||||||
|
public static final Bytes EOF1_EXCEPTION_STACK_ITEM = BYTES_ONE; |
||||||
|
|
||||||
|
/** EXT*CALL response indicating a hard failure, such as a REVERT was called */ |
||||||
|
public static final Bytes EOF1_FAILURE_STACK_ITEM = Bytes.of(2); |
||||||
|
|
||||||
|
/** |
||||||
|
* Instantiates a new Abstract call operation. |
||||||
|
* |
||||||
|
* @param opcode the opcode |
||||||
|
* @param name the name |
||||||
|
* @param stackItemsConsumed the stack items consumed |
||||||
|
* @param stackItemsProduced the stack items produced |
||||||
|
* @param gasCalculator the gas calculator |
||||||
|
*/ |
||||||
|
AbstractExtCallOperation( |
||||||
|
final int opcode, |
||||||
|
final String name, |
||||||
|
final int stackItemsConsumed, |
||||||
|
final int stackItemsProduced, |
||||||
|
final GasCalculator gasCalculator) { |
||||||
|
super(opcode, name, stackItemsConsumed, stackItemsProduced, gasCalculator); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
protected Address to(final MessageFrame frame) { |
||||||
|
return Words.toAddress(frame.getStackItem(STACK_TO)); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
protected long gas(final MessageFrame frame) { |
||||||
|
return Long.MAX_VALUE; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
protected long outputDataOffset(final MessageFrame frame) { |
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
protected long outputDataLength(final MessageFrame frame) { |
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public long gasAvailableForChildCall(final MessageFrame frame) { |
||||||
|
throw new UnsupportedOperationException("EXTCALL does not use gasAvailableForChildCall"); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public OperationResult execute(final MessageFrame frame, final EVM evm) { |
||||||
|
final Bytes toBytes = frame.getStackItem(STACK_TO).trimLeadingZeros(); |
||||||
|
final Wei value = value(frame); |
||||||
|
final boolean zeroValue = value.isZero(); |
||||||
|
long inputOffset = inputDataOffset(frame); |
||||||
|
long inputLength = inputDataLength(frame); |
||||||
|
|
||||||
|
if (!zeroValue && isStatic(frame)) { |
||||||
|
return new OperationResult( |
||||||
|
gasCalculator().callValueTransferGasCost(), ExceptionalHaltReason.ILLEGAL_STATE_CHANGE); |
||||||
|
} |
||||||
|
if (toBytes.size() > Address.SIZE) { |
||||||
|
return new OperationResult( |
||||||
|
gasCalculator().memoryExpansionGasCost(frame, inputOffset, inputLength) |
||||||
|
+ (zeroValue ? 0 : gasCalculator().callValueTransferGasCost()) |
||||||
|
+ gasCalculator().getColdAccountAccessCost(), |
||||||
|
ExceptionalHaltReason.ADDRESS_OUT_OF_RANGE); |
||||||
|
} |
||||||
|
Address to = Words.toAddress(toBytes); |
||||||
|
final Account contract = frame.getWorldUpdater().get(to); |
||||||
|
boolean accountCreation = contract == null && !zeroValue; |
||||||
|
long cost = |
||||||
|
gasCalculator().memoryExpansionGasCost(frame, inputOffset, inputLength) |
||||||
|
+ (zeroValue ? 0 : gasCalculator().callValueTransferGasCost()) |
||||||
|
+ (frame.warmUpAddress(to) |
||||||
|
? gasCalculator().getWarmStorageReadCost() |
||||||
|
: gasCalculator().getColdAccountAccessCost()) |
||||||
|
+ (accountCreation ? gasCalculator().newAccountGasCost() : 0); |
||||||
|
long currentGas = frame.getRemainingGas() - cost; |
||||||
|
if (currentGas < 0) { |
||||||
|
return new OperationResult(cost, ExceptionalHaltReason.INSUFFICIENT_GAS); |
||||||
|
} |
||||||
|
|
||||||
|
final Code code = |
||||||
|
contract == null |
||||||
|
? CodeV0.EMPTY_CODE |
||||||
|
: evm.getCode(contract.getCodeHash(), contract.getCode()); |
||||||
|
|
||||||
|
// invalid code results in a quick exit
|
||||||
|
if (!code.isValid()) { |
||||||
|
return new OperationResult(cost, ExceptionalHaltReason.INVALID_CODE, 0); |
||||||
|
} |
||||||
|
|
||||||
|
// last exceptional failure, prepare for call or soft failures
|
||||||
|
frame.clearReturnData(); |
||||||
|
|
||||||
|
// delegate calls to prior EOF versions are prohibited
|
||||||
|
if (isDelegate() && frame.getCode().getEofVersion() != code.getEofVersion()) { |
||||||
|
return softFailure(frame, cost); |
||||||
|
} |
||||||
|
|
||||||
|
long retainedGas = Math.max(currentGas / 64, gasCalculator().getMinRetainedGas()); |
||||||
|
long childGas = currentGas - retainedGas; |
||||||
|
|
||||||
|
final Account account = frame.getWorldUpdater().get(frame.getRecipientAddress()); |
||||||
|
final Wei balance = (zeroValue || account == null) ? Wei.ZERO : account.getBalance(); |
||||||
|
|
||||||
|
// There myst be a minimum gas for a call to have access to.
|
||||||
|
if (childGas < gasCalculator().getMinRetainedGas()) { |
||||||
|
return softFailure(frame, cost); |
||||||
|
} |
||||||
|
// transferring value you don't have is not a halting exception, just a failure
|
||||||
|
if (!zeroValue && (value.compareTo(balance) > 0)) { |
||||||
|
return softFailure(frame, cost); |
||||||
|
} |
||||||
|
// stack too deep, for large gas systems.
|
||||||
|
if (frame.getDepth() >= 1024) { |
||||||
|
return softFailure(frame, cost); |
||||||
|
} |
||||||
|
|
||||||
|
// all checks passed, do the call
|
||||||
|
final Bytes inputData = frame.readMutableMemory(inputOffset, inputLength); |
||||||
|
|
||||||
|
MessageFrame.builder() |
||||||
|
.parentMessageFrame(frame) |
||||||
|
.type(MessageFrame.Type.MESSAGE_CALL) |
||||||
|
.initialGas(childGas) |
||||||
|
.address(address(frame)) |
||||||
|
.contract(to) |
||||||
|
.inputData(inputData) |
||||||
|
.sender(sender(frame)) |
||||||
|
.value(value(frame)) |
||||||
|
.apparentValue(apparentValue(frame)) |
||||||
|
.code(code) |
||||||
|
.isStatic(isStatic(frame)) |
||||||
|
.completer(child -> complete(frame, child)) |
||||||
|
.build(); |
||||||
|
|
||||||
|
frame.setState(MessageFrame.State.CODE_SUSPENDED); |
||||||
|
return new OperationResult(cost + childGas, null, 0); |
||||||
|
} |
||||||
|
|
||||||
|
private @Nonnull OperationResult softFailure(final MessageFrame frame, final long cost) { |
||||||
|
frame.popStackItems(getStackItemsConsumed()); |
||||||
|
frame.pushStackItem(EOF1_EXCEPTION_STACK_ITEM); |
||||||
|
return new OperationResult(cost, null); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
Bytes getCallResultStackItem(final MessageFrame childFrame) { |
||||||
|
return switch (childFrame.getState()) { |
||||||
|
case COMPLETED_SUCCESS -> EOF1_SUCCESS_STACK_ITEM; |
||||||
|
case EXCEPTIONAL_HALT -> EOF1_EXCEPTION_STACK_ITEM; |
||||||
|
default -> EOF1_FAILURE_STACK_ITEM; |
||||||
|
}; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,67 @@ |
|||||||
|
/* |
||||||
|
* Copyright contributors to Hyperledger Besu. |
||||||
|
* |
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with |
||||||
|
* the License. You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on |
||||||
|
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the |
||||||
|
* specific language governing permissions and limitations under the License. |
||||||
|
* |
||||||
|
* SPDX-License-Identifier: Apache-2.0 |
||||||
|
*/ |
||||||
|
package org.hyperledger.besu.evm.operation; |
||||||
|
|
||||||
|
import static org.hyperledger.besu.evm.internal.Words.clampedToInt; |
||||||
|
|
||||||
|
import org.hyperledger.besu.evm.Code; |
||||||
|
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; |
||||||
|
|
||||||
|
/** The Data load operation. */ |
||||||
|
public class DataCopyOperation extends AbstractOperation { |
||||||
|
|
||||||
|
/** |
||||||
|
* Instantiates a new Data Load operation. |
||||||
|
* |
||||||
|
* @param gasCalculator the gas calculator |
||||||
|
*/ |
||||||
|
public DataCopyOperation(final GasCalculator gasCalculator) { |
||||||
|
super(0xd3, "DATACOPY", 3, 1, gasCalculator); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Cost of data Copy operation. |
||||||
|
* |
||||||
|
* @param frame the frame |
||||||
|
* @param memOffset the mem offset |
||||||
|
* @param length the length |
||||||
|
* @return the long |
||||||
|
*/ |
||||||
|
protected long cost(final MessageFrame frame, final long memOffset, final long length) { |
||||||
|
return gasCalculator().getVeryLowTierGasCost() |
||||||
|
+ gasCalculator().extCodeCopyOperationGasCost(frame, memOffset, length); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public OperationResult execute(final MessageFrame frame, final EVM evm) { |
||||||
|
Code code = frame.getCode(); |
||||||
|
if (code.getEofVersion() == 0) { |
||||||
|
return InvalidOperation.INVALID_RESULT; |
||||||
|
} |
||||||
|
final int memOffset = clampedToInt(frame.popStackItem()); |
||||||
|
final int sourceOffset = clampedToInt(frame.popStackItem()); |
||||||
|
final int length = clampedToInt(frame.popStackItem()); |
||||||
|
final long cost = cost(frame, memOffset, length); |
||||||
|
|
||||||
|
final Bytes data = code.getData(sourceOffset, length); |
||||||
|
frame.writeMemory(memOffset, length, data); |
||||||
|
|
||||||
|
return new OperationResult(cost, null); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,54 @@ |
|||||||
|
/* |
||||||
|
* 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.Code; |
||||||
|
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; |
||||||
|
|
||||||
|
/** The Data load operation. */ |
||||||
|
public class DataLoadNOperation extends AbstractFixedCostOperation { |
||||||
|
|
||||||
|
/** The constant OPCODE. */ |
||||||
|
public static final int OPCODE = 0xd1; |
||||||
|
|
||||||
|
/** |
||||||
|
* Instantiates a new Data Load operation. |
||||||
|
* |
||||||
|
* @param gasCalculator the gas calculator |
||||||
|
*/ |
||||||
|
public DataLoadNOperation(final GasCalculator gasCalculator) { |
||||||
|
super(OPCODE, "DATALOADN", 0, 1, gasCalculator, gasCalculator.getVeryLowTierGasCost()); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public OperationResult executeFixedCostOperation(final MessageFrame frame, final EVM evm) { |
||||||
|
Code code = frame.getCode(); |
||||||
|
if (code.getEofVersion() == 0) { |
||||||
|
return InvalidOperation.INVALID_RESULT; |
||||||
|
} |
||||||
|
|
||||||
|
int pc = frame.getPC(); |
||||||
|
int index = code.readBigEndianU16(pc + 1); |
||||||
|
final Bytes data = code.getData(index, 32); |
||||||
|
frame.pushStackItem(data); |
||||||
|
frame.setPC(pc + 2); |
||||||
|
|
||||||
|
return successResponse; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,52 @@ |
|||||||
|
/* |
||||||
|
* Copyright contributors to Hyperledger Besu. |
||||||
|
* |
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with |
||||||
|
* the License. You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on |
||||||
|
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the |
||||||
|
* specific language governing permissions and limitations under the License. |
||||||
|
* |
||||||
|
* SPDX-License-Identifier: Apache-2.0 |
||||||
|
*/ |
||||||
|
package org.hyperledger.besu.evm.operation; |
||||||
|
|
||||||
|
import static org.hyperledger.besu.evm.internal.Words.clampedToInt; |
||||||
|
|
||||||
|
import org.hyperledger.besu.evm.Code; |
||||||
|
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; |
||||||
|
|
||||||
|
/** The Data load operation. */ |
||||||
|
public class DataLoadOperation extends AbstractFixedCostOperation { |
||||||
|
|
||||||
|
/** |
||||||
|
* Instantiates a new Data Load operation. |
||||||
|
* |
||||||
|
* @param gasCalculator the gas calculator |
||||||
|
*/ |
||||||
|
public DataLoadOperation(final GasCalculator gasCalculator) { |
||||||
|
super(0xd0, "DATALOAD", 1, 1, gasCalculator, 4); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public Operation.OperationResult executeFixedCostOperation( |
||||||
|
final MessageFrame frame, final EVM evm) { |
||||||
|
Code code = frame.getCode(); |
||||||
|
if (code.getEofVersion() == 0) { |
||||||
|
return InvalidOperation.INVALID_RESULT; |
||||||
|
} |
||||||
|
final int sourceOffset = clampedToInt(frame.popStackItem()); |
||||||
|
|
||||||
|
final Bytes data = code.getData(sourceOffset, 32); |
||||||
|
frame.pushStackItem(data); |
||||||
|
|
||||||
|
return successResponse; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,47 @@ |
|||||||
|
/* |
||||||
|
* 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.Code; |
||||||
|
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; |
||||||
|
|
||||||
|
/** The Data load operation. */ |
||||||
|
public class DataSizeOperation extends AbstractFixedCostOperation { |
||||||
|
|
||||||
|
/** |
||||||
|
* Instantiates a new Data Load operation. |
||||||
|
* |
||||||
|
* @param gasCalculator the gas calculator |
||||||
|
*/ |
||||||
|
public DataSizeOperation(final GasCalculator gasCalculator) { |
||||||
|
super(0xd2, "DATASIZE", 0, 1, gasCalculator, gasCalculator.getBaseTierGasCost()); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public OperationResult executeFixedCostOperation(final MessageFrame frame, final EVM evm) { |
||||||
|
final Code code = frame.getCode(); |
||||||
|
if (code.getEofVersion() == 0) { |
||||||
|
return InvalidOperation.INVALID_RESULT; |
||||||
|
} |
||||||
|
final int size = code.getDataSize(); |
||||||
|
frame.pushStackItem(Bytes.ofUnsignedInt(size)); |
||||||
|
|
||||||
|
return successResponse; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,55 @@ |
|||||||
|
/* |
||||||
|
* 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.Code; |
||||||
|
import org.hyperledger.besu.evm.EVM; |
||||||
|
import org.hyperledger.besu.evm.frame.MessageFrame; |
||||||
|
import org.hyperledger.besu.evm.gascalculator.GasCalculator; |
||||||
|
|
||||||
|
/** The Dup operation. */ |
||||||
|
public class DupNOperation extends AbstractFixedCostOperation { |
||||||
|
|
||||||
|
/** DUPN Opcode 0xe6 */ |
||||||
|
public static final int OPCODE = 0xe6; |
||||||
|
|
||||||
|
/** The Dup success operation result. */ |
||||||
|
static final OperationResult dupSuccess = new OperationResult(3, null); |
||||||
|
|
||||||
|
/** |
||||||
|
* Instantiates a new Dup operation. |
||||||
|
* |
||||||
|
* @param gasCalculator the gas calculator |
||||||
|
*/ |
||||||
|
public DupNOperation(final GasCalculator gasCalculator) { |
||||||
|
super(OPCODE, "DUPN", 0, 1, gasCalculator, gasCalculator.getVeryLowTierGasCost()); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public Operation.OperationResult executeFixedCostOperation( |
||||||
|
final MessageFrame frame, final EVM evm) { |
||||||
|
Code code = frame.getCode(); |
||||||
|
if (code.getEofVersion() == 0) { |
||||||
|
return InvalidOperation.INVALID_RESULT; |
||||||
|
} |
||||||
|
int pc = frame.getPC(); |
||||||
|
|
||||||
|
int depth = code.readU8(pc + 1); |
||||||
|
frame.pushStackItem(frame.getStackItem(depth)); |
||||||
|
frame.setPC(pc + 1); |
||||||
|
|
||||||
|
return dupSuccess; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,91 @@ |
|||||||
|
/* |
||||||
|
* 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.crypto.Hash.keccak256; |
||||||
|
import static org.hyperledger.besu.evm.internal.Words.clampedAdd; |
||||||
|
import static org.hyperledger.besu.evm.internal.Words.clampedToInt; |
||||||
|
import static org.hyperledger.besu.evm.internal.Words.clampedToLong; |
||||||
|
|
||||||
|
import org.hyperledger.besu.datatypes.Address; |
||||||
|
import org.hyperledger.besu.evm.Code; |
||||||
|
import org.hyperledger.besu.evm.EVM; |
||||||
|
import org.hyperledger.besu.evm.frame.MessageFrame; |
||||||
|
import org.hyperledger.besu.evm.gascalculator.GasCalculator; |
||||||
|
|
||||||
|
import java.util.function.Supplier; |
||||||
|
|
||||||
|
import org.apache.tuweni.bytes.Bytes; |
||||||
|
import org.apache.tuweni.bytes.Bytes32; |
||||||
|
|
||||||
|
/** The Create2 operation. */ |
||||||
|
public class EOFCreateOperation extends AbstractCreateOperation { |
||||||
|
|
||||||
|
/** Opcode 0xEC for operation EOFCREATE */ |
||||||
|
public static final int OPCODE = 0xec; |
||||||
|
|
||||||
|
private static final Bytes PREFIX = Bytes.fromHexString("0xFF"); |
||||||
|
|
||||||
|
/** |
||||||
|
* Instantiates a new EOFCreate operation. |
||||||
|
* |
||||||
|
* @param gasCalculator the gas calculator |
||||||
|
*/ |
||||||
|
public EOFCreateOperation(final GasCalculator gasCalculator) { |
||||||
|
super(OPCODE, "EOFCREATE", 4, 1, gasCalculator, Integer.MAX_VALUE, 1); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public long cost(final MessageFrame frame, final Supplier<Code> codeSupplier) { |
||||||
|
final int inputOffset = clampedToInt(frame.getStackItem(2)); |
||||||
|
final int inputSize = clampedToInt(frame.getStackItem(3)); |
||||||
|
return clampedAdd( |
||||||
|
gasCalculator().memoryExpansionGasCost(frame, inputOffset, inputSize), |
||||||
|
clampedAdd( |
||||||
|
gasCalculator().txCreateCost(), |
||||||
|
gasCalculator().createKeccakCost(codeSupplier.get().getSize()))); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public Address targetContractAddress(final MessageFrame frame, final Code initcode) { |
||||||
|
final Address sender = frame.getRecipientAddress(); |
||||||
|
final Bytes32 salt = Bytes32.leftPad(frame.getStackItem(1)); |
||||||
|
final Bytes32 hash = keccak256(Bytes.concatenate(PREFIX, sender, salt, initcode.getCodeHash())); |
||||||
|
final Address address = Address.extract(hash); |
||||||
|
frame.warmUpAddress(address); |
||||||
|
return address; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
protected Code getInitCode(final MessageFrame frame, final EVM evm) { |
||||||
|
final Code code = frame.getCode(); |
||||||
|
int startIndex = frame.getPC() + 1; |
||||||
|
final int initContainerIndex = code.readU8(startIndex); |
||||||
|
|
||||||
|
return code.getSubContainer(initContainerIndex, null).orElse(null); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
protected Bytes getInputData(final MessageFrame frame) { |
||||||
|
final long inputOffset = clampedToLong(frame.getStackItem(2)); |
||||||
|
final long inputSize = clampedToLong(frame.getStackItem(3)); |
||||||
|
return frame.readMemory(inputOffset, inputSize); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
protected int getPcIncrement() { |
||||||
|
return 2; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,60 @@ |
|||||||
|
/* |
||||||
|
* 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.Code; |
||||||
|
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; |
||||||
|
|
||||||
|
/** The Exchange operation. */ |
||||||
|
public class ExchangeOperation extends AbstractFixedCostOperation { |
||||||
|
|
||||||
|
/** EXCHANGE Opcode 0xe8 */ |
||||||
|
public static final int OPCODE = 0xe8; |
||||||
|
|
||||||
|
/** The Exchange operation success result. */ |
||||||
|
static final OperationResult exchangeSuccess = new OperationResult(3, null); |
||||||
|
|
||||||
|
/** |
||||||
|
* Instantiates a new Exchange operation. |
||||||
|
* |
||||||
|
* @param gasCalculator the gas calculator |
||||||
|
*/ |
||||||
|
public ExchangeOperation(final GasCalculator gasCalculator) { |
||||||
|
super(OPCODE, "EXCHANGE", 0, 1, gasCalculator, gasCalculator.getVeryLowTierGasCost()); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public OperationResult executeFixedCostOperation(final MessageFrame frame, final EVM evm) { |
||||||
|
Code code = frame.getCode(); |
||||||
|
if (code.getEofVersion() == 0) { |
||||||
|
return InvalidOperation.INVALID_RESULT; |
||||||
|
} |
||||||
|
int pc = frame.getPC(); |
||||||
|
int imm = code.readU8(pc + 1); |
||||||
|
int n = (imm >> 4) + 1; |
||||||
|
int m = (imm & 0x0F) + 1 + n; |
||||||
|
|
||||||
|
final Bytes tmp = frame.getStackItem(n); |
||||||
|
frame.setStackItem(n, frame.getStackItem(m)); |
||||||
|
frame.setStackItem(m, tmp); |
||||||
|
frame.setPC(pc + 1); |
||||||
|
|
||||||
|
return exchangeSuccess; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,69 @@ |
|||||||
|
/* |
||||||
|
* Copyright contributors to Hyperledger Besu. |
||||||
|
* |
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with |
||||||
|
* the License. You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on |
||||||
|
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the |
||||||
|
* specific language governing permissions and limitations under the License. |
||||||
|
* |
||||||
|
* SPDX-License-Identifier: Apache-2.0 |
||||||
|
*/ |
||||||
|
package org.hyperledger.besu.evm.operation; |
||||||
|
|
||||||
|
import static org.hyperledger.besu.evm.internal.Words.clampedToLong; |
||||||
|
|
||||||
|
import org.hyperledger.besu.datatypes.Address; |
||||||
|
import org.hyperledger.besu.datatypes.Wei; |
||||||
|
import org.hyperledger.besu.evm.frame.MessageFrame; |
||||||
|
import org.hyperledger.besu.evm.gascalculator.GasCalculator; |
||||||
|
|
||||||
|
/** The Call operation. */ |
||||||
|
public class ExtCallOperation extends AbstractExtCallOperation { |
||||||
|
|
||||||
|
static final int STACK_VALUE = 1; |
||||||
|
static final int STACK_INPUT_OFFSET = 2; |
||||||
|
static final int STACK_INPUT_LENGTH = 3; |
||||||
|
|
||||||
|
/** |
||||||
|
* Instantiates a new Call operation. |
||||||
|
* |
||||||
|
* @param gasCalculator the gas calculator |
||||||
|
*/ |
||||||
|
public ExtCallOperation(final GasCalculator gasCalculator) { |
||||||
|
super(0xF8, "EXTCALL", 4, 1, gasCalculator); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
protected Wei value(final MessageFrame frame) { |
||||||
|
return Wei.wrap(frame.getStackItem(STACK_VALUE)); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
protected Wei apparentValue(final MessageFrame frame) { |
||||||
|
return value(frame); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
protected long inputDataOffset(final MessageFrame frame) { |
||||||
|
return clampedToLong(frame.getStackItem(STACK_INPUT_OFFSET)); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
protected long inputDataLength(final MessageFrame frame) { |
||||||
|
return clampedToLong(frame.getStackItem(STACK_INPUT_LENGTH)); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
protected Address address(final MessageFrame frame) { |
||||||
|
return to(frame); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
protected Address sender(final MessageFrame frame) { |
||||||
|
return frame.getRecipientAddress(); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,73 @@ |
|||||||
|
/* |
||||||
|
* Copyright contributors to Hyperledger Besu. |
||||||
|
* |
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with |
||||||
|
* the License. You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on |
||||||
|
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the |
||||||
|
* specific language governing permissions and limitations under the License. |
||||||
|
* |
||||||
|
* SPDX-License-Identifier: Apache-2.0 |
||||||
|
*/ |
||||||
|
package org.hyperledger.besu.evm.operation; |
||||||
|
|
||||||
|
import static org.hyperledger.besu.evm.internal.Words.clampedToLong; |
||||||
|
|
||||||
|
import org.hyperledger.besu.datatypes.Address; |
||||||
|
import org.hyperledger.besu.datatypes.Wei; |
||||||
|
import org.hyperledger.besu.evm.frame.MessageFrame; |
||||||
|
import org.hyperledger.besu.evm.gascalculator.GasCalculator; |
||||||
|
|
||||||
|
/** The Delegate call operation. */ |
||||||
|
public class ExtDelegateCallOperation extends AbstractExtCallOperation { |
||||||
|
|
||||||
|
static final int STACK_INPUT_OFFSET = 1; |
||||||
|
static final int STACK_INPUT_LENGTH = 2; |
||||||
|
|
||||||
|
/** |
||||||
|
* Instantiates a new Delegate call operation. |
||||||
|
* |
||||||
|
* @param gasCalculator the gas calculator |
||||||
|
*/ |
||||||
|
public ExtDelegateCallOperation(final GasCalculator gasCalculator) { |
||||||
|
super(0xF9, "EXTDELEGATECALL", 3, 1, gasCalculator); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
protected Wei value(final MessageFrame frame) { |
||||||
|
return Wei.ZERO; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
protected Wei apparentValue(final MessageFrame frame) { |
||||||
|
return frame.getApparentValue(); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
protected long inputDataOffset(final MessageFrame frame) { |
||||||
|
return clampedToLong(frame.getStackItem(STACK_INPUT_OFFSET)); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
protected long inputDataLength(final MessageFrame frame) { |
||||||
|
return clampedToLong(frame.getStackItem(STACK_INPUT_LENGTH)); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
protected Address address(final MessageFrame frame) { |
||||||
|
return frame.getRecipientAddress(); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
protected Address sender(final MessageFrame frame) { |
||||||
|
return frame.getSenderAddress(); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
protected boolean isDelegate() { |
||||||
|
return true; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,73 @@ |
|||||||
|
/* |
||||||
|
* Copyright contributors to Hyperledger Besu. |
||||||
|
* |
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with |
||||||
|
* the License. You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on |
||||||
|
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the |
||||||
|
* specific language governing permissions and limitations under the License. |
||||||
|
* |
||||||
|
* SPDX-License-Identifier: Apache-2.0 |
||||||
|
*/ |
||||||
|
package org.hyperledger.besu.evm.operation; |
||||||
|
|
||||||
|
import static org.hyperledger.besu.evm.internal.Words.clampedToLong; |
||||||
|
|
||||||
|
import org.hyperledger.besu.datatypes.Address; |
||||||
|
import org.hyperledger.besu.datatypes.Wei; |
||||||
|
import org.hyperledger.besu.evm.frame.MessageFrame; |
||||||
|
import org.hyperledger.besu.evm.gascalculator.GasCalculator; |
||||||
|
|
||||||
|
/** The Static call operation. */ |
||||||
|
public class ExtStaticCallOperation extends AbstractExtCallOperation { |
||||||
|
|
||||||
|
static final int STACK_INPUT_OFFSET = 1; |
||||||
|
static final int STACK_INPUT_LENGTH = 2; |
||||||
|
|
||||||
|
/** |
||||||
|
* Instantiates a new Static call operation. |
||||||
|
* |
||||||
|
* @param gasCalculator the gas calculator |
||||||
|
*/ |
||||||
|
public ExtStaticCallOperation(final GasCalculator gasCalculator) { |
||||||
|
super(0xFB, "EXTSTATICCALL", 3, 1, gasCalculator); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
protected Wei value(final MessageFrame frame) { |
||||||
|
return Wei.ZERO; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
protected Wei apparentValue(final MessageFrame frame) { |
||||||
|
return value(frame); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
protected long inputDataOffset(final MessageFrame frame) { |
||||||
|
return clampedToLong(frame.getStackItem(STACK_INPUT_OFFSET)); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
protected long inputDataLength(final MessageFrame frame) { |
||||||
|
return clampedToLong(frame.getStackItem(STACK_INPUT_LENGTH)); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
protected Address address(final MessageFrame frame) { |
||||||
|
return to(frame); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
protected Address sender(final MessageFrame frame) { |
||||||
|
return frame.getRecipientAddress(); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
protected boolean isStatic(final MessageFrame frame) { |
||||||
|
return true; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,76 @@ |
|||||||
|
/* |
||||||
|
* Copyright contributors to Hyperledger Besu. |
||||||
|
* |
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with |
||||||
|
* the License. You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on |
||||||
|
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the |
||||||
|
* specific language governing permissions and limitations under the License. |
||||||
|
* |
||||||
|
* SPDX-License-Identifier: Apache-2.0 |
||||||
|
*/ |
||||||
|
package org.hyperledger.besu.evm.operation; |
||||||
|
|
||||||
|
import static org.hyperledger.besu.evm.internal.Words.clampedToLong; |
||||||
|
|
||||||
|
import org.hyperledger.besu.evm.Code; |
||||||
|
import org.hyperledger.besu.evm.EVM; |
||||||
|
import org.hyperledger.besu.evm.frame.ExceptionalHaltReason; |
||||||
|
import org.hyperledger.besu.evm.frame.MessageFrame; |
||||||
|
import org.hyperledger.besu.evm.gascalculator.GasCalculator; |
||||||
|
|
||||||
|
import java.util.Optional; |
||||||
|
|
||||||
|
import org.apache.tuweni.bytes.Bytes; |
||||||
|
|
||||||
|
/** The Return operation. */ |
||||||
|
public class ReturnContractOperation extends AbstractOperation { |
||||||
|
|
||||||
|
/** Opcode of RETURNCONTRACT operation */ |
||||||
|
public static final int OPCODE = 0xEE; |
||||||
|
|
||||||
|
/** |
||||||
|
* Instantiates a new Return operation. |
||||||
|
* |
||||||
|
* @param gasCalculator the gas calculator |
||||||
|
*/ |
||||||
|
public ReturnContractOperation(final GasCalculator gasCalculator) { |
||||||
|
super(OPCODE, "RETURNCONTRACT", 2, 0, gasCalculator); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public OperationResult execute(final MessageFrame frame, final EVM evm) { |
||||||
|
Code code = frame.getCode(); |
||||||
|
if (code.getEofVersion() == 0) { |
||||||
|
return InvalidOperation.INVALID_RESULT; |
||||||
|
} |
||||||
|
|
||||||
|
int pc = frame.getPC(); |
||||||
|
int index = code.readU8(pc + 1); |
||||||
|
|
||||||
|
final long from = clampedToLong(frame.popStackItem()); |
||||||
|
final long length = clampedToLong(frame.popStackItem()); |
||||||
|
|
||||||
|
final long cost = gasCalculator().memoryExpansionGasCost(frame, from, length); |
||||||
|
if (frame.getRemainingGas() < cost) { |
||||||
|
return new OperationResult(cost, ExceptionalHaltReason.INSUFFICIENT_GAS); |
||||||
|
} |
||||||
|
|
||||||
|
if (index >= code.getSubcontainerCount()) { |
||||||
|
return new OperationResult(cost, ExceptionalHaltReason.NONEXISTENT_CONTAINER); |
||||||
|
} |
||||||
|
|
||||||
|
Bytes auxData = frame.readMemory(from, length); |
||||||
|
Optional<Code> newCode = code.getSubContainer(index, auxData); |
||||||
|
if (newCode.isEmpty()) { |
||||||
|
return new OperationResult(cost, ExceptionalHaltReason.NONEXISTENT_CONTAINER); |
||||||
|
} |
||||||
|
|
||||||
|
frame.setCreatedCode(newCode.get()); |
||||||
|
frame.setState(MessageFrame.State.CODE_SUCCESS); |
||||||
|
return new OperationResult(cost, null); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,56 @@ |
|||||||
|
/* |
||||||
|
* Copyright contributors to Hyperledger Besu. |
||||||
|
* |
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with |
||||||
|
* the License. You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on |
||||||
|
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the |
||||||
|
* specific language governing permissions and limitations under the License. |
||||||
|
* |
||||||
|
* SPDX-License-Identifier: Apache-2.0 |
||||||
|
*/ |
||||||
|
package org.hyperledger.besu.evm.operation; |
||||||
|
|
||||||
|
import static org.hyperledger.besu.evm.internal.Words.clampedToInt; |
||||||
|
|
||||||
|
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; |
||||||
|
import org.apache.tuweni.bytes.Bytes32; |
||||||
|
|
||||||
|
/** The Return data copy operation. */ |
||||||
|
public class ReturnDataLoadOperation extends AbstractOperation { |
||||||
|
|
||||||
|
/** |
||||||
|
* Instantiates a new Return data copy operation. |
||||||
|
* |
||||||
|
* @param gasCalculator the gas calculator |
||||||
|
*/ |
||||||
|
public ReturnDataLoadOperation(final GasCalculator gasCalculator) { |
||||||
|
super(0xf7, "RETURNDATALOAD", 3, 0, gasCalculator); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public OperationResult execute(final MessageFrame frame, final EVM evm) { |
||||||
|
final int offset = clampedToInt(frame.popStackItem()); |
||||||
|
Bytes returnData = frame.getReturnData(); |
||||||
|
int retunDataSize = returnData.size(); |
||||||
|
|
||||||
|
Bytes value; |
||||||
|
if (offset > retunDataSize) { |
||||||
|
value = Bytes.EMPTY; |
||||||
|
} else if (offset + 32 >= returnData.size()) { |
||||||
|
value = Bytes32.rightPad(returnData.slice(offset)); |
||||||
|
} else { |
||||||
|
value = returnData.slice(offset, 32); |
||||||
|
} |
||||||
|
|
||||||
|
frame.pushStackItem(value); |
||||||
|
return new OperationResult(3L, null); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,59 @@ |
|||||||
|
/* |
||||||
|
* 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.Code; |
||||||
|
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; |
||||||
|
|
||||||
|
/** The SwapN operation. */ |
||||||
|
public class SwapNOperation extends AbstractFixedCostOperation { |
||||||
|
|
||||||
|
/** SWAPN Opcode 0xe7 */ |
||||||
|
public static final int OPCODE = 0xe7; |
||||||
|
|
||||||
|
/** The Swap operation success result. */ |
||||||
|
static final OperationResult swapSuccess = new OperationResult(3, null); |
||||||
|
|
||||||
|
/** |
||||||
|
* Instantiates a new SwapN operation. |
||||||
|
* |
||||||
|
* @param gasCalculator the gas calculator |
||||||
|
*/ |
||||||
|
public SwapNOperation(final GasCalculator gasCalculator) { |
||||||
|
super(OPCODE, "SWAPN", 0, 1, gasCalculator, gasCalculator.getVeryLowTierGasCost()); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public Operation.OperationResult executeFixedCostOperation( |
||||||
|
final MessageFrame frame, final EVM evm) { |
||||||
|
Code code = frame.getCode(); |
||||||
|
if (code.getEofVersion() == 0) { |
||||||
|
return InvalidOperation.INVALID_RESULT; |
||||||
|
} |
||||||
|
int pc = frame.getPC(); |
||||||
|
int index = code.readU8(pc + 1); |
||||||
|
|
||||||
|
final Bytes tmp = frame.getStackItem(0); |
||||||
|
frame.setStackItem(0, frame.getStackItem(index + 1)); |
||||||
|
frame.setStackItem(index + 1, tmp); |
||||||
|
frame.setPC(pc + 1); |
||||||
|
|
||||||
|
return swapSuccess; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,95 @@ |
|||||||
|
/* |
||||||
|
* 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; |
||||||
|
|
||||||
|
import org.apache.tuweni.bytes.Bytes; |
||||||
|
|
||||||
|
public class EOFTestConstants { |
||||||
|
|
||||||
|
public static final Bytes INNER_CONTRACT = |
||||||
|
bytesFromPrettyPrint( |
||||||
|
""" |
||||||
|
# EOF |
||||||
|
ef0001 # Magic and Version ( 1 ) |
||||||
|
010004 # Types length ( 4 ) |
||||||
|
020001 # Total code sections ( 1 ) |
||||||
|
0009 # Code section 0 , 9 bytes |
||||||
|
030001 # Total subcontainers ( 1 ) |
||||||
|
0014 # Sub container 0, 20 byte |
||||||
|
040000 # Data section length( 0 ) |
||||||
|
00 # Terminator (end of header) |
||||||
|
# Code section 0 types |
||||||
|
00 # 0 inputs\s |
||||||
|
80 # 0 outputs (Non-returning function) |
||||||
|
0003 # max stack: 3 |
||||||
|
# Code section 0 |
||||||
|
5f # [0] PUSH0 |
||||||
|
35 # [1] CALLDATALOAD |
||||||
|
5f # [2] PUSH0 |
||||||
|
5f # [3] PUSH0 |
||||||
|
a1 # [4] LOG1 |
||||||
|
5f # [5] PUSH0 |
||||||
|
5f # [6] PUSH0 |
||||||
|
ee00 # [7] RETURNCONTRACT(0) |
||||||
|
# Subcontainer 0 starts here |
||||||
|
ef0001 # Magic and Version ( 1 ) |
||||||
|
010004 # Types length ( 4 ) |
||||||
|
020001 # Total code sections ( 1 ) |
||||||
|
0001 # Code section 0 , 1 bytes |
||||||
|
040000 # Data section length( 0 ) |
||||||
|
00 # Terminator (end of header) |
||||||
|
# Code section 0 types |
||||||
|
00 # 0 inputs |
||||||
|
80 # 0 outputs (Non-returning function) |
||||||
|
0000 # max stack: 0 |
||||||
|
# Code section 0 |
||||||
|
00 # [0] STOP |
||||||
|
"""); |
||||||
|
|
||||||
|
public static Bytes EOF_CREATE_CONTRACT = |
||||||
|
bytesFromPrettyPrint( |
||||||
|
String.format( |
||||||
|
""" |
||||||
|
ef0001 # Magic and Version ( 1 ) |
||||||
|
010004 # Types length ( 4 ) |
||||||
|
020001 # Total code sections ( 1 ) |
||||||
|
000e # Code section 0 , 14 bytes |
||||||
|
030001 # Total subcontainers ( 1 ) |
||||||
|
%04x # Subcontainer 0 size ? |
||||||
|
040000 # Data section length( 0 ) |
||||||
|
00 # Terminator (end of header) |
||||||
|
# Code section 0 types |
||||||
|
00 # 0 inputs\s |
||||||
|
80 # 0 outputs (Non-returning function) |
||||||
|
0004 # max stack: 4 |
||||||
|
# Code section 0 |
||||||
|
61c0de # [0] PUSH2(0xc0de) |
||||||
|
5f # [3] PUSH0 |
||||||
|
52 # [4] MSTORE |
||||||
|
6002 # [5] PUSH1(2) |
||||||
|
601e # [7] PUSH1 30 |
||||||
|
5f # [9] PUSH0 |
||||||
|
5f # [10] PUSH0 |
||||||
|
ec00 # [11] EOFCREATE(0) |
||||||
|
00 # [13] STOP |
||||||
|
# Data section (empty) |
||||||
|
%s # subcontainer |
||||||
|
""", |
||||||
|
INNER_CONTRACT.size(), INNER_CONTRACT.toUnprefixedHexString())); |
||||||
|
|
||||||
|
public static Bytes bytesFromPrettyPrint(final String prettyPrint) { |
||||||
|
return Bytes.fromHexString(prettyPrint.replaceAll("#.*?\n", "").replaceAll("\\s", "")); |
||||||
|
} |
||||||
|
} |
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue