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

Commit 5193432

Browse files
authored
Merge pull request #932 from ethereum/eip-684
Eip 684: Prevent overwriting contracts
2 parents a152764 + 5a07de1 commit 5193432

File tree

8 files changed

+62
-18
lines changed

8 files changed

+62
-18
lines changed

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
*/
1818
package org.ethereum.core;
1919

20+
import org.ethereum.config.BlockchainConfig;
2021
import org.ethereum.config.SystemProperties;
2122
import org.ethereum.crypto.HashUtil;
2223
import org.ethereum.util.FastByteComparisons;
@@ -136,6 +137,11 @@ public byte[] getEncoded() {
136137
return rlpEncoded;
137138
}
138139

140+
public boolean isContractExist(BlockchainConfig blockchainConfig) {
141+
return !FastByteComparisons.equal(codeHash, EMPTY_DATA_HASH) ||
142+
!blockchainConfig.getConstants().getInitialNonce().equals(nonce);
143+
}
144+
139145
public boolean isEmpty() {
140146
return FastByteComparisons.equal(codeHash, EMPTY_DATA_HASH) &&
141147
BigInteger.ZERO.equals(balance) &&

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

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@
3434
import org.slf4j.Logger;
3535
import org.slf4j.LoggerFactory;
3636
import org.spongycastle.util.encoders.Hex;
37-
import org.springframework.beans.factory.annotation.Autowired;
3837

3938
import java.math.BigInteger;
4039
import java.util.List;
@@ -253,6 +252,13 @@ private void call() {
253252
private void create() {
254253
byte[] newContractAddress = tx.getContractAddress();
255254

255+
AccountState existingAddr = cacheTrack.getAccountState(newContractAddress);
256+
if (existingAddr != null && existingAddr.isContractExist(blockchainConfig)) {
257+
execError("Trying to create a contract with existing contract address: 0x" + Hex.toHexString(newContractAddress));
258+
m_endGas = BigInteger.ZERO;
259+
return;
260+
}
261+
256262
//In case of hashing collisions (for TCK tests only), check for any balance before createAccount()
257263
BigInteger oldBalance = track.getBalance(newContractAddress);
258264
cacheTrack.createAccount(tx.getContractAddress());

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

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import org.ethereum.config.BlockchainConfig;
2222
import org.ethereum.config.CommonConfig;
2323
import org.ethereum.config.SystemProperties;
24+
import org.ethereum.core.AccountState;
2425
import org.ethereum.core.Repository;
2526
import org.ethereum.core.Transaction;
2627
import org.ethereum.crypto.HashUtil;
@@ -414,15 +415,18 @@ public void createContract(DataWord value, DataWord memStart, DataWord memSize)
414415
if (logger.isInfoEnabled())
415416
logger.info("creating a new contract inside contract run: [{}]", Hex.toHexString(senderAddress));
416417

418+
BlockchainConfig blockchainConfig = config.getBlockchainConfig().getConfigForBlock(getNumber().longValue());
417419
// actual gas subtract
418-
DataWord gasLimit = config.getBlockchainConfig().getConfigForBlock(getNumber().longValue()).
419-
getCreateGas(getGas());
420+
DataWord gasLimit = blockchainConfig.getCreateGas(getGas());
420421
spendGas(gasLimit.longValue(), "internal call");
421422

422423
// [2] CREATE THE CONTRACT ADDRESS
423424
byte[] nonce = getStorage().getNonce(senderAddress).toByteArray();
424425
byte[] newAddress = HashUtil.calcNewAddr(getOwnerAddress().getLast20Bytes(), nonce);
425426

427+
AccountState existingAddr = getStorage().getAccountState(newAddress);
428+
boolean contractAlreadyExists = existingAddr != null && existingAddr.isContractExist(blockchainConfig);
429+
426430
if (byTestingSuite()) {
427431
// This keeps track of the contracts created for a test
428432
getResult().addCallCreate(programCode, EMPTY_BYTE_ARRAY,
@@ -460,9 +464,11 @@ public void createContract(DataWord value, DataWord memStart, DataWord memSize)
460464
this, new DataWord(newAddress), getOwnerAddress(), value, gasLimit,
461465
newBalance, null, track, this.invoke.getBlockStore(), false, byTestingSuite());
462466

463-
ProgramResult result = ProgramResult.empty();
467+
ProgramResult result = ProgramResult.createEmpty();
464468

465-
if (isNotEmpty(programCode)) {
469+
if (contractAlreadyExists) {
470+
result.setException(new BytecodeExecutionException("Trying to create a contract with existing contract address: 0x" + Hex.toHexString(newAddress)));
471+
} else if (isNotEmpty(programCode)) {
466472
VM vm = new VM(config);
467473
Program program = new Program(programCode, programInvoke, internalTx, config).withCommonConfig(commonConfig);
468474
vm.play(program);
@@ -494,7 +500,7 @@ this, new DataWord(newAddress), getOwnerAddress(), value, gasLimit,
494500
long storageCost = getLength(code) * getBlockchainConfig().getGasCost().getCREATE_DATA();
495501
long afterSpend = programInvoke.getGas().longValue() - storageCost - result.getGasUsed();
496502
if (afterSpend < 0) {
497-
if (!config.getBlockchainConfig().getConfigForBlock(getNumber().longValue()).getConstants().createEmptyContractOnOOG()) {
503+
if (!blockchainConfig.getConstants().createEmptyContractOnOOG()) {
498504
result.setException(Program.Exception.notEnoughSpendingGas("No gas to return just created contract",
499505
storageCost, this));
500506
} else {

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,7 @@ public void merge(ProgramResult another) {
197197
}
198198
}
199199

200-
public static ProgramResult empty() {
200+
public static ProgramResult createEmpty() {
201201
ProgramResult result = new ProgramResult();
202202
result.setHReturn(EMPTY_BYTE_ARRAY);
203203
return result;

ethereumj-core/src/test/java/org/ethereum/jsontestsuite/GitHubStateTest.java

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
3030
public class GitHubStateTest {
3131

32-
static String commitSHA = "f17609b3c2fc7404addf3d228955b16ae8e0cfb4";
32+
static String commitSHA = "d098a00a4e7108f7965d1ca81e2fd51fc5b1e11b";
3333
static String treeSHA = "fdcc301d8fdd65e6f1b56ffca9a786aa337c7bb8"; // https://github.com/ethereum/tests/tree/develop/GeneralStateTests/
3434
static GitHubJSONTestSuite.Network[] targetNets = {
3535
GitHubJSONTestSuite.Network.Frontier,
@@ -57,7 +57,7 @@ public void clean() {
5757
// it reduces impact on GitHub API
5858
public void stSingleTest() throws IOException {
5959
GeneralStateTestSuite.runSingle(
60-
"stZeroKnowledge/pointAdd.json", commitSHA, GitHubJSONTestSuite.Network.Byzantium);
60+
"stRevertTest/RevertDepthCreateAddressCollision.json", commitSHA, GitHubJSONTestSuite.Network.Byzantium);
6161
}
6262

6363
@Test
@@ -96,11 +96,6 @@ public void stCallCreateCallCodeTest() throws IOException {
9696
Set<String> excluded = new HashSet<>();
9797
excluded.add("CallRecursiveBombPreCall"); // Max Gas value is pending to be < 2^63
9898

99-
// the test creates a contract with the same address as existing contract (which is not possible in
100-
// live). In this case we need to clear the storage in TransactionExecutor.create
101-
// return back to this case when the contract deleting will be implemented
102-
excluded.add("createJS_ExampleContract");
103-
10499
suite.runAll("stCallCreateCallCodeTest", excluded);
105100
}
106101

ethereumj-core/src/test/java/org/ethereum/jsontestsuite/GitHubVMTest.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -160,8 +160,8 @@ public void testVMGitHub() throws ParseException {
160160
@Test // testing full suite
161161
public void testRandomVMGitHub() throws ParseException {
162162

163-
String shacommit = "c5eafb85390eee59b838a93ae31bc16a5fd4f7b1";
164-
List<String> fileNames = getFileNamesForTreeSha(shacommit);
163+
String treeSha = "c5eafb85390eee59b838a93ae31bc16a5fd4f7b1";
164+
List<String> fileNames = getFileNamesForTreeSha(treeSha);
165165
List<String> excludedFiles =
166166
Collections.singletonList(
167167
""
@@ -171,7 +171,7 @@ public void testRandomVMGitHub() throws ParseException {
171171

172172
if (excludedFiles.contains(fileName)) continue;
173173
System.out.println("Running: " + fileName);
174-
String json = JSONReader.loadJSON("VMTests//RandomTests/" + fileName);
174+
String json = JSONReader.loadJSONFromCommit("VMTests//RandomTests/" + fileName, shacommit);
175175
GitHubJSONTestSuite.runGitHubJsonVMTest(json);
176176
}
177177

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

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
import static org.ethereum.jsontestsuite.suite.JSONReader.listJsonBlobsForTreeSha;
1414
import static org.ethereum.jsontestsuite.suite.JSONReader.loadJSONFromCommit;
15+
import static org.ethereum.jsontestsuite.suite.JSONReader.loadJSONsFromCommit;
1516

1617
/**
1718
* @author Mikhail Kalinin
@@ -49,8 +50,12 @@ private static void run(List<String> checkFiles,
4950
if (checkFiles.isEmpty()) return;
5051

5152
List<BlockTestSuite> suites = new ArrayList<>();
53+
List<String> filenames = new ArrayList<>();
5254
for (String file : checkFiles) {
53-
String json = loadJSONFromCommit(TEST_ROOT + file, commitSHA);
55+
filenames.add(TEST_ROOT + file);
56+
}
57+
List<String> jsons = loadJSONsFromCommit(filenames, commitSHA, 64);
58+
for (String json : jsons) {
5459
suites.add(new BlockTestSuite(json));
5560
}
5661

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

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
import java.nio.file.Files;
3232
import java.util.ArrayList;
3333
import java.util.List;
34+
import java.util.concurrent.*;
3435

3536
import org.apache.commons.codec.binary.Base64;
3637
import org.slf4j.Logger;
@@ -40,6 +41,31 @@ public class JSONReader {
4041

4142
private static Logger logger = LoggerFactory.getLogger("TCK-Test");
4243

44+
public static List<String> loadJSONsFromCommit(List<String> filenames, final String shacommit, int threads) {
45+
ExecutorService threadPool = Executors.newFixedThreadPool(threads);
46+
List<Future<String>> retF = new ArrayList<>();
47+
for (final String filename : filenames) {
48+
Future<String> f = threadPool.submit(new Callable<String>() {
49+
@Override
50+
public String call() throws Exception {
51+
return loadJSONFromCommit(filename, shacommit);
52+
}
53+
});
54+
retF.add(f);
55+
}
56+
57+
List<String> ret = new ArrayList<>();
58+
for (Future<String> f : retF) {
59+
try {
60+
ret.add(f.get());
61+
} catch (InterruptedException | ExecutionException e) {
62+
throw new RuntimeException(e);
63+
}
64+
}
65+
66+
return ret;
67+
}
68+
4369
public static String loadJSON(String filename) {
4470
String json = "";
4571
if (!SystemProperties.getDefault().vmTestLoadLocal())

0 commit comments

Comments
 (0)