Merge pull request #63 from nicksavers/master
Refund everything except TXFEE + DATAFEE for normal transaction
This commit is contained in:
commit
a23a860d3f
|
@ -53,8 +53,7 @@ public class Blockchain {
|
||||||
private static long INITIAL_MIN_GAS_PRICE = 10 * SZABO.longValue();
|
private static long INITIAL_MIN_GAS_PRICE = 10 * SZABO.longValue();
|
||||||
|
|
||||||
private DatabaseImpl chainDb;
|
private DatabaseImpl chainDb;
|
||||||
|
|
||||||
private long gasPrice = 1000;
|
|
||||||
private Block lastBlock;
|
private Block lastBlock;
|
||||||
|
|
||||||
// keep the index of the chain for
|
// keep the index of the chain for
|
||||||
|
@ -139,7 +138,6 @@ public class Blockchain {
|
||||||
this.index.put(block.getNumber(), block.getEncoded());
|
this.index.put(block.getNumber(), block.getEncoded());
|
||||||
|
|
||||||
WorldManager.getInstance().getWallet().processBlock(block);
|
WorldManager.getInstance().getWallet().processBlock(block);
|
||||||
this.updateGasPrice(block);
|
|
||||||
this.setLastBlock(block);
|
this.setLastBlock(block);
|
||||||
if (logger.isDebugEnabled())
|
if (logger.isDebugEnabled())
|
||||||
logger.debug("block added {}", block.toFlatString());
|
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() {
|
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() {
|
public byte[] getLatestBlockHash() {
|
||||||
|
@ -180,7 +174,6 @@ public class Blockchain {
|
||||||
logger.debug("Block #{} -> {}", lastBlock.getNumber(), lastBlock.toFlatString());
|
logger.debug("Block #{} -> {}", lastBlock.getNumber(), lastBlock.toFlatString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.updateGasPrice(lastBlock);
|
|
||||||
} finally {
|
} finally {
|
||||||
// Make sure you close the iterator to avoid resource leaks.
|
// Make sure you close the iterator to avoid resource leaks.
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -157,7 +157,7 @@ public class Transaction {
|
||||||
|
|
||||||
// TODO: performance improve multiply without BigInteger
|
// TODO: performance improve multiply without BigInteger
|
||||||
public BigInteger getTotalGasValueDebit() {
|
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() {
|
public byte[] getData() {
|
||||||
|
|
|
@ -1,16 +1,10 @@
|
||||||
package org.ethereum.jsontestsuite;
|
package org.ethereum.jsontestsuite;
|
||||||
|
|
||||||
import org.ethereum.db.ByteArrayWrapper;
|
|
||||||
import org.ethereum.util.ByteUtil;
|
import org.ethereum.util.ByteUtil;
|
||||||
import org.json.simple.JSONArray;
|
|
||||||
import org.json.simple.JSONObject;
|
import org.json.simple.JSONObject;
|
||||||
import org.spongycastle.util.encoders.Hex;
|
import org.spongycastle.util.encoders.Hex;
|
||||||
|
|
||||||
import java.math.BigInteger;
|
import java.math.BigInteger;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.regex.Pattern;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* www.ethereumJ.com
|
* www.ethereumJ.com
|
||||||
|
@ -36,10 +30,10 @@ public class CallCreate {
|
||||||
|
|
||||||
public CallCreate(JSONObject callCreateJSON) {
|
public CallCreate(JSONObject callCreateJSON) {
|
||||||
|
|
||||||
String data = (String)callCreateJSON.get("data");
|
String data = callCreateJSON.get("data").toString();
|
||||||
String destination = (String)callCreateJSON.get("destination");
|
String destination = callCreateJSON.get("destination").toString();
|
||||||
Long gasLimit = (Long)callCreateJSON.get("gasLimit");
|
String gasLimit = callCreateJSON.get("gasLimit").toString();
|
||||||
Long value = (Long)callCreateJSON.get("value");
|
String value = callCreateJSON.get("value").toString();
|
||||||
|
|
||||||
if (data != null && data.length() > 2)
|
if (data != null && data.length() > 2)
|
||||||
this.data = Hex.decode(data.substring(2));
|
this.data = Hex.decode(data.substring(2));
|
||||||
|
@ -48,8 +42,8 @@ public class CallCreate {
|
||||||
|
|
||||||
|
|
||||||
this.destination = Hex.decode(destination);
|
this.destination = Hex.decode(destination);
|
||||||
this.gasLimit = ByteUtil.bigIntegerToBytes( BigInteger.valueOf(gasLimit) );
|
this.gasLimit = ByteUtil.bigIntegerToBytes(new BigInteger(gasLimit));
|
||||||
this.value = ByteUtil.bigIntegerToBytes( BigInteger.valueOf(value) );
|
this.value = ByteUtil.bigIntegerToBytes(new BigInteger(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -69,8 +69,8 @@ public class Exec {
|
||||||
else
|
else
|
||||||
this.data = new byte[0];
|
this.data = new byte[0];
|
||||||
|
|
||||||
this.gas = ByteUtil.bigIntegerToBytes( new BigInteger(gas) );
|
this.gas = ByteUtil.bigIntegerToBytes(new BigInteger(gas));
|
||||||
this.gasPrice = ByteUtil.bigIntegerToBytes( new BigInteger(gasPrice) );
|
this.gasPrice = ByteUtil.bigIntegerToBytes(new BigInteger(gasPrice));
|
||||||
|
|
||||||
this.origin = Hex.decode(origin);
|
this.origin = Hex.decode(origin);
|
||||||
this.value = ByteUtil.bigIntegerToBytes(new BigInteger(value));
|
this.value = ByteUtil.bigIntegerToBytes(new BigInteger(value));
|
||||||
|
|
|
@ -48,7 +48,6 @@ public class TestCase {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public TestCase(JSONObject testCaseJSONObj) throws ParseException{
|
public TestCase(JSONObject testCaseJSONObj) throws ParseException{
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -59,10 +58,14 @@ public class TestCase {
|
||||||
JSONObject postJSON = (JSONObject)testCaseJSONObj.get("post");
|
JSONObject postJSON = (JSONObject)testCaseJSONObj.get("post");
|
||||||
JSONArray callCreates = (JSONArray)testCaseJSONObj.get("callcreates");
|
JSONArray callCreates = (JSONArray)testCaseJSONObj.get("callcreates");
|
||||||
|
|
||||||
Long gasNum = (Long)testCaseJSONObj.get("gas");
|
String gasString = testCaseJSONObj.get("gas").toString();
|
||||||
this.gas = ByteUtil.bigIntegerToBytes(BigInteger.valueOf(gasNum));
|
this.gas = ByteUtil.bigIntegerToBytes(new BigInteger(gasString));
|
||||||
|
|
||||||
this.out = Helper.parseDataArray((JSONArray) testCaseJSONObj.get("out"));
|
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()){
|
for (Object key : preJSON.keySet()){
|
||||||
|
|
||||||
|
|
|
@ -96,40 +96,48 @@ public class WorldManager {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2.1 PERFORM THE GAS VALUE TX
|
// 3. FIND OUT THE TRANSACTION TYPE
|
||||||
// (THIS STAGE IS NOT REVERTED BY ANY EXCEPTION)
|
byte[] receiverAddress, code = null;
|
||||||
|
boolean isContractCreation = tx.isContractCreation();
|
||||||
// first of all debit the gas from the issuer
|
if (isContractCreation) {
|
||||||
BigInteger gasDebit = tx.getTotalGasValueDebit();
|
|
||||||
|
|
||||||
byte[] receiverAddress;
|
|
||||||
|
|
||||||
// Contract creation or existing Contract call
|
|
||||||
if (tx.isContractCreation()) {
|
|
||||||
receiverAddress = tx.getContractAddress();
|
receiverAddress = tx.getContractAddress();
|
||||||
repository.createAccount(receiverAddress);
|
repository.createAccount(receiverAddress);
|
||||||
stateLogger.info("New contract created address={}",
|
stateLogger.info("New contract created address={}",
|
||||||
Hex.toHexString(receiverAddress));
|
Hex.toHexString(receiverAddress));
|
||||||
|
code = tx.getData(); // init code
|
||||||
|
if (logger.isInfoEnabled())
|
||||||
|
logger.info("running the init for contract: address={}",
|
||||||
|
Hex.toHexString(receiverAddress));
|
||||||
} else {
|
} else {
|
||||||
receiverAddress = tx.getReceiveAddress();
|
receiverAddress = tx.getReceiveAddress();
|
||||||
AccountState receiverState = repository.getAccountState(receiverAddress);
|
AccountState receiverState = repository.getAccountState(receiverAddress);
|
||||||
|
|
||||||
if (receiverState == null) {
|
if (receiverState == null) {
|
||||||
repository.createAccount(receiverAddress);
|
repository.createAccount(receiverAddress);
|
||||||
if (stateLogger.isInfoEnabled())
|
if (stateLogger.isInfoEnabled())
|
||||||
stateLogger.info("New receiver account created address={}",
|
stateLogger.info("New receiver account created address={}",
|
||||||
Hex.toHexString(receiverAddress));
|
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)
|
// (THIS STAGE IS NOT REVERTED BY ANY EXCEPTION)
|
||||||
repository.increaseNonce(senderAddress);
|
repository.increaseNonce(senderAddress);
|
||||||
|
|
||||||
// actual gas value debit from the sender
|
// 2.2 PERFORM THE GAS VALUE TX
|
||||||
// the purchase gas will be available for the
|
// (THIS STAGE IS NOT REVERTED BY ANY EXCEPTION)
|
||||||
// contract in the execution state, and
|
BigInteger gasDebit = tx.getTotalGasValueDebit();
|
||||||
// can be validate using GAS op
|
|
||||||
|
// 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) {
|
if (gasDebit.signum() == 1) {
|
||||||
BigInteger balance = senderAccount.getBalance();
|
BigInteger balance = senderAccount.getBalance();
|
||||||
if (balance.compareTo(gasDebit) == -1) {
|
if (balance.compareTo(gasDebit) == -1) {
|
||||||
|
@ -177,23 +185,7 @@ public class WorldManager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
byte[] code;
|
// 5. CREATE OR EXECUTE PROGRAM
|
||||||
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));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isContractCreation || code != null) {
|
if (isContractCreation || code != null) {
|
||||||
Block lastBlock = blockchain.getLastBlock();
|
Block lastBlock = blockchain.getLastBlock();
|
||||||
|
|
||||||
|
@ -206,6 +198,18 @@ public class WorldManager {
|
||||||
ProgramResult result = program.getResult();
|
ProgramResult result = program.getResult();
|
||||||
applyProgramResult(result, gasDebit, trackRepository,
|
applyProgramResult(result, gasDebit, trackRepository,
|
||||||
senderAddress, receiverAddress, coinbase, isContractCreation);
|
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) {
|
} catch (RuntimeException e) {
|
||||||
trackRepository.rollback();
|
trackRepository.rollback();
|
||||||
|
@ -276,7 +280,7 @@ public class WorldManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void applyBlock(Block block) {
|
public void applyBlock(Block block) {
|
||||||
|
|
||||||
int i = 0;
|
int i = 0;
|
||||||
for (Transaction tx : block.getTransactionsList()) {
|
for (Transaction tx : block.getTransactionsList()) {
|
||||||
applyTransaction(tx, block.getCoinbase());
|
applyTransaction(tx, block.getCoinbase());
|
||||||
|
|
Loading…
Reference in New Issue