Skip to content
This repository was archived by the owner on Dec 5, 2024. It is now read-only.

Commit 6b87540

Browse files
authored
Merge pull request #1173 from ethereum/feature/eip-1283
Feature/eip 1283
2 parents a8a8613 + 53098a6 commit 6b87540

File tree

15 files changed

+387
-12
lines changed

15 files changed

+387
-12
lines changed

ethereumj-core/src/main/java/org/ethereum/config/BlockchainConfig.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,4 +175,10 @@ String validateTransactionChanges(BlockStore blockStore, Block curBlock, Transac
175175
* EXTCODEHASH opcode
176176
*/
177177
boolean eip1052();
178+
179+
/**
180+
* EIP 1283: https://eips.ethereum.org/EIPS/eip-1283
181+
* Net gas metering for SSTORE without dirty maps
182+
*/
183+
boolean eip1283();
178184
}

ethereumj-core/src/main/java/org/ethereum/config/blockchain/AbstractConfig.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,11 @@ public boolean eip145() {
203203
return false;
204204
}
205205

206+
@Override
207+
public boolean eip1283() {
208+
return false;
209+
}
210+
206211
@Override
207212
public String toString() {
208213
return getClass().getSimpleName();

ethereumj-core/src/main/java/org/ethereum/config/blockchain/ConstantinopleConfig.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,4 +43,9 @@ public boolean eip1052() {
4343
public boolean eip145() {
4444
return true;
4545
}
46+
47+
@Override
48+
public boolean eip1283() {
49+
return true;
50+
}
4651
}

ethereumj-core/src/main/java/org/ethereum/config/blockchain/Eip150HFConfig.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,4 +191,9 @@ public boolean eip145() {
191191
public boolean eip1052() {
192192
return false;
193193
}
194+
195+
@Override
196+
public boolean eip1283() {
197+
return false;
198+
}
194199
}

ethereumj-core/src/main/java/org/ethereum/core/Repository.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,4 +235,10 @@ void loadAccount(byte[] addr, HashMap<ByteArrayWrapper, AccountState> cacheAccou
235235
HashMap<ByteArrayWrapper, ContractDetails> cacheDetails);
236236

237237
Repository getSnapshotTo(byte[] root);
238+
239+
/**
240+
* Clones repository so changes made to this repository are
241+
* not reflected in its clone.
242+
*/
243+
Repository clone();
238244
}

ethereumj-core/src/main/java/org/ethereum/core/TransactionExecutor.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -396,7 +396,7 @@ public TransactionExecutionSummary finalization() {
396396
// Accumulate refunds for suicides
397397
result.addFutureRefund(result.getDeleteAccounts().size() * config.getBlockchainConfig().
398398
getConfigForBlock(currentBlock.getNumber()).getGasCost().getSUICIDE_REFUND());
399-
long gasRefund = Math.min(result.getFutureRefund(), getGasUsed() / 2);
399+
long gasRefund = Math.min(Math.max(0, result.getFutureRefund()), getGasUsed() / 2);
400400
byte[] addr = tx.isContractCreation() ? tx.getContractAddress() : tx.getReceiveAddress();
401401
m_endGas = m_endGas.add(BigInteger.valueOf(gasRefund));
402402

ethereumj-core/src/main/java/org/ethereum/db/RepositoryImpl.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,14 @@ public String dumpStateTrie() {
230230
throw new RuntimeException("Not supported");
231231
}
232232

233+
/**
234+
* As tests only implementation this hack is pretty sufficient
235+
*/
236+
@Override
237+
public Repository clone() {
238+
return parent.startTracking();
239+
}
240+
233241
class ContractDetailsImpl implements ContractDetails {
234242
private byte[] address;
235243

ethereumj-core/src/main/java/org/ethereum/db/RepositoryRoot.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,11 @@ public Repository getSnapshotTo(byte[] root) {
134134
return new RepositoryRoot(stateDS, root);
135135
}
136136

137+
@Override
138+
public Repository clone() {
139+
return getSnapshotTo(getRoot());
140+
}
141+
137142
@Override
138143
public synchronized String dumpStateTrie() {
139144
return ((TrieImpl) stateTrie).dumpTrie();

ethereumj-core/src/main/java/org/ethereum/db/RepositoryWrapper.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,11 @@ public Repository getSnapshotTo(byte[] root) {
201201
return blockchain.getRepository().getSnapshotTo(root);
202202
}
203203

204+
@Override
205+
public Repository clone() {
206+
return getSnapshotTo(getRoot());
207+
}
208+
204209
@Override
205210
public int getStorageSize(byte[] addr) {
206211
return blockchain.getRepository().getStorageSize(addr);

ethereumj-core/src/main/java/org/ethereum/vm/GasCost.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ public class GasCost {
5151
private final int SET_SSTORE = 20000;
5252
private final int RESET_SSTORE = 5000;
5353
private final int REFUND_SSTORE = 15000;
54+
private final int REUSE_SSTORE = 200;
5455
private final int CREATE = 32000;
5556

5657
private final int JUMPDEST = 1;
@@ -169,6 +170,10 @@ public int getREFUND_SSTORE() {
169170
return REFUND_SSTORE;
170171
}
171172

173+
public int getREUSE_SSTORE() {
174+
return REUSE_SSTORE;
175+
}
176+
172177
public int getCREATE() {
173178
return CREATE;
174179
}

ethereumj-core/src/main/java/org/ethereum/vm/VM.java

Lines changed: 47 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -241,18 +241,54 @@ public void step(Program program) {
241241
}
242242
break;
243243
case SSTORE:
244+
DataWord currentValue = program.getCurrentValue(stack.peek());
245+
if (currentValue == null) currentValue = DataWord.ZERO;
244246
DataWord newValue = stack.get(stack.size() - 2);
245-
DataWord oldValue = program.storageLoad(stack.peek());
246-
if (oldValue == null && !newValue.isZero())
247-
gasCost = gasCosts.getSET_SSTORE();
248-
else if (oldValue != null && newValue.isZero()) {
249-
// todo: GASREFUND counter policy
250-
251-
// refund step cost policy.
252-
program.futureRefundGas(gasCosts.getREFUND_SSTORE());
253-
gasCost = gasCosts.getCLEAR_SSTORE();
254-
} else
255-
gasCost = gasCosts.getRESET_SSTORE();
247+
248+
if (blockchainConfig.eip1283()) { // Net gas metering for SSTORE
249+
if (newValue.equals(currentValue)) {
250+
gasCost = gasCosts.getREUSE_SSTORE();
251+
} else {
252+
DataWord origValue = program.getOriginalValue(stack.peek());
253+
if (origValue == null) origValue = DataWord.ZERO;
254+
if (currentValue.equals(origValue)) {
255+
if (origValue.isZero()) {
256+
gasCost = gasCosts.getSET_SSTORE();
257+
} else {
258+
gasCost = gasCosts.getCLEAR_SSTORE();
259+
if (newValue.isZero()) {
260+
program.futureRefundGas(gasCosts.getREFUND_SSTORE());
261+
}
262+
}
263+
} else {
264+
gasCost = gasCosts.getREUSE_SSTORE();
265+
if (!origValue.isZero()) {
266+
if (currentValue.isZero()) {
267+
program.futureRefundGas(-gasCosts.getREFUND_SSTORE());
268+
} else if (newValue.isZero()) {
269+
program.futureRefundGas(gasCosts.getREFUND_SSTORE());
270+
}
271+
}
272+
if (origValue.equals(newValue)) {
273+
if (origValue.isZero()) {
274+
program.futureRefundGas(gasCosts.getSET_SSTORE() - gasCosts.getREUSE_SSTORE());
275+
} else {
276+
program.futureRefundGas(gasCosts.getCLEAR_SSTORE() - gasCosts.getREUSE_SSTORE());
277+
}
278+
}
279+
}
280+
}
281+
} else { // Before EIP-1283 cost calculation
282+
if (currentValue.isZero() && !newValue.isZero())
283+
gasCost = gasCosts.getSET_SSTORE();
284+
else if (!currentValue.isZero() && newValue.isZero()) {
285+
// refund step cost policy.
286+
program.futureRefundGas(gasCosts.getREFUND_SSTORE());
287+
gasCost = gasCosts.getCLEAR_SSTORE();
288+
} else {
289+
gasCost = gasCosts.getRESET_SSTORE();
290+
}
291+
}
256292
break;
257293
case SLOAD:
258294
gasCost = gasCosts.getSLOAD();

ethereumj-core/src/main/java/org/ethereum/vm/program/Program.java

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ public class Program {
8888
private Stack stack;
8989
private Memory memory;
9090
private Storage storage;
91+
private Repository originalRepo;
9192
private byte[] returnDataBuffer;
9293

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

798+
/**
799+
* @return current Storage data for key
800+
*/
801+
public DataWord getCurrentValue(DataWord key) {
802+
return getStorage().getStorageValue(getOwnerAddress().getLast20Bytes(), key);
803+
}
804+
805+
/*
806+
* Original storage value at the beginning of current frame execution
807+
* For more info check EIP-1283 https://eips.ethereum.org/EIPS/eip-1283
808+
* @return Storage data at the beginning of Program execution
809+
*/
810+
public DataWord getOriginalValue(DataWord key) {
811+
return originalRepo.getStorageValue(getOwnerAddress().getLast20Bytes(), key);
812+
}
813+
796814
public DataWord getPrevHash() {
797815
return invoke.getPrevHash();
798816
}

ethereumj-core/src/main/java/org/ethereum/vm/program/Storage.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,11 @@ public Storage(ProgramInvoke programInvoke) {
4545
this.repository = programInvoke.getRepository();
4646
}
4747

48+
private Storage(Repository repository, DataWord address) {
49+
this.repository = repository;
50+
this.address = address;
51+
}
52+
4853
@Override
4954
public void setProgramListener(ProgramListener listener) {
5055
this.programListener = listener;
@@ -224,6 +229,11 @@ public Repository getSnapshotTo(byte[] root) {
224229
throw new UnsupportedOperationException();
225230
}
226231

232+
@Override
233+
public Repository clone() {
234+
return new Storage(repository.getSnapshotTo(getRoot()), address);
235+
}
236+
227237
@Override
228238
public int getStorageSize(byte[] addr) {
229239
return repository.getStorageSize(addr);

ethereumj-core/src/test/java/org/ethereum/jsontestsuite/suite/IterableTestRepository.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,11 @@ public Repository getSnapshotTo(byte[] root) {
7777
return new IterableTestRepository(src.getSnapshotTo(root), this);
7878
}
7979

80+
@Override
81+
public Repository clone() {
82+
return new IterableTestRepository(src.clone(), this);
83+
}
84+
8085
@Override
8186
public AccountState createAccount(byte[] addr) {
8287
addAccount(addr);

0 commit comments

Comments
 (0)