use of org.ethereum.vm.VM in project rskj by rsksmart.
the class TestRunner method runTestCase.
public List<String> runTestCase(TestCase testCase) {
logger.info("\n***");
logger.info(" Running test case: [" + testCase.getName() + "]");
logger.info("***\n");
List<String> results = new ArrayList<>();
logger.info("--------- PRE ---------");
Repository repository = loadRepository(createRepository().startTracking(), testCase.getPre());
try {
/* 2. Create ProgramInvoke - Env/Exec */
Env env = testCase.getEnv();
Exec exec = testCase.getExec();
Logs logs = testCase.getLogs();
byte[] address = exec.getAddress();
byte[] origin = exec.getOrigin();
byte[] caller = exec.getCaller();
byte[] balance = ByteUtil.bigIntegerToBytes(repository.getBalance(new RskAddress(exec.getAddress())).asBigInteger());
byte[] gasPrice = exec.getGasPrice();
byte[] gas = exec.getGas();
byte[] callValue = exec.getValue();
byte[] msgData = exec.getData();
byte[] lastHash = env.getPreviousHash();
byte[] coinbase = env.getCurrentCoinbase();
long timestamp = ByteUtil.byteArrayToLong(env.getCurrentTimestamp());
long number = ByteUtil.byteArrayToLong(env.getCurrentNumber());
byte[] difficulty = env.getCurrentDifficulty();
byte[] gaslimit = env.getCurrentGasLimit();
// Origin and caller need to exist in order to be able to execute
RskAddress originAddress = new RskAddress(origin);
if (repository.getAccountState(originAddress) == null) {
repository.createAccount(originAddress);
}
RskAddress callerAddress = new RskAddress(caller);
if (repository.getAccountState(callerAddress) == null) {
repository.createAccount(callerAddress);
}
ProgramInvoke programInvoke = new ProgramInvokeImpl(address, origin, caller, balance, gasPrice, gas, callValue, msgData, lastHash, coinbase, timestamp, number, 0, difficulty, gaslimit, repository, new BlockStoreDummy(), true);
/* 3. Create Program - exec.code */
/* 4. run VM */
VM vm = new VM(vmConfig, precompiledContracts);
Program program = new Program(vmConfig, precompiledContracts, blockFactory, mock(ActivationConfig.ForBlock.class), exec.getCode(), programInvoke, null, new HashSet<>());
boolean vmDidThrowAnEception = false;
Exception e = null;
ThreadMXBean thread;
Boolean oldMode;
long startTime = 0;
thread = ManagementFactory.getThreadMXBean();
if (thread.isThreadCpuTimeSupported()) {
oldMode = thread.isThreadCpuTimeEnabled();
thread.setThreadCpuTimeEnabled(true);
// in nanoseconds.
startTime = thread.getCurrentThreadCpuTime();
}
try {
vm.steps(program, Long.MAX_VALUE);
;
} catch (RuntimeException ex) {
vmDidThrowAnEception = true;
e = ex;
}
if (startTime != 0) {
long endTime = thread.getCurrentThreadCpuTime();
// de nano a micro.
long deltaTime = (endTime - startTime) / 1000;
logger.info("Time elapsed [uS]: " + Long.toString(deltaTime));
}
if (!program.getTrace().isEmpty()) {
try {
saveProgramTraceFile(testCase.getName(), program.getTrace(), config.databaseDir(), config.vmTraceDir(), config.vmTraceCompressed());
} catch (IOException ioe) {
vmDidThrowAnEception = true;
e = ioe;
}
}
// No items in POST means an exception is expected
if (testCase.getPost().size() == 0) {
if (vmDidThrowAnEception != true) {
String output = "VM was expected to throw an exception, but did not";
logger.info(output);
results.add(output);
} else
logger.info("VM did throw an EXPECTED exception: " + e.toString());
} else {
if (vmDidThrowAnEception) {
String output = "VM threw an unexpected exception: " + e.toString();
logger.info(output, e);
results.add(output);
return results;
}
this.trace = program.getTrace();
logger.info("--------- POST --------");
/* 5. Assert Post values */
for (RskAddress addr : testCase.getPost().keySet()) {
AccountState accountState = testCase.getPost().get(addr);
long expectedNonce = accountState.getNonceLong();
Coin expectedBalance = accountState.getBalance();
byte[] expectedCode = accountState.getCode();
// The new semantic of getAccountState() is that it will return
// null if the account does not exists. Previous semantic was
// to return a new empty AccountState.
// One example is ExtCodeSizeAddressInputTooBigRightMyAddress
// the address 0x0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6
// should not be an existent contract.
boolean accountExist = (null != repository.getAccountState(addr));
// Therefore this check is useless now, if we're going to check
// balance, nonce and storage.
/*
if (!accountExist) {
String output =
String.format("The expected account does not exist. key: [ %s ]",
addr);
logger.info(output);
results.add(output);
continue;
}
*/
// This "get" used to create an entry in the repository for the account.
// It should not.
long actualNonce = repository.getNonce(addr).longValue();
Coin actualBalance = repository.getBalance(addr);
byte[] actualCode = repository.getCode(addr);
if (actualCode == null)
actualCode = "".getBytes();
if (expectedNonce != actualNonce) {
String output = String.format("The nonce result is different. key: [ %s ], expectedNonce: [ %d ] is actualNonce: [ %d ] ", addr, expectedNonce, actualNonce);
logger.info(output);
results.add(output);
}
if (!expectedBalance.equals(actualBalance)) {
String output = String.format("The balance result is different. key: [ %s ], expectedBalance: [ %s ] is actualBalance: [ %s ] ", addr, expectedBalance.toString(), actualBalance.toString());
logger.info(output);
results.add(output);
}
if (!Arrays.equals(expectedCode, actualCode)) {
String output = String.format("The code result is different. account: [ %s ], expectedCode: [ %s ] is actualCode: [ %s ] ", addr, ByteUtil.toHexString(expectedCode), ByteUtil.toHexString(actualCode));
logger.info(output);
results.add(output);
}
// assert storage
Map<DataWord, DataWord> storage = accountState.getStorage();
for (DataWord storageKey : storage.keySet()) {
DataWord expectedStValue = storage.get(storageKey);
RskAddress accountAddress = accountState.getAddress();
if (!program.getStorage().isContract(accountAddress)) {
String output = String.format("Storage raw doesn't exist: key [ %s ], expectedValue: [ %s ]", ByteUtil.toHexString(storageKey.getData()), expectedStValue.toString());
logger.info(output);
results.add(output);
continue;
}
byte[] actualValue = program.getStorage().getStorageBytes(accountAddress, storageKey);
// and not byte arrays.
if (actualValue == null || !(expectedStValue.equals(DataWord.valueOf(actualValue)))) {
String output = String.format("Storage value different: key [ %s ], expectedValue: [ %s ], actualValue: [ %s ]", ByteUtil.toHexString(storageKey.getData()), expectedStValue.toString(), actualValue == null ? "" : ByteUtil.toHexString(actualValue));
logger.info(output);
results.add(output);
}
}
/* asset logs */
List<LogInfo> logResult = program.getResult().getLogInfoList();
Iterator<LogInfo> postLogs = logs.getIterator();
int i = 0;
while (postLogs.hasNext()) {
LogInfo expectedLogInfo = postLogs.next();
LogInfo foundLogInfo = null;
if (logResult.size() > i) {
foundLogInfo = logResult.get(i);
}
if (foundLogInfo == null) {
String output = String.format("Expected log [ %s ]", expectedLogInfo.toString());
logger.info(output);
results.add(output);
} else {
if (!Arrays.equals(expectedLogInfo.getAddress(), foundLogInfo.getAddress())) {
String output = String.format("Expected address [ %s ], found [ %s ]", ByteUtil.toHexString(expectedLogInfo.getAddress()), ByteUtil.toHexString(foundLogInfo.getAddress()));
logger.info(output);
results.add(output);
}
if (!Arrays.equals(expectedLogInfo.getData(), foundLogInfo.getData())) {
String output = String.format("Expected data [ %s ], found [ %s ]", ByteUtil.toHexString(expectedLogInfo.getData()), ByteUtil.toHexString(foundLogInfo.getData()));
logger.info(output);
results.add(output);
}
if (!expectedLogInfo.getBloom().equals(foundLogInfo.getBloom())) {
String output = String.format("Expected bloom [ %s ], found [ %s ]", ByteUtil.toHexString(expectedLogInfo.getBloom().getData()), ByteUtil.toHexString(foundLogInfo.getBloom().getData()));
logger.info(output);
results.add(output);
}
if (expectedLogInfo.getTopics().size() != foundLogInfo.getTopics().size()) {
String output = String.format("Expected number of topics [ %d ], found [ %d ]", expectedLogInfo.getTopics().size(), foundLogInfo.getTopics().size());
logger.info(output);
results.add(output);
} else {
int j = 0;
for (DataWord topic : expectedLogInfo.getTopics()) {
byte[] foundTopic = foundLogInfo.getTopics().get(j).getData();
if (!Arrays.equals(topic.getData(), foundTopic)) {
String output = String.format("Expected topic [ %s ], found [ %s ]", ByteUtil.toHexString(topic.getData()), ByteUtil.toHexString(foundTopic));
logger.info(output);
results.add(output);
}
++j;
}
}
}
++i;
}
}
// TODO: assert that you have no extra accounts in the repository
// TODO: -> basically the deleted by suicide should be deleted
// TODO: -> and no unexpected created
List<org.ethereum.vm.CallCreate> resultCallCreates = program.getResult().getCallCreateList();
// assert call creates
for (int i = 0; i < testCase.getCallCreateList().size(); ++i) {
org.ethereum.vm.CallCreate resultCallCreate = null;
if (resultCallCreates != null && resultCallCreates.size() > i) {
resultCallCreate = resultCallCreates.get(i);
}
CallCreate expectedCallCreate = testCase.getCallCreateList().get(i);
if (resultCallCreate == null && expectedCallCreate != null) {
String output = String.format("Missing call/create invoke: to: [ %s ], data: [ %s ], gas: [ %s ], value: [ %s ]", ByteUtil.toHexString(expectedCallCreate.getDestination()), ByteUtil.toHexString(expectedCallCreate.getData()), Long.toHexString(expectedCallCreate.getGasLimit()), ByteUtil.toHexString(expectedCallCreate.getValue()));
logger.info(output);
results.add(output);
continue;
}
boolean assertDestination = Arrays.equals(expectedCallCreate.getDestination(), resultCallCreate.getDestination());
if (!assertDestination) {
String output = String.format("Call/Create destination is different. Expected: [ %s ], result: [ %s ]", ByteUtil.toHexString(expectedCallCreate.getDestination()), ByteUtil.toHexString(resultCallCreate.getDestination()));
logger.info(output);
results.add(output);
}
boolean assertData = Arrays.equals(expectedCallCreate.getData(), resultCallCreate.getData());
if (!assertData) {
String output = String.format("Call/Create data is different. Expected: [ %s ], result: [ %s ]", ByteUtil.toHexString(expectedCallCreate.getData()), ByteUtil.toHexString(resultCallCreate.getData()));
logger.info(output);
results.add(output);
}
boolean assertGasLimit = expectedCallCreate.getGasLimit() == resultCallCreate.getGasLimit();
if (!assertGasLimit) {
String output = String.format("Call/Create gasLimit is different. Expected: [ %s ], result: [ %s ]", Long.toHexString(expectedCallCreate.getGasLimit()), Long.toHexString(resultCallCreate.getGasLimit()));
logger.info(output);
results.add(output);
}
boolean assertValue = Arrays.equals(expectedCallCreate.getValue(), resultCallCreate.getValue());
if (!assertValue) {
String output = String.format("Call/Create value is different. Expected: [ %s ], result: [ %s ]", ByteUtil.toHexString(expectedCallCreate.getValue()), ByteUtil.toHexString(resultCallCreate.getValue()));
logger.info(output);
results.add(output);
}
}
// assert out
byte[] expectedHReturn = testCase.getOut();
byte[] actualHReturn = EMPTY_BYTE_ARRAY;
if (program.getResult().getHReturn() != null) {
actualHReturn = program.getResult().getHReturn();
}
if (!Arrays.equals(expectedHReturn, actualHReturn)) {
String output = String.format("HReturn is different. Expected hReturn: [ %s ], actual hReturn: [ %s ]", ByteUtil.toHexString(expectedHReturn), ByteUtil.toHexString(actualHReturn));
logger.info(output);
results.add(output);
}
// assert gas
BigInteger expectedGas = new BigInteger(1, testCase.getGas());
BigInteger actualGas = new BigInteger(1, gas).subtract(BigInteger.valueOf(program.getResult().getGasUsed()));
if (validateGasUsed)
if (!expectedGas.equals(actualGas)) {
String output = String.format("Gas remaining is different. Expected gas remaining: [ %s ], actual gas remaining: [ %s ]", expectedGas.toString(), actualGas.toString());
logger.info(output);
results.add(output);
}
/*
* end of if(testCase.getPost().size() == 0)
*/
}
return results;
} finally {
// repository.close();
}
}
use of org.ethereum.vm.VM in project rskj by rsksmart.
the class BridgeTestPowerMock method testCallFromContract_afterOrchid.
@Test
public void testCallFromContract_afterOrchid() {
doReturn(false).when(activationConfig).isActive(eq(RSKIP87), anyLong());
doReturn(true).when(activationConfig).isActive(eq(RSKIP88), anyLong());
blockFactory = new BlockFactory(activationConfig);
BridgeSupportFactory bridgeSupportFactory = new BridgeSupportFactory(new RepositoryBtcBlockStoreWithCache.Factory(constants.getBridgeConstants().getBtcParams()), constants.getBridgeConstants(), activationConfig);
PrecompiledContracts precompiledContracts = new PrecompiledContracts(config, bridgeSupportFactory);
EVMAssembler assembler = new EVMAssembler();
ProgramInvoke invoke = new ProgramInvokeMockImpl();
// Save code on the sender's address so that the bridge
// thinks its being called by a contract
byte[] callerCode = assembler.assemble("0xaabb 0xccdd 0xeeff");
invoke.getRepository().saveCode(new RskAddress(invoke.getOwnerAddress().getLast20Bytes()), callerCode);
VM vm = new VM(config.getVmConfig(), precompiledContracts);
// Encode a call to the bridge's getMinimumLockTxValue function
// That means first pushing the corresponding encoded ABI storage to memory (MSTORE)
// and then doing a DELEGATECALL to the corresponding address with the correct parameters
String bridgeFunctionHex = ByteUtil.toHexString(Bridge.GET_MINIMUM_LOCK_TX_VALUE.encode());
bridgeFunctionHex = String.format("0x%s%s", bridgeFunctionHex, String.join("", Collections.nCopies(32 * 2 - bridgeFunctionHex.length(), "0")));
String asm = String.format("%s 0x00 MSTORE 0x20 0x30 0x20 0x00 0x0000000000000000000000000000000001000006 0x6000 DELEGATECALL", bridgeFunctionHex);
int numOps = asm.split(" ").length;
byte[] code = assembler.assemble(asm);
// Mock a transaction, all we really need is a hash
Transaction tx = mock(Transaction.class);
when(tx.getHash()).thenReturn(new Keccak256("001122334455667788990011223344556677889900112233445566778899aabb"));
// Run the program on the VM
Program program = new Program(config.getVmConfig(), precompiledContracts, blockFactory, activationConfig.forBlock(0), code, invoke, tx, new HashSet<>());
try {
for (int i = 0; i < numOps; i++) {
vm.step(program);
}
Assert.fail();
} catch (RuntimeException e) {
Assert.assertTrue(e.getMessage().contains("Non-local-call"));
}
}
use of org.ethereum.vm.VM in project rskj by rsksmart.
the class VMPerformanceTest method testLongOperation.
//
@Ignore
@Test
public void testLongOperation() {
/* bad example because requires ABI parsing
contract Fibonacci {
function fib() returns (uint r) {
uint256 a;
uint256 b;
uint256 c;
a=0;
b=1;
for (uint i = 1; i < 55; i++) {
c = a+b;
a = b;
b = c;
}
r = b;
}
} // contract
// Good example
contract Fibonacci {
function() {
uint256 a;
uint256 b;
uint256 c;
a=0;
b=1;
for (uint i = 1; i < 50; i++) {
c = a+b;
a = b;
b = c;
}
assembly {
mstore(0x0, b)
return(0x0, 32)
}
}
} // contract
*/
vm = new VM(config.getVmConfig(), new PrecompiledContracts(config, null));
// Strip the first 16 bytes which are added by Solidity to store the contract.
byte[] codePlusPrefix = Hex.decode(// ---------------------------------------------------------------------------------------------------------------------nn
"606060405260618060106000396000f360606040523615600d57600d565b605f5b6000600060006000600093508350600192508250600190505b60" + // "32"+ // 55
"FE" + // 254
"811015604f5782840191508150829350835081925082505b80806001019150506029565b8260005260206000f35b50505050565b00");
// "606060405260618060106000396000f360606040523615600d57600d565b605f5b6000600060006000600093508350600192508250600190505b600f811015604f5782840191508150829350835081925082505b80806001019150506029565b8260005260206000f35b50505050565b00"
/* Prefix code
Instr.# addrs. mnemonic operand xrefs description
------------------------------------------------------------------------------------------------------------------------------------------------------
[ 0] [0x00000000] PUSH1 0x60 ('`') # Place 1 byte item on stack.
[ 1] [0x00000002] PUSH1 0x40 ('@') # Place 1 byte item on stack.
[ 2] [0x00000004] MSTORE # Save word to memory.
[ 3] [0x00000005] PUSH1 0x61 ('a') This is the real contract length # Place 1 byte item on stack.
[ 4] [0x00000007] DUP1 # Duplicate 1st stack item.
[ 5] [0x00000008] PUSH1 0x10 # Place 1 byte item on stack.
[ 6] [0x0000000a] PUSH1 0x00 # Place 1 byte item on stack.
[ 7] [0x0000000c] CODECOPY # Copy code running in current environment to memory.
[ 8] [0x0000000d] PUSH1 0x00 # Place 1 byte item on stack.
[ 9] [0x0000000f] RETURN
------------------------------------------------------------------------------------------------------------------------------------------------------*/
byte[] code = Arrays.copyOfRange(codePlusPrefix, 16, codePlusPrefix.length);
program = new Program(vmConfig, precompiledContracts, blockFactory, activations, code, invoke, null, new HashSet<>());
// String s_expected_1 = "000000000000000000000000000000000000000000000000000000033FFC1244"; // 55
// String s_expected_1 = "00000000000000000000000000000000000000000000000000000002EE333961";// 50
// 254
String s_expected_1 = "0000000000000000000090A7ED63052BFF49E105B6B7BC90D0B352C89BA1AD59";
startMeasure();
vm.steps(program, Long.MAX_VALUE);
endMeasure();
byte[] actualHReturn = null;
if (program.getResult().getHReturn() != null) {
actualHReturn = program.getResult().getHReturn();
}
// if (!Arrays.equals(expectedHReturn, actualHReturn)) {
// DataWord item1 = program.stackPop();
assertEquals(s_expected_1, ByteUtil.toHexString(actualHReturn).toUpperCase());
}
use of org.ethereum.vm.VM in project rskj by rsksmart.
the class Create2Test method executeCode.
private Program executeCode(String stringCode) {
byte[] code = compiler.compile(stringCode);
VM vm = new VM(vmConfig, precompiledContracts);
Program program = new Program(vmConfig, precompiledContracts, blockFactory, activationConfig, code, invoke, transaction, new HashSet<>());
while (!program.isStopped()) {
vm.step(program);
}
return program;
}
use of org.ethereum.vm.VM in project rskj by rsksmart.
the class ExtCodeHashTest method executeExtCodeHash.
private void executeExtCodeHash(String destAddress, int gasExpected, byte[] codeHashExpected) {
String stringCode = " PUSH20 " + destAddress + " EXTCODEHASH";
byte[] code = compiler.compile(stringCode);
VM vm = new VM(vmConfig, precompiledContracts);
Program program = new Program(vmConfig, precompiledContracts, blockFactory, activationConfig, code, invoke, transaction, new HashSet<>());
while (!program.isStopped()) {
vm.step(program);
}
Assert.assertEquals(1, program.getStack().size());
DataWord dataWordResult = program.stackPop();
Assert.assertEquals(DataWord.valueOf(codeHashExpected), dataWordResult);
Assert.assertEquals(gasExpected, program.getResult().getGasUsed());
}
Aggregations