Gas calculation first draft

This commit is contained in:
romanman 2014-06-08 09:18:27 +01:00
parent 63a87f36a8
commit c6dd4f31f9
7 changed files with 168 additions and 23 deletions

View File

@ -1,6 +1,7 @@
package org.ethereum.gui;
import org.ethereum.vm.Program;
import org.ethereum.vm.ProgramInvokeImpl;
import org.ethereum.vm.VM;
import org.spongycastle.util.encoders.Hex;
@ -32,7 +33,14 @@ public class ProgramPlayDialog extends JPanel implements ActionListener,
VM vm = new VM();
// Program program = new Program(Hex.decode("630000000060445960CC60DD611234600054615566602054630000000060445960CC60DD611234600054615566602054630000000060445960CC60DD611234600054615566602054"));
// Program program = new Program(Hex.decode("60016023576000605f556014600054601e60205463abcddcba6040545b51602001600a5254516040016014525451606001601e5254516080016028525460a052546016604860003960166000f26000603f556103e75660005460005360200235602054"), null);
Program program = new Program(Hex.decode("620f424073cd2a3d9f938e13cd947ec05abc7fe734df8dd826576086602660003960866000f26001602036040e0f630000002159600060200235600054600053565b525b54602052f263000000765833602054602053566040546000602002356060546001602002356080546080536040530a0f0f630000006c59608053604053036020535760805360605356016060535760015b525b54602052f263000000765860005b525b54602052f2"), null);
String code = "60016000546006601160003960066000f261778e600054";
// String code = "620f424073cd2a3d9f938e13cd947ec05abc7fe734df8dd826576086602660003960866000f26001602036040e0f630000002159600060200235600054600053565b525b54602052f263000000765833602054602053566040546000602002356060546001602002356080546080536040530a0f0f630000006c59608053604053036020535760805360605356016060535760015b525b54602052f263000000765860005b525b54602052f2";
byte[] codeBytes =
Hex.decode(code);
Program program = new Program(codeBytes ,
new ProgramInvokeImpl(codeBytes));
program.addListener(this);
program.fullTrace();

View File

@ -44,6 +44,9 @@ public class DataWord {
public BigInteger value(){
return new BigInteger(1, data);
}
public int intValue(){
return new BigInteger(1, data).intValue();
}
public BigInteger sValue(){
return new BigInteger(data);

View File

@ -27,16 +27,19 @@ public class Program {
byte[] ops;
int pc = 0;
byte lastOp = 0;
boolean stopped = false;
ProgramInvoke invokeData;
Map<byte[], DataWord> addressChange;
int spendGas = 0;
public Program(byte[] ops, ProgramInvoke invokeData) {
spendGas(GasCost.TRANSACTION);
spendGas(GasCost.TXDATA * invokeData.getDataSize().intValue());
if (ops == null) throw new RuntimeException("program can not run with ops: null");
this.invokeData = invokeData;
@ -47,6 +50,9 @@ public class Program {
return ops[pc];
}
public void setLastOp(byte op){
this.lastOp = op;
}
public void stackPush(byte[] data){
DataWord stackWord = new DataWord(data);
@ -203,7 +209,7 @@ public class Program {
public void spendGas(int gasValue){
// todo: check it against avail gas
// todo: out of gas will revert the changes [YP 5, 6 ]
spendGas += gasValue;
result.spendGas(gasValue);
}
public void storageSave(DataWord word1, DataWord word2){
@ -276,9 +282,7 @@ public class Program {
public void fullTrace(){
// todo: add gas to full trace calc
if (logger.isDebugEnabled()){
if (logger.isDebugEnabled() || listener != null){
StringBuilder stackData = new StringBuilder();
for (int i = 0; i < stack.size(); ++i){
@ -335,22 +339,26 @@ public class Program {
logger.debug(" -- STORAGE -- {}\n", storageData);
StringBuilder global = new StringBuilder("\n");
StringBuilder globalOutput = new StringBuilder("\n");
if (stackData.length() > 0) stackData.append("\n");
global.append(" -- OPS -- ").append(opsString).append("\n");
global.append(" -- STACK -- ").append(stackData).append("\n");
global.append(" -- MEMORY -- ").append(memoryData).append("\n");
global.append(" -- STORAGE -- ").append(storageData).append("\n");
if (pc != 0)
globalOutput.append("[Op: ").append(OpCode.code(lastOp).name()).append("]\n");
globalOutput.append(" -- OPS -- ").append(opsString).append("\n");
globalOutput.append(" -- STACK -- ").append(stackData).append("\n");
globalOutput.append(" -- MEMORY -- ").append(memoryData).append("\n");
globalOutput.append(" -- STORAGE -- ").append(storageData).append("\n");
if (result.gethReturn() != null){
global.append("\n HReturn: ").append(Hex.toHexString(result.gethReturn().array()));
globalOutput.append("\n HReturn: ").append(Hex.toHexString(result.gethReturn().array()));
}
globalOutput.append("\n\n Spent Gas: ").append(result.getGasUsed());
if (listener != null){
listener.output(global.toString());
listener.output(globalOutput.toString());
}
};
}

View File

@ -0,0 +1,121 @@
package org.ethereum.vm;
import org.ethereum.crypto.ECKey;
import org.ethereum.crypto.HashUtil;
import org.spongycastle.util.encoders.Hex;
/**
* www.ethereumJ.com
* @author: Roman Mandeleil
* Created on: 03/06/2014 15:00
*/
public class ProgramInvokeImpl implements ProgramInvoke {
byte[] msgData;
public ProgramInvokeImpl(byte[] msgDataRaw){
this.msgData = msgDataRaw;
}
public ProgramInvokeImpl() {
}
/* ADDRESS op */
public DataWord getOwnerAddress(){
byte[] cowPrivKey = HashUtil.sha3("cow".getBytes());
byte[] addr = ECKey.fromPrivate(cowPrivKey).getAddress();
return new DataWord(addr);
}
/* BALANCE op */
public DataWord getBalance(){
byte[] balance = Hex.decode("0DE0B6B3A7640000");
return new DataWord(balance);
}
/* ORIGIN op */
public DataWord getOriginAddress(){
byte[] cowPrivKey = HashUtil.sha3("horse".getBytes());
byte[] addr = ECKey.fromPrivate(cowPrivKey).getAddress();
return new DataWord(addr);
}
/* CALLER op */
public DataWord getCallerAddress(){
byte[] cowPrivKey = HashUtil.sha3("monkey".getBytes());
byte[] addr = ECKey.fromPrivate(cowPrivKey).getAddress();
return new DataWord(addr);
}
/* GASPRICE op */
public DataWord getMinGasPrice(){
byte[] minGasPrice = Hex.decode("09184e72a000");
return new DataWord(minGasPrice);
}
/* CALLVALUE op */
public DataWord getCallValue(){
byte[] balance = Hex.decode("0DE0B6B3A7640000");
return new DataWord(balance);
}
/*****************/
/*** msg data ***/
/*****************/
/* CALLDATALOAD op */
public DataWord getDataValue(DataWord indexData){
byte[] data = new byte[32];
int index = indexData.value().intValue();
int size = 32;
if (msgData == null) return new DataWord(data);
if (index > msgData.length) return new DataWord(data);
if (index + 32 > msgData.length) size = msgData.length - index ;
System.arraycopy(msgData, index, data, 0, size);
return new DataWord(data);
}
/* CALLDATASIZE */
public DataWord getDataSize(){
if (msgData == null || msgData.length == 0) return new DataWord(new byte[32]);
int size = msgData.length;
return new DataWord(size);
}
/* CALLDATACOPY */
public byte[] getDataCopy(DataWord offsetData, DataWord lengthData){
int offset = offsetData.value().intValue();
int length = lengthData.value().intValue();
byte[] data = new byte[length];
if (msgData == null) return data;
if (offset > msgData.length) return data;
if (offset + length > msgData.length) length = msgData.length - offset ;
System.arraycopy(msgData, offset, data, 0, length);
return data;
}
}

View File

@ -32,6 +32,10 @@ public class ProgramResult {
return exception;
}
public int getGasUsed() {
return gasUsed;
}
public void setException(RuntimeException exception) {
this.exception = exception;
}

View File

@ -58,6 +58,7 @@ public class VM {
try {
byte op = program.getCurrentOp();
program.setLastOp(op);
logger.debug("Op: {}" ,OpCode.code(op).name());
int oldMemSize = program.getMemSize();
@ -70,8 +71,6 @@ public class VM {
program.spendGas(GasCost.SLOAD);
break;
case SSTORE:
// todo: calc gas in the execution
// todo: according to the size
break;
case BALANCE:
program.spendGas(GasCost.BALANCE);
@ -84,8 +83,9 @@ public class VM {
break;
case MSTORE8:
case MSTORE:
// todo: calc gas in the execution
// todo: according to the size
// TODO: [cpp impl] do this when [go impl] spend just the usage size
// TODO: https://github.com/ethereum/cpp-ethereum/blob/develop/libevm/VM.h#L183
program.spendGas(GasCost.STEP);
break;
default:
program.spendGas(GasCost.STEP);
@ -527,11 +527,12 @@ public class VM {
} break;
default:{
}
// memory gas calc
int newMemSize = program.getMemSize();
program.spendGas(GasCost.MEMORY * (newMemSize - oldMemSize) /32);
}
// memory gas calc
int newMemSize = program.getMemSize();
program.spendGas(GasCost.MEMORY * (newMemSize - oldMemSize) /32);
program.fullTrace();
} catch (RuntimeException e) {
program.stop();

View File

@ -14,7 +14,7 @@ log4j.logger.java.nio = WARN
log4j.logger.io.netty = FATAL
log4j.logger.org.ethereum.core = FATAL
log4j.logger.wire = FATAL
log4j.logger.VM = FATAL
log4j.logger.VM = DEBUG
log4j.logger.main = FATAL
log4j.logger.state = FATAL
log4j.logger.blockchain = FATAL