From 075b8813b82de10762a6dd558027efb2509e6a59 Mon Sep 17 00:00:00 2001 From: Anton Nahsatyrev Date: Mon, 17 Oct 2016 03:55:33 +0300 Subject: [PATCH] EIP150 implementation Resolves #571 (cherry picked from commit d6b7d83) --- .../org/ethereum/config/BlockchainConfig.java | 29 ++ .../config/blockchain/AbstractConfig.java | 24 ++ .../config/blockchain/Eip150HFConfig.java | 111 ++++++ .../config/blockchain/HomesteadConfig.java | 5 +- .../config/blockchain/OlympicConfig.java | 4 +- .../ethereum/config/net/MainNetConfig.java | 2 + .../ethereum/core/TransactionExecutor.java | 6 +- .../main/java/org/ethereum/util/Utils.java | 12 + .../main/java/org/ethereum/vm/GasCost.java | 315 +++++++++++++++--- .../src/main/java/org/ethereum/vm/VM.java | 160 +++++---- .../java/org/ethereum/vm/program/Program.java | 14 +- .../jsontestsuite/GitHubBlockTest.java | 46 ++- .../jsontestsuite/GitHubStateTest.java | 92 ++++- 13 files changed, 666 insertions(+), 154 deletions(-) create mode 100644 ethereumj-core/src/main/java/org/ethereum/config/blockchain/Eip150HFConfig.java diff --git a/ethereumj-core/src/main/java/org/ethereum/config/BlockchainConfig.java b/ethereumj-core/src/main/java/org/ethereum/config/BlockchainConfig.java index 489ff653f6..4ff2b772d3 100644 --- a/ethereumj-core/src/main/java/org/ethereum/config/BlockchainConfig.java +++ b/ethereumj-core/src/main/java/org/ethereum/config/BlockchainConfig.java @@ -8,6 +8,10 @@ import org.ethereum.db.BlockStore; import org.ethereum.db.RepositoryTrack; import org.ethereum.mine.MinerIfc; +import org.ethereum.vm.DataWord; +import org.ethereum.vm.GasCost; +import org.ethereum.vm.OpCode; +import org.ethereum.vm.program.Program; import java.math.BigInteger; import java.util.List; @@ -63,5 +67,30 @@ String validateTransactionChanges(BlockStore blockStore, Block curBlock, Transac */ void hardForkTransfers(Block block, Repository repo); + /** + * Hardcode the block hashes. I.e. if the block #1920000 should have the hash 0x1111 + * the this method should return [{1920000, 0x1111}] + */ List> blockHashConstraints(); + + /** + * EVM operations costs + */ + GasCost getGasCost(); + + /** + * Calculates available gas to be passed for callee + * Since EIP150 + * @param op Opcode + * @param requestedGas amount of gas requested by the program + * @param availableGas available gas + * @throws Program.OutOfGasException If passed args doesn't conform to limitations + */ + DataWord getCallGas(OpCode op, DataWord requestedGas, DataWord availableGas) throws Program.OutOfGasException; + + /** + * Calculates available gas to be passed for contract constructor + * Since EIP150 + */ + DataWord getCreateGas(DataWord availableGas); } diff --git a/ethereumj-core/src/main/java/org/ethereum/config/blockchain/AbstractConfig.java b/ethereumj-core/src/main/java/org/ethereum/config/blockchain/AbstractConfig.java index d9984d158d..b854d01ae6 100644 --- a/ethereumj-core/src/main/java/org/ethereum/config/blockchain/AbstractConfig.java +++ b/ethereumj-core/src/main/java/org/ethereum/config/blockchain/AbstractConfig.java @@ -13,6 +13,10 @@ import org.ethereum.db.RepositoryTrack; import org.ethereum.mine.EthashMiner; import org.ethereum.mine.MinerIfc; +import org.ethereum.vm.DataWord; +import org.ethereum.vm.GasCost; +import org.ethereum.vm.OpCode; +import org.ethereum.vm.program.Program; import java.math.BigInteger; import java.util.Collections; @@ -27,6 +31,8 @@ * Created by Anton Nashatyrev on 25.02.2016. */ public abstract class AbstractConfig implements BlockchainConfig, BlockchainNetConfig { + private static final GasCost GAS_COST = new GasCost(); + protected Constants constants; protected MinerIfc miner; @@ -98,4 +104,22 @@ public void hardForkTransfers(Block block, Repository repo) {} public List> blockHashConstraints() { return Collections.emptyList(); } + + @Override + public GasCost getGasCost() { + return GAS_COST; + } + + @Override + public DataWord getCallGas(OpCode op, DataWord requestedGas, DataWord availableGas) throws Program.OutOfGasException { + if (requestedGas.compareTo(availableGas) > 0) { + throw Program.Exception.notEnoughOpGas(op, requestedGas, availableGas); + } + return requestedGas.clone(); + } + + @Override + public DataWord getCreateGas(DataWord availableGas) { + return availableGas; + } } diff --git a/ethereumj-core/src/main/java/org/ethereum/config/blockchain/Eip150HFConfig.java b/ethereumj-core/src/main/java/org/ethereum/config/blockchain/Eip150HFConfig.java new file mode 100644 index 0000000000..fe0d1855c9 --- /dev/null +++ b/ethereumj-core/src/main/java/org/ethereum/config/blockchain/Eip150HFConfig.java @@ -0,0 +1,111 @@ +package org.ethereum.config.blockchain; + +import com.sun.org.apache.bcel.internal.generic.NEW; +import org.apache.commons.lang3.tuple.Pair; +import org.ethereum.config.BlockchainConfig; +import org.ethereum.config.BlockchainNetConfig; +import org.ethereum.config.Constants; +import org.ethereum.config.SystemProperties; +import org.ethereum.core.Block; +import org.ethereum.core.BlockHeader; +import org.ethereum.core.Repository; +import org.ethereum.core.Transaction; +import org.ethereum.db.BlockStore; +import org.ethereum.db.RepositoryTrack; +import org.ethereum.mine.MinerIfc; +import org.ethereum.util.Utils; +import org.ethereum.vm.DataWord; +import org.ethereum.vm.GasCost; +import org.ethereum.vm.OpCode; +import org.ethereum.vm.program.Program; + +import java.math.BigInteger; +import java.util.List; + +/** + * Created by Anton Nashatyrev on 14.10.2016. + */ +public class Eip150HFConfig implements BlockchainConfig, BlockchainNetConfig { + private BlockchainConfig parent; + + + private static final GasCost NEW_GAS_COST = new GasCost() { + public int getBALANCE() { return 400; } + public int getEXT_CODE_SIZE() { return 700; } + public int getEXT_CODE_COPY() { return 700; } + public int getSLOAD() { return 200; } + public int getCALL() { return 700; } + public int getSUICIDE() { return 5000; } + public int getNEW_ACCT_SUICIDE() { return 25000; } + }; + + public Eip150HFConfig(BlockchainConfig parent) { + this.parent = parent; + } + + @Override + public DataWord getCallGas(OpCode op, DataWord requestedGas, DataWord availableGas) throws Program.OutOfGasException { + DataWord maxAllowed = Utils.allButOne64th(availableGas); + return requestedGas.compareTo(maxAllowed) > 0 ? maxAllowed : requestedGas; + } + + @Override + public DataWord getCreateGas(DataWord availableGas) { + return Utils.allButOne64th(availableGas); + } + + @Override + public Constants getConstants() { + return parent.getConstants(); + } + + @Override + public MinerIfc getMineAlgorithm(SystemProperties config) { + return parent.getMineAlgorithm(config); + } + + @Override + public BigInteger calcDifficulty(BlockHeader curBlock, BlockHeader parent) { + return this.parent.calcDifficulty(curBlock, parent); + } + + @Override + public long getTransactionCost(Transaction tx) { + return parent.getTransactionCost(tx); + } + + @Override + public boolean acceptTransactionSignature(Transaction tx) { + return parent.acceptTransactionSignature(tx); + } + + @Override + public String validateTransactionChanges(BlockStore blockStore, Block curBlock, Transaction tx, RepositoryTrack repositoryTrack) { + return parent.validateTransactionChanges(blockStore, curBlock, tx, repositoryTrack); + } + + @Override + public void hardForkTransfers(Block block, Repository repo) { + parent.hardForkTransfers(block, repo); + } + + @Override + public List> blockHashConstraints() { + return parent.blockHashConstraints(); + } + + @Override + public GasCost getGasCost() { + return NEW_GAS_COST; + } + + @Override + public BlockchainConfig getConfigForBlock(long blockNumber) { + return this; + } + + @Override + public Constants getCommonConstants() { + return getConstants(); + } +} diff --git a/ethereumj-core/src/main/java/org/ethereum/config/blockchain/HomesteadConfig.java b/ethereumj-core/src/main/java/org/ethereum/config/blockchain/HomesteadConfig.java index 9efb989245..e5df7ed16b 100644 --- a/ethereumj-core/src/main/java/org/ethereum/config/blockchain/HomesteadConfig.java +++ b/ethereumj-core/src/main/java/org/ethereum/config/blockchain/HomesteadConfig.java @@ -4,7 +4,6 @@ import org.ethereum.config.Constants; import org.ethereum.core.BlockHeader; import org.ethereum.core.Transaction; -import org.ethereum.vm.GasCost; import java.math.BigInteger; @@ -45,8 +44,8 @@ public long getTransactionCost(Transaction tx) { long nonZeroes = tx.nonZeroDataBytes(); long zeroVals = ArrayUtils.getLength(tx.getData()) - nonZeroes; - return (tx.isContractCreation() ? GasCost.TRANSACTION_CREATE_CONTRACT : GasCost.TRANSACTION) - + zeroVals * GasCost.TX_ZERO_DATA + nonZeroes * GasCost.TX_NO_ZERO_DATA; + return (tx.isContractCreation() ? getGasCost().getTRANSACTION_CREATE_CONTRACT() : getGasCost().getTRANSACTION()) + + zeroVals * getGasCost().getTX_ZERO_DATA() + nonZeroes * getGasCost().getTX_NO_ZERO_DATA(); } @Override diff --git a/ethereumj-core/src/main/java/org/ethereum/config/blockchain/OlympicConfig.java b/ethereumj-core/src/main/java/org/ethereum/config/blockchain/OlympicConfig.java index fce2b08b70..8da5048906 100644 --- a/ethereumj-core/src/main/java/org/ethereum/config/blockchain/OlympicConfig.java +++ b/ethereumj-core/src/main/java/org/ethereum/config/blockchain/OlympicConfig.java @@ -4,7 +4,6 @@ import org.ethereum.config.Constants; import org.ethereum.core.BlockHeader; import org.ethereum.core.Transaction; -import org.ethereum.vm.GasCost; import java.math.BigInteger; @@ -31,6 +30,7 @@ public long getTransactionCost(Transaction tx) { long nonZeroes = tx.nonZeroDataBytes(); long zeroVals = ArrayUtils.getLength(tx.getData()) - nonZeroes; - return GasCost.TRANSACTION + zeroVals * GasCost.TX_ZERO_DATA + nonZeroes * GasCost.TX_NO_ZERO_DATA; + return getGasCost().getTRANSACTION() + zeroVals * getGasCost().getTX_ZERO_DATA() + + nonZeroes * getGasCost().getTX_NO_ZERO_DATA(); } } diff --git a/ethereumj-core/src/main/java/org/ethereum/config/net/MainNetConfig.java b/ethereumj-core/src/main/java/org/ethereum/config/net/MainNetConfig.java index de55e0a8e8..251a940e60 100644 --- a/ethereumj-core/src/main/java/org/ethereum/config/net/MainNetConfig.java +++ b/ethereumj-core/src/main/java/org/ethereum/config/net/MainNetConfig.java @@ -1,6 +1,7 @@ package org.ethereum.config.net; import org.ethereum.config.blockchain.DaoHFConfig; +import org.ethereum.config.blockchain.Eip150HFConfig; import org.ethereum.config.blockchain.FrontierConfig; import org.ethereum.config.blockchain.HomesteadConfig; @@ -14,5 +15,6 @@ public MainNetConfig() { add(0, new FrontierConfig()); add(1_150_000, new HomesteadConfig()); add(1_920_000, new DaoHFConfig()); + add(2_457_000, new Eip150HFConfig(new DaoHFConfig())); } } diff --git a/ethereumj-core/src/main/java/org/ethereum/core/TransactionExecutor.java b/ethereumj-core/src/main/java/org/ethereum/core/TransactionExecutor.java index 3a78c7da4c..59af92914d 100644 --- a/ethereumj-core/src/main/java/org/ethereum/core/TransactionExecutor.java +++ b/ethereumj-core/src/main/java/org/ethereum/core/TransactionExecutor.java @@ -264,7 +264,8 @@ public void go() { if (tx.isContractCreation()) { - int returnDataGasValue = getLength(program.getResult().getHReturn()) * GasCost.CREATE_DATA; + int returnDataGasValue = getLength(program.getResult().getHReturn()) * + config.getBlockchainConfig().getConfigForBlock(currentBlock.getNumber()).getGasCost().getCREATE_DATA(); if (m_endGas.compareTo(BigInteger.valueOf(returnDataGasValue)) >= 0) { m_endGas = m_endGas.subtract(BigInteger.valueOf(returnDataGasValue)); @@ -319,7 +320,8 @@ public TransactionExecutionSummary finalization() { if (result != null) { // Accumulate refunds for suicides - result.addFutureRefund(result.getDeleteAccounts().size() * GasCost.SUICIDE_REFUND); + result.addFutureRefund(result.getDeleteAccounts().size() * config.getBlockchainConfig(). + getConfigForBlock(currentBlock.getNumber()).getGasCost().getSUICIDE_REFUND()); long gasRefund = Math.min(result.getFutureRefund(), result.getGasUsed() / 2); byte[] addr = tx.isContractCreation() ? tx.getContractAddress() : tx.getReceiveAddress(); m_endGas = m_endGas.add(BigInteger.valueOf(gasRefund)); diff --git a/ethereumj-core/src/main/java/org/ethereum/util/Utils.java b/ethereumj-core/src/main/java/org/ethereum/util/Utils.java index eced43f021..f235243de7 100644 --- a/ethereumj-core/src/main/java/org/ethereum/util/Utils.java +++ b/ethereumj-core/src/main/java/org/ethereum/util/Utils.java @@ -1,5 +1,8 @@ package org.ethereum.util; +import org.ethereum.datasource.KeyValueDataSource; +import org.ethereum.db.ByteArrayWrapper; +import org.ethereum.vm.DataWord; import org.spongycastle.util.encoders.DecoderException; import org.spongycastle.util.encoders.Hex; @@ -21,6 +24,7 @@ import javax.swing.*; public class Utils { + private static final DataWord DIVISOR = new DataWord(64); private static SecureRandom random = new SecureRandom(); @@ -183,4 +187,12 @@ public static String repeat(String s, int n) { return ret.toString(); } } + + public static DataWord allButOne64th(DataWord dw) { + DataWord ret = dw.clone(); + DataWord d = dw.clone(); + d.div(DIVISOR); + ret.sub(d); + return ret; + } } \ No newline at end of file diff --git a/ethereumj-core/src/main/java/org/ethereum/vm/GasCost.java b/ethereumj-core/src/main/java/org/ethereum/vm/GasCost.java index 073528da14..8cdcddcebf 100644 --- a/ethereumj-core/src/main/java/org/ethereum/vm/GasCost.java +++ b/ethereumj-core/src/main/java/org/ethereum/vm/GasCost.java @@ -9,58 +9,269 @@ public class GasCost { /* backwards compatibility, remove eventually */ - public final static int STEP = 1; - public final static int SSTORE = 300; + private final int STEP = 1; + private final int SSTORE = 300; /* backwards compatibility, remove eventually */ - public final static int ZEROSTEP = 0; - public final static int QUICKSTEP = 2; - public final static int FASTESTSTEP = 3; - public final static int FASTSTEP = 5; - public final static int MIDSTEP = 8; - public final static int SLOWSTEP = 10; - public final static int EXTSTEP = 20; - - public final static int GENESISGASLIMIT = 1000000; - public final static int MINGASLIMIT = 125000; - - public final static int BALANCE = 20; - public final static int SHA3 = 30; - public final static int SHA3_WORD = 6; - public final static int SLOAD = 50; - public final static int STOP = 0; - public final static int SUICIDE = 0; - public final static int CLEAR_SSTORE = 5000; - public final static int SET_SSTORE = 20000; - public final static int RESET_SSTORE = 5000; - public final static int REFUND_SSTORE = 15000; - public final static int CREATE = 32000; - - public final static int JUMPDEST = 1; - public final static int CREATE_DATA_BYTE = 5; - public final static int CALL = 40; - public final static int STIPEND_CALL = 2300; - public final static int VT_CALL = 9000; //value transfer call - public final static int NEW_ACCT_CALL = 25000; //new account call - public final static int MEMORY = 3; - public final static int SUICIDE_REFUND = 24000; - public final static int QUAD_COEFF_DIV = 512; - public final static int CREATE_DATA = 200; - public final static int TX_NO_ZERO_DATA = 68; - public final static int TX_ZERO_DATA = 4; - public final static int TRANSACTION = 21000; - public final static int TRANSACTION_CREATE_CONTRACT = 53000; - public final static int LOG_GAS = 375; - public final static int LOG_DATA_GAS = 8; - public final static int LOG_TOPIC_GAS = 375; - public final static int COPY_GAS = 3; - public final static int EXP_GAS = 10; - public final static int EXP_BYTE_GAS = 10; - public final static int IDENTITY = 15; - public final static int IDENTITY_WORD = 3; - public final static int RIPEMD160 = 600; - public final static int RIPEMD160_WORD = 120; - public final static int SHA256 = 60; - public final static int SHA256_WORD = 12; - public final static int EC_RECOVER = 3000; + private final int ZEROSTEP = 0; + private final int QUICKSTEP = 2; + private final int FASTESTSTEP = 3; + private final int FASTSTEP = 5; + private final int MIDSTEP = 8; + private final int SLOWSTEP = 10; + private final int EXTSTEP = 20; + + private final int GENESISGASLIMIT = 1000000; + private final int MINGASLIMIT = 125000; + + private final int BALANCE = 20; + private final int SHA3 = 30; + private final int SHA3_WORD = 6; + private final int SLOAD = 50; + private final int STOP = 0; + private final int SUICIDE = 0; + private final int CLEAR_SSTORE = 5000; + private final int SET_SSTORE = 20000; + private final int RESET_SSTORE = 5000; + private final int REFUND_SSTORE = 15000; + private final int CREATE = 32000; + + private final int JUMPDEST = 1; + private final int CREATE_DATA_BYTE = 5; + private final int CALL = 40; + private final int STIPEND_CALL = 2300; + private final int VT_CALL = 9000; //value transfer call + private final int NEW_ACCT_CALL = 25000; //new account call + private final int MEMORY = 3; + private final int SUICIDE_REFUND = 24000; + private final int QUAD_COEFF_DIV = 512; + private final int CREATE_DATA = 200; + private final int TX_NO_ZERO_DATA = 68; + private final int TX_ZERO_DATA = 4; + private final int TRANSACTION = 21000; + private final int TRANSACTION_CREATE_CONTRACT = 53000; + private final int LOG_GAS = 375; + private final int LOG_DATA_GAS = 8; + private final int LOG_TOPIC_GAS = 375; + private final int COPY_GAS = 3; + private final int EXP_GAS = 10; + private final int EXP_BYTE_GAS = 10; + private final int IDENTITY = 15; + private final int IDENTITY_WORD = 3; + private final int RIPEMD160 = 600; + private final int RIPEMD160_WORD = 120; + private final int SHA256 = 60; + private final int SHA256_WORD = 12; + private final int EC_RECOVER = 3000; + private final int EXT_CODE_SIZE = 20; + private final int EXT_CODE_COPY = 20; + private final int NEW_ACCT_SUICIDE = 0; + + public int getSTEP() { + return STEP; + } + + public int getSSTORE() { + return SSTORE; + } + + public int getZEROSTEP() { + return ZEROSTEP; + } + + public int getQUICKSTEP() { + return QUICKSTEP; + } + + public int getFASTESTSTEP() { + return FASTESTSTEP; + } + + public int getFASTSTEP() { + return FASTSTEP; + } + + public int getMIDSTEP() { + return MIDSTEP; + } + + public int getSLOWSTEP() { + return SLOWSTEP; + } + + public int getEXTSTEP() { + return EXTSTEP; + } + + public int getGENESISGASLIMIT() { + return GENESISGASLIMIT; + } + + public int getMINGASLIMIT() { + return MINGASLIMIT; + } + + public int getBALANCE() { + return BALANCE; + } + + public int getSHA3() { + return SHA3; + } + + public int getSHA3_WORD() { + return SHA3_WORD; + } + + public int getSLOAD() { + return SLOAD; + } + + public int getSTOP() { + return STOP; + } + + public int getSUICIDE() { + return SUICIDE; + } + + public int getCLEAR_SSTORE() { + return CLEAR_SSTORE; + } + + public int getSET_SSTORE() { + return SET_SSTORE; + } + + public int getRESET_SSTORE() { + return RESET_SSTORE; + } + + public int getREFUND_SSTORE() { + return REFUND_SSTORE; + } + + public int getCREATE() { + return CREATE; + } + + public int getJUMPDEST() { + return JUMPDEST; + } + + public int getCREATE_DATA_BYTE() { + return CREATE_DATA_BYTE; + } + + public int getCALL() { + return CALL; + } + + public int getSTIPEND_CALL() { + return STIPEND_CALL; + } + + public int getVT_CALL() { + return VT_CALL; + } + + public int getNEW_ACCT_CALL() { + return NEW_ACCT_CALL; + } + + public int getNEW_ACCT_SUICIDE() { + return NEW_ACCT_SUICIDE; + } + + public int getMEMORY() { + return MEMORY; + } + + public int getSUICIDE_REFUND() { + return SUICIDE_REFUND; + } + + public int getQUAD_COEFF_DIV() { + return QUAD_COEFF_DIV; + } + + public int getCREATE_DATA() { + return CREATE_DATA; + } + + public int getTX_NO_ZERO_DATA() { + return TX_NO_ZERO_DATA; + } + + public int getTX_ZERO_DATA() { + return TX_ZERO_DATA; + } + + public int getTRANSACTION() { + return TRANSACTION; + } + + public int getTRANSACTION_CREATE_CONTRACT() { + return TRANSACTION_CREATE_CONTRACT; + } + + public int getLOG_GAS() { + return LOG_GAS; + } + + public int getLOG_DATA_GAS() { + return LOG_DATA_GAS; + } + + public int getLOG_TOPIC_GAS() { + return LOG_TOPIC_GAS; + } + + public int getCOPY_GAS() { + return COPY_GAS; + } + + public int getEXP_GAS() { + return EXP_GAS; + } + + public int getEXP_BYTE_GAS() { + return EXP_BYTE_GAS; + } + + public int getIDENTITY() { + return IDENTITY; + } + + public int getIDENTITY_WORD() { + return IDENTITY_WORD; + } + + public int getRIPEMD160() { + return RIPEMD160; + } + + public int getRIPEMD160_WORD() { + return RIPEMD160_WORD; + } + + public int getSHA256() { + return SHA256; + } + + public int getSHA256_WORD() { + return SHA256_WORD; + } + + public int getEC_RECOVER() { + return EC_RECOVER; + } + + public int getEXT_CODE_SIZE() { + return EXT_CODE_SIZE; + } + + public int getEXT_CODE_COPY() { + return EXT_CODE_COPY; + } } 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 18894647cc..cb501a936c 100644 --- a/ethereumj-core/src/main/java/org/ethereum/vm/VM.java +++ b/ethereumj-core/src/main/java/org/ethereum/vm/VM.java @@ -1,5 +1,6 @@ package org.ethereum.vm; +import org.ethereum.config.BlockchainConfig; import org.ethereum.config.SystemProperties; import org.ethereum.db.ContractDetails; import org.ethereum.vm.MessageCall.MsgType; @@ -68,7 +69,7 @@ public class VM { private static BigInteger _32_ = BigInteger.valueOf(32); private static final String logString = "{} Op: [{}] Gas: [{}] Deep: [{}] Hint: [{}]"; - private static BigInteger MAX_GAS = BigInteger.valueOf(Long.MAX_VALUE); + private static BigInteger MAX_GAS = BigInteger.valueOf(Long.MAX_VALUE / 2); /* Keeps track of the number of steps performed in this VM */ @@ -91,6 +92,32 @@ public VM(SystemProperties config) { dumpBlock = config.dumpBlock(); } + private long calcMemGas(GasCost gasCosts, long oldMemSize, BigInteger newMemSize, long copySize) { + long gasCost = 0; + + // Avoid overflows + if (newMemSize.compareTo(MAX_GAS) == 1) { + throw Program.Exception.gasOverflow(newMemSize, MAX_GAS); + } + + // memory gas calc + long memoryUsage = (newMemSize.longValue() + 31) / 32 * 32; + if (memoryUsage > oldMemSize) { + long memWords = (memoryUsage / 32); + long memWordsOld = (oldMemSize / 32); + //TODO #POC9 c_quadCoeffDiv = 512, this should be a constant, not magic number + long memGas = ( gasCosts.getMEMORY() * memWords + memWords * memWords / 512) + - (gasCosts.getMEMORY() * memWordsOld + memWordsOld * memWordsOld / 512); + gasCost += memGas; + } + + if (copySize > 0) { + long copyGas = gasCosts.getCOPY_GAS() * ((copySize + 31) / 32); + gasCost += copyGas; + } + return gasCost; + } + public void step(Program program) { if (vmTrace) { @@ -98,14 +125,15 @@ public void step(Program program) { } try { + BlockchainConfig blockchainConfig = program.getBlockchainConfig(); + OpCode op = OpCode.code(program.getCurrentOp()); if (op == null) { throw Program.Exception.invalidOpCode(program.getCurrentOp()); } if (op == DELEGATECALL) { // opcode since Homestead release only - if (!config.getBlockchainConfig().getConfigForBlock(program.getNumber().longValue()). - getConstants().hasDelegateCallOpcode()) { + if (!blockchainConfig.getConstants().hasDelegateCallOpcode()) { throw Program.Exception.invalidOpCode(program.getCurrentOp()); } } @@ -115,8 +143,6 @@ public void step(Program program) { program.verifyStackOverflow(op.require(), op.ret()); //Check not exceeding stack limits long oldMemSize = program.getMemSize(); - BigInteger newMemSize = BigInteger.ZERO; - long copySize = 0; Stack stack = program.getStack(); String hint = ""; @@ -124,6 +150,8 @@ public void step(Program program) { long gasCost = op.getTier().asInt(); long gasBefore = program.getGas().longValue(); int stepBefore = program.getPC(); + GasCost gasCosts = blockchainConfig.getGasCost(); + DataWord adjustedCallGas = null; /*DEBUG #POC9 if( op.asInt() == 96 || op.asInt() == -128 || op.asInt() == 57 || op.asInt() == 115) { //byte alphaone = 0x63; @@ -140,94 +168,107 @@ public void step(Program program) { // Calculate fees and spend gas switch (op) { case STOP: + gasCost = gasCosts.getSTOP(); + break; case SUICIDE: - // The ops that don't charge by step - gasCost = GasCost.STOP; + gasCost = gasCosts.getSUICIDE(); + DataWord suicideAddressWord = stack.get(stack.size() - 1); + if (!program.getStorage().isExist(suicideAddressWord.getLast20Bytes())) + gasCost += gasCosts.getNEW_ACCT_SUICIDE(); break; case SSTORE: DataWord newValue = stack.get(stack.size() - 2); DataWord oldValue = program.storageLoad(stack.peek()); if (oldValue == null && !newValue.isZero()) - gasCost = GasCost.SET_SSTORE; + gasCost = gasCosts.getSET_SSTORE(); else if (oldValue != null && newValue.isZero()) { // todo: GASREFUND counter policy // refund step cost policy. - program.futureRefundGas(GasCost.REFUND_SSTORE); - gasCost = GasCost.CLEAR_SSTORE; + program.futureRefundGas(gasCosts.getREFUND_SSTORE()); + gasCost = gasCosts.getCLEAR_SSTORE(); } else - gasCost = GasCost.RESET_SSTORE; + gasCost = gasCosts.getRESET_SSTORE(); break; case SLOAD: - gasCost = GasCost.SLOAD; + gasCost = gasCosts.getSLOAD(); break; case BALANCE: - gasCost = GasCost.BALANCE; + gasCost = gasCosts.getBALANCE(); break; // These all operate on memory and therefore potentially expand it: case MSTORE: - newMemSize = memNeeded(stack.peek(), new DataWord(32)); + gasCost += calcMemGas(gasCosts, oldMemSize, memNeeded(stack.peek(), new DataWord(32)), 0); break; case MSTORE8: - newMemSize = memNeeded(stack.peek(), new DataWord(1)); + gasCost += calcMemGas(gasCosts, oldMemSize, memNeeded(stack.peek(), new DataWord(1)), 0); break; case MLOAD: - newMemSize = memNeeded(stack.peek(), new DataWord(32)); + gasCost += calcMemGas(gasCosts, oldMemSize, memNeeded(stack.peek(), new DataWord(32)), 0); break; case RETURN: - gasCost = GasCost.STOP; //rename? - newMemSize = memNeeded(stack.peek(), stack.get(stack.size() - 2)); + gasCost = gasCosts.getSTOP() + calcMemGas(gasCosts, oldMemSize, + memNeeded(stack.peek(), stack.get(stack.size() - 2)), 0); break; case SHA3: - gasCost = GasCost.SHA3; - newMemSize = memNeeded(stack.peek(), stack.get(stack.size() - 2)); + gasCost = gasCosts.getSHA3() + calcMemGas(gasCosts, oldMemSize, memNeeded(stack.peek(), stack.get(stack.size() - 2)), 0); DataWord size = stack.get(stack.size() - 2); long chunkUsed = (size.longValueSafe() + 31) / 32; - gasCost += chunkUsed * GasCost.SHA3_WORD; + gasCost += chunkUsed * gasCosts.getSHA3_WORD(); break; case CALLDATACOPY: - copySize = stack.get(stack.size() - 3).longValueSafe(); - newMemSize = memNeeded(stack.peek(), stack.get(stack.size() - 3)); + gasCost += calcMemGas(gasCosts, oldMemSize, + memNeeded(stack.peek(), stack.get(stack.size() - 3)), + stack.get(stack.size() - 3).longValueSafe()); break; case CODECOPY: - copySize = stack.get(stack.size() - 3).longValueSafe(); - newMemSize = memNeeded(stack.peek(), stack.get(stack.size() - 3)); + gasCost += calcMemGas(gasCosts, oldMemSize, + memNeeded(stack.peek(), stack.get(stack.size() - 3)), + stack.get(stack.size() - 3).longValueSafe()); + break; + case EXTCODESIZE: + gasCost = gasCosts.getEXT_CODE_SIZE(); break; case EXTCODECOPY: - copySize = stack.get(stack.size() - 4).longValueSafe(); - newMemSize = memNeeded(stack.get(stack.size() - 2), stack.get(stack.size() - 4)); + gasCost = gasCosts.getEXT_CODE_COPY() + calcMemGas(gasCosts, oldMemSize, + memNeeded(stack.get(stack.size() - 2), stack.get(stack.size() - 4)), + stack.get(stack.size() - 4).longValueSafe()); break; case CALL: case CALLCODE: case DELEGATECALL: - gasCost = GasCost.CALL; + gasCost = gasCosts.getCALL(); DataWord callGasWord = stack.get(stack.size() - 1); - if (callGasWord.compareTo(program.getGas()) > 0) { - throw Program.Exception.notEnoughOpGas(op, callGasWord, program.getGas()); - } - - gasCost += callGasWord.longValueSafe(); DataWord callAddressWord = stack.get(stack.size() - 2); //check to see if account does not exist and is not a precompiled contract if (op == CALL && !program.getStorage().isExist(callAddressWord.getLast20Bytes())) - gasCost += GasCost.NEW_ACCT_CALL; + gasCost += gasCosts.getNEW_ACCT_CALL(); //TODO #POC9 Make sure this is converted to BigInteger (256num support) if (op != DELEGATECALL && !stack.get(stack.size() - 3).isZero() ) - gasCost += GasCost.VT_CALL; + gasCost += gasCosts.getVT_CALL(); int opOff = op == DELEGATECALL ? 3 : 4; BigInteger in = memNeeded(stack.get(stack.size() - opOff), stack.get(stack.size() - opOff - 1)); // in offset+size BigInteger out = memNeeded(stack.get(stack.size() - opOff - 2), stack.get(stack.size() - opOff - 3)); // out offset+size - newMemSize = in.max(out); + gasCost += calcMemGas(gasCosts, oldMemSize, in.max(out), 0); + + if (gasCost > program.getGas().longValueSafe()) { + throw Program.Exception.notEnoughOpGas(op, callGasWord, program.getGas()); + } + + DataWord gasLeft = program.getGas().clone(); + gasLeft.sub(new DataWord(gasCost)); + adjustedCallGas = blockchainConfig.getCallGas(op, callGasWord, gasLeft); + gasCost += adjustedCallGas.longValueSafe(); break; case CREATE: - gasCost = GasCost.CREATE; - newMemSize = memNeeded(stack.get(stack.size() - 2), stack.get(stack.size() - 3)); + gasCost = gasCosts.getCREATE() + calcMemGas(gasCosts, oldMemSize, + memNeeded(stack.get(stack.size() - 2), stack.get(stack.size() - 3)), 0); break; case LOG0: case LOG1: @@ -236,23 +277,23 @@ else if (oldValue != null && newValue.isZero()) { case LOG4: int nTopics = op.val() - OpCode.LOG0.val(); - newMemSize = memNeeded(stack.peek(), stack.get(stack.size() - 2)); BigInteger dataSize = stack.get(stack.size() - 2).value(); - BigInteger dataCost = dataSize.multiply(BigInteger.valueOf(GasCost.LOG_DATA_GAS)); + BigInteger dataCost = dataSize.multiply(BigInteger.valueOf(gasCosts.getLOG_DATA_GAS())); if (program.getGas().value().compareTo(dataCost) < 0) { throw Program.Exception.notEnoughOpGas(op, dataCost, program.getGas().value()); } - gasCost = GasCost.LOG_GAS + - GasCost.LOG_TOPIC_GAS * nTopics + - GasCost.LOG_DATA_GAS * stack.get(stack.size() - 2).longValue(); + gasCost = gasCosts.getLOG_GAS() + + gasCosts.getLOG_TOPIC_GAS() * nTopics + + gasCosts.getLOG_DATA_GAS() * stack.get(stack.size() - 2).longValue() + + calcMemGas(gasCosts, oldMemSize, memNeeded(stack.peek(), stack.get(stack.size() - 2)), 0); break; case EXP: DataWord exp = stack.get(stack.size() - 2); int bytesOccupied = exp.bytesOccupied(); - gasCost = GasCost.EXP_GAS + GasCost.EXP_BYTE_GAS * bytesOccupied; + gasCost = gasCosts.getEXP_GAS() + gasCosts.getEXP_BYTE_GAS() * bytesOccupied; break; default: break; @@ -261,29 +302,6 @@ else if (oldValue != null && newValue.isZero()) { //DEBUG System.out.println(" OP IS " + op.name() + " GASCOST IS " + gasCost + " NUM IS " + op.asInt()); program.spendGas(gasCost, op.name()); - // Avoid overflows - if (newMemSize.compareTo(MAX_GAS) == 1) { - throw Program.Exception.gasOverflow(newMemSize, MAX_GAS); - } - - // memory gas calc - long memoryUsage = (newMemSize.longValue() + 31) / 32 * 32; - if (memoryUsage > oldMemSize) { - memWords = (memoryUsage / 32); - long memWordsOld = (oldMemSize / 32); - //TODO #POC9 c_quadCoeffDiv = 512, this should be a constant, not magic number - long memGas = ( GasCost.MEMORY * memWords + memWords * memWords / 512) - - (GasCost.MEMORY * memWordsOld + memWordsOld * memWordsOld / 512); - program.spendGas(memGas, op.name() + " (memory usage)"); - gasCost += memGas; - } - - if (copySize > 0) { - long copyGas = GasCost.COPY_GAS * ((copySize + 31) / 32); - gasCost += copyGas; - program.spendGas(copyGas, op.name() + " (copy usage)"); - } - // Log debugging line for VM if (program.getNumber().intValue() == dumpBlock) this.dumpLine(op, gasBefore, gasCost + callGas, memWords, program); @@ -1084,13 +1102,13 @@ else if (oldValue != null && newValue.isZero()) { case CALL: case CALLCODE: case DELEGATECALL: { - DataWord gas = program.stackPop(); + program.stackPop(); // use adjustedCallGas instead of requested DataWord codeAddress = program.stackPop(); DataWord value = !op.equals(DELEGATECALL) ? program.stackPop() : DataWord.ZERO; if( !value.isZero()) { - gas.add(new DataWord(GasCost.STIPEND_CALL)); + adjustedCallGas.add(new DataWord(gasCosts.getSTIPEND_CALL())); } DataWord inDataOffs = program.stackPop(); @@ -1101,7 +1119,7 @@ else if (oldValue != null && newValue.isZero()) { if (logger.isInfoEnabled()) { hint = "addr: " + Hex.toHexString(codeAddress.getLast20Bytes()) - + " gas: " + gas.shortHex() + + " gas: " + adjustedCallGas.shortHex() + " inOff: " + inDataOffs.shortHex() + " inSize: " + inDataSize.shortHex(); logger.info(logString, String.format("%5s", "[" + program.getPC() + "]"), @@ -1114,7 +1132,7 @@ else if (oldValue != null && newValue.isZero()) { MessageCall msg = new MessageCall( MsgType.fromOpcode(op), - gas, codeAddress, value, inDataOffs, inDataSize, + adjustedCallGas, codeAddress, value, inDataOffs, inDataSize, outDataOffs, outDataSize); PrecompiledContracts.PrecompiledContract contract = diff --git a/ethereumj-core/src/main/java/org/ethereum/vm/program/Program.java b/ethereumj-core/src/main/java/org/ethereum/vm/program/Program.java index ed5d40d430..c73d0e7685 100644 --- a/ethereumj-core/src/main/java/org/ethereum/vm/program/Program.java +++ b/ethereumj-core/src/main/java/org/ethereum/vm/program/Program.java @@ -1,5 +1,6 @@ package org.ethereum.vm.program; +import org.ethereum.config.BlockchainConfig; import org.ethereum.config.CommonConfig; import org.ethereum.config.SystemProperties; import org.ethereum.core.Repository; @@ -32,7 +33,6 @@ import static java.lang.StrictMath.min; import static java.lang.String.format; import static java.math.BigInteger.ZERO; -import static java.math.BigInteger.valueOf; import static org.apache.commons.lang3.ArrayUtils.*; import static org.ethereum.util.BIUtil.*; import static org.ethereum.util.ByteUtil.EMPTY_BYTE_ARRAY; @@ -86,6 +86,8 @@ public class Program { private final SystemProperties config; + private final BlockchainConfig blockchainConfig; + public Program(byte[] ops, ProgramInvoke programInvoke) { this(ops, programInvoke, null); } @@ -106,6 +108,7 @@ public Program(byte[] ops, ProgramInvoke programInvoke, Transaction transaction, this.stack = setupProgramListener(new Stack()); this.storage = setupProgramListener(new Storage(programInvoke)); this.trace = new ProgramTrace(config, programInvoke); + this.blockchainConfig = config.getBlockchainConfig().getConfigForBlock(programInvoke.getNumber().longValue()); precompile(); } @@ -368,7 +371,8 @@ public void createContract(DataWord value, DataWord memStart, DataWord memSize) logger.info("creating a new contract inside contract run: [{}]", Hex.toHexString(senderAddress)); // actual gas subtract - DataWord gasLimit = getGas(); + DataWord gasLimit = config.getBlockchainConfig().getConfigForBlock(getNumber().longValue()). + getCreateGas(getGas()); spendGas(gasLimit.longValue(), "internal call"); // [2] CREATE THE CONTRACT ADDRESS @@ -426,7 +430,7 @@ this, new DataWord(newAddress), getOwnerAddress(), value, gasLimit, // 4. CREATE THE CONTRACT OUT OF RETURN byte[] code = result.getHReturn(); - long storageCost = getLength(code) * GasCost.CREATE_DATA; + long storageCost = getLength(code) * getBlockchainConfig().getGasCost().getCREATE_DATA(); long afterSpend = programInvoke.getGas().longValue() - storageCost - result.getGasUsed(); if (afterSpend < 0) { if (!config.getBlockchainConfig().getConfigForBlock(getNumber().longValue()).getConstants().createEmptyContractOnOOG()) { @@ -702,6 +706,10 @@ public DataWord getNumber() { return invoke.getNumber().clone(); } + public BlockchainConfig getBlockchainConfig() { + return blockchainConfig; + } + public DataWord getDifficulty() { return invoke.getDifficulty().clone(); } diff --git a/ethereumj-core/src/test/java/org/ethereum/jsontestsuite/GitHubBlockTest.java b/ethereumj-core/src/test/java/org/ethereum/jsontestsuite/GitHubBlockTest.java index b7c7fcfff9..55050684ed 100644 --- a/ethereumj-core/src/test/java/org/ethereum/jsontestsuite/GitHubBlockTest.java +++ b/ethereumj-core/src/test/java/org/ethereum/jsontestsuite/GitHubBlockTest.java @@ -3,6 +3,7 @@ import org.ethereum.config.BlockchainNetConfig; import org.ethereum.config.SystemProperties; import org.ethereum.config.blockchain.DaoHFConfig; +import org.ethereum.config.blockchain.Eip150HFConfig; import org.ethereum.config.blockchain.FrontierConfig; import org.ethereum.config.blockchain.HomesteadConfig; import org.ethereum.config.net.AbstractNetConfig; @@ -21,7 +22,7 @@ public class GitHubBlockTest { //SHACOMMIT of tested commit, ethereum/tests.git - public String shacommit = "92bb72cccf4b5a2d29d74248fdddfe8b43baddda"; + public String shacommit = "9ed33d7440f13c09ce7f038f92abd02d23b26f0d"; @Ignore // test for conveniently running a single test @Test @@ -48,87 +49,98 @@ private void runHomestead(String name) throws IOException, ParseException { } } - private void run(String name, boolean frontier, boolean homestead) throws IOException, ParseException { + private void runEIP150(String name) throws IOException, ParseException { + String json = JSONReader.loadJSONFromCommit("BlockchainTests/EIP150/" + name + ".json", shacommit); + SystemProperties.getDefault().setBlockchainConfig(new Eip150HFConfig(new DaoHFConfig())); + try { + GitHubJSONTestSuite.runGitHubJsonBlockTest(json, Collections.EMPTY_SET); + } finally { + SystemProperties.getDefault().setBlockchainConfig(MainNetConfig.INSTANCE); + } + } + + private void run(String name, boolean frontier, boolean homestead, boolean eip150) throws IOException, ParseException { if (frontier) runFrontier(name); if (homestead) runHomestead(name); + if (eip150) runEIP150(name); } @Test public void runBCInvalidHeaderTest() throws ParseException, IOException { - run("bcInvalidHeaderTest", true, true); + run("bcInvalidHeaderTest", true, true, true); } @Test public void runBCInvalidRLPTest() throws ParseException, IOException { - run("bcInvalidRLPTest", true, false); + run("bcInvalidRLPTest", true, false, true); } @Test public void runBCRPCAPITest() throws ParseException, IOException { - run("bcRPC_API_Test", true, true); + run("bcRPC_API_Test", true, true, true); } @Test public void runBCUncleHeaderValidityTest() throws ParseException, IOException { - run("bcUncleHeaderValiditiy", true, true); + run("bcUncleHeaderValiditiy", true, true, true); } @Test public void runBCUncleTest() throws ParseException, IOException { - run("bcUncleTest", true, true); + run("bcUncleTest", true, true, true); } @Test public void runBCValidBlockTest() throws ParseException, IOException { SystemProperties.getDefault().setGenesisInfo("frontier.json"); - run("bcValidBlockTest", true, true); + run("bcValidBlockTest", true, true, true); } @Test public void runBCBlockGasLimitTest() throws ParseException, IOException { - run("bcBlockGasLimitTest", true, true); + run("bcBlockGasLimitTest", true, true, true); } @Test public void runBCForkBlockTest() throws ParseException, IOException { - run("bcForkBlockTest", true, false); + run("bcForkBlockTest", true, false, false); } @Test public void runBCForkUncleTest() throws ParseException, IOException { - run("bcForkUncle", true, false); + run("bcForkUncle", true, false, false); } @Test public void runBCForkStressTest() throws ParseException, IOException { - run("bcForkStressTest", true, true); + run("bcForkStressTest", true, true, true); } @Test public void runBCStateTest() throws ParseException, IOException { - run("bcStateTest", true, true); + run("bcStateTest", true, true, true); } @Test public void runBCGasPricerTest() throws ParseException, IOException { - run("bcGasPricerTest", true, true); + run("bcGasPricerTest", true, true, true); } @Test public void runBCTotalDifficultyTest() throws ParseException, IOException { - run("bcTotalDifficultyTest", false, true); + run("bcTotalDifficultyTest", false, true, true); } @Test public void runBCWalletTest() throws Exception, IOException { - run("bcWalletTest", true, true); + run("bcWalletTest", true, true, true); } @Test public void runBCMultiChainTest() throws ParseException, IOException { - run("bcMultiChainTest", true, true); + run("bcMultiChainTest", true, true, true); } diff --git a/ethereumj-core/src/test/java/org/ethereum/jsontestsuite/GitHubStateTest.java b/ethereumj-core/src/test/java/org/ethereum/jsontestsuite/GitHubStateTest.java index 442196032d..0d258c2f51 100644 --- a/ethereumj-core/src/test/java/org/ethereum/jsontestsuite/GitHubStateTest.java +++ b/ethereumj-core/src/test/java/org/ethereum/jsontestsuite/GitHubStateTest.java @@ -1,6 +1,8 @@ package org.ethereum.jsontestsuite; import org.ethereum.config.SystemProperties; +import org.ethereum.config.blockchain.DaoHFConfig; +import org.ethereum.config.blockchain.Eip150HFConfig; import org.ethereum.config.blockchain.FrontierConfig; import org.ethereum.config.blockchain.HomesteadConfig; import org.ethereum.config.net.AbstractNetConfig; @@ -22,7 +24,7 @@ public class GitHubStateTest { //SHACOMMIT of tested commit, ethereum/tests.git - public String shacommit = "f28ac81493281feec0b17290565cf74042893677"; + public String shacommit = "9ed33d7440f13c09ce7f038f92abd02d23b26f0d"; private long oldForkValue; @@ -34,6 +36,8 @@ public void setup() { SystemProperties.getDefault().setBlockchainConfig(new AbstractNetConfig() {{ add(0, new FrontierConfig()); add(1_150_000, new HomesteadConfig()); + add(2_457_000, new Eip150HFConfig(new DaoHFConfig())); + }}); } @@ -45,8 +49,9 @@ public void clean() { @Ignore @Test // this method is mostly for hands-on convenient testing public void stSingleTest() throws ParseException, IOException { - String json = JSONReader.loadJSONFromCommit("StateTests/stSystemOperationsTest.json", shacommit); - GitHubJSONTestSuite.runStateTest(json, "suicideSendEtherPostDeath"); + String json = JSONReader.loadJSONFromCommit("StateTests/EIP150/stEIPSpecificTest.json", shacommit); +// String json = JSONReader.loadJSONFromCommit("StateTests/Homestead/stCallCodes.json", shacommit); + GitHubJSONTestSuite.runStateTest(json, "CallAskMoreGasOnDepth2ThenTransactionHas"); } @Test @@ -66,6 +71,9 @@ public void stCallCodes() throws ParseException, IOException { json = JSONReader.loadJSONFromCommit("StateTests/Homestead/stCallCodes.json", shacommit); GitHubJSONTestSuite.runStateTest(json, excluded); + + json = JSONReader.loadJSONFromCommit("StateTests/EIP150/Homestead/stCallCodes.json", shacommit); + GitHubJSONTestSuite.runStateTest(json, excluded); } @Test @@ -74,6 +82,9 @@ public void stCallDelegateCodes() throws ParseException, IOException { String json = JSONReader.loadJSONFromCommit("StateTests/Homestead/stCallDelegateCodes.json", shacommit); GitHubJSONTestSuite.runStateTest(json, excluded); + + json = JSONReader.loadJSONFromCommit("StateTests/EIP150/Homestead/stCallDelegateCodes.json", shacommit); + GitHubJSONTestSuite.runStateTest(json, excluded); } @Test @@ -82,6 +93,9 @@ public void stCallDelegateCodesCallCode() throws ParseException, IOException { Set excluded = new HashSet<>(); String json = JSONReader.loadJSONFromCommit("StateTests/Homestead/stCallDelegateCodesCallCode.json", shacommit); GitHubJSONTestSuite.runStateTest(json, excluded); + + json = JSONReader.loadJSONFromCommit("StateTests/EIP150/Homestead/stCallDelegateCodesCallCode.json", shacommit); + GitHubJSONTestSuite.runStateTest(json, excluded); } @Test @@ -90,6 +104,9 @@ public void stHomeSteadSpecific() throws ParseException, IOException { Set excluded = new HashSet<>(); String json = JSONReader.loadJSONFromCommit("StateTests/Homestead/stHomeSteadSpecific.json", shacommit); GitHubJSONTestSuite.runStateTest(json, excluded); + + json = JSONReader.loadJSONFromCommit("StateTests/EIP150/Homestead/stHomeSteadSpecific.json", shacommit); + GitHubJSONTestSuite.runStateTest(json, excluded); } @Test @@ -102,13 +119,22 @@ public void stCallCreateCallCodeTest() throws ParseException, IOException { json = JSONReader.loadJSONFromCommit("StateTests/Homestead/stCallCreateCallCodeTest.json", shacommit); GitHubJSONTestSuite.runStateTest(json, excluded); + + json = JSONReader.loadJSONFromCommit("StateTests/EIP150/Homestead/stCallCreateCallCodeTest.json", shacommit); + GitHubJSONTestSuite.runStateTest(json, excluded); } @Test public void stDelegatecallTest() throws ParseException, IOException { Set excluded = new HashSet<>(); - String json = JSONReader.loadJSONFromCommit("StateTests/stDelegatecallTest.json", shacommit); +// String json = JSONReader.loadJSONFromCommit("StateTests/stDelegatecallTest.json", shacommit); +// GitHubJSONTestSuite.runStateTest(json, excluded); + + String json = JSONReader.loadJSONFromCommit("StateTests/Homestead/stDelegatecallTest.json", shacommit); + GitHubJSONTestSuite.runStateTest(json, excluded); + + json = JSONReader.loadJSONFromCommit("StateTests/EIP150/Homestead/stDelegatecallTest.json", shacommit); GitHubJSONTestSuite.runStateTest(json, excluded); } @@ -119,6 +145,8 @@ public void stInitCodeTest() throws ParseException, IOException { GitHubJSONTestSuite.runStateTest(json, excluded); json = JSONReader.loadJSONFromCommit("StateTests/Homestead/stInitCodeTest.json", shacommit); GitHubJSONTestSuite.runStateTest(json, excluded); + json = JSONReader.loadJSONFromCommit("StateTests/EIP150/Homestead/stInitCodeTest.json", shacommit); + GitHubJSONTestSuite.runStateTest(json, excluded); } @Test @@ -128,6 +156,8 @@ public void stLogTests() throws ParseException, IOException { GitHubJSONTestSuite.runStateTest(json, excluded); json = JSONReader.loadJSONFromCommit("StateTests/Homestead/stLogTests.json", shacommit); GitHubJSONTestSuite.runStateTest(json, excluded); + json = JSONReader.loadJSONFromCommit("StateTests/EIP150/Homestead/stLogTests.json", shacommit); + GitHubJSONTestSuite.runStateTest(json, excluded); } @Test @@ -138,9 +168,12 @@ public void stPreCompiledContracts() throws ParseException, IOException { GitHubJSONTestSuite.runStateTest(json, excluded); json = JSONReader.loadJSONFromCommit("StateTests/Homestead/stPreCompiledContracts.json", shacommit); GitHubJSONTestSuite.runStateTest(json, excluded); + json = JSONReader.loadJSONFromCommit("StateTests/EIP150/Homestead/stPreCompiledContracts.json", shacommit); + GitHubJSONTestSuite.runStateTest(json, excluded); } @Test + @Ignore public void stMemoryStressTest() throws ParseException, IOException { Set excluded = new HashSet<>(); excluded.add("mload32bitBound_return2");// The test extends memory to 4Gb which can't be handled with Java arrays @@ -161,6 +194,9 @@ public void stMemoryTest() throws ParseException, IOException { json = JSONReader.loadJSONFromCommit("StateTests/Homestead/stMemoryTest.json", shacommit); GitHubJSONTestSuite.runStateTest(json, excluded); + + json = JSONReader.loadJSONFromCommit("StateTests/EIP150/Homestead/stMemoryTest.json", shacommit); + GitHubJSONTestSuite.runStateTest(json, excluded); } @Test @@ -173,6 +209,9 @@ public void stQuadraticComplexityTest() throws ParseException, IOException { String json = JSONReader.loadJSONFromCommit("StateTests/Homestead/stQuadraticComplexityTest.json", shacommit); GitHubJSONTestSuite.runStateTest(json, excluded); + + json = JSONReader.loadJSONFromCommit("StateTests/EIP150/Homestead/stQuadraticComplexityTest.json", shacommit); + GitHubJSONTestSuite.runStateTest(json, excluded); } @Test @@ -189,6 +228,8 @@ public void stRecursiveCreate() throws ParseException, IOException { GitHubJSONTestSuite.runStateTest(json, excluded); json = JSONReader.loadJSONFromCommit("StateTests/Homestead/stRecursiveCreate.json", shacommit); GitHubJSONTestSuite.runStateTest(json, excluded); + json = JSONReader.loadJSONFromCommit("StateTests/EIP150/Homestead/stRecursiveCreate.json", shacommit); + GitHubJSONTestSuite.runStateTest(json, excluded); } @Test @@ -199,6 +240,8 @@ public void stRefundTest() throws ParseException, IOException { GitHubJSONTestSuite.runStateTest(json, excluded); json = JSONReader.loadJSONFromCommit("StateTests/Homestead/stRefundTest.json", shacommit); GitHubJSONTestSuite.runStateTest(json, excluded); + json = JSONReader.loadJSONFromCommit("StateTests/EIP150/Homestead/stRefundTest.json", shacommit); + GitHubJSONTestSuite.runStateTest(json, excluded); } @Test @@ -226,6 +269,9 @@ public void stSystemOperationsTest() throws IOException { json = JSONReader.loadJSONFromCommit("StateTests/Homestead/stSystemOperationsTest.json", shacommit); GitHubJSONTestSuite.runStateTest(json, excluded); + + json = JSONReader.loadJSONFromCommit("StateTests/EIP150/Homestead/stSystemOperationsTest.json", shacommit); + GitHubJSONTestSuite.runStateTest(json, excluded); } @Test @@ -237,6 +283,9 @@ public void stTransactionTest() throws ParseException, IOException { json = JSONReader.loadJSONFromCommit("StateTests/Homestead/stTransactionTest.json", shacommit); GitHubJSONTestSuite.runStateTest(json, excluded); + + json = JSONReader.loadJSONFromCommit("StateTests/EIP150/Homestead/stTransactionTest.json", shacommit); + GitHubJSONTestSuite.runStateTest(json, excluded); } @Test @@ -256,6 +305,41 @@ public void stWalletTest() throws ParseException, IOException { json = JSONReader.loadJSONFromCommit("StateTests/Homestead/stWalletTest.json", shacommit); GitHubJSONTestSuite.runStateTest(json, excluded); + + json = JSONReader.loadJSONFromCommit("StateTests/EIP150/Homestead/stWalletTest.json", shacommit); + GitHubJSONTestSuite.runStateTest(json, excluded); + } + + @Test + public void stEIPSpecificTest() throws ParseException, IOException { + Set excluded = new HashSet<>(); + + String json = JSONReader.loadJSONFromCommit("StateTests/EIP150/stEIPSpecificTest.json", shacommit); + GitHubJSONTestSuite.runStateTest(json, excluded); + } + + @Test + public void stChangedTests() throws ParseException, IOException { + Set excluded = new HashSet<>(); + + String json = JSONReader.loadJSONFromCommit("StateTests/EIP150/stChangedTests.json", shacommit); + GitHubJSONTestSuite.runStateTest(json, excluded); + } + + @Test + public void stEIPsingleCodeGasPrices() throws ParseException, IOException { + Set excluded = new HashSet<>(); + + String json = JSONReader.loadJSONFromCommit("StateTests/EIP150/stEIPsingleCodeGasPrices.json", shacommit); + GitHubJSONTestSuite.runStateTest(json, excluded); + } + + @Test + public void stMemExpandingEIPCalls() throws ParseException, IOException { + Set excluded = new HashSet<>(); + + String json = JSONReader.loadJSONFromCommit("StateTests/EIP150/stMemExpandingEIPCalls.json", shacommit); + GitHubJSONTestSuite.runStateTest(json, excluded); } @Test // testing full suite