-
Notifications
You must be signed in to change notification settings - Fork 75
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
Add testmode #426
Conversation
gas <- optionalQuantity(obj \ "gas") | ||
gasPrice <- optionalQuantity(obj \ "gasPrice") | ||
value <- optionalQuantity(obj \ "value") | ||
functionName = (obj \ "functionName").extractOpt[String] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we've previously used the name "function" for this field instead of "functionName". If you don't have a strong opinion, it may be simpler to do the same thing here.
for { | ||
eIP150ForkBlock <- extractQuantity(blockchainParamsJson \ "EIP150ForkBlock") | ||
eIP158ForkBlock <- extractQuantity(blockchainParamsJson \ "EIP150ForkBlock") | ||
accountStartNonce <- extractQuantity(blockchainParamsJson \ "EIP150ForkBlock") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this code looks a little suspicious to me. Is this a copy/paste error or was it deliberate?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lol! I totally overlooked that.
src/universal/conf/testmode.conf
Outdated
} | ||
|
||
network.rpc { | ||
apis = "eth,web3,net,personal,daedalus,test" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this should include iele if we want to use testmode for the solidity-to-iele test suite, right?
} | ||
} | ||
|
||
def ieleCall(req: IeleCallRequest): ServiceResponse[CallResponse] = { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
iele transactions return a list of values rather than a single value, so I believe you want to make a IeleCallResponse class and perform rlp decoding in this method.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed
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()) |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@dwightguth done
Could you add some info on how to setup and run solidity tests? |
by the way, DO NOT REVIEW 😄 I'm resolving conflicts and doing a small refactor on this occasion |
@@ -20,8 +20,19 @@ case class TransactionRequest( | |||
nonce = nonce.getOrElse(defaultNonce), | |||
gasPrice = gasPrice.getOrElse(defaultGasPrice), | |||
gasLimit = gasLimit.getOrElse(defaultGasLimit), | |||
receivingAddress = to, | |||
receivingAddress = if (to.contains(Address(0))) None else to, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems this is the default behavior in cpp-ethereum (and what solidity tests expect). To me it (kind of) makes sense, but is a bit counterintuitive for caller (what if you really want to send tx to address 0x0?). WDYT? Other solution is to use this logic only in testmode.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well, you know... https://gastracker.io/addr/0x0000000000000000000000000000000000000000
This is of course a result of many mistakes, but maybe, for reasons beyond my imagination, someone has interest in sending Ether there. I'd say if it's not too much trouble go with testmode only, if not, don't worry about it.
Btw, the expression could be simplified as:
to.filter(_ != Address(0))
src/main/resources/application.conf
Outdated
# 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 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this be
Whether to enable JSON-RPC HTTP(S) endpoint
?
Also, minor, we could use the shorter HTTP(S)
instead of HTTP/HTTPS
There is a compilation error:
|
@@ -353,12 +382,6 @@ trait OmmersPoolBuilder { | |||
lazy val ommersPool: ActorRef = system.actorOf(OmmersPool.props(blockchain, ommersPoolSize)) | |||
} | |||
|
|||
trait ValidatorsBuilder { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This deletion causes a compilation error in snappy. Check io.iohk.ethereum.snappy.Prerequisites.components
.
src/main/resources/application.conf
Outdated
@@ -17,6 +17,9 @@ mantis { | |||
# timeout for shutting down the ActorSystem | |||
shutdown-timeout = "15.seconds" | |||
|
|||
# Whether to run Mantis in test mode (enables test_ RPC endpoints; similar to --test flag in cpp-ethereum) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does it change other functionality? If not, could be moved into rpc
section.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It does. If running in testmode we use different Ledger/Consensus implementations.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In that case maybe we should document how the functionality differs in test mode? Or is that already documented somewhere else?
override def run(): Unit = { | ||
while (!serverSocket.isClosed) { | ||
val clientSocket = serverSocket.accept() | ||
new ClientThread(jsonRpcController, clientSocket).start() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are we just piling up these threads?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's one thread per connection; it stops when connection closes
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not use a thread pool?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
good idea
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@loverdos after taking a second thought I'm not sure if it's the best idea. What are the benefits of using a thread pool here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Avoid a new thread for each new connection?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You mean sharing one thread for multiple connections? I think it doesn't make sense with current approach (we're using blocking socket reading)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am mostly concerned with preventing an unbounded number of threads and/or outstanding requests and I was thinking in the lines of using an appropriately configured Executor
.
blockchain: BlockchainImpl, | ||
syncConfig: SyncConfig, | ||
consensus: Consensus, | ||
var blockchainConfig: BlockchainConfig) { // var as it's modifiable by test_ RPC endpoints |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Couldn't we just create a new instance of this class?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not really. It's a bit tricky, because Ledger is being passed as a parameter to various other components on initialization (see NodeBuilder.scala). I wanted to create new instances, but I didn't find an elegant way to update those classes with new ledger (without introducing a var elsewhere).
blockchain: BlockchainImpl, | ||
blockchainConfig: BlockchainConfig, | ||
consensusConfig: ConsensusConfig, | ||
var blockTimestamp: Long = 0) // var, because it can be modified by test_ RPC endpoints |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Similar as above, couldn't we create a new instance?
I take it this was done? |
@LukasGasior1 I'm unable to run the tests. Trying the command you provided:
So I tried:
Any hints? |
|
||
def close(): Unit = { | ||
serverSocket.close() | ||
removeSocketFile() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If close()
throws an Exception
, the file will not be removed.
@LukasGasior1 Could you |
Also drop the errors in favour of warnings for just a bit better developer experience.
Looking good, but do we have a plan to fix the remaining tests? |
@rtkaczyk I've spent some time trying to figure them out. I think they may be related to the bug with "pending" as block param. To be honest, I wouldn't like to spend more time investigating it. Especially that this task was originally a minor thing. |
@LukasGasior1 private def handleTestRequest(testService: TestService): PartialFunction[JsonRpcRequest, Future[JsonRpcResponse]] = ... The crucial observation is that Having said that, using So, for example, when we update
TestService
I am not saying there are inconsistencies with the current state change approach but I can identify a potential source. |
The main problem here is that, when we update the blockchain config in testmode, it should also be updated globally (wherever Ledger or related classes are used - miner etc). I solved that by introducing
yes, subsequent references to ledger (from any place) will use this new confg - thanks do this wrapper mechanism.
so without testmode enabled, there are really no |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's add a // Note
in JsonRpcIpcServer
where we create Threads, so that we can revisit this.
} | ||
|
||
def mineBlocks(request: MineBlocksRequest): ServiceResponse[MineBlocksResponse] = { | ||
def mineBlock(): Future[Unit] = { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If consensus is not ethash
do we still want to run mineBlock
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
^ OK I saw that there is a specific Consensus
wired, not the one used by the rest of Mantis.
@LukasGasior1 can this be merged now? |
TODO: