Merge pull request #61 from nicksavers/master
Apply blockReward after txs and for uncles
This commit is contained in:
commit
82c0d2ceab
|
@ -118,7 +118,6 @@ public class Blockchain {
|
||||||
if(!blockStateRootHash.equals(worldStateRootHash))
|
if(!blockStateRootHash.equals(worldStateRootHash))
|
||||||
logger.warn("WARNING: STATE CONFLICT! worldstate {} mismatch", worldStateRootHash);
|
logger.warn("WARNING: STATE CONFLICT! worldstate {} mismatch", worldStateRootHash);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
// Remove all wallet transactions as they already approved by the net
|
// Remove all wallet transactions as they already approved by the net
|
||||||
for (Block block : blocks) {
|
for (Block block : blocks) {
|
||||||
|
|
|
@ -35,9 +35,7 @@ public class ProgramPlayDialog extends JPanel implements ActionListener,
|
||||||
VM vm = new VM();
|
VM vm = new VM();
|
||||||
|
|
||||||
ProgramInvoke pi = new ProgramInvokeMockImpl();
|
ProgramInvoke pi = new ProgramInvokeMockImpl();
|
||||||
|
Program program = new Program(code, pi);
|
||||||
Program program = new Program(code ,
|
|
||||||
pi);
|
|
||||||
|
|
||||||
program.addListener(this);
|
program.addListener(this);
|
||||||
program.fullTrace();
|
program.fullTrace();
|
||||||
|
|
|
@ -77,9 +77,6 @@ public class WorldManager {
|
||||||
if (blockchain != null)
|
if (blockchain != null)
|
||||||
blockchain.addWalletTransaction(tx);
|
blockchain.addWalletTransaction(tx);
|
||||||
|
|
||||||
// TODO: what is going on with simple wallet transfer ?
|
|
||||||
|
|
||||||
// 1. VALIDATE THE NONCE
|
|
||||||
byte[] senderAddress = tx.getSender();
|
byte[] senderAddress = tx.getSender();
|
||||||
AccountState senderAccount = repository.getAccountState(senderAddress);
|
AccountState senderAccount = repository.getAccountState(senderAddress);
|
||||||
|
|
||||||
|
@ -90,6 +87,7 @@ public class WorldManager {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 1. VALIDATE THE NONCE
|
||||||
BigInteger nonce = senderAccount.getNonce();
|
BigInteger nonce = senderAccount.getNonce();
|
||||||
BigInteger txNonce = new BigInteger(tx.getNonce());
|
BigInteger txNonce = new BigInteger(tx.getNonce());
|
||||||
if (nonce.compareTo(txNonce) != 0) {
|
if (nonce.compareTo(txNonce) != 0) {
|
||||||
|
@ -105,18 +103,15 @@ public class WorldManager {
|
||||||
// first of all debit the gas from the issuer
|
// first of all debit the gas from the issuer
|
||||||
BigInteger gasDebit = tx.getTotalGasValueDebit();
|
BigInteger gasDebit = tx.getTotalGasValueDebit();
|
||||||
|
|
||||||
|
|
||||||
byte[] receiverAddress;
|
byte[] receiverAddress;
|
||||||
|
|
||||||
// Contract creation or existing Contract call
|
// Contract creation or existing Contract call
|
||||||
if (tx.isContractCreation()) {
|
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));
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
receiverAddress = tx.getReceiveAddress();
|
receiverAddress = tx.getReceiveAddress();
|
||||||
AccountState receiverState = repository.getAccountState(receiverAddress);
|
AccountState receiverState = repository.getAccountState(receiverAddress);
|
||||||
|
|
||||||
|
@ -130,22 +125,19 @@ public class WorldManager {
|
||||||
|
|
||||||
// 2.2 UPDATE THE NONCE
|
// 2.2 UPDATE THE NONCE
|
||||||
// (THIS STAGE IS NOT REVERTED BY ANY EXCEPTION)
|
// (THIS STAGE IS NOT REVERTED BY ANY EXCEPTION)
|
||||||
BigInteger balance = senderAccount.getBalance();
|
repository.increaseNonce(senderAddress);
|
||||||
if (balance.compareTo(BigInteger.ZERO) == 1) {
|
|
||||||
repository.increaseNonce(senderAddress);
|
|
||||||
}
|
|
||||||
|
|
||||||
// actual gas value debit from the sender
|
// actual gas value debit from the sender
|
||||||
// the purchase gas will be available for the
|
// the purchase gas will be available for the
|
||||||
// contract in the execution state, and
|
// contract in the execution state, and
|
||||||
// can be validate using GAS op
|
// can be validate using GAS op
|
||||||
if (gasDebit.signum() == 1) {
|
if (gasDebit.signum() == 1) {
|
||||||
|
BigInteger balance = senderAccount.getBalance();
|
||||||
if (balance.compareTo(gasDebit) == -1) {
|
if (balance.compareTo(gasDebit) == -1) {
|
||||||
logger.info("No gas to start the execution: sender={}",
|
logger.info("No gas to start the execution: sender={}",
|
||||||
Hex.toHexString(senderAddress));
|
Hex.toHexString(senderAddress));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
repository.addBalance(senderAddress, gasDebit.negate());
|
repository.addBalance(senderAddress, gasDebit.negate());
|
||||||
|
|
||||||
// The coinbase get the gas cost
|
// The coinbase get the gas cost
|
||||||
|
@ -172,7 +164,6 @@ public class WorldManager {
|
||||||
BigInteger senderBalance = senderAccount.getBalance();
|
BigInteger senderBalance = senderAccount.getBalance();
|
||||||
|
|
||||||
if (senderBalance.compareTo(new BigInteger(1, tx.getValue())) >= 0) {
|
if (senderBalance.compareTo(new BigInteger(1, tx.getValue())) >= 0) {
|
||||||
|
|
||||||
repository.addBalance(receiverAddress,
|
repository.addBalance(receiverAddress,
|
||||||
new BigInteger(1, tx.getValue()));
|
new BigInteger(1, tx.getValue()));
|
||||||
repository.addBalance(senderAddress,
|
repository.addBalance(senderAddress,
|
||||||
|
@ -242,7 +233,6 @@ public class WorldManager {
|
||||||
&& result.getException() instanceof Program.OutOfGasException) {
|
&& result.getException() instanceof Program.OutOfGasException) {
|
||||||
logger.info("contract run halted by OutOfGas: contract={}",
|
logger.info("contract run halted by OutOfGas: contract={}",
|
||||||
Hex.toHexString(contractAddress));
|
Hex.toHexString(contractAddress));
|
||||||
|
|
||||||
throw result.getException();
|
throw result.getException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -262,40 +252,33 @@ public class WorldManager {
|
||||||
repository.addBalance(coinbase, refund.negate());
|
repository.addBalance(coinbase, refund.negate());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (initResults){
|
if (initResults) {
|
||||||
|
|
||||||
// Save the code created by init
|
// Save the code created by init
|
||||||
byte[] bodyCode = null;
|
byte[] bodyCode = null;
|
||||||
if (result.getHReturn() != null) {
|
if (result.getHReturn() != null) {
|
||||||
bodyCode = result.getHReturn().array();
|
bodyCode = result.getHReturn().array();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bodyCode != null) {
|
if (bodyCode != null) {
|
||||||
repository.saveCode(contractAddress, bodyCode);
|
repository.saveCode(contractAddress, bodyCode);
|
||||||
if (stateLogger.isInfoEnabled())
|
if (stateLogger.isInfoEnabled())
|
||||||
stateLogger
|
stateLogger
|
||||||
.info("saving code of the contract to the db:\n contract={} code={}",
|
.info("saving code of the contract to the db:\n contract={} code={}",
|
||||||
Hex.toHexString(contractAddress),
|
Hex.toHexString(contractAddress),
|
||||||
Hex.toHexString(bodyCode));
|
Hex.toHexString(bodyCode));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// delete the marked to die accounts
|
// delete the marked to die accounts
|
||||||
if (result.getDeleteAccounts() == null) return;
|
if (result.getDeleteAccounts() == null) return;
|
||||||
for (DataWord address : result.getDeleteAccounts()){
|
for (DataWord address : result.getDeleteAccounts()){
|
||||||
|
|
||||||
repository.delete(address.getNoLeadZeroesData());
|
repository.delete(address.getNoLeadZeroesData());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static BigInteger UNCLE_RATIO = BigInteger.valueOf(7).divide(BigInteger.valueOf(8));
|
||||||
public void applyBlock(Block block) {
|
public void applyBlock(Block block) {
|
||||||
|
|
||||||
// miner reward
|
|
||||||
if (repository.getAccountState(block.getCoinbase()) == null)
|
|
||||||
repository.createAccount(block.getCoinbase());
|
|
||||||
repository.addBalance(block.getCoinbase(), Block.BLOCK_REWARD);
|
|
||||||
|
|
||||||
int i = 0;
|
int i = 0;
|
||||||
List<Transaction> txList = block.getTransactionsList();
|
List<Transaction> txList = block.getTransactionsList();
|
||||||
for (Transaction tx : txList) {
|
for (Transaction tx : txList) {
|
||||||
|
@ -304,11 +287,13 @@ public class WorldManager {
|
||||||
Hex.toHexString(tx.getHash()));
|
Hex.toHexString(tx.getHash()));
|
||||||
++i;
|
++i;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public void applyBlockList(List<Block> blocks) {
|
// miner reward
|
||||||
for (int i = blocks.size() - 1; i >= 0; --i) {
|
if (repository.getAccountState(block.getCoinbase()) == null)
|
||||||
applyBlock(blocks.get(i));
|
repository.createAccount(block.getCoinbase());
|
||||||
|
repository.addBalance(block.getCoinbase(), Block.BLOCK_REWARD);
|
||||||
|
for (Block uncle : block.getUncleList()) {
|
||||||
|
repository.addBalance(uncle.getCoinbase(), Block.BLOCK_REWARD.multiply(UNCLE_RATIO));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -208,14 +208,14 @@ public class Program {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void suicide(DataWord obtainer){
|
public void suicide(DataWord obtainer) {
|
||||||
|
|
||||||
// 1) pass full endowment to the obtainer
|
// 1) pass full endowment to the obtainer
|
||||||
if (logger.isInfoEnabled())
|
if (logger.isInfoEnabled())
|
||||||
logger.info("Transfer to: [ {} ] heritage: [ {} ]", Hex.toHexString(obtainer.getNoLeadZeroesData())
|
logger.info("Transfer to: [ {} ] heritage: [ {} ]", Hex.toHexString(obtainer.getNoLeadZeroesData())
|
||||||
, getBalance().longValue());
|
, getBalance().longValue());
|
||||||
|
|
||||||
this.result.repository.addBalance(obtainer.getNoLeadZeroesData(),
|
this.result.getRepository().addBalance(obtainer.getNoLeadZeroesData(),
|
||||||
getBalance().value());
|
getBalance().value());
|
||||||
|
|
||||||
// 2) mark the account as for delete
|
// 2) mark the account as for delete
|
||||||
|
@ -224,8 +224,7 @@ public class Program {
|
||||||
|
|
||||||
public void createContract(DataWord gas, DataWord memStart, DataWord memSize) {
|
public void createContract(DataWord gas, DataWord memStart, DataWord memSize) {
|
||||||
|
|
||||||
if (invokeData.byTestingSuite()){
|
if (invokeData.byTestingSuite()) {
|
||||||
|
|
||||||
logger.info("[testing suite] - omit real create");
|
logger.info("[testing suite] - omit real create");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -291,7 +290,7 @@ public class Program {
|
||||||
|
|
||||||
// 5. REFUND THE REMAIN GAS
|
// 5. REFUND THE REMAIN GAS
|
||||||
BigInteger refundGas = gas.value().subtract(BigInteger.valueOf(result.getGasUsed()));
|
BigInteger refundGas = gas.value().subtract(BigInteger.valueOf(result.getGasUsed()));
|
||||||
if (refundGas.compareTo(BigInteger.ZERO) == 1){
|
if (refundGas.compareTo(BigInteger.ZERO) == 1) {
|
||||||
|
|
||||||
this.refundGas(refundGas.intValue(), "remain gas from the internal call");
|
this.refundGas(refundGas.intValue(), "remain gas from the internal call");
|
||||||
logger.info("The remain gas refunded, account: [ {} ], gas: [ {} ] ",
|
logger.info("The remain gas refunded, account: [ {} ], gas: [ {} ] ",
|
||||||
|
@ -341,7 +340,7 @@ public class Program {
|
||||||
|
|
||||||
BigInteger endowment = endowmentValue.value();
|
BigInteger endowment = endowmentValue.value();
|
||||||
BigInteger senderBalance = result.getRepository().getBalance(senderAddress);
|
BigInteger senderBalance = result.getRepository().getBalance(senderAddress);
|
||||||
if (senderBalance.compareTo(endowment) < 0){
|
if (senderBalance.compareTo(endowment) < 0) {
|
||||||
stackPushZero();
|
stackPushZero();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -449,7 +448,7 @@ public class Program {
|
||||||
public void storageSave(byte[] key, byte[] val) {
|
public void storageSave(byte[] key, byte[] val) {
|
||||||
DataWord keyWord = new DataWord(key);
|
DataWord keyWord = new DataWord(key);
|
||||||
DataWord valWord = new DataWord(val);
|
DataWord valWord = new DataWord(val);
|
||||||
result.repository.addStorageRow(this.programAddress, keyWord, valWord);
|
result.getRepository().addStorageRow(this.programAddress, keyWord, valWord);
|
||||||
}
|
}
|
||||||
|
|
||||||
public DataWord getOwnerAddress() {
|
public DataWord getOwnerAddress() {
|
||||||
|
@ -504,7 +503,7 @@ public class Program {
|
||||||
}
|
}
|
||||||
|
|
||||||
public DataWord storageLoad(DataWord key) {
|
public DataWord storageLoad(DataWord key) {
|
||||||
return result.repository.getStorageValue(this.programAddress, key);
|
return result.getRepository().getStorageValue(this.programAddress, key);
|
||||||
}
|
}
|
||||||
|
|
||||||
public DataWord getPrevHash() {
|
public DataWord getPrevHash() {
|
||||||
|
|
|
@ -13,23 +13,14 @@ import java.util.Map;
|
||||||
public class ProgramInvokeImpl implements ProgramInvoke {
|
public class ProgramInvokeImpl implements ProgramInvoke {
|
||||||
|
|
||||||
/*** TRANSACTION env ***/
|
/*** TRANSACTION env ***/
|
||||||
DataWord address;
|
private DataWord address, origin, caller,
|
||||||
DataWord origin;
|
balance, gas, gasPrice, callValue;
|
||||||
DataWord caller;
|
|
||||||
DataWord balance;
|
|
||||||
DataWord gas;
|
|
||||||
DataWord gasPrice;
|
|
||||||
DataWord callValue;
|
|
||||||
|
|
||||||
byte[] msgData;
|
byte[] msgData;
|
||||||
|
|
||||||
/*** BLOCK env ***/
|
/*** BLOCK env ***/
|
||||||
DataWord prevHash;
|
private DataWord prevHash, coinbase, timestamp,
|
||||||
DataWord coinbase;
|
number, difficulty, gaslimit;
|
||||||
DataWord timestamp;
|
|
||||||
DataWord number;
|
|
||||||
DataWord difficulty;
|
|
||||||
DataWord gaslimit;
|
|
||||||
|
|
||||||
Map<DataWord, DataWord> storage;
|
Map<DataWord, DataWord> storage;
|
||||||
|
|
||||||
|
@ -104,7 +95,6 @@ public class ProgramInvokeImpl implements ProgramInvoke {
|
||||||
|
|
||||||
/* ADDRESS op */
|
/* ADDRESS op */
|
||||||
public DataWord getOwnerAddress() {
|
public DataWord getOwnerAddress() {
|
||||||
|
|
||||||
return address;
|
return address;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,14 +18,14 @@ public class ProgramResult {
|
||||||
private RuntimeException exception;
|
private RuntimeException exception;
|
||||||
private List<DataWord> deleteAccounts;
|
private List<DataWord> deleteAccounts;
|
||||||
|
|
||||||
Repository repository = null;
|
private Repository repository = null;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* for testing runs ,
|
* for testing runs ,
|
||||||
* call/create is not executed
|
* call/create is not executed
|
||||||
* but dummy recorded
|
* but dummy recorded
|
||||||
*/
|
*/
|
||||||
List<CallCreate> callCreateList;
|
private List<CallCreate> callCreateList;
|
||||||
|
|
||||||
public void spendGas(int gas) {
|
public void spendGas(int gas) {
|
||||||
gasUsed += gas;
|
gasUsed += gas;
|
||||||
|
@ -92,11 +92,9 @@ public class ProgramResult {
|
||||||
return callCreateList;
|
return callCreateList;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addCallCreate(byte[] data, byte[] destination, byte[] gasLimit, byte[] value){
|
public void addCallCreate(byte[] data, byte[] destination, byte[] gasLimit, byte[] value) {
|
||||||
|
if (callCreateList == null)
|
||||||
if (callCreateList == null)
|
callCreateList = new ArrayList<>();
|
||||||
callCreateList = new ArrayList<>();
|
callCreateList.add(new CallCreate(data, destination, gasLimit, value));
|
||||||
|
}
|
||||||
callCreateList.add(new CallCreate(data, destination, gasLimit, value));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue