Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/eip 1283 #1173

Merged
merged 7 commits into from
Sep 10, 2018
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -175,4 +175,10 @@ String validateTransactionChanges(BlockStore blockStore, Block curBlock, Transac
* EXTCODEHASH opcode
*/
boolean eip1052();

/**
* EIP 1283: https://eips.ethereum.org/EIPS/eip-1283
* Net gas metering for SSTORE without dirty maps
*/
boolean eip1283();
}
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,11 @@ public boolean eip145() {
return false;
}

@Override
public boolean eip1283() {
return false;
}

@Override
public String toString() {
return getClass().getSimpleName();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,4 +43,9 @@ public boolean eip1052() {
public boolean eip145() {
return true;
}

@Override
public boolean eip1283() {
return true;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -191,4 +191,9 @@ public boolean eip145() {
public boolean eip1052() {
return false;
}

@Override
public boolean eip1283() {
return false;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -235,4 +235,6 @@ void loadAccount(byte[] addr, HashMap<ByteArrayWrapper, AccountState> cacheAccou
HashMap<ByteArrayWrapper, ContractDetails> cacheDetails);

Repository getSnapshotTo(byte[] root);

Repository clone();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's add a javadoc to highlight semantics of this call.

}
Original file line number Diff line number Diff line change
Expand Up @@ -396,7 +396,7 @@ public TransactionExecutionSummary finalization() {
// Accumulate refunds for suicides
result.addFutureRefund(result.getDeleteAccounts().size() * config.getBlockchainConfig().
getConfigForBlock(currentBlock.getNumber()).getGasCost().getSUICIDE_REFUND());
long gasRefund = Math.min(result.getFutureRefund(), getGasUsed() / 2);
long gasRefund = Math.min(Math.max(0, result.getFutureRefund()), getGasUsed() / 2);
byte[] addr = tx.isContractCreation() ? tx.getContractAddress() : tx.getReceiveAddress();
m_endGas = m_endGas.add(BigInteger.valueOf(gasRefund));

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,14 @@ public String dumpStateTrie() {
throw new RuntimeException("Not supported");
}

/**
* As tests only implementation this hack is pretty sufficient
*/
@Override
public Repository clone() {
return startTracking();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Basically, RepositoryImpl itself is used for tracks, thus, it makes sense to return parent.startTracking() here which will create a clone.

}

class ContractDetailsImpl implements ContractDetails {
private byte[] address;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,11 @@ public Repository getSnapshotTo(byte[] root) {
return new RepositoryRoot(stateDS, root);
}

@Override
public Repository clone() {
return getSnapshotTo(getRoot());
}

@Override
public synchronized String dumpStateTrie() {
return ((TrieImpl) stateTrie).dumpTrie();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,11 @@ public Repository getSnapshotTo(byte[] root) {
return blockchain.getRepository().getSnapshotTo(root);
}

@Override
public Repository clone() {
return getSnapshotTo(getRoot());
}

@Override
public int getStorageSize(byte[] addr) {
return blockchain.getRepository().getStorageSize(addr);
Expand Down
5 changes: 5 additions & 0 deletions ethereumj-core/src/main/java/org/ethereum/vm/GasCost.java
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ public class GasCost {
private final int SET_SSTORE = 20000;
private final int RESET_SSTORE = 5000;
private final int REFUND_SSTORE = 15000;
private final int REUSE_SSTORE = 200;
private final int CREATE = 32000;

private final int JUMPDEST = 1;
Expand Down Expand Up @@ -169,6 +170,10 @@ public int getREFUND_SSTORE() {
return REFUND_SSTORE;
}

public int getREUSE_SSTORE() {
return REUSE_SSTORE;
}

public int getCREATE() {
return CREATE;
}
Expand Down
58 changes: 47 additions & 11 deletions ethereumj-core/src/main/java/org/ethereum/vm/VM.java
Original file line number Diff line number Diff line change
Expand Up @@ -241,18 +241,54 @@ public void step(Program program) {
}
break;
case SSTORE:
DataWord currentValue = program.getCurrentValue(stack.peek());
if (currentValue == null) currentValue = DataWord.ZERO;
DataWord newValue = stack.get(stack.size() - 2);
DataWord oldValue = program.storageLoad(stack.peek());
if (oldValue == null && !newValue.isZero())
gasCost = gasCosts.getSET_SSTORE();
else if (oldValue != null && newValue.isZero()) {
// todo: GASREFUND counter policy

// refund step cost policy.
program.futureRefundGas(gasCosts.getREFUND_SSTORE());
gasCost = gasCosts.getCLEAR_SSTORE();
} else
gasCost = gasCosts.getRESET_SSTORE();

if (blockchainConfig.eip1283()) { // Net gas metering for SSTORE
if (newValue.equals(currentValue)) {
gasCost = gasCosts.getREUSE_SSTORE();
} else {
DataWord origValue = program.getOriginalValue(stack.peek());
if (origValue == null) origValue = DataWord.ZERO;
if (currentValue.equals(origValue)) {
if (origValue.isZero()) {
gasCost = gasCosts.getSET_SSTORE();
} else {
gasCost = gasCosts.getCLEAR_SSTORE();
if (newValue.isZero()) {
program.futureRefundGas(gasCosts.getREFUND_SSTORE());
}
}
} else {
gasCost = gasCosts.getREUSE_SSTORE();
if (!origValue.isZero()) {
if (currentValue.isZero()) {
program.futureRefundGas(-gasCosts.getREFUND_SSTORE());
} else if (newValue.isZero()) {
program.futureRefundGas(gasCosts.getREFUND_SSTORE());
}
}
if (origValue.equals(newValue)) {
if (origValue.isZero()) {
program.futureRefundGas(gasCosts.getSET_SSTORE() - gasCosts.getREUSE_SSTORE());
} else {
program.futureRefundGas(gasCosts.getCLEAR_SSTORE() - gasCosts.getREUSE_SSTORE());
}
}
}
}
} else { // Before EIP-1283 cost calculation
if (currentValue.isZero() && !newValue.isZero())
gasCost = gasCosts.getSET_SSTORE();
else if (!currentValue.isZero() && newValue.isZero()) {
// refund step cost policy.
program.futureRefundGas(gasCosts.getREFUND_SSTORE());
gasCost = gasCosts.getCLEAR_SSTORE();
} else {
gasCost = gasCosts.getRESET_SSTORE();
}
}
break;
case SLOAD:
gasCost = gasCosts.getSLOAD();
Expand Down
18 changes: 18 additions & 0 deletions ethereumj-core/src/main/java/org/ethereum/vm/program/Program.java
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ public class Program {
private Stack stack;
private Memory memory;
private Storage storage;
private Repository originalRepo;
private byte[] returnDataBuffer;

private ProgramResult result = new ProgramResult();
Expand Down Expand Up @@ -136,6 +137,7 @@ public Program(byte[] codeHash, byte[] ops, ProgramInvoke programInvoke, Transac
traceListener = new ProgramTraceListener(config.vmTrace());
this.memory = setupProgramListener(new Memory());
this.stack = setupProgramListener(new Stack());
this.originalRepo = programInvoke.getRepository().clone();
this.storage = setupProgramListener(new Storage(programInvoke));
this.trace = new ProgramTrace(config, programInvoke);
this.blockchainConfig = config.getBlockchainConfig().getConfigForBlock(programInvoke.getNumber().longValue());
Expand Down Expand Up @@ -793,6 +795,22 @@ public DataWord storageLoad(DataWord key) {
return getStorage().getStorageValue(getOwnerAddress().getLast20Bytes(), key);
}

/**
* @return current Storage data for key
*/
public DataWord getCurrentValue(DataWord key) {
return getStorage().getStorageValue(getOwnerAddress().getLast20Bytes(), key);
}

/*
* Original storage value at the beginning of current frame execution
* For more info check EIP-1283 https://eips.ethereum.org/EIPS/eip-1283
* @return Storage data at the beginning of Program execution
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's extend description with a reference to the EIP-1283

*/
public DataWord getOriginalValue(DataWord key) {
return originalRepo.getStorageValue(getOwnerAddress().getLast20Bytes(), key);
}

public DataWord getPrevHash() {
return invoke.getPrevHash();
}
Expand Down
10 changes: 10 additions & 0 deletions ethereumj-core/src/main/java/org/ethereum/vm/program/Storage.java
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,11 @@ public Storage(ProgramInvoke programInvoke) {
this.repository = programInvoke.getRepository();
}

private Storage(Repository repository, DataWord address) {
this.repository = repository;
this.address = address;
}

@Override
public void setProgramListener(ProgramListener listener) {
this.programListener = listener;
Expand Down Expand Up @@ -224,6 +229,11 @@ public Repository getSnapshotTo(byte[] root) {
throw new UnsupportedOperationException();
}

@Override
public Repository clone() {
return new Storage(repository.getSnapshotTo(getRoot()), address);
}

@Override
public int getStorageSize(byte[] addr) {
return repository.getStorageSize(addr);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,11 @@ public Repository getSnapshotTo(byte[] root) {
return new IterableTestRepository(src.getSnapshotTo(root), this);
}

@Override
public Repository clone() {
return new IterableTestRepository(src.clone(), this);
}

@Override
public AccountState createAccount(byte[] addr) {
addAccount(addr);
Expand Down
Loading