Skip to content
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

[CGKIELE-107] mallet #436

Merged
merged 11 commits into from
Apr 27, 2018
Merged

[CGKIELE-107] mallet #436

merged 11 commits into from
Apr 27, 2018

Conversation

rtkaczyk
Copy link
Contributor

@rtkaczyk rtkaczyk commented Apr 9, 2018

The minimalist CLI wallet for KEVM/IELE testnet.

See the list of missing features

Additional improvements:

  • a fix for sbt-verify: to regenerate checksums simply type verifyGenerate. This will create a file verify.sbt in the root dir - no need for manual copying of the output

build.sbt Outdated
"org.jline" % "jline" sha1 "dfb4e9e15e981634155ce063fa697b2b8964d507",
"org.scala-lang.modules" % "scala-parser-combinators" sha1 "3c1c5475ece77c41e18dd971f8f818c091e4961c",
// FIXME: WTF?
"com.google.j2objc" % "j2objc-annotations" sha1 "976d8d30bebc251db406f2bdb3eb01962b5685b3"
Copy link
Contributor

Choose a reason for hiding this comment

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

I did a bit of searching. This is a dependency pulled in via guava v22 (check image below) and is discussed here.

selection_108

Copy link
Contributor Author

Choose a reason for hiding this comment

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

What uses guava?

Copy link
Contributor

Choose a reason for hiding this comment

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

Using sbt with addSbtPlugin("net.virtual-void" % "sbt-dependency-graph" % "0.9.0"):

$ sbt whatDependsOn com.google.guava guava 22.0
[info] com.google.guava:guava:22.0
[info]   +-io.atomix:atomix-utils:2.1.0-beta1
[info]   | +-io.atomix:atomix-cluster:2.1.0-beta1
[info]   | [...]   
[info]   +-org.consensusresearch:scrypto_2.12:1.2.0-RC3 [S]
[info]   | [...]
[info]   +-org.scorexfoundation:iodb_2.12:0.3.0 [S]
[info]     

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@loverdos I removed the j2objc-annotations artifact from my local cache. After rebuilding, the checksum changed and it passed the verification. See also the updated PR description

@@ -93,7 +93,7 @@ class EthashMiner(
val startTime = System.currentTimeMillis()
val mineResult = mine(headerHash, block.header.difficulty.toLong, dagSize, dag, miningConfig.mineRounds)
val time = System.currentTimeMillis() - startTime
val hashRate = (mineResult.triedHashes * 1000) / time
val hashRate = if (time > 0) (mineResult.triedHashes * 1000) / time else Long.MaxValue
Copy link
Contributor

Choose a reason for hiding this comment

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

I was wondering if we could use a "better" (=monotonic) clock, e.g. System.nanoTime() whose purpose is to measure elapsed time. There is no strong guarantee that this is indeed going to be monotonic because it ultimately depends on the OS facilities but this is generally not a problem in Linux nowadays.

Another possible route is to not update the hash rate if we cannot reliably compute it.

Copy link
Contributor

Choose a reason for hiding this comment

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

Note: guava has a com.google.common.base.StopWatch class for this purpose.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'd rather not spend too much time on this, this is not really a big problem anyway. I can add a FIXME though

}

implicit class OptionOps[T](opt: Option[T]) {
def toEither[U](left: U): Either[U, T] =
Copy link
Contributor

Choose a reason for hiding this comment

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

There is scala.Option.toRight, so we can avoid introducing a new construct.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

lol, how did I miss that? :)

@LukasGasior1 LukasGasior1 mentioned this pull request Apr 16, 2018
@@ -0,0 +1,3 @@
#!/bin/bash

./bin/mantis-app -Dconfig.file=./conf/mantis.conf -Dlogback.configurationFile=./conf/logback.xml -J-Xss10M
Copy link
Contributor

Choose a reason for hiding this comment

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

we should also fix mantis-vm script to use mantis-app (currently it won't run vm but start mantis node)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good point, I was actually going to explore another way with those scripts, thanks for reminding me.

warnOnUnverifiedFiles = true,
warnOnUnusedVerifications = true
warnOnUnverifiedFiles = false,
warnOnUnusedVerifications = false
Copy link
Contributor

Choose a reason for hiding this comment

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

why this change? it seems keeping it true is more secure

Copy link
Contributor Author

Choose a reason for hiding this comment

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

false means error instead of warning. I actually didn't plan on changing this, but it happened during some fixes I applied wrt sbt-verify.

I'm not having any problems with sbt-verify now, so I wouldn't mind staying with false. WDYT?

Copy link
Contributor

Choose a reason for hiding this comment

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

Makes sense, I didn't know it means an error :)

}

case class Quoted(input: String) extends Literal {
def unqoute: String = unquote(input)
Copy link
Contributor

Choose a reason for hiding this comment

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

typo: unqoute -> unquote


protected val convert = {
case h: Hex if h.bytes.nonEmpty && h.bytes.length <= 20 =>
Address(h.bytes)
Copy link
Contributor

Choose a reason for hiding this comment

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

can we also support quoted addresses?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Why?

Copy link
Contributor

Choose a reason for hiding this comment

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

My first intuition was to try with quotes. Also geth console uses quoted addresses (it doesn't even accept unquoted ones)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I guess it would be easy to do, but for now I wouldn't go further than adding a TODO comment to consider this.
Firstly, I'd rather have the syntax be strict, and secondly there's supporting account aliases (which would be quoted) on the list missing features.

"jsonrpc" -> "2.0".asJson,
"method" -> method.asJson,
"params" -> args.asJson,
"id" -> "mallet".asJson
Copy link
Contributor

Choose a reason for hiding this comment

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

It doesn't really matter for Mantis, but the semantics of this field is that it's a unique request id. Maybe it would be better to just use a random value here?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I guess the idea was for it to be easily recognisable that the reqest came from mallet. How about "id" -> ("mallet_" + randomUuid()).asJson?

"com.github.scopt" % "scopt" sha1 "e078455e1a65597146f8608dab3247bf1eb92e6e"
)

verifyOptions in verify := VerifyOptions(
Copy link
Contributor

Choose a reason for hiding this comment

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

is this needed here? how does it relate to the options in build.sbt?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This file is auto-generated, see the PR description

@LukasGasior1
Copy link
Contributor

One thing I noticed: we probably don't want to store the importPrivateKey command in the history

@rtkaczyk
Copy link
Contributor Author

importPrivateKey command in the history

That's a really good point!

@LukasGasior1
Copy link
Contributor

Another one: -d flag does not work:

ubuntu@ip-10-0-1-82:~/mantis-faucet/mantis-1.0-daedalus-rc1$ ./bin/mallet -d "/home/ubuntu/keystore" "http://10.0.1.82:8546"                                                                                                               
[residual] arg = '/home/ubuntu/keystore'                                                                                                                                                                                                  
[residual] arg = 'http://10.0.1.82:8546'
# Executing command line:
java
-Dconfig.file=./conf/mantis.conf                                                                                                                                                                                                          
-Dlogback.configurationFile=./conf/logback.xml                                                                                                                                                                                            
-Xss10M
-Dconfig.file=./conf/mallet.conf                                                                                                                                                                                                          
-cp                                                                                                                                                                                                                                       

-jar                                                                                                                                                                                                                                      
/home/ubuntu/mantis-faucet/mantis-1.0-daedalus-rc1/lib/mantis.mantis-1.0-daedalus-rc1-launcher.jar                                                                                                                                        
mallet                                                                                                                                                                                                                                    
/home/ubuntu/keystore
http://10.0.1.82:8546

Error: node URI scheme must be explicit and either 'http' or 'https'                                                                                                                                                                      
Error: Unknown argument 'http://10.0.1.82:8546'                                                                                                                                                                                           
Try --help for more information.                               

full --data-dir works just fine

@rtkaczyk
Copy link
Contributor Author

@LukasGasior1 -d was conflicting with the launcher's script debug option, but adding -- fixed the issue.

Also on the subject, note there are no longer separate mantis and mantis-app scripts. Turns out that adding -Dconfig.file=... in the mallet script overrides the defaults from application.ini (which was the original problem that the hack tried to solve)

In other news:

  • importPrivateKey is no longer saved in history
  • absence of a receipt is correctly handled
  • receipts are displayed as formatted JSON

}

def apply(args: Seq[String]): Option[ClOptions] = {
val parser = new scopt.OptionParser[ClOptions]("scopt") {
Copy link
Contributor

Choose a reason for hiding this comment

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

super minor: the string argument here is a programName, guess it should be Constants.AppName rather than "scopt"

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Not that minor, good catch

// TODO: CL option to enable akka logging
private val akkaConfig = ConfigFactory.load("mallet")

implicit val actorSystem = ActorSystem("mallet_rpc", akkaConfig)
Copy link
Contributor

Choose a reason for hiding this comment

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

why not instantiate it in Mallet app and pass to RpcClient as a parameter?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I meant to avoid ActorSystem leaking out of RpcClient cause it's an internal detail. Obviously this is not the case now, because I forgot to add shutdown() method to RpcClient - then the actor system could be private to RpcClient. What do you think about such approach?

Copy link
Contributor

Choose a reason for hiding this comment

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

To me, actor system is not really internal to rpc client. Even though for mallet it's only used here, it has an impact on the whole app (for example, keeps it alive until it's shutdown), that's why I'd opt for putting in on app-level and pass (perhaps implicitly) to rpc client. It would also make RpcClient's dependencies more clear as well as make it reusable.

Copy link
Contributor

Choose a reason for hiding this comment

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

also, is there any reason why we're using the actorSystem.dispatcher instead of global EC or, even better, implicit ec passed as a constructor param?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

What's wrong with using dispatcher?

Copy link
Contributor

Choose a reason for hiding this comment

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

since you're using blocking operation (await), doesn't that mean that one of the threads that akka uses internally will be blocked? I know, in this case it doesn't matter since RpcClient is the only component using actors, but for the reasons mentioned above (reusability) I think it would be better to let the user of this class choose which EC he prefers (or, alternatively use global ec that won't block system dispatcher's thread).

Copy link
Contributor

@LukasGasior1 LukasGasior1 left a comment

Choose a reason for hiding this comment

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

one small comment, besides that LGMT

Copy link
Contributor

@loverdos loverdos left a comment

Choose a reason for hiding this comment

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

What I do not see is a small document that introduces mallet and its use-case, presents the design without being elaborate on this, comments on configuration options and also presents a couple of examples. In other words: a tech doc.

Any explanations, comments, etc we do on this PR description and elsewhere are great during the review process but are lost, no-one looks back on PRs and we actually do not own them and cannot reproduce them (they are not in git). What remains is the code and (hopefully) an accompanying, lightweight tech doc for the new functionality. We can just call it the mallet README, if we like.

import io.iohk.ethereum.mallet.service.PasswordReader

/**
* This implementation of [[PasswordReader]] is in non-interactive mode when the password is
Copy link
Contributor

Choose a reason for hiding this comment

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

We have a small warning in scaladoc generation:

[warn] mantis/src/main/scala/io/iohk/ethereum/mallet/main/ConstPasswordReader.scala:5: Could not find any member to link for "PasswordReader".
[warn] /**
[warn] ^
[warn] one warning found

The fix is to use the fully qualified name:

[[io.iohk.ethereum.mallet.service.PasswordReader PasswordReader]]

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Isn't it a bug? The PasswordReader is imported. See this scaladoc

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@loverdos wdyt?

Copy link
Contributor

Choose a reason for hiding this comment

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

It works only if the referenced thing is in the same package, not if it is imported. I do not know if this is intended behaviour or a bug though. So I just use the FQN on these occasions.

build.sbt Outdated
@@ -186,7 +96,6 @@ scalacOptions := Seq(
"-unchecked",
"-deprecation",
"-feature",
"-Xfatal-warnings",
"-Xlint:unsound-match",
Copy link
Contributor

Choose a reason for hiding this comment

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

After fixing the scaladoc warning, I re-enabled -Xfatal-warnings and the build went fine from an sbt clean state.

Copy link
Contributor Author

@rtkaczyk rtkaczyk Apr 26, 2018

Choose a reason for hiding this comment

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

I can re-enable it. I always disable it when working on something complicated, because of unused imports. I'm adding and removing code back and forth, and going to imports for each such change kills my concentration and infuriates me.

Copy link
Contributor

Choose a reason for hiding this comment

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

There is a keystroke in IntelliJ that takes care of unused imports :)

ssl-config {
trustManager = {
stores = [
# TODO: move to Wiki maybe?
Copy link
Contributor

Choose a reason for hiding this comment

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

Yes, we have to make some documentation elsewhere ...

Copy link
Contributor Author

Choose a reason for hiding this comment

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

As discussed, it will be done in #445


/**
* Talks to a node over HTTP(S) JSON-RPC
* Note: the URI schema determins whether HTTP or HTTPS is used
Copy link
Contributor

Choose a reason for hiding this comment

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

typo: determines

}
}

val helpHeader = "fetch the receipt for a know transaction hash"
Copy link
Contributor

Choose a reason for hiding this comment

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

typo: known

* This factory method is defining an ActorSystem, ActorMaterializer and ExecutionContext for
* the [[RpcClient]]. To customize these dependencies use [[RpcClient]]'s constructor
*/
def apply(node: Uri): RpcClient = {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

@LukasGasior1 hopefully this should address your remarks about reusability, while limiting the scope of dependencies in mallet.

Copy link
Contributor

Choose a reason for hiding this comment

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

ok, let's leave it that way

@rtkaczyk rtkaczyk merged commit 3da9694 into phase/iele_testnet Apr 27, 2018
@rtkaczyk rtkaczyk deleted the feature/mallet branch April 27, 2018 12:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants