Add basic gas step cost to mem exapnding operations and use enum directly

This commit is contained in:
nicksavers 2014-08-21 14:27:51 +02:00
parent 6281a752b4
commit e592e24eb2
1 changed files with 97 additions and 35 deletions

View File

@ -69,12 +69,11 @@ public class VM {
public void step(Program program) {
try {
byte op = program.getCurrentOp();
program.setLastOp(op);
OpCode op = OpCode.code(program.getCurrentOp());
program.setLastOp(op.val());
long oldMemSize = program.getMemSize();
long newMemSize = oldMemSize;
long newMemSize = 0;
Stack<DataWord> stack = program.getStack();
String hint = "";
@ -83,65 +82,83 @@ public class VM {
// Log debugging line for VM
if(program.getNumber().intValue() == CONFIG.dumpBlock())
this.dumpLine(op, program);
this.dumpLine(op.val(), program);
// Calculate fees and memory
switch (OpCode.code(op)) {
case SLOAD:
program.spendGas(GasCost.SLOAD, OpCode.code(op).name());
break;
case BALANCE:
program.spendGas(GasCost.BALANCE, OpCode.code(op).name());
break;
// Calculate fees and spend gas
switch (op) {
case STOP: case SUICIDE:
// The ops that doesn't charged by step, or
// charged in the following section
break;
case SSTORE:
assert(stack.size() == 2);
// for gas calculations [YP 9.2]
DataWord newValue = stack.get(stack.size()-2);
DataWord oldValue = program.storageLoad(stack.peek());
if (oldValue == null && !newValue.isZero()) {
program.spendGas(GasCost.SSTORE * 2, OpCode.code(op).name());
program.spendGas(GasCost.SSTORE * 2, op.name());
} else if (oldValue != null && newValue.isZero()) {
program.spendGas(GasCost.SSTORE * 0, OpCode.code(op).name());
program.spendGas(GasCost.SSTORE * 0, op.name());
} else
program.spendGas(GasCost.SSTORE, OpCode.code(op).name());
program.spendGas(GasCost.SSTORE, op.name());
break;
case SLOAD:
program.spendGas(GasCost.SLOAD, op.name());
break;
case BALANCE:
program.spendGas(GasCost.BALANCE, op.name());
break;
// These all operate on memory and therefore potentially expand it:
case MSTORE:
assert(stack.size() == 2);
newMemSize = stack.peek().longValue() + 32;
break;
case MLOAD:
newMemSize = stack.peek().longValue() + 32;
program.spendGas(GasCost.STEP, op.name());
break;
case MSTORE8:
assert(stack.size() == 2);
newMemSize = stack.peek().longValue() + 1;
program.spendGas(GasCost.STEP, op.name());
break;
case MLOAD:
assert(stack.size() == 1);
newMemSize = stack.peek().longValue() + 32;
program.spendGas(GasCost.STEP, op.name());
break;
case RETURN:
assert(stack.size() == 2);
newMemSize = stack.peek().longValue() + stack.get(stack.size()-2).longValue();
program.spendGas(GasCost.STEP, op.name());
break;
case SHA3:
program.spendGas(GasCost.SHA3, OpCode.code(op).name());
assert(stack.size() == 2);
program.spendGas(GasCost.SHA3, op.name());
newMemSize = stack.peek().longValue() + stack.get(stack.size()-2).longValue();
break;
case CALLDATACOPY:
assert(stack.size() == 3);
newMemSize = stack.peek().longValue() + stack.get(stack.size()-3).longValue();
program.spendGas(GasCost.STEP, op.name());
break;
case CODECOPY:
assert(stack.size() == 3);
newMemSize = stack.peek().longValue() + stack.get(stack.size()-3).longValue();
program.spendGas(GasCost.STEP, op.name());
break;
case CALL:
program.spendGas(GasCost.CALL + stack.get(stack.size()-1).longValue(), OpCode.code(op).name());
assert(stack.size() == 7);
program.spendGas(GasCost.CALL + stack.get(stack.size()-1).longValue(), op.name());
long x = stack.get(stack.size()-6).longValue() + stack.get(stack.size()-7).longValue();
long y = stack.get(stack.size()-4).longValue() + stack.get(stack.size()-5).longValue();
newMemSize = Math.max(x, y);
break;
case CREATE:
program.spendGas(GasCost.CREATE, OpCode.code(op).name());
assert(stack.size() == 3);
program.spendGas(GasCost.CREATE, op.name());
newMemSize = stack.get(stack.size()-2).longValue() + stack.get(stack.size()-3).longValue();
break;
default:
// program.spendGas(GasCost.STEP, OpCode.code(op).name());
program.spendGas(GasCost.STEP, op.name());
break;
}
@ -149,10 +166,10 @@ public class VM {
long memoryUsage = (newMemSize + 31) / 32 * 32;
// long memoryUsage = (newMemSize - oldMemSize) / 32;
if (memoryUsage > oldMemSize)
program.spendGas(GasCost.MEMORY * ((memoryUsage-oldMemSize)/32), OpCode.code(op).name() + " (memory usage)");
program.spendGas(GasCost.MEMORY * ((memoryUsage-oldMemSize)/32), op.name() + " (memory usage)");
// Execute operation
switch (OpCode.code(op)) {
switch (op) {
/**
* Stop and Arithmetic Operations
*/
@ -161,6 +178,7 @@ public class VM {
program.stop();
} break;
case ADD:{
assert(stack.size() == 2);
DataWord word1 = program.stackPop();
DataWord word2 = program.stackPop();
@ -173,6 +191,7 @@ public class VM {
} break;
case MUL:{
assert(stack.size() == 2);
DataWord word1 = program.stackPop();
DataWord word2 = program.stackPop();
@ -184,6 +203,7 @@ public class VM {
program.step();
} break;
case SUB:{
assert(stack.size() == 2);
DataWord word1 = program.stackPop();
DataWord word2 = program.stackPop();
@ -195,6 +215,7 @@ public class VM {
program.step();
} break;
case DIV:{
assert(stack.size() == 2);
DataWord word1 = program.stackPop();
DataWord word2 = program.stackPop();
@ -206,6 +227,7 @@ public class VM {
program.step();
} break;
case SDIV:{
assert(stack.size() == 2);
DataWord word1 = program.stackPop();
DataWord word2 = program.stackPop();
@ -217,6 +239,7 @@ public class VM {
program.step();
} break;
case MOD:{
assert(stack.size() == 2);
DataWord word1 = program.stackPop();
DataWord word2 = program.stackPop();
@ -228,6 +251,7 @@ public class VM {
program.step();
} break;
case SMOD:{
assert(stack.size() == 2);
DataWord word1 = program.stackPop();
DataWord word2 = program.stackPop();
@ -239,6 +263,7 @@ public class VM {
program.step();
} break;
case EXP:{
assert(stack.size() == 2);
DataWord word1 = program.stackPop();
DataWord word2 = program.stackPop();
@ -250,6 +275,7 @@ public class VM {
program.step();
} break;
case NEG:{
assert(stack.size() == 1);
DataWord word1 = program.stackPop();
word1.negate();
@ -260,6 +286,7 @@ public class VM {
program.step();
} break;
case LT:{
assert(stack.size() == 2);
// TODO: can be improved by not using BigInteger
DataWord word1 = program.stackPop();
DataWord word2 = program.stackPop();
@ -277,6 +304,7 @@ public class VM {
program.step();
} break;
case SLT:{
assert(stack.size() == 2);
// TODO: can be improved by not using BigInteger
DataWord word1 = program.stackPop();
DataWord word2 = program.stackPop();
@ -294,6 +322,7 @@ public class VM {
program.step();
} break;
case SGT:{
assert(stack.size() == 2);
// TODO: can be improved by not using BigInteger
DataWord word1 = program.stackPop();
DataWord word2 = program.stackPop();
@ -311,6 +340,7 @@ public class VM {
program.step();
} break;
case GT:{
assert(stack.size() == 2);
// TODO: can be improved by not using BigInteger
DataWord word1 = program.stackPop();
DataWord word2 = program.stackPop();
@ -328,6 +358,7 @@ public class VM {
program.step();
} break;
case EQ:{
assert(stack.size() == 2);
DataWord word1 = program.stackPop();
DataWord word2 = program.stackPop();
@ -344,6 +375,7 @@ public class VM {
program.step();
} break;
case NOT: {
assert(stack.size() == 1);
DataWord word1 = program.stackPop();
if (word1.isZero()) {
word1.getData()[31] = 1;
@ -362,6 +394,7 @@ public class VM {
* Bitwise Logic Operations
*/
case AND:{
assert(stack.size() == 2);
DataWord word1 = program.stackPop();
DataWord word2 = program.stackPop();
@ -373,6 +406,7 @@ public class VM {
program.step();
} break;
case OR: {
assert(stack.size() == 2);
DataWord word1 = program.stackPop();
DataWord word2 = program.stackPop();
@ -384,6 +418,7 @@ public class VM {
program.step();
} break;
case XOR: {
assert(stack.size() == 2);
DataWord word1 = program.stackPop();
DataWord word2 = program.stackPop();
@ -395,6 +430,7 @@ public class VM {
program.step();
} break;
case BYTE:{
assert(stack.size() == 2);
DataWord word1 = program.stackPop();
DataWord word2 = program.stackPop();
DataWord result = null;
@ -418,6 +454,7 @@ public class VM {
* SHA3
*/
case SHA3:{
assert(stack.size() == 2);
DataWord memOffsetData = program.stackPop();
DataWord lengthData = program.stackPop();
ByteBuffer buffer = program.memoryChunk(memOffsetData, lengthData);
@ -445,6 +482,7 @@ public class VM {
program.step();
} break;
case BALANCE:{
assert(stack.size() == 1);
DataWord address = program.stackPop();
DataWord balance = program.getBalance(address);
@ -484,6 +522,7 @@ public class VM {
program.step();
} break;
case CALLDATALOAD:{
assert(stack.size() == 1);
DataWord dataOffs = program.stackPop();
DataWord value = program.getDataValue(dataOffs);
@ -503,10 +542,18 @@ public class VM {
program.step();
} break;
case CALLDATACOPY:{
assert(stack.size() == 3);
DataWord memOffsetData = program.stackPop();
DataWord dataOffsetData = program.stackPop();
DataWord lengthData = program.stackPop();
// gas calculation
long price = GasCost.MEMORY * lengthData.value().intValue();
System.out.println("Spneding "+price+" gas " );
if( price < 0 ) // special case because of BigInteger to int conversion
price = Long.MAX_VALUE;
program.spendGas(price, op.name());
byte[] msgData = program.getDataCopy(dataOffsetData, lengthData);
if (logger.isInfoEnabled())
@ -525,6 +572,7 @@ public class VM {
program.step();
} break;
case CODECOPY:{
assert(stack.size() == 3);
DataWord memOffsetData = program.stackPop();
DataWord codeOffsetData = program.stackPop();
DataWord lengthData = program.stackPop();
@ -614,10 +662,12 @@ public class VM {
program.step();
} break;
case POP:{
assert(stack.size() == 1);
program.stackPop();
program.step();
} break;
case DUP:{
assert(stack.size() == 1);
DataWord word_1 = program.stackPop();
DataWord word_2 = word_1.clone();
program.stackPush(word_1);
@ -625,6 +675,7 @@ public class VM {
program.step();
} break;
case SWAP:{
assert(stack.size() == 2);
DataWord word_1 = program.stackPop();
DataWord word_2 = program.stackPop();
program.stackPush(word_1);
@ -632,6 +683,7 @@ public class VM {
program.step();
} break;
case MLOAD:{
assert(stack.size() == 1);
DataWord addr = program.stackPop();
DataWord data = program.memoryLoad(addr);
@ -642,6 +694,7 @@ public class VM {
program.step();
} break;
case MSTORE:{
assert(stack.size() == 2);
DataWord addr = program.stackPop();
DataWord value = program.stackPop();
@ -652,6 +705,7 @@ public class VM {
program.step();
} break;
case MSTORE8:{
assert(stack.size() == 2);
DataWord addr = program.stackPop();
DataWord value = program.stackPop();
byte[] byteVal = {value.getData()[31]};
@ -659,6 +713,7 @@ public class VM {
program.step();
} break;
case SLOAD:{
assert(stack.size() == 1);
DataWord key = program.stackPop();
DataWord val = program.storageLoad(key);
@ -672,6 +727,7 @@ public class VM {
program.step();
} break;
case SSTORE:{
assert(stack.size() == 2);
DataWord addr = program.stackPop();
DataWord value = program.stackPop();
@ -682,6 +738,7 @@ public class VM {
program.step();
} break;
case JUMP:{
assert(stack.size() == 1);
DataWord pos = program.stackPop();
if (logger.isInfoEnabled())
@ -690,6 +747,7 @@ public class VM {
program.setPC(pos);
} break;
case JUMPI:{
assert(stack.size() == 2);
DataWord pos = program.stackPop();
DataWord cond = program.stackPop();
@ -738,7 +796,7 @@ public class VM {
case PUSH17: case PUSH18: case PUSH19: case PUSH20: case PUSH21: case PUSH22: case PUSH23: case PUSH24:
case PUSH25: case PUSH26: case PUSH27: case PUSH28: case PUSH29: case PUSH30: case PUSH31: case PUSH32:{
program.step();
int nPush = op - PUSH1.val() + 1;
int nPush = op.val() - PUSH1.val() + 1;
byte[] data = program.sweep(nPush);
hint = "" + Hex.toHexString(data);
@ -746,20 +804,22 @@ public class VM {
program.stackPush(data);
} break;
case CREATE:{
assert(stack.size() == 3);
DataWord value = program.stackPop();
DataWord inOffset = program.stackPop();
DataWord inSize = program.stackPop();
if (logger.isInfoEnabled())
logger.info(logString, program.getPC(), OpCode.code(op)
.name(), program.getGas().value(),
program.invokeData.getCallDeep(), hint);
logger.info(logString, program.getPC(), op.name(),
program.getGas().value(),
program.invokeData.getCallDeep(), hint);
program.createContract(value, inOffset, inSize);
program.step();
} break;
case CALL:{
assert(stack.size() == 7);
DataWord gas = program.stackPop();
DataWord toAddress = program.stackPop();
DataWord value = program.stackPop();
@ -771,8 +831,8 @@ public class VM {
DataWord outDataSize = program.stackPop();
if (logger.isInfoEnabled())
logger.info(logString, program.getPC(), OpCode.code(op)
.name(), program.getGas().value(),
logger.info(logString, program.getPC(), op.name(),
program.getGas().value(),
program.invokeData.getCallDeep(), hint);
program.callToAddress(gas, toAddress, value, inDataOffs, inDataSize, outDataOffs, outDataSize);
@ -780,6 +840,7 @@ public class VM {
program.step();
} break;
case RETURN:{
assert(stack.size() == 2);
DataWord offset = program.stackPop();
DataWord size = program.stackPop();
@ -793,6 +854,7 @@ public class VM {
program.stop();
} break;
case SUICIDE:{
assert(stack.size() == 1);
DataWord address = program.stackPop();
program.suicide(address);
@ -805,10 +867,10 @@ public class VM {
}
}
if (logger.isInfoEnabled() && !OpCode.code(op).equals(CALL)
&& !OpCode.code(op).equals(CREATE))
logger.info(logString, stepBefore, OpCode.code(op).name(),
gasBefore, program.invokeData.getCallDeep(), hint);
if (logger.isInfoEnabled() && !op.equals(CALL)
&& !op.equals(CREATE))
logger.info(logString, stepBefore, op.name(), gasBefore,
program.invokeData.getCallDeep(), hint);
// program.fullTrace();
} catch (RuntimeException e) {