From ca5dbc034c501fe443f8069b80c4f816eea6e509 Mon Sep 17 00:00:00 2001 From: Adam Smolarek Date: Thu, 20 Jul 2017 15:17:10 +0200 Subject: [PATCH 01/10] config --- .../iohk/ethereum/txExecTest/ForksTest.scala | 1 + src/main/resources/application.conf | 4 + .../daoFork/DaoForkConfiguration.scala | 129 ++++++++++++++++++ .../scala/io/iohk/ethereum/utils/Config.scala | 2 + .../validators/BlockHeaderValidator.scala | 17 ++- .../jsonrpc/PersonalServiceSpec.scala | 1 + .../ethereum/mining/BlockGeneratorSpec.scala | 2 + .../handshaker/EtcHandshakerSpec.scala | 1 + .../validators/BlockHeaderValidatorSpec.scala | 1 + src/universal/conf/blockchain.conf | 4 + src/universal/conf/morden.conf | 65 ++++----- 11 files changed, 192 insertions(+), 35 deletions(-) create mode 100644 src/main/scala/io/iohk/ethereum/daoFork/DaoForkConfiguration.scala diff --git a/src/it/scala/io/iohk/ethereum/txExecTest/ForksTest.scala b/src/it/scala/io/iohk/ethereum/txExecTest/ForksTest.scala index d29cd2ec2c..3c7ca2646c 100644 --- a/src/it/scala/io/iohk/ethereum/txExecTest/ForksTest.scala +++ b/src/it/scala/io/iohk/ethereum/txExecTest/ForksTest.scala @@ -28,6 +28,7 @@ class ForksTest extends FlatSpec with Matchers { override val difficultyBombPauseBlockNumber: BigInt = Long.MaxValue override val difficultyBombContinueBlockNumber: BigInt = Long.MaxValue override val accountStartNonce: UInt256 = UInt256.Zero + override val proDaoFork: Boolean = false } val noErrors = a[Right[_, Seq[Receipt]]] diff --git a/src/main/resources/application.conf b/src/main/resources/application.conf index c42f674187..701ed18a63 100644 --- a/src/main/resources/application.conf +++ b/src/main/resources/application.conf @@ -228,6 +228,10 @@ mantis { # Doc: https://github.com/ethereumproject/ECIPs/blob/master/ECIPs/ECIP-1010.md difficulty-bomb-continue-block-number = "5000000" + # specify if this client is pro or against DAO hard fork + # if true it will accept ETH version of chain if false it will accept ETC + pro-dao-fork = false + # DAO fork block number (Ethereum HF/Classic split) # https://blog.ethereum.org/2016/07/20/hard-fork-completed/ dao-fork-block-number = "1920000" diff --git a/src/main/scala/io/iohk/ethereum/daoFork/DaoForkConfiguration.scala b/src/main/scala/io/iohk/ethereum/daoFork/DaoForkConfiguration.scala new file mode 100644 index 0000000000..6337e8eca7 --- /dev/null +++ b/src/main/scala/io/iohk/ethereum/daoFork/DaoForkConfiguration.scala @@ -0,0 +1,129 @@ +package io.iohk.ethereum.daoFork + +import akka.util.ByteString +import io.iohk.ethereum.domain.Address +import org.spongycastle.util.encoders.Hex + +object DaoForkConfiguration { + val blockExtraData = ByteString(Hex.decode("64616f2d686172642d666f726b")) + val range = 10 + val refundContract = Address(Hex.decode("bf4ed7b27f1d666546e30d74d50d173d20bca754")) + val drainList = Seq( + Address(Hex.decode("d4fe7bc31cedb7bfb8a345f31e668033056b2728")), + Address(Hex.decode("b3fb0e5aba0e20e5c49d252dfd30e102b171a425")), + Address(Hex.decode("2c19c7f9ae8b751e37aeb2d93a699722395ae18f")), + Address(Hex.decode("ecd135fa4f61a655311e86238c92adcd779555d2")), + Address(Hex.decode("1975bd06d486162d5dc297798dfc41edd5d160a7")), + Address(Hex.decode("a3acf3a1e16b1d7c315e23510fdd7847b48234f6")), + Address(Hex.decode("319f70bab6845585f412ec7724b744fec6095c85")), + Address(Hex.decode("06706dd3f2c9abf0a21ddcc6941d9b86f0596936")), + Address(Hex.decode("5c8536898fbb74fc7445814902fd08422eac56d0")), + Address(Hex.decode("6966ab0d485353095148a2155858910e0965b6f9")), + Address(Hex.decode("779543a0491a837ca36ce8c635d6154e3c4911a6")), + Address(Hex.decode("2a5ed960395e2a49b1c758cef4aa15213cfd874c")), + Address(Hex.decode("5c6e67ccd5849c0d29219c4f95f1a7a93b3f5dc5")), + Address(Hex.decode("9c50426be05db97f5d64fc54bf89eff947f0a321")), + Address(Hex.decode("200450f06520bdd6c527622a273333384d870efb")), + Address(Hex.decode("be8539bfe837b67d1282b2b1d61c3f723966f049")), + Address(Hex.decode("6b0c4d41ba9ab8d8cfb5d379c69a612f2ced8ecb")), + Address(Hex.decode("f1385fb24aad0cd7432824085e42aff90886fef5")), + Address(Hex.decode("d1ac8b1ef1b69ff51d1d401a476e7e612414f091")), + Address(Hex.decode("8163e7fb499e90f8544ea62bbf80d21cd26d9efd")), + Address(Hex.decode("51e0ddd9998364a2eb38588679f0d2c42653e4a6")), + Address(Hex.decode("627a0a960c079c21c34f7612d5d230e01b4ad4c7")), + Address(Hex.decode("f0b1aa0eb660754448a7937c022e30aa692fe0c5")), + Address(Hex.decode("24c4d950dfd4dd1902bbed3508144a54542bba94")), + Address(Hex.decode("9f27daea7aca0aa0446220b98d028715e3bc803d")), + Address(Hex.decode("a5dc5acd6a7968a4554d89d65e59b7fd3bff0f90")), + Address(Hex.decode("d9aef3a1e38a39c16b31d1ace71bca8ef58d315b")), + Address(Hex.decode("63ed5a272de2f6d968408b4acb9024f4cc208ebf")), + Address(Hex.decode("6f6704e5a10332af6672e50b3d9754dc460dfa4d")), + Address(Hex.decode("77ca7b50b6cd7e2f3fa008e24ab793fd56cb15f6")), + Address(Hex.decode("492ea3bb0f3315521c31f273e565b868fc090f17")), + Address(Hex.decode("0ff30d6de14a8224aa97b78aea5388d1c51c1f00")), + Address(Hex.decode("9ea779f907f0b315b364b0cfc39a0fde5b02a416")), + Address(Hex.decode("ceaeb481747ca6c540a000c1f3641f8cef161fa7")), + Address(Hex.decode("cc34673c6c40e791051898567a1222daf90be287")), + Address(Hex.decode("579a80d909f346fbfb1189493f521d7f48d52238")), + Address(Hex.decode("e308bd1ac5fda103967359b2712dd89deffb7973")), + Address(Hex.decode("4cb31628079fb14e4bc3cd5e30c2f7489b00960c")), + Address(Hex.decode("ac1ecab32727358dba8962a0f3b261731aad9723")), + Address(Hex.decode("4fd6ace747f06ece9c49699c7cabc62d02211f75")), + Address(Hex.decode("440c59b325d2997a134c2c7c60a8c61611212bad")), + Address(Hex.decode("4486a3d68fac6967006d7a517b889fd3f98c102b")), + Address(Hex.decode("9c15b54878ba618f494b38f0ae7443db6af648ba")), + Address(Hex.decode("27b137a85656544b1ccb5a0f2e561a5703c6a68f")), + Address(Hex.decode("21c7fdb9ed8d291d79ffd82eb2c4356ec0d81241")), + Address(Hex.decode("23b75c2f6791eef49c69684db4c6c1f93bf49a50")), + Address(Hex.decode("1ca6abd14d30affe533b24d7a21bff4c2d5e1f3b")), + Address(Hex.decode("b9637156d330c0d605a791f1c31ba5890582fe1c")), + Address(Hex.decode("6131c42fa982e56929107413a9d526fd99405560")), + Address(Hex.decode("1591fc0f688c81fbeb17f5426a162a7024d430c2")), + Address(Hex.decode("542a9515200d14b68e934e9830d91645a980dd7a")), + Address(Hex.decode("c4bbd073882dd2add2424cf47d35213405b01324")), + Address(Hex.decode("782495b7b3355efb2833d56ecb34dc22ad7dfcc4")), + Address(Hex.decode("58b95c9a9d5d26825e70a82b6adb139d3fd829eb")), + Address(Hex.decode("3ba4d81db016dc2890c81f3acec2454bff5aada5")), + Address(Hex.decode("b52042c8ca3f8aa246fa79c3feaa3d959347c0ab")), + Address(Hex.decode("e4ae1efdfc53b73893af49113d8694a057b9c0d1")), + Address(Hex.decode("3c02a7bc0391e86d91b7d144e61c2c01a25a79c5")), + Address(Hex.decode("0737a6b837f97f46ebade41b9bc3e1c509c85c53")), + Address(Hex.decode("97f43a37f595ab5dd318fb46e7a155eae057317a")), + Address(Hex.decode("52c5317c848ba20c7504cb2c8052abd1fde29d03")), + Address(Hex.decode("4863226780fe7c0356454236d3b1c8792785748d")), + Address(Hex.decode("5d2b2e6fcbe3b11d26b525e085ff818dae332479")), + Address(Hex.decode("5f9f3392e9f62f63b8eac0beb55541fc8627f42c")), + Address(Hex.decode("057b56736d32b86616a10f619859c6cd6f59092a")), + Address(Hex.decode("9aa008f65de0b923a2a4f02012ad034a5e2e2192")), + Address(Hex.decode("304a554a310c7e546dfe434669c62820b7d83490")), + Address(Hex.decode("914d1b8b43e92723e64fd0a06f5bdb8dd9b10c79")), + Address(Hex.decode("4deb0033bb26bc534b197e61d19e0733e5679784")), + Address(Hex.decode("07f5c1e1bc2c93e0402f23341973a0e043f7bf8a")), + Address(Hex.decode("35a051a0010aba705c9008d7a7eff6fb88f6ea7b")), + Address(Hex.decode("4fa802324e929786dbda3b8820dc7834e9134a2a")), + Address(Hex.decode("9da397b9e80755301a3b32173283a91c0ef6c87e")), + Address(Hex.decode("8d9edb3054ce5c5774a420ac37ebae0ac02343c6")), + Address(Hex.decode("0101f3be8ebb4bbd39a2e3b9a3639d4259832fd9")), + Address(Hex.decode("5dc28b15dffed94048d73806ce4b7a4612a1d48f")), + Address(Hex.decode("bcf899e6c7d9d5a215ab1e3444c86806fa854c76")), + Address(Hex.decode("12e626b0eebfe86a56d633b9864e389b45dcb260")), + Address(Hex.decode("a2f1ccba9395d7fcb155bba8bc92db9bafaeade7")), + Address(Hex.decode("ec8e57756626fdc07c63ad2eafbd28d08e7b0ca5")), + Address(Hex.decode("d164b088bd9108b60d0ca3751da4bceb207b0782")), + Address(Hex.decode("6231b6d0d5e77fe001c2a460bd9584fee60d409b")), + Address(Hex.decode("1cba23d343a983e9b5cfd19496b9a9701ada385f")), + Address(Hex.decode("a82f360a8d3455c5c41366975bde739c37bfeb8a")), + Address(Hex.decode("9fcd2deaff372a39cc679d5c5e4de7bafb0b1339")), + Address(Hex.decode("005f5cee7a43331d5a3d3eec71305925a62f34b6")), + Address(Hex.decode("0e0da70933f4c7849fc0d203f5d1d43b9ae4532d")), + Address(Hex.decode("d131637d5275fd1a68a3200f4ad25c71a2a9522e")), + Address(Hex.decode("bc07118b9ac290e4622f5e77a0853539789effbe")), + Address(Hex.decode("47e7aa56d6bdf3f36be34619660de61275420af8")), + Address(Hex.decode("acd87e28b0c9d1254e868b81cba4cc20d9a32225")), + Address(Hex.decode("adf80daec7ba8dcf15392f1ac611fff65d94f880")), + Address(Hex.decode("5524c55fb03cf21f549444ccbecb664d0acad706")), + Address(Hex.decode("40b803a9abce16f50f36a77ba41180eb90023925")), + Address(Hex.decode("fe24cdd8648121a43a7c86d289be4dd2951ed49f")), + Address(Hex.decode("17802f43a0137c506ba92291391a8a8f207f487d")), + Address(Hex.decode("253488078a4edf4d6f42f113d1e62836a942cf1a")), + Address(Hex.decode("86af3e9626fce1957c82e88cbf04ddf3a2ed7915")), + Address(Hex.decode("b136707642a4ea12fb4bae820f03d2562ebff487")), + Address(Hex.decode("dbe9b615a3ae8709af8b93336ce9b477e4ac0940")), + Address(Hex.decode("f14c14075d6c4ed84b86798af0956deef67365b5")), + Address(Hex.decode("ca544e5c4687d109611d0f8f928b53a25af72448")), + Address(Hex.decode("aeeb8ff27288bdabc0fa5ebb731b6f409507516c")), + Address(Hex.decode("cbb9d3703e651b0d496cdefb8b92c25aeb2171f7")), + Address(Hex.decode("6d87578288b6cb5549d5076a207456a1f6a63dc0")), + Address(Hex.decode("b2c6f0dfbb716ac562e2d85d6cb2f8d5ee87603e")), + Address(Hex.decode("accc230e8a6e5be9160b8cdf2864dd2a001c28b6")), + Address(Hex.decode("2b3455ec7fedf16e646268bf88846bd7a2319bb2")), + Address(Hex.decode("4613f3bca5c44ea06337a9e439fbc6d42e501d0a")), + Address(Hex.decode("d343b217de44030afaa275f54d31a9317c7f441e")), + Address(Hex.decode("84ef4b2357079cd7a7c69fd7a37cd0609a679106")), + Address(Hex.decode("da2fef9e4a3230988ff17df2165440f37e8b1708")), + Address(Hex.decode("f4c64518ea10f995918a454158c6b61407ea345c")), + Address(Hex.decode("7602b46df5390e432ef1c307d4f2c9ff6d65cc97")), + Address(Hex.decode("bb9bc244d798123fde783fcc1c72d3bb8c189413")), + Address(Hex.decode("807640a13483f8ac783c557fcdf27be11ea4ac7a")) + ) +} \ No newline at end of file diff --git a/src/main/scala/io/iohk/ethereum/utils/Config.scala b/src/main/scala/io/iohk/ethereum/utils/Config.scala index 6d40cbbd68..7bc13f5fee 100644 --- a/src/main/scala/io/iohk/ethereum/utils/Config.scala +++ b/src/main/scala/io/iohk/ethereum/utils/Config.scala @@ -249,6 +249,7 @@ trait BlockchainConfig { val customGenesisFileOpt: Option[String] + val proDaoFork: Boolean val daoForkBlockNumber: BigInt val daoForkBlockHash: ByteString val accountStartNonce: UInt256 @@ -273,6 +274,7 @@ object BlockchainConfig { override val customGenesisFileOpt: Option[String] = Try(blockchainConfig.getString("custom-genesis-file")).toOption + override val proDaoFork: Boolean = blockchainConfig.getBoolean("pro-dao-fork") override val daoForkBlockNumber: BigInt = BigInt(blockchainConfig.getString("dao-fork-block-number")) override val daoForkBlockHash: ByteString = ByteString(Hex.decode(blockchainConfig.getString("dao-fork-block-hash"))) override val accountStartNonce: UInt256 = UInt256(BigInt(blockchainConfig.getString("account-start-nonce"))) diff --git a/src/main/scala/io/iohk/ethereum/validators/BlockHeaderValidator.scala b/src/main/scala/io/iohk/ethereum/validators/BlockHeaderValidator.scala index 6c0d303c1a..af9c8bbb85 100644 --- a/src/main/scala/io/iohk/ethereum/validators/BlockHeaderValidator.scala +++ b/src/main/scala/io/iohk/ethereum/validators/BlockHeaderValidator.scala @@ -2,6 +2,7 @@ package io.iohk.ethereum.validators import akka.util.ByteString import io.iohk.ethereum.crypto.{kec256, kec512} +import io.iohk.ethereum.daoFork.DaoForkConfiguration import io.iohk.ethereum.domain.{BlockHeader, Blockchain, DifficultyCalculator} import io.iohk.ethereum.utils.BlockchainConfig import org.spongycastle.util.encoders.Hex @@ -58,9 +59,18 @@ class BlockHeaderValidatorImpl(blockchainConfig: BlockchainConfig) extends Block * @param blockHeader BlockHeader to validate. * @return BlockHeader if valid, an [[HeaderExtraDataError]] otherwise */ - private def validateExtraData(blockHeader: BlockHeader): Either[BlockHeaderError, BlockHeader] = - if(blockHeader.extraData.length <= MaxExtraDataSize) Right(blockHeader) - else Left(HeaderExtraDataError) + private def validateExtraData(blockHeader: BlockHeader): Either[BlockHeaderError, BlockHeader] = { + if (blockchainConfig.proDaoFork && + blockchainConfig.daoForkBlockNumber <= blockHeader.number && + blockchainConfig.daoForkBlockNumber + DaoForkConfiguration.range > blockHeader.number && + blockHeader.extraData != DaoForkConfiguration.blockExtraData) { + Left(DaoHeaderExtraDataError) + } else if (blockHeader.extraData.length <= MaxExtraDataSize) { + Right(blockHeader) + } else { + Left(HeaderExtraDataError) + } + } /** * Validates [[io.iohk.ethereum.domain.BlockHeader.unixTimestamp]] is greater than the one of its parent @@ -168,6 +178,7 @@ sealed trait BlockHeaderError object BlockHeaderError { case object HeaderParentNotFoundError extends BlockHeaderError case object HeaderExtraDataError extends BlockHeaderError + case object DaoHeaderExtraDataError extends BlockHeaderError case object HeaderTimestampError extends BlockHeaderError case object HeaderDifficultyError extends BlockHeaderError case object HeaderGasUsedError extends BlockHeaderError diff --git a/src/test/scala/io/iohk/ethereum/jsonrpc/PersonalServiceSpec.scala b/src/test/scala/io/iohk/ethereum/jsonrpc/PersonalServiceSpec.scala index 8d67a0c68c..3eacb0ddcb 100644 --- a/src/test/scala/io/iohk/ethereum/jsonrpc/PersonalServiceSpec.scala +++ b/src/test/scala/io/iohk/ethereum/jsonrpc/PersonalServiceSpec.scala @@ -352,6 +352,7 @@ class PersonalServiceSpec extends FlatSpec with Matchers with MockFactory with S override val daoForkBlockHash: ByteString = ByteString.empty override val accountStartNonce: UInt256 = UInt256.Zero override val monetaryPolicyConfig: MonetaryPolicyConfig = new MonetaryPolicyConfig(0, 0, 0) + override val proDaoFork: Boolean = false } val wallet = Wallet(address, prvKey) diff --git a/src/test/scala/io/iohk/ethereum/mining/BlockGeneratorSpec.scala b/src/test/scala/io/iohk/ethereum/mining/BlockGeneratorSpec.scala index e831567151..47bd39d16b 100644 --- a/src/test/scala/io/iohk/ethereum/mining/BlockGeneratorSpec.scala +++ b/src/test/scala/io/iohk/ethereum/mining/BlockGeneratorSpec.scala @@ -115,6 +115,7 @@ class BlockGeneratorSpec extends FlatSpec with Matchers with PropertyChecks with override val eip150BlockNumber: BigInt = Long.MaxValue override val daoForkBlockHash: ByteString = ByteString("unused") override val accountStartNonce: UInt256 = UInt256.Zero + override val proDaoFork: Boolean = false } val generalTx = SignedTransaction.sign(transaction, keyPair, None) @@ -264,6 +265,7 @@ class BlockGeneratorSpec extends FlatSpec with Matchers with PropertyChecks with override val eip150BlockNumber: BigInt = Long.MaxValue override val daoForkBlockHash: ByteString = ByteString("unused") override val accountStartNonce: UInt256 = UInt256.Zero + override val proDaoFork: Boolean = false } lazy val ledger = new LedgerImpl(VM, blockchain, blockchainConfig) diff --git a/src/test/scala/io/iohk/ethereum/network/handshaker/EtcHandshakerSpec.scala b/src/test/scala/io/iohk/ethereum/network/handshaker/EtcHandshakerSpec.scala index bd5af709a4..016112d8d4 100644 --- a/src/test/scala/io/iohk/ethereum/network/handshaker/EtcHandshakerSpec.scala +++ b/src/test/scala/io/iohk/ethereum/network/handshaker/EtcHandshakerSpec.scala @@ -160,6 +160,7 @@ class EtcHandshakerSpec extends FlatSpec with Matchers { override val chainId: Byte = 0.toByte override val monetaryPolicyConfig: MonetaryPolicyConfig = null override val accountStartNonce: UInt256 = UInt256.Zero + override val proDaoFork: Boolean = false } val etcHandshakerConfigurationWithResolver = new MockEtcHandshakerConfiguration { diff --git a/src/test/scala/io/iohk/ethereum/validators/BlockHeaderValidatorSpec.scala b/src/test/scala/io/iohk/ethereum/validators/BlockHeaderValidatorSpec.scala index a922953c35..4a12d57ac6 100644 --- a/src/test/scala/io/iohk/ethereum/validators/BlockHeaderValidatorSpec.scala +++ b/src/test/scala/io/iohk/ethereum/validators/BlockHeaderValidatorSpec.scala @@ -33,6 +33,7 @@ class BlockHeaderValidatorSpec extends FlatSpec with Matchers with PropertyCheck override val monetaryPolicyConfig: MonetaryPolicyConfig = null override val customGenesisFileOpt: Option[String] = None override val accountStartNonce: UInt256 = UInt256.Zero + override val proDaoFork: Boolean = false } val blockHeaderValidator = new BlockHeaderValidatorImpl(blockchainConfig) diff --git a/src/universal/conf/blockchain.conf b/src/universal/conf/blockchain.conf index 4e09f10fc6..938f765e8c 100644 --- a/src/universal/conf/blockchain.conf +++ b/src/universal/conf/blockchain.conf @@ -29,6 +29,10 @@ mantis { # Doc: https://github.com/ethereumproject/ECIPs/blob/master/ECIPs/ECIP-1010.md # difficulty-bomb-continue-block-number = "5000000" + # specify if this client is pro or against DAO hard fork + # if true it will accept ETH version of chain if false it will accept ETC + # pro-dao-fork = false + # DAO fork block number (Ethereum HF/Classic split) # https://blog.ethereum.org/2016/07/20/hard-fork-completed/ # dao-fork-block-number = "1920000" diff --git a/src/universal/conf/morden.conf b/src/universal/conf/morden.conf index 2ff4555919..ebcca54f51 100644 --- a/src/universal/conf/morden.conf +++ b/src/universal/conf/morden.conf @@ -1,32 +1,33 @@ -mantis { - network { - discovery.bootstrap-nodes = [ - "enode://e731347db0521f3476e6bbbb83375dcd7133a1601425ebd15fd10f3835fd4c304fba6282087ca5a0deeafadf0aa0d4fd56c3323331901c1f38bd181c283e3e35@128.199.55.137:30303", - "enode://ceb5c0f85eb994dbe9693bf46d99b03f6b838d17cc74e68d5eb003171ff39e5f120b17f965b267c319303f94d80b9d994b77062fb1486d76ce95d9f3d8fe1cb4@46.101.122.141:30303", - "enode://fb28713820e718066a2f5df6250ae9d07cff22f672dbf26be6c75d088f821a9ad230138ba492c533a80407d054b1436ef18e951bb65e6901553516c8dffe8ff0@104.155.176.151:30304", - "enode://afdc6076b9bf3e7d3d01442d6841071e84c76c73a7016cb4f35c0437df219db38565766234448f1592a07ba5295a867f0ce87b359bf50311ed0b830a2361392d@104.154.136.117:30403", - "enode://21101a9597b79e933e17bc94ef3506fe99a137808907aa8fefa67eea4b789792ad11fb391f38b00087f8800a2d3dff011572b62a31232133dd1591ac2d1502c8@104.198.71.200:30403" - ] - - peer.network-id = 2 - } - - blockchain { - frontier-block-number = "0" - homestead-block-number = "494000" - eip150-block-number = "1783000" - eip155-block-number = "1915000" - eip160-block-number = "1915000" - difficulty-bomb-pause-block-number = "1915000" - difficulty-bomb-continue-block-number = "3415000" - - dao-fork-block-number = "1783000" - dao-fork-block-hash = "f376243aeff1f256d970714c3de9fd78fa4e63cf63e32a51fe1169e375d98145" - - account-start-nonce = "1048576" - - chain-id = "3e" - - custom-genesis-file = "conf/morden.json" - } -} +mantis { + network { + discovery.bootstrap-nodes = [ + "enode://e731347db0521f3476e6bbbb83375dcd7133a1601425ebd15fd10f3835fd4c304fba6282087ca5a0deeafadf0aa0d4fd56c3323331901c1f38bd181c283e3e35@128.199.55.137:30303", + "enode://ceb5c0f85eb994dbe9693bf46d99b03f6b838d17cc74e68d5eb003171ff39e5f120b17f965b267c319303f94d80b9d994b77062fb1486d76ce95d9f3d8fe1cb4@46.101.122.141:30303", + "enode://fb28713820e718066a2f5df6250ae9d07cff22f672dbf26be6c75d088f821a9ad230138ba492c533a80407d054b1436ef18e951bb65e6901553516c8dffe8ff0@104.155.176.151:30304", + "enode://afdc6076b9bf3e7d3d01442d6841071e84c76c73a7016cb4f35c0437df219db38565766234448f1592a07ba5295a867f0ce87b359bf50311ed0b830a2361392d@104.154.136.117:30403", + "enode://21101a9597b79e933e17bc94ef3506fe99a137808907aa8fefa67eea4b789792ad11fb391f38b00087f8800a2d3dff011572b62a31232133dd1591ac2d1502c8@104.198.71.200:30403" + ] + + peer.network-id = 2 + } + + blockchain { + frontier-block-number = "0" + homestead-block-number = "494000" + eip150-block-number = "1783000" + eip155-block-number = "1915000" + eip160-block-number = "1915000" + difficulty-bomb-pause-block-number = "1915000" + difficulty-bomb-continue-block-number = "3415000" + + pro-dao-fork = false + dao-fork-block-number = "1783000" + dao-fork-block-hash = "f376243aeff1f256d970714c3de9fd78fa4e63cf63e32a51fe1169e375d98145" + + account-start-nonce = "1048576" + + chain-id = "3e" + + custom-genesis-file = "conf/morden.json" + } +} From cc026a28a5aa55c01af7651b6fcaf8c4ae06e9b9 Mon Sep 17 00:00:00 2001 From: Adam Smolarek Date: Mon, 24 Jul 2017 12:14:38 +0200 Subject: [PATCH 02/10] wip --- .../daoFork/DaoForkConfiguration.scala | 2 +- .../iohk/ethereum/mining/BlockGenerator.scala | 42 +++++++++++-------- .../scala/io/iohk/ethereum/utils/Config.scala | 4 ++ .../validators/BlockHeaderValidator.scala | 22 +++++----- src/test/resources/application.conf | 4 ++ .../ethereum/jsonrpc/EthServiceSpec.scala | 1 + .../jsonrpc/JsonRpcControllerSpec.scala | 1 + .../ethereum/mining/BlockGeneratorSpec.scala | 11 +++++ .../iohk/ethereum/ommers/OmmersPoolSpec.scala | 2 + 9 files changed, 60 insertions(+), 29 deletions(-) diff --git a/src/main/scala/io/iohk/ethereum/daoFork/DaoForkConfiguration.scala b/src/main/scala/io/iohk/ethereum/daoFork/DaoForkConfiguration.scala index 6337e8eca7..ab20f0697c 100644 --- a/src/main/scala/io/iohk/ethereum/daoFork/DaoForkConfiguration.scala +++ b/src/main/scala/io/iohk/ethereum/daoFork/DaoForkConfiguration.scala @@ -126,4 +126,4 @@ object DaoForkConfiguration { Address(Hex.decode("bb9bc244d798123fde783fcc1c72d3bb8c189413")), Address(Hex.decode("807640a13483f8ac783c557fcdf27be11ea4ac7a")) ) -} \ No newline at end of file +} diff --git a/src/main/scala/io/iohk/ethereum/mining/BlockGenerator.scala b/src/main/scala/io/iohk/ethereum/mining/BlockGenerator.scala index 158856e73f..51c8c9266d 100644 --- a/src/main/scala/io/iohk/ethereum/mining/BlockGenerator.scala +++ b/src/main/scala/io/iohk/ethereum/mining/BlockGenerator.scala @@ -20,6 +20,7 @@ import io.iohk.ethereum.validators.MptListValidator.intByteArraySerializable import io.iohk.ethereum.validators.OmmersValidator.OmmersError import io.iohk.ethereum.validators.Validators import io.iohk.ethereum.crypto._ +import io.iohk.ethereum.daoFork.DaoForkConfiguration class BlockGenerator(blockchain: Blockchain, blockchainConfig: BlockchainConfig, miningConfig: MiningConfig, ledger: Ledger, validators: Validators, blockTimestampProvider: BlockTimestampProvider = DefaultBlockTimestampProvider) { @@ -88,24 +89,29 @@ class BlockGenerator(blockchain: Blockchain, blockchainConfig: BlockchainConfig, transactionsForBlock } - private def prepareHeader(blockNumber: BigInt, ommers: Seq[BlockHeader], beneficiary: Address, parent: Block, blockTimestamp: Long) = BlockHeader( - parentHash = parent.header.hash, - ommersHash = ByteString(kec256(ommers.toBytes: Array[Byte])), - beneficiary = beneficiary.bytes, - stateRoot = ByteString.empty, - //we are not able to calculate transactionsRoot here because we do not know if they will fail - transactionsRoot = ByteString.empty, - receiptsRoot = ByteString.empty, - logsBloom = ByteString.empty, - difficulty = difficulty.calculateDifficulty(blockNumber, blockTimestamp, parent.header), - number = blockNumber, - gasLimit = calculateGasLimit(parent.header.gasLimit), - gasUsed = 0, - unixTimestamp = blockTimestamp, - extraData = ByteString("mined with etc scala"), - mixHash = ByteString.empty, - nonce = ByteString.empty - ) + private def prepareHeader(blockNumber: BigInt, ommers: Seq[BlockHeader], beneficiary: Address, parent: Block, blockTimestamp: Long) = { + val inInRange = blockchainConfig.daoForkBlockNumber <= blockNumber && + blockchainConfig.daoForkBlockNumber + DaoForkConfiguration.range > blockNumber + + BlockHeader( + parentHash = parent.header.hash, + ommersHash = ByteString(kec256(ommers.toBytes: Array[Byte])), + beneficiary = beneficiary.bytes, + stateRoot = ByteString.empty, + //we are not able to calculate transactionsRoot here because we do not know if they will fail + transactionsRoot = ByteString.empty, + receiptsRoot = ByteString.empty, + logsBloom = ByteString.empty, + difficulty = difficulty.calculateDifficulty(blockNumber, blockTimestamp, parent.header), + number = blockNumber, + gasLimit = calculateGasLimit(parent.header.gasLimit), + gasUsed = 0, + unixTimestamp = blockTimestamp, + extraData = if (inInRange && blockchainConfig.proDaoFork) DaoForkConfiguration.blockExtraData else miningConfig.headerExtraData, + mixHash = ByteString.empty, + nonce = ByteString.empty + ) + } def getPrepared(powHeaderHash: ByteString): Option[PendingBlock] = { cache.getAndUpdate(new UnaryOperator[List[PendingBlock]] { diff --git a/src/main/scala/io/iohk/ethereum/utils/Config.scala b/src/main/scala/io/iohk/ethereum/utils/Config.scala index 7bc13f5fee..32ac15bc52 100644 --- a/src/main/scala/io/iohk/ethereum/utils/Config.scala +++ b/src/main/scala/io/iohk/ethereum/utils/Config.scala @@ -217,11 +217,14 @@ object TxPoolConfig { } trait MiningConfig { + //duplicated in BlockHeaderValidator + val MaxExtraDataSize: Int = 32 val ommersPoolSize: Int val blockCacheSize: Int val coinbase: Address val activeTimeout: FiniteDuration val ommerPoolQueryTimeout: FiniteDuration + val headerExtraData: ByteString } object MiningConfig { @@ -234,6 +237,7 @@ object MiningConfig { val ommersPoolSize: Int = miningConfig.getInt("ommers-pool-size") val activeTimeout: FiniteDuration = miningConfig.getDuration("active-timeout").toMillis.millis val ommerPoolQueryTimeout: FiniteDuration = miningConfig.getDuration("ommer-pool-query-timeout").toMillis.millis + override val headerExtraData: ByteString = ByteString(miningConfig.getString("header-extra-data").getBytes).take(MaxExtraDataSize) } } } diff --git a/src/main/scala/io/iohk/ethereum/validators/BlockHeaderValidator.scala b/src/main/scala/io/iohk/ethereum/validators/BlockHeaderValidator.scala index af9c8bbb85..786fb317c4 100644 --- a/src/main/scala/io/iohk/ethereum/validators/BlockHeaderValidator.scala +++ b/src/main/scala/io/iohk/ethereum/validators/BlockHeaderValidator.scala @@ -5,7 +5,6 @@ import io.iohk.ethereum.crypto.{kec256, kec512} import io.iohk.ethereum.daoFork.DaoForkConfiguration import io.iohk.ethereum.domain.{BlockHeader, Blockchain, DifficultyCalculator} import io.iohk.ethereum.utils.BlockchainConfig -import org.spongycastle.util.encoders.Hex trait BlockHeaderValidator { @@ -59,18 +58,21 @@ class BlockHeaderValidatorImpl(blockchainConfig: BlockchainConfig) extends Block * @param blockHeader BlockHeader to validate. * @return BlockHeader if valid, an [[HeaderExtraDataError]] otherwise */ - private def validateExtraData(blockHeader: BlockHeader): Either[BlockHeaderError, BlockHeader] = { - if (blockchainConfig.proDaoFork && - blockchainConfig.daoForkBlockNumber <= blockHeader.number && - blockchainConfig.daoForkBlockNumber + DaoForkConfiguration.range > blockHeader.number && - blockHeader.extraData != DaoForkConfiguration.blockExtraData) { - Left(DaoHeaderExtraDataError) - } else if (blockHeader.extraData.length <= MaxExtraDataSize) { - Right(blockHeader) + private def validateExtraData(blockHeader: BlockHeader): Either[BlockHeaderError, BlockHeader] = + if (blockHeader.extraData.length <= MaxExtraDataSize) { + val inInRange = blockchainConfig.daoForkBlockNumber <= blockHeader.number && + blockchainConfig.daoForkBlockNumber + DaoForkConfiguration.range > blockHeader.number + val daoForkData = blockHeader.extraData == DaoForkConfiguration.blockExtraData + + (inInRange, daoForkData, blockchainConfig.proDaoFork) match { + case (false, _, _) | (true, true, true) | (true, false, false) => + Right(blockHeader) + case _ => + Left(DaoHeaderExtraDataError) + } } else { Left(HeaderExtraDataError) } - } /** * Validates [[io.iohk.ethereum.domain.BlockHeader.unixTimestamp]] is greater than the one of its parent diff --git a/src/test/resources/application.conf b/src/test/resources/application.conf index 44534b83de..b99687fbfe 100644 --- a/src/test/resources/application.conf +++ b/src/test/resources/application.conf @@ -18,6 +18,10 @@ mantis { eip155-block-number = "3000000" } + mining { + header-extra-data = "grothendieck" + } + sync { do-fast-sync = true peers-scan-interval = 500.millis diff --git a/src/test/scala/io/iohk/ethereum/jsonrpc/EthServiceSpec.scala b/src/test/scala/io/iohk/ethereum/jsonrpc/EthServiceSpec.scala index cb12ed3453..47bf21ff3a 100644 --- a/src/test/scala/io/iohk/ethereum/jsonrpc/EthServiceSpec.scala +++ b/src/test/scala/io/iohk/ethereum/jsonrpc/EthServiceSpec.scala @@ -777,6 +777,7 @@ class EthServiceSpec extends FlatSpec with Matchers with ScalaFutures with MockF override val ommersPoolSize: Int = 30 override val activeTimeout: FiniteDuration = Timeouts.shortTimeout override val ommerPoolQueryTimeout: FiniteDuration = Timeouts.normalTimeout + override val headerExtraData: ByteString = ByteString.empty } val filterConfig = new FilterConfig { diff --git a/src/test/scala/io/iohk/ethereum/jsonrpc/JsonRpcControllerSpec.scala b/src/test/scala/io/iohk/ethereum/jsonrpc/JsonRpcControllerSpec.scala index 8b88f61de6..90db67543a 100644 --- a/src/test/scala/io/iohk/ethereum/jsonrpc/JsonRpcControllerSpec.scala +++ b/src/test/scala/io/iohk/ethereum/jsonrpc/JsonRpcControllerSpec.scala @@ -1308,6 +1308,7 @@ class JsonRpcControllerSpec extends FlatSpec with Matchers with PropertyChecks w override val ommersPoolSize: Int = 30 override val activeTimeout: FiniteDuration = Timeouts.normalTimeout override val ommerPoolQueryTimeout: FiniteDuration = Timeouts.normalTimeout + override val headerExtraData: ByteString = ByteString.empty } val filterConfig = new FilterConfig { diff --git a/src/test/scala/io/iohk/ethereum/mining/BlockGeneratorSpec.scala b/src/test/scala/io/iohk/ethereum/mining/BlockGeneratorSpec.scala index 47bd39d16b..1be7489802 100644 --- a/src/test/scala/io/iohk/ethereum/mining/BlockGeneratorSpec.scala +++ b/src/test/scala/io/iohk/ethereum/mining/BlockGeneratorSpec.scala @@ -18,6 +18,7 @@ import org.spongycastle.util.encoders.Hex import io.iohk.ethereum.crypto._ import io.iohk.ethereum.db.components.Storages.PruningModeComponent import io.iohk.ethereum.db.storage.pruning.{ArchivePruning, PruningMode} +import io.iohk.ethereum.daoFork.DaoForkConfiguration import io.iohk.ethereum.domain.SignedTransaction.FirstByteOfAddress import io.iohk.ethereum.utils.Config.DbConfig import org.spongycastle.crypto.AsymmetricCipherKeyPair @@ -41,6 +42,7 @@ class BlockGeneratorSpec extends FlatSpec with Matchers with PropertyChecks with .map(pb => pb.block.copy(header = pb.block.header.copy(nonce = minedNonce, mixHash = minedMixHash, unixTimestamp = miningTimestamp))) fullBlock.right.foreach(b => validators.blockHeaderValidator.validate(b.header, blockchain) shouldBe Right(b.header)) fullBlock.right.foreach(b => ledger.executeBlock(b, validators) shouldBe a[Right[_, Seq[Receipt]]]) + fullBlock.right.foreach(b => b.header.extraData shouldBe miningConfig.headerExtraData) } it should "generate correct block with transactions" in new TestSetup { @@ -56,6 +58,7 @@ class BlockGeneratorSpec extends FlatSpec with Matchers with PropertyChecks with .map(pb => pb.block.copy(header = pb.block.header.copy(nonce = minedNonce, mixHash = minedMixHash, unixTimestamp = miningTimestamp))) fullBlock.right.foreach(b => validators.blockHeaderValidator.validate(b.header, blockchain) shouldBe Right(b.header)) fullBlock.right.foreach(b => ledger.executeBlock(b, validators) shouldBe a[Right[_, Seq[Receipt]]]) + fullBlock.right.foreach(b => b.header.extraData shouldBe miningConfig.headerExtraData) } it should "filter out failing transactions" in new TestSetup { @@ -73,6 +76,7 @@ class BlockGeneratorSpec extends FlatSpec with Matchers with PropertyChecks with fullBlock.right.foreach(b => validators.blockHeaderValidator.validate(b.header, blockchain) shouldBe Right(b.header)) fullBlock.right.foreach(b => ledger.executeBlock(b, validators) shouldBe a[Right[_, Seq[Receipt]]]) fullBlock.right.foreach(b => b.body.transactionList shouldBe Seq(signedTransaction)) + fullBlock.right.foreach(b => b.header.extraData shouldBe miningConfig.headerExtraData) } it should "filter out transactions exceeding block gas limit and include correct transactions" in new TestSetup { @@ -96,6 +100,7 @@ class BlockGeneratorSpec extends FlatSpec with Matchers with PropertyChecks with fullBlock.right.foreach(b => validators.blockHeaderValidator.validate(b.header, blockchain) shouldBe Right(b.header)) fullBlock.right.foreach(b => ledger.executeBlock(b, validators) shouldBe a[Right[_, Seq[Receipt]]]) fullBlock.right.foreach(b => b.body.transactionList shouldBe Seq(signedTransaction)) + fullBlock.right.foreach(b => b.header.extraData shouldBe miningConfig.headerExtraData) } it should "generate block before eip155 and filter out chain specific tx" in new TestSetup { @@ -135,6 +140,7 @@ class BlockGeneratorSpec extends FlatSpec with Matchers with PropertyChecks with fullBlock.right.foreach(b => validators.blockHeaderValidator.validate(b.header, blockchain) shouldBe Right(b.header)) fullBlock.right.foreach(b => ledger.executeBlock(b, validators) shouldBe a[Right[_, Seq[Receipt]]]) fullBlock.right.foreach(b => b.body.transactionList shouldBe Seq(generalTx)) + fullBlock.right.foreach(b => b.header.extraData shouldBe miningConfig.headerExtraData) } it should "generate block after eip155 and allow both chain specific and general transactions" in new TestSetup { @@ -154,6 +160,7 @@ class BlockGeneratorSpec extends FlatSpec with Matchers with PropertyChecks with fullBlock.right.foreach(b => validators.blockHeaderValidator.validate(b.header, blockchain) shouldBe Right(b.header)) fullBlock.right.foreach(b => ledger.executeBlock(b, validators) shouldBe a[Right[_, Seq[Receipt]]]) fullBlock.right.foreach(b => b.body.transactionList shouldBe Seq(signedTransaction, generalTx)) + fullBlock.right.foreach(b => b.header.extraData shouldBe miningConfig.headerExtraData) } it should "include consecutive transactions from single sender" in new TestSetup { @@ -173,6 +180,7 @@ class BlockGeneratorSpec extends FlatSpec with Matchers with PropertyChecks with fullBlock.right.foreach(b => validators.blockHeaderValidator.validate(b.header, blockchain) shouldBe Right(b.header)) fullBlock.right.foreach(b => ledger.executeBlock(b, validators) shouldBe a[Right[_, Seq[Receipt]]]) fullBlock.right.foreach(b => b.body.transactionList shouldBe Seq(signedTransaction, nextTransaction)) + fullBlock.right.foreach(b => b.header.extraData shouldBe miningConfig.headerExtraData) } it should "filter out failing transaction from the middle of tx list" in new TestSetup { @@ -205,6 +213,7 @@ class BlockGeneratorSpec extends FlatSpec with Matchers with PropertyChecks with fullBlock.right.foreach(b => validators.blockHeaderValidator.validate(b.header, blockchain) shouldBe Right(b.header)) fullBlock.right.foreach(b => ledger.executeBlock(b, validators) shouldBe a[Right[_, Seq[Receipt]]]) fullBlock.right.foreach(b => b.body.transactionList shouldBe Seq(signedTransaction, nextTransaction)) + fullBlock.right.foreach(b => b.header.extraData shouldBe miningConfig.headerExtraData) } it should "include transaction with higher gas price if nonce is the same" in new TestSetup { @@ -227,6 +236,7 @@ class BlockGeneratorSpec extends FlatSpec with Matchers with PropertyChecks with fullBlock.right.foreach(b => validators.blockHeaderValidator.validate(b.header, blockchain) shouldBe Right(b.header)) fullBlock.right.foreach(b => ledger.executeBlock(b, validators) shouldBe a[Right[_, Seq[Receipt]]]) fullBlock.right.foreach(b => b.body.transactionList shouldBe Seq(signedTransaction)) + fullBlock.right.foreach(b => b.header.extraData shouldBe miningConfig.headerExtraData) } trait TestSetup extends EphemBlockchainTestSetup { @@ -287,6 +297,7 @@ class BlockGeneratorSpec extends FlatSpec with Matchers with PropertyChecks with override val ommersPoolSize: Int = 30 override val activeTimeout: FiniteDuration = Timeouts.normalTimeout override val ommerPoolQueryTimeout: FiniteDuration = Timeouts.normalTimeout + override val headerExtraData: ByteString = ByteString("mined with etc scala") } lazy val blockTimestampProvider = new FakeBlockTimestampProvider diff --git a/src/test/scala/io/iohk/ethereum/ommers/OmmersPoolSpec.scala b/src/test/scala/io/iohk/ethereum/ommers/OmmersPoolSpec.scala index 3b57b5ace2..7f1c5f79ac 100644 --- a/src/test/scala/io/iohk/ethereum/ommers/OmmersPoolSpec.scala +++ b/src/test/scala/io/iohk/ethereum/ommers/OmmersPoolSpec.scala @@ -2,6 +2,7 @@ package io.iohk.ethereum.ommers import akka.actor.ActorSystem import akka.testkit.TestProbe +import akka.util.ByteString import io.iohk.ethereum.Fixtures.Blocks.Block3125369 import io.iohk.ethereum.Timeouts import io.iohk.ethereum.domain.{Address, Blockchain, BlockchainImpl} @@ -60,6 +61,7 @@ class OmmersPoolSpec extends FlatSpec with Matchers with MockFactory { override val ommerPoolQueryTimeout: FiniteDuration = Timeouts.normalTimeout override val blockCacheSize: Int = 4 override val activeTimeout: FiniteDuration = Timeouts.normalTimeout + override val headerExtraData: ByteString = ByteString.empty } val testProbe = TestProbe() From f57650ed860eeabf27f358b6869c941f7a6a29ba Mon Sep 17 00:00:00 2001 From: Alan Verbner Date: Wed, 13 Sep 2017 21:12:23 -0300 Subject: [PATCH 03/10] [EC-236] Apply DAO hardfork in ledger --- .../iohk/ethereum/txExecTest/ForksTest.scala | 5 ++-- .../txExecTest/util/DumpChainApp.scala | 2 +- ...onfiguration.scala => DaoForkConfig.scala} | 27 +++++++++++++++---- .../io/iohk/ethereum/ledger/Ledger.scala | 22 ++++++++++++++- .../iohk/ethereum/mining/BlockGenerator.scala | 7 +++-- .../iohk/ethereum/network/ForkResolver.scala | 7 ++--- .../ethereum/nodebuilder/NodeBuilder.scala | 2 +- .../scala/io/iohk/ethereum/utils/Config.scala | 13 ++++----- .../validators/BlockHeaderValidator.scala | 11 ++++---- .../jsonrpc/PersonalServiceSpec.scala | 5 ++-- .../ethereum/mining/BlockGeneratorSpec.scala | 18 +++++-------- .../ethereum/network/EtcPeerManagerSpec.scala | 2 +- .../handshaker/EtcHandshakerSpec.scala | 12 +++++---- .../ethereum/network/p2p/PeerActorSpec.scala | 2 +- .../validators/BlockHeaderValidatorSpec.scala | 9 ++++--- 15 files changed, 91 insertions(+), 53 deletions(-) rename src/main/scala/io/iohk/ethereum/daoFork/{DaoForkConfiguration.scala => DaoForkConfig.scala} (89%) diff --git a/src/it/scala/io/iohk/ethereum/txExecTest/ForksTest.scala b/src/it/scala/io/iohk/ethereum/txExecTest/ForksTest.scala index 3c7ca2646c..b7cac3e9c2 100644 --- a/src/it/scala/io/iohk/ethereum/txExecTest/ForksTest.scala +++ b/src/it/scala/io/iohk/ethereum/txExecTest/ForksTest.scala @@ -1,6 +1,7 @@ package io.iohk.ethereum.txExecTest import akka.util.ByteString +import io.iohk.ethereum.daoFork.{DaoForkConfig, DefaultDaoForkConfig} import io.iohk.ethereum.domain.{BlockchainImpl, Receipt, UInt256} import io.iohk.ethereum.ledger.LedgerImpl import io.iohk.ethereum.txExecTest.util.FixtureProvider @@ -23,12 +24,10 @@ class ForksTest extends FlatSpec with Matchers { // unused override val customGenesisFileOpt: Option[String] = None - override val daoForkBlockNumber: BigInt = 10000 - override val daoForkBlockHash: ByteString = ByteString("unused") override val difficultyBombPauseBlockNumber: BigInt = Long.MaxValue override val difficultyBombContinueBlockNumber: BigInt = Long.MaxValue override val accountStartNonce: UInt256 = UInt256.Zero - override val proDaoFork: Boolean = false + override val daoForkConfig: DaoForkConfig = DefaultDaoForkConfig(daoForkBlockNumber = 1000, daoForkBlockHash = ByteString("unused"), proDaoFork = false) } val noErrors = a[Right[_, Seq[Receipt]]] diff --git a/src/it/scala/io/iohk/ethereum/txExecTest/util/DumpChainApp.scala b/src/it/scala/io/iohk/ethereum/txExecTest/util/DumpChainApp.scala index e46959175e..0383fdabb9 100644 --- a/src/it/scala/io/iohk/ethereum/txExecTest/util/DumpChainApp.scala +++ b/src/it/scala/io/iohk/ethereum/txExecTest/util/DumpChainApp.scala @@ -71,7 +71,7 @@ object DumpChainApp extends App with NodeKeyBuilder with SecureRandomBuilder wit lazy val forkResolverOpt = if (blockchainConfig.customGenesisFileOpt.isDefined) None - else Some(new ForkResolver.EtcForkResolver(blockchainConfig)) + else Some(new ForkResolver.EtcForkResolver(blockchainConfig.daoForkConfig)) private val handshakerConfiguration: EtcHandshakerConfiguration = new EtcHandshakerConfiguration { diff --git a/src/main/scala/io/iohk/ethereum/daoFork/DaoForkConfiguration.scala b/src/main/scala/io/iohk/ethereum/daoFork/DaoForkConfig.scala similarity index 89% rename from src/main/scala/io/iohk/ethereum/daoFork/DaoForkConfiguration.scala rename to src/main/scala/io/iohk/ethereum/daoFork/DaoForkConfig.scala index ab20f0697c..183dd3ff8a 100644 --- a/src/main/scala/io/iohk/ethereum/daoFork/DaoForkConfiguration.scala +++ b/src/main/scala/io/iohk/ethereum/daoFork/DaoForkConfig.scala @@ -4,11 +4,28 @@ import akka.util.ByteString import io.iohk.ethereum.domain.Address import org.spongycastle.util.encoders.Hex -object DaoForkConfiguration { - val blockExtraData = ByteString(Hex.decode("64616f2d686172642d666f726b")) - val range = 10 - val refundContract = Address(Hex.decode("bf4ed7b27f1d666546e30d74d50d173d20bca754")) - val drainList = Seq( +trait DaoForkConfig { + + val proDaoFork: Boolean + val daoForkBlockNumber: BigInt + val daoForkBlockHash: ByteString + val blockExtraData: ByteString + val range: Int + val refundContract: Address + val drainList: Seq[Address] + + private val extratadaBlockRange = daoForkBlockNumber to (daoForkBlockNumber + range) + + def isDaoForkBlock(blockNumber: BigInt): Boolean = proDaoFork && (daoForkBlockNumber == blockNumber) + + def requiresExtraData(blockNumber: BigInt): Boolean = proDaoFork && (extratadaBlockRange contains blockNumber) +} + +case class DefaultDaoForkConfig(proDaoFork: Boolean, daoForkBlockNumber: BigInt, daoForkBlockHash: ByteString) extends DaoForkConfig { + override val blockExtraData = ByteString(Hex.decode("64616f2d686172642d666f726b")) + override val range = 10 + override val refundContract = Address(Hex.decode("bf4ed7b27f1d666546e30d74d50d173d20bca754")) + override val drainList = Seq( Address(Hex.decode("d4fe7bc31cedb7bfb8a345f31e668033056b2728")), Address(Hex.decode("b3fb0e5aba0e20e5c49d252dfd30e102b171a425")), Address(Hex.decode("2c19c7f9ae8b751e37aeb2d93a699722395ae18f")), diff --git a/src/main/scala/io/iohk/ethereum/ledger/Ledger.scala b/src/main/scala/io/iohk/ethereum/ledger/Ledger.scala index 4c6d4d0143..6033f9b1d3 100644 --- a/src/main/scala/io/iohk/ethereum/ledger/Ledger.scala +++ b/src/main/scala/io/iohk/ethereum/ledger/Ledger.scala @@ -1,6 +1,7 @@ package io.iohk.ethereum.ledger import akka.util.ByteString +import io.iohk.ethereum.daoFork.DaoForkConfig import io.iohk.ethereum.domain._ import io.iohk.ethereum.validators._ import io.iohk.ethereum.ledger.BlockExecutionError.{StateBeforeFailure, TxsExecutionError, ValidationAfterExecError, ValidationBeforeExecError} @@ -76,8 +77,12 @@ class LedgerImpl(vm: VM, blockchain: BlockchainImpl, blockchainConfig: Blockchai val parentStateRoot = blockchain.getBlockHeaderByHash(block.header.parentHash).map(_.stateRoot) val initialWorld = blockchain.getWorldStateProxy(block.header.number, blockchainConfig.accountStartNonce, parentStateRoot) + val inputWorld = + if(blockchainConfig.daoForkConfig isDaoForkBlock block.header.number) applyDaoFork(initialWorld, blockchainConfig.daoForkConfig) + else initialWorld + log.debug(s"About to execute ${block.body.transactionList.size} txs from block ${block.header.number} (with hash: ${block.header.hashAsHexString})") - val blockTxsExecResult = executeTransactions(block.body.transactionList, initialWorld, block.header, signedTransactionValidator) + val blockTxsExecResult = executeTransactions(block.body.transactionList, inputWorld, block.header, signedTransactionValidator) blockTxsExecResult match { case Right(_) => log.debug(s"All txs from block ${block.header.hashAsHexString} were executed successfully") case Left(error) => log.debug(s"Not all txs from block ${block.header.hashAsHexString} were executed correctly, due to ${error.reason}") @@ -371,6 +376,21 @@ class LedgerImpl(vm: VM, blockchain: BlockchainImpl, blockchainConfig: Blockchai private[ledger] def deleteAccounts(addressesToDelete: Set[Address])(worldStateProxy: InMemoryWorldStateProxy): InMemoryWorldStateProxy = addressesToDelete.foldLeft(worldStateProxy){ case (world, address) => world.deleteAccount(address) } + /** + * This function updates worldState transfering balance from drainList accounts to refundContract address + * + * @param worldState Initial world state + * @param daoForkConfig Dao fork configuration with drainList and refundContract config + * @return Updated world state proxy + */ + private def applyDaoFork(worldState: InMemoryWorldStateProxy, daoForkConfig: DaoForkConfig): InMemoryWorldStateProxy = { + daoForkConfig.drainList.foldLeft(worldState) { (ws, address) => + ws.getAccount(address) + .map(acc => ws.transfer(from = address, to = daoForkConfig.refundContract, acc.balance)) + .getOrElse(ws) + } + } + } object Ledger { diff --git a/src/main/scala/io/iohk/ethereum/mining/BlockGenerator.scala b/src/main/scala/io/iohk/ethereum/mining/BlockGenerator.scala index 51c8c9266d..0ad95891e5 100644 --- a/src/main/scala/io/iohk/ethereum/mining/BlockGenerator.scala +++ b/src/main/scala/io/iohk/ethereum/mining/BlockGenerator.scala @@ -20,7 +20,7 @@ import io.iohk.ethereum.validators.MptListValidator.intByteArraySerializable import io.iohk.ethereum.validators.OmmersValidator.OmmersError import io.iohk.ethereum.validators.Validators import io.iohk.ethereum.crypto._ -import io.iohk.ethereum.daoFork.DaoForkConfiguration +import io.iohk.ethereum.daoFork.DaoForkConfig class BlockGenerator(blockchain: Blockchain, blockchainConfig: BlockchainConfig, miningConfig: MiningConfig, ledger: Ledger, validators: Validators, blockTimestampProvider: BlockTimestampProvider = DefaultBlockTimestampProvider) { @@ -90,8 +90,7 @@ class BlockGenerator(blockchain: Blockchain, blockchainConfig: BlockchainConfig, } private def prepareHeader(blockNumber: BigInt, ommers: Seq[BlockHeader], beneficiary: Address, parent: Block, blockTimestamp: Long) = { - val inInRange = blockchainConfig.daoForkBlockNumber <= blockNumber && - blockchainConfig.daoForkBlockNumber + DaoForkConfiguration.range > blockNumber + import blockchainConfig.daoForkConfig BlockHeader( parentHash = parent.header.hash, @@ -107,7 +106,7 @@ class BlockGenerator(blockchain: Blockchain, blockchainConfig: BlockchainConfig, gasLimit = calculateGasLimit(parent.header.gasLimit), gasUsed = 0, unixTimestamp = blockTimestamp, - extraData = if (inInRange && blockchainConfig.proDaoFork) DaoForkConfiguration.blockExtraData else miningConfig.headerExtraData, + extraData = if (daoForkConfig requiresExtraData blockNumber) daoForkConfig.blockExtraData else miningConfig.headerExtraData, mixHash = ByteString.empty, nonce = ByteString.empty ) diff --git a/src/main/scala/io/iohk/ethereum/network/ForkResolver.scala b/src/main/scala/io/iohk/ethereum/network/ForkResolver.scala index 512f3ecd3c..8480083fe0 100644 --- a/src/main/scala/io/iohk/ethereum/network/ForkResolver.scala +++ b/src/main/scala/io/iohk/ethereum/network/ForkResolver.scala @@ -1,5 +1,6 @@ package io.iohk.ethereum.network +import io.iohk.ethereum.daoFork.DaoForkConfig import io.iohk.ethereum.domain.BlockHeader import io.iohk.ethereum.utils.BlockchainConfig @@ -15,15 +16,15 @@ object ForkResolver { trait Fork - class EtcForkResolver(blockchainConfig: BlockchainConfig) extends ForkResolver { + class EtcForkResolver(daoForkConfig: DaoForkConfig) extends ForkResolver { sealed trait Fork extends ForkResolver.Fork case object AcceptedFork extends Fork case object RejectedFork extends Fork - override def forkBlockNumber: BigInt = blockchainConfig.daoForkBlockNumber + override def forkBlockNumber: BigInt = daoForkConfig.daoForkBlockNumber override def recognizeFork(blockHeader: BlockHeader): Fork = { - if (blockHeader.hash == blockchainConfig.daoForkBlockHash) AcceptedFork + if (blockHeader.hash == daoForkConfig.daoForkBlockHash) AcceptedFork else RejectedFork } diff --git a/src/main/scala/io/iohk/ethereum/nodebuilder/NodeBuilder.scala b/src/main/scala/io/iohk/ethereum/nodebuilder/NodeBuilder.scala index 67a266b8a6..48846db2aa 100644 --- a/src/main/scala/io/iohk/ethereum/nodebuilder/NodeBuilder.scala +++ b/src/main/scala/io/iohk/ethereum/nodebuilder/NodeBuilder.scala @@ -130,7 +130,7 @@ trait ForkResolverBuilder { lazy val forkResolverOpt = if (blockchainConfig.customGenesisFileOpt.isDefined) None - else Some(new ForkResolver.EtcForkResolver(blockchainConfig)) + else Some(new ForkResolver.EtcForkResolver(blockchainConfig.daoForkConfig)) } trait HandshakerBuilder { diff --git a/src/main/scala/io/iohk/ethereum/utils/Config.scala b/src/main/scala/io/iohk/ethereum/utils/Config.scala index 32ac15bc52..bd15489a64 100644 --- a/src/main/scala/io/iohk/ethereum/utils/Config.scala +++ b/src/main/scala/io/iohk/ethereum/utils/Config.scala @@ -4,6 +4,7 @@ import java.net.InetSocketAddress import akka.util.ByteString import com.typesafe.config.{ConfigFactory, Config => TypesafeConfig} +import io.iohk.ethereum.daoFork.{DaoForkConfig, DefaultDaoForkConfig} import io.iohk.ethereum.db.dataSource.LevelDbConfig import io.iohk.ethereum.db.storage.pruning.{ArchivePruning, BasicPruning, PruningMode} import io.iohk.ethereum.domain.{Address, UInt256} @@ -253,9 +254,8 @@ trait BlockchainConfig { val customGenesisFileOpt: Option[String] - val proDaoFork: Boolean - val daoForkBlockNumber: BigInt - val daoForkBlockHash: ByteString + val daoForkConfig: DaoForkConfig + val accountStartNonce: UInt256 val chainId: Byte @@ -278,9 +278,10 @@ object BlockchainConfig { override val customGenesisFileOpt: Option[String] = Try(blockchainConfig.getString("custom-genesis-file")).toOption - override val proDaoFork: Boolean = blockchainConfig.getBoolean("pro-dao-fork") - override val daoForkBlockNumber: BigInt = BigInt(blockchainConfig.getString("dao-fork-block-number")) - override val daoForkBlockHash: ByteString = ByteString(Hex.decode(blockchainConfig.getString("dao-fork-block-hash"))) + val proDaoFork: Boolean = blockchainConfig.getBoolean("pro-dao-fork") + val daoForkBlockNumber: BigInt = BigInt(blockchainConfig.getString("dao-fork-block-number")) + val daoForkBlockHash: ByteString = ByteString(Hex.decode(blockchainConfig.getString("dao-fork-block-hash"))) + override val daoForkConfig = DefaultDaoForkConfig(proDaoFork, daoForkBlockNumber, daoForkBlockHash) override val accountStartNonce: UInt256 = UInt256(BigInt(blockchainConfig.getString("account-start-nonce"))) override val chainId: Byte = { diff --git a/src/main/scala/io/iohk/ethereum/validators/BlockHeaderValidator.scala b/src/main/scala/io/iohk/ethereum/validators/BlockHeaderValidator.scala index 786fb317c4..436dd793a7 100644 --- a/src/main/scala/io/iohk/ethereum/validators/BlockHeaderValidator.scala +++ b/src/main/scala/io/iohk/ethereum/validators/BlockHeaderValidator.scala @@ -2,7 +2,7 @@ package io.iohk.ethereum.validators import akka.util.ByteString import io.iohk.ethereum.crypto.{kec256, kec512} -import io.iohk.ethereum.daoFork.DaoForkConfiguration +import io.iohk.ethereum.daoFork.DaoForkConfig import io.iohk.ethereum.domain.{BlockHeader, Blockchain, DifficultyCalculator} import io.iohk.ethereum.utils.BlockchainConfig @@ -60,11 +60,12 @@ class BlockHeaderValidatorImpl(blockchainConfig: BlockchainConfig) extends Block */ private def validateExtraData(blockHeader: BlockHeader): Either[BlockHeaderError, BlockHeader] = if (blockHeader.extraData.length <= MaxExtraDataSize) { - val inInRange = blockchainConfig.daoForkBlockNumber <= blockHeader.number && - blockchainConfig.daoForkBlockNumber + DaoForkConfiguration.range > blockHeader.number - val daoForkData = blockHeader.extraData == DaoForkConfiguration.blockExtraData + import blockchainConfig._ - (inInRange, daoForkData, blockchainConfig.proDaoFork) match { + val inInRange = daoForkConfig requiresExtraData blockHeader.number + val daoForkData = blockHeader.extraData == daoForkConfig.blockExtraData + + (inInRange, daoForkData, daoForkConfig.proDaoFork) match { case (false, _, _) | (true, true, true) | (true, false, false) => Right(blockHeader) case _ => diff --git a/src/test/scala/io/iohk/ethereum/jsonrpc/PersonalServiceSpec.scala b/src/test/scala/io/iohk/ethereum/jsonrpc/PersonalServiceSpec.scala index 3eacb0ddcb..73d1c0a450 100644 --- a/src/test/scala/io/iohk/ethereum/jsonrpc/PersonalServiceSpec.scala +++ b/src/test/scala/io/iohk/ethereum/jsonrpc/PersonalServiceSpec.scala @@ -4,6 +4,7 @@ import akka.actor.ActorSystem import akka.testkit.TestProbe import akka.util.ByteString import io.iohk.ethereum.crypto.ECDSASignature +import io.iohk.ethereum.daoFork.{DaoForkConfig, DefaultDaoForkConfig} import io.iohk.ethereum.db.storage.AppStateStorage import io.iohk.ethereum.domain.{UInt256, _} import io.iohk.ethereum.jsonrpc.JsonRpcErrors._ @@ -348,11 +349,9 @@ class PersonalServiceSpec extends FlatSpec with Matchers with MockFactory with S override val difficultyBombPauseBlockNumber: BigInt = 0 override val difficultyBombContinueBlockNumber: BigInt = 0 override val customGenesisFileOpt: Option[String] = None - override val daoForkBlockNumber: BigInt = 0 - override val daoForkBlockHash: ByteString = ByteString.empty override val accountStartNonce: UInt256 = UInt256.Zero override val monetaryPolicyConfig: MonetaryPolicyConfig = new MonetaryPolicyConfig(0, 0, 0) - override val proDaoFork: Boolean = false + override val daoForkConfig: DaoForkConfig = DefaultDaoForkConfig(daoForkBlockNumber = 0, daoForkBlockHash = ByteString.empty, proDaoFork = false) } val wallet = Wallet(address, prvKey) diff --git a/src/test/scala/io/iohk/ethereum/mining/BlockGeneratorSpec.scala b/src/test/scala/io/iohk/ethereum/mining/BlockGeneratorSpec.scala index 1be7489802..06273393d6 100644 --- a/src/test/scala/io/iohk/ethereum/mining/BlockGeneratorSpec.scala +++ b/src/test/scala/io/iohk/ethereum/mining/BlockGeneratorSpec.scala @@ -6,7 +6,6 @@ import akka.util.ByteString import io.iohk.ethereum.{Timeouts, crypto} import io.iohk.ethereum.blockchain.data.GenesisDataLoader import io.iohk.ethereum.blockchain.sync.EphemBlockchainTestSetup -import io.iohk.ethereum.db.components.{SharedEphemDataSources, Storages} import io.iohk.ethereum.domain._ import io.iohk.ethereum.ledger.{BlockPreparationError, LedgerImpl} import io.iohk.ethereum.utils.{BlockchainConfig, Logger, MiningConfig, MonetaryPolicyConfig} @@ -16,16 +15,13 @@ import org.scalatest.prop.PropertyChecks import org.scalatest.{FlatSpec, Matchers} import org.spongycastle.util.encoders.Hex import io.iohk.ethereum.crypto._ -import io.iohk.ethereum.db.components.Storages.PruningModeComponent -import io.iohk.ethereum.db.storage.pruning.{ArchivePruning, PruningMode} -import io.iohk.ethereum.daoFork.DaoForkConfiguration +import io.iohk.ethereum.daoFork.{DaoForkConfig, DefaultDaoForkConfig} import io.iohk.ethereum.domain.SignedTransaction.FirstByteOfAddress import io.iohk.ethereum.utils.Config.DbConfig import org.spongycastle.crypto.AsymmetricCipherKeyPair import org.spongycastle.crypto.params.ECPublicKeyParameters import scala.concurrent.duration.FiniteDuration -import scala.concurrent.duration._ class BlockGeneratorSpec extends FlatSpec with Matchers with PropertyChecks with Logger { @@ -115,12 +111,14 @@ class BlockGeneratorSpec extends FlatSpec with Matchers with PropertyChecks with override val monetaryPolicyConfig: MonetaryPolicyConfig = MonetaryPolicyConfig(5000000, 0.2, BigInt("5000000000000000000")) // unused - override val daoForkBlockNumber: BigInt = Long.MaxValue override val eip160BlockNumber: BigInt = Long.MaxValue override val eip150BlockNumber: BigInt = Long.MaxValue - override val daoForkBlockHash: ByteString = ByteString("unused") override val accountStartNonce: UInt256 = UInt256.Zero - override val proDaoFork: Boolean = false + override val daoForkConfig: DaoForkConfig = DefaultDaoForkConfig( + daoForkBlockNumber = Long.MaxValue, + daoForkBlockHash = ByteString("unused"), + proDaoFork = false + ) } val generalTx = SignedTransaction.sign(transaction, keyPair, None) @@ -270,12 +268,10 @@ class BlockGeneratorSpec extends FlatSpec with Matchers with PropertyChecks with override val monetaryPolicyConfig: MonetaryPolicyConfig = MonetaryPolicyConfig(5000000, 0.2, BigInt("5000000000000000000")) // unused - override val daoForkBlockNumber: BigInt = Long.MaxValue override val eip160BlockNumber: BigInt = Long.MaxValue override val eip150BlockNumber: BigInt = Long.MaxValue - override val daoForkBlockHash: ByteString = ByteString("unused") override val accountStartNonce: UInt256 = UInt256.Zero - override val proDaoFork: Boolean = false + override val daoForkConfig: DaoForkConfig = DefaultDaoForkConfig(daoForkBlockNumber = Long.MaxValue, daoForkBlockHash = ByteString("unused"), proDaoFork = false) } lazy val ledger = new LedgerImpl(VM, blockchain, blockchainConfig) diff --git a/src/test/scala/io/iohk/ethereum/network/EtcPeerManagerSpec.scala b/src/test/scala/io/iohk/ethereum/network/EtcPeerManagerSpec.scala index 1682c76bd0..feeb5633aa 100644 --- a/src/test/scala/io/iohk/ethereum/network/EtcPeerManagerSpec.scala +++ b/src/test/scala/io/iohk/ethereum/network/EtcPeerManagerSpec.scala @@ -254,7 +254,7 @@ class EtcPeerManagerSpec extends FlatSpec with Matchers { blockchain.save(Fixtures.Blocks.Genesis.header) val blockchainConfig = BlockchainConfig(Config.config) - val forkResolver = new ForkResolver.EtcForkResolver(blockchainConfig) + val forkResolver = new ForkResolver.EtcForkResolver(blockchainConfig.daoForkConfig) val peerStatus = Status( protocolVersion = Versions.PV63, diff --git a/src/test/scala/io/iohk/ethereum/network/handshaker/EtcHandshakerSpec.scala b/src/test/scala/io/iohk/ethereum/network/handshaker/EtcHandshakerSpec.scala index 016112d8d4..c1cc5daced 100644 --- a/src/test/scala/io/iohk/ethereum/network/handshaker/EtcHandshakerSpec.scala +++ b/src/test/scala/io/iohk/ethereum/network/handshaker/EtcHandshakerSpec.scala @@ -5,6 +5,7 @@ import akka.util.ByteString import io.iohk.ethereum.Fixtures import io.iohk.ethereum.blockchain.sync.EphemBlockchainTestSetup import io.iohk.ethereum.crypto.generateKeyPair +import io.iohk.ethereum.daoFork.{DaoForkConfig, DefaultDaoForkConfig} import io.iohk.ethereum.db.components.Storages.PruningModeComponent import io.iohk.ethereum.db.components.{SharedEphemDataSources, Storages} import io.iohk.ethereum.db.storage.pruning.{ArchivePruning, PruningMode} @@ -145,9 +146,6 @@ class EtcHandshakerSpec extends FlatSpec with Matchers { } val blockchainConfig = new BlockchainConfig { - override val daoForkBlockHash: ByteString = forkBlockHeader.hash - override val daoForkBlockNumber: BigInt = forkBlockHeader.number - //unused override val frontierBlockNumber: BigInt = 0 override val homesteadBlockNumber: BigInt = 0 @@ -160,11 +158,15 @@ class EtcHandshakerSpec extends FlatSpec with Matchers { override val chainId: Byte = 0.toByte override val monetaryPolicyConfig: MonetaryPolicyConfig = null override val accountStartNonce: UInt256 = UInt256.Zero - override val proDaoFork: Boolean = false + override val daoForkConfig: DaoForkConfig = DefaultDaoForkConfig( + daoForkBlockNumber = forkBlockHeader.number, + daoForkBlockHash = forkBlockHeader.hash, + proDaoFork = false + ) } val etcHandshakerConfigurationWithResolver = new MockEtcHandshakerConfiguration { - override val forkResolverOpt: Option[ForkResolver] = Some(new ForkResolver.EtcForkResolver(blockchainConfig)) + override val forkResolverOpt: Option[ForkResolver] = Some(new ForkResolver.EtcForkResolver(blockchainConfig.daoForkConfig)) } val initHandshakerWithoutResolver = EtcHandshaker(new MockEtcHandshakerConfiguration) diff --git a/src/test/scala/io/iohk/ethereum/network/p2p/PeerActorSpec.scala b/src/test/scala/io/iohk/ethereum/network/p2p/PeerActorSpec.scala index 0cedb24fe6..67429b7948 100644 --- a/src/test/scala/io/iohk/ethereum/network/p2p/PeerActorSpec.scala +++ b/src/test/scala/io/iohk/ethereum/network/p2p/PeerActorSpec.scala @@ -399,7 +399,7 @@ class PeerActorSpec extends FlatSpec with Matchers { trait HandshakerSetup extends NodeStatusSetup { val handshakerConfiguration = new EtcHandshakerConfiguration { - override val forkResolverOpt: Option[ForkResolver] = Some(new ForkResolver.EtcForkResolver(blockchainConfig)) + override val forkResolverOpt: Option[ForkResolver] = Some(new ForkResolver.EtcForkResolver(blockchainConfig.daoForkConfig)) override val nodeStatusHolder: Agent[NodeStatus] = HandshakerSetup.this.nodeStatusHolder override val peerConfiguration: PeerConfiguration = HandshakerSetup.this.peerConf override val blockchain: Blockchain = HandshakerSetup.this.blockchain diff --git a/src/test/scala/io/iohk/ethereum/validators/BlockHeaderValidatorSpec.scala b/src/test/scala/io/iohk/ethereum/validators/BlockHeaderValidatorSpec.scala index 4a12d57ac6..6bb1981ceb 100644 --- a/src/test/scala/io/iohk/ethereum/validators/BlockHeaderValidatorSpec.scala +++ b/src/test/scala/io/iohk/ethereum/validators/BlockHeaderValidatorSpec.scala @@ -3,6 +3,7 @@ package io.iohk.ethereum.validators import akka.util.ByteString import io.iohk.ethereum.ObjectGenerators import io.iohk.ethereum.blockchain.sync.EphemBlockchainTestSetup +import io.iohk.ethereum.daoFork.{DaoForkConfig, DefaultDaoForkConfig} import io.iohk.ethereum.domain.{UInt256, _} import io.iohk.ethereum.utils.{BlockchainConfig, Config, MonetaryPolicyConfig} import io.iohk.ethereum.validators.BlockHeaderError._ @@ -24,16 +25,18 @@ class BlockHeaderValidatorSpec extends FlatSpec with Matchers with PropertyCheck override val difficultyBombContinueBlockNumber: BigInt = 5000000 // unused - override val daoForkBlockNumber: BigInt = Long.MaxValue override val eip155BlockNumber: BigInt = Long.MaxValue override val eip160BlockNumber: BigInt = Long.MaxValue override val eip150BlockNumber: BigInt = Long.MaxValue override val chainId: Byte = 0x3d.toByte - override val daoForkBlockHash: ByteString = ByteString("unused") override val monetaryPolicyConfig: MonetaryPolicyConfig = null override val customGenesisFileOpt: Option[String] = None override val accountStartNonce: UInt256 = UInt256.Zero - override val proDaoFork: Boolean = false + override val daoForkConfig: DaoForkConfig = DefaultDaoForkConfig( + daoForkBlockNumber = Long.MaxValue, + daoForkBlockHash = ByteString("unused"), + proDaoFork = false + ) } val blockHeaderValidator = new BlockHeaderValidatorImpl(blockchainConfig) From 03df69f2c264a399f5337e6990370a979775b356 Mon Sep 17 00:00:00 2001 From: Alan Verbner Date: Thu, 14 Sep 2017 12:40:40 -0300 Subject: [PATCH 04/10] [EC-236] BlockHeaderValidator tests --- .../iohk/ethereum/daoFork/DaoForkConfig.scala | 4 +- .../validators/BlockHeaderValidator.scala | 8 +- .../scala/io/iohk/ethereum/Fixtures.scala | 52 ++++++++ .../validators/BlockHeaderValidatorSpec.scala | 123 +++++++++++++++--- 4 files changed, 160 insertions(+), 27 deletions(-) diff --git a/src/main/scala/io/iohk/ethereum/daoFork/DaoForkConfig.scala b/src/main/scala/io/iohk/ethereum/daoFork/DaoForkConfig.scala index 183dd3ff8a..a6a8f0145c 100644 --- a/src/main/scala/io/iohk/ethereum/daoFork/DaoForkConfig.scala +++ b/src/main/scala/io/iohk/ethereum/daoFork/DaoForkConfig.scala @@ -14,7 +14,7 @@ trait DaoForkConfig { val refundContract: Address val drainList: Seq[Address] - private val extratadaBlockRange = daoForkBlockNumber to (daoForkBlockNumber + range) + private val extratadaBlockRange = daoForkBlockNumber until (daoForkBlockNumber + range) def isDaoForkBlock(blockNumber: BigInt): Boolean = proDaoFork && (daoForkBlockNumber == blockNumber) @@ -23,7 +23,7 @@ trait DaoForkConfig { case class DefaultDaoForkConfig(proDaoFork: Boolean, daoForkBlockNumber: BigInt, daoForkBlockHash: ByteString) extends DaoForkConfig { override val blockExtraData = ByteString(Hex.decode("64616f2d686172642d666f726b")) - override val range = 10 + override lazy val range = 10 override val refundContract = Address(Hex.decode("bf4ed7b27f1d666546e30d74d50d173d20bca754")) override val drainList = Seq( Address(Hex.decode("d4fe7bc31cedb7bfb8a345f31e668033056b2728")), diff --git a/src/main/scala/io/iohk/ethereum/validators/BlockHeaderValidator.scala b/src/main/scala/io/iohk/ethereum/validators/BlockHeaderValidator.scala index 436dd793a7..5abd0704f4 100644 --- a/src/main/scala/io/iohk/ethereum/validators/BlockHeaderValidator.scala +++ b/src/main/scala/io/iohk/ethereum/validators/BlockHeaderValidator.scala @@ -62,11 +62,11 @@ class BlockHeaderValidatorImpl(blockchainConfig: BlockchainConfig) extends Block if (blockHeader.extraData.length <= MaxExtraDataSize) { import blockchainConfig._ - val inInRange = daoForkConfig requiresExtraData blockHeader.number - val daoForkData = blockHeader.extraData == daoForkConfig.blockExtraData + val requiresExtraData = daoForkConfig requiresExtraData blockHeader.number + val isDaoForkData = blockHeader.extraData == daoForkConfig.blockExtraData - (inInRange, daoForkData, daoForkConfig.proDaoFork) match { - case (false, _, _) | (true, true, true) | (true, false, false) => + (requiresExtraData, isDaoForkData) match { + case (false, _) | (true, true) => Right(blockHeader) case _ => Left(DaoHeaderExtraDataError) diff --git a/src/test/scala/io/iohk/ethereum/Fixtures.scala b/src/test/scala/io/iohk/ethereum/Fixtures.scala index 0b439a3de8..e28ea9082d 100644 --- a/src/test/scala/io/iohk/ethereum/Fixtures.scala +++ b/src/test/scala/io/iohk/ethereum/Fixtures.scala @@ -230,6 +230,58 @@ object Fixtures { override val size: Long = 978L } + object ProDaoForkBlock extends FixtureBlock { + override val header: BlockHeader = BlockHeader( + parentHash = ByteString(Hex.decode("a218e2c611f21232d857e3c8cecdcdf1f65f25a4477f98f6f47e4063807f2308")), + ommersHash = ByteString(Hex.decode("1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347")), + beneficiary = ByteString(Hex.decode("bcdfc35b86bedf72f0cda046a3c16829a2ef41d1 ")), + stateRoot = ByteString(Hex.decode("c5e389416116e3696cce82ec4533cce33efccb24ce245ae9546a4b8f0d5e9a75")), + transactionsRoot = ByteString(Hex.decode("7701df8e07169452554d14aadd7bfa256d4a1d0355c1d174ab373e3e2d0a3743")), + receiptsRoot = ByteString(Hex.decode("26cf9d9422e9dd95aedc7914db690b92bab6902f5221d62694a2fa5d065f534b")), + logsBloom = ByteString(Hex.decode("0" * 512)), + difficulty = BigInt("62413376722602"), + number = 1920000, + gasLimit = 4712384, + gasUsed = 84000, + unixTimestamp = 1469020840, + extraData = ByteString(Hex.decode("64616f2d686172642d666f726b")), + mixHash = ByteString(Hex.decode("5b5acbf4bf305f948bd7be176047b20623e1417f75597341a059729165b92397")), + nonce = ByteString(Hex.decode("bede87201de42426")) + ) + override lazy val body: BlockBody = ??? + + override val transactionHashes: Seq[ByteString] = Seq( + ByteString(Hex.decode("4677a93807b73a0875d3a292eacb450d0af0d6f0eec6f283f8ad927ec539a17b")), + ByteString(Hex.decode("6f75b64d9364b71b43cde81a889f95df72e6be004b28477f9083ed0ee471a7f9")), + ByteString(Hex.decode("50d8156ee48d01b56cb17b6cb2ac8f29e1bf565be0e604b2d8ffb2fb50a0f611")), + ByteString(Hex.decode("2a5177e6d6cea40594c7d4b0115dcd087443be3ec2fa81db3c21946a5e51cea9")) + ) + override val size: Long = 976 + } + + object DaoParentBlock extends FixtureBlock { + override val header: BlockHeader = BlockHeader( + parentHash = ByteString(Hex.decode("505ffd21f4cbf2c5c34fa84cd8c92525f3a719b7ad18852bffddad601035f5f4")), + ommersHash = ByteString(Hex.decode("1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347")), + beneficiary = ByteString(Hex.decode("2a65aca4d5fc5b5c859090a6c34d164135398226")), + stateRoot = ByteString(Hex.decode("fdf2fc04580b95ca15defc639080b902e93892dcce288be0c1f7a7bbc778248b")), + transactionsRoot = ByteString(Hex.decode("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421")), + receiptsRoot = ByteString(Hex.decode("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421")), + logsBloom = ByteString(Hex.decode("00" * 256)), + difficulty = BigInt("62382916183238"), + number = 1919999, + gasLimit = 4707788, + gasUsed = 0, + unixTimestamp = 1469020838, + extraData = ByteString(Hex.decode("4477617266506f6f6c")), + mixHash = ByteString(Hex.decode("7f9ac1ddeafff0f926ed9887b8cf7d50c3f919d902e618b957022c46c8b404a6")), + nonce = ByteString(Hex.decode("60832709c8979daa")) + ) + override lazy val body: BlockBody = ??? + override lazy val transactionHashes: Seq[ByteString] = ??? + override lazy val size: Long = ??? + } + } } diff --git a/src/test/scala/io/iohk/ethereum/validators/BlockHeaderValidatorSpec.scala b/src/test/scala/io/iohk/ethereum/validators/BlockHeaderValidatorSpec.scala index 6bb1981ceb..7b37a111ff 100644 --- a/src/test/scala/io/iohk/ethereum/validators/BlockHeaderValidatorSpec.scala +++ b/src/test/scala/io/iohk/ethereum/validators/BlockHeaderValidatorSpec.scala @@ -1,7 +1,7 @@ package io.iohk.ethereum.validators import akka.util.ByteString -import io.iohk.ethereum.ObjectGenerators +import io.iohk.ethereum.{Fixtures, ObjectGenerators} import io.iohk.ethereum.blockchain.sync.EphemBlockchainTestSetup import io.iohk.ethereum.daoFork.{DaoForkConfig, DefaultDaoForkConfig} import io.iohk.ethereum.domain.{UInt256, _} @@ -12,32 +12,14 @@ import org.scalatest.{FlatSpec, Matchers} import org.spongycastle.util.encoders.Hex class BlockHeaderValidatorSpec extends FlatSpec with Matchers with PropertyChecks with ObjectGenerators { + import Fixtures.Blocks._ val ExtraDataSizeLimit = 20 //BlockHeader member's lengths obtained from Yellow paper val NonceLength = 8 //64bit val MixHashLength = 32 //256bit - val blockchainConfig = new BlockchainConfig { - override val frontierBlockNumber: BigInt = 0 - override val homesteadBlockNumber: BigInt = 1150000 - override val difficultyBombPauseBlockNumber: BigInt = 3000000 - override val difficultyBombContinueBlockNumber: BigInt = 5000000 - - // unused - override val eip155BlockNumber: BigInt = Long.MaxValue - override val eip160BlockNumber: BigInt = Long.MaxValue - override val eip150BlockNumber: BigInt = Long.MaxValue - override val chainId: Byte = 0x3d.toByte - override val monetaryPolicyConfig: MonetaryPolicyConfig = null - override val customGenesisFileOpt: Option[String] = None - override val accountStartNonce: UInt256 = UInt256.Zero - override val daoForkConfig: DaoForkConfig = DefaultDaoForkConfig( - daoForkBlockNumber = Long.MaxValue, - daoForkBlockHash = ByteString("unused"), - proDaoFork = false - ) - } + val blockchainConfig = createBlockchainConfig() val blockHeaderValidator = new BlockHeaderValidatorImpl(blockchainConfig) val difficultyCalculator = new DifficultyCalculator(blockchainConfig) @@ -59,6 +41,31 @@ class BlockHeaderValidatorSpec extends FlatSpec with Matchers with PropertyCheck } } + it should "validate DAO block (extra data)" in { + import Fixtures.Blocks._ + val cases = Table( + ("Block", "Parent Block", "Pro Dao Fork", "Valid"), + (DaoForkBlock.header, DaoParentBlock.header, false, true), + (DaoForkBlock.header, DaoParentBlock.header, true, false), + (ProDaoForkBlock.header, DaoParentBlock.header, true, true), + (ProDaoForkBlock.header, DaoParentBlock.header, false, true), // We don't care for extra data if no pro dao + (ProDaoForkBlock.header.copy(extraData = ByteString("Wrond DAO Extra")), DaoParentBlock.header, true, false), + // We need to check extradata up to 10 blocks after + (ProDaoBlock1920009Header, ProDaoBlock1920008Header, true, true), + (ProDaoBlock1920009Header.copy(extraData = ByteString("Wrond DAO Extra")), ProDaoBlock1920008Header, true, false), + (ProDaoBlock1920010Header, ProDaoBlock1920009Header, true, true) + ) + + forAll(cases) { (block, parentBlock, proDaoFork, valid ) => + val blockHeaderValidator = new BlockHeaderValidatorImpl(createBlockchainConfig(proDaoFork)) + blockHeaderValidator.validate(block, parentBlock) match { + case Right(_) => assert(valid) + case Left(DaoHeaderExtraDataError) => assert(!valid) + case _ => fail() + } + } + } + it should "return a failure if created based on invalid timestamp" in { forAll(longGen) { timestamp => val blockHeader = validBlockHeader.copy(unixTimestamp = timestamp) @@ -232,4 +239,78 @@ class BlockHeaderValidatorSpec extends FlatSpec with Matchers with PropertyCheck nonce = ByteString(Hex.decode("3fc7bc671f7cee70")) ) + def createBlockchainConfig(proDaoFork: Boolean = false): BlockchainConfig = + new BlockchainConfig { + override val frontierBlockNumber: BigInt = 0 + override val homesteadBlockNumber: BigInt = 1150000 + override val difficultyBombPauseBlockNumber: BigInt = 3000000 + override val difficultyBombContinueBlockNumber: BigInt = 5000000 + + override val daoForkConfig: DaoForkConfig = DefaultDaoForkConfig(proDaoFork, DaoForkBlock.header.number, DaoForkBlock.header.hash) + + // unused + override val eip155BlockNumber: BigInt = Long.MaxValue + override val eip160BlockNumber: BigInt = Long.MaxValue + override val eip150BlockNumber: BigInt = Long.MaxValue + override val chainId: Byte = 0x3d.toByte + override val monetaryPolicyConfig: MonetaryPolicyConfig = null + override val customGenesisFileOpt: Option[String] = None + override val accountStartNonce: UInt256 = UInt256.Zero + } + + val ProDaoBlock1920008Header = BlockHeader( + parentHash = ByteString(Hex.decode("05c45c9671ee31736b9f37ee98faa72c89e314059ecff3257206e6ab498eb9d1")), + ommersHash = ByteString(Hex.decode("1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347")), + beneficiary = ByteString(Hex.decode("2a65aca4d5fc5b5c859090a6c34d164135398226")), + stateRoot = ByteString(Hex.decode("fa8d3b3cbd37caba2faf09d5e472ae6c47a58d846751bc72306166a71d0fa4fa")), + transactionsRoot = ByteString(Hex.decode("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421")), + receiptsRoot = ByteString(Hex.decode("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421")), + logsBloom = ByteString(Hex.decode("00" * 256)), + difficulty = BigInt("62230570926948"), + number = 1920008, + gasLimit = 4707788, + gasUsed = 0, + unixTimestamp = 1469021025, + extraData = ByteString(Hex.decode("64616f2d686172642d666f726b")), + mixHash = ByteString(Hex.decode("e73421390c1b084a9806754b238715ec333cdccc8d09b90cb6e38a9d1e247d6f")), + nonce = ByteString(Hex.decode("c207c8381305bef2")) + ) + + val ProDaoBlock1920009Header = BlockHeader( + parentHash = ByteString(Hex.decode("41254723e12eb736ddef151371e4c3d614233e6cad95f2d9017de2ab8b469a18")), + ommersHash = ByteString(Hex.decode("808d06176049aecfd504197dde49f46c3dd75f1af055e417d100228162eefdd8")), + beneficiary = ByteString(Hex.decode("ea674fdde714fd979de3edf0f56aa9716b898ec8")), + stateRoot = ByteString(Hex.decode("49eb333152713b78d920440ef065ed7f681611e0c2e6933d657d6f4a7f1936ee")), + transactionsRoot = ByteString(Hex.decode("a8060f1391fd4cbde4b03d83b32a1bda445578cd6ec6b7982db20c499ed3682b")), + receiptsRoot = ByteString(Hex.decode("ab66b1986e713eaf5621059e79f04ba9c528187c1b9da969f46442c3f915c120")), + logsBloom = ByteString(Hex.decode("00000000000000020000000000020000000000000008000000000000000000000000000000000000000000000000400000000000000000000000000000202010000000000000000000000008000000000000000000000000400000000000000000000800000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000001001000020000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000004000000000000000000000000000000010000000000000000000000000000000100000000000000000000000000000")), + difficulty = BigInt("62230571058020"), + number = 1920009, + gasLimit = 4712384, + gasUsed = 109952, + unixTimestamp = 1469021040, + extraData = ByteString(Hex.decode("64616f2d686172642d666f726b")), + mixHash = ByteString(Hex.decode("5bde79f4dc5be28af2d956e748a0d6ebc1f8eb5c1397e76729269e730611cb99")), + nonce = ByteString(Hex.decode("2b4b464c0a4da82a")) + ) + + val ProDaoBlock1920010Header = BlockHeader( + parentHash = ByteString(Hex.decode("69d04aec94ad69d7d190d3b51d24cd42dded0c4767598a1d30480363509acbef")), + ommersHash = ByteString(Hex.decode("1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347")), + beneficiary = ByteString(Hex.decode("4bb96091ee9d802ed039c4d1a5f6216f90f81b01")), + stateRoot = ByteString(Hex.decode("6ee63abee7416d3a671bcbefa01aa5d4ea427e246d548e15c5f3d9a108e738fd")), + transactionsRoot = ByteString(Hex.decode("0c6d4a643ed081f92e384a5853f14d7f5ff5d68b65d0c90b46159584a80effe0")), + receiptsRoot = ByteString(Hex.decode("a7d1ddb80060d4b77c07007e9a9f0b83413bd2c5de71501683ba4764982eef4b")), + logsBloom = ByteString(Hex.decode("00000000000000020000000000020000001000000000000000000000000000000008000000000000000000000000400000000000000000000000000000202000000000000800000000000008000000000000000000000000400000000008000000000000000000000000000000000000000000000000000000000010000000000000000000000000000221000000000000000000080400000000000000011000020000000200001000000000000000000000000000000000400000000000000000000002000000000100000000000000000000000040000000000000000000000010000000000000000000000000000000000000000000000000000000000000")), + difficulty = BigInt("62230571189092"), + number = 1920010, + gasLimit = 4712388, + gasUsed = 114754, + unixTimestamp = 1469021050, + extraData = ByteString(Hex.decode("657468706f6f6c2e6f7267202855533129")), + mixHash = ByteString(Hex.decode("8f86617d6422c26a89b8b349b160973ca44f90326e758f1ef669c4046741dd06")), + nonce = ByteString(Hex.decode("c7de19e00a8c3e32")) + ) + + } From 36acfe0460387b53a78daa54b7b0162b987898bc Mon Sep 17 00:00:00 2001 From: Alan Verbner Date: Thu, 14 Sep 2017 16:28:29 -0300 Subject: [PATCH 05/10] [EC-236] Ledger apply dao fork tests --- .../ledger/InMemoryWorldStateProxy.scala | 2 +- .../io/iohk/ethereum/ledger/Ledger.scala | 6 +- .../scala/io/iohk/ethereum/Fixtures.scala | 59 +++++++++++- .../io/iohk/ethereum/ledger/LedgerSpec.scala | 89 +++++++++++++++++-- 4 files changed, 144 insertions(+), 12 deletions(-) diff --git a/src/main/scala/io/iohk/ethereum/ledger/InMemoryWorldStateProxy.scala b/src/main/scala/io/iohk/ethereum/ledger/InMemoryWorldStateProxy.scala index 0f52263170..8678c78040 100644 --- a/src/main/scala/io/iohk/ethereum/ledger/InMemoryWorldStateProxy.scala +++ b/src/main/scala/io/iohk/ethereum/ledger/InMemoryWorldStateProxy.scala @@ -125,7 +125,7 @@ class InMemoryWorldStateProxyStorage(val wrapped: InMemorySimpleMapProxy[UInt256 override def load(addr: UInt256): UInt256 = wrapped.get(addr).getOrElse(UInt256.Zero) } -class InMemoryWorldStateProxy private( +class InMemoryWorldStateProxy private[ledger]( // State MPT proxied nodes storage needed to construct the storage MPT when calling [[getStorage]]. // Accounts state and accounts storage states are saved within the same storage val stateStorage: NodesKeyValueStorage, diff --git a/src/main/scala/io/iohk/ethereum/ledger/Ledger.scala b/src/main/scala/io/iohk/ethereum/ledger/Ledger.scala index 6033f9b1d3..5d59d2688c 100644 --- a/src/main/scala/io/iohk/ethereum/ledger/Ledger.scala +++ b/src/main/scala/io/iohk/ethereum/ledger/Ledger.scala @@ -78,7 +78,7 @@ class LedgerImpl(vm: VM, blockchain: BlockchainImpl, blockchainConfig: Blockchai val initialWorld = blockchain.getWorldStateProxy(block.header.number, blockchainConfig.accountStartNonce, parentStateRoot) val inputWorld = - if(blockchainConfig.daoForkConfig isDaoForkBlock block.header.number) applyDaoFork(initialWorld, blockchainConfig.daoForkConfig) + if(blockchainConfig.daoForkConfig isDaoForkBlock block.header.number) drainDaoForkAccounts(initialWorld, blockchainConfig.daoForkConfig) else initialWorld log.debug(s"About to execute ${block.body.transactionList.size} txs from block ${block.header.number} (with hash: ${block.header.hashAsHexString})") @@ -377,13 +377,13 @@ class LedgerImpl(vm: VM, blockchain: BlockchainImpl, blockchainConfig: Blockchai addressesToDelete.foldLeft(worldStateProxy){ case (world, address) => world.deleteAccount(address) } /** - * This function updates worldState transfering balance from drainList accounts to refundContract address + * This function updates worldState transferring balance from drainList accounts to refundContract address * * @param worldState Initial world state * @param daoForkConfig Dao fork configuration with drainList and refundContract config * @return Updated world state proxy */ - private def applyDaoFork(worldState: InMemoryWorldStateProxy, daoForkConfig: DaoForkConfig): InMemoryWorldStateProxy = { + private def drainDaoForkAccounts(worldState: InMemoryWorldStateProxy, daoForkConfig: DaoForkConfig): InMemoryWorldStateProxy = { daoForkConfig.drainList.foldLeft(worldState) { (ws, address) => ws.getAccount(address) .map(acc => ws.transfer(from = address, to = daoForkConfig.refundContract, acc.balance)) diff --git a/src/test/scala/io/iohk/ethereum/Fixtures.scala b/src/test/scala/io/iohk/ethereum/Fixtures.scala index e28ea9082d..99b24b77b6 100644 --- a/src/test/scala/io/iohk/ethereum/Fixtures.scala +++ b/src/test/scala/io/iohk/ethereum/Fixtures.scala @@ -248,7 +248,64 @@ object Fixtures { mixHash = ByteString(Hex.decode("5b5acbf4bf305f948bd7be176047b20623e1417f75597341a059729165b92397")), nonce = ByteString(Hex.decode("bede87201de42426")) ) - override lazy val body: BlockBody = ??? + override lazy val body: BlockBody = BlockBody( + transactionList = Seq[SignedTransaction]( + SignedTransaction( + tx = Transaction( + nonce = BigInt("1"), + gasPrice = BigInt("20000000000"), + gasLimit = BigInt("21000"), + receivingAddress = Address(ByteString(Hex.decode("53d284357ec70ce289d6d64134dfac8e511c8a3d"))), + value = BigInt("1502561962583879700"), + payload = ByteString.empty + ), + pointSign = 0x1b.toByte, + signatureRandom = ByteString(Hex.decode("fdbbc462a8a60ac3d8b13ee236b45af9b7991cf4f0f556d3af46aa5aeca242ab")), + signature = ByteString(Hex.decode("5de5dc03fdcb6cf6d14609dbe6f5ba4300b8ff917c7d190325d9ea2144a7a2fb")), + chainId = 0x01.toByte + ).get,SignedTransaction( + tx = Transaction( + nonce = BigInt("1"), + gasPrice = BigInt("20000000000"), + gasLimit = BigInt("21000"), + receivingAddress = Address(ByteString(Hex.decode("53d284357ec70ce289d6d64134dfac8e511c8a3d"))), + value = BigInt("10046680000000000000"), + payload = ByteString.empty + ), + pointSign = 0x1b.toByte, + signatureRandom = ByteString(Hex.decode("8d94a55c7ac7adbfa2285ef7f4b0c955ae1a02647452cd4ead03ee6f449675c6")), + signature = ByteString(Hex.decode("67149821b74208176d78fc4dffbe37c8b64eecfd47532406b9727c4ae8eb7c9a")), + chainId = 0x01.toByte + ).get,SignedTransaction( + tx = Transaction( + nonce = BigInt("1"), + gasPrice = BigInt("20000000000"), + gasLimit = BigInt("21000"), + receivingAddress = Address(ByteString(Hex.decode("53d284357ec70ce289d6d64134dfac8e511c8a3d"))), + value = BigInt("20093780000000000000"), + payload = ByteString.empty + ), + pointSign = 0x1c.toByte, + signatureRandom = ByteString(Hex.decode("6d31e3d59bfea97a34103d8ce767a8fe7a79b8e2f30af1e918df53f9e78e69ab")), + signature = ByteString(Hex.decode("098e5b80e1cc436421aa54eb17e96b08fe80d28a2fbd46451b56f2bca7a321e7")), + chainId = 0x01.toByte + ).get,SignedTransaction( + tx = Transaction( + nonce = BigInt("1"), + gasPrice = BigInt("20000000000"), + gasLimit = BigInt("21000"), + receivingAddress = Address(ByteString(Hex.decode("53d284357ec70ce289d6d64134dfac8e511c8a3d"))), + value = BigInt("1022338440000000000"), + payload = ByteString.empty + ), + pointSign = 0x1b.toByte, + signatureRandom = ByteString(Hex.decode("bafb9f71cef873b9e0395b9ed89aac4f2a752e2a4b88ba3c9b6c1fea254eae73")), + signature = ByteString(Hex.decode("1cef688f6718932f7705d9c1f0dd5a8aad9ddb196b826775f6e5703fdb997706")), + chainId = 0x01.toByte + ).get + ), + uncleNodesList = Seq[BlockHeader]() + ) override val transactionHashes: Seq[ByteString] = Seq( ByteString(Hex.decode("4677a93807b73a0875d3a292eacb450d0af0d6f0eec6f283f8ad927ec539a17b")), diff --git a/src/test/scala/io/iohk/ethereum/ledger/LedgerSpec.scala b/src/test/scala/io/iohk/ethereum/ledger/LedgerSpec.scala index a059cf45e2..123813f32a 100644 --- a/src/test/scala/io/iohk/ethereum/ledger/LedgerSpec.scala +++ b/src/test/scala/io/iohk/ethereum/ledger/LedgerSpec.scala @@ -6,18 +6,16 @@ import akka.util.ByteString.{empty => bEmpty} import io.iohk.ethereum.Mocks.MockVM import io.iohk.ethereum.blockchain.sync.EphemBlockchainTestSetup import io.iohk.ethereum.crypto._ -import io.iohk.ethereum.db.components.Storages.PruningModeComponent -import io.iohk.ethereum.db.components.{SharedEphemDataSources, Storages} -import io.iohk.ethereum.db.storage.pruning.{ArchivePruning, PruningMode} +import io.iohk.ethereum.daoFork.{DaoForkConfig, DefaultDaoForkConfig} import io.iohk.ethereum.domain._ import io.iohk.ethereum.ledger.BlockExecutionError.{ValidationAfterExecError, ValidationBeforeExecError} -import io.iohk.ethereum.{Mocks, rlp} +import io.iohk.ethereum.{Fixtures, Mocks, rlp} import io.iohk.ethereum.rlp.RLPList -import io.iohk.ethereum.utils.{BlockchainConfig, Config} +import io.iohk.ethereum.utils.{BlockchainConfig, Config, MonetaryPolicyConfig} import io.iohk.ethereum.ledger.Ledger.{BlockResult, PC, PR} import io.iohk.ethereum.network.p2p.messages.PV62.BlockBody import io.iohk.ethereum.nodebuilder.SecureRandomBuilder -import io.iohk.ethereum.vm.{_} +import io.iohk.ethereum.vm._ import org.scalatest.{FlatSpec, Matchers} import org.scalatest.prop.PropertyChecks import org.spongycastle.crypto.params.ECPublicKeyParameters @@ -26,11 +24,12 @@ import io.iohk.ethereum.rlp.RLPImplicits._ import io.iohk.ethereum.validators.BlockValidator.BlockTransactionsHashError import io.iohk.ethereum.validators.SignedTransactionError.TransactionSignatureError import io.iohk.ethereum.validators._ +import org.scalamock.scalatest.MockFactory import org.spongycastle.crypto.AsymmetricCipherKeyPair import org.spongycastle.util.encoders.Hex // scalastyle:off file.size.limit -class LedgerSpec extends FlatSpec with PropertyChecks with Matchers { +class LedgerSpec extends FlatSpec with PropertyChecks with Matchers with MockFactory { val blockchainConfig = BlockchainConfig(Config.config) @@ -756,6 +755,52 @@ class LedgerSpec extends FlatSpec with PropertyChecks with Matchers { result match { case (_, executedTxs) => executedTxs shouldBe Seq.empty } } + it should "drain DAO accounts and send the funds to refund address if it's Pro DAO Fork configured" in new DaoForkTestSetup { + + // Check we drain all the accounts and send the balance to refund contract + proDaoBlockchainConfig.daoForkConfig.drainList.foreach { addr => + val daoAccountsFakeBalance = UInt256(1000) + (worldState.getAccount _).expects(addr).returning(Some(Account(nonce = 1, balance = daoAccountsFakeBalance))) + (worldState.transfer _).expects(addr, proDaoBlockchainConfig.daoForkConfig.refundContract, daoAccountsFakeBalance).returning(worldState) + } + + val ledger = new LedgerImpl(new MockVM(c => createResult( + context = c, + gasUsed = UInt256(10), + gasLimit = UInt256(10), + gasRefund = UInt256.Zero, + logs = Seq.empty, + addressesToDelete = Set.empty + )), testBlockchain, proDaoBlockchainConfig) + + ledger.executeBlockTransactions( + proDaoBlock.copy(body = proDaoBlock.body.copy(transactionList = Seq.empty)), // We don't care about block txs in this test + (new Mocks.MockValidatorsAlwaysSucceed).signedTransactionValidator + ) + } + + it should "not drain DAO accounts and send the funds to refund address if it not Pro DAO Fork configured" in new DaoForkTestSetup { + // Check we drain all the accounts and send the balance to refund contract + proDaoBlockchainConfig.daoForkConfig.drainList.foreach { addr => + val daoAccountsFakeBalance = UInt256(1000) + (worldState.transfer _).expects(addr, proDaoBlockchainConfig.daoForkConfig.refundContract, *).never() + } + + val ledger = new LedgerImpl(new MockVM(c => createResult( + context = c, + gasUsed = UInt256(10), + gasLimit = UInt256(10), + gasRefund = UInt256.Zero, + logs = Seq.empty, + addressesToDelete = Set.empty + )), testBlockchain, blockchainConfig) + + ledger.executeBlockTransactions( + proDaoBlock.copy(body = proDaoBlock.body.copy(transactionList = Seq.empty)), // We don't care about block txs in this test + (new Mocks.MockValidatorsAlwaysSucceed).signedTransactionValidator + ) + } + trait TestSetup extends SecureRandomBuilder with EphemBlockchainTestSetup { val originKeyPair: AsymmetricCipherKeyPair = generateKeyPair(secureRandom) val receiverKeyPair: AsymmetricCipherKeyPair = generateKeyPair(secureRandom) @@ -849,4 +894,34 @@ class LedgerSpec extends FlatSpec with PropertyChecks with Matchers { val validStxSignedByOrigin: SignedTransaction = SignedTransaction.sign(validTx, originKeyPair, Some(blockchainConfig.chainId)) } + trait DaoForkTestSetup extends TestSetup { + val proDaoBlockchainConfig = new BlockchainConfig { + override val frontierBlockNumber: BigInt = blockchainConfig.frontierBlockNumber + override val accountStartNonce: UInt256 = blockchainConfig.accountStartNonce + override val homesteadBlockNumber: BigInt = blockchainConfig.homesteadBlockNumber + override val difficultyBombPauseBlockNumber: BigInt = blockchainConfig.difficultyBombPauseBlockNumber + override val eip155BlockNumber: BigInt = blockchainConfig.eip155BlockNumber + override val monetaryPolicyConfig: MonetaryPolicyConfig = blockchainConfig.monetaryPolicyConfig + override val eip160BlockNumber: BigInt = blockchainConfig.eip160BlockNumber + override val eip150BlockNumber: BigInt = blockchainConfig.eip150BlockNumber + override val chainId: Byte = 0x01.toByte + override val difficultyBombContinueBlockNumber: BigInt = blockchainConfig.difficultyBombContinueBlockNumber + override val daoForkConfig: DaoForkConfig = DefaultDaoForkConfig(true, 1920000, ByteString("")) + override val customGenesisFileOpt: Option[String] = None + } + val testBlockchain = mock[BlockchainImpl] + val worldState = mock[InMemoryWorldStateProxy] + val proDaoBlock = Fixtures.Blocks.ProDaoForkBlock.block + + (testBlockchain.getBlockHeaderByHash _).expects(proDaoBlock.header.parentHash).returning(Some(Fixtures.Blocks.DaoParentBlock.header)) + (testBlockchain.getWorldStateProxy _) + .expects(proDaoBlock.header.number, proDaoBlockchainConfig.accountStartNonce, Some(Fixtures.Blocks.DaoParentBlock.header.stateRoot)) + .returning(worldState) + + (worldState.getAccount _) + .expects(proDaoBlockchainConfig.daoForkConfig.refundContract) + .anyNumberOfTimes() + .returning(Some(Account(nonce = 1, balance = UInt256.Zero))) + } + } From 23a1ba41907413adba47ceaabf47b40314b4dae5 Mon Sep 17 00:00:00 2001 From: Alan Verbner Date: Fri, 15 Sep 2017 14:46:02 -0300 Subject: [PATCH 06/10] [EC-236] DaoForkConfig refactor --- .../iohk/ethereum/txExecTest/ForksTest.scala | 6 +- .../txExecTest/util/DumpChainApp.scala | 4 +- src/main/resources/application.conf | 30 +++- .../iohk/ethereum/daoFork/DaoForkConfig.scala | 142 ++--------------- .../io/iohk/ethereum/ledger/Ledger.scala | 17 ++- .../iohk/ethereum/mining/BlockGenerator.scala | 2 +- .../iohk/ethereum/network/ForkResolver.scala | 5 +- .../ethereum/nodebuilder/NodeBuilder.scala | 4 +- .../scala/io/iohk/ethereum/utils/Config.scala | 28 +++- .../validators/BlockHeaderValidator.scala | 22 ++- src/test/resources/application.conf | 24 +++ .../jsonrpc/PersonalServiceSpec.scala | 4 +- .../io/iohk/ethereum/ledger/LedgerSpec.scala | 61 ++++---- .../ethereum/mining/BlockGeneratorSpec.scala | 12 +- .../ethereum/network/EtcPeerManagerSpec.scala | 2 +- .../handshaker/EtcHandshakerSpec.scala | 20 ++- .../ethereum/network/p2p/PeerActorSpec.scala | 2 +- .../validators/BlockHeaderValidatorSpec.scala | 23 ++- src/universal/conf/blockchain.conf | 23 +++ src/universal/conf/ethereumHF.conf | 144 +++++++++++++++++- src/universal/conf/morden.conf | 4 +- 21 files changed, 344 insertions(+), 235 deletions(-) diff --git a/src/it/scala/io/iohk/ethereum/txExecTest/ForksTest.scala b/src/it/scala/io/iohk/ethereum/txExecTest/ForksTest.scala index b7cac3e9c2..eb339e9439 100644 --- a/src/it/scala/io/iohk/ethereum/txExecTest/ForksTest.scala +++ b/src/it/scala/io/iohk/ethereum/txExecTest/ForksTest.scala @@ -1,8 +1,8 @@ package io.iohk.ethereum.txExecTest import akka.util.ByteString -import io.iohk.ethereum.daoFork.{DaoForkConfig, DefaultDaoForkConfig} -import io.iohk.ethereum.domain.{BlockchainImpl, Receipt, UInt256} +import io.iohk.ethereum.daoFork.DaoForkConfig +import io.iohk.ethereum.domain.{Address, BlockchainImpl, Receipt, UInt256} import io.iohk.ethereum.ledger.LedgerImpl import io.iohk.ethereum.txExecTest.util.FixtureProvider import io.iohk.ethereum.utils.{BlockchainConfig, MonetaryPolicyConfig} @@ -27,7 +27,7 @@ class ForksTest extends FlatSpec with Matchers { override val difficultyBombPauseBlockNumber: BigInt = Long.MaxValue override val difficultyBombContinueBlockNumber: BigInt = Long.MaxValue override val accountStartNonce: UInt256 = UInt256.Zero - override val daoForkConfig: DaoForkConfig = DefaultDaoForkConfig(daoForkBlockNumber = 1000, daoForkBlockHash = ByteString("unused"), proDaoFork = false) + override val daoForkConfig: Option[DaoForkConfig] = None } val noErrors = a[Right[_, Seq[Receipt]]] diff --git a/src/it/scala/io/iohk/ethereum/txExecTest/util/DumpChainApp.scala b/src/it/scala/io/iohk/ethereum/txExecTest/util/DumpChainApp.scala index 0383fdabb9..ead7fd265e 100644 --- a/src/it/scala/io/iohk/ethereum/txExecTest/util/DumpChainApp.scala +++ b/src/it/scala/io/iohk/ethereum/txExecTest/util/DumpChainApp.scala @@ -70,8 +70,8 @@ object DumpChainApp extends App with NodeKeyBuilder with SecureRandomBuilder wit lazy val nodeStatusHolder = Agent(nodeStatus) lazy val forkResolverOpt = - if (blockchainConfig.customGenesisFileOpt.isDefined) None - else Some(new ForkResolver.EtcForkResolver(blockchainConfig.daoForkConfig)) + if (blockchainConfig.daoForkConfig.isEmpty) None + else Some(new ForkResolver.EtcForkResolver(blockchainConfig.daoForkConfig.get)) private val handshakerConfiguration: EtcHandshakerConfiguration = new EtcHandshakerConfiguration { diff --git a/src/main/resources/application.conf b/src/main/resources/application.conf index 701ed18a63..f6e8507f9f 100644 --- a/src/main/resources/application.conf +++ b/src/main/resources/application.conf @@ -196,6 +196,9 @@ mantis { active-timeout = 5 seconds ommer-pool-query-timeout = 5.seconds + + # Extra data to add to mined blocks + header-extra-data = "mantis" } blockchain { @@ -228,16 +231,27 @@ mantis { # Doc: https://github.com/ethereumproject/ECIPs/blob/master/ECIPs/ECIP-1010.md difficulty-bomb-continue-block-number = "5000000" - # specify if this client is pro or against DAO hard fork - # if true it will accept ETH version of chain if false it will accept ETC - pro-dao-fork = false - - # DAO fork block number (Ethereum HF/Classic split) + # DAO fork configuration (Ethereum HF/Classic split) # https://blog.ethereum.org/2016/07/20/hard-fork-completed/ - dao-fork-block-number = "1920000" + dao { + # DAO fork block number + fork-block-number = "1920000" + + # The hash of the accepted DAO fork block + fork-block-hash = "94365e3a8c0b35089c1d1195081fe7489b528a84b22199c916180db8b28ade7f" + + # Extra data to be put in fork block headers + block-extra-data = null - # The hash of the accepted DAO fork block - dao-fork-block-hash = "94365e3a8c0b35089c1d1195081fe7489b528a84b22199c916180db8b28ade7f" + # number of blocks to place extra data after fork + block-extra-data-range = 10 + + # Address to send funds when draining + refund-contract-address = null + + # List of accounts to be drained + drain-list = null + } # Starting nonce a an empty account. Some networks (like Morden) use different values. account-start-nonce = "0" diff --git a/src/main/scala/io/iohk/ethereum/daoFork/DaoForkConfig.scala b/src/main/scala/io/iohk/ethereum/daoFork/DaoForkConfig.scala index a6a8f0145c..9e8d3caa40 100644 --- a/src/main/scala/io/iohk/ethereum/daoFork/DaoForkConfig.scala +++ b/src/main/scala/io/iohk/ethereum/daoFork/DaoForkConfig.scala @@ -2,145 +2,23 @@ package io.iohk.ethereum.daoFork import akka.util.ByteString import io.iohk.ethereum.domain.Address -import org.spongycastle.util.encoders.Hex trait DaoForkConfig { - val proDaoFork: Boolean - val daoForkBlockNumber: BigInt - val daoForkBlockHash: ByteString - val blockExtraData: ByteString + val forkBlockNumber: BigInt + val forkBlockHash: ByteString + val blockExtraData: Option[ByteString] val range: Int - val refundContract: Address + val refundContract: Option[Address] val drainList: Seq[Address] - private val extratadaBlockRange = daoForkBlockNumber until (daoForkBlockNumber + range) + private lazy val extratadaBlockRange = forkBlockNumber until(forkBlockNumber + range) - def isDaoForkBlock(blockNumber: BigInt): Boolean = proDaoFork && (daoForkBlockNumber == blockNumber) + def isDaoForkBlock(blockNumber: BigInt): Boolean = forkBlockNumber == blockNumber - def requiresExtraData(blockNumber: BigInt): Boolean = proDaoFork && (extratadaBlockRange contains blockNumber) -} + def requiresExtraData(blockNumber: BigInt): Boolean = blockExtraData.isDefined && (extratadaBlockRange contains blockNumber) -case class DefaultDaoForkConfig(proDaoFork: Boolean, daoForkBlockNumber: BigInt, daoForkBlockHash: ByteString) extends DaoForkConfig { - override val blockExtraData = ByteString(Hex.decode("64616f2d686172642d666f726b")) - override lazy val range = 10 - override val refundContract = Address(Hex.decode("bf4ed7b27f1d666546e30d74d50d173d20bca754")) - override val drainList = Seq( - Address(Hex.decode("d4fe7bc31cedb7bfb8a345f31e668033056b2728")), - Address(Hex.decode("b3fb0e5aba0e20e5c49d252dfd30e102b171a425")), - Address(Hex.decode("2c19c7f9ae8b751e37aeb2d93a699722395ae18f")), - Address(Hex.decode("ecd135fa4f61a655311e86238c92adcd779555d2")), - Address(Hex.decode("1975bd06d486162d5dc297798dfc41edd5d160a7")), - Address(Hex.decode("a3acf3a1e16b1d7c315e23510fdd7847b48234f6")), - Address(Hex.decode("319f70bab6845585f412ec7724b744fec6095c85")), - Address(Hex.decode("06706dd3f2c9abf0a21ddcc6941d9b86f0596936")), - Address(Hex.decode("5c8536898fbb74fc7445814902fd08422eac56d0")), - Address(Hex.decode("6966ab0d485353095148a2155858910e0965b6f9")), - Address(Hex.decode("779543a0491a837ca36ce8c635d6154e3c4911a6")), - Address(Hex.decode("2a5ed960395e2a49b1c758cef4aa15213cfd874c")), - Address(Hex.decode("5c6e67ccd5849c0d29219c4f95f1a7a93b3f5dc5")), - Address(Hex.decode("9c50426be05db97f5d64fc54bf89eff947f0a321")), - Address(Hex.decode("200450f06520bdd6c527622a273333384d870efb")), - Address(Hex.decode("be8539bfe837b67d1282b2b1d61c3f723966f049")), - Address(Hex.decode("6b0c4d41ba9ab8d8cfb5d379c69a612f2ced8ecb")), - Address(Hex.decode("f1385fb24aad0cd7432824085e42aff90886fef5")), - Address(Hex.decode("d1ac8b1ef1b69ff51d1d401a476e7e612414f091")), - Address(Hex.decode("8163e7fb499e90f8544ea62bbf80d21cd26d9efd")), - Address(Hex.decode("51e0ddd9998364a2eb38588679f0d2c42653e4a6")), - Address(Hex.decode("627a0a960c079c21c34f7612d5d230e01b4ad4c7")), - Address(Hex.decode("f0b1aa0eb660754448a7937c022e30aa692fe0c5")), - Address(Hex.decode("24c4d950dfd4dd1902bbed3508144a54542bba94")), - Address(Hex.decode("9f27daea7aca0aa0446220b98d028715e3bc803d")), - Address(Hex.decode("a5dc5acd6a7968a4554d89d65e59b7fd3bff0f90")), - Address(Hex.decode("d9aef3a1e38a39c16b31d1ace71bca8ef58d315b")), - Address(Hex.decode("63ed5a272de2f6d968408b4acb9024f4cc208ebf")), - Address(Hex.decode("6f6704e5a10332af6672e50b3d9754dc460dfa4d")), - Address(Hex.decode("77ca7b50b6cd7e2f3fa008e24ab793fd56cb15f6")), - Address(Hex.decode("492ea3bb0f3315521c31f273e565b868fc090f17")), - Address(Hex.decode("0ff30d6de14a8224aa97b78aea5388d1c51c1f00")), - Address(Hex.decode("9ea779f907f0b315b364b0cfc39a0fde5b02a416")), - Address(Hex.decode("ceaeb481747ca6c540a000c1f3641f8cef161fa7")), - Address(Hex.decode("cc34673c6c40e791051898567a1222daf90be287")), - Address(Hex.decode("579a80d909f346fbfb1189493f521d7f48d52238")), - Address(Hex.decode("e308bd1ac5fda103967359b2712dd89deffb7973")), - Address(Hex.decode("4cb31628079fb14e4bc3cd5e30c2f7489b00960c")), - Address(Hex.decode("ac1ecab32727358dba8962a0f3b261731aad9723")), - Address(Hex.decode("4fd6ace747f06ece9c49699c7cabc62d02211f75")), - Address(Hex.decode("440c59b325d2997a134c2c7c60a8c61611212bad")), - Address(Hex.decode("4486a3d68fac6967006d7a517b889fd3f98c102b")), - Address(Hex.decode("9c15b54878ba618f494b38f0ae7443db6af648ba")), - Address(Hex.decode("27b137a85656544b1ccb5a0f2e561a5703c6a68f")), - Address(Hex.decode("21c7fdb9ed8d291d79ffd82eb2c4356ec0d81241")), - Address(Hex.decode("23b75c2f6791eef49c69684db4c6c1f93bf49a50")), - Address(Hex.decode("1ca6abd14d30affe533b24d7a21bff4c2d5e1f3b")), - Address(Hex.decode("b9637156d330c0d605a791f1c31ba5890582fe1c")), - Address(Hex.decode("6131c42fa982e56929107413a9d526fd99405560")), - Address(Hex.decode("1591fc0f688c81fbeb17f5426a162a7024d430c2")), - Address(Hex.decode("542a9515200d14b68e934e9830d91645a980dd7a")), - Address(Hex.decode("c4bbd073882dd2add2424cf47d35213405b01324")), - Address(Hex.decode("782495b7b3355efb2833d56ecb34dc22ad7dfcc4")), - Address(Hex.decode("58b95c9a9d5d26825e70a82b6adb139d3fd829eb")), - Address(Hex.decode("3ba4d81db016dc2890c81f3acec2454bff5aada5")), - Address(Hex.decode("b52042c8ca3f8aa246fa79c3feaa3d959347c0ab")), - Address(Hex.decode("e4ae1efdfc53b73893af49113d8694a057b9c0d1")), - Address(Hex.decode("3c02a7bc0391e86d91b7d144e61c2c01a25a79c5")), - Address(Hex.decode("0737a6b837f97f46ebade41b9bc3e1c509c85c53")), - Address(Hex.decode("97f43a37f595ab5dd318fb46e7a155eae057317a")), - Address(Hex.decode("52c5317c848ba20c7504cb2c8052abd1fde29d03")), - Address(Hex.decode("4863226780fe7c0356454236d3b1c8792785748d")), - Address(Hex.decode("5d2b2e6fcbe3b11d26b525e085ff818dae332479")), - Address(Hex.decode("5f9f3392e9f62f63b8eac0beb55541fc8627f42c")), - Address(Hex.decode("057b56736d32b86616a10f619859c6cd6f59092a")), - Address(Hex.decode("9aa008f65de0b923a2a4f02012ad034a5e2e2192")), - Address(Hex.decode("304a554a310c7e546dfe434669c62820b7d83490")), - Address(Hex.decode("914d1b8b43e92723e64fd0a06f5bdb8dd9b10c79")), - Address(Hex.decode("4deb0033bb26bc534b197e61d19e0733e5679784")), - Address(Hex.decode("07f5c1e1bc2c93e0402f23341973a0e043f7bf8a")), - Address(Hex.decode("35a051a0010aba705c9008d7a7eff6fb88f6ea7b")), - Address(Hex.decode("4fa802324e929786dbda3b8820dc7834e9134a2a")), - Address(Hex.decode("9da397b9e80755301a3b32173283a91c0ef6c87e")), - Address(Hex.decode("8d9edb3054ce5c5774a420ac37ebae0ac02343c6")), - Address(Hex.decode("0101f3be8ebb4bbd39a2e3b9a3639d4259832fd9")), - Address(Hex.decode("5dc28b15dffed94048d73806ce4b7a4612a1d48f")), - Address(Hex.decode("bcf899e6c7d9d5a215ab1e3444c86806fa854c76")), - Address(Hex.decode("12e626b0eebfe86a56d633b9864e389b45dcb260")), - Address(Hex.decode("a2f1ccba9395d7fcb155bba8bc92db9bafaeade7")), - Address(Hex.decode("ec8e57756626fdc07c63ad2eafbd28d08e7b0ca5")), - Address(Hex.decode("d164b088bd9108b60d0ca3751da4bceb207b0782")), - Address(Hex.decode("6231b6d0d5e77fe001c2a460bd9584fee60d409b")), - Address(Hex.decode("1cba23d343a983e9b5cfd19496b9a9701ada385f")), - Address(Hex.decode("a82f360a8d3455c5c41366975bde739c37bfeb8a")), - Address(Hex.decode("9fcd2deaff372a39cc679d5c5e4de7bafb0b1339")), - Address(Hex.decode("005f5cee7a43331d5a3d3eec71305925a62f34b6")), - Address(Hex.decode("0e0da70933f4c7849fc0d203f5d1d43b9ae4532d")), - Address(Hex.decode("d131637d5275fd1a68a3200f4ad25c71a2a9522e")), - Address(Hex.decode("bc07118b9ac290e4622f5e77a0853539789effbe")), - Address(Hex.decode("47e7aa56d6bdf3f36be34619660de61275420af8")), - Address(Hex.decode("acd87e28b0c9d1254e868b81cba4cc20d9a32225")), - Address(Hex.decode("adf80daec7ba8dcf15392f1ac611fff65d94f880")), - Address(Hex.decode("5524c55fb03cf21f549444ccbecb664d0acad706")), - Address(Hex.decode("40b803a9abce16f50f36a77ba41180eb90023925")), - Address(Hex.decode("fe24cdd8648121a43a7c86d289be4dd2951ed49f")), - Address(Hex.decode("17802f43a0137c506ba92291391a8a8f207f487d")), - Address(Hex.decode("253488078a4edf4d6f42f113d1e62836a942cf1a")), - Address(Hex.decode("86af3e9626fce1957c82e88cbf04ddf3a2ed7915")), - Address(Hex.decode("b136707642a4ea12fb4bae820f03d2562ebff487")), - Address(Hex.decode("dbe9b615a3ae8709af8b93336ce9b477e4ac0940")), - Address(Hex.decode("f14c14075d6c4ed84b86798af0956deef67365b5")), - Address(Hex.decode("ca544e5c4687d109611d0f8f928b53a25af72448")), - Address(Hex.decode("aeeb8ff27288bdabc0fa5ebb731b6f409507516c")), - Address(Hex.decode("cbb9d3703e651b0d496cdefb8b92c25aeb2171f7")), - Address(Hex.decode("6d87578288b6cb5549d5076a207456a1f6a63dc0")), - Address(Hex.decode("b2c6f0dfbb716ac562e2d85d6cb2f8d5ee87603e")), - Address(Hex.decode("accc230e8a6e5be9160b8cdf2864dd2a001c28b6")), - Address(Hex.decode("2b3455ec7fedf16e646268bf88846bd7a2319bb2")), - Address(Hex.decode("4613f3bca5c44ea06337a9e439fbc6d42e501d0a")), - Address(Hex.decode("d343b217de44030afaa275f54d31a9317c7f441e")), - Address(Hex.decode("84ef4b2357079cd7a7c69fd7a37cd0609a679106")), - Address(Hex.decode("da2fef9e4a3230988ff17df2165440f37e8b1708")), - Address(Hex.decode("f4c64518ea10f995918a454158c6b61407ea345c")), - Address(Hex.decode("7602b46df5390e432ef1c307d4f2c9ff6d65cc97")), - Address(Hex.decode("bb9bc244d798123fde783fcc1c72d3bb8c189413")), - Address(Hex.decode("807640a13483f8ac783c557fcdf27be11ea4ac7a")) - ) + def getExtraData(blockNumber: BigInt): Option[ByteString] = + if(requiresExtraData(blockNumber)) blockExtraData + else None } diff --git a/src/main/scala/io/iohk/ethereum/ledger/Ledger.scala b/src/main/scala/io/iohk/ethereum/ledger/Ledger.scala index 5d59d2688c..69f6bf8162 100644 --- a/src/main/scala/io/iohk/ethereum/ledger/Ledger.scala +++ b/src/main/scala/io/iohk/ethereum/ledger/Ledger.scala @@ -77,9 +77,10 @@ class LedgerImpl(vm: VM, blockchain: BlockchainImpl, blockchainConfig: Blockchai val parentStateRoot = blockchain.getBlockHeaderByHash(block.header.parentHash).map(_.stateRoot) val initialWorld = blockchain.getWorldStateProxy(block.header.number, blockchainConfig.accountStartNonce, parentStateRoot) - val inputWorld = - if(blockchainConfig.daoForkConfig isDaoForkBlock block.header.number) drainDaoForkAccounts(initialWorld, blockchainConfig.daoForkConfig) - else initialWorld + val inputWorld = blockchainConfig.daoForkConfig match { + case Some(daoForkConfig) if daoForkConfig.isDaoForkBlock(block.header.number) => drainDaoForkAccounts(initialWorld, daoForkConfig) + case _ => initialWorld + } log.debug(s"About to execute ${block.body.transactionList.size} txs from block ${block.header.number} (with hash: ${block.header.hashAsHexString})") val blockTxsExecResult = executeTransactions(block.body.transactionList, inputWorld, block.header, signedTransactionValidator) @@ -385,9 +386,13 @@ class LedgerImpl(vm: VM, blockchain: BlockchainImpl, blockchainConfig: Blockchai */ private def drainDaoForkAccounts(worldState: InMemoryWorldStateProxy, daoForkConfig: DaoForkConfig): InMemoryWorldStateProxy = { daoForkConfig.drainList.foldLeft(worldState) { (ws, address) => - ws.getAccount(address) - .map(acc => ws.transfer(from = address, to = daoForkConfig.refundContract, acc.balance)) - .getOrElse(ws) + val afterDrainWS = for { + account <- ws.getAccount(address) + refundContractAddress <- daoForkConfig.refundContract + afterDrainingAddress = ws.transfer(from = address, to = refundContractAddress, account.balance) + } yield afterDrainingAddress + + afterDrainWS.getOrElse(ws) } } diff --git a/src/main/scala/io/iohk/ethereum/mining/BlockGenerator.scala b/src/main/scala/io/iohk/ethereum/mining/BlockGenerator.scala index 0ad95891e5..c86ef1e929 100644 --- a/src/main/scala/io/iohk/ethereum/mining/BlockGenerator.scala +++ b/src/main/scala/io/iohk/ethereum/mining/BlockGenerator.scala @@ -106,7 +106,7 @@ class BlockGenerator(blockchain: Blockchain, blockchainConfig: BlockchainConfig, gasLimit = calculateGasLimit(parent.header.gasLimit), gasUsed = 0, unixTimestamp = blockTimestamp, - extraData = if (daoForkConfig requiresExtraData blockNumber) daoForkConfig.blockExtraData else miningConfig.headerExtraData, + extraData = daoForkConfig.flatMap(daoForkConfig => daoForkConfig.getExtraData(blockNumber)).getOrElse(miningConfig.headerExtraData), mixHash = ByteString.empty, nonce = ByteString.empty ) diff --git a/src/main/scala/io/iohk/ethereum/network/ForkResolver.scala b/src/main/scala/io/iohk/ethereum/network/ForkResolver.scala index 8480083fe0..824cc06093 100644 --- a/src/main/scala/io/iohk/ethereum/network/ForkResolver.scala +++ b/src/main/scala/io/iohk/ethereum/network/ForkResolver.scala @@ -1,5 +1,6 @@ package io.iohk.ethereum.network +import akka.util.ByteString import io.iohk.ethereum.daoFork.DaoForkConfig import io.iohk.ethereum.domain.BlockHeader import io.iohk.ethereum.utils.BlockchainConfig @@ -21,10 +22,10 @@ object ForkResolver { case object AcceptedFork extends Fork case object RejectedFork extends Fork - override def forkBlockNumber: BigInt = daoForkConfig.daoForkBlockNumber + override def forkBlockNumber: BigInt = daoForkConfig.forkBlockNumber override def recognizeFork(blockHeader: BlockHeader): Fork = { - if (blockHeader.hash == daoForkConfig.daoForkBlockHash) AcceptedFork + if (blockHeader.hash == daoForkConfig.forkBlockHash) AcceptedFork else RejectedFork } diff --git a/src/main/scala/io/iohk/ethereum/nodebuilder/NodeBuilder.scala b/src/main/scala/io/iohk/ethereum/nodebuilder/NodeBuilder.scala index 48846db2aa..e11997cf94 100644 --- a/src/main/scala/io/iohk/ethereum/nodebuilder/NodeBuilder.scala +++ b/src/main/scala/io/iohk/ethereum/nodebuilder/NodeBuilder.scala @@ -129,8 +129,8 @@ trait ForkResolverBuilder { self: BlockchainConfigBuilder => lazy val forkResolverOpt = - if (blockchainConfig.customGenesisFileOpt.isDefined) None - else Some(new ForkResolver.EtcForkResolver(blockchainConfig.daoForkConfig)) + if (blockchainConfig.daoForkConfig.isEmpty) None + else Some(new ForkResolver.EtcForkResolver(blockchainConfig.daoForkConfig.get)) } trait HandshakerBuilder { diff --git a/src/main/scala/io/iohk/ethereum/utils/Config.scala b/src/main/scala/io/iohk/ethereum/utils/Config.scala index bd15489a64..4fd3a32069 100644 --- a/src/main/scala/io/iohk/ethereum/utils/Config.scala +++ b/src/main/scala/io/iohk/ethereum/utils/Config.scala @@ -4,7 +4,7 @@ import java.net.InetSocketAddress import akka.util.ByteString import com.typesafe.config.{ConfigFactory, Config => TypesafeConfig} -import io.iohk.ethereum.daoFork.{DaoForkConfig, DefaultDaoForkConfig} +import io.iohk.ethereum.daoFork.DaoForkConfig import io.iohk.ethereum.db.dataSource.LevelDbConfig import io.iohk.ethereum.db.storage.pruning.{ArchivePruning, BasicPruning, PruningMode} import io.iohk.ethereum.domain.{Address, UInt256} @@ -15,6 +15,7 @@ import io.iohk.ethereum.network.rlpx.RLPxConnectionHandler.RLPxConfiguration import io.iohk.ethereum.utils.NumericUtils._ import org.spongycastle.util.encoders.Hex +import scala.collection.JavaConverters._ import scala.concurrent.duration._ import scala.util.Try @@ -254,7 +255,7 @@ trait BlockchainConfig { val customGenesisFileOpt: Option[String] - val daoForkConfig: DaoForkConfig + val daoForkConfig: Option[DaoForkConfig] val accountStartNonce: UInt256 @@ -263,7 +264,25 @@ trait BlockchainConfig { val monetaryPolicyConfig: MonetaryPolicyConfig } + object BlockchainConfig { + + def createDaoForkConfig(daoConfig: TypesafeConfig): DaoForkConfig = { + + val theForkBlockNumber = BigInt(daoConfig.getString("fork-block-number")) + + val theForkBlockHash = ByteString(Hex.decode(daoConfig.getString("fork-block-hash"))) + + new DaoForkConfig { + override val forkBlockNumber = theForkBlockNumber + override val forkBlockHash = theForkBlockHash + override val blockExtraData = Try(daoConfig.getString("block-extra-data")).toOption.map(ByteString(_)) + override val range = Try(daoConfig.getInt("block-extra-data-range")).toOption.getOrElse(0) + override val refundContract = Try(daoConfig.getString("refund-contract-address")).toOption.map(Address(_)) + override val drainList = Try(daoConfig.getStringList("drain-list").asScala.toList).toOption.getOrElse(List.empty).map(Address(_)) + } + } + def apply(etcClientConfig: TypesafeConfig): BlockchainConfig = { val blockchainConfig = etcClientConfig.getConfig("blockchain") @@ -278,10 +297,7 @@ object BlockchainConfig { override val customGenesisFileOpt: Option[String] = Try(blockchainConfig.getString("custom-genesis-file")).toOption - val proDaoFork: Boolean = blockchainConfig.getBoolean("pro-dao-fork") - val daoForkBlockNumber: BigInt = BigInt(blockchainConfig.getString("dao-fork-block-number")) - val daoForkBlockHash: ByteString = ByteString(Hex.decode(blockchainConfig.getString("dao-fork-block-hash"))) - override val daoForkConfig = DefaultDaoForkConfig(proDaoFork, daoForkBlockNumber, daoForkBlockHash) + override val daoForkConfig = Try(blockchainConfig.getConfig("dao")).toOption.map(createDaoForkConfig) override val accountStartNonce: UInt256 = UInt256(BigInt(blockchainConfig.getString("account-start-nonce"))) override val chainId: Byte = { diff --git a/src/main/scala/io/iohk/ethereum/validators/BlockHeaderValidator.scala b/src/main/scala/io/iohk/ethereum/validators/BlockHeaderValidator.scala index 5abd0704f4..e3929417b7 100644 --- a/src/main/scala/io/iohk/ethereum/validators/BlockHeaderValidator.scala +++ b/src/main/scala/io/iohk/ethereum/validators/BlockHeaderValidator.scala @@ -58,22 +58,28 @@ class BlockHeaderValidatorImpl(blockchainConfig: BlockchainConfig) extends Block * @param blockHeader BlockHeader to validate. * @return BlockHeader if valid, an [[HeaderExtraDataError]] otherwise */ - private def validateExtraData(blockHeader: BlockHeader): Either[BlockHeaderError, BlockHeader] = - if (blockHeader.extraData.length <= MaxExtraDataSize) { - import blockchainConfig._ - - val requiresExtraData = daoForkConfig requiresExtraData blockHeader.number - val isDaoForkData = blockHeader.extraData == daoForkConfig.blockExtraData + private def validateExtraData(blockHeader: BlockHeader): Either[BlockHeaderError, BlockHeader] = { - (requiresExtraData, isDaoForkData) match { - case (false, _) | (true, true) => + def validateDaoForkExtraData(blockHeader: BlockHeader, daoForkConfig: DaoForkConfig): Either[BlockHeaderError, BlockHeader] = + (daoForkConfig requiresExtraData blockHeader.number, daoForkConfig.blockExtraData) match { + case (false, _) => + Right(blockHeader) + case (true, Some(forkExtraData)) if blockHeader.extraData == forkExtraData => Right(blockHeader) case _ => Left(DaoHeaderExtraDataError) } + + if (blockHeader.extraData.length <= MaxExtraDataSize) { + import blockchainConfig._ + + if(daoForkConfig.isEmpty) Right(blockHeader) + else validateDaoForkExtraData(blockHeader, daoForkConfig.get) + } else { Left(HeaderExtraDataError) } + } /** * Validates [[io.iohk.ethereum.domain.BlockHeader.unixTimestamp]] is greater than the one of its parent diff --git a/src/test/resources/application.conf b/src/test/resources/application.conf index b99687fbfe..38f05a0067 100644 --- a/src/test/resources/application.conf +++ b/src/test/resources/application.conf @@ -1,4 +1,7 @@ mantis { + + client-id = "mantis" + datadir = "/tmp/mantis-test/" secure-random-algo = "NativePRNGNonBlocking" @@ -16,6 +19,27 @@ mantis { blockchain { eip155-block-number = "3000000" + + dao { + # DAO fork block number (Ethereum HF/Classic split) + # https://blog.ethereum.org/2016/07/20/hard-fork-completed/ + fork-block-number = "1920000" + + # The hash of the accepted DAO fork block + fork-block-hash = "94365e3a8c0b35089c1d1195081fe7489b528a84b22199c916180db8b28ade7f" + + # Extra data to be put in fork block headers + block-extra-data = null + + # number of blocks to place extra data after fork + block-extra-data-range = 10 + + # Address to send funds when draining + refund-contract-address = null + + # List of accounts to be drained + drain-list = null + } } mining { diff --git a/src/test/scala/io/iohk/ethereum/jsonrpc/PersonalServiceSpec.scala b/src/test/scala/io/iohk/ethereum/jsonrpc/PersonalServiceSpec.scala index 73d1c0a450..2fcb83cc1e 100644 --- a/src/test/scala/io/iohk/ethereum/jsonrpc/PersonalServiceSpec.scala +++ b/src/test/scala/io/iohk/ethereum/jsonrpc/PersonalServiceSpec.scala @@ -4,7 +4,7 @@ import akka.actor.ActorSystem import akka.testkit.TestProbe import akka.util.ByteString import io.iohk.ethereum.crypto.ECDSASignature -import io.iohk.ethereum.daoFork.{DaoForkConfig, DefaultDaoForkConfig} +import io.iohk.ethereum.daoFork.DaoForkConfig import io.iohk.ethereum.db.storage.AppStateStorage import io.iohk.ethereum.domain.{UInt256, _} import io.iohk.ethereum.jsonrpc.JsonRpcErrors._ @@ -351,7 +351,7 @@ class PersonalServiceSpec extends FlatSpec with Matchers with MockFactory with S override val customGenesisFileOpt: Option[String] = None override val accountStartNonce: UInt256 = UInt256.Zero override val monetaryPolicyConfig: MonetaryPolicyConfig = new MonetaryPolicyConfig(0, 0, 0) - override val daoForkConfig: DaoForkConfig = DefaultDaoForkConfig(daoForkBlockNumber = 0, daoForkBlockHash = ByteString.empty, proDaoFork = false) + override val daoForkConfig: Option[DaoForkConfig] = None } val wallet = Wallet(address, prvKey) diff --git a/src/test/scala/io/iohk/ethereum/ledger/LedgerSpec.scala b/src/test/scala/io/iohk/ethereum/ledger/LedgerSpec.scala index 123813f32a..66a42dd321 100644 --- a/src/test/scala/io/iohk/ethereum/ledger/LedgerSpec.scala +++ b/src/test/scala/io/iohk/ethereum/ledger/LedgerSpec.scala @@ -6,7 +6,7 @@ import akka.util.ByteString.{empty => bEmpty} import io.iohk.ethereum.Mocks.MockVM import io.iohk.ethereum.blockchain.sync.EphemBlockchainTestSetup import io.iohk.ethereum.crypto._ -import io.iohk.ethereum.daoFork.{DaoForkConfig, DefaultDaoForkConfig} +import io.iohk.ethereum.daoFork.DaoForkConfig import io.iohk.ethereum.domain._ import io.iohk.ethereum.ledger.BlockExecutionError.{ValidationAfterExecError, ValidationBeforeExecError} import io.iohk.ethereum.{Fixtures, Mocks, rlp} @@ -755,23 +755,21 @@ class LedgerSpec extends FlatSpec with PropertyChecks with Matchers with MockFac result match { case (_, executedTxs) => executedTxs shouldBe Seq.empty } } - it should "drain DAO accounts and send the funds to refund address if it's Pro DAO Fork configured" in new DaoForkTestSetup { + it should "drain DAO accounts and send the funds to refund address if Pro DAO Fork was configured" in new DaoForkTestSetup { + + (worldState.getAccount _) + .expects(supportDaoForkConfig.refundContract.get) + .anyNumberOfTimes() + .returning(Some(Account(nonce = 1, balance = UInt256.Zero))) // Check we drain all the accounts and send the balance to refund contract - proDaoBlockchainConfig.daoForkConfig.drainList.foreach { addr => + supportDaoForkConfig.drainList.foreach { addr => val daoAccountsFakeBalance = UInt256(1000) (worldState.getAccount _).expects(addr).returning(Some(Account(nonce = 1, balance = daoAccountsFakeBalance))) - (worldState.transfer _).expects(addr, proDaoBlockchainConfig.daoForkConfig.refundContract, daoAccountsFakeBalance).returning(worldState) + (worldState.transfer _).expects(addr, supportDaoForkConfig.refundContract.get, daoAccountsFakeBalance).returning(worldState) } - val ledger = new LedgerImpl(new MockVM(c => createResult( - context = c, - gasUsed = UInt256(10), - gasLimit = UInt256(10), - gasRefund = UInt256.Zero, - logs = Seq.empty, - addressesToDelete = Set.empty - )), testBlockchain, proDaoBlockchainConfig) + val ledger = new LedgerImpl(new MockVM(), testBlockchain, proDaoBlockchainConfig) ledger.executeBlockTransactions( proDaoBlock.copy(body = proDaoBlock.body.copy(transactionList = Seq.empty)), // We don't care about block txs in this test @@ -779,21 +777,14 @@ class LedgerSpec extends FlatSpec with PropertyChecks with Matchers with MockFac ) } - it should "not drain DAO accounts and send the funds to refund address if it not Pro DAO Fork configured" in new DaoForkTestSetup { + it should "neither drain DAO accounts nor send the funds to refund address if Pro DAO Fork was not configured" in new DaoForkTestSetup { // Check we drain all the accounts and send the balance to refund contract - proDaoBlockchainConfig.daoForkConfig.drainList.foreach { addr => + supportDaoForkConfig.drainList.foreach { addr => val daoAccountsFakeBalance = UInt256(1000) - (worldState.transfer _).expects(addr, proDaoBlockchainConfig.daoForkConfig.refundContract, *).never() + (worldState.transfer _).expects(*, *, *).never() } - val ledger = new LedgerImpl(new MockVM(c => createResult( - context = c, - gasUsed = UInt256(10), - gasLimit = UInt256(10), - gasRefund = UInt256.Zero, - logs = Seq.empty, - addressesToDelete = Set.empty - )), testBlockchain, blockchainConfig) + val ledger = new LedgerImpl(new MockVM(), testBlockchain, blockchainConfig) ledger.executeBlockTransactions( proDaoBlock.copy(body = proDaoBlock.body.copy(transactionList = Seq.empty)), // We don't care about block txs in this test @@ -895,6 +886,20 @@ class LedgerSpec extends FlatSpec with PropertyChecks with Matchers with MockFac } trait DaoForkTestSetup extends TestSetup { + + val testBlockchain = mock[BlockchainImpl] + val worldState = mock[InMemoryWorldStateProxy] + val proDaoBlock = Fixtures.Blocks.ProDaoForkBlock.block + + val supportDaoForkConfig = new DaoForkConfig { + override val blockExtraData: Option[ByteString] = Some(ByteString("refund extra data")) + override val range: Int = 10 + override val drainList: Seq[Address] = Seq(Address(1), Address(2), Address(3)) + override val forkBlockHash: ByteString = proDaoBlock.header.hash + override val forkBlockNumber: BigInt = proDaoBlock.header.number + override val refundContract: Option[Address] = Some(Address(4)) + } + val proDaoBlockchainConfig = new BlockchainConfig { override val frontierBlockNumber: BigInt = blockchainConfig.frontierBlockNumber override val accountStartNonce: UInt256 = blockchainConfig.accountStartNonce @@ -906,22 +911,14 @@ class LedgerSpec extends FlatSpec with PropertyChecks with Matchers with MockFac override val eip150BlockNumber: BigInt = blockchainConfig.eip150BlockNumber override val chainId: Byte = 0x01.toByte override val difficultyBombContinueBlockNumber: BigInt = blockchainConfig.difficultyBombContinueBlockNumber - override val daoForkConfig: DaoForkConfig = DefaultDaoForkConfig(true, 1920000, ByteString("")) + override val daoForkConfig: Option[DaoForkConfig] = Some(supportDaoForkConfig) override val customGenesisFileOpt: Option[String] = None } - val testBlockchain = mock[BlockchainImpl] - val worldState = mock[InMemoryWorldStateProxy] - val proDaoBlock = Fixtures.Blocks.ProDaoForkBlock.block (testBlockchain.getBlockHeaderByHash _).expects(proDaoBlock.header.parentHash).returning(Some(Fixtures.Blocks.DaoParentBlock.header)) (testBlockchain.getWorldStateProxy _) .expects(proDaoBlock.header.number, proDaoBlockchainConfig.accountStartNonce, Some(Fixtures.Blocks.DaoParentBlock.header.stateRoot)) .returning(worldState) - - (worldState.getAccount _) - .expects(proDaoBlockchainConfig.daoForkConfig.refundContract) - .anyNumberOfTimes() - .returning(Some(Account(nonce = 1, balance = UInt256.Zero))) } } diff --git a/src/test/scala/io/iohk/ethereum/mining/BlockGeneratorSpec.scala b/src/test/scala/io/iohk/ethereum/mining/BlockGeneratorSpec.scala index 06273393d6..ba51f145e1 100644 --- a/src/test/scala/io/iohk/ethereum/mining/BlockGeneratorSpec.scala +++ b/src/test/scala/io/iohk/ethereum/mining/BlockGeneratorSpec.scala @@ -15,7 +15,7 @@ import org.scalatest.prop.PropertyChecks import org.scalatest.{FlatSpec, Matchers} import org.spongycastle.util.encoders.Hex import io.iohk.ethereum.crypto._ -import io.iohk.ethereum.daoFork.{DaoForkConfig, DefaultDaoForkConfig} +import io.iohk.ethereum.daoFork.DaoForkConfig import io.iohk.ethereum.domain.SignedTransaction.FirstByteOfAddress import io.iohk.ethereum.utils.Config.DbConfig import org.spongycastle.crypto.AsymmetricCipherKeyPair @@ -72,7 +72,7 @@ class BlockGeneratorSpec extends FlatSpec with Matchers with PropertyChecks with fullBlock.right.foreach(b => validators.blockHeaderValidator.validate(b.header, blockchain) shouldBe Right(b.header)) fullBlock.right.foreach(b => ledger.executeBlock(b, validators) shouldBe a[Right[_, Seq[Receipt]]]) fullBlock.right.foreach(b => b.body.transactionList shouldBe Seq(signedTransaction)) - fullBlock.right.foreach(b => b.header.extraData shouldBe miningConfig.headerExtraData) + fullBlock.right.foreach(b => b.header.extraData shouldBe miningConfig.headerExtraData) } it should "filter out transactions exceeding block gas limit and include correct transactions" in new TestSetup { @@ -114,11 +114,7 @@ class BlockGeneratorSpec extends FlatSpec with Matchers with PropertyChecks with override val eip160BlockNumber: BigInt = Long.MaxValue override val eip150BlockNumber: BigInt = Long.MaxValue override val accountStartNonce: UInt256 = UInt256.Zero - override val daoForkConfig: DaoForkConfig = DefaultDaoForkConfig( - daoForkBlockNumber = Long.MaxValue, - daoForkBlockHash = ByteString("unused"), - proDaoFork = false - ) + override val daoForkConfig: Option[DaoForkConfig] = None } val generalTx = SignedTransaction.sign(transaction, keyPair, None) @@ -271,7 +267,7 @@ class BlockGeneratorSpec extends FlatSpec with Matchers with PropertyChecks with override val eip160BlockNumber: BigInt = Long.MaxValue override val eip150BlockNumber: BigInt = Long.MaxValue override val accountStartNonce: UInt256 = UInt256.Zero - override val daoForkConfig: DaoForkConfig = DefaultDaoForkConfig(daoForkBlockNumber = Long.MaxValue, daoForkBlockHash = ByteString("unused"), proDaoFork = false) + override val daoForkConfig: Option[DaoForkConfig] = None } lazy val ledger = new LedgerImpl(VM, blockchain, blockchainConfig) diff --git a/src/test/scala/io/iohk/ethereum/network/EtcPeerManagerSpec.scala b/src/test/scala/io/iohk/ethereum/network/EtcPeerManagerSpec.scala index feeb5633aa..58205ba222 100644 --- a/src/test/scala/io/iohk/ethereum/network/EtcPeerManagerSpec.scala +++ b/src/test/scala/io/iohk/ethereum/network/EtcPeerManagerSpec.scala @@ -254,7 +254,7 @@ class EtcPeerManagerSpec extends FlatSpec with Matchers { blockchain.save(Fixtures.Blocks.Genesis.header) val blockchainConfig = BlockchainConfig(Config.config) - val forkResolver = new ForkResolver.EtcForkResolver(blockchainConfig.daoForkConfig) + val forkResolver = new ForkResolver.EtcForkResolver(blockchainConfig.daoForkConfig.get) val peerStatus = Status( protocolVersion = Versions.PV63, diff --git a/src/test/scala/io/iohk/ethereum/network/handshaker/EtcHandshakerSpec.scala b/src/test/scala/io/iohk/ethereum/network/handshaker/EtcHandshakerSpec.scala index c1cc5daced..ae0bb63b38 100644 --- a/src/test/scala/io/iohk/ethereum/network/handshaker/EtcHandshakerSpec.scala +++ b/src/test/scala/io/iohk/ethereum/network/handshaker/EtcHandshakerSpec.scala @@ -5,12 +5,12 @@ import akka.util.ByteString import io.iohk.ethereum.Fixtures import io.iohk.ethereum.blockchain.sync.EphemBlockchainTestSetup import io.iohk.ethereum.crypto.generateKeyPair -import io.iohk.ethereum.daoFork.{DaoForkConfig, DefaultDaoForkConfig} +import io.iohk.ethereum.daoFork.DaoForkConfig import io.iohk.ethereum.db.components.Storages.PruningModeComponent import io.iohk.ethereum.db.components.{SharedEphemDataSources, Storages} import io.iohk.ethereum.db.storage.pruning.{ArchivePruning, PruningMode} import io.iohk.ethereum.db.storage.AppStateStorage -import io.iohk.ethereum.domain.{Block, Blockchain, BlockchainImpl, UInt256} +import io.iohk.ethereum.domain._ import io.iohk.ethereum.network.ForkResolver import io.iohk.ethereum.network.PeerManagerActor.PeerConfiguration import io.iohk.ethereum.network.EtcPeerManagerActor.PeerInfo @@ -25,6 +25,7 @@ import io.iohk.ethereum.network.p2p.messages.WireProtocol.{Capability, Disconnec import io.iohk.ethereum.nodebuilder.SecureRandomBuilder import io.iohk.ethereum.utils._ import org.scalatest.{FlatSpec, Matchers} +import org.spongycastle.util.encoders.Hex import scala.concurrent.ExecutionContext.Implicits.global @@ -158,15 +159,18 @@ class EtcHandshakerSpec extends FlatSpec with Matchers { override val chainId: Byte = 0.toByte override val monetaryPolicyConfig: MonetaryPolicyConfig = null override val accountStartNonce: UInt256 = UInt256.Zero - override val daoForkConfig: DaoForkConfig = DefaultDaoForkConfig( - daoForkBlockNumber = forkBlockHeader.number, - daoForkBlockHash = forkBlockHeader.hash, - proDaoFork = false - ) + override val daoForkConfig: Option[DaoForkConfig] = Some(new DaoForkConfig { + override val blockExtraData: Option[ByteString] = None + override val range: Int = 10 + override val drainList: Seq[Address] = Nil + override val forkBlockHash: ByteString = ByteString(Hex.decode("94365e3a8c0b35089c1d1195081fe7489b528a84b22199c916180db8b28ade7f")) + override val forkBlockNumber: BigInt = 1920000 + override val refundContract: Option[Address] = None + }) } val etcHandshakerConfigurationWithResolver = new MockEtcHandshakerConfiguration { - override val forkResolverOpt: Option[ForkResolver] = Some(new ForkResolver.EtcForkResolver(blockchainConfig.daoForkConfig)) + override val forkResolverOpt: Option[ForkResolver] = Some(new ForkResolver.EtcForkResolver(blockchainConfig.daoForkConfig.get)) } val initHandshakerWithoutResolver = EtcHandshaker(new MockEtcHandshakerConfiguration) diff --git a/src/test/scala/io/iohk/ethereum/network/p2p/PeerActorSpec.scala b/src/test/scala/io/iohk/ethereum/network/p2p/PeerActorSpec.scala index 67429b7948..4637eb0a13 100644 --- a/src/test/scala/io/iohk/ethereum/network/p2p/PeerActorSpec.scala +++ b/src/test/scala/io/iohk/ethereum/network/p2p/PeerActorSpec.scala @@ -399,7 +399,7 @@ class PeerActorSpec extends FlatSpec with Matchers { trait HandshakerSetup extends NodeStatusSetup { val handshakerConfiguration = new EtcHandshakerConfiguration { - override val forkResolverOpt: Option[ForkResolver] = Some(new ForkResolver.EtcForkResolver(blockchainConfig.daoForkConfig)) + override val forkResolverOpt: Option[ForkResolver] = Some(new ForkResolver.EtcForkResolver(blockchainConfig.daoForkConfig.get)) override val nodeStatusHolder: Agent[NodeStatus] = HandshakerSetup.this.nodeStatusHolder override val peerConfiguration: PeerConfiguration = HandshakerSetup.this.peerConf override val blockchain: Blockchain = HandshakerSetup.this.blockchain diff --git a/src/test/scala/io/iohk/ethereum/validators/BlockHeaderValidatorSpec.scala b/src/test/scala/io/iohk/ethereum/validators/BlockHeaderValidatorSpec.scala index 7b37a111ff..c1b2d0ff37 100644 --- a/src/test/scala/io/iohk/ethereum/validators/BlockHeaderValidatorSpec.scala +++ b/src/test/scala/io/iohk/ethereum/validators/BlockHeaderValidatorSpec.scala @@ -3,7 +3,7 @@ package io.iohk.ethereum.validators import akka.util.ByteString import io.iohk.ethereum.{Fixtures, ObjectGenerators} import io.iohk.ethereum.blockchain.sync.EphemBlockchainTestSetup -import io.iohk.ethereum.daoFork.{DaoForkConfig, DefaultDaoForkConfig} +import io.iohk.ethereum.daoFork.DaoForkConfig import io.iohk.ethereum.domain.{UInt256, _} import io.iohk.ethereum.utils.{BlockchainConfig, Config, MonetaryPolicyConfig} import io.iohk.ethereum.validators.BlockHeaderError._ @@ -12,7 +12,6 @@ import org.scalatest.{FlatSpec, Matchers} import org.spongycastle.util.encoders.Hex class BlockHeaderValidatorSpec extends FlatSpec with Matchers with PropertyChecks with ObjectGenerators { - import Fixtures.Blocks._ val ExtraDataSizeLimit = 20 //BlockHeader member's lengths obtained from Yellow paper @@ -44,7 +43,7 @@ class BlockHeaderValidatorSpec extends FlatSpec with Matchers with PropertyCheck it should "validate DAO block (extra data)" in { import Fixtures.Blocks._ val cases = Table( - ("Block", "Parent Block", "Pro Dao Fork", "Valid"), + ("Block", "Parent Block", "Supports Dao Fork", "Valid"), (DaoForkBlock.header, DaoParentBlock.header, false, true), (DaoForkBlock.header, DaoParentBlock.header, true, false), (ProDaoForkBlock.header, DaoParentBlock.header, true, true), @@ -56,8 +55,8 @@ class BlockHeaderValidatorSpec extends FlatSpec with Matchers with PropertyCheck (ProDaoBlock1920010Header, ProDaoBlock1920009Header, true, true) ) - forAll(cases) { (block, parentBlock, proDaoFork, valid ) => - val blockHeaderValidator = new BlockHeaderValidatorImpl(createBlockchainConfig(proDaoFork)) + forAll(cases) { (block, parentBlock, supportsDaoFork, valid ) => + val blockHeaderValidator = new BlockHeaderValidatorImpl(createBlockchainConfig(supportsDaoFork)) blockHeaderValidator.validate(block, parentBlock) match { case Right(_) => assert(valid) case Left(DaoHeaderExtraDataError) => assert(!valid) @@ -239,14 +238,24 @@ class BlockHeaderValidatorSpec extends FlatSpec with Matchers with PropertyCheck nonce = ByteString(Hex.decode("3fc7bc671f7cee70")) ) - def createBlockchainConfig(proDaoFork: Boolean = false): BlockchainConfig = + def createBlockchainConfig(supportsDaoFork: Boolean = false): BlockchainConfig = new BlockchainConfig { + + import Fixtures.Blocks._ + override val frontierBlockNumber: BigInt = 0 override val homesteadBlockNumber: BigInt = 1150000 override val difficultyBombPauseBlockNumber: BigInt = 3000000 override val difficultyBombContinueBlockNumber: BigInt = 5000000 - override val daoForkConfig: DaoForkConfig = DefaultDaoForkConfig(proDaoFork, DaoForkBlock.header.number, DaoForkBlock.header.hash) + override val daoForkConfig: Option[DaoForkConfig] = Some(new DaoForkConfig { + override val blockExtraData: Option[ByteString] = if(supportsDaoFork) Some(ProDaoForkBlock.header.extraData) else None + override val range: Int = 10 + override val drainList: Seq[Address] = Nil + override val forkBlockHash: ByteString = if(supportsDaoFork) ProDaoForkBlock.header.hash else DaoForkBlock.header.hash + override val forkBlockNumber: BigInt = DaoForkBlock.header.number + override val refundContract: Option[Address] = None + }) // unused override val eip155BlockNumber: BigInt = Long.MaxValue diff --git a/src/universal/conf/blockchain.conf b/src/universal/conf/blockchain.conf index 938f765e8c..3bc8e7bf4e 100644 --- a/src/universal/conf/blockchain.conf +++ b/src/universal/conf/blockchain.conf @@ -40,6 +40,29 @@ mantis { # The hash of the accepted DAO fork block # dao-fork-block-hash = "94365e3a8c0b35089c1d1195081fe7489b528a84b22199c916180db8b28ade7f" + # DAO fork configuration (Ethereum HF/Classic split) + # https://blog.ethereum.org/2016/07/20/hard-fork-completed/ + # dao { + + # DAO fork block number + # fork-block-number = "1920000" + + # The hash of the accepted DAO fork block + # fork-block-hash = "94365e3a8c0b35089c1d1195081fe7489b528a84b22199c916180db8b28ade7f" + + # Extra data to be put in fork block headers + # block-extra-data = null + + # number of blocks to place extra data after fork + #block-extra-data-range = 10 + + # Address to send funds when draining + # refund-contract-address = null + + # List of accounts addresses to be drained. For example ["d4fe7bc31cedb7bfb8a345f31e668033056b2728", "b3fb0e5aba0e20e5c49d252dfd30e102b171a425"] + # drain-list = [] + #} + # Starting nonce a an empty account. Some networks (like Morden) use different values. # account-start-nonce = "0" diff --git a/src/universal/conf/ethereumHF.conf b/src/universal/conf/ethereumHF.conf index 502003d72e..7b1db4101e 100644 --- a/src/universal/conf/ethereumHF.conf +++ b/src/universal/conf/ethereumHF.conf @@ -25,9 +25,6 @@ mantis { difficulty-bomb-pause-block-number = "0" difficulty-bomb-continue-block-number = "0" - dao-fork-block-number = "1920000" - dao-fork-block-hash = "4985f5ca3d2afbec36529aa96f74de3cc10a2a4a6c44f2157a57d2c6059a11bb" - account-start-nonce = "0" chain-id = "1" @@ -39,5 +36,146 @@ mantis { era-duration = 5000000 reward-reduction-rate = 0 } + + # DAO fork configuration (Ethereum HF/Classic split) + # https://blog.ethereum.org/2016/07/20/hard-fork-completed/ + dao { + + # DAO fork block number + fork-block-number = "1920000" + + # The hash of the accepted DAO fork block + fork-block-hash = "4985f5ca3d2afbec36529aa96f74de3cc10a2a4a6c44f2157a57d2c6059a11bb" + + # Extra data to be put in fork block headers + block-extra-data = "64616f2d686172642d666f726b" + + # number of blocks to place extra data after fork + block-extra-data-range = 10 + + # Address to send funds when draining + refund-contract-address = "bf4ed7b27f1d666546e30d74d50d173d20bca754" + + # List of accounts to be drained + drain-list = [ + "d4fe7bc31cedb7bfb8a345f31e668033056b2728", + "b3fb0e5aba0e20e5c49d252dfd30e102b171a425", + "2c19c7f9ae8b751e37aeb2d93a699722395ae18f", + "ecd135fa4f61a655311e86238c92adcd779555d2", + "1975bd06d486162d5dc297798dfc41edd5d160a7", + "a3acf3a1e16b1d7c315e23510fdd7847b48234f6", + "319f70bab6845585f412ec7724b744fec6095c85", + "06706dd3f2c9abf0a21ddcc6941d9b86f0596936", + "5c8536898fbb74fc7445814902fd08422eac56d0", + "6966ab0d485353095148a2155858910e0965b6f9", + "779543a0491a837ca36ce8c635d6154e3c4911a6", + "2a5ed960395e2a49b1c758cef4aa15213cfd874c", + "5c6e67ccd5849c0d29219c4f95f1a7a93b3f5dc5", + "9c50426be05db97f5d64fc54bf89eff947f0a321", + "200450f06520bdd6c527622a273333384d870efb", + "be8539bfe837b67d1282b2b1d61c3f723966f049", + "6b0c4d41ba9ab8d8cfb5d379c69a612f2ced8ecb", + "f1385fb24aad0cd7432824085e42aff90886fef5", + "d1ac8b1ef1b69ff51d1d401a476e7e612414f091", + "8163e7fb499e90f8544ea62bbf80d21cd26d9efd", + "51e0ddd9998364a2eb38588679f0d2c42653e4a6", + "627a0a960c079c21c34f7612d5d230e01b4ad4c7", + "f0b1aa0eb660754448a7937c022e30aa692fe0c5", + "24c4d950dfd4dd1902bbed3508144a54542bba94", + "9f27daea7aca0aa0446220b98d028715e3bc803d", + "a5dc5acd6a7968a4554d89d65e59b7fd3bff0f90", + "d9aef3a1e38a39c16b31d1ace71bca8ef58d315b", + "63ed5a272de2f6d968408b4acb9024f4cc208ebf", + "6f6704e5a10332af6672e50b3d9754dc460dfa4d", + "77ca7b50b6cd7e2f3fa008e24ab793fd56cb15f6", + "492ea3bb0f3315521c31f273e565b868fc090f17", + "0ff30d6de14a8224aa97b78aea5388d1c51c1f00", + "9ea779f907f0b315b364b0cfc39a0fde5b02a416", + "ceaeb481747ca6c540a000c1f3641f8cef161fa7", + "cc34673c6c40e791051898567a1222daf90be287", + "579a80d909f346fbfb1189493f521d7f48d52238", + "e308bd1ac5fda103967359b2712dd89deffb7973", + "4cb31628079fb14e4bc3cd5e30c2f7489b00960c", + "ac1ecab32727358dba8962a0f3b261731aad9723", + "4fd6ace747f06ece9c49699c7cabc62d02211f75", + "440c59b325d2997a134c2c7c60a8c61611212bad", + "4486a3d68fac6967006d7a517b889fd3f98c102b", + "9c15b54878ba618f494b38f0ae7443db6af648ba", + "27b137a85656544b1ccb5a0f2e561a5703c6a68f", + "21c7fdb9ed8d291d79ffd82eb2c4356ec0d81241", + "23b75c2f6791eef49c69684db4c6c1f93bf49a50", + "1ca6abd14d30affe533b24d7a21bff4c2d5e1f3b", + "b9637156d330c0d605a791f1c31ba5890582fe1c", + "6131c42fa982e56929107413a9d526fd99405560", + "1591fc0f688c81fbeb17f5426a162a7024d430c2", + "542a9515200d14b68e934e9830d91645a980dd7a", + "c4bbd073882dd2add2424cf47d35213405b01324", + "782495b7b3355efb2833d56ecb34dc22ad7dfcc4", + "58b95c9a9d5d26825e70a82b6adb139d3fd829eb", + "3ba4d81db016dc2890c81f3acec2454bff5aada5", + "b52042c8ca3f8aa246fa79c3feaa3d959347c0ab", + "e4ae1efdfc53b73893af49113d8694a057b9c0d1", + "3c02a7bc0391e86d91b7d144e61c2c01a25a79c5", + "0737a6b837f97f46ebade41b9bc3e1c509c85c53", + "97f43a37f595ab5dd318fb46e7a155eae057317a", + "52c5317c848ba20c7504cb2c8052abd1fde29d03", + "4863226780fe7c0356454236d3b1c8792785748d", + "5d2b2e6fcbe3b11d26b525e085ff818dae332479", + "5f9f3392e9f62f63b8eac0beb55541fc8627f42c", + "057b56736d32b86616a10f619859c6cd6f59092a", + "9aa008f65de0b923a2a4f02012ad034a5e2e2192", + "304a554a310c7e546dfe434669c62820b7d83490", + "914d1b8b43e92723e64fd0a06f5bdb8dd9b10c79", + "4deb0033bb26bc534b197e61d19e0733e5679784", + "07f5c1e1bc2c93e0402f23341973a0e043f7bf8a", + "35a051a0010aba705c9008d7a7eff6fb88f6ea7b", + "4fa802324e929786dbda3b8820dc7834e9134a2a", + "9da397b9e80755301a3b32173283a91c0ef6c87e", + "8d9edb3054ce5c5774a420ac37ebae0ac02343c6", + "0101f3be8ebb4bbd39a2e3b9a3639d4259832fd9", + "5dc28b15dffed94048d73806ce4b7a4612a1d48f", + "bcf899e6c7d9d5a215ab1e3444c86806fa854c76", + "12e626b0eebfe86a56d633b9864e389b45dcb260", + "a2f1ccba9395d7fcb155bba8bc92db9bafaeade7", + "ec8e57756626fdc07c63ad2eafbd28d08e7b0ca5", + "d164b088bd9108b60d0ca3751da4bceb207b0782", + "6231b6d0d5e77fe001c2a460bd9584fee60d409b", + "1cba23d343a983e9b5cfd19496b9a9701ada385f", + "a82f360a8d3455c5c41366975bde739c37bfeb8a", + "9fcd2deaff372a39cc679d5c5e4de7bafb0b1339", + "005f5cee7a43331d5a3d3eec71305925a62f34b6", + "0e0da70933f4c7849fc0d203f5d1d43b9ae4532d", + "d131637d5275fd1a68a3200f4ad25c71a2a9522e", + "bc07118b9ac290e4622f5e77a0853539789effbe", + "47e7aa56d6bdf3f36be34619660de61275420af8", + "acd87e28b0c9d1254e868b81cba4cc20d9a32225", + "adf80daec7ba8dcf15392f1ac611fff65d94f880", + "5524c55fb03cf21f549444ccbecb664d0acad706", + "40b803a9abce16f50f36a77ba41180eb90023925", + "fe24cdd8648121a43a7c86d289be4dd2951ed49f", + "17802f43a0137c506ba92291391a8a8f207f487d", + "253488078a4edf4d6f42f113d1e62836a942cf1a", + "86af3e9626fce1957c82e88cbf04ddf3a2ed7915", + "b136707642a4ea12fb4bae820f03d2562ebff487", + "dbe9b615a3ae8709af8b93336ce9b477e4ac0940", + "f14c14075d6c4ed84b86798af0956deef67365b5", + "ca544e5c4687d109611d0f8f928b53a25af72448", + "aeeb8ff27288bdabc0fa5ebb731b6f409507516c", + "cbb9d3703e651b0d496cdefb8b92c25aeb2171f7", + "6d87578288b6cb5549d5076a207456a1f6a63dc0", + "b2c6f0dfbb716ac562e2d85d6cb2f8d5ee87603e", + "accc230e8a6e5be9160b8cdf2864dd2a001c28b6", + "2b3455ec7fedf16e646268bf88846bd7a2319bb2", + "4613f3bca5c44ea06337a9e439fbc6d42e501d0a", + "d343b217de44030afaa275f54d31a9317c7f441e", + "84ef4b2357079cd7a7c69fd7a37cd0609a679106", + "da2fef9e4a3230988ff17df2165440f37e8b1708", + "f4c64518ea10f995918a454158c6b61407ea345c", + "7602b46df5390e432ef1c307d4f2c9ff6d65cc97", + "bb9bc244d798123fde783fcc1c72d3bb8c189413", + "807640a13483f8ac783c557fcdf27be11ea4ac7a" + ] + } + } } diff --git a/src/universal/conf/morden.conf b/src/universal/conf/morden.conf index ebcca54f51..2cc9420611 100644 --- a/src/universal/conf/morden.conf +++ b/src/universal/conf/morden.conf @@ -20,9 +20,7 @@ mantis { difficulty-bomb-pause-block-number = "1915000" difficulty-bomb-continue-block-number = "3415000" - pro-dao-fork = false - dao-fork-block-number = "1783000" - dao-fork-block-hash = "f376243aeff1f256d970714c3de9fd78fa4e63cf63e32a51fe1169e375d98145" + dao = null account-start-nonce = "1048576" From 7f287f76dfdaf2e2b1fd351e03f2b9af467cb5cc Mon Sep 17 00:00:00 2001 From: Alan Verbner Date: Tue, 19 Sep 2017 10:10:15 -0300 Subject: [PATCH 07/10] [EC-236] Addressed PR comments --- .../iohk/ethereum/txExecTest/ForksTest.scala | 6 +- .../iohk/ethereum/daoFork/DaoForkConfig.scala | 18 ----- .../io/iohk/ethereum/ledger/Ledger.scala | 22 ++++--- .../iohk/ethereum/mining/BlockGenerator.scala | 1 - .../iohk/ethereum/network/ForkResolver.scala | 4 +- .../ethereum/nodebuilder/NodeBuilder.scala | 5 +- .../scala/io/iohk/ethereum/utils/Config.scala | 66 +++++++++++++------ .../validators/BlockHeaderValidator.scala | 21 +++--- .../jsonrpc/PersonalServiceSpec.scala | 3 +- .../io/iohk/ethereum/ledger/LedgerSpec.scala | 3 +- .../ethereum/mining/BlockGeneratorSpec.scala | 3 +- .../handshaker/EtcHandshakerSpec.scala | 4 -- .../validators/BlockHeaderValidatorSpec.scala | 16 +++-- src/universal/conf/blockchain.conf | 11 ---- 14 files changed, 84 insertions(+), 99 deletions(-) diff --git a/src/it/scala/io/iohk/ethereum/txExecTest/ForksTest.scala b/src/it/scala/io/iohk/ethereum/txExecTest/ForksTest.scala index a7477f6149..19bb53d4ae 100644 --- a/src/it/scala/io/iohk/ethereum/txExecTest/ForksTest.scala +++ b/src/it/scala/io/iohk/ethereum/txExecTest/ForksTest.scala @@ -1,11 +1,9 @@ package io.iohk.ethereum.txExecTest -import akka.util.ByteString -import io.iohk.ethereum.daoFork.DaoForkConfig -import io.iohk.ethereum.domain.{Address, BlockchainImpl, Receipt, UInt256} +import io.iohk.ethereum.domain.{BlockchainImpl, Receipt, UInt256} import io.iohk.ethereum.ledger.LedgerImpl import io.iohk.ethereum.txExecTest.util.FixtureProvider -import io.iohk.ethereum.utils.{BlockchainConfig, MonetaryPolicyConfig} +import io.iohk.ethereum.utils.{BlockchainConfig, DaoForkConfig, MonetaryPolicyConfig} import io.iohk.ethereum.validators._ import io.iohk.ethereum.vm.VM import org.scalatest.{FlatSpec, Matchers} diff --git a/src/main/scala/io/iohk/ethereum/daoFork/DaoForkConfig.scala b/src/main/scala/io/iohk/ethereum/daoFork/DaoForkConfig.scala index 9e8d3caa40..d4dc76b421 100644 --- a/src/main/scala/io/iohk/ethereum/daoFork/DaoForkConfig.scala +++ b/src/main/scala/io/iohk/ethereum/daoFork/DaoForkConfig.scala @@ -3,22 +3,4 @@ package io.iohk.ethereum.daoFork import akka.util.ByteString import io.iohk.ethereum.domain.Address -trait DaoForkConfig { - val forkBlockNumber: BigInt - val forkBlockHash: ByteString - val blockExtraData: Option[ByteString] - val range: Int - val refundContract: Option[Address] - val drainList: Seq[Address] - - private lazy val extratadaBlockRange = forkBlockNumber until(forkBlockNumber + range) - - def isDaoForkBlock(blockNumber: BigInt): Boolean = forkBlockNumber == blockNumber - - def requiresExtraData(blockNumber: BigInt): Boolean = blockExtraData.isDefined && (extratadaBlockRange contains blockNumber) - - def getExtraData(blockNumber: BigInt): Option[ByteString] = - if(requiresExtraData(blockNumber)) blockExtraData - else None -} diff --git a/src/main/scala/io/iohk/ethereum/ledger/Ledger.scala b/src/main/scala/io/iohk/ethereum/ledger/Ledger.scala index 69f6bf8162..831e6d07ce 100644 --- a/src/main/scala/io/iohk/ethereum/ledger/Ledger.scala +++ b/src/main/scala/io/iohk/ethereum/ledger/Ledger.scala @@ -1,12 +1,11 @@ package io.iohk.ethereum.ledger import akka.util.ByteString -import io.iohk.ethereum.daoFork.DaoForkConfig import io.iohk.ethereum.domain._ import io.iohk.ethereum.validators._ import io.iohk.ethereum.ledger.BlockExecutionError.{StateBeforeFailure, TxsExecutionError, ValidationAfterExecError, ValidationBeforeExecError} import io.iohk.ethereum.ledger.Ledger.{BlockPreparationResult, BlockResult, PC, PR, TxResult} -import io.iohk.ethereum.utils.{BlockchainConfig, Logger} +import io.iohk.ethereum.utils.{BlockchainConfig, DaoForkConfig, Logger} import io.iohk.ethereum.validators.{BlockValidator, SignedTransactionValidator} import io.iohk.ethereum.domain.UInt256._ import io.iohk.ethereum.vm._ @@ -385,15 +384,18 @@ class LedgerImpl(vm: VM, blockchain: BlockchainImpl, blockchainConfig: Blockchai * @return Updated world state proxy */ private def drainDaoForkAccounts(worldState: InMemoryWorldStateProxy, daoForkConfig: DaoForkConfig): InMemoryWorldStateProxy = { - daoForkConfig.drainList.foldLeft(worldState) { (ws, address) => - val afterDrainWS = for { - account <- ws.getAccount(address) - refundContractAddress <- daoForkConfig.refundContract - afterDrainingAddress = ws.transfer(from = address, to = refundContractAddress, account.balance) - } yield afterDrainingAddress - - afterDrainWS.getOrElse(ws) + + daoForkConfig.refundContract match { + case Some(refundContractAddress) => + daoForkConfig.drainList.foldLeft(worldState) { (ws, address) => + ws.getAccount(address) + .map(account => ws.transfer(from = address, to = refundContractAddress, account.balance)) + .getOrElse(ws) + } + case None => worldState } + + } } diff --git a/src/main/scala/io/iohk/ethereum/mining/BlockGenerator.scala b/src/main/scala/io/iohk/ethereum/mining/BlockGenerator.scala index c86ef1e929..8c89d2b255 100644 --- a/src/main/scala/io/iohk/ethereum/mining/BlockGenerator.scala +++ b/src/main/scala/io/iohk/ethereum/mining/BlockGenerator.scala @@ -20,7 +20,6 @@ import io.iohk.ethereum.validators.MptListValidator.intByteArraySerializable import io.iohk.ethereum.validators.OmmersValidator.OmmersError import io.iohk.ethereum.validators.Validators import io.iohk.ethereum.crypto._ -import io.iohk.ethereum.daoFork.DaoForkConfig class BlockGenerator(blockchain: Blockchain, blockchainConfig: BlockchainConfig, miningConfig: MiningConfig, ledger: Ledger, validators: Validators, blockTimestampProvider: BlockTimestampProvider = DefaultBlockTimestampProvider) { diff --git a/src/main/scala/io/iohk/ethereum/network/ForkResolver.scala b/src/main/scala/io/iohk/ethereum/network/ForkResolver.scala index 824cc06093..fcc828d3b0 100644 --- a/src/main/scala/io/iohk/ethereum/network/ForkResolver.scala +++ b/src/main/scala/io/iohk/ethereum/network/ForkResolver.scala @@ -1,9 +1,7 @@ package io.iohk.ethereum.network -import akka.util.ByteString -import io.iohk.ethereum.daoFork.DaoForkConfig import io.iohk.ethereum.domain.BlockHeader -import io.iohk.ethereum.utils.BlockchainConfig +import io.iohk.ethereum.utils.DaoForkConfig trait ForkResolver { type Fork <: ForkResolver.Fork diff --git a/src/main/scala/io/iohk/ethereum/nodebuilder/NodeBuilder.scala b/src/main/scala/io/iohk/ethereum/nodebuilder/NodeBuilder.scala index e11997cf94..d90e451d54 100644 --- a/src/main/scala/io/iohk/ethereum/nodebuilder/NodeBuilder.scala +++ b/src/main/scala/io/iohk/ethereum/nodebuilder/NodeBuilder.scala @@ -128,9 +128,8 @@ trait BlockChainBuilder { trait ForkResolverBuilder { self: BlockchainConfigBuilder => - lazy val forkResolverOpt = - if (blockchainConfig.daoForkConfig.isEmpty) None - else Some(new ForkResolver.EtcForkResolver(blockchainConfig.daoForkConfig.get)) + lazy val forkResolverOpt = blockchainConfig.daoForkConfig.map(new ForkResolver.EtcForkResolver(_)) + } trait HandshakerBuilder { diff --git a/src/main/scala/io/iohk/ethereum/utils/Config.scala b/src/main/scala/io/iohk/ethereum/utils/Config.scala index 78ca533219..e3d0148a10 100644 --- a/src/main/scala/io/iohk/ethereum/utils/Config.scala +++ b/src/main/scala/io/iohk/ethereum/utils/Config.scala @@ -4,7 +4,6 @@ import java.net.InetSocketAddress import akka.util.ByteString import com.typesafe.config.{ConfigFactory, Config => TypesafeConfig} -import io.iohk.ethereum.daoFork.DaoForkConfig import io.iohk.ethereum.db.dataSource.LevelDbConfig import io.iohk.ethereum.db.storage.pruning.{ArchivePruning, BasicPruning, PruningMode} import io.iohk.ethereum.domain.{Address, UInt256} @@ -13,6 +12,7 @@ import io.iohk.ethereum.jsonrpc.server.JsonRpcServer.JsonRpcServerConfig import io.iohk.ethereum.network.PeerManagerActor.{FastSyncHostConfiguration, PeerConfiguration} import io.iohk.ethereum.network.rlpx.RLPxConnectionHandler.RLPxConfiguration import io.iohk.ethereum.utils.NumericUtils._ +import io.iohk.ethereum.validators.BlockHeaderValidatorImpl import org.spongycastle.util.encoders.Hex import scala.collection.JavaConverters._ @@ -219,8 +219,6 @@ object TxPoolConfig { } trait MiningConfig { - //duplicated in BlockHeaderValidator - val MaxExtraDataSize: Int = 32 val ommersPoolSize: Int val blockCacheSize: Int val coinbase: Address @@ -239,11 +237,53 @@ object MiningConfig { val ommersPoolSize: Int = miningConfig.getInt("ommers-pool-size") val activeTimeout: FiniteDuration = miningConfig.getDuration("active-timeout").toMillis.millis val ommerPoolQueryTimeout: FiniteDuration = miningConfig.getDuration("ommer-pool-query-timeout").toMillis.millis - override val headerExtraData: ByteString = ByteString(miningConfig.getString("header-extra-data").getBytes).take(MaxExtraDataSize) + override val headerExtraData: ByteString = + ByteString(miningConfig + .getString("header-extra-data").getBytes) + .take(BlockHeaderValidatorImpl.MaxExtraDataSize) } } } +trait DaoForkConfig { + + val forkBlockNumber: BigInt + val forkBlockHash: ByteString + val blockExtraData: Option[ByteString] + val range: Int + val refundContract: Option[Address] + val drainList: Seq[Address] + + private lazy val extratadaBlockRange = forkBlockNumber until(forkBlockNumber + range) + + def isDaoForkBlock(blockNumber: BigInt): Boolean = forkBlockNumber == blockNumber + + def requiresExtraData(blockNumber: BigInt): Boolean = blockExtraData.isDefined && (extratadaBlockRange contains blockNumber) + + def getExtraData(blockNumber: BigInt): Option[ByteString] = + if(requiresExtraData(blockNumber)) blockExtraData + else None +} + +object DaoForkConfig { + def apply(daoConfig: TypesafeConfig): DaoForkConfig = { + + val theForkBlockNumber = BigInt(daoConfig.getString("fork-block-number")) + + val theForkBlockHash = ByteString(Hex.decode(daoConfig.getString("fork-block-hash"))) + + new DaoForkConfig { + override val forkBlockNumber: BigInt = theForkBlockNumber + override val forkBlockHash: ByteString = theForkBlockHash + override val blockExtraData: Option[ByteString] = Try(daoConfig.getString("block-extra-data")).toOption.map(ByteString(_)) + override val range: Int = Try(daoConfig.getInt("block-extra-data-range")).toOption.getOrElse(0) + override val refundContract: Option[Address] = Try(daoConfig.getString("refund-contract-address")).toOption.map(Address(_)) + override val drainList: List[Address] = Try(daoConfig.getStringList("drain-list").asScala.toList).toOption.getOrElse(List.empty).map(Address(_)) + } + } +} + + trait BlockchainConfig { val frontierBlockNumber: BigInt val homesteadBlockNumber: BigInt @@ -268,22 +308,6 @@ trait BlockchainConfig { object BlockchainConfig { - def createDaoForkConfig(daoConfig: TypesafeConfig): DaoForkConfig = { - - val theForkBlockNumber = BigInt(daoConfig.getString("fork-block-number")) - - val theForkBlockHash = ByteString(Hex.decode(daoConfig.getString("fork-block-hash"))) - - new DaoForkConfig { - override val forkBlockNumber = theForkBlockNumber - override val forkBlockHash = theForkBlockHash - override val blockExtraData = Try(daoConfig.getString("block-extra-data")).toOption.map(ByteString(_)) - override val range = Try(daoConfig.getInt("block-extra-data-range")).toOption.getOrElse(0) - override val refundContract = Try(daoConfig.getString("refund-contract-address")).toOption.map(Address(_)) - override val drainList = Try(daoConfig.getStringList("drain-list").asScala.toList).toOption.getOrElse(List.empty).map(Address(_)) - } - } - def apply(etcClientConfig: TypesafeConfig): BlockchainConfig = { val blockchainConfig = etcClientConfig.getConfig("blockchain") @@ -298,7 +322,7 @@ object BlockchainConfig { override val customGenesisFileOpt: Option[String] = Try(blockchainConfig.getString("custom-genesis-file")).toOption - override val daoForkConfig = Try(blockchainConfig.getConfig("dao")).toOption.map(createDaoForkConfig) + override val daoForkConfig = Try(blockchainConfig.getConfig("dao")).toOption.map(DaoForkConfig(_)) override val accountStartNonce: UInt256 = UInt256(BigInt(blockchainConfig.getString("account-start-nonce"))) override val chainId: Byte = { diff --git a/src/main/scala/io/iohk/ethereum/validators/BlockHeaderValidator.scala b/src/main/scala/io/iohk/ethereum/validators/BlockHeaderValidator.scala index 5ad4a2c898..62f46308e0 100644 --- a/src/main/scala/io/iohk/ethereum/validators/BlockHeaderValidator.scala +++ b/src/main/scala/io/iohk/ethereum/validators/BlockHeaderValidator.scala @@ -2,25 +2,27 @@ package io.iohk.ethereum.validators import akka.util.ByteString import io.iohk.ethereum.crypto.{kec256, kec512} -import io.iohk.ethereum.daoFork.DaoForkConfig import io.iohk.ethereum.domain.{BlockHeader, Blockchain, DifficultyCalculator} -import io.iohk.ethereum.utils.BlockchainConfig +import io.iohk.ethereum.utils.{BlockchainConfig, DaoForkConfig} trait BlockHeaderValidator { - def validate(blockHeader: BlockHeader, blockchain: Blockchain): Either[BlockHeaderError, BlockHeader] - } -class BlockHeaderValidatorImpl(blockchainConfig: BlockchainConfig) extends BlockHeaderValidator { - +object BlockHeaderValidatorImpl { val MaxExtraDataSize: Int = 32 val GasLimitBoundDivisor: Int = 1024 val MinGasLimit: BigInt = 5000 //Although the paper states this value is 125000, on the different clients 5000 is used - val difficulty = new DifficultyCalculator(blockchainConfig) val MaxGasLimit = Long.MaxValue // max gasLimit is equal 2^63-1 according to EIP106 +} + +class BlockHeaderValidatorImpl(blockchainConfig: BlockchainConfig) extends BlockHeaderValidator { + + import BlockHeaderValidatorImpl._ import BlockHeaderError._ + val difficulty = new DifficultyCalculator(blockchainConfig) + /** This method allows validate a BlockHeader (stated on * section 4.4.4 of http://paper.gavwood.com/). * @@ -73,10 +75,7 @@ class BlockHeaderValidatorImpl(blockchainConfig: BlockchainConfig) extends Block if (blockHeader.extraData.length <= MaxExtraDataSize) { import blockchainConfig._ - - if(daoForkConfig.isEmpty) Right(blockHeader) - else validateDaoForkExtraData(blockHeader, daoForkConfig.get) - + daoForkConfig.map(c => validateDaoForkExtraData(blockHeader, c)).getOrElse(Right(blockHeader)) } else { Left(HeaderExtraDataError) } diff --git a/src/test/scala/io/iohk/ethereum/jsonrpc/PersonalServiceSpec.scala b/src/test/scala/io/iohk/ethereum/jsonrpc/PersonalServiceSpec.scala index 68fa906621..09b281cc8b 100644 --- a/src/test/scala/io/iohk/ethereum/jsonrpc/PersonalServiceSpec.scala +++ b/src/test/scala/io/iohk/ethereum/jsonrpc/PersonalServiceSpec.scala @@ -4,7 +4,6 @@ import akka.actor.ActorSystem import akka.testkit.TestProbe import akka.util.ByteString import io.iohk.ethereum.crypto.ECDSASignature -import io.iohk.ethereum.daoFork.DaoForkConfig import io.iohk.ethereum.db.storage.AppStateStorage import io.iohk.ethereum.domain.{UInt256, _} import io.iohk.ethereum.jsonrpc.JsonRpcErrors._ @@ -12,7 +11,7 @@ import io.iohk.ethereum.jsonrpc.PersonalService._ import io.iohk.ethereum.keystore.KeyStore.{DecryptionFailed, IOError} import io.iohk.ethereum.keystore.{KeyStore, Wallet} import io.iohk.ethereum.transactions.PendingTransactionsManager.{AddOrOverrideTransaction, GetPendingTransactions, PendingTransaction, PendingTransactionsResponse} -import io.iohk.ethereum.utils.{BlockchainConfig, MonetaryPolicyConfig, TxPoolConfig} +import io.iohk.ethereum.utils.{BlockchainConfig, DaoForkConfig, MonetaryPolicyConfig, TxPoolConfig} import io.iohk.ethereum.{Fixtures, NormalPatience, Timeouts} import org.scalamock.matchers.Matcher import org.scalamock.scalatest.MockFactory diff --git a/src/test/scala/io/iohk/ethereum/ledger/LedgerSpec.scala b/src/test/scala/io/iohk/ethereum/ledger/LedgerSpec.scala index 7c54436da7..934443c486 100644 --- a/src/test/scala/io/iohk/ethereum/ledger/LedgerSpec.scala +++ b/src/test/scala/io/iohk/ethereum/ledger/LedgerSpec.scala @@ -6,12 +6,11 @@ import akka.util.ByteString.{empty => bEmpty} import io.iohk.ethereum.Mocks.MockVM import io.iohk.ethereum.blockchain.sync.EphemBlockchainTestSetup import io.iohk.ethereum.crypto._ -import io.iohk.ethereum.daoFork.DaoForkConfig import io.iohk.ethereum.domain._ import io.iohk.ethereum.ledger.BlockExecutionError.{ValidationAfterExecError, ValidationBeforeExecError} import io.iohk.ethereum.{Fixtures, Mocks, rlp} import io.iohk.ethereum.rlp.RLPList -import io.iohk.ethereum.utils.{BlockchainConfig, Config, MonetaryPolicyConfig} +import io.iohk.ethereum.utils.{BlockchainConfig, Config, DaoForkConfig, MonetaryPolicyConfig} import io.iohk.ethereum.ledger.Ledger.{BlockResult, PC, PR} import io.iohk.ethereum.network.p2p.messages.PV62.BlockBody import io.iohk.ethereum.nodebuilder.SecureRandomBuilder diff --git a/src/test/scala/io/iohk/ethereum/mining/BlockGeneratorSpec.scala b/src/test/scala/io/iohk/ethereum/mining/BlockGeneratorSpec.scala index 0fe2d10164..fc50dedcf9 100644 --- a/src/test/scala/io/iohk/ethereum/mining/BlockGeneratorSpec.scala +++ b/src/test/scala/io/iohk/ethereum/mining/BlockGeneratorSpec.scala @@ -8,14 +8,13 @@ import io.iohk.ethereum.blockchain.data.GenesisDataLoader import io.iohk.ethereum.blockchain.sync.EphemBlockchainTestSetup import io.iohk.ethereum.domain._ import io.iohk.ethereum.ledger.{BlockPreparationError, LedgerImpl} -import io.iohk.ethereum.utils.{BlockchainConfig, Logger, MiningConfig, MonetaryPolicyConfig} +import io.iohk.ethereum.utils._ import io.iohk.ethereum.validators._ import io.iohk.ethereum.vm.VM import org.scalatest.prop.PropertyChecks import org.scalatest.{FlatSpec, Matchers} import org.spongycastle.util.encoders.Hex import io.iohk.ethereum.crypto._ -import io.iohk.ethereum.daoFork.DaoForkConfig import io.iohk.ethereum.domain.SignedTransaction.FirstByteOfAddress import io.iohk.ethereum.utils.Config.DbConfig import org.spongycastle.crypto.AsymmetricCipherKeyPair diff --git a/src/test/scala/io/iohk/ethereum/network/handshaker/EtcHandshakerSpec.scala b/src/test/scala/io/iohk/ethereum/network/handshaker/EtcHandshakerSpec.scala index b10fd0c173..c2d157bf9d 100644 --- a/src/test/scala/io/iohk/ethereum/network/handshaker/EtcHandshakerSpec.scala +++ b/src/test/scala/io/iohk/ethereum/network/handshaker/EtcHandshakerSpec.scala @@ -5,10 +5,6 @@ import akka.util.ByteString import io.iohk.ethereum.Fixtures import io.iohk.ethereum.blockchain.sync.EphemBlockchainTestSetup import io.iohk.ethereum.crypto.generateKeyPair -import io.iohk.ethereum.daoFork.DaoForkConfig -import io.iohk.ethereum.db.components.Storages.PruningModeComponent -import io.iohk.ethereum.db.components.{SharedEphemDataSources, Storages} -import io.iohk.ethereum.db.storage.pruning.{ArchivePruning, PruningMode} import io.iohk.ethereum.db.storage.AppStateStorage import io.iohk.ethereum.domain._ import io.iohk.ethereum.network.ForkResolver diff --git a/src/test/scala/io/iohk/ethereum/validators/BlockHeaderValidatorSpec.scala b/src/test/scala/io/iohk/ethereum/validators/BlockHeaderValidatorSpec.scala index a09824dc5c..88798c9532 100644 --- a/src/test/scala/io/iohk/ethereum/validators/BlockHeaderValidatorSpec.scala +++ b/src/test/scala/io/iohk/ethereum/validators/BlockHeaderValidatorSpec.scala @@ -3,15 +3,17 @@ package io.iohk.ethereum.validators import akka.util.ByteString import io.iohk.ethereum.{Fixtures, ObjectGenerators} import io.iohk.ethereum.blockchain.sync.EphemBlockchainTestSetup -import io.iohk.ethereum.daoFork.DaoForkConfig import io.iohk.ethereum.domain.{UInt256, _} -import io.iohk.ethereum.utils.{BlockchainConfig, Config, MonetaryPolicyConfig} +import io.iohk.ethereum.utils.{BlockchainConfig, DaoForkConfig, MonetaryPolicyConfig} import io.iohk.ethereum.validators.BlockHeaderError._ import org.scalatest.prop.PropertyChecks import org.scalatest.{FlatSpec, Matchers} import org.spongycastle.util.encoders.Hex +import io.iohk.ethereum.validators.BlockHeaderValidatorImpl._ class BlockHeaderValidatorSpec extends FlatSpec with Matchers with PropertyChecks with ObjectGenerators { + + val ExtraDataSizeLimit = 20 //BlockHeader member's lengths obtained from Yellow paper @@ -32,8 +34,8 @@ class BlockHeaderValidatorSpec extends FlatSpec with Matchers with PropertyCheck it should "return a failure if created based on invalid extra data" in { forAll(randomSizeByteStringGen( - blockHeaderValidator.MaxExtraDataSize + 1, - blockHeaderValidator.MaxExtraDataSize + ExtraDataSizeLimit) + MaxExtraDataSize + 1, + MaxExtraDataSize + ExtraDataSizeLimit) ) { wrongExtraData => val invalidBlockHeader = validBlockHeader.copy(extraData = wrongExtraData) assert(blockHeaderValidator.validate(invalidBlockHeader, validBlockParent) == Left(HeaderExtraDataError)) @@ -96,9 +98,9 @@ class BlockHeaderValidatorSpec extends FlatSpec with Matchers with PropertyCheck } it should "return a failure if created based on invalid gas limit" in { - val LowerGasLimit = blockHeaderValidator.MinGasLimit.max( - validBlockParent.gasLimit - validBlockParent.gasLimit / blockHeaderValidator.GasLimitBoundDivisor + 1) - val UpperGasLimit = validBlockParent.gasLimit + validBlockParent.gasLimit / blockHeaderValidator.GasLimitBoundDivisor - 1 + val LowerGasLimit = MinGasLimit.max( + validBlockParent.gasLimit - validBlockParent.gasLimit / GasLimitBoundDivisor + 1) + val UpperGasLimit = validBlockParent.gasLimit + validBlockParent.gasLimit / GasLimitBoundDivisor - 1 forAll(bigIntGen) { gasLimit => val blockHeader = validBlockHeader.copy(gasLimit = gasLimit) diff --git a/src/universal/conf/blockchain.conf b/src/universal/conf/blockchain.conf index 35dbf81a67..1ad198e40f 100644 --- a/src/universal/conf/blockchain.conf +++ b/src/universal/conf/blockchain.conf @@ -33,17 +33,6 @@ mantis { # Doc: https://github.com/ethereumproject/ECIPs/blob/master/ECIPs/ECIP-1010.md # difficulty-bomb-continue-block-number = "5000000" - # specify if this client is pro or against DAO hard fork - # if true it will accept ETH version of chain if false it will accept ETC - # pro-dao-fork = false - - # DAO fork block number (Ethereum HF/Classic split) - # https://blog.ethereum.org/2016/07/20/hard-fork-completed/ - # dao-fork-block-number = "1920000" - - # The hash of the accepted DAO fork block - # dao-fork-block-hash = "94365e3a8c0b35089c1d1195081fe7489b528a84b22199c916180db8b28ade7f" - # DAO fork configuration (Ethereum HF/Classic split) # https://blog.ethereum.org/2016/07/20/hard-fork-completed/ # dao { From c751eca051553c53e03ba7f55e689b36672a18ce Mon Sep 17 00:00:00 2001 From: Alan Verbner Date: Wed, 20 Sep 2017 14:48:54 -0300 Subject: [PATCH 08/10] [EC-236] Ethereum tests integration --- .../ets/blockchain/BlockChainTestConfig.scala | 138 +++++++++++++++++- .../ets/blockchain/BlockchainSuite.scala | 4 +- .../ets/blockchain/ScenarioSetup.scala | 1 + 3 files changed, 137 insertions(+), 6 deletions(-) diff --git a/src/ets/scala/io/iohk/ethereum/ets/blockchain/BlockChainTestConfig.scala b/src/ets/scala/io/iohk/ethereum/ets/blockchain/BlockChainTestConfig.scala index 3b8620be48..a095880812 100644 --- a/src/ets/scala/io/iohk/ethereum/ets/blockchain/BlockChainTestConfig.scala +++ b/src/ets/scala/io/iohk/ethereum/ets/blockchain/BlockChainTestConfig.scala @@ -1,8 +1,9 @@ package io.iohk.ethereum.ets.blockchain import akka.util.ByteString -import io.iohk.ethereum.domain.UInt256 -import io.iohk.ethereum.utils.{BlockchainConfig, MonetaryPolicyConfig} +import io.iohk.ethereum.domain.{Address, UInt256} +import io.iohk.ethereum.utils.{BlockchainConfig, DaoForkConfig, MonetaryPolicyConfig} +import org.spongycastle.util.encoders.Hex trait BlockChainTestConfig extends BlockchainConfig { @@ -19,8 +20,7 @@ trait BlockChainTestConfig extends BlockchainConfig { override val chainId: Byte = 0x3d.toByte override val customGenesisFileOpt: Option[String] = Some("test-genesis.json") override val monetaryPolicyConfig: MonetaryPolicyConfig = MonetaryPolicyConfig(5000000, 0.2, BigInt("5000000000000000000")) - override val daoForkBlockNumber: BigInt = Long.MaxValue - override val daoForkBlockHash: ByteString = ByteString("unused") + override val daoForkConfig: Option[DaoForkConfig] = None override val accountStartNonce: UInt256 = UInt256.Zero } @@ -45,4 +45,134 @@ class HomesteadToEIP150At5 extends BlockChainTestConfig { override val eip150BlockNumber = 5 override val homesteadBlockNumber = 0 } +class HomesteadToDaoAt5 extends BlockChainTestConfig { + override val homesteadBlockNumber = 0 + override val daoForkConfig: Option[DaoForkConfig] = Some( + new DaoForkConfig { + override val forkBlockNumber = 5 + override val forkBlockHash = ByteString(Hex.decode("f6d7ef1087b5fd94eada533cf8a563f78c3944a2f8ae850e80935d20dc3b7315")) + override val blockExtraData = Some(ByteString(Hex.decode("64616f2d686172642d666f726b"))) + override val range = 10 + override val refundContract = Some(Address("bf4ed7b27f1d666546e30d74d50d173d20bca754")) + override val drainList = Seq( + Address("d4fe7bc31cedb7bfb8a345f31e668033056b2728"), + Address("b3fb0e5aba0e20e5c49d252dfd30e102b171a425"), + Address("2c19c7f9ae8b751e37aeb2d93a699722395ae18f"), + Address("ecd135fa4f61a655311e86238c92adcd779555d2"), + Address("1975bd06d486162d5dc297798dfc41edd5d160a7"), + Address("a3acf3a1e16b1d7c315e23510fdd7847b48234f6"), + Address("319f70bab6845585f412ec7724b744fec6095c85"), + Address("06706dd3f2c9abf0a21ddcc6941d9b86f0596936"), + Address("5c8536898fbb74fc7445814902fd08422eac56d0"), + Address("6966ab0d485353095148a2155858910e0965b6f9"), + Address("779543a0491a837ca36ce8c635d6154e3c4911a6"), + Address("2a5ed960395e2a49b1c758cef4aa15213cfd874c"), + Address("5c6e67ccd5849c0d29219c4f95f1a7a93b3f5dc5"), + Address("9c50426be05db97f5d64fc54bf89eff947f0a321"), + Address("200450f06520bdd6c527622a273333384d870efb"), + Address("be8539bfe837b67d1282b2b1d61c3f723966f049"), + Address("6b0c4d41ba9ab8d8cfb5d379c69a612f2ced8ecb"), + Address("f1385fb24aad0cd7432824085e42aff90886fef5"), + Address("d1ac8b1ef1b69ff51d1d401a476e7e612414f091"), + Address("8163e7fb499e90f8544ea62bbf80d21cd26d9efd"), + Address("51e0ddd9998364a2eb38588679f0d2c42653e4a6"), + Address("627a0a960c079c21c34f7612d5d230e01b4ad4c7"), + Address("f0b1aa0eb660754448a7937c022e30aa692fe0c5"), + Address("24c4d950dfd4dd1902bbed3508144a54542bba94"), + Address("9f27daea7aca0aa0446220b98d028715e3bc803d"), + Address("a5dc5acd6a7968a4554d89d65e59b7fd3bff0f90"), + Address("d9aef3a1e38a39c16b31d1ace71bca8ef58d315b"), + Address("63ed5a272de2f6d968408b4acb9024f4cc208ebf"), + Address("6f6704e5a10332af6672e50b3d9754dc460dfa4d"), + Address("77ca7b50b6cd7e2f3fa008e24ab793fd56cb15f6"), + Address("492ea3bb0f3315521c31f273e565b868fc090f17"), + Address("0ff30d6de14a8224aa97b78aea5388d1c51c1f00"), + Address("9ea779f907f0b315b364b0cfc39a0fde5b02a416"), + Address("ceaeb481747ca6c540a000c1f3641f8cef161fa7"), + Address("cc34673c6c40e791051898567a1222daf90be287"), + Address("579a80d909f346fbfb1189493f521d7f48d52238"), + Address("e308bd1ac5fda103967359b2712dd89deffb7973"), + Address("4cb31628079fb14e4bc3cd5e30c2f7489b00960c"), + Address("ac1ecab32727358dba8962a0f3b261731aad9723"), + Address("4fd6ace747f06ece9c49699c7cabc62d02211f75"), + Address("440c59b325d2997a134c2c7c60a8c61611212bad"), + Address("4486a3d68fac6967006d7a517b889fd3f98c102b"), + Address("9c15b54878ba618f494b38f0ae7443db6af648ba"), + Address("27b137a85656544b1ccb5a0f2e561a5703c6a68f"), + Address("21c7fdb9ed8d291d79ffd82eb2c4356ec0d81241"), + Address("23b75c2f6791eef49c69684db4c6c1f93bf49a50"), + Address("1ca6abd14d30affe533b24d7a21bff4c2d5e1f3b"), + Address("b9637156d330c0d605a791f1c31ba5890582fe1c"), + Address("6131c42fa982e56929107413a9d526fd99405560"), + Address("1591fc0f688c81fbeb17f5426a162a7024d430c2"), + Address("542a9515200d14b68e934e9830d91645a980dd7a"), + Address("c4bbd073882dd2add2424cf47d35213405b01324"), + Address("782495b7b3355efb2833d56ecb34dc22ad7dfcc4"), + Address("58b95c9a9d5d26825e70a82b6adb139d3fd829eb"), + Address("3ba4d81db016dc2890c81f3acec2454bff5aada5"), + Address("b52042c8ca3f8aa246fa79c3feaa3d959347c0ab"), + Address("e4ae1efdfc53b73893af49113d8694a057b9c0d1"), + Address("3c02a7bc0391e86d91b7d144e61c2c01a25a79c5"), + Address("0737a6b837f97f46ebade41b9bc3e1c509c85c53"), + Address("97f43a37f595ab5dd318fb46e7a155eae057317a"), + Address("52c5317c848ba20c7504cb2c8052abd1fde29d03"), + Address("4863226780fe7c0356454236d3b1c8792785748d"), + Address("5d2b2e6fcbe3b11d26b525e085ff818dae332479"), + Address("5f9f3392e9f62f63b8eac0beb55541fc8627f42c"), + Address("057b56736d32b86616a10f619859c6cd6f59092a"), + Address("9aa008f65de0b923a2a4f02012ad034a5e2e2192"), + Address("304a554a310c7e546dfe434669c62820b7d83490"), + Address("914d1b8b43e92723e64fd0a06f5bdb8dd9b10c79"), + Address("4deb0033bb26bc534b197e61d19e0733e5679784"), + Address("07f5c1e1bc2c93e0402f23341973a0e043f7bf8a"), + Address("35a051a0010aba705c9008d7a7eff6fb88f6ea7b"), + Address("4fa802324e929786dbda3b8820dc7834e9134a2a"), + Address("9da397b9e80755301a3b32173283a91c0ef6c87e"), + Address("8d9edb3054ce5c5774a420ac37ebae0ac02343c6"), + Address("0101f3be8ebb4bbd39a2e3b9a3639d4259832fd9"), + Address("5dc28b15dffed94048d73806ce4b7a4612a1d48f"), + Address("bcf899e6c7d9d5a215ab1e3444c86806fa854c76"), + Address("12e626b0eebfe86a56d633b9864e389b45dcb260"), + Address("a2f1ccba9395d7fcb155bba8bc92db9bafaeade7"), + Address("ec8e57756626fdc07c63ad2eafbd28d08e7b0ca5"), + Address("d164b088bd9108b60d0ca3751da4bceb207b0782"), + Address("6231b6d0d5e77fe001c2a460bd9584fee60d409b"), + Address("1cba23d343a983e9b5cfd19496b9a9701ada385f"), + Address("a82f360a8d3455c5c41366975bde739c37bfeb8a"), + Address("9fcd2deaff372a39cc679d5c5e4de7bafb0b1339"), + Address("005f5cee7a43331d5a3d3eec71305925a62f34b6"), + Address("0e0da70933f4c7849fc0d203f5d1d43b9ae4532d"), + Address("d131637d5275fd1a68a3200f4ad25c71a2a9522e"), + Address("bc07118b9ac290e4622f5e77a0853539789effbe"), + Address("47e7aa56d6bdf3f36be34619660de61275420af8"), + Address("acd87e28b0c9d1254e868b81cba4cc20d9a32225"), + Address("adf80daec7ba8dcf15392f1ac611fff65d94f880"), + Address("5524c55fb03cf21f549444ccbecb664d0acad706"), + Address("40b803a9abce16f50f36a77ba41180eb90023925"), + Address("fe24cdd8648121a43a7c86d289be4dd2951ed49f"), + Address("17802f43a0137c506ba92291391a8a8f207f487d"), + Address("253488078a4edf4d6f42f113d1e62836a942cf1a"), + Address("86af3e9626fce1957c82e88cbf04ddf3a2ed7915"), + Address("b136707642a4ea12fb4bae820f03d2562ebff487"), + Address("dbe9b615a3ae8709af8b93336ce9b477e4ac0940"), + Address("f14c14075d6c4ed84b86798af0956deef67365b5"), + Address("ca544e5c4687d109611d0f8f928b53a25af72448"), + Address("aeeb8ff27288bdabc0fa5ebb731b6f409507516c"), + Address("cbb9d3703e651b0d496cdefb8b92c25aeb2171f7"), + Address("6d87578288b6cb5549d5076a207456a1f6a63dc0"), + Address("b2c6f0dfbb716ac562e2d85d6cb2f8d5ee87603e"), + Address("accc230e8a6e5be9160b8cdf2864dd2a001c28b6"), + Address("2b3455ec7fedf16e646268bf88846bd7a2319bb2"), + Address("4613f3bca5c44ea06337a9e439fbc6d42e501d0a"), + Address("d343b217de44030afaa275f54d31a9317c7f441e"), + Address("84ef4b2357079cd7a7c69fd7a37cd0609a679106"), + Address("da2fef9e4a3230988ff17df2165440f37e8b1708"), + Address("f4c64518ea10f995918a454158c6b61407ea345c"), + Address("7602b46df5390e432ef1c307d4f2c9ff6d65cc97"), + Address("bb9bc244d798123fde783fcc1c72d3bb8c189413"), + Address("807640a13483f8ac783c557fcdf27be11ea4ac7a") + ) + } + ) +} diff --git a/src/ets/scala/io/iohk/ethereum/ets/blockchain/BlockchainSuite.scala b/src/ets/scala/io/iohk/ethereum/ets/blockchain/BlockchainSuite.scala index f980e45037..9ff857d90d 100644 --- a/src/ets/scala/io/iohk/ethereum/ets/blockchain/BlockchainSuite.scala +++ b/src/ets/scala/io/iohk/ethereum/ets/blockchain/BlockchainSuite.scala @@ -9,8 +9,8 @@ import org.scalatest._ class BlockchainSuite extends FreeSpec with Matchers with Logger { - val unsupportedNetworks = Set("Byzantium","Constantinople", "EIP158", "EIP158ToByzantiumAt5", "HomesteadToDaoAt5") - val supportedNetworks = Set("EIP150", "Frontier", "FrontierToHomesteadAt5", "Homestead", "HomesteadToEIP150At5") + val unsupportedNetworks = Set("Byzantium","Constantinople", "EIP158", "EIP158ToByzantiumAt5") + val supportedNetworks = Set("EIP150", "Frontier", "FrontierToHomesteadAt5", "Homestead", "HomesteadToEIP150At5", "HomesteadToDaoAt5") //Map of ignored tests, empty set of ignored names means cancellation of whole group val ignoredTests: Map[String, Set[String]] = Map( diff --git a/src/ets/scala/io/iohk/ethereum/ets/blockchain/ScenarioSetup.scala b/src/ets/scala/io/iohk/ethereum/ets/blockchain/ScenarioSetup.scala index dc4a9748b6..e8dcf7186d 100644 --- a/src/ets/scala/io/iohk/ethereum/ets/blockchain/ScenarioSetup.scala +++ b/src/ets/scala/io/iohk/ethereum/ets/blockchain/ScenarioSetup.scala @@ -69,6 +69,7 @@ abstract class ScenarioSetup(scenario: BlockchainScenario) case "Homestead" => new HomesteadConfig case "FrontierToHomesteadAt5" => new FrontierToHomesteadAt5 case "HomesteadToEIP150At5" => new HomesteadToEIP150At5 + case "HomesteadToDaoAt5" => new HomesteadToDaoAt5 // Some default config, test will fail or be canceled case _ => new FrontierConfig From 54875bcd34fac21f8fe4985abac8d9255a1a3779 Mon Sep 17 00:00:00 2001 From: Alan Verbner Date: Thu, 21 Sep 2017 08:26:01 -0300 Subject: [PATCH 09/10] [EC-236] Fix remove isDefined call --- .../scala/io/iohk/ethereum/txExecTest/util/DumpChainApp.scala | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/it/scala/io/iohk/ethereum/txExecTest/util/DumpChainApp.scala b/src/it/scala/io/iohk/ethereum/txExecTest/util/DumpChainApp.scala index ead7fd265e..d8e65392a3 100644 --- a/src/it/scala/io/iohk/ethereum/txExecTest/util/DumpChainApp.scala +++ b/src/it/scala/io/iohk/ethereum/txExecTest/util/DumpChainApp.scala @@ -69,9 +69,7 @@ object DumpChainApp extends App with NodeKeyBuilder with SecureRandomBuilder wit lazy val nodeStatusHolder = Agent(nodeStatus) - lazy val forkResolverOpt = - if (blockchainConfig.daoForkConfig.isEmpty) None - else Some(new ForkResolver.EtcForkResolver(blockchainConfig.daoForkConfig.get)) + lazy val forkResolverOpt = blockchainConfig.daoForkConfig.map(new ForkResolver.EtcForkResolver(_)) private val handshakerConfiguration: EtcHandshakerConfiguration = new EtcHandshakerConfiguration { From d5fb4d70bf28d2120a88638f81ab3adba4bae062 Mon Sep 17 00:00:00 2001 From: Alan Verbner Date: Fri, 22 Sep 2017 09:02:59 -0300 Subject: [PATCH 10/10] [EC-236] Fix ets compilation issue --- .../io/iohk/ethereum/ets/blockchain/BlockchainTestConfig.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ets/scala/io/iohk/ethereum/ets/blockchain/BlockchainTestConfig.scala b/src/ets/scala/io/iohk/ethereum/ets/blockchain/BlockchainTestConfig.scala index bcb14d5911..a3a5649889 100644 --- a/src/ets/scala/io/iohk/ethereum/ets/blockchain/BlockchainTestConfig.scala +++ b/src/ets/scala/io/iohk/ethereum/ets/blockchain/BlockchainTestConfig.scala @@ -45,7 +45,7 @@ class HomesteadToEIP150At5 extends BlockchainTestConfig { override val eip150BlockNumber = 5 override val homesteadBlockNumber = 0 } -class HomesteadToDaoAt5 extends BlockChainTestConfig { +class HomesteadToDaoAt5 extends BlockchainTestConfig { override val homesteadBlockNumber = 0 override val daoForkConfig: Option[DaoForkConfig] = Some( new DaoForkConfig {