Skip to content

Commit 1a430fd

Browse files
author
Igor Grahovac
committed
ETCM-697: Fixed state root calculation when block mining in ets. Added storing of contract codes and storage data
1 parent 04413c7 commit 1a430fd

File tree

5 files changed

+132
-60
lines changed

5 files changed

+132
-60
lines changed

src/main/resources/conf/testmode.conf

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,15 @@ mantis {
1414

1515
blockchains {
1616
network = "test"
17+
18+
test {
19+
chain-id = 1
20+
21+
istanbul-block-number = 0
22+
}
1723
}
1824

1925
network.rpc {
2026
apis = "eth,web3,net,personal,mantis,test,iele,debug,qa,checkpointing"
2127
}
22-
2328
}

src/main/scala/io/iohk/ethereum/jsonrpc/TestJsonMethodsImplicits.scala

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -54,26 +54,26 @@ object TestJsonMethodsImplicits extends JsonMethodsImplicits {
5454

5555
private def extractBlockchainParams(blockchainParamsJson: JValue): Either[JsonRpcError, BlockchainParams] = {
5656
for {
57-
eIP150ForkBlock <- extractQuantity(blockchainParamsJson \ "EIP150ForkBlock")
58-
eIP158ForkBlock <- extractQuantity(blockchainParamsJson \ "EIP158ForkBlock")
57+
eIP150ForkBlock <- optionalQuantity(blockchainParamsJson \ "EIP150ForkBlock")
58+
eIP158ForkBlock <- optionalQuantity(blockchainParamsJson \ "EIP158ForkBlock")
5959
accountStartNonce <- optionalQuantity(blockchainParamsJson \ "accountStartNonce")
6060
allowFutureBlocks = (blockchainParamsJson \ "allowFutureBlocks").extractOrElse(true)
6161
blockReward <- optionalQuantity(blockchainParamsJson \ "blockReward")
62-
byzantiumForkBlock <- extractQuantity(blockchainParamsJson \ "byzantiumForkBlock")
63-
homesteadForkBlock <- extractQuantity(blockchainParamsJson \ "homesteadForkBlock")
64-
constantinopleForkBlock <- extractQuantity(blockchainParamsJson \ "constantinopleForkBlock")
65-
istanbulForkBlock <- extractQuantity(blockchainParamsJson \ "istanbulForkBlock")
62+
byzantiumForkBlock <- optionalQuantity(blockchainParamsJson \ "byzantiumForkBlock")
63+
homesteadForkBlock <- optionalQuantity(blockchainParamsJson \ "homesteadForkBlock")
64+
constantinopleForkBlock <- optionalQuantity(blockchainParamsJson \ "constantinopleForkBlock")
65+
istanbulForkBlock <- optionalQuantity(blockchainParamsJson \ "istanbulForkBlock")
6666
} yield BlockchainParams(
67-
eIP150ForkBlock,
68-
eIP158ForkBlock,
67+
eIP150ForkBlock.getOrElse(0),
68+
eIP158ForkBlock.getOrElse(0),
6969
accountStartNonce.getOrElse(0),
7070
allowFutureBlocks,
7171
blockReward.getOrElse(0),
72-
byzantiumForkBlock,
73-
homesteadForkBlock,
72+
byzantiumForkBlock.getOrElse(0),
73+
homesteadForkBlock.getOrElse(0),
7474
0,
75-
constantinopleForkBlock,
76-
istanbulForkBlock
75+
constantinopleForkBlock.getOrElse(0),
76+
istanbulForkBlock.getOrElse(0)
7777
)
7878
}
7979

src/main/scala/io/iohk/ethereum/jsonrpc/TestService.scala

Lines changed: 66 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,12 @@ import io.iohk.ethereum.ledger._
1212
import io.iohk.ethereum.testmode.{TestLedgerWrapper, TestmodeConsensus}
1313
import io.iohk.ethereum.transactions.PendingTransactionsManager
1414
import io.iohk.ethereum.transactions.PendingTransactionsManager.PendingTransactionsResponse
15-
import io.iohk.ethereum.utils.{ByteStringUtils, Logger}
15+
import io.iohk.ethereum.utils.{BlockchainConfig, ByteStringUtils, Logger}
1616
import monix.eval.Task
1717
import monix.execution.Scheduler
1818
import org.bouncycastle.util.encoders.Hex
1919
import io.iohk.ethereum.jsonrpc.JsonMethodsImplicits._
20+
import io.iohk.ethereum.ledger.InMemoryWorldStateProxy.persistState
2021

2122
import scala.concurrent.duration._
2223
import scala.util.{Failure, Success, Try}
@@ -151,6 +152,9 @@ class TestService(
151152
val genesisDataLoader = new GenesisDataLoader(blockchain, newBlockchainConfig)
152153
genesisDataLoader.loadGenesisData(genesisData)
153154

155+
//save account codes to world state
156+
storeGenesisAccountCodes(newBlockchainConfig, genesisData.alloc)
157+
storeGenesisAccountStorageData(newBlockchainConfig, genesisData.alloc)
154158
// update test ledger with new config
155159
testLedgerWrapper.blockchainConfig = newBlockchainConfig
156160

@@ -160,6 +164,43 @@ class TestService(
160164
Task.now(Right(SetChainParamsResponse()))
161165
}
162166

167+
private def storeGenesisAccountCodes(config: BlockchainConfig, accounts: Map[String, GenesisAccount]): Unit = {
168+
val genesisBlock = blockchain.getBlockByNumber(0).get
169+
val world =
170+
blockchain.getWorldStateProxy(0, UInt256.Zero, genesisBlock.header.stateRoot, false, config.ethCompatibleStorage)
171+
172+
val accountsWithCodes = accounts
173+
.filter(pair => pair._2.code.isDefined)
174+
175+
val worldToPersist = accountsWithCodes.foldLeft(world)((world, addressAccountPair) => {
176+
world.saveCode(Address(addressAccountPair._1), addressAccountPair._2.code.get)
177+
})
178+
179+
InMemoryWorldStateProxy.persistState(worldToPersist)
180+
}
181+
182+
private def storeGenesisAccountStorageData(config: BlockchainConfig, accounts: Map[String, GenesisAccount]): Unit = {
183+
val genesisBlock = blockchain.getBlockByNumber(0).get
184+
val world =
185+
blockchain.getWorldStateProxy(0, UInt256.Zero, genesisBlock.header.stateRoot, false, config.ethCompatibleStorage)
186+
187+
val accountsWithStorageData = accounts
188+
.filter(pair => pair._2.storage.isDefined && pair._2.storage.get.nonEmpty)
189+
190+
val worldToPersist = accountsWithStorageData.foldLeft(world)((world, addressAccountPair) => {
191+
val address = Address(addressAccountPair._1)
192+
val emptyStorage = world.getStorage(address)
193+
val updatedStorage = addressAccountPair._2.storage.get.foldLeft(emptyStorage) { case (storage, (key, value)) =>
194+
storage.store(key, value)
195+
}
196+
val updatedWorld = world.saveStorage(Address(addressAccountPair._1), updatedStorage)
197+
updatedWorld.contractStorages.values.foreach(cs => cs.inner.nodeStorage.persist())
198+
updatedWorld
199+
})
200+
201+
InMemoryWorldStateProxy.persistState(worldToPersist)
202+
}
203+
163204
def mineBlocks(request: MineBlocksRequest): ServiceResponse[MineBlocksResponse] = {
164205
def mineBlock(): Task[Unit] = {
165206
getBlockForMining(blockchain.getBestBlock().get)
@@ -274,6 +315,29 @@ class TestService(
274315
}
275316

276317
def storageRangeAt(request: StorageRangeRequest): ServiceResponse[StorageRangeResponse] = {
277-
Task.now(Right(StorageRangeResponse(complete = true, storage = Map())))
318+
319+
val blockOpt = request.parameters.blockHashOrNumber
320+
.fold(number => blockchain.getBlockByNumber(number), hash => blockchain.getBlockByHash(hash))
321+
322+
if (blockOpt.isEmpty) {
323+
Task.now(Right(AccountsInRangeResponse(Map(), ByteString(0))))
324+
}
325+
326+
val accountOpt = blockchain.getAccount(Address(request.parameters.address), blockOpt.get.header.number)
327+
328+
if (accountOpt.isEmpty) {
329+
Task.now(Right(AccountsInRangeResponse(Map(), ByteString(0))))
330+
}
331+
332+
val storage = blockchain.getAccountStorageAt(accountOpt.get.storageRoot, request.parameters.begin, true)
333+
334+
Task.now(
335+
Right(
336+
StorageRangeResponse(
337+
complete = true,
338+
storage = Map(request.parameters.address -> StorageEntry(ByteString(""), ByteString("")))
339+
)
340+
)
341+
)
278342
}
279343
}

src/main/scala/io/iohk/ethereum/ledger/BlockPreparator.scala

Lines changed: 46 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import io.iohk.ethereum.domain._
77
import io.iohk.ethereum.ledger.BlockExecutionError.{StateBeforeFailure, TxsExecutionError}
88
import io.iohk.ethereum.ledger.Ledger._
99
import io.iohk.ethereum.ledger.BlockPreparator._
10-
import io.iohk.ethereum.utils.{BlockchainConfig, Logger}
10+
import io.iohk.ethereum.utils.{BlockchainConfig, Config, Logger}
1111
import io.iohk.ethereum.vm.{PC => _, _}
1212

1313
import scala.annotation.tailrec
@@ -60,50 +60,52 @@ class BlockPreparator(
6060
block: Block,
6161
worldStateProxy: InMemoryWorldStateProxy
6262
): InMemoryWorldStateProxy = {
63-
val blockNumber = block.header.number
64-
65-
val minerRewardForBlock = blockRewardCalculator.calculateMiningRewardForBlock(blockNumber)
66-
val minerRewardForOmmers =
67-
blockRewardCalculator.calculateMiningRewardForOmmers(blockNumber, block.body.uncleNodesList.size)
68-
69-
val minerAddress = Address(block.header.beneficiary)
70-
val treasuryAddress = blockchainConfig.treasuryAddress
71-
val existsTreasuryContract = worldStateProxy.getAccount(treasuryAddress).isDefined
72-
73-
val worldAfterPayingBlockReward =
74-
if (block.header.treasuryOptOut.isEmpty || !existsTreasuryContract) {
75-
val minerReward = minerRewardForOmmers + minerRewardForBlock
76-
val worldAfterMinerReward = increaseAccountBalance(minerAddress, UInt256(minerReward))(worldStateProxy)
77-
log.debug(s"Paying block $blockNumber reward of $minerReward to miner with address $minerAddress")
78-
worldAfterMinerReward
79-
} else if (block.header.treasuryOptOut.get) {
80-
val minerReward = minerRewardForOmmers + minerRewardForBlock * MinerRewardPercentageAfterECIP1098 / 100
81-
val worldAfterMinerReward = increaseAccountBalance(minerAddress, UInt256(minerReward))(worldStateProxy)
82-
log.debug(
83-
s"Paying block $blockNumber reward of $minerReward to miner with address $minerAddress, miner opted-out of treasury"
84-
)
85-
worldAfterMinerReward
86-
} else {
87-
val minerReward = minerRewardForOmmers + minerRewardForBlock * MinerRewardPercentageAfterECIP1098 / 100
88-
val worldAfterMinerReward = increaseAccountBalance(minerAddress, UInt256(minerReward))(worldStateProxy)
89-
val treasuryReward = minerRewardForBlock * TreasuryRewardPercentageAfterECIP1098 / 100
90-
val worldAfterTreasuryReward =
91-
increaseAccountBalance(treasuryAddress, UInt256(treasuryReward))(worldAfterMinerReward)
92-
93-
log.debug(
94-
s"Paying block $blockNumber reward of $minerReward to miner with address $minerAddress" +
95-
s"paying treasury reward of $treasuryReward to treasury with address $treasuryAddress"
96-
)
97-
worldAfterTreasuryReward
98-
}
99-
100-
block.body.uncleNodesList.foldLeft(worldAfterPayingBlockReward) { (ws, ommer) =>
101-
val ommerAddress = Address(ommer.beneficiary)
102-
val ommerReward = blockRewardCalculator.calculateOmmerRewardForInclusion(blockNumber, ommer.number)
63+
if (!Config.testmode) {
64+
val blockNumber = block.header.number
65+
66+
val minerRewardForBlock = blockRewardCalculator.calculateMiningRewardForBlock(blockNumber)
67+
val minerRewardForOmmers =
68+
blockRewardCalculator.calculateMiningRewardForOmmers(blockNumber, block.body.uncleNodesList.size)
69+
70+
val minerAddress = Address(block.header.beneficiary)
71+
val treasuryAddress = blockchainConfig.treasuryAddress
72+
val existsTreasuryContract = worldStateProxy.getAccount(treasuryAddress).isDefined
73+
74+
val worldAfterPayingBlockReward =
75+
if (block.header.treasuryOptOut.isEmpty || !existsTreasuryContract) {
76+
val minerReward = minerRewardForOmmers + minerRewardForBlock
77+
val worldAfterMinerReward = increaseAccountBalance(minerAddress, UInt256(minerReward))(worldStateProxy)
78+
log.debug(s"Paying block $blockNumber reward of $minerReward to miner with address $minerAddress")
79+
worldAfterMinerReward
80+
} else if (block.header.treasuryOptOut.get) {
81+
val minerReward = minerRewardForOmmers + minerRewardForBlock * MinerRewardPercentageAfterECIP1098 / 100
82+
val worldAfterMinerReward = increaseAccountBalance(minerAddress, UInt256(minerReward))(worldStateProxy)
83+
log.debug(
84+
s"Paying block $blockNumber reward of $minerReward to miner with address $minerAddress, miner opted-out of treasury"
85+
)
86+
worldAfterMinerReward
87+
} else {
88+
val minerReward = minerRewardForOmmers + minerRewardForBlock * MinerRewardPercentageAfterECIP1098 / 100
89+
val worldAfterMinerReward = increaseAccountBalance(minerAddress, UInt256(minerReward))(worldStateProxy)
90+
val treasuryReward = minerRewardForBlock * TreasuryRewardPercentageAfterECIP1098 / 100
91+
val worldAfterTreasuryReward =
92+
increaseAccountBalance(treasuryAddress, UInt256(treasuryReward))(worldAfterMinerReward)
93+
94+
log.debug(
95+
s"Paying block $blockNumber reward of $minerReward to miner with address $minerAddress" +
96+
s"paying treasury reward of $treasuryReward to treasury with address $treasuryAddress"
97+
)
98+
worldAfterTreasuryReward
99+
}
100+
block.body.uncleNodesList.foldLeft(worldAfterPayingBlockReward) { (ws, ommer) =>
101+
val ommerAddress = Address(ommer.beneficiary)
102+
val ommerReward = blockRewardCalculator.calculateOmmerRewardForInclusion(blockNumber, ommer.number)
103103

104-
log.debug(s"Paying block $blockNumber reward of $ommerReward to ommer with account address $ommerAddress")
105-
increaseAccountBalance(ommerAddress, UInt256(ommerReward))(ws)
106-
}
104+
log.debug(s"Paying block $blockNumber reward of $ommerReward to ommer with account address $ommerAddress")
105+
increaseAccountBalance(ommerAddress, UInt256(ommerReward))(ws)
106+
}
107+
} else
108+
worldStateProxy
107109
}
108110

109111
/**

src/main/scala/io/iohk/ethereum/testmode/TestmodeConsensus.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import io.iohk.ethereum.consensus._
55
import io.iohk.ethereum.consensus.blocks.{BlockTimestampProvider, NoOmmersBlockGenerator, TestBlockGenerator}
66
import io.iohk.ethereum.consensus.difficulty.DifficultyCalculator
77
import io.iohk.ethereum.consensus.ethash.MinerResponses.MinerNotExist
8+
import io.iohk.ethereum.consensus.ethash.validators.ValidatorsExecutor
89
import io.iohk.ethereum.consensus.ethash.{MinerProtocol, MinerResponse}
910
import io.iohk.ethereum.consensus.validators._
1011
import io.iohk.ethereum.consensus.validators.std.{StdBlockValidator, StdSignedTransactionValidator}
@@ -64,7 +65,7 @@ class TestmodeConsensus(
6465
}
6566
}
6667

67-
override def validators: Validators = new TestValidators
68+
override def validators: Validators = ValidatorsExecutor.apply(blockchainConfig, Protocol.Ethash)
6869

6970
override val blockPreparator: BlockPreparator = new BlockPreparator(
7071
vm = vm,

0 commit comments

Comments
 (0)