diff --git a/ethereumj-core/src/main/java/org/ethereum/gui/ProgramPlayDialog.java b/ethereumj-core/src/main/java/org/ethereum/gui/ProgramPlayDialog.java index 39b7110e..a1de74f3 100644 --- a/ethereumj-core/src/main/java/org/ethereum/gui/ProgramPlayDialog.java +++ b/ethereumj-core/src/main/java/org/ethereum/gui/ProgramPlayDialog.java @@ -47,7 +47,7 @@ public class ProgramPlayDialog extends JPanel implements ActionListener, // Hex.decode(code); Program program = new Program(tx.getData() , - ProgramInvokeFactory.createProgramInvoke(tx)); + ProgramInvokeFactory.createProgramInvoke(tx, null)); program.addListener(this); program.fullTrace(); diff --git a/ethereumj-core/src/main/java/org/ethereum/manager/WorldManager.java b/ethereumj-core/src/main/java/org/ethereum/manager/WorldManager.java index 3e7960ce..43c6d482 100644 --- a/ethereumj-core/src/main/java/org/ethereum/manager/WorldManager.java +++ b/ethereumj-core/src/main/java/org/ethereum/manager/WorldManager.java @@ -2,6 +2,7 @@ package org.ethereum.manager; import org.ethereum.core.AccountState; import org.ethereum.core.Block; +import org.ethereum.core.Blockchain; import org.ethereum.core.Transaction; import org.ethereum.crypto.HashUtil; import org.ethereum.db.Database; @@ -105,8 +106,11 @@ public class WorldManager { byte[] initCode = tx.getData(); + Block lastBlock = + MainData.instance.getBlockchain().getLastBlock(); + ProgramInvoke programInvoke = - ProgramInvokeFactory.createProgramInvoke(tx); + ProgramInvokeFactory.createProgramInvoke(tx, lastBlock); VM vm = new VM(); Program program = new Program(initCode, programInvoke); diff --git a/ethereumj-core/src/main/java/org/ethereum/vm/DataWord.java b/ethereumj-core/src/main/java/org/ethereum/vm/DataWord.java index 8d9b98f6..5f391c62 100644 --- a/ethereumj-core/src/main/java/org/ethereum/vm/DataWord.java +++ b/ethereumj-core/src/main/java/org/ethereum/vm/DataWord.java @@ -31,6 +31,14 @@ public class DataWord { this.data = data.array(); } + public DataWord(long num) { + ByteBuffer bLong = ByteBuffer.allocate(8).putLong(num); + ByteBuffer data = ByteBuffer.allocate(32); + System.arraycopy(bLong.array(), 0, data.array(), 24, 8); + this.data = data.array(); + } + + public DataWord(byte[] data) { if (data == null){ diff --git a/ethereumj-core/src/main/java/org/ethereum/vm/Program.java b/ethereumj-core/src/main/java/org/ethereum/vm/Program.java index 9bc189e4..2479c8a3 100644 --- a/ethereumj-core/src/main/java/org/ethereum/vm/Program.java +++ b/ethereumj-core/src/main/java/org/ethereum/vm/Program.java @@ -242,11 +242,17 @@ public class Program { return invokeData.getCallerAddress(); } - public DataWord getMinGasPrice(){ + public DataWord getGasPrice(){ if (invokeData == null) return new DataWord( new byte[0]); return invokeData.getMinGasPrice(); } + public DataWord getGas(){ + if (invokeData == null) return new DataWord( new byte[0]); + return invokeData.getGas(); + } + + public DataWord getCallValue(){ if (invokeData == null) return new DataWord( new byte[0]); return invokeData.getCallValue(); @@ -271,6 +277,30 @@ public class Program { return storage.get(key); } + public DataWord getPrevHash(){ + return invokeData.getPrevHash(); + } + + public DataWord getCoinbase(){ + return invokeData.getCoinbase(); + } + + public DataWord getTimestamp(){ + return invokeData.getTimestamp(); + } + + public DataWord getNumber(){ + return invokeData.getNumber(); + } + + public DataWord getDifficulty(){ + return invokeData.getDifficulty(); + } + + public DataWord getGaslimit(){ + return invokeData.getGaslimit(); + } + public ProgramResult getResult() { return result; diff --git a/ethereumj-core/src/main/java/org/ethereum/vm/ProgramInvoke.java b/ethereumj-core/src/main/java/org/ethereum/vm/ProgramInvoke.java index a5c0ca9b..f84a7131 100644 --- a/ethereumj-core/src/main/java/org/ethereum/vm/ProgramInvoke.java +++ b/ethereumj-core/src/main/java/org/ethereum/vm/ProgramInvoke.java @@ -14,11 +14,17 @@ public interface ProgramInvoke { public DataWord getOriginAddress(); public DataWord getCallerAddress(); public DataWord getMinGasPrice(); + public DataWord getGas(); public DataWord getCallValue(); - - public DataWord getDataSize(); public DataWord getDataValue(DataWord indexData); - public byte[] getDataCopy(DataWord offsetData, DataWord lengthData); + public byte[] getDataCopy(DataWord offsetData, DataWord lengthData); + + public DataWord getPrevHash(); + public DataWord getCoinbase(); + public DataWord getTimestamp(); + public DataWord getNumber(); + public DataWord getDifficulty(); + public DataWord getGaslimit(); } diff --git a/ethereumj-core/src/main/java/org/ethereum/vm/ProgramInvokeImpl.java b/ethereumj-core/src/main/java/org/ethereum/vm/ProgramInvokeImpl.java index 0978934f..65aa8ba5 100644 --- a/ethereumj-core/src/main/java/org/ethereum/vm/ProgramInvokeImpl.java +++ b/ethereumj-core/src/main/java/org/ethereum/vm/ProgramInvokeImpl.java @@ -1,8 +1,6 @@ package org.ethereum.vm; -import org.ethereum.crypto.ECKey; -import org.ethereum.crypto.HashUtil; -import org.spongycastle.util.encoders.Hex; +import org.ethereum.util.ByteUtil; /** * www.ethereumJ.com @@ -12,6 +10,7 @@ import org.spongycastle.util.encoders.Hex; public class ProgramInvokeImpl implements ProgramInvoke { + /*** TRANSACTION env ***/ DataWord address; DataWord origin; DataWord caller; @@ -22,14 +21,22 @@ public class ProgramInvokeImpl implements ProgramInvoke { byte[] msgData; + /*** BLOCK env ***/ + DataWord prevHash; + DataWord coinbase; + DataWord timestamp; + DataWord number; + DataWord difficulty; + DataWord gaslimit; + - public ProgramInvokeImpl(byte[] msgDataRaw){ - this.msgData = msgDataRaw; - } public ProgramInvokeImpl(byte[] address, byte[] origin, byte[] caller, byte[] balance, - byte[] gasPrice, byte[] gas, byte[] callValue, byte[] msgData) { + byte[] gasPrice, byte[] gas, byte[] callValue, byte[] msgData, + byte[] lastHash, byte[] coinbase, long timestamp, long number, byte[] difficulty, + long gaslimit) { + // Transaction env this.address = new DataWord(address); this.origin = new DataWord(origin); this.caller = new DataWord(caller); @@ -37,8 +44,16 @@ public class ProgramInvokeImpl implements ProgramInvoke { this.gasPrice = new DataWord(gasPrice); this.gas = new DataWord(gas); this.callValue = new DataWord(callValue); - this.msgData = msgData; + + // last Block env + this.prevHash = new DataWord(lastHash); + this.coinbase = new DataWord(coinbase); + this.timestamp = new DataWord(timestamp); + this.number = new DataWord(number); + this.difficulty = new DataWord(difficulty); + this.gaslimit = new DataWord(gaslimit); + } /* ADDRESS op */ @@ -67,6 +82,12 @@ public class ProgramInvokeImpl implements ProgramInvoke { return gasPrice; } + /* GAS op */ + public DataWord getGas(){ + return gas; + } + + /* CALLVALUE op */ public DataWord getCallValue(){ @@ -120,4 +141,34 @@ public class ProgramInvokeImpl implements ProgramInvoke { return data; } + + /* PREVHASH op */ + public DataWord getPrevHash() { + return prevHash; + } + + /* COINBASE op */ + public DataWord getCoinbase() { + return coinbase; + } + + /* TIMESTAMP op */ + public DataWord getTimestamp() { + return timestamp; + } + + /* NUMBER op */ + public DataWord getNumber() { + return number; + } + + /* DIFFICULTY op */ + public DataWord getDifficulty() { + return difficulty; + } + + /* GASLIMIT op */ + public DataWord getGaslimit() { + return gaslimit; + } } diff --git a/ethereumj-core/src/main/java/org/ethereum/vm/VM.java b/ethereumj-core/src/main/java/org/ethereum/vm/VM.java index 56f5c28b..884be8d2 100644 --- a/ethereumj-core/src/main/java/org/ethereum/vm/VM.java +++ b/ethereumj-core/src/main/java/org/ethereum/vm/VM.java @@ -332,7 +332,6 @@ public class VM { } break; case CALLDATASIZE:{ DataWord dataSize = program.getDataSize(); - program.stackPush(dataSize); program.step(); } break; @@ -370,34 +369,47 @@ public class VM { program.memorySave(memOffsetData.getData(), code); program.step(); } break; - case GASPRICE: - + case GASPRICE:{ + DataWord gasPrice = program.getGasPrice(); + program.stackPush(gasPrice); program.step(); - break; + } break; /** * Block Information */ - case PREVHASH: + case PREVHASH: { + DataWord prevHash = program.getPrevHash(); + program.stackPush(prevHash); program.step(); - break; - case COINBASE: + } break; + case COINBASE: { + DataWord coinbase = program.getCoinbase(); + program.stackPush(coinbase); program.step(); - break; - case TIMESTAMP: + } break; + case TIMESTAMP:{ + DataWord timestamp = program.getTimestamp(); + program.stackPush(timestamp); program.step(); - break; - case NUMBER: + } break; + case NUMBER:{ + DataWord number = program.getNumber(); + program.stackPush(number); program.step(); - break; - case DIFFICULTY: + } break; + case DIFFICULTY:{ + DataWord difficulty = program.getDifficulty(); + program.stackPush(difficulty); program.step(); - break; - case GASLIMIT: + } break; + case GASLIMIT:{ + DataWord gaslimit = program.getGaslimit(); + program.stackPush(gaslimit); program.step(); - break; + } break; case POP:{ program.stackPop(); program.step(); @@ -485,9 +497,12 @@ public class VM { program.stackPush(wordMemSize); program.step(); } break; - case GAS: + case GAS:{ + DataWord gas = program.getGas(); + program.stackPush(gas); program.step(); - break; + } break; + case PUSH1: case PUSH2: case PUSH3: case PUSH4: case PUSH5: case PUSH6: case PUSH7: case PUSH8: case PUSH9: case PUSH10: case PUSH11: case PUSH12: case PUSH13: case PUSH14: case PUSH15: case PUSH16: diff --git a/ethereumj-core/src/test/java/org/ethereum/vm/ProgramInvokeMockImpl.java b/ethereumj-core/src/test/java/org/ethereum/vm/ProgramInvokeMockImpl.java index 84947fa7..ffd8c25d 100644 --- a/ethereumj-core/src/test/java/org/ethereum/vm/ProgramInvokeMockImpl.java +++ b/ethereumj-core/src/test/java/org/ethereum/vm/ProgramInvokeMockImpl.java @@ -56,7 +56,6 @@ public class ProgramInvokeMockImpl implements ProgramInvoke { return new DataWord(addr); } - /* GASPRICE op */ public DataWord getMinGasPrice(){ @@ -64,6 +63,11 @@ public class ProgramInvokeMockImpl implements ProgramInvoke { return new DataWord(minGasPrice); } + /* GAS op */ + public DataWord getGas() { + byte[] minGasPrice = Hex.decode("03E8"); + return new DataWord(minGasPrice); + } /* CALLVALUE op */ public DataWord getCallValue(){ @@ -118,4 +122,40 @@ public class ProgramInvokeMockImpl implements ProgramInvoke { return data; } + + @Override + public DataWord getPrevHash() { + byte[] prevHash = Hex.decode("961CB117ABA86D1E596854015A1483323F18883C2D745B0BC03E87F146D2BB1C"); + return new DataWord(prevHash); + } + + @Override + public DataWord getCoinbase() { + byte[] coinBase = Hex.decode("E559DE5527492BCB42EC68D07DF0742A98EC3F1E"); + return new DataWord(coinBase); + } + + @Override + public DataWord getTimestamp() { + long timestamp = 1401421348; + return new DataWord(timestamp); + } + + @Override + public DataWord getNumber() { + long number = 33; + return new DataWord(number); + } + + @Override + public DataWord getDifficulty() { + byte[] difficulty = Hex.decode("3ED290"); + return new DataWord(difficulty); + } + + @Override + public DataWord getGaslimit() { + long gasLimit = 968269; + return new DataWord(gasLimit); + } } diff --git a/ethereumj-core/src/test/java/org/ethereum/vm/VMTest.java b/ethereumj-core/src/test/java/org/ethereum/vm/VMTest.java index 8934e0bb..8bfd4205 100644 --- a/ethereumj-core/src/test/java/org/ethereum/vm/VMTest.java +++ b/ethereumj-core/src/test/java/org/ethereum/vm/VMTest.java @@ -2802,6 +2802,131 @@ public class VMTest { fail(); } + @Test // PREVHASH OP + public void testPREVHASH_1(){ + + VM vm = new VM(); + Program program = + new Program(Hex.decode("40"), + createProgramInvoke_1()); + String s_expected_1 = "961CB117ABA86D1E596854015A1483323F18883C2D745B0BC03E87F146D2BB1C"; + + vm.step(program); + + DataWord item1 = program.stack.pop(); + assertEquals(s_expected_1, Hex.toHexString(item1.data).toUpperCase()); + } + + + @Test // COINBASE OP + public void testCOINBASE_1(){ + + VM vm = new VM(); + Program program = + new Program(Hex.decode("41"), + createProgramInvoke_1()); + String s_expected_1 = "000000000000000000000000E559DE5527492BCB42EC68D07DF0742A98EC3F1E"; + + vm.step(program); + + DataWord item1 = program.stack.pop(); + assertEquals(s_expected_1, Hex.toHexString(item1.data).toUpperCase()); + } + + @Test // TIMESTAMP OP + public void testTIMESTAMP_1(){ + + VM vm = new VM(); + Program program = + new Program(Hex.decode("42"), + createProgramInvoke_1()); + String s_expected_1 = "000000000000000000000000000000000000000000000000000000005387FE24"; + + vm.step(program); + + DataWord item1 = program.stack.pop(); + assertEquals(s_expected_1, Hex.toHexString(item1.data).toUpperCase()); + } + + + @Test // NUMBER OP + public void testNUMBER_1(){ + + VM vm = new VM(); + Program program = + new Program(Hex.decode("43"), + createProgramInvoke_1()); + String s_expected_1 = "0000000000000000000000000000000000000000000000000000000000000021"; + + vm.step(program); + + DataWord item1 = program.stack.pop(); + assertEquals(s_expected_1, Hex.toHexString(item1.data).toUpperCase()); + } + + @Test // DIFFICULTY OP + public void testDIFFICULTY_1(){ + + VM vm = new VM(); + Program program = + new Program(Hex.decode("44"), + createProgramInvoke_1()); + String s_expected_1 = "00000000000000000000000000000000000000000000000000000000003ED290"; + + vm.step(program); + + DataWord item1 = program.stack.pop(); + assertEquals(s_expected_1, Hex.toHexString(item1.data).toUpperCase()); + } + + + @Test // GASPRICE OP + public void testGASPRICE_1(){ + + VM vm = new VM(); + Program program = + new Program(Hex.decode("3A"), + createProgramInvoke_1()); + String s_expected_1 = "000000000000000000000000000000000000000000000000000009184E72A000"; + + vm.step(program); + + DataWord item1 = program.stack.pop(); + assertEquals(s_expected_1, Hex.toHexString(item1.data).toUpperCase()); + } + + @Test // GAS OP + public void testGAS_1(){ + + VM vm = new VM(); + Program program = + new Program(Hex.decode("5C"), + createProgramInvoke_1()); + String s_expected_1 = "00000000000000000000000000000000000000000000000000000000000003E8"; + + vm.step(program); + + DataWord item1 = program.stack.pop(); + assertEquals(s_expected_1, Hex.toHexString(item1.data).toUpperCase()); + } + + @Test // GASLIMIT OP + public void testGASLIMIT_1(){ + + VM vm = new VM(); + Program program = + new Program(Hex.decode("45"), + createProgramInvoke_1()); + String s_expected_1 = "00000000000000000000000000000000000000000000000000000000000EC64D"; + + + vm.step(program); + + DataWord item1 = program.stack.pop(); + assertEquals(s_expected_1, Hex.toHexString(item1.data).toUpperCase()); + } + + /* TEST CASE LIST END */ @@ -2827,16 +2952,6 @@ public class VMTest { /** * todo: * - * 15) PREVHASH: - * 16) COINBASE: - * 17) TIMESTAMP: - * 18) NUMBER: - * 19) DIFFICULTY: - - * 20) GASPRICE - * 20) GASLIMIT - * 20) GAS - * * 22) CREATE: * 23) CALL: * @@ -2846,8 +2961,8 @@ public class VMTest { /** - contract creation - ----------------- + contract creation (gas usage) + ----------------------------- G_TRANSACTION = (500) 60016000546006601160003960066000f261778e600054 (115) PUSH1 6001 (1)