diff --git a/ethereumj-core/src/main/java/org/ethereum/core/Blockchain.java b/ethereumj-core/src/main/java/org/ethereum/core/Blockchain.java index 28d2869b..a89afaad 100644 --- a/ethereumj-core/src/main/java/org/ethereum/core/Blockchain.java +++ b/ethereumj-core/src/main/java/org/ethereum/core/Blockchain.java @@ -53,8 +53,7 @@ public class Blockchain { private static long INITIAL_MIN_GAS_PRICE = 10 * SZABO.longValue(); private DatabaseImpl chainDb; - - private long gasPrice = 1000; + private Block lastBlock; // keep the index of the chain for @@ -139,7 +138,6 @@ public class Blockchain { this.index.put(block.getNumber(), block.getEncoded()); WorldManager.getInstance().getWallet().processBlock(block); - this.updateGasPrice(block); this.setLastBlock(block); if (logger.isDebugEnabled()) logger.debug("block added {}", block.toFlatString()); @@ -148,13 +146,9 @@ public class Blockchain { } } - public void updateGasPrice(Block block) { - // In case of the genesis block we don't want to rely on the min gas price - this.gasPrice = block.isGenesis() ? block.getMinGasPrice() : INITIAL_MIN_GAS_PRICE; - } - public long getGasPrice() { - return gasPrice; + // In case of the genesis block we don't want to rely on the min gas price + return lastBlock.isGenesis() ? lastBlock.getMinGasPrice() : INITIAL_MIN_GAS_PRICE; } public byte[] getLatestBlockHash() { @@ -180,7 +174,6 @@ public class Blockchain { logger.debug("Block #{} -> {}", lastBlock.getNumber(), lastBlock.toFlatString()); } } - this.updateGasPrice(lastBlock); } finally { // Make sure you close the iterator to avoid resource leaks. try { diff --git a/ethereumj-core/src/main/java/org/ethereum/core/Transaction.java b/ethereumj-core/src/main/java/org/ethereum/core/Transaction.java index d0d23dff..56170f25 100644 --- a/ethereumj-core/src/main/java/org/ethereum/core/Transaction.java +++ b/ethereumj-core/src/main/java/org/ethereum/core/Transaction.java @@ -157,7 +157,7 @@ public class Transaction { // TODO: performance improve multiply without BigInteger public BigInteger getTotalGasValueDebit() { - return new BigInteger(1, gasLimit).multiply(new BigInteger(1,gasPrice)); + return new BigInteger(1, gasLimit).multiply(new BigInteger(1, gasPrice)); } public byte[] getData() { diff --git a/ethereumj-core/src/main/java/org/ethereum/jsontestsuite/CallCreate.java b/ethereumj-core/src/main/java/org/ethereum/jsontestsuite/CallCreate.java index 49a6c4fe..2089d39d 100644 --- a/ethereumj-core/src/main/java/org/ethereum/jsontestsuite/CallCreate.java +++ b/ethereumj-core/src/main/java/org/ethereum/jsontestsuite/CallCreate.java @@ -1,16 +1,10 @@ package org.ethereum.jsontestsuite; -import org.ethereum.db.ByteArrayWrapper; import org.ethereum.util.ByteUtil; -import org.json.simple.JSONArray; import org.json.simple.JSONObject; import org.spongycastle.util.encoders.Hex; import java.math.BigInteger; -import java.util.Arrays; -import java.util.HashMap; -import java.util.Map; -import java.util.regex.Pattern; /** * www.ethereumJ.com @@ -36,10 +30,10 @@ public class CallCreate { public CallCreate(JSONObject callCreateJSON) { - String data = (String)callCreateJSON.get("data"); - String destination = (String)callCreateJSON.get("destination"); - Long gasLimit = (Long)callCreateJSON.get("gasLimit"); - Long value = (Long)callCreateJSON.get("value"); + String data = callCreateJSON.get("data").toString(); + String destination = callCreateJSON.get("destination").toString(); + String gasLimit = callCreateJSON.get("gasLimit").toString(); + String value = callCreateJSON.get("value").toString(); if (data != null && data.length() > 2) this.data = Hex.decode(data.substring(2)); @@ -48,8 +42,8 @@ public class CallCreate { this.destination = Hex.decode(destination); - this.gasLimit = ByteUtil.bigIntegerToBytes( BigInteger.valueOf(gasLimit) ); - this.value = ByteUtil.bigIntegerToBytes( BigInteger.valueOf(value) ); + this.gasLimit = ByteUtil.bigIntegerToBytes(new BigInteger(gasLimit)); + this.value = ByteUtil.bigIntegerToBytes(new BigInteger(value)); } diff --git a/ethereumj-core/src/main/java/org/ethereum/jsontestsuite/Exec.java b/ethereumj-core/src/main/java/org/ethereum/jsontestsuite/Exec.java index 73757c74..9fe15074 100644 --- a/ethereumj-core/src/main/java/org/ethereum/jsontestsuite/Exec.java +++ b/ethereumj-core/src/main/java/org/ethereum/jsontestsuite/Exec.java @@ -69,8 +69,8 @@ public class Exec { else this.data = new byte[0]; - this.gas = ByteUtil.bigIntegerToBytes( new BigInteger(gas) ); - this.gasPrice = ByteUtil.bigIntegerToBytes( new BigInteger(gasPrice) ); + this.gas = ByteUtil.bigIntegerToBytes(new BigInteger(gas)); + this.gasPrice = ByteUtil.bigIntegerToBytes(new BigInteger(gasPrice)); this.origin = Hex.decode(origin); this.value = ByteUtil.bigIntegerToBytes(new BigInteger(value)); diff --git a/ethereumj-core/src/main/java/org/ethereum/jsontestsuite/TestCase.java b/ethereumj-core/src/main/java/org/ethereum/jsontestsuite/TestCase.java index a6440234..548a3f59 100644 --- a/ethereumj-core/src/main/java/org/ethereum/jsontestsuite/TestCase.java +++ b/ethereumj-core/src/main/java/org/ethereum/jsontestsuite/TestCase.java @@ -48,7 +48,6 @@ public class TestCase { this.name = name; } - public TestCase(JSONObject testCaseJSONObj) throws ParseException{ try { @@ -59,10 +58,14 @@ public class TestCase { JSONObject postJSON = (JSONObject)testCaseJSONObj.get("post"); JSONArray callCreates = (JSONArray)testCaseJSONObj.get("callcreates"); - Long gasNum = (Long)testCaseJSONObj.get("gas"); - this.gas = ByteUtil.bigIntegerToBytes(BigInteger.valueOf(gasNum)); - - this.out = Helper.parseDataArray((JSONArray) testCaseJSONObj.get("out")); + String gasString = testCaseJSONObj.get("gas").toString(); + this.gas = ByteUtil.bigIntegerToBytes(new BigInteger(gasString)); + + String outString = testCaseJSONObj.get("out").toString(); + if (outString != null && outString.length() > 2) + this.out = Hex.decode(outString.substring(2)); + else + this.out = new byte[0]; for (Object key : preJSON.keySet()){ 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 3c029f9e..3b9631a4 100644 --- a/ethereumj-core/src/main/java/org/ethereum/manager/WorldManager.java +++ b/ethereumj-core/src/main/java/org/ethereum/manager/WorldManager.java @@ -96,40 +96,48 @@ public class WorldManager { return; } - // 2.1 PERFORM THE GAS VALUE TX - // (THIS STAGE IS NOT REVERTED BY ANY EXCEPTION) - - // first of all debit the gas from the issuer - BigInteger gasDebit = tx.getTotalGasValueDebit(); - - byte[] receiverAddress; - - // Contract creation or existing Contract call - if (tx.isContractCreation()) { + // 3. FIND OUT THE TRANSACTION TYPE + byte[] receiverAddress, code = null; + boolean isContractCreation = tx.isContractCreation(); + if (isContractCreation) { receiverAddress = tx.getContractAddress(); repository.createAccount(receiverAddress); stateLogger.info("New contract created address={}", Hex.toHexString(receiverAddress)); + code = tx.getData(); // init code + if (logger.isInfoEnabled()) + logger.info("running the init for contract: address={}", + Hex.toHexString(receiverAddress)); } else { receiverAddress = tx.getReceiveAddress(); AccountState receiverState = repository.getAccountState(receiverAddress); - if (receiverState == null) { repository.createAccount(receiverAddress); if (stateLogger.isInfoEnabled()) stateLogger.info("New receiver account created address={}", Hex.toHexString(receiverAddress)); + } else { + code = repository.getCode(receiverAddress); + if (code != null) { + if (logger.isInfoEnabled()) + logger.info("calling for existing contract: address={}", + Hex.toHexString(receiverAddress)); + } } } - - // 2.2 UPDATE THE NONCE + + // 2.1 UPDATE THE NONCE // (THIS STAGE IS NOT REVERTED BY ANY EXCEPTION) repository.increaseNonce(senderAddress); - // actual gas value debit from the sender - // the purchase gas will be available for the - // contract in the execution state, and - // can be validate using GAS op + // 2.2 PERFORM THE GAS VALUE TX + // (THIS STAGE IS NOT REVERTED BY ANY EXCEPTION) + BigInteger gasDebit = tx.getTotalGasValueDebit(); + + // Debit the actual total gas value from the sender + // the purchased gas will be available for + // the contract in the execution state, + // it can be retrieved using GAS op if (gasDebit.signum() == 1) { BigInteger balance = senderAccount.getBalance(); if (balance.compareTo(gasDebit) == -1) { @@ -177,23 +185,7 @@ public class WorldManager { } } - byte[] code; - boolean isContractCreation = tx.isContractCreation(); - // 3. FIND OUT THE TRANSACTION TYPE - if (isContractCreation) { - code = tx.getData(); // init code - if (logger.isInfoEnabled()) - logger.info("running the init for contract: address={}", - Hex.toHexString(receiverAddress)); - } else { - code = trackRepository.getCode(receiverAddress); - if (code != null) { - if (logger.isInfoEnabled()) - logger.info("calling for existing contract: address={}", - Hex.toHexString(receiverAddress)); - } - } - + // 5. CREATE OR EXECUTE PROGRAM if (isContractCreation || code != null) { Block lastBlock = blockchain.getLastBlock(); @@ -206,6 +198,18 @@ public class WorldManager { ProgramResult result = program.getResult(); applyProgramResult(result, gasDebit, trackRepository, senderAddress, receiverAddress, coinbase, isContractCreation); + } else { + // refund everything except fee (500 + 5*txdata) + BigInteger gasPrice = new BigInteger(1, tx.getGasPrice()); + long dataFee = tx.getData() == null ? 0: tx.getData().length * GasCost.TXDATA; + long minTxFee = GasCost.TRANSACTION + dataFee; + BigInteger refund = gasDebit.subtract(BigInteger.valueOf( + minTxFee).multiply(gasPrice)); + if (refund.signum() > 0) { + // gas refund + repository.addBalance(senderAddress, refund); + repository.addBalance(coinbase, refund.negate()); + } } } catch (RuntimeException e) { trackRepository.rollback(); @@ -276,7 +280,7 @@ public class WorldManager { } public void applyBlock(Block block) { - + int i = 0; for (Transaction tx : block.getTransactionsList()) { applyTransaction(tx, block.getCoinbase());