use of org.ethereum.vm.program.Program in project rskj by rsksmart.
the class TransactionExecutor method create.
private void create() {
RskAddress newContractAddress = tx.getContractAddress();
if (isEmpty(tx.getData())) {
mEndGas = toBI(tx.getGasLimit()).subtract(BigInteger.valueOf(basicTxCost));
cacheTrack.createAccount(newContractAddress);
} else {
ProgramInvoke programInvoke = programInvokeFactory.createProgramInvoke(tx, txindex, executionBlock, cacheTrack, blockStore);
this.vm = new VM(vmConfig, precompiledContracts);
BlockchainConfig configForBlock = config.getBlockchainConfig().getConfigForBlock(executionBlock.getNumber());
this.program = new Program(vmConfig, precompiledContracts, configForBlock, tx.getData(), programInvoke, tx);
// reset storage if the contract with the same address already exists
// TCK test case only - normally this is near-impossible situation in the real network
ContractDetails contractDetails = program.getStorage().getContractDetails(newContractAddress);
for (DataWord key : contractDetails.getStorageKeys()) {
program.storageSave(key, DataWord.ZERO);
}
}
Coin endowment = tx.getValue();
cacheTrack.transfer(tx.getSender(), newContractAddress, endowment);
}
use of org.ethereum.vm.program.Program in project rskj by rsksmart.
the class TransactionExecutor method call.
private void call() {
if (!readyToExecute) {
return;
}
logger.trace("Call transaction {} {}", toBI(tx.getNonce()), tx.getHash());
RskAddress targetAddress = tx.getReceiveAddress();
// DataWord(targetAddress)) can fail with exception:
// java.lang.RuntimeException: Data word can't exceed 32 bytes:
// if targetAddress size is greater than 32 bytes.
// But init() will detect this earlier
precompiledContract = precompiledContracts.getContractForAddress(new DataWord(targetAddress.getBytes()));
if (precompiledContract != null) {
precompiledContract.init(tx, executionBlock, track, blockStore, receiptStore, result.getLogInfoList());
long requiredGas = precompiledContract.getGasForData(tx.getData());
BigInteger txGasLimit = toBI(tx.getGasLimit());
if (!localCall && txGasLimit.compareTo(BigInteger.valueOf(requiredGas)) < 0) {
// no refund
// no endowment
execError(String.format("Out of Gas calling precompiled contract 0x%s, required: %d, left: %s ", targetAddress.toString(), (requiredGas + basicTxCost), mEndGas));
mEndGas = BigInteger.ZERO;
return;
} else {
long gasUsed = requiredGas + basicTxCost;
mEndGas = txGasLimit.subtract(BigInteger.valueOf(requiredGas + basicTxCost));
// FIXME: save return for vm trace
try {
byte[] out = precompiledContract.execute(tx.getData());
result.setHReturn(out);
} catch (RuntimeException e) {
result.setException(e);
}
result.spendGas(gasUsed);
}
} else {
byte[] code = track.getCode(targetAddress);
if (isEmpty(code)) {
mEndGas = toBI(tx.getGasLimit()).subtract(BigInteger.valueOf(basicTxCost));
result.spendGas(basicTxCost);
} else {
ProgramInvoke programInvoke = programInvokeFactory.createProgramInvoke(tx, txindex, executionBlock, cacheTrack, blockStore);
this.vm = new VM(vmConfig, precompiledContracts);
BlockchainConfig configForBlock = config.getBlockchainConfig().getConfigForBlock(executionBlock.getNumber());
this.program = new Program(vmConfig, precompiledContracts, configForBlock, code, programInvoke, tx);
}
}
if (result.getException() == null) {
Coin endowment = tx.getValue();
cacheTrack.transfer(tx.getSender(), targetAddress, endowment);
}
}
use of org.ethereum.vm.program.Program in project rskj by rsksmart.
the class VM method dumpLine.
/*
* Dumping the VM state at the current operation in various styles
* - standard Not Yet Implemented
* - standard+ (owner address, program counter, operation, gas left)
* - pretty (stack, memory, storage, level, contract,
* vmCounter, internalSteps, operation
gasBefore, gasCost, memWords)
*/
private void dumpLine(OpCode op, long gasBefore, long gasCost, long memWords, Program program) {
if ("standard+".equals(vmConfig.dumpStyle())) {
switch(op) {
case STOP:
case RETURN:
case SUICIDE:
ContractDetails details = program.getStorage().getContractDetails(new RskAddress(program.getOwnerAddress()));
List<DataWord> storageKeys = new ArrayList<>(details.getStorage().keySet());
Collections.sort(storageKeys);
storageKeys.forEach(key -> dumpLogger.trace("{} {}", Hex.toHexString(key.getNoLeadZeroesData()), Hex.toHexString(details.getStorage().get(key).getNoLeadZeroesData())));
break;
default:
break;
}
String addressString = Hex.toHexString(program.getOwnerAddress().getLast20Bytes());
String pcString = Hex.toHexString(new DataWord(program.getPC()).getNoLeadZeroesData());
String opString = Hex.toHexString(new byte[] { op.val() });
String gasString = Long.toHexString(program.getRemainingGas());
dumpLogger.trace("{} {} {} {}", addressString, pcString, opString, gasString);
} else if ("pretty".equals(vmConfig.dumpStyle())) {
dumpLogger.trace("-------------------------------------------------------------------------");
dumpLogger.trace(" STACK");
program.getStack().forEach(item -> dumpLogger.trace("{}", item));
dumpLogger.trace(" MEMORY");
String memoryString = program.memoryToString();
if (!"".equals(memoryString)) {
dumpLogger.trace("{}", memoryString);
}
dumpLogger.trace(" STORAGE");
ContractDetails details = program.getStorage().getContractDetails(new RskAddress(program.getOwnerAddress()));
List<DataWord> storageKeys = new ArrayList<>(details.getStorage().keySet());
Collections.sort(storageKeys);
storageKeys.forEach(key -> dumpLogger.trace("{}: {}", key.shortHex(), details.getStorage().get(key).shortHex()));
int level = program.getCallDeep();
String contract = Hex.toHexString(program.getOwnerAddress().getLast20Bytes());
String internalSteps = String.format("%4s", Integer.toHexString(program.getPC())).replace(' ', '0').toUpperCase();
dumpLogger.trace("{} | {} | #{} | {} : {} | {} | -{} | {}x32", level, contract, vmCounter, internalSteps, op, gasBefore, gasCost, memWords);
}
}
use of org.ethereum.vm.program.Program in project rskj by rsksmart.
the class TransactionExecutor method finalization.
public void finalization() {
if (!readyToExecute) {
return;
}
// RSK if local call gas balances must not be changed
if (localCall) {
return;
}
logger.trace("Finalize transaction {} {}", toBI(tx.getNonce()), tx.getHash());
cacheTrack.commit();
// Should include only LogInfo's that was added during not rejected transactions
List<LogInfo> notRejectedLogInfos = result.getLogInfoList().stream().filter(logInfo -> !logInfo.isRejected()).collect(Collectors.toList());
TransactionExecutionSummary.Builder summaryBuilder = TransactionExecutionSummary.builderFor(tx).gasLeftover(mEndGas).logs(notRejectedLogInfos).result(result.getHReturn());
if (result != null) {
// Accumulate refunds for suicides
result.addFutureRefund((long) result.getDeleteAccounts().size() * GasCost.SUICIDE_REFUND);
long gasRefund = Math.min(result.getFutureRefund(), result.getGasUsed() / 2);
RskAddress addr = tx.isContractCreation() ? tx.getContractAddress() : tx.getReceiveAddress();
mEndGas = mEndGas.add(BigInteger.valueOf(gasRefund));
summaryBuilder.gasUsed(toBI(result.getGasUsed())).gasRefund(toBI(gasRefund)).deletedAccounts(result.getDeleteAccounts()).internalTransactions(result.getInternalTransactions());
ContractDetails cdetails = track.getContractDetails(addr);
if (cdetails != null) {
summaryBuilder.storageDiff(cdetails.getStorage());
}
if (result.getException() != null) {
summaryBuilder.markAsFailed();
}
}
logger.trace("Building transaction execution summary");
TransactionExecutionSummary summary = summaryBuilder.build();
// Refund for gas leftover
track.addBalance(tx.getSender(), summary.getLeftover().add(summary.getRefund()));
logger.trace("Pay total refund to sender: [{}], refund val: [{}]", tx.getSender(), summary.getRefund());
// Transfer fees to miner
Coin summaryFee = summary.getFee();
// TODO: REMOVE THIS WHEN THE LocalBLockTests starts working with REMASC
if (config.isRemascEnabled()) {
logger.trace("Adding fee to remasc contract account");
track.addBalance(PrecompiledContracts.REMASC_ADDR, summaryFee);
} else {
track.addBalance(coinbase, summaryFee);
}
this.paidFees = summaryFee;
if (result != null) {
logger.trace("Processing result");
logs = notRejectedLogInfos;
result.getCodeChanges().forEach((key, value) -> track.saveCode(new RskAddress(key), value));
// Traverse list of suicides
result.getDeleteAccounts().forEach(address -> track.delete(new RskAddress(address)));
}
if (listener != null) {
listener.onTransactionExecuted(summary);
}
logger.trace("tx listener done");
if (config.vmTrace() && program != null && result != null) {
ProgramTrace trace = program.getTrace().result(result.getHReturn()).error(result.getException());
String txHash = tx.getHash().toHexString();
try {
saveProgramTraceFile(config, txHash, trace);
if (listener != null) {
listener.onVMTraceCreated(txHash, trace);
}
} catch (IOException e) {
String errorMessage = String.format("Cannot write trace to file: %s", e.getMessage());
panicProcessor.panic("executor", errorMessage);
logger.error(errorMessage);
}
}
logger.trace("tx finalization done");
}
use of org.ethereum.vm.program.Program in project rskj by rsksmart.
the class VMExecutionTest method swapnTwentiethItem.
@Test
public void swapnTwentiethItem() {
Program program = executeCode("PUSH1 0x01 PUSH1 0x02 PUSH1 0x03 PUSH1 0x04 PUSH1 0x05 PUSH1 0x06 PUSH1 0x07 PUSH1 0x08 PUSH1 0x09 PUSH1 0x0a PUSH1 0x0b PUSH1 0x0c PUSH1 0x0d PUSH1 0x0e PUSH1 0x0f PUSH1 0x10 PUSH1 0x11 PUSH1 0x12 PUSH1 0x13 PUSH1 0x14 PUSH1 0x12 SWAPN", 22);
Stack stack = program.getStack();
Assert.assertEquals(20, stack.size());
Assert.assertEquals(new DataWord(1), stack.peek());
Assert.assertEquals(new DataWord(20), stack.get(0));
for (int k = 1; k < 19; k++) Assert.assertEquals(new DataWord(k + 1), stack.get(k));
}
Aggregations