-
Notifications
You must be signed in to change notification settings - Fork 75
New issue
Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? # to your account
[ETCM-252] faucet - handle account #783
Conversation
…-252-faucet-handle-account
var wallet: Wallet = _ | ||
|
||
override def preStart(): Unit = { | ||
log info "||=== Faucet Handler Hook ===||" |
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 we log that?
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.
log removed, it is not necessary.
walletService.getWallet.runSyncUnsafe() match { | ||
case Left(error) => | ||
log.error(s"Couldn't initialize wallet - error: $error") | ||
//context become unavailable |
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 think we should kill the faucet or try to recover
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 one is still not addressed. We could end up with the "running" but nonworking faucet. The better idea is to kill the whole app. It will be easier to notice (ex. in metrics)
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 like this idea. So, I separated 3 cases.
1_ if it can't load the wallet, the app shutdown.
2_ While trying to load the wallet with the configuration. At this moment the wallet is disable “FaucetUnavailable”.
3_ When the wallet is loaded, the status is WalletAvailable and we can use the faucet with normality.
If this approach results ok, I will add this description in the documentation.
What do you think?
I have pending another task of improvements, unit test in the supervisor actor.
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 think it is a good direction
src/main/scala/io/iohk/ethereum/faucet/jsonrpc/FaucetRpcService.scala
Outdated
Show resolved
Hide resolved
src/main/scala/io/iohk/ethereum/faucet/jsonrpc/WalletService.scala
Outdated
Show resolved
Hide resolved
src/main/scala/io/iohk/ethereum/faucet/jsonrpc/WalletService.scala
Outdated
Show resolved
Hide resolved
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.
LGTM
import FaucetHandler.FaucetHandlerMsg._ | ||
import FaucetHandler.FaucetHandlerResponse._ | ||
|
||
var wallet: Wallet = _ |
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 context become available(wallet)
?
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.
Done
implicit lazy val actorTimeout: Timeout = Timeout(config.responseTimeout) | ||
implicit val ec: ExecutionContext = system.dispatcher | ||
|
||
private def faucetHandler(): Task[ActorRef] = |
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.
maybe this could be something we receive from params of via implementing a trait. I think it will help when we added tests for the Service.
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.
Done
case Left(err) => | ||
throw new RuntimeException(s"Cannot unlock wallet for use in faucet (${config.walletAddress}), because of $err") | ||
} | ||
class FaucetRpcService(config: FaucetConfig)(implicit system: ActorSystem) extends RetrySupport with Logger { |
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.
// TODO: Add unit tests for this class. (it could be done in a different task)
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.
Add task: ETCM-395
ByteString(rlp.encode(stx.tx.toRLPEncodable)) | ||
def status(statusRequest: StatusRequest): ServiceResponse[StatusResponse] = | ||
faucetHandler() | ||
.flatMap(handler => handler.askFor[Any](FaucetHandlerMsg.Status)) |
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.
what happens if we can't reach the actor? i mean in terms of response...
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.
Pending task: ETCM-396
_ -> | ||
log.info("actor system finished") | ||
)(system.dispatcher), | ||
1.seconds |
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 the pre-existing mantis config value?
# timeout for shutting down the ActorSystem
shutdown-timeout = "15.seconds"
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 mean as in src/main/scala/io/iohk/ethereum/nodebuilder/NodeBuilder.scala
:
trait ShutdownHookBuilder {
self: Logger =>
...
lazy val shutdownTimeoutDuration: Duration = Config.shutdownTimeout
...
}
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.
Done
|
||
val mockRpcClient = mock[RpcClient] | ||
val mockKeyStore = mock[KeyStore] | ||
val config: FaucetConfig = |
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.
val config: FaucetConfig = | |
val config: FaucetConfig = | |
FaucetConfig( | |
walletAddress = wallet.address, | |
walletPassword = "", | |
txGasPrice = 10, | |
txGasLimit = 20, | |
txValue = 1, | |
rpcAddress = "", | |
keyStoreDir = "", | |
minRequestInterval = 10.seconds, | |
handlerTimeout = 10.seconds, | |
responseTimeout = 10.seconds, | |
supervisor = mock[SupervisorConfig] | |
) |
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.
Done
val mockRpcClient = mock[RpcClient] | ||
val mockKeyStore = mock[KeyStore] | ||
val config: FaucetConfig = | ||
FaucetConfig( |
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.
^ far more readable if someone is using just github to check the code, or is in a server environment.
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.
Done
with NormalPatience { | ||
|
||
"Faucet Handler" - { | ||
"without wallet unlocked" - { |
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.
what about the scenario about Faucet initialization succeeded
?
"Faucet Handler" - { | ||
"without wallet unlocked" - { | ||
|
||
"should try to unlock the Wallet if it is not initialized but decryption failed" in new TestSetup { |
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.
For me this test should like:
"Faucet Handler" + "without wallet unlocked" + "should not respond in case wallet unlock fails"
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.
Done
"Faucet Handler" - { | ||
"without wallet unlocked" - { | ||
|
||
"should try to unlock the Wallet if it is not initialized but decryption failed" in new TestSetup { |
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 try to unlock the Wallet if it is not initialized but decryption failed" in new TestSetup { | |
"should not respond in case wallet unlock fails" in new TestSetup { |
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.
Done
…-252-faucet-handle-account
val name = "FaucetSupervisor" | ||
} | ||
|
||
class FaucetSupervisor(walletRpcClient: WalletService, config: FaucetConfig, shutdown: () => Unit)(implicit |
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 think is better to directly pass the Handler, i mean, why the supervisor needs to know about the WalletService?
|
||
lazy val handlerTimeout: Timeout = Timeout(faucetConfig.handlerTimeout) | ||
|
||
def faucetHandler()(implicit system: ActorSystem): Task[ActorRef] = { |
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.
(minor) selectFaucetHandler
IMO in that way is more obvious that is a function, and what is doing
import io.iohk.ethereum.faucet.{FaucetConfigBuilder, FaucetHandler, FaucetSupervisor} | ||
import monix.eval.Task | ||
|
||
trait FaucetHandlerBuilder { |
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.
FaucetHandlerSelector
?
Description
The Faucet assumes that the ops user should configure an account on the
faucet.keystore-dir
before start. When starting the “faucet”, it automatically loads the account, and prepares the context to be used.Proposed Solution
When starting the Faucet, it initializes an actor that handles the account. I added a supervisor that monitors the actor that handles the account.
We have 3 cases:
Important Changes Introduced
When the wallet is loaded successfully, the status of "faucet" changed, now it is WalletAvailable.