Skip to content

Add testmode #426

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 31 commits into from
Apr 24, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
a5930d7
wip - testmode
Mar 19, 2018
d9f1b5c
Cleanup
Mar 19, 2018
a5d0cc9
Fix scalastyle
Mar 19, 2018
c6a172f
Add iele_ transaction endpoints
Mar 22, 2018
ce3d726
Cleanup
Mar 22, 2018
3448160
Rename 'functionName' param to 'function'; fix chain config msg
Mar 22, 2018
34018ab
Fix
Mar 22, 2018
943fd3b
Fix
Mar 23, 2018
9e8b4de
Fix test
Mar 23, 2018
786f0a7
Send proper config based on vm type
Mar 23, 2018
a8c3a99
Update iele call response
Mar 26, 2018
99d0742
Send config on every request; fix rlp decoding
Mar 26, 2018
69baedd
Kevm config in call ctx msg
Mar 26, 2018
3a3195c
Merge remote-tracking branch 'origin/feature/consensus_as_a_service_E…
Mar 28, 2018
04958f7
Merge remote-tracking branch 'origin/phase/iele_testnet' into feature…
Mar 28, 2018
d8f62df
wip
Mar 29, 2018
db7776d
wip
Mar 29, 2018
eb18f82
Cleanup
Mar 29, 2018
3221837
Use block generator from consensus in TestService
Mar 30, 2018
dfbc9ab
Sending to address 0x0 not allowed only in testmode
Apr 3, 2018
0d56e6d
Update config
Apr 3, 2018
2e2be41
Fix compile in snappy
Apr 3, 2018
e43749a
Fix ethCompatibleStorage param in blockPreparator; remove default value
Apr 5, 2018
8814879
Better config doc
Apr 5, 2018
78e5228
Upgrade sbt-verify to 0.4.1
Apr 3, 2018
fc4ffef
Wrap socket close in Try
Apr 11, 2018
e8d2fb7
Fix it test
Apr 16, 2018
493da55
Fix ets
Apr 17, 2018
0b6d237
Add thead pool note
Apr 19, 2018
380e8a0
Merge remote-tracking branch 'origin/phase/iele_testnet' into feature…
Apr 24, 2018
fe62c56
Fix
Apr 24, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ val dep = {
"com.miguno.akka" %% "akka-mock-scheduler" % "0.5.1" % "it,test",
"commons-io" % "commons-io" % "2.5",
"com.typesafe.akka" %% "akka-stream" % akkaVersion,
"org.scala-sbt.ipcsocket" % "ipcsocket" % "1.0.0",

// Pluggable Consensus: AtomixRaft
"io.atomix" % "atomix" % "2.1.0-beta1",
Expand Down Expand Up @@ -112,6 +113,9 @@ val verifyDeps = Seq(
"com.lihaoyi" % "fastparse-utils" sha1 "92da792e8608653317ed6eb456f935fbfb2316bc",
"com.lihaoyi" % "sourcecode" sha1 "ef9a771975cb0860f2b42778c5cf1f5d76818979",
"com.google.protobuf" % "protobuf-java" sha1 "b32aba0cbe737a4ca953f71688725972e3ee927c",
"org.scala-sbt.ipcsocket" % "ipcsocket" sha1 "b671d32896b96c0311947309952078bf374a5c17",
"net.java.dev.jna" % "jna" sha1 "55b548d3195efc5280bf1c3f17b49659c54dee40",
"net.java.dev.jna" % "jna-platform" sha1 "00ab163522ed76eb01c8c9a750dedacb134fc8c0",

// Pluggable Consensus (AtomixRaft)
"io.atomix" % "atomix" sha1 "aa30000cb7d864b4ed52b3d0ade62eee425bf490",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ abstract class ScenarioSetup(_vm: VMImpl, scenario: BlockchainScenario) {

val consensus: TestConsensus = ScenarioSetup.loadEthashConsensus(_vm, blockchain, blockchainConfig)

val emptyWorld = blockchain.getWorldStateProxy(-1, UInt256.Zero, None)
val emptyWorld = blockchain.getWorldStateProxy(-1, UInt256.Zero, None, false, true)

val ledger = new LedgerImpl(blockchain, new BlockQueue(blockchain, 10, 10), blockchainConfig, consensus)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ trait ScenarioSetup extends EphemBlockchainTestSetup {

override lazy val ledger: LedgerImpl = newLedger()

val emptyWorld = blockchain.getWorldStateProxy(-1, UInt256.Zero, None)
val emptyWorld = blockchain.getWorldStateProxy(-1, UInt256.Zero, None, false, true)

val existingAddress = Address(10)
val existingAccount = Account(nonce = UInt256.Zero, balance = UInt256(10))
Expand Down
78 changes: 46 additions & 32 deletions src/main/resources/application.conf
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,11 @@ mantis {
# timeout for shutting down the ActorSystem
shutdown-timeout = "15.seconds"

# Whether to run Mantis in test mode (similar to --test flag in cpp-ethereum).
# When set, test validators and consensus are used by this node.
# It also enables test_ RPC endpoints.
testmode = false

# one of the algorithms defined here:
# https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#SecureRandom
# Uncomment this to specify, otherwise use the default implementation
Expand Down Expand Up @@ -144,50 +149,60 @@ mantis {
}

rpc {
# JSON-RPC mode
# Available modes are: http, https
# Choosing https requires creating a certificate and setting up 'certificate-keystore-path' and
# 'certificate-password-file'
# See: https://github.com/input-output-hk/mantis/wiki/Creating-self-signed-certificate-for-using-JSON-RPC-with-HTTPS
mode = "http"

# Whether to enable JSON-RPC endpoint
enabled = true

# Listening address of JSON-RPC HTTP/HTTPS endpoint
interface = "localhost"

# Listening port of JSON-RPC HTTP/HTTPS endpoint
port = 8546

# Path to the keystore storing the certificates (used only for https)
# null value indicates HTTPS is not being used
certificate-keystore-path = null
http {
# JSON-RPC mode
# Available modes are: http, https
# Choosing https requires creating a certificate and setting up 'certificate-keystore-path' and
# 'certificate-password-file'
# See: https://github.com/input-output-hk/mantis/wiki/Creating-self-signed-certificate-for-using-JSON-RPC-with-HTTPS
mode = "http"

# Whether to enable JSON-RPC HTTP(S) endpoint
enabled = true

# Listening address of JSON-RPC HTTP(S) endpoint
interface = "localhost"

# Listening port of JSON-RPC HTTP(S) endpoint
port = 8546

# Path to the keystore storing the certificates (used only for https)
# null value indicates HTTPS is not being used
certificate-keystore-path = null

# Type of certificate keystore being used
# null value indicates HTTPS is not being used
certificate-keystore-type = null

# File with the password used for accessing the certificate keystore (used only for https)
# null value indicates HTTPS is not being used
certificate-password-file = null

# Domains allowed to query RPC endpoint. Use "*" to enable requests from
# any domain.
cors-allowed-origins = []
}

# Type of certificate keystore being used
# null value indicates HTTPS is not being used
certificate-keystore-type = null
ipc {
# Whether to enable JSON-RPC over IPC
enabled = true

# File with the password used for accessing the certificate keystore (used only for https)
# null value indicates HTTPS is not being used
certificate-password-file = null
# Path to IPC socket file
socket-file = ${mantis.datadir}"/mantis.ipc"
}

# Enabled JSON-RPC APIs over the JSON-RPC endpoint
# Available choices are: eth, web3, net, personal, daedalus
# Available choices are: eth, web3, net, personal, test, daedalus, iele
apis = "eth,web3,net,personal,daedalus"

# Domains allowed to query RPC endpoint. Use "*" to enable requests from
# any domain.
cors-allowed-origins = []

# Maximum number of blocks for daedalus_getAccountTransactions
account-transactions-max-blocks = 50000

net {
peer-manager-timeout = 5.seconds
}

active-timeout = 5.seconds
miner-active-timeout = 5.seconds
}
}

Expand Down Expand Up @@ -542,4 +557,3 @@ akka {
logger-startup-timeout = 30s
log-dead-letters = off
}

8 changes: 6 additions & 2 deletions src/main/scala/io/iohk/ethereum/Mantis.scala
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
package io.iohk.ethereum

import io.iohk.ethereum.nodebuilder.StdNode
import io.iohk.ethereum.nodebuilder.{StdNode, TestNode}
import io.iohk.ethereum.utils.Config

object Mantis {
def main(args: Array[String]): Unit = {
val node = new StdNode
val node =
if (Config.testmode) new TestNode
else new StdNode

node.start()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ class GenesisDataLoader(
} yield ()
}

private def loadGenesisData(genesisData: GenesisData): Try[Unit] = {
def loadGenesisData(genesisData: GenesisData): Try[Unit] = {
import MerklePatriciaTrie.defaultByteArraySerializable

val ephemDataSource = EphemDataSource()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ import io.iohk.ethereum.consensus.ethash.EthashConsensus
import io.iohk.ethereum.nodebuilder._
import io.iohk.ethereum.utils.{Config, Logger}

trait ConsensusBuilder {
def consensus: Consensus
}

/**
* A consensus builder is responsible to instantiate the consensus protocol.
* This is done dynamically when Mantis boots, based on its configuration.
Expand All @@ -13,7 +17,7 @@ import io.iohk.ethereum.utils.{Config, Logger}
* [[io.iohk.ethereum.consensus.ethash.EthashConsensus EthashConsensus]],
* [[io.iohk.ethereum.consensus.atomixraft.AtomixRaftConsensus AtomixRaftConsensus]]
*/
trait ConsensusBuilder {
trait StdConsensusBuilder extends ConsensusBuilder {
self: VmBuilder with BlockchainBuilder with BlockchainConfigBuilder with ConsensusConfigBuilder with Logger ⇒

private lazy val mantisConfig = Config.config
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,13 @@ import io.iohk.ethereum.utils.Logger
* A [[io.iohk.ethereum.consensus.ConsensusBuilder ConsensusBuilder]] that builds a
* [[io.iohk.ethereum.consensus.TestConsensus TestConsensus]]
*/
trait TestConsensusBuilder { self: ConsensusBuilder
trait TestConsensusBuilder { self: StdConsensusBuilder
protected def buildTestConsensus(): TestConsensus =
buildConsensus().asInstanceOf[TestConsensus] // we are in tests, so if we get an exception, so be it
}

/** A standard [[TestConsensusBuilder]] cake. */
trait StdTestConsensusBuilder extends ConsensusBuilder
trait StdTestConsensusBuilder extends StdConsensusBuilder
with TestConsensusBuilder
with VmBuilder
with VmConfigBuilder
Expand Down
22 changes: 11 additions & 11 deletions src/main/scala/io/iohk/ethereum/domain/Blockchain.scala
Original file line number Diff line number Diff line change
Expand Up @@ -181,15 +181,15 @@ trait Blockchain {

def getWorldStateProxy(blockNumber: BigInt,
accountStartNonce: UInt256,
stateRootHash: Option[ByteString] = None,
noEmptyAccounts: Boolean = false,
ethCompatibleStorage: Boolean = true): WS
stateRootHash: Option[ByteString],
noEmptyAccounts: Boolean,
ethCompatibleStorage: Boolean): WS

def getReadOnlyWorldStateProxy(blockNumber: Option[BigInt],
accountStartNonce: UInt256,
stateRootHash: Option[ByteString] = None,
noEmptyAccounts: Boolean = false,
ethCompatibleStorage: Boolean = true): WS
stateRootHash: Option[ByteString],
noEmptyAccounts: Boolean,
ethCompatibleStorage: Boolean): WS

def pruneState(blockNumber: BigInt): Unit

Expand Down Expand Up @@ -316,24 +316,24 @@ class BlockchainImpl(
override def getWorldStateProxy(blockNumber: BigInt,
accountStartNonce: UInt256,
stateRootHash: Option[ByteString],
noEmptyAccount: Boolean = false,
ethCompatibleStorage: Boolean = true): InMemoryWorldStateProxy =
noEmptyAccounts: Boolean,
ethCompatibleStorage: Boolean): InMemoryWorldStateProxy =
InMemoryWorldStateProxy(
evmCodeStorage,
nodesKeyValueStorageFor(Some(blockNumber)),
accountStartNonce,
(number: BigInt) => getBlockHeaderByNumber(number).map(_.hash),
stateRootHash,
noEmptyAccount,
noEmptyAccounts,
ethCompatibleStorage
)

//FIXME Maybe we can use this one in regular execution too and persist underlying storage when block execution is successful
override def getReadOnlyWorldStateProxy(blockNumber: Option[BigInt],
accountStartNonce: UInt256,
stateRootHash: Option[ByteString],
noEmptyAccount: Boolean = false,
ethCompatibleStorage: Boolean = true): InMemoryWorldStateProxy =
noEmptyAccounts: Boolean,
ethCompatibleStorage: Boolean): InMemoryWorldStateProxy =
InMemoryWorldStateProxy(
evmCodeStorage,
ReadOnlyNodeStorage(nodesKeyValueStorageFor(blockNumber)),
Expand Down
8 changes: 4 additions & 4 deletions src/main/scala/io/iohk/ethereum/extvm/ExtVMInterface.scala
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,13 @@ import akka.stream.{ActorMaterializer, OverflowStrategy}
import akka.stream.scaladsl.{Framing, Keep, Sink, SinkQueueWithCancel, Source, SourceQueueWithComplete, Tcp}
import akka.util.ByteString
import io.iohk.ethereum.ledger.{InMemoryWorldStateProxy, InMemoryWorldStateProxyStorage}
import io.iohk.ethereum.utils.BlockchainConfig
import io.iohk.ethereum.utils.{BlockchainConfig, VmConfig}
import io.iohk.ethereum.vm._

import scala.annotation.tailrec
import scala.util.{Failure, Success, Try}

class ExtVMInterface(host: String, port: Int, blockchainConfig: BlockchainConfig, testMode: Boolean)(implicit system: ActorSystem)
class ExtVMInterface(externaVmConfig: VmConfig.ExternalConfig, blockchainConfig: BlockchainConfig, testMode: Boolean)(implicit system: ActorSystem)
extends VM[InMemoryWorldStateProxy, InMemoryWorldStateProxyStorage]{

private implicit val materializer = ActorMaterializer()
Expand All @@ -29,7 +29,7 @@ class ExtVMInterface(host: String, port: Int, blockchainConfig: BlockchainConfig
private def initConnection(): Unit = {
close()

val connection = Tcp().outgoingConnection(host, port)
val connection = Tcp().outgoingConnection(externaVmConfig.host, externaVmConfig.port)

val (connOut, connIn) = Source.queue[ByteString](QueueBufferSize, OverflowStrategy.dropTail)
.via(connection)
Expand All @@ -41,7 +41,7 @@ class ExtVMInterface(host: String, port: Int, blockchainConfig: BlockchainConfig
out = Some(connOut)
in = Some(connIn)

val client = new VMClient(new MessageHandler(connIn, connOut), testMode)
val client = new VMClient(externaVmConfig, new MessageHandler(connIn, connOut), testMode)
client.sendHello(ApiVersionProvider.version, blockchainConfig)
//TODO: await hello response, check version

Expand Down
24 changes: 16 additions & 8 deletions src/main/scala/io/iohk/ethereum/extvm/VMClient.scala
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import io.iohk.ethereum.vm.{WorldStateProxy, _}
import Implicits._
import akka.util.ByteString
import io.iohk.ethereum.domain._
import io.iohk.ethereum.utils.{BlockchainConfig, Logger}
import io.iohk.ethereum.utils.{BlockchainConfig, Logger, VmConfig}

import scala.annotation.tailrec

Expand All @@ -14,13 +14,17 @@ import scala.annotation.tailrec
* This is useful to override configuration for each test, rather than to recreate the VM.
*/
class VMClient(
externalVmConfig: VmConfig.ExternalConfig,
messageHandler: MessageHandler,
testMode: Boolean)
extends Logger {

def sendHello(version: String, blockchainConfig: BlockchainConfig): Unit = {
val config = BlockchainConfigForEvm(blockchainConfig)
val configMsg = msg.Hello.Config.EthereumConfig(buildEthereumConfigMsg(BlockchainConfigForEvm(blockchainConfig)))
val configMsg = externalVmConfig.vmType match {
case VmConfig.ExternalConfig.VmTypeIele => msg.Hello.Config.IeleConfig(buildIeleConfigMsg())

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

based on our discussion on slack, weren't we planning for our near-term solution to be to make IeleConfig also be passed on every CallContext?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

case _ => msg.Hello.Config.EthereumConfig(buildEthereumConfigMsg(config))
}
val helloMsg = msg.Hello(version, configMsg)
messageHandler.sendMessage(helloMsg)
}
Expand Down Expand Up @@ -125,11 +129,12 @@ class VMClient(
import msg.CallContext.Config
val blockHeader = buildBlockHeaderMsg(ctx.blockHeader)

val ethereumConfig =
if (testMode)
Config.EthereumConfig(buildEthereumConfigMsg(ctx.evmConfig.blockchainConfig))
else
Config.Empty
val config = externalVmConfig.vmType match {
case VmConfig.ExternalConfig.VmTypeIele => Config.IeleConfig(buildIeleConfigMsg()) // always pass config for IELE
case VmConfig.ExternalConfig.VmTypeKevm => Config.EthereumConfig(buildEthereumConfigMsg(ctx.evmConfig.blockchainConfig)) // always pass config for KEVM
case _ if testMode => Config.EthereumConfig(buildEthereumConfigMsg(ctx.evmConfig.blockchainConfig))
case _ => Config.Empty
}

msg.CallContext(
callerAddr = ctx.callerAddr,
Expand All @@ -139,7 +144,7 @@ class VMClient(
gasPrice = ctx.gasPrice,
gasProvided = ctx.startGas,
blockHeader = Some(blockHeader),
config = ethereumConfig
config = config
)
}

Expand All @@ -154,6 +159,9 @@ class VMClient(
accountStartNonce = blockchainConfig.accountStartNonce
)

private def buildIeleConfigMsg(): msg.IeleConfig =
msg.IeleConfig()

private def buildBlockHeaderMsg(header: BlockHeader): msg.BlockHeader =
msg.BlockHeader(
beneficiary = header.beneficiary,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -565,12 +565,6 @@ object EthJsonMethodsImplicits extends JsonMethodsImplicits {
data = data.getOrElse(ByteString("")))
}

private def optionalQuantity(input: JValue): Either[JsonRpcError, Option[BigInt]] =
input match {
case JNothing => Right(None)
case o => extractQuantity(o).map(Some(_))
}

implicit val daedalus_getAccountTransactions =
new JsonDecoder[GetAccountTransactionsRequest] with JsonEncoder[GetAccountTransactionsResponse] {
def decodeJson(params: Option[JArray]): Either[JsonRpcError, GetAccountTransactionsRequest] =
Expand All @@ -587,4 +581,19 @@ object EthJsonMethodsImplicits extends JsonMethodsImplicits {
override def encodeJson(t: GetAccountTransactionsResponse): JValue =
JObject("transactions" -> JArray(t.transactions.map(Extraction.decompose).toList))
}

implicit val eth_getStorageRoot = new JsonDecoder[GetStorageRootRequest] with JsonEncoder[GetStorageRootResponse] {
def decodeJson(params: Option[JArray]): Either[JsonRpcError, GetStorageRootRequest] =
params match {
case Some(JArray((addressStr: JString) :: (blockValue: JValue) :: Nil)) =>
for {
address <- extractAddress(addressStr)
block <- extractBlockParam(blockValue)
} yield GetStorageRootRequest(address, block)
case _ => Left(InvalidParams())
}

def encodeJson(t: GetStorageRootResponse): JValue = encodeAsHex(t.storageRoot)
}

}
Loading