diff --git a/ethereumj-core/src/main/java/org/ethereum/config/BlockchainConfig.java b/ethereumj-core/src/main/java/org/ethereum/config/BlockchainConfig.java
index 84f1256961..fea46125d2 100644
--- a/ethereumj-core/src/main/java/org/ethereum/config/BlockchainConfig.java
+++ b/ethereumj-core/src/main/java/org/ethereum/config/BlockchainConfig.java
@@ -52,6 +52,11 @@ public interface BlockchainConfig {
*/
BigInteger calcDifficulty(BlockHeader curBlock, BlockHeader parent);
+ /**
+ * Calculates difficulty adjustment to target mean block time
+ */
+ BigInteger getCalcDifficultyMultiplier(BlockHeader curBlock, BlockHeader parent);
+
/**
* Calculates transaction gas fee
*/
diff --git a/ethereumj-core/src/main/java/org/ethereum/config/blockchain/AbstractConfig.java b/ethereumj-core/src/main/java/org/ethereum/config/blockchain/AbstractConfig.java
index 1d2399fbee..b6386d955f 100644
--- a/ethereumj-core/src/main/java/org/ethereum/config/blockchain/AbstractConfig.java
+++ b/ethereumj-core/src/main/java/org/ethereum/config/blockchain/AbstractConfig.java
@@ -100,8 +100,6 @@ public BigInteger calcDifficulty(BlockHeader curBlock, BlockHeader parent) {
return difficulty;
}
- protected abstract BigInteger getCalcDifficultyMultiplier(BlockHeader curBlock, BlockHeader parent);
-
protected int getExplosion(BlockHeader curBlock, BlockHeader parent) {
int periodCount = (int) (curBlock.getNumber() / getConstants().getEXP_DIFFICULTY_PERIOD());
return periodCount - 2;
diff --git a/ethereumj-core/src/main/java/org/ethereum/config/blockchain/ByzantiumConfig.java b/ethereumj-core/src/main/java/org/ethereum/config/blockchain/ByzantiumConfig.java
index 22151e4fe4..dd4151f174 100644
--- a/ethereumj-core/src/main/java/org/ethereum/config/blockchain/ByzantiumConfig.java
+++ b/ethereumj-core/src/main/java/org/ethereum/config/blockchain/ByzantiumConfig.java
@@ -1,9 +1,31 @@
package org.ethereum.config.blockchain;
import org.ethereum.config.BlockchainConfig;
+import org.ethereum.config.Constants;
+import org.ethereum.core.Block;
+import org.ethereum.core.BlockHeader;
+import org.ethereum.core.Repository;
+import org.spongycastle.util.encoders.Hex;
+
+import java.math.BigInteger;
+
+import static org.ethereum.util.BIUtil.max;
/**
- * Created by Anton Nashatyrev on 15.08.2017.
+ * EIPs included in the Hard Fork:
+ *
+ * - 100 - Change difficulty adjustment to target mean block time including uncles
+ * - 140 - REVERT instruction in the Ethereum Virtual Machine
+ * - 196 - Precompiled contracts for addition and scalar multiplication on the elliptic curve alt_bn128
+ * - 197 - Precompiled contracts for optimal Ate pairing check on the elliptic curve alt_bn128
+ * - 198 - Precompiled contract for bigint modular exponentiation
+ * - 211 - New opcodes: RETURNDATASIZE and RETURNDATACOPY
+ * - 214 - New opcode STATICCALL
+ * - 658 - Embedding transaction return data in receipts
+ *
+ *
+ * @author Mikhail Kalinin
+ * @since 14.08.2017
*/
public class ByzantiumConfig extends Eip160HFConfig {
@@ -11,6 +33,35 @@ public ByzantiumConfig(BlockchainConfig parent) {
super(parent);
}
+ @Override
+ public BigInteger calcDifficulty(BlockHeader curBlock, BlockHeader parent) {
+ BigInteger pd = parent.getDifficultyBI();
+ BigInteger quotient = pd.divide(getConstants().getDIFFICULTY_BOUND_DIVISOR());
+
+ BigInteger sign = getCalcDifficultyMultiplier(curBlock, parent);
+
+ BigInteger fromParent = pd.add(quotient.multiply(sign));
+ BigInteger difficulty = max(getConstants().getMINIMUM_DIFFICULTY(), fromParent);
+
+ int explosion = getExplosion(curBlock, parent);
+
+ if (explosion >= 0) {
+ difficulty = max(getConstants().getMINIMUM_DIFFICULTY(), difficulty.add(BigInteger.ONE.shiftLeft(explosion)));
+ }
+
+ return difficulty;
+ }
+
+ protected int getExplosion(BlockHeader curBlock, BlockHeader parent) {
+ int periodCount = (int) (curBlock.getNumber() / getConstants().getEXP_DIFFICULTY_PERIOD());
+ return periodCount - 2;
+ }
+
+ @Override
+ public BigInteger getCalcDifficultyMultiplier(BlockHeader curBlock, BlockHeader parent) {
+ long unclesAdj = parent.hasUncles() ? 2 : 1;
+ return BigInteger.valueOf(Math.max(unclesAdj - (curBlock.getTimestamp() - parent.getTimestamp()) / 9, -99));
+
@Override
public boolean eip140() {
return true;
diff --git a/ethereumj-core/src/main/java/org/ethereum/config/blockchain/ETCFork3M.java b/ethereumj-core/src/main/java/org/ethereum/config/blockchain/ETCFork3M.java
index 82b8b834e1..77f4a18dd9 100644
--- a/ethereumj-core/src/main/java/org/ethereum/config/blockchain/ETCFork3M.java
+++ b/ethereumj-core/src/main/java/org/ethereum/config/blockchain/ETCFork3M.java
@@ -66,7 +66,8 @@ public BigInteger calcDifficulty(BlockHeader curBlock, BlockHeader parent) {
return difficulty;
}
- protected BigInteger getCalcDifficultyMultiplier(BlockHeader curBlock, BlockHeader parent) {
+ @Override
+ public BigInteger getCalcDifficultyMultiplier(BlockHeader curBlock, BlockHeader parent) {
return BigInteger.valueOf(Math.max(1 - (curBlock.getTimestamp() - parent.getTimestamp()) / 10, -99));
}
diff --git a/ethereumj-core/src/main/java/org/ethereum/config/blockchain/Eip150HFConfig.java b/ethereumj-core/src/main/java/org/ethereum/config/blockchain/Eip150HFConfig.java
index 64f7bc9874..1e541ba3c8 100644
--- a/ethereumj-core/src/main/java/org/ethereum/config/blockchain/Eip150HFConfig.java
+++ b/ethereumj-core/src/main/java/org/ethereum/config/blockchain/Eip150HFConfig.java
@@ -87,6 +87,11 @@ public BigInteger calcDifficulty(BlockHeader curBlock, BlockHeader parent) {
return this.parent.calcDifficulty(curBlock, parent);
}
+ @Override
+ public BigInteger getCalcDifficultyMultiplier(BlockHeader curBlock, BlockHeader parent) {
+ return this.parent.getCalcDifficultyMultiplier(curBlock, parent);
+ }
+
@Override
public long getTransactionCost(Transaction tx) {
return parent.getTransactionCost(tx);
diff --git a/ethereumj-core/src/main/java/org/ethereum/config/blockchain/HomesteadConfig.java b/ethereumj-core/src/main/java/org/ethereum/config/blockchain/HomesteadConfig.java
index 45a63f3047..9bfd4648cf 100644
--- a/ethereumj-core/src/main/java/org/ethereum/config/blockchain/HomesteadConfig.java
+++ b/ethereumj-core/src/main/java/org/ethereum/config/blockchain/HomesteadConfig.java
@@ -52,7 +52,7 @@ public HomesteadConfig(Constants constants) {
}
@Override
- protected BigInteger getCalcDifficultyMultiplier(BlockHeader curBlock, BlockHeader parent) {
+ public BigInteger getCalcDifficultyMultiplier(BlockHeader curBlock, BlockHeader parent) {
return BigInteger.valueOf(Math.max(1 - (curBlock.getTimestamp() - parent.getTimestamp()) / 10, -99));
}
diff --git a/ethereumj-core/src/main/java/org/ethereum/config/blockchain/OlympicConfig.java b/ethereumj-core/src/main/java/org/ethereum/config/blockchain/OlympicConfig.java
index fd3bb40f93..82f8d8eb97 100644
--- a/ethereumj-core/src/main/java/org/ethereum/config/blockchain/OlympicConfig.java
+++ b/ethereumj-core/src/main/java/org/ethereum/config/blockchain/OlympicConfig.java
@@ -37,7 +37,7 @@ public OlympicConfig(Constants constants) {
}
@Override
- protected BigInteger getCalcDifficultyMultiplier(BlockHeader curBlock, BlockHeader parent) {
+ public BigInteger getCalcDifficultyMultiplier(BlockHeader curBlock, BlockHeader parent) {
return BigInteger.valueOf(curBlock.getTimestamp() >= parent.getTimestamp() +
getConstants().getDURATION_LIMIT() ? -1 : 1);
}
diff --git a/ethereumj-core/src/main/java/org/ethereum/core/BlockHeader.java b/ethereumj-core/src/main/java/org/ethereum/core/BlockHeader.java
index 125d016a7d..976393c17f 100644
--- a/ethereumj-core/src/main/java/org/ethereum/core/BlockHeader.java
+++ b/ethereumj-core/src/main/java/org/ethereum/core/BlockHeader.java
@@ -148,7 +148,7 @@ public BlockHeader(byte[] parentHash, byte[] unclesHash, byte[] coinbase,
this.extraData = extraData;
this.mixHash = mixHash;
this.nonce = nonce;
- this.stateRoot = HashUtil.EMPTY_TRIE_HASH;
+ this.stateRoot = EMPTY_TRIE_HASH;
}
public boolean isGenesis() {
@@ -374,6 +374,10 @@ public BigInteger calcDifficulty(BlockchainNetConfig config, BlockHeader parent)
calcDifficulty(this, parent);
}
+ public boolean hasUncles() {
+ return !FastByteComparisons.equal(unclesHash, EMPTY_TRIE_HASH);
+ }
+
public String toString() {
return toStringWithSuffix("\n");
}
diff --git a/ethereumj-core/src/test/java/org/ethereum/jsontestsuite/GitHubJSONTestSuite.java b/ethereumj-core/src/test/java/org/ethereum/jsontestsuite/GitHubJSONTestSuite.java
index 402d9086b3..4e544653cd 100644
--- a/ethereumj-core/src/test/java/org/ethereum/jsontestsuite/GitHubJSONTestSuite.java
+++ b/ethereumj-core/src/test/java/org/ethereum/jsontestsuite/GitHubJSONTestSuite.java
@@ -19,6 +19,7 @@
import org.ethereum.config.BlockchainNetConfig;
import org.ethereum.config.blockchain.*;
+import org.ethereum.config.net.BaseNetConfig;
import org.ethereum.jsontestsuite.suite.*;
import org.ethereum.jsontestsuite.suite.runners.TransactionTestRunner;
import org.json.simple.JSONObject;
@@ -263,15 +264,37 @@ public enum Network {
EIP150,
EIP158,
Byzantium,
- Constantinople;
+ Constantinople,
+
+ // Transition networks
+ FrontierToHomesteadAt5,
+ HomesteadToDaoAt5,
+ HomesteadToEIP150At5;
public BlockchainNetConfig getConfig() {
switch (this) {
+
case Frontier: return new FrontierConfig();
case Homestead: return new HomesteadConfig();
case EIP150: return new Eip150HFConfig(new DaoHFConfig());
case EIP158: return new Eip160HFConfig(new DaoHFConfig());
case Byzantium: return new ByzantiumConfig(new DaoHFConfig());
+
+ case FrontierToHomesteadAt5: return new BaseNetConfig() {{
+ add(0, new FrontierConfig());
+ add(5, new HomesteadConfig());
+ }};
+
+ case HomesteadToDaoAt5: return new BaseNetConfig() {{
+ add(0, new HomesteadConfig());
+ add(5, new DaoHFConfig(new HomesteadConfig(), 5));
+ }};
+
+ case HomesteadToEIP150At5: return new BaseNetConfig() {{
+ add(0, new HomesteadConfig());
+ add(5, new Eip150HFConfig(new HomesteadConfig()));
+ }};
+
default: throw new IllegalArgumentException("Unknown network value: " + this.name());
}
}
diff --git a/ethereumj-core/src/test/java/org/ethereum/jsontestsuite/GitHubTestNetTest.java b/ethereumj-core/src/test/java/org/ethereum/jsontestsuite/GitHubTestNetTest.java
index 4bacd14558..412c2bf73b 100644
--- a/ethereumj-core/src/test/java/org/ethereum/jsontestsuite/GitHubTestNetTest.java
+++ b/ethereumj-core/src/test/java/org/ethereum/jsontestsuite/GitHubTestNetTest.java
@@ -17,57 +17,47 @@
*/
package org.ethereum.jsontestsuite;
-import org.ethereum.config.SystemProperties;
-import org.ethereum.config.blockchain.DaoHFConfig;
-import org.ethereum.config.blockchain.Eip150HFConfig;
-import org.ethereum.config.blockchain.FrontierConfig;
-import org.ethereum.config.blockchain.HomesteadConfig;
-import org.ethereum.config.net.BaseNetConfig;
-import org.ethereum.config.net.MainNetConfig;
-import org.ethereum.jsontestsuite.suite.JSONReader;
-import org.json.simple.parser.ParseException;
+import org.ethereum.jsontestsuite.suite.BlockchainTestSuite;
import org.junit.*;
import org.junit.runners.MethodSorters;
import java.io.IOException;
-import java.util.Collections;
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class GitHubTestNetTest {
- //SHACOMMIT of tested commit, ethereum/tests.git
- public String shacommit = "9ed33d7440f13c09ce7f038f92abd02d23b26f0d";
+ static String commitSHA = "85f6d7cc01b6bd04e071f5ba579fc675cfd2043b";
+ static String treeSHA = "0af522c09e8a264f651f5a4715301381c14784d7"; // https://github.com/ethereum/tests/tree/develop/BlockchainTests/TransitionTests
- @Before
- public void setup() {
- SystemProperties.getDefault().setGenesisInfo("frontier.json");
- SystemProperties.getDefault().setBlockchainConfig(new BaseNetConfig() {{
- add(0, new FrontierConfig());
- add(5, new HomesteadConfig());
- add(8, new DaoHFConfig(new HomesteadConfig(), 8));
- add(10, new Eip150HFConfig(new DaoHFConfig(new HomesteadConfig(), 8)));
+ static BlockchainTestSuite suite;
- }});
+ @BeforeClass
+ public static void setup() {
+ suite = new BlockchainTestSuite(treeSHA, commitSHA);
}
- @After
- public void clean() {
- SystemProperties.getDefault().setBlockchainConfig(MainNetConfig.INSTANCE);
+ @Test
+ @Ignore
+ // this method is mostly for hands-on convenient testing
+ // using this method turn off initializing of BlockchainTestSuite to avoid unnecessary GitHub API hits
+ public void bcTransitionSingle() throws IOException {
+ BlockchainTestSuite.runSingle(
+ "TransitionTests/bcHomesteadToDao/DaoTransactions.json", commitSHA);
}
@Test
- public void bcEIP150Test() throws ParseException, IOException {
- String json = JSONReader.loadJSONFromCommit("BlockchainTests/TestNetwork/bcEIP150Test.json", shacommit);
- GitHubJSONTestSuite.runGitHubJsonBlockTest(json, Collections.EMPTY_SET);
+ public void bcFrontierToHomestead() throws IOException {
+ suite.runAll("TransitionTests/bcFrontierToHomestead", GitHubJSONTestSuite.Network.FrontierToHomesteadAt5);
}
+
@Test
- public void bcSimpleTransitionTest() throws ParseException, IOException {
- String json = JSONReader.loadJSONFromCommit("BlockchainTests/TestNetwork/bcSimpleTransitionTest.json", shacommit);
- GitHubJSONTestSuite.runGitHubJsonBlockTest(json, Collections.EMPTY_SET);
+ @Ignore // TODO fix it
+ public void bcHomesteadToDao() throws IOException {
+ suite.runAll("TransitionTests/bcHomesteadToDao", GitHubJSONTestSuite.Network.HomesteadToDaoAt5);
}
+
@Test
- public void bcTheDaoTest() throws ParseException, IOException {
- String json = JSONReader.loadJSONFromCommit("BlockchainTests/TestNetwork/bcTheDaoTest.json", shacommit);
- GitHubJSONTestSuite.runGitHubJsonBlockTest(json, Collections.EMPTY_SET);
+ public void bcHomesteadToEIP150() throws IOException {
+ suite.runAll("TransitionTests/bcHomesteadToEIP150", GitHubJSONTestSuite.Network.HomesteadToEIP150At5);
}
}
diff --git a/ethereumj-core/src/test/java/org/ethereum/jsontestsuite/suite/BlockchainTestSuite.java b/ethereumj-core/src/test/java/org/ethereum/jsontestsuite/suite/BlockchainTestSuite.java
index b5f1cffbce..736e68816b 100644
--- a/ethereumj-core/src/test/java/org/ethereum/jsontestsuite/suite/BlockchainTestSuite.java
+++ b/ethereumj-core/src/test/java/org/ethereum/jsontestsuite/suite/BlockchainTestSuite.java
@@ -33,6 +33,10 @@ public BlockchainTestSuite(String treeSHA, String commitSHA, GitHubJSONTestSuite
this.networks = networks;
}
+ public BlockchainTestSuite(String treeSHA, String commitSHA) {
+ this(treeSHA, commitSHA, GitHubJSONTestSuite.Network.values());
+ }
+
private static void run(List checkFiles,
String commitSHA,
GitHubJSONTestSuite.Network[] networks) throws IOException {
@@ -142,4 +146,9 @@ public static void runSingle(String testFile, String commitSHA,
logger.info(" " + testFile);
run(Collections.singletonList(testFile), commitSHA, new GitHubJSONTestSuite.Network[] { network });
}
+
+ public static void runSingle(String testFile, String commitSHA) throws IOException {
+ logger.info(" " + testFile);
+ run(Collections.singletonList(testFile), commitSHA, GitHubJSONTestSuite.Network.values());
+ }
}