diff --git a/.buildkite/pipeline.nix b/.buildkite/pipeline.nix index 186975d167..99a5513d30 100644 --- a/.buildkite/pipeline.nix +++ b/.buildkite/pipeline.nix @@ -20,17 +20,17 @@ in ]; }; - scalafmt = commonAttrs // { - label = "scalafmtCheck"; + scalafixAndFmt = commonAttrs // { + label = "scalafix & scalafmt"; command = '' - nix-shell --run '$SBT scalafmtCheck' + nix-shell --run '$SBT formatCheck' ''; retry.automatic = false; }; compile = commonAttrs // { label = "compile everything"; - dependsOn = [ scalafmt ]; + dependsOn = [ scalafixAndFmt ]; command = '' nix-shell --run '$SBT compile-all' ''; diff --git a/.buildkite/shell.nix b/.buildkite/shell.nix index 89ed36c636..3c24839eb5 100644 --- a/.buildkite/shell.nix +++ b/.buildkite/shell.nix @@ -21,5 +21,5 @@ with pkgs; mkShell { nativeBuildInputs = [ sbt solc lllc jdk8 protoc-wrapper retesteth netcat-gnu ]; # SBT = "sbt -v -mem 2048 -J-Xmx4g -Dsbt.ivy.home=/cache/ivy2 -Dsbt.boot.directory=/cache/sbt -Dmaven.repo.local=/cache/maven -Dnix=true"; - SBT = "sbt -v -mem 2048 -J-Xmx6g -Dnix=true"; + SBT = "sbt -v -mem 8192 -Dnix=true"; } diff --git a/.jvmopts b/.jvmopts index 9ff04d1fb3..c5e53f2131 100644 --- a/.jvmopts +++ b/.jvmopts @@ -1,5 +1,5 @@ -Xms1g -Xmx4g --XX:ReservedCodeCacheSize=256m +-XX:ReservedCodeCacheSize=1024m -XX:MaxMetaspaceSize=1g -Xss4M \ No newline at end of file diff --git a/.scalafix.conf b/.scalafix.conf new file mode 100644 index 0000000000..ff0628f0a1 --- /dev/null +++ b/.scalafix.conf @@ -0,0 +1,27 @@ +rules = [ + ExplicitResultTypes + NoAutoTupling + NoValInForComprehension + OrganizeImports + ProcedureSyntax + RemoveUnused +] + +OrganizeImports { + groupedImports = Explode + groups = [ + "re:javax?\\." + "akka." + "cats." + "monix." + "scala." + "scala.meta." + "*" + "io.iohk.ethereum." + ] + removeUnused = true +} + +RemoveUnused { + imports = false // handled by OrganizeImports +} \ No newline at end of file diff --git a/.scalafmt.conf b/.scalafmt.conf index 7abf61394b..edfb93867d 100644 --- a/.scalafmt.conf +++ b/.scalafmt.conf @@ -1,3 +1,5 @@ -version = "2.7.1" -align = none +version = "2.7.5" +align.preset = some maxColumn = 120 + +rewrite.rules = [AvoidInfix, RedundantBraces, RedundantParens, SortModifiers] \ No newline at end of file diff --git a/build.sbt b/build.sbt index 1514076ac6..1ec33f4874 100644 --- a/build.sbt +++ b/build.sbt @@ -45,6 +45,13 @@ def commonSettings(projectName: String): Seq[sbt.Def.Setting[_]] = Seq( name := projectName, organization := "io.iohk", scalaVersion := `scala-2.13`, + semanticdbEnabled := true, // enable SemanticDB + semanticdbVersion := scalafixSemanticdb.revision, // use Scalafix compatible version + ThisBuild / scalafixScalaBinaryVersion := CrossVersion.binaryScalaVersion(scalaVersion.value), + ThisBuild / scalafixDependencies ++= List( + "com.github.liancheng" %% "organize-imports" % "0.5.0", + "com.github.vovapolu" %% "scaluzzi" % "0.1.16" + ), // Scalanet snapshots are published to Sonatype after each build. resolvers += "Sonatype OSS Snapshots" at "https://oss.sonatype.org/content/repositories/snapshots", testOptions in Test += Tests @@ -53,7 +60,9 @@ def commonSettings(projectName: String): Seq[sbt.Def.Setting[_]] = Seq( "-unchecked", "-deprecation", "-feature", - "-Xfatal-warnings", + // "-Xfatal-warnings", // disabled until unused are removed + "-Ywarn-unused", + "-Xlint", "-encoding", "utf-8" ), @@ -86,6 +95,7 @@ lazy val bytes = { .in(file("bytes")) .configs(Integration) .settings(commonSettings("mantis-bytes")) + .settings(inConfig(Integration)(scalafixConfigSettings(Integration))) .settings(publishSettings) .settings( libraryDependencies ++= @@ -102,6 +112,7 @@ lazy val crypto = { .configs(Integration) .dependsOn(bytes) .settings(commonSettings("mantis-crypto")) + .settings(inConfig(Integration)(scalafixConfigSettings(Integration))) .settings(publishSettings) .settings( libraryDependencies ++= @@ -119,6 +130,7 @@ lazy val rlp = { .configs(Integration) .dependsOn(bytes) .settings(commonSettings("mantis-rlp")) + .settings(inConfig(Integration)(scalafixConfigSettings(Integration))) .settings(publishSettings) .settings( libraryDependencies ++= @@ -176,8 +188,6 @@ lazy val node = { (test in Evm) := (test in Evm).dependsOn(solidityCompile).value (sourceDirectory in Evm) := baseDirectory.value / "src" / "evmTest" - val sep = java.io.File.separator - val node = project .in(file(".")) .configs(Integration, Benchmark, Evm, Rpc) @@ -201,6 +211,9 @@ lazy val node = { buildInfoOptions in Compile += BuildInfoOption.ToMap ) .settings(commonSettings("mantis"): _*) + .settings(inConfig(Integration)(scalafixConfigSettings(Integration))) + .settings(inConfig(Evm)(scalafixConfigSettings(Evm))) + .settings(inConfig(Rpc)(scalafixConfigSettings(Rpc))) .settings( libraryDependencies ++= dep ) @@ -290,6 +303,36 @@ addCommandAlias( |""".stripMargin ) +// format all modules +addCommandAlias( + "formatAll", + """;compile-all + |;bytes/scalafixAll + |;bytes/scalafmtAll + |;crypto/scalafixAll + |;crypto/scalafmtAll + |;rlp/scalafixAll + |;rlp/scalafmtAll + |;scalafixAll + |;scalafmtAll + |""".stripMargin +) + +// check modules formatting +addCommandAlias( + "formatCheck", + """;compile-all + |;bytes/scalafixAll --check + |;bytes/scalafmtCheckAll + |;crypto/scalafixAll --check + |;crypto/scalafmtCheckAll + |;rlp/scalafixAll --check + |;rlp/scalafmtCheckAll + |;scalafixAll --check + |;scalafmtCheckAll + |""".stripMargin +) + // testAll addCommandAlias( "testAll", diff --git a/bytes/src/main/scala/io/iohk/ethereum/utils/ByteStringUtils.scala b/bytes/src/main/scala/io/iohk/ethereum/utils/ByteStringUtils.scala index 321987bcaa..992028bee4 100644 --- a/bytes/src/main/scala/io/iohk/ethereum/utils/ByteStringUtils.scala +++ b/bytes/src/main/scala/io/iohk/ethereum/utils/ByteStringUtils.scala @@ -14,7 +14,7 @@ object ByteStringUtils { ByteString(Hex.decode(hash)) implicit class Padding(val bs: ByteString) extends AnyVal { - def padToByteString(length: Int, b: Byte): ByteString = { + def padToByteString(length: Int, b: Byte): ByteString = if (length <= bs.length) bs else { val len = Math.max(bs.length, length) @@ -27,7 +27,6 @@ object ByteStringUtils { } ByteString.fromArray(result) } - } } implicit class ByteStringOps(val bytes: ByteString) extends AnyVal { @@ -54,9 +53,8 @@ object ByteStringUtils { def asByteArray: Array[Byte] = Array(b) } - implicit val byteStringOrdering: Ordering[ByteString] = { + implicit val byteStringOrdering: Ordering[ByteString] = Ordering.by[ByteString, Seq[Byte]](_.toSeq) - } def concatByteStrings(head: ByteStringElement, tail: ByteStringElement*): ByteString = { val it = Iterator.single(head) ++ tail.iterator diff --git a/bytes/src/main/scala/io/iohk/ethereum/utils/ByteUtils.scala b/bytes/src/main/scala/io/iohk/ethereum/utils/ByteUtils.scala index 46d1316231..b3b17eac66 100644 --- a/bytes/src/main/scala/io/iohk/ethereum/utils/ByteUtils.scala +++ b/bytes/src/main/scala/io/iohk/ethereum/utils/ByteUtils.scala @@ -1,7 +1,8 @@ package io.iohk.ethereum.utils import java.math.BigInteger -import java.nio.{ByteBuffer, ByteOrder} +import java.nio.ByteBuffer +import java.nio.ByteOrder import akka.util.ByteString @@ -9,8 +10,7 @@ import scala.util.Random object ByteUtils { - /** - * Calculates number of matching bytes from the beginning of both arrays. + /** Calculates number of matching bytes from the beginning of both arrays. * Due to performance reasons needs to be as fast as possible which means usage of while loops and var's. * * @param a - first array of bytes to check @@ -19,9 +19,8 @@ object ByteUtils { */ def matchingLength(a: Array[Byte], b: Array[Byte]): Int = { var prefixLen = 0 - while (prefixLen < a.length && prefixLen < b.length && a(prefixLen) == b(prefixLen)) { + while (prefixLen < a.length && prefixLen < b.length && a(prefixLen) == b(prefixLen)) prefixLen = prefixLen + 1 - } prefixLen } @@ -38,7 +37,7 @@ object ByteUtils { bigIntegerToBytes(b.bigInteger, numBytes) def toBigInt(bytes: ByteString): BigInt = - bytes.foldLeft(BigInt(0)) { (n, b) => (n << 8) + (b & 0xff) } + bytes.foldLeft(BigInt(0))((n, b) => (n << 8) + (b & 0xff)) def bigIntToUnsignedByteArray(i: BigInt): Array[Byte] = { val asByteArray = i.toByteArray @@ -46,8 +45,7 @@ object ByteUtils { else asByteArray } - /** - * Calculates xor distance between two byte arrays. Due to performance reasons needs to be as fast as possible + /** Calculates xor distance between two byte arrays. Due to performance reasons needs to be as fast as possible * which means usage of while loops and var's. * * @param a - array of bytes to xor @@ -108,9 +106,8 @@ object ByteUtils { data } - def compactPickledBytes(buffer: ByteBuffer): ByteString = { + def compactPickledBytes(buffer: ByteBuffer): ByteString = ByteString(compactPickledBytesToArray(buffer)) - } def byteSequenceToBuffer(bytes: IndexedSeq[Byte]): ByteBuffer = ByteBuffer.wrap(bytes.toArray) @@ -127,12 +124,10 @@ object ByteUtils { ret } - def getIntFromWord(arr: Array[Byte]): Int = { + def getIntFromWord(arr: Array[Byte]): Int = ByteBuffer.wrap(arr, 0, 4).order(ByteOrder.LITTLE_ENDIAN).getInt - } - /** - * Converts array of Int to corresponding array of bytes. Due to performance reasons needs to be as fast as possible + /** Converts array of Int to corresponding array of bytes. Due to performance reasons needs to be as fast as possible * which means usage of while loops and var's. * * @param arr - array of int's to convert @@ -141,7 +136,7 @@ object ByteUtils { * @param bigEndian - param specifying which int representation should be used. * @return Unit */ - def intsToBytesMut(arr: Array[Int], b: Array[Byte], bigEndian: Boolean): Unit = { + def intsToBytesMut(arr: Array[Int], b: Array[Byte], bigEndian: Boolean): Unit = if (!bigEndian) { var off = 0 var i = 0 @@ -175,10 +170,8 @@ object ByteUtils { i = i + 1 } } - } - /** - * Converts array of bytes to corresponding array of ints. Due to performance reasons needs to be as fast as possible + /** Converts array of bytes to corresponding array of ints. Due to performance reasons needs to be as fast as possible * which means usage of while loops and var's. * * @param b - array of bytes to convert @@ -187,7 +180,7 @@ object ByteUtils { * @param bigEndian - param specifying which int representation should be used. * @return Unit */ - def bytesToIntsMut(b: Array[Byte], arr: Array[Int], bigEndian: Boolean): Unit = { + def bytesToIntsMut(b: Array[Byte], arr: Array[Int], bigEndian: Boolean): Unit = if (!bigEndian) { var off = 0 var i = 0 @@ -222,6 +215,5 @@ object ByteUtils { i = i + 1 } } - } } diff --git a/bytes/src/test/scala/io/iohk/ethereum/utils/ByteStringUtilsTest.scala b/bytes/src/test/scala/io/iohk/ethereum/utils/ByteStringUtilsTest.scala index 5aed0cbf1a..e938422aec 100644 --- a/bytes/src/test/scala/io/iohk/ethereum/utils/ByteStringUtilsTest.scala +++ b/bytes/src/test/scala/io/iohk/ethereum/utils/ByteStringUtilsTest.scala @@ -1,11 +1,16 @@ package io.iohk.ethereum.utils import akka.util.ByteString -import org.scalatest.wordspec.AnyWordSpec + +import scala.collection.immutable.ArraySeq +import scala.util.Failure +import scala.util.Success +import scala.util.Try + import org.scalatest.matchers.should.Matchers +import org.scalatest.wordspec.AnyWordSpec + import ByteStringUtils._ -import scala.collection.immutable.ArraySeq -import scala.util.{Try, Success, Failure} class ByteStringUtilsTest extends AnyWordSpec with Matchers { @@ -39,7 +44,7 @@ class ByteStringUtilsTest extends AnyWordSpec with Matchers { val bs3: Byte = 2 val bs4 = Array[Byte](3, 3) val bs5 = Array[Byte](4, 4) - val summarized: ByteString = bs1 ++ bs2 + bs1 ++ bs2 val concatenated: ByteString = ByteStringUtils.concatByteStrings(bs1, bs2, bs3, bs4, bs5) concatenated shouldEqual string2hash("0000FFFF0203030404") } diff --git a/bytes/src/test/scala/io/iohk/ethereum/utils/ByteUtilsSpec.scala b/bytes/src/test/scala/io/iohk/ethereum/utils/ByteUtilsSpec.scala index 53370e309c..7b2dc0f0f9 100644 --- a/bytes/src/test/scala/io/iohk/ethereum/utils/ByteUtilsSpec.scala +++ b/bytes/src/test/scala/io/iohk/ethereum/utils/ByteUtilsSpec.scala @@ -1,8 +1,9 @@ package io.iohk.ethereum.utils -import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks +import org.scalacheck.Arbitrary +import org.scalacheck.Gen import org.scalatest.funsuite.AnyFunSuite -import org.scalacheck.{Arbitrary, Gen} +import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks class ByteUtilsSpec extends AnyFunSuite with ScalaCheckPropertyChecks { def byteArrayOfNItemsGen(n: Int): Gen[Array[Byte]] = @@ -12,7 +13,7 @@ class ByteUtilsSpec extends AnyFunSuite with ScalaCheckPropertyChecks { forAll(byteArrayOfNItemsGen(32)) { bytes => val toInts = ByteUtils.bytesToInts(bytes, bigEndian = false) val asBytes = ByteUtils.intsToBytes(toInts, bigEndian = false) - assert(asBytes sameElements bytes) + assert(asBytes.sameElements(bytes)) } } @@ -20,7 +21,7 @@ class ByteUtilsSpec extends AnyFunSuite with ScalaCheckPropertyChecks { forAll(byteArrayOfNItemsGen(32)) { bytes => val toInts = ByteUtils.bytesToInts(bytes, bigEndian = true) val asBytes = ByteUtils.intsToBytes(toInts, bigEndian = true) - assert(asBytes sameElements bytes) + assert(asBytes.sameElements(bytes)) } } } diff --git a/crypto/src/main/scala/io/iohk/ethereum/crypto/ConcatKDFBytesGenerator.scala b/crypto/src/main/scala/io/iohk/ethereum/crypto/ConcatKDFBytesGenerator.scala index 1c415c5741..02506b7d8d 100644 --- a/crypto/src/main/scala/io/iohk/ethereum/crypto/ConcatKDFBytesGenerator.scala +++ b/crypto/src/main/scala/io/iohk/ethereum/crypto/ConcatKDFBytesGenerator.scala @@ -1,18 +1,17 @@ package io.iohk.ethereum.crypto import akka.util.ByteString + import org.bouncycastle.crypto.Digest import org.bouncycastle.util.Pack -/** - * Basic KDF generator for derived keys and ivs as defined by NIST SP 800-56A. +/** Basic KDF generator for derived keys and ivs as defined by NIST SP 800-56A. * @param digest for source of derived keys */ class ConcatKDFBytesGenerator(digest: Digest) { val digestSize: Int = digest.getDigestSize - /** - * @param outputLength length of output that will be produced by this method, + /** @param outputLength length of output that will be produced by this method, * maximum value is (digest output size in bits) * (2^32 - 1) but it should not be a problem * because we are using Int * @throws scala.IllegalArgumentException ("Output length too large") when outputLength is greater than (digest output size in bits) * (2^32 - 1) diff --git a/crypto/src/main/scala/io/iohk/ethereum/crypto/ECDSASignature.scala b/crypto/src/main/scala/io/iohk/ethereum/crypto/ECDSASignature.scala index 5151f5eac6..1d112d9733 100644 --- a/crypto/src/main/scala/io/iohk/ethereum/crypto/ECDSASignature.scala +++ b/crypto/src/main/scala/io/iohk/ethereum/crypto/ECDSASignature.scala @@ -1,15 +1,19 @@ package io.iohk.ethereum.crypto import akka.util.ByteString -import io.iohk.ethereum.utils.ByteUtils + +import scala.util.Try + import org.bouncycastle.asn1.x9.X9IntegerConverter import org.bouncycastle.crypto.AsymmetricCipherKeyPair import org.bouncycastle.crypto.digests.SHA256Digest import org.bouncycastle.crypto.params.ECPublicKeyParameters -import org.bouncycastle.crypto.signers.{ECDSASigner, HMacDSAKCalculator} -import org.bouncycastle.math.ec.{ECCurve, ECPoint} +import org.bouncycastle.crypto.signers.ECDSASigner +import org.bouncycastle.crypto.signers.HMacDSAKCalculator +import org.bouncycastle.math.ec.ECCurve +import org.bouncycastle.math.ec.ECPoint -import scala.util.Try +import io.iohk.ethereum.utils.ByteUtils object ECDSASignature { @@ -29,18 +33,16 @@ object ECDSASignature { val positivePointSign: Byte = 28 val newPositivePointSign: Byte = 36 - val allowedPointSigns = Set(negativePointSign, positivePointSign) + val allowedPointSigns: Set[Byte] = Set(negativePointSign, positivePointSign) - def apply(r: ByteString, s: ByteString, v: Byte): ECDSASignature = { + def apply(r: ByteString, s: ByteString, v: Byte): ECDSASignature = ECDSASignature(BigInt(1, r.toArray), BigInt(1, s.toArray), v) - } - def fromBytes(bytes65: ByteString): Option[ECDSASignature] = { + def fromBytes(bytes65: ByteString): Option[ECDSASignature] = if (bytes65.length == EncodedLength) Some(apply(bytes65.take(RLength), bytes65.drop(RLength).take(SLength), bytes65.last)) else None - } def sign(messageHash: ByteString, prvKey: ByteString): ECDSASignature = sign(messageHash.toArray, keyPairFromPrvKey(prvKey.toArray), None) @@ -63,18 +65,17 @@ object ECDSASignature { val pointSign = chainId match { case Some(id) if v == negativePointSign => (id * 2 + newNegativePointSign).toByte case Some(id) if v == positivePointSign => (id * 2 + newPositivePointSign).toByte - case None => v - case _ => throw new IllegalStateException(s"Unexpected pointSign. ChainId: ${chainId}, v: ${v}") + case None => v + case _ => throw new IllegalStateException(s"Unexpected pointSign. ChainId: ${chainId}, v: ${v}") } ECDSASignature(r, s, pointSign) } - /** - * new formula for calculating point sign post EIP 155 adoption + /** new formula for calculating point sign post EIP 155 adoption * v = CHAIN_ID * 2 + 35 or v = CHAIN_ID * 2 + 36 */ - private def getRecoveredPointSign(pointSign: Byte, chainId: Option[Byte]): Option[Byte] = { + private def getRecoveredPointSign(pointSign: Byte, chainId: Option[Byte]): Option[Byte] = (chainId match { case Some(id) => if (pointSign == negativePointSign || pointSign == (id * 2 + newNegativePointSign).toByte) { @@ -86,7 +87,6 @@ object ECDSASignature { } case None => Some(pointSign) }).filter(pointSign => allowedPointSigns.contains(pointSign)) - } private def canonicalise(s: BigInt): BigInt = { val halfCurveOrder: BigInt = curveParams.getN.shiftRight(1) @@ -109,7 +109,7 @@ object ECDSASignature { recId: Byte, chainId: Option[Byte], messageHash: Array[Byte] - ): Option[Array[Byte]] = { + ): Option[Array[Byte]] = Try { val order = curve.getCurve.getOrder //ignore case when x = r + order because it is negligibly improbable @@ -132,7 +132,6 @@ object ECDSASignature { } else None } }.toOption.flatten - } private def constructPoint(xCoordinate: BigInt, recId: Int): ECPoint = { val x9 = new X9IntegerConverter @@ -142,8 +141,7 @@ object ECDSASignature { } } -/** - * ECDSASignature r and s are same as in documentation where signature is represented by tuple (r, s) +/** ECDSASignature r and s are same as in documentation where signature is represented by tuple (r, s) * * The `publicKey` method is also the way to verify the signature: if the key can be retrieved based * on the signed message, the signature is correct, otherwise it isn't. @@ -154,8 +152,7 @@ object ECDSASignature { */ case class ECDSASignature(r: BigInt, s: BigInt, v: Byte) { - /** - * returns ECC point encoded with on compression and without leading byte indicating compression + /** returns ECC point encoded with on compression and without leading byte indicating compression * @param messageHash message to be signed; should be a hash of the actual data. * @param chainId optional value if you want new signing schema with recovery id calculated with chain id * @return @@ -163,8 +160,7 @@ case class ECDSASignature(r: BigInt, s: BigInt, v: Byte) { def publicKey(messageHash: Array[Byte], chainId: Option[Byte] = None): Option[Array[Byte]] = ECDSASignature.recoverPubBytes(r, s, v, chainId, messageHash) - /** - * returns ECC point encoded with on compression and without leading byte indicating compression + /** returns ECC point encoded with on compression and without leading byte indicating compression * @param messageHash message to be signed; should be a hash of the actual data. * @return */ diff --git a/crypto/src/main/scala/io/iohk/ethereum/crypto/ECIESCoder.scala b/crypto/src/main/scala/io/iohk/ethereum/crypto/ECIESCoder.scala index a5a728837e..f10d5b26f3 100644 --- a/crypto/src/main/scala/io/iohk/ethereum/crypto/ECIESCoder.scala +++ b/crypto/src/main/scala/io/iohk/ethereum/crypto/ECIESCoder.scala @@ -1,16 +1,18 @@ package io.iohk.ethereum.crypto -import java.io.{ByteArrayInputStream, IOException} +import java.io.ByteArrayInputStream +import java.io.IOException import java.math.BigInteger import java.security.SecureRandom +import org.bouncycastle.crypto.BufferedBlockCipher +import org.bouncycastle.crypto.InvalidCipherTextException import org.bouncycastle.crypto.digests.SHA256Digest import org.bouncycastle.crypto.engines.AESEngine import org.bouncycastle.crypto.generators.ECKeyPairGenerator import org.bouncycastle.crypto.macs.HMac import org.bouncycastle.crypto.modes.SICBlockCipher import org.bouncycastle.crypto.params._ -import org.bouncycastle.crypto.{BufferedBlockCipher, InvalidCipherTextException} import org.bouncycastle.math.ec.ECPoint object ECIESCoder { @@ -18,7 +20,7 @@ object ECIESCoder { val KeySize = 128 val PublicKeyOverheadSize = 65 val MacOverheadSize = 32 - val OverheadSize = PublicKeyOverheadSize + KeySize / 8 + MacOverheadSize + val OverheadSize: Int = PublicKeyOverheadSize + KeySize / 8 + MacOverheadSize @throws[IOException] @throws[InvalidCipherTextException] diff --git a/crypto/src/main/scala/io/iohk/ethereum/crypto/EthereumIESEngine.scala b/crypto/src/main/scala/io/iohk/ethereum/crypto/EthereumIESEngine.scala index e0c5dcbfad..160e324b9a 100644 --- a/crypto/src/main/scala/io/iohk/ethereum/crypto/EthereumIESEngine.scala +++ b/crypto/src/main/scala/io/iohk/ethereum/crypto/EthereumIESEngine.scala @@ -3,15 +3,22 @@ package io.iohk.ethereum.crypto import java.io.ByteArrayInputStream import akka.util.ByteString + +import org.bouncycastle.crypto.BufferedBlockCipher +import org.bouncycastle.crypto.Digest +import org.bouncycastle.crypto.InvalidCipherTextException +import org.bouncycastle.crypto.Mac import org.bouncycastle.crypto.agreement.ECDHBasicAgreement import org.bouncycastle.crypto.generators.ECKeyPairGenerator -import org.bouncycastle.crypto.params.{ECPrivateKeyParameters, ECPublicKeyParameters, KeyParameter, ParametersWithIV} +import org.bouncycastle.crypto.params.ECPrivateKeyParameters +import org.bouncycastle.crypto.params.ECPublicKeyParameters +import org.bouncycastle.crypto.params.KeyParameter +import org.bouncycastle.crypto.params.ParametersWithIV import org.bouncycastle.crypto.parsers.ECIESPublicKeyParser -import org.bouncycastle.crypto.{BufferedBlockCipher, Digest, InvalidCipherTextException, Mac} -import org.bouncycastle.util.{Arrays, BigIntegers} +import org.bouncycastle.util.Arrays +import org.bouncycastle.util.BigIntegers -/** - * Support class for constructing integrated encryption cipher +/** Support class for constructing integrated encryption cipher * for doing basic message exchanges on top of key agreement ciphers. * Follows the description given in IEEE Std 1363a with a couple of changes * specific to Ethereum: @@ -19,8 +26,7 @@ import org.bouncycastle.util.{Arrays, BigIntegers} * - Include the encryption IV in the MAC computation */ -/** - * set up for use with stream mode, where the key derivation function +/** set up for use with stream mode, where the key derivation function * is used to provide a stream of bytes to xor with the message. * * @param kdf the key derivation function used for byte generation @@ -62,7 +68,7 @@ class EthereumIESEngine( IV match { case Some(iv) => cphr.init(true, new ParametersWithIV(new KeyParameter(firstPart.toArray), iv)) - case None => cphr.init(true, new KeyParameter(firstPart.toArray)) + case None => cphr.init(true, new KeyParameter(firstPart.toArray)) } val encrypted = new Array[Byte](cphr.getOutputSize(inLen)) @@ -119,7 +125,7 @@ class EthereumIESEngine( IV match { case Some(iv) => cphr.init(false, new ParametersWithIV(new KeyParameter(firstPart.toArray), iv)) - case None => cphr.init(false, new KeyParameter(firstPart.toArray)) + case None => cphr.init(false, new KeyParameter(firstPart.toArray)) } val decrypted = new Array[Byte](cphr.getOutputSize(inLen - encodedPublicKey.length - mac.getMacSize)) @@ -157,7 +163,7 @@ class EthereumIESEngine( inLen - encodedPublicKey.length - messageAuthenticationCodeCalculated.length ) - macData foreach { data => mac.update(data, 0, data.length) } + macData.foreach(data => mac.update(data, 0, data.length)) mac.doFinal(messageAuthenticationCodeCalculated, 0) if (!Arrays.constantTimeAreEqual(messageAuthenticationCode, messageAuthenticationCodeCalculated)) diff --git a/crypto/src/main/scala/io/iohk/ethereum/crypto/MGF1BytesGeneratorExt.scala b/crypto/src/main/scala/io/iohk/ethereum/crypto/MGF1BytesGeneratorExt.scala index 7049540277..d840560bef 100644 --- a/crypto/src/main/scala/io/iohk/ethereum/crypto/MGF1BytesGeneratorExt.scala +++ b/crypto/src/main/scala/io/iohk/ethereum/crypto/MGF1BytesGeneratorExt.scala @@ -1,10 +1,10 @@ package io.iohk.ethereum.crypto import akka.util.ByteString + import org.bouncycastle.crypto.Digest -/** - * This class is borrowed from bouncycastle project +/** This class is borrowed from bouncycastle project * The only change made is addition of 'counterStart' parameter to * conform to Crypto++ capabilities */ diff --git a/crypto/src/main/scala/io/iohk/ethereum/crypto/SymmetricCipher.scala b/crypto/src/main/scala/io/iohk/ethereum/crypto/SymmetricCipher.scala index 36e341473b..c966f483f2 100644 --- a/crypto/src/main/scala/io/iohk/ethereum/crypto/SymmetricCipher.scala +++ b/crypto/src/main/scala/io/iohk/ethereum/crypto/SymmetricCipher.scala @@ -2,13 +2,16 @@ package io.iohk.ethereum.crypto import akka.util.ByteString +import scala.util.Try + import org.bouncycastle.crypto.BufferedBlockCipher import org.bouncycastle.crypto.engines.AESEngine -import org.bouncycastle.crypto.modes.{CBCBlockCipher, SICBlockCipher} -import org.bouncycastle.crypto.paddings.{PKCS7Padding, PaddedBufferedBlockCipher} -import org.bouncycastle.crypto.params.{KeyParameter, ParametersWithIV} - -import scala.util.Try +import org.bouncycastle.crypto.modes.CBCBlockCipher +import org.bouncycastle.crypto.modes.SICBlockCipher +import org.bouncycastle.crypto.paddings.PKCS7Padding +import org.bouncycastle.crypto.paddings.PaddedBufferedBlockCipher +import org.bouncycastle.crypto.params.KeyParameter +import org.bouncycastle.crypto.params.ParametersWithIV trait SymmetricCipher { def encrypt(secret: ByteString, iv: ByteString, message: ByteString): ByteString = diff --git a/crypto/src/main/scala/io/iohk/ethereum/crypto/package.scala b/crypto/src/main/scala/io/iohk/ethereum/crypto/package.scala index d288449eec..799da4db49 100644 --- a/crypto/src/main/scala/io/iohk/ethereum/crypto/package.scala +++ b/crypto/src/main/scala/io/iohk/ethereum/crypto/package.scala @@ -4,15 +4,21 @@ import java.nio.charset.StandardCharsets import java.security.SecureRandom import akka.util.ByteString -import io.iohk.ethereum.utils.ByteUtils + import org.bouncycastle.asn1.sec.SECNamedCurves import org.bouncycastle.asn1.x9.X9ECParameters import org.bouncycastle.crypto.AsymmetricCipherKeyPair -import org.bouncycastle.crypto.digests.{KeccakDigest, RIPEMD160Digest, SHA256Digest} -import org.bouncycastle.crypto.generators.{ECKeyPairGenerator, PKCS5S2ParametersGenerator, SCrypt} +import org.bouncycastle.crypto.digests.KeccakDigest +import org.bouncycastle.crypto.digests.RIPEMD160Digest +import org.bouncycastle.crypto.digests.SHA256Digest +import org.bouncycastle.crypto.generators.ECKeyPairGenerator +import org.bouncycastle.crypto.generators.PKCS5S2ParametersGenerator +import org.bouncycastle.crypto.generators.SCrypt import org.bouncycastle.crypto.params._ import org.bouncycastle.util.encoders.Hex +import io.iohk.ethereum.utils.ByteUtils + package object crypto { val curveParams: X9ECParameters = SECNamedCurves.getByName("secp256k1") diff --git a/crypto/src/main/scala/io/iohk/ethereum/crypto/zksnark/BN128.scala b/crypto/src/main/scala/io/iohk/ethereum/crypto/zksnark/BN128.scala index fd5bad1d60..d27a738c8b 100644 --- a/crypto/src/main/scala/io/iohk/ethereum/crypto/zksnark/BN128.scala +++ b/crypto/src/main/scala/io/iohk/ethereum/crypto/zksnark/BN128.scala @@ -1,11 +1,11 @@ package io.iohk.ethereum.crypto.zksnark import akka.util.ByteString + import io.iohk.ethereum.crypto.zksnark.BN128.Point import io.iohk.ethereum.crypto.zksnark.FiniteField.Ops._ -/** - * Barreto–Naehrig curve over some finite field +/** Barreto–Naehrig curve over some finite field * Curve equation: * Y^2^ = X^3^ + b, where "b" is a constant number belonging to corresponding specific field * @@ -17,20 +17,19 @@ import io.iohk.ethereum.crypto.zksnark.FiniteField.Ops._ * */ sealed abstract class BN128[T: FiniteField] { - val zero = Point(FiniteField[T].zero, FiniteField[T].zero, FiniteField[T].zero) + val zero: Point[T] = Point(FiniteField[T].zero, FiniteField[T].zero, FiniteField[T].zero) def Fp_B: T - protected def createPointOnCurve(x: T, y: T): Option[Point[T]] = { + protected def createPointOnCurve(x: T, y: T): Option[Point[T]] = if (x.isZero() && y.isZero()) Some(zero) else { val point = Point(x, y, FiniteField[T].one) Some(point).filter(isValidPoint) } - } - def toAffineCoordinates(p1: Point[T]): Point[T] = { + def toAffineCoordinates(p1: Point[T]): Point[T] = if (p1.isZero) Point(zero.x, FiniteField[T].one, zero.z) else { @@ -42,7 +41,6 @@ sealed abstract class BN128[T: FiniteField] { val ay = p1.y * zInvMul Point(ax, ay, FiniteField[T].one) } - } def toEthNotation(p1: Point[T]): Point[T] = { val affine = toAffineCoordinates(p1) @@ -53,11 +51,10 @@ sealed abstract class BN128[T: FiniteField] { affine } - /** - * Point is on curve when its coordinates (x, y) satisfy curve equation which in jacobian coordinates becomes + /** Point is on curve when its coordinates (x, y) satisfy curve equation which in jacobian coordinates becomes * Y^2^ = X^3^ + b * Z^6^ */ - def isOnCurve(p1: Point[T]): Boolean = { + def isOnCurve(p1: Point[T]): Boolean = if (p1.isZero) true else { @@ -66,9 +63,8 @@ sealed abstract class BN128[T: FiniteField] { val r = (p1.x.squared() * p1.x) + (Fp_B * z6) l == r } - } - def add(p1: Point[T], p2: Point[T]): Point[T] = { + def add(p1: Point[T], p2: Point[T]): Point[T] = if (p1.isZero) p2 else if (p2.isZero) @@ -103,9 +99,8 @@ sealed abstract class BN128[T: FiniteField] { Point(x3, y3, z3) } } - } - def dbl(p1: Point[T]): Point[T] = { + def dbl(p1: Point[T]): Point[T] = if (p1.isZero) p1 else { @@ -125,14 +120,11 @@ sealed abstract class BN128[T: FiniteField] { Point(x3, y3, z3) } - } - - /** - * Multiplication by scalar n is just addition n times e.g n * P = P + P + .. n times. + /** Multiplication by scalar n is just addition n times e.g n * P = P + P + .. n times. * Faster algorithm is used here, which is known as: * Double-and-add */ - def mul(p1: Point[T], s: BigInt): Point[T] = { + def mul(p1: Point[T], s: BigInt): Point[T] = if (s == 0 || p1.isZero) zero else { @@ -147,7 +139,6 @@ sealed abstract class BN128[T: FiniteField] { } result } - } def isValidPoint(p1: Point[T]): Boolean = p1.isValid && isOnCurve(p1) @@ -186,47 +177,41 @@ object BN128 { case class BN128G1(p: Point[Fp]) object BN128G1 { - /** - * Constructs valid element of subgroup `G1` + /** Constructs valid element of subgroup `G1` * To be valid element of subgroup, elements needs to be valid point (have valid coordinates in Fp_2 and to be on curve * Bn128 in Fp * @return [[scala.None]] if element is invald group element, [[io.iohk.ethereum.crypto.zksnark.BN128.BN128G1]] */ - def apply(xx: ByteString, yy: ByteString): Option[BN128G1] = { + def apply(xx: ByteString, yy: ByteString): Option[BN128G1] = // Every element of our Fp is also element of subgroup G1 BN128Fp.createPoint(xx, yy).map(new BN128G1(_)) - } } case class BN128G2(p: Point[Fp2]) object BN128G2 { import BN128Fp2._ - /** - * "r" order of cyclic subgroup + /** "r" order of cyclic subgroup */ - val R = BigInt("21888242871839275222246405745257275088548364400416034343698204186575808495617") + val R: BigInt = BigInt("21888242871839275222246405745257275088548364400416034343698204186575808495617") private val negOneModR = (-BigInt(1)).mod(R) - private def isGroupElement(p: Point[Fp2]): Boolean = { + private def isGroupElement(p: Point[Fp2]): Boolean = add(mul(p, negOneModR), p).isZero // -1 * p + p == 0 - } - /** - * Constructs valid element of subgroup `G2` + /** Constructs valid element of subgroup `G2` * To be valid element of subgroup, elements needs to be valid point (have valid coordinates in Fp_2 and to be on curve * Bn128 in Fp_2) and fullfill the equation `-1 * p + p == 0` * @return [[scala.None]] if element is invald group element, [[io.iohk.ethereum.crypto.zksnark.BN128.BN128G2]] */ - def apply(a: ByteString, b: ByteString, c: ByteString, d: ByteString): Option[BN128G2] = { + def apply(a: ByteString, b: ByteString, c: ByteString, d: ByteString): Option[BN128G2] = createPoint(a, b, c, d).flatMap { point => if (isGroupElement(point)) Some(BN128G2(point)) else None } - } def mulByP(p: Point[Fp2]): Point[Fp2] = { val rx = Fp2.TWIST_MUL_BY_P_X * Fp2.frobeniusMap(p.x, 1) diff --git a/crypto/src/main/scala/io/iohk/ethereum/crypto/zksnark/FieldElement.scala b/crypto/src/main/scala/io/iohk/ethereum/crypto/zksnark/FieldElement.scala index a1b769eb5c..1ab380a1c2 100644 --- a/crypto/src/main/scala/io/iohk/ethereum/crypto/zksnark/FieldElement.scala +++ b/crypto/src/main/scala/io/iohk/ethereum/crypto/zksnark/FieldElement.scala @@ -1,8 +1,9 @@ package io.iohk.ethereum.crypto.zksnark import akka.util.ByteString -import io.iohk.ethereum.utils.ByteUtils + import io.iohk.ethereum.crypto.zksnark.FiniteField.Ops._ +import io.iohk.ethereum.utils.ByteUtils // Arithmetic in on all finite fields described in: // https://eprint.iacr.org/2010/354.pdf - 'High-Speed Software Implementation of the Optimal Ate Pairing over Barreto–Naehrig Curves' @@ -12,26 +13,22 @@ case class Fp(inner: BigInt) extends FieldElement object Fp { - /** - * "p" field parameter of F_p, F_p2, F_p6 and F_p12 + /** "p" field parameter of F_p, F_p2, F_p6 and F_p12 */ val P: BigInt = BigInt("21888242871839275222246405745257275088696311157297823662689037894645226208583") - /** - * "b" curve parameter for BN128Fp + /** "b" curve parameter for BN128Fp */ val B_Fp: Fp = Fp(BigInt(3)) - val twoInv = Fp(BigInt(2).modInverse(P)) + val twoInv: Fp = Fp(BigInt(2).modInverse(P)) - val NON_RESIDUE = Fp(BigInt("21888242871839275222246405745257275088696311157297823662689037894645226208582")) + val NON_RESIDUE: Fp = Fp(BigInt("21888242871839275222246405745257275088696311157297823662689037894645226208582")) - def apply(inner: ByteString): Fp = { + def apply(inner: ByteString): Fp = new Fp(ByteUtils.toBigInt(inner)) - } - /** - * Implementation of finite field "Fp" modular arithmetic + /** Implementation of finite field "Fp" modular arithmetic */ implicit object FpImpl extends FiniteField[Fp] { override def zero: Fp = Fp(BigInt(0)) @@ -39,15 +36,15 @@ object Fp { override def one: Fp = Fp(BigInt(1)) override def add(a: Fp, b: Fp): Fp = Fp { - (a.inner + b.inner) mod P + (a.inner + b.inner).mod(P) } override def mul(a: Fp, b: Fp): Fp = Fp { - (a.inner * b.inner) mod P + (a.inner * b.inner).mod(P) } override def sub(a: Fp, b: Fp): Fp = Fp { - (a.inner - b.inner) mod P + (a.inner - b.inner).mod(P) } override def inv(a: Fp): Fp = Fp { @@ -55,12 +52,11 @@ object Fp { } override def neg(a: Fp): Fp = Fp { - (-a.inner) mod P + (-a.inner).mod(P) } - override def isValid(a: Fp): Boolean = { + override def isValid(a: Fp): Boolean = a.inner >= 0 && a.inner < P - } override def isZero(a: Fp): Boolean = a.inner == BigInt(0) @@ -72,25 +68,23 @@ case class Fp2(a: Fp, b: Fp) extends FieldElement object Fp2 { // It is also Twist for Fp2 - val NON_RESIDUE = Fp2(Fp(BigInt(9)), Fp(BigInt(1))) + val NON_RESIDUE: Fp2 = Fp2(Fp(BigInt(9)), Fp(BigInt(1))) - val TWIST_MUL_BY_P_X = Fp2( + val TWIST_MUL_BY_P_X: Fp2 = Fp2( Fp(BigInt("21575463638280843010398324269430826099269044274347216827212613867836435027261")), Fp(BigInt("10307601595873709700152284273816112264069230130616436755625194854815875713954")) ) - val TWIST_MUL_BY_P_Y = Fp2( + val TWIST_MUL_BY_P_Y: Fp2 = Fp2( Fp(BigInt("2821565182194536844548159561693502659359617185244120367078079554186484126554")), Fp(BigInt("3505843767911556378687030309984248845540243509899259641013678093033130930403")) ) - def apply(inner1: ByteString, inner2: ByteString): Fp2 = { + def apply(inner1: ByteString, inner2: ByteString): Fp2 = new Fp2(Fp(inner1), Fp(inner2)) - } - def mulByConst(a: Fp2, c: Fp): Fp2 = { + def mulByConst(a: Fp2, c: Fp): Fp2 = Fp2(a.a * c, a.b * c) - } private val FROBENIUS_COEFFS_B: Array[Fp] = Array[Fp]( FiniteField[Fp].one, @@ -108,13 +102,11 @@ object Fp2 { override def zero: Fp2 = Fp2(FiniteField[Fp].zero, FiniteField[Fp].zero) - override def add(a: Fp2, b: Fp2): Fp2 = { + override def add(a: Fp2, b: Fp2): Fp2 = Fp2(a.a + b.a, a.b + b.b) - } - override def sub(a: Fp2, b: Fp2): Fp2 = { + override def sub(a: Fp2, b: Fp2): Fp2 = Fp2(a.a - b.a, a.b - b.b) - } override def mul(a: Fp2, b: Fp2): Fp2 = { val aa = a.a * b.a @@ -126,9 +118,8 @@ object Fp2 { Fp2(ra, rb) } - override def neg(a: Fp2): Fp2 = { + override def neg(a: Fp2): Fp2 = Fp2(a.a.negated(), a.b.negated()) - } override def inv(a: Fp2): Fp2 = { val t0 = a.a.squared() @@ -142,15 +133,14 @@ object Fp2 { Fp2(ra, rb) } - override def isValid(a: Fp2): Boolean = { + override def isValid(a: Fp2): Boolean = a.a.isValid() && a.b.isValid() - } override def isZero(a: Fp2): Boolean = a == zero } - val B_Fp2 = mulByConst(NON_RESIDUE.inversed(), Fp.B_Fp) + val B_Fp2: Fp2 = mulByConst(NON_RESIDUE.inversed(), Fp.B_Fp) } case class Fp6(a: Fp2, b: Fp2, c: Fp2) extends FieldElement @@ -434,9 +424,8 @@ object Fp12 { def negExp(a: Fp12, exp: BigInt): Fp12 = unitaryInverse(cyclotomicExp(a, exp)) - def finalExp(el: Fp12): Fp12 = { + def finalExp(el: Fp12): Fp12 = finalExpLastChunk(finalExpFirstChunk(el)) - } private def finalExpFirstChunk(el: Fp12): Fp12 = { val a = unitaryInverse(el) @@ -477,7 +466,7 @@ object Fp12 { v } - val pairingFinalExp = BigInt("4965661367192848881") + val pairingFinalExp: BigInt = BigInt("4965661367192848881") private val FROBENIUS_COEFFS_B: Array[Fp2] = Array[Fp2]( new Fp2(FiniteField[Fp].one, FiniteField[Fp].zero), diff --git a/crypto/src/main/scala/io/iohk/ethereum/crypto/zksnark/PairingCheck.scala b/crypto/src/main/scala/io/iohk/ethereum/crypto/zksnark/PairingCheck.scala index 34699be8f6..0da9c80aca 100644 --- a/crypto/src/main/scala/io/iohk/ethereum/crypto/zksnark/PairingCheck.scala +++ b/crypto/src/main/scala/io/iohk/ethereum/crypto/zksnark/PairingCheck.scala @@ -1,16 +1,17 @@ package io.iohk.ethereum.crypto.zksnark -import io.iohk.ethereum.crypto.zksnark.BN128.{BN128G1, BN128G2, Point} -import io.iohk.ethereum.crypto.zksnark.FiniteField.Ops._ - import scala.collection.mutable.ArrayBuffer +import io.iohk.ethereum.crypto.zksnark.BN128.BN128G1 +import io.iohk.ethereum.crypto.zksnark.BN128.BN128G2 +import io.iohk.ethereum.crypto.zksnark.BN128.Point +import io.iohk.ethereum.crypto.zksnark.FiniteField.Ops._ + object PairingCheck { - val loopCount = BigInt("29793968203157093288") + val loopCount: BigInt = BigInt("29793968203157093288") - /** - * Pairing function is defined as: `e: G_1 x G_2 -> G_T` where G1 is element of [[io.iohk.ethereum.crypto.zksnark.BN128.BN128G1]] + /** Pairing function is defined as: `e: G_1 x G_2 -> G_T` where G1 is element of [[io.iohk.ethereum.crypto.zksnark.BN128.BN128G1]] * and G2 is element of [[io.iohk.ethereum.crypto.zksnark.BN128.BN128G2]] * * Description of algorithms in optimal ate pairing @@ -33,7 +34,7 @@ object PairingCheck { Fp12.finalExp(product) == FiniteField[Fp12].one } - private def millerLoop(g1: BN128G1, g2: BN128G2): Fp12 = { + private def millerLoop(g1: BN128G1, g2: BN128G2): Fp12 = if (g1.p.isZero || g2.p.isZero) { FiniteField[Fp12].one } else { @@ -71,7 +72,6 @@ object PairingCheck { f } - } private def calcEllCoeffs(base: Point[Fp2]): Seq[EllCoeffs] = { val coeffs = new ArrayBuffer[EllCoeffs]() diff --git a/crypto/src/test/scala/io/iohk/ethereum/crypto/AesCbcSpec.scala b/crypto/src/test/scala/io/iohk/ethereum/crypto/AesCbcSpec.scala index 1442fcda6f..1784c192ee 100644 --- a/crypto/src/test/scala/io/iohk/ethereum/crypto/AesCbcSpec.scala +++ b/crypto/src/test/scala/io/iohk/ethereum/crypto/AesCbcSpec.scala @@ -1,11 +1,13 @@ package io.iohk.ethereum.crypto import java.nio.charset.StandardCharsets + import akka.util.ByteString + import org.bouncycastle.util.encoders.Hex -import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks import org.scalatest.flatspec.AnyFlatSpec import org.scalatest.matchers.should.Matchers +import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks class AesCbcSpec extends AnyFlatSpec with Matchers with ScalaCheckPropertyChecks { diff --git a/crypto/src/test/scala/io/iohk/ethereum/crypto/AesCtrSpec.scala b/crypto/src/test/scala/io/iohk/ethereum/crypto/AesCtrSpec.scala index 156e1daff7..704549713d 100644 --- a/crypto/src/test/scala/io/iohk/ethereum/crypto/AesCtrSpec.scala +++ b/crypto/src/test/scala/io/iohk/ethereum/crypto/AesCtrSpec.scala @@ -1,10 +1,11 @@ package io.iohk.ethereum.crypto import akka.util.ByteString + import org.bouncycastle.util.encoders.Hex -import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks import org.scalatest.flatspec.AnyFlatSpec import org.scalatest.matchers.should.Matchers +import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks class AesCtrSpec extends AnyFlatSpec with Matchers with ScalaCheckPropertyChecks { diff --git a/crypto/src/test/scala/io/iohk/ethereum/crypto/ECDSASignatureSpec.scala b/crypto/src/test/scala/io/iohk/ethereum/crypto/ECDSASignatureSpec.scala index c80f49ed8e..a33d449abd 100644 --- a/crypto/src/test/scala/io/iohk/ethereum/crypto/ECDSASignatureSpec.scala +++ b/crypto/src/test/scala/io/iohk/ethereum/crypto/ECDSASignatureSpec.scala @@ -1,14 +1,16 @@ package io.iohk.ethereum.crypto import akka.util.ByteString -import io.iohk.ethereum.utils.ByteStringUtils -import org.scalacheck.Arbitrary -import org.scalacheck.Arbitrary.arbitrary + import org.bouncycastle.crypto.params.ECPublicKeyParameters import org.bouncycastle.util.encoders.Hex -import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks +import org.scalacheck.Arbitrary +import org.scalacheck.Arbitrary.arbitrary import org.scalatest.flatspec.AnyFlatSpec import org.scalatest.matchers.should.Matchers +import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks + +import io.iohk.ethereum.utils.ByteStringUtils class ECDSASignatureSpec extends AnyFlatSpec with Matchers with ScalaCheckPropertyChecks with SecureRandomBuilder { "ECDSASignature" should "recover public key correctly for go ethereum transaction" in { diff --git a/crypto/src/test/scala/io/iohk/ethereum/crypto/Generators.scala b/crypto/src/test/scala/io/iohk/ethereum/crypto/Generators.scala index 37caf4be96..be13e2af13 100644 --- a/crypto/src/test/scala/io/iohk/ethereum/crypto/Generators.scala +++ b/crypto/src/test/scala/io/iohk/ethereum/crypto/Generators.scala @@ -1,7 +1,9 @@ package io.iohk.ethereum.crypto import akka.util.ByteString -import org.scalacheck.{Arbitrary, Gen} + +import org.scalacheck.Arbitrary +import org.scalacheck.Gen object Generators { diff --git a/crypto/src/test/scala/io/iohk/ethereum/crypto/Pbkdf2HMacSha256Spec.scala b/crypto/src/test/scala/io/iohk/ethereum/crypto/Pbkdf2HMacSha256Spec.scala index 50bff9802b..9f8973f6a0 100644 --- a/crypto/src/test/scala/io/iohk/ethereum/crypto/Pbkdf2HMacSha256Spec.scala +++ b/crypto/src/test/scala/io/iohk/ethereum/crypto/Pbkdf2HMacSha256Spec.scala @@ -1,11 +1,13 @@ package io.iohk.ethereum.crypto import java.nio.charset.StandardCharsets + import akka.util.ByteString + import org.bouncycastle.util.encoders.Hex -import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks import org.scalatest.flatspec.AnyFlatSpec import org.scalatest.matchers.should.Matchers +import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks class Pbkdf2HMacSha256Spec extends AnyFlatSpec with Matchers with ScalaCheckPropertyChecks { diff --git a/crypto/src/test/scala/io/iohk/ethereum/crypto/Ripemd160Spec.scala b/crypto/src/test/scala/io/iohk/ethereum/crypto/Ripemd160Spec.scala index 3623658bcd..fde66cacda 100644 --- a/crypto/src/test/scala/io/iohk/ethereum/crypto/Ripemd160Spec.scala +++ b/crypto/src/test/scala/io/iohk/ethereum/crypto/Ripemd160Spec.scala @@ -1,15 +1,17 @@ package io.iohk.ethereum.crypto import java.nio.charset.StandardCharsets + import org.bouncycastle.util.encoders.Hex -import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks import org.scalatest.funsuite.AnyFunSuite import org.scalatest.matchers.should.Matchers +import org.scalatest.prop.TableFor2 +import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks class Ripemd160Spec extends AnyFunSuite with ScalaCheckPropertyChecks with Matchers { // these examples were taken from http://homes.esat.kuleuven.be/~bosselae/ripemd160.html#Outline - val examples = Table[String, String]( + val examples: TableFor2[String, String] = Table[String, String]( ("input", "result"), ("", "9c1185a5c5e9fc54612808977ee8f548b2258d31"), ("a", "0bdc9d2d256b3ee9daae347be6f4dc835a467ffe"), diff --git a/crypto/src/test/scala/io/iohk/ethereum/crypto/ScryptSpec.scala b/crypto/src/test/scala/io/iohk/ethereum/crypto/ScryptSpec.scala index a3446dc233..03a15668ff 100644 --- a/crypto/src/test/scala/io/iohk/ethereum/crypto/ScryptSpec.scala +++ b/crypto/src/test/scala/io/iohk/ethereum/crypto/ScryptSpec.scala @@ -1,11 +1,13 @@ package io.iohk.ethereum.crypto import java.nio.charset.StandardCharsets + import akka.util.ByteString + import org.bouncycastle.util.encoders.Hex -import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks import org.scalatest.flatspec.AnyFlatSpec import org.scalatest.matchers.should.Matchers +import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks class ScryptSpec extends AnyFlatSpec with Matchers with ScalaCheckPropertyChecks { diff --git a/crypto/src/test/scala/io/iohk/ethereum/crypto/zksnarks/BN128FpSpec.scala b/crypto/src/test/scala/io/iohk/ethereum/crypto/zksnarks/BN128FpSpec.scala index 199a3c3d05..647e2056de 100644 --- a/crypto/src/test/scala/io/iohk/ethereum/crypto/zksnarks/BN128FpSpec.scala +++ b/crypto/src/test/scala/io/iohk/ethereum/crypto/zksnarks/BN128FpSpec.scala @@ -1,13 +1,16 @@ package io.iohk.ethereum.crypto.zksnarks -import io.iohk.ethereum.crypto.zksnark.BN128.Point -import io.iohk.ethereum.crypto.zksnark.{BN128Fp, Fp} -import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks import org.scalatest.funsuite.AnyFunSuite +import org.scalatest.prop.TableFor3 +import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks + +import io.iohk.ethereum.crypto.zksnark.BN128.Point +import io.iohk.ethereum.crypto.zksnark.BN128Fp +import io.iohk.ethereum.crypto.zksnark.Fp class BN128FpSpec extends AnyFunSuite with ScalaCheckPropertyChecks { - val testData = Table[Fp, Fp, Fp]( + val testData: TableFor3[Fp, Fp, Fp] = Table[Fp, Fp, Fp]( ("x", "y", "z"), (Fp(1), Fp(2), Fp(1)), ( diff --git a/crypto/src/test/scala/io/iohk/ethereum/crypto/zksnarks/FpFieldSpec.scala b/crypto/src/test/scala/io/iohk/ethereum/crypto/zksnarks/FpFieldSpec.scala index 2bab4e7f6b..71bbf59a13 100644 --- a/crypto/src/test/scala/io/iohk/ethereum/crypto/zksnarks/FpFieldSpec.scala +++ b/crypto/src/test/scala/io/iohk/ethereum/crypto/zksnarks/FpFieldSpec.scala @@ -1,12 +1,14 @@ package io.iohk.ethereum.crypto.zksnarks -import io.iohk.ethereum.crypto.zksnark._ -import io.iohk.ethereum.crypto.zksnark.FiniteField.Ops._ -import org.scalacheck.Gen +import java.math.BigInteger + import org.scalacheck.Arbitrary.arbitrary -import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks +import org.scalacheck.Gen import org.scalatest.funsuite.AnyFunSuite -import java.math.BigInteger +import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks + +import io.iohk.ethereum.crypto.zksnark.FiniteField.Ops._ +import io.iohk.ethereum.crypto.zksnark._ abstract class FieldSpec[T: FiniteField] extends AnyFunSuite with ScalaCheckPropertyChecks { val bigIntGen: Gen[BigInteger] = for { diff --git a/nix/overlay.nix b/nix/overlay.nix index c328a4c530..ba096b6f0e 100644 --- a/nix/overlay.nix +++ b/nix/overlay.nix @@ -3,7 +3,7 @@ rev: final: prev: { mantis = final.callPackage ./mantis.nix { src = ../.; - depsSha256 = "sha256-vzp0pLLhuXFvb+DIVFeiIviBho6K0e5Xymo617EgIm8="; + depsSha256 = "sha256-9XlUBMUe1jQyqguhQgk5DAZ9UtcG6JyCWaBZsIbzBDY="; }; mantis-hash = final.mantis.override { diff --git a/project/plugins.sbt b/project/plugins.sbt index b146ede58e..b9e8f92420 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -12,3 +12,4 @@ addSbtPlugin("org.scalameta" % "sbt-scalafmt" % "2.4.2") addSbtPlugin("org.scalastyle" %% "scalastyle-sbt-plugin" % "1.0.0") addSbtPlugin("org.scoverage" % "sbt-scoverage" % "1.6.1") addSbtPlugin("com.geirsson" % "sbt-ci-release" % "1.5.6") +addSbtPlugin("ch.epfl.scala" % "sbt-scalafix" % "0.9.29") diff --git a/rlp/src/main/scala/io/iohk/ethereum/rlp/RLP.scala b/rlp/src/main/scala/io/iohk/ethereum/rlp/RLP.scala index 9af998fb22..91e56c75e8 100644 --- a/rlp/src/main/scala/io/iohk/ethereum/rlp/RLP.scala +++ b/rlp/src/main/scala/io/iohk/ethereum/rlp/RLP.scala @@ -2,11 +2,11 @@ package io.iohk.ethereum.rlp import java.nio.ByteBuffer -import scala.annotation.{switch, tailrec} +import scala.annotation.switch +import scala.annotation.tailrec import scala.collection.immutable.Queue -/** - * Recursive Length Prefix (RLP) encoding. +/** Recursive Length Prefix (RLP) encoding. *

* The purpose of RLP is to encode arbitrarily nested arrays of binary data, and * RLP is the main encoding method used to serialize objects in Ethereum. The @@ -34,8 +34,7 @@ import scala.collection.immutable.Queue private[rlp] object RLP { - /** - * Reason for threshold according to Vitalik Buterin: + /** Reason for threshold according to Vitalik Buterin: * - 56 bytes maximizes the benefit of both options * - if we went with 60 then we would have only had 4 slots for long strings * so RLP would not have been able to store objects above 4gb @@ -45,8 +44,7 @@ private[rlp] object RLP { */ private val SizeThreshold: Int = 56 - /** - * Allow for content up to size of 2^64 bytes * + /** Allow for content up to size of 2^64 bytes * */ private val MaxItemLength: Double = Math.pow(256, 8) @@ -57,16 +55,14 @@ private[rlp] object RLP { * its own RLP encoding. */ - /** - * [0x80] + /** [0x80] * If a string is 0-55 bytes long, the RLP encoding consists of a single * byte with value 0x80 plus the length of the string followed by the * string. The range of the first byte is thus [0x80, 0xb7]. */ private val OffsetShortItem: Int = 0x80 - /** - * [0xb7] + /** [0xb7] * If a string is more than 55 bytes long, the RLP encoding consists of a * single byte with value 0xb7 plus the length of the length of the string * in binary form, followed by the length of the string, followed by the @@ -76,8 +72,7 @@ private[rlp] object RLP { */ private val OffsetLongItem: Int = 0xb7 - /** - * [0xc0] + /** [0xc0] * If the total payload of a list (i.e. the combined length of all its * items) is 0-55 bytes long, the RLP encoding consists of a single byte * with value 0xc0 plus the length of the list followed by the concatenation @@ -86,8 +81,7 @@ private[rlp] object RLP { */ private val OffsetShortList: Int = 0xc0 - /** - * [0xf7] + /** [0xf7] * If the total payload of a list is more than 55 bytes long, the RLP * encoding consists of a single byte with value 0xf7 plus the length of the * length of the list in binary form, followed by the length of the list, @@ -96,8 +90,7 @@ private[rlp] object RLP { */ private val OffsetLongList = 0xf7 - /** - * This functions decodes an RLP encoded Array[Byte] without converting it to any specific type. This method should + /** This functions decodes an RLP encoded Array[Byte] without converting it to any specific type. This method should * be faster (as no conversions are done) * * @param data RLP Encoded instance to be decoded @@ -106,68 +99,59 @@ private[rlp] object RLP { */ private[rlp] def rawDecode(data: Array[Byte]): RLPEncodeable = decodeWithPos(data, 0)._1 - /** - * This function encodes an RLPEncodeable instance + /** This function encodes an RLPEncodeable instance * * @param input RLP Instance to be encoded * @return A byte array with item encoded */ - private[rlp] def encode(input: RLPEncodeable): Array[Byte] = { + private[rlp] def encode(input: RLPEncodeable): Array[Byte] = input match { case list: RLPList => - val output = list.items.foldLeft(Array[Byte]()) { (acum, item) => acum ++ encode(item) } + val output = list.items.foldLeft(Array[Byte]())((acum, item) => acum ++ encode(item)) encodeLength(output.length, OffsetShortList) ++ output case value: RLPValue => val inputAsBytes = value.bytes if (inputAsBytes.length == 1 && (inputAsBytes(0) & 0xff) < 0x80) inputAsBytes else encodeLength(inputAsBytes.length, OffsetShortItem) ++ inputAsBytes } - } - /** - * This function transform a byte into byte array + /** This function transform a byte into byte array * * @param singleByte to encode * @return encoded bytes */ - private[rlp] def byteToByteArray(singleByte: Byte): Array[Byte] = { + private[rlp] def byteToByteArray(singleByte: Byte): Array[Byte] = if ((singleByte & 0xff) == 0) Array.emptyByteArray else Array[Byte](singleByte) - } - /** - * This function converts a short value to a big endian byte array of minimal length + /** This function converts a short value to a big endian byte array of minimal length * * @param singleShort value to encode * @return encoded bytes */ - private[rlp] def shortToBigEndianMinLength(singleShort: Short): Array[Byte] = { + private[rlp] def shortToBigEndianMinLength(singleShort: Short): Array[Byte] = if ((singleShort & 0xff) == singleShort) byteToByteArray(singleShort.toByte) else Array[Byte]((singleShort >> 8 & 0xff).toByte, (singleShort >> 0 & 0xff).toByte) - } - /** - * This function converts an int value to a big endian byte array of minimal length + /** This function converts an int value to a big endian byte array of minimal length * * @param singleInt value to encode * @return encoded bytes */ - private[rlp] def intToBigEndianMinLength(singleInt: Int): Array[Byte] = { + private[rlp] def intToBigEndianMinLength(singleInt: Int): Array[Byte] = if (singleInt == (singleInt & 0xff)) byteToByteArray(singleInt.toByte) else if (singleInt == (singleInt & 0xffff)) shortToBigEndianMinLength(singleInt.toShort) else if (singleInt == (singleInt & 0xffffff)) Array[Byte]((singleInt >>> 16).toByte, (singleInt >>> 8).toByte, singleInt.toByte) else Array[Byte]((singleInt >>> 24).toByte, (singleInt >>> 16).toByte, (singleInt >>> 8).toByte, singleInt.toByte) - } - /** - * This function converts from a big endian byte array of minimal length to an int value + /** This function converts from a big endian byte array of minimal length to an int value * * @param bytes encoded bytes * @return Int value * @throws RLPException If the value cannot be converted to a valid int */ - private[rlp] def bigEndianMinLengthToInt(bytes: Array[Byte]): Int = { + private[rlp] def bigEndianMinLengthToInt(bytes: Array[Byte]): Int = (bytes.length: @switch) match { case 0 => 0: Short case 1 => bytes(0) & 0xff @@ -177,10 +161,8 @@ private[rlp] object RLP { ((bytes(0) & 0xff) << 24) + ((bytes(1) & 0xff) << 16) + ((bytes(2) & 0xff) << 8) + (bytes(3) & 0xff) case _ => throw RLPException("Bytes don't represent an int") } - } - /** - * Converts a int value into a byte array. + /** Converts a int value into a byte array. * * @param value - int value to convert * @return value with leading byte that are zeroes striped @@ -188,27 +170,24 @@ private[rlp] object RLP { private def intToBytesNoLeadZeroes(value: Int): Array[Byte] = ByteBuffer.allocate(Integer.BYTES).putInt(value).array().dropWhile(_ == (0: Byte)) - /** - * Integer limitation goes up to 2^31-1 so length can never be bigger than MAX_ITEM_LENGTH + /** Integer limitation goes up to 2^31-1 so length can never be bigger than MAX_ITEM_LENGTH */ - private def encodeLength(length: Int, offset: Int): Array[Byte] = { + private def encodeLength(length: Int, offset: Int): Array[Byte] = if (length < SizeThreshold) Array((length + offset).toByte) else if (length < MaxItemLength && length > 0xff) { val binaryLength: Array[Byte] = intToBytesNoLeadZeroes(length) (binaryLength.length + offset + SizeThreshold - 1).toByte +: binaryLength } else if (length < MaxItemLength && length <= 0xff) Array((1 + offset + SizeThreshold - 1).toByte, length.toByte) else throw RLPException("Input too long") - } - /** - * This function calculates, based on RLP definition, the bounds of a single value. + /** This function calculates, based on RLP definition, the bounds of a single value. * * @param data An Array[Byte] containing the RLP item to be searched * @param pos Initial position to start searching * @return Item Bounds description * @see [[io.iohk.ethereum.rlp.ItemBounds]] */ - private[rlp] def getItemBounds(data: Array[Byte], pos: Int): ItemBounds = { + private[rlp] def getItemBounds(data: Array[Byte], pos: Int): ItemBounds = if (data.isEmpty) throw RLPException("Empty Data") else { val prefix: Int = data(pos) & 0xff @@ -236,7 +215,6 @@ private[rlp] object RLP { ItemBounds(start = beginPos, end = beginPos + length - 1, isList = true) } } - } private def decodeWithPos(data: Array[Byte], pos: Int): (RLPEncodeable, Int) = if (data.isEmpty) throw RLPException("data is too short") @@ -255,13 +233,12 @@ private[rlp] object RLP { pos: Int, length: Int, acum: Queue[RLPEncodeable] - ): (Queue[RLPEncodeable]) = { + ): (Queue[RLPEncodeable]) = if (length == 0) acum else { val (decoded, decodedEnd) = decodeWithPos(data, pos) decodeListRecursive(data, decodedEnd, length - (decodedEnd - pos), acum :+ decoded) } - } } private case class ItemBounds(start: Int, end: Int, isList: Boolean, isEmpty: Boolean = false) diff --git a/rlp/src/main/scala/io/iohk/ethereum/rlp/RLPImplicitConversions.scala b/rlp/src/main/scala/io/iohk/ethereum/rlp/RLPImplicitConversions.scala index a6018e4a69..8db558ce2c 100644 --- a/rlp/src/main/scala/io/iohk/ethereum/rlp/RLPImplicitConversions.scala +++ b/rlp/src/main/scala/io/iohk/ethereum/rlp/RLPImplicitConversions.scala @@ -1,10 +1,11 @@ package io.iohk.ethereum.rlp import akka.util.ByteString -import io.iohk.ethereum.rlp.RLPImplicits._ import scala.language.implicitConversions +import io.iohk.ethereum.rlp.RLPImplicits._ + object RLPImplicitConversions { implicit def toEncodeable[T](value: T)(implicit enc: RLPEncoder[T]): RLPEncodeable = enc.encode(value) diff --git a/rlp/src/main/scala/io/iohk/ethereum/rlp/RLPImplicitDerivations.scala b/rlp/src/main/scala/io/iohk/ethereum/rlp/RLPImplicitDerivations.scala index c445a5e9e3..78ab66d776 100644 --- a/rlp/src/main/scala/io/iohk/ethereum/rlp/RLPImplicitDerivations.scala +++ b/rlp/src/main/scala/io/iohk/ethereum/rlp/RLPImplicitDerivations.scala @@ -1,9 +1,17 @@ package io.iohk.ethereum.rlp -import shapeless.{HList, HNil, Lazy, ::, LabelledGeneric, <:!<, Witness} -import shapeless.labelled.{FieldType, field} -import scala.util.control.NonFatal import scala.reflect.ClassTag +import scala.util.control.NonFatal + +import shapeless.:: +import shapeless.<:!< +import shapeless.HList +import shapeless.HNil +import shapeless.LabelledGeneric +import shapeless.Lazy +import shapeless.Witness +import shapeless.labelled.FieldType +import shapeless.labelled.field /** Automatically derive RLP codecs for case classes. */ object RLPImplicitDerivations { @@ -15,7 +23,7 @@ object RLPImplicitDerivations { omitTrailingOptionals: Boolean ) object DerivationPolicy { - val default = DerivationPolicy(omitTrailingOptionals = false) + val default: DerivationPolicy = DerivationPolicy(omitTrailingOptionals = false) } /** Support introspecting on what happened during encoding the tail. */ @@ -135,7 +143,7 @@ object RLPImplicitDerivations { policy: DerivationPolicy = DerivationPolicy.default ): RLPListDecoder[HNil] = RLPListDecoder { - case Nil => HNil -> Nil + case Nil => HNil -> Nil case _ if policy.omitTrailingOptionals => HNil -> Nil case items => throw RLPException( @@ -179,9 +187,8 @@ object RLPImplicitDerivations { tryDecode(subject, rlps.head) { rlp => if (policy.omitTrailingOptionals && tInfos.forall(_.isOptional)) { // Expect that it's a value. We have a decoder for optional fields, so we have to wrap it into a list. - try { - hDecoder.value.decode(RLPList(rlp)) - } catch { + try hDecoder.value.decode(RLPList(rlp)) + catch { case NonFatal(_) => // The trailing fields can be followed in the RLP list by additional items // and random data which we cannot decode. diff --git a/rlp/src/main/scala/io/iohk/ethereum/rlp/RLPImplicits.scala b/rlp/src/main/scala/io/iohk/ethereum/rlp/RLPImplicits.scala index ce48f42dcc..510cd306f3 100644 --- a/rlp/src/main/scala/io/iohk/ethereum/rlp/RLPImplicits.scala +++ b/rlp/src/main/scala/io/iohk/ethereum/rlp/RLPImplicits.scala @@ -1,13 +1,15 @@ package io.iohk.ethereum.rlp import akka.util.ByteString + import io.iohk.ethereum.rlp.RLP._ import io.iohk.ethereum.utils.ByteUtils + import RLPCodec.Ops object RLPImplicits { - implicit val byteEncDec = new RLPEncoder[Byte] with RLPDecoder[Byte] { + implicit val byteEncDec: RLPEncoder[Byte] with RLPDecoder[Byte] = new RLPEncoder[Byte] with RLPDecoder[Byte] { override def encode(obj: Byte): RLPValue = RLPValue(byteToByteArray(obj)) override def decode(rlp: RLPEncodeable): Byte = rlp match { @@ -22,7 +24,7 @@ object RLPImplicits { } } - implicit val shortEncDec = new RLPEncoder[Short] with RLPDecoder[Short] { + implicit val shortEncDec: RLPEncoder[Short] with RLPDecoder[Short] = new RLPEncoder[Short] with RLPDecoder[Short] { override def encode(obj: Short): RLPValue = RLPValue(shortToBigEndianMinLength(obj)) override def decode(rlp: RLPEncodeable): Short = rlp match { @@ -38,17 +40,18 @@ object RLPImplicits { } } - implicit val intEncDec = new RLPEncoder[Int] with RLPDecoder[Int] { + implicit val intEncDec: RLPEncoder[Int] with RLPDecoder[Int] = new RLPEncoder[Int] with RLPDecoder[Int] { override def encode(obj: Int): RLPValue = RLPValue(intToBigEndianMinLength(obj)) override def decode(rlp: RLPEncodeable): Int = rlp match { case RLPValue(bytes) => bigEndianMinLengthToInt(bytes) - case _ => throw RLPException("src is not an RLPValue", rlp) + case _ => throw RLPException("src is not an RLPValue", rlp) } } //Used for decoding and encoding positive (or 0) BigInts - implicit val bigIntEncDec = new RLPEncoder[BigInt] with RLPDecoder[BigInt] { + implicit val bigIntEncDec: RLPEncoder[BigInt] with RLPDecoder[BigInt] = new RLPEncoder[BigInt] + with RLPDecoder[BigInt] { override def encode(obj: BigInt): RLPValue = RLPValue( if (obj.equals(BigInt(0))) byteToByteArray(0: Byte) else ByteUtils.bigIntToUnsignedByteArray(obj) @@ -56,42 +59,45 @@ object RLPImplicits { override def decode(rlp: RLPEncodeable): BigInt = rlp match { case RLPValue(bytes) => - bytes.foldLeft[BigInt](BigInt(0)) { (rec, byte) => (rec << (8: Int)) + BigInt(byte & 0xff) } + bytes.foldLeft[BigInt](BigInt(0))((rec, byte) => (rec << (8: Int)) + BigInt(byte & 0xff)) case _ => throw RLPException("src is not an RLPValue", rlp) } } //Used for decoding and encoding positive (or 0) longs - implicit val longEncDec = new RLPEncoder[Long] with RLPDecoder[Long] { - override def encode(obj: Long): RLPValue = bigIntEncDec.encode(BigInt(obj)) + implicit val longEncDec: RLPEncoder[Long] with RLPDecoder[Long] = new RLPEncoder[Long] with RLPDecoder[Long] { + override def encode(obj: Long): RLPEncodeable = bigIntEncDec.encode(BigInt(obj)) override def decode(rlp: RLPEncodeable): Long = rlp match { case RLPValue(bytes) if bytes.length <= 8 => bigIntEncDec.decode(rlp).toLong - case RLPValue(bytes) => throw RLPException(s"expected max 8 bytes for Long; got ${bytes.length}", rlp) - case _ => throw RLPException(s"src is not an RLPValue", rlp) + case RLPValue(bytes) => throw RLPException(s"expected max 8 bytes for Long; got ${bytes.length}", rlp) + case _ => throw RLPException(s"src is not an RLPValue", rlp) } } - implicit val stringEncDec = new RLPEncoder[String] with RLPDecoder[String] { + implicit val stringEncDec: RLPEncoder[String] with RLPDecoder[String] = new RLPEncoder[String] + with RLPDecoder[String] { override def encode(obj: String): RLPValue = RLPValue(obj.getBytes) override def decode(rlp: RLPEncodeable): String = rlp match { case RLPValue(bytes) => new String(bytes) - case _ => throw RLPException("src is not an RLPValue", rlp) + case _ => throw RLPException("src is not an RLPValue", rlp) } } - implicit val byteArrayEncDec = new RLPEncoder[Array[Byte]] with RLPDecoder[Array[Byte]] { + implicit val byteArrayEncDec: RLPEncoder[Array[Byte]] with RLPDecoder[Array[Byte]] = new RLPEncoder[Array[Byte]] + with RLPDecoder[Array[Byte]] { override def encode(obj: Array[Byte]): RLPValue = RLPValue(obj) override def decode(rlp: RLPEncodeable): Array[Byte] = rlp match { case RLPValue(bytes) => bytes - case _ => throw RLPException("src is not an RLPValue", rlp) + case _ => throw RLPException("src is not an RLPValue", rlp) } } - implicit val byteStringEncDec = new RLPEncoder[ByteString] with RLPDecoder[ByteString] { + implicit val byteStringEncDec: RLPEncoder[ByteString] with RLPDecoder[ByteString] = new RLPEncoder[ByteString] + with RLPDecoder[ByteString] { override def encode(obj: ByteString): RLPEncodeable = byteArrayEncDec.encode(obj.toArray[Byte]) override def decode(rlp: RLPEncodeable): ByteString = ByteString(byteArrayEncDec.decode(rlp)) @@ -106,7 +112,7 @@ object RLPImplicits { override def decode(rlp: RLPEncodeable): Seq[T] = rlp match { case l: RLPList => l.items.map(dec.decode) - case _ => throw RLPException("src is not a Seq", rlp) + case _ => throw RLPException("src is not a Seq", rlp) } } @@ -114,18 +120,19 @@ object RLPImplicits { seqEncDec[T]().xmap(_.toList, _.toSeq) implicit def optionEnc[T](implicit enc: RLPEncoder[T]): RLPEncoder[Option[T]] = { - case None => RLPList() + case None => RLPList() case Some(value) => RLPList(enc.encode(value)) } implicit def optionDec[T](implicit dec: RLPDecoder[T]): RLPDecoder[Option[T]] = { case RLPList(value) => Some(dec.decode(value)) - case RLPList() => None - case rlp => throw RLPException(s"${rlp} should be a list with 1 or 0 elements", rlp) + case RLPList() => None + case rlp => throw RLPException(s"${rlp} should be a list with 1 or 0 elements", rlp) } - implicit val booleanEncDec = new RLPEncoder[Boolean] with RLPDecoder[Boolean] { - override def encode(obj: Boolean): RLPValue = { + implicit val booleanEncDec: RLPEncoder[Boolean] with RLPDecoder[Boolean] = new RLPEncoder[Boolean] + with RLPDecoder[Boolean] { + override def encode(obj: Boolean): RLPEncodeable = { val intRepresentation: Int = if (obj) 1 else 0 intEncDec.encode(intRepresentation) } diff --git a/rlp/src/main/scala/io/iohk/ethereum/rlp/package.scala b/rlp/src/main/scala/io/iohk/ethereum/rlp/package.scala index 8bc758325e..78ac363c00 100644 --- a/rlp/src/main/scala/io/iohk/ethereum/rlp/package.scala +++ b/rlp/src/main/scala/io/iohk/ethereum/rlp/package.scala @@ -1,8 +1,10 @@ package io.iohk.ethereum import akka.util.ByteString + import scala.reflect.ClassTag import scala.util.control.NonFatal + import io.iohk.ethereum.utils.Hex package object rlp { @@ -82,19 +84,16 @@ package object rlp { def rawDecode(input: Array[Byte]): RLPEncodeable = RLP.rawDecode(input) - def tryDecode[T](subject: => String, encodeable: RLPEncodeable)(f: RLPEncodeable => T): T = { - try { - f(encodeable) - } catch { + def tryDecode[T](subject: => String, encodeable: RLPEncodeable)(f: RLPEncodeable => T): T = + try f(encodeable) + catch { case RLPException(message, encodeables) => RLPException.decodeError(subject, message, encodeable :: encodeables) case NonFatal(ex) => RLPException.decodeError(subject, ex.getMessage, List(encodeable)) } - } - /** - * This function calculates the next element item based on a previous element starting position. It's meant to be + /** This function calculates the next element item based on a previous element starting position. It's meant to be * used while decoding a stream of RLPEncoded Items. * * @param data Data with encoded items diff --git a/rlp/src/test/scala/io/iohk/ethereum/rlp/RLPSuite.scala b/rlp/src/test/scala/io/iohk/ethereum/rlp/RLPSuite.scala index 0d005a4171..f3a1328013 100644 --- a/rlp/src/test/scala/io/iohk/ethereum/rlp/RLPSuite.scala +++ b/rlp/src/test/scala/io/iohk/ethereum/rlp/RLPSuite.scala @@ -1,42 +1,47 @@ package io.iohk.ethereum.rlp import akka.util.ByteString -import io.iohk.ethereum.rlp.RLPImplicitConversions._ -import io.iohk.ethereum.rlp.RLPImplicits._ -import io.iohk.ethereum.utils.Hex -import org.scalacheck.{Arbitrary, Gen} -import org.scalatestplus.scalacheck.{ScalaCheckDrivenPropertyChecks, ScalaCheckPropertyChecks} + import scala.language.implicitConversions import scala.util.Try + +import org.scalacheck.Arbitrary +import org.scalacheck.Gen import org.scalatest.funsuite.AnyFunSuite +import org.scalatestplus.scalacheck.ScalaCheckDrivenPropertyChecks +import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks + +import io.iohk.ethereum.rlp.RLPImplicitConversions._ +import io.iohk.ethereum.rlp.RLPImplicits._ +import io.iohk.ethereum.utils.Hex class RLPSuite extends AnyFunSuite with ScalaCheckPropertyChecks with ScalaCheckDrivenPropertyChecks { test("nextElementIndex of empty data") { - val maybeIndex = Try { nextElementIndex(Array.emptyByteArray, 0) } + val maybeIndex = Try(nextElementIndex(Array.emptyByteArray, 0)) assert(maybeIndex.isFailure) } test("Decoding of empty data") { - val maybeDecoded = Try { decode[Array[Byte]](Array.emptyByteArray) } + val maybeDecoded = Try(decode[Array[Byte]](Array.emptyByteArray)) assert(maybeDecoded.isFailure) } test("Decoding failure: Passing RLPValue when RLPList is expected") { val data = encode(0.toLong) - val maybeSeqObtained = Try { decode[Seq[Long]](data)(seqEncDec()) } + val maybeSeqObtained = Try(decode[Seq[Long]](data)(seqEncDec())) assert(maybeSeqObtained.isFailure) } test("Decoding failure: Passing RLPList when RLPValue is expected") { val data = RLP.encode(RLPList("cat", "dog")) - val maybeByteObtained = Try { decode[Byte](data) } - val maybeShortObtained = Try { decode[Short](data) } - val maybeIntObtained = Try { decode[Int](data) } - val maybeLongObtained = Try { decode[Long](data) } - val maybeBigIntObtained = Try { decode[BigInt](data) } - val maybeStringObtained = Try { decode[String](data) } - val maybeByteArrayObtained = Try { decode[Array[Byte]](data) } + val maybeByteObtained = Try(decode[Byte](data)) + val maybeShortObtained = Try(decode[Short](data)) + val maybeIntObtained = Try(decode[Int](data)) + val maybeLongObtained = Try(decode[Long](data)) + val maybeBigIntObtained = Try(decode[BigInt](data)) + val maybeStringObtained = Try(decode[String](data)) + val maybeByteArrayObtained = Try(decode[Array[Byte]](data)) assert(maybeByteObtained.isFailure) assert(maybeShortObtained.isFailure) assert(maybeIntObtained.isFailure) @@ -49,10 +54,10 @@ class RLPSuite extends AnyFunSuite with ScalaCheckPropertyChecks with ScalaCheck test("Decoding failure: Passing an RLPValue larger than expected") { val num: BigInt = 16 * BigInt(Long.MaxValue) val data = encode(num) - val maybeByteObtained = Try { decode[Byte](data) } - val maybeShortObtained = Try { decode[Short](data) } - val maybeIntObtained = Try { decode[Int](data) } - val maybeLongObtained = Try { decode[Long](data) } + val maybeByteObtained = Try(decode[Byte](data)) + val maybeShortObtained = Try(decode[Short](data)) + val maybeIntObtained = Try(decode[Int](data)) + val maybeLongObtained = Try(decode[Long](data)) assert(maybeByteObtained.isFailure) assert(maybeShortObtained.isFailure) assert(maybeIntObtained.isFailure) @@ -63,85 +68,81 @@ class RLPSuite extends AnyFunSuite with ScalaCheckPropertyChecks with ScalaCheck val expected = Array[Byte](0x80.toByte) val data = encode(0: Byte) - assert(expected sameElements data) + assert(expected.sameElements(data)) val dataObtained = decode[Byte](data) val obtained: Byte = dataObtained assert((0: Byte) == obtained) val expected2 = Array[Byte](0x78.toByte) val data2 = encode(120: Byte) - assert(expected2 sameElements data2) + assert(expected2.sameElements(data2)) val dataObtained2 = decode[Byte](data2) val obtained2: Byte = dataObtained2 assert((120: Byte) == obtained2) val expected3 = Array[Byte](0x7f.toByte) val data3 = encode(127: Byte) - assert(expected3 sameElements data3) + assert(expected3.sameElements(data3)) val dataObtained3 = decode[Byte](data3) val obtained3: Byte = dataObtained3 assert((127: Byte) == obtained3) forAll(Gen.choose[Byte](Byte.MinValue, Byte.MaxValue)) { (aByte: Byte) => - { - val data = encode(aByte) - val dataObtained = decode[Byte](data) - val obtained: Byte = dataObtained - assert(aByte == obtained) - } + val data = encode(aByte) + val dataObtained = decode[Byte](data) + val obtained: Byte = dataObtained + assert(aByte == obtained) } } test("Short Encoding") { val expected4 = Array[Byte](0x82.toByte, 0x76.toByte, 0x5f.toByte) val data4 = encode(30303.toShort) - assert(expected4 sameElements data4) + assert(expected4.sameElements(data4)) val dataObtained4 = decode[Short](data4) val obtained4: Short = dataObtained4 assert((30303: Short) == obtained4) val expected5 = Array[Byte](0x82.toByte, 0x4e.toByte, 0xea.toByte) val data5 = encode(20202.toShort) - assert(expected5 sameElements data5) + assert(expected5.sameElements(data5)) val dataObtained5 = decode[Short](data5) val obtained5: Short = dataObtained5 assert((20202: Short) == obtained5) val expected6 = Array[Byte](0x82.toByte, 0x9d.toByte, 0x0a.toByte) val data6 = encode(40202.toShort) - assert(expected6 sameElements data6) + assert(expected6.sameElements(data6)) val dataObtained6 = decode[Short](data6) val obtained6: Short = dataObtained6 assert(40202.toShort == obtained6) val expected7 = Array[Byte](0x7f.toByte) val data7 = encode(127.toShort) - assert(expected7 sameElements data7) + assert(expected7.sameElements(data7)) val dataObtained7 = decode[Short](data7) val obtained7: Short = dataObtained7 assert(127.toShort == obtained7) val expected8 = Array[Byte](0x80.toByte) val data8 = encode(0.toShort) - assert(expected8 sameElements data8) + assert(expected8.sameElements(data8)) val dataObtained8 = decode[Short](data8) val obtained8: Short = dataObtained8 assert(0.toShort == obtained8) forAll(Gen.choose[Short](Short.MinValue, Short.MaxValue)) { (aShort: Short) => - { - val data = encode(aShort) - val dataObtained = decode[Short](data) - val obtained: Short = dataObtained - assert(aShort == obtained) - } + val data = encode(aShort) + val dataObtained = decode[Short](data) + val obtained: Short = dataObtained + assert(aShort == obtained) } } test("String encoding") { val expected = Array[Byte](0x80.toByte) val data = encode("") - assert(expected sameElements data) + assert(expected.sameElements(data)) val dataObtained = decode[String](data) val obtained: String = dataObtained assert("" == obtained) @@ -166,7 +167,7 @@ class RLPSuite extends AnyFunSuite with ScalaCheckPropertyChecks with ScalaCheck 0x74.toByte ) val data2 = encode("EthereumJ Client") - assert(expected2 sameElements data2) + assert(expected2.sameElements(data2)) val dataObtained2 = decode[String](data2) val obtained2: String = dataObtained2 assert("EthereumJ Client" == obtained2) @@ -220,7 +221,7 @@ class RLPSuite extends AnyFunSuite with ScalaCheckPropertyChecks with ScalaCheck 0x2b.toByte ) val data3 = encode("Ethereum(++)/ZeroGox/v0.5.0/ncurses/Linux/g++") - assert(expected3 sameElements data3) + assert(expected3.sameElements(data3)) val dataObtained3 = decode[String](data3) val obtained3: String = dataObtained3 assert("Ethereum(++)/ZeroGox/v0.5.0/ncurses/Linux/g++" == obtained3) @@ -320,7 +321,7 @@ class RLPSuite extends AnyFunSuite with ScalaCheckPropertyChecks with ScalaCheck 0x2b.toByte ) val data4 = encode("Ethereum(++)/ZeroGox/v0.5.0/ncurses/Linux/g++Ethereum(++)/ZeroGox/v0.5.0/ncurses/Linux/g++") - assert(expected4 sameElements data4) + assert(expected4.sameElements(data4)) val dataObtained4 = decode[String](data4) val obtained4: String = dataObtained4 assert("Ethereum(++)/ZeroGox/v0.5.0/ncurses/Linux/g++Ethereum(++)/ZeroGox/v0.5.0/ncurses/Linux/g++" == obtained4) @@ -328,104 +329,98 @@ class RLPSuite extends AnyFunSuite with ScalaCheckPropertyChecks with ScalaCheck val strGen = (n: Int) => Gen.choose(0, n).flatMap(long => Gen.listOfN(long, Gen.alphaChar).map(_.mkString)) forAll(strGen(10000)) { (aString: String) => - { - val data = encode(aString) - val dataObtained = decode[String](data) - val obtained: String = dataObtained - assert(aString == obtained) - } + val data = encode(aString) + val dataObtained = decode[String](data) + val obtained: String = dataObtained + assert(aString == obtained) } } test("Int Encoding") { val expected = Array[Byte](0x80.toByte) val data = encode(0) - assert(expected sameElements data) + assert(expected.sameElements(data)) val dataObtained = decode[Int](data) val obtained: Int = dataObtained assert(0 == obtained) val expected2 = Array(0x78.toByte) val data2 = encode(120) - assert(expected2 sameElements data2) + assert(expected2.sameElements(data2)) val dataObtained2 = decode[Int](data2) val obtained2: Int = dataObtained2 assert(120 == obtained2) val expected3 = Array(0x7f.toByte) val data3 = encode(127) - assert(expected3 sameElements data3) + assert(expected3.sameElements(data3)) val dataObtained3 = decode[Int](data3) val obtained3: Int = dataObtained3 assert(127 == obtained3) val expected4 = Array(0x82.toByte, 0x76.toByte, 0x5f.toByte) val data4 = encode(30303) - assert(expected4 sameElements data4) + assert(expected4.sameElements(data4)) val dataObtained4 = decode[Int](data4) val obtained4: Int = dataObtained4 assert(30303 == obtained4) val expected5 = Array(0x82.toByte, 0x4e.toByte, 0xea.toByte) val data5 = encode(20202) - assert(expected5 sameElements data5) + assert(expected5.sameElements(data5)) val dataObtained5 = decode[Int](data5) val obtained5: Int = dataObtained5 assert(20202 == obtained5) val expected6 = Array(0x83.toByte, 1.toByte, 0.toByte, 0.toByte) val data6 = encode(65536) - assert(expected6 sameElements data6) + assert(expected6.sameElements(data6)) val dataObtained6 = decode[Int](data6) val obtained6: Int = dataObtained6 assert(65536 == obtained6) val expected7 = Array(0x84.toByte, 0x80.toByte, 0x00.toByte, 0x00.toByte, 0x00.toByte) val data7 = encode(Integer.MIN_VALUE) - assert(expected7 sameElements data7) + assert(expected7.sameElements(data7)) val dataObtained7 = decode[Int](data7) val obtained7: Int = dataObtained7 assert(Integer.MIN_VALUE == obtained7) val expected8 = Array(0x84.toByte, 0x7f.toByte, 0xff.toByte, 0xff.toByte, 0xff.toByte) val data8 = encode(Integer.MAX_VALUE) - assert(expected8 sameElements data8) + assert(expected8.sameElements(data8)) val dataObtained8 = decode[Int](data8) val obtained8: Int = dataObtained8 assert(Integer.MAX_VALUE == obtained8) val expected9 = Array(0x84.toByte, 0xff.toByte, 0xff.toByte, 0xff.toByte, 0xff.toByte) val data9 = encode(0xffffffff) - assert(expected9 sameElements data9) + assert(expected9.sameElements(data9)) val dataObtained9 = decode[Int](data9) val obtained9: Int = dataObtained9 assert(0xffffffff == obtained9) forAll(Gen.choose[Int](Int.MinValue, Int.MaxValue)) { (anInt: Int) => - { - val data = encode(anInt) - val dataObtained = decode[Int](data) - val obtained: Int = dataObtained - assert(anInt == obtained) - } + val data = encode(anInt) + val dataObtained = decode[Int](data) + val obtained: Int = dataObtained + assert(anInt == obtained) } } test("Long Encoding") { forAll(Gen.choose[Long](0, Long.MaxValue)) { (aLong: Long) => - { - val data = encode(aLong) - val dataObtained = decode[Long](data) - val obtained: Long = dataObtained - assert(aLong == obtained) - } + val data = encode(aLong) + val dataObtained = decode[Long](data) + val obtained: Long = dataObtained + assert(aLong == obtained) } } test("BigInt Encoding") { val expected = Array[Byte](0x80.toByte) val data = encode(BigInt(0)) - assert(expected sameElements data) + assert(expected.sameElements(data)) val dataObtained = decode[BigInt](data) val obtained: BigInt = dataObtained assert(BigInt(0) == obtained) @@ -433,19 +428,17 @@ class RLPSuite extends AnyFunSuite with ScalaCheckPropertyChecks with ScalaCheck val bigInt = BigInt("100102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", 16) val expected2 = "a0100102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f" val data2 = encode(bigInt) - assert(expected2 equals Hex.toHexString(data2)) + assert(expected2.equals(Hex.toHexString(data2))) val dataObtained2 = decode[BigInt](data2) val obtained2: BigInt = dataObtained2 assert(bigInt == obtained2) forAll(Arbitrary.arbitrary[BigInt]) { (aBigIntSigned: BigInt) => - { - val aBigInt = aBigIntSigned.abs - val data = encode(aBigInt) - val dataObtained = decode[BigInt](data) - val obtained: BigInt = dataObtained - assert(aBigInt == obtained) - } + val aBigInt = aBigIntSigned.abs + val data = encode(aBigInt) + val dataObtained = decode[BigInt](data) + val obtained: BigInt = dataObtained + assert(aBigInt == obtained) } } @@ -456,10 +449,10 @@ class RLPSuite extends AnyFunSuite with ScalaCheckPropertyChecks with ScalaCheck val expected = "b840" + byteArr val data = encode(byteArray) - assert(expected equals Hex.toHexString(data)) + assert(expected.equals(Hex.toHexString(data))) val dataObtained = decode[Array[Byte]](data) val obtained: Array[Byte] = dataObtained - assert(byteArray sameElements obtained) + assert(byteArray.sameElements(obtained)) val shouldBeError = Try { val byteArray255Elements = Array.fill(255)(0x1.toByte) @@ -468,35 +461,29 @@ class RLPSuite extends AnyFunSuite with ScalaCheckPropertyChecks with ScalaCheck assert(shouldBeError.isSuccess) forAll(Gen.nonEmptyListOf(Arbitrary.arbitrary[Byte])) { (aByteList: List[Byte]) => - { - val data = encode(aByteList.toArray) - val dataObtained = decode[Array[Byte]](data) - val obtained: Array[Byte] = dataObtained - assert(aByteList.toArray sameElements obtained) - } + val data = encode(aByteList.toArray) + val dataObtained = decode[Array[Byte]](data) + val obtained: Array[Byte] = dataObtained + assert(aByteList.toArray.sameElements(obtained)) } } test("Encode ByteString") { forAll(Gen.nonEmptyListOf(Arbitrary.arbitrary[Byte])) { (aByteList: List[Byte]) => - { - val byteString = ByteString(aByteList.toArray) - val data = encode(byteString) - val dataObtained = decode[ByteString](data) - val obtained: ByteString = dataObtained - assert(byteString equals obtained) - } + val byteString = ByteString(aByteList.toArray) + val data = encode(byteString) + val dataObtained = decode[ByteString](data) + val obtained: ByteString = dataObtained + assert(byteString.equals(obtained)) } } test("Encode Seq") { forAll(Gen.nonEmptyListOf(Gen.choose[Long](0, Long.MaxValue))) { (aLongList: List[Long]) => - { - val aLongSeq: Seq[Long] = aLongList - val data = encode(aLongSeq)(seqEncDec()) - val dataObtained: Seq[Long] = decode[Seq[Long]](data)(seqEncDec()) - assert(aLongSeq equals dataObtained) - } + val aLongSeq: Seq[Long] = aLongList + val data = encode(aLongSeq)(seqEncDec()) + val dataObtained: Seq[Long] = decode[Seq[Long]](data)(seqEncDec()) + assert(aLongSeq.equals(dataObtained)) } } @@ -516,14 +503,14 @@ class RLPSuite extends AnyFunSuite with ScalaCheckPropertyChecks with ScalaCheck assert(expected == Hex.toHexString(data)) val dataObtained = decode[Seq[String]](data)(stringSeqEncDec) val obtained = dataObtained - assert(Seq("cat", "dog") equals obtained) + assert(Seq("cat", "dog").equals(obtained)) val expected2 = "cc83646f6783676f6483636174" val data2 = RLP.encode(RLPList("dog", "god", "cat")) assert(expected2 == Hex.toHexString(data2)) val dataObtained2 = decode[Seq[String]](data2)(stringSeqEncDec) val obtained2 = dataObtained2 - assert(Seq("dog", "god", "cat") equals obtained2) + assert(Seq("dog", "god", "cat").equals(obtained2)) } test("Encode Long List") { @@ -534,7 +521,7 @@ class RLPSuite extends AnyFunSuite with ScalaCheckPropertyChecks with ScalaCheck assert(expected == Hex.toHexString(data)) val dataObtained = decode[Seq[String]](data)(stringSeqEncDec) val obtained = dataObtained - assert(list equals obtained) + assert(list.equals(obtained)) } test("Encode multilist") { @@ -544,7 +531,7 @@ class RLPSuite extends AnyFunSuite with ScalaCheckPropertyChecks with ScalaCheck assert(expected == Hex.toHexString(data)) val dataObtained = decode[MultiList1](data) val obtained = dataObtained - assert(multilist1 equals obtained) + assert(multilist1.equals(obtained)) val multilist2 = MultiList2(Seq("cat", "dog"), Seq(1, 2)) val expected2 = "cdc88363617483646f67c20102c0" @@ -552,7 +539,7 @@ class RLPSuite extends AnyFunSuite with ScalaCheckPropertyChecks with ScalaCheck assert(expected2 == Hex.toHexString(data2)) val dataObtained2 = decode[MultiList2](data2) val obtained2 = dataObtained2 - assert(multilist2 equals obtained2) + assert(multilist2.equals(obtained2)) } test("Encode Empty List Of List") { @@ -562,7 +549,7 @@ class RLPSuite extends AnyFunSuite with ScalaCheckPropertyChecks with ScalaCheck assert(expected == Hex.toHexString(data)) val dataObtained = decode[EmptyListOfList](data) val obtained = dataObtained - assert(emptyListOfList equals obtained) + assert(emptyListOfList.equals(obtained)) } test("Encode Rep Of Two List Of List") { @@ -572,7 +559,7 @@ class RLPSuite extends AnyFunSuite with ScalaCheckPropertyChecks with ScalaCheck assert(expected == Hex.toHexString(data)) val dataObtained = decode[RepOfTwoListOfList](data) val obtained = dataObtained - assert(twoListOfList equals obtained) + assert(twoListOfList.equals(obtained)) } test("https://github.com/ethereum/tests/blob/master/rlptest.txt") { @@ -582,7 +569,7 @@ class RLPSuite extends AnyFunSuite with ScalaCheckPropertyChecks with ScalaCheck val dataObtained = RLP.rawDecode(data) val obtained: RLPEncodeable = dataObtained val encodedAgain = RLP.encode(obtained) - assert(data sameElements encodedAgain) + assert(data.sameElements(encodedAgain)) } } @@ -594,7 +581,7 @@ class RLPSuite extends AnyFunSuite with ScalaCheckPropertyChecks with ScalaCheck val data = encode(block)(TestSimpleBlock.encDec) val dataObtained = decode[TestSimpleBlock](data) val obtained: TestSimpleBlock = dataObtained - assert(block equals obtained) + assert(block.equals(obtained)) } test("Partial Data Parse Test") { @@ -612,15 +599,15 @@ class RLPSuite extends AnyFunSuite with ScalaCheckPropertyChecks with ScalaCheck val data = Seq(RLP.encode(seq1), RLP.encode(seq2), RLP.encode(seq3)).reduce(_ ++ _) val decoded1 = decode[Seq[String]](data) - assert(decoded1 equals "cat" :: "dog" :: Nil) + assert(decoded1.equals("cat" :: "dog" :: Nil)) val secondItemIndex = nextElementIndex(data, 0) val decoded2 = decode[Seq[Int]](data.drop(secondItemIndex)) - assert(decoded2 equals 23 :: 10 :: 1986 :: Nil) + assert(decoded2.equals(23 :: 10 :: 1986 :: Nil)) val thirdItemIndex = nextElementIndex(data, secondItemIndex) val decoded3 = decode[Seq[String]](data.drop(thirdItemIndex)) - assert(decoded3 equals Seq("cat", "Lorem ipsum dolor sit amet, consectetur adipisicing elit")) + assert(decoded3.equals(Seq("cat", "Lorem ipsum dolor sit amet, consectetur adipisicing elit"))) } implicit def emptySeqEncDec: RLPEncoder[Seq[Any]] with RLPDecoder[Seq[Any]] = new RLPEncoder[Seq[Any]] @@ -629,28 +616,30 @@ class RLPSuite extends AnyFunSuite with ScalaCheckPropertyChecks with ScalaCheck override def decode(rlp: RLPEncodeable): Seq[Any] = rlp match { case l: RLPList if l.items.isEmpty => Seq() - case _ => throw new Exception("src is not an empty Seq") + case _ => throw new Exception("src is not an empty Seq") } } - implicit val stringSeqEncDec = new RLPEncoder[Seq[String]] with RLPDecoder[Seq[String]] { + implicit val stringSeqEncDec: RLPEncoder[Seq[String]] with RLPDecoder[Seq[String]] = new RLPEncoder[Seq[String]] + with RLPDecoder[Seq[String]] { override def encode(strings: Seq[String]): RLPEncodeable = RLPList(strings.map(stringEncDec.encode): _*) override def decode(rlp: RLPEncodeable): Seq[String] = rlp match { case l: RLPList => l.items.map(item => item: String) - case _ => throw new RuntimeException("Invalid String Seq Decoder") + case _ => throw new RuntimeException("Invalid String Seq Decoder") } } implicit def stringSeqFromEncodeable(rlp: RLPEncodeable)(implicit dec: RLPDecoder[Seq[String]]): Seq[String] = dec.decode(rlp) - implicit val intSeqEncDec = new RLPEncoder[Seq[Int]] with RLPDecoder[Seq[Int]] { + implicit val intSeqEncDec: RLPEncoder[Seq[Int]] with RLPDecoder[Seq[Int]] = new RLPEncoder[Seq[Int]] + with RLPDecoder[Seq[Int]] { override def encode(ints: Seq[Int]): RLPEncodeable = ints: RLPList override def decode(rlp: RLPEncodeable): Seq[Int] = rlp match { case l: RLPList => l.items.map(item => item: Int) - case _ => throw new RuntimeException("Invalid Int Seq Decoder") + case _ => throw new RuntimeException("Invalid Int Seq Decoder") } } @@ -659,7 +648,8 @@ class RLPSuite extends AnyFunSuite with ScalaCheckPropertyChecks with ScalaCheck case class MultiList1(number: Int, seq1: Seq[String], string: String, seq2: Seq[Int]) object MultiList1 { - implicit val encDec = new RLPEncoder[MultiList1] with RLPDecoder[MultiList1] { + implicit val encDec: RLPEncoder[MultiList1] with RLPDecoder[MultiList1] = new RLPEncoder[MultiList1] + with RLPDecoder[MultiList1] { override def encode(obj: MultiList1): RLPEncodeable = { import obj._ RLPList(number, seq1, string, seq2) @@ -667,7 +657,7 @@ class RLPSuite extends AnyFunSuite with ScalaCheckPropertyChecks with ScalaCheck override def decode(rlp: RLPEncodeable): MultiList1 = rlp match { case l: RLPList => MultiList1(l.items.head, l.items(1), l.items(2), l.items(3)) - case _ => throw new RuntimeException("Invalid Int Seq Decoder") + case _ => throw new RuntimeException("Invalid Int Seq Decoder") } } } @@ -675,7 +665,8 @@ class RLPSuite extends AnyFunSuite with ScalaCheckPropertyChecks with ScalaCheck case class MultiList2(seq1: Seq[String], seq2: Seq[Int], seq3: Seq[Any] = Seq()) object MultiList2 { - implicit val encDec = new RLPEncoder[MultiList2] with RLPDecoder[MultiList2] { + implicit val encDec: RLPEncoder[MultiList2] with RLPDecoder[MultiList2] = new RLPEncoder[MultiList2] + with RLPDecoder[MultiList2] { override def encode(obj: MultiList2): RLPEncodeable = { import obj._ RLPList(seq1, seq2, seq3) @@ -683,7 +674,7 @@ class RLPSuite extends AnyFunSuite with ScalaCheckPropertyChecks with ScalaCheck override def decode(rlp: RLPEncodeable): MultiList2 = rlp match { case l: RLPList => MultiList2(l.items.head, l.items(1), emptySeqEncDec.decode(l.items(2))) - case _ => throw new RuntimeException("Invalid Int Seq Decoder") + case _ => throw new RuntimeException("Invalid Int Seq Decoder") } } } @@ -691,16 +682,17 @@ class RLPSuite extends AnyFunSuite with ScalaCheckPropertyChecks with ScalaCheck case class EmptyListOfList() object EmptyListOfList { - val instance = Seq(RLPList(RLPList(), RLPList()), RLPList()) + val instance: Seq[RLPList] = Seq(RLPList(RLPList(), RLPList()), RLPList()) - implicit val encDec = new RLPEncoder[EmptyListOfList] with RLPDecoder[EmptyListOfList] { + implicit val encDec: RLPEncoder[EmptyListOfList] with RLPDecoder[EmptyListOfList] = new RLPEncoder[EmptyListOfList] + with RLPDecoder[EmptyListOfList] { override def encode(obj: EmptyListOfList): RLPEncodeable = RLPList(instance: _*) override def decode(rlp: RLPEncodeable): EmptyListOfList = rlp match { case l: RLPList => l.items match { case items if items == instance => EmptyListOfList() - case _ => throw new RuntimeException("Invalid EmptyListOfList Decoder") + case _ => throw new RuntimeException("Invalid EmptyListOfList Decoder") } case _ => throw new RuntimeException("Invalid EmptyListOfList Decoder") } @@ -710,20 +702,21 @@ class RLPSuite extends AnyFunSuite with ScalaCheckPropertyChecks with ScalaCheck case class RepOfTwoListOfList() object RepOfTwoListOfList { - val instance = Seq(RLPList(), RLPList(RLPList()), RLPList(RLPList(), RLPList(RLPList()))) - - implicit val encDec = new RLPEncoder[RepOfTwoListOfList] with RLPDecoder[RepOfTwoListOfList] { - override def encode(obj: RepOfTwoListOfList): RLPEncodeable = RLPList(instance: _*) - - override def decode(rlp: RLPEncodeable): RepOfTwoListOfList = rlp match { - case l: RLPList => - l.items match { - case items if items == instance => RepOfTwoListOfList() - case _ => throw new RuntimeException("Invalid RepOfTwoListOfList Decoder") - } - case _ => throw new RuntimeException("Invalid RepOfTwoListOfList Decoder") + val instance: Seq[RLPList] = Seq(RLPList(), RLPList(RLPList()), RLPList(RLPList(), RLPList(RLPList()))) + + implicit val encDec: RLPEncoder[RepOfTwoListOfList] with RLPDecoder[RepOfTwoListOfList] = + new RLPEncoder[RepOfTwoListOfList] with RLPDecoder[RepOfTwoListOfList] { + override def encode(obj: RepOfTwoListOfList): RLPEncodeable = RLPList(instance: _*) + + override def decode(rlp: RLPEncodeable): RepOfTwoListOfList = rlp match { + case l: RLPList => + l.items match { + case items if items == instance => RepOfTwoListOfList() + case _ => throw new RuntimeException("Invalid RepOfTwoListOfList Decoder") + } + case _ => throw new RuntimeException("Invalid RepOfTwoListOfList Decoder") + } } - } } val rlpTestData: Seq[(RLPEncodeable, String)] = Seq( @@ -748,18 +741,19 @@ class RLPSuite extends AnyFunSuite with ScalaCheckPropertyChecks with ScalaCheck private case class TestSimpleTransaction(id: Int, name: String) private object TestSimpleTransaction { - implicit val encDec = new RLPEncoder[TestSimpleTransaction] with RLPDecoder[TestSimpleTransaction] { - override def encode(obj: TestSimpleTransaction): RLPEncodeable = { - import obj._ - RLPList(id, name) + implicit val encDec: RLPEncoder[TestSimpleTransaction] with RLPDecoder[TestSimpleTransaction] = + new RLPEncoder[TestSimpleTransaction] with RLPDecoder[TestSimpleTransaction] { + override def encode(obj: TestSimpleTransaction): RLPEncodeable = { + import obj._ + RLPList(id, name) + } + + override def decode(rlp: RLPEncodeable): TestSimpleTransaction = rlp match { + case RLPList(id, name) => TestSimpleTransaction(id, name) + case _ => throw new RuntimeException("Invalid Simple Transaction") + } } - override def decode(rlp: RLPEncodeable): TestSimpleTransaction = rlp match { - case RLPList(id, name) => TestSimpleTransaction(id, name) - case _ => throw new RuntimeException("Invalid Simple Transaction") - } - } - implicit def fromEncodeable(rlp: RLPEncodeable)(implicit dec: RLPDecoder[TestSimpleTransaction] ): TestSimpleTransaction = dec.decode(rlp) @@ -775,7 +769,8 @@ class RLPSuite extends AnyFunSuite with ScalaCheckPropertyChecks with ScalaCheck ) private object TestSimpleBlock { - implicit val encDec = new RLPEncoder[TestSimpleBlock] with RLPDecoder[TestSimpleBlock] { + implicit val encDec: RLPEncoder[TestSimpleBlock] with RLPDecoder[TestSimpleBlock] = new RLPEncoder[TestSimpleBlock] + with RLPDecoder[TestSimpleBlock] { override def encode(obj: TestSimpleBlock): RLPEncodeable = { import obj._ RLPList( diff --git a/src/it/scala/io/iohk/ethereum/db/DataSourceIntegrationTestBehavior.scala b/src/it/scala/io/iohk/ethereum/db/DataSourceIntegrationTestBehavior.scala index 1361a58673..37d7d72211 100644 --- a/src/it/scala/io/iohk/ethereum/db/DataSourceIntegrationTestBehavior.scala +++ b/src/it/scala/io/iohk/ethereum/db/DataSourceIntegrationTestBehavior.scala @@ -4,11 +4,16 @@ import java.io.File import java.nio.file.Files import akka.util.ByteString -import io.iohk.ethereum.ObjectGenerators -import io.iohk.ethereum.db.dataSource.{DataSource, DataSourceUpdate} -import io.iohk.ethereum.db.dataSource.DataSource.{Key, Namespace, Value} + import org.scalatest.flatspec.AnyFlatSpec import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks + +import io.iohk.ethereum.ObjectGenerators +import io.iohk.ethereum.db.dataSource.DataSource +import io.iohk.ethereum.db.dataSource.DataSource.Key +import io.iohk.ethereum.db.dataSource.DataSource.Namespace +import io.iohk.ethereum.db.dataSource.DataSource.Value +import io.iohk.ethereum.db.dataSource.DataSourceUpdate import io.iohk.ethereum.utils.ByteStringUtils._ trait DataSourceIntegrationTestBehavior extends ScalaCheckPropertyChecks with ObjectGenerators { @@ -25,9 +30,8 @@ trait DataSourceIntegrationTestBehavior extends ScalaCheckPropertyChecks with Ob def withDir(testCode: String => Any): Unit = { val path = Files.createTempDirectory("testdb").getFileName.toString - try { - testCode(path) - } finally { + try testCode(path) + finally { val dir = new File(path) assert(!dir.exists() || dir.delete(), "File deletion failed") } @@ -43,11 +47,10 @@ trait DataSourceIntegrationTestBehavior extends ScalaCheckPropertyChecks with Ob def updateInSeparateCalls( dataSource: DataSource, toUpsert: Seq[(ByteString, ByteString)] - ): Unit = { + ): Unit = toUpsert.foreach { keyValuePair => dataSource.update(prepareUpdate(toUpsert = Seq(keyValuePair))) } - } // scalastyle:off def dataSource(createDataSource: => String => DataSource): Unit = { diff --git a/src/it/scala/io/iohk/ethereum/db/RockDbIteratorSpec.scala b/src/it/scala/io/iohk/ethereum/db/RockDbIteratorSpec.scala index a68a2f8fe6..ca3efba34f 100644 --- a/src/it/scala/io/iohk/ethereum/db/RockDbIteratorSpec.scala +++ b/src/it/scala/io/iohk/ethereum/db/RockDbIteratorSpec.scala @@ -3,17 +3,28 @@ package io.iohk.ethereum.db import java.nio.file.Files import akka.util.ByteString + import cats.effect.Resource -import cats.effect.concurrent.{Deferred, Ref} -import io.iohk.ethereum.db.dataSource.{DataSourceUpdateOptimized, RocksDbConfig, RocksDbDataSource} -import io.iohk.ethereum.db.storage.{EvmCodeStorage, Namespaces, NodeStorage} -import io.iohk.ethereum.{FlatSpecBase, ResourceFixtures} +import cats.effect.concurrent.Deferred +import cats.effect.concurrent.Ref + import monix.eval.Task -import monix.reactive.{Consumer, Observable} -import org.scalatest.matchers.should.Matchers +import monix.reactive.Consumer +import monix.reactive.Observable import scala.util.Random +import org.scalatest.matchers.should.Matchers + +import io.iohk.ethereum.FlatSpecBase +import io.iohk.ethereum.ResourceFixtures +import io.iohk.ethereum.db.dataSource.DataSourceUpdateOptimized +import io.iohk.ethereum.db.dataSource.RocksDbConfig +import io.iohk.ethereum.db.dataSource.RocksDbDataSource +import io.iohk.ethereum.db.storage.EvmCodeStorage +import io.iohk.ethereum.db.storage.Namespaces +import io.iohk.ethereum.db.storage.NodeStorage + class RockDbIteratorSpec extends FlatSpecBase with ResourceFixtures with Matchers { type Fixture = RocksDbDataSource @@ -25,12 +36,11 @@ class RockDbIteratorSpec extends FlatSpecBase with ResourceFixtures with Matcher arr } - def genRandomByteString(): ByteString = { + def genRandomByteString(): ByteString = ByteString.fromArrayUnsafe(genRandomArray()) - } def writeNValuesToDb(n: Int, db: RocksDbDataSource, namespace: IndexedSeq[Byte]): Task[Unit] = { - val iterable = (0 until n) + val iterable = 0 until n Observable.fromIterable(iterable).foreachL { _ => db.update(Seq(DataSourceUpdateOptimized(namespace, Seq(), Seq((genRandomArray(), genRandomArray()))))) } @@ -59,9 +69,7 @@ class RockDbIteratorSpec extends FlatSpecBase with ResourceFixtures with Matcher // iterators needs to be closed before closing db. _ <- fib.cancel finalCounter <- counter.get - } yield { - assert(finalCounter < largeNum) - } + } yield assert(finalCounter < largeNum) } it should "read all key values in db" in testCaseT { db => @@ -76,9 +84,7 @@ class RockDbIteratorSpec extends FlatSpecBase with ResourceFixtures with Matcher counter.update(current => current + 1) }) finalCounter <- counter.get - } yield { - assert(finalCounter == largeNum) - } + } yield assert(finalCounter == largeNum) } it should "iterate over keys and values from different namespaces" in testCaseT { db => @@ -123,14 +129,12 @@ class RockDbIteratorSpec extends FlatSpecBase with ResourceFixtures with Matcher it should "return empty list when iterating empty db" in testCaseT { db => for { elems <- db.iterate().toListL - } yield { - assert(elems.isEmpty) - } + } yield assert(elems.isEmpty) } } object RockDbIteratorSpec { - def getRockDbTestConfig(dbPath: String) = { + def getRockDbTestConfig(dbPath: String): RocksDbConfig = new RocksDbConfig { override val createIfMissing: Boolean = true override val paranoidChecks: Boolean = false @@ -142,14 +146,12 @@ object RockDbIteratorSpec { override val blockSize: Long = 16384 override val blockCacheSize: Long = 33554432 } - } - def buildRockDbResource(): Resource[Task, RocksDbDataSource] = { + def buildRockDbResource(): Resource[Task, RocksDbDataSource] = Resource.make { Task { val tempDir = Files.createTempDirectory("temp-iter-dir") RocksDbDataSource(getRockDbTestConfig(tempDir.toAbsolutePath.toString), Namespaces.nsSeq) } }(db => Task(db.destroy())) - } } diff --git a/src/it/scala/io/iohk/ethereum/db/RocksDbDataSourceIntegrationSuite.scala b/src/it/scala/io/iohk/ethereum/db/RocksDbDataSourceIntegrationSuite.scala index 05e6544da6..796fb08830 100644 --- a/src/it/scala/io/iohk/ethereum/db/RocksDbDataSourceIntegrationSuite.scala +++ b/src/it/scala/io/iohk/ethereum/db/RocksDbDataSourceIntegrationSuite.scala @@ -1,9 +1,11 @@ package io.iohk.ethereum.db -import io.iohk.ethereum.db.dataSource.{RocksDbConfig, RocksDbDataSource} -import io.iohk.ethereum.db.storage.Namespaces import org.scalatest.flatspec.AnyFlatSpec +import io.iohk.ethereum.db.dataSource.RocksDbConfig +import io.iohk.ethereum.db.dataSource.RocksDbDataSource +import io.iohk.ethereum.db.storage.Namespaces + class RocksDbDataSourceIntegrationSuite extends AnyFlatSpec with DataSourceIntegrationTestBehavior { private def createDataSource(dataSourcePath: String) = RocksDbDataSource( @@ -21,5 +23,5 @@ class RocksDbDataSourceIntegrationSuite extends AnyFlatSpec with DataSourceInteg Namespaces.nsSeq ) - it should behave like dataSource(createDataSource) + (it should behave).like(dataSource(createDataSource)) } diff --git a/src/it/scala/io/iohk/ethereum/ledger/BlockImporterItSpec.scala b/src/it/scala/io/iohk/ethereum/ledger/BlockImporterItSpec.scala index 934dd69430..16d5eca8b5 100644 --- a/src/it/scala/io/iohk/ethereum/ledger/BlockImporterItSpec.scala +++ b/src/it/scala/io/iohk/ethereum/ledger/BlockImporterItSpec.scala @@ -1,29 +1,43 @@ package io.iohk.ethereum.ledger +import akka.actor.ActorRef import akka.testkit.TestProbe import akka.util.ByteString + import cats.data.NonEmptyList -import io.iohk.ethereum.blockchain.sync.regular.BlockImporter.NewCheckpoint -import io.iohk.ethereum.blockchain.sync.regular.{BlockFetcher, BlockImporter} -import io.iohk.ethereum.checkpointing.CheckpointingTestHelpers -import io.iohk.ethereum.consensus.{GetBlockHeaderByHash, GetNBlocksBack} -import io.iohk.ethereum.consensus.blocks.CheckpointBlockGenerator -import io.iohk.ethereum.consensus.pow.validators.{OmmersValidator, StdOmmersValidator} -import io.iohk.ethereum.consensus.validators.Validators -import io.iohk.ethereum.domain._ -import io.iohk.ethereum.mpt.MerklePatriciaTrie -import io.iohk.ethereum.utils.Config.SyncConfig -import io.iohk.ethereum.utils.Config -import io.iohk.ethereum.{Fixtures, Mocks, NormalPatience, ObjectGenerators, Timeouts, crypto} -import io.iohk.ethereum.ledger.BlockResult + import monix.execution.Scheduler +import monix.execution.schedulers.SchedulerService + +import scala.concurrent.duration._ + import org.scalamock.scalatest.MockFactory import org.scalatest.BeforeAndAfterAll import org.scalatest.concurrent.Eventually import org.scalatest.flatspec.AnyFlatSpecLike import org.scalatest.matchers.should.Matchers -import scala.concurrent.duration._ +import io.iohk.ethereum.Fixtures +import io.iohk.ethereum.Mocks +import io.iohk.ethereum.NormalPatience +import io.iohk.ethereum.ObjectGenerators +import io.iohk.ethereum.Timeouts +import io.iohk.ethereum.blockchain.sync.regular.BlockFetcher +import io.iohk.ethereum.blockchain.sync.regular.BlockImporter +import io.iohk.ethereum.blockchain.sync.regular.BlockImporter.NewCheckpoint +import io.iohk.ethereum.checkpointing.CheckpointingTestHelpers +import io.iohk.ethereum.consensus.GetBlockHeaderByHash +import io.iohk.ethereum.consensus.GetNBlocksBack +import io.iohk.ethereum.consensus.blocks.CheckpointBlockGenerator +import io.iohk.ethereum.consensus.pow.validators.OmmersValidator +import io.iohk.ethereum.consensus.pow.validators.StdOmmersValidator +import io.iohk.ethereum.consensus.validators.Validators +import io.iohk.ethereum.crypto +import io.iohk.ethereum.domain._ +import io.iohk.ethereum.ledger.BlockResult +import io.iohk.ethereum.mpt.MerklePatriciaTrie +import io.iohk.ethereum.utils.Config +import io.iohk.ethereum.utils.Config.SyncConfig class BlockImporterItSpec extends MockFactory @@ -34,32 +48,32 @@ class BlockImporterItSpec with Eventually with NormalPatience { - implicit val testScheduler = Scheduler.fixedPool("test", 32) + implicit val testScheduler: SchedulerService = Scheduler.fixedPool("test", 32) override def afterAll(): Unit = { testScheduler.shutdown() testScheduler.awaitTermination(60.second) } - override lazy val blockQueue = BlockQueue(blockchain, SyncConfig(Config.config)) + override lazy val blockQueue: BlockQueue = BlockQueue(blockchain, SyncConfig(Config.config)) - val genesis = Block( + val genesis: Block = Block( Fixtures.Blocks.Genesis.header.copy(stateRoot = ByteString(MerklePatriciaTrie.EmptyRootHash)), Fixtures.Blocks.Genesis.body ) - val genesisWeight = ChainWeight.zero.increase(genesis.header) + val genesisWeight: ChainWeight = ChainWeight.zero.increase(genesis.header) blockchain.save(genesis, Seq(), genesisWeight, saveAsBestBlock = true) lazy val checkpointBlockGenerator: CheckpointBlockGenerator = new CheckpointBlockGenerator - val fetcherProbe = TestProbe() - val ommersPoolProbe = TestProbe() - val broadcasterProbe = TestProbe() - val pendingTransactionsManagerProbe = TestProbe() - val supervisor = TestProbe() + val fetcherProbe: TestProbe = TestProbe() + val ommersPoolProbe: TestProbe = TestProbe() + val broadcasterProbe: TestProbe = TestProbe() + val pendingTransactionsManagerProbe: TestProbe = TestProbe() + val supervisor: TestProbe = TestProbe() - val emptyWorld = InMemoryWorldStateProxy( + val emptyWorld: InMemoryWorldStateProxy = InMemoryWorldStateProxy( storagesInstance.storages.evmCodeStorage, blockchain.getBackingMptStorage(-1), (number: BigInt) => blockchainReader.getBlockHeaderByNumber(number).map(_.hash), @@ -81,7 +95,7 @@ class BlockImporterItSpec .validate(parentHash, blockNumber, ommers, getBlockHeaderByHash, getNBlocksBack) } - override lazy val blockImport = mkBlockImport( + override lazy val blockImport: BlockImport = mkBlockImport( validators = successValidators, blockExecutionOpt = Some( new BlockExecution( @@ -102,7 +116,7 @@ class BlockImporterItSpec ) // } - val blockImporter = system.actorOf( + val blockImporter: ActorRef = system.actorOf( BlockImporter.props( fetcherProbe.ref, blockImport, @@ -125,12 +139,12 @@ class BlockImporterItSpec val oldBlock3: Block = getBlock(genesisBlock.number + 3, difficulty = 103, parent = oldBlock2.header.hash) val oldBlock4: Block = getBlock(genesisBlock.number + 4, difficulty = 104, parent = oldBlock3.header.hash) - val weight1 = ChainWeight.totalDifficultyOnly(block1.header.difficulty) - val newWeight2 = weight1.increase(newBlock2.header) - val newWeight3 = newWeight2.increase(newBlock3.header) - val oldWeight2 = weight1.increase(oldBlock2.header) - val oldWeight3 = oldWeight2.increase(oldBlock3.header) - val oldWeight4 = oldWeight3.increase(oldBlock4.header) + val weight1: ChainWeight = ChainWeight.totalDifficultyOnly(block1.header.difficulty) + val newWeight2: ChainWeight = weight1.increase(newBlock2.header) + val newWeight3: ChainWeight = newWeight2.increase(newBlock3.header) + val oldWeight2: ChainWeight = weight1.increase(oldBlock2.header) + val oldWeight3: ChainWeight = oldWeight2.increase(oldBlock3.header) + val oldWeight4: ChainWeight = oldWeight3.increase(oldBlock4.header) //saving initial main chain blockchain.save(block1, Nil, weight1, saveAsBestBlock = true) @@ -138,8 +152,8 @@ class BlockImporterItSpec blockchain.save(oldBlock3, Nil, oldWeight3, saveAsBestBlock = true) blockchain.save(oldBlock4, Nil, oldWeight4, saveAsBestBlock = true) - val oldBranch = List(oldBlock2, oldBlock3, oldBlock4) - val newBranch = List(newBlock2, newBlock3) + val oldBranch: List[Block] = List(oldBlock2, oldBlock3, oldBlock4) + val newBranch: List[Block] = List(newBlock2, newBlock3) blockImporter ! BlockImporter.Start @@ -163,7 +177,7 @@ class BlockImporterItSpec blockImporter ! BlockFetcher.PickedBlocks(NonEmptyList.fromListUnsafe(newBranch)) //because the blocks are not valid, we shouldn't reorganise, but at least stay with a current chain, and the best block of the current chain is oldBlock4 - eventually { blockchain.getBestBlock().get shouldEqual oldBlock4 } + eventually(blockchain.getBestBlock().get shouldEqual oldBlock4) } it should "return a correct new best block after reorganising longer chain to a shorter one if its weight is bigger" in { @@ -175,7 +189,7 @@ class BlockImporterItSpec blockImporter ! BlockFetcher.PickedBlocks(NonEmptyList.fromListUnsafe(newBranch)) - eventually { blockchain.getBestBlock().get shouldEqual newBlock3 } + eventually(blockchain.getBestBlock().get shouldEqual newBlock3) } it should "return Unknown branch, in case of PickedBlocks with block that has a parent that's not in the chain" in { @@ -202,7 +216,7 @@ class BlockImporterItSpec //not reorganising anymore until oldBlock4(not part of the chain anymore), no block/ommer validation when not part of the chain, resolveBranch is returning UnknownBranch blockImporter ! BlockFetcher.PickedBlocks(NonEmptyList.fromListUnsafe(List(newBlock5ParentOldBlock4))) - eventually { blockchain.getBestBlock().get shouldEqual newBlock4ParentOldBlock3 } + eventually(blockchain.getBestBlock().get shouldEqual newBlock4ParentOldBlock3) } it should "switch to a branch with a checkpoint" in { @@ -215,8 +229,8 @@ class BlockImporterItSpec blockImporter ! BlockFetcher.PickedBlocks(NonEmptyList.fromListUnsafe(newBranch)) - eventually { blockchain.getBestBlock().get shouldEqual oldBlock5WithCheckpoint } - eventually { blockchain.getLatestCheckpointBlockNumber() shouldEqual oldBlock5WithCheckpoint.header.number } + eventually(blockchain.getBestBlock().get shouldEqual oldBlock5WithCheckpoint) + eventually(blockchain.getLatestCheckpointBlockNumber() shouldEqual oldBlock5WithCheckpoint.header.number) } it should "switch to a branch with a newer checkpoint" in { @@ -229,8 +243,8 @@ class BlockImporterItSpec blockImporter ! BlockFetcher.PickedBlocks(NonEmptyList.fromListUnsafe(newBranch)) - eventually { blockchain.getBestBlock().get shouldEqual newBlock4WithCheckpoint } - eventually { blockchain.getLatestCheckpointBlockNumber() shouldEqual newBlock4WithCheckpoint.header.number } + eventually(blockchain.getBestBlock().get shouldEqual newBlock4WithCheckpoint) + eventually(blockchain.getLatestCheckpointBlockNumber() shouldEqual newBlock4WithCheckpoint.header.number) } it should "return a correct checkpointed block after receiving a request for generating a new checkpoint" in { @@ -248,8 +262,8 @@ class BlockImporterItSpec val checkpointBlock = checkpointBlockGenerator.generate(newBlock5, Checkpoint(signatures)) blockImporter ! NewCheckpoint(checkpointBlock) - eventually { blockchain.getBestBlock().get shouldEqual checkpointBlock } - eventually { blockchain.getLatestCheckpointBlockNumber() shouldEqual newBlock5.header.number + 1 } + eventually(blockchain.getBestBlock().get shouldEqual checkpointBlock) + eventually(blockchain.getLatestCheckpointBlockNumber() shouldEqual newBlock5.header.number + 1) } it should "ask BlockFetcher to resolve missing node" in { @@ -278,7 +292,7 @@ class BlockImporterItSpec val msg = fetcherProbe .fishForMessage(Timeouts.longTimeout) { case BlockFetcher.FetchStateNode(_, _) => true - case _ => false + case _ => false } .asInstanceOf[BlockFetcher.FetchStateNode] diff --git a/src/it/scala/io/iohk/ethereum/mpt/MerklePatriciaTreeIntegrationSuite.scala b/src/it/scala/io/iohk/ethereum/mpt/MerklePatriciaTreeIntegrationSuite.scala index 68e5a0e2ec..bc645df528 100644 --- a/src/it/scala/io/iohk/ethereum/mpt/MerklePatriciaTreeIntegrationSuite.scala +++ b/src/it/scala/io/iohk/ethereum/mpt/MerklePatriciaTreeIntegrationSuite.scala @@ -3,14 +3,15 @@ package io.iohk.ethereum.mpt import java.nio.ByteBuffer import java.security.MessageDigest -import io.iohk.ethereum.ObjectGenerators -import io.iohk.ethereum.mpt.MerklePatriciaTrie._ -import io.iohk.ethereum.utils.Logger +import scala.util.Random + import org.bouncycastle.util.encoders.Hex import org.scalatest.funsuite.AnyFunSuite import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks -import scala.util.Random +import io.iohk.ethereum.ObjectGenerators +import io.iohk.ethereum.mpt.MerklePatriciaTrie._ +import io.iohk.ethereum.utils.Logger class MerklePatriciaTreeIntegrationSuite extends AnyFunSuite @@ -31,9 +32,8 @@ class MerklePatriciaTreeIntegrationSuite override def fromBytes(bytes: Array[Byte]): Int = ByteBuffer.wrap(bytes).getInt() } - def md5(bytes: Array[Byte]): Array[Byte] = { + def md5(bytes: Array[Byte]): Array[Byte] = MessageDigest.getInstance("MD5").digest(bytes) - } test("EthereumJ compatibility - Insert of the first 40000 numbers") { withRocksDbNodeStorage { ns => diff --git a/src/it/scala/io/iohk/ethereum/sync/FastSyncItSpec.scala b/src/it/scala/io/iohk/ethereum/sync/FastSyncItSpec.scala index c0a7f9bcc8..7aefcc71d8 100644 --- a/src/it/scala/io/iohk/ethereum/sync/FastSyncItSpec.scala +++ b/src/it/scala/io/iohk/ethereum/sync/FastSyncItSpec.scala @@ -1,6 +1,15 @@ package io.iohk.ethereum.sync import akka.util.ByteString + +import monix.execution.Scheduler +import monix.execution.schedulers.SchedulerService + +import scala.concurrent.duration._ + +import org.scalatest.BeforeAndAfterAll +import org.scalatest.matchers.should.Matchers + import io.iohk.ethereum.FlatSpecBase import io.iohk.ethereum.blockchain.sync.Blacklist.BlacklistReason.BlacklistReasonType import io.iohk.ethereum.domain._ @@ -10,14 +19,9 @@ import io.iohk.ethereum.sync.FastSyncItSpec._ import io.iohk.ethereum.sync.util.FastSyncItSpecUtils.FakePeer import io.iohk.ethereum.sync.util.SyncCommonItSpec._ import io.iohk.ethereum.sync.util.SyncCommonItSpecUtils._ -import monix.execution.Scheduler -import org.scalatest.BeforeAndAfterAll -import org.scalatest.matchers.should.Matchers - -import scala.concurrent.duration._ class FastSyncItSpec extends FlatSpecBase with Matchers with BeforeAndAfterAll { - implicit val testScheduler = Scheduler.fixedPool("test", 16) + implicit val testScheduler: SchedulerService = Scheduler.fixedPool("test", 16) override def afterAll(): Unit = { testScheduler.shutdown() @@ -120,9 +124,9 @@ class FastSyncItSpec extends FlatSpecBase with Matchers with BeforeAndAfterAll { _ <- peer2.importBlocksUntil(2000)(IdentityUpdate).startAndForget _ <- peer1.startFastSync().delayExecution(50.milliseconds) _ <- peer1.waitForFastSyncFinish() - } yield { - assert(peer1.bl.getBestBlockNumber() == peer2.bl.getBestBlockNumber() - peer2.testSyncConfig.pivotBlockOffset) - } + } yield assert( + peer1.bl.getBestBlockNumber() == peer2.bl.getBestBlockNumber() - peer2.testSyncConfig.pivotBlockOffset + ) } it should "update pivot block and sync this new pivot block state" in customTestCaseResourceM( @@ -134,9 +138,9 @@ class FastSyncItSpec extends FlatSpecBase with Matchers with BeforeAndAfterAll { _ <- peer2.importBlocksUntil(2000)(updateStateAtBlock(1500)).startAndForget _ <- peer1.startFastSync().delayExecution(50.milliseconds) _ <- peer1.waitForFastSyncFinish() - } yield { - assert(peer1.bl.getBestBlockNumber() == peer2.bl.getBestBlockNumber() - peer2.testSyncConfig.pivotBlockOffset) - } + } yield assert( + peer1.bl.getBestBlockNumber() == peer2.bl.getBestBlockNumber() - peer2.testSyncConfig.pivotBlockOffset + ) } it should "sync state to peer from partially synced state" in customTestCaseResourceM( @@ -150,9 +154,9 @@ class FastSyncItSpec extends FlatSpecBase with Matchers with BeforeAndAfterAll { _ <- peer1.connectToPeers(Set(peer2.node)) _ <- peer1.startFastSync().delayExecution(50.milliseconds) _ <- peer1.waitForFastSyncFinish() - } yield { - assert(peer1.bl.getBestBlockNumber() == peer2.bl.getBestBlockNumber() - peer2.testSyncConfig.pivotBlockOffset) - } + } yield assert( + peer1.bl.getBestBlockNumber() == peer2.bl.getBestBlockNumber() - peer2.testSyncConfig.pivotBlockOffset + ) } it should "follow the longest chains" in customTestCaseResourceM( @@ -191,9 +195,9 @@ class FastSyncItSpec extends FlatSpecBase with Matchers with BeforeAndAfterAll { _ <- peer1.connectToPeers(Set(peer2.node, peer3.node)) _ <- peer1.startFastSync().delayExecution(50.milliseconds) _ <- peer1.waitForFastSyncFinish() - } yield { - assert(peer1.bl.getBestBlockNumber() == peer3.bl.getBestBlockNumber() - peer3.testSyncConfig.pivotBlockOffset) - } + } yield assert( + peer1.bl.getBestBlockNumber() == peer3.bl.getBestBlockNumber() - peer3.testSyncConfig.pivotBlockOffset + ) } it should "blacklist peer on Invalid batch last header number" in customTestCaseResourceM( diff --git a/src/it/scala/io/iohk/ethereum/sync/RegularSyncItSpec.scala b/src/it/scala/io/iohk/ethereum/sync/RegularSyncItSpec.scala index 0c0fdfbbe0..280aff074f 100644 --- a/src/it/scala/io/iohk/ethereum/sync/RegularSyncItSpec.scala +++ b/src/it/scala/io/iohk/ethereum/sync/RegularSyncItSpec.scala @@ -1,26 +1,29 @@ package io.iohk.ethereum.sync +import monix.execution.Scheduler +import monix.execution.schedulers.SchedulerService + +import scala.concurrent.duration._ + import com.typesafe.config.ConfigValueFactory -import io.iohk.ethereum.FreeSpecBase -import io.iohk.ethereum.metrics.{Metrics, MetricsConfig} -import io.iohk.ethereum.sync.util.RegularSyncItSpecUtils.FakePeer -import io.iohk.ethereum.sync.util.SyncCommonItSpec._ -import io.iohk.ethereum.utils.Config import io.prometheus.client.CollectorRegistry -import monix.execution.Scheduler import org.scalatest.BeforeAndAfterAll import org.scalatest.matchers.should.Matchers -import scala.concurrent.duration._ +import io.iohk.ethereum.FreeSpecBase +import io.iohk.ethereum.metrics.Metrics +import io.iohk.ethereum.metrics.MetricsConfig +import io.iohk.ethereum.sync.util.RegularSyncItSpecUtils.FakePeer +import io.iohk.ethereum.sync.util.SyncCommonItSpec._ +import io.iohk.ethereum.utils.Config class RegularSyncItSpec extends FreeSpecBase with Matchers with BeforeAndAfterAll { - implicit val testScheduler = Scheduler.fixedPool("test", 16) + implicit val testScheduler: SchedulerService = Scheduler.fixedPool("test", 16) - override def beforeAll(): Unit = { + override def beforeAll(): Unit = Metrics.configure( MetricsConfig(Config.config.withValue("metrics.enabled", ConfigValueFactory.fromAnyRef(true))) ) - } override def afterAll(): Unit = { testScheduler.shutdown() @@ -36,9 +39,7 @@ class RegularSyncItSpec extends FreeSpecBase with Matchers with BeforeAndAfterAl _ <- peer2.startRegularSync() _ <- peer2.connectToPeers(Set(peer1.node)) _ <- peer2.waitForRegularSyncLoadLastBlock(blockNumber) - } yield { - assert(peer1.bl.getBestBlock().get.hash == peer2.bl.getBestBlock().get.hash) - } + } yield assert(peer1.bl.getBestBlock().get.hash == peer2.bl.getBestBlock().get.hash) } "given a previously mined blockchain" in customTestCaseResourceM(FakePeer.start2FakePeersRes()) { @@ -51,9 +52,7 @@ class RegularSyncItSpec extends FreeSpecBase with Matchers with BeforeAndAfterAl _ <- peer2.startRegularSync() _ <- peer2.connectToPeers(Set(peer1.node)) _ <- peer2.waitForRegularSyncLoadLastBlock(blockHeadersPerRequest + 1) - } yield { - assert(peer1.bl.getBestBlock().get.hash == peer2.bl.getBestBlock().get.hash) - } + } yield assert(peer1.bl.getBestBlock().get.hash == peer2.bl.getBestBlock().get.hash) } } @@ -71,9 +70,7 @@ class RegularSyncItSpec extends FreeSpecBase with Matchers with BeforeAndAfterAl _ <- peer1.waitForRegularSyncLoadLastBlock(blockNumer + 2) _ <- peer1.mineNewBlocks(100.milliseconds, 2)(IdentityUpdate) _ <- peer2.waitForRegularSyncLoadLastBlock(blockNumer + 4) - } yield { - assert(peer1.bl.getBestBlock().get.hash == peer2.bl.getBestBlock().get.hash) - } + } yield assert(peer1.bl.getBestBlock().get.hash == peer2.bl.getBestBlock().get.hash) } "peers should keep being synced on checkpoints" in customTestCaseResourceM( @@ -158,12 +155,10 @@ class RegularSyncItSpec extends FreeSpecBase with Matchers with BeforeAndAfterAl //without new added blocks the syncing and reorganisation are not triggered _ <- peer1.mineNewBlocks(500.milliseconds, 10)(IdentityUpdate) _ <- peer1.waitForRegularSyncLoadLastBlock(19) - } yield { - assert(true) - //these should pass + } yield assert(true) + //these should pass // assert(peer1.bl.getBestBlock().get.hash == peer2.bl.getBestBlock().get.hash ) // assert(peer1.bl.getLatestCheckpointBlockNumber() == peer2.bl.getLatestCheckpointBlockNumber()) - } } "peers with divergent chains will be forced to resolve branches" in customTestCaseResourceM( diff --git a/src/it/scala/io/iohk/ethereum/sync/util/CommonFakePeer.scala b/src/it/scala/io/iohk/ethereum/sync/util/CommonFakePeer.scala index 4ff622610a..2fb64fa010 100644 --- a/src/it/scala/io/iohk/ethereum/sync/util/CommonFakePeer.scala +++ b/src/it/scala/io/iohk/ethereum/sync/util/CommonFakePeer.scala @@ -1,51 +1,74 @@ package io.iohk.ethereum.sync.util +import java.net.InetSocketAddress import java.nio.file.Files +import java.nio.file.Path import java.time.Clock import java.util.concurrent.atomic.AtomicReference -import akka.actor.{ActorRef, ActorSystem} + +import akka.actor.ActorRef +import akka.actor.ActorSystem import akka.testkit.TestProbe -import akka.util.{ByteString, Timeout} +import akka.util.ByteString +import akka.util.Timeout + +import monix.eval.Task + +import scala.concurrent.duration.FiniteDuration +import scala.concurrent.duration._ + +import org.bouncycastle.crypto.AsymmetricCipherKeyPair + +import io.iohk.ethereum.Fixtures +import io.iohk.ethereum.Timeouts +import io.iohk.ethereum.blockchain.sync.BlockchainHostActor +import io.iohk.ethereum.blockchain.sync.CacheBasedBlacklist +import io.iohk.ethereum.blockchain.sync.TestSyncConfig +import io.iohk.ethereum.blockchain.sync.regular.BlockBroadcast import io.iohk.ethereum.blockchain.sync.regular.BlockBroadcast.BlockToBroadcast -import io.iohk.ethereum.blockchain.sync.regular.{BlockBroadcast, BlockBroadcasterActor} +import io.iohk.ethereum.blockchain.sync.regular.BlockBroadcasterActor import io.iohk.ethereum.blockchain.sync.regular.BlockBroadcasterActor.BroadcastBlock -import io.iohk.ethereum.blockchain.sync.{BlockchainHostActor, CacheBasedBlacklist, TestSyncConfig} -import io.iohk.ethereum.db.components.{RocksDbDataSourceComponent, Storages} -import io.iohk.ethereum.db.dataSource.{RocksDbConfig, RocksDbDataSource} -import io.iohk.ethereum.db.storage.pruning.{ArchivePruning, PruningMode} -import io.iohk.ethereum.db.storage.{AppStateStorage, Namespaces} -import io.iohk.ethereum.domain.{Block, Blockchain, BlockchainImpl, BlockchainReader, ChainWeight, UInt256} -import io.iohk.ethereum.security.SecureRandomBuilder +import io.iohk.ethereum.db.components.RocksDbDataSourceComponent +import io.iohk.ethereum.db.components.Storages +import io.iohk.ethereum.db.dataSource.RocksDbConfig +import io.iohk.ethereum.db.dataSource.RocksDbDataSource +import io.iohk.ethereum.db.storage.AppStateStorage +import io.iohk.ethereum.db.storage.Namespaces +import io.iohk.ethereum.db.storage.pruning.ArchivePruning +import io.iohk.ethereum.db.storage.pruning.PruningMode +import io.iohk.ethereum.domain.Block +import io.iohk.ethereum.domain.Blockchain +import io.iohk.ethereum.domain.BlockchainImpl +import io.iohk.ethereum.domain.BlockchainReader +import io.iohk.ethereum.domain.ChainWeight import io.iohk.ethereum.ledger.InMemoryWorldStateProxy import io.iohk.ethereum.mpt.MerklePatriciaTrie +import io.iohk.ethereum.network.EtcPeerManagerActor import io.iohk.ethereum.network.EtcPeerManagerActor.PeerInfo -import io.iohk.ethereum.network.PeerManagerActor.{FastSyncHostConfiguration, PeerConfiguration} +import io.iohk.ethereum.network.ForkResolver +import io.iohk.ethereum.network.KnownNodesManager +import io.iohk.ethereum.network.PeerEventBusActor +import io.iohk.ethereum.network.PeerManagerActor +import io.iohk.ethereum.network.PeerManagerActor.FastSyncHostConfiguration +import io.iohk.ethereum.network.PeerManagerActor.PeerConfiguration +import io.iohk.ethereum.network.PeerStatisticsActor +import io.iohk.ethereum.network.ServerActor +import io.iohk.ethereum.network.discovery.DiscoveryConfig +import io.iohk.ethereum.network.discovery.Node import io.iohk.ethereum.network.discovery.PeerDiscoveryManager.DiscoveredNodesInfo -import io.iohk.ethereum.network.discovery.{DiscoveryConfig, Node} -import io.iohk.ethereum.network.handshaker.{EtcHandshaker, EtcHandshakerConfiguration, Handshaker} -import io.iohk.ethereum.network.p2p.EthereumMessageDecoder +import io.iohk.ethereum.network.handshaker.EtcHandshaker +import io.iohk.ethereum.network.handshaker.EtcHandshakerConfiguration +import io.iohk.ethereum.network.handshaker.Handshaker import io.iohk.ethereum.network.p2p.messages.Capability import io.iohk.ethereum.network.rlpx.AuthHandshaker import io.iohk.ethereum.network.rlpx.RLPxConnectionHandler.RLPxConfiguration -import io.iohk.ethereum.network.{ - EtcPeerManagerActor, - ForkResolver, - KnownNodesManager, - PeerEventBusActor, - PeerManagerActor, - PeerStatisticsActor, - ServerActor -} import io.iohk.ethereum.nodebuilder.PruningConfigBuilder +import io.iohk.ethereum.security.SecureRandomBuilder import io.iohk.ethereum.sync.util.SyncCommonItSpec._ import io.iohk.ethereum.sync.util.SyncCommonItSpecUtils._ import io.iohk.ethereum.utils.ServerStatus.Listening import io.iohk.ethereum.utils._ import io.iohk.ethereum.vm.EvmConfig -import io.iohk.ethereum.{Fixtures, Timeouts} -import monix.eval.Task - -import scala.concurrent.duration.{FiniteDuration, _} abstract class CommonFakePeer(peerName: String, fakePeerCustomConfig: FakePeerCustomConfig) extends SecureRandomBuilder @@ -56,13 +79,13 @@ abstract class CommonFakePeer(peerName: String, fakePeerCustomConfig: FakePeerCu import scala.language.postfixOps - implicit val clock = Clock.systemUTC() + implicit val clock: Clock = Clock.systemUTC() - implicit val system = ActorSystem(peerName) + implicit val system: ActorSystem = ActorSystem(peerName) - val peerDiscoveryManager = TestProbe().ref + val peerDiscoveryManager: ActorRef = TestProbe().ref - val nodeKey = io.iohk.ethereum.crypto.generateKeyPair(secureRandom) + val nodeKey: AsymmetricCipherKeyPair = io.iohk.ethereum.crypto.generateKeyPair(secureRandom) private val nodeStatus = NodeStatus( @@ -71,9 +94,9 @@ abstract class CommonFakePeer(peerName: String, fakePeerCustomConfig: FakePeerCu discoveryStatus = ServerStatus.NotListening ) - lazy val tempDir = Files.createTempDirectory("temp-fast-sync") + lazy val tempDir: Path = Files.createTempDirectory("temp-fast-sync") - def getRockDbTestConfig(dbPath: String) = { + def getRockDbTestConfig(dbPath: String): RocksDbConfig = new RocksDbConfig { override val createIfMissing: Boolean = true override val paranoidChecks: Boolean = false @@ -85,51 +108,48 @@ abstract class CommonFakePeer(peerName: String, fakePeerCustomConfig: FakePeerCu override val blockSize: Long = 16384 override val blockCacheSize: Long = 33554432 } - } sealed trait LocalPruningConfigBuilder extends PruningConfigBuilder { override lazy val pruningMode: PruningMode = ArchivePruning } lazy val nodeStatusHolder = new AtomicReference(nodeStatus) - lazy val storagesInstance = new RocksDbDataSourceComponent - with LocalPruningConfigBuilder - with Storages.DefaultStorages { - override lazy val dataSource: RocksDbDataSource = - RocksDbDataSource(getRockDbTestConfig(tempDir.toAbsolutePath.toString), Namespaces.nsSeq) - } + lazy val storagesInstance: RocksDbDataSourceComponent with LocalPruningConfigBuilder with Storages.DefaultStorages = + new RocksDbDataSourceComponent with LocalPruningConfigBuilder with Storages.DefaultStorages { + override lazy val dataSource: RocksDbDataSource = + RocksDbDataSource(getRockDbTestConfig(tempDir.toAbsolutePath.toString), Namespaces.nsSeq) + } lazy val blockchainConfig = Config.blockchains.blockchainConfig - lazy val discoveryConfig = DiscoveryConfig(Config.config, blockchainConfig.bootstrapNodes) + lazy val discoveryConfig: DiscoveryConfig = DiscoveryConfig(Config.config, blockchainConfig.bootstrapNodes) - /** - * Default persist interval is 20s, which is too long for tests. As in all tests we treat peer as connected when + /** Default persist interval is 20s, which is too long for tests. As in all tests we treat peer as connected when * it is persisted in storage. */ - lazy val knownNodesManagerConfig = + lazy val knownNodesManagerConfig: KnownNodesManager.KnownNodesManagerConfig = KnownNodesManager.KnownNodesManagerConfig(config).copy(persistInterval = 1.seconds) - lazy val knownNodesManager = system.actorOf( + lazy val knownNodesManager: ActorRef = system.actorOf( KnownNodesManager.props( knownNodesManagerConfig, storagesInstance.storages.knownNodesStorage ) ) - val blockchainReader = BlockchainReader(storagesInstance.storages) - val bl = BlockchainImpl(storagesInstance.storages, blockchainReader) + val blockchainReader: BlockchainReader = BlockchainReader(storagesInstance.storages) + val bl: BlockchainImpl = BlockchainImpl(storagesInstance.storages, blockchainReader) val evmCodeStorage = storagesInstance.storages.evmCodeStorage - val genesis = Block( + val genesis: Block = Block( Fixtures.Blocks.Genesis.header.copy(stateRoot = ByteString(MerklePatriciaTrie.EmptyRootHash)), Fixtures.Blocks.Genesis.body ) - val genesisWeight = ChainWeight.zero.increase(genesis.header) + val genesisWeight: ChainWeight = ChainWeight.zero.increase(genesis.header) bl.save(genesis, Seq(), genesisWeight, saveAsBestBlock = true) lazy val nh = nodeStatusHolder - val peerConf = new PeerConfiguration { + val peerConf: PeerConfiguration = new PeerConfiguration { override val fastSyncHostConfiguration: FastSyncHostConfiguration = new FastSyncHostConfiguration { val maxBlocksHeadersPerMessage: Int = fakePeerCustomConfig.hostConfig.maxBlocksHeadersPerMessage val maxBlocksBodiesPerMessage: Int = fakePeerCustomConfig.hostConfig.maxBlocksBodiesPerMessage @@ -162,7 +182,7 @@ abstract class CommonFakePeer(peerName: String, fakePeerCustomConfig: FakePeerCu override val statSlotCount: Int = 30 } - lazy val peerEventBus = system.actorOf(PeerEventBusActor.props, "peer-event-bus") + lazy val peerEventBus: ActorRef = system.actorOf(PeerEventBusActor.props, "peer-event-bus") private val handshakerConfiguration: EtcHandshakerConfiguration = new EtcHandshakerConfiguration { @@ -179,7 +199,7 @@ abstract class CommonFakePeer(peerName: String, fakePeerCustomConfig: FakePeerCu lazy val authHandshaker: AuthHandshaker = AuthHandshaker(nodeKey, secureRandom) - lazy val peerStatistics = + lazy val peerStatistics: ActorRef = system.actorOf(PeerStatisticsActor.props(peerEventBus, slotDuration = 1.minute, slotCount = 30)) lazy val blacklist: CacheBasedBlacklist = CacheBasedBlacklist.empty(1000) @@ -214,14 +234,14 @@ abstract class CommonFakePeer(peerName: String, fakePeerCustomConfig: FakePeerCu lazy val server: ActorRef = system.actorOf(ServerActor.props(nodeStatusHolder, peerManager), "server") - val listenAddress = randomAddress() + val listenAddress: InetSocketAddress = randomAddress() - lazy val node = + lazy val node: Node = Node(ByteString(nodeStatus.nodeId), listenAddress.getAddress, listenAddress.getPort, listenAddress.getPort) - lazy val vmConfig = VmConfig(Config.config) + lazy val vmConfig: VmConfig = VmConfig(Config.config) - val testSyncConfig = syncConfig.copy( + val testSyncConfig: Config.SyncConfig = syncConfig.copy( minPeersToChoosePivotBlock = 1, peersScanInterval = 5.milliseconds, blockHeadersPerRequest = 200, @@ -239,11 +259,11 @@ abstract class CommonFakePeer(peerName: String, fakePeerCustomConfig: FakePeerCu lazy val broadcaster = new BlockBroadcast(etcPeerManager) - lazy val broadcasterActor = system.actorOf( + lazy val broadcasterActor: ActorRef = system.actorOf( BlockBroadcasterActor.props(broadcaster, peerEventBus, etcPeerManager, blacklist, testSyncConfig, system.scheduler) ) - private def getMptForBlock(block: Block) = { + private def getMptForBlock(block: Block) = InMemoryWorldStateProxy( storagesInstance.storages.evmCodeStorage, bl.getBackingMptStorage(block.number), @@ -253,11 +273,9 @@ abstract class CommonFakePeer(peerName: String, fakePeerCustomConfig: FakePeerCu noEmptyAccounts = EvmConfig.forBlock(block.number, blockchainConfig).noEmptyAccounts, ethCompatibleStorage = blockchainConfig.ethCompatibleStorage ) - } - private def broadcastBlock(block: Block, weight: ChainWeight) = { + private def broadcastBlock(block: Block, weight: ChainWeight) = broadcasterActor ! BroadcastBlock(BlockToBroadcast(block, weight)) - } def getCurrentState(): BlockchainState = { val bestBlock = bl.getBestBlock().get @@ -266,7 +284,7 @@ abstract class CommonFakePeer(peerName: String, fakePeerCustomConfig: FakePeerCu BlockchainState(bestBlock, currentWorldState, currentWeight) } - def startPeer(): Task[Unit] = { + def startPeer(): Task[Unit] = for { _ <- Task { peerManager ! PeerManagerActor.StartConnecting @@ -276,16 +294,14 @@ abstract class CommonFakePeer(peerName: String, fakePeerCustomConfig: FakePeerCu status.serverStatus == Listening(listenAddress) } } yield () - } - def shutdown(): Task[Unit] = { + def shutdown(): Task[Unit] = for { _ <- Task.deferFuture(system.terminate()) _ <- Task(storagesInstance.dataSource.destroy()) } yield () - } - def connectToPeers(nodes: Set[Node]): Task[Unit] = { + def connectToPeers(nodes: Set[Node]): Task[Unit] = for { _ <- Task { peerManager ! DiscoveredNodesInfo(nodes) @@ -297,7 +313,6 @@ abstract class CommonFakePeer(peerName: String, fakePeerCustomConfig: FakePeerCu requestedNodes.subsetOf(currentNodes) } } yield () - } private def createChildBlock(parent: Block, parentWeight: ChainWeight, parentWorld: InMemoryWorldStateProxy)( updateWorldForBlock: (BigInt, InMemoryWorldStateProxy) => InMemoryWorldStateProxy @@ -313,7 +328,7 @@ abstract class CommonFakePeer(peerName: String, fakePeerCustomConfig: FakePeerCu private def generateInvalidBlock( currentBestBlock: Block - )(updateWorldForBlock: (BigInt, InMemoryWorldStateProxy) => InMemoryWorldStateProxy): Task[Unit] = { + )(updateWorldForBlock: (BigInt, InMemoryWorldStateProxy) => InMemoryWorldStateProxy): Task[Unit] = Task { val currentWorld = getMptForBlock(currentBestBlock) @@ -333,11 +348,10 @@ abstract class CommonFakePeer(peerName: String, fakePeerCustomConfig: FakePeerCu broadcastBlock(childBlock, newWeight) bl.save(childBlock, Seq(), newWeight, saveAsBestBlock = true) } - } private def generateValidBlock( currentBestBlock: Block - )(updateWorldForBlock: (BigInt, InMemoryWorldStateProxy) => InMemoryWorldStateProxy): Task[Unit] = { + )(updateWorldForBlock: (BigInt, InMemoryWorldStateProxy) => InMemoryWorldStateProxy): Task[Unit] = Task { val currentWeight = bl.getChainWeightByHash(currentBestBlock.hash).get val currentWorld = getMptForBlock(currentBestBlock) @@ -346,11 +360,10 @@ abstract class CommonFakePeer(peerName: String, fakePeerCustomConfig: FakePeerCu bl.save(newBlock, Seq(), newWeight, saveAsBestBlock = true) broadcastBlock(newBlock, newWeight) } - } def importBlocksUntil( n: BigInt - )(updateWorldForBlock: (BigInt, InMemoryWorldStateProxy) => InMemoryWorldStateProxy): Task[Unit] = { + )(updateWorldForBlock: (BigInt, InMemoryWorldStateProxy) => InMemoryWorldStateProxy): Task[Unit] = Task(bl.getBestBlock()).flatMap { block => if (block.get.number >= n) { Task(()) @@ -358,12 +371,11 @@ abstract class CommonFakePeer(peerName: String, fakePeerCustomConfig: FakePeerCu generateValidBlock(block.get)(updateWorldForBlock).flatMap(_ => importBlocksUntil(n)(updateWorldForBlock)) } } - } def importInvalidBlocks( from: BigInt, to: BigInt - )(updateWorldForBlock: (BigInt, InMemoryWorldStateProxy) => InMemoryWorldStateProxy): Task[Unit] = { + )(updateWorldForBlock: (BigInt, InMemoryWorldStateProxy) => InMemoryWorldStateProxy): Task[Unit] = Task(bl.getBestBlock()).flatMap { block => if (block.get.number >= to) { Task(()) @@ -378,12 +390,11 @@ abstract class CommonFakePeer(peerName: String, fakePeerCustomConfig: FakePeerCu } } - } def importInvalidBlockNumbers( from: BigInt, to: BigInt - )(updateWorldForBlock: (BigInt, InMemoryWorldStateProxy) => InMemoryWorldStateProxy): Task[Unit] = { + )(updateWorldForBlock: (BigInt, InMemoryWorldStateProxy) => InMemoryWorldStateProxy): Task[Unit] = Task(bl.getBestBlock()).flatMap { block => if (block.get.number >= to) { Task(()) @@ -396,6 +407,5 @@ abstract class CommonFakePeer(peerName: String, fakePeerCustomConfig: FakePeerCu } } - } } diff --git a/src/it/scala/io/iohk/ethereum/sync/util/FastSyncItSpecUtils.scala b/src/it/scala/io/iohk/ethereum/sync/util/FastSyncItSpecUtils.scala index 381a449ed9..64ae61e23a 100644 --- a/src/it/scala/io/iohk/ethereum/sync/util/FastSyncItSpecUtils.scala +++ b/src/it/scala/io/iohk/ethereum/sync/util/FastSyncItSpecUtils.scala @@ -1,22 +1,28 @@ package io.iohk.ethereum.sync.util +import akka.actor.ActorRef import akka.util.ByteString + import cats.effect.Resource + +import monix.eval.Task + +import scala.annotation.tailrec +import scala.concurrent.duration._ +import scala.util.Try + import io.iohk.ethereum.Mocks.MockValidatorsAlwaysSucceed import io.iohk.ethereum.blockchain.sync.SyncProtocol import io.iohk.ethereum.blockchain.sync.fast.FastSync import io.iohk.ethereum.blockchain.sync.fast.FastSync.SyncState import io.iohk.ethereum.crypto.kec256 import io.iohk.ethereum.domain.Address -import io.iohk.ethereum.mpt.{HashNode, MptNode, MptTraversals} +import io.iohk.ethereum.mpt.HashNode +import io.iohk.ethereum.mpt.MptNode +import io.iohk.ethereum.mpt.MptTraversals import io.iohk.ethereum.sync.util.SyncCommonItSpecUtils.FakePeerCustomConfig.defaultConfig import io.iohk.ethereum.sync.util.SyncCommonItSpecUtils._ import io.iohk.ethereum.utils.ByteUtils -import monix.eval.Task - -import scala.annotation.tailrec -import scala.concurrent.duration._ -import scala.util.Try object FastSyncItSpecUtils { class FakePeer(peerName: String, fakePeerCustomConfig: FakePeerCustomConfig) @@ -24,7 +30,7 @@ object FastSyncItSpecUtils { lazy val validators = new MockValidatorsAlwaysSucceed - lazy val fastSync = system.actorOf( + lazy val fastSync: ActorRef = system.actorOf( FastSync.props( storagesInstance.storages.fastSyncStateStorage, storagesInstance.storages.appStateStorage, @@ -45,14 +51,13 @@ object FastSyncItSpecUtils { fastSync ! SyncProtocol.Start } - def waitForFastSyncFinish(): Task[Boolean] = { + def waitForFastSyncFinish(): Task[Boolean] = retryUntilWithDelay(Task(storagesInstance.storages.appStateStorage.isFastSyncDone()), 1.second, 90) { isDone => isDone } - } // Reads whole trie into memory, if the trie lacks nodes in storage it will be None - def getBestBlockTrie(): Option[MptNode] = { + def getBestBlockTrie(): Option[MptNode] = Try { val bestBlock = bl.getBestBlock().get val bestStateRoot = bestBlock.header.stateRoot @@ -61,11 +66,10 @@ object FastSyncItSpecUtils { storagesInstance.storages.stateStorage.getBackingStorage(bestBlock.number) ) }.toOption - } def containsExpectedDataUpToAccountAtBlock(n: BigInt, blockNumber: BigInt): Boolean = { @tailrec - def go(i: BigInt): Boolean = { + def go(i: BigInt): Boolean = if (i >= n) { true } else { @@ -91,12 +95,11 @@ object FastSyncItSpecUtils { false } } - } go(0) } - def startWithState(): Task[Unit] = { + def startWithState(): Task[Unit] = Task { val currentBest = bl.getBestBlock().get.header val safeTarget = currentBest.number + syncConfig.fastSyncBlockValidationX @@ -115,64 +118,58 @@ object FastSyncItSpecUtils { ) storagesInstance.storages.fastSyncStateStorage.putSyncState(syncState) }.map(_ => ()) - } } object FakePeer { - def startFakePeer(peerName: String, fakePeerCustomConfig: FakePeerCustomConfig): Task[FakePeer] = { + def startFakePeer(peerName: String, fakePeerCustomConfig: FakePeerCustomConfig): Task[FakePeer] = for { peer <- Task(new FakePeer(peerName, fakePeerCustomConfig)) _ <- peer.startPeer() } yield peer - } def start1FakePeerRes( fakePeerCustomConfig: FakePeerCustomConfig = defaultConfig, name: String - ): Resource[Task, FakePeer] = { + ): Resource[Task, FakePeer] = Resource.make { startFakePeer(name, fakePeerCustomConfig) } { peer => peer.shutdown() } - } def start2FakePeersRes( fakePeerCustomConfig1: FakePeerCustomConfig = defaultConfig, fakePeerCustomConfig2: FakePeerCustomConfig = defaultConfig - ): Resource[Task, (FakePeer, FakePeer)] = { + ): Resource[Task, (FakePeer, FakePeer)] = for { peer1 <- start1FakePeerRes(fakePeerCustomConfig1, "Peer1") peer2 <- start1FakePeerRes(fakePeerCustomConfig2, "Peer2") } yield (peer1, peer2) - } def start3FakePeersRes( fakePeerCustomConfig1: FakePeerCustomConfig = defaultConfig, fakePeerCustomConfig2: FakePeerCustomConfig = defaultConfig, fakePeerCustomConfig3: FakePeerCustomConfig = defaultConfig - ): Resource[Task, (FakePeer, FakePeer, FakePeer)] = { + ): Resource[Task, (FakePeer, FakePeer, FakePeer)] = for { peer1 <- start1FakePeerRes(fakePeerCustomConfig1, "Peer1") peer2 <- start1FakePeerRes(fakePeerCustomConfig2, "Peer2") peer3 <- start1FakePeerRes(fakePeerCustomConfig3, "Peer3") } yield (peer1, peer2, peer3) - } def start4FakePeersRes( fakePeerCustomConfig1: FakePeerCustomConfig = defaultConfig, fakePeerCustomConfig2: FakePeerCustomConfig = defaultConfig, fakePeerCustomConfig3: FakePeerCustomConfig = defaultConfig, fakePeerCustomConfig4: FakePeerCustomConfig = defaultConfig - ): Resource[Task, (FakePeer, FakePeer, FakePeer, FakePeer)] = { + ): Resource[Task, (FakePeer, FakePeer, FakePeer, FakePeer)] = for { peer1 <- start1FakePeerRes(fakePeerCustomConfig1, "Peer1") peer2 <- start1FakePeerRes(fakePeerCustomConfig2, "Peer2") peer3 <- start1FakePeerRes(fakePeerCustomConfig3, "Peer3") peer4 <- start1FakePeerRes(fakePeerCustomConfig4, "Peer3") } yield (peer1, peer2, peer3, peer4) - } } } diff --git a/src/it/scala/io/iohk/ethereum/sync/util/RegularSyncItSpecUtils.scala b/src/it/scala/io/iohk/ethereum/sync/util/RegularSyncItSpecUtils.scala index 19d45e8884..45ba36332c 100644 --- a/src/it/scala/io/iohk/ethereum/sync/util/RegularSyncItSpecUtils.scala +++ b/src/it/scala/io/iohk/ethereum/sync/util/RegularSyncItSpecUtils.scala @@ -1,29 +1,43 @@ package io.iohk.ethereum.sync.util -import akka.actor.{ActorRef, typed} +import akka.actor.ActorRef +import akka.actor.typed +import akka.actor.typed.scaladsl.adapter._ import akka.util.ByteString + import cats.effect.Resource + +import monix.eval.Task +import monix.execution.Scheduler + +import scala.concurrent.duration._ + import io.iohk.ethereum.Mocks.MockValidatorsAlwaysSucceed +import io.iohk.ethereum.blockchain.sync.PeersClient +import io.iohk.ethereum.blockchain.sync.SyncProtocol +import io.iohk.ethereum.blockchain.sync.regular.BlockBroadcast import io.iohk.ethereum.blockchain.sync.regular.BlockBroadcast.BlockToBroadcast +import io.iohk.ethereum.blockchain.sync.regular.BlockBroadcasterActor import io.iohk.ethereum.blockchain.sync.regular.BlockBroadcasterActor.BroadcastBlock +import io.iohk.ethereum.blockchain.sync.regular.BlockFetcher +import io.iohk.ethereum.blockchain.sync.regular.BlockFetcher.AdaptedMessageFromEventBus +import io.iohk.ethereum.blockchain.sync.regular.BlockImporter import io.iohk.ethereum.blockchain.sync.regular.BlockImporter.Start -import io.iohk.ethereum.blockchain.sync.regular.{ - BlockBroadcast, - BlockBroadcasterActor, - BlockFetcher, - BlockImporter, - RegularSync -} +import io.iohk.ethereum.blockchain.sync.regular.RegularSync import io.iohk.ethereum.blockchain.sync.regular.RegularSync.NewCheckpoint -import io.iohk.ethereum.blockchain.sync.{PeersClient, SyncProtocol} import io.iohk.ethereum.checkpointing.CheckpointingTestHelpers +import io.iohk.ethereum.consensus.ConsensusConfig +import io.iohk.ethereum.consensus.FullConsensusConfig import io.iohk.ethereum.consensus.Protocol.NoAdditionalPoWData import io.iohk.ethereum.consensus.blocks.CheckpointBlockGenerator -import io.iohk.ethereum.consensus.pow.{EthashConfig, PoWConsensus} -import io.iohk.ethereum.consensus.{ConsensusConfig, FullConsensusConfig, pow} +import io.iohk.ethereum.consensus.pow +import io.iohk.ethereum.consensus.pow.EthashConfig +import io.iohk.ethereum.consensus.pow.PoWConsensus +import io.iohk.ethereum.consensus.pow.validators.ValidatorsExecutor import io.iohk.ethereum.crypto import io.iohk.ethereum.domain._ import io.iohk.ethereum.ledger._ +import io.iohk.ethereum.mpt.MerklePatriciaTrie import io.iohk.ethereum.network.PeerId import io.iohk.ethereum.network.p2p.messages.BaseETH6XMessages.NewBlock import io.iohk.ethereum.nodebuilder.VmSetup @@ -32,13 +46,6 @@ import io.iohk.ethereum.sync.util.SyncCommonItSpecUtils.FakePeerCustomConfig.def import io.iohk.ethereum.sync.util.SyncCommonItSpecUtils._ import io.iohk.ethereum.transactions.PendingTransactionsManager import io.iohk.ethereum.utils._ -import monix.eval.Task -import monix.execution.Scheduler -import akka.actor.typed.scaladsl.adapter._ -import io.iohk.ethereum.blockchain.sync.regular.BlockFetcher.AdaptedMessageFromEventBus -import io.iohk.ethereum.mpt.MerklePatriciaTrie - -import scala.concurrent.duration._ object RegularSyncItSpecUtils { class ValidatorsExecutorAlwaysSucceed extends MockValidatorsAlwaysSucceed { @@ -81,9 +88,9 @@ object RegularSyncItSpecUtils { "peers-client" ) - lazy val consensus = buildEthashConsensus() + lazy val consensus: PoWConsensus = buildEthashConsensus() - lazy val blockQueue = BlockQueue(bl, syncConfig) + lazy val blockQueue: BlockQueue = BlockQueue(bl, syncConfig) lazy val blockValidation = new BlockValidation(consensus, blockchainReader, blockQueue) lazy val blockExecution = new BlockExecution( @@ -104,7 +111,7 @@ object RegularSyncItSpecUtils { "pending-transactions-manager" ) - lazy val validators = buildEthashConsensus().validators + lazy val validators: ValidatorsExecutor = buildEthashConsensus().validators val broadcasterRef: ActorRef = system.actorOf( BlockBroadcasterActor @@ -125,7 +132,7 @@ object RegularSyncItSpecUtils { "block-fetcher" ) - lazy val blockImporter = system.actorOf( + lazy val blockImporter: ActorRef = system.actorOf( BlockImporter.props( fetcher.toClassic, blockImport, @@ -139,7 +146,7 @@ object RegularSyncItSpecUtils { ) ) - lazy val regularSync = system.actorOf( + lazy val regularSync: ActorRef = system.actorOf( RegularSync.props( peersClient, etcPeerManager, @@ -162,7 +169,7 @@ object RegularSyncItSpecUtils { def broadcastBlock( blockNumber: Option[Int] = None - )(updateWorldForBlock: (BigInt, InMemoryWorldStateProxy) => InMemoryWorldStateProxy): Task[Unit] = { + )(updateWorldForBlock: (BigInt, InMemoryWorldStateProxy) => InMemoryWorldStateProxy): Task[Unit] = Task(blockNumber match { case Some(bNumber) => blockchainReader @@ -179,11 +186,9 @@ object RegularSyncItSpecUtils { broadcastBlock(newBlock, newWeight) } } - } - def waitForRegularSyncLoadLastBlock(blockNumber: BigInt): Task[Boolean] = { - retryUntilWithDelay(Task(bl.getBestBlockNumber() == blockNumber), 1.second, 90) { isDone => isDone } - } + def waitForRegularSyncLoadLastBlock(blockNumber: BigInt): Task[Boolean] = + retryUntilWithDelay(Task(bl.getBestBlockNumber() == blockNumber), 1.second, 90)(isDone => isDone) def mineNewBlock( plusDifficulty: BigInt = 0 @@ -200,13 +205,12 @@ object RegularSyncItSpecUtils { def mineNewBlocks(delay: FiniteDuration, nBlocks: Int)( updateWorldForBlock: (BigInt, InMemoryWorldStateProxy) => InMemoryWorldStateProxy - ): Task[Unit] = { + ): Task[Unit] = if (nBlocks > 0) { mineNewBlock()(updateWorldForBlock) .delayExecution(delay) .flatMap(_ => mineNewBlocks(delay, nBlocks - 1)(updateWorldForBlock)) } else Task(()) - } def addCheckpointedBlock(parent: Block): Task[Unit] = Task { val signatures = CheckpointingTestHelpers.createCheckpointSignatures( @@ -222,7 +226,7 @@ object RegularSyncItSpecUtils { fetcher ! AdaptedMessageFromEventBus(NewBlock(checkpoint, checkpoint.header.difficulty), peerId) } - private def getMptForBlock(block: Block) = { + private def getMptForBlock(block: Block) = InMemoryWorldStateProxy( storagesInstance.storages.evmCodeStorage, bl.getBackingMptStorage(block.number), @@ -232,11 +236,9 @@ object RegularSyncItSpecUtils { noEmptyAccounts = false, ethCompatibleStorage = true ) - } - private def broadcastBlock(block: Block, weight: ChainWeight) = { + private def broadcastBlock(block: Block, weight: ChainWeight) = broadcasterActor ! BroadcastBlock(BlockToBroadcast(block, weight)) - } private def createChildBlock( parent: Block, @@ -263,33 +265,30 @@ object RegularSyncItSpecUtils { object FakePeer { - def startFakePeer(peerName: String, fakePeerCustomConfig: FakePeerCustomConfig): Task[FakePeer] = { + def startFakePeer(peerName: String, fakePeerCustomConfig: FakePeerCustomConfig): Task[FakePeer] = for { peer <- Task(new FakePeer(peerName, fakePeerCustomConfig)) _ <- peer.startPeer() } yield peer - } def start1FakePeerRes( fakePeerCustomConfig: FakePeerCustomConfig = defaultConfig, name: String - ): Resource[Task, FakePeer] = { + ): Resource[Task, FakePeer] = Resource.make { startFakePeer(name, fakePeerCustomConfig) } { peer => peer.shutdown() } - } def start2FakePeersRes( fakePeerCustomConfig1: FakePeerCustomConfig = defaultConfig, fakePeerCustomConfig2: FakePeerCustomConfig = defaultConfig - ): Resource[Task, (FakePeer, FakePeer)] = { + ): Resource[Task, (FakePeer, FakePeer)] = for { peer1 <- start1FakePeerRes(fakePeerCustomConfig1, "Peer1") peer2 <- start1FakePeerRes(fakePeerCustomConfig2, "Peer2") } yield (peer1, peer2) - } } } diff --git a/src/it/scala/io/iohk/ethereum/sync/util/SyncCommonItSpec.scala b/src/it/scala/io/iohk/ethereum/sync/util/SyncCommonItSpec.scala index 2c85bfde8f..7eb75649d3 100644 --- a/src/it/scala/io/iohk/ethereum/sync/util/SyncCommonItSpec.scala +++ b/src/it/scala/io/iohk/ethereum/sync/util/SyncCommonItSpec.scala @@ -1,8 +1,10 @@ package io.iohk.ethereum.sync.util -import java.net.{InetSocketAddress, ServerSocket} +import java.net.InetSocketAddress +import java.net.ServerSocket -import io.iohk.ethereum.domain.{Block, ChainWeight} +import io.iohk.ethereum.domain.Block +import io.iohk.ethereum.domain.ChainWeight import io.iohk.ethereum.ledger.InMemoryWorldStateProxy object SyncCommonItSpec { @@ -10,11 +12,8 @@ object SyncCommonItSpec { def randomAddress(): InetSocketAddress = { val s = new ServerSocket(0) - try { - new InetSocketAddress("localhost", s.getLocalPort) - } finally { - s.close() - } + try new InetSocketAddress("localhost", s.getLocalPort) + finally s.close() } final case class BlockchainState( diff --git a/src/it/scala/io/iohk/ethereum/sync/util/SyncCommonItSpecUtils.scala b/src/it/scala/io/iohk/ethereum/sync/util/SyncCommonItSpecUtils.scala index 5bfbd75f89..b441aa207f 100644 --- a/src/it/scala/io/iohk/ethereum/sync/util/SyncCommonItSpecUtils.scala +++ b/src/it/scala/io/iohk/ethereum/sync/util/SyncCommonItSpecUtils.scala @@ -1,16 +1,18 @@ package io.iohk.ethereum.sync.util -import java.util.concurrent.{ThreadLocalRandom, TimeoutException} +import java.util.concurrent.ThreadLocalRandom +import java.util.concurrent.TimeoutException -import io.iohk.ethereum.network.PeerManagerActor.FastSyncHostConfiguration import monix.eval.Task import scala.concurrent.duration.FiniteDuration +import io.iohk.ethereum.network.PeerManagerActor.FastSyncHostConfiguration + object SyncCommonItSpecUtils { def retryUntilWithDelay[A](source: Task[A], delay: FiniteDuration, maxRetries: Int)( predicate: A => Boolean - ): Task[A] = { + ): Task[A] = source.delayExecution(delay).flatMap { result => if (predicate(result)) { Task.now(result) @@ -22,7 +24,6 @@ object SyncCommonItSpecUtils { } } } - } case class HostConfig( maxBlocksHeadersPerMessage: Int, @@ -46,6 +47,6 @@ object SyncCommonItSpecUtils { final case class FakePeerCustomConfig(hostConfig: HostConfig) object FakePeerCustomConfig { - val defaultConfig = FakePeerCustomConfig(HostConfig(200, 200, 200, 200)) + val defaultConfig: FakePeerCustomConfig = FakePeerCustomConfig(HostConfig(200, 200, 200, 200)) } } diff --git a/src/it/scala/io/iohk/ethereum/txExecTest/ContractTest.scala b/src/it/scala/io/iohk/ethereum/txExecTest/ContractTest.scala index b4e919ab58..4c929fa267 100644 --- a/src/it/scala/io/iohk/ethereum/txExecTest/ContractTest.scala +++ b/src/it/scala/io/iohk/ethereum/txExecTest/ContractTest.scala @@ -1,17 +1,20 @@ package io.iohk.ethereum.txExecTest -import java.util.concurrent.Executors -import io.iohk.ethereum.domain.{BlockchainImpl, BlockchainReader, Receipt} -import io.iohk.ethereum.ledger.{BlockExecution, BlockQueue, BlockValidation} -import io.iohk.ethereum.txExecTest.util.FixtureProvider -import io.iohk.ethereum.utils.Config import org.scalatest.flatspec.AnyFlatSpec +import org.scalatest.matchers.dsl.ResultOfATypeInvocation import org.scalatest.matchers.should.Matchers +import io.iohk.ethereum.domain.Receipt +import io.iohk.ethereum.ledger.BlockExecution +import io.iohk.ethereum.ledger.BlockQueue +import io.iohk.ethereum.ledger.BlockValidation +import io.iohk.ethereum.txExecTest.util.FixtureProvider +import io.iohk.ethereum.utils.Config + class ContractTest extends AnyFlatSpec with Matchers { val blockchainConfig = Config.blockchains.blockchainConfig - val syncConfig = Config.SyncConfig(Config.config) - val noErrors = a[Right[_, Seq[Receipt]]] + val syncConfig: Config.SyncConfig = Config.SyncConfig(Config.config) + val noErrors: ResultOfATypeInvocation[Right[_, Seq[Receipt]]] = a[Right[_, Seq[Receipt]]] "Ledger" should "execute and validate" in new ScenarioSetup { val fixtures: FixtureProvider.Fixture = FixtureProvider.loadFixtures("/txExecTest/purchaseContract") diff --git a/src/it/scala/io/iohk/ethereum/txExecTest/ECIP1017Test.scala b/src/it/scala/io/iohk/ethereum/txExecTest/ECIP1017Test.scala index ec6ed983f7..77fc77ca2e 100644 --- a/src/it/scala/io/iohk/ethereum/txExecTest/ECIP1017Test.scala +++ b/src/it/scala/io/iohk/ethereum/txExecTest/ECIP1017Test.scala @@ -1,18 +1,28 @@ package io.iohk.ethereum.txExecTest -import io.iohk.ethereum.domain.{Address, BlockchainImpl, BlockchainReader, Receipt, UInt256} -import io.iohk.ethereum.ledger.{BlockExecution, BlockQueue, BlockValidation} -import io.iohk.ethereum.txExecTest.util.FixtureProvider -import io.iohk.ethereum.utils.{BlockchainConfig, ForkBlockNumbers, MonetaryPolicyConfig} import org.scalatest.flatspec.AnyFlatSpec +import org.scalatest.matchers.dsl.ResultOfATypeInvocation import org.scalatest.matchers.should.Matchers +import io.iohk.ethereum.domain.Address +import io.iohk.ethereum.domain.BlockchainImpl +import io.iohk.ethereum.domain.BlockchainReader +import io.iohk.ethereum.domain.Receipt +import io.iohk.ethereum.domain.UInt256 +import io.iohk.ethereum.ledger.BlockExecution +import io.iohk.ethereum.ledger.BlockQueue +import io.iohk.ethereum.ledger.BlockValidation +import io.iohk.ethereum.txExecTest.util.FixtureProvider +import io.iohk.ethereum.utils.BlockchainConfig +import io.iohk.ethereum.utils.ForkBlockNumbers +import io.iohk.ethereum.utils.MonetaryPolicyConfig + class ECIP1017Test extends AnyFlatSpec with Matchers { val EraDuration = 3 trait TestSetup extends ScenarioSetup { - override lazy val blockchainConfig = BlockchainConfig( + override lazy val blockchainConfig: BlockchainConfig = BlockchainConfig( monetaryPolicyConfig = MonetaryPolicyConfig(EraDuration, 0.2, 5000000000000000000L, 3000000000000000000L), // unused maxCodeSize = None, @@ -50,11 +60,10 @@ class ECIP1017Test extends AnyFlatSpec with Matchers { gasTieBreaker = false, treasuryAddress = Address(0) ) - val noErrors = a[Right[_, Seq[Receipt]]] + val noErrors: ResultOfATypeInvocation[Right[_, Seq[Receipt]]] = a[Right[_, Seq[Receipt]]] } - /** - * Tests the block reward calculation through out all the monetary policy through all the eras till block + /** Tests the block reward calculation through out all the monetary policy through all the eras till block * mining reward goes to zero. Block mining reward is tested till era 200 (that starts at block number 602) * as the reward reaches zero at era 193 (which starts at block number 579), given an eraDuration of 3, * a rewardReductionRate of 0.2 and a firstEraBlockReward of 5 ether. @@ -67,7 +76,7 @@ class ECIP1017Test extends AnyFlatSpec with Matchers { protected val testBlockchainStorages = FixtureProvider.prepareStorages(endBlock, fixtures) - (startBlock to endBlock) foreach { blockToExecute => + (startBlock to endBlock).foreach { blockToExecute => val storages = FixtureProvider.prepareStorages(blockToExecute - 1, fixtures) val blockchainReader = BlockchainReader(storages) val blockchain = BlockchainImpl(storages, blockchainReader) diff --git a/src/it/scala/io/iohk/ethereum/txExecTest/ForksTest.scala b/src/it/scala/io/iohk/ethereum/txExecTest/ForksTest.scala index 5f187a4fec..6f7a569547 100644 --- a/src/it/scala/io/iohk/ethereum/txExecTest/ForksTest.scala +++ b/src/it/scala/io/iohk/ethereum/txExecTest/ForksTest.scala @@ -1,17 +1,26 @@ package io.iohk.ethereum.txExecTest -import java.util.concurrent.Executors -import io.iohk.ethereum.domain.{Address, BlockchainImpl, BlockchainReader, Receipt, UInt256} -import io.iohk.ethereum.ledger.{BlockExecution, BlockQueue, BlockValidation} -import io.iohk.ethereum.txExecTest.util.FixtureProvider -import io.iohk.ethereum.utils.{BlockchainConfig, ForkBlockNumbers, MonetaryPolicyConfig} import org.scalatest.flatspec.AnyFlatSpec +import org.scalatest.matchers.dsl.ResultOfATypeInvocation import org.scalatest.matchers.should.Matchers +import io.iohk.ethereum.domain.Address +import io.iohk.ethereum.domain.BlockchainImpl +import io.iohk.ethereum.domain.BlockchainReader +import io.iohk.ethereum.domain.Receipt +import io.iohk.ethereum.domain.UInt256 +import io.iohk.ethereum.ledger.BlockExecution +import io.iohk.ethereum.ledger.BlockQueue +import io.iohk.ethereum.ledger.BlockValidation +import io.iohk.ethereum.txExecTest.util.FixtureProvider +import io.iohk.ethereum.utils.BlockchainConfig +import io.iohk.ethereum.utils.ForkBlockNumbers +import io.iohk.ethereum.utils.MonetaryPolicyConfig + class ForksTest extends AnyFlatSpec with Matchers { trait TestSetup extends ScenarioSetup { - override lazy val blockchainConfig = BlockchainConfig( + override lazy val blockchainConfig: BlockchainConfig = BlockchainConfig( forkBlockNumbers = ForkBlockNumbers( frontierBlockNumber = 0, homesteadBlockNumber = 3, @@ -49,7 +58,7 @@ class ForksTest extends AnyFlatSpec with Matchers { ethCompatibleStorage = true, treasuryAddress = Address(0) ) - val noErrors = a[Right[_, Seq[Receipt]]] + val noErrors: ResultOfATypeInvocation[Right[_, Seq[Receipt]]] = a[Right[_, Seq[Receipt]]] } "Ledger" should "execute blocks with respect to forks" in new TestSetup { @@ -60,7 +69,7 @@ class ForksTest extends AnyFlatSpec with Matchers { protected val testBlockchainStorages = FixtureProvider.prepareStorages(endBlock, fixtures) - (startBlock to endBlock) foreach { blockToExecute => + (startBlock to endBlock).foreach { blockToExecute => val storages = FixtureProvider.prepareStorages(blockToExecute - 1, fixtures) val blockchainReader = BlockchainReader(storages) val blockchain = BlockchainImpl(storages, blockchainReader) diff --git a/src/it/scala/io/iohk/ethereum/txExecTest/ScenarioSetup.scala b/src/it/scala/io/iohk/ethereum/txExecTest/ScenarioSetup.scala index af65788336..c540f8992e 100644 --- a/src/it/scala/io/iohk/ethereum/txExecTest/ScenarioSetup.scala +++ b/src/it/scala/io/iohk/ethereum/txExecTest/ScenarioSetup.scala @@ -1,7 +1,9 @@ package io.iohk.ethereum.txExecTest import io.iohk.ethereum.blockchain.sync.EphemBlockchainTestSetup -import io.iohk.ethereum.domain.{BlockchainImpl, BlockchainReader, BlockchainStorages} +import io.iohk.ethereum.domain.BlockchainImpl +import io.iohk.ethereum.domain.BlockchainReader +import io.iohk.ethereum.domain.BlockchainStorages import io.iohk.ethereum.ledger.VMImpl trait ScenarioSetup extends EphemBlockchainTestSetup { diff --git a/src/it/scala/io/iohk/ethereum/txExecTest/util/DumpChainActor.scala b/src/it/scala/io/iohk/ethereum/txExecTest/util/DumpChainActor.scala index f4f29a981e..d91c44f19c 100644 --- a/src/it/scala/io/iohk/ethereum/txExecTest/util/DumpChainActor.scala +++ b/src/it/scala/io/iohk/ethereum/txExecTest/util/DumpChainActor.scala @@ -3,33 +3,45 @@ package io.iohk.ethereum.txExecTest.util import java.io.FileWriter import java.net.URI -import akka.actor.{Actor, ActorRef, _} +import akka.actor.Actor +import akka.actor.ActorRef +import akka.actor._ import akka.util.ByteString + +import scala.collection.immutable.HashMap +import scala.concurrent.ExecutionContext.Implicits.global +import scala.concurrent.duration._ +import scala.language.postfixOps + +import org.bouncycastle.util.encoders.Hex + import io.iohk.ethereum.crypto.kec256 +import io.iohk.ethereum.domain.BlockBody +import io.iohk.ethereum.domain.BlockHeader import io.iohk.ethereum.domain.BlockHeaderImplicits._ -import io.iohk.ethereum.domain.{BlockBody, BlockHeader, Receipt} -import io.iohk.ethereum.mpt.{BranchNode, ExtensionNode, HashNode, LeafNode, MptNode} +import io.iohk.ethereum.domain.Receipt +import io.iohk.ethereum.mpt.BranchNode +import io.iohk.ethereum.mpt.ExtensionNode +import io.iohk.ethereum.mpt.HashNode +import io.iohk.ethereum.mpt.LeafNode +import io.iohk.ethereum.mpt.MptNode +import io.iohk.ethereum.network.Peer import io.iohk.ethereum.network.PeerActor.SendMessage import io.iohk.ethereum.network.PeerEventBusActor.PeerEvent.MessageFromPeer +import io.iohk.ethereum.network.PeerEventBusActor.PeerSelector +import io.iohk.ethereum.network.PeerEventBusActor.Subscribe import io.iohk.ethereum.network.PeerEventBusActor.SubscriptionClassifier.MessageClassifier -import io.iohk.ethereum.network.PeerEventBusActor.{PeerSelector, Subscribe} -import io.iohk.ethereum.network.PeerManagerActor.{GetPeers, Peers} +import io.iohk.ethereum.network.PeerManagerActor +import io.iohk.ethereum.network.PeerManagerActor.GetPeers +import io.iohk.ethereum.network.PeerManagerActor.Peers import io.iohk.ethereum.network.p2p.messages.Codes import io.iohk.ethereum.network.p2p.messages.ETH62._ import io.iohk.ethereum.network.p2p.messages.ETH63.MptNodeEncoders._ import io.iohk.ethereum.network.p2p.messages.ETH63.ReceiptImplicits._ import io.iohk.ethereum.network.p2p.messages.ETH63._ -import io.iohk.ethereum.network.{Peer, PeerManagerActor} import io.iohk.ethereum.txExecTest.util.DumpChainActor._ -import org.bouncycastle.util.encoders.Hex - -import scala.collection.immutable.HashMap -import scala.concurrent.ExecutionContext.Implicits.global -import scala.concurrent.duration._ -import scala.language.postfixOps -/** - * Actor used for obtaining all the blockchain data (blocks, receipts, nodes) from the blocks [startBlock, maxBlocks] +/** Actor used for obtaining all the blockchain data (blocks, receipts, nodes) from the blocks [startBlock, maxBlocks] * from a peer bootstrapNode. * The bootstrapNode is assumed to respond to all the messages and properly, so no validation of the received data is done. */ @@ -127,10 +139,10 @@ class DumpChainActor( val nodes = NodeData(stateNodes).values.indices.map(i => NodeData(stateNodes).getMptNode(i)) val children = nodes.flatMap { - case n: BranchNode => n.children.collect { case HashNode(h) => ByteString(h) } + case n: BranchNode => n.children.collect { case HashNode(h) => ByteString(h) } case ExtensionNode(_, HashNode(h), _, _, _) => Seq(ByteString(h)) - case _: LeafNode => Seq.empty - case _ => Seq.empty + case _: LeafNode => Seq.empty + case _ => Seq.empty } var contractChildren: Seq[ByteString] = Nil @@ -158,9 +170,9 @@ class DumpChainActor( val cNodes = NodeData(contractNodes).values.indices.map(i => NodeData(contractNodes).getMptNode(i)) contractChildren = contractChildren ++ cNodes.flatMap { - case n: BranchNode => n.children.collect { case HashNode(h) => ByteString(h) } + case n: BranchNode => n.children.collect { case HashNode(h) => ByteString(h) } case ExtensionNode(_, HashNode(h), _, _, _) => Seq(ByteString(h)) - case _ => Seq.empty + case _ => Seq.empty } stateNodesHashes = stateNodesHashes ++ children.toSet @@ -182,13 +194,13 @@ class DumpChainActor( } - private def assignWork(): Unit = { + private def assignWork(): Unit = if (!anyRequestsRemaining()) { dumpChainToFile() println("Finished download, dumped chain to file") assignWorkTimeout.cancel() connectToBootstrapTimeout.cancel() - context stop self + context.stop(self) } else { if (peers.nonEmpty) { val peerToRequest = peers.head @@ -228,7 +240,6 @@ class DumpChainActor( } } } - } private def anyRequestsRemaining(): Boolean = nodesToRequest.nonEmpty || blockBodiesToRequest.nonEmpty || receiptsToRequest.nonEmpty || (blockHeaderToRequest < maxBlocks) @@ -283,6 +294,8 @@ object DumpChainActor { Props( new DumpChainActor(peerManager, peerMessageBus: ActorRef, startBlock: BigInt, maxBlocks: BigInt, bootstrapNode) ) - val emptyStorage = ByteString(Hex.decode("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421")) - val emptyEvm = ByteString(Hex.decode("c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470")) + val emptyStorage: ByteString = ByteString( + Hex.decode("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421") + ) + val emptyEvm: ByteString = ByteString(Hex.decode("c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470")) } diff --git a/src/it/scala/io/iohk/ethereum/txExecTest/util/DumpChainApp.scala b/src/it/scala/io/iohk/ethereum/txExecTest/util/DumpChainApp.scala index 0415bda290..27d6c032d2 100644 --- a/src/it/scala/io/iohk/ethereum/txExecTest/util/DumpChainApp.scala +++ b/src/it/scala/io/iohk/ethereum/txExecTest/util/DumpChainApp.scala @@ -2,36 +2,56 @@ package io.iohk.ethereum.txExecTest.util import java.time.Clock import java.util.concurrent.atomic.AtomicReference + +import akka.actor.ActorRef import akka.actor.ActorSystem import akka.util.ByteString + +import scala.concurrent.duration._ + +import com.typesafe.config import com.typesafe.config.ConfigFactory +import org.bouncycastle.util.encoders.Hex +import org.scalamock.scalatest.MockFactory + import io.iohk.ethereum.blockchain.sync.CacheBasedBlacklist +import io.iohk.ethereum.db.components.RocksDbDataSourceComponent +import io.iohk.ethereum.db.components.Storages import io.iohk.ethereum.db.components.Storages.PruningModeComponent -import io.iohk.ethereum.db.components.{RocksDbDataSourceComponent, Storages} -import io.iohk.ethereum.db.dataSource.{DataSourceBatchUpdate} -import io.iohk.ethereum.db.storage.NodeStorage.{NodeEncoded, NodeHash} -import io.iohk.ethereum.db.storage.pruning.{ArchivePruning, PruningMode} -import io.iohk.ethereum.db.storage.{AppStateStorage, MptStorage, StateStorage} +import io.iohk.ethereum.db.dataSource.DataSourceBatchUpdate +import io.iohk.ethereum.db.storage.AppStateStorage +import io.iohk.ethereum.db.storage.MptStorage +import io.iohk.ethereum.db.storage.NodeStorage.NodeEncoded +import io.iohk.ethereum.db.storage.NodeStorage.NodeHash +import io.iohk.ethereum.db.storage.pruning.ArchivePruning +import io.iohk.ethereum.db.storage.pruning.PruningMode import io.iohk.ethereum.domain.BlockHeader.HeaderExtraFields.HefEmpty -import io.iohk.ethereum.domain.{Blockchain, UInt256, _} -import io.iohk.ethereum.jsonrpc.ProofService.{EmptyStorageValueProof, StorageProof, StorageProofKey} -import io.iohk.ethereum.ledger.{InMemoryWorldStateProxy, InMemoryWorldStateProxyStorage} +import io.iohk.ethereum.domain.Blockchain +import io.iohk.ethereum.domain._ +import io.iohk.ethereum.jsonrpc.ProofService.EmptyStorageValueProof +import io.iohk.ethereum.jsonrpc.ProofService.StorageProof +import io.iohk.ethereum.jsonrpc.ProofService.StorageProofKey +import io.iohk.ethereum.ledger.InMemoryWorldStateProxy +import io.iohk.ethereum.ledger.InMemoryWorldStateProxyStorage import io.iohk.ethereum.mpt.MptNode import io.iohk.ethereum.network.EtcPeerManagerActor.PeerInfo +import io.iohk.ethereum.network.ForkResolver +import io.iohk.ethereum.network.PeerEventBusActor +import io.iohk.ethereum.network.PeerManagerActor import io.iohk.ethereum.network.PeerManagerActor.PeerConfiguration import io.iohk.ethereum.network.PeerStatisticsActor import io.iohk.ethereum.network.discovery.DiscoveryConfig -import io.iohk.ethereum.network.handshaker.{EtcHandshaker, EtcHandshakerConfiguration, Handshaker} +import io.iohk.ethereum.network.handshaker.EtcHandshaker +import io.iohk.ethereum.network.handshaker.EtcHandshakerConfiguration +import io.iohk.ethereum.network.handshaker.Handshaker import io.iohk.ethereum.network.p2p.messages.Capability import io.iohk.ethereum.network.rlpx.RLPxConnectionHandler.RLPxConfiguration -import io.iohk.ethereum.network.{ForkResolver, PeerEventBusActor, PeerManagerActor} -import io.iohk.ethereum.nodebuilder.{AuthHandshakerBuilder, NodeKeyBuilder} +import io.iohk.ethereum.nodebuilder.AuthHandshakerBuilder +import io.iohk.ethereum.nodebuilder.NodeKeyBuilder import io.iohk.ethereum.security.SecureRandomBuilder -import io.iohk.ethereum.utils.{Config, NodeStatus, ServerStatus} -import org.bouncycastle.util.encoders.Hex -import org.scalamock.scalatest.MockFactory - -import scala.concurrent.duration._ +import io.iohk.ethereum.utils.Config +import io.iohk.ethereum.utils.NodeStatus +import io.iohk.ethereum.utils.ServerStatus object DumpChainApp extends App @@ -39,17 +59,17 @@ object DumpChainApp with SecureRandomBuilder with AuthHandshakerBuilder with MockFactory { - val conf = ConfigFactory.load("txExecTest/chainDump.conf") - val node = conf.getString("node") - val genesisHash = ByteString(Hex.decode(conf.getString("genesisHash"))) - val privateNetworkId = conf.getInt("networkId") - val startBlock = conf.getInt("startBlock") - val maxBlocks = conf.getInt("maxBlocks") + val conf: config.Config = ConfigFactory.load("txExecTest/chainDump.conf") + val node: String = conf.getString("node") + val genesisHash: ByteString = ByteString(Hex.decode(conf.getString("genesisHash"))) + val privateNetworkId: Int = conf.getInt("networkId") + val startBlock: Int = conf.getInt("startBlock") + val maxBlocks: Int = conf.getInt("maxBlocks") val blockchainConfig = Config.blockchains.blockchainConfig - val discoveryConfig = DiscoveryConfig(Config.config, blockchainConfig.bootstrapNodes) + val discoveryConfig: DiscoveryConfig = DiscoveryConfig(Config.config, blockchainConfig.bootstrapNodes) - val peerConfig = new PeerConfiguration { + val peerConfig: PeerConfiguration = new PeerConfiguration { override val rlpxConfiguration: RLPxConfiguration = Config.Network.peer.rlpxConfiguration override val connectRetryDelay: FiniteDuration = Config.Network.peer.connectRetryDelay override val connectMaxRetries: Int = Config.Network.peer.connectMaxRetries @@ -74,22 +94,24 @@ object DumpChainApp override val statSlotCount: Int = 30 } - val actorSystem = ActorSystem("mantis_system") + val actorSystem: ActorSystem = ActorSystem("mantis_system") trait PruningConfig extends PruningModeComponent { override val pruningMode: PruningMode = ArchivePruning } - val storagesInstance = new RocksDbDataSourceComponent with PruningConfig with Storages.DefaultStorages + val storagesInstance: RocksDbDataSourceComponent with PruningConfig with Storages.DefaultStorages = + new RocksDbDataSourceComponent with PruningConfig with Storages.DefaultStorages val blockchain: Blockchain = new BlockchainMock(genesisHash) - val blockchainReader = mock[BlockchainReader] + val blockchainReader: BlockchainReader = mock[BlockchainReader] (blockchainReader.getHashByBlockNumber _).expects(*).returning(Some(genesisHash)) - val nodeStatus = + val nodeStatus: NodeStatus = NodeStatus(key = nodeKey, serverStatus = ServerStatus.NotListening, discoveryStatus = ServerStatus.NotListening) lazy val nodeStatusHolder = new AtomicReference(nodeStatus) - lazy val forkResolverOpt = blockchainConfig.daoForkConfig.map(new ForkResolver.EtcForkResolver(_)) + lazy val forkResolverOpt: Option[ForkResolver.EtcForkResolver] = + blockchainConfig.daoForkConfig.map(new ForkResolver.EtcForkResolver(_)) private val handshakerConfiguration: EtcHandshakerConfiguration = new EtcHandshakerConfiguration { @@ -104,13 +126,14 @@ object DumpChainApp lazy val handshaker: Handshaker[PeerInfo] = EtcHandshaker(handshakerConfiguration) - val peerMessageBus = actorSystem.actorOf(PeerEventBusActor.props) + val peerMessageBus: ActorRef = actorSystem.actorOf(PeerEventBusActor.props) - val peerStatistics = actorSystem.actorOf(PeerStatisticsActor.props(peerMessageBus, 1.minute, 30)(Clock.systemUTC())) + val peerStatistics: ActorRef = + actorSystem.actorOf(PeerStatisticsActor.props(peerMessageBus, 1.minute, 30)(Clock.systemUTC())) val blacklist: CacheBasedBlacklist = CacheBasedBlacklist.empty(100) - val peerManager = actorSystem.actorOf( + val peerManager: ActorRef = actorSystem.actorOf( PeerManagerActor.props( peerDiscoveryManager = actorSystem.deadLetters, // TODO: fixme peerConfiguration = peerConfig, diff --git a/src/it/scala/io/iohk/ethereum/txExecTest/util/FixtureProvider.scala b/src/it/scala/io/iohk/ethereum/txExecTest/util/FixtureProvider.scala index 287d8a1d31..8184379534 100644 --- a/src/it/scala/io/iohk/ethereum/txExecTest/util/FixtureProvider.scala +++ b/src/it/scala/io/iohk/ethereum/txExecTest/util/FixtureProvider.scala @@ -3,23 +3,32 @@ package io.iohk.ethereum.txExecTest.util import java.io.Closeable import akka.util.ByteString + +import scala.io.Source +import scala.util.Try + +import org.bouncycastle.util.encoders.Hex + +import io.iohk.ethereum.db.cache.AppCaches +import io.iohk.ethereum.db.cache.LruCache +import io.iohk.ethereum.db.components.EphemDataSourceComponent +import io.iohk.ethereum.db.storage.NodeStorage.NodeHash import io.iohk.ethereum.db.storage._ -import io.iohk.ethereum.domain._ -import io.iohk.ethereum.domain.BlockHeaderImplicits._ +import io.iohk.ethereum.db.storage.pruning.ArchivePruning +import io.iohk.ethereum.db.storage.pruning.PruningMode import io.iohk.ethereum.domain.BlockBody._ +import io.iohk.ethereum.domain.BlockHeaderImplicits._ +import io.iohk.ethereum.domain._ +import io.iohk.ethereum.mpt.BranchNode +import io.iohk.ethereum.mpt.ExtensionNode +import io.iohk.ethereum.mpt.HashNode +import io.iohk.ethereum.mpt.LeafNode +import io.iohk.ethereum.mpt.MptNode import io.iohk.ethereum.network.p2p.messages.ETH63._ -import MptNodeEncoders._ -import ReceiptImplicits._ -import io.iohk.ethereum.db.cache.{AppCaches, LruCache} -import io.iohk.ethereum.db.components.EphemDataSourceComponent -import io.iohk.ethereum.db.storage.NodeStorage.NodeHash -import io.iohk.ethereum.db.storage.pruning.{ArchivePruning, PruningMode} -import io.iohk.ethereum.mpt.{BranchNode, ExtensionNode, HashNode, LeafNode, MptNode} import io.iohk.ethereum.utils.Config -import org.bouncycastle.util.encoders.Hex -import scala.io.Source -import scala.util.Try +import MptNodeEncoders._ +import ReceiptImplicits._ object FixtureProvider { @@ -89,7 +98,7 @@ object FixtureProvider { storages.stateStorage.saveNode(ByteString(m.hash), m.toBytes, block.header.number) m.next match { case HashNode(hash) if hash.nonEmpty => traverse(ByteString(hash)) - case _ => + case _ => } case Some(m: LeafNode) => @@ -205,8 +214,7 @@ object FixtureProvider { ) } - private def withClose[A, B <: Closeable](closeable: B)(f: B => A): A = { - try { f(closeable) } - finally { closeable.close() } - } + private def withClose[A, B <: Closeable](closeable: B)(f: B => A): A = + try f(closeable) + finally closeable.close() } diff --git a/src/main/scala/io/iohk/ethereum/App.scala b/src/main/scala/io/iohk/ethereum/App.scala index a8c5c91455..0ab331d337 100644 --- a/src/main/scala/io/iohk/ethereum/App.scala +++ b/src/main/scala/io/iohk/ethereum/App.scala @@ -1,10 +1,12 @@ package io.iohk.ethereum import io.iohk.ethereum.cli.CliLauncher -import io.iohk.ethereum.crypto.{EcKeyGen, SignatureValidator} +import io.iohk.ethereum.crypto.EcKeyGen +import io.iohk.ethereum.crypto.SignatureValidator import io.iohk.ethereum.extvm.VmServerApp import io.iohk.ethereum.faucet.Faucet -import io.iohk.ethereum.utils.{Config, Logger} +import io.iohk.ethereum.utils.Config +import io.iohk.ethereum.utils.Logger object App extends Logger { @@ -20,19 +22,18 @@ object App extends Logger { val sigValidator = "signature-validator" args.headOption match { - case None => Mantis.main(args) - case Some(`launchMantis`) => Mantis.main(args.tail) + case None => Mantis.main(args) + case Some(`launchMantis`) => Mantis.main(args.tail) case Some(`launchKeytool`) => KeyTool.main(args.tail) - case Some(`downloadBootstrap`) => { + case Some(`downloadBootstrap`) => Config.Db.dataSource match { case "rocksdb" => BootstrapDownload.main(args.tail :+ Config.Db.RocksDb.path) } - } - case Some(`vmServer`) => VmServerApp.main(args.tail) - case Some(`faucet`) => Faucet.main(args.tail) - case Some(`ecKeyGen`) => EcKeyGen.main(args.tail) + case Some(`vmServer`) => VmServerApp.main(args.tail) + case Some(`faucet`) => Faucet.main(args.tail) + case Some(`ecKeyGen`) => EcKeyGen.main(args.tail) case Some(`sigValidator`) => SignatureValidator.main(args.tail) - case Some(`cli`) => CliLauncher.main(args.tail) + case Some(`cli`) => CliLauncher.main(args.tail) case Some(unknown) => log.error( s"Unrecognised launcher option $unknown, " + diff --git a/src/main/scala/io/iohk/ethereum/BootstrapDownload.scala b/src/main/scala/io/iohk/ethereum/BootstrapDownload.scala index 468f386ab1..1fd6830167 100644 --- a/src/main/scala/io/iohk/ethereum/BootstrapDownload.scala +++ b/src/main/scala/io/iohk/ethereum/BootstrapDownload.scala @@ -1,16 +1,19 @@ package io.iohk.ethereum -import java.io.{File, FileInputStream, FileOutputStream} +import java.io.File +import java.io.FileInputStream +import java.io.FileOutputStream import java.net.URL import java.nio.file._ -import java.security.{DigestInputStream, MessageDigest} +import java.security.DigestInputStream +import java.security.MessageDigest import java.util.zip.ZipInputStream -import io.iohk.ethereum.utils.Logger import org.bouncycastle.util.encoders.Hex -/** - * A facility to +import io.iohk.ethereum.utils.Logger + +/** A facility to * - check the download location for a minimum amount of free space * - download a zip from a URL and generate SHA-512 checksum * - check the checksum @@ -19,7 +22,7 @@ import org.bouncycastle.util.encoders.Hex */ object BootstrapDownload extends Logger { - val bufferSize = 4 * 1024 + val bufferSize: Int = 4 * 1024 val leveldbFolderName = "leveldb" private def assertAndLog(cond: Boolean, msg: String): Unit = { @@ -51,9 +54,7 @@ object BootstrapDownload extends Logger { } finally (out.close()) Hex.toHexString(sha512.digest) - } finally { - dis.close() - } + } finally dis.close() } def unzip(zipFile: File, destination: Path): Unit = { @@ -61,31 +62,28 @@ object BootstrapDownload extends Logger { val in = new FileInputStream(zipFile) try { val zis = new ZipInputStream(in) - try { - Iterator.continually(zis.getNextEntry).takeWhile(_ != null).foreach { file => - if (!file.isDirectory) { - val outPath = destination.resolve(file.getName) - val outPathParent = outPath.getParent - if (!outPathParent.toFile.exists()) { - outPathParent.toFile.mkdirs() - } - - val outFile = outPath.toFile - val out = new FileOutputStream(outFile) - try { - val buffer = new Array[Byte](bufferSize) - Iterator.continually(zis.read(buffer)).takeWhile(_ != -1).foreach(out.write(buffer, 0, _)) - } finally (out.close()) + try Iterator.continually(zis.getNextEntry).takeWhile(_ != null).foreach { file => + if (!file.isDirectory) { + val outPath = destination.resolve(file.getName) + val outPathParent = outPath.getParent + if (!outPathParent.toFile.exists()) { + outPathParent.toFile.mkdirs() } + + val outFile = outPath.toFile + val out = new FileOutputStream(outFile) + try { + val buffer = new Array[Byte](bufferSize) + Iterator.continually(zis.read(buffer)).takeWhile(_ != -1).foreach(out.write(buffer, 0, _)) + } finally (out.close()) } } finally (zis.close()) } finally (in.close()) } - def deleteDownloadedFile(downloadedFile: File): Unit = { + def deleteDownloadedFile(downloadedFile: File): Unit = if (downloadedFile.delete()) log.info(s"Downloaded file $downloadedFile successfully deleted") else log.info(s"Failed to delete downloaded file $downloadedFile") - } // scalastyle:off method.length def main(args: Array[String]): Unit = { diff --git a/src/main/scala/io/iohk/ethereum/Mantis.scala b/src/main/scala/io/iohk/ethereum/Mantis.scala index ad9ba719d3..f10e3a3b85 100644 --- a/src/main/scala/io/iohk/ethereum/Mantis.scala +++ b/src/main/scala/io/iohk/ethereum/Mantis.scala @@ -1,11 +1,13 @@ package io.iohk.ethereum -import io.iohk.ethereum.nodebuilder.{StdNode, TestNode} -import io.iohk.ethereum.utils.{Config, Logger} +import java.util.logging.LogManager + import org.rocksdb -import java.nio.file.{Files, Paths} -import java.util.logging.LogManager +import io.iohk.ethereum.nodebuilder.StdNode +import io.iohk.ethereum.nodebuilder.TestNode +import io.iohk.ethereum.utils.Config +import io.iohk.ethereum.utils.Logger object Mantis extends Logger { def main(args: Array[String]): Unit = { diff --git a/src/main/scala/io/iohk/ethereum/blockchain/data/GenesisDataLoader.scala b/src/main/scala/io/iohk/ethereum/blockchain/data/GenesisDataLoader.scala index 2fadb1b49c..71a265acf2 100644 --- a/src/main/scala/io/iohk/ethereum/blockchain/data/GenesisDataLoader.scala +++ b/src/main/scala/io/iohk/ethereum/blockchain/data/GenesisDataLoader.scala @@ -1,27 +1,39 @@ package io.iohk.ethereum.blockchain.data import java.io.FileNotFoundException + import akka.util.ByteString -import io.iohk.ethereum.blockchain.data.GenesisDataLoader.JsonSerializers.{ - ByteStringJsonSerializer, - UInt256JsonSerializer -} + +import scala.io.Source +import scala.util.Failure +import scala.util.Success +import scala.util.Try + +import org.bouncycastle.util.encoders.Hex +import org.json4s.CustomSerializer +import org.json4s.DefaultFormats +import org.json4s.Formats +import org.json4s.JString +import org.json4s.JValue + +import io.iohk.ethereum.blockchain.data.GenesisDataLoader.JsonSerializers.ByteStringJsonSerializer +import io.iohk.ethereum.blockchain.data.GenesisDataLoader.JsonSerializers.UInt256JsonSerializer +import io.iohk.ethereum.crypto import io.iohk.ethereum.db.dataSource.EphemDataSource -import io.iohk.ethereum.db.storage.{ArchiveNodeStorage, MptStorage, NodeStorage, SerializingMptStorage, StateStorage} +import io.iohk.ethereum.db.storage.ArchiveNodeStorage +import io.iohk.ethereum.db.storage.MptStorage +import io.iohk.ethereum.db.storage.NodeStorage +import io.iohk.ethereum.db.storage.SerializingMptStorage +import io.iohk.ethereum.db.storage.StateStorage import io.iohk.ethereum.db.storage.StateStorage.GenesisDataLoad -import io.iohk.ethereum.rlp.RLPList -import io.iohk.ethereum.utils.BlockchainConfig -import io.iohk.ethereum.utils.Logger -import io.iohk.ethereum.{crypto, rlp} import io.iohk.ethereum.domain._ import io.iohk.ethereum.jsonrpc.JsonMethodsImplicits import io.iohk.ethereum.mpt.MerklePatriciaTrie +import io.iohk.ethereum.rlp import io.iohk.ethereum.rlp.RLPImplicits._ -import org.json4s.{CustomSerializer, DefaultFormats, Formats, JString, JValue} -import org.bouncycastle.util.encoders.Hex - -import scala.io.Source -import scala.util.{Failure, Success, Try} +import io.iohk.ethereum.rlp.RLPList +import io.iohk.ethereum.utils.BlockchainConfig +import io.iohk.ethereum.utils.Logger class GenesisDataLoader( blockchain: Blockchain, @@ -37,7 +49,7 @@ class GenesisDataLoader( import Account._ private val emptyTrieRootHash = ByteString(crypto.kec256(rlp.encode(Array.emptyByteArray))) - private val emptyEvmHash: ByteString = crypto.kec256(ByteString.empty) + crypto.kec256(ByteString.empty) def loadGenesisData(): Unit = { log.debug("Loading genesis data") @@ -54,11 +66,8 @@ class GenesisDataLoader( } match { case Success(customGenesis) => log.info(s"Using custom genesis data from: $customGenesisFile") - try { - customGenesis.getLines().mkString - } finally { - customGenesis.close() - } + try customGenesis.getLines().mkString + finally customGenesis.close() case Failure(ex) => log.error(s"Cannot load custom genesis data from: $customGenesisFile", ex) throw ex @@ -66,11 +75,8 @@ class GenesisDataLoader( case None => log.info("Using default genesis data") val src = Source.fromResource("blockchain/default-genesis.json") - try { - src.getLines().mkString - } finally { - src.close() - } + try src.getLines().mkString + finally src.close() } } @@ -93,7 +99,6 @@ class GenesisDataLoader( } def loadGenesisData(genesisData: GenesisData): Try[Unit] = { - import MerklePatriciaTrie.defaultByteArraySerializable val storage = stateStorage.getReadOnlyStorage val initalRootHash = MerklePatriciaTrie.EmptyRootHash @@ -158,7 +163,7 @@ class GenesisDataLoader( val storageTrie = storage.foldLeft(emptyTrie) { case (trie, (key, UInt256.Zero)) => trie - case (trie, (key, value)) => trie.put(key, value) + case (trie, (key, value)) => trie.put(key, value) } ByteString(storageTrie.getRootHash) @@ -199,7 +204,7 @@ object GenesisDataLoader { else "0" ++ noPrefix Try(ByteString(Hex.decode(inp))) match { case Success(bs) => bs - case Failure(_) => throw new RuntimeException("Cannot parse hex string: " + s) + case Failure(_) => throw new RuntimeException("Cannot parse hex string: " + s) } case other => throw new RuntimeException("Expected hex string, but got: " + other) } @@ -215,7 +220,7 @@ object GenesisDataLoader { def deserializeUint256String(jv: JValue): UInt256 = jv match { case JString(s) => Try(UInt256(BigInt(s))) match { - case Failure(_) => throw new RuntimeException("Cannot parse hex string: " + s) + case Failure(_) => throw new RuntimeException("Cannot parse hex string: " + s) case Success(value) => value } case other => throw new RuntimeException("Expected hex string, but got: " + other) diff --git a/src/main/scala/io/iohk/ethereum/blockchain/data/genesis.scala b/src/main/scala/io/iohk/ethereum/blockchain/data/genesis.scala index d87e7c117e..21f99f8f6d 100644 --- a/src/main/scala/io/iohk/ethereum/blockchain/data/genesis.scala +++ b/src/main/scala/io/iohk/ethereum/blockchain/data/genesis.scala @@ -1,6 +1,7 @@ package io.iohk.ethereum.blockchain.data import akka.util.ByteString + import io.iohk.ethereum.domain.UInt256 case class PrecompiledAccountConfig(name: String) diff --git a/src/main/scala/io/iohk/ethereum/blockchain/sync/Blacklist.scala b/src/main/scala/io/iohk/ethereum/blockchain/sync/Blacklist.scala index 5a5a8fcead..22e276385b 100644 --- a/src/main/scala/io/iohk/ethereum/blockchain/sync/Blacklist.scala +++ b/src/main/scala/io/iohk/ethereum/blockchain/sync/Blacklist.scala @@ -1,18 +1,21 @@ package io.iohk.ethereum.blockchain.sync -import com.github.blemale.scaffeine.{Cache, Scaffeine} -import io.iohk.ethereum.utils.Logger - import scala.concurrent.duration.FiniteDuration import scala.concurrent.duration._ import scala.jdk.CollectionConverters._ -import scala.jdk.OptionConverters._ import scala.jdk.DurationConverters._ -import Blacklist._ -import io.iohk.ethereum.consensus.validators.std.StdBlockValidator.BlockError +import scala.jdk.OptionConverters._ + +import com.github.blemale.scaffeine.Cache +import com.github.blemale.scaffeine.Scaffeine + import io.iohk.ethereum.blockchain.sync.Blacklist.BlacklistReason.BlacklistReasonType +import io.iohk.ethereum.consensus.validators.std.StdBlockValidator.BlockError import io.iohk.ethereum.network.NetworkMetrics import io.iohk.ethereum.network.p2p.messages.WireProtocol.Disconnect +import io.iohk.ethereum.utils.Logger + +import Blacklist._ trait Blacklist { def isBlacklisted(id: BlacklistId): Boolean @@ -315,9 +318,8 @@ object Blacklist { OtherSubprotocolSpecificReason ) - def getP2PBlacklistReasonByDescription(description: String): BlacklistReason = { + def getP2PBlacklistReasonByDescription(description: String): BlacklistReason = allP2PReasons.find(_.description == description).getOrElse(OtherSubprotocolSpecificReason) - } } } @@ -330,9 +332,9 @@ final case class CacheBasedBlacklist(cache: Cache[BlacklistId, BlacklistReasonTy override def add(id: BlacklistId, duration: FiniteDuration, reason: BlacklistReason): Unit = { log.info("Blacklisting peer [{}] for {}. Reason: {}", id, duration, reason.description) reason.reasonType.group match { - case "FastSyncBlacklistGroup" => NetworkMetrics.BlacklistedReasonsFastSyncGroup.increment() + case "FastSyncBlacklistGroup" => NetworkMetrics.BlacklistedReasonsFastSyncGroup.increment() case "RegularSyncBlacklistGroup" => NetworkMetrics.BlacklistedReasonsRegularSyncGroup.increment() - case "P2PBlacklistGroup" => NetworkMetrics.BlacklistedReasonsP2PGroup.increment() + case "P2PBlacklistGroup" => NetworkMetrics.BlacklistedReasonsP2PGroup.increment() } cache.policy().expireVariably().toScala match { case Some(varExpiration) => varExpiration.put(id, reason.reasonType, duration.toJava) diff --git a/src/main/scala/io/iohk/ethereum/blockchain/sync/BlockchainHostActor.scala b/src/main/scala/io/iohk/ethereum/blockchain/sync/BlockchainHostActor.scala index 270f18d9df..6e73c631de 100644 --- a/src/main/scala/io/iohk/ethereum/blockchain/sync/BlockchainHostActor.scala +++ b/src/main/scala/io/iohk/ethereum/blockchain/sync/BlockchainHostActor.scala @@ -1,22 +1,34 @@ package io.iohk.ethereum.blockchain.sync -import akka.actor.{Actor, ActorLogging, ActorRef, Props} +import akka.actor.Actor +import akka.actor.ActorLogging +import akka.actor.ActorRef +import akka.actor.Props import akka.util.ByteString + import io.iohk.ethereum.db.storage.EvmCodeStorage -import io.iohk.ethereum.domain.{BlockHeader, Blockchain, BlockchainReader} +import io.iohk.ethereum.domain.BlockHeader +import io.iohk.ethereum.domain.BlockchainReader +import io.iohk.ethereum.network.EtcPeerManagerActor import io.iohk.ethereum.network.PeerEventBusActor.PeerEvent.MessageFromPeer +import io.iohk.ethereum.network.PeerEventBusActor.PeerSelector +import io.iohk.ethereum.network.PeerEventBusActor.Subscribe import io.iohk.ethereum.network.PeerEventBusActor.SubscriptionClassifier.MessageClassifier -import io.iohk.ethereum.network.PeerEventBusActor.{PeerSelector, Subscribe} import io.iohk.ethereum.network.PeerManagerActor.PeerConfiguration -import io.iohk.ethereum.network.p2p.{Message, MessageSerializable} -import io.iohk.ethereum.network.p2p.messages.ETH62.{BlockBodies, BlockHeaders, GetBlockBodies, GetBlockHeaders} -import io.iohk.ethereum.network.p2p.messages.ETH63.{GetNodeData, GetReceipts, NodeData, Receipts} -import io.iohk.ethereum.network.p2p.messages.ETH63.MptNodeEncoders._ -import io.iohk.ethereum.network.EtcPeerManagerActor +import io.iohk.ethereum.network.p2p.Message +import io.iohk.ethereum.network.p2p.MessageSerializable import io.iohk.ethereum.network.p2p.messages.Codes +import io.iohk.ethereum.network.p2p.messages.ETH62.BlockBodies +import io.iohk.ethereum.network.p2p.messages.ETH62.BlockHeaders +import io.iohk.ethereum.network.p2p.messages.ETH62.GetBlockBodies +import io.iohk.ethereum.network.p2p.messages.ETH62.GetBlockHeaders +import io.iohk.ethereum.network.p2p.messages.ETH63.GetNodeData +import io.iohk.ethereum.network.p2p.messages.ETH63.GetReceipts +import io.iohk.ethereum.network.p2p.messages.ETH63.MptNodeEncoders._ +import io.iohk.ethereum.network.p2p.messages.ETH63.NodeData +import io.iohk.ethereum.network.p2p.messages.ETH63.Receipts -/** - * BlockchainHost actor is in charge of replying to the peer's requests for blockchain data, which includes both +/** BlockchainHost actor is in charge of replying to the peer's requests for blockchain data, which includes both * node and block data. */ class BlockchainHostActor( @@ -33,14 +45,13 @@ class BlockchainHostActor( peerEventBusActor ! Subscribe(MessageClassifier(requestMsgsCodes, PeerSelector.AllPeers)) override def receive: Receive = { case MessageFromPeer(message, peerId) => - val responseOpt = handleBlockFastDownload(message) orElse handleEvmCodeMptFastDownload(message) + val responseOpt = handleBlockFastDownload(message).orElse(handleEvmCodeMptFastDownload(message)) responseOpt.foreach { response => etcPeerManagerActor ! EtcPeerManagerActor.SendMessage(response, peerId) } } - /** - * Handles requests for node data, which includes both mpt nodes and evm code (both requested by hash). + /** Handles requests for node data, which includes both mpt nodes and evm code (both requested by hash). * Both types of node data are requested by the same GetNodeData message * * @param message to be processed @@ -64,8 +75,7 @@ class BlockchainHostActor( case _ => None } - /** - * Handles request for block data, which includes receipts, block bodies and headers (all requested by hash) + /** Handles request for block data, which includes receipts, block bodies and headers (all requested by hash) * * @param message to be processed * @return message response if message is a request for block data or None if not @@ -91,7 +101,7 @@ class BlockchainHostActor( blockNumber match { case Some(startBlockNumber) if startBlockNumber >= 0 && request.maxHeaders >= 0 && request.skip >= 0 => val headersCount: BigInt = - request.maxHeaders min peerConfiguration.fastSyncHostConfiguration.maxBlocksHeadersPerMessage + request.maxHeaders.min(peerConfiguration.fastSyncHostConfiguration.maxBlocksHeadersPerMessage) val range = if (request.reverse) { startBlockNumber to (startBlockNumber - (request.skip + 1) * headersCount + 1) by -(request.skip + 1) diff --git a/src/main/scala/io/iohk/ethereum/blockchain/sync/PeerListSupportNg.scala b/src/main/scala/io/iohk/ethereum/blockchain/sync/PeerListSupportNg.scala index f9e3a7d33f..ee918ecabc 100644 --- a/src/main/scala/io/iohk/ethereum/blockchain/sync/PeerListSupportNg.scala +++ b/src/main/scala/io/iohk/ethereum/blockchain/sync/PeerListSupportNg.scala @@ -1,21 +1,29 @@ package io.iohk.ethereum.blockchain.sync -import akka.actor.{Actor, ActorLogging, ActorRef, Scheduler} +import akka.actor.Actor +import akka.actor.ActorLogging +import akka.actor.ActorRef +import akka.actor.Scheduler + +import scala.concurrent.ExecutionContext +import scala.concurrent.duration._ + +import io.iohk.ethereum.network.EtcPeerManagerActor import io.iohk.ethereum.network.EtcPeerManagerActor.PeerInfo +import io.iohk.ethereum.network.Peer import io.iohk.ethereum.network.PeerEventBusActor.PeerEvent.PeerDisconnected +import io.iohk.ethereum.network.PeerEventBusActor.PeerSelector +import io.iohk.ethereum.network.PeerEventBusActor.Subscribe import io.iohk.ethereum.network.PeerEventBusActor.SubscriptionClassifier.PeerDisconnectedClassifier -import io.iohk.ethereum.network.PeerEventBusActor.{PeerSelector, Subscribe, Unsubscribe} -import io.iohk.ethereum.network.{EtcPeerManagerActor, Peer, PeerId} +import io.iohk.ethereum.network.PeerEventBusActor.Unsubscribe +import io.iohk.ethereum.network.PeerId import io.iohk.ethereum.utils.Config.SyncConfig -import scala.concurrent.ExecutionContext -import scala.concurrent.duration._ - trait PeerListSupportNg { self: Actor with ActorLogging => import PeerListSupportNg._ import Blacklist._ - private implicit val ec: ExecutionContext = context.dispatcher + implicit private val ec: ExecutionContext = context.dispatcher protected val bigIntReverseOrdering: Ordering[BigInt] = Ordering[BigInt].reverse @@ -36,7 +44,7 @@ trait PeerListSupportNg { self: Actor with ActorLogging => def handlePeerListMessages: Receive = { case EtcPeerManagerActor.HandshakedPeers(peers) => updatePeers(peers) - case PeerDisconnected(peerId) => removePeerById(peerId) + case PeerDisconnected(peerId) => removePeerById(peerId) } def peersToDownloadFrom: Map[PeerId, PeerWithInfo] = @@ -62,13 +70,12 @@ trait PeerListSupportNg { self: Actor with ActorLogging => handshakedPeers = updated } - private def removePeerById(peerId: PeerId): Unit = { + private def removePeerById(peerId: PeerId): Unit = if (handshakedPeers.keySet.contains(peerId)) { peerEventBus ! Unsubscribe(PeerDisconnectedClassifier(PeerSelector.WithId(peerId))) blacklist.remove(peerId) handshakedPeers = handshakedPeers - peerId } - } } diff --git a/src/main/scala/io/iohk/ethereum/blockchain/sync/PeerRequestHandler.scala b/src/main/scala/io/iohk/ethereum/blockchain/sync/PeerRequestHandler.scala index bb99936bd8..56820ac8d5 100644 --- a/src/main/scala/io/iohk/ethereum/blockchain/sync/PeerRequestHandler.scala +++ b/src/main/scala/io/iohk/ethereum/blockchain/sync/PeerRequestHandler.scala @@ -1,15 +1,22 @@ package io.iohk.ethereum.blockchain.sync -import scala.concurrent.ExecutionContext.Implicits.global -import scala.reflect.ClassTag import akka.actor._ -import io.iohk.ethereum.network.{EtcPeerManagerActor, Peer} -import io.iohk.ethereum.network.PeerEventBusActor.PeerEvent.{MessageFromPeer, PeerDisconnected} -import io.iohk.ethereum.network.PeerEventBusActor.SubscriptionClassifier.{MessageClassifier, PeerDisconnectedClassifier} -import io.iohk.ethereum.network.PeerEventBusActor.{PeerSelector, Subscribe, Unsubscribe} -import io.iohk.ethereum.network.p2p.{Message, MessageSerializable} +import scala.concurrent.ExecutionContext.Implicits.global import scala.concurrent.duration.FiniteDuration +import scala.reflect.ClassTag + +import io.iohk.ethereum.network.EtcPeerManagerActor +import io.iohk.ethereum.network.Peer +import io.iohk.ethereum.network.PeerEventBusActor.PeerEvent.MessageFromPeer +import io.iohk.ethereum.network.PeerEventBusActor.PeerEvent.PeerDisconnected +import io.iohk.ethereum.network.PeerEventBusActor.PeerSelector +import io.iohk.ethereum.network.PeerEventBusActor.Subscribe +import io.iohk.ethereum.network.PeerEventBusActor.SubscriptionClassifier.MessageClassifier +import io.iohk.ethereum.network.PeerEventBusActor.SubscriptionClassifier.PeerDisconnectedClassifier +import io.iohk.ethereum.network.PeerEventBusActor.Unsubscribe +import io.iohk.ethereum.network.p2p.Message +import io.iohk.ethereum.network.p2p.MessageSerializable class PeerRequestHandler[RequestMsg <: Message, ResponseMsg <: Message: ClassTag]( peer: Peer, @@ -41,8 +48,8 @@ class PeerRequestHandler[RequestMsg <: Message, ResponseMsg <: Message: ClassTag } override def receive: Receive = { - case MessageFromPeer(responseMsg: ResponseMsg, _) => handleResponseMsg(responseMsg) - case Timeout => handleTimeout() + case MessageFromPeer(responseMsg: ResponseMsg, _) => handleResponseMsg(responseMsg) + case Timeout => handleTimeout() case PeerDisconnected(peerId) if peerId == peer.id => handleTerminated() } @@ -64,7 +71,7 @@ class PeerRequestHandler[RequestMsg <: Message, ResponseMsg <: Message: ClassTag def cleanupAndStop(): Unit = { timeout.cancel() peerEventBus ! Unsubscribe() - context stop self + context.stop(self) } } diff --git a/src/main/scala/io/iohk/ethereum/blockchain/sync/PeersClient.scala b/src/main/scala/io/iohk/ethereum/blockchain/sync/PeersClient.scala index 3cabe99eda..82dc089cb4 100644 --- a/src/main/scala/io/iohk/ethereum/blockchain/sync/PeersClient.scala +++ b/src/main/scala/io/iohk/ethereum/blockchain/sync/PeersClient.scala @@ -1,19 +1,28 @@ package io.iohk.ethereum.blockchain.sync -import akka.actor.{Actor, ActorLogging, ActorRef, Cancellable, Props, Scheduler} +import akka.actor.Actor +import akka.actor.ActorLogging +import akka.actor.ActorRef +import akka.actor.Cancellable +import akka.actor.Props +import akka.actor.Scheduler + +import scala.concurrent.ExecutionContext +import scala.reflect.ClassTag + import io.iohk.ethereum.blockchain.sync.Blacklist.BlacklistReason import io.iohk.ethereum.blockchain.sync.PeerListSupportNg.PeerWithInfo import io.iohk.ethereum.network.EtcPeerManagerActor.PeerInfo +import io.iohk.ethereum.network.Peer +import io.iohk.ethereum.network.PeerId +import io.iohk.ethereum.network.p2p.Message +import io.iohk.ethereum.network.p2p.MessageSerializable import io.iohk.ethereum.network.p2p.messages.Codes -import io.iohk.ethereum.network.{Peer, PeerId} import io.iohk.ethereum.network.p2p.messages.ETH62._ -import io.iohk.ethereum.network.p2p.messages.ETH63.{GetNodeData, NodeData} -import io.iohk.ethereum.network.p2p.{Message, MessageSerializable} +import io.iohk.ethereum.network.p2p.messages.ETH63.GetNodeData +import io.iohk.ethereum.network.p2p.messages.ETH63.NodeData import io.iohk.ethereum.utils.Config.SyncConfig -import scala.concurrent.ExecutionContext -import scala.reflect.ClassTag - class PeersClient( val etcPeerManager: ActorRef, val peerEventBus: ActorRef, @@ -38,8 +47,8 @@ class PeersClient( } def running(requesters: Requesters): Receive = - handlePeerListMessages orElse { - case PrintStatus => printStatus(requesters: Requesters) + handlePeerListMessages.orElse { + case PrintStatus => printStatus(requesters: Requesters) case BlacklistPeer(peerId, reason) => blacklistIfHandshaked(peerId, syncConfig.blacklistDuration, reason) case Request(message, peerSelector, toSerializable) => val requester = sender() @@ -49,7 +58,7 @@ class PeersClient( val handler = makeRequest(peer, message, responseMsgCode(message), toSerializable)(scheduler, responseClassTag(message)) val newRequesters = requesters + (handler -> requester) - context become running(newRequesters) + context.become(running(newRequesters)) case None => log.debug("No suitable peer found to issue a request") requester ! NoSuitablePeer @@ -81,7 +90,7 @@ class PeersClient( private def handleResponse[ResponseMsg <: ResponseMessage](requesters: Requesters, responseMsg: ResponseMsg): Unit = { val requestHandler = sender() requesters.get(requestHandler).foreach(_ ! responseMsg) - context become running(requesters - requestHandler) + context.become(running(requesters - requestHandler)) } private def selectPeer(peerSelector: PeerSelector): Option[Peer] = @@ -92,15 +101,15 @@ class PeersClient( private def responseClassTag[RequestMsg <: Message](requestMsg: RequestMsg): ClassTag[_ <: Message] = requestMsg match { case _: GetBlockHeaders => implicitly[ClassTag[BlockHeaders]] - case _: GetBlockBodies => implicitly[ClassTag[BlockBodies]] - case _: GetNodeData => implicitly[ClassTag[NodeData]] + case _: GetBlockBodies => implicitly[ClassTag[BlockBodies]] + case _: GetNodeData => implicitly[ClassTag[NodeData]] } private def responseMsgCode[RequestMsg <: Message](requestMsg: RequestMsg): Int = requestMsg match { case _: GetBlockHeaders => Codes.BlockHeadersCode - case _: GetBlockBodies => Codes.BlockBodiesCode - case _: GetNodeData => Codes.NodeDataCode + case _: GetBlockBodies => Codes.BlockBodiesCode + case _: GetNodeData => Codes.NodeDataCode } private def printStatus(requesters: Requesters): Unit = { diff --git a/src/main/scala/io/iohk/ethereum/blockchain/sync/SyncController.scala b/src/main/scala/io/iohk/ethereum/blockchain/sync/SyncController.scala index f1ef3b8bfa..7267dc47e9 100644 --- a/src/main/scala/io/iohk/ethereum/blockchain/sync/SyncController.scala +++ b/src/main/scala/io/iohk/ethereum/blockchain/sync/SyncController.scala @@ -1,14 +1,24 @@ package io.iohk.ethereum.blockchain.sync -import akka.actor.{Actor, ActorLogging, ActorRef, PoisonPill, Props, Scheduler} +import akka.actor.Actor +import akka.actor.ActorLogging +import akka.actor.ActorRef +import akka.actor.PoisonPill +import akka.actor.Props +import akka.actor.Scheduler + import io.iohk.ethereum.blockchain.sync.fast.FastSync import io.iohk.ethereum.blockchain.sync.regular.RegularSync import io.iohk.ethereum.consensus.validators.Validators -import io.iohk.ethereum.db.storage.{AppStateStorage, EvmCodeStorage, FastSyncStateStorage, NodeStorage} -import io.iohk.ethereum.domain.{Blockchain, BlockchainReader} -import io.iohk.ethereum.utils.Config.SyncConfig +import io.iohk.ethereum.db.storage.AppStateStorage +import io.iohk.ethereum.db.storage.EvmCodeStorage +import io.iohk.ethereum.db.storage.FastSyncStateStorage +import io.iohk.ethereum.db.storage.NodeStorage +import io.iohk.ethereum.domain.Blockchain +import io.iohk.ethereum.domain.BlockchainReader import io.iohk.ethereum.ledger.BlockImport import io.iohk.ethereum.ledger.BranchResolution +import io.iohk.ethereum.utils.Config.SyncConfig class SyncController( appStateStorage: AppStateStorage, @@ -29,7 +39,7 @@ class SyncController( ) extends Actor with ActorLogging { - def scheduler: Scheduler = externalSchedulerOpt getOrElse context.system.scheduler + def scheduler: Scheduler = externalSchedulerOpt.getOrElse(context.system.scheduler) override def receive: Receive = idle @@ -94,7 +104,7 @@ class SyncController( "fast-sync" ) fastSync ! SyncProtocol.Start - context become runningFastSync(fastSync) + context.become(runningFastSync(fastSync)) } def startRegularSync(): Unit = { @@ -118,7 +128,7 @@ class SyncController( "regular-sync" ) regularSync ! SyncProtocol.Start - context become runningRegularSync(regularSync) + context.become(runningRegularSync(regularSync)) } } diff --git a/src/main/scala/io/iohk/ethereum/blockchain/sync/SyncProtocol.scala b/src/main/scala/io/iohk/ethereum/blockchain/sync/SyncProtocol.scala index 002bca971e..d1b4d8eb4a 100644 --- a/src/main/scala/io/iohk/ethereum/blockchain/sync/SyncProtocol.scala +++ b/src/main/scala/io/iohk/ethereum/blockchain/sync/SyncProtocol.scala @@ -10,8 +10,8 @@ object SyncProtocol { sealed trait Status { def syncing: Boolean = this match { case Status.Syncing(_, _, _) => true - case Status.NotSyncing => false - case Status.SyncDone => false + case Status.NotSyncing => false + case Status.SyncDone => false } def notSyncing: Boolean = !syncing @@ -19,10 +19,10 @@ object SyncProtocol { object Status { case class Progress(current: BigInt, target: BigInt) { val isEmpty: Boolean = current == 0 && target == 0 - val nonEmpty = !isEmpty + val nonEmpty: Boolean = !isEmpty } object Progress { - val empty = Progress(0, 0) + val empty: Progress = Progress(0, 0) } case class Syncing( startingBlockNumber: BigInt, diff --git a/src/main/scala/io/iohk/ethereum/blockchain/sync/fast/DownloaderState.scala b/src/main/scala/io/iohk/ethereum/blockchain/sync/fast/DownloaderState.scala index 69debd0974..15552c7f53 100644 --- a/src/main/scala/io/iohk/ethereum/blockchain/sync/fast/DownloaderState.scala +++ b/src/main/scala/io/iohk/ethereum/blockchain/sync/fast/DownloaderState.scala @@ -1,26 +1,27 @@ package io.iohk.ethereum.blockchain.sync.fast import akka.util.ByteString + import cats.data.NonEmptyList + +import scala.annotation.tailrec + import io.iohk.ethereum.blockchain.sync.fast.SyncStateScheduler.SyncResponse -import io.iohk.ethereum.blockchain.sync.fast.SyncStateSchedulerActor.{ - NoUsefulDataInResponse, - PeerRequest, - ResponseProcessingResult, - UnrequestedResponse, - UsefulData -} +import io.iohk.ethereum.blockchain.sync.fast.SyncStateSchedulerActor.NoUsefulDataInResponse +import io.iohk.ethereum.blockchain.sync.fast.SyncStateSchedulerActor.PeerRequest +import io.iohk.ethereum.blockchain.sync.fast.SyncStateSchedulerActor.ResponseProcessingResult +import io.iohk.ethereum.blockchain.sync.fast.SyncStateSchedulerActor.UnrequestedResponse +import io.iohk.ethereum.blockchain.sync.fast.SyncStateSchedulerActor.UsefulData import io.iohk.ethereum.crypto.kec256 +import io.iohk.ethereum.network.Peer +import io.iohk.ethereum.network.PeerId import io.iohk.ethereum.network.p2p.messages.ETH63.NodeData -import io.iohk.ethereum.network.{Peer, PeerId} - -import scala.annotation.tailrec final case class DownloaderState( activeRequests: Map[PeerId, NonEmptyList[ByteString]], nodesToGet: Map[ByteString, Option[PeerId]] ) { - lazy val nonDownloadedNodes = nodesToGet.collect { + lazy val nonDownloadedNodes: Seq[ByteString] = nodesToGet.collect { case (hash, maybePeer) if maybePeer.isEmpty => hash }.toSeq @@ -44,7 +45,7 @@ final case class DownloaderState( copy(activeRequests = activeRequests + (peerRequest.peer.id -> peerRequest.nodes), nodesToGet = newNodesToget) } - def handleRequestFailure(from: Peer): DownloaderState = { + def handleRequestFailure(from: Peer): DownloaderState = activeRequests .get(from.id) .map { requestedNodes => @@ -55,10 +56,8 @@ final case class DownloaderState( copy(activeRequests = activeRequests - from.id, nodesToGet = newNodesToGet) } .getOrElse(this) - } - /** - * Responses from peers should be delivered in order, but can contain gaps or can be not full, so we cannot fail + /** Responses from peers should be delivered in order, but can contain gaps or can be not full, so we cannot fail * on first not matching response. * Matched responses are returned in correct order, the hashes to be rescheduled are returned in no particular order * as they will either way end up in map of hashes to be re-downloaded @@ -74,7 +73,7 @@ final case class DownloaderState( remainingResponses: List[ByteString], nonReceivedRequested: List[ByteString], processed: List[SyncResponse] - ): (List[ByteString], List[SyncResponse]) = { + ): (List[ByteString], List[SyncResponse]) = if (remainingRequestedHashes.isEmpty) { (nonReceivedRequested, processed.reverse) } else { @@ -104,14 +103,13 @@ final case class DownloaderState( ) } } - } val firstReceivedResponse = SyncResponse(kec256(received.head), received.head) go(requested.toList, firstReceivedResponse, received.tail, List.empty, List.empty) } - def handleRequestSuccess(from: Peer, receivedMessage: NodeData): (ResponseProcessingResult, DownloaderState) = { + def handleRequestSuccess(from: Peer, receivedMessage: NodeData): (ResponseProcessingResult, DownloaderState) = activeRequests .get(from.id) .map { requestedHashes => @@ -142,7 +140,6 @@ final case class DownloaderState( } } .getOrElse((UnrequestedResponse, this)) - } def assignTasksToPeers( peers: NonEmptyList[Peer], @@ -155,7 +152,7 @@ final case class DownloaderState( nodesRemaining: Seq[ByteString], createdRequests: List[PeerRequest], currentState: DownloaderState - ): (Seq[PeerRequest], DownloaderState) = { + ): (Seq[PeerRequest], DownloaderState) = if (peersRemaining.isEmpty || nodesRemaining.isEmpty) { (createdRequests.reverse, currentState.scheduleNewNodesForRetrieval(nodesRemaining)) } else { @@ -169,7 +166,6 @@ final case class DownloaderState( currentState.addActiveRequest(peerRequest) ) } - } val currentNodesToDeliver = newNodes.map(nodes => nonDownloadedNodes ++ nodes).getOrElse(nonDownloadedNodes) if (currentNodesToDeliver.isEmpty) { diff --git a/src/main/scala/io/iohk/ethereum/blockchain/sync/fast/FastSync.scala b/src/main/scala/io/iohk/ethereum/blockchain/sync/fast/FastSync.scala index 4077051f2e..fb449e3282 100644 --- a/src/main/scala/io/iohk/ethereum/blockchain/sync/fast/FastSync.scala +++ b/src/main/scala/io/iohk/ethereum/blockchain/sync/fast/FastSync.scala @@ -1,9 +1,25 @@ package io.iohk.ethereum.blockchain.sync.fast +import java.time.Instant +import java.util.concurrent.TimeUnit +import java.util.concurrent.atomic.AtomicInteger + import akka.actor._ import akka.util.ByteString + import cats.data.NonEmptyList import cats.implicits._ + +import scala.annotation.tailrec +import scala.collection.mutable +import scala.concurrent.ExecutionContext.Implicits.global +import scala.concurrent.duration._ +import scala.util.Random +import scala.util.Success +import scala.util.Try + +import org.bouncycastle.util.encoders.Hex + import io.iohk.ethereum.blockchain.sync.Blacklist.BlacklistReason._ import io.iohk.ethereum.blockchain.sync.Blacklist._ import io.iohk.ethereum.blockchain.sync.PeerListSupportNg.PeerWithInfo @@ -13,14 +29,15 @@ import io.iohk.ethereum.blockchain.sync._ import io.iohk.ethereum.blockchain.sync.fast.HeaderSkeleton._ import io.iohk.ethereum.blockchain.sync.fast.ReceiptsValidator.ReceiptsValidationResult import io.iohk.ethereum.blockchain.sync.fast.SyncBlocksValidator.BlockBodyValidationResult -import io.iohk.ethereum.blockchain.sync.fast.SyncStateSchedulerActor.{ - RestartRequested, - StartSyncingTo, - StateSyncFinished, - WaitingForNewTargetBlock -} +import io.iohk.ethereum.blockchain.sync.fast.SyncStateSchedulerActor.RestartRequested +import io.iohk.ethereum.blockchain.sync.fast.SyncStateSchedulerActor.StartSyncingTo +import io.iohk.ethereum.blockchain.sync.fast.SyncStateSchedulerActor.StateSyncFinished +import io.iohk.ethereum.blockchain.sync.fast.SyncStateSchedulerActor.WaitingForNewTargetBlock import io.iohk.ethereum.consensus.validators.Validators -import io.iohk.ethereum.db.storage.{AppStateStorage, EvmCodeStorage, FastSyncStateStorage, NodeStorage} +import io.iohk.ethereum.db.storage.AppStateStorage +import io.iohk.ethereum.db.storage.EvmCodeStorage +import io.iohk.ethereum.db.storage.FastSyncStateStorage +import io.iohk.ethereum.db.storage.NodeStorage import io.iohk.ethereum.domain._ import io.iohk.ethereum.mpt.MerklePatriciaTrie import io.iohk.ethereum.network.EtcPeerManagerActor.PeerInfo @@ -30,18 +47,6 @@ import io.iohk.ethereum.network.p2p.messages.ETH62._ import io.iohk.ethereum.network.p2p.messages.ETH63._ import io.iohk.ethereum.utils.ByteStringUtils import io.iohk.ethereum.utils.Config.SyncConfig -import org.bouncycastle.util.encoders.Hex - -import java.time.Instant -import java.util.concurrent.TimeUnit -import scala.annotation.tailrec -import scala.concurrent.ExecutionContext.Implicits.global -import scala.concurrent.duration._ -import scala.util.Random -import scala.collection.mutable -import scala.util.Try -import scala.util.Success -import java.util.concurrent.atomic.AtomicInteger // scalastyle:off file.size.limit class FastSync( @@ -70,8 +75,8 @@ class FastSync( override def receive: Receive = idle - def idle: Receive = handlePeerListMessages orElse { - case SyncProtocol.Start => start() + def idle: Receive = handlePeerListMessages.orElse { + case SyncProtocol.Start => start() case SyncProtocol.GetStatus => sender() ! SyncProtocol.Status.NotSyncing } @@ -79,7 +84,7 @@ class FastSync( log.info("Trying to start block synchronization (fast mode)") fastSyncStateStorage.getSyncState() match { case Some(syncState) => startWithState(syncState) - case None => startFromScratch() + case None => startFromScratch() } } @@ -96,16 +101,16 @@ class FastSync( "pivot-block-selector" ) pivotBlockSelector ! PivotBlockSelector.SelectPivotBlock - context become waitingForPivotBlock + context.become(waitingForPivotBlock) } - def waitingForPivotBlock: Receive = handlePeerListMessages orElse { + def waitingForPivotBlock: Receive = handlePeerListMessages.orElse { case SyncProtocol.GetStatus => sender() ! SyncProtocol.Status.NotSyncing case PivotBlockSelector.Result(pivotBlockHeader) => if (pivotBlockHeader.number < 1) { log.info("Unable to start block synchronization in fast mode: pivot block is less than 1") appStateStorage.fastSyncDone().commit() - context become idle + context.become(idle) syncController ! Done } else { val initialSyncState = @@ -200,14 +205,14 @@ class FastSync( syncState = syncState.copy(downloadedNodesCount = saved, totalNodesCount = saved + missing) } - def receive: Receive = handlePeerListMessages orElse handleStatus orElse handleRequestFailure orElse { + def receive: Receive = handlePeerListMessages.orElse(handleStatus).orElse(handleRequestFailure).orElse { case UpdatePivotBlock(reason) => updatePivotBlock(reason) case WaitingForNewTargetBlock => log.info("State sync stopped until receiving new pivot block") updatePivotBlock(ImportedLastBlock) - case ProcessSyncing => processSyncing() - case PrintStatus => printStatus() - case PersistSyncState => persistSyncState() + case ProcessSyncing => processSyncing() + case PrintStatus => printStatus() + case PersistSyncState => persistSyncState() case r @ ResponseReceived(_, _, _) => handleResponses(r) case StateSyncFinished => syncState = syncState.copy(stateSyncFinished = true) @@ -305,9 +310,8 @@ class FastSync( blockHeaders: Seq[BlockHeader], currentSkeleton: HeaderSkeleton ): Unit = { - def validHeadersChain(headers: Seq[BlockHeader], requestedNum: BigInt): Boolean = { + def validHeadersChain(headers: Seq[BlockHeader], requestedNum: BigInt): Boolean = headers.nonEmpty && headers.size <= requestedNum && checkHeadersChain(headers) - } removeRequestHandler(sender()) requestedHeaders.get(peer) match { @@ -373,7 +377,7 @@ class FastSync( handleRewind(header, masterPeer.get, fastSyncBlockValidationN, blacklistDuration, continueSyncing = false) // Start branch resolution and wait for response from the FastSyncBranchResolver actor. - context become waitingForBranchResolution + context.become(waitingForBranchResolution) branchResolver ! FastSyncBranchResolverActor.StartBranchResolver } } @@ -382,7 +386,7 @@ class FastSync( error match { // These are the reasons that make the master peer suspicious case InvalidPenultimateHeader(_, header) => handleMasterPeerFailure(header) - case InvalidBatchHash(_, header) => handleMasterPeerFailure(header) + case InvalidBatchHash(_, header) => handleMasterPeerFailure(header) // Otherwise probably it's just this peer's fault case _ => log.warning(error.msg) @@ -390,7 +394,7 @@ class FastSync( } } - private def waitingForBranchResolution: Receive = handleStatus orElse handleRequestFailure orElse { + private def waitingForBranchResolution: Receive = handleStatus.orElse(handleRequestFailure).orElse { case FastSyncBranchResolverActor.BranchResolvedSuccessful(firstCommonBlockNumber, newMasterPeer) => log.debug( s"Resolved branch with first common block number $firstCommonBlockNumber for new master peer $newMasterPeer" @@ -430,14 +434,13 @@ class FastSync( def askForPivotBlockUpdate(updateReason: PivotBlockUpdateReason): Unit = { syncState = syncState.copy(updatingPivotBlock = true) log.info("Asking for new pivot block") - val pivotBlockSelector = { + val pivotBlockSelector = context.actorOf( PivotBlockSelector.props(etcPeerManager, peerEventBus, syncConfig, scheduler, context.self, blacklist), s"$countActor-pivot-block-selector-update" ) - } pivotBlockSelector ! PivotBlockSelector.SelectPivotBlock - context become waitingForPivotBlockUpdate(updateReason) + context.become(waitingForPivotBlockUpdate(updateReason)) } private def newPivotIsGoodEnough( @@ -451,12 +454,12 @@ class FastSync( } def waitingForPivotBlockUpdate(updateReason: PivotBlockUpdateReason): Receive = - handlePeerListMessages orElse handleStatus orElse handleRequestFailure orElse { + handlePeerListMessages.orElse(handleStatus).orElse(handleRequestFailure).orElse { case PivotBlockSelector.Result(pivotBlockHeader) if newPivotIsGoodEnough(pivotBlockHeader, syncState, updateReason) => log.info("New pivot block with number {} received", pivotBlockHeader.number) updatePivotSyncState(updateReason, pivotBlockHeader) - context become this.receive + context.become(this.receive) processSyncing() case PivotBlockSelector.Result(pivotBlockHeader) @@ -484,7 +487,7 @@ class FastSync( ) //There's always at least one state root to fetch ) - private def updatePivotBlock(updateReason: PivotBlockUpdateReason): Unit = { + private def updatePivotBlock(updateReason: PivotBlockUpdateReason): Unit = if (syncState.pivotBlockUpdateFailures <= syncConfig.maximumTargetUpdateFailures) { if (assignedHandlers.nonEmpty || syncState.blockChainWorkQueued) { log.info("Still waiting for some responses, rescheduling pivot block update") @@ -497,7 +500,6 @@ class FastSync( log.warning("Sync failure! Number of pivot block update failures reached maximum.") sys.exit(1) } - } private def updatePivotSyncState(updateReason: PivotBlockUpdateReason, pivotBlockHeader: BlockHeader): Unit = updateReason match { @@ -551,20 +553,20 @@ class FastSync( private def removeRequestHandler(handler: ActorRef): Unit = { log.debug(s"Removing request handler ${handler.path}") - context unwatch handler + context.unwatch(handler) skeletonHandler = skeletonHandler.filter(_ != handler) assignedHandlers -= handler } // TODO [ETCM-676]: Move to blockchain and make sure it's atomic private def discardLastBlocks(startBlock: BigInt, blocksToDiscard: Int): Unit = { - (startBlock to ((startBlock - blocksToDiscard) max 1) by -1).foreach { n => + (startBlock to ((startBlock - blocksToDiscard).max(1)) by -1).foreach { n => blockchainReader.getBlockHeaderByNumber(n).foreach { headerToRemove => blockchain.removeBlock(headerToRemove.hash, withState = false) } } // TODO (maybe ETCM-77): Manage last checkpoint number too - appStateStorage.putBestBlockNumber((startBlock - blocksToDiscard - 1) max 0).commit() + appStateStorage.putBestBlockNumber((startBlock - blocksToDiscard - 1).max(0)).commit() } private def validateHeader(header: BlockHeader, peer: Peer): Either[HeaderProcessingResult, BlockHeader] = { @@ -634,12 +636,11 @@ class FastSync( parentWeight <- getParentChainWeight(header) } yield (validatedHeader, parentWeight) - def getParentChainWeight(header: BlockHeader) = { + def getParentChainWeight(header: BlockHeader) = blockchain.getChainWeightByHash(header.parentHash).toRight(ParentChainWeightNotFound(header)) - } @tailrec - def processHeaders(headers: Seq[BlockHeader]): HeaderProcessingResult = { + def processHeaders(headers: Seq[BlockHeader]): HeaderProcessingResult = if (headers.nonEmpty) { val header = headers.head processHeader(header) match { @@ -654,7 +655,6 @@ class FastSync( } } else HeadersProcessingFinished - } processHeaders(headers) match { case ParentChainWeightNotFound(header) => @@ -753,8 +753,7 @@ class FastSync( blacklistIfHandshaked(peer.id, blacklistDuration, reason) } - /** - * Restarts download from a few blocks behind the current best block header, as an unexpected DB error happened + /** Restarts download from a few blocks behind the current best block header, as an unexpected DB error happened */ private def redownloadBlockchain(): Unit = { syncState = syncState.copy( @@ -766,12 +765,11 @@ class FastSync( log.debug("Missing block header for known hash") } - private def persistSyncState(): Unit = { + private def persistSyncState(): Unit = syncStateStorageActor ! syncState.copy( blockBodiesQueue = requestedBlockBodies.values.flatten.toSeq.distinct ++ syncState.blockBodiesQueue, receiptsQueue = requestedReceipts.values.flatten.toSeq.distinct ++ syncState.receiptsQueue ) - } private def printStatus(): Unit = { def formatPeerEntry(entry: PeerWithInfo): String = formatPeer(entry.peer) @@ -797,7 +795,8 @@ class FastSync( } private def insertBlocks(requestedHashes: Seq[ByteString], blockBodies: Seq[BlockBody]): Unit = { - (requestedHashes zip blockBodies) + requestedHashes + .zip(blockBodies) .map { case (hash, body) => blockchain.storeBlockBody(hash, body) } @@ -812,20 +811,18 @@ class FastSync( } } - def hasBestBlockFreshEnoughToUpdatePivotBlock(info: PeerInfo, state: SyncState, syncConfig: SyncConfig): Boolean = { + def hasBestBlockFreshEnoughToUpdatePivotBlock(info: PeerInfo, state: SyncState, syncConfig: SyncConfig): Boolean = (info.maxBlockNumber - syncConfig.pivotBlockOffset) - state.pivotBlock.number >= syncConfig.maxPivotBlockAge - } private def getPeersWithFreshEnoughPivot( peers: NonEmptyList[PeerWithInfo], state: SyncState, syncConfig: SyncConfig - ): List[(Peer, BigInt)] = { + ): List[(Peer, BigInt)] = peers.collect { case PeerWithInfo(peer, info) if hasBestBlockFreshEnoughToUpdatePivotBlock(info, state, syncConfig) => (peer, info.maxBlockNumber) } - } def noBlockchainWorkRemaining: Boolean = syncState.isBlockchainWorkFinished && assignedHandlers.isEmpty @@ -907,7 +904,7 @@ class FastSync( discardLastBlocks(syncState.safeDownloadTarget, syncConfig.fastSyncBlockValidationX - 1) cleanup() appStateStorage.fastSyncDone().commit() - context become idle + context.become(idle) peerRequestsTime = Map.empty syncController ! Done } @@ -920,7 +917,7 @@ class FastSync( fastSyncStateStorage.purge() } - def processDownloads(): Unit = { + def processDownloads(): Unit = if (unassignedPeers.isEmpty) { if (assignedHandlers.nonEmpty) { log.debug("There are no available peers, waiting for [{}] responses.", assignedHandlers.size) @@ -936,7 +933,6 @@ class FastSync( .sortBy(_.peerInfo.maxBlockNumber)(bigIntReverseOrdering) .foreach(assignBlockchainWork) } - } def assignBlockchainWork(peerWithInfo: PeerWithInfo): Unit = { val PeerWithInfo(peer, peerInfo) = peerWithInfo @@ -980,7 +976,7 @@ class FastSync( s"$countActor-peer-request-handler-receipts" ) - context watch handler + context.watch(handler) assignedHandlers += (handler -> peer) peerRequestsTime += (peer -> Instant.now()) syncState = syncState.copy(receiptsQueue = remainingReceipts) @@ -1004,14 +1000,14 @@ class FastSync( s"$countActor-peer-request-handler-block-bodies" ) - context watch handler + context.watch(handler) assignedHandlers += (handler -> peer) peerRequestsTime += (peer -> Instant.now()) syncState = syncState.copy(blockBodiesQueue = remainingBlockBodies) requestedBlockBodies += handler -> blockBodiesToGet } - private def requestBlockHeaders(peer: Peer): Unit = { + private def requestBlockHeaders(peer: Peer): Unit = Try(blockHeadersQueue.dequeue()) match { case Success(toRequest) => log.debug( @@ -1033,15 +1029,13 @@ class FastSync( s"$countActor-peer-request-handler-block-headers" ) - context watch handler + context.watch(handler) assignedHandlers += (handler -> peer) requestedHeaders += (peer -> toRequest) peerRequestsTime += (peer -> Instant.now()) case _ => log.warning("Tried to request more block headers but work queue was empty.") } - } - private def requestSkeletonHeaders(peerCandidate: Peer): Unit = { val skeleton = HeaderSkeleton(syncState.bestBlockHeaderNumber + 1, syncState.safeDownloadTarget, blockHeadersPerRequest) @@ -1098,7 +1092,7 @@ class FastSync( s"$countActor-peer-request-handler-block-headers-skeleton" ) - context watch handler + context.watch(handler) skeletonHandler = Some(handler) currentSkeletonState = Some(skeleton) peerRequestsTime += (peer -> Instant.now()) @@ -1119,9 +1113,8 @@ class FastSync( private def blockchainDataToDownload: Boolean = syncState.blockChainWorkQueued || syncState.bestBlockHeaderNumber < syncState.safeDownloadTarget - private def fullySynced: Boolean = { + private def fullySynced: Boolean = syncState.isBlockchainWorkFinished && assignedHandlers.isEmpty && syncState.stateSyncFinished - } private def updateBestBlockIfNeeded(receivedHashes: Seq[ByteString]): Unit = { val fullBlocks = receivedHashes.flatMap { hash => @@ -1185,8 +1178,7 @@ object FastSync { private case object PersistSyncState private case object PrintStatus - /** - * Sync state that should be persisted. + /** Sync state that should be persisted. */ final case class SyncState( pivotBlock: BlockHeader, @@ -1223,8 +1215,8 @@ object FastSync { def updateDiscardedBlocks(header: BlockHeader, N: Int): SyncState = copy( blockBodiesQueue = Seq.empty, receiptsQueue = Seq.empty, - bestBlockHeaderNumber = (header.number - N - 1) max 0, - nextBlockToFullyValidate = (header.number - N) max 1 + bestBlockHeaderNumber = (header.number - N - 1).max(0), + nextBlockToFullyValidate = (header.number - N).max(1) ) def updatePivotBlock(newPivot: BlockHeader, numberOfSafeBlocks: BigInt, updateFailures: Boolean): SyncState = @@ -1258,14 +1250,14 @@ object FastSync { sealed abstract class PivotBlockUpdateReason { def isSyncRestart: Boolean = this match { - case ImportedLastBlock => false + case ImportedLastBlock => false case LastBlockValidationFailed => false - case SyncRestart => true + case SyncRestart => true } } case object ImportedLastBlock extends PivotBlockUpdateReason case object LastBlockValidationFailed extends PivotBlockUpdateReason case object SyncRestart extends PivotBlockUpdateReason - private[fast] final case class HeaderRange(from: BigInt, limit: BigInt) + final private[fast] case class HeaderRange(from: BigInt, limit: BigInt) } diff --git a/src/main/scala/io/iohk/ethereum/blockchain/sync/fast/FastSyncBranchResolver.scala b/src/main/scala/io/iohk/ethereum/blockchain/sync/fast/FastSyncBranchResolver.scala index d0c1913f04..e25aade69b 100644 --- a/src/main/scala/io/iohk/ethereum/blockchain/sync/fast/FastSyncBranchResolver.scala +++ b/src/main/scala/io/iohk/ethereum/blockchain/sync/fast/FastSyncBranchResolver.scala @@ -1,7 +1,10 @@ package io.iohk.ethereum.blockchain.sync.fast import cats.data.NonEmptyList -import io.iohk.ethereum.domain.{BlockHeader, Blockchain, BlockchainReader} + +import io.iohk.ethereum.domain.BlockHeader +import io.iohk.ethereum.domain.Blockchain +import io.iohk.ethereum.domain.BlockchainReader import io.iohk.ethereum.network.Peer import io.iohk.ethereum.utils.Logger @@ -30,8 +33,7 @@ trait FastSyncBranchResolver { object FastSyncBranchResolver { - /** - * Stores the current search state for binary search. + /** Stores the current search state for binary search. * Meaning we know the first common block lies between minBlockNumber and maxBlockNumber. */ final case class SearchState(minBlockNumber: BigInt, maxBlockNumber: BigInt, masterPeer: Peer) @@ -40,21 +42,19 @@ object FastSyncBranchResolver { def childOf(blockHeaderNumber: BigInt): BigInt = blockHeaderNumber + 1 } -/** - * Attempt to find last common block within recent blocks by looking for a parent/child +/** Attempt to find last common block within recent blocks by looking for a parent/child * relationship between our block headers and remote peer's block headers. */ class RecentBlocksSearch(blockchainReader: BlockchainReader) { - /** - * Find the highest common block by trying to find a block so that our block n is the parent of remote candidate block n + 1 + /** Find the highest common block by trying to find a block so that our block n is the parent of remote candidate block n + 1 */ def getHighestCommonBlock( candidateHeaders: Seq[BlockHeader], bestBlockNumber: BigInt ): Option[BigInt] = { def isParent(potentialParent: BigInt, childCandidate: BlockHeader): Boolean = - blockchainReader.getBlockHeaderByNumber(potentialParent).exists { _.isParentOf(childCandidate) } + blockchainReader.getBlockHeaderByNumber(potentialParent).exists(_.isParentOf(childCandidate)) NonEmptyList.fromList(candidateHeaders.reverse.toList).flatMap { remoteHeaders => val blocksToBeCompared = bestBlockNumber.until(bestBlockNumber - remoteHeaders.size).by(-1).toList remoteHeaders.toList @@ -75,8 +75,7 @@ object BinarySearchSupport extends Logger { final case class ContinueBinarySearch(searchState: SearchState) extends BinarySearchResult case object NoCommonBlock extends BinarySearchResult - /** - * Returns the block number in the middle between min and max. + /** Returns the block number in the middle between min and max. * If there is no middle, it will return the lower value. * * E.g. calling this method with min = 3 and max = 6 will return 4 diff --git a/src/main/scala/io/iohk/ethereum/blockchain/sync/fast/FastSyncBranchResolverActor.scala b/src/main/scala/io/iohk/ethereum/blockchain/sync/fast/FastSyncBranchResolverActor.scala index 69f6447987..5de9d3d842 100644 --- a/src/main/scala/io/iohk/ethereum/blockchain/sync/fast/FastSyncBranchResolverActor.scala +++ b/src/main/scala/io/iohk/ethereum/blockchain/sync/fast/FastSyncBranchResolverActor.scala @@ -1,25 +1,32 @@ package io.iohk.ethereum.blockchain.sync.fast -import akka.actor.{Actor, ActorLogging, ActorRef, PoisonPill, Props, Scheduler, Terminated} +import akka.actor.Actor +import akka.actor.ActorLogging +import akka.actor.ActorRef +import akka.actor.Props +import akka.actor.Scheduler +import akka.actor.Terminated +import akka.actor.Timers + +import scala.concurrent.duration._ + +import io.iohk.ethereum.blockchain.sync.Blacklist import io.iohk.ethereum.blockchain.sync.Blacklist.BlacklistReason +import io.iohk.ethereum.blockchain.sync.PeerListSupportNg import io.iohk.ethereum.blockchain.sync.PeerListSupportNg.PeerWithInfo -import io.iohk.ethereum.blockchain.sync.PeerRequestHandler.{RequestFailed, ResponseReceived} -import io.iohk.ethereum.blockchain.sync.fast.FastSyncBranchResolverActor._ -import io.iohk.ethereum.blockchain.sync.{Blacklist, PeerListSupportNg, PeerRequestHandler} +import io.iohk.ethereum.blockchain.sync.PeerRequestHandler +import io.iohk.ethereum.blockchain.sync.PeerRequestHandler.RequestFailed +import io.iohk.ethereum.blockchain.sync.PeerRequestHandler.ResponseReceived import io.iohk.ethereum.db.storage.AppStateStorage -import io.iohk.ethereum.domain.{BlockHeader, Blockchain, BlockchainReader} +import io.iohk.ethereum.domain.BlockHeader +import io.iohk.ethereum.domain.Blockchain +import io.iohk.ethereum.domain.BlockchainReader import io.iohk.ethereum.network.Peer import io.iohk.ethereum.network.p2p.messages.Codes -import io.iohk.ethereum.network.p2p.messages.ETH62.{BlockHeaders, GetBlockHeaders} +import io.iohk.ethereum.network.p2p.messages.ETH62.BlockHeaders +import io.iohk.ethereum.network.p2p.messages.ETH62.GetBlockHeaders import io.iohk.ethereum.utils.Config.SyncConfig -import scala.concurrent.ExecutionContext.Implicits.global -import scala.concurrent.duration._ -import monix.eval.Coeval -import monix.catnap.cancelables.AssignableCancelableF.Bool -import akka.actor.Timers -import io.iohk.ethereum.blockchain.sync.fast.BinarySearchSupport.ContinueBinarySearch - class FastSyncBranchResolverActor( val fastSync: ActorRef, val peerEventBus: ActorRef, @@ -46,7 +53,7 @@ class FastSyncBranchResolverActor( override def receive: Receive = waitingForPeerWithHighestBlock - private def waitingForPeerWithHighestBlock: Receive = handlePeerListMessages orElse { case StartBranchResolver => + private def waitingForPeerWithHighestBlock: Receive = handlePeerListMessages.orElse { case StartBranchResolver => getPeerWithHighestBlock match { case Some(peerWithInfo @ PeerWithInfo(peer, _)) => log.debug( @@ -66,7 +73,7 @@ class FastSyncBranchResolverActor( bestBlockNumber: BigInt, requestHandler: ActorRef ): Receive = - handlePeerListMessages orElse { + handlePeerListMessages.orElse { case ResponseReceived(peer, BlockHeaders(headers), timeTaken) if peer == masterPeer => if (headers.size == recentHeadersSize) { log.debug("Received {} block headers from peer {} in {} ms", headers.size, masterPeer.id, timeTaken) @@ -74,7 +81,7 @@ class FastSyncBranchResolverActor( } else { handleInvalidResponse(peer, requestHandler) } - case RequestFailed(peer, reason) => handleRequestFailure(peer, sender(), reason) + case RequestFailed(peer, reason) => handleRequestFailure(peer, sender(), reason) case Terminated(ref) if ref == requestHandler => handlePeerTermination(masterPeer, ref) } @@ -82,8 +89,8 @@ class FastSyncBranchResolverActor( searchState: SearchState, blockHeaderNumberToSearch: BigInt, requestHandler: ActorRef - ): Receive = { - handlePeerListMessages orElse { + ): Receive = + handlePeerListMessages.orElse { case ResponseReceived(peer, BlockHeaders(headers), durationMs) if peer == searchState.masterPeer => context.unwatch(requestHandler) headers.toList match { @@ -94,11 +101,10 @@ class FastSyncBranchResolverActor( log.warning(ReceivedWrongHeaders, blockHeaderNumberToSearch, headers.map(_.number)) handleInvalidResponse(peer, requestHandler) } - case RequestFailed(peer, reason) => handleRequestFailure(peer, sender(), reason) + case RequestFailed(peer, reason) => handleRequestFailure(peer, sender(), reason) case Terminated(ref) if ref == requestHandler => handlePeerTermination(searchState.masterPeer, ref) - case Terminated(_) => () // ignore + case Terminated(_) => () // ignore } - } private def requestRecentBlockHeaders(masterPeer: Peer, bestBlockNumber: BigInt): Unit = { val requestHandler = sendGetBlockHeadersRequest( @@ -109,15 +115,14 @@ class FastSyncBranchResolverActor( context.become(waitingForRecentBlockHeaders(masterPeer, bestBlockNumber, requestHandler)) } - /** - * Searches recent blocks for a valid parent/child relationship. + /** Searches recent blocks for a valid parent/child relationship. * If we dont't find one, we switch to binary search. */ private def handleRecentBlockHeadersResponse( blockHeaders: Seq[BlockHeader], masterPeer: Peer, bestBlockNumber: BigInt - ): Unit = { + ): Unit = recentBlocksSearch.getHighestCommonBlock(blockHeaders, bestBlockNumber) match { case Some(highestCommonBlockNumber) => finalizeBranchResolver(highestCommonBlockNumber, masterPeer) @@ -127,7 +132,6 @@ class FastSyncBranchResolverActor( SearchState(minBlockNumber = 1, maxBlockNumber = bestBlockNumber, masterPeer) ) } - } private def requestBlockHeaderForBinarySearch(searchState: SearchState): Unit = { val headerNumberToRequest = blockHeaderNumberToRequest(searchState.minBlockNumber, searchState.maxBlockNumber) @@ -158,8 +162,7 @@ class FastSyncBranchResolverActor( context.stop(self) } - /** - * In case of fatal errors (and to prevent trying forever) branch resolver will signal fast-sync about + /** In case of fatal errors (and to prevent trying forever) branch resolver will signal fast-sync about * the error and let fast-sync decide if it issues another request. */ private def stopWithFailure(response: BranchResolutionFailed): Unit = { diff --git a/src/main/scala/io/iohk/ethereum/blockchain/sync/fast/FastSyncMetrics.scala b/src/main/scala/io/iohk/ethereum/blockchain/sync/fast/FastSyncMetrics.scala index 645490be92..0f53cd1c66 100644 --- a/src/main/scala/io/iohk/ethereum/blockchain/sync/fast/FastSyncMetrics.scala +++ b/src/main/scala/io/iohk/ethereum/blockchain/sync/fast/FastSyncMetrics.scala @@ -1,37 +1,39 @@ package io.iohk.ethereum.blockchain.sync.fast +import java.util.concurrent.atomic.AtomicLong + +import scala.concurrent.duration.MILLISECONDS + import com.google.common.util.concurrent.AtomicDouble + import io.iohk.ethereum.blockchain.sync.fast.FastSync.SyncState import io.iohk.ethereum.metrics.MetricsContainer -import java.util.concurrent.atomic.AtomicLong -import scala.concurrent.duration.MILLISECONDS - object FastSyncMetrics extends MetricsContainer { - private final val PivotBlockNumberGauge = + final private val PivotBlockNumberGauge = metrics.registry.gauge("fastsync.block.pivotBlock.number.gauge", new AtomicDouble(0d)) - private final val BestFullBlockNumberGauge = + final private val BestFullBlockNumberGauge = metrics.registry.gauge("fastsync.block.bestFullBlock.number.gauge", new AtomicDouble(0d)) - private final val BestHeaderNumberGauge = + final private val BestHeaderNumberGauge = metrics.registry.gauge("fastsync.block.bestHeader.number.gauge", new AtomicDouble(0d)) - private final val MptStateTotalNodesGauge = + final private val MptStateTotalNodesGauge = metrics.registry.gauge("fastsync.state.totalNodes.gauge", new AtomicLong(0L)) - private final val MptStateDownloadedNodesGauge = + final private val MptStateDownloadedNodesGauge = metrics.registry.gauge("fastsync.state.downloadedNodes.gauge", new AtomicLong(0L)) - private final val FastSyncTotalTimeMinutesGauge = + final private val FastSyncTotalTimeMinutesGauge = metrics.registry.gauge("fastsync.totaltime.minutes.gauge", new AtomicDouble(0d)) - private final val BlockHeadersDownloadedTimer = + final private val BlockHeadersDownloadedTimer = metrics.registry.timer("fastsync.block.downloadBlockHeaders.timer") - private final val BlockBodiesDownloadTimer = + final private val BlockBodiesDownloadTimer = metrics.registry.timer("fastsync.block.downloadBlockBodies.timer") - private final val BlockReceiptsDownloadTimer = + final private val BlockReceiptsDownloadTimer = metrics.registry.timer("fastsync.block.downloadBlockReceipts.timer") - private final val MptStateDownloadTimer = + final private val MptStateDownloadTimer = metrics.registry.timer("fastsync.state.downloadState.timer") def measure(syncState: SyncState): Unit = { diff --git a/src/main/scala/io/iohk/ethereum/blockchain/sync/fast/HeaderSkeleton.scala b/src/main/scala/io/iohk/ethereum/blockchain/sync/fast/HeaderSkeleton.scala index 06749c5bf9..03663610c7 100644 --- a/src/main/scala/io/iohk/ethereum/blockchain/sync/fast/HeaderSkeleton.scala +++ b/src/main/scala/io/iohk/ethereum/blockchain/sync/fast/HeaderSkeleton.scala @@ -3,8 +3,7 @@ package io.iohk.ethereum.blockchain.sync.fast import io.iohk.ethereum.blockchain.sync.fast.HeaderSkeleton._ import io.iohk.ethereum.domain.BlockHeader -/** - * This class contains the state of the current skeleton being downloaded. This state is represented as the downloaded +/** This class contains the state of the current skeleton being downloaded. This state is represented as the downloaded * skeleton headers plus the downloaded batches. * A skeleton of block headers consists of `limit` headers, separated by `gapSize` blocks in between. * A batch of blocks is a sequence of `gapSize + 1` block headers starting one block after the previous skeleton @@ -46,23 +45,19 @@ final case class HeaderSkeleton( private val remainingBlocks: BigInt = to - from + 1 - /** - * Number of batched headers to request to a peer + /** Number of batched headers to request to a peer */ val batchSize: BigInt = remainingBlocks.min(maxSkeletonHeaders) - /** - * Number of blocks in between each skeleton header + /** Number of blocks in between each skeleton header */ val gapSize: BigInt = batchSize - 1 - /** - * Not to be confused with `from`. This is the number of the first header in the skeleton. + /** Not to be confused with `from`. This is the number of the first header in the skeleton. */ val firstSkeletonHeaderNumber: BigInt = from + gapSize - /** - * Maximum number of blocks to be downloaded at once. This is the total number of skeleton headers that the skeleton contains. + /** Maximum number of blocks to be downloaded at once. This is the total number of skeleton headers that the skeleton contains. */ val limit: BigInt = { val remainingSkeletonHeaders = remainingBlocks / batchSize @@ -80,8 +75,7 @@ final case class HeaderSkeleton( _ <- checkSkeletonHeaderNumbers(headers) } yield copy(skeletonHeaders = headers) - /** - * Use this method to update this state with the downloaded skeleton + /** Use this method to update this state with the downloaded skeleton * @param headers The downloaded skeleton * @return Either the updated structure if the validation succeeded or an error */ @@ -102,13 +96,11 @@ final case class HeaderSkeleton( Either.cond(isValid, (), InvalidHeaderNumber(downloadedHeaderNumbers, skeletonHeaderNumbers)) } - /** - * An ordered sequence with the numbers of the first block of each batch + /** An ordered sequence with the numbers of the first block of each batch */ val batchStartingHeaderNumbers: Seq[BigInt] = from +: skeletonHeaderNumbers.dropRight(1).map(_ + 1) - /** - * Use this method to update this state with a downloaded batch of headers + /** Use this method to update this state with a downloaded batch of headers * @param batchHeaders The downloaded batch of headers * @return Either the updated structure if the validation succeeded or an error */ @@ -119,7 +111,7 @@ final case class HeaderSkeleton( batchStartingNumber <- findBatchStartingNumber(batchHeaders) } yield copy(batches = batches + (batchStartingNumber -> batchHeaders)) - private def findSkeletonHeader(batchHeaders: Seq[BlockHeader]): Either[HeaderBatchError, BlockHeader] = { + private def findSkeletonHeader(batchHeaders: Seq[BlockHeader]): Either[HeaderBatchError, BlockHeader] = batchHeaders.lastOption match { case Some(header) => for { @@ -129,27 +121,24 @@ final case class HeaderSkeleton( case None => Left(EmptyDownloadedBatch(skeletonHeaderNumbers)) } - } - private def findSkeletonHeaderByNumber(header: BlockHeader): Either[InvalidBatchLastNumber, BlockHeader] = { + private def findSkeletonHeaderByNumber(header: BlockHeader): Either[InvalidBatchLastNumber, BlockHeader] = skeletonHeaders .find(_.number == header.number) .toRight(InvalidBatchLastNumber(header.number, skeletonHeaderNumbers)) - } private def checkSkeletonParentHash( batchHeaders: Seq[BlockHeader], skeletonHeader: BlockHeader - ): Either[HeaderBatchError, Unit] = { + ): Either[HeaderBatchError, Unit] = batchHeaders.dropRight(1).lastOption match { case Some(penultimateBatchHeader) if penultimateBatchHeader.hash != skeletonHeader.parentHash => Left(InvalidPenultimateHeader(penultimateBatchHeader, skeletonHeader)) case _ => Right(()) } - } - private def findBatchStartingNumber(batchHeaders: Seq[BlockHeader]): Either[HeaderBatchError, BigInt] = { + private def findBatchStartingNumber(batchHeaders: Seq[BlockHeader]): Either[HeaderBatchError, BigInt] = batchHeaders.headOption.map(_.number) match { case Some(firstBatchHeader) => val found = batchStartingHeaderNumbers.find(_ == firstBatchHeader) @@ -157,12 +146,10 @@ final case class HeaderSkeleton( case None => Left(EmptyDownloadedBatch(skeletonHeaderNumbers)) } - } private val isFull: Boolean = batchStartingHeaderNumbers.forall(batches.contains) - /** - * The complete skeleton plus the filled in batches, or `None` if not everything was downloaded + /** The complete skeleton plus the filled in batches, or `None` if not everything was downloaded */ val fullChain: Option[Seq[BlockHeader]] = if (isFull) Some(batchStartingHeaderNumbers.flatMap(batches.apply)) diff --git a/src/main/scala/io/iohk/ethereum/blockchain/sync/fast/LoadableBloomFilter.scala b/src/main/scala/io/iohk/ethereum/blockchain/sync/fast/LoadableBloomFilter.scala index 2e7f251e59..d787a08007 100644 --- a/src/main/scala/io/iohk/ethereum/blockchain/sync/fast/LoadableBloomFilter.scala +++ b/src/main/scala/io/iohk/ethereum/blockchain/sync/fast/LoadableBloomFilter.scala @@ -1,22 +1,25 @@ package io.iohk.ethereum.blockchain.sync.fast -import com.google.common.hash.{BloomFilter, Funnel} +import monix.eval.Task +import monix.reactive.Consumer +import monix.reactive.Observable + +import com.google.common.hash.BloomFilter +import com.google.common.hash.Funnel + import io.iohk.ethereum.blockchain.sync.fast.LoadableBloomFilter.BloomFilterLoadingResult import io.iohk.ethereum.db.dataSource.RocksDbDataSource.IterationError -import monix.eval.Task -import monix.reactive.{Consumer, Observable} class LoadableBloomFilter[A](bloomFilter: BloomFilter[A], source: Observable[Either[IterationError, A]]) { - val loadFromSource: Task[BloomFilterLoadingResult] = { + val loadFromSource: Task[BloomFilterLoadingResult] = source .consumeWith(Consumer.foldLeftTask(BloomFilterLoadingResult()) { (s, e) => e match { - case Left(value) => Task.now(s.copy(error = Some(value))) + case Left(value) => Task.now(s.copy(error = Some(value))) case Right(value) => Task(bloomFilter.put(value)).map(_ => s.copy(writtenElements = s.writtenElements + 1)) } }) .memoizeOnSuccess - } def put(elem: A): Boolean = bloomFilter.put(elem) @@ -28,9 +31,8 @@ class LoadableBloomFilter[A](bloomFilter: BloomFilter[A], source: Observable[Eit object LoadableBloomFilter { def apply[A](expectedSize: Int, loadingSource: Observable[Either[IterationError, A]])(implicit f: Funnel[A] - ): LoadableBloomFilter[A] = { + ): LoadableBloomFilter[A] = new LoadableBloomFilter[A](BloomFilter.create[A](f, expectedSize), loadingSource) - } case class BloomFilterLoadingResult(writtenElements: Long, error: Option[IterationError]) object BloomFilterLoadingResult { diff --git a/src/main/scala/io/iohk/ethereum/blockchain/sync/fast/PivotBlockSelector.scala b/src/main/scala/io/iohk/ethereum/blockchain/sync/fast/PivotBlockSelector.scala index cb2a1c3ee7..a4e3ab072d 100644 --- a/src/main/scala/io/iohk/ethereum/blockchain/sync/fast/PivotBlockSelector.scala +++ b/src/main/scala/io/iohk/ethereum/blockchain/sync/fast/PivotBlockSelector.scala @@ -1,26 +1,36 @@ package io.iohk.ethereum.blockchain.sync.fast -import akka.actor.{Actor, ActorLogging, ActorRef, Cancellable, Props, Scheduler} +import akka.actor.Actor +import akka.actor.ActorLogging +import akka.actor.ActorRef +import akka.actor.Cancellable +import akka.actor.Props +import akka.actor.Scheduler import akka.util.ByteString -import io.iohk.ethereum.blockchain.sync.Blacklist.BlacklistReason.{ - InvalidPivotBlockElectionResponse, - PivotBlockElectionTimeout -} + +import scala.concurrent.ExecutionContext.Implicits.global +import scala.concurrent.duration.FiniteDuration + +import io.iohk.ethereum.blockchain.sync.Blacklist +import io.iohk.ethereum.blockchain.sync.Blacklist.BlacklistReason.InvalidPivotBlockElectionResponse +import io.iohk.ethereum.blockchain.sync.Blacklist.BlacklistReason.PivotBlockElectionTimeout +import io.iohk.ethereum.blockchain.sync.PeerListSupportNg import io.iohk.ethereum.blockchain.sync.PeerListSupportNg.PeerWithInfo -import io.iohk.ethereum.blockchain.sync.{Blacklist, PeerListSupportNg} import io.iohk.ethereum.domain.BlockHeader +import io.iohk.ethereum.network.EtcPeerManagerActor import io.iohk.ethereum.network.EtcPeerManagerActor.PeerInfo +import io.iohk.ethereum.network.Peer import io.iohk.ethereum.network.PeerEventBusActor.PeerEvent.MessageFromPeer +import io.iohk.ethereum.network.PeerEventBusActor.PeerSelector +import io.iohk.ethereum.network.PeerEventBusActor.Subscribe import io.iohk.ethereum.network.PeerEventBusActor.SubscriptionClassifier.MessageClassifier -import io.iohk.ethereum.network.PeerEventBusActor.{PeerSelector, Subscribe, Unsubscribe} +import io.iohk.ethereum.network.PeerEventBusActor.Unsubscribe +import io.iohk.ethereum.network.PeerId import io.iohk.ethereum.network.p2p.messages.Codes -import io.iohk.ethereum.network.p2p.messages.ETH62.{BlockHeaders, GetBlockHeaders} -import io.iohk.ethereum.network.{EtcPeerManagerActor, Peer, PeerId} +import io.iohk.ethereum.network.p2p.messages.ETH62.BlockHeaders +import io.iohk.ethereum.network.p2p.messages.ETH62.GetBlockHeaders import io.iohk.ethereum.utils.Config.SyncConfig -import scala.concurrent.ExecutionContext.Implicits.global -import scala.concurrent.duration.FiniteDuration - class PivotBlockSelector( val etcPeerManager: ActorRef, val peerEventBus: ActorRef, @@ -39,7 +49,7 @@ class PivotBlockSelector( override def receive: Receive = idle - private def idle: Receive = handlePeerListMessages orElse { case SelectPivotBlock => + private def idle: Receive = handlePeerListMessages.orElse { case SelectPivotBlock => val electionDetails = collectVoters() startPivotBlockSelection(electionDetails) } @@ -61,12 +71,14 @@ class PivotBlockSelector( peersToAsk.foreach(peer => obtainBlockHeaderFromPeer(peer.id, expectedPivotBlock)) val timeout = scheduler.scheduleOnce(peerResponseTimeout, self, ElectionPivotBlockTimeout) - context become runningPivotBlockElection( - peersToAsk.map(_.id).toSet, - waitingPeers.map(_.id), - expectedPivotBlock, - timeout, - Map.empty + context.become( + runningPivotBlockElection( + peersToAsk.map(_.id).toSet, + waitingPeers.map(_.id), + expectedPivotBlock, + timeout, + Map.empty + ) ) } else { log.info( @@ -105,7 +117,7 @@ class PivotBlockSelector( timeout: Cancellable, headers: Map[ByteString, BlockHeaderWithVotes] ): Receive = - handlePeerListMessages orElse { + handlePeerListMessages.orElse { case MessageFromPeer(blockHeaders: BlockHeaders, peerId) => peerEventBus ! Unsubscribe(MessageClassifier(Set(Codes.BlockHeadersCode), PeerSelector.WithId(peerId))) val updatedPeersToAsk = peersToAsk - peerId @@ -152,12 +164,14 @@ class PivotBlockSelector( obtainBlockHeaderFromPeer(additionalPeer, pivotBlockNumber) - context become runningPivotBlockElection( - peersToAsk + additionalPeer, - newWaitingPeers, - pivotBlockNumber, - newTimeout, - headers + context.become( + runningPivotBlockElection( + peersToAsk + additionalPeer, + newWaitingPeers, + pivotBlockNumber, + newTimeout, + headers + ) ) } else { // No more peers. Restart the whole process peerEventBus ! Unsubscribe() @@ -166,12 +180,14 @@ class PivotBlockSelector( } // Continue voting } else { - context become runningPivotBlockElection( - peersToAsk, - waitingPeers, - pivotBlockNumber, - timeout, - headers + context.become( + runningPivotBlockElection( + peersToAsk, + waitingPeers, + pivotBlockNumber, + timeout, + headers + ) ) } } @@ -182,14 +198,14 @@ class PivotBlockSelector( private def scheduleRetry(interval: FiniteDuration): Unit = { pivotBlockRetryCount = 0 scheduler.scheduleOnce(interval, self, SelectPivotBlock) - context become idle + context.become(idle) } private def sendResponseAndCleanup(pivotBlockHeader: BlockHeader): Unit = { log.info("Found pivot block: {} hash: {}", pivotBlockHeader.number, pivotBlockHeader.hashAsHexString) fastSync ! Result(pivotBlockHeader) peerEventBus ! Unsubscribe() - context stop self + context.stop(self) } private def obtainBlockHeaderFromPeer(peer: PeerId, blockNumber: BigInt): Unit = { @@ -248,9 +264,8 @@ object PivotBlockSelector { } import cats.implicits._ implicit class SortableHeadersMap(headers: Map[ByteString, BlockHeaderWithVotes]) { - def mostVotedHeader: Option[BlockHeaderWithVotes] = { + def mostVotedHeader: Option[BlockHeaderWithVotes] = headers.toList.maximumByOption { case (_, headerWithVotes) => headerWithVotes.votes }.map(_._2) - } } final case class ElectionDetails( diff --git a/src/main/scala/io/iohk/ethereum/blockchain/sync/fast/ReceiptsValidator.scala b/src/main/scala/io/iohk/ethereum/blockchain/sync/fast/ReceiptsValidator.scala index 1e7a3aa8c0..864ab081de 100644 --- a/src/main/scala/io/iohk/ethereum/blockchain/sync/fast/ReceiptsValidator.scala +++ b/src/main/scala/io/iohk/ethereum/blockchain/sync/fast/ReceiptsValidator.scala @@ -1,9 +1,11 @@ package io.iohk.ethereum.blockchain.sync.fast import akka.util.ByteString + import io.iohk.ethereum.consensus.validators.Validators import io.iohk.ethereum.consensus.validators.std.StdBlockValidator.BlockError -import io.iohk.ethereum.domain.{Blockchain, BlockchainReader, Receipt} +import io.iohk.ethereum.domain.BlockchainReader +import io.iohk.ethereum.domain.Receipt trait ReceiptsValidator { @@ -13,8 +15,7 @@ trait ReceiptsValidator { def blockchainReader: BlockchainReader def validators: Validators - /** - * Validates whether the received receipts match the block headers stored on the blockchain, + /** Validates whether the received receipts match the block headers stored on the blockchain, * returning the valid receipts * * @param requestedHashes hash of the blocks to which the requested receipts should belong @@ -31,7 +32,7 @@ trait ReceiptsValidator { case (Some(header), receipt) => validators.blockValidator.validateBlockAndReceipts(header, receipt) match { case Left(err) => Some(Invalid(err)) - case _ => None + case _ => None } case (None, _) => Some(DbError) } diff --git a/src/main/scala/io/iohk/ethereum/blockchain/sync/fast/StateStorageActor.scala b/src/main/scala/io/iohk/ethereum/blockchain/sync/fast/StateStorageActor.scala index 91f92c3e84..948460eeb2 100644 --- a/src/main/scala/io/iohk/ethereum/blockchain/sync/fast/StateStorageActor.scala +++ b/src/main/scala/io/iohk/ethereum/blockchain/sync/fast/StateStorageActor.scala @@ -1,16 +1,21 @@ package io.iohk.ethereum.blockchain.sync.fast -import akka.actor.{Actor, ActorLogging} +import akka.actor.Actor +import akka.actor.ActorLogging import akka.pattern.pipe + +import monix.eval.Task +import monix.execution.Scheduler + +import scala.util.Failure +import scala.util.Success +import scala.util.Try + import io.iohk.ethereum.blockchain.sync.fast.FastSync.SyncState import io.iohk.ethereum.blockchain.sync.fast.StateStorageActor.GetStorage import io.iohk.ethereum.db.storage.FastSyncStateStorage -import monix.eval.Task -import monix.execution.Scheduler -import scala.util.{Failure, Success, Try} -/** - * Persists current state of fast sync to a storage. Can save only one state at a time. +/** Persists current state of fast sync to a storage. Can save only one state at a time. * If during persisting new state is received then it will be saved immediately after current state * was persisted. * If during persisting more than one new state is received then only the last state will be kept in queue. @@ -19,7 +24,7 @@ class StateStorageActor extends Actor with ActorLogging { def receive: Receive = { // after initialization send a valid Storage reference - case storage: FastSyncStateStorage => context become idle(storage) + case storage: FastSyncStateStorage => context.become(idle(storage)) } def idle(storage: FastSyncStateStorage): Receive = { @@ -31,11 +36,11 @@ class StateStorageActor extends Actor with ActorLogging { def busy(storage: FastSyncStateStorage, stateToPersist: Option[SyncState]): Receive = { // update state waiting to be persisted later. we only keep newest state - case state: SyncState => context become busy(storage, Some(state)) + case state: SyncState => context.become(busy(storage, Some(state))) // exception was thrown during persisting of a state. push case Failure(e) => throw e // state was saved in the storage. become idle - case Success(s: FastSyncStateStorage) if stateToPersist.isEmpty => context become idle(s) + case Success(s: FastSyncStateStorage) if stateToPersist.isEmpty => context.become(idle(s)) // state was saved in the storage but new state is already waiting to be saved. case Success(s: FastSyncStateStorage) if stateToPersist.isDefined => stateToPersist.foreach(persistState(s, _)) @@ -46,7 +51,7 @@ class StateStorageActor extends Actor with ActorLogging { implicit val scheduler: Scheduler = Scheduler(context.dispatcher) val persistingQueues: Task[Try[FastSyncStateStorage]] = Task { - lazy val result = Try { storage.putSyncState(syncState) } + lazy val result = Try(storage.putSyncState(syncState)) if (log.isDebugEnabled) { val now = System.currentTimeMillis() result @@ -57,8 +62,8 @@ class StateStorageActor extends Actor with ActorLogging { result } } - persistingQueues.runToFuture pipeTo self - context become busy(storage, None) + persistingQueues.runToFuture.pipeTo(self) + context.become(busy(storage, None)) } } diff --git a/src/main/scala/io/iohk/ethereum/blockchain/sync/fast/SyncBlocksValidator.scala b/src/main/scala/io/iohk/ethereum/blockchain/sync/fast/SyncBlocksValidator.scala index df72bd0ecc..c7e03880dd 100644 --- a/src/main/scala/io/iohk/ethereum/blockchain/sync/fast/SyncBlocksValidator.scala +++ b/src/main/scala/io/iohk/ethereum/blockchain/sync/fast/SyncBlocksValidator.scala @@ -2,8 +2,13 @@ package io.iohk.ethereum.blockchain.sync.fast import akka.actor.ActorLogging import akka.util.ByteString -import io.iohk.ethereum.consensus.validators.{BlockHeaderError, BlockHeaderValid, Validators} -import io.iohk.ethereum.domain.{BlockBody, BlockHeader, BlockchainReader} + +import io.iohk.ethereum.consensus.validators.BlockHeaderError +import io.iohk.ethereum.consensus.validators.BlockHeaderValid +import io.iohk.ethereum.consensus.validators.Validators +import io.iohk.ethereum.domain.BlockBody +import io.iohk.ethereum.domain.BlockHeader +import io.iohk.ethereum.domain.BlockchainReader trait SyncBlocksValidator { this: ActorLogging => @@ -14,7 +19,8 @@ trait SyncBlocksValidator { this: ActorLogging => def validators: Validators def validateBlocks(requestedHashes: Seq[ByteString], blockBodies: Seq[BlockBody]): BlockBodyValidationResult = - (requestedHashes zip blockBodies) + requestedHashes + .zip(blockBodies) .map { case (hash, body) => (blockchainReader.getBlockHeaderByHash(hash), body) } .foldLeft[BlockBodyValidationResult](Valid) { case (Valid, (Some(header), body)) => @@ -27,7 +33,7 @@ trait SyncBlocksValidator { this: ActorLogging => }, _ => Valid ) - case (Valid, _) => DbError + case (Valid, _) => DbError case (invalid, _) => invalid } diff --git a/src/main/scala/io/iohk/ethereum/blockchain/sync/fast/SyncSchedulerActorState.scala b/src/main/scala/io/iohk/ethereum/blockchain/sync/fast/SyncSchedulerActorState.scala index 9add8b4d22..c2cbdd28de 100644 --- a/src/main/scala/io/iohk/ethereum/blockchain/sync/fast/SyncSchedulerActorState.scala +++ b/src/main/scala/io/iohk/ethereum/blockchain/sync/fast/SyncSchedulerActorState.scala @@ -2,13 +2,18 @@ package io.iohk.ethereum.blockchain.sync.fast import akka.actor.ActorRef import akka.util.ByteString + import cats.data.NonEmptyList -import io.iohk.ethereum.blockchain.sync.fast.SyncStateScheduler.{ProcessingStatistics, SchedulerState} -import io.iohk.ethereum.blockchain.sync.fast.SyncStateSchedulerActor.{PeerRequest, RequestResult} -import io.iohk.ethereum.network.{Peer, PeerId} import scala.collection.immutable.Queue +import io.iohk.ethereum.blockchain.sync.fast.SyncStateScheduler.ProcessingStatistics +import io.iohk.ethereum.blockchain.sync.fast.SyncStateScheduler.SchedulerState +import io.iohk.ethereum.blockchain.sync.fast.SyncStateSchedulerActor.PeerRequest +import io.iohk.ethereum.blockchain.sync.fast.SyncStateSchedulerActor.RequestResult +import io.iohk.ethereum.network.Peer +import io.iohk.ethereum.network.PeerId + case class SyncSchedulerActorState( currentSchedulerState: SchedulerState, currentDownloaderState: DownloaderState, @@ -29,29 +34,24 @@ case class SyncSchedulerActorState( newSchedulerState: SchedulerState, newDownloaderState: DownloaderState, newStats: ProcessingStatistics - ): SyncSchedulerActorState = { + ): SyncSchedulerActorState = copy( currentSchedulerState = newSchedulerState, currentDownloaderState = newDownloaderState, currentStats = newStats ) - } - def withNewDownloaderState(newDownloaderState: DownloaderState): SyncSchedulerActorState = { + def withNewDownloaderState(newDownloaderState: DownloaderState): SyncSchedulerActorState = copy(currentDownloaderState = newDownloaderState) - } - def withRestartRequested(restartRequester: ActorRef): SyncSchedulerActorState = { + def withRestartRequested(restartRequester: ActorRef): SyncSchedulerActorState = copy(restartRequested = Some(restartRequester)) - } - def initProcessing: SyncSchedulerActorState = { + def initProcessing: SyncSchedulerActorState = copy(processing = true) - } - def finishProcessing: SyncSchedulerActorState = { + def finishProcessing: SyncSchedulerActorState = copy(processing = false) - } def assignTasksToPeers( freePeers: NonEmptyList[Peer], @@ -69,11 +69,10 @@ case class SyncSchedulerActorState( (requests, copy(currentSchedulerState = newState, currentDownloaderState = newDownloaderState)) } - def getRequestToProcess: Option[(RequestResult, SyncSchedulerActorState)] = { + def getRequestToProcess: Option[(RequestResult, SyncSchedulerActorState)] = nodesToProcess.dequeueOption.map { case (result, restOfResults) => (result, copy(nodesToProcess = restOfResults)) } - } def numberOfRemainingRequests: Int = nodesToProcess.size @@ -81,7 +80,7 @@ case class SyncSchedulerActorState( def activePeerRequests: Map[PeerId, NonEmptyList[ByteString]] = currentDownloaderState.activeRequests - override def toString: String = { + override def toString: String = s""" Status of mpt state sync: | Number of Pending requests: ${currentSchedulerState.numberOfPendingRequests}, | Number of Missing hashes waiting to be retrieved: ${currentSchedulerState.queue.size()}, @@ -91,7 +90,6 @@ case class SyncSchedulerActorState( | Number of not requested hashes: ${currentStats.notRequestedHashes}, | Number of active peer requests: ${currentDownloaderState.activeRequests.size} """.stripMargin - } } object SyncSchedulerActorState { @@ -100,7 +98,7 @@ object SyncSchedulerActorState { initialStats: ProcessingStatistics, targetBlock: BigInt, syncInitiator: ActorRef - ): SyncSchedulerActorState = { + ): SyncSchedulerActorState = SyncSchedulerActorState( initialSchedulerState, DownloaderState(), @@ -112,5 +110,4 @@ object SyncSchedulerActorState { restartRequested = None ) - } } diff --git a/src/main/scala/io/iohk/ethereum/blockchain/sync/fast/SyncStateScheduler.scala b/src/main/scala/io/iohk/ethereum/blockchain/sync/fast/SyncStateScheduler.scala index a2387b98c2..81eaceefd8 100644 --- a/src/main/scala/io/iohk/ethereum/blockchain/sync/fast/SyncStateScheduler.scala +++ b/src/main/scala/io/iohk/ethereum/blockchain/sync/fast/SyncStateScheduler.scala @@ -1,16 +1,9 @@ package io.iohk.ethereum.blockchain.sync.fast import java.util.Comparator + import akka.util.ByteString -import com.google.common.hash.{BloomFilter, Funnel, PrimitiveSink} -import io.iohk.ethereum.blockchain.sync.fast.LoadableBloomFilter.BloomFilterLoadingResult -import io.iohk.ethereum.blockchain.sync.fast.SyncStateScheduler._ -import io.iohk.ethereum.db.dataSource.RocksDbDataSource.IterationError -import io.iohk.ethereum.db.storage.{EvmCodeStorage, NodeStorage} -import io.iohk.ethereum.domain.{Account, Blockchain, BlockchainReader} -import io.iohk.ethereum.mpt.{BranchNode, ExtensionNode, HashNode, LeafNode, MerklePatriciaTrie, MptNode} -import io.iohk.ethereum.network.p2p.messages.ETH63.MptNodeEncoders.MptNodeDec -import io.vavr.collection.PriorityQueue + import monix.eval.Task import monix.reactive.Observable @@ -18,8 +11,28 @@ import scala.annotation.tailrec import scala.collection.immutable.ArraySeq import scala.util.Try -/** - * Scheduler which traverses Merkle patricia trie in DFS fashion, while also creating requests for nodes missing in traversed +import com.google.common.hash.BloomFilter +import com.google.common.hash.Funnel +import com.google.common.hash.PrimitiveSink +import io.vavr.collection.PriorityQueue + +import io.iohk.ethereum.blockchain.sync.fast.LoadableBloomFilter.BloomFilterLoadingResult +import io.iohk.ethereum.blockchain.sync.fast.SyncStateScheduler._ +import io.iohk.ethereum.db.dataSource.RocksDbDataSource.IterationError +import io.iohk.ethereum.db.storage.EvmCodeStorage +import io.iohk.ethereum.db.storage.NodeStorage +import io.iohk.ethereum.domain.Account +import io.iohk.ethereum.domain.Blockchain +import io.iohk.ethereum.domain.BlockchainReader +import io.iohk.ethereum.mpt.BranchNode +import io.iohk.ethereum.mpt.ExtensionNode +import io.iohk.ethereum.mpt.HashNode +import io.iohk.ethereum.mpt.LeafNode +import io.iohk.ethereum.mpt.MerklePatriciaTrie +import io.iohk.ethereum.mpt.MptNode +import io.iohk.ethereum.network.p2p.messages.ETH63.MptNodeEncoders.MptNodeDec + +/** Scheduler which traverses Merkle patricia trie in DFS fashion, while also creating requests for nodes missing in traversed * trie. * Traversal example: Merkle Patricia Trie with 2 leaf child nodes, each with non empty code value. * Final State: @@ -54,7 +67,7 @@ class SyncStateScheduler( val loadFilterFromBlockchain: Task[BloomFilterLoadingResult] = bloomFilter.loadFromSource - def initState(targetRootHash: ByteString): Option[SchedulerState] = { + def initState(targetRootHash: ByteString): Option[SchedulerState] = if (targetRootHash == emptyStateRootHash) { None } else if (blockchainReader.getMptNodeByHash(targetRootHash).isDefined) { @@ -64,10 +77,8 @@ class SyncStateScheduler( val initialRequest = StateNodeRequest(targetRootHash, None, StateNode, Seq(), 0, 0) Option(initialState.schedule(initialRequest)) } - } - /** - * Default responses processor which ignores duplicated or not requested hashes, but informs the caller about critical + /** Default responses processor which ignores duplicated or not requested hashes, but informs the caller about critical * errors. * If it would valuable, it possible to implement processor which would gather statistics about duplicated or not requested data. */ @@ -80,7 +91,7 @@ class SyncStateScheduler( currentState: SchedulerState, currentStatistics: ProcessingStatistics, remaining: Seq[SyncResponse] - ): Either[CriticalError, (SchedulerState, ProcessingStatistics)] = { + ): Either[CriticalError, (SchedulerState, ProcessingStatistics)] = if (remaining.isEmpty) { Right((currentState, currentStatistics)) } else { @@ -103,18 +114,15 @@ class SyncStateScheduler( go(newState, currentStatistics, remaining.tail) } } - } go(state, ProcessingStatistics(), responses) } - def getMissingNodes(state: SchedulerState, max: Int): (List[ByteString], SchedulerState) = { + def getMissingNodes(state: SchedulerState, max: Int): (List[ByteString], SchedulerState) = state.getMissingHashes(max) - } - def getAllMissingNodes(state: SchedulerState): (List[ByteString], SchedulerState) = { + def getAllMissingNodes(state: SchedulerState): (List[ByteString], SchedulerState) = getMissingNodes(state, state.numberOfMissingHashes) - } def persistBatch(state: SchedulerState, targetBlockNumber: BigInt): SchedulerState = { // Potential optimisation would be to expose some kind batch api from db to make only 1 write instead od 100k @@ -136,18 +144,17 @@ class SyncStateScheduler( private def isRequestAlreadyKnownOrResolved( state: SchedulerState, response: SyncResponse - ): Either[ResponseProcessingError, StateNodeRequest] = { + ): Either[ResponseProcessingError, StateNodeRequest] = for { activeRequest <- state.getPendingRequestByHash(response.hash).toRight(NotRequestedItem) _ <- if (activeRequest.resolvedData.isDefined) Left(AlreadyProcessedItem) else Right(()) } yield activeRequest - } private def processActiveResponse( state: SchedulerState, activeRequest: StateNodeRequest, response: SyncResponse - ): Either[ResponseProcessingError, SchedulerState] = { + ): Either[ResponseProcessingError, SchedulerState] = activeRequest.requestType match { case _: CodeRequest => Right(state.commit(activeRequest.copy(resolvedData = Some(response.data)))) case requestType: NodeRequest => @@ -164,18 +171,16 @@ class SyncStateScheduler( } } } - } def processResponse( state: SchedulerState, response: SyncResponse - ): Either[ResponseProcessingError, SchedulerState] = { + ): Either[ResponseProcessingError, SchedulerState] = for { activeRequest <- isRequestAlreadyKnownOrResolved(state, response) newState <- processActiveResponse(state, activeRequest, response) } yield newState - } // scalastyle:off method.length private def createPossibleChildRequests( mptNode: MptNode, @@ -247,21 +252,19 @@ class SyncStateScheduler( case _ => Right(Nil) } - private def isInDatabase(req: StateNodeRequest): Boolean = { + private def isInDatabase(req: StateNodeRequest): Boolean = req.requestType match { case _: CodeRequest => evmCodeStorage.get(req.nodeHash).isDefined case _: NodeRequest => blockchainReader.getMptNodeByHash(req.nodeHash).isDefined } - } - private def isRequestedHashAlreadyCommitted(state: SchedulerState, req: StateNodeRequest): Boolean = { + private def isRequestedHashAlreadyCommitted(state: SchedulerState, req: StateNodeRequest): Boolean = state.memBatch.contains(req.nodeHash) || - (bloomFilter.mightContain(req.nodeHash) && isInDatabase( - req - )) // if hash is in bloom filter we need to double check on db - } + (bloomFilter.mightContain(req.nodeHash) && isInDatabase( + req + )) // if hash is in bloom filter we need to double check on db } object SyncStateScheduler { @@ -282,14 +285,12 @@ object SyncStateScheduler { case object StorageNode extends NodeRequest implicit object ByteStringFunnel extends Funnel[ByteString] { - override def funnel(from: ByteString, into: PrimitiveSink): Unit = { + override def funnel(from: ByteString, into: PrimitiveSink): Unit = into.putBytes(from.toArray) - } } - def getEmptyFilter(expectedFilterSize: Int): BloomFilter[ByteString] = { + def getEmptyFilter(expectedFilterSize: Int): BloomFilter[ByteString] = BloomFilter.create[ByteString](ByteStringFunnel, expectedFilterSize) - } def apply( blockchain: Blockchain, @@ -327,9 +328,8 @@ object SyncStateScheduler { } private val stateNodeRequestComparator = new Comparator[StateNodeRequest] { - override def compare(o1: StateNodeRequest, o2: StateNodeRequest): Int = { - o2.nodeDepth compare o1.nodeDepth - } + override def compare(o1: StateNodeRequest, o2: StateNodeRequest): Int = + o2.nodeDepth.compare(o1.nodeDepth) } implicit class Tuple2Ops[A, B](o: io.vavr.Tuple2[A, B]) { @@ -344,7 +344,7 @@ object SyncStateScheduler { memBatch: Map[ByteString, (ByteString, RequestType)] ) { - def schedule(request: StateNodeRequest): SchedulerState = { + def schedule(request: StateNodeRequest): SchedulerState = activeRequest.get(request.nodeHash) match { case Some(oldRequest) => copy(activeRequest + (request.nodeHash -> oldRequest.copy(parents = oldRequest.parents ++ request.parents))) @@ -352,7 +352,6 @@ object SyncStateScheduler { case None => copy(activeRequest + (request.nodeHash -> request), queue.enqueue(request)) } - } def getMissingHashes(max: Int): (List[ByteString], SchedulerState) = { @tailrec @@ -360,7 +359,7 @@ object SyncStateScheduler { currentQueue: PriorityQueue[StateNodeRequest], remaining: Int, got: List[ByteString] - ): (PriorityQueue[StateNodeRequest], List[ByteString]) = { + ): (PriorityQueue[StateNodeRequest], List[ByteString]) = if (remaining == 0) { (currentQueue, got.reverse) } else if (currentQueue.isEmpty) { @@ -369,7 +368,6 @@ object SyncStateScheduler { val (elem, newQueue) = currentQueue.dequeue().asScala() go(newQueue, remaining - 1, elem.nodeHash :: got) } - } val (newQueue, elements) = go(queue, max, List.empty) (elements, copy(queue = newQueue)) @@ -389,7 +387,7 @@ object SyncStateScheduler { currentRequests: Map[ByteString, StateNodeRequest], currentBatch: Map[ByteString, (ByteString, RequestType)], parentsToCheck: Seq[ByteString] - ): (Map[ByteString, StateNodeRequest], Map[ByteString, (ByteString, RequestType)]) = { + ): (Map[ByteString, StateNodeRequest], Map[ByteString, (ByteString, RequestType)]) = if (parentsToCheck.isEmpty) { (currentRequests, currentBatch) } else { @@ -424,7 +422,6 @@ object SyncStateScheduler { ) } } - } val newActive = activeRequest - request.nodeHash val newMemBatch = memBatch + (request.nodeHash -> (request.resolvedData.get, request.requestType)) @@ -446,19 +443,17 @@ object SyncStateScheduler { requestNewChildren.foldLeft(stateWithUpdatedParent) { case (state, child) => state.schedule(child) } } - def getNodesToPersist: (Seq[(ByteString, (ByteString, RequestType))], SchedulerState) = { + def getNodesToPersist: (Seq[(ByteString, (ByteString, RequestType))], SchedulerState) = (memBatch.toSeq, copy(memBatch = Map.empty)) - } } object SchedulerState { - def apply(): SchedulerState = { + def apply(): SchedulerState = new SchedulerState( Map.empty[ByteString, StateNodeRequest], PriorityQueue.empty(stateNodeRequestComparator), Map.empty ) - } } case object ProcessingSuccess diff --git a/src/main/scala/io/iohk/ethereum/blockchain/sync/fast/SyncStateSchedulerActor.scala b/src/main/scala/io/iohk/ethereum/blockchain/sync/fast/SyncStateSchedulerActor.scala index 00947ff514..0cf721a750 100644 --- a/src/main/scala/io/iohk/ethereum/blockchain/sync/fast/SyncStateSchedulerActor.scala +++ b/src/main/scala/io/iohk/ethereum/blockchain/sync/fast/SyncStateSchedulerActor.scala @@ -1,31 +1,39 @@ package io.iohk.ethereum.blockchain.sync.fast -import akka.actor.{Actor, ActorLogging, ActorRef, Props, Timers} +import akka.actor.Actor +import akka.actor.ActorLogging +import akka.actor.ActorRef +import akka.actor.Props +import akka.actor.Timers import akka.pattern.pipe import akka.util.ByteString + import cats.data.NonEmptyList + +import monix.eval.Task +import monix.execution.Scheduler + +import scala.concurrent.duration._ + +import io.iohk.ethereum.blockchain.sync.Blacklist import io.iohk.ethereum.blockchain.sync.Blacklist.BlacklistReason import io.iohk.ethereum.blockchain.sync.Blacklist.BlacklistReason.InvalidStateResponse +import io.iohk.ethereum.blockchain.sync.PeerListSupportNg import io.iohk.ethereum.blockchain.sync.PeerListSupportNg.PeerWithInfo +import io.iohk.ethereum.blockchain.sync.PeerRequestHandler import io.iohk.ethereum.blockchain.sync.PeerRequestHandler.ResponseReceived import io.iohk.ethereum.blockchain.sync.fast.LoadableBloomFilter.BloomFilterLoadingResult -import io.iohk.ethereum.blockchain.sync.fast.SyncStateScheduler.{ - CriticalError, - ProcessingStatistics, - SchedulerState, - SyncResponse -} +import io.iohk.ethereum.blockchain.sync.fast.SyncStateScheduler.CriticalError +import io.iohk.ethereum.blockchain.sync.fast.SyncStateScheduler.ProcessingStatistics +import io.iohk.ethereum.blockchain.sync.fast.SyncStateScheduler.SchedulerState +import io.iohk.ethereum.blockchain.sync.fast.SyncStateScheduler.SyncResponse import io.iohk.ethereum.blockchain.sync.fast.SyncStateSchedulerActor._ -import io.iohk.ethereum.blockchain.sync.{Blacklist, PeerListSupportNg, PeerRequestHandler} import io.iohk.ethereum.network.Peer import io.iohk.ethereum.network.p2p.messages.Codes -import io.iohk.ethereum.network.p2p.messages.ETH63.{GetNodeData, NodeData} +import io.iohk.ethereum.network.p2p.messages.ETH63.GetNodeData +import io.iohk.ethereum.network.p2p.messages.ETH63.NodeData import io.iohk.ethereum.utils.ByteStringUtils import io.iohk.ethereum.utils.Config.SyncConfig -import monix.eval.Task -import monix.execution.Scheduler - -import scala.concurrent.duration._ class SyncStateSchedulerActor( sync: SyncStateScheduler, @@ -40,7 +48,7 @@ class SyncStateSchedulerActor( with ActorLogging with Timers { - private implicit val monixScheduler: Scheduler = Scheduler(context.dispatcher) + implicit private val monixScheduler: Scheduler = Scheduler(context.dispatcher) private def getFreePeers(state: DownloaderState): List[Peer] = peersToDownloadFrom.collect { @@ -93,7 +101,7 @@ class SyncStateSchedulerActor( } def waitingForBloomFilterToLoad(lastReceivedCommand: Option[(SyncStateSchedulerActorCommand, ActorRef)]): Receive = - handlePeerListMessages orElse { + handlePeerListMessages.orElse { case BloomFilterResult(result) => log.debug( "Loaded {} already known elements from storage to bloom filter the error while loading was {}", @@ -126,13 +134,15 @@ class SyncStateSchedulerActor( log.info("Starting state sync to root {} on block {}", ByteStringUtils.hash2string(root), bn) //TODO handle case when we already have root i.e state is synced up to this point val initState = sync.initState(root).get - context become syncing( - SyncSchedulerActorState.initial(initState, initialStats, bn, initiator) + context.become( + syncing( + SyncSchedulerActorState.initial(initState, initialStats, bn, initiator) + ) ) self ! Sync } - def idle(processingStatistics: ProcessingStatistics): Receive = handlePeerListMessages orElse { + def idle(processingStatistics: ProcessingStatistics): Receive = handlePeerListMessages.orElse { case StartSyncingTo(root, bn) => startSyncing(root, bn, processingStatistics, sender()) case PrintInfo => @@ -141,7 +151,7 @@ class SyncStateSchedulerActor( private def finalizeSync( state: SyncSchedulerActorState - ): Unit = { + ): Unit = if (state.memBatch.nonEmpty) { log.debug("Persisting {} elements to blockchain and finalizing the state sync", state.memBatch.size) val finalState = sync.persistBatch(state.currentSchedulerState, state.targetBlock) @@ -153,12 +163,11 @@ class SyncStateSchedulerActor( state.syncInitiator ! StateSyncFinished context.become(idle(ProcessingStatistics())) } - } private def processNodes( currentState: SyncSchedulerActorState, requestResult: RequestResult - ): ProcessingResult = { + ): ProcessingResult = requestResult match { case RequestData(nodeData, from) => val (resp, newDownloaderState) = currentState.currentDownloaderState.handleRequestSuccess(from, nodeData) @@ -188,7 +197,6 @@ class SyncStateSchedulerActor( Left(DownloaderError(newDownloaderState, from, Some(BlacklistReason.FastSyncRequestFailed(reason)))) ) } - } private def handleRestart( currentState: SchedulerState, @@ -204,7 +212,7 @@ class SyncStateSchedulerActor( // scalastyle:off cyclomatic.complexity method.length def syncing(currentState: SyncSchedulerActorState): Receive = - handlePeerListMessages orElse handleRequestResults orElse { + handlePeerListMessages.orElse(handleRequestResults).orElse { case Sync if currentState.hasRemainingPendingRequests && !currentState.restartHasBeenRequested => val freePeers = getFreePeers(currentState.currentDownloaderState) (currentState.getRequestToProcess, NonEmptyList.fromList(freePeers)) match { @@ -341,12 +349,11 @@ object SyncStateSchedulerActor { to: ActorRef, currentStats: ProcessingStatistics, currentState: SyncStateScheduler.SchedulerState - ): Unit = { + ): Unit = to ! StateSyncStats( currentStats.saved + currentState.memBatch.size, currentState.numberOfPendingRequests ) - } final case class StateSyncStats(saved: Long, missing: Long) @@ -359,9 +366,8 @@ object SyncStateSchedulerActor { peerEventBus: ActorRef, blacklist: Blacklist, scheduler: akka.actor.Scheduler - ): Props = { + ): Props = Props(new SyncStateSchedulerActor(sync, syncConfig, etcPeerManager, peerEventBus, blacklist, scheduler)(scheduler)) - } final case object PrintInfo final case object PrintInfoKey diff --git a/src/main/scala/io/iohk/ethereum/blockchain/sync/regular/BlockBroadcast.scala b/src/main/scala/io/iohk/ethereum/blockchain/sync/regular/BlockBroadcast.scala index 1159eb7e94..7ed705cabc 100644 --- a/src/main/scala/io/iohk/ethereum/blockchain/sync/regular/BlockBroadcast.scala +++ b/src/main/scala/io/iohk/ethereum/blockchain/sync/regular/BlockBroadcast.scala @@ -1,21 +1,27 @@ package io.iohk.ethereum.blockchain.sync.regular import akka.actor.ActorRef + +import scala.util.Random + import io.iohk.ethereum.blockchain.sync.PeerListSupportNg.PeerWithInfo import io.iohk.ethereum.blockchain.sync.regular.BlockBroadcast.BlockToBroadcast -import io.iohk.ethereum.domain.{Block, ChainWeight} +import io.iohk.ethereum.domain.Block +import io.iohk.ethereum.domain.ChainWeight +import io.iohk.ethereum.network.EtcPeerManagerActor import io.iohk.ethereum.network.EtcPeerManagerActor.PeerInfo +import io.iohk.ethereum.network.Peer +import io.iohk.ethereum.network.PeerId import io.iohk.ethereum.network.p2p.MessageSerializable +import io.iohk.ethereum.network.p2p.messages.BaseETH6XMessages +import io.iohk.ethereum.network.p2p.messages.ETC64 +import io.iohk.ethereum.network.p2p.messages.ETH62 import io.iohk.ethereum.network.p2p.messages.ETH62.BlockHash -import io.iohk.ethereum.network.p2p.messages.{BaseETH6XMessages, ETH62, ETC64, ProtocolVersions} -import io.iohk.ethereum.network.{EtcPeerManagerActor, Peer, PeerId} - -import scala.util.Random +import io.iohk.ethereum.network.p2p.messages.ProtocolVersions class BlockBroadcast(val etcPeerManager: ActorRef) { - /** - * Broadcasts various NewBlock's messages to handshaked peers, considering that a block should not be sent to a peer + /** Broadcasts various NewBlock's messages to handshaked peers, considering that a block should not be sent to a peer * that is thought to know it. * The hash of the block is sent to all of those peers while the block itself is only sent to * the square root of the total number of those peers, with the subset being obtained randomly. @@ -53,8 +59,7 @@ class BlockBroadcast(val etcPeerManager: ActorRef) { etcPeerManager ! EtcPeerManagerActor.SendMessage(newBlockHashMsg, peer.id) } - /** - * Obtains a random subset of peers. The returned set will verify: + /** Obtains a random subset of peers. The returned set will verify: * subsetPeers.size == sqrt(peers.size) * * @param peers @@ -68,8 +73,7 @@ class BlockBroadcast(val etcPeerManager: ActorRef) { object BlockBroadcast { - /** - * BlockToBroadcast was created to decouple block information from protocol new block messages + /** BlockToBroadcast was created to decouple block information from protocol new block messages * (they are different versions of NewBlock msg) */ case class BlockToBroadcast(block: Block, chainWeight: ChainWeight) { diff --git a/src/main/scala/io/iohk/ethereum/blockchain/sync/regular/BlockBroadcasterActor.scala b/src/main/scala/io/iohk/ethereum/blockchain/sync/regular/BlockBroadcasterActor.scala index bdf20926c3..7e492f62da 100644 --- a/src/main/scala/io/iohk/ethereum/blockchain/sync/regular/BlockBroadcasterActor.scala +++ b/src/main/scala/io/iohk/ethereum/blockchain/sync/regular/BlockBroadcasterActor.scala @@ -1,8 +1,14 @@ package io.iohk.ethereum.blockchain.sync.regular -import akka.actor.{Actor, ActorLogging, ActorRef, Props, Scheduler} +import akka.actor.Actor +import akka.actor.ActorLogging +import akka.actor.ActorRef +import akka.actor.Props +import akka.actor.Scheduler + +import io.iohk.ethereum.blockchain.sync.Blacklist +import io.iohk.ethereum.blockchain.sync.PeerListSupportNg import io.iohk.ethereum.blockchain.sync.regular.BlockBroadcast.BlockToBroadcast -import io.iohk.ethereum.blockchain.sync.{Blacklist, PeerListSupportNg} import io.iohk.ethereum.utils.Config.SyncConfig class BlockBroadcasterActor( @@ -17,11 +23,11 @@ class BlockBroadcasterActor( with PeerListSupportNg { import BlockBroadcasterActor._ - override def receive: Receive = handlePeerListMessages orElse handleBroadcastMessages + override def receive: Receive = handlePeerListMessages.orElse(handleBroadcastMessages) private def handleBroadcastMessages: Receive = { case BroadcastBlock(newBlock) => broadcast.broadcastBlock(newBlock, handshakedPeers) - case BroadcastBlocks(blocks) => blocks.foreach(broadcast.broadcastBlock(_, handshakedPeers)) + case BroadcastBlocks(blocks) => blocks.foreach(broadcast.broadcastBlock(_, handshakedPeers)) } } object BlockBroadcasterActor { diff --git a/src/main/scala/io/iohk/ethereum/blockchain/sync/regular/BlockFetcher.scala b/src/main/scala/io/iohk/ethereum/blockchain/sync/regular/BlockFetcher.scala index 4651ee6d32..23081a51e3 100644 --- a/src/main/scala/io/iohk/ethereum/blockchain/sync/regular/BlockFetcher.scala +++ b/src/main/scala/io/iohk/ethereum/blockchain/sync/regular/BlockFetcher.scala @@ -1,39 +1,50 @@ package io.iohk.ethereum.blockchain.sync.regular -import akka.actor.typed.{ActorRef, Behavior} -import akka.actor.typed.scaladsl.{AbstractBehavior, ActorContext, Behaviors} +import akka.actor.typed.ActorRef +import akka.actor.typed.Behavior +import akka.actor.typed.scaladsl.AbstractBehavior +import akka.actor.typed.scaladsl.ActorContext +import akka.actor.typed.scaladsl.Behaviors +import akka.actor.typed.scaladsl.adapter._ import akka.actor.{ActorRef => ClassicActorRef} -import akka.util.{ByteString, Timeout} +import akka.util.ByteString +import akka.util.Timeout + import cats.data.NonEmptyList import cats.instances.option._ + +import monix.execution.{Scheduler => MonixScheduler} + +import scala.concurrent.duration._ + +import mouse.all._ + import io.iohk.ethereum.blockchain.sync.Blacklist.BlacklistReason -import io.iohk.ethereum.consensus.validators.BlockValidator import io.iohk.ethereum.blockchain.sync.PeersClient._ -import io.iohk.ethereum.blockchain.sync.regular.BlockFetcherState.{ - AwaitingBodiesToBeIgnored, - AwaitingHeadersToBeIgnored, - HeadersNotFormingSeq, - HeadersNotMatchingReadyBlocks -} +import io.iohk.ethereum.blockchain.sync.regular.BlockFetcherState.AwaitingBodiesToBeIgnored +import io.iohk.ethereum.blockchain.sync.regular.BlockFetcherState.AwaitingHeadersToBeIgnored +import io.iohk.ethereum.blockchain.sync.regular.BlockFetcherState.HeadersNotFormingSeq +import io.iohk.ethereum.blockchain.sync.regular.BlockFetcherState.HeadersNotMatchingReadyBlocks import io.iohk.ethereum.blockchain.sync.regular.BlockImporter.ImportNewBlock import io.iohk.ethereum.blockchain.sync.regular.RegularSync.ProgressProtocol +import io.iohk.ethereum.consensus.validators.BlockValidator import io.iohk.ethereum.domain._ +import io.iohk.ethereum.network.Peer +import io.iohk.ethereum.network.PeerEventBusActor import io.iohk.ethereum.network.PeerEventBusActor.PeerEvent.MessageFromPeer +import io.iohk.ethereum.network.PeerEventBusActor.PeerSelector +import io.iohk.ethereum.network.PeerEventBusActor.Subscribe import io.iohk.ethereum.network.PeerEventBusActor.SubscriptionClassifier.MessageClassifier -import io.iohk.ethereum.network.PeerEventBusActor.{PeerSelector, Subscribe} -import io.iohk.ethereum.network.{Peer, PeerEventBusActor, PeerId} +import io.iohk.ethereum.network.PeerId import io.iohk.ethereum.network.p2p.Message -import io.iohk.ethereum.network.p2p.messages.{Codes, BaseETH6XMessages, ETC64} +import io.iohk.ethereum.network.p2p.messages.BaseETH6XMessages +import io.iohk.ethereum.network.p2p.messages.Codes +import io.iohk.ethereum.network.p2p.messages.ETC64 import io.iohk.ethereum.network.p2p.messages.ETH62._ import io.iohk.ethereum.network.p2p.messages.ETH63.NodeData import io.iohk.ethereum.utils.ByteStringUtils import io.iohk.ethereum.utils.Config.SyncConfig import io.iohk.ethereum.utils.FunctorOps._ -import monix.execution.{Scheduler => MonixScheduler} -import mouse.all._ -import akka.actor.typed.scaladsl.adapter._ - -import scala.concurrent.duration._ class BlockFetcher( val peersClient: ClassicActorRef, @@ -79,7 +90,7 @@ class BlockFetcher( Behaviors.same } - override def onMessage(message: FetchCommand): Behavior[FetchCommand] = { + override def onMessage(message: FetchCommand): Behavior[FetchCommand] = message match { case Start(importer, fromBlock) => val sa = context.spawn(subscribeAdapter(context.self), "fetcher-subscribe-adapter") @@ -97,7 +108,6 @@ class BlockFetcher( log.debug("Fetcher subscribe adapter received unhandled message {}", msg) Behaviors.unhandled } - } // scalastyle:off cyclomatic.complexity method.length private def processFetchCommands(state: BlockFetcherState): Behavior[FetchCommand] = @@ -208,7 +218,7 @@ class BlockFetcher( case AdaptedMessageFromEventBus(NewBlockHashes(hashes), _) => log.debug("Received NewBlockHashes numbers {}", hashes.map(_.number).mkString(", ")) val newState = state.validateNewBlockHashes(hashes) match { - case Left(_) => state + case Left(_) => state case Right(validHashes) => state.withPossibleNewTopAt(validHashes.lastOption.map(_.number)) } supervisor ! ProgressProtocol.GotNewBlock(newState.knownTop) diff --git a/src/main/scala/io/iohk/ethereum/blockchain/sync/regular/BlockFetcherState.scala b/src/main/scala/io/iohk/ethereum/blockchain/sync/regular/BlockFetcherState.scala index 127d67e4b2..4a0367abbb 100644 --- a/src/main/scala/io/iohk/ethereum/blockchain/sync/regular/BlockFetcherState.scala +++ b/src/main/scala/io/iohk/ethereum/blockchain/sync/regular/BlockFetcherState.scala @@ -2,21 +2,25 @@ package io.iohk.ethereum.blockchain.sync.regular import akka.actor.ActorRef import akka.util.ByteString + import cats.data.NonEmptyList import cats.implicits._ + +import scala.annotation.tailrec +import scala.collection.immutable.Queue + import io.iohk.ethereum.blockchain.sync.Blacklist.BlacklistReason import io.iohk.ethereum.blockchain.sync.regular.BlockFetcherState._ import io.iohk.ethereum.consensus.validators.BlockValidator -import io.iohk.ethereum.domain.{Block, BlockBody, BlockHeader, HeadersSeq} +import io.iohk.ethereum.domain.Block +import io.iohk.ethereum.domain.BlockBody +import io.iohk.ethereum.domain.BlockHeader +import io.iohk.ethereum.domain.HeadersSeq import io.iohk.ethereum.network.PeerId import io.iohk.ethereum.network.p2p.messages.ETH62.BlockHash -import scala.annotation.tailrec -import scala.collection.immutable.Queue - // scalastyle:off number.of.methods -/** - * State used by the BlockFetcher +/** State used by the BlockFetcher * * @param importer the BlockImporter actor reference * @param readyBlocks @@ -61,8 +65,7 @@ case class BlockFetcherState( .orElse(waitingHeaders.headOption.map(_.number)) .getOrElse(lastBlock) - /** - * Next block number to be fetched, calculated in a way to maintain local queues consistency, + /** Next block number to be fetched, calculated in a way to maintain local queues consistency, * even if `lastBlock` property is much higher - it's more important to have this consistency * here and allow standard rollback/reorganization mechanisms to kick in if we get too far with mining, * therefore `lastBlock` is used here only if blocks and headers queues are empty @@ -75,16 +78,15 @@ case class BlockFetcherState( def takeHashes(amount: Int): Seq[ByteString] = waitingHeaders.take(amount).map(_.hash) def appendHeaders(headers: Seq[BlockHeader]): Either[ValidationErrors, BlockFetcherState] = - validatedHeaders(headers.sortBy(_.number)).map(validHeaders => { + validatedHeaders(headers.sortBy(_.number)).map { validHeaders => val lastNumber = HeadersSeq.lastNumber(validHeaders) withPossibleNewTopAt(lastNumber) .copy( waitingHeaders = waitingHeaders ++ validHeaders ) - }) + } - /** - * Validates received headers consistency and their compatibility with the state + /** Validates received headers consistency and their compatibility with the state */ private def validatedHeaders(headers: Seq[BlockHeader]): Either[ValidationErrors, Seq[BlockHeader]] = if (headers.isEmpty) { @@ -99,12 +101,11 @@ case class BlockFetcherState( ) } - private def checkConsistencyWithReadyBlocks(headers: Seq[BlockHeader]): Boolean = { + private def checkConsistencyWithReadyBlocks(headers: Seq[BlockHeader]): Boolean = (readyBlocks, headers) match { - case (_ :+ last, head +: _) if waitingHeaders.isEmpty => last.header isParentOf head - case _ => true + case (_ :+ last, head +: _) if waitingHeaders.isEmpty => last.header.isParentOf(head) + case _ => true } - } def validateNewBlockHashes(hashes: Seq[BlockHash]): Either[String, Seq[BlockHash]] = hashes @@ -116,8 +117,7 @@ case class BlockFetcherState( } ) - /** - * When bodies are requested, the response don't need to be a complete sub chain, + /** When bodies are requested, the response don't need to be a complete sub chain, * even more, we could receive an empty chain and that will be considered valid. Here we just * validate that the received bodies corresponds to an ordered subset of the requested headers. */ @@ -134,7 +134,7 @@ case class BlockFetcherState( ): Option[Seq[Block]] = (requestedHeaders, respondedBodies) match { case (Seq(), _ +: _) => None - case (_, Seq()) => Some(matchedBlocks) + case (_, Seq()) => Some(matchedBlocks) case (header +: remainingHeaders, body +: remainingBodies) => val doMatch = blockValidator.validateHeaderAndBody(header, body).isRight if (doMatch) @@ -143,8 +143,7 @@ case class BlockFetcherState( bodiesAreOrderedSubsetOfRequested(remainingHeaders, respondedBodies, matchedBlocks) } - /** - * If blocks is empty collection - headers in queue are removed as the cause is: + /** If blocks is empty collection - headers in queue are removed as the cause is: * - the headers are from rejected fork and therefore it won't be possible to resolve blocks for them * - given peer is still syncing (quite unlikely due to preference of peers with best total difficulty * when making a request) @@ -159,8 +158,7 @@ case class BlockFetcherState( state.enqueueRequestedBlock(block, fromPeer) } - /** - * If the requested block is not the next in the line in the waiting headers queue, + /** If the requested block is not the next in the line in the waiting headers queue, * we opt for not adding it in the ready blocks queue. */ def enqueueRequestedBlock(block: Block, fromPeer: PeerId): BlockFetcherState = @@ -189,8 +187,7 @@ case class BlockFetcherState( None } - /** - * Returns all the ready blocks but only if it includes blocks with number: + /** Returns all the ready blocks but only if it includes blocks with number: * - lower = min(from, atLeastWith) * - upper = max(from, atLeastWith) */ @@ -224,7 +221,7 @@ case class BlockFetcherState( def invalidateBlocksFrom(nr: BigInt): (Option[PeerId], BlockFetcherState) = invalidateBlocksFrom(nr, Some(nr)) - def invalidateBlocksFrom(nr: BigInt, toBlacklist: Option[BigInt]): (Option[PeerId], BlockFetcherState) = { + def invalidateBlocksFrom(nr: BigInt, toBlacklist: Option[BigInt]): (Option[PeerId], BlockFetcherState) = ( toBlacklist.flatMap(blockProviders.get), this @@ -234,7 +231,6 @@ case class BlockFetcherState( blockProviders = blockProviders - nr ) ) - } def exists(hash: ByteString): Boolean = existsInReadyBlocks(hash) || existsInWaitingHeaders(hash) @@ -302,8 +298,7 @@ object BlockFetcherState { case object NotFetchingHeaders extends FetchingHeadersState case object AwaitingHeaders extends FetchingHeadersState - /** - * Headers request in progress but will be ignored due to invalidation + /** Headers request in progress but will be ignored due to invalidation * State used to keep track of pending request to prevent multiple requests in parallel */ case object AwaitingHeadersToBeIgnored extends FetchingHeadersState @@ -312,8 +307,7 @@ object BlockFetcherState { case object NotFetchingBodies extends FetchingBodiesState case object AwaitingBodies extends FetchingBodiesState - /** - * Bodies request in progress but will be ignored due to invalidation + /** Bodies request in progress but will be ignored due to invalidation * State used to keep track of pending request to prevent multiple requests in parallel */ case object AwaitingBodiesToBeIgnored extends FetchingBodiesState diff --git a/src/main/scala/io/iohk/ethereum/blockchain/sync/regular/BlockImporter.scala b/src/main/scala/io/iohk/ethereum/blockchain/sync/regular/BlockImporter.scala index 50b874bb80..3879704f7f 100644 --- a/src/main/scala/io/iohk/ethereum/blockchain/sync/regular/BlockImporter.scala +++ b/src/main/scala/io/iohk/ethereum/blockchain/sync/regular/BlockImporter.scala @@ -1,9 +1,21 @@ package io.iohk.ethereum.blockchain.sync.regular +import akka.actor.Actor import akka.actor.Actor.Receive -import akka.actor.{Actor, ActorLogging, ActorRef, NotInfluenceReceiveTimeout, Props, ReceiveTimeout} +import akka.actor.ActorLogging +import akka.actor.ActorRef +import akka.actor.NotInfluenceReceiveTimeout +import akka.actor.Props +import akka.actor.ReceiveTimeout + import cats.data.NonEmptyList import cats.implicits._ + +import monix.eval.Task +import monix.execution.Scheduler + +import scala.concurrent.duration._ + import io.iohk.ethereum.blockchain.sync.Blacklist.BlacklistReason import io.iohk.ethereum.blockchain.sync.regular.BlockBroadcast.BlockToBroadcast import io.iohk.ethereum.blockchain.sync.regular.BlockBroadcasterActor.BroadcastBlocks @@ -15,14 +27,11 @@ import io.iohk.ethereum.mpt.MerklePatriciaTrie.MissingNodeException import io.iohk.ethereum.network.PeerId import io.iohk.ethereum.ommers.OmmersPool.AddOmmers import io.iohk.ethereum.transactions.PendingTransactionsManager -import io.iohk.ethereum.transactions.PendingTransactionsManager.{AddUncheckedTransactions, RemoveTransactions} +import io.iohk.ethereum.transactions.PendingTransactionsManager.AddUncheckedTransactions +import io.iohk.ethereum.transactions.PendingTransactionsManager.RemoveTransactions import io.iohk.ethereum.utils.ByteStringUtils import io.iohk.ethereum.utils.Config.SyncConfig import io.iohk.ethereum.utils.FunctorOps._ -import monix.eval.Task -import monix.execution.Scheduler - -import scala.concurrent.duration._ class BlockImporter( fetcher: ActorRef, @@ -97,7 +106,7 @@ class BlockImporter( if (newBehavior == Running) { self ! PickBlocks } - context become behavior(newState) + context.become(behavior(newState)) case PickBlocks if !state.importing => pickBlocks(state) } @@ -117,7 +126,7 @@ class BlockImporter( log.debug("Starting Regular Sync, current best block is {}", bestKnownBlockNumber) fetcher ! BlockFetcher.Start(self, bestKnownBlockNumber) supervisor ! ProgressProtocol.StartingFrom(bestKnownBlockNumber) - context become running(ImporterState.initial) + context.become(running(ImporterState.initial)) } private def pickBlocks(state: ImporterState): Unit = { @@ -140,7 +149,7 @@ class BlockImporter( } .flatMap { case Right(blocksToImport) => handleBlocksImport(blocksToImport) - case Left(resolvingFrom) => Task.now(ResolvingBranch(resolvingFrom)) + case Left(resolvingFrom) => Task.now(ResolvingBranch(resolvingFrom)) }, blockImportType ) @@ -222,35 +231,31 @@ class BlockImporter( ): ImportFn = { def doLog(entry: ImportMessages.LogEntry): Unit = log.log(entry._1, entry._2) importWith( - { - Task(doLog(importMessages.preImport())) - .flatMap(_ => blockImport.importBlock(block)) - .tap(importMessages.messageForImportResult _ andThen doLog) - .tap { - case BlockImportedToTop(importedBlocksData) => - val (blocks, weights) = importedBlocksData.map(data => (data.block, data.weight)).unzip - broadcastBlocks(blocks, weights) - updateTxPool(importedBlocksData.map(_.block), Seq.empty) - supervisor ! ProgressProtocol.ImportedBlock(block.number, internally) - case ChainReorganised(oldBranch, newBranch, weights) => - updateTxPool(newBranch, oldBranch) - broadcastBlocks(newBranch, weights) - newBranch.lastOption.foreach(block => - supervisor ! ProgressProtocol.ImportedBlock(block.number, internally) - ) - case BlockImportFailedDueToMissingNode(missingNodeException) if syncConfig.redownloadMissingStateNodes => - // state node re-download will be handled when downloading headers - doLog(importMessages.missingStateNode(missingNodeException)) - Running - case BlockImportFailedDueToMissingNode(missingNodeException) => - Task.raiseError(missingNodeException) - case BlockImportFailed(error) if informFetcherOnFail => - fetcher ! BlockFetcher.BlockImportFailed(block.number, BlacklistReason.BlockImportError(error)) - case BlockEnqueued | DuplicateBlock | UnknownParent | BlockImportFailed(_) => () - case result => log.error("Unknown block import result {}", result) - } - .map(_ => Running) - }, + Task(doLog(importMessages.preImport())) + .flatMap(_ => blockImport.importBlock(block)) + .tap((importMessages.messageForImportResult _).andThen(doLog)) + .tap { + case BlockImportedToTop(importedBlocksData) => + val (blocks, weights) = importedBlocksData.map(data => (data.block, data.weight)).unzip + broadcastBlocks(blocks, weights) + updateTxPool(importedBlocksData.map(_.block), Seq.empty) + supervisor ! ProgressProtocol.ImportedBlock(block.number, internally) + case ChainReorganised(oldBranch, newBranch, weights) => + updateTxPool(newBranch, oldBranch) + broadcastBlocks(newBranch, weights) + newBranch.lastOption.foreach(block => supervisor ! ProgressProtocol.ImportedBlock(block.number, internally)) + case BlockImportFailedDueToMissingNode(missingNodeException) if syncConfig.redownloadMissingStateNodes => + // state node re-download will be handled when downloading headers + doLog(importMessages.missingStateNode(missingNodeException)) + Running + case BlockImportFailedDueToMissingNode(missingNodeException) => + Task.raiseError(missingNodeException) + case BlockImportFailed(error) if informFetcherOnFail => + fetcher ! BlockFetcher.BlockImportFailed(block.number, BlacklistReason.BlockImportError(error)) + case BlockEnqueued | DuplicateBlock | UnknownParent | BlockImportFailed(_) => () + case result => log.error("Unknown block import result {}", result) + } + .map(_ => Running), blockImportType ) } @@ -268,7 +273,7 @@ class BlockImporter( private def importWith(importTask: Task[NewBehavior], blockImportType: BlockImportType)( state: ImporterState ): Unit = { - context become running(state.importingBlocks()) + context.become(running(state.importingBlocks())) importTask .map(self ! ImportDone(_, blockImportType)) @@ -309,9 +314,9 @@ class BlockImporter( private def bestKnownBlockNumber: BigInt = blockchain.getBestBlockNumber() private def getBehavior(newBehavior: NewBehavior, blockImportType: BlockImportType): Behavior = newBehavior match { - case Running => running + case Running => running case ResolvingMissingNode(blocksToRetry) => resolvingMissingNode(blocksToRetry, blockImportType) - case ResolvingBranch(from) => resolvingBranch(from) + case ResolvingBranch(from) => resolvingBranch(from) } } diff --git a/src/main/scala/io/iohk/ethereum/blockchain/sync/regular/BodiesFetcher.scala b/src/main/scala/io/iohk/ethereum/blockchain/sync/regular/BodiesFetcher.scala index c56e53b8b9..ae261192ed 100644 --- a/src/main/scala/io/iohk/ethereum/blockchain/sync/regular/BodiesFetcher.scala +++ b/src/main/scala/io/iohk/ethereum/blockchain/sync/regular/BodiesFetcher.scala @@ -1,19 +1,27 @@ package io.iohk.ethereum.blockchain.sync.regular -import akka.actor.typed.{ActorRef, Behavior} -import akka.actor.typed.scaladsl.{AbstractBehavior, ActorContext, Behaviors} +import akka.actor.typed.ActorRef +import akka.actor.typed.Behavior +import akka.actor.typed.scaladsl.AbstractBehavior +import akka.actor.typed.scaladsl.ActorContext +import akka.actor.typed.scaladsl.Behaviors import akka.actor.{ActorRef => ClassicActorRef} import akka.util.ByteString -import io.iohk.ethereum.blockchain.sync.PeersClient.{BestPeer, Request} + +import monix.execution.Scheduler + +import scala.util.Failure +import scala.util.Success + +import io.iohk.ethereum.blockchain.sync.PeersClient.BestPeer +import io.iohk.ethereum.blockchain.sync.PeersClient.Request import io.iohk.ethereum.blockchain.sync.regular.BlockFetcher.FetchCommand import io.iohk.ethereum.blockchain.sync.regular.BodiesFetcher.BodiesFetcherCommand import io.iohk.ethereum.network.Peer import io.iohk.ethereum.network.p2p.Message -import io.iohk.ethereum.network.p2p.messages.ETH62.{BlockBodies, GetBlockBodies} +import io.iohk.ethereum.network.p2p.messages.ETH62.BlockBodies +import io.iohk.ethereum.network.p2p.messages.ETH62.GetBlockBodies import io.iohk.ethereum.utils.Config.SyncConfig -import monix.execution.Scheduler - -import scala.util.{Failure, Success} class BodiesFetcher( val peersClient: ClassicActorRef, @@ -30,7 +38,7 @@ class BodiesFetcher( override def makeAdaptedMessage[T <: Message](peer: Peer, msg: T): BodiesFetcherCommand = AdaptedMessage(peer, msg) - override def onMessage(message: BodiesFetcherCommand): Behavior[BodiesFetcherCommand] = { + override def onMessage(message: BodiesFetcherCommand): Behavior[BodiesFetcherCommand] = message match { case FetchBodies(hashes) => log.debug("Start fetching bodies") @@ -45,13 +53,12 @@ class BodiesFetcher( Behaviors.same case _ => Behaviors.unhandled } - } private def requestBodies(hashes: Seq[ByteString]): Unit = { val resp = makeRequest(Request.create(GetBlockBodies(hashes), BestPeer), BodiesFetcher.RetryBodiesRequest) context.pipeToSelf(resp.runToFuture) { case Success(res) => res - case Failure(_) => BodiesFetcher.RetryBodiesRequest + case Failure(_) => BodiesFetcher.RetryBodiesRequest } } } @@ -68,5 +75,5 @@ object BodiesFetcher { sealed trait BodiesFetcherCommand final case class FetchBodies(hashes: Seq[ByteString]) extends BodiesFetcherCommand final case object RetryBodiesRequest extends BodiesFetcherCommand - private final case class AdaptedMessage[T <: Message](peer: Peer, msg: T) extends BodiesFetcherCommand + final private case class AdaptedMessage[T <: Message](peer: Peer, msg: T) extends BodiesFetcherCommand } diff --git a/src/main/scala/io/iohk/ethereum/blockchain/sync/regular/FetchRequest.scala b/src/main/scala/io/iohk/ethereum/blockchain/sync/regular/FetchRequest.scala index 596c32445c..f38b7e4d0d 100644 --- a/src/main/scala/io/iohk/ethereum/blockchain/sync/regular/FetchRequest.scala +++ b/src/main/scala/io/iohk/ethereum/blockchain/sync/regular/FetchRequest.scala @@ -1,20 +1,26 @@ package io.iohk.ethereum.blockchain.sync.regular import akka.actor.ActorRef -import io.iohk.ethereum.blockchain.sync.PeersClient -import io.iohk.ethereum.blockchain.sync.PeersClient.{BlacklistPeer, NoSuitablePeer, Request, RequestFailed} -import io.iohk.ethereum.network.Peer -import io.iohk.ethereum.network.p2p.Message -import io.iohk.ethereum.utils.Config.SyncConfig -import monix.eval.Task -import org.slf4j.Logger import akka.pattern.ask import akka.util.Timeout -import io.iohk.ethereum.utils.FunctorOps._ + +import monix.eval.Task import scala.concurrent.duration._ import scala.util.Failure +import org.slf4j.Logger + +import io.iohk.ethereum.blockchain.sync.PeersClient +import io.iohk.ethereum.blockchain.sync.PeersClient.BlacklistPeer +import io.iohk.ethereum.blockchain.sync.PeersClient.NoSuitablePeer +import io.iohk.ethereum.blockchain.sync.PeersClient.Request +import io.iohk.ethereum.blockchain.sync.PeersClient.RequestFailed +import io.iohk.ethereum.network.Peer +import io.iohk.ethereum.network.p2p.Message +import io.iohk.ethereum.utils.Config.SyncConfig +import io.iohk.ethereum.utils.FunctorOps._ + trait FetchRequest[A] { val peersClient: ActorRef val syncConfig: SyncConfig @@ -36,10 +42,10 @@ trait FetchRequest[A] { def blacklistPeerOnFailedRequest(msg: Any): Unit = msg match { case RequestFailed(peer, reason) => peersClient ! BlacklistPeer(peer.id, reason) - case _ => () + case _ => () } - def handleRequestResult(fallback: A)(msg: Any): Task[A] = { + def handleRequestResult(fallback: A)(msg: Any): Task[A] = msg match { case failed: RequestFailed => log.debug("Request failed due to {}", failed) @@ -52,5 +58,4 @@ trait FetchRequest[A] { case PeersClient.Response(peer, msg) => Task.now(makeAdaptedMessage(peer, msg)) } - } } diff --git a/src/main/scala/io/iohk/ethereum/blockchain/sync/regular/HeadersFetcher.scala b/src/main/scala/io/iohk/ethereum/blockchain/sync/regular/HeadersFetcher.scala index 6b12072be2..f7a864309f 100644 --- a/src/main/scala/io/iohk/ethereum/blockchain/sync/regular/HeadersFetcher.scala +++ b/src/main/scala/io/iohk/ethereum/blockchain/sync/regular/HeadersFetcher.scala @@ -1,19 +1,28 @@ package io.iohk.ethereum.blockchain.sync.regular -import akka.actor.typed.{ActorRef, Behavior} -import akka.actor.typed.scaladsl.{AbstractBehavior, ActorContext, Behaviors} +import akka.actor.typed.ActorRef +import akka.actor.typed.Behavior +import akka.actor.typed.scaladsl.AbstractBehavior +import akka.actor.typed.scaladsl.ActorContext +import akka.actor.typed.scaladsl.Behaviors import akka.actor.{ActorRef => ClassicActorRef} -import io.iohk.ethereum.blockchain.sync.PeersClient.{BestPeer, Request} + +import monix.eval.Task +import monix.execution.Scheduler + +import scala.util.Failure +import scala.util.Success + +import org.slf4j.Logger + +import io.iohk.ethereum.blockchain.sync.PeersClient.BestPeer +import io.iohk.ethereum.blockchain.sync.PeersClient.Request import io.iohk.ethereum.blockchain.sync.regular.BlockFetcher.FetchCommand import io.iohk.ethereum.blockchain.sync.regular.HeadersFetcher.HeadersFetcherCommand import io.iohk.ethereum.network.Peer import io.iohk.ethereum.network.p2p.Message -import io.iohk.ethereum.network.p2p.messages.ETH62.{BlockHeaders, GetBlockHeaders} +import io.iohk.ethereum.network.p2p.messages.ETH62.BlockHeaders +import io.iohk.ethereum.network.p2p.messages.ETH62.GetBlockHeaders import io.iohk.ethereum.utils.Config.SyncConfig -import monix.eval.Task -import monix.execution.Scheduler -import org.slf4j.Logger - -import scala.util.{Failure, Success} class HeadersFetcher( val peersClient: ClassicActorRef, @@ -60,7 +69,7 @@ class HeadersFetcher( context.pipeToSelf(resp.runToFuture) { case Success(res) => res - case Failure(_) => HeadersFetcher.RetryHeadersRequest + case Failure(_) => HeadersFetcher.RetryHeadersRequest } } } @@ -77,5 +86,5 @@ object HeadersFetcher { sealed trait HeadersFetcherCommand final case class FetchHeaders(blockNumber: BigInt, amount: BigInt) extends HeadersFetcherCommand final case object RetryHeadersRequest extends HeadersFetcherCommand - private final case class AdaptedMessage[T <: Message](peer: Peer, msg: T) extends HeadersFetcherCommand + final private case class AdaptedMessage[T <: Message](peer: Peer, msg: T) extends HeadersFetcherCommand } diff --git a/src/main/scala/io/iohk/ethereum/blockchain/sync/regular/ImportMessages.scala b/src/main/scala/io/iohk/ethereum/blockchain/sync/regular/ImportMessages.scala index 31d3b67018..4d2b2354b4 100644 --- a/src/main/scala/io/iohk/ethereum/blockchain/sync/regular/ImportMessages.scala +++ b/src/main/scala/io/iohk/ethereum/blockchain/sync/regular/ImportMessages.scala @@ -2,6 +2,7 @@ package io.iohk.ethereum.blockchain.sync.regular import akka.event.Logging._ import akka.util.ByteString + import io.iohk.ethereum.domain.Block import io.iohk.ethereum.ledger._ import io.iohk.ethereum.mpt.MerklePatriciaTrie.MissingNodeException @@ -24,12 +25,12 @@ sealed abstract class ImportMessages(block: Block) { def messageForImportResult(importResult: BlockImportResult): LogEntry = importResult match { - case BlockImportedToTop(_) => importedToTheTop() - case BlockEnqueued => enqueued() - case DuplicateBlock => duplicated() - case UnknownParent => orphaned() - case ChainReorganised(_, newBranch, _) => reorganisedChain(newBranch) - case BlockImportFailed(error) => importFailed(error) + case BlockImportedToTop(_) => importedToTheTop() + case BlockEnqueued => enqueued() + case DuplicateBlock => duplicated() + case UnknownParent => orphaned() + case ChainReorganised(_, newBranch, _) => reorganisedChain(newBranch) + case BlockImportFailed(error) => importFailed(error) case BlockImportFailedDueToMissingNode(reason) => missingStateNode(reason) } } diff --git a/src/main/scala/io/iohk/ethereum/blockchain/sync/regular/RegularSync.scala b/src/main/scala/io/iohk/ethereum/blockchain/sync/regular/RegularSync.scala index 7b69599538..aaaa946f96 100644 --- a/src/main/scala/io/iohk/ethereum/blockchain/sync/regular/RegularSync.scala +++ b/src/main/scala/io/iohk/ethereum/blockchain/sync/regular/RegularSync.scala @@ -1,19 +1,31 @@ package io.iohk.ethereum.blockchain.sync.regular -import akka.actor.{Actor, ActorLogging, ActorRef, AllForOneStrategy, Cancellable, Props, Scheduler, SupervisorStrategy} +import akka.actor.Actor +import akka.actor.ActorLogging +import akka.actor.ActorRef +import akka.actor.AllForOneStrategy +import akka.actor.Cancellable +import akka.actor.Props +import akka.actor.Scheduler +import akka.actor.SupervisorStrategy +import akka.actor.typed.scaladsl.adapter._ import akka.actor.typed.{ActorRef => TypedActorRef} -import io.iohk.ethereum.blockchain.sync.{Blacklist, SyncProtocol} + +import io.iohk.ethereum.blockchain.sync.Blacklist +import io.iohk.ethereum.blockchain.sync.SyncProtocol import io.iohk.ethereum.blockchain.sync.SyncProtocol.Status import io.iohk.ethereum.blockchain.sync.SyncProtocol.Status.Progress -import io.iohk.ethereum.blockchain.sync.regular.RegularSync.{NewCheckpoint, ProgressProtocol, ProgressState} +import io.iohk.ethereum.blockchain.sync.regular.BlockFetcher.InternalLastBlockImport +import io.iohk.ethereum.blockchain.sync.regular.RegularSync.NewCheckpoint +import io.iohk.ethereum.blockchain.sync.regular.RegularSync.ProgressProtocol +import io.iohk.ethereum.blockchain.sync.regular.RegularSync.ProgressState import io.iohk.ethereum.consensus.validators.BlockValidator -import io.iohk.ethereum.domain.{Block, Blockchain} +import io.iohk.ethereum.domain.Block +import io.iohk.ethereum.domain.Blockchain +import io.iohk.ethereum.ledger.BlockImport +import io.iohk.ethereum.ledger.BranchResolution import io.iohk.ethereum.utils.ByteStringUtils import io.iohk.ethereum.utils.Config.SyncConfig -import akka.actor.typed.scaladsl.adapter._ -import io.iohk.ethereum.blockchain.sync.regular.BlockFetcher.InternalLastBlockImport -import io.iohk.ethereum.ledger.BranchResolution -import io.iohk.ethereum.ledger.BlockImport class RegularSync( peersClient: ActorRef, @@ -89,21 +101,21 @@ class RegularSync( case ProgressProtocol.StartedFetching => val newState = progressState.copy(startedFetching = true) - context become running(newState) + context.become(running(newState)) case ProgressProtocol.StartingFrom(blockNumber) => val newState = progressState.copy(initialBlock = blockNumber, currentBlock = blockNumber) - context become running(newState) + context.become(running(newState)) case ProgressProtocol.GotNewBlock(blockNumber) => log.info(s"Got information about new block [number = $blockNumber]") val newState = progressState.copy(bestKnownNetworkBlock = blockNumber) - context become running(newState) + context.become(running(newState)) case ProgressProtocol.ImportedBlock(blockNumber, internally) => log.info(s"Imported new block [number = $blockNumber, internally = $internally]") val newState = progressState.copy(currentBlock = blockNumber) if (internally) { fetcher ! InternalLastBlockImport(blockNumber) } - context become running(newState) + context.become(running(newState)) } override def supervisorStrategy: SupervisorStrategy = AllForOneStrategy()(SupervisorStrategy.defaultDecider) @@ -154,7 +166,7 @@ object RegularSync { currentBlock: BigInt, bestKnownNetworkBlock: BigInt ) { - def toStatus: SyncProtocol.Status = { + def toStatus: SyncProtocol.Status = if (startedFetching && bestKnownNetworkBlock != 0 && currentBlock < bestKnownNetworkBlock) { Status.Syncing(initialBlock, Progress(currentBlock, bestKnownNetworkBlock), None) } else if (startedFetching && currentBlock >= bestKnownNetworkBlock) { @@ -162,7 +174,6 @@ object RegularSync { } else { Status.NotSyncing } - } } sealed trait ProgressProtocol object ProgressProtocol { diff --git a/src/main/scala/io/iohk/ethereum/blockchain/sync/regular/RegularSyncMetrics.scala b/src/main/scala/io/iohk/ethereum/blockchain/sync/regular/RegularSyncMetrics.scala index 6997ef87ba..947a82bb11 100644 --- a/src/main/scala/io/iohk/ethereum/blockchain/sync/regular/RegularSyncMetrics.scala +++ b/src/main/scala/io/iohk/ethereum/blockchain/sync/regular/RegularSyncMetrics.scala @@ -1,17 +1,21 @@ package io.iohk.ethereum.blockchain.sync.regular -import io.iohk.ethereum.metrics.MetricsContainer +import scala.concurrent.duration.NANOSECONDS + +import io.micrometer.core.instrument.Timer -import scala.concurrent.duration.{MILLISECONDS, NANOSECONDS} +import io.iohk.ethereum.metrics.MetricsContainer object RegularSyncMetrics extends MetricsContainer { - private final val blockPropagationTimer = "regularsync.blocks.propagation.timer" + final private val blockPropagationTimer = "regularsync.blocks.propagation.timer" - final val MinedBlockPropagationTimer = metrics.timer(blockPropagationTimer, "blocktype", "MinedBlockPropagation") - final val CheckpointBlockPropagationTimer = + final val MinedBlockPropagationTimer: Timer = + metrics.timer(blockPropagationTimer, "blocktype", "MinedBlockPropagation") + final val CheckpointBlockPropagationTimer: Timer = metrics.timer(blockPropagationTimer, "blocktype", "CheckpointBlockPropagation") - final val NewBlockPropagationTimer = metrics.timer(blockPropagationTimer, "blocktype", "NewBlockPropagation") - final val DefaultBlockPropagationTimer = metrics.timer(blockPropagationTimer, "blocktype", "DefaultBlockPropagation") + final val NewBlockPropagationTimer: Timer = metrics.timer(blockPropagationTimer, "blocktype", "NewBlockPropagation") + final val DefaultBlockPropagationTimer: Timer = + metrics.timer(blockPropagationTimer, "blocktype", "DefaultBlockPropagation") def recordMinedBlockPropagationTimer(nanos: Long): Unit = MinedBlockPropagationTimer.record(nanos, NANOSECONDS) def recordImportCheckpointPropagationTimer(nanos: Long): Unit = diff --git a/src/main/scala/io/iohk/ethereum/blockchain/sync/regular/StateNodeFetcher.scala b/src/main/scala/io/iohk/ethereum/blockchain/sync/regular/StateNodeFetcher.scala index 78186cad94..7b4a65e6b6 100644 --- a/src/main/scala/io/iohk/ethereum/blockchain/sync/regular/StateNodeFetcher.scala +++ b/src/main/scala/io/iohk/ethereum/blockchain/sync/regular/StateNodeFetcher.scala @@ -1,21 +1,30 @@ package io.iohk.ethereum.blockchain.sync.regular -import akka.actor.typed.scaladsl.{AbstractBehavior, ActorContext, Behaviors} -import akka.actor.typed.{ActorRef, Behavior} +import akka.actor.typed.ActorRef +import akka.actor.typed.Behavior +import akka.actor.typed.scaladsl.AbstractBehavior +import akka.actor.typed.scaladsl.ActorContext +import akka.actor.typed.scaladsl.Behaviors import akka.actor.{ActorRef => ClassicActorRef} import akka.util.ByteString + +import cats.syntax.either._ + +import monix.execution.Scheduler + +import scala.util.Failure +import scala.util.Success + +import io.iohk.ethereum.blockchain.sync.Blacklist.BlacklistReason import io.iohk.ethereum.blockchain.sync.PeersClient._ -import io.iohk.ethereum.blockchain.sync.regular.BlockFetcher.{FetchCommand, FetchedStateNode} +import io.iohk.ethereum.blockchain.sync.regular.BlockFetcher.FetchCommand +import io.iohk.ethereum.blockchain.sync.regular.BlockFetcher.FetchedStateNode import io.iohk.ethereum.crypto.kec256 import io.iohk.ethereum.network.Peer import io.iohk.ethereum.network.p2p.Message -import io.iohk.ethereum.network.p2p.messages.ETH63.{GetNodeData, NodeData} +import io.iohk.ethereum.network.p2p.messages.ETH63.GetNodeData +import io.iohk.ethereum.network.p2p.messages.ETH63.NodeData import io.iohk.ethereum.utils.Config.SyncConfig -import cats.syntax.either._ -import io.iohk.ethereum.blockchain.sync.Blacklist.BlacklistReason -import monix.execution.Scheduler - -import scala.util.{Failure, Success} class StateNodeFetcher( val peersClient: ClassicActorRef, @@ -34,7 +43,7 @@ class StateNodeFetcher( private var requester: Option[StateNodeRequester] = None - override def onMessage(message: StateNodeFetcherCommand): Behavior[StateNodeFetcherCommand] = { + override def onMessage(message: StateNodeFetcherCommand): Behavior[StateNodeFetcherCommand] = message match { case StateNodeFetcher.FetchStateNode(hash, sender) => log.debug("Start fetching state node") @@ -45,7 +54,7 @@ class StateNodeFetcher( log.debug("Received state node response from peer {}", peer) requester - .collect(stateNodeRequester => { + .collect { stateNodeRequester => val validatedNode = values .asRight[BlacklistReason] .ensure(BlacklistReason.EmptyStateNodeResponse)(_.nonEmpty) @@ -62,7 +71,7 @@ class StateNodeFetcher( requester = None Behaviors.same[StateNodeFetcherCommand] } - }) + } .getOrElse(Behaviors.same) case StateNodeFetcher.RetryStateNodeRequest if requester.isDefined => @@ -74,13 +83,12 @@ class StateNodeFetcher( Behaviors.same case _ => Behaviors.unhandled } - } private def requestStateNode(hash: ByteString): Unit = { val resp = makeRequest(Request.create(GetNodeData(List(hash)), BestPeer), StateNodeFetcher.RetryStateNodeRequest) context.pipeToSelf(resp.runToFuture) { case Success(res) => res - case Failure(_) => StateNodeFetcher.RetryStateNodeRequest + case Failure(_) => StateNodeFetcher.RetryStateNodeRequest } } } @@ -97,7 +105,7 @@ object StateNodeFetcher { sealed trait StateNodeFetcherCommand final case class FetchStateNode(hash: ByteString, originalSender: ClassicActorRef) extends StateNodeFetcherCommand final case object RetryStateNodeRequest extends StateNodeFetcherCommand - private final case class AdaptedMessage[T <: Message](peer: Peer, msg: T) extends StateNodeFetcherCommand + final private case class AdaptedMessage[T <: Message](peer: Peer, msg: T) extends StateNodeFetcherCommand final case class StateNodeRequester(hash: ByteString, replyTo: ClassicActorRef) } diff --git a/src/main/scala/io/iohk/ethereum/cli/CliCommands.scala b/src/main/scala/io/iohk/ethereum/cli/CliCommands.scala index a0cea9fa10..3d92696b89 100644 --- a/src/main/scala/io/iohk/ethereum/cli/CliCommands.scala +++ b/src/main/scala/io/iohk/ethereum/cli/CliCommands.scala @@ -1,15 +1,20 @@ package io.iohk.ethereum.cli +import java.security.SecureRandom + import cats.implicits._ -import com.monovore.decline.{Command, Opts} + +import com.monovore.decline.Command +import com.monovore.decline.Opts +import org.bouncycastle.util.encoders.Hex + import io.iohk.ethereum.crypto import io.iohk.ethereum.crypto._ import io.iohk.ethereum.domain.Address -import io.iohk.ethereum.keystore.{EncryptedKey, EncryptedKeyJsonCodec} -import io.iohk.ethereum.utils.ByteStringUtils -import java.security.SecureRandom +import io.iohk.ethereum.keystore.EncryptedKey +import io.iohk.ethereum.keystore.EncryptedKeyJsonCodec import io.iohk.ethereum.security.SecureRandomBuilder -import org.bouncycastle.util.encoders.Hex +import io.iohk.ethereum.utils.ByteStringUtils object CliCommands extends SecureRandomBuilder { @@ -44,8 +49,7 @@ object CliCommands extends SecureRandomBuilder { keyNumberOpts.map { numOfKeys => val keyPairs = for (_ <- 1 to numOfKeys) yield newRandomKeyPairAsStrings(secureRandom) - /** - * The key pairs will be printed in the format: + /** The key pairs will be printed in the format: * priv-key-hex (32 bytes) * pub-key-hex (64 bytes) */ diff --git a/src/main/scala/io/iohk/ethereum/cli/CliLauncher.scala b/src/main/scala/io/iohk/ethereum/cli/CliLauncher.scala index 29a595f856..6a7501830d 100644 --- a/src/main/scala/io/iohk/ethereum/cli/CliLauncher.scala +++ b/src/main/scala/io/iohk/ethereum/cli/CliLauncher.scala @@ -1,16 +1,16 @@ package io.iohk.ethereum.cli -import com.monovore.decline._ - import scala.collection.immutable.ArraySeq +import com.monovore.decline._ + //scalastyle:off object CliLauncher extends App { - private val arguments: Seq[String] = PlatformApp.ambientArgs getOrElse ArraySeq.unsafeWrapArray(args) + private val arguments: Seq[String] = PlatformApp.ambientArgs.getOrElse(ArraySeq.unsafeWrapArray(args)) CliCommands.api.map(println).parse(arguments, sys.env) match { case Left(help) => System.err.println(help) - case Right(_) => () + case Right(_) => () } } diff --git a/src/main/scala/io/iohk/ethereum/common/SimpleMap.scala b/src/main/scala/io/iohk/ethereum/common/SimpleMap.scala index 810fc15320..9e923d0f17 100644 --- a/src/main/scala/io/iohk/ethereum/common/SimpleMap.scala +++ b/src/main/scala/io/iohk/ethereum/common/SimpleMap.scala @@ -1,20 +1,17 @@ package io.iohk.ethereum.common -/** - * Interface to represent a key-value structure +/** Interface to represent a key-value structure */ trait SimpleMap[K, V, T <: SimpleMap[K, V, T]] { - /** - * This function obtains the value asociated with the key passed, if there exists one. + /** This function obtains the value asociated with the key passed, if there exists one. * * @param key * @return Option object with value if there exists one. */ def get(key: K): Option[V] - /** - * This function inserts a (key-value) pair into the trie. If the key is already asociated with another value it is updated. + /** This function inserts a (key-value) pair into the trie. If the key is already asociated with another value it is updated. * * @param key * @param value @@ -22,32 +19,28 @@ trait SimpleMap[K, V, T <: SimpleMap[K, V, T]] { */ def put(key: K, value: V): T = update(Nil, Seq(key -> value)) - /** - * This function inserts a (key-value) pair into the trie. If the key is already asociated with another value it is updated. + /** This function inserts a (key-value) pair into the trie. If the key is already asociated with another value it is updated. * * @param kv to insert * @return New trie with the (key-value) pair inserted. */ def +(kv: (K, V)): T = put(kv._1, kv._2) - /** - * This function deletes a (key-value) pair from the trie. If no (key-value) pair exists with the passed trie then there's no effect on it. + /** This function deletes a (key-value) pair from the trie. If no (key-value) pair exists with the passed trie then there's no effect on it. * * @param key * @return New trie with the (key-value) pair associated with the key passed deleted from the trie. */ def remove(key: K): T = update(Seq(key), Nil) - /** - * This function deletes a (key-value) pair from the trie. If no (key-value) pair exists with the passed trie then there's no effect on it. + /** This function deletes a (key-value) pair from the trie. If no (key-value) pair exists with the passed trie then there's no effect on it. * * @param key * @return New trie with the (key-value) pair associated with the key passed deleted from the trie. */ def -(key: K): T = remove(key) - /** - * This function updates the KeyValueStore by deleting, updating and inserting new (key-value) pairs. + /** This function updates the KeyValueStore by deleting, updating and inserting new (key-value) pairs. * * @param toRemove which includes all the keys to be removed from the KeyValueStore. * @param toUpsert which includes all the (key-value) pairs to be inserted into the KeyValueStore. diff --git a/src/main/scala/io/iohk/ethereum/consensus/Consensus.scala b/src/main/scala/io/iohk/ethereum/consensus/Consensus.scala index ddba5bde6d..27cc47913e 100644 --- a/src/main/scala/io/iohk/ethereum/consensus/Consensus.scala +++ b/src/main/scala/io/iohk/ethereum/consensus/Consensus.scala @@ -1,24 +1,25 @@ package io.iohk.ethereum.consensus -import io.iohk.ethereum.consensus.blocks.{BlockGenerator, TestBlockGenerator} +import monix.eval.Task + +import io.iohk.ethereum.consensus.blocks.BlockGenerator +import io.iohk.ethereum.consensus.blocks.TestBlockGenerator import io.iohk.ethereum.consensus.difficulty.DifficultyCalculator import io.iohk.ethereum.consensus.pow.miners.MinerProtocol -import io.iohk.ethereum.consensus.pow.miners.MockedMiner.{MockedMinerProtocol, MockedMinerResponse} +import io.iohk.ethereum.consensus.pow.miners.MockedMiner.MockedMinerProtocol +import io.iohk.ethereum.consensus.pow.miners.MockedMiner.MockedMinerResponse import io.iohk.ethereum.consensus.validators.Validators import io.iohk.ethereum.ledger.BlockPreparator import io.iohk.ethereum.ledger.VMImpl import io.iohk.ethereum.nodebuilder.Node -import monix.eval.Task -/** - * Abstraction for a consensus protocol implementation. +/** Abstraction for a consensus protocol implementation. * * @see [[io.iohk.ethereum.consensus.Protocol Protocol]] */ trait Consensus { - /** - * The type of configuration [[io.iohk.ethereum.consensus.FullConsensusConfig#specific specific]] + /** The type of configuration [[io.iohk.ethereum.consensus.FullConsensusConfig#specific specific]] * to this consensus protocol implementation. */ type Config <: AnyRef /*Product*/ @@ -27,53 +28,44 @@ trait Consensus { def config: FullConsensusConfig[Config] - /** - * This is the VM used while preparing and generating blocks. + /** This is the VM used while preparing and generating blocks. */ def vm: VMImpl - /** - * Provides the set of validators specific to this consensus protocol. + /** Provides the set of validators specific to this consensus protocol. */ def validators: Validators - /** - * This is used by the [[io.iohk.ethereum.consensus.Consensus#blockGenerator blockGenerator]]. + /** This is used by the [[io.iohk.ethereum.consensus.Consensus#blockGenerator blockGenerator]]. */ def blockPreparator: BlockPreparator - /** - * Returns the [[io.iohk.ethereum.consensus.blocks.BlockGenerator BlockGenerator]] + /** Returns the [[io.iohk.ethereum.consensus.blocks.BlockGenerator BlockGenerator]] * this consensus protocol uses. */ def blockGenerator: BlockGenerator def difficultyCalculator: DifficultyCalculator - /** - * Starts the consensus protocol on the current `node`. + /** Starts the consensus protocol on the current `node`. */ def startProtocol(node: Node): Unit - /** - * Stops the consensus protocol on the current node. + /** Stops the consensus protocol on the current node. * This is called internally when the node terminates. */ def stopProtocol(): Unit - /** - * Sends msg to the internal miner and waits for the response + /** Sends msg to the internal miner and waits for the response */ def askMiner(msg: MockedMinerProtocol): Task[MockedMinerResponse] - /** - * Sends msg to the internal miner + /** Sends msg to the internal miner */ def sendMiner(msg: MinerProtocol): Unit } -/** - * Internal API, used for testing. +/** Internal API, used for testing. * * This is a [[Consensus]] API for the needs of the test suites. * It gives a lot of flexibility overriding parts of a consensus' behavior diff --git a/src/main/scala/io/iohk/ethereum/consensus/ConsensusBuilder.scala b/src/main/scala/io/iohk/ethereum/consensus/ConsensusBuilder.scala index c91380daa3..2298d4d7fc 100644 --- a/src/main/scala/io/iohk/ethereum/consensus/ConsensusBuilder.scala +++ b/src/main/scala/io/iohk/ethereum/consensus/ConsensusBuilder.scala @@ -1,17 +1,18 @@ package io.iohk.ethereum.consensus -import io.iohk.ethereum.consensus.Protocol.{NoAdditionalPoWData, RestrictedPoWMinerData} +import io.iohk.ethereum.consensus.Protocol.NoAdditionalPoWData +import io.iohk.ethereum.consensus.Protocol.RestrictedPoWMinerData import io.iohk.ethereum.consensus.pow.PoWConsensus import io.iohk.ethereum.consensus.pow.validators.ValidatorsExecutor import io.iohk.ethereum.nodebuilder._ -import io.iohk.ethereum.utils.{Config, Logger} +import io.iohk.ethereum.utils.Config +import io.iohk.ethereum.utils.Logger trait ConsensusBuilder { def consensus: Consensus } -/** - * A consensus builder is responsible to instantiate the consensus protocol. +/** A consensus builder is responsible to instantiate the consensus protocol. * This is done dynamically when Mantis boots, based on its configuration. * * @see [[io.iohk.ethereum.consensus.Consensus Consensus]], @@ -42,7 +43,7 @@ trait StdConsensusBuilder extends ConsensusBuilder { val additionalPoWData = consensusConfig.protocol match { case Protocol.PoW | Protocol.MockedPow => NoAdditionalPoWData - case Protocol.RestrictedPoW => RestrictedPoWMinerData(nodeKey) + case Protocol.RestrictedPoW => RestrictedPoWMinerData(nodeKey) } val consensus = PoWConsensus( diff --git a/src/main/scala/io/iohk/ethereum/consensus/ConsensusConfig.scala b/src/main/scala/io/iohk/ethereum/consensus/ConsensusConfig.scala index 2a527b1a2f..29f541adda 100644 --- a/src/main/scala/io/iohk/ethereum/consensus/ConsensusConfig.scala +++ b/src/main/scala/io/iohk/ethereum/consensus/ConsensusConfig.scala @@ -1,13 +1,14 @@ package io.iohk.ethereum.consensus import akka.util.ByteString + import com.typesafe.config.{Config => TypesafeConfig} + import io.iohk.ethereum.consensus.validators.BlockHeaderValidator import io.iohk.ethereum.domain.Address import io.iohk.ethereum.utils.Logger -/** - * Provides generic consensus configuration. Each consensus protocol implementation +/** Provides generic consensus configuration. Each consensus protocol implementation * will use its own specific configuration as well. * * @param protocol Designates the consensus protocol. @@ -32,13 +33,13 @@ object ConsensusConfig extends Logger { final val MiningEnabled = "mining-enabled" } - final val AllowedProtocols = Set( + final val AllowedProtocols: Set[String] = Set( Protocol.Names.PoW, Protocol.Names.MockedPow, Protocol.Names.RestrictedPoW ) - final val AllowedProtocolsError = (s: String) => + final val AllowedProtocolsError: String => String = (s: String) => Keys.Consensus + " is configured as '" + s + "'" + " but it should be one of " + diff --git a/src/main/scala/io/iohk/ethereum/consensus/ConsensusMetrics.scala b/src/main/scala/io/iohk/ethereum/consensus/ConsensusMetrics.scala index 47b3ac2ab3..c9d9253663 100644 --- a/src/main/scala/io/iohk/ethereum/consensus/ConsensusMetrics.scala +++ b/src/main/scala/io/iohk/ethereum/consensus/ConsensusMetrics.scala @@ -1,13 +1,15 @@ package io.iohk.ethereum.consensus +import io.micrometer.core.instrument.Timer + import io.iohk.ethereum.metrics.MetricsContainer object ConsensusMetrics extends MetricsContainer { - private final val blockGenTimer = "consensus.blocks.generate.timer" - final val PoWBlockGeneratorTiming = metrics.timer(blockGenTimer, "class", "PoWBlockGenerator") - final val RestrictedPoWBlockGeneratorTiming = + final private val blockGenTimer = "consensus.blocks.generate.timer" + final val PoWBlockGeneratorTiming: Timer = metrics.timer(blockGenTimer, "class", "PoWBlockGenerator") + final val RestrictedPoWBlockGeneratorTiming: Timer = metrics.timer(blockGenTimer, "class", "RestrictedPoWBlockGenerator") - final val NoOmmersBlockGeneratorTiming = metrics.timer(blockGenTimer, "class", "NoOmmersBlockGenerator") + final val NoOmmersBlockGeneratorTiming: Timer = metrics.timer(blockGenTimer, "class", "NoOmmersBlockGenerator") - final val MinedBlockEvaluationTimer = metrics.timer("consensus.minedblocks.evaluation.timer") + final val MinedBlockEvaluationTimer: Timer = metrics.timer("consensus.minedblocks.evaluation.timer") } diff --git a/src/main/scala/io/iohk/ethereum/consensus/Protocol.scala b/src/main/scala/io/iohk/ethereum/consensus/Protocol.scala index 16ce5d714e..19dd2ac29d 100644 --- a/src/main/scala/io/iohk/ethereum/consensus/Protocol.scala +++ b/src/main/scala/io/iohk/ethereum/consensus/Protocol.scala @@ -2,14 +2,12 @@ package io.iohk.ethereum.consensus import org.bouncycastle.crypto.AsymmetricCipherKeyPair -/** - * Enumerates the known consensus protocols that Mantis can use. +/** Enumerates the known consensus protocols that Mantis can use. * For the respective implementations, see [[io.iohk.ethereum.consensus.Consensus Consensus]]. */ sealed trait Protocol { - /** - * We use this `name` to specify the protocol in configuration. + /** We use this `name` to specify the protocol in configuration. * * @see [[io.iohk.ethereum.consensus.Protocol.Names]] */ @@ -34,8 +32,7 @@ object Protocol { /** The standard Ethereum PoW consensus protocol. */ case object PoW extends ProtocolImpl(Names.PoW) - /** - * Non-standard ethereum PoW consensus protocol, which allows restricting list of possible miners. + /** Non-standard ethereum PoW consensus protocol, which allows restricting list of possible miners. * Main differences from basic PoW consensus protocol: * - Each miner, signs header data before mining i.e prepared header without mixHash and Nonce, and appends this * signature to blockheader.extraData field. Only such prepared header is mined upon. @@ -50,13 +47,13 @@ object Protocol { case object RestrictedPoW extends ProtocolImpl(Names.RestrictedPoW) /** All the known protocols. If a protocol is not put here, then it cannot be used to run Mantis. */ - final val KnownProtocols = Set( + final val KnownProtocols: Set[ProtocolImpl] = Set( PoW, MockedPow, RestrictedPoW ) - final val KnownProtocolNames = KnownProtocols.map(_.name) + final val KnownProtocolNames: Set[String] = KnownProtocols.map(_.name) def find(name: String): Option[Protocol] = KnownProtocols.find(_.name == name) diff --git a/src/main/scala/io/iohk/ethereum/consensus/TestConsensusBuilder.scala b/src/main/scala/io/iohk/ethereum/consensus/TestConsensusBuilder.scala index dfa0160e78..086910175e 100644 --- a/src/main/scala/io/iohk/ethereum/consensus/TestConsensusBuilder.scala +++ b/src/main/scala/io/iohk/ethereum/consensus/TestConsensusBuilder.scala @@ -4,8 +4,7 @@ import io.iohk.ethereum.nodebuilder._ import io.iohk.ethereum.security.SecureRandomBuilder import io.iohk.ethereum.utils.Logger -/** - * A [[io.iohk.ethereum.consensus.ConsensusBuilder ConsensusBuilder]] that builds a +/** A [[io.iohk.ethereum.consensus.ConsensusBuilder ConsensusBuilder]] that builds a * [[io.iohk.ethereum.consensus.TestConsensus TestConsensus]] */ trait TestConsensusBuilder { self: StdConsensusBuilder => diff --git a/src/main/scala/io/iohk/ethereum/consensus/blocks/BlockGenerator.scala b/src/main/scala/io/iohk/ethereum/consensus/blocks/BlockGenerator.scala index 5d3bc7011c..8a223c6342 100644 --- a/src/main/scala/io/iohk/ethereum/consensus/blocks/BlockGenerator.scala +++ b/src/main/scala/io/iohk/ethereum/consensus/blocks/BlockGenerator.scala @@ -1,10 +1,11 @@ package io.iohk.ethereum.consensus.blocks -import io.iohk.ethereum.domain.{Address, Block, SignedTransaction} +import io.iohk.ethereum.domain.Address +import io.iohk.ethereum.domain.Block +import io.iohk.ethereum.domain.SignedTransaction import io.iohk.ethereum.ledger.InMemoryWorldStateProxy -/** - * We use a `BlockGenerator` to create the next block. +/** We use a `BlockGenerator` to create the next block. * In a PoW setting, this is what a miner typically does. * In general, a [[BlockGenerator]] depends on and is provided by the * [[io.iohk.ethereum.consensus.Consensus Consensus]]. @@ -16,8 +17,7 @@ import io.iohk.ethereum.ledger.InMemoryWorldStateProxy */ trait BlockGenerator { - /** - * The type of consensus-specific data used in the block generation process. + /** The type of consensus-specific data used in the block generation process. * For example, under [[io.iohk.ethereum.consensus.pow.PoWConsensus EthashConsensus]], * this represents the [[io.iohk.ethereum.domain.BlockBody#uncleNodesList ommers]]. */ @@ -26,15 +26,13 @@ trait BlockGenerator { /** An empty `X` */ def emptyX: X - /** - * This function returns the block currently being mined block with highest timestamp + /** This function returns the block currently being mined block with highest timestamp */ def getPendingBlock: Option[PendingBlock] def getPendingBlockAndState: Option[PendingBlockAndState] - /** - * Generates the next block. + /** Generates the next block. */ def generateBlock( parent: Block, @@ -45,8 +43,7 @@ trait BlockGenerator { ): PendingBlockAndState } -/** - * Internal API, used for testing. +/** Internal API, used for testing. * * This is a [[BlockGenerator]] API for the needs of the test suites. */ diff --git a/src/main/scala/io/iohk/ethereum/consensus/blocks/BlockGeneratorSkeleton.scala b/src/main/scala/io/iohk/ethereum/consensus/blocks/BlockGeneratorSkeleton.scala index 9e283fe4d2..1c2cd42dcd 100644 --- a/src/main/scala/io/iohk/ethereum/consensus/blocks/BlockGeneratorSkeleton.scala +++ b/src/main/scala/io/iohk/ethereum/consensus/blocks/BlockGeneratorSkeleton.scala @@ -1,25 +1,31 @@ package io.iohk.ethereum.consensus.blocks import java.util.concurrent.atomic.AtomicReference + import akka.util.ByteString + import io.iohk.ethereum.consensus.ConsensusConfig import io.iohk.ethereum.consensus.difficulty.DifficultyCalculator import io.iohk.ethereum.consensus.pow.blocks.Ommers +import io.iohk.ethereum.consensus.pow.blocks.OmmersSeqEnc import io.iohk.ethereum.consensus.validators.std.MptListValidator.intByteArraySerializable import io.iohk.ethereum.crypto.kec256 import io.iohk.ethereum.db.dataSource.EphemDataSource -import io.iohk.ethereum.db.storage.{EvmCodeStorage, StateStorage} -import io.iohk.ethereum.domain._ +import io.iohk.ethereum.db.storage.EvmCodeStorage +import io.iohk.ethereum.db.storage.StateStorage import io.iohk.ethereum.domain.BlockHeader.HeaderExtraFields._ -import io.iohk.ethereum.consensus.pow.blocks.OmmersSeqEnc -import io.iohk.ethereum.ledger.{BlockResult, PreparedBlock} -import io.iohk.ethereum.ledger.{BlockPreparator, BloomFilter, InMemoryWorldStateProxy} -import io.iohk.ethereum.mpt.{ByteArraySerializable, MerklePatriciaTrie} +import io.iohk.ethereum.domain._ +import io.iohk.ethereum.ledger.BlockPreparator +import io.iohk.ethereum.ledger.BlockResult +import io.iohk.ethereum.ledger.BloomFilter +import io.iohk.ethereum.ledger.InMemoryWorldStateProxy +import io.iohk.ethereum.ledger.PreparedBlock +import io.iohk.ethereum.mpt.ByteArraySerializable +import io.iohk.ethereum.mpt.MerklePatriciaTrie import io.iohk.ethereum.utils.BlockchainConfig import io.iohk.ethereum.utils.ByteUtils.or -/** - * This is a skeleton for a generic [[io.iohk.ethereum.consensus.blocks.BlockGenerator BlockGenerator]]. +/** This is a skeleton for a generic [[io.iohk.ethereum.consensus.blocks.BlockGenerator BlockGenerator]]. */ abstract class BlockGeneratorSkeleton( blockchainConfig: BlockchainConfig, @@ -151,7 +157,7 @@ abstract class BlockGeneratorSkeleton( .flatMap { case (_, txs) => txs } val transactionsForBlock: Seq[SignedTransaction] = sortedTransactions - .scanLeft(BigInt(0), None: Option[SignedTransaction]) { case ((accumulatedGas, _), stx) => + .scanLeft((BigInt(0), None: Option[SignedTransaction])) { case ((accumulatedGas, _), stx) => (accumulatedGas + stx.tx.gasLimit, Some(stx)) } .collect { case (gas, Some(stx)) => (gas, stx) } @@ -180,8 +186,7 @@ abstract class BlockGeneratorSkeleton( def blockTimestampProvider: BlockTimestampProvider = _blockTimestampProvider - /** - * This function returns the block currently being mined block with highest timestamp + /** This function returns the block currently being mined block with highest timestamp */ def getPendingBlock: Option[PendingBlock] = getPendingBlockAndState.map(_.pendingBlock) diff --git a/src/main/scala/io/iohk/ethereum/consensus/blocks/CheckpointBlockGenerator.scala b/src/main/scala/io/iohk/ethereum/consensus/blocks/CheckpointBlockGenerator.scala index c3095e67f0..5ca4392301 100644 --- a/src/main/scala/io/iohk/ethereum/consensus/blocks/CheckpointBlockGenerator.scala +++ b/src/main/scala/io/iohk/ethereum/consensus/blocks/CheckpointBlockGenerator.scala @@ -1,6 +1,7 @@ package io.iohk.ethereum.consensus.blocks import akka.util.ByteString + import io.iohk.ethereum.crypto.ECDSASignatureImplicits.ECDSASignatureOrdering import io.iohk.ethereum.domain.BlockHeader.HeaderExtraFields.HefPostEcip1097 import io.iohk.ethereum.domain._ diff --git a/src/main/scala/io/iohk/ethereum/consensus/blocks/NoOmmersBlockGenerator.scala b/src/main/scala/io/iohk/ethereum/consensus/blocks/NoOmmersBlockGenerator.scala index 241f32dde0..621ddd6ae7 100644 --- a/src/main/scala/io/iohk/ethereum/consensus/blocks/NoOmmersBlockGenerator.scala +++ b/src/main/scala/io/iohk/ethereum/consensus/blocks/NoOmmersBlockGenerator.scala @@ -1,12 +1,13 @@ package io.iohk.ethereum.consensus.blocks import io.iohk.ethereum.consensus.ConsensusConfig +import io.iohk.ethereum.consensus.ConsensusMetrics import io.iohk.ethereum.consensus.difficulty.DifficultyCalculator +import io.iohk.ethereum.db.storage.EvmCodeStorage import io.iohk.ethereum.domain._ -import io.iohk.ethereum.ledger.{BlockPreparator, InMemoryWorldStateProxy} +import io.iohk.ethereum.ledger.BlockPreparator +import io.iohk.ethereum.ledger.InMemoryWorldStateProxy import io.iohk.ethereum.utils.BlockchainConfig -import io.iohk.ethereum.consensus.ConsensusMetrics -import io.iohk.ethereum.db.storage.EvmCodeStorage abstract class NoOmmersBlockGenerator( evmCodeStorage: EvmCodeStorage, diff --git a/src/main/scala/io/iohk/ethereum/consensus/blocks/package.scala b/src/main/scala/io/iohk/ethereum/consensus/blocks/package.scala index 247cc83952..19d70a4a65 100644 --- a/src/main/scala/io/iohk/ethereum/consensus/blocks/package.scala +++ b/src/main/scala/io/iohk/ethereum/consensus/blocks/package.scala @@ -1,6 +1,7 @@ package io.iohk.ethereum.consensus -import io.iohk.ethereum.domain.{Block, Receipt} +import io.iohk.ethereum.domain.Block +import io.iohk.ethereum.domain.Receipt import io.iohk.ethereum.ledger.InMemoryWorldStateProxy package object blocks { diff --git a/src/main/scala/io/iohk/ethereum/consensus/difficulty/DifficultyCalculator.scala b/src/main/scala/io/iohk/ethereum/consensus/difficulty/DifficultyCalculator.scala index 0b5e2d6193..9e6fdbeb03 100644 --- a/src/main/scala/io/iohk/ethereum/consensus/difficulty/DifficultyCalculator.scala +++ b/src/main/scala/io/iohk/ethereum/consensus/difficulty/DifficultyCalculator.scala @@ -1,6 +1,7 @@ package io.iohk.ethereum.consensus.difficulty -import io.iohk.ethereum.consensus.pow.difficulty.{TargetTimeDifficultyCalculator, EthashDifficultyCalculator} +import io.iohk.ethereum.consensus.pow.difficulty.EthashDifficultyCalculator +import io.iohk.ethereum.consensus.pow.difficulty.TargetTimeDifficultyCalculator import io.iohk.ethereum.domain.BlockHeader import io.iohk.ethereum.utils.BlockchainConfig @@ -9,12 +10,11 @@ trait DifficultyCalculator { } object DifficultyCalculator { - def apply(blockchainConfig: BlockchainConfig): DifficultyCalculator = { + def apply(blockchainConfig: BlockchainConfig): DifficultyCalculator = blockchainConfig.powTargetTime match { case Some(targetTime) => new TargetTimeDifficultyCalculator(targetTime) - case None => new EthashDifficultyCalculator(blockchainConfig) + case None => new EthashDifficultyCalculator(blockchainConfig) } - } val DifficultyBoundDivision: Int = 2048 val FrontierTimestampDiffLimit: Int = -99 diff --git a/src/main/scala/io/iohk/ethereum/consensus/package.scala b/src/main/scala/io/iohk/ethereum/consensus/package.scala index b8ae309cb4..1ae2f9382a 100644 --- a/src/main/scala/io/iohk/ethereum/consensus/package.scala +++ b/src/main/scala/io/iohk/ethereum/consensus/package.scala @@ -1,15 +1,16 @@ package io.iohk.ethereum import akka.util.ByteString + +import scala.reflect.ClassTag + import io.iohk.ethereum.consensus.blocks.BlockGenerator import io.iohk.ethereum.consensus.pow.PoWConsensus import io.iohk.ethereum.consensus.validators.Validators -import io.iohk.ethereum.domain.{Block, BlockHeader} - -import scala.reflect.ClassTag +import io.iohk.ethereum.domain.Block +import io.iohk.ethereum.domain.BlockHeader -/** - * Provides everything related to consensus. +/** Provides everything related to consensus. * Different consensus protocols are implemented in sub-packages. */ package object consensus { @@ -34,10 +35,9 @@ package object consensus { throw new IllegalArgumentException(msg) } - final implicit class RichConsensus(val consensus: Consensus) extends AnyVal { + implicit final class RichConsensus(val consensus: Consensus) extends AnyVal { - /** - * There are APIs that expect that the standard Ethash consensus is running and so depend + /** There are APIs that expect that the standard Ethash consensus is running and so depend * on either its configuration or general PoW semantics. * This is a method that can handle such cases via a respective if/then/else construct: * if we run under [[io.iohk.ethereum.consensus.pow.PoWConsensus EthashConsensus]] @@ -46,7 +46,7 @@ package object consensus { def ifEthash[A](_then: PoWConsensus => A)(_else: => A): A = consensus match { case ethash: PoWConsensus => _then(ethash) - case _ => _else + case _ => _else } } } diff --git a/src/main/scala/io/iohk/ethereum/consensus/pow/EthashConfig.scala b/src/main/scala/io/iohk/ethereum/consensus/pow/EthashConfig.scala index 718442d484..1fec1c9314 100644 --- a/src/main/scala/io/iohk/ethereum/consensus/pow/EthashConfig.scala +++ b/src/main/scala/io/iohk/ethereum/consensus/pow/EthashConfig.scala @@ -2,9 +2,10 @@ package io.iohk.ethereum package consensus package pow -import com.typesafe.config.{Config => TypesafeConfig} +import scala.concurrent.duration.FiniteDuration +import scala.concurrent.duration._ -import scala.concurrent.duration.{FiniteDuration, _} +import com.typesafe.config.{Config => TypesafeConfig} final case class EthashConfig( ommersPoolSize: Int, diff --git a/src/main/scala/io/iohk/ethereum/consensus/pow/EthashUtils.scala b/src/main/scala/io/iohk/ethereum/consensus/pow/EthashUtils.scala index 9aa8c3ed08..9395a60a29 100644 --- a/src/main/scala/io/iohk/ethereum/consensus/pow/EthashUtils.scala +++ b/src/main/scala/io/iohk/ethereum/consensus/pow/EthashUtils.scala @@ -1,17 +1,20 @@ package io.iohk.ethereum.consensus package pow +import java.lang.Integer.remainderUnsigned import java.math.BigInteger import java.util import akka.util.ByteString -import io.iohk.ethereum.crypto.{kec256, kec512} -import io.iohk.ethereum.utils.ByteUtils._ + +import scala.annotation.tailrec + import org.bouncycastle.util.BigIntegers import org.bouncycastle.util.encoders.Hex -import java.lang.Integer.remainderUnsigned -import scala.annotation.tailrec +import io.iohk.ethereum.crypto.kec256 +import io.iohk.ethereum.crypto.kec512 +import io.iohk.ethereum.utils.ByteUtils._ object EthashUtils { @@ -91,10 +94,9 @@ object EthashUtils { } @tailrec - private def highestPrimeBelow(n: Long, len: Long): Long = { + private def highestPrimeBelow(n: Long, len: Long): Long = if (isPrime(n / len)) n else highestPrimeBelow(n - 2 * len, len) - } private def isPrime(n: BigInt): Boolean = { @tailrec @@ -139,9 +141,8 @@ object EthashUtils { nonce: Array[Byte], fullSize: Long, cache: Array[Int] - ): EthashProofOfWork = { + ): EthashProofOfWork = hashimoto(hashWithoutNonce, nonce, fullSize, (calcDatasetItem _).curried(cache)) - } def hashimoto( hashWithoutNonce: Array[Byte], @@ -241,13 +242,12 @@ object EthashUtils { } } - private def fnv(v1: Int, v2: Int): Int = { + private def fnv(v1: Int, v2: Int): Int = (v1 * FNV_PRIME) ^ v2 - } private[pow] def checkDifficulty(blockDifficulty: Long, proofOfWork: EthashProofOfWork): Boolean = { @tailrec - def compare(a1: Array[Byte], a2: Array[Byte]): Int = { + def compare(a1: Array[Byte], a2: Array[Byte]): Int = if (a1.length > a2.length) 1 else if (a1.length < a2.length) -1 else { @@ -256,7 +256,6 @@ object EthashUtils { else if ((a1.head & 0xff) < (a2.head & 0xff)) -1 else compare(a1.tail, a2.tail) } - } val headerDifficultyAsByteArray: Array[Byte] = BigIntegers.asUnsignedByteArray(32, BigInteger.ONE.shiftLeft(256).divide(BigInteger.valueOf(blockDifficulty))) diff --git a/src/main/scala/io/iohk/ethereum/consensus/pow/KeccakCalculation.scala b/src/main/scala/io/iohk/ethereum/consensus/pow/KeccakCalculation.scala index 1124a3ff0a..f937a0591f 100644 --- a/src/main/scala/io/iohk/ethereum/consensus/pow/KeccakCalculation.scala +++ b/src/main/scala/io/iohk/ethereum/consensus/pow/KeccakCalculation.scala @@ -1,15 +1,16 @@ package io.iohk.ethereum.consensus.pow import akka.util.ByteString -import io.iohk.ethereum.crypto.{kec256, kec256PoW} + +import io.iohk.ethereum.crypto.kec256 +import io.iohk.ethereum.crypto.kec256PoW import io.iohk.ethereum.utils.ByteUtils object KeccakCalculation { final val difficultyNumerator: BigInt = BigInt(2).pow(256) - /** - * Computation of mixHash = keccak256(keccak256(rlp(unsealed header)), nonce) + /** Computation of mixHash = keccak256(keccak256(rlp(unsealed header)), nonce) * @param hashHeader the rlp(unsealed header) * @return KeccakProofOWork containing the computed mixHash */ @@ -21,8 +22,7 @@ object KeccakCalculation { KeccakMixHash(mixHash = ByteString(mixHash)) } - /** - * Validates if mixHash <= 2^256 / difficulty + /** Validates if mixHash <= 2^256 / difficulty * @param mixHash * @param difficulty * @return boolean indicating whether PoW is valid or not diff --git a/src/main/scala/io/iohk/ethereum/consensus/pow/PoWBlockCreator.scala b/src/main/scala/io/iohk/ethereum/consensus/pow/PoWBlockCreator.scala index fe732a49b2..6188ee0218 100644 --- a/src/main/scala/io/iohk/ethereum/consensus/pow/PoWBlockCreator.scala +++ b/src/main/scala/io/iohk/ethereum/consensus/pow/PoWBlockCreator.scala @@ -2,16 +2,20 @@ package io.iohk.ethereum.consensus.pow import akka.actor.ActorRef import akka.util.ByteString + +import monix.eval.Task + +import scala.concurrent.duration.FiniteDuration + import io.iohk.ethereum.consensus.blocks.PendingBlockAndState import io.iohk.ethereum.consensus.pow.blocks.PoWBlockGenerator -import io.iohk.ethereum.domain.{Address, Block} +import io.iohk.ethereum.domain.Address +import io.iohk.ethereum.domain.Block import io.iohk.ethereum.jsonrpc.AkkaTaskOps.TaskActorOps import io.iohk.ethereum.ledger.InMemoryWorldStateProxy import io.iohk.ethereum.ommers.OmmersPool import io.iohk.ethereum.transactions.PendingTransactionsManager.PendingTransactionsResponse import io.iohk.ethereum.transactions.TransactionPicker -import monix.eval.Task -import scala.concurrent.duration.FiniteDuration class PoWBlockCreator( val pendingTransactionsManager: ActorRef, @@ -44,13 +48,12 @@ class PoWBlockCreator( } } - private def getOmmersFromPool(parentBlockHash: ByteString): Task[OmmersPool.Ommers] = { + private def getOmmersFromPool(parentBlockHash: ByteString): Task[OmmersPool.Ommers] = ommersPool .askFor[OmmersPool.Ommers](OmmersPool.GetOmmers(parentBlockHash)) .onErrorHandle { ex => log.error("Failed to get ommers, mining block with empty ommers list", ex) OmmersPool.Ommers(Nil) } - } } diff --git a/src/main/scala/io/iohk/ethereum/consensus/pow/PoWConsensus.scala b/src/main/scala/io/iohk/ethereum/consensus/pow/PoWConsensus.scala index 2a6b4279c8..872fd501b3 100644 --- a/src/main/scala/io/iohk/ethereum/consensus/pow/PoWConsensus.scala +++ b/src/main/scala/io/iohk/ethereum/consensus/pow/PoWConsensus.scala @@ -2,32 +2,40 @@ package io.iohk.ethereum package consensus package pow -import akka.util.Timeout -import akka.actor.typed.{ActorRef, DispatcherSelector} +import akka.actor.typed.ActorRef +import akka.actor.typed.DispatcherSelector import akka.actor.typed.scaladsl.adapter._ +import akka.util.Timeout + +import monix.eval.Task + +import scala.concurrent.duration._ + import io.iohk.ethereum.consensus.Protocol._ import io.iohk.ethereum.consensus.blocks.TestBlockGenerator import io.iohk.ethereum.consensus.difficulty.DifficultyCalculator import io.iohk.ethereum.consensus.pow.PoWMiningCoordinator.CoordinatorProtocol -import io.iohk.ethereum.consensus.pow.blocks.{PoWBlockGenerator, PoWBlockGeneratorImpl, RestrictedPoWBlockGeneratorImpl} -import io.iohk.ethereum.consensus.pow.miners.MockedMiner.{MockedMinerProtocol, MockedMinerResponse} +import io.iohk.ethereum.consensus.pow.blocks.PoWBlockGenerator +import io.iohk.ethereum.consensus.pow.blocks.PoWBlockGeneratorImpl +import io.iohk.ethereum.consensus.pow.blocks.RestrictedPoWBlockGeneratorImpl +import io.iohk.ethereum.consensus.pow.miners.MinerProtocol +import io.iohk.ethereum.consensus.pow.miners.MockedMiner +import io.iohk.ethereum.consensus.pow.miners.MockedMiner.MockedMinerProtocol +import io.iohk.ethereum.consensus.pow.miners.MockedMiner.MockedMinerResponse import io.iohk.ethereum.consensus.pow.miners.MockedMiner.MockedMinerResponses.MinerNotExist -import io.iohk.ethereum.consensus.pow.miners.{MinerProtocol, MockedMiner} import io.iohk.ethereum.consensus.pow.validators.ValidatorsExecutor import io.iohk.ethereum.consensus.validators.Validators import io.iohk.ethereum.db.storage.EvmCodeStorage -import io.iohk.ethereum.domain.{Blockchain, BlockchainReader, BlockchainImpl} +import io.iohk.ethereum.domain.BlockchainImpl +import io.iohk.ethereum.domain.BlockchainReader import io.iohk.ethereum.jsonrpc.AkkaTaskOps.TaskActorOps import io.iohk.ethereum.ledger.BlockPreparator import io.iohk.ethereum.ledger.VMImpl import io.iohk.ethereum.nodebuilder.Node -import io.iohk.ethereum.utils.{BlockchainConfig, Logger} -import monix.eval.Task +import io.iohk.ethereum.utils.BlockchainConfig +import io.iohk.ethereum.utils.Logger -import scala.concurrent.duration._ - -/** - * Implements standard Ethereum consensus (Proof of Work). +/** Implements standard Ethereum consensus (Proof of Work). */ class PoWConsensus private ( val vm: VMImpl, @@ -44,7 +52,7 @@ class PoWConsensus private ( type Config = EthashConfig - private[this] final val _blockPreparator = new BlockPreparator( + final private[this] val _blockPreparator = new BlockPreparator( vm = vm, signedTxValidator = validators.signedTransactionValidator, blockchain = blockchain, @@ -57,7 +65,7 @@ class PoWConsensus private ( @volatile private[pow] var mockedMinerRef: Option[akka.actor.ActorRef] = None final val BlockForgerDispatcherId = "mantis.async.dispatchers.block-forger" - private implicit val timeout: Timeout = 5.seconds + implicit private val timeout: Timeout = 5.seconds override def sendMiner(msg: MinerProtocol): Unit = msg match { @@ -72,11 +80,10 @@ class PoWConsensus private ( } // no interactions are done with minerCoordinatorRef using the ask pattern - override def askMiner(msg: MockedMinerProtocol): Task[MockedMinerResponse] = { + override def askMiner(msg: MockedMinerProtocol): Task[MockedMinerResponse] = mockedMinerRef .map(_.askFor[MockedMinerResponse](msg)) .getOrElse(Task.now(MinerNotExist)) - } private[this] val mutex = new Object @@ -86,7 +93,7 @@ class PoWConsensus private ( * * TODO further refactors should focus on extracting two types - one with a miner, one without - based on the config */ - private[this] def startMiningProcess(node: Node, blockCreator: PoWBlockCreator): Unit = { + private[this] def startMiningProcess(node: Node, blockCreator: PoWBlockCreator): Unit = mutex.synchronized { if (minerCoordinatorRef.isEmpty && mockedMinerRef.isEmpty) { config.generic.protocol match { @@ -112,21 +119,17 @@ class PoWConsensus private ( sendMiner(MinerProtocol.StartMining) } } - } - private[this] def stopMiningProcess(): Unit = { + private[this] def stopMiningProcess(): Unit = sendMiner(MinerProtocol.StopMining) - } - /** - * This is used by the [[io.iohk.ethereum.consensus.Consensus#blockGenerator blockGenerator]]. + /** This is used by the [[io.iohk.ethereum.consensus.Consensus#blockGenerator blockGenerator]]. */ def blockPreparator: BlockPreparator = this._blockPreparator - /** - * Starts the consensus protocol on the current `node`. + /** Starts the consensus protocol on the current `node`. */ - def startProtocol(node: Node): Unit = { + def startProtocol(node: Node): Unit = if (config.miningEnabled) { log.info("Mining is enabled. Will try to start configured miner actor") val blockCreator = node.consensus match { @@ -142,18 +145,16 @@ class PoWConsensus private ( startMiningProcess(node, blockCreator) } else log.info("Not starting any miner actor because mining is disabled") - } - def stopProtocol(): Unit = { + def stopProtocol(): Unit = if (config.miningEnabled) { stopMiningProcess() } - } def protocol: Protocol = Protocol.PoW /** Internal API, used for testing */ - protected def newBlockGenerator(validators: Validators): PoWBlockGenerator = { + protected def newBlockGenerator(validators: Validators): PoWBlockGenerator = validators match { case _validators: ValidatorsExecutor => val blockPreparator = new BlockPreparator( @@ -178,10 +179,9 @@ class PoWConsensus private ( case _ => wrongValidatorsArgument[ValidatorsExecutor](validators) } - } /** Internal API, used for testing */ - def withValidators(validators: Validators): PoWConsensus = { + def withValidators(validators: Validators): PoWConsensus = validators match { case _validators: ValidatorsExecutor => val blockGenerator = newBlockGenerator(validators) @@ -201,7 +201,6 @@ class PoWConsensus private ( case _ => wrongValidatorsArgument[ValidatorsExecutor](validators) } - } def withVM(vm: VMImpl): PoWConsensus = new PoWConsensus( diff --git a/src/main/scala/io/iohk/ethereum/consensus/pow/PoWMiningCoordinator.scala b/src/main/scala/io/iohk/ethereum/consensus/pow/PoWMiningCoordinator.scala index 193c387c25..dcf88901eb 100644 --- a/src/main/scala/io/iohk/ethereum/consensus/pow/PoWMiningCoordinator.scala +++ b/src/main/scala/io/iohk/ethereum/consensus/pow/PoWMiningCoordinator.scala @@ -1,17 +1,25 @@ package io.iohk.ethereum.consensus.pow import akka.actor.typed.Behavior -import akka.actor.typed.scaladsl.{AbstractBehavior, ActorContext, Behaviors} +import akka.actor.typed.scaladsl.AbstractBehavior +import akka.actor.typed.scaladsl.ActorContext +import akka.actor.typed.scaladsl.Behaviors import akka.actor.{ActorRef => ClassicActorRef} -import akka.util.Timeout -import io.iohk.ethereum.consensus.pow.PoWMiningCoordinator.CoordinatorProtocol -import io.iohk.ethereum.consensus.pow.miners.{EthashDAGManager, EthashMiner, KeccakMiner, Miner} -import io.iohk.ethereum.domain.{Block, Blockchain} -import io.iohk.ethereum.jsonrpc.EthMiningService -import monix.execution.{CancelableFuture, Scheduler} + +import monix.execution.CancelableFuture +import monix.execution.Scheduler import scala.concurrent.duration.DurationInt +import io.iohk.ethereum.consensus.pow.PoWMiningCoordinator.CoordinatorProtocol +import io.iohk.ethereum.consensus.pow.miners.EthashDAGManager +import io.iohk.ethereum.consensus.pow.miners.EthashMiner +import io.iohk.ethereum.consensus.pow.miners.KeccakMiner +import io.iohk.ethereum.consensus.pow.miners.Miner +import io.iohk.ethereum.domain.Block +import io.iohk.ethereum.domain.Blockchain +import io.iohk.ethereum.jsonrpc.EthMiningService + object PoWMiningCoordinator { // TODO in ETCM-773 make trait sealed trait CoordinatorProtocol @@ -72,8 +80,8 @@ class PoWMiningCoordinator private ( import PoWMiningCoordinator._ - private implicit val scheduler: Scheduler = Scheduler(context.executionContext) - private implicit val timeout: Timeout = 5.seconds + implicit private val scheduler: Scheduler = Scheduler(context.executionContext) + 5.seconds private val log = context.log private val dagManager = new EthashDAGManager(blockCreator) @@ -122,12 +130,11 @@ class PoWMiningCoordinator private ( case OnDemandMining => handleMiningOnDemand() } - private def getMiningAlgorithm(currentBlockNumber: BigInt): MiningAlgorithm = { + private def getMiningAlgorithm(currentBlockNumber: BigInt): MiningAlgorithm = ecip1049BlockNumber match { - case None => EthashAlgorithm + case None => EthashAlgorithm case Some(blockNumber) => if (currentBlockNumber + 1 >= blockNumber) KeccakAlgorithm else EthashAlgorithm } - } private def mineWithEthash(bestBlock: Block): Unit = { log.debug("Mining with Ethash") diff --git a/src/main/scala/io/iohk/ethereum/consensus/pow/RestrictedPoWSigner.scala b/src/main/scala/io/iohk/ethereum/consensus/pow/RestrictedPoWSigner.scala index b568b6e15b..caf61d57ef 100644 --- a/src/main/scala/io/iohk/ethereum/consensus/pow/RestrictedPoWSigner.scala +++ b/src/main/scala/io/iohk/ethereum/consensus/pow/RestrictedPoWSigner.scala @@ -1,11 +1,13 @@ package io.iohk.ethereum.consensus.pow import akka.util.ByteString + +import org.bouncycastle.crypto.AsymmetricCipherKeyPair + import io.iohk.ethereum.crypto import io.iohk.ethereum.crypto.ECDSASignature import io.iohk.ethereum.domain.BlockHeader import io.iohk.ethereum.domain.BlockHeader.getEncodedWithoutNonce -import org.bouncycastle.crypto.AsymmetricCipherKeyPair object RestrictedPoWSigner { diff --git a/src/main/scala/io/iohk/ethereum/consensus/pow/blocks/PoWBlockGenerator.scala b/src/main/scala/io/iohk/ethereum/consensus/pow/blocks/PoWBlockGenerator.scala index 5fa3884704..dee997791d 100644 --- a/src/main/scala/io/iohk/ethereum/consensus/pow/blocks/PoWBlockGenerator.scala +++ b/src/main/scala/io/iohk/ethereum/consensus/pow/blocks/PoWBlockGenerator.scala @@ -1,17 +1,20 @@ package io.iohk.ethereum.consensus.pow.blocks import java.util.function.UnaryOperator + import akka.util.ByteString + import io.iohk.ethereum.consensus.ConsensusConfig +import io.iohk.ethereum.consensus.ConsensusMetrics import io.iohk.ethereum.consensus.blocks._ import io.iohk.ethereum.consensus.difficulty.DifficultyCalculator import io.iohk.ethereum.consensus.pow.validators.ValidatorsExecutor import io.iohk.ethereum.crypto.kec256 +import io.iohk.ethereum.db.storage.EvmCodeStorage import io.iohk.ethereum.domain._ -import io.iohk.ethereum.ledger.{BlockPreparator, InMemoryWorldStateProxy} +import io.iohk.ethereum.ledger.BlockPreparator +import io.iohk.ethereum.ledger.InMemoryWorldStateProxy import io.iohk.ethereum.utils.BlockchainConfig -import io.iohk.ethereum.consensus.ConsensusMetrics -import io.iohk.ethereum.db.storage.EvmCodeStorage /** Internal API, used for testing (especially mocks) */ trait PoWBlockGenerator extends TestBlockGenerator { @@ -82,7 +85,7 @@ class PoWBlockGeneratorImpl( val parentHash = pHeader.hash val ommers = validators.ommersValidator.validate(parentHash, blockNumber, x, blockchainReader) match { - case Left(_) => emptyX + case Left(_) => emptyX case Right(_) => x } diff --git a/src/main/scala/io/iohk/ethereum/consensus/pow/blocks/RestrictedPoWBlockGeneratorImpl.scala b/src/main/scala/io/iohk/ethereum/consensus/pow/blocks/RestrictedPoWBlockGeneratorImpl.scala index 85ef227dcd..a6813b495b 100644 --- a/src/main/scala/io/iohk/ethereum/consensus/pow/blocks/RestrictedPoWBlockGeneratorImpl.scala +++ b/src/main/scala/io/iohk/ethereum/consensus/pow/blocks/RestrictedPoWBlockGeneratorImpl.scala @@ -1,16 +1,23 @@ package io.iohk.ethereum.consensus.pow.blocks +import org.bouncycastle.crypto.AsymmetricCipherKeyPair + import io.iohk.ethereum.consensus.ConsensusConfig -import io.iohk.ethereum.consensus.blocks.{BlockTimestampProvider, DefaultBlockTimestampProvider, PendingBlockAndState} +import io.iohk.ethereum.consensus.ConsensusMetrics +import io.iohk.ethereum.consensus.blocks.BlockTimestampProvider +import io.iohk.ethereum.consensus.blocks.DefaultBlockTimestampProvider +import io.iohk.ethereum.consensus.blocks.PendingBlockAndState import io.iohk.ethereum.consensus.difficulty.DifficultyCalculator import io.iohk.ethereum.consensus.pow.RestrictedPoWSigner import io.iohk.ethereum.consensus.pow.validators.ValidatorsExecutor -import io.iohk.ethereum.domain.{Address, Block, BlockchainReader, SignedTransaction} -import io.iohk.ethereum.ledger.{BlockPreparator, InMemoryWorldStateProxy} -import io.iohk.ethereum.utils.BlockchainConfig -import org.bouncycastle.crypto.AsymmetricCipherKeyPair -import io.iohk.ethereum.consensus.ConsensusMetrics import io.iohk.ethereum.db.storage.EvmCodeStorage +import io.iohk.ethereum.domain.Address +import io.iohk.ethereum.domain.Block +import io.iohk.ethereum.domain.BlockchainReader +import io.iohk.ethereum.domain.SignedTransaction +import io.iohk.ethereum.ledger.BlockPreparator +import io.iohk.ethereum.ledger.InMemoryWorldStateProxy +import io.iohk.ethereum.utils.BlockchainConfig class RestrictedPoWBlockGeneratorImpl( evmCodeStorage: EvmCodeStorage, @@ -46,7 +53,7 @@ class RestrictedPoWBlockGeneratorImpl( val validatedOmmers = validators.ommersValidator.validate(parentHash, blockNumber, ommers, blockchainReader) match { - case Left(_) => emptyX + case Left(_) => emptyX case Right(_) => ommers } val prepared = prepareBlock( diff --git a/src/main/scala/io/iohk/ethereum/consensus/pow/blocks/package.scala b/src/main/scala/io/iohk/ethereum/consensus/pow/blocks/package.scala index cba459629c..faf127690e 100644 --- a/src/main/scala/io/iohk/ethereum/consensus/pow/blocks/package.scala +++ b/src/main/scala/io/iohk/ethereum/consensus/pow/blocks/package.scala @@ -2,12 +2,13 @@ package io.iohk.ethereum.consensus.pow import io.iohk.ethereum.domain.BlockHeader import io.iohk.ethereum.domain.BlockHeaderImplicits._ -import io.iohk.ethereum.rlp.{RLPEncodeable, RLPList, RLPSerializable} +import io.iohk.ethereum.rlp.RLPEncodeable +import io.iohk.ethereum.rlp.RLPList +import io.iohk.ethereum.rlp.RLPSerializable package object blocks { - /** - * This is type `X` in `BlockGenerator`. + /** This is type `X` in `BlockGenerator`. * * @see [[io.iohk.ethereum.consensus.pow.blocks.PoWBlockGenerator EthashBlockGenerator]], * [[io.iohk.ethereum.consensus.blocks.BlockGenerator.X BlockGenerator{ type X}]] diff --git a/src/main/scala/io/iohk/ethereum/consensus/pow/difficulty/EthashDifficultyCalculator.scala b/src/main/scala/io/iohk/ethereum/consensus/pow/difficulty/EthashDifficultyCalculator.scala index 06b405bd0b..9fa03eff2a 100644 --- a/src/main/scala/io/iohk/ethereum/consensus/pow/difficulty/EthashDifficultyCalculator.scala +++ b/src/main/scala/io/iohk/ethereum/consensus/pow/difficulty/EthashDifficultyCalculator.scala @@ -5,7 +5,6 @@ import io.iohk.ethereum.domain.BlockHeader import io.iohk.ethereum.utils.BlockchainConfig class EthashDifficultyCalculator(blockchainConfig: BlockchainConfig) extends DifficultyCalculator { - import blockchainConfig._ import blockchainConfig.forkBlockNumbers._ import DifficultyCalculator._ @@ -48,7 +47,7 @@ class EthashDifficultyCalculator(blockchainConfig: BlockchainConfig) extends Dif difficultyWithoutBomb + extraDifficulty } - private def calculateBombExponent(blockNumber: BigInt): Int = { + private def calculateBombExponent(blockNumber: BigInt): Int = if (blockNumber < difficultyBombPauseBlockNumber) (blockNumber / ExpDifficultyPeriod - 2).toInt else if (blockNumber < difficultyBombContinueBlockNumber) @@ -57,5 +56,4 @@ class EthashDifficultyCalculator(blockchainConfig: BlockchainConfig) extends Dif val delay = (difficultyBombContinueBlockNumber - difficultyBombPauseBlockNumber) / ExpDifficultyPeriod ((blockNumber / ExpDifficultyPeriod) - delay - 2).toInt } - } } diff --git a/src/main/scala/io/iohk/ethereum/consensus/pow/difficulty/TargetTimeDifficultyCalculator.scala b/src/main/scala/io/iohk/ethereum/consensus/pow/difficulty/TargetTimeDifficultyCalculator.scala index 7411271451..cb852f792d 100644 --- a/src/main/scala/io/iohk/ethereum/consensus/pow/difficulty/TargetTimeDifficultyCalculator.scala +++ b/src/main/scala/io/iohk/ethereum/consensus/pow/difficulty/TargetTimeDifficultyCalculator.scala @@ -7,8 +7,7 @@ class TargetTimeDifficultyCalculator(powTargetTime: Long) extends DifficultyCalc import DifficultyCalculator._ - /** - * The lowerBoundExpectedRatio (l for abbreviation below) divides the timestamp diff into ranges: + /** The lowerBoundExpectedRatio (l for abbreviation below) divides the timestamp diff into ranges: * [0, l) => c = 1, difficulty increases * [l, 2*l) => c = 0. difficulty stays the same * ... diff --git a/src/main/scala/io/iohk/ethereum/consensus/pow/miners/EthashDAGManager.scala b/src/main/scala/io/iohk/ethereum/consensus/pow/miners/EthashDAGManager.scala index ef3d269ce5..56d19bc41f 100644 --- a/src/main/scala/io/iohk/ethereum/consensus/pow/miners/EthashDAGManager.scala +++ b/src/main/scala/io/iohk/ethereum/consensus/pow/miners/EthashDAGManager.scala @@ -1,20 +1,29 @@ package io.iohk.ethereum.consensus.pow.miners +import java.io.File +import java.io.FileInputStream +import java.io.FileOutputStream + import akka.util.ByteString -import io.iohk.ethereum.consensus.pow.miners.EthashMiner.DagFilePrefix -import io.iohk.ethereum.consensus.pow.{EthashUtils, PoWBlockCreator} -import io.iohk.ethereum.utils.{ByteUtils, Logger} + +import scala.util.Failure +import scala.util.Success +import scala.util.Try + import org.bouncycastle.util.encoders.Hex -import java.io.{File, FileInputStream, FileOutputStream} -import scala.util.{Failure, Success, Try} +import io.iohk.ethereum.consensus.pow.EthashUtils +import io.iohk.ethereum.consensus.pow.PoWBlockCreator +import io.iohk.ethereum.consensus.pow.miners.EthashMiner.DagFilePrefix +import io.iohk.ethereum.utils.ByteUtils +import io.iohk.ethereum.utils.Logger class EthashDAGManager(blockCreator: PoWBlockCreator) extends Logger { var currentEpoch: Option[Long] = None var currentEpochDagSize: Option[Long] = None var currentEpochDag: Option[Array[Array[Int]]] = None - def calculateDagSize(blockNumber: Long, epoch: Long): (Array[Array[Int]], Long) = { + def calculateDagSize(blockNumber: Long, epoch: Long): (Array[Array[Int]], Long) = (currentEpoch, currentEpochDag, currentEpochDagSize) match { case (Some(`epoch`), Some(dag), Some(dagSize)) => (dag, dagSize) case _ => @@ -36,14 +45,12 @@ class EthashDAGManager(blockCreator: PoWBlockCreator) extends Logger { currentEpochDagSize = Some(dagSize) (dag, dagSize) } - } - private def dagFile(seed: ByteString): File = { + private def dagFile(seed: ByteString): File = new File( s"${blockCreator.miningConfig.ethashDir}/full-R${EthashUtils.Revision}-${Hex .toHexString(seed.take(8).toArray[Byte])}" ) - } private def generateDagAndSaveToFile(epoch: Long, dagNumHashes: Int, seed: ByteString): Array[Array[Int]] = { val file = dagFile(seed) diff --git a/src/main/scala/io/iohk/ethereum/consensus/pow/miners/EthashMiner.scala b/src/main/scala/io/iohk/ethereum/consensus/pow/miners/EthashMiner.scala index 1a194543e6..eac674ba55 100644 --- a/src/main/scala/io/iohk/ethereum/consensus/pow/miners/EthashMiner.scala +++ b/src/main/scala/io/iohk/ethereum/consensus/pow/miners/EthashMiner.scala @@ -2,23 +2,28 @@ package io.iohk.ethereum.consensus.pow.miners import akka.actor.{ActorRef => ClassicActorRef} import akka.util.ByteString -import io.iohk.ethereum.blockchain.sync.SyncProtocol -import io.iohk.ethereum.consensus.blocks.{PendingBlock, PendingBlockAndState} + +import monix.execution.CancelableFuture +import monix.execution.Scheduler + +import scala.util.Random + +import io.iohk.ethereum.consensus.blocks.PendingBlock +import io.iohk.ethereum.consensus.blocks.PendingBlockAndState +import io.iohk.ethereum.consensus.pow.EthashUtils +import io.iohk.ethereum.consensus.pow.PoWBlockCreator +import io.iohk.ethereum.consensus.pow.PoWMiningCoordinator import io.iohk.ethereum.consensus.pow.PoWMiningCoordinator.CoordinatorProtocol import io.iohk.ethereum.consensus.pow.miners.MinerProtocol._ -import io.iohk.ethereum.consensus.pow.{EthashUtils, PoWBlockCreator, PoWMiningCoordinator} import io.iohk.ethereum.crypto -import io.iohk.ethereum.domain.{Block, BlockHeader} +import io.iohk.ethereum.domain.Block +import io.iohk.ethereum.domain.BlockHeader import io.iohk.ethereum.jsonrpc.EthMiningService -import io.iohk.ethereum.jsonrpc.EthMiningService.SubmitHashRateRequest import io.iohk.ethereum.utils.BigIntExtensionMethods._ -import io.iohk.ethereum.utils.{ByteStringUtils, ByteUtils, Logger} -import monix.execution.{CancelableFuture, Scheduler} - -import scala.util.Random +import io.iohk.ethereum.utils.ByteUtils +import io.iohk.ethereum.utils.Logger -/** - * Implementation of Ethash CPU mining worker. +/** Implementation of Ethash CPU mining worker. * Could be started by switching configuration flag "consensus.mining-enabled" to true * Implementation explanation at https://eth.wiki/concepts/ethash/ethash */ diff --git a/src/main/scala/io/iohk/ethereum/consensus/pow/miners/KeccakMiner.scala b/src/main/scala/io/iohk/ethereum/consensus/pow/miners/KeccakMiner.scala index 84813b4b10..fc0cd08b39 100644 --- a/src/main/scala/io/iohk/ethereum/consensus/pow/miners/KeccakMiner.scala +++ b/src/main/scala/io/iohk/ethereum/consensus/pow/miners/KeccakMiner.scala @@ -1,19 +1,27 @@ package io.iohk.ethereum.consensus.pow.miners import akka.util.ByteString -import io.iohk.ethereum.blockchain.sync.SyncProtocol -import io.iohk.ethereum.consensus.blocks.{PendingBlock, PendingBlockAndState} + +import monix.execution.CancelableFuture +import monix.execution.Scheduler + +import scala.util.Random + +import io.iohk.ethereum.consensus.blocks.PendingBlock +import io.iohk.ethereum.consensus.blocks.PendingBlockAndState +import io.iohk.ethereum.consensus.pow.KeccakCalculation +import io.iohk.ethereum.consensus.pow.PoWBlockCreator +import io.iohk.ethereum.consensus.pow.PoWMiningCoordinator import io.iohk.ethereum.consensus.pow.PoWMiningCoordinator.CoordinatorProtocol -import io.iohk.ethereum.consensus.pow.miners.MinerProtocol.{MiningResult, MiningSuccessful, MiningUnsuccessful} -import io.iohk.ethereum.consensus.pow.{KeccakCalculation, PoWBlockCreator, PoWMiningCoordinator} -import io.iohk.ethereum.domain.{Block, BlockHeader} +import io.iohk.ethereum.consensus.pow.miners.MinerProtocol.MiningResult +import io.iohk.ethereum.consensus.pow.miners.MinerProtocol.MiningSuccessful +import io.iohk.ethereum.consensus.pow.miners.MinerProtocol.MiningUnsuccessful +import io.iohk.ethereum.domain.Block +import io.iohk.ethereum.domain.BlockHeader import io.iohk.ethereum.jsonrpc.EthMiningService -import io.iohk.ethereum.jsonrpc.EthMiningService.SubmitHashRateRequest import io.iohk.ethereum.utils.BigIntExtensionMethods.BigIntAsUnsigned -import io.iohk.ethereum.utils.{ByteStringUtils, ByteUtils, Logger} -import monix.execution.{CancelableFuture, Scheduler} - -import scala.util.Random +import io.iohk.ethereum.utils.ByteUtils +import io.iohk.ethereum.utils.Logger class KeccakMiner( blockCreator: PoWBlockCreator, diff --git a/src/main/scala/io/iohk/ethereum/consensus/pow/miners/Miner.scala b/src/main/scala/io/iohk/ethereum/consensus/pow/miners/Miner.scala index 40511d45ef..21315263e7 100644 --- a/src/main/scala/io/iohk/ethereum/consensus/pow/miners/Miner.scala +++ b/src/main/scala/io/iohk/ethereum/consensus/pow/miners/Miner.scala @@ -2,15 +2,19 @@ package io.iohk.ethereum.consensus.pow.miners import akka.actor.{ActorRef => ClassicActorRef} import akka.util.ByteString + +import monix.execution.CancelableFuture + import io.iohk.ethereum.blockchain.sync.SyncProtocol import io.iohk.ethereum.consensus.pow.PoWMiningCoordinator import io.iohk.ethereum.consensus.pow.PoWMiningCoordinator.CoordinatorProtocol -import io.iohk.ethereum.consensus.pow.miners.MinerProtocol.{MiningResult, MiningSuccessful} +import io.iohk.ethereum.consensus.pow.miners.MinerProtocol.MiningResult +import io.iohk.ethereum.consensus.pow.miners.MinerProtocol.MiningSuccessful import io.iohk.ethereum.domain.Block import io.iohk.ethereum.jsonrpc.EthMiningService import io.iohk.ethereum.jsonrpc.EthMiningService.SubmitHashRateRequest -import io.iohk.ethereum.utils.{ByteStringUtils, Logger} -import monix.execution.CancelableFuture +import io.iohk.ethereum.utils.ByteStringUtils +import io.iohk.ethereum.utils.Logger trait Miner extends Logger { def processMining(bestBlock: Block): CancelableFuture[CoordinatorProtocol] @@ -19,7 +23,7 @@ trait Miner extends Logger { miningResult: MiningResult, syncController: ClassicActorRef, block: Block - ): CoordinatorProtocol = { + ): CoordinatorProtocol = miningResult match { case MiningSuccessful(_, mixHash, nonce) => log.info( @@ -36,7 +40,6 @@ trait Miner extends Logger { log.info("Mining unsuccessful") PoWMiningCoordinator.MiningUnsuccessful } - } def submitHashRate(ethMiningService: EthMiningService, time: Long, mineResult: MiningResult): Unit = { val hashRate = if (time > 0) (mineResult.triedHashes.toLong * 1000000000) / time else Long.MaxValue diff --git a/src/main/scala/io/iohk/ethereum/consensus/pow/miners/MinerProtocol.scala b/src/main/scala/io/iohk/ethereum/consensus/pow/miners/MinerProtocol.scala index 981a75edec..fc3200b09b 100644 --- a/src/main/scala/io/iohk/ethereum/consensus/pow/miners/MinerProtocol.scala +++ b/src/main/scala/io/iohk/ethereum/consensus/pow/miners/MinerProtocol.scala @@ -2,6 +2,7 @@ package io.iohk.ethereum.consensus.pow.miners import akka.actor.typed.ActorRef import akka.util.ByteString + import io.iohk.ethereum.consensus.pow.PoWMiningCoordinator.CoordinatorProtocol import io.iohk.ethereum.domain.Block diff --git a/src/main/scala/io/iohk/ethereum/consensus/pow/miners/MockedMiner.scala b/src/main/scala/io/iohk/ethereum/consensus/pow/miners/MockedMiner.scala index ecbec0684d..2c4e6c05db 100644 --- a/src/main/scala/io/iohk/ethereum/consensus/pow/miners/MockedMiner.scala +++ b/src/main/scala/io/iohk/ethereum/consensus/pow/miners/MockedMiner.scala @@ -1,28 +1,36 @@ package io.iohk.ethereum.consensus.pow.miners +import akka.actor.Actor +import akka.actor.ActorLogging +import akka.actor.ActorRef +import akka.actor.Props import akka.actor.Status.Failure -import akka.actor.{Actor, ActorLogging, ActorRef, Props} import akka.util.ByteString + +import monix.execution.Scheduler + +import scala.concurrent.duration._ + import io.iohk.ethereum.blockchain.sync.SyncProtocol import io.iohk.ethereum.consensus.blocks.PendingBlockAndState +import io.iohk.ethereum.consensus.pow.PoWBlockCreator +import io.iohk.ethereum.consensus.pow.PoWConsensus import io.iohk.ethereum.consensus.pow.miners.MinerProtocol._ -import io.iohk.ethereum.consensus.pow.miners.MockedMiner.{MineBlock, MineBlocks, MockedMinerProtocol} -import io.iohk.ethereum.consensus.pow.miners.MockedMiner.MockedMinerResponses.{ - MinerIsWorking, - MinerNotSupported, - MiningError, - MiningOrdered -} -import io.iohk.ethereum.consensus.pow.{PoWBlockCreator, PoWConsensus} +import io.iohk.ethereum.consensus.pow.miners.MockedMiner.MineBlock +import io.iohk.ethereum.consensus.pow.miners.MockedMiner.MineBlocks +import io.iohk.ethereum.consensus.pow.miners.MockedMiner.MockedMinerProtocol +import io.iohk.ethereum.consensus.pow.miners.MockedMiner.MockedMinerResponses.MinerIsWorking +import io.iohk.ethereum.consensus.pow.miners.MockedMiner.MockedMinerResponses.MinerNotSupported +import io.iohk.ethereum.consensus.pow.miners.MockedMiner.MockedMinerResponses.MiningError +import io.iohk.ethereum.consensus.pow.miners.MockedMiner.MockedMinerResponses.MiningOrdered import io.iohk.ethereum.consensus.wrongConsensusArgument -import io.iohk.ethereum.domain.{Block, Blockchain, BlockchainReader} +import io.iohk.ethereum.domain.Block +import io.iohk.ethereum.domain.Blockchain +import io.iohk.ethereum.domain.BlockchainReader import io.iohk.ethereum.ledger.InMemoryWorldStateProxy import io.iohk.ethereum.nodebuilder.Node import io.iohk.ethereum.utils.ByteStringUtils import io.iohk.ethereum.utils.ByteStringUtils.ByteStringOps -import monix.execution.Scheduler - -import scala.concurrent.duration._ class MockedMiner( blockchain: Blockchain, @@ -36,12 +44,12 @@ class MockedMiner( override def receive: Receive = stopped - def stopped: Receive = notSupportedMockedMinerMessages orElse { case StartMining => - context become waiting() + def stopped: Receive = notSupportedMockedMinerMessages.orElse { case StartMining => + context.become(waiting()) } def waiting(): Receive = { - case StopMining => context become stopped + case StopMining => context.become(stopped) case mineBlocks: MineBlocks => mineBlocks.parentBlock match { case Some(parentHash) => @@ -76,7 +84,8 @@ class MockedMiner( if (numBlocks > 0) { blockCreator .getBlockForMining(parentBlock, withTransactions, initialWorldStateBeforeExecution) - .runToFuture pipeTo self + .runToFuture + .pipeTo(self) } else { log.info(s"Mining all mocked blocks successful") context.become(waiting()) @@ -124,7 +133,7 @@ object MockedMiner { ) ).withDispatcher(BlockForgerDispatcherId) - def apply(node: Node): ActorRef = { + def apply(node: Node): ActorRef = node.consensus match { case consensus: PoWConsensus => val blockCreator = new PoWBlockCreator( @@ -143,7 +152,6 @@ object MockedMiner { case consensus => wrongConsensusArgument[PoWConsensus](consensus) } - } // TODO to be removed in ETCM-773 sealed trait MockedMinerProtocol extends MinerProtocol diff --git a/src/main/scala/io/iohk/ethereum/consensus/pow/validators/EthashBlockHeaderValidator.scala b/src/main/scala/io/iohk/ethereum/consensus/pow/validators/EthashBlockHeaderValidator.scala index 26b954cae1..f42c5ed8eb 100644 --- a/src/main/scala/io/iohk/ethereum/consensus/pow/validators/EthashBlockHeaderValidator.scala +++ b/src/main/scala/io/iohk/ethereum/consensus/pow/validators/EthashBlockHeaderValidator.scala @@ -2,15 +2,18 @@ package io.iohk.ethereum.consensus.pow package validators import akka.util.ByteString + +import monix.execution.atomic.Atomic +import monix.execution.atomic.AtomicAny + +import io.iohk.ethereum.consensus.validators.BlockHeaderError import io.iohk.ethereum.consensus.validators.BlockHeaderError.HeaderPoWError -import io.iohk.ethereum.consensus.validators.{BlockHeaderError, BlockHeaderValid} +import io.iohk.ethereum.consensus.validators.BlockHeaderValid import io.iohk.ethereum.crypto import io.iohk.ethereum.domain.BlockHeader import io.iohk.ethereum.utils.BlockchainConfig -import monix.execution.atomic.{Atomic, AtomicAny} -/** - * A block header validator for Ethash. +/** A block header validator for Ethash. */ class EthashBlockHeaderValidator(blockchainConfig: BlockchainConfig) { import EthashBlockHeaderValidator._ @@ -19,8 +22,7 @@ class EthashBlockHeaderValidator(blockchainConfig: BlockchainConfig) { // we need atomic since validators can be used from multiple places protected val powCaches: AtomicAny[List[PowCacheData]] = Atomic(List.empty[PowCacheData]) - /** - * Validates [[io.iohk.ethereum.domain.BlockHeader.nonce]] and [[io.iohk.ethereum.domain.BlockHeader.mixHash]] are correct + /** Validates [[io.iohk.ethereum.domain.BlockHeader.nonce]] and [[io.iohk.ethereum.domain.BlockHeader.mixHash]] are correct * based on validations stated in section 4.4.4 of http://paper.gavwood.com/ * * @param blockHeader BlockHeader to validate. @@ -29,7 +31,7 @@ class EthashBlockHeaderValidator(blockchainConfig: BlockchainConfig) { def validateHeader(blockHeader: BlockHeader): Either[BlockHeaderError, BlockHeaderValid] = { import EthashUtils._ - def getPowCacheData(epoch: Long, seed: ByteString): PowCacheData = { + def getPowCacheData(epoch: Long, seed: ByteString): PowCacheData = powCaches.transformAndExtract { cache => cache.find(_.epoch == epoch) match { case Some(pcd) => (pcd, cache) @@ -39,7 +41,6 @@ class EthashBlockHeaderValidator(blockchainConfig: BlockchainConfig) { (data, (data :: cache).take(MaxPowCaches)) } } - } val epoch = EthashUtils.epoch(blockHeader.number.toLong, blockchainConfig.forkBlockNumbers.ecip1099BlockNumber.toLong) diff --git a/src/main/scala/io/iohk/ethereum/consensus/pow/validators/KeccakBlockHeaderValidator.scala b/src/main/scala/io/iohk/ethereum/consensus/pow/validators/KeccakBlockHeaderValidator.scala index 0b939fe0a6..dfdbcf962f 100644 --- a/src/main/scala/io/iohk/ethereum/consensus/pow/validators/KeccakBlockHeaderValidator.scala +++ b/src/main/scala/io/iohk/ethereum/consensus/pow/validators/KeccakBlockHeaderValidator.scala @@ -1,14 +1,14 @@ package io.iohk.ethereum.consensus.pow.validators import io.iohk.ethereum.consensus.pow.KeccakCalculation +import io.iohk.ethereum.consensus.validators.BlockHeaderError import io.iohk.ethereum.consensus.validators.BlockHeaderError.HeaderPoWError -import io.iohk.ethereum.consensus.validators.{BlockHeaderError, BlockHeaderValid} +import io.iohk.ethereum.consensus.validators.BlockHeaderValid import io.iohk.ethereum.domain.BlockHeader object KeccakBlockHeaderValidator { - /** - * Validates [[io.iohk.ethereum.domain.BlockHeader.nonce]] and [[io.iohk.ethereum.domain.BlockHeader.mixHash]] are correct + /** Validates [[io.iohk.ethereum.domain.BlockHeader.nonce]] and [[io.iohk.ethereum.domain.BlockHeader.mixHash]] are correct * @param blockHeader * @return BlockHeaderValid if valid or an BlockHeaderError.HeaderPoWError otherwise */ diff --git a/src/main/scala/io/iohk/ethereum/consensus/pow/validators/MockedPowBlockHeaderValidator.scala b/src/main/scala/io/iohk/ethereum/consensus/pow/validators/MockedPowBlockHeaderValidator.scala index 5b36855e39..0935d55a21 100644 --- a/src/main/scala/io/iohk/ethereum/consensus/pow/validators/MockedPowBlockHeaderValidator.scala +++ b/src/main/scala/io/iohk/ethereum/consensus/pow/validators/MockedPowBlockHeaderValidator.scala @@ -2,7 +2,9 @@ package io.iohk.ethereum.consensus.pow package validators import io.iohk.ethereum.consensus.difficulty.DifficultyCalculator -import io.iohk.ethereum.consensus.validators.{BlockHeaderError, BlockHeaderValid, BlockHeaderValidatorSkeleton} +import io.iohk.ethereum.consensus.validators.BlockHeaderError +import io.iohk.ethereum.consensus.validators.BlockHeaderValid +import io.iohk.ethereum.consensus.validators.BlockHeaderValidatorSkeleton import io.iohk.ethereum.domain.BlockHeader import io.iohk.ethereum.utils.BlockchainConfig diff --git a/src/main/scala/io/iohk/ethereum/consensus/pow/validators/OmmersValidator.scala b/src/main/scala/io/iohk/ethereum/consensus/pow/validators/OmmersValidator.scala index 78ba7ec63e..78398d0834 100644 --- a/src/main/scala/io/iohk/ethereum/consensus/pow/validators/OmmersValidator.scala +++ b/src/main/scala/io/iohk/ethereum/consensus/pow/validators/OmmersValidator.scala @@ -1,10 +1,15 @@ package io.iohk.ethereum.consensus.pow.validators import akka.util.ByteString -import io.iohk.ethereum.consensus.pow.validators.OmmersValidator.{OmmersError, OmmersValid} + +import io.iohk.ethereum.consensus.GetBlockHeaderByHash +import io.iohk.ethereum.consensus.GetNBlocksBack +import io.iohk.ethereum.consensus.pow.validators.OmmersValidator.OmmersError +import io.iohk.ethereum.consensus.pow.validators.OmmersValidator.OmmersValid import io.iohk.ethereum.consensus.validators.BlockHeaderError -import io.iohk.ethereum.consensus.{GetBlockHeaderByHash, GetNBlocksBack} -import io.iohk.ethereum.domain.{Block, BlockHeader, BlockchainReader} +import io.iohk.ethereum.domain.Block +import io.iohk.ethereum.domain.BlockHeader +import io.iohk.ethereum.domain.BlockchainReader trait OmmersValidator { diff --git a/src/main/scala/io/iohk/ethereum/consensus/pow/validators/PoWBlockHeaderValidator.scala b/src/main/scala/io/iohk/ethereum/consensus/pow/validators/PoWBlockHeaderValidator.scala index 5c2421c469..508be568d3 100644 --- a/src/main/scala/io/iohk/ethereum/consensus/pow/validators/PoWBlockHeaderValidator.scala +++ b/src/main/scala/io/iohk/ethereum/consensus/pow/validators/PoWBlockHeaderValidator.scala @@ -1,22 +1,22 @@ package io.iohk.ethereum.consensus.pow.validators import io.iohk.ethereum.consensus.difficulty.DifficultyCalculator -import io.iohk.ethereum.consensus.validators.{BlockHeaderError, BlockHeaderValid, BlockHeaderValidatorSkeleton} +import io.iohk.ethereum.consensus.validators.BlockHeaderError +import io.iohk.ethereum.consensus.validators.BlockHeaderValid +import io.iohk.ethereum.consensus.validators.BlockHeaderValidatorSkeleton import io.iohk.ethereum.domain.BlockHeader import io.iohk.ethereum.utils.BlockchainConfig class PoWBlockHeaderValidator(blockchainConfig: BlockchainConfig) extends BlockHeaderValidatorSkeleton(blockchainConfig) { - /** - * The difficulty calculator. This is specific to the consensus protocol. + /** The difficulty calculator. This is specific to the consensus protocol. */ override protected def difficulty: DifficultyCalculator = DifficultyCalculator(blockchainConfig) private val ethashBlockHeaderValidator = new EthashBlockHeaderValidator(blockchainConfig) - /** - * A hook where even more consensus-specific validation can take place. + /** A hook where even more consensus-specific validation can take place. * For example, PoW validation is done here. */ override protected[validators] def validateEvenMore( @@ -28,6 +28,6 @@ class PoWBlockHeaderValidator(blockchainConfig: BlockchainConfig) private def isKeccak(currentBlockNumber: BigInt): Boolean = blockchainConfig.forkBlockNumbers.ecip1049BlockNumber match { case Some(keccakBlock) => currentBlockNumber >= keccakBlock - case None => false + case None => false } } diff --git a/src/main/scala/io/iohk/ethereum/consensus/pow/validators/RestrictedEthashBlockHeaderValidator.scala b/src/main/scala/io/iohk/ethereum/consensus/pow/validators/RestrictedEthashBlockHeaderValidator.scala index fafb83acbe..57aa38f49d 100644 --- a/src/main/scala/io/iohk/ethereum/consensus/pow/validators/RestrictedEthashBlockHeaderValidator.scala +++ b/src/main/scala/io/iohk/ethereum/consensus/pow/validators/RestrictedEthashBlockHeaderValidator.scala @@ -1,9 +1,12 @@ package io.iohk.ethereum.consensus.pow.validators import akka.util.ByteString + import io.iohk.ethereum.consensus.pow.RestrictedPoWSigner +import io.iohk.ethereum.consensus.validators.BlockHeaderError import io.iohk.ethereum.consensus.validators.BlockHeaderError.RestrictedPoWHeaderExtraDataError -import io.iohk.ethereum.consensus.validators.{BlockHeaderError, BlockHeaderValid, BlockHeaderValidator} +import io.iohk.ethereum.consensus.validators.BlockHeaderValid +import io.iohk.ethereum.consensus.validators.BlockHeaderValidator import io.iohk.ethereum.crypto.ECDSASignature import io.iohk.ethereum.domain.BlockHeader import io.iohk.ethereum.utils.BlockchainConfig @@ -11,7 +14,7 @@ import io.iohk.ethereum.utils.BlockchainConfig class RestrictedEthashBlockHeaderValidator(blockchainConfig: BlockchainConfig) extends PoWBlockHeaderValidator(blockchainConfig) { - val ExtraDataMaxSize = BlockHeaderValidator.MaxExtraDataSize + ECDSASignature.EncodedLength + val ExtraDataMaxSize: Int = BlockHeaderValidator.MaxExtraDataSize + ECDSASignature.EncodedLength private def validateSignatureAgainstAllowedMiners( blockHeader: BlockHeader, diff --git a/src/main/scala/io/iohk/ethereum/consensus/pow/validators/StdOmmersValidator.scala b/src/main/scala/io/iohk/ethereum/consensus/pow/validators/StdOmmersValidator.scala index 5661627ae2..a33fd16468 100644 --- a/src/main/scala/io/iohk/ethereum/consensus/pow/validators/StdOmmersValidator.scala +++ b/src/main/scala/io/iohk/ethereum/consensus/pow/validators/StdOmmersValidator.scala @@ -1,10 +1,15 @@ package io.iohk.ethereum.consensus.pow.validators import akka.util.ByteString + +import io.iohk.ethereum.consensus.GetBlockHeaderByHash +import io.iohk.ethereum.consensus.GetNBlocksBack +import io.iohk.ethereum.consensus.pow.validators.OmmersValidator.OmmersError import io.iohk.ethereum.consensus.pow.validators.OmmersValidator.OmmersError._ -import io.iohk.ethereum.consensus.pow.validators.OmmersValidator.{OmmersError, OmmersValid} -import io.iohk.ethereum.consensus.validators.{BlockHeaderError, BlockHeaderValid, BlockHeaderValidator} -import io.iohk.ethereum.consensus.{GetBlockHeaderByHash, GetNBlocksBack} +import io.iohk.ethereum.consensus.pow.validators.OmmersValidator.OmmersValid +import io.iohk.ethereum.consensus.validators.BlockHeaderError +import io.iohk.ethereum.consensus.validators.BlockHeaderValid +import io.iohk.ethereum.consensus.validators.BlockHeaderValidator import io.iohk.ethereum.domain.BlockHeader class StdOmmersValidator(blockHeaderValidator: BlockHeaderValidator) extends OmmersValidator { @@ -37,8 +42,7 @@ class StdOmmersValidator(blockHeaderValidator: BlockHeaderValidator) extends Omm ommers: Seq[BlockHeader], getBlockHeaderByHash: GetBlockHeaderByHash, getNBlocksBack: GetNBlocksBack - ): Either[OmmersError, OmmersValid] = { - + ): Either[OmmersError, OmmersValid] = if (ommers.isEmpty) Right(OmmersValid) else @@ -49,7 +53,6 @@ class StdOmmersValidator(blockHeaderValidator: BlockHeaderValidator) extends Omm _ <- validateOmmersAncestors(parentHash, blockNumber, ommers, getNBlocksBack) _ <- validateOmmersNotUsed(parentHash, blockNumber, ommers, getNBlocksBack) } yield OmmersValid - } /** Validates ommers length based on validations stated in section 11.1 of the YP * @@ -57,10 +60,9 @@ class StdOmmersValidator(blockHeaderValidator: BlockHeaderValidator) extends Omm * * @return [[OmmersValidator.OmmersValid]] if valid, an [[OmmersValidator.OmmersError.OmmersLengthError]] otherwise */ - private def validateOmmersLength(ommers: Seq[BlockHeader]): Either[OmmersError, OmmersValid] = { + private def validateOmmersLength(ommers: Seq[BlockHeader]): Either[OmmersError, OmmersValid] = if (ommers.length <= OmmerSizeLimit) Right(OmmersValid) else Left(OmmersLengthError) - } /** Validates that each ommer's header is valid based on validations stated in section 11.1 of the YP * @@ -142,10 +144,9 @@ class StdOmmersValidator(blockHeaderValidator: BlockHeaderValidator) extends Omm * @param ommers the list of ommers to validate * @return [[OmmersValidator.OmmersValid]] if valid, an [[OmmersValidator.OmmersError.OmmersDuplicatedError]] otherwise */ - private def validateDuplicatedOmmers(ommers: Seq[BlockHeader]): Either[OmmersError, OmmersValid] = { + private def validateDuplicatedOmmers(ommers: Seq[BlockHeader]): Either[OmmersError, OmmersValid] = if (ommers.distinct.length == ommers.length) Right(OmmersValid) else Left(OmmersDuplicatedError) - } private def collectAncestors( parentHash: ByteString, diff --git a/src/main/scala/io/iohk/ethereum/consensus/pow/validators/StdValidatorsExecutor.scala b/src/main/scala/io/iohk/ethereum/consensus/pow/validators/StdValidatorsExecutor.scala index 2108312ad8..a394cbf975 100644 --- a/src/main/scala/io/iohk/ethereum/consensus/pow/validators/StdValidatorsExecutor.scala +++ b/src/main/scala/io/iohk/ethereum/consensus/pow/validators/StdValidatorsExecutor.scala @@ -1,9 +1,10 @@ package io.iohk.ethereum.consensus.pow.validators -import io.iohk.ethereum.consensus.validators.{BlockHeaderValidator, BlockValidator, SignedTransactionValidator} +import io.iohk.ethereum.consensus.validators.BlockHeaderValidator +import io.iohk.ethereum.consensus.validators.BlockValidator +import io.iohk.ethereum.consensus.validators.SignedTransactionValidator -/** - * Implements validators that adhere to the PoW-specific +/** Implements validators that adhere to the PoW-specific * [[io.iohk.ethereum.consensus.pow.validators.ValidatorsExecutor]] * interface. */ diff --git a/src/main/scala/io/iohk/ethereum/consensus/pow/validators/ValidatorsExecutor.scala b/src/main/scala/io/iohk/ethereum/consensus/pow/validators/ValidatorsExecutor.scala index ad40ad2fc6..390f59cfc2 100644 --- a/src/main/scala/io/iohk/ethereum/consensus/pow/validators/ValidatorsExecutor.scala +++ b/src/main/scala/io/iohk/ethereum/consensus/pow/validators/ValidatorsExecutor.scala @@ -1,12 +1,20 @@ package io.iohk.ethereum.consensus.pow.validators import akka.util.ByteString -import io.iohk.ethereum.consensus.{GetBlockHeaderByHash, GetNBlocksBack, Protocol} -import io.iohk.ethereum.consensus.validators.std.{StdBlockValidator, StdSignedTransactionValidator, StdValidators} -import io.iohk.ethereum.consensus.validators.{BlockHeaderValidator, Validators} -import io.iohk.ethereum.domain.{Block, Receipt} + +import io.iohk.ethereum.consensus.GetBlockHeaderByHash +import io.iohk.ethereum.consensus.GetNBlocksBack +import io.iohk.ethereum.consensus.Protocol +import io.iohk.ethereum.consensus.validators.BlockHeaderValidator +import io.iohk.ethereum.consensus.validators.Validators +import io.iohk.ethereum.consensus.validators.std.StdBlockValidator +import io.iohk.ethereum.consensus.validators.std.StdSignedTransactionValidator +import io.iohk.ethereum.consensus.validators.std.StdValidators +import io.iohk.ethereum.domain.Block +import io.iohk.ethereum.domain.Receipt +import io.iohk.ethereum.ledger.BlockExecutionError import io.iohk.ethereum.ledger.BlockExecutionError.ValidationBeforeExecError -import io.iohk.ethereum.ledger.{BlockExecutionError, BlockExecutionSuccess} +import io.iohk.ethereum.ledger.BlockExecutionSuccess import io.iohk.ethereum.utils.BlockchainConfig trait ValidatorsExecutor extends Validators { @@ -16,23 +24,20 @@ trait ValidatorsExecutor extends Validators { block: Block, getBlockHeaderByHash: GetBlockHeaderByHash, getNBlocksBack: GetNBlocksBack - ): Either[BlockExecutionError.ValidationBeforeExecError, BlockExecutionSuccess] = { - + ): Either[BlockExecutionError.ValidationBeforeExecError, BlockExecutionSuccess] = ValidatorsExecutor.validateBlockBeforeExecution( self = this, block = block, getBlockHeaderByHash = getBlockHeaderByHash, getNBlocksBack = getNBlocksBack ) - } def validateBlockAfterExecution( block: Block, stateRootHash: ByteString, receipts: Seq[Receipt], gasUsed: BigInt - ): Either[BlockExecutionError, BlockExecutionSuccess] = { - + ): Either[BlockExecutionError, BlockExecutionSuccess] = ValidatorsExecutor.validateBlockAfterExecution( self = this, block = block, @@ -40,14 +45,13 @@ trait ValidatorsExecutor extends Validators { receipts = receipts, gasUsed = gasUsed ) - } } object ValidatorsExecutor { def apply(blockchainConfig: BlockchainConfig, protocol: Protocol): ValidatorsExecutor = { val blockHeaderValidator: BlockHeaderValidator = protocol match { - case Protocol.MockedPow => new MockedPowBlockHeaderValidator(blockchainConfig) - case Protocol.PoW => new PoWBlockHeaderValidator(blockchainConfig) + case Protocol.MockedPow => new MockedPowBlockHeaderValidator(blockchainConfig) + case Protocol.PoW => new PoWBlockHeaderValidator(blockchainConfig) case Protocol.RestrictedPoW => new RestrictedEthashBlockHeaderValidator(blockchainConfig) } @@ -61,14 +65,13 @@ object ValidatorsExecutor { // Created only for testing purposes, shouldn't be used in production code. // Connected with: https://github.com/ethereum/tests/issues/480 - def apply(blockchainConfig: BlockchainConfig, blockHeaderValidator: BlockHeaderValidator): ValidatorsExecutor = { + def apply(blockchainConfig: BlockchainConfig, blockHeaderValidator: BlockHeaderValidator): ValidatorsExecutor = new StdValidatorsExecutor( StdBlockValidator, blockHeaderValidator, new StdSignedTransactionValidator(blockchainConfig), new StdOmmersValidator(blockHeaderValidator) ) - } def validateBlockBeforeExecution( self: ValidatorsExecutor, @@ -101,8 +104,7 @@ object ValidatorsExecutor { stateRootHash: ByteString, receipts: Seq[Receipt], gasUsed: BigInt - ): Either[BlockExecutionError, BlockExecutionSuccess] = { - + ): Either[BlockExecutionError, BlockExecutionSuccess] = StdValidators.validateBlockAfterExecution( self = self, block = block, @@ -110,5 +112,4 @@ object ValidatorsExecutor { receipts = receipts, gasUsed = gasUsed ) - } } diff --git a/src/main/scala/io/iohk/ethereum/consensus/validators/BlockHeaderValidator.scala b/src/main/scala/io/iohk/ethereum/consensus/validators/BlockHeaderValidator.scala index 9627f3c518..296fd6adcc 100644 --- a/src/main/scala/io/iohk/ethereum/consensus/validators/BlockHeaderValidator.scala +++ b/src/main/scala/io/iohk/ethereum/consensus/validators/BlockHeaderValidator.scala @@ -5,8 +5,7 @@ import io.iohk.ethereum.crypto.ECDSASignature import io.iohk.ethereum.domain.BlockHeader import io.iohk.ethereum.domain.BlockHeader.HeaderExtraFields -/** - * Validates a [[io.iohk.ethereum.domain.BlockHeader BlockHeader]]. +/** Validates a [[io.iohk.ethereum.domain.BlockHeader BlockHeader]]. */ trait BlockHeaderValidator { def validate( diff --git a/src/main/scala/io/iohk/ethereum/consensus/validators/BlockHeaderValidatorSkeleton.scala b/src/main/scala/io/iohk/ethereum/consensus/validators/BlockHeaderValidatorSkeleton.scala index e8ef07fac4..1d98f05d87 100644 --- a/src/main/scala/io/iohk/ethereum/consensus/validators/BlockHeaderValidatorSkeleton.scala +++ b/src/main/scala/io/iohk/ethereum/consensus/validators/BlockHeaderValidatorSkeleton.scala @@ -4,11 +4,12 @@ import io.iohk.ethereum.consensus.GetBlockHeaderByHash import io.iohk.ethereum.consensus.difficulty.DifficultyCalculator import io.iohk.ethereum.consensus.validators.BlockHeaderError._ import io.iohk.ethereum.domain.BlockHeader -import io.iohk.ethereum.domain.BlockHeader.HeaderExtraFields.{HefEmpty, HefPostEcip1097} -import io.iohk.ethereum.utils.{BlockchainConfig, DaoForkConfig} +import io.iohk.ethereum.domain.BlockHeader.HeaderExtraFields.HefEmpty +import io.iohk.ethereum.domain.BlockHeader.HeaderExtraFields.HefPostEcip1097 +import io.iohk.ethereum.utils.BlockchainConfig +import io.iohk.ethereum.utils.DaoForkConfig -/** - * A block header validator that does everything Ethereum prescribes except from: +/** A block header validator that does everything Ethereum prescribes except from: * - PoW validation * - Difficulty validation. * @@ -24,13 +25,11 @@ abstract class BlockHeaderValidatorSkeleton(blockchainConfig: BlockchainConfig) private val blockWithCheckpointHeaderValidator = new BlockWithCheckpointHeaderValidator(blockchainConfig) - /** - * The difficulty calculator. This is specific to the consensus protocol. + /** The difficulty calculator. This is specific to the consensus protocol. */ protected def difficulty: DifficultyCalculator - /** - * A hook where even more consensus-specific validation can take place. + /** A hook where even more consensus-specific validation can take place. * For example, PoW validation is done here. */ protected def validateEvenMore(blockHeader: BlockHeader): Either[BlockHeaderError, BlockHeaderValid] @@ -41,10 +40,9 @@ abstract class BlockHeaderValidatorSkeleton(blockchainConfig: BlockchainConfig) * @param blockHeader BlockHeader to validate. * @param parentHeader BlockHeader of the parent of the block to validate. */ - def validate(blockHeader: BlockHeader, parentHeader: BlockHeader): Either[BlockHeaderError, BlockHeaderValid] = { + def validate(blockHeader: BlockHeader, parentHeader: BlockHeader): Either[BlockHeaderError, BlockHeaderValid] = if (blockHeader.hasCheckpoint) validateBlockWithCheckpointHeader(blockHeader, parentHeader) else validateRegularHeader(blockHeader, parentHeader) - } /** This method allows validate a BlockHeader (stated on * section 4.4.4 of http://paper.gavwood.com/). @@ -55,14 +53,13 @@ abstract class BlockHeaderValidatorSkeleton(blockchainConfig: BlockchainConfig) override def validate( blockHeader: BlockHeader, getBlockHeaderByHash: GetBlockHeaderByHash - ): Either[BlockHeaderError, BlockHeaderValid] = { + ): Either[BlockHeaderError, BlockHeaderValid] = for { blockHeaderParent <- getBlockHeaderByHash(blockHeader.parentHash) .map(Right(_)) .getOrElse(Left(HeaderParentNotFoundError)) _ <- validate(blockHeader, blockHeaderParent) } yield BlockHeaderValid - } /** This method runs a validation of the header of regular block. * It runs basic validation and pow validation (hidden in validateEvenMore) @@ -73,7 +70,7 @@ abstract class BlockHeaderValidatorSkeleton(blockchainConfig: BlockchainConfig) private def validateRegularHeader( blockHeader: BlockHeader, parentHeader: BlockHeader - ): Either[BlockHeaderError, BlockHeaderValid] = { + ): Either[BlockHeaderError, BlockHeaderValid] = for { // NOTE how we include everything except PoW (which is deferred to `validateEvenMore`), // and that difficulty validation is in effect abstract (due to `difficulty`). @@ -86,7 +83,6 @@ abstract class BlockHeaderValidatorSkeleton(blockchainConfig: BlockchainConfig) _ <- validateExtraFields(blockHeader) _ <- validateEvenMore(blockHeader) } yield BlockHeaderValid - } /** This method runs a validation of the header of block with checkpoint. * It runs basic validation and checkpoint specific validation @@ -97,16 +93,14 @@ abstract class BlockHeaderValidatorSkeleton(blockchainConfig: BlockchainConfig) private def validateBlockWithCheckpointHeader( blockHeader: BlockHeader, parentHeader: BlockHeader - ): Either[BlockHeaderError, BlockHeaderValid] = { + ): Either[BlockHeaderError, BlockHeaderValid] = for { _ <- blockWithCheckpointHeaderValidator.validate(blockHeader, parentHeader) _ <- validateNumber(blockHeader, parentHeader) _ <- validateExtraFields(blockHeader) } yield BlockHeaderValid - } - /** - * Validates [[io.iohk.ethereum.domain.BlockHeader.extraData]] length + /** Validates [[io.iohk.ethereum.domain.BlockHeader.extraData]] length * based on validations stated in section 4.4.4 of http://paper.gavwood.com/ * * @param blockHeader BlockHeader to validate. @@ -118,7 +112,7 @@ abstract class BlockHeaderValidatorSkeleton(blockchainConfig: BlockchainConfig) blockHeader: BlockHeader, daoForkConfig: DaoForkConfig ): Either[BlockHeaderError, BlockHeaderValid] = - (daoForkConfig requiresExtraData blockHeader.number, daoForkConfig.blockExtraData) match { + (daoForkConfig.requiresExtraData(blockHeader.number), daoForkConfig.blockExtraData) match { case (false, _) => Right(BlockHeaderValid) case (true, Some(forkExtraData)) if blockHeader.extraData == forkExtraData => @@ -135,8 +129,7 @@ abstract class BlockHeaderValidatorSkeleton(blockchainConfig: BlockchainConfig) } } - /** - * Validates [[io.iohk.ethereum.domain.BlockHeader.unixTimestamp]] is greater than the one of its parent + /** Validates [[io.iohk.ethereum.domain.BlockHeader.unixTimestamp]] is greater than the one of its parent * based on validations stated in section 4.4.4 of http://paper.gavwood.com/ * * @param blockHeader BlockHeader to validate. @@ -150,8 +143,7 @@ abstract class BlockHeaderValidatorSkeleton(blockchainConfig: BlockchainConfig) if (blockHeader.unixTimestamp > parentHeader.unixTimestamp) Right(BlockHeaderValid) else Left(HeaderTimestampError) - /** - * Validates [[io.iohk.ethereum.domain.BlockHeader.difficulty]] is correct + /** Validates [[io.iohk.ethereum.domain.BlockHeader.difficulty]] is correct * based on validations stated in section 4.4.4 of http://paper.gavwood.com/ * * @param blockHeader BlockHeader to validate. @@ -166,8 +158,7 @@ abstract class BlockHeaderValidatorSkeleton(blockchainConfig: BlockchainConfig) Right(BlockHeaderValid) else Left(HeaderDifficultyError) - /** - * Validates [[io.iohk.ethereum.domain.BlockHeader.gasUsed]] is not greater than [[io.iohk.ethereum.domain.BlockHeader.gasLimit]] + /** Validates [[io.iohk.ethereum.domain.BlockHeader.gasUsed]] is not greater than [[io.iohk.ethereum.domain.BlockHeader.gasLimit]] * based on validations stated in section 4.4.4 of http://paper.gavwood.com/ * * @param blockHeader BlockHeader to validate. @@ -177,8 +168,7 @@ abstract class BlockHeaderValidatorSkeleton(blockchainConfig: BlockchainConfig) if (blockHeader.gasUsed <= blockHeader.gasLimit && blockHeader.gasUsed >= 0) Right(BlockHeaderValid) else Left(HeaderGasUsedError) - /** - * Validates [[io.iohk.ethereum.domain.BlockHeader.gasLimit]] follows the restrictions based on its parent gasLimit + /** Validates [[io.iohk.ethereum.domain.BlockHeader.gasLimit]] follows the restrictions based on its parent gasLimit * based on validations stated in section 4.4.4 of http://paper.gavwood.com/ * * EIP106(https://github.com/ethereum/EIPs/issues/106) adds additional validation of maximum value for gasLimit. @@ -190,8 +180,7 @@ abstract class BlockHeaderValidatorSkeleton(blockchainConfig: BlockchainConfig) private def validateGasLimit( blockHeader: BlockHeader, parentHeader: BlockHeader - ): Either[BlockHeaderError, BlockHeaderValid] = { - + ): Either[BlockHeaderError, BlockHeaderValid] = if (blockHeader.gasLimit > MaxGasLimit && blockHeader.number >= blockchainConfig.forkBlockNumbers.eip106BlockNumber) Left(HeaderGasLimitError) else { @@ -202,10 +191,8 @@ abstract class BlockHeaderValidatorSkeleton(blockchainConfig: BlockchainConfig) else Left(HeaderGasLimitError) } - } - /** - * Validates [[io.iohk.ethereum.domain.BlockHeader.number]] is the next one after its parents number + /** Validates [[io.iohk.ethereum.domain.BlockHeader.number]] is the next one after its parents number * based on validations stated in section 4.4.4 of http://paper.gavwood.com/ * * @param blockHeader BlockHeader to validate. @@ -219,8 +206,7 @@ abstract class BlockHeaderValidatorSkeleton(blockchainConfig: BlockchainConfig) if (blockHeader.number == parentHeader.number + 1) Right(BlockHeaderValid) else Left(HeaderNumberError) - /** - * Validates [[io.iohk.ethereum.domain.BlockHeader.extraFields]] match the ECIP1097 and ECIP1098 enabling configuration + /** Validates [[io.iohk.ethereum.domain.BlockHeader.extraFields]] match the ECIP1097 and ECIP1098 enabling configuration * * @param blockHeader BlockHeader to validate. * @return BlockHeader if valid, an [[HeaderExtraFieldsError]] otherwise @@ -231,20 +217,19 @@ abstract class BlockHeaderValidatorSkeleton(blockchainConfig: BlockchainConfig) blockHeader.extraFields match { case HefPostEcip1097(_) if isECIP1097Activated && isECIP1098Activated => Right(BlockHeaderValid) - case HefEmpty if !isECIP1097Activated && isECIP1098Activated => Right(BlockHeaderValid) - case HefEmpty if !isECIP1097Activated && !isECIP1098Activated => Right(BlockHeaderValid) + case HefEmpty if !isECIP1097Activated && isECIP1098Activated => Right(BlockHeaderValid) + case HefEmpty if !isECIP1097Activated && !isECIP1098Activated => Right(BlockHeaderValid) case _ => val error = HeaderExtraFieldsError(blockHeader.extraFields, isECIP1097Activated, isECIP1098Activated) Left(error) } } - override def validateHeaderOnly(blockHeader: BlockHeader): Either[BlockHeaderError, BlockHeaderValid] = { + override def validateHeaderOnly(blockHeader: BlockHeader): Either[BlockHeaderError, BlockHeaderValid] = for { _ <- validateExtraData(blockHeader) _ <- validateGasUsed(blockHeader) _ <- validateExtraFields(blockHeader) _ <- validateEvenMore(blockHeader) } yield BlockHeaderValid - } } diff --git a/src/main/scala/io/iohk/ethereum/consensus/validators/BlockValidator.scala b/src/main/scala/io/iohk/ethereum/consensus/validators/BlockValidator.scala index 6fec110193..ff1bc01357 100644 --- a/src/main/scala/io/iohk/ethereum/consensus/validators/BlockValidator.scala +++ b/src/main/scala/io/iohk/ethereum/consensus/validators/BlockValidator.scala @@ -1,7 +1,10 @@ package io.iohk.ethereum.consensus.validators -import io.iohk.ethereum.consensus.validators.std.StdBlockValidator.{BlockError, BlockValid} -import io.iohk.ethereum.domain.{BlockHeader, BlockBody, Receipt} +import io.iohk.ethereum.consensus.validators.std.StdBlockValidator.BlockError +import io.iohk.ethereum.consensus.validators.std.StdBlockValidator.BlockValid +import io.iohk.ethereum.domain.BlockBody +import io.iohk.ethereum.domain.BlockHeader +import io.iohk.ethereum.domain.Receipt trait BlockValidator { def validateHeaderAndBody(blockHeader: BlockHeader, blockBody: BlockBody): Either[BlockError, BlockValid] diff --git a/src/main/scala/io/iohk/ethereum/consensus/validators/BlockWithCheckpointHeaderValidator.scala b/src/main/scala/io/iohk/ethereum/consensus/validators/BlockWithCheckpointHeaderValidator.scala index b013e8e3cd..c0866515fd 100644 --- a/src/main/scala/io/iohk/ethereum/consensus/validators/BlockWithCheckpointHeaderValidator.scala +++ b/src/main/scala/io/iohk/ethereum/consensus/validators/BlockWithCheckpointHeaderValidator.scala @@ -3,7 +3,8 @@ package io.iohk.ethereum.consensus.validators import io.iohk.ethereum.consensus.validators.BlockHeaderError._ import io.iohk.ethereum.domain.BlockHeader import io.iohk.ethereum.ledger.BloomFilter -import io.iohk.ethereum.utils.{BlockchainConfig, ByteStringUtils} +import io.iohk.ethereum.utils.BlockchainConfig +import io.iohk.ethereum.utils.ByteStringUtils /** Validator specialized for the block with checkpoint * @@ -11,7 +12,7 @@ import io.iohk.ethereum.utils.{BlockchainConfig, ByteStringUtils} */ class BlockWithCheckpointHeaderValidator(blockchainConfig: BlockchainConfig) { - def validate(blockHeader: BlockHeader, parentHeader: BlockHeader): Either[BlockHeaderError, BlockHeaderValid] = { + def validate(blockHeader: BlockHeader, parentHeader: BlockHeader): Either[BlockHeaderError, BlockHeaderValid] = for { _ <- validateLexicographicalOrderOfSignatures(blockHeader) _ <- validateCheckpointSignatures(blockHeader, parentHeader) @@ -20,7 +21,6 @@ class BlockWithCheckpointHeaderValidator(blockchainConfig: BlockchainConfig) { _ <- validateGasUsed(blockHeader) _ <- validateTimestamp(blockHeader, parentHeader) } yield BlockHeaderValid - } private def validateLexicographicalOrderOfSignatures( header: BlockHeader @@ -35,8 +35,7 @@ class BlockWithCheckpointHeaderValidator(blockchainConfig: BlockchainConfig) { .getOrElse(Left(BlockWithCheckpointHeaderValidator.NoCheckpointInHeaderError)) } - /** - * Validates [[io.iohk.ethereum.domain.BlockHeader.checkpoint]] signatures + /** Validates [[io.iohk.ethereum.domain.BlockHeader.checkpoint]] signatures * * @param blockHeader BlockHeader to validate. * @param parentHeader BlockHeader of the parent of the block to validate. @@ -45,7 +44,7 @@ class BlockWithCheckpointHeaderValidator(blockchainConfig: BlockchainConfig) { private def validateCheckpointSignatures( blockHeader: BlockHeader, parentHeader: BlockHeader - ): Either[BlockHeaderError, BlockHeaderValid] = { + ): Either[BlockHeaderError, BlockHeaderValid] = blockHeader.checkpoint .map { checkpoint => lazy val signaturesWithRecoveredKeys = checkpoint.signatures.map(s => s -> s.publicKey(parentHeader.hash)) @@ -61,7 +60,7 @@ class BlockWithCheckpointHeaderValidator(blockchainConfig: BlockchainConfig) { lazy val (validSignatures, invalidSignatures) = signaturesWithRecoveredKeys.partition { //signatures are valid if the signers are known AND distinct case (sig, Some(pk)) => blockchainConfig.checkpointPubKeys.contains(pk) && !repeatedSigners.contains(pk) - case _ => false + case _ => false } // we fail fast if there are too many signatures (DoS protection) @@ -78,10 +77,8 @@ class BlockWithCheckpointHeaderValidator(blockchainConfig: BlockchainConfig) { Right(BlockHeaderValid) } .getOrElse(Left(BlockWithCheckpointHeaderValidator.NoCheckpointInHeaderError)) - } - /** - * Validates emptiness of: + /** Validates emptiness of: * - beneficiary * - extraData * - treasuryOptOut @@ -95,7 +92,7 @@ class BlockWithCheckpointHeaderValidator(blockchainConfig: BlockchainConfig) { * @param blockHeader BlockHeader to validate. * @return BlockHeader if valid, an [[io.iohk.ethereum.consensus.validators.BlockHeaderError.HeaderFieldNotEmptyError]] otherwise */ - private def validateEmptyFields(blockHeader: BlockHeader): Either[BlockHeaderError, BlockHeaderValid] = { + private def validateEmptyFields(blockHeader: BlockHeader): Either[BlockHeaderError, BlockHeaderValid] = if (blockHeader.beneficiary != BlockHeader.EmptyBeneficiary) notEmptyFieldError("beneficiary") else if (blockHeader.ommersHash != BlockHeader.EmptyOmmers) @@ -113,12 +110,10 @@ class BlockWithCheckpointHeaderValidator(blockchainConfig: BlockchainConfig) { else if (blockHeader.mixHash.nonEmpty) notEmptyFieldError("mixHash") else Right(BlockHeaderValid) - } private def notEmptyFieldError(field: String) = Left(HeaderFieldNotEmptyError(s"$field is not empty")) - /** - * Validates fields which should be equal to parent equivalents: + /** Validates fields which should be equal to parent equivalents: * - stateRoot * * @param blockHeader BlockHeader to validate. @@ -128,7 +123,7 @@ class BlockWithCheckpointHeaderValidator(blockchainConfig: BlockchainConfig) { private def validateFieldsCopiedFromParent( blockHeader: BlockHeader, parentHeader: BlockHeader - ): Either[BlockHeaderError, BlockHeaderValid] = { + ): Either[BlockHeaderError, BlockHeaderValid] = if (blockHeader.stateRoot != parentHeader.stateRoot) fieldNotMatchedParentFieldError("stateRoot") else if (blockHeader.gasLimit != parentHeader.gasLimit) @@ -136,23 +131,19 @@ class BlockWithCheckpointHeaderValidator(blockchainConfig: BlockchainConfig) { else if (blockHeader.difficulty != parentHeader.difficulty) fieldNotMatchedParentFieldError("difficulty") else Right(BlockHeaderValid) - } private def fieldNotMatchedParentFieldError(field: String) = Left(HeaderNotMatchParentError(s"$field has different value that similar parent field")) - /** - * Validates gasUsed equal to zero + /** Validates gasUsed equal to zero * @param blockHeader BlockHeader to validate. * @return BlockHeader if valid, an [[io.iohk.ethereum.consensus.validators.BlockHeaderError.HeaderGasUsedError]] otherwise */ - private def validateGasUsed(blockHeader: BlockHeader): Either[BlockHeaderError, BlockHeaderValid] = { + private def validateGasUsed(blockHeader: BlockHeader): Either[BlockHeaderError, BlockHeaderValid] = if (blockHeader.gasUsed != BigInt(0)) Left(HeaderGasUsedError) else Right(BlockHeaderValid) - } - /** - * Validates [[io.iohk.ethereum.domain.BlockHeader.unixTimestamp]] is one bigger than parent unixTimestamp + /** Validates [[io.iohk.ethereum.domain.BlockHeader.unixTimestamp]] is one bigger than parent unixTimestamp * * @param blockHeader BlockHeader to validate. * @param parentHeader BlockHeader of the parent of the block to validate. diff --git a/src/main/scala/io/iohk/ethereum/consensus/validators/Validators.scala b/src/main/scala/io/iohk/ethereum/consensus/validators/Validators.scala index 3260fb616c..1fb27681ea 100644 --- a/src/main/scala/io/iohk/ethereum/consensus/validators/Validators.scala +++ b/src/main/scala/io/iohk/ethereum/consensus/validators/Validators.scala @@ -1,10 +1,14 @@ package io.iohk.ethereum.consensus.validators import akka.util.ByteString -import io.iohk.ethereum.consensus.{GetBlockHeaderByHash, GetNBlocksBack} -import io.iohk.ethereum.domain.{Block, Receipt} + +import io.iohk.ethereum.consensus.GetBlockHeaderByHash +import io.iohk.ethereum.consensus.GetNBlocksBack +import io.iohk.ethereum.domain.Block +import io.iohk.ethereum.domain.Receipt +import io.iohk.ethereum.ledger.BlockExecutionError import io.iohk.ethereum.ledger.BlockExecutionError.ValidationBeforeExecError -import io.iohk.ethereum.ledger.{BlockExecutionError, BlockExecutionSuccess} +import io.iohk.ethereum.ledger.BlockExecutionSuccess trait Validators { def blockValidator: BlockValidator diff --git a/src/main/scala/io/iohk/ethereum/consensus/validators/std/MptListValidator.scala b/src/main/scala/io/iohk/ethereum/consensus/validators/std/MptListValidator.scala index 30cfc10e31..c3592ac21c 100644 --- a/src/main/scala/io/iohk/ethereum/consensus/validators/std/MptListValidator.scala +++ b/src/main/scala/io/iohk/ethereum/consensus/validators/std/MptListValidator.scala @@ -3,19 +3,20 @@ package std import io.iohk.ethereum.db.dataSource.EphemDataSource import io.iohk.ethereum.db.storage.StateStorage -import io.iohk.ethereum.mpt.{ByteArraySerializable, MerklePatriciaTrie} +import io.iohk.ethereum.mpt.ByteArraySerializable +import io.iohk.ethereum.mpt.MerklePatriciaTrie import io.iohk.ethereum.rlp.RLPImplicits._ -import io.iohk.ethereum.rlp.{decode, encode} +import io.iohk.ethereum.rlp.decode +import io.iohk.ethereum.rlp.encode object MptListValidator { - lazy val intByteArraySerializable = new ByteArraySerializable[Int] { + lazy val intByteArraySerializable: ByteArraySerializable[Int] = new ByteArraySerializable[Int] { override def fromBytes(bytes: Array[Byte]): Int = decode[Int](bytes) override def toBytes(input: Int): Array[Byte] = encode(input) } - /** - * This function validates if a lists matches a Mpt Hash. To do so it inserts into an ephemeral MPT + /** This function validates if a lists matches a Mpt Hash. To do so it inserts into an ephemeral MPT * (itemIndex, item) tuples and validates the resulting hash * * @param hash Hash to expect @@ -29,7 +30,7 @@ object MptListValidator { val trie = MerklePatriciaTrie[Int, K]( source = stateStorage )(intByteArraySerializable, vSerializable) - val trieRoot = toValidate.zipWithIndex.foldLeft(trie) { (trie, r) => trie.put(r._2, r._1) }.getRootHash - hash sameElements trieRoot + val trieRoot = toValidate.zipWithIndex.foldLeft(trie)((trie, r) => trie.put(r._2, r._1)).getRootHash + hash.sameElements(trieRoot) } } diff --git a/src/main/scala/io/iohk/ethereum/consensus/validators/std/StdBlockValidator.scala b/src/main/scala/io/iohk/ethereum/consensus/validators/std/StdBlockValidator.scala index f54d1f9930..a389e744d9 100644 --- a/src/main/scala/io/iohk/ethereum/consensus/validators/std/StdBlockValidator.scala +++ b/src/main/scala/io/iohk/ethereum/consensus/validators/std/StdBlockValidator.scala @@ -1,17 +1,21 @@ package io.iohk.ethereum.consensus.validators.std import akka.util.ByteString + import io.iohk.ethereum.consensus.pow.blocks.OmmersSeqEnc import io.iohk.ethereum.consensus.validators.BlockValidator import io.iohk.ethereum.crypto._ -import io.iohk.ethereum.domain.{Block, BlockBody, BlockHeader, Receipt, SignedTransaction} +import io.iohk.ethereum.domain.Block +import io.iohk.ethereum.domain.BlockBody +import io.iohk.ethereum.domain.BlockHeader +import io.iohk.ethereum.domain.Receipt +import io.iohk.ethereum.domain.SignedTransaction import io.iohk.ethereum.ledger.BloomFilter import io.iohk.ethereum.utils.ByteUtils.or object StdBlockValidator extends BlockValidator { - /** - * Validates [[io.iohk.ethereum.domain.BlockHeader.transactionsRoot]] matches [[BlockBody.transactionList]] + /** Validates [[io.iohk.ethereum.domain.BlockHeader.transactionsRoot]] matches [[BlockBody.transactionList]] * based on validations stated in section 4.4.2 of http://paper.gavwood.com/ * * @param block Block to validate @@ -27,8 +31,7 @@ object StdBlockValidator extends BlockValidator { else Left(BlockTransactionsHashError) } - /** - * Validates [[BlockBody.uncleNodesList]] against [[io.iohk.ethereum.domain.BlockHeader.ommersHash]] + /** Validates [[BlockBody.uncleNodesList]] against [[io.iohk.ethereum.domain.BlockHeader.ommersHash]] * based on validations stated in section 4.4.2 of http://paper.gavwood.com/ * * @param block Block to validate @@ -36,12 +39,11 @@ object StdBlockValidator extends BlockValidator { */ private def validateOmmersHash(block: Block): Either[BlockError, BlockValid] = { val encodedOmmers: Array[Byte] = block.body.uncleNodesList.toBytes - if (kec256(encodedOmmers) sameElements block.header.ommersHash) Right(BlockValid) + if (kec256(encodedOmmers).sameElements(block.header.ommersHash)) Right(BlockValid) else Left(BlockOmmersHashError) } - /** - * Validates [[Receipt]] against [[io.iohk.ethereum.domain.BlockHeader.receiptsRoot]] + /** Validates [[Receipt]] against [[io.iohk.ethereum.domain.BlockHeader.receiptsRoot]] * based on validations stated in section 4.4.2 of http://paper.gavwood.com/ * * @param blockHeader Block header to validate @@ -56,8 +58,7 @@ object StdBlockValidator extends BlockValidator { else Left(BlockReceiptsHashError) } - /** - * Validates [[io.iohk.ethereum.domain.BlockHeader.logsBloom]] against [[Receipt.logsBloomFilter]] + /** Validates [[io.iohk.ethereum.domain.BlockHeader.logsBloom]] against [[Receipt.logsBloomFilter]] * based on validations stated in section 4.4.2 of http://paper.gavwood.com/ * * @param blockHeader Block header to validate @@ -72,43 +73,36 @@ object StdBlockValidator extends BlockValidator { else Left(BlockLogBloomError) } - /** - * Validates that the block body does not contain transactions + /** Validates that the block body does not contain transactions * * @param blockBody BlockBody to validate * @return BlockValid if there are no transactions, error otherwise */ - private def validateNoTransactions(blockBody: BlockBody): Either[BlockError, BlockValid] = { + private def validateNoTransactions(blockBody: BlockBody): Either[BlockError, BlockValid] = Either.cond(blockBody.transactionList.isEmpty, BlockValid, CheckpointBlockTransactionsNotEmptyError) - } - /** - * Validates that the block body does not contain ommers + /** Validates that the block body does not contain ommers * * @param blockBody BlockBody to validate * @return BlockValid if there are no ommers, error otherwise */ - private def validateNoOmmers(blockBody: BlockBody): Either[BlockError, BlockValid] = { + private def validateNoOmmers(blockBody: BlockBody): Either[BlockError, BlockValid] = Either.cond(blockBody.uncleNodesList.isEmpty, BlockValid, CheckpointBlockOmmersNotEmptyError) - } - /** - * This method allows validate block with checkpoint. It performs the following validations: + /** This method allows validate block with checkpoint. It performs the following validations: * - no transactions in the body * - no ommers in the body * * @param blockBody BlockBody to validate * @return The BlockValid if validations are ok, BlockError otherwise */ - private def validateBlockWithCheckpoint(blockBody: BlockBody): Either[BlockError, BlockValid] = { + private def validateBlockWithCheckpoint(blockBody: BlockBody): Either[BlockError, BlockValid] = for { _ <- validateNoTransactions(blockBody) _ <- validateNoOmmers(blockBody) } yield BlockValid - } - /** - * This method allows validate a regular Block. It only performs the following validations (stated on + /** This method allows validate a regular Block. It only performs the following validations (stated on * section 4.4.2 of http://paper.gavwood.com/): * - BlockValidator.validateTransactionRoot * - BlockValidator.validateOmmersHash @@ -116,15 +110,13 @@ object StdBlockValidator extends BlockValidator { * @param block Block to validate * @return The BlockValid if validations are ok, BlockError otherwise */ - private def validateRegularBlock(block: Block): Either[BlockError, BlockValid] = { + private def validateRegularBlock(block: Block): Either[BlockError, BlockValid] = for { _ <- validateTransactionRoot(block) _ <- validateOmmersHash(block) } yield BlockValid - } - /** - * This method allows validate a Block. It only perfoms the following validations (stated on + /** This method allows validate a Block. It only perfoms the following validations (stated on * section 4.4.2 of http://paper.gavwood.com/): * - validate regular block or block with checkpoint * - BlockValidator.validateReceipts @@ -134,15 +126,13 @@ object StdBlockValidator extends BlockValidator { * @param receipts Receipts to be in validation process * @return The block if validations are ok, error otherwise */ - def validate(block: Block, receipts: Seq[Receipt]): Either[BlockError, BlockValid] = { + def validate(block: Block, receipts: Seq[Receipt]): Either[BlockError, BlockValid] = for { _ <- validateHeaderAndBody(block.header, block.body) _ <- validateBlockAndReceipts(block.header, receipts) } yield BlockValid - } - /** - * This method allows validate that a BlockHeader matches a BlockBody. + /** This method allows validate that a BlockHeader matches a BlockBody. * * @param blockHeader to validate * @param blockBody to validate @@ -154,8 +144,7 @@ object StdBlockValidator extends BlockValidator { else validateRegularBlock(block) } - /** - * This method allows validations of the block with its associated receipts. + /** This method allows validations of the block with its associated receipts. * It only perfoms the following validations (stated on section 4.4.2 of http://paper.gavwood.com/): * - BlockValidator.validateReceipts * - BlockValidator.validateLogBloom @@ -164,12 +153,11 @@ object StdBlockValidator extends BlockValidator { * @param receipts Receipts to be in validation process * @return The block if validations are ok, error otherwise */ - def validateBlockAndReceipts(blockHeader: BlockHeader, receipts: Seq[Receipt]): Either[BlockError, BlockValid] = { + def validateBlockAndReceipts(blockHeader: BlockHeader, receipts: Seq[Receipt]): Either[BlockError, BlockValid] = for { _ <- validateReceipts(blockHeader, receipts) _ <- validateLogBloom(blockHeader, receipts) } yield BlockValid - } sealed trait BlockError diff --git a/src/main/scala/io/iohk/ethereum/consensus/validators/std/StdSignedTransactionValidator.scala b/src/main/scala/io/iohk/ethereum/consensus/validators/std/StdSignedTransactionValidator.scala index 3da0449424..a3254743d8 100644 --- a/src/main/scala/io/iohk/ethereum/consensus/validators/std/StdSignedTransactionValidator.scala +++ b/src/main/scala/io/iohk/ethereum/consensus/validators/std/StdSignedTransactionValidator.scala @@ -11,8 +11,7 @@ class StdSignedTransactionValidator(blockchainConfig: BlockchainConfig) extends val secp256k1n: BigInt = BigInt("115792089237316195423570985008687907852837564279074904382605163141518161494337") - /** - * Initial tests of intrinsic validity stated in Section 6 of YP + /** Initial tests of intrinsic validity stated in Section 6 of YP * * @param stx Transaction to validate * @param senderAccount Account of the sender of the tx @@ -27,7 +26,7 @@ class StdSignedTransactionValidator(blockchainConfig: BlockchainConfig) extends blockHeader: BlockHeader, upfrontGasCost: UInt256, accumGasUsed: BigInt - ): Either[SignedTransactionError, SignedTransactionValid] = { + ): Either[SignedTransactionError, SignedTransactionValid] = for { _ <- checkSyntacticValidity(stx) _ <- validateSignature(stx, blockHeader.number) @@ -36,10 +35,8 @@ class StdSignedTransactionValidator(blockchainConfig: BlockchainConfig) extends _ <- validateAccountHasEnoughGasToPayUpfrontCost(senderAccount.balance, upfrontGasCost) _ <- validateBlockHasEnoughGasLimitForTx(stx, accumGasUsed, blockHeader.gasLimit) } yield SignedTransactionValid - } - /** - * Validates if the transaction is syntactically valid (lengths of the transaction fields are correct) + /** Validates if the transaction is syntactically valid (lengths of the transaction fields are correct) * * @param stx Transaction to validate * @return Either the validated transaction or TransactionSyntaxError if an error was detected @@ -71,8 +68,7 @@ class StdSignedTransactionValidator(blockchainConfig: BlockchainConfig) extends Right(SignedTransactionValid) } - /** - * Validates if the transaction signature is valid as stated in appendix F in YP + /** Validates if the transaction signature is valid as stated in appendix F in YP * * @param stx Transaction to validate * @param blockNumber Number of the block for this transaction @@ -96,8 +92,7 @@ class StdSignedTransactionValidator(blockchainConfig: BlockchainConfig) extends else Left(TransactionSignatureError) } - /** - * Validates if the transaction nonce matches current sender account's nonce + /** Validates if the transaction nonce matches current sender account's nonce * * @param stx Transaction to validate * @param senderNonce Nonce of the sender of the transaction @@ -106,13 +101,11 @@ class StdSignedTransactionValidator(blockchainConfig: BlockchainConfig) extends private def validateNonce( stx: SignedTransaction, senderNonce: UInt256 - ): Either[SignedTransactionError, SignedTransactionValid] = { + ): Either[SignedTransactionError, SignedTransactionValid] = if (senderNonce == UInt256(stx.tx.nonce)) Right(SignedTransactionValid) else Left(TransactionNonceError(UInt256(stx.tx.nonce), senderNonce)) - } - /** - * Validates the gas limit is no smaller than the intrinsic gas used by the transaction. + /** Validates the gas limit is no smaller than the intrinsic gas used by the transaction. * * @param stx Transaction to validate * @param blockHeaderNumber Number of the block where the stx transaction was included @@ -129,8 +122,7 @@ class StdSignedTransactionValidator(blockchainConfig: BlockchainConfig) extends else Left(TransactionNotEnoughGasForIntrinsicError(stx.tx.gasLimit, txIntrinsicGas)) } - /** - * Validates the sender account balance contains at least the cost required in up-front payment. + /** Validates the sender account balance contains at least the cost required in up-front payment. * * @param senderBalance Balance of the sender of the tx * @param upfrontCost Upfront cost of the transaction tx @@ -139,13 +131,11 @@ class StdSignedTransactionValidator(blockchainConfig: BlockchainConfig) extends private def validateAccountHasEnoughGasToPayUpfrontCost( senderBalance: UInt256, upfrontCost: UInt256 - ): Either[SignedTransactionError, SignedTransactionValid] = { + ): Either[SignedTransactionError, SignedTransactionValid] = if (senderBalance >= upfrontCost) Right(SignedTransactionValid) else Left(TransactionSenderCantPayUpfrontCostError(upfrontCost, senderBalance)) - } - /** - * The sum of the transaction’s gas limit and the gas utilised in this block prior must be no greater than the + /** The sum of the transaction’s gas limit and the gas utilised in this block prior must be no greater than the * block’s gasLimit * * @param stx Transaction to validate @@ -157,8 +147,7 @@ class StdSignedTransactionValidator(blockchainConfig: BlockchainConfig) extends stx: SignedTransaction, accumGasUsed: BigInt, blockGasLimit: BigInt - ): Either[SignedTransactionError, SignedTransactionValid] = { + ): Either[SignedTransactionError, SignedTransactionValid] = if (stx.tx.gasLimit + accumGasUsed <= blockGasLimit) Right(SignedTransactionValid) else Left(TransactionGasLimitTooBigError(stx.tx.gasLimit, accumGasUsed, blockGasLimit)) - } } diff --git a/src/main/scala/io/iohk/ethereum/consensus/validators/std/StdValidators.scala b/src/main/scala/io/iohk/ethereum/consensus/validators/std/StdValidators.scala index 3c3238f377..386ecd5d30 100644 --- a/src/main/scala/io/iohk/ethereum/consensus/validators/std/StdValidators.scala +++ b/src/main/scala/io/iohk/ethereum/consensus/validators/std/StdValidators.scala @@ -1,15 +1,20 @@ package io.iohk.ethereum.consensus.validators.std import akka.util.ByteString -import io.iohk.ethereum.consensus.validators._ -import io.iohk.ethereum.consensus.{GetBlockHeaderByHash, GetNBlocksBack} -import io.iohk.ethereum.domain.{Block, Receipt} -import io.iohk.ethereum.ledger.BlockExecutionError.{ValidationAfterExecError, ValidationBeforeExecError} -import io.iohk.ethereum.ledger.{BlockExecutionError, BlockExecutionSuccess} + import org.bouncycastle.util.encoders.Hex -/** - * Implements validators that adhere to the original [[io.iohk.ethereum.consensus.validators.Validators Validators]] +import io.iohk.ethereum.consensus.GetBlockHeaderByHash +import io.iohk.ethereum.consensus.GetNBlocksBack +import io.iohk.ethereum.consensus.validators._ +import io.iohk.ethereum.domain.Block +import io.iohk.ethereum.domain.Receipt +import io.iohk.ethereum.ledger.BlockExecutionError +import io.iohk.ethereum.ledger.BlockExecutionError.ValidationAfterExecError +import io.iohk.ethereum.ledger.BlockExecutionError.ValidationBeforeExecError +import io.iohk.ethereum.ledger.BlockExecutionSuccess + +/** Implements validators that adhere to the original [[io.iohk.ethereum.consensus.validators.Validators Validators]] * interface. * * @see [[io.iohk.ethereum.consensus.pow.validators.StdValidatorsExecutor StdEthashValidators]] @@ -25,23 +30,20 @@ final class StdValidators( block: Block, getBlockHeaderByHash: GetBlockHeaderByHash, getNBlocksBack: GetNBlocksBack - ): Either[ValidationBeforeExecError, BlockExecutionSuccess] = { - + ): Either[ValidationBeforeExecError, BlockExecutionSuccess] = StdValidators.validateBlockBeforeExecution( self = this, block = block, getBlockHeaderByHash = getBlockHeaderByHash, getNBlocksBack = getNBlocksBack ) - } def validateBlockAfterExecution( block: Block, stateRootHash: ByteString, receipts: Seq[Receipt], gasUsed: BigInt - ): Either[BlockExecutionError, BlockExecutionSuccess] = { - + ): Either[BlockExecutionError, BlockExecutionSuccess] = StdValidators.validateBlockAfterExecution( self = this, block = block, @@ -49,7 +51,6 @@ final class StdValidators( receipts = receipts, gasUsed = gasUsed ) - } } object StdValidators { @@ -90,7 +91,7 @@ object StdValidators { else { blockAndReceiptsValidation match { case Left(err) => Left(ValidationAfterExecError(err.toString)) - case _ => Right(BlockExecutionSuccess) + case _ => Right(BlockExecutionSuccess) } } } diff --git a/src/main/scala/io/iohk/ethereum/crypto/ECDSASignatureImplicits.scala b/src/main/scala/io/iohk/ethereum/crypto/ECDSASignatureImplicits.scala index 8e7c7b2ee6..61e5b8281c 100644 --- a/src/main/scala/io/iohk/ethereum/crypto/ECDSASignatureImplicits.scala +++ b/src/main/scala/io/iohk/ethereum/crypto/ECDSASignatureImplicits.scala @@ -11,14 +11,13 @@ object ECDSASignatureImplicits { implicit val ecdsaSignatureDec: RLPDecoder[ECDSASignature] = new RLPDecoder[ECDSASignature] { override def decode(rlp: RLPEncodeable): ECDSASignature = rlp match { case RLPList(r, s, v) => ECDSASignature(r: ByteString, s: ByteString, v) - case _ => throw new RuntimeException("Cannot decode ECDSASignature") + case _ => throw new RuntimeException("Cannot decode ECDSASignature") } } implicit class ECDSASignatureEnc(ecdsaSignature: ECDSASignature) extends RLPSerializable { - override def toRLPEncodable: RLPEncodeable = { + override def toRLPEncodable: RLPEncodeable = RLPList(ecdsaSignature.r, ecdsaSignature.s, ecdsaSignature.v) - } } implicit val ECDSASignatureOrdering: Ordering[ECDSASignature] = Ordering.by(sig => (sig.r, sig.s, sig.v)) diff --git a/src/main/scala/io/iohk/ethereum/crypto/EcKeyGen.scala b/src/main/scala/io/iohk/ethereum/crypto/EcKeyGen.scala index cbd77c288c..878c09a283 100644 --- a/src/main/scala/io/iohk/ethereum/crypto/EcKeyGen.scala +++ b/src/main/scala/io/iohk/ethereum/crypto/EcKeyGen.scala @@ -2,8 +2,7 @@ package io.iohk.ethereum.crypto import io.iohk.ethereum.security.SecureRandomBuilder -/** - * A simple tool to generate ECDSA key pairs. Takes an optional positional argument [n] - number of key pairs +/** A simple tool to generate ECDSA key pairs. Takes an optional positional argument [n] - number of key pairs * to generate (default is 1). * The key pairs will be printed in the format: * priv-key-hex (32 bytes) @@ -17,9 +16,9 @@ import io.iohk.ethereum.security.SecureRandomBuilder * The tool can also be used to generate keys for an Ethereum account. */ object EcKeyGen extends App with SecureRandomBuilder { - val numOfKeys = args.headOption.map(_.toInt).getOrElse(1) + val numOfKeys: Int = args.headOption.map(_.toInt).getOrElse(1) - val keyPairs = for (_ <- 1 to numOfKeys) yield newRandomKeyPairAsStrings(secureRandom) + val keyPairs: IndexedSeq[(String, String)] = for (_ <- 1 to numOfKeys) yield newRandomKeyPairAsStrings(secureRandom) //scalastyle:off println(keyPairs.map { case (prv, pub) => s"$prv\n$pub\n" }.mkString("\n")) diff --git a/src/main/scala/io/iohk/ethereum/crypto/SignatureValidator.scala b/src/main/scala/io/iohk/ethereum/crypto/SignatureValidator.scala index 21b583b323..0469488219 100644 --- a/src/main/scala/io/iohk/ethereum/crypto/SignatureValidator.scala +++ b/src/main/scala/io/iohk/ethereum/crypto/SignatureValidator.scala @@ -1,13 +1,16 @@ package io.iohk.ethereum.crypto import akka.util.ByteString + +import scala.util.Failure +import scala.util.Success +import scala.util.Try + import io.iohk.ethereum.crypto import io.iohk.ethereum.jsonrpc.JsonMethodsImplicits import io.iohk.ethereum.security.SecureRandomBuilder import io.iohk.ethereum.utils.ByteStringUtils -import scala.util.{Failure, Success, Try} - // scalastyle:off regex object SignatureValidator extends App with SecureRandomBuilder with JsonMethodsImplicits { diff --git a/src/main/scala/io/iohk/ethereum/db/cache/AppCaches.scala b/src/main/scala/io/iohk/ethereum/db/cache/AppCaches.scala index 017a065b05..6191112ddd 100644 --- a/src/main/scala/io/iohk/ethereum/db/cache/AppCaches.scala +++ b/src/main/scala/io/iohk/ethereum/db/cache/AppCaches.scala @@ -1,10 +1,11 @@ package io.iohk.ethereum.db.cache -import io.iohk.ethereum.db.storage.NodeStorage.{NodeEncoded, NodeHash} +import io.iohk.ethereum.db.storage.NodeStorage.NodeEncoded +import io.iohk.ethereum.db.storage.NodeStorage.NodeHash import io.iohk.ethereum.utils.Config trait AppCaches extends CacheComponent { - val caches = new Caches { + val caches: Caches = new Caches { override val nodeCache: Cache[NodeHash, NodeEncoded] = MapCache.createCache(Config.NodeCacheConfig) } } diff --git a/src/main/scala/io/iohk/ethereum/db/cache/LruCache.scala b/src/main/scala/io/iohk/ethereum/db/cache/LruCache.scala index e8ac9edf66..53a1965170 100644 --- a/src/main/scala/io/iohk/ethereum/db/cache/LruCache.scala +++ b/src/main/scala/io/iohk/ethereum/db/cache/LruCache.scala @@ -2,11 +2,15 @@ package io.iohk.ethereum.db.cache import java.util.concurrent.TimeUnit import java.util.concurrent.atomic.AtomicLong -import io.iohk.ethereum.utils.Config.NodeCacheConfig -import com.google.common.cache -import com.google.common.cache.{CacheBuilder, RemovalNotification} + import scala.concurrent.duration.FiniteDuration +import com.google.common.cache +import com.google.common.cache.CacheBuilder +import com.google.common.cache.RemovalNotification + +import io.iohk.ethereum.utils.Config.NodeCacheConfig + class LruCache[K <: AnyRef, V <: AnyRef]( config: NodeCacheConfig, notificationHandler: Option[RemovalNotification[K, V] => Unit] = None @@ -45,10 +49,9 @@ class LruCache[K <: AnyRef, V <: AnyRef]( this } - private def isTimeToClear: Boolean = { + private def isTimeToClear: Boolean = FiniteDuration(System.nanoTime(), TimeUnit.NANOSECONDS) - FiniteDuration( lastClear.get(), TimeUnit.NANOSECONDS ) >= config.maxHoldTime - } } diff --git a/src/main/scala/io/iohk/ethereum/db/cache/MapCache.scala b/src/main/scala/io/iohk/ethereum/db/cache/MapCache.scala index 80fdac9179..84713c6e5d 100644 --- a/src/main/scala/io/iohk/ethereum/db/cache/MapCache.scala +++ b/src/main/scala/io/iohk/ethereum/db/cache/MapCache.scala @@ -3,10 +3,11 @@ package io.iohk.ethereum.db.cache import java.util.concurrent.TimeUnit import java.util.concurrent.atomic.AtomicLong -import io.iohk.ethereum.utils.Config.NodeCacheConfig import scala.collection.mutable import scala.concurrent.duration.FiniteDuration +import io.iohk.ethereum.utils.Config.NodeCacheConfig + //TODO EC-492 Investigate more carefully possibility of having read cache in front of db // class is not entirely thread safe // All updates need to be atomic and visible in respect to get, as get may be called from other threads. @@ -23,40 +24,35 @@ class MapCache[K, V](val cache: mutable.Map[K, V], config: NodeCacheConfig) exte this } - override def getValues: Seq[(K, V)] = { + override def getValues: Seq[(K, V)] = cache.toSeq - } - override def get(key: K): Option[V] = { + override def get(key: K): Option[V] = this.synchronized { cache.get(key) } - } override def clear(): Unit = { lastClear.getAndSet(System.nanoTime()) cache.clear() } - override def shouldPersist: Boolean = { + override def shouldPersist: Boolean = cache.size > config.maxSize || isTimeToClear - } - private def isTimeToClear: Boolean = { + private def isTimeToClear: Boolean = FiniteDuration(System.nanoTime(), TimeUnit.NANOSECONDS) - FiniteDuration( lastClear.get(), TimeUnit.NANOSECONDS ) >= config.maxHoldTime - } } object MapCache { def getMap[K, V]: mutable.Map[K, V] = mutable.Map.empty - def createCache[K, V](config: NodeCacheConfig): MapCache[K, V] = { + def createCache[K, V](config: NodeCacheConfig): MapCache[K, V] = new MapCache[K, V](getMap[K, V], config) - } private case class TestCacheConfig(override val maxSize: Long, override val maxHoldTime: FiniteDuration) extends NodeCacheConfig @@ -64,7 +60,6 @@ object MapCache { def createTestCache[K, V]( maxSize: Long, maxHoldTime: FiniteDuration = FiniteDuration(5, TimeUnit.MINUTES) - ): Cache[K, V] = { + ): Cache[K, V] = createCache[K, V](TestCacheConfig(maxSize, maxHoldTime)) - } } diff --git a/src/main/scala/io/iohk/ethereum/db/components/EphemDataSourceComponent.scala b/src/main/scala/io/iohk/ethereum/db/components/EphemDataSourceComponent.scala index 1466a64c40..b864daae59 100644 --- a/src/main/scala/io/iohk/ethereum/db/components/EphemDataSourceComponent.scala +++ b/src/main/scala/io/iohk/ethereum/db/components/EphemDataSourceComponent.scala @@ -3,5 +3,5 @@ package io.iohk.ethereum.db.components import io.iohk.ethereum.db.dataSource.EphemDataSource trait EphemDataSourceComponent extends DataSourceComponent { - val dataSource = EphemDataSource() + val dataSource: EphemDataSource = EphemDataSource() } diff --git a/src/main/scala/io/iohk/ethereum/db/components/RocksDbDataSourceComponent.scala b/src/main/scala/io/iohk/ethereum/db/components/RocksDbDataSourceComponent.scala index cd4d71a60a..f5fd24d2a3 100644 --- a/src/main/scala/io/iohk/ethereum/db/components/RocksDbDataSourceComponent.scala +++ b/src/main/scala/io/iohk/ethereum/db/components/RocksDbDataSourceComponent.scala @@ -6,6 +6,6 @@ import io.iohk.ethereum.utils.Config trait RocksDbDataSourceComponent extends DataSourceComponent { - lazy val dataSource = RocksDbDataSource(Config.Db.RocksDb, Namespaces.nsSeq) + lazy val dataSource: RocksDbDataSource = RocksDbDataSource(Config.Db.RocksDb, Namespaces.nsSeq) } diff --git a/src/main/scala/io/iohk/ethereum/db/components/Storages.scala b/src/main/scala/io/iohk/ethereum/db/components/Storages.scala index 05d7ecfa5a..7b395f27b4 100644 --- a/src/main/scala/io/iohk/ethereum/db/components/Storages.scala +++ b/src/main/scala/io/iohk/ethereum/db/components/Storages.scala @@ -1,6 +1,7 @@ package io.iohk.ethereum.db.components -import io.iohk.ethereum.db.cache.{AppCaches, LruCache} +import io.iohk.ethereum.db.cache.AppCaches +import io.iohk.ethereum.db.cache.LruCache import io.iohk.ethereum.db.storage.NodeStorage.NodeHash import io.iohk.ethereum.db.storage._ import io.iohk.ethereum.db.storage.pruning.PruningMode diff --git a/src/main/scala/io/iohk/ethereum/db/dataSource/DataSource.scala b/src/main/scala/io/iohk/ethereum/db/dataSource/DataSource.scala index 4bdd76ebf2..3e43e2c61d 100644 --- a/src/main/scala/io/iohk/ethereum/db/dataSource/DataSource.scala +++ b/src/main/scala/io/iohk/ethereum/db/dataSource/DataSource.scala @@ -1,13 +1,13 @@ package io.iohk.ethereum.db.dataSource -import io.iohk.ethereum.db.dataSource.RocksDbDataSource.IterationError import monix.reactive.Observable +import io.iohk.ethereum.db.dataSource.RocksDbDataSource.IterationError + trait DataSource { import DataSource._ - /** - * This function obtains the associated value to a key. It requires the (key-value) pair to be in the DataSource + /** This function obtains the associated value to a key. It requires the (key-value) pair to be in the DataSource * * @param namespace which will be searched for the key. * @param key the key retrieve the value. @@ -15,8 +15,7 @@ trait DataSource { */ def apply(namespace: Namespace, key: Key): Value = get(namespace, key).get - /** - * This function obtains the associated value to a key, if there exists one. + /** This function obtains the associated value to a key, if there exists one. * * @param namespace which will be searched for the key. * @param key the key retrieve the value. @@ -24,8 +23,7 @@ trait DataSource { */ def get(namespace: Namespace, key: Key): Option[Value] - /** - * This function obtains the associated value to a key, if there exists one. It assumes that + /** This function obtains the associated value to a key, if there exists one. It assumes that * caller already properly serialized key. Useful when caller knows some pattern in data to * avoid generic serialization. * @@ -34,34 +32,28 @@ trait DataSource { */ def getOptimized(namespace: Namespace, key: Array[Byte]): Option[Array[Byte]] - /** - * This function updates the DataSource by deleting, updating and inserting new (key-value) pairs. + /** This function updates the DataSource by deleting, updating and inserting new (key-value) pairs. * Implementations should guarantee that the whole operation is atomic. */ def update(dataSourceUpdates: Seq[DataUpdate]): Unit - /** - * This function updates the DataSource by deleting all the (key-value) pairs in it. + /** This function updates the DataSource by deleting all the (key-value) pairs in it. */ def clear(): Unit - /** - * This function closes the DataSource, without deleting the files used by it. + /** This function closes the DataSource, without deleting the files used by it. */ def close(): Unit - /** - * This function closes the DataSource, if it is not yet closed, and deletes all the files used by it. + /** This function closes the DataSource, if it is not yet closed, and deletes all the files used by it. */ def destroy(): Unit - /** - * Return key-value pairs until first error or until whole db has been iterated + /** Return key-value pairs until first error or until whole db has been iterated */ def iterate(): Observable[Either[IterationError, (Array[Byte], Array[Byte])]] - /** - * Return key-value pairs until first error or until whole namespace has been iterated + /** Return key-value pairs until first error or until whole namespace has been iterated */ def iterate(namespace: Namespace): Observable[Either[IterationError, (Array[Byte], Array[Byte])]] diff --git a/src/main/scala/io/iohk/ethereum/db/dataSource/DataSourceBatchUpdate.scala b/src/main/scala/io/iohk/ethereum/db/dataSource/DataSourceBatchUpdate.scala index aa31626713..7b6ef7f9f7 100644 --- a/src/main/scala/io/iohk/ethereum/db/dataSource/DataSourceBatchUpdate.scala +++ b/src/main/scala/io/iohk/ethereum/db/dataSource/DataSourceBatchUpdate.scala @@ -12,8 +12,7 @@ case class DataSourceBatchUpdate(dataSource: DataSource, updates: Array[DataUpda DataSourceBatchUpdate(dataSource, this.updates ++ that.updates) } - def commit(): Unit = { + def commit(): Unit = dataSource.update(ArraySeq.unsafeWrapArray(updates)) - } } diff --git a/src/main/scala/io/iohk/ethereum/db/dataSource/DataSourceUpdate.scala b/src/main/scala/io/iohk/ethereum/db/dataSource/DataSourceUpdate.scala index 57af85c6cf..c33f0550c2 100644 --- a/src/main/scala/io/iohk/ethereum/db/dataSource/DataSourceUpdate.scala +++ b/src/main/scala/io/iohk/ethereum/db/dataSource/DataSourceUpdate.scala @@ -1,11 +1,12 @@ package io.iohk.ethereum.db.dataSource -import io.iohk.ethereum.db.dataSource.DataSource.{Key, Namespace, Value} +import io.iohk.ethereum.db.dataSource.DataSource.Key +import io.iohk.ethereum.db.dataSource.DataSource.Namespace +import io.iohk.ethereum.db.dataSource.DataSource.Value sealed trait DataUpdate -/** - * This represent updates to be performed on the DataSource by deleting, updating and inserting new (key-value) pairs. +/** This represent updates to be performed on the DataSource by deleting, updating and inserting new (key-value) pairs. * * @param namespace from which the (key-value) pairs will be removed and inserted. * @param toRemove which includes all the keys to be removed from the DataSource. @@ -14,8 +15,7 @@ sealed trait DataUpdate */ case class DataSourceUpdate(namespace: Namespace, toRemove: Seq[Key], toUpsert: Seq[(Key, Value)]) extends DataUpdate -/** - * This represent updates the DataSource by deleting, updating and inserting new (key-value) pairs. +/** This represent updates the DataSource by deleting, updating and inserting new (key-value) pairs. * It assumes that caller already properly serialized key and value. * Useful when caller knows some pattern in data to avoid generic serialization. * diff --git a/src/main/scala/io/iohk/ethereum/db/dataSource/EphemDataSource.scala b/src/main/scala/io/iohk/ethereum/db/dataSource/EphemDataSource.scala index d36e14b4d9..1b60063ad4 100644 --- a/src/main/scala/io/iohk/ethereum/db/dataSource/EphemDataSource.scala +++ b/src/main/scala/io/iohk/ethereum/db/dataSource/EphemDataSource.scala @@ -2,27 +2,25 @@ package io.iohk.ethereum.db.dataSource import java.nio.ByteBuffer +import monix.reactive.Observable + import io.iohk.ethereum.db.dataSource.DataSource._ import io.iohk.ethereum.db.dataSource.RocksDbDataSource.IterationError -import monix.reactive.Observable class EphemDataSource(var storage: Map[ByteBuffer, Array[Byte]]) extends DataSource { - /** - * key.drop to remove namespace prefix from the key + /** key.drop to remove namespace prefix from the key * @return key values paris from this storage */ def getAll(namespace: Namespace): Seq[(IndexedSeq[Byte], IndexedSeq[Byte])] = synchronized { storage.toSeq.map { case (key, value) => (key.array().drop(namespace.length).toIndexedSeq, value.toIndexedSeq) } } - override def get(namespace: Namespace, key: Key): Option[Value] = { + override def get(namespace: Namespace, key: Key): Option[Value] = storage.get(ByteBuffer.wrap((namespace ++ key).toArray)).map(_.toIndexedSeq) - } - override def getOptimized(namespace: Namespace, key: Array[Byte]): Option[Array[Byte]] = { + override def getOptimized(namespace: Namespace, key: Array[Byte]): Option[Array[Byte]] = get(namespace, key.toIndexedSeq).map(_.toArray) - } override def update(dataSourceUpdates: Seq[DataUpdate]): Unit = synchronized { dataSourceUpdates.foreach { @@ -58,13 +56,12 @@ class EphemDataSource(var storage: Map[ByteBuffer, Array[Byte]]) extends DataSou override def destroy(): Unit = () - override def iterate(): Observable[Either[IterationError, (Array[Byte], Array[Byte])]] = { - Observable.fromIterable(storage.toList.map { case (key, value) => Right(key.array(), value) }) - } + override def iterate(): Observable[Either[IterationError, (Array[Byte], Array[Byte])]] = + Observable.fromIterable(storage.toList.map { case (key, value) => Right((key.array(), value)) }) override def iterate(namespace: Namespace): Observable[Either[IterationError, (Array[Byte], Array[Byte])]] = { - val namespaceVals = storage collect { - case (buffer, bytes) if buffer.array().startsWith(namespace) => Right(buffer.array(), bytes) + val namespaceVals = storage.collect { + case (buffer, bytes) if buffer.array().startsWith(namespace) => Right((buffer.array(), bytes)) } Observable.fromIterable(namespaceVals) diff --git a/src/main/scala/io/iohk/ethereum/db/dataSource/RocksDbDataSource.scala b/src/main/scala/io/iohk/ethereum/db/dataSource/RocksDbDataSource.scala index 4e5252695b..4e3b1d9951 100644 --- a/src/main/scala/io/iohk/ethereum/db/dataSource/RocksDbDataSource.scala +++ b/src/main/scala/io/iohk/ethereum/db/dataSource/RocksDbDataSource.scala @@ -2,19 +2,22 @@ package io.iohk.ethereum.db.dataSource import java.util.concurrent.locks.ReentrantReadWriteLock -import io.iohk.ethereum.utils.Logger import cats.effect.Resource -import io.iohk.ethereum.db.dataSource.DataSource._ -import io.iohk.ethereum.db.dataSource.RocksDbDataSource._ -import io.iohk.ethereum.utils.TryWithResources.withResources + import monix.eval.Task import monix.reactive.Observable -import org.rocksdb._ import scala.collection.immutable.ArraySeq import scala.collection.mutable import scala.util.control.NonFatal +import org.rocksdb._ + +import io.iohk.ethereum.db.dataSource.DataSource._ +import io.iohk.ethereum.db.dataSource.RocksDbDataSource._ +import io.iohk.ethereum.utils.Logger +import io.iohk.ethereum.utils.TryWithResources.withResources + class RocksDbDataSource( private var db: RocksDB, private val rocksDbConfig: RocksDbConfig, @@ -29,8 +32,7 @@ class RocksDbDataSource( @volatile private var isClosed = false - /** - * This function obtains the associated value to a key, if there exists one. + /** This function obtains the associated value to a key, if there exists one. * * @param namespace which will be searched for the key. * @param key the key retrieve the value. @@ -50,13 +52,10 @@ class RocksDbDataSource( s"Not found associated value to a namespace: $namespace and a key: $key", error ) - } finally { - dbLock.readLock().unlock() - } + } finally dbLock.readLock().unlock() } - /** - * This function obtains the associated value to a key, if there exists one. It assumes that + /** This function obtains the associated value to a key, if there exists one. It assumes that * caller already properly serialized key. Useful when caller knows some pattern in data to * avoid generic serialization. * @@ -73,9 +72,7 @@ class RocksDbDataSource( throw error case NonFatal(error) => throw RocksDbDataSourceException(s"Not found associated value to a key: $key", error) - } finally { - dbLock.readLock().unlock() - } + } finally dbLock.readLock().unlock() } override def update(dataSourceUpdates: Seq[DataUpdate]): Unit = { @@ -105,45 +102,37 @@ class RocksDbDataSource( throw error case NonFatal(error) => throw RocksDbDataSourceException(s"DataSource not updated", error) - } finally { - dbLock.writeLock().unlock() - } + } finally dbLock.writeLock().unlock() } - private def dbIterator: Resource[Task, RocksIterator] = { + private def dbIterator: Resource[Task, RocksIterator] = Resource.fromAutoCloseable(Task(db.newIterator())) - } - private def namespaceIterator(namespace: Namespace): Resource[Task, RocksIterator] = { + private def namespaceIterator(namespace: Namespace): Resource[Task, RocksIterator] = Resource.fromAutoCloseable(Task(db.newIterator(handles(namespace)))) - } - private def moveIterator(it: RocksIterator): Observable[Either[IterationError, (Array[Byte], Array[Byte])]] = { + private def moveIterator(it: RocksIterator): Observable[Either[IterationError, (Array[Byte], Array[Byte])]] = Observable .fromTask(Task(it.seekToFirst())) .flatMap { _ => Observable.repeatEvalF(for { isValid <- Task(it.isValid) - item <- if (isValid) Task(Right(it.key(), it.value())) else Task.raiseError(IterationFinished) + item <- if (isValid) Task(Right((it.key(), it.value()))) else Task.raiseError(IterationFinished) _ <- Task(it.next()) } yield item) } .onErrorHandleWith { case IterationFinished => Observable.empty - case ex => Observable(Left(IterationError(ex))) + case ex => Observable(Left(IterationError(ex))) } - } - def iterate(): Observable[Either[IterationError, (Array[Byte], Array[Byte])]] = { + def iterate(): Observable[Either[IterationError, (Array[Byte], Array[Byte])]] = Observable.fromResource(dbIterator).flatMap(it => moveIterator(it)) - } - def iterate(namespace: Namespace): Observable[Either[IterationError, (Array[Byte], Array[Byte])]] = { + def iterate(namespace: Namespace): Observable[Either[IterationError, (Array[Byte], Array[Byte])]] = Observable.fromResource(namespaceIterator(namespace)).flatMap(it => moveIterator(it)) - } - /** - * This function is used only for tests. + /** This function is used only for tests. * This function updates the DataSource by deleting all the (key-value) pairs in it. */ override def clear(): Unit = { @@ -161,8 +150,7 @@ class RocksDbDataSource( this.isClosed = false } - /** - * This function closes the DataSource, without deleting the files used by it. + /** This function closes the DataSource, without deleting the files used by it. */ override def close(): Unit = { log.info(s"About to close DataSource in path: ${rocksDbConfig.path}") @@ -186,26 +174,18 @@ class RocksDbDataSource( throw error case NonFatal(error) => throw RocksDbDataSourceException(s"Not closed the DataSource properly", error) - } finally { - dbLock.writeLock().unlock() - } + } finally dbLock.writeLock().unlock() } - /** - * This function is used only for tests. + /** This function is used only for tests. * This function closes the DataSource, if it is not yet closed, and deletes all the files used by it. */ - override def destroy(): Unit = { - try { - if (!isClosed) { - close() - } - } finally { - destroyDB() - } - } + override def destroy(): Unit = + try if (!isClosed) { + close() + } finally destroyDB() - protected def destroyDB(): Unit = { + protected def destroyDB(): Unit = try { import rocksDbConfig._ val tableCfg = new BlockBasedTableConfig() @@ -232,13 +212,11 @@ class RocksDbDataSource( case NonFatal(error) => throw RocksDbDataSourceException(s"Not destroyed the DataSource properly", error) } - } - private def assureNotClosed(): Unit = { + private def assureNotClosed(): Unit = if (isClosed) { throw RocksDbDataSourceClosedException(s"This ${getClass.getSimpleName} has been closed") } - } } @@ -261,8 +239,7 @@ object RocksDbDataSource { case class RocksDbDataSourceClosedException(message: String) extends IllegalStateException(message) case class RocksDbDataSourceException(message: String, cause: Throwable) extends RuntimeException(message, cause) - /** - * The rocksdb implementation acquires a lock from the operating system to prevent misuse + /** The rocksdb implementation acquires a lock from the operating system to prevent misuse */ private val dbLock = new ReentrantReadWriteLock() @@ -318,9 +295,7 @@ object RocksDbDataSource { } catch { case NonFatal(error) => throw RocksDbDataSourceException(s"Not created the DataSource properly", error) - } finally { - RocksDbDataSource.dbLock.writeLock().unlock() - } + } finally RocksDbDataSource.dbLock.writeLock().unlock() } def apply(rocksDbConfig: RocksDbConfig, namespaces: Seq[Namespace]): RocksDbDataSource = { diff --git a/src/main/scala/io/iohk/ethereum/db/storage/AppStateStorage.scala b/src/main/scala/io/iohk/ethereum/db/storage/AppStateStorage.scala index 808add3200..91d7598a37 100644 --- a/src/main/scala/io/iohk/ethereum/db/storage/AppStateStorage.scala +++ b/src/main/scala/io/iohk/ethereum/db/storage/AppStateStorage.scala @@ -2,13 +2,13 @@ package io.iohk.ethereum.db.storage import java.math.BigInteger -import io.iohk.ethereum.db.dataSource.{DataSource, DataSourceBatchUpdate} -import io.iohk.ethereum.db.storage.AppStateStorage._ - import scala.collection.immutable.ArraySeq -/** - * This class is used to store app state variables +import io.iohk.ethereum.db.dataSource.DataSource +import io.iohk.ethereum.db.dataSource.DataSourceBatchUpdate +import io.iohk.ethereum.db.storage.AppStateStorage._ + +/** This class is used to store app state variables * Key: see AppStateStorage.Keys * Value: stored string value */ @@ -48,12 +48,10 @@ class AppStateStorage(val dataSource: DataSource) extends TransactionalKeyValueS def putSyncStartingBlock(n: BigInt): DataSourceBatchUpdate = put(Keys.SyncStartingBlock, n.toString) - private def getBigInt(key: Key): BigInt = { + private def getBigInt(key: Key): BigInt = get(key).map(BigInt(_)).getOrElse(BigInt(BigInteger.ZERO)) - } - /** - * It is safe to return zero in case of not having any checkpoint block, + /** It is safe to return zero in case of not having any checkpoint block, * because we assume that genesis block is a kinda stable checkpoint block (without real checkpoint) * * @return Latest CheckpointBlock Number @@ -61,13 +59,11 @@ class AppStateStorage(val dataSource: DataSource) extends TransactionalKeyValueS def getLatestCheckpointBlockNumber(): BigInt = getBigInt(Keys.LatestCheckpointBlockNumber) - def removeLatestCheckpointBlockNumber(): DataSourceBatchUpdate = { + def removeLatestCheckpointBlockNumber(): DataSourceBatchUpdate = update(toRemove = Seq(Keys.LatestCheckpointBlockNumber), toUpsert = Nil) - } - def putLatestCheckpointBlockNumber(latestCheckpointBlockNumber: BigInt): DataSourceBatchUpdate = { + def putLatestCheckpointBlockNumber(latestCheckpointBlockNumber: BigInt): DataSourceBatchUpdate = update(Nil, Seq(Keys.LatestCheckpointBlockNumber -> latestCheckpointBlockNumber.toString)) - } } object AppStateStorage { diff --git a/src/main/scala/io/iohk/ethereum/db/storage/ArchiveNodeStorage.scala b/src/main/scala/io/iohk/ethereum/db/storage/ArchiveNodeStorage.scala index c06feba8a6..c5504b10a3 100644 --- a/src/main/scala/io/iohk/ethereum/db/storage/ArchiveNodeStorage.scala +++ b/src/main/scala/io/iohk/ethereum/db/storage/ArchiveNodeStorage.scala @@ -1,10 +1,10 @@ package io.iohk.ethereum.db.storage -import io.iohk.ethereum.db.storage.NodeStorage.{NodeEncoded, NodeHash} +import io.iohk.ethereum.db.storage.NodeStorage.NodeEncoded +import io.iohk.ethereum.db.storage.NodeStorage.NodeHash import io.iohk.ethereum.mpt.NodesKeyValueStorage -/** - * This class is used to store Nodes (defined in mpt/Node.scala), by using: +/** This class is used to store Nodes (defined in mpt/Node.scala), by using: * Key: hash of the RLP encoded node * Value: the RLP encoded node */ diff --git a/src/main/scala/io/iohk/ethereum/db/storage/BlockBodiesStorage.scala b/src/main/scala/io/iohk/ethereum/db/storage/BlockBodiesStorage.scala index 479621634f..206f18fceb 100644 --- a/src/main/scala/io/iohk/ethereum/db/storage/BlockBodiesStorage.scala +++ b/src/main/scala/io/iohk/ethereum/db/storage/BlockBodiesStorage.scala @@ -1,15 +1,18 @@ package io.iohk.ethereum.db.storage import akka.util.ByteString -import boopickle.Default.{Pickle, Unpickle} + +import boopickle.Default.Pickle +import boopickle.Default.Unpickle + import io.iohk.ethereum.db.dataSource.DataSource import io.iohk.ethereum.db.storage.BlockBodiesStorage.BlockBodyHash import io.iohk.ethereum.domain.BlockBody -import io.iohk.ethereum.utils.ByteUtils.{byteSequenceToBuffer, compactPickledBytes} +import io.iohk.ethereum.utils.ByteUtils.byteSequenceToBuffer +import io.iohk.ethereum.utils.ByteUtils.compactPickledBytes import io.iohk.ethereum.utils.Picklers._ -/** - * This class is used to store the BlockBody, by using: +/** This class is used to store the BlockBody, by using: * Key: hash of the block to which the BlockBody belong * Value: the block body */ @@ -26,7 +29,7 @@ class BlockBodiesStorage(val dataSource: DataSource) extends TransactionalKeyVal compactPickledBytes(Pickle.intoBytes(blockBody)) override def valueDeserializer: IndexedSeq[Byte] => BlockBody = - byteSequenceToBuffer _ andThen Unpickle[BlockBody].fromBytes + (byteSequenceToBuffer _).andThen(Unpickle[BlockBody].fromBytes) } object BlockBodiesStorage { diff --git a/src/main/scala/io/iohk/ethereum/db/storage/BlockHeadersStorage.scala b/src/main/scala/io/iohk/ethereum/db/storage/BlockHeadersStorage.scala index c2ca24e633..585c950308 100644 --- a/src/main/scala/io/iohk/ethereum/db/storage/BlockHeadersStorage.scala +++ b/src/main/scala/io/iohk/ethereum/db/storage/BlockHeadersStorage.scala @@ -1,16 +1,18 @@ package io.iohk.ethereum.db.storage import akka.util.ByteString -import boopickle.Default.{Pickle, Unpickle} -import boopickle.DefaultBasic._ + +import boopickle.Default.Pickle +import boopickle.Default.Unpickle + import io.iohk.ethereum.db.dataSource.DataSource import io.iohk.ethereum.db.storage.BlockHeadersStorage.BlockHeaderHash import io.iohk.ethereum.domain.BlockHeader -import io.iohk.ethereum.utils.ByteUtils.{byteSequenceToBuffer, compactPickledBytes} +import io.iohk.ethereum.utils.ByteUtils.byteSequenceToBuffer +import io.iohk.ethereum.utils.ByteUtils.compactPickledBytes import io.iohk.ethereum.utils.Picklers._ -/** - * This class is used to store the BlockHeader, by using: +/** This class is used to store the BlockHeader, by using: * Key: hash of the block to which the BlockHeader belong * Value: the block header */ @@ -30,7 +32,7 @@ class BlockHeadersStorage(val dataSource: DataSource) override def valueDeserializer: IndexedSeq[Byte] => BlockHeader = // TODO: consider reusing this formula in other storages: ETCM-322 - byteSequenceToBuffer _ andThen Unpickle[BlockHeader].fromBytes + (byteSequenceToBuffer _).andThen(Unpickle[BlockHeader].fromBytes) } object BlockHeadersStorage { diff --git a/src/main/scala/io/iohk/ethereum/db/storage/BlockNumberMappingStorage.scala b/src/main/scala/io/iohk/ethereum/db/storage/BlockNumberMappingStorage.scala index de93a1b7af..01217fcc32 100644 --- a/src/main/scala/io/iohk/ethereum/db/storage/BlockNumberMappingStorage.scala +++ b/src/main/scala/io/iohk/ethereum/db/storage/BlockNumberMappingStorage.scala @@ -3,11 +3,12 @@ package io.iohk.ethereum.db.storage import java.math.BigInteger import akka.util.ByteString -import io.iohk.ethereum.db.dataSource.DataSource -import io.iohk.ethereum.db.storage.BlockHeadersStorage.BlockHeaderHash import scala.collection.immutable.ArraySeq +import io.iohk.ethereum.db.dataSource.DataSource +import io.iohk.ethereum.db.storage.BlockHeadersStorage.BlockHeaderHash + class BlockNumberMappingStorage(val dataSource: DataSource) extends TransactionalKeyValueStorage[BigInt, BlockHeaderHash] { override val namespace: IndexedSeq[Byte] = Namespaces.HeightsNamespace diff --git a/src/main/scala/io/iohk/ethereum/db/storage/CachedKeyValueStorage.scala b/src/main/scala/io/iohk/ethereum/db/storage/CachedKeyValueStorage.scala index 9b51aa4646..7594a961c2 100644 --- a/src/main/scala/io/iohk/ethereum/db/storage/CachedKeyValueStorage.scala +++ b/src/main/scala/io/iohk/ethereum/db/storage/CachedKeyValueStorage.scala @@ -9,7 +9,7 @@ trait CachedKeyValueStorage[K, V, T <: CachedKeyValueStorage[K, V, T]] extends S protected val cache: Cache[K, V] def apply(cache: Cache[K, V], storage: I): T - def get(key: K): Option[V] = cache.get(key) orElse storage.get(key) + def get(key: K): Option[V] = cache.get(key).orElse(storage.get(key)) def update(toRemove: Seq[K], toUpsert: Seq[(K, V)]): T = { cache.update(toRemove, toUpsert) @@ -31,12 +31,11 @@ trait CachedKeyValueStorage[K, V, T <: CachedKeyValueStorage[K, V, T]] extends S } // TODO EC-491 Consider other persist strategy like sliding window (save and clear only old stuff which survived long enough) - def persist(): Boolean = { + def persist(): Boolean = if (cache.shouldPersist) { forcePersist() true } else { false } - } } diff --git a/src/main/scala/io/iohk/ethereum/db/storage/CachedReferenceCountedStorage.scala b/src/main/scala/io/iohk/ethereum/db/storage/CachedReferenceCountedStorage.scala index 261a13641f..c6e52a9df0 100644 --- a/src/main/scala/io/iohk/ethereum/db/storage/CachedReferenceCountedStorage.scala +++ b/src/main/scala/io/iohk/ethereum/db/storage/CachedReferenceCountedStorage.scala @@ -3,16 +3,19 @@ package io.iohk.ethereum.db.storage import java.nio.ByteBuffer import akka.util.ByteString + +import scala.collection.mutable + import boopickle.Default._ import com.google.common.cache.RemovalNotification -import io.iohk.ethereum.db.cache.Cache -import io.iohk.ethereum.db.storage.NodeStorage.{NodeEncoded, NodeHash} -import io.iohk.ethereum.mpt.{ByteArraySerializable, NodesKeyValueStorage} -import scala.collection.mutable +import io.iohk.ethereum.db.cache.Cache +import io.iohk.ethereum.db.storage.NodeStorage.NodeEncoded +import io.iohk.ethereum.db.storage.NodeStorage.NodeHash +import io.iohk.ethereum.mpt.ByteArraySerializable +import io.iohk.ethereum.mpt.NodesKeyValueStorage -/** - * In-memory pruner - All pruning is done in LRU cache, which means all mpt nodes saved to db, are there permanently. +/** In-memory pruner - All pruning is done in LRU cache, which means all mpt nodes saved to db, are there permanently. * There are two occasions where node is saved to disk: * 1 - When cache becomes full, least recently used nodes are flushed to disk. In normal operation, these nodes * have already survived several pruning cycles, and still have references pointing at them, which makes them @@ -36,7 +39,7 @@ class CachedReferenceCountedStorage( bn: BigInt ) extends NodesKeyValueStorage { - def get(nodeHash: NodeHash): Option[NodeEncoded] = { + def get(nodeHash: NodeHash): Option[NodeEncoded] = cache .get(nodeHash) .fold { @@ -45,7 +48,6 @@ class CachedReferenceCountedStorage( entry.nodeEncoded } }(entry => Some(entry.nodeEncoded)) - } def update(toRemove: Seq[ByteString], toUpsert: Seq[(ByteString, NodeEncoded)]): NodesKeyValueStorage = { changeLog.withChangeLog(bn) { blockChangeLog => @@ -96,7 +98,7 @@ object CachedReferenceCountedStorage { def persistCache[V](cache: Cache[ByteString, V], storage: NodeStorage, forced: Boolean = false)(implicit ser: ByteArraySerializable[V] - ): Boolean = { + ): Boolean = if (cache.shouldPersist || forced) { val values = cache.getValues val serialized = values.map { case (key, value) => key -> ser.toBytes(value) } @@ -106,7 +108,6 @@ object CachedReferenceCountedStorage { } else { false } - } def prune(deathRow: List[NodeHash], cache: Cache[NodeHash, HeapEntry], blockToPrune: BigInt): Unit = { val toDelFromCache = getNodesToPruneInCache(cache, deathRow, blockToPrune) @@ -125,15 +126,16 @@ object CachedReferenceCountedStorage { val nodeHash = update.hash val currentState = - newState.get(nodeHash) orElse - cache.get(nodeHash).map((_, false)) orElse - nodeStorage.get(nodeHash).map(HeapEntry.fromBytes).map((_, false)) + newState + .get(nodeHash) + .orElse(cache.get(nodeHash).map((_, false))) + .orElse(nodeStorage.get(nodeHash).map(HeapEntry.fromBytes).map((_, false))) currentState.foreach { case (current, deletable) => val reversedState = update match { case Increase(_) => (current.decrementParents(newBestAfterRollback), deletable) case Decrease(_) => (current.incrementParents(newBestAfterRollback), deletable) - case New(_) => (current.decrementParents(newBestAfterRollback), true) + case New(_) => (current.decrementParents(newBestAfterRollback), true) } newState += nodeHash -> reversedState } @@ -144,15 +146,14 @@ object CachedReferenceCountedStorage { private def gatherCacheUpdates( previousState: Map[NodeHash, (HeapEntry, Boolean)] - ): (List[NodeHash], List[(NodeHash, HeapEntry)]) = { - previousState.foldLeft(List.empty[NodeHash], List.empty[(NodeHash, HeapEntry)]) { + ): (List[NodeHash], List[(NodeHash, HeapEntry)]) = + previousState.foldLeft((List.empty[NodeHash], List.empty[(NodeHash, HeapEntry)])) { case ((toDel, toUpdate), (entryKey, (entryValue, deletable))) => if (entryValue.numOfParents == 0 && deletable) (entryKey :: toDel, toUpdate) else (toDel, (entryKey, entryValue) :: toUpdate) } - } def rollback( cache: Cache[NodeHash, HeapEntry], @@ -178,11 +179,15 @@ object CachedReferenceCountedStorage { class NoHistoryCachedReferenceCountedStorage(nodeStorage: NodeStorage, cache: Cache[ByteString, HeapEntry], bn: BigInt) extends NodesKeyValueStorage { - def get(nodeHash: NodeHash): Option[NodeEncoded] = { - cache.get(nodeHash).map(_.nodeEncoded) orElse nodeStorage + def get(nodeHash: NodeHash): Option[NodeEncoded] = + cache .get(nodeHash) - .map(enc => HeapEntry.fromBytes(enc).nodeEncoded) - } + .map(_.nodeEncoded) + .orElse( + nodeStorage + .get(nodeHash) + .map(enc => HeapEntry.fromBytes(enc).nodeEncoded) + ) def update(toRemove: Seq[ByteString], toUpsert: Seq[(ByteString, NodeEncoded)]): NodesKeyValueStorage = { toUpsert.foreach { case (key, value) => @@ -203,13 +208,11 @@ import io.iohk.ethereum.utils.ByteUtils._ final case class HeapEntry(nodeEncoded: NodeEncoded, numOfParents: Int, bn: BigInt) { - def incrementParents(incrementationBlock: BigInt): HeapEntry = { + def incrementParents(incrementationBlock: BigInt): HeapEntry = copy(numOfParents = numOfParents + 1, bn = incrementationBlock) - } - def decrementParents(decrementationBlock: BigInt): HeapEntry = { + def decrementParents(decrementationBlock: BigInt): HeapEntry = copy(numOfParents = numOfParents - 1, bn = decrementationBlock) - } } object HeapEntry { @@ -217,15 +220,13 @@ object HeapEntry { implicit val HeapEntryPickler: Pickler[HeapEntry] = generatePickler[HeapEntry] - def toBytes(entry: HeapEntry): Array[Byte] = { + def toBytes(entry: HeapEntry): Array[Byte] = compactPickledBytes(Pickle.intoBytes(entry)).toArray[Byte] - } - def fromBytes(asbytes: Array[Byte]): HeapEntry = { + def fromBytes(asbytes: Array[Byte]): HeapEntry = Unpickle[HeapEntry].fromBytes(ByteBuffer.wrap(asbytes)) - } - implicit val heapEntrySerializer = new ByteArraySerializable[HeapEntry] { + implicit val heapEntrySerializer: ByteArraySerializable[HeapEntry] = new ByteArraySerializable[HeapEntry] { override def toBytes(input: HeapEntry): Array[Byte] = HeapEntry.toBytes(input) override def fromBytes(bytes: Array[Byte]): HeapEntry = HeapEntry.fromBytes(bytes) } @@ -249,7 +250,7 @@ object Update { class ChangeLog(nodeStorage: NodeStorage) { private val logs = mutable.Map.empty[BigInt, BlockChangeLog] - def persistChangeLog(forBlock: BigInt): Unit = { + def persistChangeLog(forBlock: BigInt): Unit = logs.get(forBlock).foreach { changeLog => nodeStorage.update( Nil, @@ -260,7 +261,6 @@ class ChangeLog(nodeStorage: NodeStorage) { ) logs.remove(forBlock) } - } def withChangeLog(bn: BigInt)(updates: BlockChangeLog => Unit): Unit = { val changeLog = getChangeLogForBlock(bn) @@ -268,7 +268,7 @@ class ChangeLog(nodeStorage: NodeStorage) { logs.update(bn, changeLog) } - def getChangeLogForBlock(bn: BigInt): BlockChangeLog = { + def getChangeLogForBlock(bn: BigInt): BlockChangeLog = logs.getOrElse( bn, { val newChangeLog = new BlockChangeLog(List.empty, Set.empty) @@ -276,19 +276,15 @@ class ChangeLog(nodeStorage: NodeStorage) { newChangeLog } ) - } - def removeBlockMetaData(bn: BigInt): Unit = { + def removeBlockMetaData(bn: BigInt): Unit = nodeStorage.update(Seq(ChangeLog.getLogKey(bn), ChangeLog.getDrwKey(bn)), Nil) - } - def getChangeLogFromStorage(bn: BigInt): Option[List[Update]] = { + def getChangeLogFromStorage(bn: BigInt): Option[List[Update]] = nodeStorage.get(ChangeLog.getLogKey(bn)).map(ChangeLog.deserializeChangeLog) - } - def getDeathRowFromStorage(bn: BigInt): Option[List[NodeHash]] = { + def getDeathRowFromStorage(bn: BigInt): Option[List[NodeHash]] = nodeStorage.get(ChangeLog.getDrwKey(bn)).map(ChangeLog.deserializeDeathRow) - } } object ChangeLog { diff --git a/src/main/scala/io/iohk/ethereum/db/storage/ChainWeightStorage.scala b/src/main/scala/io/iohk/ethereum/db/storage/ChainWeightStorage.scala index 4f918320a2..40ae576dfe 100644 --- a/src/main/scala/io/iohk/ethereum/db/storage/ChainWeightStorage.scala +++ b/src/main/scala/io/iohk/ethereum/db/storage/ChainWeightStorage.scala @@ -1,14 +1,16 @@ package io.iohk.ethereum.db.storage import akka.util.ByteString + import boopickle.Default._ + import io.iohk.ethereum.db.dataSource.DataSource import io.iohk.ethereum.db.storage.ChainWeightStorage._ import io.iohk.ethereum.domain.ChainWeight -import io.iohk.ethereum.utils.ByteUtils.{byteSequenceToBuffer, compactPickledBytes} +import io.iohk.ethereum.utils.ByteUtils.byteSequenceToBuffer +import io.iohk.ethereum.utils.ByteUtils.compactPickledBytes -/** - * This class is used to store the ChainWeight of blocks, by using: +/** This class is used to store the ChainWeight of blocks, by using: * Key: hash of the block * Value: ChainWeight */ @@ -16,9 +18,9 @@ class ChainWeightStorage(val dataSource: DataSource) extends TransactionalKeyVal val namespace: IndexedSeq[Byte] = Namespaces.ChainWeightNamespace val keySerializer: BlockHash => ByteString = identity val keyDeserializer: IndexedSeq[Byte] => BlockHash = bytes => ByteString(bytes: _*) - val valueSerializer: ChainWeight => IndexedSeq[Byte] = Pickle.intoBytes[ChainWeight] _ andThen compactPickledBytes + val valueSerializer: ChainWeight => IndexedSeq[Byte] = (Pickle.intoBytes[ChainWeight] _).andThen(compactPickledBytes) val valueDeserializer: IndexedSeq[Byte] => ChainWeight = - byteSequenceToBuffer _ andThen Unpickle[ChainWeight].fromBytes + (byteSequenceToBuffer _).andThen(Unpickle[ChainWeight].fromBytes) } object ChainWeightStorage { diff --git a/src/main/scala/io/iohk/ethereum/db/storage/EvmCodeStorage.scala b/src/main/scala/io/iohk/ethereum/db/storage/EvmCodeStorage.scala index 63a030aaf7..92feda1c1f 100644 --- a/src/main/scala/io/iohk/ethereum/db/storage/EvmCodeStorage.scala +++ b/src/main/scala/io/iohk/ethereum/db/storage/EvmCodeStorage.scala @@ -1,13 +1,14 @@ package io.iohk.ethereum.db.storage import akka.util.ByteString + +import monix.reactive.Observable + import io.iohk.ethereum.db.dataSource.DataSource import io.iohk.ethereum.db.dataSource.RocksDbDataSource.IterationError import io.iohk.ethereum.db.storage.EvmCodeStorage._ -import monix.reactive.Observable -/** - * This class is used to store the EVM Code, by using: +/** This class is used to store the EVM Code, by using: * Key: hash of the code * Value: the code */ @@ -19,11 +20,10 @@ class EvmCodeStorage(val dataSource: DataSource) extends TransactionalKeyValueSt def valueDeserializer: IndexedSeq[Byte] => Code = (code: IndexedSeq[Byte]) => ByteString(code.toArray) // overriding to avoid going through IndexedSeq[Byte] - override def storageContent: Observable[Either[IterationError, (CodeHash, Code)]] = { + override def storageContent: Observable[Either[IterationError, (CodeHash, Code)]] = dataSource.iterate(namespace).map { result => result.map { case (key, value) => (ByteString.fromArrayUnsafe(key), ByteString.fromArrayUnsafe(value)) } } - } } object EvmCodeStorage { diff --git a/src/main/scala/io/iohk/ethereum/db/storage/FastSyncNodeStorage.scala b/src/main/scala/io/iohk/ethereum/db/storage/FastSyncNodeStorage.scala index 3734efa4a7..2fbdc8d925 100644 --- a/src/main/scala/io/iohk/ethereum/db/storage/FastSyncNodeStorage.scala +++ b/src/main/scala/io/iohk/ethereum/db/storage/FastSyncNodeStorage.scala @@ -1,11 +1,12 @@ package io.iohk.ethereum.db.storage import akka.util.ByteString -import io.iohk.ethereum.db.storage.NodeStorage.{NodeEncoded, NodeHash} + +import io.iohk.ethereum.db.storage.NodeStorage.NodeEncoded +import io.iohk.ethereum.db.storage.NodeStorage.NodeHash import io.iohk.ethereum.db.storage.encoding._ -/** - * This class is specialization of ReferenceCountNodeStorage. +/** This class is specialization of ReferenceCountNodeStorage. * It Uses the same serialization format as ReferenceCountNodeStorage, but omits all logic regarding reference counting. * It is possible to do that as during FastSyncing we are saving every mpt node under one block (one mpt trie), so every * node saved will have its reference count equal to 1. diff --git a/src/main/scala/io/iohk/ethereum/db/storage/FastSyncStateStorage.scala b/src/main/scala/io/iohk/ethereum/db/storage/FastSyncStateStorage.scala index 67a8c89611..5924d8958e 100644 --- a/src/main/scala/io/iohk/ethereum/db/storage/FastSyncStateStorage.scala +++ b/src/main/scala/io/iohk/ethereum/db/storage/FastSyncStateStorage.scala @@ -3,14 +3,16 @@ package io.iohk.ethereum.db.storage import java.nio.ByteBuffer import akka.util.ByteString + +import scala.collection.immutable.ArraySeq + import boopickle.CompositePickler import boopickle.Default._ + import io.iohk.ethereum.blockchain.sync.fast.FastSync._ import io.iohk.ethereum.db.dataSource.DataSource import io.iohk.ethereum.utils.ByteUtils.compactPickledBytes -import scala.collection.immutable.ArraySeq - object FastSyncStateStorage { val syncStateKey: String = "fast-sync-state" diff --git a/src/main/scala/io/iohk/ethereum/db/storage/KeyValueStorage.scala b/src/main/scala/io/iohk/ethereum/db/storage/KeyValueStorage.scala index ac7d38e15c..86630d539e 100644 --- a/src/main/scala/io/iohk/ethereum/db/storage/KeyValueStorage.scala +++ b/src/main/scala/io/iohk/ethereum/db/storage/KeyValueStorage.scala @@ -1,12 +1,14 @@ package io.iohk.ethereum.db.storage -import io.iohk.ethereum.common.SimpleMap -import io.iohk.ethereum.db.dataSource.RocksDbDataSource.IterationError -import io.iohk.ethereum.db.dataSource.{DataSource, DataSourceUpdate} import monix.reactive.Observable import scala.collection.immutable.ArraySeq +import io.iohk.ethereum.common.SimpleMap +import io.iohk.ethereum.db.dataSource.DataSource +import io.iohk.ethereum.db.dataSource.DataSourceUpdate +import io.iohk.ethereum.db.dataSource.RocksDbDataSource.IterationError + trait KeyValueStorage[K, V, T <: KeyValueStorage[K, V, T]] extends SimpleMap[K, V, T] { val dataSource: DataSource @@ -18,16 +20,14 @@ trait KeyValueStorage[K, V, T <: KeyValueStorage[K, V, T]] extends SimpleMap[K, protected def apply(dataSource: DataSource): T - /** - * This function obtains the associated value to a key in the current namespace, if there exists one. + /** This function obtains the associated value to a key in the current namespace, if there exists one. * * @param key * @return the value associated with the passed key, if there exists one. */ def get(key: K): Option[V] = dataSource.get(namespace, keySerializer(key)).map(valueDeserializer) - /** - * This function updates the KeyValueStorage by deleting, updating and inserting new (key-value) pairs + /** This function updates the KeyValueStorage by deleting, updating and inserting new (key-value) pairs * in the current namespace. * * @param toRemove which includes all the keys to be removed from the KeyValueStorage. @@ -48,7 +48,7 @@ trait KeyValueStorage[K, V, T <: KeyValueStorage[K, V, T]] extends SimpleMap[K, apply(dataSource) } - def storageContent: Observable[Either[IterationError, (K, V)]] = { + def storageContent: Observable[Either[IterationError, (K, V)]] = dataSource.iterate(namespace).map { result => result.map { case (key, value) => val kseq = keyDeserializer(ArraySeq.unsafeWrapArray(key)) @@ -56,5 +56,4 @@ trait KeyValueStorage[K, V, T <: KeyValueStorage[K, V, T]] extends SimpleMap[K, (kseq, vseq) } } - } } diff --git a/src/main/scala/io/iohk/ethereum/db/storage/KnownNodesStorage.scala b/src/main/scala/io/iohk/ethereum/db/storage/KnownNodesStorage.scala index cb7ef3985b..931e5e6960 100644 --- a/src/main/scala/io/iohk/ethereum/db/storage/KnownNodesStorage.scala +++ b/src/main/scala/io/iohk/ethereum/db/storage/KnownNodesStorage.scala @@ -2,12 +2,12 @@ package io.iohk.ethereum.db.storage import java.net.URI -import io.iohk.ethereum.db.dataSource.{DataSource, DataSourceBatchUpdate} - import scala.collection.immutable.ArraySeq -/** - * This class is used to store discovered nodes +import io.iohk.ethereum.db.dataSource.DataSource +import io.iohk.ethereum.db.dataSource.DataSourceBatchUpdate + +/** This class is used to store discovered nodes * Value: stored nodes list */ class KnownNodesStorage(val dataSource: DataSource) extends TransactionalKeyValueStorage[String, Set[String]] { @@ -30,9 +30,8 @@ class KnownNodesStorage(val dataSource: DataSource) extends TransactionalKeyValu def valueDeserializer: IndexedSeq[Byte] => Set[String] = (valueBytes: IndexedSeq[Byte]) => new String(valueBytes.toArray, StorageStringCharset.UTF8Charset).split(' ').toSet - def getKnownNodes(): Set[URI] = { + def getKnownNodes(): Set[URI] = get(key).getOrElse(Set.empty).filter(_.nonEmpty).map(new URI(_)) - } def updateKnownNodes(toAdd: Set[URI] = Set.empty, toRemove: Set[URI] = Set.empty): DataSourceBatchUpdate = { val updated = (getKnownNodes() ++ toAdd) -- toRemove diff --git a/src/main/scala/io/iohk/ethereum/db/storage/MptStorage.scala b/src/main/scala/io/iohk/ethereum/db/storage/MptStorage.scala index 65aafcfe16..2cf0e4e1bb 100644 --- a/src/main/scala/io/iohk/ethereum/db/storage/MptStorage.scala +++ b/src/main/scala/io/iohk/ethereum/db/storage/MptStorage.scala @@ -1,9 +1,12 @@ package io.iohk.ethereum.db.storage import akka.util.ByteString + import io.iohk.ethereum.db.storage.NodeStorage.NodeEncoded import io.iohk.ethereum.mpt.MerklePatriciaTrie.MissingRootNodeException -import io.iohk.ethereum.mpt.{MptNode, MptTraversals, NodesKeyValueStorage} +import io.iohk.ethereum.mpt.MptNode +import io.iohk.ethereum.mpt.MptTraversals +import io.iohk.ethereum.mpt.NodesKeyValueStorage trait MptStorage { def get(nodeId: Array[Byte]): MptNode @@ -27,22 +30,19 @@ class SerializingMptStorage(storage: NodesKeyValueStorage) extends MptStorage { collapsed } - override def persist(): Unit = { + override def persist(): Unit = storage.persist() - } } object MptStorage { - def collapseNode(node: Option[MptNode]): (Option[MptNode], List[(ByteString, Array[Byte])]) = { + def collapseNode(node: Option[MptNode]): (Option[MptNode], List[(ByteString, Array[Byte])]) = if (node.isEmpty) (None, List.empty[(ByteString, Array[Byte])]) else { val (hashNode, newNodes) = MptTraversals.collapseTrie(node.get) (Some(hashNode), newNodes) } - } - def decodeNode(nodeEncoded: NodeEncoded, nodeId: Array[Byte]): MptNode = { + def decodeNode(nodeEncoded: NodeEncoded, nodeId: Array[Byte]): MptNode = MptTraversals.decodeNode(nodeEncoded).withCachedHash(nodeId).withCachedRlpEncoded(nodeEncoded) - } } diff --git a/src/main/scala/io/iohk/ethereum/db/storage/Namespaces.scala b/src/main/scala/io/iohk/ethereum/db/storage/Namespaces.scala index f8550942db..7ffde38952 100644 --- a/src/main/scala/io/iohk/ethereum/db/storage/Namespaces.scala +++ b/src/main/scala/io/iohk/ethereum/db/storage/Namespaces.scala @@ -13,7 +13,7 @@ object Namespaces { val FastSyncStateNamespace: IndexedSeq[Byte] = IndexedSeq[Byte]('f'.toByte) val TransactionMappingNamespace: IndexedSeq[Byte] = IndexedSeq[Byte]('l'.toByte) - val nsSeq = Seq( + val nsSeq: Seq[IndexedSeq[Byte]] = Seq( ReceiptsNamespace, HeaderNamespace, BodyNamespace, diff --git a/src/main/scala/io/iohk/ethereum/db/storage/NodeStorage.scala b/src/main/scala/io/iohk/ethereum/db/storage/NodeStorage.scala index aeafdbb80e..bfd2ed4054 100644 --- a/src/main/scala/io/iohk/ethereum/db/storage/NodeStorage.scala +++ b/src/main/scala/io/iohk/ethereum/db/storage/NodeStorage.scala @@ -1,11 +1,15 @@ package io.iohk.ethereum.db.storage import akka.util.ByteString + +import monix.reactive.Observable + import io.iohk.ethereum.db.cache.Cache +import io.iohk.ethereum.db.dataSource.DataSource +import io.iohk.ethereum.db.dataSource.DataSourceUpdateOptimized import io.iohk.ethereum.db.dataSource.RocksDbDataSource.IterationError -import io.iohk.ethereum.db.dataSource.{DataSource, DataSourceUpdateOptimized} -import io.iohk.ethereum.db.storage.NodeStorage.{NodeEncoded, NodeHash} -import monix.reactive.Observable +import io.iohk.ethereum.db.storage.NodeStorage.NodeEncoded +import io.iohk.ethereum.db.storage.NodeStorage.NodeHash sealed trait NodesStorage extends { def get(key: NodeHash): Option[NodeEncoded] @@ -13,8 +17,7 @@ sealed trait NodesStorage extends { def updateCond(toRemove: Seq[NodeHash], toUpsert: Seq[(NodeHash, NodeEncoded)], inMemory: Boolean): NodesStorage } -/** - * This class is used to store Nodes (defined in mpt/Node.scala), by using: +/** This class is used to store Nodes (defined in mpt/Node.scala), by using: * Key: hash of the RLP encoded node * Value: the RLP encoded node */ @@ -30,8 +33,7 @@ class NodeStorage(val dataSource: DataSource) override def get(key: NodeHash): Option[NodeEncoded] = dataSource.getOptimized(namespace, key.toArray) - /** - * This function updates the KeyValueStorage by deleting, updating and inserting new (key-value) pairs + /** This function updates the KeyValueStorage by deleting, updating and inserting new (key-value) pairs * in the current namespace. * * @param toRemove which includes all the keys to be removed from the KeyValueStorage. @@ -52,17 +54,15 @@ class NodeStorage(val dataSource: DataSource) apply(dataSource) } - override def storageContent: Observable[Either[IterationError, (NodeHash, NodeEncoded)]] = { + override def storageContent: Observable[Either[IterationError, (NodeHash, NodeEncoded)]] = dataSource.iterate(namespace).map { result => result.map { case (key, value) => (ByteString.fromArrayUnsafe(key), value) } } - } protected def apply(dataSource: DataSource): NodeStorage = new NodeStorage(dataSource) - def updateCond(toRemove: Seq[NodeHash], toUpsert: Seq[(NodeHash, NodeEncoded)], inMemory: Boolean): NodesStorage = { + def updateCond(toRemove: Seq[NodeHash], toUpsert: Seq[(NodeHash, NodeEncoded)], inMemory: Boolean): NodesStorage = update(toRemove, toUpsert) - } } class CachedNodeStorage(val storage: NodeStorage, val cache: Cache[NodeHash, NodeEncoded]) diff --git a/src/main/scala/io/iohk/ethereum/db/storage/ReadOnlyNodeStorage.scala b/src/main/scala/io/iohk/ethereum/db/storage/ReadOnlyNodeStorage.scala index ac975383d6..9415cc3fb7 100644 --- a/src/main/scala/io/iohk/ethereum/db/storage/ReadOnlyNodeStorage.scala +++ b/src/main/scala/io/iohk/ethereum/db/storage/ReadOnlyNodeStorage.scala @@ -1,34 +1,33 @@ package io.iohk.ethereum.db.storage -import io.iohk.ethereum.db.storage.NodeStorage.{NodeEncoded, NodeHash} -import io.iohk.ethereum.mpt.NodesKeyValueStorage import scala.collection.mutable -/** - * This storage allows to read from another NodesKeyValueStorage but doesn't remove or upsert into database. +import io.iohk.ethereum.db.storage.NodeStorage.NodeEncoded +import io.iohk.ethereum.db.storage.NodeStorage.NodeHash +import io.iohk.ethereum.mpt.NodesKeyValueStorage + +/** This storage allows to read from another NodesKeyValueStorage but doesn't remove or upsert into database. * To do so, it uses an internal in memory cache to apply all the changes. */ class ReadOnlyNodeStorage private (wrapped: NodesKeyValueStorage) extends NodesKeyValueStorage { - val buffer = mutable.Map.empty[NodeHash, Option[NodeEncoded]] + val buffer: mutable.Map[NodeHash, Option[NodeEncoded]] = mutable.Map.empty[NodeHash, Option[NodeEncoded]] private def changes: (Seq[NodeHash], Seq[(NodeHash, NodeEncoded)]) = buffer.foldLeft(Seq.empty[NodeHash] -> Seq.empty[(NodeHash, NodeEncoded)]) { (acc, cachedItem) => cachedItem match { case (key, Some(value)) => (acc._1, acc._2 :+ key -> value) - case (key, None) => (acc._1 :+ key, acc._2) + case (key, None) => (acc._1 :+ key, acc._2) } } - /** - * This function obtains the value asociated with the key passed, if there exists one. + /** This function obtains the value asociated with the key passed, if there exists one. * * @param key * @return Option object with value if there exists one. */ override def get(key: NodeHash): Option[NodeEncoded] = buffer.getOrElse(key, wrapped.get(key)) - /** - * This function updates the KeyValueStore by deleting, updating and inserting new (key-value) pairs. + /** This function updates the KeyValueStore by deleting, updating and inserting new (key-value) pairs. * * @param toRemove which includes all the keys to be removed from the KeyValueStore. * @param toUpsert which includes all the (key-value) pairs to be inserted into the KeyValueStore. diff --git a/src/main/scala/io/iohk/ethereum/db/storage/ReceiptStorage.scala b/src/main/scala/io/iohk/ethereum/db/storage/ReceiptStorage.scala index c6819f31e8..c03ae6bfab 100644 --- a/src/main/scala/io/iohk/ethereum/db/storage/ReceiptStorage.scala +++ b/src/main/scala/io/iohk/ethereum/db/storage/ReceiptStorage.scala @@ -1,15 +1,20 @@ package io.iohk.ethereum.db.storage import akka.util.ByteString -import boopickle.Default.{Pickle, Unpickle} + +import boopickle.Default.Pickle +import boopickle.Default.Unpickle +import boopickle.DefaultBasic._ + import io.iohk.ethereum.db.dataSource.DataSource import io.iohk.ethereum.db.storage.ReceiptStorage._ -import io.iohk.ethereum.domain.{Address, SuccessOutcome, _} -import io.iohk.ethereum.utils.ByteUtils.{byteSequenceToBuffer, compactPickledBytes} -import boopickle.DefaultBasic._ +import io.iohk.ethereum.domain.Address +import io.iohk.ethereum.domain.SuccessOutcome +import io.iohk.ethereum.domain._ +import io.iohk.ethereum.utils.ByteUtils.byteSequenceToBuffer +import io.iohk.ethereum.utils.ByteUtils.compactPickledBytes -/** - * This class is used to store the Receipts, by using: +/** This class is used to store the Receipts, by using: * Key: hash of the block to which the list of receipts belong * Value: the list of receipts */ @@ -28,7 +33,7 @@ class ReceiptStorage(val dataSource: DataSource) extends TransactionalKeyValueSt compactPickledBytes(Pickle.intoBytes(receipts)) override def valueDeserializer: IndexedSeq[Byte] => ReceiptSeq = - byteSequenceToBuffer _ andThen Unpickle[Seq[Receipt]].fromBytes + (byteSequenceToBuffer _).andThen(Unpickle[Seq[Receipt]].fromBytes) } object ReceiptStorage { @@ -39,13 +44,13 @@ object ReceiptStorage { transformPickler[ByteString, Array[Byte]](ByteString(_))(_.toArray[Byte]) implicit val hashOutcomePickler: Pickler[HashOutcome] = transformPickler[HashOutcome, ByteString] { hash => HashOutcome(hash) - } { outcome => outcome.stateHash } + }(outcome => outcome.stateHash) implicit val successOutcomePickler: Pickler[SuccessOutcome.type] = transformPickler[SuccessOutcome.type, ByteString] { _ => SuccessOutcome - } { _ => ByteString(Array(1.toByte)) } + }(_ => ByteString(Array(1.toByte))) implicit val failureOutcomePickler: Pickler[FailureOutcome.type] = transformPickler[FailureOutcome.type, ByteString] { _ => FailureOutcome - } { _ => ByteString(Array(0.toByte)) } + }(_ => ByteString(Array(0.toByte))) implicit val transactionOutcomePickler: Pickler[TransactionOutcome] = compositePickler[TransactionOutcome] .addConcreteType[HashOutcome] .addConcreteType[SuccessOutcome.type] @@ -56,7 +61,7 @@ object ReceiptStorage { implicit val txLogEntryPickler: Pickler[TxLogEntry] = transformPickler[TxLogEntry, (Address, Seq[ByteString], ByteString)] { case (address, topics, data) => TxLogEntry(address, topics, data) - } { entry => (entry.loggerAddress, entry.logTopics, entry.data) } + }(entry => (entry.loggerAddress, entry.logTopics, entry.data)) implicit val receiptPickler: Pickler[Receipt] = transformPickler[Receipt, (TransactionOutcome, BigInt, ByteString, Seq[TxLogEntry])] { diff --git a/src/main/scala/io/iohk/ethereum/db/storage/ReferenceCountNodeStorage.scala b/src/main/scala/io/iohk/ethereum/db/storage/ReferenceCountNodeStorage.scala index dc2f4b86e3..3909513152 100644 --- a/src/main/scala/io/iohk/ethereum/db/storage/ReferenceCountNodeStorage.scala +++ b/src/main/scala/io/iohk/ethereum/db/storage/ReferenceCountNodeStorage.scala @@ -1,14 +1,16 @@ package io.iohk.ethereum.db.storage import akka.util.ByteString -import io.iohk.ethereum.db.storage.NodeStorage.{NodeEncoded, NodeHash} -import encoding._ + +import io.iohk.ethereum.db.storage.NodeStorage.NodeEncoded +import io.iohk.ethereum.db.storage.NodeStorage.NodeHash import io.iohk.ethereum.db.storage.pruning.PruneSupport import io.iohk.ethereum.mpt.NodesKeyValueStorage import io.iohk.ethereum.utils.Logger -/** - * This class helps to deal with two problems regarding MptNodes storage: +import encoding._ + +/** This class helps to deal with two problems regarding MptNodes storage: * 1) Define a way to delete ones that are no longer needed but allow rollbacks to be performed * 2) Avoids removal of nodes that can be used in different trie branches because the hash is the same * @@ -46,7 +48,7 @@ class ReferenceCountNodeStorage(nodeStorage: NodesStorage, bn: BigInt) extends N val changes = prepareRemovalChanges(toRemove, upsertChanges, bn) val (toUpsertUpdated, snapshots) = - changes.foldLeft(Seq.empty[(NodeHash, NodeEncoded)], Seq.empty[StoredNodeSnapshot]) { + changes.foldLeft((Seq.empty[(NodeHash, NodeEncoded)], Seq.empty[StoredNodeSnapshot])) { case ((upsertAcc, snapshotAcc), (key, (storedNode, theSnapshot))) => // Update it in DB @@ -126,18 +128,15 @@ object ReferenceCountNodeStorage extends PruneSupport with Logger { val nodeKeyLength = 32 - def drRowKey(bn: BigInt): ByteString = { + def drRowKey(bn: BigInt): ByteString = ByteString("dr".getBytes()) ++ ByteString(bn.toByteArray) - } - def getDeathRow(key: ByteString, nodeStorage: NodesStorage): ByteString = { + def getDeathRow(key: ByteString, nodeStorage: NodesStorage): ByteString = ByteString(nodeStorage.get(key).getOrElse(Array[Byte]())) - } type Changes = Map[NodeHash, (StoredNode, StoredNodeSnapshot)] - /** - * Fetches snapshots stored in the DB for the given block number and deletes the stored nodes, referred to + /** Fetches snapshots stored in the DB for the given block number and deletes the stored nodes, referred to * by these snapshots, that meet criteria for deletion (see `getNodesToBeRemovedInPruning` for details). * * All snapshots for this block are removed, which means state can no longer be rolled back to this point. @@ -158,8 +157,7 @@ object ReferenceCountNodeStorage extends PruneSupport with Logger { log.debug(s"Pruned block $blockNumber") } - /** - * Looks for the StoredNode snapshots based on block number and saves (or deletes) them + /** Looks for the StoredNode snapshots based on block number and saves (or deletes) them * * @param blockNumber BlockNumber to rollback * @param nodeStorage NodeStorage @@ -172,10 +170,10 @@ object ReferenceCountNodeStorage extends PruneSupport with Logger { // We need to delete deathrow for rollbacked block val deathRowKey = drRowKey(blockNumber) // Transform them to db operations - val (toRemove, toUpsert) = snapshots.foldLeft(Seq.empty[NodeHash], Seq.empty[(NodeHash, NodeEncoded)]) { + val (toRemove, toUpsert) = snapshots.foldLeft((Seq.empty[NodeHash], Seq.empty[(NodeHash, NodeEncoded)])) { // Undo Actions case ((r, u), StoredNodeSnapshot(nodeHash, Some(sn))) => (r, (nodeHash -> storedNodeToBytes(sn)) +: u) - case ((r, u), StoredNodeSnapshot(nodeHash, None)) => (nodeHash +: r, u) + case ((r, u), StoredNodeSnapshot(nodeHash, None)) => (nodeHash +: r, u) } // also remove snapshot as we have done a rollback nodeStorage.updateCond(toRemove :+ snapshotsCountKey :+ deathRowKey, toUpsert, inMemory) @@ -189,7 +187,7 @@ object ReferenceCountNodeStorage extends PruneSupport with Logger { val maybeSnapshotCount = nodeStorage.get(snapshotsCountKey).map(snapshotsCountFromBytes) maybeSnapshotCount match { case Some(snapshotCount) => f(snapshotsCountKey, snapshotCount) - case None => () + case None => () } } @@ -198,8 +196,7 @@ object ReferenceCountNodeStorage extends PruneSupport with Logger { (BigInt(0) until snapshotCount).map(snapshotIndex => getSnapshotKeyFn(snapshotIndex)) } - /** - * Within death row of this block, it looks for Nodes that are not longer being used in order to remove them + /** Within death row of this block, it looks for Nodes that are not longer being used in order to remove them * from DB. To do so, it checks if nodes marked in death row have still reference count equal to 0 and are not used by future * blocks. * @param blockNumber @@ -219,16 +216,13 @@ object ReferenceCountNodeStorage extends PruneSupport with Logger { for { node <- nodeStorage.get(key).map(storedNodeFromBytes) if node.references == 0 && node.lastUsedByBlock <= blockNumber - } yield { - nodesToRemove = key :: nodesToRemove - } + } yield nodesToRemove = key :: nodesToRemove } nodesToRemove } - /** - * Wrapper of MptNode in order to store number of references it has. + /** Wrapper of MptNode in order to store number of references it has. * * @param nodeEncoded Encoded Mpt Node to be used in MerklePatriciaTrie * @param references Number of references the node has. Each time it's updated references are increased and everytime it's deleted, decreased @@ -246,8 +240,7 @@ object ReferenceCountNodeStorage extends PruneSupport with Logger { def withoutReferences(nodeEncoded: Array[Byte]): StoredNode = new StoredNode(ByteString(nodeEncoded), 0, 0) } - /** - * Key to be used to store BlockNumber -> Snapshots Count + /** Key to be used to store BlockNumber -> Snapshots Count * * @param blockNumber Block Number Tag * @return Key @@ -256,8 +249,7 @@ object ReferenceCountNodeStorage extends PruneSupport with Logger { "sck".getBytes ++ blockNumber.toByteArray ) - /** - * Returns a snapshot key given a block number and a snapshot index + /** Returns a snapshot key given a block number and a snapshot index * @param blockNumber Block Number Ta * @param index Snapshot Index * @return @@ -266,8 +258,7 @@ object ReferenceCountNodeStorage extends PruneSupport with Logger { ("sk".getBytes ++ blockNumber.toByteArray) ++ index.toByteArray ) - /** - * Used to store a node snapshot in the db. This will be used to rollback a transaction. + /** Used to store a node snapshot in the db. This will be used to rollback a transaction. * @param nodeKey Node's key * @param storedNode Stored node that can be rolledback. If None, it means that node wasn't previously in the DB */ diff --git a/src/main/scala/io/iohk/ethereum/db/storage/StateStorage.scala b/src/main/scala/io/iohk/ethereum/db/storage/StateStorage.scala index 7cbb3b0f13..1739b8050f 100644 --- a/src/main/scala/io/iohk/ethereum/db/storage/StateStorage.scala +++ b/src/main/scala/io/iohk/ethereum/db/storage/StateStorage.scala @@ -2,17 +2,22 @@ package io.iohk.ethereum.db.storage import java.util.concurrent.TimeUnit -import io.iohk.ethereum.db.cache.{LruCache, MapCache} -import io.iohk.ethereum.db.dataSource.{DataSource, EphemDataSource} -import io.iohk.ethereum.db.storage.NodeStorage.{NodeEncoded, NodeHash} -import io.iohk.ethereum.db.storage.StateStorage.{FlushSituation, GenesisDataLoad} -import io.iohk.ethereum.db.storage.pruning.{ArchivePruning, PruningMode} +import scala.concurrent.duration.FiniteDuration + +import io.iohk.ethereum.db.cache.LruCache +import io.iohk.ethereum.db.cache.MapCache +import io.iohk.ethereum.db.dataSource.DataSource +import io.iohk.ethereum.db.dataSource.EphemDataSource +import io.iohk.ethereum.db.storage.NodeStorage.NodeEncoded +import io.iohk.ethereum.db.storage.NodeStorage.NodeHash +import io.iohk.ethereum.db.storage.StateStorage.FlushSituation +import io.iohk.ethereum.db.storage.StateStorage.GenesisDataLoad +import io.iohk.ethereum.db.storage.pruning.ArchivePruning +import io.iohk.ethereum.db.storage.pruning.PruningMode import io.iohk.ethereum.mpt.MptNode import io.iohk.ethereum.network.p2p.messages.ETH63.MptNodeEncoders._ import io.iohk.ethereum.utils.Config.NodeCacheConfig -import scala.concurrent.duration.FiniteDuration - // scalastyle:off trait StateStorage { def getBackingStorage(bn: BigInt): MptStorage @@ -34,33 +39,27 @@ class ArchiveStateStorage(private val nodeStorage: NodeStorage, private val cach true } - override def onBlockSave(bn: BigInt, currentBestSavedBlock: BigInt)(updateBestBlocksData: () => Unit): Unit = { + override def onBlockSave(bn: BigInt, currentBestSavedBlock: BigInt)(updateBestBlocksData: () => Unit): Unit = if (cachedNodeStorage.persist()) { updateBestBlocksData() } - } - override def onBlockRollback(bn: BigInt, currentBestSavedBlock: BigInt)(updateBestBlocksData: () => Unit): Unit = { + override def onBlockRollback(bn: BigInt, currentBestSavedBlock: BigInt)(updateBestBlocksData: () => Unit): Unit = if (cachedNodeStorage.persist()) { updateBestBlocksData() } - } - override def getReadOnlyStorage: MptStorage = { + override def getReadOnlyStorage: MptStorage = new SerializingMptStorage(ReadOnlyNodeStorage(new ArchiveNodeStorage(cachedNodeStorage))) - } - override def getBackingStorage(bn: BigInt): MptStorage = { + override def getBackingStorage(bn: BigInt): MptStorage = new SerializingMptStorage(new ArchiveNodeStorage(cachedNodeStorage)) - } - override def saveNode(nodeHash: NodeHash, nodeEncoded: NodeEncoded, bn: BigInt): Unit = { + override def saveNode(nodeHash: NodeHash, nodeEncoded: NodeEncoded, bn: BigInt): Unit = nodeStorage.put(nodeHash, nodeEncoded) - } - override def getNode(nodeHash: NodeHash): Option[MptNode] = { + override def getNode(nodeHash: NodeHash): Option[MptNode] = cachedNodeStorage.get(nodeHash).map(_.toMptNode) - } } class ReferenceCountedStateStorage( @@ -91,21 +90,17 @@ class ReferenceCountedStateStorage( } } - override def getBackingStorage(bn: BigInt): MptStorage = { + override def getBackingStorage(bn: BigInt): MptStorage = new SerializingMptStorage(new ReferenceCountNodeStorage(cachedNodeStorage, bn)) - } - override def getReadOnlyStorage: MptStorage = { + override def getReadOnlyStorage: MptStorage = new SerializingMptStorage(ReadOnlyNodeStorage(new FastSyncNodeStorage(cachedNodeStorage, 0))) - } - override def saveNode(nodeHash: NodeHash, nodeEncoded: NodeEncoded, bn: BigInt): Unit = { + override def saveNode(nodeHash: NodeHash, nodeEncoded: NodeEncoded, bn: BigInt): Unit = new FastSyncNodeStorage(nodeStorage, bn).update(Nil, Seq(nodeHash -> nodeEncoded)) - } - override def getNode(nodeHash: NodeHash): Option[MptNode] = { + override def getNode(nodeHash: NodeHash): Option[MptNode] = new FastSyncNodeStorage(cachedNodeStorage, 0).get(nodeHash).map(_.toMptNode) - } } class CachedReferenceCountedStateStorage( @@ -116,11 +111,10 @@ class CachedReferenceCountedStateStorage( private val changeLog = new ChangeLog(nodeStorage) - override def forcePersist(reason: FlushSituation): Boolean = { + override def forcePersist(reason: FlushSituation): Boolean = reason match { case GenesisDataLoad => CachedReferenceCountedStorage.persistCache(lruCache, nodeStorage, forced = true) } - } override def onBlockSave(bn: BigInt, currentBestSavedBlock: BigInt)(updateBestBlocksData: () => Unit): Unit = { val blockToPrune = bn - pruningHistory @@ -151,9 +145,14 @@ class CachedReferenceCountedStateStorage( nodeStorage.put(nodeHash, HeapEntry.toBytes(HeapEntry(nodeEncoded, 1, bn))) override def getNode(nodeHash: NodeHash): Option[MptNode] = - lruCache.get(nodeHash).map(_.nodeEncoded.toMptNode) orElse nodeStorage + lruCache .get(nodeHash) - .map(enc => HeapEntry.fromBytes(enc).nodeEncoded.toMptNode) + .map(_.nodeEncoded.toMptNode) + .orElse( + nodeStorage + .get(nodeHash) + .map(enc => HeapEntry.fromBytes(enc).nodeEncoded.toMptNode) + ) } object StateStorage { @@ -162,13 +161,12 @@ object StateStorage { nodeStorage: NodeStorage, cachedNodeStorage: CachedNodeStorage, lruCache: LruCache[NodeHash, HeapEntry] - ): StateStorage = { + ): StateStorage = pruningMode match { - case ArchivePruning => new ArchiveStateStorage(nodeStorage, cachedNodeStorage) - case pruning.BasicPruning(history) => new ReferenceCountedStateStorage(nodeStorage, cachedNodeStorage, history) + case ArchivePruning => new ArchiveStateStorage(nodeStorage, cachedNodeStorage) + case pruning.BasicPruning(history) => new ReferenceCountedStateStorage(nodeStorage, cachedNodeStorage, history) case pruning.InMemoryPruning(history) => new CachedReferenceCountedStateStorage(nodeStorage, history, lruCache) } - } def getReadOnlyStorage(source: EphemDataSource): MptStorage = mptStorageFromNodeStorage(new NodeStorage(source)) diff --git a/src/main/scala/io/iohk/ethereum/db/storage/StorageStringCharset.scala b/src/main/scala/io/iohk/ethereum/db/storage/StorageStringCharset.scala index 342277eb21..e842d1d34a 100644 --- a/src/main/scala/io/iohk/ethereum/db/storage/StorageStringCharset.scala +++ b/src/main/scala/io/iohk/ethereum/db/storage/StorageStringCharset.scala @@ -3,5 +3,5 @@ package io.iohk.ethereum.db.storage import java.nio.charset.Charset object StorageStringCharset { - val UTF8Charset = Charset.forName("UTF-8") + val UTF8Charset: Charset = Charset.forName("UTF-8") } diff --git a/src/main/scala/io/iohk/ethereum/db/storage/TransactionMappingStorage.scala b/src/main/scala/io/iohk/ethereum/db/storage/TransactionMappingStorage.scala index 71de2cf870..a06e83cdaf 100644 --- a/src/main/scala/io/iohk/ethereum/db/storage/TransactionMappingStorage.scala +++ b/src/main/scala/io/iohk/ethereum/db/storage/TransactionMappingStorage.scala @@ -1,11 +1,15 @@ package io.iohk.ethereum.db.storage import akka.util.ByteString -import io.iohk.ethereum.db.dataSource.DataSource -import io.iohk.ethereum.db.storage.TransactionMappingStorage.{TransactionLocation, TxHash} -import io.iohk.ethereum.utils.ByteUtils.{byteSequenceToBuffer, compactPickledBytes} + import boopickle.Default._ +import io.iohk.ethereum.db.dataSource.DataSource +import io.iohk.ethereum.db.storage.TransactionMappingStorage.TransactionLocation +import io.iohk.ethereum.db.storage.TransactionMappingStorage.TxHash +import io.iohk.ethereum.utils.ByteUtils.byteSequenceToBuffer +import io.iohk.ethereum.utils.ByteUtils.compactPickledBytes + class TransactionMappingStorage(val dataSource: DataSource) extends TransactionalKeyValueStorage[TxHash, TransactionLocation] { @@ -14,7 +18,7 @@ class TransactionMappingStorage(val dataSource: DataSource) def keyDeserializer: IndexedSeq[Byte] => TxHash = identity def valueSerializer: TransactionLocation => IndexedSeq[Byte] = tl => compactPickledBytes(Pickle.intoBytes(tl)) def valueDeserializer: IndexedSeq[Byte] => TransactionLocation = - byteSequenceToBuffer _ andThen Unpickle[TransactionLocation].fromBytes + (byteSequenceToBuffer _).andThen(Unpickle[TransactionLocation].fromBytes) implicit val byteStringPickler: Pickler[ByteString] = transformPickler[ByteString, Array[Byte]](ByteString(_))(_.toArray[Byte]) diff --git a/src/main/scala/io/iohk/ethereum/db/storage/TransactionalKeyValueStorage.scala b/src/main/scala/io/iohk/ethereum/db/storage/TransactionalKeyValueStorage.scala index 0a9f113949..f459c9d3ff 100644 --- a/src/main/scala/io/iohk/ethereum/db/storage/TransactionalKeyValueStorage.scala +++ b/src/main/scala/io/iohk/ethereum/db/storage/TransactionalKeyValueStorage.scala @@ -1,13 +1,15 @@ package io.iohk.ethereum.db.storage -import io.iohk.ethereum.db.dataSource.RocksDbDataSource.IterationError -import io.iohk.ethereum.db.dataSource.{DataSource, DataSourceBatchUpdate, DataSourceUpdate} import monix.reactive.Observable import scala.collection.immutable.ArraySeq -/** - * Represents transactional key value storage mapping keys of type K to values of type V +import io.iohk.ethereum.db.dataSource.DataSource +import io.iohk.ethereum.db.dataSource.DataSourceBatchUpdate +import io.iohk.ethereum.db.dataSource.DataSourceUpdate +import io.iohk.ethereum.db.dataSource.RocksDbDataSource.IterationError + +/** Represents transactional key value storage mapping keys of type K to values of type V * Note: all methods methods that perform updates return [[io.iohk.ethereum.db.dataSource.DataSourceBatchUpdate]] * meaning no updates are actually saved in the underlying DataSource until `.commit()` is called. */ @@ -20,19 +22,17 @@ trait TransactionalKeyValueStorage[K, V] { def valueDeserializer: IndexedSeq[Byte] => V def keyDeserializer: IndexedSeq[Byte] => K - /** - * This function obtains the associated value to a key in the current namespace, if there exists one. + /** This function obtains the associated value to a key in the current namespace, if there exists one. * * @param key * @return the value associated with the passed key, if there exists one. */ def get(key: K): Option[V] = dataSource.get(namespace, keySerializer(key)).map(valueDeserializer) - /** - * This function creates a batch of updates to the KeyValueStorage by deleting, updating and inserting new (key-value) + /** This function creates a batch of updates to the KeyValueStorage by deleting, updating and inserting new (key-value) * pairs in the current namespace. The batch should be committed atomically. */ - def update(toRemove: Seq[K], toUpsert: Seq[(K, V)]): DataSourceBatchUpdate = { + def update(toRemove: Seq[K], toUpsert: Seq[(K, V)]): DataSourceBatchUpdate = DataSourceBatchUpdate( dataSource, Array( @@ -45,7 +45,6 @@ trait TransactionalKeyValueStorage[K, V] { ) ) ) - } def put(key: K, value: V): DataSourceBatchUpdate = update(Nil, Seq(key -> value)) @@ -56,7 +55,7 @@ trait TransactionalKeyValueStorage[K, V] { def emptyBatchUpdate: DataSourceBatchUpdate = DataSourceBatchUpdate(dataSource, Array.empty) - def storageContent: Observable[Either[IterationError, (K, V)]] = { + def storageContent: Observable[Either[IterationError, (K, V)]] = dataSource.iterate(namespace).map { result => result.map { case (key, value) => val kseq = keyDeserializer(ArraySeq.unsafeWrapArray(key)) @@ -64,5 +63,4 @@ trait TransactionalKeyValueStorage[K, V] { (kseq, vseq) } } - } } diff --git a/src/main/scala/io/iohk/ethereum/db/storage/encoding/package.scala b/src/main/scala/io/iohk/ethereum/db/storage/encoding/package.scala index 920a409372..f1f12ed87a 100644 --- a/src/main/scala/io/iohk/ethereum/db/storage/encoding/package.scala +++ b/src/main/scala/io/iohk/ethereum/db/storage/encoding/package.scala @@ -1,6 +1,7 @@ package io.iohk.ethereum.db.storage -import io.iohk.ethereum.db.storage.ReferenceCountNodeStorage.{StoredNode, StoredNodeSnapshot} +import io.iohk.ethereum.db.storage.ReferenceCountNodeStorage.StoredNode +import io.iohk.ethereum.db.storage.ReferenceCountNodeStorage.StoredNodeSnapshot import io.iohk.ethereum.rlp.RLPImplicitConversions._ import io.iohk.ethereum.rlp.RLPImplicits._ import io.iohk.ethereum.rlp.{encode => rlpEncode, _} @@ -26,7 +27,7 @@ package object encoding { private val storedNodeEncDec = new RLPDecoder[StoredNode] with RLPEncoder[StoredNode] { override def decode(rlp: RLPEncodeable): StoredNode = rlp match { case RLPList(nodeEncoded, references, lastUsedByBlock) => StoredNode(nodeEncoded, references, lastUsedByBlock) - case _ => throw new RuntimeException("Error when decoding stored node") + case _ => throw new RuntimeException("Error when decoding stored node") } override def encode(obj: StoredNode): RLPEncodeable = RLPList(obj.nodeEncoded, obj.references, obj.lastUsedByBlock) @@ -37,7 +38,7 @@ package object encoding { case RLPList(nodeHash, storedNode) => StoredNodeSnapshot(byteStringFromEncodeable(nodeHash), Some(storedNodeFromBytes(storedNode))) case RLPValue(nodeHash) => StoredNodeSnapshot(byteStringFromEncodeable(nodeHash), None) - case _ => throw new RuntimeException("Error when decoding stored nodes") + case _ => throw new RuntimeException("Error when decoding stored nodes") } override def encode(objs: StoredNodeSnapshot): RLPEncodeable = objs match { diff --git a/src/main/scala/io/iohk/ethereum/db/storage/pruning/package.scala b/src/main/scala/io/iohk/ethereum/db/storage/pruning/package.scala index 879af3db55..bdb52a6d78 100644 --- a/src/main/scala/io/iohk/ethereum/db/storage/pruning/package.scala +++ b/src/main/scala/io/iohk/ethereum/db/storage/pruning/package.scala @@ -9,15 +9,13 @@ package object pruning { trait PruneSupport { - /** - * Remove unused data for the given block number + /** Remove unused data for the given block number * @param blockNumber BlockNumber to prune * @param nodeStorage NodeStorage */ def prune(blockNumber: BigInt, nodeStorage: NodesStorage, inMemory: Boolean): Unit - /** - * Rollbacks blocknumber changes + /** Rollbacks blocknumber changes * @param blockNumber BlockNumber to rollback * @param nodeStorage NodeStorage */ diff --git a/src/main/scala/io/iohk/ethereum/domain/Account.scala b/src/main/scala/io/iohk/ethereum/domain/Account.scala index 2e479a038f..394d0db777 100644 --- a/src/main/scala/io/iohk/ethereum/domain/Account.scala +++ b/src/main/scala/io/iohk/ethereum/domain/Account.scala @@ -1,23 +1,25 @@ package io.iohk.ethereum.domain import akka.util.ByteString + +import scala.util.Try + +import org.bouncycastle.util.encoders.Hex + import io.iohk.ethereum.crypto.kec256 import io.iohk.ethereum.mpt.ByteArraySerializable import io.iohk.ethereum.network.p2p.messages.ETH63.AccountImplicits import io.iohk.ethereum.rlp import io.iohk.ethereum.rlp.RLPImplicits._ -import org.bouncycastle.util.encoders.Hex - -import scala.util.Try object Account { - val EmptyStorageRootHash = ByteString(kec256(rlp.encode(Array.empty[Byte]))) + val EmptyStorageRootHash: ByteString = ByteString(kec256(rlp.encode(Array.empty[Byte]))) val EmptyCodeHash: ByteString = kec256(ByteString()) def empty(startNonce: UInt256 = UInt256.Zero): Account = Account(nonce = startNonce, storageRoot = EmptyStorageRootHash, codeHash = EmptyCodeHash) - implicit val accountSerializer = new ByteArraySerializable[Account] { + implicit val accountSerializer: ByteArraySerializable[Account] = new ByteArraySerializable[Account] { import AccountImplicits._ @@ -48,15 +50,13 @@ case class Account( def withStorage(storageRoot: ByteString): Account = copy(storageRoot = storageRoot) - /** - * According to EIP161: An account is considered empty when it has no code and zero nonce and zero balance. + /** According to EIP161: An account is considered empty when it has no code and zero nonce and zero balance. * An account's storage is not relevant when determining emptiness. */ def isEmpty(startNonce: UInt256 = UInt256.Zero): Boolean = nonce == startNonce && balance == UInt256.Zero && codeHash == Account.EmptyCodeHash - /** - * Under EIP-684 if this evaluates to true then we have a conflict when creating a new account + /** Under EIP-684 if this evaluates to true then we have a conflict when creating a new account */ def nonEmptyCodeOrNonce(startNonce: UInt256 = UInt256.Zero): Boolean = nonce != startNonce || codeHash != Account.EmptyCodeHash diff --git a/src/main/scala/io/iohk/ethereum/domain/Address.scala b/src/main/scala/io/iohk/ethereum/domain/Address.scala index 9696d4d41b..d32807fce4 100644 --- a/src/main/scala/io/iohk/ethereum/domain/Address.scala +++ b/src/main/scala/io/iohk/ethereum/domain/Address.scala @@ -1,17 +1,19 @@ package io.iohk.ethereum.domain import akka.util.ByteString + +import org.bouncycastle.crypto.AsymmetricCipherKeyPair +import org.bouncycastle.util.encoders.Hex + import io.iohk.ethereum.crypto import io.iohk.ethereum.mpt.ByteArrayEncoder import io.iohk.ethereum.utils.ByteUtils.padLeft -import org.bouncycastle.crypto.AsymmetricCipherKeyPair -import org.bouncycastle.util.encoders.Hex object Address { val Length = 20 - implicit val hashedAddressEncoder = new ByteArrayEncoder[Address] { + implicit val hashedAddressEncoder: ByteArrayEncoder[Address] = new ByteArrayEncoder[Address] { override def toBytes(addr: Address): Array[Byte] = crypto.kec256(addr.toArray) } @@ -49,7 +51,7 @@ class Address private (val bytes: ByteString) { override def equals(that: Any): Boolean = that match { case addr: Address => addr.bytes == bytes - case _ => false + case _ => false } override def hashCode: Int = diff --git a/src/main/scala/io/iohk/ethereum/domain/Block.scala b/src/main/scala/io/iohk/ethereum/domain/Block.scala index 220315889c..82fb80e121 100644 --- a/src/main/scala/io/iohk/ethereum/domain/Block.scala +++ b/src/main/scala/io/iohk/ethereum/domain/Block.scala @@ -1,11 +1,14 @@ package io.iohk.ethereum.domain import akka.util.ByteString + import io.iohk.ethereum.domain.BlockHeaderImplicits._ -import io.iohk.ethereum.rlp.{RLPEncodeable, RLPList, RLPSerializable, rawDecode} +import io.iohk.ethereum.rlp.RLPEncodeable +import io.iohk.ethereum.rlp.RLPList +import io.iohk.ethereum.rlp.RLPSerializable +import io.iohk.ethereum.rlp.rawDecode -/** - * This class represent a block as a header and a body which are returned in two different messages +/** This class represent a block as a header and a body which are returned in two different messages * * @param header Block header * @param body Block body diff --git a/src/main/scala/io/iohk/ethereum/domain/BlockBody.scala b/src/main/scala/io/iohk/ethereum/domain/BlockBody.scala index 544b242a53..a24b2c3daa 100644 --- a/src/main/scala/io/iohk/ethereum/domain/BlockBody.scala +++ b/src/main/scala/io/iohk/ethereum/domain/BlockBody.scala @@ -1,7 +1,10 @@ package io.iohk.ethereum.domain import io.iohk.ethereum.domain.BlockHeaderImplicits._ -import io.iohk.ethereum.rlp.{RLPEncodeable, RLPList, RLPSerializable, rawDecode} +import io.iohk.ethereum.rlp.RLPEncodeable +import io.iohk.ethereum.rlp.RLPList +import io.iohk.ethereum.rlp.RLPSerializable +import io.iohk.ethereum.rlp.rawDecode import io.iohk.ethereum.utils.ByteStringUtils.ByteStringOps case class BlockBody(transactionList: Seq[SignedTransaction], uncleNodesList: Seq[BlockHeader]) { @@ -18,7 +21,7 @@ case class BlockBody(transactionList: Seq[SignedTransaction], uncleNodesList: Se object BlockBody { - val empty = BlockBody(Seq.empty, Seq.empty) + val empty: BlockBody = BlockBody(Seq.empty, Seq.empty) def blockBodyToRlpEncodable( blockBody: BlockBody, diff --git a/src/main/scala/io/iohk/ethereum/domain/BlockHeader.scala b/src/main/scala/io/iohk/ethereum/domain/BlockHeader.scala index b484e23919..8209c2562b 100644 --- a/src/main/scala/io/iohk/ethereum/domain/BlockHeader.scala +++ b/src/main/scala/io/iohk/ethereum/domain/BlockHeader.scala @@ -1,16 +1,23 @@ package io.iohk.ethereum.domain import akka.util.ByteString + +import io.iohk.ethereum.crypto import io.iohk.ethereum.crypto.kec256 -import io.iohk.ethereum.{crypto, rlp} -import io.iohk.ethereum.rlp.{RLPDecoder, RLPEncodeable, RLPList, RLPSerializable, rawDecode, encode => rlpEncode} -import BlockHeaderImplicits._ -import io.iohk.ethereum.utils.ByteStringUtils -import io.iohk.ethereum.domain.BlockHeader.HeaderExtraFields._ import io.iohk.ethereum.domain.BlockHeader.HeaderExtraFields +import io.iohk.ethereum.domain.BlockHeader.HeaderExtraFields._ +import io.iohk.ethereum.rlp +import io.iohk.ethereum.rlp.RLPDecoder +import io.iohk.ethereum.rlp.RLPEncodeable +import io.iohk.ethereum.rlp.RLPList +import io.iohk.ethereum.rlp.RLPSerializable +import io.iohk.ethereum.rlp.rawDecode +import io.iohk.ethereum.rlp.{encode => rlpEncode} +import io.iohk.ethereum.utils.ByteStringUtils + +import BlockHeaderImplicits._ -/** - * @param extraFields contains the new fields added in ECIPs 1097 and 1098 and can contain values: +/** @param extraFields contains the new fields added in ECIPs 1097 and 1098 and can contain values: * - HefPreECIP1098: represents the ETC blocks without checkpointing nor treasury enabled * - HefPostECIP1098: represents the ETC blocks with treasury enabled but not checkpointing * - HefPostECIP1097: represents the ETC blocks with both checkpointing and treasury enabled @@ -42,7 +49,7 @@ case class BlockHeader( val checkpoint: Option[Checkpoint] = extraFields match { case HefPostEcip1097(maybeCheckpoint) => maybeCheckpoint - case _ => None + case _ => None } val hasCheckpoint: Boolean = checkpoint.isDefined @@ -79,8 +86,7 @@ case class BlockHeader( s"}" } - /** - * calculates blockHash for given block header + /** calculates blockHash for given block header * @return - hash that can be used to get block bodies / receipts */ lazy val hash: ByteString = ByteString(kec256(this.toBytes: Array[Byte])) @@ -102,8 +108,7 @@ object BlockHeader { val EmptyOmmers: ByteString = ByteString(crypto.kec256(rlp.encode(RLPList()))) - /** - * Given a block header, returns it's rlp encoded bytes without nonce and mix hash + /** Given a block header, returns it's rlp encoded bytes without nonce and mix hash * * @param blockHeader to be encoded without PoW fields * @return rlp.encode( [blockHeader.parentHash, ..., blockHeader.extraData] + extra fields ) @@ -115,7 +120,7 @@ object BlockHeader { val numberOfPowFields = 2 val numberOfExtraFields = blockHeader.extraFields match { case HefPostEcip1097(_) => 1 - case HefEmpty => 0 + case HefEmpty => 0 } val preECIP1098Fields = rlpList.items.dropRight(numberOfPowFields + numberOfExtraFields) diff --git a/src/main/scala/io/iohk/ethereum/domain/Blockchain.scala b/src/main/scala/io/iohk/ethereum/domain/Blockchain.scala index 9523de450a..578284d246 100644 --- a/src/main/scala/io/iohk/ethereum/domain/Blockchain.scala +++ b/src/main/scala/io/iohk/ethereum/domain/Blockchain.scala @@ -1,28 +1,32 @@ package io.iohk.ethereum.domain import java.util.concurrent.atomic.AtomicReference + import akka.util.ByteString -import cats.syntax.flatMap._ + import cats.instances.option._ +import cats.syntax.flatMap._ + +import scala.annotation.tailrec + import io.iohk.ethereum.db.dataSource.DataSourceBatchUpdate -import io.iohk.ethereum.db.dataSource.RocksDbDataSource.IterationError -import io.iohk.ethereum.db.storage.NodeStorage.{NodeEncoded, NodeHash} +import io.iohk.ethereum.db.storage.NodeStorage.NodeEncoded +import io.iohk.ethereum.db.storage.NodeStorage.NodeHash import io.iohk.ethereum.db.storage.TransactionMappingStorage.TransactionLocation import io.iohk.ethereum.db.storage._ -import io.iohk.ethereum.db.storage.pruning.PruningMode import io.iohk.ethereum.domain import io.iohk.ethereum.domain.BlockchainImpl.BestBlockLatestCheckpointNumbers import io.iohk.ethereum.jsonrpc.ProofService.StorageProof -import io.iohk.ethereum.ledger.{InMemoryWorldStateProxy, InMemoryWorldStateProxyStorage} -import io.iohk.ethereum.mpt.{MerklePatriciaTrie, MptNode} -import io.iohk.ethereum.utils.{ByteStringUtils, Logger} -import io.iohk.ethereum.vm.{Storage, WorldStateProxy} -import monix.reactive.Observable - -import scala.annotation.tailrec - -/** - * Entity to be used to persist and query Blockchain related objects (blocks, transactions, ommers) +import io.iohk.ethereum.ledger.InMemoryWorldStateProxy +import io.iohk.ethereum.ledger.InMemoryWorldStateProxyStorage +import io.iohk.ethereum.mpt.MerklePatriciaTrie +import io.iohk.ethereum.mpt.MptNode +import io.iohk.ethereum.utils.ByteStringUtils +import io.iohk.ethereum.utils.Logger +import io.iohk.ethereum.vm.Storage +import io.iohk.ethereum.vm.WorldStateProxy + +/** Entity to be used to persist and query Blockchain related objects (blocks, transactions, ommers) */ // scalastyle:off number.of.methods trait Blockchain { @@ -30,8 +34,7 @@ trait Blockchain { type S <: Storage[S] type WS <: WorldStateProxy[WS, S] - /** - * Get an account for an address and a block number + /** Get an account for an address and a block number * * @param address address of the account * @param blockNumber the block that determines the state of the account @@ -40,16 +43,14 @@ trait Blockchain { def getAccountProof(address: Address, blockNumber: BigInt): Option[Vector[MptNode]] - /** - * Get account storage at given position + /** Get account storage at given position * * @param rootHash storage root hash * @param position storage position */ def getAccountStorageAt(rootHash: ByteString, position: BigInt, ethCompatibleStorage: Boolean): ByteString - /** - * Get a storage-value and its proof being the path from the root node until the last matching node. + /** Get a storage-value and its proof being the path from the root node until the last matching node. * * @param rootHash storage root hash * @param position storage position @@ -60,8 +61,7 @@ trait Blockchain { ethCompatibleStorage: Boolean ): StorageProof - /** - * Get the MptStorage + /** Get the MptStorage * @param blockNumber * @return MptStorage */ @@ -73,8 +73,7 @@ trait Blockchain { */ def getReadOnlyMptStorage(): MptStorage - /** - * Looks up ChainWeight for a given chain + /** Looks up ChainWeight for a given chain * @param blockhash Hash of top block in the chain * @return ChainWeight if found */ @@ -86,27 +85,23 @@ trait Blockchain { def getLatestCheckpointBlockNumber(): BigInt - /** - * Persists full block along with receipts and chain weight + /** Persists full block along with receipts and chain weight * @param saveAsBestBlock - whether to save the block's number as current best block */ def save(block: Block, receipts: Seq[Receipt], chainWeight: ChainWeight, saveAsBestBlock: Boolean): Unit - /** - * Persists a block in the underlying Blockchain Database + /** Persists a block in the underlying Blockchain Database * Note: all store* do not update the database immediately, rather they create * a [[io.iohk.ethereum.db.dataSource.DataSourceBatchUpdate]] which then has to be committed (atomic operation) * * @param block Block to be saved */ - def storeBlock(block: Block): DataSourceBatchUpdate = { + def storeBlock(block: Block): DataSourceBatchUpdate = storeBlockHeader(block.header).and(storeBlockBody(block.header.hash, block.body)) - } def removeBlock(hash: ByteString, withState: Boolean): Unit - /** - * Persists a block header in the underlying Blockchain Database + /** Persists a block header in the underlying Blockchain Database * * @param blockHeader Block to be saved */ @@ -128,8 +123,7 @@ trait Blockchain { def genesisBlock: Block - /** - * Strict check if given block hash is in chain + /** Strict check if given block hash is in chain * Using any of getXXXByHash is not always accurate - after restart the best block is often lower than before restart * The result of that is returning data of blocks which we don't consider as a part of the chain anymore * @param hash block hash @@ -163,12 +157,11 @@ class BlockchainImpl( ) ) - override def isInChain(hash: ByteString): Boolean = { + override def isInChain(hash: ByteString): Boolean = (for { header <- blockchainReader.getBlockHeaderByHash(hash) if header.number <= getBestBlockNumber() hash <- blockchainReader.getHashByBlockNumber(header.number) } yield header.hash == hash).getOrElse(false) - } override def getChainWeightByHash(blockhash: ByteString): Option[ChainWeight] = chainWeightStorage.get(blockhash) @@ -193,9 +186,13 @@ class BlockchainImpl( override def getBestBlock(): Option[Block] = { val bestBlockNumber = getBestBlockNumber() log.debug("Trying to get best block with number {}", bestBlockNumber) - blockchainReader.getBlockByNumber(bestBlockNumber) orElse blockchainReader.getBlockByNumber( - appStateStorage.getBestBlockNumber() - ) + blockchainReader + .getBlockByNumber(bestBlockNumber) + .orElse( + blockchainReader.getBlockByNumber( + appStateStorage.getBestBlockNumber() + ) + ) } override def getAccount(address: Address, blockNumber: BigInt): Option[Account] = @@ -302,9 +299,8 @@ class BlockchainImpl( blockHeadersStorage.put(hash, blockHeader).and(saveBlockNumberMapping(blockHeader.number, hash)) } - override def storeBlockBody(blockHash: ByteString, blockBody: BlockBody): DataSourceBatchUpdate = { + override def storeBlockBody(blockHash: ByteString, blockBody: BlockBody): DataSourceBatchUpdate = blockBodiesStorage.put(blockHash, blockBody).and(saveTxsLocations(blockHash, blockBody)) - } override def storeReceipts(blockHash: ByteString, receipts: Seq[Receipt]): DataSourceBatchUpdate = receiptStorage.put(blockHash, receipts) @@ -312,14 +308,13 @@ class BlockchainImpl( override def storeEvmCode(hash: ByteString, evmCode: ByteString): DataSourceBatchUpdate = evmCodeStorage.put(hash, evmCode) - override def saveBestKnownBlocks(bestBlockNumber: BigInt, latestCheckpointNumber: Option[BigInt] = None): Unit = { + override def saveBestKnownBlocks(bestBlockNumber: BigInt, latestCheckpointNumber: Option[BigInt] = None): Unit = latestCheckpointNumber match { case Some(number) => saveBestKnownBlockAndLatestCheckpointNumber(bestBlockNumber, number) case None => saveBestKnownBlock(bestBlockNumber) } - } private def saveBestKnownBlock(bestBlockNumber: BigInt): Unit = bestKnownBlockAndLatestCheckpoint.updateAndGet(_.copy(bestBlockNumber = bestBlockNumber)) @@ -340,9 +335,8 @@ class BlockchainImpl( private def saveBlockNumberMapping(number: BigInt, hash: ByteString): DataSourceBatchUpdate = blockNumberMappingStorage.put(number, hash) - private def removeBlockNumberMapping(number: BigInt): DataSourceBatchUpdate = { + private def removeBlockNumberMapping(number: BigInt): DataSourceBatchUpdate = blockNumberMappingStorage.remove(number) - } override def removeBlock(blockHash: ByteString, withState: Boolean): Unit = { val maybeBlock = blockchainReader.getBlockByHash(blockHash) @@ -420,19 +414,18 @@ class BlockchainImpl( // not transactional part if (withState) - stateStorage.onBlockRollback(block.number, bestBlockNumber) { () => persistBestBlocksData() } + stateStorage.onBlockRollback(block.number, bestBlockNumber)(() => persistBestBlocksData()) } // scalastyle:on method.length - /** - * Recursive function which try to find the previous checkpoint by traversing blocks from top to the bottom. + /** Recursive function which try to find the previous checkpoint by traversing blocks from top to the bottom. * In case of finding the checkpoint block number, the function will finish the job and return result */ @tailrec private def findPreviousCheckpointBlockNumber( blockNumberToCheck: BigInt, latestCheckpointBlockNumber: BigInt - ): BigInt = { + ): BigInt = if (blockNumberToCheck > 0) { val maybePreviousCheckpointBlockNumber = for { currentBlock <- blockchainReader.getBlockByNumber(blockNumberToCheck) @@ -442,10 +435,9 @@ class BlockchainImpl( maybePreviousCheckpointBlockNumber match { case Some(previousCheckpointBlockNumber) => previousCheckpointBlockNumber - case None => findPreviousCheckpointBlockNumber(blockNumberToCheck - 1, latestCheckpointBlockNumber) + case None => findPreviousCheckpointBlockNumber(blockNumberToCheck - 1, latestCheckpointBlockNumber) } } else 0 - } private def saveTxsLocations(blockHash: ByteString, blockBody: BlockBody): DataSourceBatchUpdate = blockBody.transactionList.zipWithIndex.foldLeft(transactionMappingStorage.emptyBatchUpdate) { @@ -453,11 +445,10 @@ class BlockchainImpl( updates.and(transactionMappingStorage.put(tx.hash, TransactionLocation(blockHash, index))) } - private def removeTxsLocations(stxs: Seq[SignedTransaction]): DataSourceBatchUpdate = { + private def removeTxsLocations(stxs: Seq[SignedTransaction]): DataSourceBatchUpdate = stxs.map(_.hash).foldLeft(transactionMappingStorage.emptyBatchUpdate) { case (updates, hash) => updates.and(transactionMappingStorage.remove(hash)) } - } override type S = InMemoryWorldStateProxyStorage override type WS = InMemoryWorldStateProxy diff --git a/src/main/scala/io/iohk/ethereum/domain/BlockchainReader.scala b/src/main/scala/io/iohk/ethereum/domain/BlockchainReader.scala index 6b63b42660..87f88a60df 100644 --- a/src/main/scala/io/iohk/ethereum/domain/BlockchainReader.scala +++ b/src/main/scala/io/iohk/ethereum/domain/BlockchainReader.scala @@ -1,13 +1,12 @@ package io.iohk.ethereum.domain import akka.util.ByteString -import io.iohk.ethereum.db.storage.{ - BlockBodiesStorage, - BlockHeadersStorage, - BlockNumberMappingStorage, - ReceiptStorage, - StateStorage -} + +import io.iohk.ethereum.db.storage.BlockBodiesStorage +import io.iohk.ethereum.db.storage.BlockHeadersStorage +import io.iohk.ethereum.db.storage.BlockNumberMappingStorage +import io.iohk.ethereum.db.storage.ReceiptStorage +import io.iohk.ethereum.db.storage.StateStorage import io.iohk.ethereum.mpt.MptNode class BlockchainReader( @@ -18,8 +17,7 @@ class BlockchainReader( receiptStorage: ReceiptStorage ) { - /** - * Allows to query a blockHeader by block hash + /** Allows to query a blockHeader by block hash * * @param hash of the block that's being searched * @return [[BlockHeader]] if found @@ -27,8 +25,7 @@ class BlockchainReader( def getBlockHeaderByHash(hash: ByteString): Option[BlockHeader] = blockHeadersStorage.get(hash) - /** - * Allows to query a blockBody by block hash + /** Allows to query a blockBody by block hash * * @param hash of the block that's being searched * @return [[io.iohk.ethereum.domain.BlockBody]] if found @@ -36,8 +33,7 @@ class BlockchainReader( def getBlockBodyByHash(hash: ByteString): Option[BlockBody] = blockBodiesStorage.get(hash) - /** - * Allows to query for a block based on it's hash + /** Allows to query for a block based on it's hash * * @param hash of the block that's being searched * @return Block if found @@ -48,8 +44,7 @@ class BlockchainReader( body <- getBlockBodyByHash(hash) } yield Block(header, body) - /** - * Returns a block hash given a block number + /** Returns a block hash given a block number * * @param number Number of the searchead block * @return Block hash if found @@ -57,15 +52,13 @@ class BlockchainReader( def getHashByBlockNumber(number: BigInt): Option[ByteString] = blockNumberMappingStorage.get(number) - def getBlockHeaderByNumber(number: BigInt): Option[BlockHeader] = { + def getBlockHeaderByNumber(number: BigInt): Option[BlockHeader] = for { hash <- getHashByBlockNumber(number) header <- getBlockHeaderByHash(hash) } yield header - } - /** - * Allows to query for a block based on it's number + /** Allows to query for a block based on it's number * * @param number Block number * @return Block if it exists @@ -76,16 +69,14 @@ class BlockchainReader( block <- getBlockByHash(hash) } yield block - /** - * Returns MPT node searched by it's hash + /** Returns MPT node searched by it's hash * @param hash Node Hash * @return MPT node */ def getMptNodeByHash(hash: ByteString): Option[MptNode] = stateStorage.getNode(hash) - /** - * Returns the receipts based on a block hash + /** Returns the receipts based on a block hash * @param blockhash * @return Receipts if found */ diff --git a/src/main/scala/io/iohk/ethereum/domain/HeadersSeq.scala b/src/main/scala/io/iohk/ethereum/domain/HeadersSeq.scala index ef53b322fa..f60fb4d387 100644 --- a/src/main/scala/io/iohk/ethereum/domain/HeadersSeq.scala +++ b/src/main/scala/io/iohk/ethereum/domain/HeadersSeq.scala @@ -3,12 +3,11 @@ package io.iohk.ethereum.domain object HeadersSeq { def lastNumber(headers: HeadersSeq): Option[BigInt] = headers.lastOption.map(_.number) - def areChain(headers: HeadersSeq): Boolean = { + def areChain(headers: HeadersSeq): Boolean = if (headers.length > 1) headers.zip(headers.tail).forall { case (parent, child) => parent.hash == child.parentHash && parent.number + 1 == child.number } else headers.nonEmpty - } } diff --git a/src/main/scala/io/iohk/ethereum/domain/Receipt.scala b/src/main/scala/io/iohk/ethereum/domain/Receipt.scala index 0027b16b8a..9565eb13ee 100644 --- a/src/main/scala/io/iohk/ethereum/domain/Receipt.scala +++ b/src/main/scala/io/iohk/ethereum/domain/Receipt.scala @@ -1,9 +1,11 @@ package io.iohk.ethereum.domain import akka.util.ByteString -import io.iohk.ethereum.mpt.ByteArraySerializable + import org.bouncycastle.util.encoders.Hex +import io.iohk.ethereum.mpt.ByteArraySerializable + object Receipt { val byteArraySerializable: ByteArraySerializable[Receipt] = new ByteArraySerializable[Receipt] { @@ -19,14 +21,12 @@ object Receipt { cumulativeGasUsed: BigInt, logsBloomFilter: ByteString, logs: Seq[TxLogEntry] - ): Receipt = { + ): Receipt = Receipt(HashOutcome(postTransactionStateHash), cumulativeGasUsed, logsBloomFilter, logs) - } } -/** - * @param postTransactionStateHash For blocks where block.number >= byzantium-block-number (from config), +/** @param postTransactionStateHash For blocks where block.number >= byzantium-block-number (from config), * the intermediate state root is replaced by a status code, * 0 indicating failure [[FailureOutcome]] (due to any operation that can cause * the transaction or top-level call to revert) @@ -44,8 +44,8 @@ case class Receipt( override def toString: String = { val stateHash = postTransactionStateHash match { case HashOutcome(hash) => hash.toArray[Byte] - case SuccessOutcome => Array(1.toByte) - case _ => Array(0.toByte) + case SuccessOutcome => Array(1.toByte) + case _ => Array(0.toByte) } s"Receipt{ " + diff --git a/src/main/scala/io/iohk/ethereum/domain/SignedTransaction.scala b/src/main/scala/io/iohk/ethereum/domain/SignedTransaction.scala index caa01222f7..57b29444bb 100644 --- a/src/main/scala/io/iohk/ethereum/domain/SignedTransaction.scala +++ b/src/main/scala/io/iohk/ethereum/domain/SignedTransaction.scala @@ -1,21 +1,27 @@ package io.iohk.ethereum.domain +import java.math.BigInteger +import java.util.concurrent.Executors + import akka.util.ByteString -import com.google.common.cache.{Cache, CacheBuilder} + +import monix.eval.Task +import monix.execution.Scheduler + +import scala.util.Try + +import com.google.common.cache.Cache +import com.google.common.cache.CacheBuilder +import org.bouncycastle.crypto.AsymmetricCipherKeyPair + import io.iohk.ethereum.crypto -import io.iohk.ethereum.crypto.{ECDSASignature, kec256} +import io.iohk.ethereum.crypto.ECDSASignature +import io.iohk.ethereum.crypto.kec256 import io.iohk.ethereum.mpt.ByteArraySerializable import io.iohk.ethereum.network.p2p.messages.BaseETH6XMessages.SignedTransactions._ import io.iohk.ethereum.rlp.RLPImplicitConversions._ import io.iohk.ethereum.rlp.RLPImplicits._ import io.iohk.ethereum.rlp.{encode => rlpEncode, _} -import java.math.BigInteger -import java.util.concurrent.Executors -import monix.eval.Task -import monix.execution.Scheduler -import org.bouncycastle.crypto.AsymmetricCipherKeyPair -import org.bouncycastle.util.encoders.Hex -import scala.util.Try object SignedTransaction { @@ -74,18 +80,16 @@ object SignedTransaction { SignedTransactionWithSender(tx, sig, address) } - private def bytesToSign(tx: Transaction, chainId: Option[Byte]): Array[Byte] = { + private def bytesToSign(tx: Transaction, chainId: Option[Byte]): Array[Byte] = chainId match { case Some(id) => chainSpecificTransactionBytes(tx, id) case None => generalTransactionBytes(tx) } - } - def getSender(tx: SignedTransaction): Option[Address] = { - Option(txSenders.getIfPresent(tx.hash)) orElse calculateSender(tx) - } + def getSender(tx: SignedTransaction): Option[Address] = + Option(txSenders.getIfPresent(tx.hash)).orElse(calculateSender(tx)) private def calculateSender(tx: SignedTransaction): Option[Address] = Try { val ECDSASignature(_, _, v) = tx.signature @@ -115,13 +119,11 @@ object SignedTransaction { Task.traverse(blocktx.toSeq)(calculateSendersForTxs).runAsyncAndForget } - private def calculateSendersForTxs(txs: Seq[SignedTransaction]): Task[Unit] = { + private def calculateSendersForTxs(txs: Seq[SignedTransaction]): Task[Unit] = Task(txs.foreach(calculateAndCacheSender)) - } - private def calculateAndCacheSender(stx: SignedTransaction) = { + private def calculateAndCacheSender(stx: SignedTransaction) = calculateSender(stx).foreach(address => txSenders.put(stx.hash, address)) - } private def generalTransactionBytes(tx: Transaction): Array[Byte] = { val receivingAddressAsArray: Array[Byte] = tx.receivingAddress.map(_.toArray).getOrElse(Array.emptyByteArray) @@ -147,7 +149,7 @@ object SignedTransaction { ) } - val byteArraySerializable = new ByteArraySerializable[SignedTransaction] { + val byteArraySerializable: ByteArraySerializable[SignedTransaction] = new ByteArraySerializable[SignedTransaction] { override def fromBytes(bytes: Array[Byte]): SignedTransaction = bytes.toSignedTransaction @@ -176,14 +178,12 @@ case class SignedTransactionWithSender(tx: SignedTransaction, senderAddress: Add object SignedTransactionWithSender { - def getSignedTransactions(stxs: Seq[SignedTransaction]): Seq[SignedTransactionWithSender] = { + def getSignedTransactions(stxs: Seq[SignedTransaction]): Seq[SignedTransactionWithSender] = stxs.foldLeft(List.empty[SignedTransactionWithSender]) { (acc, stx) => val sender = SignedTransaction.getSender(stx) - sender.fold(acc) { addr => SignedTransactionWithSender(stx, addr) :: acc } + sender.fold(acc)(addr => SignedTransactionWithSender(stx, addr) :: acc) } - } - def apply(transaction: Transaction, signature: ECDSASignature, sender: Address): SignedTransactionWithSender = { + def apply(transaction: Transaction, signature: ECDSASignature, sender: Address): SignedTransactionWithSender = SignedTransactionWithSender(SignedTransaction(transaction, signature), sender) - } } diff --git a/src/main/scala/io/iohk/ethereum/domain/Transaction.scala b/src/main/scala/io/iohk/ethereum/domain/Transaction.scala index d3b7f70baf..6befb5c799 100644 --- a/src/main/scala/io/iohk/ethereum/domain/Transaction.scala +++ b/src/main/scala/io/iohk/ethereum/domain/Transaction.scala @@ -1,6 +1,7 @@ package io.iohk.ethereum.domain import akka.util.ByteString + import org.bouncycastle.util.encoders.Hex object Transaction { diff --git a/src/main/scala/io/iohk/ethereum/domain/TxLogEntry.scala b/src/main/scala/io/iohk/ethereum/domain/TxLogEntry.scala index 8df6d8bb4c..1f0944770a 100644 --- a/src/main/scala/io/iohk/ethereum/domain/TxLogEntry.scala +++ b/src/main/scala/io/iohk/ethereum/domain/TxLogEntry.scala @@ -1,13 +1,13 @@ package io.iohk.ethereum.domain import akka.util.ByteString + import org.bouncycastle.util.encoders.Hex case class TxLogEntry(loggerAddress: Address, logTopics: Seq[ByteString], data: ByteString) { - override def toString: String = { + override def toString: String = s"${getClass.getSimpleName}(" + s"loggerAddress: $loggerAddress" + s"logTopics: ${logTopics.map(e => Hex.toHexString(e.toArray[Byte]))}" + s"data: ${Hex.toHexString(data.toArray[Byte])}" + ")" - } } diff --git a/src/main/scala/io/iohk/ethereum/domain/UInt256.scala b/src/main/scala/io/iohk/ethereum/domain/UInt256.scala index 46dc0693bc..d97fba4d6c 100644 --- a/src/main/scala/io/iohk/ethereum/domain/UInt256.scala +++ b/src/main/scala/io/iohk/ethereum/domain/UInt256.scala @@ -1,10 +1,11 @@ package io.iohk.ethereum.domain import akka.util.ByteString -import io.iohk.ethereum.utils.ByteUtils import scala.language.implicitConversions +import io.iohk.ethereum.utils.ByteUtils + // scalastyle:off number.of.methods object UInt256 { @@ -128,20 +129,20 @@ class UInt256 private (private val n: BigInt) extends Ordered[UInt256] { private def zeroCheck(x: UInt256)(result: => BigInt): UInt256 = if (x.isZero) Zero else UInt256(result) - def div(that: UInt256): UInt256 = zeroCheck(that) { new UInt256(this.n / that.n) } + def div(that: UInt256): UInt256 = zeroCheck(that)(new UInt256(this.n / that.n)) - def sdiv(that: UInt256): UInt256 = zeroCheck(that) { UInt256(this.signedN / that.signedN) } + def sdiv(that: UInt256): UInt256 = zeroCheck(that)(UInt256(this.signedN / that.signedN)) - def mod(that: UInt256): UInt256 = zeroCheck(that) { UInt256(this.n mod that.n) } + def mod(that: UInt256): UInt256 = zeroCheck(that)(UInt256(this.n.mod(that.n))) - def smod(that: UInt256): UInt256 = zeroCheck(that) { UInt256(this.signedN % that.signedN.abs) } + def smod(that: UInt256): UInt256 = zeroCheck(that)(UInt256(this.signedN % that.signedN.abs)) def addmod(that: UInt256, modulus: UInt256): UInt256 = zeroCheck(modulus) { new UInt256((this.n + that.n) % modulus.n) } def mulmod(that: UInt256, modulus: UInt256): UInt256 = zeroCheck(modulus) { - new UInt256((this.n * that.n) mod modulus.n) + new UInt256((this.n * that.n).mod(modulus.n)) } def slt(that: UInt256): Boolean = this.signedN < that.signedN @@ -150,7 +151,7 @@ class UInt256 private (private val n: BigInt) extends Ordered[UInt256] { def sshift(that: UInt256): UInt256 = UInt256(this.signedN >> that.signedN.toInt) - def signExtend(that: UInt256): UInt256 = { + def signExtend(that: UInt256): UInt256 = if (that.n < 0 || that.n > 31) { this } else { @@ -160,7 +161,6 @@ class UInt256 private (private val n: BigInt) extends Ordered[UInt256] { val newN = if (negative) n | (MaxValue ^ mask) else n & mask new UInt256(newN) } - } def fillingAdd(that: UInt256): UInt256 = { val result = this.n + that.n @@ -171,12 +171,11 @@ class UInt256 private (private val n: BigInt) extends Ordered[UInt256] { } //standard methods - override def equals(that: Any): Boolean = { + override def equals(that: Any): Boolean = that match { case that: UInt256 => this.n.equals(that.n) - case other => other == n + case other => other == n } - } override def hashCode: Int = n.hashCode() @@ -200,13 +199,11 @@ class UInt256 private (private val n: BigInt) extends Ordered[UInt256] { // conversions def toBigInt: BigInt = n - /** - * @return an Int with MSB=0, thus a value in range [0, Int.MaxValue] + /** @return an Int with MSB=0, thus a value in range [0, Int.MaxValue] */ def toInt: Int = n.intValue & Int.MaxValue - /** - * @return a Long with MSB=0, thus a value in range [0, Long.MaxValue] + /** @return a Long with MSB=0, thus a value in range [0, Long.MaxValue] */ def toLong: Long = n.longValue & Long.MaxValue } diff --git a/src/main/scala/io/iohk/ethereum/domain/package.scala b/src/main/scala/io/iohk/ethereum/domain/package.scala index 02b25177e8..aebcc281fd 100644 --- a/src/main/scala/io/iohk/ethereum/domain/package.scala +++ b/src/main/scala/io/iohk/ethereum/domain/package.scala @@ -1,22 +1,27 @@ package io.iohk.ethereum import akka.util.ByteString + +import org.bouncycastle.util.BigIntegers + import io.iohk.ethereum.db.storage.MptStorage -import io.iohk.ethereum.mpt.{ByteArrayEncoder, ByteArraySerializable, HashByteArraySerializable, MerklePatriciaTrie} +import io.iohk.ethereum.mpt.ByteArrayEncoder +import io.iohk.ethereum.mpt.ByteArraySerializable +import io.iohk.ethereum.mpt.HashByteArraySerializable +import io.iohk.ethereum.mpt.MerklePatriciaTrie import io.iohk.ethereum.rlp.RLPImplicits._ import io.iohk.ethereum.utils.ByteUtils -import org.bouncycastle.util.BigIntegers package object domain { type HeadersSeq = Seq[BlockHeader] object EthereumUInt256Mpt { - val byteArrayBigIntSerializer = new ByteArrayEncoder[BigInt] { + val byteArrayBigIntSerializer: ByteArrayEncoder[BigInt] = new ByteArrayEncoder[BigInt] { override def toBytes(input: BigInt): Array[Byte] = ByteUtils.padLeft(ByteString(BigIntegers.asUnsignedByteArray(input.bigInteger)), 32).toArray[Byte] } - val rlpBigIntSerializer = new ByteArraySerializable[BigInt] { + val rlpBigIntSerializer: ByteArraySerializable[BigInt] = new ByteArraySerializable[BigInt] { override def fromBytes(bytes: Array[Byte]): BigInt = rlp.decode[BigInt](bytes) override def toBytes(input: BigInt): Array[Byte] = rlp.encode[BigInt](input) @@ -30,7 +35,7 @@ package object domain { } object ArbitraryIntegerMpt { - val bigIntSerializer = new ByteArraySerializable[BigInt] { + val bigIntSerializer: ByteArraySerializable[BigInt] = new ByteArraySerializable[BigInt] { override def fromBytes(bytes: Array[Byte]): BigInt = BigInt(bytes) override def toBytes(input: BigInt): Array[Byte] = input.toByteArray } diff --git a/src/main/scala/io/iohk/ethereum/extvm/ApiVersionProvider.scala b/src/main/scala/io/iohk/ethereum/extvm/ApiVersionProvider.scala index deca3a27c2..6d0352a5aa 100644 --- a/src/main/scala/io/iohk/ethereum/extvm/ApiVersionProvider.scala +++ b/src/main/scala/io/iohk/ethereum/extvm/ApiVersionProvider.scala @@ -7,10 +7,7 @@ object ApiVersionProvider { lazy val version: String = { val source = Source.fromResource(ResourcePath) - try { - source.getLines().next() - } finally { - source.close() - } + try source.getLines().next() + finally source.close() } } diff --git a/src/main/scala/io/iohk/ethereum/extvm/ExtVMInterface.scala b/src/main/scala/io/iohk/ethereum/extvm/ExtVMInterface.scala index 913e9780b5..9039a4a80c 100644 --- a/src/main/scala/io/iohk/ethereum/extvm/ExtVMInterface.scala +++ b/src/main/scala/io/iohk/ethereum/extvm/ExtVMInterface.scala @@ -1,24 +1,30 @@ package io.iohk.ethereum.extvm +import java.nio.ByteOrder + import akka.actor.ActorSystem import akka.stream.OverflowStrategy -import akka.stream.scaladsl.{Framing, Keep, Sink, SinkQueueWithCancel, Source, SourceQueueWithComplete, Tcp} +import akka.stream.scaladsl.Framing +import akka.stream.scaladsl.Keep +import akka.stream.scaladsl.Sink +import akka.stream.scaladsl.Source +import akka.stream.scaladsl.Tcp import akka.util.ByteString -import io.iohk.ethereum.ledger.{InMemoryWorldStateProxy, InMemoryWorldStateProxyStorage} -import io.iohk.ethereum.utils.{BlockchainConfig, VmConfig} -import io.iohk.ethereum.vm._ -import java.nio.ByteOrder + import scala.annotation.tailrec -import scala.util.{Failure, Success, Try} +import scala.util.Failure +import scala.util.Success +import scala.util.Try + +import io.iohk.ethereum.ledger.InMemoryWorldStateProxy +import io.iohk.ethereum.ledger.InMemoryWorldStateProxyStorage +import io.iohk.ethereum.utils.BlockchainConfig +import io.iohk.ethereum.utils.VmConfig +import io.iohk.ethereum.vm._ class ExtVMInterface(externaVmConfig: VmConfig.ExternalConfig, blockchainConfig: BlockchainConfig, testMode: Boolean)( implicit system: ActorSystem ) extends VM[InMemoryWorldStateProxy, InMemoryWorldStateProxyStorage] { - - private var out: Option[SourceQueueWithComplete[ByteString]] = None - - private var in: Option[SinkQueueWithCancel[ByteString]] = None - private var vmClient: Option[VMClient] = None initConnection() @@ -36,9 +42,6 @@ class ExtVMInterface(externaVmConfig: VmConfig.ExternalConfig, blockchainConfig: .toMat(Sink.queue[ByteString]())(Keep.both) .run() - out = Some(connOut) - in = Some(connIn) - val client = new VMClient(externaVmConfig, new MessageHandler(connIn, connOut), testMode) client.sendHello(ApiVersionProvider.version, blockchainConfig) //TODO: await hello response, check version @@ -47,7 +50,7 @@ class ExtVMInterface(externaVmConfig: VmConfig.ExternalConfig, blockchainConfig: } @tailrec - override final def run(context: PC): PR = { + final override def run(context: PC): PR = { if (vmClient.isEmpty) initConnection() Try(vmClient.get.run(context)) match { diff --git a/src/main/scala/io/iohk/ethereum/extvm/Implicits.scala b/src/main/scala/io/iohk/ethereum/extvm/Implicits.scala index 7c2c9f6e56..3c2a81ef59 100644 --- a/src/main/scala/io/iohk/ethereum/extvm/Implicits.scala +++ b/src/main/scala/io/iohk/ethereum/extvm/Implicits.scala @@ -1,10 +1,13 @@ package io.iohk.ethereum.extvm -import language.implicitConversions - import akka.util.ByteString + import com.google.protobuf.{ByteString => GByteString} -import io.iohk.ethereum.domain.{Address, UInt256} + +import io.iohk.ethereum.domain.Address +import io.iohk.ethereum.domain.UInt256 + +import language.implicitConversions object Implicits { implicit def byteString2GByteString(b: ByteString): GByteString = diff --git a/src/main/scala/io/iohk/ethereum/extvm/MessageHandler.scala b/src/main/scala/io/iohk/ethereum/extvm/MessageHandler.scala index cb02340dab..ea517717e2 100644 --- a/src/main/scala/io/iohk/ethereum/extvm/MessageHandler.scala +++ b/src/main/scala/io/iohk/ethereum/extvm/MessageHandler.scala @@ -2,17 +2,20 @@ package io.iohk.ethereum.extvm import java.math.BigInteger -import akka.stream.scaladsl.{SinkQueueWithCancel, SourceQueueWithComplete} +import akka.stream.scaladsl.SinkQueueWithCancel +import akka.stream.scaladsl.SourceQueueWithComplete import akka.util.ByteString -import com.google.protobuf.{CodedInputStream, Message} -import org.bouncycastle.util.BigIntegers -import scalapb.{GeneratedMessage, GeneratedMessageCompanion, LiteParser} -import scala.concurrent.duration._ import scala.concurrent.Await import scala.concurrent.ExecutionContext.Implicits.global +import scala.concurrent.duration._ import scala.util.Try +import com.google.protobuf.CodedInputStream +import org.bouncycastle.util.BigIntegers +import scalapb.GeneratedMessage +import scalapb.GeneratedMessageCompanion + class MessageHandler(in: SinkQueueWithCancel[ByteString], out: SourceQueueWithComplete[ByteString]) { private val AwaitTimeout = 5.minutes @@ -21,13 +24,13 @@ class MessageHandler(in: SinkQueueWithCancel[ByteString], out: SourceQueueWithCo val bytes = msg.toByteArray val lengthBytes = ByteString(BigIntegers.asUnsignedByteArray(LengthPrefixSize, BigInteger.valueOf(bytes.length))) - out offer (lengthBytes ++ ByteString(bytes)) + out.offer(lengthBytes ++ ByteString(bytes)) } def awaitMessage[M <: GeneratedMessage](implicit companion: GeneratedMessageCompanion[M]): M = { - val resF = in.pull() map { + val resF = in.pull().map { case Some(bytes) => companion.parseFrom(CodedInputStream.newInstance(bytes.toArray[Byte])) - case None => throw new RuntimeException("Stream completed") + case None => throw new RuntimeException("Stream completed") } Await.result(resF, AwaitTimeout) diff --git a/src/main/scala/io/iohk/ethereum/extvm/VMClient.scala b/src/main/scala/io/iohk/ethereum/extvm/VMClient.scala index 92405c9f58..d71600be3b 100644 --- a/src/main/scala/io/iohk/ethereum/extvm/VMClient.scala +++ b/src/main/scala/io/iohk/ethereum/extvm/VMClient.scala @@ -1,17 +1,22 @@ package io.iohk.ethereum.extvm -import io.iohk.ethereum.vm -import io.iohk.ethereum.vm.{WorldStateProxy, _} -import Implicits._ import akka.util.ByteString -import io.iohk.ethereum.domain._ -import io.iohk.ethereum.utils.{BlockchainConfig, Logger, VmConfig} -import scalapb.UnknownFieldSet import scala.annotation.tailrec -/** - * @param testMode - if enabled the client will send blockchain configuration with each configuration. +import scalapb.UnknownFieldSet + +import io.iohk.ethereum.domain._ +import io.iohk.ethereum.utils.BlockchainConfig +import io.iohk.ethereum.utils.Logger +import io.iohk.ethereum.utils.VmConfig +import io.iohk.ethereum.vm +import io.iohk.ethereum.vm.WorldStateProxy +import io.iohk.ethereum.vm._ + +import Implicits._ + +/** @param testMode - if enabled the client will send blockchain configuration with each configuration. * This is useful to override configuration for each test, rather than to recreate the VM. */ class VMClient(externalVmConfig: VmConfig.ExternalConfig, messageHandler: MessageHandler, testMode: Boolean) @@ -21,7 +26,7 @@ class VMClient(externalVmConfig: VmConfig.ExternalConfig, messageHandler: Messag val config = BlockchainConfigForEvm(blockchainConfig) val configMsg = externalVmConfig.vmType match { case VmConfig.ExternalConfig.VmTypeIele => msg.Hello.Config.IeleConfig(buildIeleConfigMsg()) - case _ => msg.Hello.Config.EthereumConfig(buildEthereumConfigMsg(config)) + case _ => msg.Hello.Config.EthereumConfig(buildEthereumConfigMsg(config)) } val helloMsg = msg.Hello(version, configMsg) messageHandler.sendMessage(helloMsg) @@ -80,7 +85,7 @@ class VMClient(externalVmConfig: VmConfig.ExternalConfig, messageHandler: Messag log.debug("Client received msg: GetBlockhash") val blockhashMsg = world.getBlockHash(offset) match { case Some(value) => msg.Blockhash(hash = value) - case None => msg.Blockhash() + case None => msg.Blockhash() } messageHandler.sendMessage(blockhashMsg) messageLoop[W, S](world) @@ -144,7 +149,7 @@ class VMClient(externalVmConfig: VmConfig.ExternalConfig, messageHandler: Messag 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 + case _ => Config.Empty } msg.CallContext( @@ -182,8 +187,7 @@ class VMClient(externalVmConfig: VmConfig.ExternalConfig, messageHandler: Messag unixTimestamp = header.unixTimestamp ) - def close(): Unit = { + def close(): Unit = messageHandler.close() - } } diff --git a/src/main/scala/io/iohk/ethereum/extvm/VMServer.scala b/src/main/scala/io/iohk/ethereum/extvm/VMServer.scala index 0ae122f1c7..38290fa3e8 100644 --- a/src/main/scala/io/iohk/ethereum/extvm/VMServer.scala +++ b/src/main/scala/io/iohk/ethereum/extvm/VMServer.scala @@ -1,23 +1,39 @@ package io.iohk.ethereum.extvm +import java.nio.ByteOrder + import akka.NotUsed import akka.actor.ActorSystem import akka.stream.OverflowStrategy -import akka.stream.scaladsl.{Flow, Framing, Keep, Sink, Source, Tcp} +import akka.stream.scaladsl.Flow +import akka.stream.scaladsl.Framing +import akka.stream.scaladsl.Keep +import akka.stream.scaladsl.Sink +import akka.stream.scaladsl.Source +import akka.stream.scaladsl.Tcp import akka.util.ByteString + +import scala.annotation.tailrec +import scala.util.Failure +import scala.util.Success +import scala.util.Try + import com.google.protobuf.{ByteString => GByteString} import com.typesafe.config.ConfigFactory -import io.iohk.ethereum.domain.{Address, BlockHeader} + +import io.iohk.ethereum.domain.Address +import io.iohk.ethereum.domain.BlockHeader import io.iohk.ethereum.extvm.Implicits._ import io.iohk.ethereum.utils._ -import io.iohk.ethereum.vm.{BlockchainConfigForEvm, ProgramResult, VM, ProgramContext, EvmConfig} -import java.nio.ByteOrder -import scala.annotation.tailrec -import scala.util.{Failure, Success, Try} +import io.iohk.ethereum.vm.BlockchainConfigForEvm +import io.iohk.ethereum.vm.EvmConfig +import io.iohk.ethereum.vm.ProgramContext +import io.iohk.ethereum.vm.ProgramResult +import io.iohk.ethereum.vm.VM object VmServerApp extends Logger { - implicit val system = ActorSystem("EVM_System") + implicit val system: ActorSystem = ActorSystem("EVM_System") def main(args: Array[String]): Unit = { val config = ConfigFactory.load() @@ -51,7 +67,7 @@ class VMServer(messageHandler: MessageHandler) extends Logger { private[extvm] var processingThread: Thread = _ @tailrec - private def processNextCall(): Unit = { + private def processNextCall(): Unit = Try { val callContext = messageHandler.awaitMessage[msg.CallContext] log.debug("Server received msg: CallContext") @@ -66,7 +82,6 @@ class VMServer(messageHandler: MessageHandler) extends Logger { case Success(_) => processNextCall() case Failure(_) => close() } - } private def awaitHello(): Unit = { val helloMsg = messageHandler.awaitMessage[msg.Hello] @@ -176,7 +191,7 @@ class VMServer(messageHandler: MessageHandler) extends Logger { } // scalastyle:off magic.number - private def constructBlockchainConfig(conf: msg.EthereumConfig): BlockchainConfigForEvm = { + private def constructBlockchainConfig(conf: msg.EthereumConfig): BlockchainConfigForEvm = BlockchainConfigForEvm( frontierBlockNumber = conf.frontierBlockNumber, homesteadBlockNumber = conf.homesteadBlockNumber, @@ -194,5 +209,4 @@ class VMServer(messageHandler: MessageHandler) extends Logger { phoenixBlockNumber = BigInt(10500839), //TODO include phoenix block number in protobuf chainId = 0x3d.toByte //TODO include chainId in protobuf ) - } } diff --git a/src/main/scala/io/iohk/ethereum/extvm/World.scala b/src/main/scala/io/iohk/ethereum/extvm/World.scala index f5aa2123fc..cb00b7cbbb 100644 --- a/src/main/scala/io/iohk/ethereum/extvm/World.scala +++ b/src/main/scala/io/iohk/ethereum/extvm/World.scala @@ -1,7 +1,10 @@ package io.iohk.ethereum.extvm import akka.util.ByteString -import io.iohk.ethereum.domain.{Account, Address, UInt256} + +import io.iohk.ethereum.domain.Account +import io.iohk.ethereum.domain.Address +import io.iohk.ethereum.domain.UInt256 import io.iohk.ethereum.vm object World { @@ -48,12 +51,11 @@ case class World( protected def noEmptyAccounts: Boolean = noEmptyAccountsCond - override def keepPrecompileTouched(world: World): World = { + override def keepPrecompileTouched(world: World): World = if (world.touchedAccounts.contains(ripmdContractAddress)) copy(touchedAccounts = touchedAccounts + ripmdContractAddress) else this - } def getCode(address: Address): ByteString = codeRepo.getOrElse(address, codeCache.getCode(address)) diff --git a/src/main/scala/io/iohk/ethereum/extvm/cache.scala b/src/main/scala/io/iohk/ethereum/extvm/cache.scala index 334c3047cb..732a9a29fc 100644 --- a/src/main/scala/io/iohk/ethereum/extvm/cache.scala +++ b/src/main/scala/io/iohk/ethereum/extvm/cache.scala @@ -1,12 +1,15 @@ package io.iohk.ethereum.extvm import akka.util.ByteString -import io.iohk.ethereum.domain.{Account, Address, UInt256} -import io.iohk.ethereum.utils.Logger -import io.iohk.ethereum.extvm.Implicits._ import scala.collection.mutable +import io.iohk.ethereum.domain.Account +import io.iohk.ethereum.domain.Address +import io.iohk.ethereum.domain.UInt256 +import io.iohk.ethereum.extvm.Implicits._ +import io.iohk.ethereum.utils.Logger + class AccountCache(messageHandler: MessageHandler) extends Logger { private val cache = mutable.Map[Address, Option[Account]]() diff --git a/src/main/scala/io/iohk/ethereum/faucet/Faucet.scala b/src/main/scala/io/iohk/ethereum/faucet/Faucet.scala index 9f19108b09..798820e2f7 100644 --- a/src/main/scala/io/iohk/ethereum/faucet/Faucet.scala +++ b/src/main/scala/io/iohk/ethereum/faucet/Faucet.scala @@ -5,9 +5,7 @@ import io.iohk.ethereum.utils.Logger object Faucet extends Logger { - def main(args: Array[String]): Unit = { - + def main(args: Array[String]): Unit = (new FaucetServer).start() - } } diff --git a/src/main/scala/io/iohk/ethereum/faucet/FaucetConfig.scala b/src/main/scala/io/iohk/ethereum/faucet/FaucetConfig.scala index 4223889426..e9ee1e9a96 100644 --- a/src/main/scala/io/iohk/ethereum/faucet/FaucetConfig.scala +++ b/src/main/scala/io/iohk/ethereum/faucet/FaucetConfig.scala @@ -1,9 +1,12 @@ package io.iohk.ethereum.faucet -import com.typesafe.config.{Config, ConfigFactory} -import io.iohk.ethereum.domain.Address +import scala.concurrent.duration.FiniteDuration +import scala.concurrent.duration._ + +import com.typesafe.config.Config +import com.typesafe.config.ConfigFactory -import scala.concurrent.duration.{FiniteDuration, _} +import io.iohk.ethereum.domain.Address trait FaucetConfigBuilder { lazy val rawConfig: Config = ConfigFactory.load() @@ -17,13 +20,11 @@ case class RpcClientConfig( ) object RpcClientConfig { - def apply(rpcClientConfig: Config): RpcClientConfig = { - + def apply(rpcClientConfig: Config): RpcClientConfig = RpcClientConfig( address = rpcClientConfig.getString("rpc-address"), timeout = rpcClientConfig.getDuration("timeout").toMillis.millis ) - } } case class FaucetConfig( diff --git a/src/main/scala/io/iohk/ethereum/faucet/FaucetHandler.scala b/src/main/scala/io/iohk/ethereum/faucet/FaucetHandler.scala index db41adbe32..a14a196d20 100644 --- a/src/main/scala/io/iohk/ethereum/faucet/FaucetHandler.scala +++ b/src/main/scala/io/iohk/ethereum/faucet/FaucetHandler.scala @@ -1,23 +1,26 @@ package io.iohk.ethereum.faucet -import akka.actor.{Actor, ActorLogging, Props} +import akka.actor.Actor +import akka.actor.ActorLogging +import akka.actor.Props import akka.util.ByteString + +import monix.execution.Scheduler.Implicits.global + import io.iohk.ethereum.domain.Address import io.iohk.ethereum.faucet.FaucetHandler.WalletException import io.iohk.ethereum.faucet.FaucetStatus.WalletAvailable import io.iohk.ethereum.faucet.jsonrpc.WalletService import io.iohk.ethereum.keystore.KeyStore.KeyStoreError import io.iohk.ethereum.keystore.Wallet -import monix.execution.Scheduler.Implicits.global class FaucetHandler(walletService: WalletService, config: FaucetConfig) extends Actor with ActorLogging { import FaucetHandler.FaucetHandlerMsg._ import FaucetHandler.FaucetHandlerResponse._ - override def preStart(): Unit = { + override def preStart(): Unit = self ! Initialization - } override def receive: Receive = unavailable() @@ -25,7 +28,7 @@ class FaucetHandler(walletService: WalletService, config: FaucetConfig) extends case Status => sender() ! StatusResponse(FaucetStatus.FaucetUnavailable) - case Initialization => { + case Initialization => log.info("Initialization called (faucet unavailable)") walletService.getWallet.runSyncUnsafe() match { case Left(error) => @@ -33,9 +36,8 @@ class FaucetHandler(walletService: WalletService, config: FaucetConfig) extends throw new WalletException(error) case Right(wallet) => log.info("Faucet initialization succeeded") - context become available(wallet) + context.become(available(wallet)) } - } case SendFunds(addressTo: Address) => log.info( s"SendFunds called, to: $addressTo, value: ${config.txValue}, gas price: ${config.txGasPrice}," + diff --git a/src/main/scala/io/iohk/ethereum/faucet/FaucetSupervisor.scala b/src/main/scala/io/iohk/ethereum/faucet/FaucetSupervisor.scala index bc1361bbcf..9f172afb60 100644 --- a/src/main/scala/io/iohk/ethereum/faucet/FaucetSupervisor.scala +++ b/src/main/scala/io/iohk/ethereum/faucet/FaucetSupervisor.scala @@ -1,13 +1,19 @@ package io.iohk.ethereum.faucet -import akka.actor.{ActorRef, ActorSystem, OneForOneStrategy, SupervisorStrategy} -import akka.pattern.{BackoffOpts, BackoffSupervisor} +import akka.actor.ActorRef +import akka.actor.ActorSystem +import akka.actor.OneForOneStrategy +import akka.actor.Props +import akka.actor.SupervisorStrategy +import akka.pattern.BackoffOpts +import akka.pattern.BackoffSupervisor + +import scala.concurrent.duration._ + import io.iohk.ethereum.faucet.FaucetHandler.WalletException import io.iohk.ethereum.faucet.jsonrpc.WalletService import io.iohk.ethereum.utils.Logger -import scala.concurrent.duration._ - object FaucetSupervisor { val name = "FaucetSupervisor" } @@ -16,14 +22,14 @@ class FaucetSupervisor(walletService: WalletService, config: FaucetConfig, shutd system: ActorSystem ) extends Logger { - val childProps = FaucetHandler.props(walletService, config) + val childProps: Props = FaucetHandler.props(walletService, config) val minBackoff: FiniteDuration = config.supervisor.minBackoff val maxBackoff: FiniteDuration = config.supervisor.maxBackoff val randomFactor: Double = config.supervisor.randomFactor val autoReset: FiniteDuration = config.supervisor.autoReset - val supervisorProps = BackoffSupervisor.props( + val supervisorProps: Props = BackoffSupervisor.props( BackoffOpts .onFailure( childProps, diff --git a/src/main/scala/io/iohk/ethereum/faucet/SupervisorConfig.scala b/src/main/scala/io/iohk/ethereum/faucet/SupervisorConfig.scala index e91ed46ac3..dbde5be9a1 100644 --- a/src/main/scala/io/iohk/ethereum/faucet/SupervisorConfig.scala +++ b/src/main/scala/io/iohk/ethereum/faucet/SupervisorConfig.scala @@ -1,7 +1,9 @@ package io.iohk.ethereum.faucet +import scala.concurrent.duration.FiniteDuration +import scala.concurrent.duration._ + import com.typesafe.config.Config -import scala.concurrent.duration.{FiniteDuration, _} case class SupervisorConfig( minBackoff: FiniteDuration, diff --git a/src/main/scala/io/iohk/ethereum/faucet/jsonrpc/FaucetBuilder.scala b/src/main/scala/io/iohk/ethereum/faucet/jsonrpc/FaucetBuilder.scala index 9847ef02a9..a18117a01a 100644 --- a/src/main/scala/io/iohk/ethereum/faucet/jsonrpc/FaucetBuilder.scala +++ b/src/main/scala/io/iohk/ethereum/faucet/jsonrpc/FaucetBuilder.scala @@ -1,15 +1,20 @@ package io.iohk.ethereum.faucet.jsonrpc import akka.actor.ActorSystem -import io.iohk.ethereum.faucet.{FaucetConfigBuilder, FaucetSupervisor} + +import scala.concurrent.Await +import scala.concurrent.ExecutionContextExecutor + +import io.iohk.ethereum.faucet.FaucetConfigBuilder +import io.iohk.ethereum.faucet.FaucetSupervisor import io.iohk.ethereum.jsonrpc.server.controllers.ApisBase import io.iohk.ethereum.jsonrpc.server.controllers.JsonRpcBaseController.JsonRpcConfig import io.iohk.ethereum.jsonrpc.server.http.JsonRpcHttpServer import io.iohk.ethereum.keystore.KeyStoreImpl -import io.iohk.ethereum.security.{SSLContextBuilder, SecureRandomBuilder} -import io.iohk.ethereum.utils.{KeyStoreConfig, Logger} - -import scala.concurrent.Await +import io.iohk.ethereum.security.SSLContextBuilder +import io.iohk.ethereum.security.SecureRandomBuilder +import io.iohk.ethereum.utils.KeyStoreConfig +import io.iohk.ethereum.utils.Logger trait ActorSystemBuilder { def systemName: String @@ -19,7 +24,7 @@ trait ActorSystemBuilder { trait FaucetControllerBuilder { self: FaucetConfigBuilder with ActorSystemBuilder => - implicit val ec = system.dispatcher + implicit val ec: ExecutionContextExecutor = system.dispatcher } trait FaucetRpcServiceBuilder { @@ -83,7 +88,7 @@ trait FaucetJsonRpcHttpServerBuilder { with FaucetJsonRpcControllerBuilder with SSLContextBuilder => - val faucetJsonRpcHttpServer = JsonRpcHttpServer( + val faucetJsonRpcHttpServer: Either[String, JsonRpcHttpServer] = JsonRpcHttpServer( faucetJsonRpcController, faucetJsonRpcHealthCheck, jsonRpcConfig.httpServerConfig, @@ -95,7 +100,7 @@ trait FaucetJsonRpcHttpServerBuilder { trait ShutdownHookBuilder { self: ActorSystemBuilder with FaucetConfigBuilder with Logger => - def shutdown(): Unit = { + def shutdown(): Unit = Await.ready( system .terminate() @@ -105,7 +110,6 @@ trait ShutdownHookBuilder { )(system.dispatcher), faucetConfig.shutdownTimeout ) - } } class FaucetServer @@ -133,6 +137,6 @@ class FaucetServer private[this] def startJsonRpcHttpServer() = faucetJsonRpcHttpServer match { case Right(jsonRpcServer) => jsonRpcServer.run() - case Left(error) => throw new RuntimeException(s"$error") + case Left(error) => throw new RuntimeException(s"$error") } } diff --git a/src/main/scala/io/iohk/ethereum/faucet/jsonrpc/FaucetDomain.scala b/src/main/scala/io/iohk/ethereum/faucet/jsonrpc/FaucetDomain.scala index b77d03c28c..23957381e0 100644 --- a/src/main/scala/io/iohk/ethereum/faucet/jsonrpc/FaucetDomain.scala +++ b/src/main/scala/io/iohk/ethereum/faucet/jsonrpc/FaucetDomain.scala @@ -1,6 +1,7 @@ package io.iohk.ethereum.faucet.jsonrpc import akka.util.ByteString + import io.iohk.ethereum.domain.Address import io.iohk.ethereum.faucet.FaucetStatus diff --git a/src/main/scala/io/iohk/ethereum/faucet/jsonrpc/FaucetHandlerSelector.scala b/src/main/scala/io/iohk/ethereum/faucet/jsonrpc/FaucetHandlerSelector.scala index b9fd9259b8..239389ffac 100644 --- a/src/main/scala/io/iohk/ethereum/faucet/jsonrpc/FaucetHandlerSelector.scala +++ b/src/main/scala/io/iohk/ethereum/faucet/jsonrpc/FaucetHandlerSelector.scala @@ -1,27 +1,31 @@ package io.iohk.ethereum.faucet.jsonrpc -import akka.actor.{ActorRef, ActorSystem} +import akka.actor.ActorRef +import akka.actor.ActorSystem import akka.pattern.RetrySupport import akka.util.Timeout -import io.iohk.ethereum.faucet.{FaucetConfigBuilder, FaucetHandler, FaucetSupervisor} + import monix.eval.Task +import io.iohk.ethereum.faucet.FaucetConfigBuilder +import io.iohk.ethereum.faucet.FaucetHandler +import io.iohk.ethereum.faucet.FaucetSupervisor + trait FaucetHandlerSelector { self: FaucetConfigBuilder with RetrySupport => - val handlerPath = s"user/${FaucetSupervisor.name}/${FaucetHandler.name}" + val handlerPath: String = s"user/${FaucetSupervisor.name}/${FaucetHandler.name}" lazy val attempts = faucetConfig.supervisor.attempts lazy val delay = faucetConfig.supervisor.delay lazy val handlerTimeout: Timeout = Timeout(faucetConfig.handlerTimeout) - def selectFaucetHandler()(implicit system: ActorSystem): Task[ActorRef] = { + def selectFaucetHandler()(implicit system: ActorSystem): Task[ActorRef] = Task.deferFuture( retry(() => system.actorSelection(handlerPath).resolveOne(handlerTimeout.duration), attempts, delay)( system.dispatcher, system.scheduler ) ) - } } diff --git a/src/main/scala/io/iohk/ethereum/faucet/jsonrpc/FaucetJsonRpcController.scala b/src/main/scala/io/iohk/ethereum/faucet/jsonrpc/FaucetJsonRpcController.scala index 16887e0553..15f46db78e 100644 --- a/src/main/scala/io/iohk/ethereum/faucet/jsonrpc/FaucetJsonRpcController.scala +++ b/src/main/scala/io/iohk/ethereum/faucet/jsonrpc/FaucetJsonRpcController.scala @@ -1,11 +1,14 @@ package io.iohk.ethereum.faucet.jsonrpc +import monix.eval.Task + import io.iohk.ethereum.faucet.jsonrpc.FaucetDomain._ +import io.iohk.ethereum.jsonrpc.JsonRpcError +import io.iohk.ethereum.jsonrpc.JsonRpcRequest +import io.iohk.ethereum.jsonrpc.JsonRpcResponse import io.iohk.ethereum.jsonrpc.server.controllers.JsonRpcBaseController import io.iohk.ethereum.jsonrpc.server.controllers.JsonRpcBaseController.JsonRpcConfig -import io.iohk.ethereum.jsonrpc.{JsonRpcError, JsonRpcRequest, JsonRpcResponse} import io.iohk.ethereum.utils.Logger -import monix.eval.Task class FaucetJsonRpcController( faucetRpcService: FaucetRpcService, @@ -26,7 +29,7 @@ class FaucetJsonRpcController( val notFoundFn: PartialFunction[JsonRpcRequest, Task[JsonRpcResponse]] = { case _ => Task.now(errorResponse(req, JsonRpcError.MethodNotFound)) } - (handleFaucetRequest orElse notFoundFn)(req) + (handleFaucetRequest.orElse(notFoundFn))(req) } private def handleFaucetRequest: PartialFunction[JsonRpcRequest, Task[JsonRpcResponse]] = { diff --git a/src/main/scala/io/iohk/ethereum/faucet/jsonrpc/FaucetJsonRpcHealthCheck.scala b/src/main/scala/io/iohk/ethereum/faucet/jsonrpc/FaucetJsonRpcHealthCheck.scala index 1e4a06e10a..df07140954 100644 --- a/src/main/scala/io/iohk/ethereum/faucet/jsonrpc/FaucetJsonRpcHealthCheck.scala +++ b/src/main/scala/io/iohk/ethereum/faucet/jsonrpc/FaucetJsonRpcHealthCheck.scala @@ -1,15 +1,18 @@ package io.iohk.ethereum.faucet.jsonrpc +import monix.eval.Task + import io.iohk.ethereum.faucet.jsonrpc.FaucetDomain.StatusRequest import io.iohk.ethereum.healthcheck.HealthcheckResponse -import io.iohk.ethereum.jsonrpc.{JsonRpcHealthChecker, JsonRpcHealthcheck} -import monix.eval.Task +import io.iohk.ethereum.jsonrpc.JsonRpcHealthChecker +import io.iohk.ethereum.jsonrpc.JsonRpcHealthcheck class FaucetJsonRpcHealthCheck(faucetRpcService: FaucetRpcService) extends JsonRpcHealthChecker { protected def mainService: String = "faucet health" - final val statusHC = JsonRpcHealthcheck.fromServiceResponse("status", faucetRpcService.status(StatusRequest())) + final val statusHC: Task[JsonRpcHealthcheck[FaucetDomain.StatusResponse]] = + JsonRpcHealthcheck.fromServiceResponse("status", faucetRpcService.status(StatusRequest())) override def healthCheck(): Task[HealthcheckResponse] = { val statusF = statusHC.map(_.toResult) diff --git a/src/main/scala/io/iohk/ethereum/faucet/jsonrpc/FaucetMethodsImplicits.scala b/src/main/scala/io/iohk/ethereum/faucet/jsonrpc/FaucetMethodsImplicits.scala index 8464e04e5c..2a8f96d13b 100644 --- a/src/main/scala/io/iohk/ethereum/faucet/jsonrpc/FaucetMethodsImplicits.scala +++ b/src/main/scala/io/iohk/ethereum/faucet/jsonrpc/FaucetMethodsImplicits.scala @@ -1,17 +1,24 @@ package io.iohk.ethereum.faucet.jsonrpc -import io.iohk.ethereum.faucet.jsonrpc.FaucetDomain.{SendFundsRequest, SendFundsResponse, StatusRequest, StatusResponse} +import org.json4s.JsonAST.JArray +import org.json4s.JsonAST.JObject +import org.json4s.JsonAST.JString + +import io.iohk.ethereum.faucet.jsonrpc.FaucetDomain.SendFundsRequest +import io.iohk.ethereum.faucet.jsonrpc.FaucetDomain.SendFundsResponse +import io.iohk.ethereum.faucet.jsonrpc.FaucetDomain.StatusRequest +import io.iohk.ethereum.faucet.jsonrpc.FaucetDomain.StatusResponse import io.iohk.ethereum.jsonrpc.JsonMethodsImplicits import io.iohk.ethereum.jsonrpc.JsonRpcError.InvalidParams +import io.iohk.ethereum.jsonrpc.serialization.JsonEncoder +import io.iohk.ethereum.jsonrpc.serialization.JsonMethodDecoder import io.iohk.ethereum.jsonrpc.serialization.JsonMethodDecoder.NoParamsMethodDecoder -import io.iohk.ethereum.jsonrpc.serialization.{JsonEncoder, JsonMethodDecoder} -import org.json4s.JsonAST.{JArray, JObject, JString} object FaucetMethodsImplicits extends JsonMethodsImplicits { implicit val sendFundsRequestDecoder: JsonMethodDecoder[SendFundsRequest] = { case Some(JArray((input: JString) :: Nil)) => extractAddress(input).map(SendFundsRequest) - case _ => Left(InvalidParams()) + case _ => Left(InvalidParams()) } implicit val sendFundsResponseEncoder: JsonEncoder[SendFundsResponse] = (t: SendFundsResponse) => encodeAsHex(t.txId) diff --git a/src/main/scala/io/iohk/ethereum/faucet/jsonrpc/FaucetRpcService.scala b/src/main/scala/io/iohk/ethereum/faucet/jsonrpc/FaucetRpcService.scala index 34cdea0b64..68f1491a2e 100644 --- a/src/main/scala/io/iohk/ethereum/faucet/jsonrpc/FaucetRpcService.scala +++ b/src/main/scala/io/iohk/ethereum/faucet/jsonrpc/FaucetRpcService.scala @@ -3,11 +3,18 @@ package io.iohk.ethereum.faucet.jsonrpc import akka.actor.ActorSystem import akka.pattern.RetrySupport import akka.util.Timeout -import io.iohk.ethereum.faucet.FaucetHandler.{FaucetHandlerMsg, FaucetHandlerResponse} -import io.iohk.ethereum.faucet.jsonrpc.FaucetDomain.{SendFundsRequest, SendFundsResponse, StatusRequest, StatusResponse} -import io.iohk.ethereum.faucet.{FaucetConfig, FaucetConfigBuilder} + +import io.iohk.ethereum.faucet.FaucetConfig +import io.iohk.ethereum.faucet.FaucetConfigBuilder +import io.iohk.ethereum.faucet.FaucetHandler.FaucetHandlerMsg +import io.iohk.ethereum.faucet.FaucetHandler.FaucetHandlerResponse +import io.iohk.ethereum.faucet.jsonrpc.FaucetDomain.SendFundsRequest +import io.iohk.ethereum.faucet.jsonrpc.FaucetDomain.SendFundsResponse +import io.iohk.ethereum.faucet.jsonrpc.FaucetDomain.StatusRequest +import io.iohk.ethereum.faucet.jsonrpc.FaucetDomain.StatusResponse import io.iohk.ethereum.jsonrpc.AkkaTaskOps._ -import io.iohk.ethereum.jsonrpc.{JsonRpcError, ServiceResponse} +import io.iohk.ethereum.jsonrpc.JsonRpcError +import io.iohk.ethereum.jsonrpc.ServiceResponse import io.iohk.ethereum.utils.Logger class FaucetRpcService(config: FaucetConfig)(implicit system: ActorSystem) @@ -23,14 +30,14 @@ class FaucetRpcService(config: FaucetConfig)(implicit system: ActorSystem) .flatMap(handler => handler .askFor[Any](FaucetHandlerMsg.SendFunds(sendFundsRequest.address)) - .map(handleSendFundsResponse orElse handleErrors) + .map(handleSendFundsResponse.orElse(handleErrors)) ) .onErrorRecover(handleErrors) def status(statusRequest: StatusRequest): ServiceResponse[StatusResponse] = selectFaucetHandler() .flatMap(handler => handler.askFor[Any](FaucetHandlerMsg.Status)) - .map(handleStatusResponse orElse handleErrors) + .map(handleStatusResponse.orElse(handleErrors)) .onErrorRecover(handleErrors) private def handleSendFundsResponse: PartialFunction[Any, Either[JsonRpcError, SendFundsResponse]] = { diff --git a/src/main/scala/io/iohk/ethereum/faucet/jsonrpc/WalletRpcClient.scala b/src/main/scala/io/iohk/ethereum/faucet/jsonrpc/WalletRpcClient.scala index e90fd8ae78..3a409bcdfa 100644 --- a/src/main/scala/io/iohk/ethereum/faucet/jsonrpc/WalletRpcClient.scala +++ b/src/main/scala/io/iohk/ethereum/faucet/jsonrpc/WalletRpcClient.scala @@ -1,19 +1,23 @@ package io.iohk.ethereum.faucet.jsonrpc +import javax.net.ssl.SSLContext + import akka.actor.ActorSystem import akka.http.scaladsl.model.Uri -import io.circe.syntax._ import akka.util.ByteString + +import monix.eval.Task + +import scala.concurrent.ExecutionContext +import scala.concurrent.duration.Duration + +import io.circe.syntax._ + import io.iohk.ethereum.domain.Address import io.iohk.ethereum.jsonrpc.client.RpcClient import io.iohk.ethereum.jsonrpc.client.RpcClient.RpcError import io.iohk.ethereum.security.SSLError import io.iohk.ethereum.utils.Logger -import javax.net.ssl.SSLContext -import monix.eval.Task - -import scala.concurrent.ExecutionContext -import scala.concurrent.duration.Duration class WalletRpcClient(node: Uri, timeout: Duration, getSSLContext: () => Either[SSLError, SSLContext])(implicit system: ActorSystem, diff --git a/src/main/scala/io/iohk/ethereum/faucet/jsonrpc/WalletService.scala b/src/main/scala/io/iohk/ethereum/faucet/jsonrpc/WalletService.scala index 1ee118e4ba..3f806fe418 100644 --- a/src/main/scala/io/iohk/ethereum/faucet/jsonrpc/WalletService.scala +++ b/src/main/scala/io/iohk/ethereum/faucet/jsonrpc/WalletService.scala @@ -1,24 +1,30 @@ package io.iohk.ethereum.faucet.jsonrpc import akka.util.ByteString + import cats.data.EitherT -import io.iohk.ethereum.domain.{Address, Transaction} + +import monix.eval.Task + +import io.iohk.ethereum.domain.Address +import io.iohk.ethereum.domain.Transaction import io.iohk.ethereum.faucet.FaucetConfig import io.iohk.ethereum.jsonrpc.client.RpcClient.RpcError +import io.iohk.ethereum.keystore.KeyStore import io.iohk.ethereum.keystore.KeyStore.KeyStoreError -import io.iohk.ethereum.keystore.{KeyStore, Wallet} +import io.iohk.ethereum.keystore.Wallet import io.iohk.ethereum.network.p2p.messages.BaseETH6XMessages.SignedTransactions.SignedTransactionEnc import io.iohk.ethereum.rlp -import io.iohk.ethereum.utils.{ByteStringUtils, Logger} -import monix.eval.Task +import io.iohk.ethereum.utils.ByteStringUtils +import io.iohk.ethereum.utils.Logger class WalletService(walletRpcClient: WalletRpcClient, keyStore: KeyStore, config: FaucetConfig) extends Logger { - def sendFunds(wallet: Wallet, addressTo: Address): Task[Either[RpcError, ByteString]] = { + def sendFunds(wallet: Wallet, addressTo: Address): Task[Either[RpcError, ByteString]] = (for { nonce <- EitherT(walletRpcClient.getNonce(wallet.address)) txId <- EitherT(walletRpcClient.sendTransaction(prepareTx(wallet, addressTo, nonce))) - } yield txId).value map { + } yield txId).value.map { case Right(txId) => val txIdHex = s"0x${ByteStringUtils.hash2string(txId)}" log.info(s"Sending ${config.txValue} ETC to $addressTo in tx: $txIdHex.") @@ -27,7 +33,6 @@ class WalletService(walletRpcClient: WalletRpcClient, keyStore: KeyStore, config log.error(s"An error occurred while using faucet", error) Left(error) } - } private def prepareTx(wallet: Wallet, targetAddress: Address, nonce: BigInt): ByteString = { val transaction = diff --git a/src/main/scala/io/iohk/ethereum/forkid/ForkId.scala b/src/main/scala/io/iohk/ethereum/forkid/ForkId.scala index 6d80bbcd32..c13a577676 100644 --- a/src/main/scala/io/iohk/ethereum/forkid/ForkId.scala +++ b/src/main/scala/io/iohk/ethereum/forkid/ForkId.scala @@ -1,14 +1,14 @@ package io.iohk.ethereum.forkid import java.util.zip.CRC32 -import java.nio.ByteBuffer import akka.util.ByteString -import io.iohk.ethereum.utils.BlockchainConfig + +import io.iohk.ethereum.rlp._ import io.iohk.ethereum.utils.BigIntExtensionMethods._ +import io.iohk.ethereum.utils.BlockchainConfig import io.iohk.ethereum.utils.ByteUtils._ import io.iohk.ethereum.utils.Hex -import io.iohk.ethereum.rlp._ import RLPImplicitConversions._ @@ -30,7 +30,7 @@ object ForkId { new ForkId(crc.getValue(), next) } - val noFork = BigInt("1000000000000000000") + val noFork: BigInt = BigInt("1000000000000000000") def gatherForks(config: BlockchainConfig): List[BigInt] = { val maybeDaoBlock: Option[BigInt] = config.daoForkConfig.flatMap { daoConf => @@ -56,13 +56,12 @@ object ForkId { } - implicit val forkIdEnc = new RLPDecoder[ForkId] { + implicit val forkIdEnc: RLPDecoder[ForkId] = new RLPDecoder[ForkId] { def decode(rlp: RLPEncodeable): ForkId = rlp match { - case RLPList(hash, next) => { + case RLPList(hash, next) => val i = bigIntFromEncodeable(next) ForkId(bigIntFromEncodeable(hash), if (i == 0) None else Some(i)) - } case _ => throw new RuntimeException("Error when decoding ForkId") } } diff --git a/src/main/scala/io/iohk/ethereum/forkid/ForkIdValidator.scala b/src/main/scala/io/iohk/ethereum/forkid/ForkIdValidator.scala index b50ec1dd02..5cd8b061f0 100644 --- a/src/main/scala/io/iohk/ethereum/forkid/ForkIdValidator.scala +++ b/src/main/scala/io/iohk/ethereum/forkid/ForkIdValidator.scala @@ -1,17 +1,21 @@ package io.iohk.ethereum.forkid +import java.util.zip.CRC32 + import akka.util.ByteString + import cats.Monad import cats.data.EitherT._ import cats.implicits._ -import io.iohk.ethereum.utils.BigIntExtensionMethods._ -import io.iohk.ethereum.utils.BlockchainConfig -import io.iohk.ethereum.utils.ByteUtils._ + import monix.eval.Task + import org.typelevel.log4cats.Logger +import org.typelevel.log4cats.SelfAwareStructuredLogger import org.typelevel.log4cats.slf4j.Slf4jLogger -import java.util.zip.CRC32 +import io.iohk.ethereum.utils.BlockchainConfig +import io.iohk.ethereum.utils.ByteUtils._ sealed trait ForkIdValidationResult case object Connect extends ForkIdValidationResult @@ -20,9 +24,9 @@ case object ErrLocalIncompatibleOrStale extends ForkIdValidationResult object ForkIdValidator { - implicit val unsafeLogger = Slf4jLogger.getLogger[Task] + implicit val unsafeLogger: SelfAwareStructuredLogger[Task] = Slf4jLogger.getLogger[Task] - val maxUInt64 = (BigInt(0x7fffffffffffffffL) << 1) + 1 // scalastyle:ignore magic.number + val maxUInt64: BigInt = (BigInt(0x7fffffffffffffffL) << 1) + 1 // scalastyle:ignore magic.number /** Tells whether it makes sense to connect to a peer or gives a reason why it isn't a good idea. * @@ -87,14 +91,13 @@ object ForkIdValidator { crc.update(genesisHash.asByteBuffer) val genesisChecksum = BigInt(crc.getValue()) - genesisChecksum +: (forks.map { fork => + genesisChecksum +: forks.map { fork => crc.update(bigIntToBytes(fork, 8)) BigInt(crc.getValue()) - }).toVector + }.toVector } - /** - * 1) If local and remote FORK_HASH matches, compare local head to FORK_NEXT. + /** 1) If local and remote FORK_HASH matches, compare local head to FORK_NEXT. * The two nodes are in the same fork state currently. * They might know of differing future forks, but that’s not relevant until the fork triggers (might be postponed, nodes might be updated to match). * 1a) A remotely announced but remotely not passed block is already passed locally, disconnect, since the chains are incompatible. @@ -106,13 +109,12 @@ object ForkIdValidator { currentHeight: BigInt ): Option[ForkIdValidationResult] = remoteId match { - case ForkId(hash, _) if checksum != hash => None + case ForkId(hash, _) if checksum != hash => None case ForkId(_, Some(next)) if currentHeight >= next => Some(ErrLocalIncompatibleOrStale) - case _ => Some(Connect) + case _ => Some(Connect) } - /** - * 2) If the remote FORK_HASH is a subset of the local past forks and the remote FORK_NEXT matches with the locally following fork block number, connect. + /** 2) If the remote FORK_HASH is a subset of the local past forks and the remote FORK_NEXT matches with the locally following fork block number, connect. * Remote node is currently syncing. It might eventually diverge from us, but at this current point in time we don’t have enough information. */ def checkSubset( @@ -128,12 +130,10 @@ object ForkIdValidator { case (sum, fork) if sum == remoteId.hash => if (fork == remoteId.next.getOrElse(0)) Connect else ErrRemoteStale } - /** - * 3) If the remote FORK_HASH is a superset of the local past forks and can be completed with locally known future forks, connect. + /** 3) If the remote FORK_HASH is a superset of the local past forks and can be completed with locally known future forks, connect. * Local node is currently syncing. It might eventually diverge from the remote, but at this current point in time we don’t have enough information. */ - def checkSuperset(checksums: Vector[BigInt], remoteId: ForkId, i: Int): Option[ForkIdValidationResult] = { + def checkSuperset(checksums: Vector[BigInt], remoteId: ForkId, i: Int): Option[ForkIdValidationResult] = checksums.drop(i).collectFirst { case sum if sum == remoteId.hash => Connect } - } } diff --git a/src/main/scala/io/iohk/ethereum/jsonrpc/AkkaTaskOps.scala b/src/main/scala/io/iohk/ethereum/jsonrpc/AkkaTaskOps.scala index 7ac4b11244..b3ed88d187 100644 --- a/src/main/scala/io/iohk/ethereum/jsonrpc/AkkaTaskOps.scala +++ b/src/main/scala/io/iohk/ethereum/jsonrpc/AkkaTaskOps.scala @@ -1,8 +1,10 @@ package io.iohk.ethereum.jsonrpc -import akka.actor.{Actor, ActorRef} +import akka.actor.Actor +import akka.actor.ActorRef import akka.pattern.ask import akka.util.Timeout + import monix.eval.Task import scala.reflect.ClassTag diff --git a/src/main/scala/io/iohk/ethereum/jsonrpc/BlockResponse.scala b/src/main/scala/io/iohk/ethereum/jsonrpc/BlockResponse.scala index d173fd40ce..2383d3b936 100644 --- a/src/main/scala/io/iohk/ethereum/jsonrpc/BlockResponse.scala +++ b/src/main/scala/io/iohk/ethereum/jsonrpc/BlockResponse.scala @@ -1,10 +1,15 @@ package io.iohk.ethereum.jsonrpc import akka.util.ByteString + import cats.implicits._ + import io.iohk.ethereum.consensus.pow.RestrictedPoWSigner import io.iohk.ethereum.crypto.ECDSASignature -import io.iohk.ethereum.domain.{Block, BlockBody, BlockHeader, ChainWeight} +import io.iohk.ethereum.domain.Block +import io.iohk.ethereum.domain.BlockBody +import io.iohk.ethereum.domain.BlockHeader +import io.iohk.ethereum.domain.ChainWeight import io.iohk.ethereum.utils.ByteStringUtils case class CheckpointResponse(signatures: Seq[ECDSASignature], signers: Seq[ByteString]) diff --git a/src/main/scala/io/iohk/ethereum/jsonrpc/CheckpointingJsonMethodsImplicits.scala b/src/main/scala/io/iohk/ethereum/jsonrpc/CheckpointingJsonMethodsImplicits.scala index 3609eab8bd..b81e35700a 100644 --- a/src/main/scala/io/iohk/ethereum/jsonrpc/CheckpointingJsonMethodsImplicits.scala +++ b/src/main/scala/io/iohk/ethereum/jsonrpc/CheckpointingJsonMethodsImplicits.scala @@ -1,13 +1,16 @@ package io.iohk.ethereum.jsonrpc import akka.util.ByteString + +import org.json4s.Extraction +import org.json4s.JsonAST +import org.json4s.JsonAST._ + import io.iohk.ethereum.crypto.ECDSASignature import io.iohk.ethereum.jsonrpc.CheckpointingService._ import io.iohk.ethereum.jsonrpc.JsonRpcError.InvalidParams import io.iohk.ethereum.jsonrpc.serialization.JsonMethodCodec import io.iohk.ethereum.jsonrpc.serialization.JsonSerializers.QuantitiesSerializer -import org.json4s.JsonAST._ -import org.json4s.{Extraction, JsonAST} object CheckpointingJsonMethodsImplicits extends JsonMethodsImplicits { diff --git a/src/main/scala/io/iohk/ethereum/jsonrpc/CheckpointingService.scala b/src/main/scala/io/iohk/ethereum/jsonrpc/CheckpointingService.scala index cd64352bc4..91264100dd 100644 --- a/src/main/scala/io/iohk/ethereum/jsonrpc/CheckpointingService.scala +++ b/src/main/scala/io/iohk/ethereum/jsonrpc/CheckpointingService.scala @@ -2,13 +2,19 @@ package io.iohk.ethereum.jsonrpc import akka.actor.ActorRef import akka.util.ByteString + +import monix.eval.Task + import io.iohk.ethereum.blockchain.sync.regular.RegularSync.NewCheckpoint import io.iohk.ethereum.consensus.blocks.CheckpointBlockGenerator import io.iohk.ethereum.crypto.ECDSASignature -import io.iohk.ethereum.domain.{Block, Blockchain, BlockchainReader, Checkpoint} -import io.iohk.ethereum.utils.{ByteStringUtils, Logger} -import monix.eval.Task +import io.iohk.ethereum.domain.Block +import io.iohk.ethereum.domain.Blockchain +import io.iohk.ethereum.domain.BlockchainReader +import io.iohk.ethereum.domain.Checkpoint import io.iohk.ethereum.ledger.BlockQueue +import io.iohk.ethereum.utils.ByteStringUtils +import io.iohk.ethereum.utils.Logger class CheckpointingService( blockchain: Blockchain, diff --git a/src/main/scala/io/iohk/ethereum/jsonrpc/DebugJsonMethodsImplicits.scala b/src/main/scala/io/iohk/ethereum/jsonrpc/DebugJsonMethodsImplicits.scala index ca4714c008..5cd3959535 100644 --- a/src/main/scala/io/iohk/ethereum/jsonrpc/DebugJsonMethodsImplicits.scala +++ b/src/main/scala/io/iohk/ethereum/jsonrpc/DebugJsonMethodsImplicits.scala @@ -1,9 +1,14 @@ package io.iohk.ethereum.jsonrpc -import io.iohk.ethereum.jsonrpc.DebugService.{ListPeersInfoRequest, ListPeersInfoResponse} +import org.json4s.JsonAST.JArray +import org.json4s.JsonAST.JString +import org.json4s.JsonAST.JValue + +import io.iohk.ethereum.jsonrpc.DebugService.ListPeersInfoRequest +import io.iohk.ethereum.jsonrpc.DebugService.ListPeersInfoResponse +import io.iohk.ethereum.jsonrpc.serialization.JsonEncoder +import io.iohk.ethereum.jsonrpc.serialization.JsonMethodCodec import io.iohk.ethereum.jsonrpc.serialization.JsonMethodDecoder.NoParamsMethodDecoder -import io.iohk.ethereum.jsonrpc.serialization.{JsonEncoder, JsonMethodCodec} -import org.json4s.JsonAST.{JArray, JString, JValue} object DebugJsonMethodsImplicits extends JsonMethodsImplicits { diff --git a/src/main/scala/io/iohk/ethereum/jsonrpc/DebugService.scala b/src/main/scala/io/iohk/ethereum/jsonrpc/DebugService.scala index 171545fd7a..d4c2f7c943 100644 --- a/src/main/scala/io/iohk/ethereum/jsonrpc/DebugService.scala +++ b/src/main/scala/io/iohk/ethereum/jsonrpc/DebugService.scala @@ -2,15 +2,23 @@ package io.iohk.ethereum.jsonrpc import akka.actor.ActorRef import akka.util.Timeout -import io.iohk.ethereum.jsonrpc.AkkaTaskOps._ -import io.iohk.ethereum.jsonrpc.DebugService.{ListPeersInfoRequest, ListPeersInfoResponse} -import io.iohk.ethereum.network.EtcPeerManagerActor.{PeerInfo, PeerInfoResponse} -import io.iohk.ethereum.network.PeerManagerActor.Peers -import io.iohk.ethereum.network.{EtcPeerManagerActor, Peer, PeerActor, PeerId, PeerManagerActor} + import monix.eval.Task import scala.concurrent.duration._ +import io.iohk.ethereum.jsonrpc.AkkaTaskOps._ +import io.iohk.ethereum.jsonrpc.DebugService.ListPeersInfoRequest +import io.iohk.ethereum.jsonrpc.DebugService.ListPeersInfoResponse +import io.iohk.ethereum.network.EtcPeerManagerActor +import io.iohk.ethereum.network.EtcPeerManagerActor.PeerInfo +import io.iohk.ethereum.network.EtcPeerManagerActor.PeerInfoResponse +import io.iohk.ethereum.network.Peer +import io.iohk.ethereum.network.PeerActor +import io.iohk.ethereum.network.PeerId +import io.iohk.ethereum.network.PeerManagerActor +import io.iohk.ethereum.network.PeerManagerActor.Peers + object DebugService { case class ListPeersInfoRequest() case class ListPeersInfoResponse(peers: List[PeerInfo]) @@ -18,12 +26,11 @@ object DebugService { class DebugService(peerManager: ActorRef, etcPeerManager: ActorRef) { - def listPeersInfo(getPeersInfoRequest: ListPeersInfoRequest): ServiceResponse[ListPeersInfoResponse] = { + def listPeersInfo(getPeersInfoRequest: ListPeersInfoRequest): ServiceResponse[ListPeersInfoResponse] = for { ids <- getPeerIds peers <- Task.traverse(ids)(getPeerInfo) } yield Right(ListPeersInfoResponse(peers.flatten)) - } private def getPeerIds: Task[List[PeerId]] = { implicit val timeout: Timeout = Timeout(5.seconds) diff --git a/src/main/scala/io/iohk/ethereum/jsonrpc/EthBlocksJsonMethodsImplicits.scala b/src/main/scala/io/iohk/ethereum/jsonrpc/EthBlocksJsonMethodsImplicits.scala index d862c05f47..eb2336b40d 100644 --- a/src/main/scala/io/iohk/ethereum/jsonrpc/EthBlocksJsonMethodsImplicits.scala +++ b/src/main/scala/io/iohk/ethereum/jsonrpc/EthBlocksJsonMethodsImplicits.scala @@ -1,140 +1,153 @@ package io.iohk.ethereum.jsonrpc +import org.json4s.Extraction +import org.json4s.JsonAST.JArray +import org.json4s.JsonAST.JBool +import org.json4s.JsonAST.JField +import org.json4s.JsonAST.JString +import org.json4s.JsonAST.JValue + import io.iohk.ethereum.jsonrpc.EthBlocksService._ import io.iohk.ethereum.jsonrpc.JsonRpcError.InvalidParams -import io.iohk.ethereum.jsonrpc.serialization.{JsonEncoder, JsonMethodDecoder} +import io.iohk.ethereum.jsonrpc.serialization.JsonEncoder +import io.iohk.ethereum.jsonrpc.serialization.JsonMethodDecoder import io.iohk.ethereum.jsonrpc.serialization.JsonMethodDecoder.NoParamsMethodDecoder -import org.json4s.Extraction -import org.json4s.JsonAST.{JArray, JBool, JField, JString, JValue} object EthBlocksJsonMethodsImplicits extends JsonMethodsImplicits { - implicit val eth_blockNumber = new NoParamsMethodDecoder(BestBlockNumberRequest()) - with JsonEncoder[BestBlockNumberResponse] { - override def encodeJson(t: BestBlockNumberResponse): JValue = Extraction.decompose(t.bestBlockNumber) - } - - implicit val eth_getBlockTransactionCountByHash = new JsonMethodDecoder[TxCountByBlockHashRequest] - with JsonEncoder[TxCountByBlockHashResponse] { - override def decodeJson(params: Option[JArray]): Either[JsonRpcError, TxCountByBlockHashRequest] = - params match { - case Some(JArray(JString(input) :: Nil)) => - extractHash(input).map(TxCountByBlockHashRequest) - case _ => Left(InvalidParams()) - } + implicit val eth_blockNumber + : NoParamsMethodDecoder[BestBlockNumberRequest] with JsonEncoder[BestBlockNumberResponse] = + new NoParamsMethodDecoder(BestBlockNumberRequest()) with JsonEncoder[BestBlockNumberResponse] { + override def encodeJson(t: BestBlockNumberResponse): JValue = Extraction.decompose(t.bestBlockNumber) + } - override def encodeJson(t: TxCountByBlockHashResponse): JValue = - Extraction.decompose(t.txsQuantity.map(BigInt(_))) - } - - implicit val eth_getBlockByHash = new JsonMethodDecoder[BlockByBlockHashRequest] - with JsonEncoder[BlockByBlockHashResponse] { - override def decodeJson(params: Option[JArray]): Either[JsonRpcError, BlockByBlockHashRequest] = { - params match { - case Some(JArray(JString(blockHash) :: JBool(fullTxs) :: Nil)) => - extractHash(blockHash).map(BlockByBlockHashRequest(_, fullTxs)) - case _ => Left(InvalidParams()) - } + implicit val eth_getBlockTransactionCountByHash + : JsonMethodDecoder[TxCountByBlockHashRequest] with JsonEncoder[TxCountByBlockHashResponse] = + new JsonMethodDecoder[TxCountByBlockHashRequest] with JsonEncoder[TxCountByBlockHashResponse] { + override def decodeJson(params: Option[JArray]): Either[JsonRpcError, TxCountByBlockHashRequest] = + params match { + case Some(JArray(JString(input) :: Nil)) => + extractHash(input).map(TxCountByBlockHashRequest) + case _ => Left(InvalidParams()) + } + + override def encodeJson(t: TxCountByBlockHashResponse): JValue = + Extraction.decompose(t.txsQuantity.map(BigInt(_))) } - override def encodeJson(t: BlockByBlockHashResponse): JValue = - Extraction.decompose(t.blockResponse) - } - - implicit val eth_getBlockByNumber = new JsonMethodDecoder[BlockByNumberRequest] - with JsonEncoder[BlockByNumberResponse] { - override def decodeJson(params: Option[JArray]): Either[JsonRpcError, BlockByNumberRequest] = { - params match { - case Some(JArray(blockStr :: JBool(fullTxs) :: Nil)) => - extractBlockParam(blockStr).map(BlockByNumberRequest(_, fullTxs)) - case _ => Left(InvalidParams()) - } + implicit val eth_getBlockByHash + : JsonMethodDecoder[BlockByBlockHashRequest] with JsonEncoder[BlockByBlockHashResponse] = + new JsonMethodDecoder[BlockByBlockHashRequest] with JsonEncoder[BlockByBlockHashResponse] { + override def decodeJson(params: Option[JArray]): Either[JsonRpcError, BlockByBlockHashRequest] = + params match { + case Some(JArray(JString(blockHash) :: JBool(fullTxs) :: Nil)) => + extractHash(blockHash).map(BlockByBlockHashRequest(_, fullTxs)) + case _ => Left(InvalidParams()) + } + + override def encodeJson(t: BlockByBlockHashResponse): JValue = + Extraction.decompose(t.blockResponse) } - override def encodeJson(t: BlockByNumberResponse): JValue = - Extraction.decompose(t.blockResponse) - } - - implicit val eth_getUncleByBlockHashAndIndex = new JsonMethodDecoder[UncleByBlockHashAndIndexRequest] - with JsonEncoder[UncleByBlockHashAndIndexResponse] { - override def decodeJson(params: Option[JArray]): Either[JsonRpcError, UncleByBlockHashAndIndexRequest] = - params match { - case Some(JArray(JString(blockHash) :: uncleIndex :: Nil)) => - for { - hash <- extractHash(blockHash) - uncleBlockIndex <- extractQuantity(uncleIndex) - } yield UncleByBlockHashAndIndexRequest(hash, uncleBlockIndex) - case _ => Left(InvalidParams()) - } + implicit val eth_getBlockByNumber: JsonMethodDecoder[BlockByNumberRequest] with JsonEncoder[BlockByNumberResponse] = + new JsonMethodDecoder[BlockByNumberRequest] with JsonEncoder[BlockByNumberResponse] { + override def decodeJson(params: Option[JArray]): Either[JsonRpcError, BlockByNumberRequest] = + params match { + case Some(JArray(blockStr :: JBool(fullTxs) :: Nil)) => + extractBlockParam(blockStr).map(BlockByNumberRequest(_, fullTxs)) + case _ => Left(InvalidParams()) + } + + override def encodeJson(t: BlockByNumberResponse): JValue = + Extraction.decompose(t.blockResponse) + } - override def encodeJson(t: UncleByBlockHashAndIndexResponse): JValue = { - val uncleBlockResponse = Extraction.decompose(t.uncleBlockResponse) - uncleBlockResponse.removeField { - case JField("transactions", _) => true - case _ => false + implicit val eth_getUncleByBlockHashAndIndex + : JsonMethodDecoder[UncleByBlockHashAndIndexRequest] with JsonEncoder[UncleByBlockHashAndIndexResponse] = + new JsonMethodDecoder[UncleByBlockHashAndIndexRequest] with JsonEncoder[UncleByBlockHashAndIndexResponse] { + override def decodeJson(params: Option[JArray]): Either[JsonRpcError, UncleByBlockHashAndIndexRequest] = + params match { + case Some(JArray(JString(blockHash) :: uncleIndex :: Nil)) => + for { + hash <- extractHash(blockHash) + uncleBlockIndex <- extractQuantity(uncleIndex) + } yield UncleByBlockHashAndIndexRequest(hash, uncleBlockIndex) + case _ => Left(InvalidParams()) + } + + override def encodeJson(t: UncleByBlockHashAndIndexResponse): JValue = { + val uncleBlockResponse = Extraction.decompose(t.uncleBlockResponse) + uncleBlockResponse.removeField { + case JField("transactions", _) => true + case _ => false + } } } - } - - implicit val eth_getUncleByBlockNumberAndIndex = new JsonMethodDecoder[UncleByBlockNumberAndIndexRequest] - with JsonEncoder[UncleByBlockNumberAndIndexResponse] { - override def decodeJson(params: Option[JArray]): Either[JsonRpcError, UncleByBlockNumberAndIndexRequest] = - params match { - case Some(JArray(blockStr :: uncleIndex :: Nil)) => - for { - block <- extractBlockParam(blockStr) - uncleBlockIndex <- extractQuantity(uncleIndex) - } yield UncleByBlockNumberAndIndexRequest(block, uncleBlockIndex) - case _ => Left(InvalidParams()) - } - override def encodeJson(t: UncleByBlockNumberAndIndexResponse): JValue = { - val uncleBlockResponse = Extraction.decompose(t.uncleBlockResponse) - uncleBlockResponse.removeField { - case JField("transactions", _) => true - case _ => false + implicit val eth_getUncleByBlockNumberAndIndex + : JsonMethodDecoder[UncleByBlockNumberAndIndexRequest] with JsonEncoder[UncleByBlockNumberAndIndexResponse] = + new JsonMethodDecoder[UncleByBlockNumberAndIndexRequest] with JsonEncoder[UncleByBlockNumberAndIndexResponse] { + override def decodeJson(params: Option[JArray]): Either[JsonRpcError, UncleByBlockNumberAndIndexRequest] = + params match { + case Some(JArray(blockStr :: uncleIndex :: Nil)) => + for { + block <- extractBlockParam(blockStr) + uncleBlockIndex <- extractQuantity(uncleIndex) + } yield UncleByBlockNumberAndIndexRequest(block, uncleBlockIndex) + case _ => Left(InvalidParams()) + } + + override def encodeJson(t: UncleByBlockNumberAndIndexResponse): JValue = { + val uncleBlockResponse = Extraction.decompose(t.uncleBlockResponse) + uncleBlockResponse.removeField { + case JField("transactions", _) => true + case _ => false + } } } - } - - implicit val eth_getUncleCountByBlockNumber = new JsonMethodDecoder[GetUncleCountByBlockNumberRequest] - with JsonEncoder[GetUncleCountByBlockNumberResponse] { - def decodeJson(params: Option[JArray]): Either[JsonRpcError, GetUncleCountByBlockNumberRequest] = - params match { - case Some(JArray((blockValue: JValue) :: Nil)) => - for { - block <- extractBlockParam(blockValue) - } yield GetUncleCountByBlockNumberRequest(block) - case _ => Left(InvalidParams()) - } - def encodeJson(t: GetUncleCountByBlockNumberResponse): JValue = encodeAsHex(t.result) - } - - implicit val eth_getUncleCountByBlockHash = new JsonMethodDecoder[GetUncleCountByBlockHashRequest] - with JsonEncoder[GetUncleCountByBlockHashResponse] { - def decodeJson(params: Option[JArray]): Either[JsonRpcError, GetUncleCountByBlockHashRequest] = - params match { - case Some(JArray(JString(hash) :: Nil)) => - for { - blockHash <- extractHash(hash) - } yield GetUncleCountByBlockHashRequest(blockHash) - case _ => Left(InvalidParams()) - } + implicit val eth_getUncleCountByBlockNumber + : JsonMethodDecoder[GetUncleCountByBlockNumberRequest] with JsonEncoder[GetUncleCountByBlockNumberResponse] = + new JsonMethodDecoder[GetUncleCountByBlockNumberRequest] with JsonEncoder[GetUncleCountByBlockNumberResponse] { + def decodeJson(params: Option[JArray]): Either[JsonRpcError, GetUncleCountByBlockNumberRequest] = + params match { + case Some(JArray((blockValue: JValue) :: Nil)) => + for { + block <- extractBlockParam(blockValue) + } yield GetUncleCountByBlockNumberRequest(block) + case _ => Left(InvalidParams()) + } + + def encodeJson(t: GetUncleCountByBlockNumberResponse): JValue = encodeAsHex(t.result) + } - def encodeJson(t: GetUncleCountByBlockHashResponse): JValue = encodeAsHex(t.result) - } - - implicit val eth_getBlockTransactionCountByNumber = new JsonMethodDecoder[GetBlockTransactionCountByNumberRequest] - with JsonEncoder[GetBlockTransactionCountByNumberResponse] { - def decodeJson(params: Option[JArray]): Either[JsonRpcError, GetBlockTransactionCountByNumberRequest] = - params match { - case Some(JArray((blockValue: JValue) :: Nil)) => - for { - block <- extractBlockParam(blockValue) - } yield GetBlockTransactionCountByNumberRequest(block) - case _ => Left(InvalidParams()) - } + implicit val eth_getUncleCountByBlockHash + : JsonMethodDecoder[GetUncleCountByBlockHashRequest] with JsonEncoder[GetUncleCountByBlockHashResponse] = + new JsonMethodDecoder[GetUncleCountByBlockHashRequest] with JsonEncoder[GetUncleCountByBlockHashResponse] { + def decodeJson(params: Option[JArray]): Either[JsonRpcError, GetUncleCountByBlockHashRequest] = + params match { + case Some(JArray(JString(hash) :: Nil)) => + for { + blockHash <- extractHash(hash) + } yield GetUncleCountByBlockHashRequest(blockHash) + case _ => Left(InvalidParams()) + } + + def encodeJson(t: GetUncleCountByBlockHashResponse): JValue = encodeAsHex(t.result) + } - def encodeJson(t: GetBlockTransactionCountByNumberResponse): JValue = encodeAsHex(t.result) - } + implicit val eth_getBlockTransactionCountByNumber: JsonMethodDecoder[GetBlockTransactionCountByNumberRequest] + with JsonEncoder[GetBlockTransactionCountByNumberResponse] = + new JsonMethodDecoder[GetBlockTransactionCountByNumberRequest] + with JsonEncoder[GetBlockTransactionCountByNumberResponse] { + def decodeJson(params: Option[JArray]): Either[JsonRpcError, GetBlockTransactionCountByNumberRequest] = + params match { + case Some(JArray((blockValue: JValue) :: Nil)) => + for { + block <- extractBlockParam(blockValue) + } yield GetBlockTransactionCountByNumberRequest(block) + case _ => Left(InvalidParams()) + } + + def encodeJson(t: GetBlockTransactionCountByNumberResponse): JValue = encodeAsHex(t.result) + } } diff --git a/src/main/scala/io/iohk/ethereum/jsonrpc/EthBlocksService.scala b/src/main/scala/io/iohk/ethereum/jsonrpc/EthBlocksService.scala index 5d4e1c63b6..ee5a8da35f 100644 --- a/src/main/scala/io/iohk/ethereum/jsonrpc/EthBlocksService.scala +++ b/src/main/scala/io/iohk/ethereum/jsonrpc/EthBlocksService.scala @@ -1,10 +1,14 @@ package io.iohk.ethereum.jsonrpc import akka.util.ByteString -import io.iohk.ethereum.domain.{Blockchain, BlockchainReader} + import monix.eval.Task + import org.bouncycastle.util.encoders.Hex + import io.iohk.ethereum.consensus.Consensus +import io.iohk.ethereum.domain.Blockchain +import io.iohk.ethereum.domain.BlockchainReader import io.iohk.ethereum.ledger.BlockQueue object EthBlocksService { @@ -44,8 +48,7 @@ class EthBlocksService( ) extends ResolveBlock { import EthBlocksService._ - /** - * eth_blockNumber that returns the number of most recent block. + /** eth_blockNumber that returns the number of most recent block. * * @return Current block number the client is on. */ @@ -53,8 +56,7 @@ class EthBlocksService( Right(BestBlockNumberResponse(blockchain.getBestBlockNumber())) } - /** - * Implements the eth_getBlockTransactionCountByHash method that fetches the number of txs that a certain block has. + /** Implements the eth_getBlockTransactionCountByHash method that fetches the number of txs that a certain block has. * * @param request with the hash of the block requested * @return the number of txs that the block has or None if the client doesn't have the block requested @@ -65,23 +67,21 @@ class EthBlocksService( Right(TxCountByBlockHashResponse(txsCount)) } - /** - * Implements the eth_getBlockByHash method that fetches a requested block. + /** Implements the eth_getBlockByHash method that fetches a requested block. * * @param request with the hash of the block requested * @return the block requested or None if the client doesn't have the block */ def getByBlockHash(request: BlockByBlockHashRequest): ServiceResponse[BlockByBlockHashResponse] = Task { val BlockByBlockHashRequest(blockHash, fullTxs) = request - val blockOpt = blockchainReader.getBlockByHash(blockHash) orElse blockQueue.getBlockByHash(blockHash) - val weight = blockchain.getChainWeightByHash(blockHash) orElse blockQueue.getChainWeightByHash(blockHash) + val blockOpt = blockchainReader.getBlockByHash(blockHash).orElse(blockQueue.getBlockByHash(blockHash)) + val weight = blockchain.getChainWeightByHash(blockHash).orElse(blockQueue.getChainWeightByHash(blockHash)) val blockResponseOpt = blockOpt.map(block => BlockResponse(block, weight, fullTxs = fullTxs)) Right(BlockByBlockHashResponse(blockResponseOpt)) } - /** - * Implements the eth_getBlockByNumber method that fetches a requested block. + /** Implements the eth_getBlockByNumber method that fetches a requested block. * * @param request with the block requested (by it's number or by tag) * @return the block requested or None if the client doesn't have the block @@ -98,16 +98,14 @@ class EthBlocksService( def getBlockTransactionCountByNumber( req: GetBlockTransactionCountByNumberRequest - ): ServiceResponse[GetBlockTransactionCountByNumberResponse] = { + ): ServiceResponse[GetBlockTransactionCountByNumberResponse] = Task { resolveBlock(req.block).map { case ResolvedBlock(block, _) => GetBlockTransactionCountByNumberResponse(block.body.transactionList.size) } } - } - /** - * Implements the eth_getUncleByBlockHashAndIndex method that fetches an uncle from a certain index in a requested block. + /** Implements the eth_getUncleByBlockHashAndIndex method that fetches an uncle from a certain index in a requested block. * * @param request with the hash of the block and the index of the uncle requested * @return the uncle that the block has at the given index or None if the client doesn't have the block or if there's no uncle in that index @@ -133,8 +131,7 @@ class EthBlocksService( Right(UncleByBlockHashAndIndexResponse(uncleBlockResponseOpt)) } - /** - * Implements the eth_getUncleByBlockNumberAndIndex method that fetches an uncle from a certain index in a requested block. + /** Implements the eth_getUncleByBlockNumberAndIndex method that fetches an uncle from a certain index in a requested block. * * @param request with the number/tag of the block and the index of the uncle requested * @return the uncle that the block has at the given index or None if the client doesn't have the block or if there's no uncle in that index @@ -166,17 +163,16 @@ class EthBlocksService( def getUncleCountByBlockNumber( req: GetUncleCountByBlockNumberRequest - ): ServiceResponse[GetUncleCountByBlockNumberResponse] = { + ): ServiceResponse[GetUncleCountByBlockNumberResponse] = Task { resolveBlock(req.block).map { case ResolvedBlock(block, _) => GetUncleCountByBlockNumberResponse(block.body.uncleNodesList.size) } } - } def getUncleCountByBlockHash( req: GetUncleCountByBlockHashRequest - ): ServiceResponse[GetUncleCountByBlockHashResponse] = { + ): ServiceResponse[GetUncleCountByBlockHashResponse] = Task { blockchainReader.getBlockBodyByHash(req.blockHash) match { case Some(blockBody) => @@ -187,5 +183,4 @@ class EthBlocksService( ) } } - } } diff --git a/src/main/scala/io/iohk/ethereum/jsonrpc/EthFilterJsonMethodsImplicits.scala b/src/main/scala/io/iohk/ethereum/jsonrpc/EthFilterJsonMethodsImplicits.scala index 25a27cdc75..6297510750 100644 --- a/src/main/scala/io/iohk/ethereum/jsonrpc/EthFilterJsonMethodsImplicits.scala +++ b/src/main/scala/io/iohk/ethereum/jsonrpc/EthFilterJsonMethodsImplicits.scala @@ -1,22 +1,22 @@ package io.iohk.ethereum.jsonrpc +import akka.util.ByteString + +import org.json4s.Extraction +import org.json4s.JsonAST._ + import io.iohk.ethereum.jsonrpc.EthFilterService._ import io.iohk.ethereum.jsonrpc.JsonRpcError.InvalidParams -import io.iohk.ethereum.jsonrpc.serialization.JsonMethodDecoder.NoParamsMethodDecoder import io.iohk.ethereum.jsonrpc.serialization.JsonEncoder -import io.iohk.ethereum.jsonrpc.serialization.JsonEncoder.OptionToNull._ import io.iohk.ethereum.jsonrpc.serialization.JsonMethodDecoder -import org.json4s.JsonAST._ -import org.json4s.JsonDSL._ -import org.json4s.Extraction -import akka.util.ByteString +import io.iohk.ethereum.jsonrpc.serialization.JsonMethodDecoder.NoParamsMethodDecoder object EthFilterJsonMethodsImplicits extends JsonMethodsImplicits { - implicit val newFilterResponseEnc = new JsonEncoder[NewFilterResponse] { + implicit val newFilterResponseEnc: JsonEncoder[NewFilterResponse] = new JsonEncoder[NewFilterResponse] { def encodeJson(t: NewFilterResponse): JValue = encodeAsHex(t.filterId) } - implicit val eth_newFilter = new JsonMethodDecoder[NewFilterRequest] { + implicit val eth_newFilter: JsonMethodDecoder[NewFilterRequest] = new JsonMethodDecoder[NewFilterRequest] { def decodeJson(params: Option[JArray]): Either[JsonRpcError, NewFilterRequest] = params match { case Some(JArray((filterObj: JObject) :: Nil)) => @@ -27,77 +27,84 @@ object EthFilterJsonMethodsImplicits extends JsonMethodsImplicits { } } - implicit val eth_newBlockFilter = new NoParamsMethodDecoder(NewBlockFilterRequest()) {} - - implicit val eth_newPendingTransactionFilter = new NoParamsMethodDecoder(NewPendingTransactionFilterRequest()) {} - - implicit val eth_uninstallFilter = new JsonMethodDecoder[UninstallFilterRequest] - with JsonEncoder[UninstallFilterResponse] { - def decodeJson(params: Option[JArray]): Either[JsonRpcError, UninstallFilterRequest] = - params match { - case Some(JArray((rawFilterId: JValue) :: Nil)) => - for { - filterId <- extractQuantity(rawFilterId) - } yield UninstallFilterRequest(filterId) - case _ => Left(InvalidParams()) - } - override def encodeJson(t: UninstallFilterResponse): JValue = JBool(t.success) - } - - implicit val eth_getFilterChanges = new JsonMethodDecoder[GetFilterChangesRequest] - with JsonEncoder[GetFilterChangesResponse] { - def decodeJson(params: Option[JArray]): Either[JsonRpcError, GetFilterChangesRequest] = - params match { - case Some(JArray((rawFilterId: JValue) :: Nil)) => - for { - filterId <- extractQuantity(rawFilterId) - } yield GetFilterChangesRequest(filterId) - case _ => Left(InvalidParams()) - } - override def encodeJson(t: GetFilterChangesResponse): JValue = - t.filterChanges match { - case FilterManager.LogFilterChanges(logs) => JArray(logs.map(Extraction.decompose).toList) - case FilterManager.BlockFilterChanges(blockHashes) => JArray(blockHashes.map(encodeAsHex).toList) - case FilterManager.PendingTransactionFilterChanges(txHashes) => JArray(txHashes.map(encodeAsHex).toList) - } - } - - implicit val eth_getFilterLogs = new JsonMethodDecoder[GetFilterLogsRequest] with JsonEncoder[GetFilterLogsResponse] { - import FilterManager._ - - def decodeJson(params: Option[JArray]): Either[JsonRpcError, GetFilterLogsRequest] = - params match { - case Some(JArray((rawFilterId: JValue) :: Nil)) => - for { - filterId <- extractQuantity(rawFilterId) - } yield GetFilterLogsRequest(filterId) - case _ => Left(InvalidParams()) - } + implicit val eth_newBlockFilter: NoParamsMethodDecoder[NewBlockFilterRequest] = new NoParamsMethodDecoder( + NewBlockFilterRequest() + ) {} + + implicit val eth_newPendingTransactionFilter: NoParamsMethodDecoder[NewPendingTransactionFilterRequest] = + new NoParamsMethodDecoder(NewPendingTransactionFilterRequest()) {} + + implicit val eth_uninstallFilter + : JsonMethodDecoder[UninstallFilterRequest] with JsonEncoder[UninstallFilterResponse] = + new JsonMethodDecoder[UninstallFilterRequest] with JsonEncoder[UninstallFilterResponse] { + def decodeJson(params: Option[JArray]): Either[JsonRpcError, UninstallFilterRequest] = + params match { + case Some(JArray((rawFilterId: JValue) :: Nil)) => + for { + filterId <- extractQuantity(rawFilterId) + } yield UninstallFilterRequest(filterId) + case _ => Left(InvalidParams()) + } + override def encodeJson(t: UninstallFilterResponse): JValue = JBool(t.success) + } - override def encodeJson(t: GetFilterLogsResponse): JValue = - t.filterLogs match { - case LogFilterLogs(logs) => JArray(logs.map(Extraction.decompose).toList) - case BlockFilterLogs(blockHashes) => JArray(blockHashes.map(encodeAsHex).toList) - case PendingTransactionFilterLogs(txHashes) => JArray(txHashes.map(encodeAsHex).toList) - } - } + implicit val eth_getFilterChanges + : JsonMethodDecoder[GetFilterChangesRequest] with JsonEncoder[GetFilterChangesResponse] = + new JsonMethodDecoder[GetFilterChangesRequest] with JsonEncoder[GetFilterChangesResponse] { + def decodeJson(params: Option[JArray]): Either[JsonRpcError, GetFilterChangesRequest] = + params match { + case Some(JArray((rawFilterId: JValue) :: Nil)) => + for { + filterId <- extractQuantity(rawFilterId) + } yield GetFilterChangesRequest(filterId) + case _ => Left(InvalidParams()) + } + override def encodeJson(t: GetFilterChangesResponse): JValue = + t.filterChanges match { + case FilterManager.LogFilterChanges(logs) => JArray(logs.map(Extraction.decompose).toList) + case FilterManager.BlockFilterChanges(blockHashes) => JArray(blockHashes.map(encodeAsHex).toList) + case FilterManager.PendingTransactionFilterChanges(txHashes) => JArray(txHashes.map(encodeAsHex).toList) + } + } - implicit val eth_getLogs = new JsonMethodDecoder[GetLogsRequest] with JsonEncoder[GetLogsResponse] { - def decodeJson(params: Option[JArray]): Either[JsonRpcError, GetLogsRequest] = - params match { - case Some(JArray((filterObj: JObject) :: Nil)) => - for { - filter <- extractFilter(filterObj) - } yield GetLogsRequest(filter) - case _ => Left(InvalidParams()) - } + implicit val eth_getFilterLogs: JsonMethodDecoder[GetFilterLogsRequest] with JsonEncoder[GetFilterLogsResponse] = + new JsonMethodDecoder[GetFilterLogsRequest] with JsonEncoder[GetFilterLogsResponse] { + import FilterManager._ + + def decodeJson(params: Option[JArray]): Either[JsonRpcError, GetFilterLogsRequest] = + params match { + case Some(JArray((rawFilterId: JValue) :: Nil)) => + for { + filterId <- extractQuantity(rawFilterId) + } yield GetFilterLogsRequest(filterId) + case _ => Left(InvalidParams()) + } + + override def encodeJson(t: GetFilterLogsResponse): JValue = + t.filterLogs match { + case LogFilterLogs(logs) => JArray(logs.map(Extraction.decompose).toList) + case BlockFilterLogs(blockHashes) => JArray(blockHashes.map(encodeAsHex).toList) + case PendingTransactionFilterLogs(txHashes) => JArray(txHashes.map(encodeAsHex).toList) + } + } - override def encodeJson(t: GetLogsResponse): JValue = - JArray(t.filterLogs.logs.map(Extraction.decompose).toList) - } + implicit val eth_getLogs: JsonMethodDecoder[GetLogsRequest] with JsonEncoder[GetLogsResponse] = + new JsonMethodDecoder[GetLogsRequest] with JsonEncoder[GetLogsResponse] { + def decodeJson(params: Option[JArray]): Either[JsonRpcError, GetLogsRequest] = + params match { + case Some(JArray((filterObj: JObject) :: Nil)) => + for { + filter <- extractFilter(filterObj) + } yield GetLogsRequest(filter) + case _ => Left(InvalidParams()) + } + + override def encodeJson(t: GetLogsResponse): JValue = + JArray(t.filterLogs.logs.map(Extraction.decompose).toList) + } private def extractFilter(obj: JObject): Either[JsonRpcError, Filter] = { - def allSuccess[T](eithers: Seq[Either[JsonRpcError, T]]): Either[JsonRpcError, Seq[T]] = { + def allSuccess[T](eithers: Seq[Either[JsonRpcError, T]]): Either[JsonRpcError, Seq[T]] = if (eithers.forall(_.isRight)) { val values = eithers.collect { case Right(v) => v } Right(values) @@ -105,33 +112,30 @@ object EthFilterJsonMethodsImplicits extends JsonMethodsImplicits { val values = eithers.collect { case Left(err) => err.message } Left(InvalidParams(msg = values.mkString("\n"))) } - } - def parseTopic(jstr: JString): Either[JsonRpcError, ByteString] = { + def parseTopic(jstr: JString): Either[JsonRpcError, ByteString] = extractBytes(jstr).left.map(_ => InvalidParams(msg = s"Unable to parse topics, expected byte data but got ${jstr.values}") ) - } - def parseNestedTopics(jarr: JArray): Either[JsonRpcError, Seq[ByteString]] = { + def parseNestedTopics(jarr: JArray): Either[JsonRpcError, Seq[ByteString]] = allSuccess(jarr.arr.map { case jstr: JString => parseTopic(jstr) - case other => Left(InvalidParams(msg = s"Unable to parse topics, expected byte data but got: $other")) + case other => Left(InvalidParams(msg = s"Unable to parse topics, expected byte data but got: $other")) }) - } val topicsEither: Either[JsonRpcError, Seq[Seq[ByteString]]] = allSuccess((obj \ "topics").extractOpt[JArray].map(_.arr).getOrElse(Nil).map { - case JNull => Right(Nil) + case JNull => Right(Nil) case jstr: JString => parseTopic(jstr).map(Seq(_)) - case jarr: JArray => parseNestedTopics(jarr) - case other => Left(InvalidParams(msg = s"Unable to parse topics, expected byte data or array but got: $other")) + case jarr: JArray => parseNestedTopics(jarr) + case other => Left(InvalidParams(msg = s"Unable to parse topics, expected byte data or array but got: $other")) }) def optionalBlockParam(field: String) = (obj \ field).extractOpt[JValue].flatMap { case JNothing => None - case other => Some(extractBlockParam(other)) + case other => Some(extractBlockParam(other)) } for { diff --git a/src/main/scala/io/iohk/ethereum/jsonrpc/EthFilterService.scala b/src/main/scala/io/iohk/ethereum/jsonrpc/EthFilterService.scala index 9bd760da2b..2bd2f4021b 100644 --- a/src/main/scala/io/iohk/ethereum/jsonrpc/EthFilterService.scala +++ b/src/main/scala/io/iohk/ethereum/jsonrpc/EthFilterService.scala @@ -3,14 +3,14 @@ package io.iohk.ethereum.jsonrpc import akka.actor.ActorRef import akka.util.ByteString import akka.util.Timeout + import io.iohk.ethereum.domain._ -import io.iohk.ethereum.jsonrpc.{FilterManager => FM} import io.iohk.ethereum.jsonrpc.AkkaTaskOps._ import io.iohk.ethereum.jsonrpc.FilterManager.FilterChanges import io.iohk.ethereum.jsonrpc.FilterManager.FilterLogs import io.iohk.ethereum.jsonrpc.FilterManager.LogFilterLogs +import io.iohk.ethereum.jsonrpc.{FilterManager => FM} import io.iohk.ethereum.utils._ -import monix.eval.Task object EthFilterService { case class NewFilterRequest(filter: Filter) diff --git a/src/main/scala/io/iohk/ethereum/jsonrpc/EthInfoJsonMethodsImplicits.scala b/src/main/scala/io/iohk/ethereum/jsonrpc/EthInfoJsonMethodsImplicits.scala index d0e361eec8..19dce32696 100644 --- a/src/main/scala/io/iohk/ethereum/jsonrpc/EthInfoJsonMethodsImplicits.scala +++ b/src/main/scala/io/iohk/ethereum/jsonrpc/EthInfoJsonMethodsImplicits.scala @@ -1,62 +1,75 @@ package io.iohk.ethereum.jsonrpc import akka.util.ByteString + +import org.json4s.Extraction +import org.json4s.JsonAST.JArray +import org.json4s.JsonAST.JString +import org.json4s.JsonAST.JValue +import org.json4s.JsonAST._ +import org.json4s.JsonDSL._ + import io.iohk.ethereum.jsonrpc.EthInfoService._ import io.iohk.ethereum.jsonrpc.JsonRpcError.InvalidParams -import io.iohk.ethereum.jsonrpc.PersonalService.{SendTransactionRequest, SendTransactionResponse, SignRequest} -import io.iohk.ethereum.jsonrpc.ProofService.{GetProofRequest, GetProofResponse, StorageProofKey} -import io.iohk.ethereum.jsonrpc.serialization.JsonEncoder.OptionToNull._ +import io.iohk.ethereum.jsonrpc.PersonalService.SendTransactionRequest +import io.iohk.ethereum.jsonrpc.PersonalService.SendTransactionResponse +import io.iohk.ethereum.jsonrpc.PersonalService.SignRequest +import io.iohk.ethereum.jsonrpc.serialization.JsonEncoder +import io.iohk.ethereum.jsonrpc.serialization.JsonMethodCodec +import io.iohk.ethereum.jsonrpc.serialization.JsonMethodDecoder import io.iohk.ethereum.jsonrpc.serialization.JsonMethodDecoder.NoParamsMethodDecoder -import io.iohk.ethereum.jsonrpc.serialization.{JsonEncoder, JsonMethodCodec, JsonMethodDecoder} -import org.json4s.JsonAST.{JArray, JString, JValue, _} -import org.json4s.JsonDSL._ -import org.json4s.Extraction object EthJsonMethodsImplicits extends JsonMethodsImplicits { - implicit val eth_chainId = new NoParamsMethodDecoder(ChainIdRequest()) with JsonEncoder[ChainIdResponse] { - def encodeJson(t: ChainIdResponse) = encodeAsHex(t.value) - } - - implicit val eth_protocolVersion = new NoParamsMethodDecoder(ProtocolVersionRequest()) - with JsonEncoder[ProtocolVersionResponse] { - def encodeJson(t: ProtocolVersionResponse): JValue = t.value - } + implicit val eth_chainId: NoParamsMethodDecoder[ChainIdRequest] with JsonEncoder[ChainIdResponse] = + new NoParamsMethodDecoder(ChainIdRequest()) with JsonEncoder[ChainIdResponse] { + def encodeJson(t: ChainIdResponse) = encodeAsHex(t.value) + } - implicit val eth_syncing = new NoParamsMethodDecoder(SyncingRequest()) with JsonEncoder[SyncingResponse] { - def encodeJson(t: SyncingResponse): JValue = t.syncStatus match { - case Some(syncStatus) => Extraction.decompose(syncStatus) - case None => false + implicit val eth_protocolVersion + : NoParamsMethodDecoder[ProtocolVersionRequest] with JsonEncoder[ProtocolVersionResponse] = + new NoParamsMethodDecoder(ProtocolVersionRequest()) with JsonEncoder[ProtocolVersionResponse] { + def encodeJson(t: ProtocolVersionResponse): JValue = t.value } - } - implicit val eth_sendTransaction = new JsonMethodCodec[SendTransactionRequest, SendTransactionResponse] { - def decodeJson(params: Option[JArray]): Either[JsonRpcError, SendTransactionRequest] = - params match { - case Some(JArray(JObject(tx) :: _)) => - extractTx(tx.toMap).map(SendTransactionRequest) - case _ => - Left(InvalidParams()) + implicit val eth_syncing: NoParamsMethodDecoder[SyncingRequest] with JsonEncoder[SyncingResponse] = + new NoParamsMethodDecoder(SyncingRequest()) with JsonEncoder[SyncingResponse] { + def encodeJson(t: SyncingResponse): JValue = t.syncStatus match { + case Some(syncStatus) => Extraction.decompose(syncStatus) + case None => false } + } - def encodeJson(t: SendTransactionResponse): JValue = - encodeAsHex(t.txHash) - } - - implicit val eth_call = new JsonMethodDecoder[CallRequest] with JsonEncoder[CallResponse] { - def decodeJson(params: Option[JArray]): Either[JsonRpcError, CallRequest] = - params match { - case Some(JArray((txObj: JObject) :: (blockValue: JValue) :: Nil)) => - for { - blockParam <- extractBlockParam(blockValue) - tx <- extractCall(txObj) - } yield CallRequest(tx, blockParam) - case _ => Left(InvalidParams()) - } + implicit val eth_sendTransaction: JsonMethodCodec[SendTransactionRequest, SendTransactionResponse] = + new JsonMethodCodec[SendTransactionRequest, SendTransactionResponse] { + def decodeJson(params: Option[JArray]): Either[JsonRpcError, SendTransactionRequest] = + params match { + case Some(JArray(JObject(tx) :: _)) => + extractTx(tx.toMap).map(SendTransactionRequest) + case _ => + Left(InvalidParams()) + } + + def encodeJson(t: SendTransactionResponse): JValue = + encodeAsHex(t.txHash) + } - def encodeJson(t: CallResponse): JValue = encodeAsHex(t.returnData) - } + implicit val eth_call: JsonMethodDecoder[CallRequest] with JsonEncoder[CallResponse] = + new JsonMethodDecoder[CallRequest] with JsonEncoder[CallResponse] { + def decodeJson(params: Option[JArray]): Either[JsonRpcError, CallRequest] = + params match { + case Some(JArray((txObj: JObject) :: (blockValue: JValue) :: Nil)) => + for { + blockParam <- extractBlockParam(blockValue) + tx <- extractCall(txObj) + } yield CallRequest(tx, blockParam) + case _ => Left(InvalidParams()) + } + + def encodeJson(t: CallResponse): JValue = encodeAsHex(t.returnData) + } - implicit val eth_estimateGas = new JsonMethodDecoder[CallRequest] with JsonEncoder[EstimateGasResponse] { + implicit val eth_estimateGas: eth_estimateGas = new eth_estimateGas + class eth_estimateGas extends JsonMethodDecoder[CallRequest] with JsonEncoder[EstimateGasResponse] { override def encodeJson(t: EstimateGasResponse): JValue = encodeAsHex(t.gas) override def decodeJson(params: Option[JArray]): Either[JsonRpcError, CallRequest] = @@ -69,7 +82,7 @@ object EthJsonMethodsImplicits extends JsonMethodsImplicits { } - implicit val eth_sign = new JsonMethodDecoder[SignRequest] { + implicit val eth_sign: JsonMethodDecoder[SignRequest] = new JsonMethodDecoder[SignRequest] { override def decodeJson(params: Option[JArray]): Either[JsonRpcError, SignRequest] = params match { case Some(JArray(JString(addr) :: JString(message) :: _)) => @@ -83,13 +96,12 @@ object EthJsonMethodsImplicits extends JsonMethodsImplicits { } def extractCall(obj: JObject): Either[JsonRpcError, CallTx] = { - def toEitherOpt[A, B](opt: Option[Either[A, B]]): Either[A, Option[B]] = { + def toEitherOpt[A, B](opt: Option[Either[A, B]]): Either[A, Option[B]] = opt match { case Some(Right(v)) => Right(Option(v)) - case Some(Left(e)) => Left(e) - case None => Right(None) + case Some(Left(e)) => Left(e) + case None => Right(None) } - } for { from <- toEitherOpt((obj \ "from").extractOpt[String].map(extractBytes)) diff --git a/src/main/scala/io/iohk/ethereum/jsonrpc/EthInfoService.scala b/src/main/scala/io/iohk/ethereum/jsonrpc/EthInfoService.scala index b098c2ebf3..94fc4b85c0 100644 --- a/src/main/scala/io/iohk/ethereum/jsonrpc/EthInfoService.scala +++ b/src/main/scala/io/iohk/ethereum/jsonrpc/EthInfoService.scala @@ -1,30 +1,32 @@ package io.iohk.ethereum.jsonrpc import akka.actor.ActorRef -import akka.util.{ByteString, Timeout} +import akka.util.ByteString +import akka.util.Timeout + import cats.syntax.either._ + +import monix.eval.Task + +import scala.reflect.ClassTag + import io.iohk.ethereum.blockchain.sync.SyncProtocol import io.iohk.ethereum.blockchain.sync.SyncProtocol.Status import io.iohk.ethereum.blockchain.sync.SyncProtocol.Status.Progress +import io.iohk.ethereum.consensus.Consensus import io.iohk.ethereum.crypto._ -import io.iohk.ethereum.domain.{BlockHeader, _} +import io.iohk.ethereum.domain.BlockHeader +import io.iohk.ethereum.domain._ import io.iohk.ethereum.jsonrpc.AkkaTaskOps._ import io.iohk.ethereum.keystore.KeyStore -import io.iohk.ethereum.ledger.{InMemoryWorldStateProxy, StxLedger} +import io.iohk.ethereum.ledger.InMemoryWorldStateProxy +import io.iohk.ethereum.ledger.StxLedger import io.iohk.ethereum.network.p2p.messages.Capability import io.iohk.ethereum.rlp import io.iohk.ethereum.rlp.RLPImplicitConversions._ import io.iohk.ethereum.rlp.RLPImplicits._ import io.iohk.ethereum.rlp.RLPList -import monix.eval.Task - -import java.util.Date -import java.util.concurrent.atomic.AtomicReference -import scala.collection.concurrent.{TrieMap, Map => ConcurrentMap} -import scala.language.existentials -import scala.reflect.ClassTag import io.iohk.ethereum.utils.BlockchainConfig -import io.iohk.ethereum.consensus.Consensus object EthInfoService { case class ChainIdRequest() @@ -90,8 +92,7 @@ class EthInfoService( def chainId(req: ChainIdRequest): ServiceResponse[ChainIdResponse] = Task.now(Right(ChainIdResponse(blockchainConfig.chainId))) - /** - * Implements the eth_syncing method that returns syncing information if the node is syncing. + /** Implements the eth_syncing method that returns syncing information if the node is syncing. * * @return The syncing status if the node is syncing or None if not */ @@ -113,24 +114,23 @@ class EthInfoService( ) ) case Status.NotSyncing => SyncingResponse(None) - case Status.SyncDone => SyncingResponse(None) + case Status.SyncDone => SyncingResponse(None) } .map(_.asRight) - def call(req: CallRequest): ServiceResponse[CallResponse] = { + def call(req: CallRequest): ServiceResponse[CallResponse] = Task { doCall(req)(stxLedger.simulateTransaction).map(r => CallResponse(r.vmReturnData)) } - } def ieleCall(req: IeleCallRequest): ServiceResponse[IeleCallResponse] = { import req.tx val args = tx.arguments.getOrElse(Nil) val dataEither = (tx.function, tx.contractCode) match { - case (Some(function), None) => Right(rlp.encode(RLPList(function, args))) + case (Some(function), None) => Right(rlp.encode(RLPList(function, args))) case (None, Some(contractCode)) => Right(rlp.encode(RLPList(contractCode, args))) - case _ => Left(JsonRpcError.InvalidParams("Iele transaction should contain either functionName or contractCode")) + case _ => Left(JsonRpcError.InvalidParams("Iele transaction should contain either functionName or contractCode")) } dataEither match { @@ -145,11 +145,10 @@ class EthInfoService( } } - def estimateGas(req: CallRequest): ServiceResponse[EstimateGasResponse] = { + def estimateGas(req: CallRequest): ServiceResponse[EstimateGasResponse] = Task { doCall(req)(stxLedger.binarySearchGasEstimation).map(gasUsed => EstimateGasResponse(gasUsed)) } - } private def doCall[A](req: CallRequest)( f: (SignedTransactionWithSender, BlockHeader, Option[InMemoryWorldStateProxy]) => A @@ -162,7 +161,7 @@ class EthInfoService( if (req.tx.gas.isDefined) Right[JsonRpcError, BigInt](req.tx.gas.get) else resolveBlock(BlockParam.Latest).map(r => r.block.header.gasLimit) - private def prepareTransaction(req: CallRequest): Either[JsonRpcError, SignedTransactionWithSender] = { + private def prepareTransaction(req: CallRequest): Either[JsonRpcError, SignedTransactionWithSender] = getGasLimit(req).map { gasLimit => val fromAddress = req.tx.from .map(Address.apply) // `from` param, if specified @@ -180,6 +179,5 @@ class EthInfoService( val fakeSignature = ECDSASignature(0, 0, 0.toByte) SignedTransactionWithSender(tx, fakeSignature, fromAddress) } - } } diff --git a/src/main/scala/io/iohk/ethereum/jsonrpc/EthMiningJsonMethodsImplicits.scala b/src/main/scala/io/iohk/ethereum/jsonrpc/EthMiningJsonMethodsImplicits.scala index a8cbbd1537..3dd1ce0be2 100644 --- a/src/main/scala/io/iohk/ethereum/jsonrpc/EthMiningJsonMethodsImplicits.scala +++ b/src/main/scala/io/iohk/ethereum/jsonrpc/EthMiningJsonMethodsImplicits.scala @@ -1,66 +1,75 @@ package io.iohk.ethereum.jsonrpc +import org.json4s.JsonAST +import org.json4s.JsonAST.JArray +import org.json4s.JsonAST.JBool +import org.json4s.JsonAST.JString +import org.json4s.JsonAST.JValue + import io.iohk.ethereum.jsonrpc.EthMiningService._ import io.iohk.ethereum.jsonrpc.JsonRpcError.InvalidParams +import io.iohk.ethereum.jsonrpc.serialization.JsonEncoder +import io.iohk.ethereum.jsonrpc.serialization.JsonMethodDecoder import io.iohk.ethereum.jsonrpc.serialization.JsonMethodDecoder.NoParamsMethodDecoder -import io.iohk.ethereum.jsonrpc.serialization.{JsonEncoder, JsonMethodDecoder} -import org.json4s.JsonAST -import org.json4s.JsonAST.{JArray, JBool, JString, JValue} object EthMiningJsonMethodsImplicits extends JsonMethodsImplicits { - implicit val eth_mining = new NoParamsMethodDecoder(GetMiningRequest()) with JsonEncoder[GetMiningResponse] { - override def encodeJson(t: GetMiningResponse): JValue = JBool(t.isMining) - } - - implicit val eth_getWork = new NoParamsMethodDecoder(GetWorkRequest()) with JsonEncoder[GetWorkResponse] { - override def encodeJson(t: GetWorkResponse): JsonAST.JValue = { - val powHeaderHash = encodeAsHex(t.powHeaderHash) - val dagSeed = encodeAsHex(t.dagSeed) - val target = encodeAsHex(t.target) - JArray(List(powHeaderHash, dagSeed, target)) + implicit val eth_mining: NoParamsMethodDecoder[GetMiningRequest] with JsonEncoder[GetMiningResponse] = + new NoParamsMethodDecoder(GetMiningRequest()) with JsonEncoder[GetMiningResponse] { + override def encodeJson(t: GetMiningResponse): JValue = JBool(t.isMining) } - } - implicit val eth_submitHashrate = new JsonMethodDecoder[SubmitHashRateRequest] - with JsonEncoder[SubmitHashRateResponse] { - override def decodeJson(params: Option[JsonAST.JArray]): Either[JsonRpcError, SubmitHashRateRequest] = - params match { - case Some(JArray(hashRate :: JString(id) :: Nil)) => - val result: Either[JsonRpcError, SubmitHashRateRequest] = for { - rate <- extractQuantity(hashRate) - miner <- extractHash(id) - } yield SubmitHashRateRequest(rate, miner) - result - case _ => - Left(InvalidParams()) + implicit val eth_getWork: NoParamsMethodDecoder[GetWorkRequest] with JsonEncoder[GetWorkResponse] = + new NoParamsMethodDecoder(GetWorkRequest()) with JsonEncoder[GetWorkResponse] { + override def encodeJson(t: GetWorkResponse): JsonAST.JValue = { + val powHeaderHash = encodeAsHex(t.powHeaderHash) + val dagSeed = encodeAsHex(t.dagSeed) + val target = encodeAsHex(t.target) + JArray(List(powHeaderHash, dagSeed, target)) } + } - override def encodeJson(t: SubmitHashRateResponse): JValue = JBool(t.success) - } + implicit val eth_submitHashrate: JsonMethodDecoder[SubmitHashRateRequest] with JsonEncoder[SubmitHashRateResponse] = + new JsonMethodDecoder[SubmitHashRateRequest] with JsonEncoder[SubmitHashRateResponse] { + override def decodeJson(params: Option[JsonAST.JArray]): Either[JsonRpcError, SubmitHashRateRequest] = + params match { + case Some(JArray(hashRate :: JString(id) :: Nil)) => + val result: Either[JsonRpcError, SubmitHashRateRequest] = for { + rate <- extractQuantity(hashRate) + miner <- extractHash(id) + } yield SubmitHashRateRequest(rate, miner) + result + case _ => + Left(InvalidParams()) + } - implicit val eth_hashrate = new NoParamsMethodDecoder(GetHashRateRequest()) with JsonEncoder[GetHashRateResponse] { - override def encodeJson(t: GetHashRateResponse): JsonAST.JValue = encodeAsHex(t.hashRate) - } + override def encodeJson(t: SubmitHashRateResponse): JValue = JBool(t.success) + } - implicit val eth_coinbase = new NoParamsMethodDecoder(GetCoinbaseRequest()) with JsonEncoder[GetCoinbaseResponse] { - override def encodeJson(t: GetCoinbaseResponse): JsonAST.JValue = { - encodeAsHex(t.address.bytes) + implicit val eth_hashrate: NoParamsMethodDecoder[GetHashRateRequest] with JsonEncoder[GetHashRateResponse] = + new NoParamsMethodDecoder(GetHashRateRequest()) with JsonEncoder[GetHashRateResponse] { + override def encodeJson(t: GetHashRateResponse): JsonAST.JValue = encodeAsHex(t.hashRate) } - } - implicit val eth_submitWork = new JsonMethodDecoder[SubmitWorkRequest] with JsonEncoder[SubmitWorkResponse] { - override def decodeJson(params: Option[JsonAST.JArray]): Either[JsonRpcError, SubmitWorkRequest] = params match { - case Some(JArray(JString(nonce) :: JString(powHeaderHash) :: JString(mixHash) :: Nil)) => - for { - n <- extractBytes(nonce) - p <- extractBytes(powHeaderHash) - m <- extractBytes(mixHash) - } yield SubmitWorkRequest(n, p, m) - case _ => - Left(InvalidParams()) + implicit val eth_coinbase: NoParamsMethodDecoder[GetCoinbaseRequest] with JsonEncoder[GetCoinbaseResponse] = + new NoParamsMethodDecoder(GetCoinbaseRequest()) with JsonEncoder[GetCoinbaseResponse] { + override def encodeJson(t: GetCoinbaseResponse): JsonAST.JValue = + encodeAsHex(t.address.bytes) } - override def encodeJson(t: SubmitWorkResponse): JValue = JBool(t.success) - } + implicit val eth_submitWork: JsonMethodDecoder[SubmitWorkRequest] with JsonEncoder[SubmitWorkResponse] = + new JsonMethodDecoder[SubmitWorkRequest] with JsonEncoder[SubmitWorkResponse] { + override def decodeJson(params: Option[JsonAST.JArray]): Either[JsonRpcError, SubmitWorkRequest] = params match { + case Some(JArray(JString(nonce) :: JString(powHeaderHash) :: JString(mixHash) :: Nil)) => + for { + n <- extractBytes(nonce) + p <- extractBytes(powHeaderHash) + m <- extractBytes(mixHash) + } yield SubmitWorkRequest(n, p, m) + case _ => + Left(InvalidParams()) + } + + override def encodeJson(t: SubmitWorkResponse): JValue = JBool(t.success) + } } diff --git a/src/main/scala/io/iohk/ethereum/jsonrpc/EthMiningService.scala b/src/main/scala/io/iohk/ethereum/jsonrpc/EthMiningService.scala index 73220f8a70..7c48143c6e 100644 --- a/src/main/scala/io/iohk/ethereum/jsonrpc/EthMiningService.scala +++ b/src/main/scala/io/iohk/ethereum/jsonrpc/EthMiningService.scala @@ -1,27 +1,33 @@ package io.iohk.ethereum.jsonrpc +import java.time.Duration +import java.util.Date +import java.util.concurrent.atomic.AtomicReference + import akka.actor.ActorRef -import akka.util.{ByteString, Timeout} +import akka.util.ByteString +import akka.util.Timeout + +import monix.eval.Task + +import scala.collection.concurrent.TrieMap +import scala.collection.concurrent.{Map => ConcurrentMap} +import scala.concurrent.duration.FiniteDuration + import io.iohk.ethereum.blockchain.sync.SyncProtocol +import io.iohk.ethereum.consensus.Consensus import io.iohk.ethereum.consensus.ConsensusConfig import io.iohk.ethereum.consensus.blocks.PendingBlockAndState import io.iohk.ethereum.consensus.pow.EthashUtils import io.iohk.ethereum.crypto.kec256 -import io.iohk.ethereum.domain.{Address, BlockHeader, Blockchain} +import io.iohk.ethereum.domain.Address +import io.iohk.ethereum.domain.BlockHeader +import io.iohk.ethereum.domain.Blockchain import io.iohk.ethereum.jsonrpc.AkkaTaskOps._ import io.iohk.ethereum.jsonrpc.server.controllers.JsonRpcBaseController.JsonRpcConfig import io.iohk.ethereum.ommers.OmmersPool -import monix.eval.Task - -import java.time.Duration -import java.util.Date -import java.util.concurrent.atomic.AtomicReference -import scala.collection.concurrent.{TrieMap, Map => ConcurrentMap} -import scala.concurrent.duration.FiniteDuration -import scala.language.existentials import io.iohk.ethereum.transactions.TransactionPicker import io.iohk.ethereum.utils.BlockchainConfig -import io.iohk.ethereum.consensus.Consensus object EthMiningService { @@ -65,19 +71,17 @@ class EthMiningService( def getMining(req: GetMiningRequest): ServiceResponse[GetMiningResponse] = ifEthash(req) { _ => - val isMining = lastActive - .updateAndGet((e: Option[Date]) => { - e.filter { time => - Duration.between(time.toInstant, (new Date).toInstant).toMillis < jsonRpcConfig.minerActiveTimeout.toMillis - } - }) - .isDefined + val isMining = lastActive.updateAndGet { (e: Option[Date]) => + e.filter { time => + Duration.between(time.toInstant, (new Date).toInstant).toMillis < jsonRpcConfig.minerActiveTimeout.toMillis + } + }.isDefined GetMiningResponse(isMining) } def getWork(req: GetWorkRequest): ServiceResponse[GetWorkResponse] = - consensus.ifEthash(ethash => { + consensus.ifEthash { ethash => reportActive() blockchain.getBestBlock() match { case Some(block) => @@ -103,10 +107,10 @@ class EthMiningService( log.error("Getting current best block failed") Task.now(Left(JsonRpcError.InternalError)) } - })(Task.now(Left(JsonRpcError.ConsensusIsNotEthash))) + }(Task.now(Left(JsonRpcError.ConsensusIsNotEthash))) def submitWork(req: SubmitWorkRequest): ServiceResponse[SubmitWorkResponse] = - consensus.ifEthash[ServiceResponse[SubmitWorkResponse]](ethash => { + consensus.ifEthash[ServiceResponse[SubmitWorkResponse]] { ethash => reportActive() Task { ethash.blockGenerator.getPrepared(req.powHeaderHash) match { @@ -120,7 +124,7 @@ class EthMiningService( Right(SubmitWorkResponse(false)) } } - })(Task.now(Left(JsonRpcError.ConsensusIsNotEthash))) + }(Task.now(Left(JsonRpcError.ConsensusIsNotEthash))) def getCoinbase(req: GetCoinbaseRequest): ServiceResponse[GetCoinbaseResponse] = Task.now(Right(GetCoinbaseResponse(consensusConfig.coinbase))) @@ -142,11 +146,10 @@ class EthMiningService( } // NOTE This is called from places that guarantee we are running Ethash consensus. - private def removeObsoleteHashrates(now: Date): Unit = { + private def removeObsoleteHashrates(now: Date): Unit = hashRate.filterInPlace { case (_, (_, reported)) => Duration.between(reported.toInstant, now.toInstant).toMillis < jsonRpcConfig.minerActiveTimeout.toMillis } - } private def reportActive(): Option[Date] = { val now = new Date() @@ -154,7 +157,7 @@ class EthMiningService( } private def getOmmersFromPool(parentBlockHash: ByteString): Task[OmmersPool.Ommers] = - consensus.ifEthash(ethash => { + consensus.ifEthash { ethash => val miningConfig = ethash.config.specific implicit val timeout: Timeout = Timeout(miningConfig.ommerPoolQueryTimeout) @@ -164,11 +167,10 @@ class EthMiningService( log.error("failed to get ommer, mining block with empty ommers list", ex) OmmersPool.Ommers(Nil) } - })(Task.now(OmmersPool.Ommers(Nil))) // NOTE If not Ethash consensus, ommers do not make sense, so => Nil + }(Task.now(OmmersPool.Ommers(Nil))) // NOTE If not Ethash consensus, ommers do not make sense, so => Nil - private[jsonrpc] def ifEthash[Req, Res](req: Req)(f: Req => Res): ServiceResponse[Res] = { + private[jsonrpc] def ifEthash[Req, Res](req: Req)(f: Req => Res): ServiceResponse[Res] = consensus.ifEthash[ServiceResponse[Res]](_ => Task.now(Right(f(req))))( Task.now(Left(JsonRpcError.ConsensusIsNotEthash)) ) - } } diff --git a/src/main/scala/io/iohk/ethereum/jsonrpc/EthProofJsonMethodsImplicits.scala b/src/main/scala/io/iohk/ethereum/jsonrpc/EthProofJsonMethodsImplicits.scala index 6fa31dcf9c..a19080b200 100644 --- a/src/main/scala/io/iohk/ethereum/jsonrpc/EthProofJsonMethodsImplicits.scala +++ b/src/main/scala/io/iohk/ethereum/jsonrpc/EthProofJsonMethodsImplicits.scala @@ -1,10 +1,16 @@ package io.iohk.ethereum.jsonrpc +import org.json4s.JsonAST.JArray +import org.json4s.JsonAST.JString +import org.json4s.JsonAST.JValue +import org.json4s.JsonAST._ + import io.iohk.ethereum.jsonrpc.JsonRpcError.InvalidParams -import io.iohk.ethereum.jsonrpc.ProofService.{GetProofRequest, GetProofResponse, StorageProofKey} +import io.iohk.ethereum.jsonrpc.ProofService.GetProofRequest +import io.iohk.ethereum.jsonrpc.ProofService.GetProofResponse +import io.iohk.ethereum.jsonrpc.ProofService.StorageProofKey import io.iohk.ethereum.jsonrpc.serialization.JsonEncoder import io.iohk.ethereum.jsonrpc.serialization.JsonMethodDecoder -import org.json4s.JsonAST.{JArray, JString, JValue, _} object EthProofJsonMethodsImplicits extends JsonMethodsImplicits { def extractStorageKeys(input: JValue): Either[JsonRpcError, Seq[StorageProofKey]] = { @@ -34,9 +40,9 @@ object EthProofJsonMethodsImplicits extends JsonMethodsImplicits { case _ => Left(InvalidParams()) } - override def encodeJson(t: GetProofResponse): JValue = { + override def encodeJson(t: GetProofResponse): JValue = JObject( - "accountProof" -> JArray(t.proofAccount.accountProof.toList.map { ap => encodeAsHex(ap) }), + "accountProof" -> JArray(t.proofAccount.accountProof.toList.map(ap => encodeAsHex(ap))), "balance" -> encodeAsHex(t.proofAccount.balance), "codeHash" -> encodeAsHex(t.proofAccount.codeHash), "nonce" -> encodeAsHex(t.proofAccount.nonce), @@ -44,12 +50,11 @@ object EthProofJsonMethodsImplicits extends JsonMethodsImplicits { "storageProof" -> JArray(t.proofAccount.storageProof.toList.map { sp => JObject( "key" -> encodeAsHex(sp.key.v), - "proof" -> JArray(sp.proof.toList.map { p => encodeAsHex(p) }), + "proof" -> JArray(sp.proof.toList.map(p => encodeAsHex(p))), "value" -> encodeAsHex(sp.value) ) }) ) - } } } diff --git a/src/main/scala/io/iohk/ethereum/jsonrpc/EthProofService.scala b/src/main/scala/io/iohk/ethereum/jsonrpc/EthProofService.scala index a531df821e..e6b3aaf15f 100644 --- a/src/main/scala/io/iohk/ethereum/jsonrpc/EthProofService.scala +++ b/src/main/scala/io/iohk/ethereum/jsonrpc/EthProofService.scala @@ -1,24 +1,30 @@ package io.iohk.ethereum.jsonrpc import akka.util.ByteString + import cats.implicits._ + +import monix.eval.Task + import io.iohk.ethereum.consensus.blocks.BlockGenerator -import io.iohk.ethereum.domain.{Account, Address, Block, Blockchain, BlockchainReader, UInt256} +import io.iohk.ethereum.domain.Account +import io.iohk.ethereum.domain.Address +import io.iohk.ethereum.domain.Block +import io.iohk.ethereum.domain.Blockchain +import io.iohk.ethereum.domain.BlockchainReader +import io.iohk.ethereum.domain.UInt256 +import io.iohk.ethereum.jsonrpc.ProofService.GetProofRequest +import io.iohk.ethereum.jsonrpc.ProofService.GetProofResponse +import io.iohk.ethereum.jsonrpc.ProofService.ProofAccount +import io.iohk.ethereum.jsonrpc.ProofService.StorageProof import io.iohk.ethereum.jsonrpc.ProofService.StorageProof.asRlpSerializedNode -import io.iohk.ethereum.jsonrpc.ProofService.{ - GetProofRequest, - GetProofResponse, - ProofAccount, - StorageProof, - StorageProofKey -} -import io.iohk.ethereum.mpt.{MptNode, MptTraversals} -import monix.eval.Task +import io.iohk.ethereum.jsonrpc.ProofService.StorageProofKey +import io.iohk.ethereum.mpt.MptNode +import io.iohk.ethereum.mpt.MptTraversals object ProofService { - /** - * Request to eth get proof + /** Request to eth get proof * * @param address the address of the account or contract * @param storageKeys array of storage keys; @@ -45,15 +51,14 @@ object ProofService { case (None, Some(proof)) => EmptyStorageValue(StorageProofKey(position), proof.map(asRlpSerializedNode)) case (Some(value), None) => EmptyStorageProof(StorageProofKey(position), value) - case (None, None) => EmptyStorageValueProof(StorageProofKey(position)) + case (None, None) => EmptyStorageValueProof(StorageProofKey(position)) } def asRlpSerializedNode(node: MptNode): ByteString = ByteString(MptTraversals.encodeNode(node)) } - /** - * Object proving a relationship of a storage value to an account's storageHash + /** Object proving a relationship of a storage value to an account's storageHash * * @param key storage proof key * @param value the value of the storage slot in its account tree @@ -74,8 +79,7 @@ object ProofService { /** The key used to get the storage slot in its account tree */ case class StorageProofKey(v: BigInt) extends AnyVal - /** - * The merkle proofs of the specified account connecting them to the blockhash of the block specified. + /** The merkle proofs of the specified account connecting them to the blockhash of the block specified. * * Proof of account consists of: * - account object: nonce, balance, storageHash, codeHash @@ -128,14 +132,12 @@ object ProofService { trait ProofService { - /** - * Returns the account- and storage-values of the specified account including the Merkle-proof. + /** Returns the account- and storage-values of the specified account including the Merkle-proof. */ def getProof(req: GetProofRequest): ServiceResponse[GetProofResponse] } -/** - * Spec: [EIP-1186](https://eips.ethereum.org/EIPS/eip-1186) +/** Spec: [EIP-1186](https://eips.ethereum.org/EIPS/eip-1186) * besu: https://github.com/PegaSysEng/pantheon/pull/1824/files * parity: https://github.com/openethereum/parity-ethereum/pull/9001 * geth: https://github.com/ethereum/go-ethereum/pull/17737 @@ -147,13 +149,11 @@ class EthProofService( ethCompatibleStorage: Boolean ) extends ProofService { - def getProof(req: GetProofRequest): ServiceResponse[GetProofResponse] = { + def getProof(req: GetProofRequest): ServiceResponse[GetProofResponse] = getProofAccount(req.address, req.storageKeys, req.blockNumber) .map(_.map(GetProofResponse.apply)) - } - /** - * Get account and storage values for account including Merkle Proof. + /** Get account and storage values for account including Merkle Proof. * * @param address address of the account * @param storageKeys storage keys which should be proofed and included @@ -182,7 +182,7 @@ class EthProofService( def getStorageProof( account: Account, storageKeys: Seq[StorageProofKey] - ): Seq[StorageProof] = { + ): Seq[StorageProof] = storageKeys.toList .map { storageKey => blockchain @@ -192,7 +192,6 @@ class EthProofService( ethCompatibleStorage = ethCompatibleStorage ) } - } private def noAccount(address: Address, blockNumber: BigInt): JsonRpcError = JsonRpcError.LogicError(s"No account found for Address [${address.toString}] blockNumber [${blockNumber.toString}]") @@ -216,8 +215,8 @@ class EthProofService( blockParam match { case BlockParam.WithNumber(blockNumber) => getBlock(blockNumber).map(ResolvedBlock(_, pendingState = None)) - case BlockParam.Earliest => getBlock(0).map(ResolvedBlock(_, pendingState = None)) - case BlockParam.Latest => getLatestBlock().map(ResolvedBlock(_, pendingState = None)) + case BlockParam.Earliest => getBlock(0).map(ResolvedBlock(_, pendingState = None)) + case BlockParam.Latest => getLatestBlock().map(ResolvedBlock(_, pendingState = None)) case BlockParam.Pending => blockGenerator.getPendingBlockAndState .map(pb => ResolvedBlock(pb.pendingBlock.block, pendingState = Some(pb.worldState))) diff --git a/src/main/scala/io/iohk/ethereum/jsonrpc/EthTxJsonMethodsImplicits.scala b/src/main/scala/io/iohk/ethereum/jsonrpc/EthTxJsonMethodsImplicits.scala index e6d4837fc2..b422038d16 100644 --- a/src/main/scala/io/iohk/ethereum/jsonrpc/EthTxJsonMethodsImplicits.scala +++ b/src/main/scala/io/iohk/ethereum/jsonrpc/EthTxJsonMethodsImplicits.scala @@ -1,32 +1,36 @@ package io.iohk.ethereum.jsonrpc +import org.json4s.Extraction +import org.json4s.JsonAST._ +import org.json4s.JsonDSL._ + import io.iohk.ethereum.jsonrpc.EthTxService._ import io.iohk.ethereum.jsonrpc.JsonRpcError.InvalidParams -import io.iohk.ethereum.jsonrpc.serialization.JsonMethodDecoder.NoParamsMethodDecoder import io.iohk.ethereum.jsonrpc.serialization.JsonEncoder import io.iohk.ethereum.jsonrpc.serialization.JsonEncoder.OptionToNull._ import io.iohk.ethereum.jsonrpc.serialization.JsonMethodDecoder -import org.json4s.JsonAST._ -import org.json4s.JsonDSL._ -import org.json4s.Extraction +import io.iohk.ethereum.jsonrpc.serialization.JsonMethodDecoder.NoParamsMethodDecoder object EthTxJsonMethodsImplicits extends JsonMethodsImplicits { implicit val transactionResponseJsonEncoder: JsonEncoder[TransactionResponse] = Extraction.decompose(_) - implicit val eth_gasPrice = new NoParamsMethodDecoder(GetGasPriceRequest()) with JsonEncoder[GetGasPriceResponse] { - override def encodeJson(t: GetGasPriceResponse): JValue = encodeAsHex(t.price) - } + implicit val eth_gasPrice: NoParamsMethodDecoder[GetGasPriceRequest] with JsonEncoder[GetGasPriceResponse] = + new NoParamsMethodDecoder(GetGasPriceRequest()) with JsonEncoder[GetGasPriceResponse] { + override def encodeJson(t: GetGasPriceResponse): JValue = encodeAsHex(t.price) + } - implicit val eth_pendingTransactions = new NoParamsMethodDecoder(EthPendingTransactionsRequest()) - with JsonEncoder[EthPendingTransactionsResponse] { + implicit val eth_pendingTransactions + : NoParamsMethodDecoder[EthPendingTransactionsRequest] with JsonEncoder[EthPendingTransactionsResponse] = + new NoParamsMethodDecoder(EthPendingTransactionsRequest()) with JsonEncoder[EthPendingTransactionsResponse] { - override def encodeJson(t: EthPendingTransactionsResponse): JValue = - JArray(t.pendingTransactions.toList.map { pendingTx => - encodeAsHex(pendingTx.stx.tx.hash) - }) - } + override def encodeJson(t: EthPendingTransactionsResponse): JValue = + JArray(t.pendingTransactions.toList.map { pendingTx => + encodeAsHex(pendingTx.stx.tx.hash) + }) + } - implicit val eth_getTransactionByHash = + implicit val eth_getTransactionByHash + : JsonMethodDecoder[GetTransactionByHashRequest] with JsonEncoder[GetTransactionByHashResponse] = new JsonMethodDecoder[GetTransactionByHashRequest] with JsonEncoder[GetTransactionByHashResponse] { override def decodeJson(params: Option[JArray]): Either[JsonRpcError, GetTransactionByHashRequest] = params match { @@ -41,7 +45,8 @@ object EthTxJsonMethodsImplicits extends JsonMethodsImplicits { JsonEncoder.encode(t.txResponse) } - implicit val eth_getTransactionReceipt = + implicit val eth_getTransactionReceipt + : JsonMethodDecoder[GetTransactionReceiptRequest] with JsonEncoder[GetTransactionReceiptResponse] = new JsonMethodDecoder[GetTransactionReceiptRequest] with JsonEncoder[GetTransactionReceiptResponse] { override def decodeJson(params: Option[JArray]): Either[JsonRpcError, GetTransactionReceiptRequest] = params match { @@ -56,13 +61,15 @@ object EthTxJsonMethodsImplicits extends JsonMethodsImplicits { Extraction.decompose(t.txResponse) } - implicit val GetTransactionByBlockHashAndIndexResponseEncoder = + implicit val GetTransactionByBlockHashAndIndexResponseEncoder + : JsonEncoder[GetTransactionByBlockHashAndIndexResponse] = new JsonEncoder[GetTransactionByBlockHashAndIndexResponse] { override def encodeJson(t: GetTransactionByBlockHashAndIndexResponse): JValue = JsonEncoder.encode(t.transactionResponse) } - implicit val GetTransactionByBlockHashAndIndexRequestDecoder = + implicit val GetTransactionByBlockHashAndIndexRequestDecoder + : JsonMethodDecoder[GetTransactionByBlockHashAndIndexRequest] = new JsonMethodDecoder[GetTransactionByBlockHashAndIndexRequest] { override def decodeJson(params: Option[JArray]): Either[JsonRpcError, GetTransactionByBlockHashAndIndexRequest] = params match { @@ -75,13 +82,15 @@ object EthTxJsonMethodsImplicits extends JsonMethodsImplicits { } } - implicit val GetTransactionByBlockNumberAndIndexResponseEncoder = + implicit val GetTransactionByBlockNumberAndIndexResponseEncoder + : JsonEncoder[GetTransactionByBlockNumberAndIndexResponse] = new JsonEncoder[GetTransactionByBlockNumberAndIndexResponse] { override def encodeJson(t: GetTransactionByBlockNumberAndIndexResponse): JValue = JsonEncoder.encode(t.transactionResponse) } - implicit val GetTransactionByBlockNumberAndIndexRequestDecoder = + implicit val GetTransactionByBlockNumberAndIndexRequestDecoder + : JsonMethodDecoder[GetTransactionByBlockNumberAndIndexRequest] = new JsonMethodDecoder[GetTransactionByBlockNumberAndIndexRequest] { override def decodeJson( params: Option[JArray] @@ -96,24 +105,25 @@ object EthTxJsonMethodsImplicits extends JsonMethodsImplicits { } } - implicit val eth_sendRawTransaction = new JsonMethodDecoder[SendRawTransactionRequest] - with JsonEncoder[SendRawTransactionResponse] { - def decodeJson(params: Option[JArray]): Either[JsonRpcError, SendRawTransactionRequest] = - params match { - case Some(JArray(JString(dataStr) :: Nil)) => - for { - data <- extractBytes(dataStr) - } yield SendRawTransactionRequest(data) - case _ => Left(InvalidParams()) - } + implicit val eth_sendRawTransaction + : JsonMethodDecoder[SendRawTransactionRequest] with JsonEncoder[SendRawTransactionResponse] = + new JsonMethodDecoder[SendRawTransactionRequest] with JsonEncoder[SendRawTransactionResponse] { + def decodeJson(params: Option[JArray]): Either[JsonRpcError, SendRawTransactionRequest] = + params match { + case Some(JArray(JString(dataStr) :: Nil)) => + for { + data <- extractBytes(dataStr) + } yield SendRawTransactionRequest(data) + case _ => Left(InvalidParams()) + } - def encodeJson(t: SendRawTransactionResponse): JValue = encodeAsHex(t.transactionHash) - } + def encodeJson(t: SendRawTransactionResponse): JValue = encodeAsHex(t.transactionHash) + } implicit val RawTransactionResponseJsonEncoder: JsonEncoder[RawTransactionResponse] = new JsonEncoder[RawTransactionResponse] { override def encodeJson(t: RawTransactionResponse): JValue = - t.transactionResponse.map(RawTransactionCodec.asRawTransaction _ andThen encodeAsHex) + t.transactionResponse.map((RawTransactionCodec.asRawTransaction _).andThen(encodeAsHex)) } } diff --git a/src/main/scala/io/iohk/ethereum/jsonrpc/EthTxService.scala b/src/main/scala/io/iohk/ethereum/jsonrpc/EthTxService.scala index 30c0924c6b..a707a60a13 100644 --- a/src/main/scala/io/iohk/ethereum/jsonrpc/EthTxService.scala +++ b/src/main/scala/io/iohk/ethereum/jsonrpc/EthTxService.scala @@ -1,21 +1,26 @@ package io.iohk.ethereum.jsonrpc +import akka.actor.ActorRef import akka.util.ByteString -import io.iohk.ethereum.transactions.PendingTransactionsManager.PendingTransaction + import monix.eval.Task -import io.iohk.ethereum.domain.{Block, Blockchain, BlockchainReader, Receipt, SignedTransaction} -import io.iohk.ethereum.db.storage.TransactionMappingStorage.TransactionLocation -import io.iohk.ethereum.transactions.PendingTransactionsManager -import io.iohk.ethereum.transactions.TransactionPicker -import io.iohk.ethereum.db.storage.TransactionMappingStorage -import scala.util.Try -import scala.util.Success +import scala.concurrent.duration.FiniteDuration import scala.util.Failure -import akka.actor.ActorRef +import scala.util.Success +import scala.util.Try -import scala.concurrent.duration.FiniteDuration import io.iohk.ethereum.consensus.Consensus +import io.iohk.ethereum.db.storage.TransactionMappingStorage +import io.iohk.ethereum.db.storage.TransactionMappingStorage.TransactionLocation +import io.iohk.ethereum.domain.Block +import io.iohk.ethereum.domain.Blockchain +import io.iohk.ethereum.domain.BlockchainReader +import io.iohk.ethereum.domain.Receipt +import io.iohk.ethereum.domain.SignedTransaction +import io.iohk.ethereum.transactions.PendingTransactionsManager +import io.iohk.ethereum.transactions.PendingTransactionsManager.PendingTransaction +import io.iohk.ethereum.transactions.TransactionPicker object EthTxService { case class GetTransactionByHashRequest(txHash: ByteString) //rename to match request @@ -46,20 +51,17 @@ class EthTxService( with ResolveBlock { import EthTxService._ - /** - * Implements the eth_getRawTransactionByHash - fetch raw transaction data of a transaction with the given hash. + /** Implements the eth_getRawTransactionByHash - fetch raw transaction data of a transaction with the given hash. * * The tx requested will be fetched from the pending tx pool or from the already executed txs (depending on the tx state) * * @param req with the tx requested (by it's hash) * @return the raw transaction hask or None if the client doesn't have the tx */ - def getRawTransactionByHash(req: GetTransactionByHashRequest): ServiceResponse[RawTransactionResponse] = { + def getRawTransactionByHash(req: GetTransactionByHashRequest): ServiceResponse[RawTransactionResponse] = getTransactionDataByHash(req.txHash).map(asRawTransactionResponse) - } - /** - * eth_getRawTransactionByBlockHashAndIndex returns raw transaction data of a transaction with the block hash and index of which it was mined + /** eth_getRawTransactionByBlockHashAndIndex returns raw transaction data of a transaction with the block hash and index of which it was mined * * @return the tx requested or None if the client doesn't have the block or if there's no tx in the that index */ @@ -72,8 +74,7 @@ class EthTxService( private def asRawTransactionResponse(txResponse: Option[TransactionData]): Right[Nothing, RawTransactionResponse] = Right(RawTransactionResponse(txResponse.map(_.stx))) - /** - * Implements the eth_getTransactionByHash method that fetches a requested tx. + /** Implements the eth_getTransactionByHash method that fetches a requested tx. * The tx requested will be fetched from the pending tx pool or from the already executed txs (depending on the tx state) * * @param req with the tx requested (by it's hash) @@ -130,8 +131,7 @@ class EthTxService( Right(GetTransactionReceiptResponse(result)) } - /** - * eth_getTransactionByBlockHashAndIndex that returns information about a transaction by block hash and + /** eth_getTransactionByBlockHashAndIndex that returns information about a transaction by block hash and * transaction index position. * * @return the tx requested or None if the client doesn't have the block or if there's no tx in the that index @@ -185,8 +185,7 @@ class EthTxService( } } - /** - * eth_getTransactionByBlockNumberAndIndex Returns the information about a transaction with + /** eth_getTransactionByBlockNumberAndIndex Returns the information about a transaction with * the block number and index of which it was mined. * * @param req block number and index @@ -200,8 +199,7 @@ class EthTxService( .map(GetTransactionByBlockNumberAndIndexResponse) } - /** - * eth_getRawTransactionByBlockNumberAndIndex Returns raw transaction data of a transaction + /** eth_getRawTransactionByBlockNumberAndIndex Returns raw transaction data of a transaction * with the block number and index of which it was mined. * * @param req block number and ordering in which a transaction is mined within its block @@ -215,7 +213,7 @@ class EthTxService( .map(RawTransactionResponse) } - private def getTransactionDataByBlockNumberAndIndex(block: BlockParam, transactionIndex: BigInt) = { + private def getTransactionDataByBlockNumberAndIndex(block: BlockParam, transactionIndex: BigInt) = resolveBlock(block) .map { blockWithTx => val blockTxs = blockWithTx.block.body.transactionList @@ -231,10 +229,8 @@ class EthTxService( } .left .flatMap(_ => Right(None)) - } - /** - * Returns the transactions that are pending in the transaction pool and have a from address that is one of the accounts this node manages. + /** Returns the transactions that are pending in the transaction pool and have a from address that is one of the accounts this node manages. * * @param req request * @return pending transactions diff --git a/src/main/scala/io/iohk/ethereum/jsonrpc/EthUserJsonMethodsImplicits.scala b/src/main/scala/io/iohk/ethereum/jsonrpc/EthUserJsonMethodsImplicits.scala index 79393d6971..4a5f640332 100644 --- a/src/main/scala/io/iohk/ethereum/jsonrpc/EthUserJsonMethodsImplicits.scala +++ b/src/main/scala/io/iohk/ethereum/jsonrpc/EthUserJsonMethodsImplicits.scala @@ -1,88 +1,89 @@ package io.iohk.ethereum.jsonrpc +import org.json4s.JsonAST._ + import io.iohk.ethereum.jsonrpc.EthUserService._ import io.iohk.ethereum.jsonrpc.JsonRpcError.InvalidParams -import io.iohk.ethereum.jsonrpc.serialization.JsonMethodDecoder.NoParamsMethodDecoder import io.iohk.ethereum.jsonrpc.serialization.JsonEncoder -import io.iohk.ethereum.jsonrpc.serialization.JsonEncoder.OptionToNull._ import io.iohk.ethereum.jsonrpc.serialization.JsonMethodDecoder -import org.json4s.JsonAST._ -import org.json4s.JsonDSL._ -import org.json4s.Extraction object EthUserJsonMethodsImplicits extends JsonMethodsImplicits { - implicit val eth_getCode = new JsonMethodDecoder[GetCodeRequest] with JsonEncoder[GetCodeResponse] { - def decodeJson(params: Option[JArray]): Either[JsonRpcError, GetCodeRequest] = - params match { - case Some(JArray((address: JString) :: (blockValue: JValue) :: Nil)) => - for { - addr <- extractAddress(address) - block <- extractBlockParam(blockValue) - } yield GetCodeRequest(addr, block) - case _ => Left(InvalidParams()) - } + implicit val eth_getCode: JsonMethodDecoder[GetCodeRequest] with JsonEncoder[GetCodeResponse] = + new JsonMethodDecoder[GetCodeRequest] with JsonEncoder[GetCodeResponse] { + def decodeJson(params: Option[JArray]): Either[JsonRpcError, GetCodeRequest] = + params match { + case Some(JArray((address: JString) :: (blockValue: JValue) :: Nil)) => + for { + addr <- extractAddress(address) + block <- extractBlockParam(blockValue) + } yield GetCodeRequest(addr, block) + case _ => Left(InvalidParams()) + } - def encodeJson(t: GetCodeResponse): JValue = encodeAsHex(t.result) - } + def encodeJson(t: GetCodeResponse): JValue = encodeAsHex(t.result) + } - implicit val eth_getBalance = new JsonMethodDecoder[GetBalanceRequest] with JsonEncoder[GetBalanceResponse] { - def decodeJson(params: Option[JArray]): Either[JsonRpcError, GetBalanceRequest] = - params match { - case Some(JArray((addressStr: JString) :: (blockValue: JValue) :: Nil)) => - for { - address <- extractAddress(addressStr) - block <- extractBlockParam(blockValue) - } yield GetBalanceRequest(address, block) - case other => - Left(InvalidParams()) - } + implicit val eth_getBalance: JsonMethodDecoder[GetBalanceRequest] with JsonEncoder[GetBalanceResponse] = + new JsonMethodDecoder[GetBalanceRequest] with JsonEncoder[GetBalanceResponse] { + def decodeJson(params: Option[JArray]): Either[JsonRpcError, GetBalanceRequest] = + params match { + case Some(JArray((addressStr: JString) :: (blockValue: JValue) :: Nil)) => + for { + address <- extractAddress(addressStr) + block <- extractBlockParam(blockValue) + } yield GetBalanceRequest(address, block) + case _ => + Left(InvalidParams()) + } - def encodeJson(t: GetBalanceResponse): JValue = encodeAsHex(t.value) - } + def encodeJson(t: GetBalanceResponse): JValue = encodeAsHex(t.value) + } - implicit val eth_getStorageAt = new JsonMethodDecoder[GetStorageAtRequest] with JsonEncoder[GetStorageAtResponse] { - def decodeJson(params: Option[JArray]): Either[JsonRpcError, GetStorageAtRequest] = - params match { - case Some(JArray((addressStr: JString) :: (positionStr: JString) :: (blockValue: JValue) :: Nil)) => - for { - address <- extractAddress(addressStr) - position <- extractQuantity(positionStr) - block <- extractBlockParam(blockValue) - } yield GetStorageAtRequest(address, position, block) - case _ => Left(InvalidParams()) - } + implicit val eth_getStorageAt: JsonMethodDecoder[GetStorageAtRequest] with JsonEncoder[GetStorageAtResponse] = + new JsonMethodDecoder[GetStorageAtRequest] with JsonEncoder[GetStorageAtResponse] { + def decodeJson(params: Option[JArray]): Either[JsonRpcError, GetStorageAtRequest] = + params match { + case Some(JArray((addressStr: JString) :: (positionStr: JString) :: (blockValue: JValue) :: Nil)) => + for { + address <- extractAddress(addressStr) + position <- extractQuantity(positionStr) + block <- extractBlockParam(blockValue) + } yield GetStorageAtRequest(address, position, block) + case _ => Left(InvalidParams()) + } - def encodeJson(t: GetStorageAtResponse): JValue = encodeAsHex(t.value) - } + def encodeJson(t: GetStorageAtResponse): JValue = encodeAsHex(t.value) + } - implicit val eth_getTransactionCount = new JsonMethodDecoder[GetTransactionCountRequest] - with JsonEncoder[GetTransactionCountResponse] { - def decodeJson(params: Option[JArray]): Either[JsonRpcError, GetTransactionCountRequest] = - params match { - case Some(JArray((addressStr: JString) :: (blockValue: JValue) :: Nil)) => - for { - address <- extractAddress(addressStr) - block <- extractBlockParam(blockValue) - } yield GetTransactionCountRequest(address, block) - case _ => Left(InvalidParams()) - } + implicit val eth_getTransactionCount + : JsonMethodDecoder[GetTransactionCountRequest] with JsonEncoder[GetTransactionCountResponse] = + new JsonMethodDecoder[GetTransactionCountRequest] with JsonEncoder[GetTransactionCountResponse] { + def decodeJson(params: Option[JArray]): Either[JsonRpcError, GetTransactionCountRequest] = + params match { + case Some(JArray((addressStr: JString) :: (blockValue: JValue) :: Nil)) => + for { + address <- extractAddress(addressStr) + block <- extractBlockParam(blockValue) + } yield GetTransactionCountRequest(address, block) + case _ => Left(InvalidParams()) + } - def encodeJson(t: GetTransactionCountResponse): JValue = encodeAsHex(t.value) - } + def encodeJson(t: GetTransactionCountResponse): JValue = encodeAsHex(t.value) + } - implicit val eth_getStorageRoot = new JsonMethodDecoder[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()) - } + implicit val eth_getStorageRoot: JsonMethodDecoder[GetStorageRootRequest] with JsonEncoder[GetStorageRootResponse] = + new JsonMethodDecoder[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) - } + def encodeJson(t: GetStorageRootResponse): JValue = encodeAsHex(t.storageRoot) + } } diff --git a/src/main/scala/io/iohk/ethereum/jsonrpc/EthUserService.scala b/src/main/scala/io/iohk/ethereum/jsonrpc/EthUserService.scala index 67ed30aff7..f0acf459a4 100644 --- a/src/main/scala/io/iohk/ethereum/jsonrpc/EthUserService.scala +++ b/src/main/scala/io/iohk/ethereum/jsonrpc/EthUserService.scala @@ -1,13 +1,15 @@ package io.iohk.ethereum.jsonrpc import akka.util.ByteString + +import monix.eval.Task + +import io.iohk.ethereum.consensus.Consensus import io.iohk.ethereum.db.storage.EvmCodeStorage import io.iohk.ethereum.domain._ import io.iohk.ethereum.ledger.InMemoryWorldStateProxy import io.iohk.ethereum.mpt.MerklePatriciaTrie.MissingNodeException import io.iohk.ethereum.utils.BlockchainConfig -import monix.eval.Task -import io.iohk.ethereum.consensus.Consensus object EthUserService { case class GetStorageAtRequest(address: Address, position: BigInt, block: BlockParam) @@ -31,7 +33,7 @@ class EthUserService( ) extends ResolveBlock { import EthUserService._ - def getCode(req: GetCodeRequest): ServiceResponse[GetCodeResponse] = { + def getCode(req: GetCodeRequest): ServiceResponse[GetCodeResponse] = Task { resolveBlock(req.block).map { case ResolvedBlock(block, _) => val world = InMemoryWorldStateProxy( @@ -46,7 +48,6 @@ class EthUserService( GetCodeResponse(world.getCode(req.address)) } } - } def getBalance(req: GetBalanceRequest): ServiceResponse[GetBalanceResponse] = withAccount(req.address, req.block) { account => diff --git a/src/main/scala/io/iohk/ethereum/jsonrpc/ExpiringMap.scala b/src/main/scala/io/iohk/ethereum/jsonrpc/ExpiringMap.scala index 295a4cc042..958655bcfb 100644 --- a/src/main/scala/io/iohk/ethereum/jsonrpc/ExpiringMap.scala +++ b/src/main/scala/io/iohk/ethereum/jsonrpc/ExpiringMap.scala @@ -1,13 +1,13 @@ package io.iohk.ethereum.jsonrpc -import java.time.temporal.ChronoUnit import java.time.Duration - -import io.iohk.ethereum.jsonrpc.ExpiringMap.ValueWithDuration +import java.time.temporal.ChronoUnit import scala.collection.mutable import scala.util.Try +import io.iohk.ethereum.jsonrpc.ExpiringMap.ValueWithDuration + object ExpiringMap { case class ValueWithDuration[V](value: V, expiration: Duration) @@ -16,8 +16,7 @@ object ExpiringMap { new ExpiringMap(mutable.Map.empty, defaultElementRetentionTime) } -/** - * Simple wrapper around mutable map which enriches each element with expiration time (specified by user or default) +/** Simple wrapper around mutable map which enriches each element with expiration time (specified by user or default) * Map is passive which means it only check for expiration and remove expired element during get function. * Duration in all calls is relative to current System.nanoTime() */ @@ -33,9 +32,8 @@ class ExpiringMap[K, V] private ( this } - def add(k: K, v: V, duration: Duration): ExpiringMap[K, V] = { + def add(k: K, v: V, duration: Duration): ExpiringMap[K, V] = addFor(k, v, duration) - } def addForever(k: K, v: V): ExpiringMap[K, V] = addFor(k, v, maxHoldDuration) @@ -48,7 +46,7 @@ class ExpiringMap[K, V] private ( this } - def get(k: K): Option[V] = { + def get(k: K): Option[V] = underlying .get(k) .flatMap(value => @@ -59,7 +57,6 @@ class ExpiringMap[K, V] private ( None } ) - } private def isNotExpired(value: ValueWithDuration[V]) = currentNanoDuration().minus(value.expiration).isNegative diff --git a/src/main/scala/io/iohk/ethereum/jsonrpc/FilterManager.scala b/src/main/scala/io/iohk/ethereum/jsonrpc/FilterManager.scala index 9e103b4230..caa6e0fb91 100644 --- a/src/main/scala/io/iohk/ethereum/jsonrpc/FilterManager.scala +++ b/src/main/scala/io/iohk/ethereum/jsonrpc/FilterManager.scala @@ -1,19 +1,28 @@ package io.iohk.ethereum.jsonrpc -import akka.actor.{Actor, ActorRef, Cancellable, Props, Scheduler} -import akka.util.{ByteString, Timeout} +import akka.actor.Actor +import akka.actor.ActorRef +import akka.actor.Cancellable +import akka.actor.Props +import akka.actor.Scheduler +import akka.util.ByteString +import akka.util.Timeout + +import monix.eval.Task +import monix.execution + +import scala.annotation.tailrec +import scala.util.Random + import io.iohk.ethereum.consensus.blocks.BlockGenerator -import io.iohk.ethereum.db.storage.AppStateStorage import io.iohk.ethereum.domain._ import io.iohk.ethereum.jsonrpc.AkkaTaskOps.TaskActorOps import io.iohk.ethereum.keystore.KeyStore import io.iohk.ethereum.ledger.BloomFilter import io.iohk.ethereum.transactions.PendingTransactionsManager import io.iohk.ethereum.transactions.PendingTransactionsManager.PendingTransaction -import io.iohk.ethereum.utils.{FilterConfig, TxPoolConfig} -import monix.eval.Task -import scala.annotation.tailrec -import scala.util.Random +import io.iohk.ethereum.utils.FilterConfig +import io.iohk.ethereum.utils.TxPoolConfig class FilterManager( blockchain: Blockchain, @@ -30,8 +39,8 @@ class FilterManager( import akka.pattern.pipe import context.system - def scheduler: Scheduler = externalSchedulerOpt getOrElse system.scheduler - private implicit val executionContext = monix.execution.Scheduler(system.dispatcher) + def scheduler: Scheduler = externalSchedulerOpt.getOrElse(system.scheduler) + implicit private val executionContext: execution.Scheduler = monix.execution.Scheduler(system.dispatcher) val maxBlockHashesChanges = 256 @@ -43,17 +52,17 @@ class FilterManager( var filterTimeouts: Map[BigInt, Cancellable] = Map.empty - implicit val timeout = Timeout(txPoolConfig.pendingTxManagerQueryTimeout) + implicit val timeout: Timeout = Timeout(txPoolConfig.pendingTxManagerQueryTimeout) override def receive: Receive = { case NewLogFilter(fromBlock, toBlock, address, topics) => addFilterAndSendResponse(LogFilter(generateId(), fromBlock, toBlock, address, topics)) - case NewBlockFilter => addFilterAndSendResponse(BlockFilter(generateId())) + case NewBlockFilter => addFilterAndSendResponse(BlockFilter(generateId())) case NewPendingTransactionFilter => addFilterAndSendResponse(PendingTransactionFilter(generateId())) - case UninstallFilter(id) => uninstallFilter(id) - case GetFilterLogs(id) => getFilterLogs(id) - case GetFilterChanges(id) => getFilterChanges(id) - case FilterTimeout(id) => uninstallFilter(id) + case UninstallFilter(id) => uninstallFilter(id) + case GetFilterLogs(id) => getFilterLogs(id) + case GetFilterChanges(id) => getFilterChanges(id) + case FilterTimeout(id) => uninstallFilter(id) case gl: GetLogs => val filter = LogFilter(0, gl.fromBlock, gl.toBlock, gl.address, gl.topics) sender() ! LogFilterLogs(getLogs(filter, None)) @@ -116,7 +125,7 @@ class FilterManager( val bytesToCheckInBloomFilter = filter.address.map(a => Seq(a.bytes)).getOrElse(Nil) ++ filter.topics.flatten @tailrec - def recur(currentBlockNumber: BigInt, toBlockNumber: BigInt, logsSoFar: Seq[TxLog]): Seq[TxLog] = { + def recur(currentBlockNumber: BigInt, toBlockNumber: BigInt, logsSoFar: Seq[TxLog]): Seq[TxLog] = if (currentBlockNumber > toBlockNumber) { logsSoFar } else { @@ -140,10 +149,9 @@ class FilterManager( case None => logsSoFar } case Some(_) => recur(currentBlockNumber + 1, toBlockNumber, logsSoFar) - case None => logsSoFar + case None => logsSoFar } } - } val bestBlockNumber = blockchain.getBestBlockNumber() @@ -224,52 +232,48 @@ class FilterManager( } } - private def topicsMatch(logTopics: Seq[ByteString], filterTopics: Seq[Seq[ByteString]]): Boolean = { + private def topicsMatch(logTopics: Seq[ByteString], filterTopics: Seq[Seq[ByteString]]): Boolean = logTopics.size >= filterTopics.size && - (filterTopics zip logTopics).forall { case (filter, log) => filter.isEmpty || filter.contains(log) } - } + filterTopics.zip(logTopics).forall { case (filter, log) => filter.isEmpty || filter.contains(log) } private def getBlockHashesAfter(blockNumber: BigInt): Seq[ByteString] = { val bestBlock = blockchain.getBestBlockNumber() @tailrec - def recur(currentBlockNumber: BigInt, hashesSoFar: Seq[ByteString]): Seq[ByteString] = { + def recur(currentBlockNumber: BigInt, hashesSoFar: Seq[ByteString]): Seq[ByteString] = if (currentBlockNumber > bestBlock) { hashesSoFar } else blockchainReader.getBlockHeaderByNumber(currentBlockNumber) match { case Some(header) => recur(currentBlockNumber + 1, hashesSoFar :+ header.hash) - case None => hashesSoFar + case None => hashesSoFar } - } recur(blockNumber + 1, Nil) } - private def getPendingTransactions(): Task[Seq[PendingTransaction]] = { + private def getPendingTransactions(): Task[Seq[PendingTransaction]] = pendingTransactionsManager .askFor[PendingTransactionsManager.PendingTransactionsResponse](PendingTransactionsManager.GetPendingTransactions) .flatMap { response => keyStore.listAccounts() match { case Right(accounts) => Task.now( - response.pendingTransactions.filter { pt => accounts.contains(pt.stx.senderAddress) } + response.pendingTransactions.filter(pt => accounts.contains(pt.stx.senderAddress)) ) case Left(_) => Task.raiseError(new RuntimeException("Cannot get account list")) } } - } private def generateId(): BigInt = BigInt(Random.nextLong()).abs - private def resolveBlockNumber(blockParam: BlockParam, bestBlockNumber: BigInt): BigInt = { + private def resolveBlockNumber(blockParam: BlockParam, bestBlockNumber: BigInt): BigInt = blockParam match { case BlockParam.WithNumber(blockNumber) => blockNumber - case BlockParam.Earliest => 0 - case BlockParam.Latest => bestBlockNumber - case BlockParam.Pending => bestBlockNumber + case BlockParam.Earliest => 0 + case BlockParam.Latest => bestBlockNumber + case BlockParam.Pending => bestBlockNumber } - } } object FilterManager { diff --git a/src/main/scala/io/iohk/ethereum/jsonrpc/IeleJsonMethodsImplicits.scala b/src/main/scala/io/iohk/ethereum/jsonrpc/IeleJsonMethodsImplicits.scala index 80062aaca1..20f837eb63 100644 --- a/src/main/scala/io/iohk/ethereum/jsonrpc/IeleJsonMethodsImplicits.scala +++ b/src/main/scala/io/iohk/ethereum/jsonrpc/IeleJsonMethodsImplicits.scala @@ -1,11 +1,18 @@ package io.iohk.ethereum.jsonrpc import akka.util.ByteString + +import org.json4s.JsonAST.JArray +import org.json4s.JsonAST.JObject +import org.json4s.JsonAST.JString +import org.json4s.JsonAST.JValue + import io.iohk.ethereum.jsonrpc.EthInfoService._ import io.iohk.ethereum.jsonrpc.JsonRpcError.InvalidParams -import io.iohk.ethereum.jsonrpc.PersonalService.{InvalidAddress, SendIeleTransactionRequest} -import io.iohk.ethereum.jsonrpc.serialization.{JsonEncoder, JsonMethodDecoder} -import org.json4s.JsonAST.{JArray, JObject, JString, JValue} +import io.iohk.ethereum.jsonrpc.PersonalService.InvalidAddress +import io.iohk.ethereum.jsonrpc.PersonalService.SendIeleTransactionRequest +import io.iohk.ethereum.jsonrpc.serialization.JsonEncoder +import io.iohk.ethereum.jsonrpc.serialization.JsonMethodDecoder object IeleJsonMethodsImplicits extends JsonMethodsImplicits { @@ -34,42 +41,43 @@ object IeleJsonMethodsImplicits extends JsonMethodsImplicits { ) } - implicit val iele_call = new JsonMethodDecoder[IeleCallRequest] with JsonEncoder[IeleCallResponse] { - def decodeJson(params: Option[JArray]): Either[JsonRpcError, IeleCallRequest] = - params match { - case Some(JArray((txObj: JObject) :: (blockValue: JValue) :: Nil)) => - for { - blockParam <- extractBlockParam(blockValue) - tx <- extractIeleCall(txObj) - } yield IeleCallRequest(tx, blockParam) - case _ => Left(InvalidParams()) - } - - override def encodeJson(t: IeleCallResponse): JValue = JArray(t.returnData.map(encodeAsHex).toList) - } + implicit val iele_call: JsonMethodDecoder[IeleCallRequest] with JsonEncoder[IeleCallResponse] = + new JsonMethodDecoder[IeleCallRequest] with JsonEncoder[IeleCallResponse] { + def decodeJson(params: Option[JArray]): Either[JsonRpcError, IeleCallRequest] = + params match { + case Some(JArray((txObj: JObject) :: (blockValue: JValue) :: Nil)) => + for { + blockParam <- extractBlockParam(blockValue) + tx <- extractIeleCall(txObj) + } yield IeleCallRequest(tx, blockParam) + case _ => Left(InvalidParams()) + } + + override def encodeJson(t: IeleCallResponse): JValue = JArray(t.returnData.map(encodeAsHex).toList) + } protected def extractIeleTx(input: Map[String, JValue]): Either[JsonRpcError, IeleTransactionRequest] = { def optionalQuantity(name: String): Either[JsonRpcError, Option[BigInt]] = input.get(name) match { case Some(v) => extractQuantity(v).map(Some(_)) - case None => Right(None) + case None => Right(None) } for { from <- input.get("from") match { case Some(JString(s)) => extractAddress(s) - case Some(_) => Left(InvalidAddress) - case _ => Left(InvalidParams("TX 'from' is required")) + case Some(_) => Left(InvalidAddress) + case _ => Left(InvalidParams("TX 'from' is required")) } to <- input.get("to") match { case Some(JString(s)) => extractAddress(s).map { case addr if addr.toUInt256.isZero => None - case addr => Some(addr) + case addr => Some(addr) } case Some(_) => Left(InvalidAddress) - case None => Right(None) + case None => Right(None) } value <- optionalQuantity("value") @@ -86,21 +94,22 @@ object IeleJsonMethodsImplicits extends JsonMethodsImplicits { contractCode <- input.get("contractCode") match { case Some(JString(s)) => extractBytes(s).map(Some(_)) - case Some(_) => Left(InvalidParams()) - case None => Right(None) + case Some(_) => Left(InvalidParams()) + case None => Right(None) } } yield IeleTransactionRequest(from, to, value, gas, gasPrice, nonce, function, arguments, contractCode) } - implicit val iele_sendTransaction = new JsonMethodDecoder[SendIeleTransactionRequest] { - def decodeJson(params: Option[JArray]): Either[JsonRpcError, SendIeleTransactionRequest] = - params match { - case Some(JArray(JObject(tx) :: _)) => - extractIeleTx(tx.toMap).map(SendIeleTransactionRequest) - case _ => - Left(InvalidParams()) - } - } + implicit val iele_sendTransaction: JsonMethodDecoder[SendIeleTransactionRequest] = + new JsonMethodDecoder[SendIeleTransactionRequest] { + def decodeJson(params: Option[JArray]): Either[JsonRpcError, SendIeleTransactionRequest] = + params match { + case Some(JArray(JObject(tx) :: _)) => + extractIeleTx(tx.toMap).map(SendIeleTransactionRequest) + case _ => + Left(InvalidParams()) + } + } } diff --git a/src/main/scala/io/iohk/ethereum/jsonrpc/JsonMethodsImplicits.scala b/src/main/scala/io/iohk/ethereum/jsonrpc/JsonMethodsImplicits.scala index b9137cfa00..97e380ee96 100644 --- a/src/main/scala/io/iohk/ethereum/jsonrpc/JsonMethodsImplicits.scala +++ b/src/main/scala/io/iohk/ethereum/jsonrpc/JsonMethodsImplicits.scala @@ -1,22 +1,31 @@ package io.iohk.ethereum.jsonrpc import java.time.Duration + import akka.util.ByteString + +import scala.util.Try + +import org.bouncycastle.util.encoders.Hex +import org.json4s.Formats +import org.json4s.JsonAST._ +import org.json4s.JsonDSL._ + import io.iohk.ethereum.crypto.ECDSASignature import io.iohk.ethereum.domain.Address import io.iohk.ethereum.jsonrpc.JsonRpcError.InvalidParams import io.iohk.ethereum.jsonrpc.NetService._ import io.iohk.ethereum.jsonrpc.PersonalService._ -import io.iohk.ethereum.jsonrpc.Web3Service.{ClientVersionRequest, ClientVersionResponse, Sha3Request, Sha3Response} +import io.iohk.ethereum.jsonrpc.Web3Service.ClientVersionRequest +import io.iohk.ethereum.jsonrpc.Web3Service.ClientVersionResponse +import io.iohk.ethereum.jsonrpc.Web3Service.Sha3Request +import io.iohk.ethereum.jsonrpc.Web3Service.Sha3Response +import io.iohk.ethereum.jsonrpc.serialization.JsonEncoder +import io.iohk.ethereum.jsonrpc.serialization.JsonMethodCodec +import io.iohk.ethereum.jsonrpc.serialization.JsonMethodDecoder import io.iohk.ethereum.jsonrpc.serialization.JsonMethodDecoder.NoParamsMethodDecoder -import io.iohk.ethereum.jsonrpc.serialization.{JsonEncoder, JsonMethodCodec, JsonMethodDecoder, JsonSerializers} +import io.iohk.ethereum.jsonrpc.serialization.JsonSerializers import io.iohk.ethereum.utils.BigIntExtensionMethods.BigIntAsUnsigned -import org.bouncycastle.util.encoders.Hex -import org.json4s.Formats -import org.json4s.JsonAST._ -import org.json4s.JsonDSL._ - -import scala.util.Try trait JsonMethodsImplicits { implicit val formats: Formats = JsonSerializers.formats @@ -44,13 +53,12 @@ trait JsonMethodsImplicits { duration <- getDuration(quantity) } yield duration - private def getDuration(value: BigInt): Either[JsonRpcError, Duration] = { + private def getDuration(value: BigInt): Either[JsonRpcError, Duration] = Either.cond( value.isValidInt, Duration.ofSeconds(value.toInt), InvalidParams("Duration should be an number of seconds, less than 2^31 - 1") ) - } protected def extractAddress(input: JString): Either[JsonRpcError, Address] = extractAddress(input.s) @@ -82,27 +90,27 @@ trait JsonMethodsImplicits { protected def optionalQuantity(input: JValue): Either[JsonRpcError, Option[BigInt]] = input match { case JNothing => Right(None) - case o => extractQuantity(o).map(Some(_)) + case o => extractQuantity(o).map(Some(_)) } protected def extractTx(input: Map[String, JValue]): Either[JsonRpcError, TransactionRequest] = { def optionalQuantity(name: String): Either[JsonRpcError, Option[BigInt]] = input.get(name) match { case Some(v) => extractQuantity(v).map(Some(_)) - case None => Right(None) + case None => Right(None) } for { from <- input.get("from") match { case Some(JString(s)) if s.nonEmpty => extractAddress(s) - case Some(_) => Left(InvalidAddress) - case _ => Left(InvalidParams("TX 'from' is required")) + case Some(_) => Left(InvalidAddress) + case _ => Left(InvalidParams("TX 'from' is required")) } to <- input.get("to") match { case Some(JString(s)) if s.nonEmpty => extractAddress(s).map(Option.apply) - case Some(JString(_)) => extractAddress("0x0").map(Option.apply) - case Some(_) => Left(InvalidAddress) - case None => Right(None) + case Some(JString(_)) => extractAddress("0x0").map(Option.apply) + case Some(_) => Left(InvalidAddress) + case None => Right(None) } value <- optionalQuantity("value") @@ -115,24 +123,23 @@ trait JsonMethodsImplicits { data <- input.get("data") match { case Some(JString(s)) => extractBytes(s).map(Some(_)) - case Some(_) => Left(InvalidParams()) - case None => Right(None) + case Some(_) => Left(InvalidParams()) + case None => Right(None) } } yield TransactionRequest(from, to, value, gas, gasPrice, nonce, data) } - protected def extractBlockParam(input: JValue): Either[JsonRpcError, BlockParam] = { + protected def extractBlockParam(input: JValue): Either[JsonRpcError, BlockParam] = input match { case JString("earliest") => Right(BlockParam.Earliest) - case JString("latest") => Right(BlockParam.Latest) - case JString("pending") => Right(BlockParam.Pending) + case JString("latest") => Right(BlockParam.Latest) + case JString("pending") => Right(BlockParam.Pending) case other => extractQuantity(other) .map(BlockParam.WithNumber) .left .map(_ => JsonRpcError.InvalidParams(s"Invalid default block param: $other")) } - } def toEitherOpt[A, B](opt: Option[Either[A, B]]): Either[A, Option[B]] = opt.map(_.map(Some.apply)).getOrElse(Right(None)) @@ -143,67 +150,75 @@ object JsonMethodsImplicits extends JsonMethodsImplicits { import JsonRpcError._ - implicit val web3_sha3 = new JsonMethodDecoder[Sha3Request] with JsonEncoder[Sha3Response] { - override def decodeJson(params: Option[JArray]): Either[JsonRpcError, Sha3Request] = - params match { - case Some(JArray((input: JString) :: Nil)) => extractBytes(input).map(Sha3Request) - case _ => Left(InvalidParams()) - } + implicit val web3_sha3: JsonMethodDecoder[Sha3Request] with JsonEncoder[Sha3Response] = + new JsonMethodDecoder[Sha3Request] with JsonEncoder[Sha3Response] { + override def decodeJson(params: Option[JArray]): Either[JsonRpcError, Sha3Request] = + params match { + case Some(JArray((input: JString) :: Nil)) => extractBytes(input).map(Sha3Request) + case _ => Left(InvalidParams()) + } - override def encodeJson(t: Sha3Response): JValue = encodeAsHex(t.data) - } + override def encodeJson(t: Sha3Response): JValue = encodeAsHex(t.data) + } - implicit val web3_clientVersion = new NoParamsMethodDecoder(ClientVersionRequest()) - with JsonEncoder[ClientVersionResponse] { - override def encodeJson(t: ClientVersionResponse): JValue = t.value - } + implicit val web3_clientVersion: NoParamsMethodDecoder[ClientVersionRequest] with JsonEncoder[ClientVersionResponse] = + new NoParamsMethodDecoder(ClientVersionRequest()) with JsonEncoder[ClientVersionResponse] { + override def encodeJson(t: ClientVersionResponse): JValue = t.value + } - implicit val net_version = new NoParamsMethodDecoder(VersionRequest()) with JsonEncoder[VersionResponse] { - override def encodeJson(t: VersionResponse): JValue = t.value - } + implicit val net_version: NoParamsMethodDecoder[VersionRequest] with JsonEncoder[VersionResponse] = + new NoParamsMethodDecoder(VersionRequest()) with JsonEncoder[VersionResponse] { + override def encodeJson(t: VersionResponse): JValue = t.value + } - implicit val net_listening = new NoParamsMethodDecoder(ListeningRequest()) with JsonEncoder[ListeningResponse] { - override def encodeJson(t: ListeningResponse): JValue = t.value - } + implicit val net_listening: NoParamsMethodDecoder[ListeningRequest] with JsonEncoder[ListeningResponse] = + new NoParamsMethodDecoder(ListeningRequest()) with JsonEncoder[ListeningResponse] { + override def encodeJson(t: ListeningResponse): JValue = t.value + } - implicit val net_peerCount = new NoParamsMethodDecoder(PeerCountRequest()) with JsonEncoder[PeerCountResponse] { - override def encodeJson(t: PeerCountResponse): JValue = encodeAsHex(t.value) - } + implicit val net_peerCount: NoParamsMethodDecoder[PeerCountRequest] with JsonEncoder[PeerCountResponse] = + new NoParamsMethodDecoder(PeerCountRequest()) with JsonEncoder[PeerCountResponse] { + override def encodeJson(t: PeerCountResponse): JValue = encodeAsHex(t.value) + } - implicit val personal_importRawKey = new JsonMethodDecoder[ImportRawKeyRequest] - with JsonEncoder[ImportRawKeyResponse] { - def decodeJson(params: Option[JArray]): Either[JsonRpcError, ImportRawKeyRequest] = - params match { - case Some(JArray(JString(key) :: JString(passphrase) :: _)) => - extractBytes(key).map(ImportRawKeyRequest(_, passphrase)) - case _ => - Left(InvalidParams()) - } + implicit val personal_importRawKey: JsonMethodDecoder[ImportRawKeyRequest] with JsonEncoder[ImportRawKeyResponse] = + new JsonMethodDecoder[ImportRawKeyRequest] with JsonEncoder[ImportRawKeyResponse] { + def decodeJson(params: Option[JArray]): Either[JsonRpcError, ImportRawKeyRequest] = + params match { + case Some(JArray(JString(key) :: JString(passphrase) :: _)) => + extractBytes(key).map(ImportRawKeyRequest(_, passphrase)) + case _ => + Left(InvalidParams()) + } - def encodeJson(t: ImportRawKeyResponse): JValue = - JString(t.address.toString) - } + def encodeJson(t: ImportRawKeyResponse): JValue = + JString(t.address.toString) + } - implicit val personal_newAccount = new JsonMethodDecoder[NewAccountRequest] with JsonEncoder[NewAccountResponse] { - def decodeJson(params: Option[JArray]): Either[JsonRpcError, NewAccountRequest] = - params match { - case Some(JArray(JString(passphrase) :: _)) => - Right(NewAccountRequest(passphrase)) - case _ => - Left(InvalidParams()) - } + implicit val personal_newAccount: JsonMethodDecoder[NewAccountRequest] with JsonEncoder[NewAccountResponse] = + new JsonMethodDecoder[NewAccountRequest] with JsonEncoder[NewAccountResponse] { + def decodeJson(params: Option[JArray]): Either[JsonRpcError, NewAccountRequest] = + params match { + case Some(JArray(JString(passphrase) :: _)) => + Right(NewAccountRequest(passphrase)) + case _ => + Left(InvalidParams()) + } - def encodeJson(t: NewAccountResponse): JValue = - JString(t.address.toString) - } + def encodeJson(t: NewAccountResponse): JValue = + JString(t.address.toString) + } - implicit val personal_listAccounts = new NoParamsMethodDecoder(ListAccountsRequest()) - with JsonEncoder[ListAccountsResponse] { + implicit val personal_listAccounts + : NoParamsMethodDecoder[ListAccountsRequest] with JsonEncoder[ListAccountsResponse] = new NoParamsMethodDecoder( + ListAccountsRequest() + ) with JsonEncoder[ListAccountsResponse] { def encodeJson(t: ListAccountsResponse): JValue = JArray(t.addresses.map(a => JString(a.toString))) } - implicit val personal_sendTransaction = + implicit val personal_sendTransaction + : JsonMethodCodec[SendTransactionWithPassphraseRequest, SendTransactionWithPassphraseResponse] = new JsonMethodCodec[SendTransactionWithPassphraseRequest, SendTransactionWithPassphraseResponse] { def decodeJson(params: Option[JArray]): Either[JsonRpcError, SendTransactionWithPassphraseRequest] = params match { @@ -217,85 +232,87 @@ object JsonMethodsImplicits extends JsonMethodsImplicits { encodeAsHex(t.txHash) } - implicit val personal_sign = new JsonMethodCodec[SignRequest, SignResponse] { - override def encodeJson(t: SignResponse): JValue = { - import t.signature._ - encodeAsHex(ByteString(r.toUnsignedByteArray ++ s.toUnsignedByteArray :+ v)) + implicit val personal_sign: JsonMethodCodec[SignRequest, SignResponse] = + new JsonMethodCodec[SignRequest, SignResponse] { + override def encodeJson(t: SignResponse): JValue = { + import t.signature._ + encodeAsHex(ByteString(r.toUnsignedByteArray ++ s.toUnsignedByteArray :+ v)) + } + + override def decodeJson(params: Option[JArray]): Either[JsonRpcError, SignRequest] = + params match { + case Some(JArray(JString(message) :: JString(addr) :: JString(passphase) :: _)) => + for { + message <- extractBytes(message) + address <- extractAddress(addr) + } yield SignRequest(message, address, Some(passphase)) + case _ => + Left(InvalidParams()) + } } - override def decodeJson(params: Option[JArray]): Either[JsonRpcError, SignRequest] = - params match { - case Some(JArray(JString(message) :: JString(addr) :: JString(passphase) :: _)) => - for { - message <- extractBytes(message) - address <- extractAddress(addr) - } yield SignRequest(message, address, Some(passphase)) - case _ => - Left(InvalidParams()) - } - } + implicit val personal_ecRecover: JsonMethodCodec[EcRecoverRequest, EcRecoverResponse] = + new JsonMethodCodec[EcRecoverRequest, EcRecoverResponse] { - implicit val personal_ecRecover = new JsonMethodCodec[EcRecoverRequest, EcRecoverResponse] { - - def decodeJson(params: Option[JArray]): Either[JsonRpcError, EcRecoverRequest] = - params match { - case Some(JArray(JString(message) :: JString(signature) :: _)) => - val decoded = for { - msg <- extractBytes(message) - sig <- extractBytes(signature, ECDSASignature.EncodedLength) - } yield (msg, sig) - - decoded.flatMap { case (msg, sig) => - val r = sig.take(ECDSASignature.RLength) - val s = sig.drop(ECDSASignature.RLength).take(ECDSASignature.SLength) - val v = sig.last - - if (ECDSASignature.allowedPointSigns.contains(v)) { - Right(EcRecoverRequest(msg, ECDSASignature(r, s, v))) - } else { - Left(InvalidParams("invalid point sign v, allowed values are 27 and 28")) + def decodeJson(params: Option[JArray]): Either[JsonRpcError, EcRecoverRequest] = + params match { + case Some(JArray(JString(message) :: JString(signature) :: _)) => + val decoded = for { + msg <- extractBytes(message) + sig <- extractBytes(signature, ECDSASignature.EncodedLength) + } yield (msg, sig) + + decoded.flatMap { case (msg, sig) => + val r = sig.take(ECDSASignature.RLength) + val s = sig.drop(ECDSASignature.RLength).take(ECDSASignature.SLength) + val v = sig.last + + if (ECDSASignature.allowedPointSigns.contains(v)) { + Right(EcRecoverRequest(msg, ECDSASignature(r, s, v))) + } else { + Left(InvalidParams("invalid point sign v, allowed values are 27 and 28")) + } } - } - case _ => - Left(InvalidParams()) - } - - def encodeJson(t: EcRecoverResponse): JValue = - encodeAsHex(t.address.bytes) - } + case _ => + Left(InvalidParams()) + } - implicit val personal_unlockAccount = new JsonMethodCodec[UnlockAccountRequest, UnlockAccountResponse] { - def decodeJson(params: Option[JArray]): Either[JsonRpcError, UnlockAccountRequest] = { - params match { - case Some(JArray(JString(addr) :: JString(passphrase) :: JNull :: _)) => - extractAddress(addr).map(UnlockAccountRequest(_, passphrase, None)) - case Some(JArray(JString(addr) :: JString(passphrase) :: duration :: _)) => - for { - addr <- extractAddress(addr) - duration <- extractDurationQuantity(duration) - } yield UnlockAccountRequest(addr, passphrase, Some(duration)) - case Some(JArray(JString(addr) :: JString(passphrase) :: _)) => - extractAddress(addr).map(UnlockAccountRequest(_, passphrase, None)) - case _ => - Left(InvalidParams()) - } + def encodeJson(t: EcRecoverResponse): JValue = + encodeAsHex(t.address.bytes) } - def encodeJson(t: UnlockAccountResponse): JValue = - JBool(t.result) - } + implicit val personal_unlockAccount: JsonMethodCodec[UnlockAccountRequest, UnlockAccountResponse] = + new JsonMethodCodec[UnlockAccountRequest, UnlockAccountResponse] { + def decodeJson(params: Option[JArray]): Either[JsonRpcError, UnlockAccountRequest] = + params match { + case Some(JArray(JString(addr) :: JString(passphrase) :: JNull :: _)) => + extractAddress(addr).map(UnlockAccountRequest(_, passphrase, None)) + case Some(JArray(JString(addr) :: JString(passphrase) :: duration :: _)) => + for { + addr <- extractAddress(addr) + duration <- extractDurationQuantity(duration) + } yield UnlockAccountRequest(addr, passphrase, Some(duration)) + case Some(JArray(JString(addr) :: JString(passphrase) :: _)) => + extractAddress(addr).map(UnlockAccountRequest(_, passphrase, None)) + case _ => + Left(InvalidParams()) + } - implicit val personal_lockAccount = new JsonMethodCodec[LockAccountRequest, LockAccountResponse] { - def decodeJson(params: Option[JArray]): Either[JsonRpcError, LockAccountRequest] = { - params match { - case Some(JArray(JString(addr) :: _)) => - extractAddress(addr).map(LockAccountRequest) - case _ => - Left(InvalidParams()) - } + def encodeJson(t: UnlockAccountResponse): JValue = + JBool(t.result) } - def encodeJson(t: LockAccountResponse): JValue = - JBool(t.result) - } + implicit val personal_lockAccount: JsonMethodCodec[LockAccountRequest, LockAccountResponse] = + new JsonMethodCodec[LockAccountRequest, LockAccountResponse] { + def decodeJson(params: Option[JArray]): Either[JsonRpcError, LockAccountRequest] = + params match { + case Some(JArray(JString(addr) :: _)) => + extractAddress(addr).map(LockAccountRequest) + case _ => + Left(InvalidParams()) + } + + def encodeJson(t: LockAccountResponse): JValue = + JBool(t.result) + } } diff --git a/src/main/scala/io/iohk/ethereum/jsonrpc/JsonRpcController.scala b/src/main/scala/io/iohk/ethereum/jsonrpc/JsonRpcController.scala index 29e8546520..2c1cceed30 100644 --- a/src/main/scala/io/iohk/ethereum/jsonrpc/JsonRpcController.scala +++ b/src/main/scala/io/iohk/ethereum/jsonrpc/JsonRpcController.scala @@ -1,31 +1,34 @@ package io.iohk.ethereum.jsonrpc +import monix.eval.Task + +import org.json4s.JsonDSL._ + import io.iohk.ethereum.jsonrpc.CheckpointingService._ -import io.iohk.ethereum.jsonrpc.DebugService.{ListPeersInfoRequest, ListPeersInfoResponse} +import io.iohk.ethereum.jsonrpc.DebugService.ListPeersInfoRequest +import io.iohk.ethereum.jsonrpc.DebugService.ListPeersInfoResponse import io.iohk.ethereum.jsonrpc.EthBlocksService._ +import io.iohk.ethereum.jsonrpc.EthFilterService._ import io.iohk.ethereum.jsonrpc.EthInfoService._ +import io.iohk.ethereum.jsonrpc.EthMiningService._ import io.iohk.ethereum.jsonrpc.EthTxService._ import io.iohk.ethereum.jsonrpc.EthUserService._ -import io.iohk.ethereum.jsonrpc.EthFilterService._ -import io.iohk.ethereum.jsonrpc.MantisService.{GetAccountTransactionsRequest, GetAccountTransactionsResponse} -import io.iohk.ethereum.jsonrpc.EthMiningService._ +import io.iohk.ethereum.jsonrpc.MantisService.GetAccountTransactionsRequest +import io.iohk.ethereum.jsonrpc.MantisService.GetAccountTransactionsResponse import io.iohk.ethereum.jsonrpc.NetService._ import io.iohk.ethereum.jsonrpc.PersonalService._ -import io.iohk.ethereum.jsonrpc.ProofService.{GetProofRequest, GetProofResponse} -import io.iohk.ethereum.jsonrpc.QAService.{ - GenerateCheckpointRequest, - GenerateCheckpointResponse, - GetFederationMembersInfoRequest, - GetFederationMembersInfoResponse -} +import io.iohk.ethereum.jsonrpc.ProofService.GetProofRequest +import io.iohk.ethereum.jsonrpc.ProofService.GetProofResponse +import io.iohk.ethereum.jsonrpc.QAService.GenerateCheckpointRequest +import io.iohk.ethereum.jsonrpc.QAService.GenerateCheckpointResponse +import io.iohk.ethereum.jsonrpc.QAService.GetFederationMembersInfoRequest +import io.iohk.ethereum.jsonrpc.QAService.GetFederationMembersInfoResponse import io.iohk.ethereum.jsonrpc.TestService._ import io.iohk.ethereum.jsonrpc.Web3Service._ import io.iohk.ethereum.jsonrpc.server.controllers.JsonRpcBaseController import io.iohk.ethereum.jsonrpc.server.controllers.JsonRpcBaseController.JsonRpcConfig import io.iohk.ethereum.nodebuilder.ApisBuilder import io.iohk.ethereum.utils.Logger -import monix.eval.Task -import org.json4s.JsonDSL._ case class JsonRpcController( web3Service: Web3Service, @@ -229,12 +232,11 @@ case class JsonRpcController( handle[ListPeersInfoRequest, ListPeersInfoResponse](debugService.listPeersInfo, req) } - private def handleTestRequest: PartialFunction[JsonRpcRequest, Task[JsonRpcResponse]] = { + private def handleTestRequest: PartialFunction[JsonRpcRequest, Task[JsonRpcResponse]] = testServiceOpt match { case Some(testService) => handleTestRequest(testService) - case None => PartialFunction.empty + case None => PartialFunction.empty } - } private def handleTestRequest(testService: TestService): PartialFunction[JsonRpcRequest, Task[JsonRpcResponse]] = { case req @ JsonRpcRequest(_, "test_setChainParams", _, _) => @@ -320,7 +322,7 @@ case class JsonRpcController( private def handleRpcRequest: PartialFunction[JsonRpcRequest, Task[JsonRpcResponse]] = { case req @ JsonRpcRequest(_, "rpc_modules", _, _) => - val result = enabledApis.map { _ -> "1.0" }.toMap + val result = enabledApis.map(_ -> "1.0").toMap Task(JsonRpcResponse("2.0", Some(result), None, req.id)) } } diff --git a/src/main/scala/io/iohk/ethereum/jsonrpc/JsonRpcControllerMetrics.scala b/src/main/scala/io/iohk/ethereum/jsonrpc/JsonRpcControllerMetrics.scala index b8854632ba..2fcb671e50 100644 --- a/src/main/scala/io/iohk/ethereum/jsonrpc/JsonRpcControllerMetrics.scala +++ b/src/main/scala/io/iohk/ethereum/jsonrpc/JsonRpcControllerMetrics.scala @@ -1,21 +1,22 @@ package io.iohk.ethereum.jsonrpc -import io.iohk.ethereum.metrics.MetricsContainer -import java.util.concurrent.TimeUnit import java.time.Duration +import io.micrometer.core.instrument.Counter + +import io.iohk.ethereum.metrics.MetricsContainer + case object JsonRpcControllerMetrics extends MetricsContainer { - /** - * Counts attempts to call non-existing methods. + /** Counts attempts to call non-existing methods. */ - final val NotFoundMethodsCounter = metrics.counter("json.rpc.notfound.calls.counter") + final val NotFoundMethodsCounter: Counter = metrics.counter("json.rpc.notfound.calls.counter") - final val MethodsSuccessCounter = metrics.counter("json.rpc.methods.success.counter") - final val MethodsExceptionCounter = metrics.counter("json.rpc.methods.exception.counter") - final val MethodsErrorCounter = metrics.counter("json.rpc.methods.error.counter") + final val MethodsSuccessCounter: Counter = metrics.counter("json.rpc.methods.success.counter") + final val MethodsExceptionCounter: Counter = metrics.counter("json.rpc.methods.exception.counter") + final val MethodsErrorCounter: Counter = metrics.counter("json.rpc.methods.error.counter") - final val HealhcheckErrorCounter = metrics.counter("json.rpc.healthcheck.error.counter") + final val HealhcheckErrorCounter: Counter = metrics.counter("json.rpc.healthcheck.error.counter") final val MethodsTimerName = "json.rpc.methods.timer" diff --git a/src/main/scala/io/iohk/ethereum/jsonrpc/JsonRpcError.scala b/src/main/scala/io/iohk/ethereum/jsonrpc/JsonRpcError.scala index 6d6c0982d4..615e901030 100644 --- a/src/main/scala/io/iohk/ethereum/jsonrpc/JsonRpcError.scala +++ b/src/main/scala/io/iohk/ethereum/jsonrpc/JsonRpcError.scala @@ -1,8 +1,13 @@ package io.iohk.ethereum.jsonrpc +import org.json4s.JInt +import org.json4s.JLong +import org.json4s.JObject +import org.json4s.JString +import org.json4s.JValue + import io.iohk.ethereum.consensus.Protocol import io.iohk.ethereum.jsonrpc.serialization.JsonEncoder -import org.json4s.{JLong, JInt, JObject, JString, JValue} case class JsonRpcError(code: Int, message: String, data: Option[JValue]) @@ -25,25 +30,27 @@ object JsonRpcError extends JsonMethodsImplicits { ) case class RateLimitInformation(backoffSeconds: Long) - def RateLimitError(backoffSeconds: Long) = + def RateLimitError(backoffSeconds: Long): JsonRpcError = JsonRpcError(-32005, "request rate exceeded", RateLimitInformation(backoffSeconds)) - val ParseError = JsonRpcError(-32700, "An error occurred on the server while parsing the JSON text", None) - val InvalidRequest = JsonRpcError(-32600, "The JSON sent is not a valid Request object", None) - val MethodNotFound = JsonRpcError(-32601, "The method does not exist / is not available", None) - def InvalidParams(msg: String = "Invalid method parameters") = JsonRpcError(-32602, msg, None) - val InternalError = JsonRpcError(-32603, "Internal JSON-RPC error", None) - def LogicError(msg: String) = JsonRpcError(-32000, msg, None) - val AccountLocked = LogicError("account is locked or unknown") + val ParseError: JsonRpcError = + JsonRpcError(-32700, "An error occurred on the server while parsing the JSON text", None) + val InvalidRequest: JsonRpcError = JsonRpcError(-32600, "The JSON sent is not a valid Request object", None) + val MethodNotFound: JsonRpcError = JsonRpcError(-32601, "The method does not exist / is not available", None) + def InvalidParams(msg: String = "Invalid method parameters"): JsonRpcError = JsonRpcError(-32602, msg, None) + val InternalError: JsonRpcError = JsonRpcError(-32603, "Internal JSON-RPC error", None) + def LogicError(msg: String): JsonRpcError = JsonRpcError(-32000, msg, None) + val AccountLocked: JsonRpcError = LogicError("account is locked or unknown") // We use the recommendation from https://eth.wiki/json-rpc/json-rpc-error-codes-improvement-proposal // // Note Error Code "2", "Action not allowed" could be a candidate here, but the description they provide // probably does not match this use-case. - final val ConsensusIsNotEthash = JsonRpcError(200, s"The consensus algorithm is not ${Protocol.Names.PoW}", None) + final val ConsensusIsNotEthash: JsonRpcError = + JsonRpcError(200, s"The consensus algorithm is not ${Protocol.Names.PoW}", None) def executionError(reasons: List[EthCustomError]): JsonRpcError = JsonRpcError(3, "Execution error", reasons) - val NodeNotFound = executionError(List(EthCustomError.DoesntExist("State node"))) - val BlockNotFound = executionError(List(EthCustomError.DoesntExist("Block"))) + val NodeNotFound: JsonRpcError = executionError(List(EthCustomError.DoesntExist("State node"))) + val BlockNotFound: JsonRpcError = executionError(List(EthCustomError.DoesntExist("Block"))) // Custom errors based on proposal https://eth.wiki/json-rpc/json-rpc-error-codes-improvement-proposal sealed abstract class EthCustomError private (val code: Int, val message: String) diff --git a/src/main/scala/io/iohk/ethereum/jsonrpc/JsonRpcHealthChecker.scala b/src/main/scala/io/iohk/ethereum/jsonrpc/JsonRpcHealthChecker.scala index e35161f21f..35f0584c97 100644 --- a/src/main/scala/io/iohk/ethereum/jsonrpc/JsonRpcHealthChecker.scala +++ b/src/main/scala/io/iohk/ethereum/jsonrpc/JsonRpcHealthChecker.scala @@ -1,15 +1,16 @@ package io.iohk.ethereum.jsonrpc -import io.iohk.ethereum.healthcheck.HealthcheckResponse import monix.eval.Task +import io.iohk.ethereum.healthcheck.HealthcheckResponse + trait JsonRpcHealthChecker { def healthCheck(): Task[HealthcheckResponse] - def handleResponse(responseF: Task[HealthcheckResponse]): Task[HealthcheckResponse] = { + def handleResponse(responseF: Task[HealthcheckResponse]): Task[HealthcheckResponse] = responseF .map { - case response if (!response.isOK) => + case response if !response.isOK => JsonRpcControllerMetrics.HealhcheckErrorCounter.increment() response case response => response @@ -18,5 +19,4 @@ trait JsonRpcHealthChecker { JsonRpcControllerMetrics.HealhcheckErrorCounter.increment() Task.raiseError(t) } - } } diff --git a/src/main/scala/io/iohk/ethereum/jsonrpc/JsonRpcHealthcheck.scala b/src/main/scala/io/iohk/ethereum/jsonrpc/JsonRpcHealthcheck.scala index e2118a83f7..582f340b4a 100644 --- a/src/main/scala/io/iohk/ethereum/jsonrpc/JsonRpcHealthcheck.scala +++ b/src/main/scala/io/iohk/ethereum/jsonrpc/JsonRpcHealthcheck.scala @@ -1,21 +1,21 @@ package io.iohk.ethereum.jsonrpc -import io.iohk.ethereum.healthcheck.HealthcheckResult import monix.eval.Task +import io.iohk.ethereum.healthcheck.HealthcheckResult + final case class JsonRpcHealthcheck[Response]( name: String, healthCheck: Either[String, Response], info: Option[String] = None ) { - def toResult: HealthcheckResult = { + def toResult: HealthcheckResult = healthCheck .fold( HealthcheckResult.error(name, _), result => HealthcheckResult.ok(name, info) ) - } def withPredicate(message: String)(predicate: Response => Boolean): JsonRpcHealthcheck[Response] = copy(healthCheck = healthCheck.filterOrElse(predicate, message)) diff --git a/src/main/scala/io/iohk/ethereum/jsonrpc/JsonRpcRequest.scala b/src/main/scala/io/iohk/ethereum/jsonrpc/JsonRpcRequest.scala index 89911d58d8..419725cc88 100644 --- a/src/main/scala/io/iohk/ethereum/jsonrpc/JsonRpcRequest.scala +++ b/src/main/scala/io/iohk/ethereum/jsonrpc/JsonRpcRequest.scala @@ -1,19 +1,19 @@ package io.iohk.ethereum.jsonrpc -import org.json4s.JsonAST.{JArray, JValue} -import org.json4s.native.Serialization.write import org.json4s.DefaultFormats import org.json4s.Formats +import org.json4s.JsonAST.JArray +import org.json4s.JsonAST.JValue +import org.json4s.native.Serialization.write //TODO: work on a more elegant solution trait SensitiveInformationToString { val method: String - def toStringWithSensitiveInformation: String = { + def toStringWithSensitiveInformation: String = if (!method.contains("personal")) toString else "sensitive information" - } } case class JsonRpcRequest(jsonrpc: String, method: String, params: Option[JArray], id: Option[JValue]) diff --git a/src/main/scala/io/iohk/ethereum/jsonrpc/JsonRpcResponse.scala b/src/main/scala/io/iohk/ethereum/jsonrpc/JsonRpcResponse.scala index 30419c9160..0eea0ab2a8 100644 --- a/src/main/scala/io/iohk/ethereum/jsonrpc/JsonRpcResponse.scala +++ b/src/main/scala/io/iohk/ethereum/jsonrpc/JsonRpcResponse.scala @@ -1,9 +1,9 @@ package io.iohk.ethereum.jsonrpc -import org.json4s.native.Serialization.write -import org.json4s.JsonAST.JValue import org.json4s.DefaultFormats import org.json4s.Formats +import org.json4s.JsonAST.JValue +import org.json4s.native.Serialization.write case class JsonRpcResponse(jsonrpc: String, result: Option[JValue], error: Option[JsonRpcError], id: JValue) { def inspect: String = { diff --git a/src/main/scala/io/iohk/ethereum/jsonrpc/MantisJsonMethodImplicits.scala b/src/main/scala/io/iohk/ethereum/jsonrpc/MantisJsonMethodImplicits.scala index 55bcfec53a..e22e3f8fb1 100644 --- a/src/main/scala/io/iohk/ethereum/jsonrpc/MantisJsonMethodImplicits.scala +++ b/src/main/scala/io/iohk/ethereum/jsonrpc/MantisJsonMethodImplicits.scala @@ -1,13 +1,18 @@ package io.iohk.ethereum.jsonrpc +import org.json4s.JsonAST._ +import org.json4s.Merge + import io.iohk.ethereum.jsonrpc.EthTxJsonMethodsImplicits.transactionResponseJsonEncoder import io.iohk.ethereum.jsonrpc.JsonRpcError.InvalidParams -import io.iohk.ethereum.jsonrpc.MantisService.{GetAccountTransactionsRequest, GetAccountTransactionsResponse} +import io.iohk.ethereum.jsonrpc.MantisService.GetAccountTransactionsRequest +import io.iohk.ethereum.jsonrpc.MantisService.GetAccountTransactionsResponse +import io.iohk.ethereum.jsonrpc.serialization.JsonEncoder import io.iohk.ethereum.jsonrpc.serialization.JsonEncoder.Ops._ -import io.iohk.ethereum.jsonrpc.serialization.{JsonEncoder, JsonMethodCodec, JsonMethodDecoder} +import io.iohk.ethereum.jsonrpc.serialization.JsonMethodCodec +import io.iohk.ethereum.jsonrpc.serialization.JsonMethodDecoder import io.iohk.ethereum.transactions.TransactionHistoryService.ExtendedTransactionData -import org.json4s.JsonAST._ -import org.json4s.Merge + import JsonEncoder.OptionToNull._ object MantisJsonMethodImplicits extends JsonMethodsImplicits { diff --git a/src/main/scala/io/iohk/ethereum/jsonrpc/MantisService.scala b/src/main/scala/io/iohk/ethereum/jsonrpc/MantisService.scala index fdafb33025..6f5c0b2ead 100644 --- a/src/main/scala/io/iohk/ethereum/jsonrpc/MantisService.scala +++ b/src/main/scala/io/iohk/ethereum/jsonrpc/MantisService.scala @@ -1,13 +1,16 @@ package io.iohk.ethereum.jsonrpc +import cats.implicits._ + +import monix.eval.Task + +import scala.collection.immutable.NumericRange + import io.iohk.ethereum.domain.Address -import io.iohk.ethereum.jsonrpc.MantisService.{GetAccountTransactionsRequest, GetAccountTransactionsResponse} +import io.iohk.ethereum.jsonrpc.MantisService.GetAccountTransactionsRequest +import io.iohk.ethereum.jsonrpc.MantisService.GetAccountTransactionsResponse import io.iohk.ethereum.jsonrpc.server.controllers.JsonRpcBaseController.JsonRpcConfig import io.iohk.ethereum.transactions.TransactionHistoryService import io.iohk.ethereum.transactions.TransactionHistoryService.ExtendedTransactionData -import monix.eval.Task -import cats.implicits._ - -import scala.collection.immutable.NumericRange object MantisService { case class GetAccountTransactionsRequest(address: Address, blocksRange: NumericRange[BigInt]) @@ -16,7 +19,7 @@ object MantisService { class MantisService(transactionHistoryService: TransactionHistoryService, jsonRpcConfig: JsonRpcConfig) { def getAccountTransactions( request: GetAccountTransactionsRequest - ): ServiceResponse[GetAccountTransactionsResponse] = { + ): ServiceResponse[GetAccountTransactionsResponse] = if (request.blocksRange.length > jsonRpcConfig.accountTransactionsMaxBlocks) { Task.now( Left( @@ -31,5 +34,4 @@ class MantisService(transactionHistoryService: TransactionHistoryService, jsonRp .getAccountTransactions(request.address, request.blocksRange) .map(GetAccountTransactionsResponse(_).asRight) } - } } diff --git a/src/main/scala/io/iohk/ethereum/jsonrpc/NetService.scala b/src/main/scala/io/iohk/ethereum/jsonrpc/NetService.scala index 94a56e5394..dea2e0a9b4 100644 --- a/src/main/scala/io/iohk/ethereum/jsonrpc/NetService.scala +++ b/src/main/scala/io/iohk/ethereum/jsonrpc/NetService.scala @@ -4,14 +4,18 @@ import java.util.concurrent.atomic.AtomicReference import akka.actor.ActorRef import akka.util.Timeout -import io.iohk.ethereum.jsonrpc.NetService.NetServiceConfig -import io.iohk.ethereum.network.PeerManagerActor -import io.iohk.ethereum.utils.ServerStatus.{Listening, NotListening} -import io.iohk.ethereum.utils.{Config, NodeStatus} + import monix.eval.Task import scala.concurrent.duration._ +import io.iohk.ethereum.jsonrpc.NetService.NetServiceConfig +import io.iohk.ethereum.network.PeerManagerActor +import io.iohk.ethereum.utils.Config +import io.iohk.ethereum.utils.NodeStatus +import io.iohk.ethereum.utils.ServerStatus.Listening +import io.iohk.ethereum.utils.ServerStatus.NotListening + object NetService { case class VersionRequest() case class VersionResponse(value: String) @@ -38,7 +42,7 @@ class NetService(nodeStatusHolder: AtomicReference[NodeStatus], peerManager: Act def version(req: VersionRequest): ServiceResponse[VersionResponse] = Task.now(Right(VersionResponse(Config.Network.peer.networkId.toString))) - def listening(req: ListeningRequest): ServiceResponse[ListeningResponse] = { + def listening(req: ListeningRequest): ServiceResponse[ListeningResponse] = Task.now { Right( nodeStatusHolder.get().serverStatus match { @@ -47,13 +51,12 @@ class NetService(nodeStatusHolder: AtomicReference[NodeStatus], peerManager: Act } ) } - } def peerCount(req: PeerCountRequest): ServiceResponse[PeerCountResponse] = { implicit val timeout: Timeout = Timeout(config.peerManagerTimeout) import io.iohk.ethereum.jsonrpc.AkkaTaskOps._ peerManager .askFor[PeerManagerActor.Peers](PeerManagerActor.GetPeers) - .map { peers => Right(PeerCountResponse(peers.handshaked.size)) } + .map(peers => Right(PeerCountResponse(peers.handshaked.size))) } } diff --git a/src/main/scala/io/iohk/ethereum/jsonrpc/NodeJsonRpcHealthChecker.scala b/src/main/scala/io/iohk/ethereum/jsonrpc/NodeJsonRpcHealthChecker.scala index fd0fee9ddc..806696bf55 100644 --- a/src/main/scala/io/iohk/ethereum/jsonrpc/NodeJsonRpcHealthChecker.scala +++ b/src/main/scala/io/iohk/ethereum/jsonrpc/NodeJsonRpcHealthChecker.scala @@ -1,24 +1,22 @@ package io.iohk.ethereum.jsonrpc -import io.iohk.ethereum.healthcheck.HealthcheckResponse -import io.iohk.ethereum.jsonrpc.EthBlocksService.{ - BlockByNumberRequest, - BlockByNumberResponse, - BestBlockNumberRequest, - BestBlockNumberResponse -} -import io.iohk.ethereum.jsonrpc.EthInfoService._ -import io.iohk.ethereum.jsonrpc.NodeJsonRpcHealthChecker.JsonRpcHealthConfig -import io.iohk.ethereum.jsonrpc.NetService._ -import io.iohk.ethereum.jsonrpc.AkkaTaskOps._ -import com.typesafe.config.{Config => TypesafeConfig} -import monix.eval.Task -import java.time.Instant import java.time.Duration +import java.time.Instant + import akka.actor.ActorRef +import akka.util.Timeout + +import monix.eval.Task + +import com.typesafe.config.{Config => TypesafeConfig} + import io.iohk.ethereum.blockchain.sync.SyncProtocol import io.iohk.ethereum.blockchain.sync.SyncProtocol.Status._ -import akka.util.Timeout +import io.iohk.ethereum.healthcheck.HealthcheckResponse +import io.iohk.ethereum.jsonrpc.AkkaTaskOps._ +import io.iohk.ethereum.jsonrpc.EthBlocksService.BlockByNumberRequest +import io.iohk.ethereum.jsonrpc.NetService._ +import io.iohk.ethereum.jsonrpc.NodeJsonRpcHealthChecker.JsonRpcHealthConfig import io.iohk.ethereum.utils.AsyncConfig class NodeJsonRpcHealthChecker( @@ -76,9 +74,9 @@ class NodeJsonRpcHealthChecker( JsonRpcHealthcheck .fromTask("syncStatus", syncingController.askFor[SyncProtocol.Status](SyncProtocol.GetStatus)) .map(_.withInfo { - case NotSyncing => "STARTING" + case NotSyncing => "STARTING" case s: Syncing if isConsideredSyncing(s.blocksProgress) => "SYNCING" - case _ => "SYNCED" + case _ => "SYNCED" }) override def healthCheck(): Task[HealthcheckResponse] = { diff --git a/src/main/scala/io/iohk/ethereum/jsonrpc/PersonalService.scala b/src/main/scala/io/iohk/ethereum/jsonrpc/PersonalService.scala index 3a5429e4fe..72a4d8a8b9 100644 --- a/src/main/scala/io/iohk/ethereum/jsonrpc/PersonalService.scala +++ b/src/main/scala/io/iohk/ethereum/jsonrpc/PersonalService.scala @@ -1,27 +1,37 @@ package io.iohk.ethereum.jsonrpc import java.time.Duration + import akka.actor.ActorRef -import akka.util.{ByteString, Timeout} +import akka.util.ByteString +import akka.util.Timeout + +import monix.eval.Task + +import scala.util.Try + import io.iohk.ethereum.crypto import io.iohk.ethereum.crypto.ECDSASignature import io.iohk.ethereum.db.storage.AppStateStorage -import io.iohk.ethereum.domain.{Account, Address, Blockchain} +import io.iohk.ethereum.domain.Account +import io.iohk.ethereum.domain.Address +import io.iohk.ethereum.domain.Blockchain import io.iohk.ethereum.jsonrpc.AkkaTaskOps._ -import io.iohk.ethereum.jsonrpc.PersonalService._ import io.iohk.ethereum.jsonrpc.JsonRpcError._ -import io.iohk.ethereum.keystore.{KeyStore, Wallet} -import io.iohk.ethereum.rlp.RLPList -import io.iohk.ethereum.transactions.PendingTransactionsManager -import io.iohk.ethereum.transactions.PendingTransactionsManager.{AddOrOverrideTransaction, PendingTransactionsResponse} -import io.iohk.ethereum.utils.{BlockchainConfig, Logger, TxPoolConfig} +import io.iohk.ethereum.jsonrpc.PersonalService._ +import io.iohk.ethereum.keystore.KeyStore +import io.iohk.ethereum.keystore.Wallet import io.iohk.ethereum.rlp -import io.iohk.ethereum.rlp.RLPImplicits._ import io.iohk.ethereum.rlp.RLPImplicitConversions._ +import io.iohk.ethereum.rlp.RLPImplicits._ +import io.iohk.ethereum.rlp.RLPList +import io.iohk.ethereum.transactions.PendingTransactionsManager +import io.iohk.ethereum.transactions.PendingTransactionsManager.AddOrOverrideTransaction +import io.iohk.ethereum.transactions.PendingTransactionsManager.PendingTransactionsResponse +import io.iohk.ethereum.utils.BlockchainConfig import io.iohk.ethereum.utils.ByteStringUtils.ByteStringOps -import monix.eval.Task - -import scala.util.Try +import io.iohk.ethereum.utils.Logger +import io.iohk.ethereum.utils.TxPoolConfig object PersonalService { @@ -54,10 +64,10 @@ object PersonalService { case class EcRecoverRequest(message: ByteString, signature: ECDSASignature) case class EcRecoverResponse(address: Address) - val InvalidKey = InvalidParams("Invalid key provided, expected 32 bytes (64 hex digits)") - val InvalidAddress = InvalidParams("Invalid address, expected 20 bytes (40 hex digits)") - val InvalidPassphrase = LogicError("Could not decrypt key with given passphrase") - val KeyNotFound = LogicError("No key found for the given address") + val InvalidKey: JsonRpcError = InvalidParams("Invalid key provided, expected 32 bytes (64 hex digits)") + val InvalidAddress: JsonRpcError = InvalidParams("Invalid address, expected 20 bytes (40 hex digits)") + val InvalidPassphrase: JsonRpcError = LogicError("Could not decrypt key with given passphrase") + val KeyNotFound: JsonRpcError = LogicError("No key found for the given address") val PassPhraseTooShort: Int => JsonRpcError = minLength => LogicError(s"Provided passphrase must have at least $minLength characters") @@ -160,7 +170,7 @@ class PersonalService( } } - def sendTransaction(request: SendTransactionRequest): ServiceResponse[SendTransactionResponse] = { + def sendTransaction(request: SendTransactionRequest): ServiceResponse[SendTransactionResponse] = Task(unlockedWallets.get(request.tx.from)).flatMap { case Some(wallet) => val futureTxHash = sendTransaction(request.tx, wallet) @@ -168,16 +178,15 @@ class PersonalService( case None => Task.now(Left(AccountLocked)) } - } def sendIeleTransaction(request: SendIeleTransactionRequest): ServiceResponse[SendTransactionResponse] = { import request.tx val args = tx.arguments.getOrElse(Nil) val dataEither = (tx.function, tx.contractCode) match { - case (Some(function), None) => Right(rlp.encode(RLPList(function, args))) + case (Some(function), None) => Right(rlp.encode(RLPList(function, args))) case (None, Some(contractCode)) => Right(rlp.encode(RLPList(contractCode, args))) - case _ => Left(JsonRpcError.InvalidParams("Iele transaction should contain either functionName or contractCode")) + case _ => Left(JsonRpcError.InvalidParams("Iele transaction should contain either functionName or contractCode")) } dataEither match { @@ -204,7 +213,7 @@ class PersonalService( } latestPendingTxNonceFuture.map { maybeLatestPendingTxNonce => val maybeCurrentNonce = getCurrentAccount(request.from).map(_.nonce.toBigInt) - val maybeNextTxNonce = maybeLatestPendingTxNonce.map(_ + 1) orElse maybeCurrentNonce + val maybeNextTxNonce = maybeLatestPendingTxNonce.map(_ + 1).orElse(maybeCurrentNonce) val tx = request.toTransaction(maybeNextTxNonce.getOrElse(blockchainConfig.accountStartNonce)) val stx = if (blockchain.getBestBlockNumber() >= blockchainConfig.forkBlockNumbers.eip155BlockNumber) { @@ -233,10 +242,10 @@ class PersonalService( } private val handleError: PartialFunction[KeyStore.KeyStoreError, JsonRpcError] = { - case KeyStore.DecryptionFailed => InvalidPassphrase - case KeyStore.KeyNotFound => KeyNotFound + case KeyStore.DecryptionFailed => InvalidPassphrase + case KeyStore.KeyNotFound => KeyNotFound case KeyStore.PassPhraseTooShort(minLength) => PassPhraseTooShort(minLength) - case KeyStore.IOError(msg) => LogicError(msg) - case KeyStore.DuplicateKeySaved => LogicError("account already exists") + case KeyStore.IOError(msg) => LogicError(msg) + case KeyStore.DuplicateKeySaved => LogicError("account already exists") } } diff --git a/src/main/scala/io/iohk/ethereum/jsonrpc/QAJsonMethodsImplicits.scala b/src/main/scala/io/iohk/ethereum/jsonrpc/QAJsonMethodsImplicits.scala index da7f5a836c..232a65a4fc 100644 --- a/src/main/scala/io/iohk/ethereum/jsonrpc/QAJsonMethodsImplicits.scala +++ b/src/main/scala/io/iohk/ethereum/jsonrpc/QAJsonMethodsImplicits.scala @@ -1,17 +1,22 @@ package io.iohk.ethereum.jsonrpc import akka.util.ByteString -import io.iohk.ethereum.jsonrpc.JsonRpcError.InvalidParams -import io.iohk.ethereum.jsonrpc.QAService.{MineBlocksRequest, MineBlocksResponse, _} -import io.iohk.ethereum.jsonrpc.serialization.{JsonEncoder, JsonMethodCodec} -import io.iohk.ethereum.jsonrpc.serialization.JsonMethodDecoder.NoParamsMethodDecoder + import org.json4s.Extraction import org.json4s.JsonAST._ +import io.iohk.ethereum.jsonrpc.JsonRpcError.InvalidParams +import io.iohk.ethereum.jsonrpc.QAService.MineBlocksRequest +import io.iohk.ethereum.jsonrpc.QAService.MineBlocksResponse +import io.iohk.ethereum.jsonrpc.QAService._ +import io.iohk.ethereum.jsonrpc.serialization.JsonEncoder +import io.iohk.ethereum.jsonrpc.serialization.JsonMethodCodec +import io.iohk.ethereum.jsonrpc.serialization.JsonMethodDecoder.NoParamsMethodDecoder + object QAJsonMethodsImplicits extends JsonMethodsImplicits { implicit val qa_mineBlocks: JsonMethodCodec[MineBlocksRequest, MineBlocksResponse] = new JsonMethodCodec[MineBlocksRequest, MineBlocksResponse] { - def decodeJson(params: Option[JArray]): Either[JsonRpcError, MineBlocksRequest] = { + def decodeJson(params: Option[JArray]): Either[JsonRpcError, MineBlocksRequest] = params match { case Some(JArray(JInt(numBlocks) :: JBool(withTransactions) :: Nil)) => Right(MineBlocksRequest(numBlocks.toInt, withTransactions)) @@ -25,7 +30,6 @@ object QAJsonMethodsImplicits extends JsonMethodsImplicits { case _ => Left(InvalidParams()) } - } def encodeJson(t: MineBlocksResponse): JValue = JObject( "responseType" -> JString(t.responseType.entryName), @@ -35,7 +39,7 @@ object QAJsonMethodsImplicits extends JsonMethodsImplicits { implicit val qa_generateCheckpoint: JsonMethodCodec[GenerateCheckpointRequest, GenerateCheckpointResponse] = new JsonMethodCodec[GenerateCheckpointRequest, GenerateCheckpointResponse] { - def decodeJson(params: Option[JArray]): Either[JsonRpcError, GenerateCheckpointRequest] = { + def decodeJson(params: Option[JArray]): Either[JsonRpcError, GenerateCheckpointRequest] = params match { case Some(JArray((keys: JArray) :: JString(hash) :: Nil)) => for { @@ -47,7 +51,6 @@ object QAJsonMethodsImplicits extends JsonMethodsImplicits { case _ => Left(InvalidParams()) } - } def encodeJson(t: GenerateCheckpointResponse): JValue = Extraction.decompose(t.checkpoint) } @@ -56,7 +59,7 @@ object QAJsonMethodsImplicits extends JsonMethodsImplicits { import cats.implicits._ arr.arr.traverse { case JString(key) => extractBytes(key) - case other => Left(InvalidParams(msg = s"Unable to parse private key, expected byte data but got: $other")) + case other => Left(InvalidParams(msg = s"Unable to parse private key, expected byte data but got: $other")) } } diff --git a/src/main/scala/io/iohk/ethereum/jsonrpc/QAService.scala b/src/main/scala/io/iohk/ethereum/jsonrpc/QAService.scala index b3df2cb8e4..edcd0d99b2 100644 --- a/src/main/scala/io/iohk/ethereum/jsonrpc/QAService.scala +++ b/src/main/scala/io/iohk/ethereum/jsonrpc/QAService.scala @@ -2,21 +2,31 @@ package io.iohk.ethereum.jsonrpc import akka.actor.ActorRef import akka.util.ByteString + import cats.implicits._ + +import monix.eval.Task + import enumeratum._ +import mouse.all._ + import io.iohk.ethereum.blockchain.sync.regular.RegularSync.NewCheckpoint import io.iohk.ethereum.consensus._ import io.iohk.ethereum.consensus.blocks.CheckpointBlockGenerator +import io.iohk.ethereum.consensus.pow.miners.MockedMiner.MineBlocks +import io.iohk.ethereum.consensus.pow.miners.MockedMiner.MockedMinerResponse +import io.iohk.ethereum.consensus.pow.miners.MockedMiner.MockedMinerResponses import io.iohk.ethereum.consensus.pow.miners.MockedMiner.MockedMinerResponses._ -import io.iohk.ethereum.consensus.pow.miners.MockedMiner.{MineBlocks, MockedMinerResponse, MockedMinerResponses} import io.iohk.ethereum.crypto import io.iohk.ethereum.crypto.ECDSASignature -import io.iohk.ethereum.domain.{Block, Blockchain, BlockchainReader, Checkpoint} +import io.iohk.ethereum.domain.Block +import io.iohk.ethereum.domain.Blockchain +import io.iohk.ethereum.domain.BlockchainReader +import io.iohk.ethereum.domain.Checkpoint import io.iohk.ethereum.jsonrpc.QAService.MineBlocksResponse.MinerResponseType import io.iohk.ethereum.jsonrpc.QAService._ -import io.iohk.ethereum.utils.{BlockchainConfig, Logger} -import monix.eval.Task -import mouse.all._ +import io.iohk.ethereum.utils.BlockchainConfig +import io.iohk.ethereum.utils.Logger class QAService( consensus: Consensus, @@ -27,13 +37,12 @@ class QAService( syncController: ActorRef ) extends Logger { - /** - * qa_mineBlocks that instructs mocked miner to mine given number of blocks + /** qa_mineBlocks that instructs mocked miner to mine given number of blocks * * @param req with requested block's data * @return nothing */ - def mineBlocks(req: MineBlocksRequest): ServiceResponse[MineBlocksResponse] = { + def mineBlocks(req: MineBlocksRequest): ServiceResponse[MineBlocksResponse] = consensus .askMiner(MineBlocks(req.numBlocks, req.withTransactions, req.parentBlock)) .map(_ |> (MineBlocksResponse(_)) |> (_.asRight)) @@ -41,7 +50,6 @@ class QAService( log.warn("Unable to mine requested blocks", throwable) Left(JsonRpcError.InternalError) } - } def generateCheckpoint( req: GenerateCheckpointRequest @@ -74,11 +82,10 @@ class QAService( def getFederationMembersInfo( req: GetFederationMembersInfoRequest - ): ServiceResponse[GetFederationMembersInfoResponse] = { + ): ServiceResponse[GetFederationMembersInfoResponse] = Task { Right(GetFederationMembersInfoResponse(blockchainConfig.checkpointPubKeys.toList)) } - } } object QAService { @@ -90,8 +97,8 @@ object QAService { private def extractMessage(response: MockedMinerResponse): Option[String] = response match { case MinerIsWorking | MiningOrdered | MinerNotExist => None - case MiningError(msg) => Some(msg) - case MinerNotSupported(msg) => Some(msg.toString) + case MiningError(msg) => Some(msg) + case MinerNotSupported(msg) => Some(msg.toString) } sealed trait MinerResponseType extends EnumEntry @@ -105,10 +112,10 @@ object QAService { case object MinerNotSupport extends MinerResponseType def apply(minerResponse: MockedMinerResponse): MinerResponseType = minerResponse match { - case MockedMinerResponses.MinerIsWorking => MinerIsWorking - case MockedMinerResponses.MiningOrdered => MiningOrdered - case MockedMinerResponses.MinerNotExist => MinerNotExist - case MockedMinerResponses.MiningError(_) => MiningError + case MockedMinerResponses.MinerIsWorking => MinerIsWorking + case MockedMinerResponses.MiningOrdered => MiningOrdered + case MockedMinerResponses.MinerNotExist => MinerNotExist + case MockedMinerResponses.MiningError(_) => MiningError case MockedMinerResponses.MinerNotSupported(_) => MinerNotSupport } } diff --git a/src/main/scala/io/iohk/ethereum/jsonrpc/RawTransactionCodec.scala b/src/main/scala/io/iohk/ethereum/jsonrpc/RawTransactionCodec.scala index cbe839b17d..07010d4ba7 100644 --- a/src/main/scala/io/iohk/ethereum/jsonrpc/RawTransactionCodec.scala +++ b/src/main/scala/io/iohk/ethereum/jsonrpc/RawTransactionCodec.scala @@ -1,6 +1,7 @@ package io.iohk.ethereum.jsonrpc import akka.util.ByteString + import io.iohk.ethereum.domain.SignedTransaction import io.iohk.ethereum.network.p2p.messages.BaseETH6XMessages.SignedTransactions.SignedTransactionEnc import io.iohk.ethereum.rlp diff --git a/src/main/scala/io/iohk/ethereum/jsonrpc/ResolveBlock.scala b/src/main/scala/io/iohk/ethereum/jsonrpc/ResolveBlock.scala index d813d76c93..6fd83234e5 100644 --- a/src/main/scala/io/iohk/ethereum/jsonrpc/ResolveBlock.scala +++ b/src/main/scala/io/iohk/ethereum/jsonrpc/ResolveBlock.scala @@ -1,8 +1,8 @@ package io.iohk.ethereum.jsonrpc -import io.iohk.ethereum.domain._ -import io.iohk.ethereum.ledger.{InMemoryWorldStateProxy, StxLedger} import io.iohk.ethereum.consensus.Consensus +import io.iohk.ethereum.domain._ +import io.iohk.ethereum.ledger.InMemoryWorldStateProxy sealed trait BlockParam @@ -20,24 +20,22 @@ trait ResolveBlock { def blockchainReader: BlockchainReader def consensus: Consensus - def resolveBlock(blockParam: BlockParam): Either[JsonRpcError, ResolvedBlock] = { + def resolveBlock(blockParam: BlockParam): Either[JsonRpcError, ResolvedBlock] = blockParam match { case BlockParam.WithNumber(blockNumber) => getBlock(blockNumber).map(ResolvedBlock(_, pendingState = None)) - case BlockParam.Earliest => getBlock(0).map(ResolvedBlock(_, pendingState = None)) - case BlockParam.Latest => getLatestBlock().map(ResolvedBlock(_, pendingState = None)) + case BlockParam.Earliest => getBlock(0).map(ResolvedBlock(_, pendingState = None)) + case BlockParam.Latest => getLatestBlock().map(ResolvedBlock(_, pendingState = None)) case BlockParam.Pending => consensus.blockGenerator.getPendingBlockAndState .map(pb => ResolvedBlock(pb.pendingBlock.block, pendingState = Some(pb.worldState))) .map(Right.apply) .getOrElse(resolveBlock(BlockParam.Latest)) //Default behavior in other clients } - } - private def getBlock(number: BigInt): Either[JsonRpcError, Block] = { + private def getBlock(number: BigInt): Either[JsonRpcError, Block] = blockchainReader .getBlockByNumber(number) .toRight(JsonRpcError.InvalidParams(s"Block $number not found")) - } private def getLatestBlock(): Either[JsonRpcError, Block] = blockchain diff --git a/src/main/scala/io/iohk/ethereum/jsonrpc/TestJsonMethodsImplicits.scala b/src/main/scala/io/iohk/ethereum/jsonrpc/TestJsonMethodsImplicits.scala index fd11633e77..d6c3e6b3e2 100644 --- a/src/main/scala/io/iohk/ethereum/jsonrpc/TestJsonMethodsImplicits.scala +++ b/src/main/scala/io/iohk/ethereum/jsonrpc/TestJsonMethodsImplicits.scala @@ -1,18 +1,22 @@ package io.iohk.ethereum.jsonrpc import akka.util.ByteString -import io.iohk.ethereum.jsonrpc.JsonRpcError.InvalidParams -import io.iohk.ethereum.jsonrpc.TestService._ -import io.iohk.ethereum.jsonrpc.serialization.{JsonEncoder, JsonMethodDecoder} -import org.json4s.JsonAST._ -import org.json4s.JsonDSL._ + import cats.implicits._ -import io.iohk.ethereum.blockchain.data.GenesisAccount import scala.util.Try + +import org.json4s.Extraction +import org.json4s.JsonAST._ +import org.json4s.JsonDSL._ + +import io.iohk.ethereum.blockchain.data.GenesisAccount import io.iohk.ethereum.domain.UInt256 +import io.iohk.ethereum.jsonrpc.JsonRpcError.InvalidParams +import io.iohk.ethereum.jsonrpc.TestService._ +import io.iohk.ethereum.jsonrpc.serialization.JsonEncoder +import io.iohk.ethereum.jsonrpc.serialization.JsonMethodDecoder import io.iohk.ethereum.testmode.SealEngineType -import org.json4s.Extraction object TestJsonMethodsImplicits extends JsonMethodsImplicits { @@ -69,11 +73,11 @@ object TestJsonMethodsImplicits extends JsonMethodsImplicits { private def extractSealEngine(str: String) = str match { case "NoReward" => Right(SealEngineType.NoReward) - case "NoProof" => Right(SealEngineType.NoProof) - case other => Left(InvalidParams(s"unknown seal engine $other")) + case "NoProof" => Right(SealEngineType.NoProof) + case other => Left(InvalidParams(s"unknown seal engine $other")) } - private def extractGenesis(genesisJson: JValue): Either[JsonRpcError, GenesisParams] = { + private def extractGenesis(genesisJson: JValue): Either[JsonRpcError, GenesisParams] = for { author <- extractBytes((genesisJson \ "author").extract[String]) difficulty = (genesisJson \ "difficulty").extractOrElse("0") @@ -84,9 +88,8 @@ object TestJsonMethodsImplicits extends JsonMethodsImplicits { nonce <- extractBytes((genesisJson \ "nonce").extract[String]) mixHash <- extractBytes((genesisJson \ "mixHash").extract[String]) } yield GenesisParams(author, difficulty, extraData, gasLimit, parentHash, timestamp, nonce, mixHash) - } - private def extractBlockchainParams(blockchainParamsJson: JValue): Either[JsonRpcError, BlockchainParams] = { + private def extractBlockchainParams(blockchainParamsJson: JValue): Either[JsonRpcError, BlockchainParams] = for { eIP150ForkBlock <- optionalQuantity(blockchainParamsJson \ "EIP150ForkBlock") eIP158ForkBlock <- optionalQuantity(blockchainParamsJson \ "EIP158ForkBlock") @@ -109,7 +112,6 @@ object TestJsonMethodsImplicits extends JsonMethodsImplicits { constantinopleForkBlock = constantinopleForkBlock, istanbulForkBlock = istanbulForkBlock ) - } override def encodeJson(t: SetChainParamsResponse): JValue = true } diff --git a/src/main/scala/io/iohk/ethereum/jsonrpc/TestService.scala b/src/main/scala/io/iohk/ethereum/jsonrpc/TestService.scala index 2e205abe90..5411ab1a2c 100644 --- a/src/main/scala/io/iohk/ethereum/jsonrpc/TestService.scala +++ b/src/main/scala/io/iohk/ethereum/jsonrpc/TestService.scala @@ -1,28 +1,48 @@ package io.iohk.ethereum.jsonrpc import akka.actor.ActorRef -import akka.util.{ByteString, Timeout} -import io.iohk.ethereum.blockchain.data.{GenesisAccount, GenesisData, GenesisDataLoader} +import akka.util.ByteString +import akka.util.Timeout + +import monix.eval.Task +import monix.execution.Scheduler + +import scala.concurrent.duration._ +import scala.util.Failure +import scala.util.Success +import scala.util.Try + +import org.bouncycastle.util.encoders.Hex + +import io.iohk.ethereum.blockchain.data.GenesisAccount +import io.iohk.ethereum.blockchain.data.GenesisData +import io.iohk.ethereum.blockchain.data.GenesisDataLoader import io.iohk.ethereum.consensus.ConsensusConfig import io.iohk.ethereum.consensus.blocks._ +import io.iohk.ethereum.crypto import io.iohk.ethereum.crypto.kec256 -import io.iohk.ethereum.db.storage.{StateStorage, TransactionMappingStorage} -import io.iohk.ethereum.{crypto, domain, rlp} +import io.iohk.ethereum.db.storage.StateStorage +import io.iohk.ethereum.db.storage.TransactionMappingStorage +import io.iohk.ethereum.domain +import io.iohk.ethereum.domain.Account +import io.iohk.ethereum.domain.Address +import io.iohk.ethereum.domain.Block import io.iohk.ethereum.domain.Block._ -import io.iohk.ethereum.domain.{Account, Address, Block, BlockchainImpl, BlockchainReader, UInt256} +import io.iohk.ethereum.domain.BlockchainImpl +import io.iohk.ethereum.domain.BlockchainReader +import io.iohk.ethereum.domain.UInt256 +import io.iohk.ethereum.jsonrpc.JsonMethodsImplicits._ import io.iohk.ethereum.ledger._ -import io.iohk.ethereum.testmode.{SealEngineType, TestModeComponentsProvider} +import io.iohk.ethereum.rlp +import io.iohk.ethereum.rlp.RLPList +import io.iohk.ethereum.testmode.SealEngineType +import io.iohk.ethereum.testmode.TestModeComponentsProvider import io.iohk.ethereum.transactions.PendingTransactionsManager import io.iohk.ethereum.transactions.PendingTransactionsManager.PendingTransactionsResponse -import io.iohk.ethereum.utils.{BlockchainConfig, ByteStringUtils, ForkBlockNumbers, Logger} -import monix.eval.Task -import monix.execution.Scheduler -import org.bouncycastle.util.encoders.Hex -import io.iohk.ethereum.jsonrpc.JsonMethodsImplicits._ -import io.iohk.ethereum.rlp.RLPList - -import scala.concurrent.duration._ -import scala.util.{Failure, Success, Try} +import io.iohk.ethereum.utils.BlockchainConfig +import io.iohk.ethereum.utils.ByteStringUtils +import io.iohk.ethereum.utils.ForkBlockNumbers +import io.iohk.ethereum.utils.Logger object TestService { case class GenesisParams( @@ -175,10 +195,10 @@ class TestService( storeGenesisAccountStorageData(genesisData.alloc) accountHashWithAdresses = (etherbase.toUnprefixedString :: genesisData.alloc.keys.toList) - .map(hexAddress => { + .map { hexAddress => val address = Address(hexAddress) crypto.kec256(address.bytes) -> address - }) + } .sortBy(v => UInt256(v._1)) SetChainParamsResponse().rightNow @@ -223,7 +243,7 @@ class TestService( private def storeGenesisAccountCodes(accounts: Map[String, GenesisAccount]): Unit = accounts .collect { case (_, GenesisAccount(_, _, Some(code), _, _)) => code } - .foreach { code => blockchain.storeEvmCode(kec256(code), code).commit() } + .foreach(code => blockchain.storeEvmCode(kec256(code), code).commit()) private def storeGenesisAccountStorageData(accounts: Map[String, GenesisAccount]): Unit = { val emptyStorage = domain.EthereumUInt256Mpt.storageMpt( @@ -240,7 +260,7 @@ class TestService( } def mineBlocks(request: MineBlocksRequest): ServiceResponse[MineBlocksResponse] = { - def mineBlock(): Task[Unit] = { + def mineBlock(): Task[Unit] = getBlockForMining(blockchain.getBestBlock().get) .flatMap(blockForMining => testModeComponentsProvider @@ -252,7 +272,6 @@ class TestService( pendingTransactionsManager ! PendingTransactionsManager.ClearPendingTransactions blockTimestamp += 1 } - } def doNTimesF(n: Int)(fn: Task[Unit]): Task[Unit] = fn.flatMap { _ => if (n <= 1) Task.unit @@ -275,7 +294,7 @@ class TestService( RewindToBlockResponse().rightNow } - def importRawBlock(request: ImportRawBlockRequest): ServiceResponse[ImportRawBlockResponse] = { + def importRawBlock(request: ImportRawBlockRequest): ServiceResponse[ImportRawBlockResponse] = Try(decode(request.blockRlp).toBlock) match { case Failure(_) => Task.now(Left(JsonRpcError(-1, "block validation failed!", None))) @@ -285,11 +304,10 @@ class TestService( .importBlock(value) .flatMap(handleResult(value)) } - } private def handleResult( block: Block - )(blockImportResult: BlockImportResult): ServiceResponse[ImportRawBlockResponse] = { + )(blockImportResult: BlockImportResult): ServiceResponse[ImportRawBlockResponse] = blockImportResult match { case BlockImportedToTop(blockImportData) => val blockHash = s"0x${ByteStringUtils.hash2string(blockImportData.head.block.header.hash)}" @@ -301,7 +319,6 @@ class TestService( log.warn("Block import failed with {}", e) Task.now(Left(JsonRpcError(-1, "block validation failed!", None))) } - } def setEtherbase(req: SetEtherbaseRequest): ServiceResponse[SetEtherbaseResponse] = { etherbase = req.etherbase @@ -314,9 +331,7 @@ class TestService( (_, account) <- genesisData.alloc storage <- account.storage storageKey <- storage.keys - } { - preimageCache.put(crypto.kec256(storageKey.bytes), storageKey) - } + } preimageCache.put(crypto.kec256(storageKey.bytes), storageKey) } private def getBlockForMining(parentBlock: Block): Task[PendingBlock] = { @@ -444,7 +459,7 @@ class TestService( private val emptyLogRlpHash: ByteString = ByteString(crypto.kec256(rlp.encode(RLPList()))) - private implicit class RichResponse[A](response: A) { + implicit private class RichResponse[A](response: A) { def rightNow: Task[Either[JsonRpcError, A]] = Task.now(Right(response)) } } diff --git a/src/main/scala/io/iohk/ethereum/jsonrpc/TransactionReceiptResponse.scala b/src/main/scala/io/iohk/ethereum/jsonrpc/TransactionReceiptResponse.scala index ac646d4354..054ba16e1c 100644 --- a/src/main/scala/io/iohk/ethereum/jsonrpc/TransactionReceiptResponse.scala +++ b/src/main/scala/io/iohk/ethereum/jsonrpc/TransactionReceiptResponse.scala @@ -1,25 +1,23 @@ package io.iohk.ethereum.jsonrpc import akka.util.ByteString + import io.iohk.ethereum.crypto.kec256 -import io.iohk.ethereum.domain.{ - Address, - BlockHeader, - FailureOutcome, - HashOutcome, - Receipt, - SignedTransaction, - SuccessOutcome, - UInt256 -} +import io.iohk.ethereum.domain.Address +import io.iohk.ethereum.domain.BlockHeader +import io.iohk.ethereum.domain.FailureOutcome +import io.iohk.ethereum.domain.HashOutcome +import io.iohk.ethereum.domain.Receipt +import io.iohk.ethereum.domain.SignedTransaction +import io.iohk.ethereum.domain.SuccessOutcome +import io.iohk.ethereum.domain.UInt256 import io.iohk.ethereum.jsonrpc.FilterManager.TxLog import io.iohk.ethereum.rlp -import io.iohk.ethereum.rlp.RLPList import io.iohk.ethereum.rlp.RLPImplicitConversions._ +import io.iohk.ethereum.rlp.RLPList import io.iohk.ethereum.rlp.UInt256RLPImplicits._ -/** - * Params docs copied from - https://eth.wiki/json-rpc/API +/** Params docs copied from - https://eth.wiki/json-rpc/API * * @param transactionHash DATA, 32 Bytes - hash of the transaction. * @param transactionIndex QUANTITY - integer of the transactions index position in the block. @@ -82,8 +80,8 @@ object TransactionReceiptResponse { } val (root, status) = receipt.postTransactionStateHash match { - case FailureOutcome => (None, Some(BigInt(0))) - case SuccessOutcome => (None, Some(BigInt(1))) + case FailureOutcome => (None, Some(BigInt(0))) + case SuccessOutcome => (None, Some(BigInt(1))) case HashOutcome(stateHash) => (Some(stateHash), None) } diff --git a/src/main/scala/io/iohk/ethereum/jsonrpc/TransactionRequest.scala b/src/main/scala/io/iohk/ethereum/jsonrpc/TransactionRequest.scala index 40a1023501..a93a153f1c 100644 --- a/src/main/scala/io/iohk/ethereum/jsonrpc/TransactionRequest.scala +++ b/src/main/scala/io/iohk/ethereum/jsonrpc/TransactionRequest.scala @@ -1,7 +1,9 @@ package io.iohk.ethereum.jsonrpc import akka.util.ByteString -import io.iohk.ethereum.domain.{Address, Transaction} + +import io.iohk.ethereum.domain.Address +import io.iohk.ethereum.domain.Transaction import io.iohk.ethereum.utils.Config case class TransactionRequest( diff --git a/src/main/scala/io/iohk/ethereum/jsonrpc/TransactionResponse.scala b/src/main/scala/io/iohk/ethereum/jsonrpc/TransactionResponse.scala index cf2b628ddb..35ef9bf19f 100644 --- a/src/main/scala/io/iohk/ethereum/jsonrpc/TransactionResponse.scala +++ b/src/main/scala/io/iohk/ethereum/jsonrpc/TransactionResponse.scala @@ -1,7 +1,9 @@ package io.iohk.ethereum.jsonrpc import akka.util.ByteString -import io.iohk.ethereum.domain.{BlockHeader, SignedTransaction, UInt256} + +import io.iohk.ethereum.domain.BlockHeader +import io.iohk.ethereum.domain.SignedTransaction trait BaseTransactionResponse { def hash: ByteString diff --git a/src/main/scala/io/iohk/ethereum/jsonrpc/Web3Service.scala b/src/main/scala/io/iohk/ethereum/jsonrpc/Web3Service.scala index 56e4e26319..8f2c3a6524 100644 --- a/src/main/scala/io/iohk/ethereum/jsonrpc/Web3Service.scala +++ b/src/main/scala/io/iohk/ethereum/jsonrpc/Web3Service.scala @@ -1,9 +1,11 @@ package io.iohk.ethereum.jsonrpc import akka.util.ByteString + +import monix.eval.Task + import io.iohk.ethereum.crypto import io.iohk.ethereum.utils.Config -import monix.eval.Task object Web3Service { case class Sha3Request(data: ByteString) @@ -16,11 +18,9 @@ object Web3Service { class Web3Service { import Web3Service._ - def sha3(req: Sha3Request): ServiceResponse[Sha3Response] = { + def sha3(req: Sha3Request): ServiceResponse[Sha3Response] = Task(Right(Sha3Response(crypto.kec256(req.data)))) - } - def clientVersion(req: ClientVersionRequest): ServiceResponse[ClientVersionResponse] = { + def clientVersion(req: ClientVersionRequest): ServiceResponse[ClientVersionResponse] = Task(Right(ClientVersionResponse(Config.clientVersion))) - } } diff --git a/src/main/scala/io/iohk/ethereum/jsonrpc/client/CommonJsonCodecs.scala b/src/main/scala/io/iohk/ethereum/jsonrpc/client/CommonJsonCodecs.scala index cf44a45992..fea13cd7a7 100644 --- a/src/main/scala/io/iohk/ethereum/jsonrpc/client/CommonJsonCodecs.scala +++ b/src/main/scala/io/iohk/ethereum/jsonrpc/client/CommonJsonCodecs.scala @@ -1,14 +1,16 @@ package io.iohk.ethereum.jsonrpc.client import akka.util.ByteString + +import scala.util.Try + import io.circe._ import io.circe.syntax._ +import org.bouncycastle.util.encoders.Hex + import io.iohk.ethereum.domain.Address import io.iohk.ethereum.utils.NumericUtils._ import io.iohk.ethereum.utils.StringUtils -import org.bouncycastle.util.encoders.Hex - -import scala.util.Try object CommonJsonCodecs { implicit val decodeBigInt: Decoder[BigInt] = { (c: HCursor) => diff --git a/src/main/scala/io/iohk/ethereum/jsonrpc/client/RpcClient.scala b/src/main/scala/io/iohk/ethereum/jsonrpc/client/RpcClient.scala index 8a212afce8..5d7a1abc61 100644 --- a/src/main/scala/io/iohk/ethereum/jsonrpc/client/RpcClient.scala +++ b/src/main/scala/io/iohk/ethereum/jsonrpc/client/RpcClient.scala @@ -1,27 +1,33 @@ package io.iohk.ethereum.jsonrpc.client -import java.io.{PrintWriter, StringWriter} import java.util.UUID +import javax.net.ssl.SSLContext import akka.actor.ActorSystem +import akka.http.scaladsl.ConnectionContext +import akka.http.scaladsl.Http +import akka.http.scaladsl.HttpsConnectionContext import akka.http.scaladsl.model._ -import akka.http.scaladsl.settings.{ClientConnectionSettings, ConnectionPoolSettings} +import akka.http.scaladsl.settings.ClientConnectionSettings +import akka.http.scaladsl.settings.ConnectionPoolSettings import akka.http.scaladsl.unmarshalling.Unmarshal -import akka.http.scaladsl.{ConnectionContext, Http, HttpsConnectionContext} import akka.stream.StreamTcpException import akka.stream.scaladsl.TcpIdleTimeoutException + +import monix.eval.Task + +import scala.concurrent.ExecutionContext +import scala.concurrent.duration._ + +import io.circe.Decoder +import io.circe.Json import io.circe.generic.auto._ import io.circe.parser.parse import io.circe.syntax._ -import io.circe.{Decoder, Json} + import io.iohk.ethereum.jsonrpc.JsonRpcError import io.iohk.ethereum.security.SSLError import io.iohk.ethereum.utils.Logger -import javax.net.ssl.SSLContext -import monix.eval.Task - -import scala.concurrent.ExecutionContext -import scala.concurrent.duration._ abstract class RpcClient(node: Uri, timeout: Duration, getSSLContext: () => Either[SSLError, SSLContext])(implicit system: ActorSystem, @@ -42,9 +48,8 @@ abstract class RpcClient(node: Uri, timeout: Duration, getSSLContext: () => Eith .withIdleTimeout(timeout) ) - protected def doRequest[T: Decoder](method: String, args: Seq[Json]): RpcResponse[T] = { + protected def doRequest[T: Decoder](method: String, args: Seq[Json]): RpcResponse[T] = doJsonRequest(method, args).map(_.flatMap(getResult[T])) - } protected def doJsonRequest( method: String, @@ -55,14 +60,13 @@ abstract class RpcClient(node: Uri, timeout: Duration, getSSLContext: () => Eith makeRpcCall(request.asJson) } - private def getResult[T: Decoder](jsonResponse: Json): Either[RpcError, T] = { + private def getResult[T: Decoder](jsonResponse: Json): Either[RpcError, T] = jsonResponse.hcursor.downField("error").as[JsonRpcError] match { case Right(error) => Left(RpcClientError(s"Node returned an error: ${error.message} (${error.code})")) case Left(_) => jsonResponse.hcursor.downField("result").as[T].left.map(f => RpcClientError(f.message)) } - } private def makeRpcCall(jsonRequest: Json): Task[Either[RpcError, Json]] = { val entity = HttpEntity(ContentTypes.`application/json`, jsonRequest.noSpaces) @@ -88,21 +92,13 @@ abstract class RpcClient(node: Uri, timeout: Duration, getSSLContext: () => Eith } } - private def prepareJsonRequest(method: String, args: Seq[Json]): Json = { + private def prepareJsonRequest(method: String, args: Seq[Json]): Json = Map( "jsonrpc" -> "2.0".asJson, "method" -> method.asJson, "params" -> args.asJson, "id" -> s"${UUID.randomUUID()}".asJson ).asJson - } - - private def exceptionToString(ex: Throwable): String = { - val sw = new StringWriter() - sw.append(ex.getMessage + "\n") - ex.printStackTrace(new PrintWriter(sw)) - sw.toString - } } diff --git a/src/main/scala/io/iohk/ethereum/jsonrpc/serialization/JsonEncoder.scala b/src/main/scala/io/iohk/ethereum/jsonrpc/serialization/JsonEncoder.scala index 2843b42a9e..d462e8b8be 100644 --- a/src/main/scala/io/iohk/ethereum/jsonrpc/serialization/JsonEncoder.scala +++ b/src/main/scala/io/iohk/ethereum/jsonrpc/serialization/JsonEncoder.scala @@ -1,7 +1,14 @@ package io.iohk.ethereum.jsonrpc.serialization +import org.json4s.JArray +import org.json4s.JBool +import org.json4s.JInt +import org.json4s.JLong +import org.json4s.JNull +import org.json4s.JString +import org.json4s.JValue + import io.iohk.ethereum.jsonrpc.JsonMethodsImplicits -import org.json4s.{JArray, JBool, JInt, JLong, JNull, JString, JValue} trait JsonEncoder[T] { def encodeJson(t: T): JValue @@ -30,7 +37,7 @@ object JsonEncoder { trait OptionToNull { implicit def optionToNullEncoder[T](implicit valueEncoder: JsonEncoder[T]): JsonEncoder[Option[T]] = { case Some(value) => valueEncoder.encodeJson(value) - case None => JNull + case None => JNull } } object OptionToNull extends OptionToNull diff --git a/src/main/scala/io/iohk/ethereum/jsonrpc/serialization/JsonMethodDecoder.scala b/src/main/scala/io/iohk/ethereum/jsonrpc/serialization/JsonMethodDecoder.scala index d336d5c2a8..997e54596e 100644 --- a/src/main/scala/io/iohk/ethereum/jsonrpc/serialization/JsonMethodDecoder.scala +++ b/src/main/scala/io/iohk/ethereum/jsonrpc/serialization/JsonMethodDecoder.scala @@ -1,8 +1,9 @@ package io.iohk.ethereum.jsonrpc.serialization +import org.json4s.JsonAST.JArray + import io.iohk.ethereum.jsonrpc.JsonRpcError import io.iohk.ethereum.jsonrpc.JsonRpcError.InvalidParams -import org.json4s.JsonAST.JArray trait JsonMethodDecoder[T] { def decodeJson(params: Option[JArray]): Either[JsonRpcError, T] @@ -12,7 +13,7 @@ object JsonMethodDecoder { def decodeJson(params: Option[JArray]): Either[JsonRpcError, T] = params match { case None | Some(JArray(Nil)) => Right(request) - case _ => Left(InvalidParams(s"No parameters expected")) + case _ => Left(InvalidParams(s"No parameters expected")) } } } diff --git a/src/main/scala/io/iohk/ethereum/jsonrpc/serialization/JsonSerializers.scala b/src/main/scala/io/iohk/ethereum/jsonrpc/serialization/JsonSerializers.scala index e9ca9ce9dd..b8b63132f1 100644 --- a/src/main/scala/io/iohk/ethereum/jsonrpc/serialization/JsonSerializers.scala +++ b/src/main/scala/io/iohk/ethereum/jsonrpc/serialization/JsonSerializers.scala @@ -1,10 +1,16 @@ package io.iohk.ethereum.jsonrpc.serialization import akka.util.ByteString + +import org.bouncycastle.util.encoders.Hex +import org.json4s.CustomSerializer +import org.json4s.DefaultFormats +import org.json4s.Formats +import org.json4s.JNull +import org.json4s.JString + import io.iohk.ethereum.domain.Address import io.iohk.ethereum.jsonrpc.JsonRpcError -import org.bouncycastle.util.encoders.Hex -import org.json4s.{CustomSerializer, DefaultFormats, Formats, JNull, JString} object JsonSerializers { implicit val formats: Formats = @@ -13,7 +19,7 @@ object JsonSerializers { object UnformattedDataJsonSerializer extends CustomSerializer[ByteString](_ => ( - { PartialFunction.empty }, + PartialFunction.empty, { case bs: ByteString => JString(s"0x${Hex.toHexString(bs.toArray)}") } ) ) @@ -21,7 +27,7 @@ object JsonSerializers { object QuantitiesSerializer extends CustomSerializer[BigInt](_ => ( - { PartialFunction.empty }, + PartialFunction.empty, { case n: BigInt => if (n == 0) JString("0x0") @@ -34,7 +40,7 @@ object JsonSerializers { object OptionNoneToJNullSerializer extends CustomSerializer[Option[_]](formats => ( - { PartialFunction.empty }, + PartialFunction.empty, { case None => JNull } ) ) @@ -42,7 +48,7 @@ object JsonSerializers { object AddressJsonSerializer extends CustomSerializer[Address](_ => ( - { PartialFunction.empty }, + PartialFunction.empty, { case addr: Address => JString(s"0x${Hex.toHexString(addr.bytes.toArray)}") } ) ) @@ -50,7 +56,7 @@ object JsonSerializers { object RpcErrorJsonSerializer extends CustomSerializer[JsonRpcError](_ => ( - { PartialFunction.empty }, + PartialFunction.empty, { case err: JsonRpcError => JsonEncoder.encode(err) } ) ) diff --git a/src/main/scala/io/iohk/ethereum/jsonrpc/server/controllers/JsonRpcBaseController.scala b/src/main/scala/io/iohk/ethereum/jsonrpc/server/controllers/JsonRpcBaseController.scala index 1040293943..dd04965d3e 100644 --- a/src/main/scala/io/iohk/ethereum/jsonrpc/server/controllers/JsonRpcBaseController.scala +++ b/src/main/scala/io/iohk/ethereum/jsonrpc/server/controllers/JsonRpcBaseController.scala @@ -1,26 +1,33 @@ package io.iohk.ethereum.jsonrpc.server.controllers -import java.util.concurrent.TimeUnit +import java.time.Duration import cats.syntax.all._ -import com.typesafe.config.{Config => TypesafeConfig} -import io.iohk.ethereum.jsonrpc.JsonRpcError.{InternalError, MethodNotFound} -import io.iohk.ethereum.jsonrpc.serialization.{JsonEncoder, JsonMethodDecoder} -import io.iohk.ethereum.jsonrpc.server.http.JsonRpcHttpServer.JsonRpcHttpServerConfig -import io.iohk.ethereum.jsonrpc.server.ipc.JsonRpcIpcServer.JsonRpcIpcServerConfig -import io.iohk.ethereum.jsonrpc.{JsonRpcControllerMetrics, JsonRpcError, JsonRpcRequest, JsonRpcResponse} -import io.iohk.ethereum.jsonrpc.NodeJsonRpcHealthChecker.JsonRpcHealthConfig -import io.iohk.ethereum.utils.Logger + import monix.eval.Task -import org.json4s.JsonDSL._ -import org.json4s.{DefaultFormats, native} import scala.collection.immutable.ArraySeq import scala.concurrent.ExecutionContext import scala.concurrent.duration.FiniteDuration -import io.micrometer.core.instrument.Timer -import io.micrometer.core.annotation.Timed -import java.time.Duration + +import com.typesafe.config.{Config => TypesafeConfig} +import org.json4s.DefaultFormats +import org.json4s.JsonDSL._ +import org.json4s.native +import org.json4s.native.Serialization + +import io.iohk.ethereum.jsonrpc.JsonRpcControllerMetrics +import io.iohk.ethereum.jsonrpc.JsonRpcError +import io.iohk.ethereum.jsonrpc.JsonRpcError.InternalError +import io.iohk.ethereum.jsonrpc.JsonRpcError.MethodNotFound +import io.iohk.ethereum.jsonrpc.JsonRpcRequest +import io.iohk.ethereum.jsonrpc.JsonRpcResponse +import io.iohk.ethereum.jsonrpc.NodeJsonRpcHealthChecker.JsonRpcHealthConfig +import io.iohk.ethereum.jsonrpc.serialization.JsonEncoder +import io.iohk.ethereum.jsonrpc.serialization.JsonMethodDecoder +import io.iohk.ethereum.jsonrpc.server.http.JsonRpcHttpServer.JsonRpcHttpServerConfig +import io.iohk.ethereum.jsonrpc.server.ipc.JsonRpcIpcServer.JsonRpcIpcServerConfig +import io.iohk.ethereum.utils.Logger trait ApisBase { def available: List[String] @@ -31,8 +38,7 @@ trait JsonRpcBaseController { import JsonRpcBaseController._ - /** - * FIXME: We are making mandatory to pass a config in all the Controllers that implements this trait + /** FIXME: We are making mandatory to pass a config in all the Controllers that implements this trait * when it is just used for the disabled methods. * We should change this behaviour in order to remove this unnecessary dependency. */ @@ -43,9 +49,9 @@ trait JsonRpcBaseController { def enabledApis: Seq[String] - implicit val formats = DefaultFormats + implicit val formats: DefaultFormats.type = DefaultFormats - implicit val serialization = native.Serialization + implicit val serialization: Serialization.type = native.Serialization def handleRequest(request: JsonRpcRequest): Task[JsonRpcResponse] = { val startTimeNanos = System.nanoTime() @@ -58,7 +64,7 @@ trait JsonRpcBaseController { } val handleFn: PartialFunction[JsonRpcRequest, Task[JsonRpcResponse]] = - enabledApis.foldLeft(notFoundFn)((fn, api) => apisHandleFns.getOrElse(api, PartialFunction.empty) orElse fn) + enabledApis.foldLeft(notFoundFn)((fn, api) => apisHandleFns.getOrElse(api, PartialFunction.empty).orElse(fn)) handleFn(request) .flatTap { @@ -78,7 +84,7 @@ trait JsonRpcBaseController { JsonRpcControllerMetrics.recordMethodTime(request.method, time) } } - .flatTap { response => Task { log.debug(s"sending response ${response.inspect}") } } + .flatTap(response => Task(log.debug(s"sending response ${response.inspect}"))) .onErrorRecoverWith { case t: Throwable => JsonRpcControllerMetrics.MethodsExceptionCounter.increment() log.error(s"Error serving request: ${request.toStringWithSensitiveInformation}", t) @@ -89,13 +95,13 @@ trait JsonRpcBaseController { def handle[Req, Res]( fn: Req => Task[Either[JsonRpcError, Res]], rpcReq: JsonRpcRequest - )(implicit dec: JsonMethodDecoder[Req], enc: JsonEncoder[Res]): Task[JsonRpcResponse] = { + )(implicit dec: JsonMethodDecoder[Req], enc: JsonEncoder[Res]): Task[JsonRpcResponse] = dec.decodeJson(rpcReq.params) match { case Right(req) => fn(req) .map { case Right(success) => successResponse(rpcReq, success) - case Left(error) => errorResponse(rpcReq, error) + case Left(error) => errorResponse(rpcReq, error) } .recover { case ex => log.error("Failed to handle RPC request", ex) @@ -104,7 +110,6 @@ trait JsonRpcBaseController { case Left(error) => Task.now(errorResponse(rpcReq, error)) } - } private def successResponse[T](req: JsonRpcRequest, result: T)(implicit enc: JsonEncoder[T]): JsonRpcResponse = JsonRpcResponse(req.jsonrpc, Some(enc.encodeJson(result)), None, req.id.getOrElse(0)) diff --git a/src/main/scala/io/iohk/ethereum/jsonrpc/server/http/InsecureJsonRpcHttpServer.scala b/src/main/scala/io/iohk/ethereum/jsonrpc/server/http/InsecureJsonRpcHttpServer.scala index 075eee0323..33b6bd6d36 100644 --- a/src/main/scala/io/iohk/ethereum/jsonrpc/server/http/InsecureJsonRpcHttpServer.scala +++ b/src/main/scala/io/iohk/ethereum/jsonrpc/server/http/InsecureJsonRpcHttpServer.scala @@ -2,15 +2,18 @@ package io.iohk.ethereum.jsonrpc.server.http import akka.actor.ActorSystem import akka.http.scaladsl.Http + +import scala.concurrent.ExecutionContext.Implicits.global +import scala.util.Failure +import scala.util.Success + import ch.megard.akka.http.cors.scaladsl.model.HttpOriginMatcher + import io.iohk.ethereum.jsonrpc._ import io.iohk.ethereum.jsonrpc.server.controllers.JsonRpcBaseController import io.iohk.ethereum.jsonrpc.server.http.JsonRpcHttpServer.JsonRpcHttpServerConfig import io.iohk.ethereum.utils.Logger -import scala.concurrent.ExecutionContext.Implicits.global -import scala.util.{Failure, Success} - class InsecureJsonRpcHttpServer( val jsonRpcController: JsonRpcBaseController, val jsonRpcHealthChecker: JsonRpcHealthChecker, @@ -22,9 +25,9 @@ class InsecureJsonRpcHttpServer( def run(): Unit = { val bindingResultF = Http(actorSystem).newServerAt(config.interface, config.port).bind(route) - bindingResultF onComplete { + bindingResultF.onComplete { case Success(serverBinding) => log.info(s"JSON RPC HTTP server listening on ${serverBinding.localAddress}") - case Failure(ex) => log.error("Cannot start JSON HTTP RPC server", ex) + case Failure(ex) => log.error("Cannot start JSON HTTP RPC server", ex) } } diff --git a/src/main/scala/io/iohk/ethereum/jsonrpc/server/http/JsonRpcHttpServer.scala b/src/main/scala/io/iohk/ethereum/jsonrpc/server/http/JsonRpcHttpServer.scala index b9142b07a8..bb62dd70ae 100644 --- a/src/main/scala/io/iohk/ethereum/jsonrpc/server/http/JsonRpcHttpServer.scala +++ b/src/main/scala/io/iohk/ethereum/jsonrpc/server/http/JsonRpcHttpServer.scala @@ -1,45 +1,56 @@ package io.iohk.ethereum.jsonrpc.server.http import java.security.SecureRandom +import javax.net.ssl.SSLContext + import akka.actor.ActorSystem import akka.http.scaladsl.model._ import akka.http.scaladsl.server.Directives._ import akka.http.scaladsl.server._ + +import monix.eval.Task +import monix.execution.Scheduler.Implicits.global + +import scala.concurrent.duration.FiniteDuration +import scala.concurrent.duration._ + import ch.megard.akka.http.cors.javadsl.CorsRejection import ch.megard.akka.http.cors.scaladsl.CorsDirectives._ import ch.megard.akka.http.cors.scaladsl.model.HttpOriginMatcher import ch.megard.akka.http.cors.scaladsl.settings.CorsSettings import com.typesafe.config.{Config => TypesafeConfig} import de.heikoseeberger.akkahttpjson4s.Json4sSupport +import org.json4s.DefaultFormats +import org.json4s.Formats +import org.json4s.JInt +import org.json4s.native +import org.json4s.native.Serialization + import io.iohk.ethereum.faucet.jsonrpc.FaucetJsonRpcController import io.iohk.ethereum.jsonrpc._ import io.iohk.ethereum.jsonrpc.serialization.JsonSerializers import io.iohk.ethereum.jsonrpc.server.controllers.JsonRpcBaseController import io.iohk.ethereum.jsonrpc.server.http.JsonRpcHttpServer.JsonRpcHttpServerConfig import io.iohk.ethereum.security.SSLError -import io.iohk.ethereum.utils.{BuildInfo, ConfigUtils, Logger} -import javax.net.ssl.SSLContext -import monix.eval.Task -import monix.execution.Scheduler.Implicits.global -import org.json4s.native.Serialization -import org.json4s.{DefaultFormats, JInt, native} -import scala.concurrent.duration.{FiniteDuration, _} +import io.iohk.ethereum.utils.BuildInfo +import io.iohk.ethereum.utils.ConfigUtils +import io.iohk.ethereum.utils.Logger trait JsonRpcHttpServer extends Json4sSupport with Logger { val jsonRpcController: JsonRpcBaseController val jsonRpcHealthChecker: JsonRpcHealthChecker val config: JsonRpcHttpServerConfig - implicit val serialization = native.Serialization + implicit val serialization: Serialization.type = native.Serialization - implicit val formats = DefaultFormats + JsonSerializers.RpcErrorJsonSerializer + implicit val formats: Formats = DefaultFormats + JsonSerializers.RpcErrorJsonSerializer def corsAllowedOrigins: HttpOriginMatcher lazy val jsonRpcErrorCodes: List[Int] = List(JsonRpcError.InvalidRequest.code, JsonRpcError.ParseError.code, JsonRpcError.InvalidParams().code) - val corsSettings = CorsSettings.defaultSettings + val corsSettings: CorsSettings = CorsSettings.defaultSettings .withAllowGenericHttpRequests(true) .withAllowedOrigins(corsAllowedOrigins) @@ -85,11 +96,10 @@ trait JsonRpcHttpServer extends Json4sSupport with Logger { } } - def handleRequest(request: JsonRpcRequest): StandardRoute = { + def handleRequest(request: JsonRpcRequest): StandardRoute = complete(handleResponse(jsonRpcController.handleRequest(request)).runToFuture) - } - private def handleResponse(f: Task[JsonRpcResponse]): Task[(StatusCode, JsonRpcResponse)] = f map { jsonRpcResponse => + private def handleResponse(f: Task[JsonRpcResponse]): Task[(StatusCode, JsonRpcResponse)] = f.map { jsonRpcResponse => jsonRpcResponse.error match { case Some(JsonRpcError(error, _, _)) if jsonRpcErrorCodes.contains(error) => (StatusCodes.BadRequest, jsonRpcResponse) @@ -97,8 +107,7 @@ trait JsonRpcHttpServer extends Json4sSupport with Logger { } } - /** - * Try to start JSON RPC server + /** Try to start JSON RPC server */ def run(): Unit diff --git a/src/main/scala/io/iohk/ethereum/jsonrpc/server/http/RateLimit.scala b/src/main/scala/io/iohk/ethereum/jsonrpc/server/http/RateLimit.scala index 7016ef9e30..fbd59908fb 100644 --- a/src/main/scala/io/iohk/ethereum/jsonrpc/server/http/RateLimit.scala +++ b/src/main/scala/io/iohk/ethereum/jsonrpc/server/http/RateLimit.scala @@ -3,21 +3,28 @@ package io.iohk.ethereum.jsonrpc.server.http import java.time.Duration import akka.NotUsed -import akka.http.scaladsl.model.{RemoteAddress, StatusCodes} -import akka.http.scaladsl.server.{Directive0, Route} -import io.iohk.ethereum.jsonrpc.server.http.JsonRpcHttpServer.RateLimitConfig +import akka.http.scaladsl.model.RemoteAddress +import akka.http.scaladsl.model.StatusCodes +import akka.http.scaladsl.server.Directive0 import akka.http.scaladsl.server.Directives._ +import akka.http.scaladsl.server.Route + import com.google.common.base.Ticker import com.google.common.cache.CacheBuilder -import io.iohk.ethereum.jsonrpc.JsonRpcError import de.heikoseeberger.akkahttpjson4s.Json4sSupport +import org.json4s.DefaultFormats +import org.json4s.Formats +import org.json4s.Serialization +import org.json4s.native + +import io.iohk.ethereum.jsonrpc.JsonRpcError import io.iohk.ethereum.jsonrpc.serialization.JsonSerializers -import org.json4s.{DefaultFormats, Formats, Serialization, native} +import io.iohk.ethereum.jsonrpc.server.http.JsonRpcHttpServer.RateLimitConfig class RateLimit(config: RateLimitConfig) extends Directive0 with Json4sSupport { - private implicit val serialization: Serialization = native.Serialization - private implicit val formats: Formats = DefaultFormats + JsonSerializers.RpcErrorJsonSerializer + implicit private val serialization: Serialization = native.Serialization + implicit private val formats: Formats = DefaultFormats + JsonSerializers.RpcErrorJsonSerializer private[this] lazy val minInterval = config.minRequestInterval.toSeconds @@ -55,7 +62,7 @@ class RateLimit(config: RateLimitConfig) extends Directive0 with Json4sSupport { // 1) no IP address is extracted unless config.enabled is true // 2) no LRU is created unless config.enabled is true // 3) cache is accessed only once (using get) - override def tapply(f: Unit => Route): Route = { + override def tapply(f: Unit => Route): Route = if (config.enabled) { extractClientIP { ip => if (isBelowRateLimit(ip)) { @@ -66,6 +73,5 @@ class RateLimit(config: RateLimitConfig) extends Directive0 with Json4sSupport { } } } else f.apply(()) - } } diff --git a/src/main/scala/io/iohk/ethereum/jsonrpc/server/http/SecureJsonRpcHttpServer.scala b/src/main/scala/io/iohk/ethereum/jsonrpc/server/http/SecureJsonRpcHttpServer.scala index 981aed455b..7b33138d06 100644 --- a/src/main/scala/io/iohk/ethereum/jsonrpc/server/http/SecureJsonRpcHttpServer.scala +++ b/src/main/scala/io/iohk/ethereum/jsonrpc/server/http/SecureJsonRpcHttpServer.scala @@ -1,19 +1,23 @@ package io.iohk.ethereum.jsonrpc.server.http +import java.security.SecureRandom +import javax.net.ssl.SSLContext + import akka.actor.ActorSystem -import akka.http.scaladsl.{ConnectionContext, Http} +import akka.http.scaladsl.ConnectionContext +import akka.http.scaladsl.Http + +import scala.concurrent.ExecutionContext.Implicits.global +import scala.util.Failure +import scala.util.Success + import ch.megard.akka.http.cors.scaladsl.model.HttpOriginMatcher -import io.iohk.ethereum.jsonrpc.JsonRpcHealthChecker -import io.iohk.ethereum.security.SSLError -import io.iohk.ethereum.jsonrpc.server.http.JsonRpcHttpServer.JsonRpcHttpServerConfig -import java.security.SecureRandom +import io.iohk.ethereum.jsonrpc.JsonRpcHealthChecker import io.iohk.ethereum.jsonrpc.server.controllers.JsonRpcBaseController +import io.iohk.ethereum.jsonrpc.server.http.JsonRpcHttpServer.JsonRpcHttpServerConfig +import io.iohk.ethereum.security.SSLError import io.iohk.ethereum.utils.Logger -import javax.net.ssl.SSLContext - -import scala.concurrent.ExecutionContext.Implicits.global -import scala.util.{Failure, Success} class SecureJsonRpcHttpServer( val jsonRpcController: JsonRpcBaseController, @@ -32,9 +36,9 @@ class SecureJsonRpcHttpServer( case Right(httpsContext) => val bindingResultF = Http().newServerAt(config.interface, config.port).enableHttps(httpsContext).bind(route) - bindingResultF onComplete { + bindingResultF.onComplete { case Success(serverBinding) => log.info(s"JSON RPC HTTPS server listening on ${serverBinding.localAddress}") - case Failure(ex) => log.error("Cannot start JSON HTTPS RPC server", ex) + case Failure(ex) => log.error("Cannot start JSON HTTPS RPC server", ex) } case Left(error) => log.error(s"Cannot start JSON HTTPS RPC server due to: $error") diff --git a/src/main/scala/io/iohk/ethereum/jsonrpc/server/ipc/JsonRpcIpcServer.scala b/src/main/scala/io/iohk/ethereum/jsonrpc/server/ipc/JsonRpcIpcServer.scala index df5db0b0f6..68f0d0e024 100644 --- a/src/main/scala/io/iohk/ethereum/jsonrpc/server/ipc/JsonRpcIpcServer.scala +++ b/src/main/scala/io/iohk/ethereum/jsonrpc/server/ipc/JsonRpcIpcServer.scala @@ -1,23 +1,31 @@ package io.iohk.ethereum.jsonrpc.server.ipc -import java.io.{BufferedReader, File, InputStreamReader} -import java.net.{ServerSocket, Socket} +import java.io.BufferedReader +import java.io.File +import java.io.InputStreamReader +import java.net.ServerSocket +import java.net.Socket import akka.actor.ActorSystem -import io.iohk.ethereum.jsonrpc.serialization.JsonSerializers -import io.iohk.ethereum.jsonrpc.server.ipc.JsonRpcIpcServer.JsonRpcIpcServerConfig -import io.iohk.ethereum.jsonrpc.{JsonRpcController, JsonRpcRequest} -import io.iohk.ethereum.utils.Logger + import monix.execution.Scheduler.Implicits.global + +import scala.annotation.tailrec +import scala.concurrent.duration._ +import scala.util.Try + +import org.json4s.Formats import org.json4s.JsonAST.JValue +import org.json4s.native import org.json4s.native.JsonMethods._ import org.json4s.native.Serialization -import org.json4s.native import org.scalasbt.ipcsocket.UnixDomainServerSocket -import scala.annotation.tailrec -import scala.concurrent.duration._ -import scala.util.Try +import io.iohk.ethereum.jsonrpc.JsonRpcController +import io.iohk.ethereum.jsonrpc.JsonRpcRequest +import io.iohk.ethereum.jsonrpc.serialization.JsonSerializers +import io.iohk.ethereum.jsonrpc.server.ipc.JsonRpcIpcServer.JsonRpcIpcServerConfig +import io.iohk.ethereum.utils.Logger class JsonRpcIpcServer(jsonRpcController: JsonRpcController, config: JsonRpcIpcServerConfig)(implicit system: ActorSystem @@ -32,13 +40,12 @@ class JsonRpcIpcServer(jsonRpcController: JsonRpcController, config: JsonRpcIpcS serverSocket = new UnixDomainServerSocket(config.socketFile) new Thread { - override def run(): Unit = { + override def run(): Unit = while (!serverSocket.isClosed) { val clientSocket = serverSocket.accept() // Note: consider using a thread pool to limit the number of connections/requests new ClientThread(jsonRpcController, clientSocket).start() } - } }.start() } @@ -54,8 +61,8 @@ class JsonRpcIpcServer(jsonRpcController: JsonRpcController, config: JsonRpcIpcS class ClientThread(jsonRpcController: JsonRpcController, clientSocket: Socket) extends Thread { - implicit private val serialization = native.Serialization - implicit private val formats = JsonSerializers.formats + native.Serialization + implicit private val formats: Formats = JsonSerializers.formats private val out = clientSocket.getOutputStream private val in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream)) @@ -65,9 +72,8 @@ class JsonRpcIpcServer(jsonRpcController: JsonRpcController, config: JsonRpcIpcS private var running = true override def run(): Unit = { - while (running) { + while (running) handleNextRequest() - } clientSocket.close() } @@ -81,12 +87,12 @@ class JsonRpcIpcServer(jsonRpcController: JsonRpcController, config: JsonRpcIpcS val dataSoFar = accum ++ newData parseOpt(dataSoFar) match { case Some(json) => Some(json) - case None => readNextMessage(dataSoFar) + case None => readNextMessage(dataSoFar) } } } - private def handleNextRequest(): Unit = { + private def handleNextRequest(): Unit = readNextMessage() match { case Some(nextMsgJson) => val request = nextMsgJson.extract[JsonRpcRequest] @@ -97,7 +103,6 @@ class JsonRpcIpcServer(jsonRpcController: JsonRpcController, config: JsonRpcIpcS case None => running = false } - } } } diff --git a/src/main/scala/io/iohk/ethereum/keystore/EncryptedKey.scala b/src/main/scala/io/iohk/ethereum/keystore/EncryptedKey.scala index bc8703bde6..99949b0bf6 100644 --- a/src/main/scala/io/iohk/ethereum/keystore/EncryptedKey.scala +++ b/src/main/scala/io/iohk/ethereum/keystore/EncryptedKey.scala @@ -4,6 +4,7 @@ import java.security.SecureRandom import java.util.UUID import akka.util.ByteString + import io.iohk.ethereum.crypto import io.iohk.ethereum.crypto.SymmetricCipher import io.iohk.ethereum.domain.Address @@ -50,7 +51,7 @@ object EncryptedKey { case ScryptParams(salt, n, r, p, dklen) => crypto.scrypt(passphrase, salt, n, r, p, dklen) - case Pbkdf2Params(salt, prf, c, dklen) => + case Pbkdf2Params(salt, _, c, dklen) => // prf is currently ignored, only hmac sha256 is used crypto.pbkdf2HMacSha256(passphrase, salt, c, dklen) } @@ -59,8 +60,7 @@ object EncryptedKey { crypto.kec256(dk.slice(16, 32) ++ ciphertext) } -/** - * Represents an encrypted private key stored in the keystore +/** Represents an encrypted private key stored in the keystore * See: https://github.com/ethereum/wiki/wiki/Web3-Secret-Storage-Definition */ case class EncryptedKey( diff --git a/src/main/scala/io/iohk/ethereum/keystore/EncryptedKeyJsonCodec.scala b/src/main/scala/io/iohk/ethereum/keystore/EncryptedKeyJsonCodec.scala index 6619019aae..76278033fe 100644 --- a/src/main/scala/io/iohk/ethereum/keystore/EncryptedKeyJsonCodec.scala +++ b/src/main/scala/io/iohk/ethereum/keystore/EncryptedKeyJsonCodec.scala @@ -3,15 +3,23 @@ package io.iohk.ethereum.keystore import java.util.UUID import akka.util.ByteString -import io.iohk.ethereum.domain.Address -import io.iohk.ethereum.keystore.EncryptedKey._ -import org.json4s.JsonAST.{JObject, JString, JValue} + +import scala.util.Try + +import org.bouncycastle.util.encoders.Hex +import org.json4s.CustomSerializer +import org.json4s.DefaultFormats +import org.json4s.Extraction +import org.json4s.Formats +import org.json4s.JField +import org.json4s.JsonAST.JObject +import org.json4s.JsonAST.JString +import org.json4s.JsonAST.JValue import org.json4s.JsonDSL._ import org.json4s.native.JsonMethods._ -import org.json4s.{CustomSerializer, DefaultFormats, Extraction, JField} -import org.bouncycastle.util.encoders.Hex -import scala.util.Try +import io.iohk.ethereum.domain.Address +import io.iohk.ethereum.keystore.EncryptedKey._ object EncryptedKeyJsonCodec { @@ -22,7 +30,7 @@ object EncryptedKeyJsonCodec { ) ) - private implicit val formats = DefaultFormats + byteStringSerializer + implicit private val formats: Formats = DefaultFormats + byteStringSerializer private def asHex(bs: ByteString): String = Hex.toHexString(bs.toArray) @@ -67,11 +75,11 @@ object EncryptedKeyJsonCodec { private def encodeKdf(kdfParams: KdfParams): JObject = kdfParams match { - case ScryptParams(salt, n, r, p, dklen) => + case ScryptParams(_, _, _, _, _) => ("kdf" -> Scrypt) ~ ("kdfparams" -> Extraction.decompose(kdfParams)) - case Pbkdf2Params(salt, prf, c, dklen) => + case Pbkdf2Params(_, _, _, _) => ("kdf" -> Pbkdf2) ~ ("kdfparams" -> Extraction.decompose(kdfParams)) } diff --git a/src/main/scala/io/iohk/ethereum/keystore/KeyStore.scala b/src/main/scala/io/iohk/ethereum/keystore/KeyStore.scala index 705c27773e..0837b92bc8 100644 --- a/src/main/scala/io/iohk/ethereum/keystore/KeyStore.scala +++ b/src/main/scala/io/iohk/ethereum/keystore/KeyStore.scala @@ -2,18 +2,22 @@ package io.iohk.ethereum.keystore import java.io.File import java.nio.charset.StandardCharsets -import java.nio.file.{Files, Paths} +import java.nio.file.Files +import java.nio.file.Paths import java.security.SecureRandom +import java.time.ZoneOffset +import java.time.ZonedDateTime import java.time.format.DateTimeFormatter -import java.time.{ZoneOffset, ZonedDateTime} import akka.util.ByteString -import io.iohk.ethereum.crypto._ -import io.iohk.ethereum.domain.Address -import io.iohk.ethereum.utils.{KeyStoreConfig, Logger} import scala.util.Try +import io.iohk.ethereum.crypto._ +import io.iohk.ethereum.domain.Address +import io.iohk.ethereum.utils.KeyStoreConfig +import io.iohk.ethereum.utils.Logger + object KeyStore { sealed trait KeyStoreError case object KeyNotFound extends KeyStoreError @@ -99,10 +103,6 @@ class KeyStoreImpl(keyStoreConfig: KeyStoreConfig, secureRandom: SecureRandom) e _ <- overwrite(keyFileName, newEncKey) } yield () - private def deleteFile(fileName: String): Either[KeyStoreError, Boolean] = { - Try(Files.deleteIfExists(Paths.get(keyStoreConfig.keyStoreDir, fileName))).toEither.left.map(ioError) - } - private def init(): Unit = { val dir = new File(keyStoreConfig.keyStoreDir) val res = Try(dir.isDirectory || dir.mkdirs()).filter(identity) @@ -135,12 +135,11 @@ class KeyStoreImpl(keyStoreConfig: KeyStoreConfig, secureRandom: SecureRandom) e }.toEither.left.map(ioError) } - private def load(address: Address): Either[KeyStoreError, EncryptedKey] = { + private def load(address: Address): Either[KeyStoreError, EncryptedKey] = for { filename <- findKeyFileName(address) key <- load(filename) } yield key - } private def load(path: String): Either[KeyStoreError, EncryptedKey] = for { @@ -175,9 +174,9 @@ class KeyStoreImpl(keyStoreConfig: KeyStoreConfig, secureRandom: SecureRandom) e } private def containsAccount(encKey: EncryptedKey): Either[KeyStoreError, Boolean] = load(encKey.address) match { - case Right(_) => Right(true) + case Right(_) => Right(true) case Left(KeyNotFound) => Right(false) - case Left(err) => Left(err) + case Left(err) => Left(err) } private def findKeyFileName(address: Address): Either[KeyStoreError, String] = for { @@ -188,8 +187,7 @@ class KeyStoreImpl(keyStoreConfig: KeyStoreConfig, secureRandom: SecureRandom) e .getOrElse(Left(KeyNotFound)) } yield matching - private def sortKeyFilesByDate(files: List[String]): List[String] = { + private def sortKeyFilesByDate(files: List[String]): List[String] = // given the date and filename formats sorting by date is equivalent to sorting by name files.sorted - } } diff --git a/src/main/scala/io/iohk/ethereum/keystore/Wallet.scala b/src/main/scala/io/iohk/ethereum/keystore/Wallet.scala index 39071d3b13..f8c8200804 100644 --- a/src/main/scala/io/iohk/ethereum/keystore/Wallet.scala +++ b/src/main/scala/io/iohk/ethereum/keystore/Wallet.scala @@ -1,10 +1,15 @@ package io.iohk.ethereum.keystore import akka.util.ByteString -import io.iohk.ethereum.crypto._ -import io.iohk.ethereum.domain.{Address, SignedTransaction, SignedTransactionWithSender, Transaction} + import org.bouncycastle.crypto.AsymmetricCipherKeyPair +import io.iohk.ethereum.crypto._ +import io.iohk.ethereum.domain.Address +import io.iohk.ethereum.domain.SignedTransaction +import io.iohk.ethereum.domain.SignedTransactionWithSender +import io.iohk.ethereum.domain.Transaction + case class Wallet(address: Address, prvKey: ByteString) { lazy val keyPair: AsymmetricCipherKeyPair = keyPairFromPrvKey(prvKey.toArray) diff --git a/src/main/scala/io/iohk/ethereum/ledger/BlockData.scala b/src/main/scala/io/iohk/ethereum/ledger/BlockData.scala index 329a375123..480ed4e48a 100644 --- a/src/main/scala/io/iohk/ethereum/ledger/BlockData.scala +++ b/src/main/scala/io/iohk/ethereum/ledger/BlockData.scala @@ -1,7 +1,7 @@ package io.iohk.ethereum.ledger import io.iohk.ethereum.domain.Block -import io.iohk.ethereum.domain.Receipt import io.iohk.ethereum.domain.ChainWeight +import io.iohk.ethereum.domain.Receipt case class BlockData(block: Block, receipts: Seq[Receipt], weight: ChainWeight) diff --git a/src/main/scala/io/iohk/ethereum/ledger/BlockExecution.scala b/src/main/scala/io/iohk/ethereum/ledger/BlockExecution.scala index 3d470b7cd4..056b67a7dc 100644 --- a/src/main/scala/io/iohk/ethereum/ledger/BlockExecution.scala +++ b/src/main/scala/io/iohk/ethereum/ledger/BlockExecution.scala @@ -1,15 +1,18 @@ package io.iohk.ethereum.ledger -import io.iohk.ethereum.domain._ -import io.iohk.ethereum.ledger.BlockExecutionError.MissingParentError -import io.iohk.ethereum.ledger.BlockResult -import io.iohk.ethereum.utils.{BlockchainConfig, ByteStringUtils, DaoForkConfig, Logger} -import io.iohk.ethereum.vm.EvmConfig +import cats.implicits._ import scala.annotation.tailrec -import cats.implicits._ + import io.iohk.ethereum.db.storage.EvmCodeStorage +import io.iohk.ethereum.domain._ +import io.iohk.ethereum.ledger.BlockExecutionError.MissingParentError +import io.iohk.ethereum.ledger.BlockResult import io.iohk.ethereum.mpt.MerklePatriciaTrie.MPTException +import io.iohk.ethereum.utils.BlockchainConfig +import io.iohk.ethereum.utils.DaoForkConfig +import io.iohk.ethereum.utils.Logger +import io.iohk.ethereum.vm.EvmConfig class BlockExecution( blockchain: BlockchainImpl, @@ -58,7 +61,7 @@ class BlockExecution( } /** Executes a block (executes transactions and pays rewards) */ - private def executeBlock(block: Block): Either[BlockExecutionError, BlockResult] = { + private def executeBlock(block: Block): Either[BlockExecutionError, BlockResult] = for { parentHeader <- blockchainReader .getBlockHeaderByHash(block.header.parentHash) @@ -71,9 +74,8 @@ class BlockExecution( // State root hash needs to be up-to-date for validateBlockAfterExecution worldPersisted = InMemoryWorldStateProxy.persistState(worldToPersist) } yield execResult.copy(worldState = worldPersisted) - } - protected def buildInitialWorld(block: Block, parentHeader: BlockHeader): InMemoryWorldStateProxy = { + protected def buildInitialWorld(block: Block, parentHeader: BlockHeader): InMemoryWorldStateProxy = InMemoryWorldStateProxy( evmCodeStorage = evmCodeStorage, blockchain.getBackingMptStorage(block.header.number), @@ -83,7 +85,6 @@ class BlockExecution( noEmptyAccounts = EvmConfig.forBlock(parentHeader.number, blockchainConfig).noEmptyAccounts, ethCompatibleStorage = blockchainConfig.ethCompatibleStorage ) - } /** This function runs transactions * @@ -131,7 +132,7 @@ class BlockExecution( private def drainDaoForkAccounts( worldState: InMemoryWorldStateProxy, daoForkConfig: DaoForkConfig - ): InMemoryWorldStateProxy = { + ): InMemoryWorldStateProxy = daoForkConfig.refundContract match { case Some(refundContractAddress) => daoForkConfig.drainList.foldLeft(worldState) { (ws, address) => @@ -141,7 +142,6 @@ class BlockExecution( } case None => worldState } - } /** Executes and validates a list of blocks, storing the results in the blockchain. * @@ -161,7 +161,7 @@ class BlockExecution( remainingBlocksIncOrder: List[Block], parentWeight: ChainWeight, error: Option[BlockExecutionError] - ): (List[BlockData], Option[BlockExecutionError]) = { + ): (List[BlockData], Option[BlockExecutionError]) = if (remainingBlocksIncOrder.isEmpty) { (executedBlocksDecOrder.reverse, None) } else { @@ -176,7 +176,6 @@ class BlockExecution( (executedBlocksDecOrder.reverse, Some(executionError)) } } - } go(List.empty[BlockData], blocks, parentChainWeight, None) } diff --git a/src/main/scala/io/iohk/ethereum/ledger/BlockImport.scala b/src/main/scala/io/iohk/ethereum/ledger/BlockImport.scala index e575431985..bfb38c475b 100644 --- a/src/main/scala/io/iohk/ethereum/ledger/BlockImport.scala +++ b/src/main/scala/io/iohk/ethereum/ledger/BlockImport.scala @@ -1,19 +1,24 @@ package io.iohk.ethereum.ledger import akka.util.ByteString -import io.iohk.ethereum.consensus.validators.BlockHeaderError.HeaderParentNotFoundError -import io.iohk.ethereum.domain._ -import io.iohk.ethereum.ledger.BlockExecutionError.{MPTError, ValidationBeforeExecError} -import io.iohk.ethereum.ledger.BlockQueue.Leaf -import io.iohk.ethereum.mpt.MerklePatriciaTrie.MissingNodeException -import io.iohk.ethereum.utils.{ByteStringUtils, Logger} + import monix.eval.Task import monix.execution.Scheduler -import org.bouncycastle.util.encoders.Hex import scala.annotation.tailrec import scala.concurrent.ExecutionContext +import org.bouncycastle.util.encoders.Hex + +import io.iohk.ethereum.consensus.validators.BlockHeaderError.HeaderParentNotFoundError +import io.iohk.ethereum.domain._ +import io.iohk.ethereum.ledger.BlockExecutionError.MPTError +import io.iohk.ethereum.ledger.BlockExecutionError.ValidationBeforeExecError +import io.iohk.ethereum.ledger.BlockQueue.Leaf +import io.iohk.ethereum.mpt.MerklePatriciaTrie.MissingNodeException +import io.iohk.ethereum.utils.ByteStringUtils +import io.iohk.ethereum.utils.Logger + class BlockImport( blockchain: BlockchainImpl, blockchainReader: BlockchainReader, @@ -34,7 +39,7 @@ class BlockImport( * - [[io.iohk.ethereum.ledger.DuplicateBlock]] - block already exists either in the main chain or in the queue * - [[io.iohk.ethereum.ledger.BlockImportFailed]] - block failed to execute (when importing to top or reorganising the chain) */ - def importBlock(block: Block)(implicit blockExecutionScheduler: Scheduler): Task[BlockImportResult] = { + def importBlock(block: Block)(implicit blockExecutionScheduler: Scheduler): Task[BlockImportResult] = blockchain.getBestBlock() match { case Some(bestBlock) => if (isBlockADuplicate(block.header, bestBlock.header.number)) { @@ -67,7 +72,6 @@ class BlockImport( log.error("Getting current best block failed") Task.now(BlockImportFailed("Couldn't find the current best block")) } - } private def isBlockADuplicate(block: BlockHeader, currentBestBlockNumber: BigInt): Boolean = { val hash = block.hash @@ -79,7 +83,7 @@ class BlockImport( private def isPossibleNewBestBlock(newBlock: BlockHeader, currentBestBlock: BlockHeader): Boolean = newBlock.parentHash == currentBestBlock.hash && newBlock.number == currentBestBlock.number + 1 - private def measureBlockMetrics(importResult: BlockImportResult): Unit = { + private def measureBlockMetrics(importResult: BlockImportResult): Unit = importResult match { case BlockImportedToTop(blockImportData) => blockImportData.foreach(blockData => BlockMetrics.measure(blockData.block, blockchainReader.getBlockByHash)) @@ -87,7 +91,6 @@ class BlockImport( newBranch.foreach(block => BlockMetrics.measure(block, blockchainReader.getBlockByHash)) case _ => () } - } private def importToTop( block: Block, @@ -192,7 +195,7 @@ class BlockImport( .validateBlockBeforeExecution(block) .fold( error => handleBlockValidationError(error, block), - _ => { + _ => blockQueue.enqueueBlock(block, currentBestBlock.header.number) match { case Some(Leaf(leafHash, leafWeight)) if leafWeight > currentWeight => log.debug("Found a better chain, about to reorganise") @@ -201,7 +204,6 @@ class BlockImport( case _ => BlockEnqueued } - } ) } @@ -237,7 +239,7 @@ class BlockImport( execResult.fold( { case MPTError(reason: MissingNodeException) => BlockImportFailedDueToMissingNode(reason) - case err => BlockImportFailed(s"Error while trying to reorganise chain: $err") + case err => BlockImportFailed(s"Error while trying to reorganise chain: $err") }, ChainReorganised.tupled ) @@ -255,7 +257,7 @@ class BlockImport( val (executedBlocks, maybeError) = blockExecution.executeAndValidateBlocks(newBranch, parentWeight) maybeError match { case None => - Right(oldBlocksData.map(_.block), executedBlocks.map(_.block), executedBlocks.map(_.weight)) + Right((oldBlocksData.map(_.block), executedBlocks.map(_.block), executedBlocks.map(_.weight))) case Some(error) => revertChainReorganisation(newBranch, oldBlocksData, executedBlocks) @@ -305,7 +307,7 @@ class BlockImport( */ private def removeBlocksUntil(parent: ByteString, fromNumber: BigInt): List[BlockData] = { @tailrec - def removeBlocksUntil(parent: ByteString, fromNumber: BigInt, acc: List[BlockData]): List[BlockData] = { + def removeBlocksUntil(parent: ByteString, fromNumber: BigInt, acc: List[BlockData]): List[BlockData] = blockchainReader.getBlockByNumber(fromNumber) match { case Some(block) if block.header.hash == parent || fromNumber == 0 => acc @@ -326,7 +328,6 @@ class BlockImport( log.error(s"Unexpected missing block number: $fromNumber") acc } - } removeBlocksUntil(parent, fromNumber, Nil) } diff --git a/src/main/scala/io/iohk/ethereum/ledger/BlockMetrics.scala b/src/main/scala/io/iohk/ethereum/ledger/BlockMetrics.scala index aa7dc9c258..f41dcb7bac 100644 --- a/src/main/scala/io/iohk/ethereum/ledger/BlockMetrics.scala +++ b/src/main/scala/io/iohk/ethereum/ledger/BlockMetrics.scala @@ -1,27 +1,29 @@ package io.iohk.ethereum.ledger import akka.util.ByteString + import com.google.common.util.concurrent.AtomicDouble + import io.iohk.ethereum.domain.Block import io.iohk.ethereum.metrics.MetricsContainer case object BlockMetrics extends MetricsContainer { - private[this] final val BlockNumberGauge = + final private[this] val BlockNumberGauge = metrics.registry.gauge("sync.block.number.gauge", new AtomicDouble(0d)) - private[this] final val CheckpointBlockNumberGauge = + final private[this] val CheckpointBlockNumberGauge = metrics.registry.gauge("sync.block.checkpoint.number.gauge", new AtomicDouble(0d)) - private[this] final val BlockGasLimitGauge = + final private[this] val BlockGasLimitGauge = metrics.registry.gauge("sync.block.gasLimit.gauge", new AtomicDouble(0d)) - private[this] final val BlockGasUsedGauge = + final private[this] val BlockGasUsedGauge = metrics.registry.gauge("sync.block.gasUsed.gauge", new AtomicDouble(0d)) - private[this] final val BlockDifficultyGauge = + final private[this] val BlockDifficultyGauge = metrics.registry.gauge("sync.block.difficulty.gauge", new AtomicDouble(0d)) - private[this] final val BlockTransactionsGauge = + final private[this] val BlockTransactionsGauge = metrics.registry.gauge("sync.block.transactions.gauge", new AtomicDouble(0d)) - private[this] final val BlockUnclesGauge = + final private[this] val BlockUnclesGauge = metrics.registry.gauge("sync.block.uncles.gauge", new AtomicDouble(0d)) - private[this] final val TimeBetweenParentGauge = + final private[this] val TimeBetweenParentGauge = metrics.registry.gauge("sync.block.timeBetweenParent.seconds.gauge", new AtomicDouble(0d)) def measure(block: Block, getBlockByHashFn: ByteString => Option[Block]): Unit = { diff --git a/src/main/scala/io/iohk/ethereum/ledger/BlockPreparator.scala b/src/main/scala/io/iohk/ethereum/ledger/BlockPreparator.scala index fc8933d052..1d569a63b1 100644 --- a/src/main/scala/io/iohk/ethereum/ledger/BlockPreparator.scala +++ b/src/main/scala/io/iohk/ethereum/ledger/BlockPreparator.scala @@ -1,20 +1,21 @@ package io.iohk.ethereum.ledger +import scala.annotation.tailrec + import io.iohk.ethereum.consensus.validators.SignedTransactionError.TransactionSignatureError import io.iohk.ethereum.consensus.validators.SignedTransactionValidator import io.iohk.ethereum.db.storage.EvmCodeStorage import io.iohk.ethereum.domain.UInt256._ import io.iohk.ethereum.domain._ -import io.iohk.ethereum.ledger.BlockExecutionError.{StateBeforeFailure, TxsExecutionError} +import io.iohk.ethereum.ledger.BlockExecutionError.StateBeforeFailure +import io.iohk.ethereum.ledger.BlockExecutionError.TxsExecutionError import io.iohk.ethereum.ledger.BlockPreparator._ +import io.iohk.ethereum.utils.BlockchainConfig import io.iohk.ethereum.utils.ByteStringUtils.ByteStringOps -import io.iohk.ethereum.utils.{BlockchainConfig, Config, Logger} +import io.iohk.ethereum.utils.Logger import io.iohk.ethereum.vm.{PC => _, _} -import scala.annotation.tailrec - -/** - * This is used from a [[io.iohk.ethereum.consensus.blocks.BlockGenerator BlockGenerator]]. +/** This is used from a [[io.iohk.ethereum.consensus.blocks.BlockGenerator BlockGenerator]]. */ class BlockPreparator( vm: VMImpl, @@ -32,8 +33,7 @@ class BlockPreparator( blockchainConfig.forkBlockNumbers.constantinopleBlockNumber ) - /** - * This function updates the state in order to pay rewards based on YP section 11.3 and with the required + /** This function updates the state in order to pay rewards based on YP section 11.3 and with the required * modifications due to ECIP1097: * 1. Reward for block is distributed as: * a. If treasury is disabled or it's has been selfdestructed: @@ -94,16 +94,14 @@ class BlockPreparator( private def treasuryEnabled(blockNo: BigInt): Boolean = blockNo >= blockchainConfig.forkBlockNumbers.ecip1098BlockNumber - /** - * v0 ≡ Tg (Tx gas limit) * Tp (Tx gas price). See YP equation number (68) + /** v0 ≡ Tg (Tx gas limit) * Tp (Tx gas price). See YP equation number (68) * * @param tx Target transaction * @return Upfront cost */ private[ledger] def calculateUpfrontGas(tx: Transaction): UInt256 = UInt256(tx.gasLimit * tx.gasPrice) - /** - * v0 ≡ Tg (Tx gas limit) * Tp (Tx gas price) + Tv (Tx value). See YP equation number (65) + /** v0 ≡ Tg (Tx gas limit) * Tp (Tx gas price) + Tv (Tx value). See YP equation number (65) * * @param tx Target transaction * @return Upfront cost @@ -111,8 +109,7 @@ class BlockPreparator( private[ledger] def calculateUpfrontCost(tx: Transaction): UInt256 = UInt256(calculateUpfrontGas(tx) + tx.value) - /** - * Increments account nonce by 1 stated in YP equation (69) and + /** Increments account nonce by 1 stated in YP equation (69) and * Pays the upfront Tx gas calculated as TxGasPrice * TxGasLimit from balance. YP equation (68) * * @param stx @@ -139,19 +136,17 @@ class BlockPreparator( vm.run(context) } - /** - * Calculate total gas to be refunded + /** Calculate total gas to be refunded * See YP, eq (72) */ - private[ledger] def calcTotalGasToRefund(stx: SignedTransaction, result: PR): BigInt = { + private[ledger] def calcTotalGasToRefund(stx: SignedTransaction, result: PR): BigInt = result.error.map(_.useWholeGas) match { - case Some(true) => 0 + case Some(true) => 0 case Some(false) => result.gasRemaining case None => val gasUsed = stx.tx.gasLimit - result.gasRemaining result.gasRemaining + (gasUsed / 2).min(result.gasRefund) } - } private[ledger] def increaseAccountBalance(address: Address, value: UInt256)( world: InMemoryWorldStateProxy @@ -163,17 +158,15 @@ class BlockPreparator( private[ledger] def pay(address: Address, value: UInt256, withTouch: Boolean)( world: InMemoryWorldStateProxy - ): InMemoryWorldStateProxy = { + ): InMemoryWorldStateProxy = if (world.isZeroValueTransferToNonExistentAccount(address, value)) { world } else { val savedWorld = increaseAccountBalance(address, value)(world) if (withTouch) savedWorld.touchAccounts(address) else savedWorld } - } - /** - * Delete all accounts (that appear in SUICIDE list). YP eq (78). + /** Delete all accounts (that appear in SUICIDE list). YP eq (78). * The contract storage should be cleared during pruning as nodes could be used in other tries. * The contract code is also not deleted as there can be contracts with the exact same code, making it risky to delete * the code of an account in case it is shared with another one. @@ -190,8 +183,7 @@ class BlockPreparator( ): InMemoryWorldStateProxy = addressesToDelete.foldLeft(worldStateProxy) { case (world, address) => world.deleteAccount(address) } - /** - * EIP161 - State trie clearing + /** EIP161 - State trie clearing * Delete all accounts that have been touched (involved in any potentially state-changing operation) during transaction execution. * * All potentially state-changing operation are: @@ -207,12 +199,11 @@ class BlockPreparator( * Set is cleared */ private[ledger] def deleteEmptyTouchedAccounts(world: InMemoryWorldStateProxy): InMemoryWorldStateProxy = { - def deleteEmptyAccount(world: InMemoryWorldStateProxy, address: Address) = { + def deleteEmptyAccount(world: InMemoryWorldStateProxy, address: Address) = if (world.getAccount(address).exists(_.isEmpty(blockchainConfig.accountStartNonce))) world.deleteAccount(address) else world - } world.touchedAccounts .foldLeft(world)(deleteEmptyAccount) @@ -246,13 +237,13 @@ class BlockPreparator( val payMinerForGasFn = pay(Address(blockHeader.beneficiary), (executionGasToPayToMiner * gasPrice).toUInt256, withTouch = true) _ - val worldAfterPayments = (refundGasFn andThen payMinerForGasFn)(resultWithErrorHandling.world) + val worldAfterPayments = (refundGasFn.andThen(payMinerForGasFn))(resultWithErrorHandling.world) val deleteAccountsFn = deleteAccounts(resultWithErrorHandling.addressesToDelete) _ val deleteTouchedAccountsFn = deleteEmptyTouchedAccounts _ val persistStateFn = InMemoryWorldStateProxy.persistState _ - val world2 = (deleteAccountsFn andThen deleteTouchedAccountsFn andThen persistStateFn)(worldAfterPayments) + val world2 = (deleteAccountsFn.andThen(deleteTouchedAccountsFn).andThen(persistStateFn))(worldAfterPayments) log.debug(s"""Transaction ${stx.hash.toHex} execution end. Summary: | - Error: ${result.error}. @@ -263,8 +254,7 @@ class BlockPreparator( } // scalastyle:off method.length - /** - * This functions executes all the signed transactions from a block (till one of those executions fails) + /** This functions executes all the signed transactions from a block (till one of those executions fails) * * @param signedTransactions from the block that are left to execute * @param world that will be updated by the execution of the signedTransactions @@ -275,7 +265,7 @@ class BlockPreparator( * if one of them failed */ @tailrec - private[ledger] final def executeTransactions( + final private[ledger] def executeTransactions( signedTransactions: Seq[SignedTransaction], world: InMemoryWorldStateProxy, blockHeader: BlockHeader, @@ -302,7 +292,7 @@ class BlockPreparator( val validatedStx = for { accData <- accountDataOpt _ <- signedTxValidator.validate(stx, accData._1, blockHeader, upfrontCost, acumGas) - } yield (accData) + } yield accData validatedStx match { case Right((account, address)) => @@ -336,7 +326,7 @@ class BlockPreparator( } @tailrec - private[ledger] final def executePreparedTransactions( + final private[ledger] def executePreparedTransactions( signedTransactions: Seq[SignedTransaction], world: InMemoryWorldStateProxy, blockHeader: BlockHeader, @@ -401,5 +391,5 @@ class BlockPreparator( object BlockPreparator { val TreasuryRewardPercentageAfterECIP1098 = 20 - val MinerRewardPercentageAfterECIP1098 = 100 - TreasuryRewardPercentageAfterECIP1098 + val MinerRewardPercentageAfterECIP1098: Int = 100 - TreasuryRewardPercentageAfterECIP1098 } diff --git a/src/main/scala/io/iohk/ethereum/ledger/BlockQueue.scala b/src/main/scala/io/iohk/ethereum/ledger/BlockQueue.scala index de097edda9..36ecacf843 100644 --- a/src/main/scala/io/iohk/ethereum/ledger/BlockQueue.scala +++ b/src/main/scala/io/iohk/ethereum/ledger/BlockQueue.scala @@ -1,13 +1,17 @@ package io.iohk.ethereum.ledger import akka.util.ByteString -import io.iohk.ethereum.domain.{Block, Blockchain, ChainWeight} -import io.iohk.ethereum.ledger.BlockQueue.{Leaf, QueuedBlock} -import io.iohk.ethereum.utils.Config.SyncConfig -import io.iohk.ethereum.utils.Logger import scala.annotation.tailrec import scala.jdk.CollectionConverters._ + +import io.iohk.ethereum.domain.Block +import io.iohk.ethereum.domain.Blockchain +import io.iohk.ethereum.domain.ChainWeight +import io.iohk.ethereum.ledger.BlockQueue.Leaf +import io.iohk.ethereum.ledger.BlockQueue.QueuedBlock +import io.iohk.ethereum.utils.Config.SyncConfig +import io.iohk.ethereum.utils.Logger object BlockQueue { case class QueuedBlock(block: Block, weight: Option[ChainWeight]) case class Leaf(hash: ByteString, weight: ChainWeight) @@ -23,8 +27,7 @@ class BlockQueue(blockchain: Blockchain, val maxQueuedBlockNumberAhead: Int, val private val blocks = new java.util.concurrent.ConcurrentHashMap[ByteString, QueuedBlock].asScala private val parentToChildren = new java.util.concurrent.ConcurrentHashMap[ByteString, Set[ByteString]].asScala - /** - * Enqueue a block for optional later inclusion into the blockchain. + /** Enqueue a block for optional later inclusion into the blockchain. * Queued blocks are stored as trees with bi-directional relations. Therefore when a younger blocks arrives, * for which the total difficulty is known, we can update total difficulties of all its descendants. * @@ -82,23 +85,21 @@ class BlockQueue(blockchain: Blockchain, val maxQueuedBlockNumberAhead: Int, val def isQueued(hash: ByteString): Boolean = blocks.contains(hash) - /** - * Returns the weight of the block corresponding to the hash, or None if not found + /** Returns the weight of the block corresponding to the hash, or None if not found * @param hash the block's hash to get the weight from * @return the weight of the block corresponding to the hash, or None if not found */ def getChainWeightByHash(hash: ByteString): Option[ChainWeight] = blocks.get(hash).flatMap(_.weight) - /** - * Takes a branch going from descendant block upwards to the oldest ancestor + /** Takes a branch going from descendant block upwards to the oldest ancestor * @param descendant the youngest block to be removed * @param dequeue should the branch be removed from the queue. Shared part of branch won't be removed * @return full branch from oldest ancestor to descendant, even if not all of it is removed */ def getBranch(descendant: ByteString, dequeue: Boolean): List[Block] = { - def recur(hash: ByteString, childShared: Boolean): List[Block] = { + def recur(hash: ByteString, childShared: Boolean): List[Block] = blocks.get(hash) match { case Some(QueuedBlock(block, _)) => import block.header.parentHash @@ -115,13 +116,11 @@ class BlockQueue(blockchain: Blockchain, val maxQueuedBlockNumberAhead: Int, val case _ => Nil } - } recur(descendant, false).reverse } - /** - * Removes a whole subtree begining with the ancestor. To be used when ancestor fails to execute + /** Removes a whole subtree begining with the ancestor. To be used when ancestor fails to execute * @param ancestor hash of the ancestor block */ def removeSubtree(ancestor: ByteString): Unit = @@ -132,16 +131,14 @@ class BlockQueue(blockchain: Blockchain, val maxQueuedBlockNumberAhead: Int, val parentToChildren -= block.header.hash } - /** - * Clear the BlockQueue + /** Clear the BlockQueue */ def clear(): Unit = { blocks.clear() parentToChildren.clear() } - /** - * Removes stale blocks - too old or too young in relation the current best block number + /** Removes stale blocks - too old or too young in relation the current best block number * @param bestBlockNumber - best block number of the main chain */ private def cleanUp(bestBlockNumber: BigInt): Unit = { @@ -154,12 +151,11 @@ class BlockQueue(blockchain: Blockchain, val maxQueuedBlockNumberAhead: Int, val parentToChildren --= staleHashes } - /** - * Updates chain weights for a subtree. + /** Updates chain weights for a subtree. * @param ancestor An ancestor's hash that determines the subtree * @return Best leaf from the affected subtree */ - private def updateChainWeights(ancestor: ByteString): Option[Leaf] = { + private def updateChainWeights(ancestor: ByteString): Option[Leaf] = blocks.get(ancestor).flatMap(_.weight).flatMap { weight => parentToChildren.get(ancestor) match { @@ -174,10 +170,8 @@ class BlockQueue(blockchain: Blockchain, val maxQueuedBlockNumberAhead: Int, val Some(Leaf(ancestor, weight)) } } - } - /** - * Find a closest (youngest) chained ancestor. Chained means being part of a known chain, thus having total + /** Find a closest (youngest) chained ancestor. Chained means being part of a known chain, thus having total * difficulty defined * * @param descendant the block we start the search from diff --git a/src/main/scala/io/iohk/ethereum/ledger/BlockRewardCalculator.scala b/src/main/scala/io/iohk/ethereum/ledger/BlockRewardCalculator.scala index 5ebab51bdc..cec4b118af 100644 --- a/src/main/scala/io/iohk/ethereum/ledger/BlockRewardCalculator.scala +++ b/src/main/scala/io/iohk/ethereum/ledger/BlockRewardCalculator.scala @@ -2,8 +2,7 @@ package io.iohk.ethereum.ledger import io.iohk.ethereum.utils.MonetaryPolicyConfig -/** - * Calculates rewards for mining blocks and ommers. +/** Calculates rewards for mining blocks and ommers. * https://github.com/ethereumproject/ECIPs/blob/master/ECIPs/ECIP-1039.md completely specifies eventual rounding issues. */ class BlockRewardCalculator( @@ -56,8 +55,7 @@ class BlockRewardCalculator( */ val firstEraOmmerMiningRewardDenom: BigInt = 8 - /** - * Calculates the miner reward for the block, that is, without considering the ommers included + /** Calculates the miner reward for the block, that is, without considering the ommers included * * @param blockNumber of the mined block * @return miner reward for the block @@ -69,8 +67,7 @@ class BlockRewardCalculator( newBlockReward(blockNumber) * eraMultiplier / eraDivisor } - /** - * Calculates the miner reward for the ommers included on the block + /** Calculates the miner reward for the ommers included on the block * * @param blockNumber of the mined block * @param ommersCount the number of ommers on the block @@ -79,8 +76,7 @@ class BlockRewardCalculator( def calculateMiningRewardForOmmers(blockNumber: BigInt, ommersCount: Int): BigInt = calculateMiningRewardPerOmmer(blockNumber) * ommersCount - /** - * Calculates the ommers reward for the ommers included on the block + /** Calculates the ommers reward for the ommers included on the block * * @param blockNumber of the mined block * @param ommerNumber the block number of the ommer @@ -96,15 +92,13 @@ class BlockRewardCalculator( calculateMiningRewardForBlock(blockNumber) * ommerMiningRewardNumer / ommerMiningRewardDenom } - /** - * Calculates reward given to the miner for each ommer included in the block + /** Calculates reward given to the miner for each ommer included in the block * * @param blockNumber mined block * @return reward given to the miner for each ommer included */ - private def calculateMiningRewardPerOmmer(blockNumber: BigInt): BigInt = { + private def calculateMiningRewardPerOmmer(blockNumber: BigInt): BigInt = calculateMiningRewardForBlock(blockNumber) * ommerInclusionRewardNumer / ommerInclusionRewardDenom - } /** era number counting from 0 */ private def eraNumber(blockNumber: BigInt): Int = diff --git a/src/main/scala/io/iohk/ethereum/ledger/BlockValidation.scala b/src/main/scala/io/iohk/ethereum/ledger/BlockValidation.scala index c565bb1993..a5fd57444d 100644 --- a/src/main/scala/io/iohk/ethereum/ledger/BlockValidation.scala +++ b/src/main/scala/io/iohk/ethereum/ledger/BlockValidation.scala @@ -1,8 +1,12 @@ package io.iohk.ethereum.ledger import akka.util.ByteString + import io.iohk.ethereum.consensus.Consensus -import io.iohk.ethereum.domain.{Block, BlockHeader, BlockchainReader, Receipt} +import io.iohk.ethereum.domain.Block +import io.iohk.ethereum.domain.BlockHeader +import io.iohk.ethereum.domain.BlockchainReader +import io.iohk.ethereum.domain.Receipt import io.iohk.ethereum.ledger.BlockExecutionError.ValidationBeforeExecError class BlockValidation( @@ -11,17 +15,15 @@ class BlockValidation( blockQueue: BlockQueue ) { - def validateBlockBeforeExecution(block: Block): Either[ValidationBeforeExecError, BlockExecutionSuccess] = { + def validateBlockBeforeExecution(block: Block): Either[ValidationBeforeExecError, BlockExecutionSuccess] = consensus.validators.validateBlockBeforeExecution( block = block, getBlockHeaderByHash = getBlockHeaderFromChainOrQueue, getNBlocksBack = getNBlocksBackFromChainOrQueue ) - } - private def getBlockHeaderFromChainOrQueue(hash: ByteString): Option[BlockHeader] = { + private def getBlockHeaderFromChainOrQueue(hash: ByteString): Option[BlockHeader] = blockchainReader.getBlockHeaderByHash(hash).orElse(blockQueue.getBlockByHash(hash).map(_.header)) - } private def getNBlocksBackFromChainOrQueue(hash: ByteString, n: Int): List[Block] = { val queuedBlocks = blockQueue.getBranch(hash, dequeue = false).takeRight(n) @@ -50,12 +52,11 @@ class BlockValidation( stateRootHash: ByteString, receipts: Seq[Receipt], gasUsed: BigInt - ): Either[BlockExecutionError, BlockExecutionSuccess] = { + ): Either[BlockExecutionError, BlockExecutionSuccess] = consensus.validators.validateBlockAfterExecution( block = block, stateRootHash = stateRootHash, receipts = receipts, gasUsed = gasUsed ) - } } diff --git a/src/main/scala/io/iohk/ethereum/ledger/BloomFilter.scala b/src/main/scala/io/iohk/ethereum/ledger/BloomFilter.scala index ba872eee94..7f5ee0b33a 100644 --- a/src/main/scala/io/iohk/ethereum/ledger/BloomFilter.scala +++ b/src/main/scala/io/iohk/ethereum/ledger/BloomFilter.scala @@ -1,8 +1,9 @@ package io.iohk.ethereum.ledger import akka.util.ByteString -import io.iohk.ethereum.domain.TxLogEntry + import io.iohk.ethereum.crypto._ +import io.iohk.ethereum.domain.TxLogEntry import io.iohk.ethereum.utils.ByteUtils import io.iohk.ethereum.utils.ByteUtils.or @@ -13,17 +14,15 @@ object BloomFilter { val EmptyBloomFilter: ByteString = ByteString(Array.fill(BloomFilterByteSize)(0.toByte)) private val IntIndexesToAccess: Set[Int] = Set(0, 2, 4) - def containsAnyOf(bloomFilterBytes: ByteString, toCheck: Seq[ByteString]): Boolean = { + def containsAnyOf(bloomFilterBytes: ByteString, toCheck: Seq[ByteString]): Boolean = toCheck.exists { bytes => val bloomFilterForBytes = bloomFilter(bytes.toArray[Byte]) val andResult = ByteUtils.and(bloomFilterForBytes, bloomFilterBytes.toArray[Byte]) - andResult sameElements bloomFilterForBytes + andResult.sameElements(bloomFilterForBytes) } - } - /** - * Given the logs of a receipt creates the bloom filter associated with them + /** Given the logs of a receipt creates the bloom filter associated with them * as stated in section 4.4.1 of the YP * * @param logs from the receipt whose bloom filter will be created diff --git a/src/main/scala/io/iohk/ethereum/ledger/BranchResolution.scala b/src/main/scala/io/iohk/ethereum/ledger/BranchResolution.scala index 427ae49ae0..2a97e0f4ff 100644 --- a/src/main/scala/io/iohk/ethereum/ledger/BranchResolution.scala +++ b/src/main/scala/io/iohk/ethereum/ledger/BranchResolution.scala @@ -1,12 +1,17 @@ package io.iohk.ethereum.ledger import cats.data.NonEmptyList -import io.iohk.ethereum.domain.{Block, BlockHeader, Blockchain, BlockchainReader, ChainWeight} + +import io.iohk.ethereum.domain.Block +import io.iohk.ethereum.domain.BlockHeader +import io.iohk.ethereum.domain.Blockchain +import io.iohk.ethereum.domain.BlockchainReader +import io.iohk.ethereum.domain.ChainWeight import io.iohk.ethereum.utils.Logger class BranchResolution(blockchain: Blockchain, blockchainReader: BlockchainReader) extends Logger { - def resolveBranch(headers: NonEmptyList[BlockHeader]): BranchResolutionResult = { + def resolveBranch(headers: NonEmptyList[BlockHeader]): BranchResolutionResult = if (!doHeadersFormChain(headers)) { InvalidBranch } else { @@ -18,7 +23,6 @@ class BranchResolution(blockchain: Blockchain, blockchainReader: BlockchainReade else compareBranch(headers) } - } private[ledger] def doHeadersFormChain(headers: NonEmptyList[BlockHeader]): Boolean = headers.toList.zip(headers.tail).forall { case (parent, child) => diff --git a/src/main/scala/io/iohk/ethereum/ledger/InMemorySimpleMapProxy.scala b/src/main/scala/io/iohk/ethereum/ledger/InMemorySimpleMapProxy.scala index 8663ebb739..96682c4bba 100644 --- a/src/main/scala/io/iohk/ethereum/ledger/InMemorySimpleMapProxy.scala +++ b/src/main/scala/io/iohk/ethereum/ledger/InMemorySimpleMapProxy.scala @@ -7,8 +7,7 @@ object InMemorySimpleMapProxy { new InMemorySimpleMapProxy(inner, Map.empty[K, Option[V]]) } -/** - * This class keeps holds changes made to the inner [[io.iohk.ethereum.common.SimpleMap]] until data is commited +/** This class keeps holds changes made to the inner [[io.iohk.ethereum.common.SimpleMap]] until data is commited * * @param inner [[io.iohk.ethereum.common.SimpleMap]] to proxy * @param cache InMemory map where data is going to be cached @@ -23,12 +22,11 @@ class InMemorySimpleMapProxy[K, V, I <: SimpleMap[K, V, I]] private (val inner: def changes: Changes = cache.foldLeft(Seq.empty[K] -> Seq.empty[(K, V)]) { (acc, cachedItem) => cachedItem match { case (key, Some(value)) => (acc._1, acc._2 :+ key -> value) - case (key, None) => (acc._1 :+ key, acc._2) + case (key, None) => (acc._1 :+ key, acc._2) } } - /** - * Persists the changes into the underlying [[io.iohk.ethereum.common.SimpleMap]] + /** Persists the changes into the underlying [[io.iohk.ethereum.common.SimpleMap]] * * @return Updated proxy */ @@ -37,15 +35,13 @@ class InMemorySimpleMapProxy[K, V, I <: SimpleMap[K, V, I]] private (val inner: new InMemorySimpleMapProxy[K, V, I](inner.update(changesToApply._1, changesToApply._2), Map.empty) } - /** - * Clears the cache without applying the changes + /** Clears the cache without applying the changes * * @return Updated proxy */ def rollback: InMemorySimpleMapProxy[K, V, I] = new InMemorySimpleMapProxy[K, V, I](inner, Map.empty) - /** - * This function obtains the value asociated with the key passed, if there exists one. + /** This function obtains the value asociated with the key passed, if there exists one. * * @param key * @return Option object with value if there exists one. @@ -54,8 +50,7 @@ class InMemorySimpleMapProxy[K, V, I <: SimpleMap[K, V, I]] private (val inner: def wrapped: I = inner - /** - * This function updates the KeyValueStore by deleting, updating and inserting new (key-value) pairs. + /** This function updates the KeyValueStore by deleting, updating and inserting new (key-value) pairs. * * @param toRemove which includes all the keys to be removed from the KeyValueStore. * @param toUpsert which includes all the (key-value) pairs to be inserted into the KeyValueStore. @@ -63,7 +58,7 @@ class InMemorySimpleMapProxy[K, V, I <: SimpleMap[K, V, I]] private (val inner: * @return the new DataSource after the removals and insertions were done. */ override def update(toRemove: Seq[K], toUpsert: Seq[(K, V)]): InMemorySimpleMapProxy[K, V, I] = { - val afterRemoval = toRemove.foldLeft(cache) { (updated, key) => updated + (key -> None) } + val afterRemoval = toRemove.foldLeft(cache)((updated, key) => updated + (key -> None)) val afterInserts = toUpsert.foldLeft(afterRemoval) { (updated, toUpsert) => updated + (toUpsert._1 -> Some(toUpsert._2)) } diff --git a/src/main/scala/io/iohk/ethereum/ledger/InMemoryWorldStateProxy.scala b/src/main/scala/io/iohk/ethereum/ledger/InMemoryWorldStateProxy.scala index 4e3c808aa5..911c20a57b 100644 --- a/src/main/scala/io/iohk/ethereum/ledger/InMemoryWorldStateProxy.scala +++ b/src/main/scala/io/iohk/ethereum/ledger/InMemoryWorldStateProxy.scala @@ -1,13 +1,15 @@ package io.iohk.ethereum.ledger import akka.util.ByteString + import io.iohk.ethereum.crypto.kec256 import io.iohk.ethereum.db.storage.EvmCodeStorage.Code import io.iohk.ethereum.db.storage._ import io.iohk.ethereum.domain import io.iohk.ethereum.domain._ import io.iohk.ethereum.mpt.MerklePatriciaTrie -import io.iohk.ethereum.vm.{Storage, WorldStateProxy} +import io.iohk.ethereum.vm.Storage +import io.iohk.ethereum.vm.WorldStateProxy object InMemoryWorldStateProxy { @@ -55,8 +57,7 @@ object InMemoryWorldStateProxy { ) } - /** - * Updates state trie with current changes but does not persist them into the storages. To do so it: + /** Updates state trie with current changes but does not persist them into the storages. To do so it: * - Commits code (to get account's code hashes) * - Commits constract storages (to get account's contract storage root) * - Updates state tree @@ -65,7 +66,7 @@ object InMemoryWorldStateProxy { * @return Updated world */ def persistState(worldState: InMemoryWorldStateProxy): InMemoryWorldStateProxy = { - def persistCode(worldState: InMemoryWorldStateProxy): InMemoryWorldStateProxy = { + def persistCode(worldState: InMemoryWorldStateProxy): InMemoryWorldStateProxy = worldState.accountCodes.foldLeft(worldState) { case (updatedWorldState, (address, code)) => val codeHash = kec256(code) updatedWorldState.evmCodeStorage.put(codeHash, code).commit() @@ -75,7 +76,6 @@ object InMemoryWorldStateProxy { accountCodes = Map.empty ) } - } def persistContractStorage(worldState: InMemoryWorldStateProxy): InMemoryWorldStateProxy = worldState.contractStorages.foldLeft(worldState) { case (updatedWorldState, (address, storageTrie)) => @@ -94,11 +94,10 @@ object InMemoryWorldStateProxy { def persistAccountsStateTrie(worldState: InMemoryWorldStateProxy): InMemoryWorldStateProxy = worldState.copyWith(accountsStateTrie = worldState.accountsStateTrie.persist()) - (persistCode _ andThen persistContractStorage andThen persistAccountsStateTrie)(worldState) + ((persistCode _).andThen(persistContractStorage).andThen(persistAccountsStateTrie))(worldState) } - /** - * Returns an [[InMemorySimpleMapProxy]] of the accounts state trie "The world state (state), is a mapping + /** Returns an [[InMemorySimpleMapProxy]] of the accounts state trie "The world state (state), is a mapping * between Keccak 256-bit hashes of the addresses (160-bit identifiers) and account states (a data structure serialised as RLP [...]). * Though not stored on the blockchain, it is assumed that the implementation will maintain this mapping in a * modified Merkle Patricia tree [...])." @@ -112,14 +111,13 @@ object InMemoryWorldStateProxy { private def createProxiedAccountsStateTrie( accountsStorage: MptStorage, stateRootHash: ByteString - ): InMemorySimpleMapProxy[Address, Account, MerklePatriciaTrie[Address, Account]] = { + ): InMemorySimpleMapProxy[Address, Account, MerklePatriciaTrie[Address, Account]] = InMemorySimpleMapProxy.wrap[Address, Account, MerklePatriciaTrie[Address, Account]]( MerklePatriciaTrie[Address, Account]( stateRootHash.toArray[Byte], accountsStorage )(Address.hashedAddressEncoder, accountSerializer) ) - } } class InMemoryWorldStateProxyStorage( @@ -163,9 +161,8 @@ class InMemoryWorldStateProxy( override def getGuaranteedAccount(address: Address): Account = super.getGuaranteedAccount(address) - override def saveAccount(address: Address, account: Account): InMemoryWorldStateProxy = { + override def saveAccount(address: Address, account: Account): InMemoryWorldStateProxy = copyWith(accountsStateTrie = accountsStateTrie.put(address, account)) - } override def deleteAccount(address: Address): InMemoryWorldStateProxy = copyWith( @@ -200,15 +197,13 @@ class InMemoryWorldStateProxy( override def noEmptyAccounts: Boolean = noEmptyAccountsCond - override def keepPrecompileTouched(world: InMemoryWorldStateProxy): InMemoryWorldStateProxy = { + override def keepPrecompileTouched(world: InMemoryWorldStateProxy): InMemoryWorldStateProxy = if (world.touchedAccounts.contains(ripmdContractAddress)) copyWith(touchedAccounts = touchedAccounts + ripmdContractAddress) else this - } - /** - * Returns world state root hash. This value is only updated after persist. + /** Returns world state root hash. This value is only updated after persist. */ def stateRootHash: ByteString = ByteString(accountsStateTrie.inner.getRootHash) @@ -244,8 +239,7 @@ class InMemoryWorldStateProxy( override def getBlockHash(number: UInt256): Option[UInt256] = getBlockByNumber(number).map(UInt256(_)) - /** - * Returns an [[InMemorySimpleMapProxy]] of the contract storage, for `ethCompatibleStorage` defined as "trie as a map-ping from the Keccak + /** Returns an [[InMemorySimpleMapProxy]] of the contract storage, for `ethCompatibleStorage` defined as "trie as a map-ping from the Keccak * 256-bit hash of the 256-bit integer keys to the RLP-encoded256-bit integer values." * See [[http://paper.gavwood.com YP 4.1]] * diff --git a/src/main/scala/io/iohk/ethereum/ledger/PreparedBlock.scala b/src/main/scala/io/iohk/ethereum/ledger/PreparedBlock.scala index 9106f8aa48..406d112600 100644 --- a/src/main/scala/io/iohk/ethereum/ledger/PreparedBlock.scala +++ b/src/main/scala/io/iohk/ethereum/ledger/PreparedBlock.scala @@ -1,6 +1,7 @@ package io.iohk.ethereum.ledger import akka.util.ByteString + import io.iohk.ethereum.domain.Block case class PreparedBlock( diff --git a/src/main/scala/io/iohk/ethereum/ledger/StxLedger.scala b/src/main/scala/io/iohk/ethereum/ledger/StxLedger.scala index 9e8c7cc55e..5bbb2fc7e1 100644 --- a/src/main/scala/io/iohk/ethereum/ledger/StxLedger.scala +++ b/src/main/scala/io/iohk/ethereum/ledger/StxLedger.scala @@ -1,11 +1,16 @@ package io.iohk.ethereum.ledger +import scala.annotation.tailrec + import io.iohk.ethereum.db.storage.EvmCodeStorage -import io.iohk.ethereum.domain.{Account, BlockHeader, BlockchainImpl, BlockchainReader, SignedTransactionWithSender} +import io.iohk.ethereum.domain.Account +import io.iohk.ethereum.domain.BlockHeader +import io.iohk.ethereum.domain.BlockchainImpl +import io.iohk.ethereum.domain.BlockchainReader +import io.iohk.ethereum.domain.SignedTransactionWithSender import io.iohk.ethereum.ledger.TxResult import io.iohk.ethereum.utils.BlockchainConfig import io.iohk.ethereum.vm.EvmConfig -import scala.annotation.tailrec class StxLedger( blockchain: BlockchainImpl, @@ -70,8 +75,7 @@ class StxLedger( object StxLedger { - /** - * Function finds minimal value in some interval for which provided function do not return error + /** Function finds minimal value in some interval for which provided function do not return error * If searched value is not in provided interval, function returns maximum value of searched interval * @param min minimum of searched interval * @param max maximum of searched interval diff --git a/src/main/scala/io/iohk/ethereum/ledger/TxResult.scala b/src/main/scala/io/iohk/ethereum/ledger/TxResult.scala index 7f2a382e4e..a3f0707166 100644 --- a/src/main/scala/io/iohk/ethereum/ledger/TxResult.scala +++ b/src/main/scala/io/iohk/ethereum/ledger/TxResult.scala @@ -1,8 +1,9 @@ package io.iohk.ethereum.ledger import akka.util.ByteString -import io.iohk.ethereum.vm.ProgramError + import io.iohk.ethereum.domain.TxLogEntry +import io.iohk.ethereum.vm.ProgramError case class TxResult( worldState: InMemoryWorldStateProxy, diff --git a/src/main/scala/io/iohk/ethereum/ledger/package.scala b/src/main/scala/io/iohk/ethereum/ledger/package.scala index 55c3e51ed1..8bfd244d6f 100644 --- a/src/main/scala/io/iohk/ethereum/ledger/package.scala +++ b/src/main/scala/io/iohk/ethereum/ledger/package.scala @@ -1,8 +1,8 @@ package io.iohk.ethereum -import io.iohk.ethereum.vm.VM import io.iohk.ethereum.vm.ProgramContext import io.iohk.ethereum.vm.ProgramResult +import io.iohk.ethereum.vm.VM package object ledger { type VMImpl = VM[InMemoryWorldStateProxy, InMemoryWorldStateProxyStorage] diff --git a/src/main/scala/io/iohk/ethereum/logger/LoggingMailbox.scala b/src/main/scala/io/iohk/ethereum/logger/LoggingMailbox.scala index d4abb2e728..27c51a563e 100644 --- a/src/main/scala/io/iohk/ethereum/logger/LoggingMailbox.scala +++ b/src/main/scala/io/iohk/ethereum/logger/LoggingMailbox.scala @@ -2,13 +2,14 @@ package io.iohk.ethereum.logger import java.util.concurrent.atomic.AtomicInteger -import akka.actor.{ActorRef, ActorSystem} +import akka.actor.ActorRef +import akka.actor.ActorSystem import akka.dispatch._ import akka.event.Logging + import com.typesafe.config.Config -/** - * Logs the mailbox size when exceeding the configured limit. It logs at most once per second +/** Logs the mailbox size when exceeding the configured limit. It logs at most once per second * when the messages are enqueued or dequeued. * * Configuration: @@ -35,7 +36,7 @@ class LoggingMailbox(owner: ActorRef, system: ActorSystem, sizeLimit: Int) exten private val interval = 1000000000L // 1 s, in nanoseconds private lazy val log = Logging(system, classOf[LoggingMailbox]) - private val path = owner.path.toString + owner.path.toString @volatile private var logTime: Long = System.nanoTime() private val queueSize = new AtomicInteger private val dequeueCount = new AtomicInteger @@ -61,7 +62,7 @@ class LoggingMailbox(owner: ActorRef, system: ActorSystem, sizeLimit: Int) exten val now = System.nanoTime() if (now - logTime > interval) { val msgPerSecond = dequeueCount.get.toDouble / ((now - logTime).toDouble / interval) - val actorName = owner.path.name + owner.path.name logTime = now dequeueCount.set(0) log.info("Mailbox size for [{}] is [{}], processing [{}] msg/s", owner, size, f"$msgPerSecond%2.2f") @@ -70,7 +71,6 @@ class LoggingMailbox(owner: ActorRef, system: ActorSystem, sizeLimit: Int) exten override def numberOfMessages: Int = queueSize.get - override def cleanUp(owner: ActorRef, deadLetters: MessageQueue): Unit = { + override def cleanUp(owner: ActorRef, deadLetters: MessageQueue): Unit = super.cleanUp(owner, deadLetters) - } } diff --git a/src/main/scala/io/iohk/ethereum/metrics/DeltaSpikeGauge.scala b/src/main/scala/io/iohk/ethereum/metrics/DeltaSpikeGauge.scala index 49acdb8ad6..5bfd1b7c8d 100644 --- a/src/main/scala/io/iohk/ethereum/metrics/DeltaSpikeGauge.scala +++ b/src/main/scala/io/iohk/ethereum/metrics/DeltaSpikeGauge.scala @@ -1,33 +1,31 @@ package io.iohk.ethereum.metrics -import java.util.concurrent.atomic.{AtomicBoolean, AtomicInteger} +import java.util.concurrent.atomic.AtomicBoolean +import java.util.concurrent.atomic.AtomicInteger -/** - * A gauge that starts at `0` and can be triggered to go to `1`. +/** A gauge that starts at `0` and can be triggered to go to `1`. * Next time it is sampled, it goes back to `0`. * This is normally used for either one-off signals (e.g. when an application starts) * or slowly re-appearing signals. Specifically, the sampling rate must be greater * than the rate the signal is triggered. */ class DeltaSpikeGauge(name: String, metrics: Metrics) { - private[this] final val isTriggeredRef = new AtomicBoolean(false) - private[this] final val valueRef = new AtomicInteger(0) + final private[this] val isTriggeredRef = new AtomicBoolean(false) + final private[this] val valueRef = new AtomicInteger(0) - private[this] def getValue(): Double = { + private[this] def getValue(): Double = if (isTriggeredRef.compareAndSet(true, false)) { valueRef.getAndSet(0) } else { valueRef.get() } - } - private[this] final val gauge = metrics.gauge(name, () => getValue()) + metrics.gauge(name, () => getValue()) - def trigger(): Unit = { + def trigger(): Unit = if (isTriggeredRef.compareAndSet(false, true)) { valueRef.set(1) // Let one of the exporting metric registries pick up the `1`. // As soon as that happens, `getValue` will make sure that we go back to `0`. } - } } diff --git a/src/main/scala/io/iohk/ethereum/metrics/MeterRegistryBuilder.scala b/src/main/scala/io/iohk/ethereum/metrics/MeterRegistryBuilder.scala index 19c3c786c8..a55a9eb3fe 100644 --- a/src/main/scala/io/iohk/ethereum/metrics/MeterRegistryBuilder.scala +++ b/src/main/scala/io/iohk/ethereum/metrics/MeterRegistryBuilder.scala @@ -1,23 +1,24 @@ package io.iohk.ethereum.metrics -import io.iohk.ethereum.utils.Logger -import io.iohk.ethereum.utils.LoggingUtils.getClassName +import io.micrometer.core.instrument._ import io.micrometer.core.instrument.composite.CompositeMeterRegistry import io.micrometer.core.instrument.config.MeterFilter -import io.micrometer.core.instrument._ -import io.micrometer.prometheus.{PrometheusMeterRegistry, PrometheusConfig} -import io.prometheus.client.CollectorRegistry import io.micrometer.jmx.JmxMeterRegistry +import io.micrometer.prometheus.PrometheusConfig +import io.micrometer.prometheus.PrometheusMeterRegistry +import io.prometheus.client.CollectorRegistry + +import io.iohk.ethereum.utils.Logger +import io.iohk.ethereum.utils.LoggingUtils.getClassName object MeterRegistryBuilder extends Logger { - private[this] final val StdMetricsClock = Clock.SYSTEM + final private[this] val StdMetricsClock = Clock.SYSTEM private[this] def onMeterAdded(m: Meter): Unit = log.debug(s"New ${getClassName(m)} metric: " + m.getId.getName) - /** - * Build our meter registry consist in: + /** Build our meter registry consist in: * 1. Create each Meter registry * 2. Config the resultant composition */ @@ -46,9 +47,8 @@ object MeterRegistryBuilder extends Logger { registry .config() .meterFilter(new MeterFilter { - override def map(id: Meter.Id): Meter.Id = { + override def map(id: Meter.Id): Meter.Id = id.withName(MetricsUtils.mkNameWithPrefix(metricsPrefix)(id.getName)) - } }) .onMeterAdded(onMeterAdded) diff --git a/src/main/scala/io/iohk/ethereum/metrics/Metrics.scala b/src/main/scala/io/iohk/ethereum/metrics/Metrics.scala index 8785cd6ed3..39afb67ba3 100644 --- a/src/main/scala/io/iohk/ethereum/metrics/Metrics.scala +++ b/src/main/scala/io/iohk/ethereum/metrics/Metrics.scala @@ -2,14 +2,14 @@ package io.iohk.ethereum.metrics import java.util.concurrent.atomic.AtomicReference +import scala.util.Try + import io.micrometer.core.instrument._ import io.micrometer.core.instrument.simple.SimpleMeterRegistry import io.prometheus.client.exporter.HTTPServer import io.prometheus.client.hotspot.DefaultExports import kamon.Kamon -import scala.util.Try - case class Metrics(metricsPrefix: String, registry: MeterRegistry, serverPort: Int = 0) { private[this] def mkName: String => String = MetricsUtils.mkNameWithPrefix(metricsPrefix) @@ -30,8 +30,7 @@ case class Metrics(metricsPrefix: String, registry: MeterRegistry, serverPort: I def deltaSpike(name: String): DeltaSpikeGauge = new DeltaSpikeGauge(mkName(name), this) - /** - * Returns a [[io.micrometer.core.instrument.Gauge Gauge]]. + /** Returns a [[io.micrometer.core.instrument.Gauge Gauge]]. * @param computeValue A function that computes the current gauge value. */ def gauge(name: String, computeValue: () => Double): Gauge = @@ -43,16 +42,14 @@ case class Metrics(metricsPrefix: String, registry: MeterRegistry, serverPort: I .builder(mkName(name), this, (_: Any) => computeValue()) .register(registry) - /** - * Returns a [[io.micrometer.core.instrument.Counter Counter]]. + /** Returns a [[io.micrometer.core.instrument.Counter Counter]]. */ def counter(name: String): Counter = Counter .builder(mkName(name)) .register(registry) - /** - * Returns a [[io.micrometer.core.instrument.Timer Timer]]. + /** Returns a [[io.micrometer.core.instrument.Timer Timer]]. */ def timer(name: String, tags: String*): Timer = Timer @@ -60,8 +57,7 @@ case class Metrics(metricsPrefix: String, registry: MeterRegistry, serverPort: I .tags(tags: _*) .register(registry) - /** - * Returns a [[io.micrometer.core.instrument.DistributionSummary DistributionSummary]]. + /** Returns a [[io.micrometer.core.instrument.DistributionSummary DistributionSummary]]. */ def distribution(name: String): DistributionSummary = DistributionSummary @@ -73,20 +69,19 @@ object Metrics { final val MetricsPrefix = "app" //+ Metrics singleton support - private[this] final val metricsSentinel = Metrics(MetricsPrefix, new SimpleMeterRegistry()) + final private[this] val metricsSentinel = Metrics(MetricsPrefix, new SimpleMeterRegistry()) - private[this] final val metricsRef = new AtomicReference[Metrics](metricsSentinel) + final private[this] val metricsRef = new AtomicReference[Metrics](metricsSentinel) private[this] def setOnce(metrics: Metrics): Boolean = metricsRef.compareAndSet(metricsSentinel, metrics) def get(): Metrics = metricsRef.get() //- Metrics singleton support - /** - * Instantiates and configures the metrics "service". This should happen once in the lifetime of the application. + /** Instantiates and configures the metrics "service". This should happen once in the lifetime of the application. * After this call completes successfully, you can obtain the metrics service by using `Metrics.get()`. */ - def configure(config: MetricsConfig): Try[Unit] = { + def configure(config: MetricsConfig): Try[Unit] = Try { if (config.enabled) { val registry = MeterRegistryBuilder.build(MetricsPrefix) @@ -99,5 +94,4 @@ object Metrics { } } } - } } diff --git a/src/main/scala/io/iohk/ethereum/metrics/MetricsContainer.scala b/src/main/scala/io/iohk/ethereum/metrics/MetricsContainer.scala index b034fa592f..8e5fed7415 100644 --- a/src/main/scala/io/iohk/ethereum/metrics/MetricsContainer.scala +++ b/src/main/scala/io/iohk/ethereum/metrics/MetricsContainer.scala @@ -1,7 +1,6 @@ package io.iohk.ethereum.metrics -/** - * An object that contains metrics, typically owned by an application component. +/** An object that contains metrics, typically owned by an application component. * We also use it as a marker trait, so that subclasses can easily give us an idea * of what metrics we implement across the application. */ diff --git a/src/main/scala/io/iohk/ethereum/mpt/HexPrefix.scala b/src/main/scala/io/iohk/ethereum/mpt/HexPrefix.scala index 06391fc58d..817d2243bf 100644 --- a/src/main/scala/io/iohk/ethereum/mpt/HexPrefix.scala +++ b/src/main/scala/io/iohk/ethereum/mpt/HexPrefix.scala @@ -2,8 +2,7 @@ package io.iohk.ethereum.mpt object HexPrefix { - /** - * Pack nibbles to binary + /** Pack nibbles to binary * * @param nibbles sequence * @param isLeaf boolean used to encode whether or not the data being encoded corresponds to a LeafNode or an ExtensionNode @@ -21,8 +20,7 @@ object HexPrefix { nibblesToBytes(nibblesWithFlag) } - /** - * Unpack a binary string to its nibbles equivalent + /** Unpack a binary string to its nibbles equivalent * * @param src of binary data * @return array of nibbles in byte-format and @@ -39,8 +37,7 @@ object HexPrefix { (res, t) } - /** - * Transforms an array of 8bit values to the corresponding array of 4bit values (hexadecimal format) + /** Transforms an array of 8bit values to the corresponding array of 4bit values (hexadecimal format) * Needs to be as fast possible, which requires usage of var's and mutable arrays. * @param bytes byte[] * @return array with each individual nibble @@ -58,8 +55,7 @@ object HexPrefix { newArray } - /** - * Transforms an array of 4bit values (hexadecimal format) to the corresponding array of 8bit values + /** Transforms an array of 4bit values (hexadecimal format) to the corresponding array of 8bit values * Needs to be as fast possible, which requires usage of var's and mutable arrays. * @param nibbles byte[] * @return array with bytes combining pairs of nibbles diff --git a/src/main/scala/io/iohk/ethereum/mpt/MerklePatriciaTrie.scala b/src/main/scala/io/iohk/ethereum/mpt/MerklePatriciaTrie.scala index 33783d0fef..da9a9793a1 100644 --- a/src/main/scala/io/iohk/ethereum/mpt/MerklePatriciaTrie.scala +++ b/src/main/scala/io/iohk/ethereum/mpt/MerklePatriciaTrie.scala @@ -1,23 +1,28 @@ package io.iohk.ethereum.mpt import akka.util.ByteString + +import scala.annotation.tailrec + +import org.bouncycastle.util.encoders.Hex + import io.iohk.ethereum.common.SimpleMap import io.iohk.ethereum.db.storage.MptStorage -import io.iohk.ethereum.db.storage.NodeStorage.{NodeEncoded, NodeHash} +import io.iohk.ethereum.db.storage.NodeStorage.NodeEncoded +import io.iohk.ethereum.db.storage.NodeStorage.NodeHash import io.iohk.ethereum.mpt import io.iohk.ethereum.rlp.RLPImplicits._ import io.iohk.ethereum.rlp.{encode => encodeRLP} -import org.bouncycastle.util.encoders.Hex import io.iohk.ethereum.utils.ByteUtils.matchingLength -import scala.annotation.tailrec object MerklePatriciaTrie { - implicit val defaultByteArraySerializable = new ByteArraySerializable[Array[Byte]] { - override def toBytes(input: Array[Byte]): Array[Byte] = input + implicit val defaultByteArraySerializable: ByteArraySerializable[Array[Byte]] = + new ByteArraySerializable[Array[Byte]] { + override def toBytes(input: Array[Byte]): Array[Byte] = input - override def fromBytes(bytes: Array[Byte]): Array[Byte] = bytes - } + override def fromBytes(bytes: Array[Byte]): Array[Byte] = bytes + } class MPTException(val message: String) extends RuntimeException(message) @@ -28,7 +33,7 @@ object MerklePatriciaTrie { class MissingRootNodeException(hash: ByteString) extends MissingNodeException(hash, s"Root node not found ${Hex.toHexString(hash.toArray)}") - val EmptyEncoded = encodeRLP(Array.emptyByteArray) + val EmptyEncoded: Array[Byte] = encodeRLP(Array.emptyByteArray) val EmptyRootHash: Array[Byte] = Node.hashFn(EmptyEncoded) private case class NodeInsertResult(newNode: MptNode, toDeleteFromStorage: List[MptNode] = Nil) @@ -50,13 +55,12 @@ object MerklePatriciaTrie { def apply[K, V](rootHash: Array[Byte], source: MptStorage)(implicit kSerializer: ByteArrayEncoder[K], vSerializer: ByteArraySerializable[V] - ): MerklePatriciaTrie[K, V] = { - if (EmptyRootHash sameElements rootHash) + ): MerklePatriciaTrie[K, V] = + if (EmptyRootHash.sameElements(rootHash)) MerklePatriciaTrie(source) else { new MerklePatriciaTrie[K, V](Some(mpt.HashNode(rootHash)), source)(kSerializer, vSerializer) } - } } trait NodesKeyValueStorage extends SimpleMap[NodeHash, NodeEncoded, NodesKeyValueStorage] { @@ -73,14 +77,13 @@ class MerklePatriciaTrie[K, V] private (private[mpt] val rootNode: Option[MptNod lazy val getRootHash: Array[Byte] = rootNode.map(_.hash).getOrElse(EmptyRootHash) - /** - * Get the value associated with the key passed, if there exists one. + /** Get the value associated with the key passed, if there exists one. * * @param key * @return Option object with value if there exists one. * @throws io.iohk.ethereum.mpt.MerklePatriciaTrie.MPTException if there is any inconsistency in how the trie is build. */ - def get(key: K): Option[V] = { + def get(key: K): Option[V] = pathTraverse[Option[V]](None, mkKeyNibbles(key)) { case (_, Some(LeafNode(_, value, _, _, _))) => Some(vSerializer.fromBytes(value.toArray[Byte])) @@ -90,16 +93,14 @@ class MerklePatriciaTrie[K, V] private (private[mpt] val rootNode: Option[MptNod case _ => None }.flatten - } - /** - * Get the proof associated with the key passed, if there exists one. + /** Get the proof associated with the key passed, if there exists one. * * @param key * @return Option object with proof if there exists one. * @throws io.iohk.ethereum.mpt.MerklePatriciaTrie.MPTException if there is any inconsistency in how the trie is build. */ - def getProof(key: K): Option[Vector[MptNode]] = { + def getProof(key: K): Option[Vector[MptNode]] = pathTraverse[Vector[MptNode]](Vector.empty, mkKeyNibbles(key)) { case (acc, node) => node match { case Some(nextNodeOnExt @ (_: BranchNode | _: ExtensionNode | _: LeafNode | _: HashNode)) => @@ -107,10 +108,8 @@ class MerklePatriciaTrie[K, V] private (private[mpt] val rootNode: Option[MptNod case _ => acc } } - } - /** - * Traverse given path from the root to value and accumulate data. + /** Traverse given path from the root to value and accumulate data. * Only nodes which are significant for searching for value are taken into account. * * @param acc initial accumulator @@ -122,14 +121,14 @@ class MerklePatriciaTrie[K, V] private (private[mpt] val rootNode: Option[MptNod private def pathTraverse[T](acc: T, searchKey: Array[Byte])(op: (T, Option[MptNode]) => T): Option[T] = { @tailrec - def pathTraverse(acc: T, node: MptNode, searchKey: Array[Byte], op: (T, Option[MptNode]) => T): Option[T] = { + def pathTraverse(acc: T, node: MptNode, searchKey: Array[Byte], op: (T, Option[MptNode]) => T): Option[T] = node match { case LeafNode(key, _, _, _, _) => - if (key.toArray[Byte] sameElements searchKey) Some(op(acc, Some(node))) else Some(op(acc, None)) + if (key.toArray[Byte].sameElements(searchKey)) Some(op(acc, Some(node))) else Some(op(acc, None)) case extNode @ ExtensionNode(sharedKey, _, _, _, _) => val (commonKey, remainingKey) = searchKey.splitAt(sharedKey.length) - if (searchKey.length >= sharedKey.length && (sharedKey.toArray[Byte] sameElements commonKey)) { + if (searchKey.length >= sharedKey.length && (sharedKey.toArray[Byte].sameElements(commonKey))) { pathTraverse(op(acc, Some(node)), extNode.next, remainingKey, op) } else Some(op(acc, None)) @@ -149,7 +148,6 @@ class MerklePatriciaTrie[K, V] private (private[mpt] val rootNode: Option[MptNod case NullNode => Some(op(acc, None)) } - } rootNode match { case Some(root) => @@ -169,8 +167,7 @@ class MerklePatriciaTrie[K, V] private (private[mpt] val rootNode: Option[MptNod private def mkKeyNibbles(key: K): Array[Byte] = HexPrefix.bytesToNibbles(kSerializer.toBytes(key)) - /** - * This function inserts a (key-value) pair into the trie. If the key is already asociated with another value it is updated. + /** This function inserts a (key-value) pair into the trie. If the key is already asociated with another value it is updated. * * @param key * @param value @@ -179,44 +176,45 @@ class MerklePatriciaTrie[K, V] private (private[mpt] val rootNode: Option[MptNod */ override def put(key: K, value: V): MerklePatriciaTrie[K, V] = { val keyNibbles = HexPrefix.bytesToNibbles(kSerializer.toBytes(key)) - rootNode map { root => - val NodeInsertResult(newRoot, nodesToRemoveFromStorage) = put(root, keyNibbles, vSerializer.toBytes(value)) - val newRootNode = nodeStorage.updateNodesInStorage(newRoot = Some(newRoot), toRemove = nodesToRemoveFromStorage) - new MerklePatriciaTrie(newRootNode, nodeStorage)(kSerializer, vSerializer) - } getOrElse { - val newRoot = LeafNode(ByteString(keyNibbles), ByteString(vSerializer.toBytes(value))) - val newRootNode = nodeStorage.updateNodesInStorage(Some(newRoot), Nil) - new MerklePatriciaTrie(newRootNode, nodeStorage) - } + rootNode + .map { root => + val NodeInsertResult(newRoot, nodesToRemoveFromStorage) = put(root, keyNibbles, vSerializer.toBytes(value)) + val newRootNode = nodeStorage.updateNodesInStorage(newRoot = Some(newRoot), toRemove = nodesToRemoveFromStorage) + new MerklePatriciaTrie(newRootNode, nodeStorage)(kSerializer, vSerializer) + } + .getOrElse { + val newRoot = LeafNode(ByteString(keyNibbles), ByteString(vSerializer.toBytes(value))) + val newRootNode = nodeStorage.updateNodesInStorage(Some(newRoot), Nil) + new MerklePatriciaTrie(newRootNode, nodeStorage) + } } - /** - * This function deletes a (key-value) pair from the trie. If no (key-value) pair exists with the passed trie then there's no effect on it. + /** This function deletes a (key-value) pair from the trie. If no (key-value) pair exists with the passed trie then there's no effect on it. * * @param key * @return New trie with the (key-value) pair associated with the key passed deleted from the trie. * @throws io.iohk.ethereum.mpt.MerklePatriciaTrie.MPTException if there is any inconsistency in how the trie is build. */ - override def remove(key: K): MerklePatriciaTrie[K, V] = { - rootNode map { root => - val keyNibbles = HexPrefix.bytesToNibbles(bytes = kSerializer.toBytes(key)) - remove(root, keyNibbles) match { - case NodeRemoveResult(true, Some(newRoot), nodesToRemoveFromStorage) => - val newRootNode = - nodeStorage.updateNodesInStorage(newRoot = Some(newRoot), toRemove = nodesToRemoveFromStorage) - new MerklePatriciaTrie(newRootNode, nodeStorage)(kSerializer, vSerializer) - case NodeRemoveResult(true, None, nodesToRemoveFromStorage) => - val newRootNode = nodeStorage.updateNodesInStorage(newRoot = None, toRemove = nodesToRemoveFromStorage) - new MerklePatriciaTrie(None, nodeStorage)(kSerializer, vSerializer) - case NodeRemoveResult(false, _, _) => this + override def remove(key: K): MerklePatriciaTrie[K, V] = + rootNode + .map { root => + val keyNibbles = HexPrefix.bytesToNibbles(bytes = kSerializer.toBytes(key)) + remove(root, keyNibbles) match { + case NodeRemoveResult(true, Some(newRoot), nodesToRemoveFromStorage) => + val newRootNode = + nodeStorage.updateNodesInStorage(newRoot = Some(newRoot), toRemove = nodesToRemoveFromStorage) + new MerklePatriciaTrie(newRootNode, nodeStorage)(kSerializer, vSerializer) + case NodeRemoveResult(true, None, nodesToRemoveFromStorage) => + nodeStorage.updateNodesInStorage(newRoot = None, toRemove = nodesToRemoveFromStorage) + new MerklePatriciaTrie(None, nodeStorage)(kSerializer, vSerializer) + case NodeRemoveResult(false, _, _) => this + } + } + .getOrElse { + this } - } getOrElse { - this - } - } - /** - * This function updates the KeyValueStore by deleting, updating and inserting new (key-value) pairs. + /** This function updates the KeyValueStore by deleting, updating and inserting new (key-value) pairs. * * @param toRemove which includes all the keys to be removed from the KeyValueStore. * @param toUpsert which includes all the (key-value) pairs to be inserted into the KeyValueStore. @@ -224,17 +222,17 @@ class MerklePatriciaTrie[K, V] private (private[mpt] val rootNode: Option[MptNod * @return the new DataSource after the removals and insertions were done. */ override def update(toRemove: Seq[K], toUpsert: Seq[(K, V)]): MerklePatriciaTrie[K, V] = { - val afterRemoval = toRemove.foldLeft(this) { (acc, key) => acc - key } - toUpsert.foldLeft(afterRemoval) { (acc, item) => acc + item } + val afterRemoval = toRemove.foldLeft(this)((acc, key) => acc - key) + toUpsert.foldLeft(afterRemoval)((acc, item) => acc + item) } @tailrec private def get(node: MptNode, searchKey: Array[Byte]): Option[Array[Byte]] = node match { case LeafNode(key, value, _, _, _) => - if (key.toArray[Byte] sameElements searchKey) Some(value.toArray[Byte]) else None + if (key.toArray[Byte].sameElements(searchKey)) Some(value.toArray[Byte]) else None case extNode @ ExtensionNode(sharedKey, _, _, _, _) => val (commonKey, remainingKey) = searchKey.splitAt(sharedKey.length) - if (searchKey.length >= sharedKey.length && (sharedKey sameElements commonKey)) { + if (searchKey.length >= sharedKey.length && (sharedKey.sameElements(commonKey))) { get(extNode.next, remainingKey) } else None case branch @ BranchNode(_, terminator, _, _, _) => @@ -250,9 +248,9 @@ class MerklePatriciaTrie[K, V] private (private[mpt] val rootNode: Option[MptNod } private def put(node: MptNode, searchKey: Array[Byte], value: Array[Byte]): NodeInsertResult = node match { - case leafNode: LeafNode => putInLeafNode(leafNode, searchKey, value) + case leafNode: LeafNode => putInLeafNode(leafNode, searchKey, value) case extensionNode: ExtensionNode => putInExtensionNode(extensionNode, searchKey, value) - case branchNode: BranchNode => putInBranchNode(branchNode, searchKey, value) + case branchNode: BranchNode => putInBranchNode(branchNode, searchKey, value) case HashNode(bytes) => put(nodeStorage.get(bytes), searchKey, value) case _ => throw new MPTException("Cannot put node in NullNode") @@ -381,9 +379,9 @@ class MerklePatriciaTrie[K, V] private (private[mpt] val rootNode: Option[MptNod } private def remove(node: MptNode, searchKey: Array[Byte]): NodeRemoveResult = node match { - case leafNode: LeafNode => removeFromLeafNode(leafNode, searchKey) + case leafNode: LeafNode => removeFromLeafNode(leafNode, searchKey) case extensionNode: ExtensionNode => removeFromExtensionNode(extensionNode, searchKey) - case branchNode: BranchNode => removeFromBranchNode(branchNode, searchKey) + case branchNode: BranchNode => removeFromBranchNode(branchNode, searchKey) case HashNode(bytes) => remove(nodeStorage.get(bytes), searchKey) case _ => throw new MPTException("Cannot delete node NullNode") @@ -408,11 +406,13 @@ class MerklePatriciaTrie[K, V] private (private[mpt] val rootNode: Option[MptNod remove(child, searchKey.tail) match { case NodeRemoveResult(true, maybeNewChild, nodesToRemoveFromStorage) => // Something changed in a child so we need to fix - val nodeToFix = maybeNewChild map { newChild => - branchNode.updateChild(searchKeyHead, newChild) - } getOrElse { - BranchNode(children.updated(searchKeyHead, NullNode), optStoredValue) - } + val nodeToFix = maybeNewChild + .map { newChild => + branchNode.updateChild(searchKeyHead, newChild) + } + .getOrElse { + BranchNode(children.updated(searchKeyHead, NullNode), optStoredValue) + } val fixedNode = fix(nodeToFix) NodeRemoveResult( hasChanged = true, @@ -431,7 +431,7 @@ class MerklePatriciaTrie[K, V] private (private[mpt] val rootNode: Option[MptNod private def removeFromLeafNode(leafNode: LeafNode, searchKey: Array[Byte]): NodeRemoveResult = { val LeafNode(existingKey, _, _, _, _) = leafNode - if (existingKey sameElements searchKey) { + if (existingKey.sameElements(searchKey)) { // We found the node to delete NodeRemoveResult(hasChanged = true, newNode = None, toDeleteFromStorage = List(leafNode)) } else NodeRemoveResult(hasChanged = false, newNode = None) @@ -445,25 +445,26 @@ class MerklePatriciaTrie[K, V] private (private[mpt] val rootNode: Option[MptNod remove(extensionNode.next, searchKey.drop(cp)) match { case NodeRemoveResult(true, maybeNewChild, nodesToRemoveFromStorage) => // If we changed the child, we need to fix this extension node - maybeNewChild map { newChild => - val toFix = ExtensionNode(sharedKey, newChild) - val fixedNode = fix(toFix) - NodeRemoveResult( - hasChanged = true, - newNode = Some(fixedNode), - toDeleteFromStorage = extensionNode :: nodesToRemoveFromStorage - ) - } getOrElse { - throw new MPTException("A trie with newRoot extension should have at least 2 values stored") - } + maybeNewChild + .map { newChild => + val toFix = ExtensionNode(sharedKey, newChild) + val fixedNode = fix(toFix) + NodeRemoveResult( + hasChanged = true, + newNode = Some(fixedNode), + toDeleteFromStorage = extensionNode :: nodesToRemoveFromStorage + ) + } + .getOrElse { + throw new MPTException("A trie with newRoot extension should have at least 2 values stored") + } case NodeRemoveResult(false, _, nodesToRemoveFromStorage) => NodeRemoveResult(hasChanged = false, newNode = None, toDeleteFromStorage = nodesToRemoveFromStorage) } } else NodeRemoveResult(hasChanged = false, newNode = Some(extensionNode)) } - /** - * Given a node which may be in an invalid state, fix it such that it is then in a valid state. Invalid state means: + /** Given a node which may be in an invalid state, fix it such that it is then in a valid state. Invalid state means: * - Branch node where there is only a single entry; * - Extension node followed by anything other than a Branch node. * @@ -486,7 +487,7 @@ class MerklePatriciaTrie[K, V] private (private[mpt] val rootNode: Option[MptNod val temporalExtNode = ExtensionNode(ByteString(index.toByte), children(index)) fix(temporalExtNode) case (Nil, Some(value)) => LeafNode(ByteString.empty, value) - case _ => node + case _ => node } case extensionNode @ ExtensionNode(sharedKey, _, _, _, _) => val nextNode = extensionNode.next match { diff --git a/src/main/scala/io/iohk/ethereum/mpt/MptTraversals.scala b/src/main/scala/io/iohk/ethereum/mpt/MptTraversals.scala index f74c6b7454..b79691bcbe 100644 --- a/src/main/scala/io/iohk/ethereum/mpt/MptTraversals.scala +++ b/src/main/scala/io/iohk/ethereum/mpt/MptTraversals.scala @@ -1,12 +1,16 @@ package io.iohk.ethereum.mpt import akka.util.ByteString + import io.iohk.ethereum.db.storage.MptStorage import io.iohk.ethereum.db.storage.NodeStorage.NodeEncoded import io.iohk.ethereum.mpt.MerklePatriciaTrie.MPTException import io.iohk.ethereum.mpt.MptVisitors._ +import io.iohk.ethereum.rlp.RLPEncodeable import io.iohk.ethereum.rlp.RLPImplicitConversions._ -import io.iohk.ethereum.rlp.{RLPEncodeable, RLPList, RLPValue, rawDecode} +import io.iohk.ethereum.rlp.RLPList +import io.iohk.ethereum.rlp.RLPValue +import io.iohk.ethereum.rlp.rawDecode object MptTraversals { @@ -17,9 +21,8 @@ object MptTraversals { (HashNode(rootHash.toArray[Byte]), (rootHash, nodeEncoded) :: nodeCapper.getNodesToUpdate) } - def parseTrieIntoMemory(rootNode: MptNode, source: MptStorage): MptNode = { + def parseTrieIntoMemory(rootNode: MptNode, source: MptStorage): MptNode = dispatch(rootNode, new MptConstructionVisitor(source)) - } def encodeNode(node: MptNode, nodeCapper: Option[NodeCapper] = None): Array[Byte] = { val nodeEncoded = encode(node, nodeCapper) @@ -31,13 +34,11 @@ object MptTraversals { dispatch(node, new RlpHashingVisitor(new RlpEncVisitor, 0, nodeCap)) } - def decodeNode(nodeEncoded: NodeEncoded): MptNode = { + def decodeNode(nodeEncoded: NodeEncoded): MptNode = parseMpt(decodeNodeRlp(nodeEncoded)) - } - def decodeNodeRlp(nodeEncoded: NodeEncoded): RLPEncodeable = { + def decodeNodeRlp(nodeEncoded: NodeEncoded): RLPEncodeable = rawDecode(nodeEncoded) - } private def parseMpt(nodeEncoded: RLPEncodeable): MptNode = nodeEncoded match { case list @ RLPList(items @ _*) if items.size == MerklePatriciaTrie.ListSize => @@ -71,7 +72,7 @@ object MptTraversals { case _ => throw new MPTException("Invalid Node") } - private def dispatch[T](input: MptNode, visitor: MptVisitor[T]): T = { + private def dispatch[T](input: MptNode, visitor: MptVisitor[T]): T = input match { case leaf: LeafNode => visitor.visitLeaf(leaf) @@ -99,5 +100,4 @@ object MptTraversals { case nullNode: NullNode.type => visitor.visitNull() } - } } diff --git a/src/main/scala/io/iohk/ethereum/mpt/MptVisitors/MptConstructionVisitor.scala b/src/main/scala/io/iohk/ethereum/mpt/MptVisitors/MptConstructionVisitor.scala index b4946b7807..365adf637c 100644 --- a/src/main/scala/io/iohk/ethereum/mpt/MptVisitors/MptConstructionVisitor.scala +++ b/src/main/scala/io/iohk/ethereum/mpt/MptVisitors/MptConstructionVisitor.scala @@ -2,21 +2,23 @@ package io.iohk.ethereum.mpt.MptVisitors import io.iohk.ethereum.db.storage.MptStorage import io.iohk.ethereum.db.storage.NodeStorage.NodeHash -import io.iohk.ethereum.mpt.{BranchNode, ExtensionNode, HashNode, LeafNode, MptNode, NullNode} +import io.iohk.ethereum.mpt.BranchNode +import io.iohk.ethereum.mpt.ExtensionNode +import io.iohk.ethereum.mpt.HashNode +import io.iohk.ethereum.mpt.LeafNode +import io.iohk.ethereum.mpt.MptNode +import io.iohk.ethereum.mpt.NullNode class MptConstructionVisitor(source: MptStorage) extends MptVisitor[MptNode] { - def visitLeaf(leaf: LeafNode): MptNode = { + def visitLeaf(leaf: LeafNode): MptNode = leaf - } - def visitHash(hashNode: HashNode): HashNodeResult[MptNode] = { + def visitHash(hashNode: HashNode): HashNodeResult[MptNode] = ResolveResult(source.get(hashNode.hash)) - } - override def visitNull(): MptNode = { + override def visitNull(): MptNode = NullNode - } override def visitExtension(extension: ExtensionNode): ExtensionVisitor[MptNode] = new MptExtensionVisitor(extension, source) @@ -27,17 +29,15 @@ class MptConstructionVisitor(source: MptStorage) extends MptVisitor[MptNode] { class MptBranchVisitor(branchNode: BranchNode, source: MptStorage) extends BranchVisitor[MptNode] { var resolvedChildren: List[MptNode] = List.empty - override def visitChild(child: => MptNode): Unit = { + override def visitChild(child: => MptNode): Unit = resolvedChildren = child :: resolvedChildren - } override def visitChild(): MptVisitor[MptNode] = new MptConstructionVisitor(source) override def visitTerminator(term: Option[NodeHash]): Unit = () - override def done(): MptNode = { + override def done(): MptNode = branchNode.copy(children = resolvedChildren.reverse.toArray) - } } class MptExtensionVisitor(extensionNode: ExtensionNode, source: MptStorage) extends ExtensionVisitor[MptNode] { @@ -45,11 +45,9 @@ class MptExtensionVisitor(extensionNode: ExtensionNode, source: MptStorage) exte override def visitNext(): MptVisitor[MptNode] = new MptConstructionVisitor(source) - override def visitNext(value: => MptNode): Unit = { + override def visitNext(value: => MptNode): Unit = resolvedNext = value - } - override def done(): MptNode = { + override def done(): MptNode = extensionNode.copy(next = resolvedNext) - } } diff --git a/src/main/scala/io/iohk/ethereum/mpt/MptVisitors/MptVisitor.scala b/src/main/scala/io/iohk/ethereum/mpt/MptVisitors/MptVisitor.scala index d8a5562eae..b0f7a43e6f 100644 --- a/src/main/scala/io/iohk/ethereum/mpt/MptVisitors/MptVisitor.scala +++ b/src/main/scala/io/iohk/ethereum/mpt/MptVisitors/MptVisitor.scala @@ -1,11 +1,16 @@ package io.iohk.ethereum.mpt.MptVisitors import akka.util.ByteString -import io.iohk.ethereum.mpt.{BranchNode, ExtensionNode, HashNode, LeafNode, MptNode} + +import io.iohk.ethereum.mpt.BranchNode +import io.iohk.ethereum.mpt.ExtensionNode +import io.iohk.ethereum.mpt.HashNode +import io.iohk.ethereum.mpt.LeafNode +import io.iohk.ethereum.mpt.MptNode sealed abstract class HashNodeResult[T] { def next(visitor: MptVisitor[T])(f: (MptNode, MptVisitor[T]) => T): T = this match { - case Result(value) => value + case Result(value) => value case ResolveResult(node) => f(node, visitor) } } diff --git a/src/main/scala/io/iohk/ethereum/mpt/MptVisitors/RlpEncVisitor.scala b/src/main/scala/io/iohk/ethereum/mpt/MptVisitors/RlpEncVisitor.scala index e5b0e177f9..70d400de21 100644 --- a/src/main/scala/io/iohk/ethereum/mpt/MptVisitors/RlpEncVisitor.scala +++ b/src/main/scala/io/iohk/ethereum/mpt/MptVisitors/RlpEncVisitor.scala @@ -2,12 +2,18 @@ package io.iohk.ethereum.mpt.MptVisitors import java.util -import io.iohk.ethereum.db.storage.NodeStorage.NodeHash -import io.iohk.ethereum.mpt.{BranchNode, ExtensionNode, HashNode, HexPrefix, LeafNode} -import io.iohk.ethereum.rlp.{RLPEncodeable, RLPList, RLPValue} - import scala.collection.immutable.ArraySeq +import io.iohk.ethereum.db.storage.NodeStorage.NodeHash +import io.iohk.ethereum.mpt.BranchNode +import io.iohk.ethereum.mpt.ExtensionNode +import io.iohk.ethereum.mpt.HashNode +import io.iohk.ethereum.mpt.HexPrefix +import io.iohk.ethereum.mpt.LeafNode +import io.iohk.ethereum.rlp.RLPEncodeable +import io.iohk.ethereum.rlp.RLPList +import io.iohk.ethereum.rlp.RLPValue + class RlpExtensionVisitor(extensionNode: ExtensionNode) extends ExtensionVisitor[RLPEncodeable] { val array: Array[RLPEncodeable] = new Array[RLPEncodeable](2) @@ -15,9 +21,8 @@ class RlpExtensionVisitor(extensionNode: ExtensionNode) extends ExtensionVisitor override def visitNext(): MptVisitor[RLPEncodeable] = new RlpEncVisitor - override def visitNext(value: => RLPEncodeable): Unit = { + override def visitNext(value: => RLPEncodeable): Unit = array(1) = value - } override def done(): RLPEncodeable = { val copy = util.Arrays.copyOf[RLPEncodeable](array, 2) @@ -31,34 +36,28 @@ class RlpBranchVisitor(branchNode: BranchNode) extends BranchVisitor[RLPEncodeab override def visitChild(): MptVisitor[RLPEncodeable] = new RlpEncVisitor - override def visitChild(child: => RLPEncodeable): Unit = { + override def visitChild(child: => RLPEncodeable): Unit = list = child :: list - } - override def visitTerminator(term: Option[NodeHash]): Unit = { + override def visitTerminator(term: Option[NodeHash]): Unit = list = RLPValue(term.map(_.toArray[Byte]).getOrElse(Array.emptyByteArray)) :: list - } - override def done(): RLPEncodeable = { + override def done(): RLPEncodeable = RLPList(list.reverse: _*) - } } class RlpEncVisitor extends MptVisitor[RLPEncodeable] { - def visitLeaf(leaf: LeafNode): RLPEncodeable = { + def visitLeaf(leaf: LeafNode): RLPEncodeable = RLPList( RLPValue(HexPrefix.encode(nibbles = leaf.key.toArray[Byte], isLeaf = true)), RLPValue(leaf.value.toArray[Byte]) ) - } - def visitHash(hashNode: HashNode): HashNodeResult[RLPEncodeable] = { + def visitHash(hashNode: HashNode): HashNodeResult[RLPEncodeable] = Result(RLPValue(hashNode.hashNode)) - } - override def visitNull(): RLPEncodeable = { + override def visitNull(): RLPEncodeable = RLPValue(Array.emptyByteArray) - } override def visitExtension(extension: ExtensionNode): ExtensionVisitor[RLPEncodeable] = new RlpExtensionVisitor( extension diff --git a/src/main/scala/io/iohk/ethereum/mpt/MptVisitors/RlpHashingVisitor.scala b/src/main/scala/io/iohk/ethereum/mpt/MptVisitors/RlpHashingVisitor.scala index 69e1bf72a1..eb1f42aecc 100644 --- a/src/main/scala/io/iohk/ethereum/mpt/MptVisitors/RlpHashingVisitor.scala +++ b/src/main/scala/io/iohk/ethereum/mpt/MptVisitors/RlpHashingVisitor.scala @@ -1,19 +1,26 @@ package io.iohk.ethereum.mpt.MptVisitors import akka.util.ByteString -import io.iohk.ethereum.db.storage.NodeStorage.{NodeEncoded, NodeHash} -import io.iohk.ethereum.mpt.{BranchNode, ExtensionNode, HashNode, LeafNode, MptNode, Node} -import io.iohk.ethereum.rlp.{RLPEncodeable, RLPValue} + +import io.iohk.ethereum.db.storage.NodeStorage.NodeEncoded +import io.iohk.ethereum.db.storage.NodeStorage.NodeHash +import io.iohk.ethereum.mpt.BranchNode +import io.iohk.ethereum.mpt.ExtensionNode +import io.iohk.ethereum.mpt.HashNode +import io.iohk.ethereum.mpt.LeafNode +import io.iohk.ethereum.mpt.MptNode +import io.iohk.ethereum.mpt.Node +import io.iohk.ethereum.rlp.RLPEncodeable +import io.iohk.ethereum.rlp.RLPValue class NodeCapper(withUpdates: Boolean) { private var nodesToUpdate = List.empty[(NodeHash, NodeEncoded)] - def capNode(nodeEncoded: RLPEncodeable, depth: Int): RLPEncodeable = { + def capNode(nodeEncoded: RLPEncodeable, depth: Int): RLPEncodeable = if (depth > 0) capNode(nodeEncoded) else nodeEncoded - } private def capNode(nodeEncoded: RLPEncodeable): RLPEncodeable = { val asArray = io.iohk.ethereum.rlp.encode(nodeEncoded) @@ -33,14 +40,13 @@ class NodeCapper(withUpdates: Boolean) { class RlpHashingVisitor(downstream: MptVisitor[RLPEncodeable], depth: Int, nodeCapper: NodeCapper) extends MptVisitor[RLPEncodeable] { - def visitLeaf(value: LeafNode): RLPEncodeable = { + def visitLeaf(value: LeafNode): RLPEncodeable = if (value.parsedRlp.isDefined) { value.parsedRlp.get } else { val leafEncoded = downstream.visitLeaf(value) nodeCapper.capNode(leafEncoded, depth) } - } def visitExtension(value: ExtensionNode): ExtensionVisitor[RLPEncodeable] = new RlpHashingExtensionVisitor(downstream.visitExtension(value), depth, value.parsedRlp, nodeCapper) @@ -61,27 +67,24 @@ class RlpHashingBranchVisitor( parsedRlp: Option[RLPEncodeable], nodeCapper: NodeCapper ) extends BranchVisitor[RLPEncodeable] { - override def done(): RLPEncodeable = { + override def done(): RLPEncodeable = if (parsedRlp.isEmpty) { val branchEncoded = downstream.done() nodeCapper.capNode(branchEncoded, depth) } else { parsedRlp.get } - } override def visitChild(): MptVisitor[RLPEncodeable] = new RlpHashingVisitor(downstream.visitChild(), depth + 1, nodeCapper) - override def visitChild(child: => RLPEncodeable): Unit = { + override def visitChild(child: => RLPEncodeable): Unit = if (parsedRlp.isEmpty) downstream.visitChild(child) - } - override def visitTerminator(term: Option[NodeHash]): Unit = { + override def visitTerminator(term: Option[NodeHash]): Unit = if (parsedRlp.isEmpty) downstream.visitTerminator(term) - } } class RlpHashingExtensionVisitor( @@ -90,20 +93,18 @@ class RlpHashingExtensionVisitor( parsedRlp: Option[RLPEncodeable], nodeCapper: NodeCapper ) extends ExtensionVisitor[RLPEncodeable] { - override def visitNext(value: => RLPEncodeable): Unit = { + override def visitNext(value: => RLPEncodeable): Unit = if (parsedRlp.isEmpty) downstream.visitNext(value) - } override def visitNext(): MptVisitor[RLPEncodeable] = new RlpHashingVisitor(downstream.visitNext(), depth + 1, nodeCapper) - override def done(): RLPEncodeable = { + override def done(): RLPEncodeable = if (parsedRlp.isEmpty) { val extensionNodeEncoded = downstream.done() nodeCapper.capNode(extensionNodeEncoded, depth) } else { parsedRlp.get } - } } diff --git a/src/main/scala/io/iohk/ethereum/mpt/Node.scala b/src/main/scala/io/iohk/ethereum/mpt/Node.scala index 59b002a254..7e1ef9a51b 100644 --- a/src/main/scala/io/iohk/ethereum/mpt/Node.scala +++ b/src/main/scala/io/iohk/ethereum/mpt/Node.scala @@ -3,11 +3,12 @@ package io.iohk.ethereum.mpt import java.util import akka.util.ByteString + import io.iohk.ethereum.crypto -import io.iohk.ethereum.rlp.{RLPEncodeable, RLPValue} +import io.iohk.ethereum.rlp.RLPEncodeable +import io.iohk.ethereum.rlp.RLPValue -/** - * Trie elements +/** Trie elements */ sealed abstract class MptNode { val cachedHash: Option[Array[Byte]] @@ -28,18 +29,16 @@ sealed abstract class MptNode { val parsedRlp: Option[RLPEncodeable] // Overriding equals is necessery to avoid array comparisons. - override def equals(obj: Any): Boolean = { + override def equals(obj: Any): Boolean = if (!obj.isInstanceOf[MptNode]) { false } else { val compared = obj.asInstanceOf[MptNode] - hash sameElements compared.hash + hash.sameElements(compared.hash) } - } - override def hashCode(): Int = { + override def hashCode(): Int = 17 + util.Arrays.hashCode(hash) - } def isNew: Boolean = parsedRlp.isEmpty } @@ -49,9 +48,8 @@ object MptNode { } object Node { - def hashFn(input: Array[Byte]): Array[Byte] = { + def hashFn(input: Array[Byte]): Array[Byte] = crypto.kec256(input, 0, input.length) - } } case class LeafNode( @@ -93,8 +91,7 @@ case class BranchNode( require(children.length == 16, "MptBranch childHashes length have to be 16") - /** - * This function creates a new BranchNode by updating one of the children of the self node. + /** This function creates a new BranchNode by updating one of the children of the self node. * * @param childIndex of the BranchNode children where the child should be inserted. * @param childNode to be inserted as a child of the new BranchNode (and hashed if necessary). @@ -131,8 +128,7 @@ case object NullNode extends MptNode { object ExtensionNode { - /** - * This function creates a new ExtensionNode with next parameter as its node pointer + /** This function creates a new ExtensionNode with next parameter as its node pointer * * @param sharedKey of the new ExtensionNode. * @param next to be inserted as the node pointer (and hashed if necessary). @@ -148,19 +144,16 @@ object BranchNode { val numberOfChildren = 16 private val emptyChildren: Array[MptNode] = Array.fill(numberOfChildren)(NullNode) - /** - * This function creates a new terminator BranchNode having only a value associated with it. + /** This function creates a new terminator BranchNode having only a value associated with it. * This new BranchNode will be temporarily in an invalid state. * * @param terminator to be associated with the new BranchNode. * @return a new BranchNode. */ - def withValueOnly(terminator: Array[Byte]): BranchNode = { + def withValueOnly(terminator: Array[Byte]): BranchNode = BranchNode(util.Arrays.copyOf(emptyChildren, numberOfChildren), Some(ByteString(terminator))) - } - /** - * This function creates a new BranchNode having only one child associated with it (and optionaly a value). + /** This function creates a new BranchNode having only one child associated with it (and optionaly a value). * This new BranchNode will be temporarily in an invalid state. * * @param position of the BranchNode children where the child should be inserted. diff --git a/src/main/scala/io/iohk/ethereum/mpt/package.scala b/src/main/scala/io/iohk/ethereum/mpt/package.scala index ca849e5a4c..145d8ac8bc 100644 --- a/src/main/scala/io/iohk/ethereum/mpt/package.scala +++ b/src/main/scala/io/iohk/ethereum/mpt/package.scala @@ -1,6 +1,7 @@ package io.iohk.ethereum import akka.util.ByteString + import io.iohk.ethereum.db.storage.EvmCodeStorage.Code package object mpt { @@ -15,7 +16,7 @@ package object mpt { trait ByteArraySerializable[T] extends ByteArrayEncoder[T] with ByteArrayDecoder[T] - implicit val byteStringSerializer = new ByteArraySerializable[ByteString] { + implicit val byteStringSerializer: ByteArraySerializable[ByteString] = new ByteArraySerializable[ByteString] { override def toBytes(input: Code): Array[Byte] = input.toArray[Byte] override def fromBytes(bytes: Array[Byte]): Code = ByteString(bytes) } diff --git a/src/main/scala/io/iohk/ethereum/network/ConnectedPeers.scala b/src/main/scala/io/iohk/ethereum/network/ConnectedPeers.scala index 1dc21f7c2e..9489bc1e6d 100644 --- a/src/main/scala/io/iohk/ethereum/network/ConnectedPeers.scala +++ b/src/main/scala/io/iohk/ethereum/network/ConnectedPeers.scala @@ -4,6 +4,7 @@ import java.net.InetSocketAddress import akka.actor.ActorRef import akka.util.ByteString + import scala.concurrent.duration.FiniteDuration case class ConnectedPeers( @@ -48,14 +49,13 @@ case class ConnectedPeers( def getPeer(peerId: PeerId): Option[Peer] = peers.get(peerId) - def addNewPendingPeer(pendingPeer: Peer): ConnectedPeers = { + def addNewPendingPeer(pendingPeer: Peer): ConnectedPeers = if (pendingPeer.incomingConnection) copy(incomingPendingPeers = incomingPendingPeers + (pendingPeer.id -> pendingPeer)) else copy(outgoingPendingPeers = outgoingPendingPeers + (pendingPeer.id -> pendingPeer)) - } - def promotePeerToHandshaked(peerAfterHandshake: Peer): ConnectedPeers = { + def promotePeerToHandshaked(peerAfterHandshake: Peer): ConnectedPeers = if (peerAfterHandshake.incomingConnection) copy( incomingPendingPeers = incomingPendingPeers - PeerId.fromRef(peerAfterHandshake.ref), @@ -66,7 +66,6 @@ case class ConnectedPeers( outgoingPendingPeers = outgoingPendingPeers - PeerId.fromRef(peerAfterHandshake.ref), handshakedPeers = handshakedPeers + (peerAfterHandshake.id -> peerAfterHandshake) ) - } def removeTerminatedPeer(peerRef: ActorRef): (Iterable[PeerId], ConnectedPeers) = { val peersId = allPeers.collect { case (id, peer) if peer.ref == peerRef => id } @@ -110,11 +109,10 @@ case class ConnectedPeers( } } - private def canPrune(incoming: Boolean, minCreateTimeMillis: Long)(peer: Peer): Boolean = { + private def canPrune(incoming: Boolean, minCreateTimeMillis: Long)(peer: Peer): Boolean = peer.incomingConnection == incoming && - peer.createTimeMillis <= minCreateTimeMillis && - !pruningPeers.contains(peer.id) - } + peer.createTimeMillis <= minCreateTimeMillis && + !pruningPeers.contains(peer.id) } object ConnectedPeers { diff --git a/src/main/scala/io/iohk/ethereum/network/EtcPeerManagerActor.scala b/src/main/scala/io/iohk/ethereum/network/EtcPeerManagerActor.scala index 0e23807312..faed7d2d32 100644 --- a/src/main/scala/io/iohk/ethereum/network/EtcPeerManagerActor.scala +++ b/src/main/scala/io/iohk/ethereum/network/EtcPeerManagerActor.scala @@ -1,24 +1,35 @@ package io.iohk.ethereum.network -import akka.actor.{Actor, ActorLogging, ActorRef, Props} +import akka.actor.Actor +import akka.actor.ActorLogging +import akka.actor.ActorRef +import akka.actor.Props import akka.util.ByteString + import io.iohk.ethereum.db.storage.AppStateStorage import io.iohk.ethereum.domain.ChainWeight import io.iohk.ethereum.network.EtcPeerManagerActor._ -import io.iohk.ethereum.network.PeerActor.{DisconnectPeer, SendMessage} +import io.iohk.ethereum.network.PeerActor.DisconnectPeer +import io.iohk.ethereum.network.PeerActor.SendMessage import io.iohk.ethereum.network.PeerEventBusActor.PeerEvent._ +import io.iohk.ethereum.network.PeerEventBusActor.PeerSelector +import io.iohk.ethereum.network.PeerEventBusActor.Subscribe import io.iohk.ethereum.network.PeerEventBusActor.SubscriptionClassifier._ -import io.iohk.ethereum.network.PeerEventBusActor.{PeerSelector, Subscribe, Unsubscribe} +import io.iohk.ethereum.network.PeerEventBusActor.Unsubscribe import io.iohk.ethereum.network.handshaker.Handshaker.HandshakeResult -import io.iohk.ethereum.network.p2p.messages.ETH62.{BlockHeaders, GetBlockHeaders, NewBlockHashes} +import io.iohk.ethereum.network.p2p.Message +import io.iohk.ethereum.network.p2p.MessageSerializable +import io.iohk.ethereum.network.p2p.messages.BaseETH6XMessages +import io.iohk.ethereum.network.p2p.messages.Codes +import io.iohk.ethereum.network.p2p.messages.ETC64 import io.iohk.ethereum.network.p2p.messages.ETC64.NewBlock +import io.iohk.ethereum.network.p2p.messages.ETH62.BlockHeaders +import io.iohk.ethereum.network.p2p.messages.ETH62.GetBlockHeaders +import io.iohk.ethereum.network.p2p.messages.ETH62.NewBlockHashes import io.iohk.ethereum.network.p2p.messages.WireProtocol.Disconnect -import io.iohk.ethereum.network.p2p.messages.{Codes, BaseETH6XMessages, ETC64} -import io.iohk.ethereum.network.p2p.{Message, MessageSerializable} import io.iohk.ethereum.utils.ByteStringUtils -/** - * EtcPeerManager actor is in charge of keeping updated information about each peer, while also being able to +/** EtcPeerManager actor is in charge of keeping updated information about each peer, while also being able to * query it for this information. * In order to do so it receives events for peer creation, disconnection and new messages being sent and * received by each peer. @@ -38,21 +49,19 @@ class EtcPeerManagerActor( override def receive: Receive = handleMessages(Map.empty) - /** - * Processes both messages for updating the information about each peer and for requesting this information + /** Processes both messages for updating the information about each peer and for requesting this information * * @param peersWithInfo, which has the peer and peer information for each handshaked peer (identified by it's id) */ def handleMessages(peersWithInfo: PeersWithInfo): Receive = - handleCommonMessages(peersWithInfo) orElse handlePeersInfoEvents(peersWithInfo) + handleCommonMessages(peersWithInfo).orElse(handlePeersInfoEvents(peersWithInfo)) private def peerHasUpdatedBestBlock(peerInfo: PeerInfo): Boolean = { val peerBestBlockIsItsGenesisBlock = peerInfo.bestBlockHash == peerInfo.remoteStatus.genesisHash peerBestBlockIsItsGenesisBlock || (!peerBestBlockIsItsGenesisBlock && peerInfo.maxBlockNumber > 0) } - /** - * Processes both messages for sending messages and for requesting peer information + /** Processes both messages for sending messages and for requesting peer information * * @param peersWithInfo, which has the peer and peer information for each handshaked peer (identified by it's id) */ @@ -72,11 +81,10 @@ class EtcPeerManagerActor( NetworkMetrics.SentMessagesCounter.increment() val newPeersWithInfo = updatePeersWithInfo(peersWithInfo, peerId, message.underlyingMsg, handleSentMessage) peerManagerActor ! PeerManagerActor.SendMessage(message, peerId) - context become handleMessages(newPeersWithInfo) + context.become(handleMessages(newPeersWithInfo)) } - /** - * Processes events and updating the information about each peer + /** Processes events and updating the information about each peer * * @param peersWithInfo, which has the peer and peer information for each handshaked peer (identified by it's id) */ @@ -85,7 +93,7 @@ class EtcPeerManagerActor( case MessageFromPeer(message, peerId) if peersWithInfo.contains(peerId) => val newPeersWithInfo = updatePeersWithInfo(peersWithInfo, peerId, message, handleReceivedMessage) NetworkMetrics.ReceivedMessagesCounter.increment() - context become handleMessages(newPeersWithInfo) + context.become(handleMessages(newPeersWithInfo)) case PeerHandshakeSuccessful(peer, peerInfo: PeerInfo) => peerEventBusActor ! Subscribe(PeerDisconnectedClassifier(PeerSelector.WithId(peer.id))) @@ -94,18 +102,17 @@ class EtcPeerManagerActor( //Ask for the highest block from the peer peer.ref ! SendMessage(GetBlockHeaders(Right(peerInfo.remoteStatus.bestHash), 1, 0, false)) NetworkMetrics.registerAddHandshakedPeer(peer) - context become handleMessages(peersWithInfo + (peer.id -> PeerWithInfo(peer, peerInfo))) + context.become(handleMessages(peersWithInfo + (peer.id -> PeerWithInfo(peer, peerInfo)))) case PeerDisconnected(peerId) if peersWithInfo.contains(peerId) => peerEventBusActor ! Unsubscribe(PeerDisconnectedClassifier(PeerSelector.WithId(peerId))) peerEventBusActor ! Unsubscribe(MessageClassifier(msgCodesWithInfo, PeerSelector.WithId(peerId))) NetworkMetrics.registerRemoveHandshakedPeer(peersWithInfo(peerId).peer) - context become handleMessages(peersWithInfo - peerId) + context.become(handleMessages(peersWithInfo - peerId)) } - /** - * Processes the message, updating the information for each peer + /** Processes the message, updating the information for each peer * * @param peers with the information for each peer * @param peerId from whom the message was received (or who sent the message) @@ -118,17 +125,15 @@ class EtcPeerManagerActor( peerId: PeerId, message: Message, messageHandler: (Message, PeerWithInfo) => PeerInfo - ): PeersWithInfo = { + ): PeersWithInfo = if (peers.contains(peerId)) { val peerWithInfo = peers(peerId) val newPeerInfo = messageHandler(message, peerWithInfo) peers + (peerId -> peerWithInfo.copy(peerInfo = newPeerInfo)) } else peers - } - /** - * Processes the message and the old peer info and returns the peer info + /** Processes the message and the old peer info and returns the peer info * * @param message to be processed * @param initialPeerWithInfo from before the message was processed @@ -137,21 +142,18 @@ class EtcPeerManagerActor( private def handleSentMessage(message: Message, initialPeerWithInfo: PeerWithInfo): PeerInfo = initialPeerWithInfo.peerInfo - /** - * Processes the message and the old peer info and returns the peer info + /** Processes the message and the old peer info and returns the peer info * * @param message to be processed * @param initialPeerWithInfo from before the message was processed * @return new updated peer info */ - private def handleReceivedMessage(message: Message, initialPeerWithInfo: PeerWithInfo): PeerInfo = { - (updateChainWeight(message) _ - andThen updateForkAccepted(message, initialPeerWithInfo.peer) - andThen updateMaxBlock(message))(initialPeerWithInfo.peerInfo) - } + private def handleReceivedMessage(message: Message, initialPeerWithInfo: PeerWithInfo): PeerInfo = + ((updateChainWeight(message) _) + .andThen(updateForkAccepted(message, initialPeerWithInfo.peer)) + .andThen(updateMaxBlock(message)))(initialPeerWithInfo.peerInfo) - /** - * Processes the message and updates the chain weight of the peer + /** Processes the message and updates the chain weight of the peer * * @param message to be processed * @param initialPeerInfo from before the message was processed @@ -162,11 +164,10 @@ class EtcPeerManagerActor( case newBlock: BaseETH6XMessages.NewBlock => initialPeerInfo.copy(chainWeight = ChainWeight.totalDifficultyOnly(newBlock.totalDifficulty)) case newBlock: ETC64.NewBlock => initialPeerInfo.copy(chainWeight = newBlock.chainWeight) - case _ => initialPeerInfo + case _ => initialPeerInfo } - /** - * Processes the message and updates if the fork block was accepted from the peer + /** Processes the message and updates if the fork block was accepted from the peer * * @param message to be processed * @param initialPeerInfo from before the message was processed @@ -194,15 +195,14 @@ class EtcPeerManagerActor( case _ => initialPeerInfo } - /** - * Processes the message and updates the max block number from the peer + /** Processes the message and updates the max block number from the peer * * @param message to be processed * @param initialPeerInfo from before the message was processed * @return new peer info with the max block number updated */ private def updateMaxBlock(message: Message)(initialPeerInfo: PeerInfo): PeerInfo = { - def update(ns: Seq[(BigInt, ByteString)]): PeerInfo = { + def update(ns: Seq[(BigInt, ByteString)]): PeerInfo = if (ns.isEmpty) { initialPeerInfo } else { @@ -215,7 +215,6 @@ class EtcPeerManagerActor( } else initialPeerInfo } - } message match { case m: BlockHeaders => @@ -236,8 +235,7 @@ object EtcPeerManagerActor { val msgCodesWithInfo: Set[Int] = Set(Codes.BlockHeadersCode, Codes.NewBlockCode, Codes.NewBlockHashesCode) - /** - * RemoteStatus was created to decouple status information from protocol status messages + /** RemoteStatus was created to decouple status information from protocol status messages * (they are different versions of Status msg) */ case class RemoteStatus( @@ -247,7 +245,7 @@ object EtcPeerManagerActor { bestHash: ByteString, genesisHash: ByteString ) { - override def toString: String = { + override def toString: String = s"RemoteStatus { " + s"protocolVersion: $protocolVersion, " + s"networkId: $networkId, " + @@ -255,15 +253,13 @@ object EtcPeerManagerActor { s"bestHash: ${ByteStringUtils.hash2string(bestHash)}, " + s"genesisHash: ${ByteStringUtils.hash2string(genesisHash)}," + s"}" - } } object RemoteStatus { - def apply(status: ETC64.Status): RemoteStatus = { + def apply(status: ETC64.Status): RemoteStatus = RemoteStatus(status.protocolVersion, status.networkId, status.chainWeight, status.bestHash, status.genesisHash) - } - def apply(status: BaseETH6XMessages.Status): RemoteStatus = { + def apply(status: BaseETH6XMessages.Status): RemoteStatus = RemoteStatus( status.protocolVersion, status.networkId, @@ -271,7 +267,6 @@ object EtcPeerManagerActor { status.bestHash, status.genesisHash ) - } } case class PeerInfo( @@ -301,7 +296,7 @@ object EtcPeerManagerActor { } object PeerInfo { - def apply(remoteStatus: RemoteStatus, forkAccepted: Boolean): PeerInfo = { + def apply(remoteStatus: RemoteStatus, forkAccepted: Boolean): PeerInfo = PeerInfo( remoteStatus, remoteStatus.chainWeight, @@ -309,7 +304,6 @@ object EtcPeerManagerActor { 0, remoteStatus.bestHash ) - } def withForkAccepted(remoteStatus: RemoteStatus): PeerInfo = PeerInfo(remoteStatus, forkAccepted = true) diff --git a/src/main/scala/io/iohk/ethereum/network/ForkResolver.scala b/src/main/scala/io/iohk/ethereum/network/ForkResolver.scala index fcc828d3b0..872718d07d 100644 --- a/src/main/scala/io/iohk/ethereum/network/ForkResolver.scala +++ b/src/main/scala/io/iohk/ethereum/network/ForkResolver.scala @@ -22,10 +22,9 @@ object ForkResolver { override def forkBlockNumber: BigInt = daoForkConfig.forkBlockNumber - override def recognizeFork(blockHeader: BlockHeader): Fork = { + override def recognizeFork(blockHeader: BlockHeader): Fork = if (blockHeader.hash == daoForkConfig.forkBlockHash) AcceptedFork else RejectedFork - } override def isAccepted(fork: Fork): Boolean = fork == AcceptedFork } diff --git a/src/main/scala/io/iohk/ethereum/network/KnownNodesManager.scala b/src/main/scala/io/iohk/ethereum/network/KnownNodesManager.scala index 9f64b1e643..6a06c23d9a 100644 --- a/src/main/scala/io/iohk/ethereum/network/KnownNodesManager.scala +++ b/src/main/scala/io/iohk/ethereum/network/KnownNodesManager.scala @@ -2,12 +2,16 @@ package io.iohk.ethereum.network import java.net.URI -import akka.actor.{Actor, ActorLogging, Props, Scheduler} -import io.iohk.ethereum.db.storage.KnownNodesStorage -import io.iohk.ethereum.network.KnownNodesManager.KnownNodesManagerConfig +import akka.actor.Actor +import akka.actor.ActorLogging +import akka.actor.Props +import akka.actor.Scheduler -import scala.concurrent.duration._ import scala.concurrent.ExecutionContext.Implicits.global +import scala.concurrent.duration._ + +import io.iohk.ethereum.db.storage.KnownNodesStorage +import io.iohk.ethereum.network.KnownNodesManager.KnownNodesManagerConfig class KnownNodesManager( config: KnownNodesManagerConfig, @@ -18,7 +22,7 @@ class KnownNodesManager( import KnownNodesManager._ - private def scheduler = externalSchedulerOpt getOrElse context.system.scheduler + private def scheduler = externalSchedulerOpt.getOrElse(context.system.scheduler) var knownNodes: Set[URI] = knownNodesStorage.getKnownNodes() diff --git a/src/main/scala/io/iohk/ethereum/network/NetworkMetrics.scala b/src/main/scala/io/iohk/ethereum/network/NetworkMetrics.scala index 8390f19488..818dadf34b 100644 --- a/src/main/scala/io/iohk/ethereum/network/NetworkMetrics.scala +++ b/src/main/scala/io/iohk/ethereum/network/NetworkMetrics.scala @@ -2,48 +2,50 @@ package io.iohk.ethereum.network import java.util.concurrent.atomic.AtomicLong +import io.micrometer.core.instrument.Counter + import io.iohk.ethereum.metrics.MetricsContainer case object NetworkMetrics extends MetricsContainer { - private final val HandshakedIncomingPeersGauge = + final private val HandshakedIncomingPeersGauge = metrics.registry.gauge("network.peers.incoming.handshaked.gauge", new AtomicLong(0)) - private final val HandshakedOutgoingPeersGauge = + final private val HandshakedOutgoingPeersGauge = metrics.registry.gauge("network.peers.outgoing.handshaked.gauge", new AtomicLong(0)) - final val ReceivedMessagesCounter = metrics.counter("network.messages.received.counter") + final val ReceivedMessagesCounter: Counter = metrics.counter("network.messages.received.counter") - final val SentMessagesCounter = metrics.counter("network.messages.sent.counter") + final val SentMessagesCounter: Counter = metrics.counter("network.messages.sent.counter") - final val DiscoveredPeersSize = metrics.registry.gauge("network.discovery.foundPeers.gauge", new AtomicLong(0)) + final val DiscoveredPeersSize: AtomicLong = + metrics.registry.gauge("network.discovery.foundPeers.gauge", new AtomicLong(0)) - final val BlacklistedPeersSize = metrics.registry.gauge("network.peers.blacklisted.gauge", new AtomicLong(0)) + final val BlacklistedPeersSize: AtomicLong = + metrics.registry.gauge("network.peers.blacklisted.gauge", new AtomicLong(0)) - final val BlacklistedReasonsFastSyncGroup = + final val BlacklistedReasonsFastSyncGroup: Counter = metrics.registry.counter("network.peers.blacklisted.fastSyncGroup.counter") - final val BlacklistedReasonsRegularSyncGroup = + final val BlacklistedReasonsRegularSyncGroup: Counter = metrics.registry.counter("network.peers.blacklisted.regularSyncGroup.counter") - final val BlacklistedReasonsP2PGroup = metrics.registry.counter("network.peers.blacklisted.p2pGroup.counter") + final val BlacklistedReasonsP2PGroup: Counter = metrics.registry.counter("network.peers.blacklisted.p2pGroup.counter") - final val PendingPeersSize = metrics.registry.gauge("network.peers.pending.gauge", new AtomicLong(0)) + final val PendingPeersSize: AtomicLong = metrics.registry.gauge("network.peers.pending.gauge", new AtomicLong(0)) - final val TriedPeersSize = + final val TriedPeersSize: AtomicLong = metrics.registry.gauge("network.tried.peers.gauge", new AtomicLong(0L)) - def registerAddHandshakedPeer(peer: Peer): Unit = { + def registerAddHandshakedPeer(peer: Peer): Unit = if (peer.incomingConnection) { HandshakedIncomingPeersGauge.incrementAndGet() } else { HandshakedOutgoingPeersGauge.incrementAndGet() } - } - def registerRemoveHandshakedPeer(peer: Peer): Unit = { + def registerRemoveHandshakedPeer(peer: Peer): Unit = if (peer.incomingConnection) { HandshakedIncomingPeersGauge.decrementAndGet() } else { HandshakedOutgoingPeersGauge.decrementAndGet() } - } } diff --git a/src/main/scala/io/iohk/ethereum/network/Peer.scala b/src/main/scala/io/iohk/ethereum/network/Peer.scala index 9c5819f30d..397cb08a15 100644 --- a/src/main/scala/io/iohk/ethereum/network/Peer.scala +++ b/src/main/scala/io/iohk/ethereum/network/Peer.scala @@ -1,10 +1,11 @@ package io.iohk.ethereum.network +import java.net.InetSocketAddress + import akka.actor.ActorRef import akka.util.ByteString -import io.iohk.ethereum.blockchain.sync.Blacklist.BlacklistId -import java.net.InetSocketAddress +import io.iohk.ethereum.blockchain.sync.Blacklist.BlacklistId final case class PeerId(value: String) extends BlacklistId diff --git a/src/main/scala/io/iohk/ethereum/network/PeerActor.scala b/src/main/scala/io/iohk/ethereum/network/PeerActor.scala index d4484c2bbc..6a2b74760a 100644 --- a/src/main/scala/io/iohk/ethereum/network/PeerActor.scala +++ b/src/main/scala/io/iohk/ethereum/network/PeerActor.scala @@ -1,27 +1,33 @@ package io.iohk.ethereum.network -import java.net.{InetSocketAddress, URI} +import java.net.InetSocketAddress +import java.net.URI + import akka.actor.SupervisorStrategy.Escalate import akka.actor._ import akka.util.ByteString + +import org.bouncycastle.util.encoders.Hex + import io.iohk.ethereum.network.PeerActor.Status._ -import io.iohk.ethereum.network.PeerEventBusActor.PeerEvent.{MessageFromPeer, PeerHandshakeSuccessful} +import io.iohk.ethereum.network.PeerEventBusActor.PeerEvent.MessageFromPeer +import io.iohk.ethereum.network.PeerEventBusActor.PeerEvent.PeerHandshakeSuccessful import io.iohk.ethereum.network.PeerEventBusActor.Publish import io.iohk.ethereum.network.PeerManagerActor.PeerConfiguration import io.iohk.ethereum.network.handshaker.Handshaker -import io.iohk.ethereum.network.handshaker.Handshaker.HandshakeComplete.{HandshakeFailure, HandshakeSuccess} -import io.iohk.ethereum.network.handshaker.Handshaker.{HandshakeResult, NextMessage} +import io.iohk.ethereum.network.handshaker.Handshaker.HandshakeComplete.HandshakeFailure +import io.iohk.ethereum.network.handshaker.Handshaker.HandshakeComplete.HandshakeSuccess +import io.iohk.ethereum.network.handshaker.Handshaker.HandshakeResult +import io.iohk.ethereum.network.handshaker.Handshaker.NextMessage import io.iohk.ethereum.network.p2p._ -import io.iohk.ethereum.network.p2p.messages.Capability.Capabilities -import io.iohk.ethereum.network.p2p.messages.{Capability, ETH63} +import io.iohk.ethereum.network.p2p.messages.Capability import io.iohk.ethereum.network.p2p.messages.WireProtocol._ +import io.iohk.ethereum.network.rlpx.AuthHandshaker +import io.iohk.ethereum.network.rlpx.RLPxConnectionHandler import io.iohk.ethereum.network.rlpx.RLPxConnectionHandler.RLPxConfiguration -import io.iohk.ethereum.network.rlpx.{AuthHandshaker, RLPxConnectionHandler} import io.iohk.ethereum.utils.Logger -import org.bouncycastle.util.encoders.Hex -/** - * Peer actor is responsible for initiating and handling high-level connection with peer. +/** Peer actor is responsible for initiating and handling high-level connection with peer. * It creates child RLPxConnectionActor for handling underlying RLPx communication. * Once RLPx connection is established it proceeds with protocol handshake (i.e `Hello` * and `Status` exchange). @@ -48,27 +54,27 @@ class PeerActor[R <: HandshakeResult]( Escalate } - def scheduler: Scheduler = externalSchedulerOpt getOrElse system.scheduler + def scheduler: Scheduler = externalSchedulerOpt.getOrElse(system.scheduler) override def receive: Receive = waitingForInitialCommand - def waitingForInitialCommand: Receive = stashMessages orElse { + def waitingForInitialCommand: Receive = stashMessages.orElse { case HandleConnection(connection, remoteAddress) => val rlpxConnection = createRlpxConnection(remoteAddress, None) rlpxConnection.ref ! RLPxConnectionHandler.HandleConnection(connection) - context become waitingForConnectionResult(rlpxConnection) + context.become(waitingForConnectionResult(rlpxConnection)) case ConnectTo(uri) => val rlpxConnection = createRlpxConnection(new InetSocketAddress(uri.getHost, uri.getPort), Some(uri)) rlpxConnection.ref ! RLPxConnectionHandler.ConnectTo(uri) - context become waitingForConnectionResult(rlpxConnection) + context.become(waitingForConnectionResult(rlpxConnection)) case GetStatus => sender() ! StatusResponse(Idle) } def createRlpxConnection(remoteAddress: InetSocketAddress, uriOpt: Option[URI]): RLPxConnection = { val ref = rlpxConnectionFactory(context) - context watch ref + context.watch(ref) RLPxConnection(ref, remoteAddress, uriOpt) } @@ -80,7 +86,7 @@ class PeerActor[R <: HandshakeResult]( } def waitingForConnectionResult(rlpxConnection: RLPxConnection, numRetries: Int = 0): Receive = - handleTerminated(rlpxConnection, numRetries, Connecting) orElse stashMessages orElse { + handleTerminated(rlpxConnection, numRetries, Connecting).orElse(stashMessages).orElse { case RLPxConnectionHandler.ConnectionEstablished(remoteNodeId) => val newUri = rlpxConnection.uriOpt.map(outGoingUri => modifyOutGoingUri(remoteNodeId, rlpxConnection, outGoingUri)) @@ -95,15 +101,15 @@ class PeerActor[R <: HandshakeResult]( log.debug("Failed to establish RLPx connection") rlpxConnection.uriOpt match { case Some(uri) if numRetries < peerConfiguration.connectMaxRetries => - context unwatch rlpxConnection.ref + context.unwatch(rlpxConnection.ref) scheduleConnectRetry(uri, numRetries) case Some(uri) => context.parent ! PeerClosedConnection(peerAddress.getHostString, Disconnect.Reasons.Other) knownNodesManager ! KnownNodesManager.RemoveKnownNode(uri) - context stop self + context.stop(self) case None => log.debug("Connection was initiated by remote peer, not attempting to reconnect") - context stop self + context.stop(self) } case GetStatus => sender() ! StatusResponse(Connecting) @@ -116,9 +122,11 @@ class PeerActor[R <: HandshakeResult]( timeout: Cancellable, numRetries: Int ): Receive = - handleTerminated(rlpxConnection, numRetries, Handshaking(numRetries)) orElse - handleDisconnectMsg(rlpxConnection, Handshaking(numRetries)) orElse - handlePingMsg(rlpxConnection) orElse stashMessages orElse { + handleTerminated(rlpxConnection, numRetries, Handshaking(numRetries)) + .orElse(handleDisconnectMsg(rlpxConnection, Handshaking(numRetries))) + .orElse(handlePingMsg(rlpxConnection)) + .orElse(stashMessages) + .orElse { case RLPxConnectionHandler.InitialHelloReceived(msg, negotiatedProtocol) => // Processes the InitialHelloReceived, cancels the timeout and processes a new message but only if the handshaker @@ -151,8 +159,7 @@ class PeerActor[R <: HandshakeResult]( } - /** - * Asks for the next message to send to the handshaker, or, if there is None, + /** Asks for the next message to send to the handshaker, or, if there is None, * becomes MessageHandler if handshake was successful or disconnects from the peer otherwise * * @param handshaker @@ -169,16 +176,16 @@ class PeerActor[R <: HandshakeResult]( case Right(NextMessage(msgToSend, timeoutTime)) => rlpxConnection.sendMessage(msgToSend) val newTimeout = scheduler.scheduleOnce(timeoutTime, self, ResponseTimeout) - context become processingHandshaking(handshaker, remoteNodeId, rlpxConnection, newTimeout, numRetries) + context.become(processingHandshaking(handshaker, remoteNodeId, rlpxConnection, newTimeout, numRetries)) case Left(HandshakeSuccess(handshakeResult)) => - rlpxConnection.uriOpt.foreach { uri => knownNodesManager ! KnownNodesManager.AddKnownNode(uri) } - context become new HandshakedPeer(remoteNodeId, rlpxConnection, handshakeResult).receive + rlpxConnection.uriOpt.foreach(uri => knownNodesManager ! KnownNodesManager.AddKnownNode(uri)) + context.become(new HandshakedPeer(remoteNodeId, rlpxConnection, handshakeResult).receive) unstashAll() case Left(HandshakeFailure(reason)) => context.parent ! PeerClosedConnection(peerAddress.getHostString, reason) - rlpxConnection.uriOpt.foreach { uri => knownNodesManager ! KnownNodesManager.RemoveKnownNode(uri) } + rlpxConnection.uriOpt.foreach(uri => knownNodesManager ! KnownNodesManager.RemoveKnownNode(uri)) disconnectFromPeer(rlpxConnection, reason) } @@ -186,28 +193,28 @@ class PeerActor[R <: HandshakeResult]( private def scheduleConnectRetry(uri: URI, numRetries: Int): Unit = { log.debug("Scheduling connection retry in {}", peerConfiguration.connectRetryDelay) scheduler.scheduleOnce(peerConfiguration.connectRetryDelay, self, RetryConnectionTimeout) - context become { + context.become { case RetryConnectionTimeout => reconnect(uri, numRetries + 1) - case GetStatus => sender() ! StatusResponse(Connecting) + case GetStatus => sender() ! StatusResponse(Connecting) } } private def disconnectFromPeer(rlpxConnection: RLPxConnection, reason: Int): Unit = { rlpxConnection.sendMessage(Disconnect(reason)) scheduler.scheduleOnce(peerConfiguration.disconnectPoisonPillTimeout, self, PoisonPill) - context unwatch rlpxConnection.ref - context become disconnected + context.unwatch(rlpxConnection.ref) + context.become(disconnected) } private def stopActor(rlpxConnection: RLPxConnection, status: Status): Unit = status match { case Handshaked => gracefulStop(rlpxConnection) - case _ => context stop self + case _ => context.stop(self) } private def gracefulStop(rlpxConnection: RLPxConnection): Unit = { scheduler.scheduleOnce(peerConfiguration.disconnectPoisonPillTimeout, self, PoisonPill) - context unwatch rlpxConnection.ref - context become disconnected + context.unwatch(rlpxConnection.ref) + context.become(disconnected) } def disconnected: Receive = { case GetStatus => @@ -234,7 +241,7 @@ class PeerActor[R <: HandshakeResult]( val address = new InetSocketAddress(uri.getHost, uri.getPort) val newConnection = createRlpxConnection(address, Some(uri)) newConnection.ref ! RLPxConnectionHandler.ConnectTo(uri) - context become waitingForConnectionResult(newConnection, numRetries) + context.become(waitingForConnectionResult(newConnection, numRetries)) } def handlePingMsg(rlpxConnection: RLPxConnection): Receive = { case RLPxConnectionHandler.MessageReceived(_: Ping) => @@ -264,9 +271,9 @@ class PeerActor[R <: HandshakeResult]( // The actor logs incoming messages, which can be quite verbose even for DEBUG mode. // ActorLogging doesn't support TRACE, but we can push more details if trace is enabled using the normal logging facilites. object MessageLogger extends Logger { - val isTraceEnabled = { + val isTraceEnabled: Boolean = { var enabled = false - log.whenTraceEnabled({ enabled = true }) + log.whenTraceEnabled { enabled = true } enabled } def logMessage(peerId: PeerId, message: Message): Unit = @@ -280,17 +287,17 @@ class PeerActor[R <: HandshakeResult]( class HandshakedPeer(remoteNodeId: ByteString, rlpxConnection: RLPxConnection, handshakeResult: R) { - val peerId = PeerId(Hex.toHexString(remoteNodeId.toArray)) + val peerId: PeerId = PeerId(Hex.toHexString(remoteNodeId.toArray)) val peer: Peer = Peer(peerId, peerAddress, self, incomingConnection, Some(remoteNodeId)) peerEventBus ! Publish(PeerHandshakeSuccessful(peer, handshakeResult)) - /** - * main behavior of actor that handles peer communication and subscriptions for messages + /** main behavior of actor that handles peer communication and subscriptions for messages */ def receive: Receive = - handlePingMsg(rlpxConnection) orElse - handleDisconnectMsg(rlpxConnection, Handshaked) orElse - handleTerminated(rlpxConnection, 0, Handshaked) orElse { + handlePingMsg(rlpxConnection) + .orElse(handleDisconnectMsg(rlpxConnection, Handshaked)) + .orElse(handleTerminated(rlpxConnection, 0, Handshaked)) + .orElse { case RLPxConnectionHandler.MessageReceived(message) => MessageLogger.logMessage(peerId, message) @@ -348,9 +355,8 @@ object PeerActor { } case class RLPxConnection(ref: ActorRef, remoteAddress: InetSocketAddress, uriOpt: Option[URI]) { - def sendMessage(message: MessageSerializable): Unit = { + def sendMessage(message: MessageSerializable): Unit = ref ! RLPxConnectionHandler.SendMessage(message) - } } case class HandleConnection(connection: ActorRef, remoteAddress: InetSocketAddress) diff --git a/src/main/scala/io/iohk/ethereum/network/PeerEventBusActor.scala b/src/main/scala/io/iohk/ethereum/network/PeerEventBusActor.scala index 5d22c5d719..05ab900d3b 100644 --- a/src/main/scala/io/iohk/ethereum/network/PeerEventBusActor.scala +++ b/src/main/scala/io/iohk/ethereum/network/PeerEventBusActor.scala @@ -1,8 +1,13 @@ package io.iohk.ethereum.network -import akka.actor.{Actor, ActorRef, Props} +import akka.actor.Actor +import akka.actor.ActorRef +import akka.actor.Props import akka.event.ActorEventBus -import io.iohk.ethereum.network.PeerEventBusActor.PeerEvent.{MessageFromPeer, PeerDisconnected, PeerHandshakeSuccessful} + +import io.iohk.ethereum.network.PeerEventBusActor.PeerEvent.MessageFromPeer +import io.iohk.ethereum.network.PeerEventBusActor.PeerEvent.PeerDisconnected +import io.iohk.ethereum.network.PeerEventBusActor.PeerEvent.PeerHandshakeSuccessful import io.iohk.ethereum.network.PeerEventBusActor.SubscriptionClassifier._ import io.iohk.ethereum.network.handshaker.Handshaker.HandshakeResult import io.iohk.ethereum.network.p2p.Message @@ -52,8 +57,7 @@ object PeerEventBusActor { private var messageSubscriptions: Map[(Subscriber, PeerSelector), Set[Int]] = Map.empty private var connectionSubscriptions: Seq[Subscription] = Nil - /** - * Subscribes the subscriber to a requested event + /** Subscribes the subscriber to a requested event * * @param subscriber * @param to, classifier for the event subscribed @@ -61,11 +65,10 @@ object PeerEventBusActor { */ override def subscribe(subscriber: ActorRef, to: Classifier): Boolean = to match { case msgClassifier: MessageClassifier => subscribeToMessageReceived(subscriber, msgClassifier) - case _ => subscribeToConnectionEvent(subscriber, to) + case _ => subscribeToConnectionEvent(subscriber, to) } - /** - * Unsubscribes the subscriber from a requested event + /** Unsubscribes the subscriber from a requested event * * @param subscriber * @param from, classifier for the event to unsubscribe @@ -73,11 +76,10 @@ object PeerEventBusActor { */ override def unsubscribe(subscriber: ActorRef, from: Classifier): Boolean = from match { case msgClassifier: MessageClassifier => unsubscribeFromMessageReceived(subscriber, msgClassifier) - case _ => unsubscribeFromConnectionEvent(subscriber, from) + case _ => unsubscribeFromConnectionEvent(subscriber, from) } - /** - * Unsubscribes the subscriber from all events it was subscribed + /** Unsubscribes the subscriber from all events it was subscribed * * @param subscriber */ @@ -113,8 +115,7 @@ object PeerEventBusActor { interestedSubscribers.foreach(_ ! event) } - /** - * Subscribes the subscriber to a requested message received event + /** Subscribes the subscriber to a requested message received event * * @param subscriber * @param to, classifier for the message received event subscribed @@ -133,8 +134,7 @@ object PeerEventBusActor { } } - /** - * Subscribes the subscriber to a requested connection event (new peer handshaked or peer disconnected) + /** Subscribes the subscriber to a requested connection event (new peer handshaked or peer disconnected) * * @param subscriber * @param to, classifier for the connection event subscribed @@ -150,14 +150,13 @@ object PeerEventBusActor { } } - /** - * Unsubscribes the subscriber from a requested received message event event + /** Unsubscribes the subscriber from a requested received message event event * * @param subscriber * @param from, classifier for the message received event to unsubscribe * @return true if successful and false if not (because it wasn't subscribed to that Classifier, or otherwise) */ - private def unsubscribeFromMessageReceived(subscriber: ActorRef, from: MessageClassifier): Boolean = { + private def unsubscribeFromMessageReceived(subscriber: ActorRef, from: MessageClassifier): Boolean = messageSubscriptions.get((subscriber, from.peerSelector)).exists { messageCodes => val newMessageCodes = messageCodes -- from.messageCodes if (messageCodes == newMessageCodes) false @@ -167,10 +166,8 @@ object PeerEventBusActor { true } } - } - /** - * Unsubscribes the subscriber from a requested event + /** Unsubscribes the subscriber from a requested event * * @param subscriber * @param from, classifier for the connection event to unsubscribe @@ -209,10 +206,10 @@ class PeerEventBusActor extends Actor { val peerEventBus: PeerEventBus = new PeerEventBus override def receive: Receive = { - case Subscribe(to) => peerEventBus.subscribe(sender(), to) + case Subscribe(to) => peerEventBus.subscribe(sender(), to) case Unsubscribe(Some(from)) => peerEventBus.unsubscribe(sender(), from) - case Unsubscribe(None) => peerEventBus.unsubscribe(sender()) - case Publish(ev: PeerEvent) => peerEventBus.publish(ev) + case Unsubscribe(None) => peerEventBus.unsubscribe(sender()) + case Publish(ev: PeerEvent) => peerEventBus.publish(ev) } } diff --git a/src/main/scala/io/iohk/ethereum/network/PeerManagerActor.scala b/src/main/scala/io/iohk/ethereum/network/PeerManagerActor.scala index 64ed0ec0a6..71a6886fff 100644 --- a/src/main/scala/io/iohk/ethereum/network/PeerManagerActor.scala +++ b/src/main/scala/io/iohk/ethereum/network/PeerManagerActor.scala @@ -1,32 +1,40 @@ package io.iohk.ethereum.network +import java.net.InetSocketAddress +import java.net.URI +import java.util.Collections.newSetFromMap + import akka.actor.SupervisorStrategy.Stop import akka.actor._ -import akka.util.{ByteString, Timeout} -import io.iohk.ethereum.blockchain.sync.Blacklist.BlacklistId +import akka.util.ByteString +import akka.util.Timeout + +import monix.eval.Task +import monix.execution.{Scheduler => MonixScheduler} + +import scala.collection.mutable +import scala.concurrent.duration._ +import scala.jdk.CollectionConverters._ + +import org.bouncycastle.util.encoders.Hex + import io.iohk.ethereum.blockchain.sync.Blacklist +import io.iohk.ethereum.blockchain.sync.Blacklist.BlacklistId import io.iohk.ethereum.jsonrpc.AkkaTaskOps.TaskActorOps import io.iohk.ethereum.network.PeerActor.PeerClosedConnection import io.iohk.ethereum.network.PeerActor.Status.Handshaked import io.iohk.ethereum.network.PeerEventBusActor._ import io.iohk.ethereum.network.PeerManagerActor.PeerConfiguration -import io.iohk.ethereum.network.discovery.{DiscoveryConfig, Node, PeerDiscoveryManager} +import io.iohk.ethereum.network.discovery.DiscoveryConfig +import io.iohk.ethereum.network.discovery.Node +import io.iohk.ethereum.network.discovery.PeerDiscoveryManager import io.iohk.ethereum.network.handshaker.Handshaker import io.iohk.ethereum.network.handshaker.Handshaker.HandshakeResult +import io.iohk.ethereum.network.p2p.MessageSerializable import io.iohk.ethereum.network.p2p.messages.Capability import io.iohk.ethereum.network.p2p.messages.WireProtocol.Disconnect -import io.iohk.ethereum.network.p2p.{MessageDecoder, MessageSerializable} import io.iohk.ethereum.network.rlpx.AuthHandshaker import io.iohk.ethereum.network.rlpx.RLPxConnectionHandler.RLPxConfiguration -import monix.eval.Task -import monix.execution.{Scheduler => MonixScheduler} -import org.bouncycastle.util.encoders.Hex - -import java.net.{InetSocketAddress, URI} -import java.util.Collections.newSetFromMap -import scala.collection.mutable -import scala.concurrent.duration._ -import scala.jdk.CollectionConverters._ class PeerManagerActor( peerEventBus: ActorRef, @@ -42,8 +50,7 @@ class PeerManagerActor( with ActorLogging with Stash { - /** - * Maximum number of blacklisted nodes will never be larger than number of peers provided by discovery + /** Maximum number of blacklisted nodes will never be larger than number of peers provided by discovery * Discovery provides remote nodes from all networks (ETC,ETH, Mordor etc.) only during handshake we learn that some * of the remote nodes are not compatible that's why we mark them as useless (blacklist them). * @@ -76,7 +83,7 @@ class PeerManagerActor( // Subscribe to the handshake event of any peer peerEventBus ! Subscribe(SubscriptionClassifier.PeerHandshaked) - def scheduler: Scheduler = externalSchedulerOpt getOrElse context.system.scheduler + def scheduler: Scheduler = externalSchedulerOpt.getOrElse(context.system.scheduler) implicit val monix: MonixScheduler = MonixScheduler(context.dispatcher) override val supervisorStrategy: OneForOneStrategy = @@ -88,27 +95,25 @@ class PeerManagerActor( case StartConnecting => scheduleNodesUpdate() knownNodesManager ! KnownNodesManager.GetKnownNodes - context become listening(ConnectedPeers.empty) + context.become(listening(ConnectedPeers.empty)) unstashAll() case _ => stash() } - private def scheduleNodesUpdate(): Unit = { + private def scheduleNodesUpdate(): Unit = scheduler.scheduleWithFixedDelay( peerConfiguration.updateNodesInitialDelay, peerConfiguration.updateNodesInterval, peerDiscoveryManager, PeerDiscoveryManager.GetDiscoveredNodesInfo ) - } - private def listening(connectedPeers: ConnectedPeers): Receive = { - handleCommonMessages(connectedPeers) orElse - handleConnections(connectedPeers) orElse - handleNewNodesToConnectMessages(connectedPeers) orElse - handlePruning(connectedPeers) - } + private def listening(connectedPeers: ConnectedPeers): Receive = + handleCommonMessages(connectedPeers) + .orElse(handleConnections(connectedPeers)) + .orElse(handleNewNodesToConnectMessages(connectedPeers)) + .orElse(handlePruning(connectedPeers)) private def handleNewNodesToConnectMessages(connectedPeers: ConnectedPeers): Receive = { case KnownNodesManager.KnownNodes(nodes) => @@ -128,7 +133,7 @@ class PeerManagerActor( maybeConnectToDiscoveredNodes(connectedPeers, nodes) } - private def maybeConnectToRandomNode(connectedPeers: ConnectedPeers, node: Node): Unit = { + private def maybeConnectToRandomNode(connectedPeers: ConnectedPeers, node: Node): Unit = if (connectedPeers.outgoingConnectionDemand > 0) { if (connectedPeers.canConnectTo(node)) { triedNodes.add(node.id) @@ -137,7 +142,6 @@ class PeerManagerActor( peerDiscoveryManager ! PeerDiscoveryManager.GetRandomNodeInfo } } - } private def maybeConnectToDiscoveredNodes(connectedPeers: ConnectedPeers, nodes: Set[Node]): Unit = { val discoveredNodes = nodes @@ -165,10 +169,10 @@ class PeerManagerActor( if (nodesToConnect.nonEmpty) { log.debug("Trying to connect to {} nodes", nodesToConnect.size) - nodesToConnect.foreach(n => { + nodesToConnect.foreach { n => triedNodes.add(n.id) self ! ConnectToPeer(n.toUri) - }) + } } else { log.debug("The nodes list is empty, no new nodes to connect to") } @@ -201,7 +205,7 @@ class PeerManagerActor( import Disconnect.Reasons._ reason match { case TooManyPeers | AlreadyConnected | ClientQuitting => peerConfiguration.shortBlacklistDuration - case _ => peerConfiguration.longBlacklistDuration + case _ => peerConfiguration.longBlacklistDuration } } @@ -230,7 +234,7 @@ class PeerManagerActor( case Right(address) => val (peer, newConnectedPeers) = createPeer(address, incomingConnection = true, connectedPeers) peer.ref ! PeerActor.HandleConnection(connection, remoteAddress) - context become listening(newConnectedPeers) + context.become(listening(newConnectedPeers)) case Left(error) => handleConnectionErrors(error) @@ -254,7 +258,7 @@ class PeerManagerActor( case Right(address) => val (peer, newConnectedPeers) = createPeer(address, incomingConnection = false, connectedPeers) peer.ref ! PeerActor.ConnectTo(uri) - context become listening(newConnectedPeers) + context.become(listening(newConnectedPeers)) case Left(error) => handleConnectionErrors(error) } @@ -276,8 +280,8 @@ class PeerManagerActor( if (newConnectedPeers.outgoingConnectionDemand > 0) { peerDiscoveryManager ! PeerDiscoveryManager.GetRandomNodeInfo } - context unwatch ref - context become listening(newConnectedPeers) + context.unwatch(ref) + context.become(listening(newConnectedPeers)) case PeerEvent.PeerHandshakeSuccessful(handshakedPeer, _) => if ( @@ -288,7 +292,7 @@ class PeerManagerActor( // It looks like all incoming slots are taken; try to make some room. self ! SchedulePruneIncomingPeers - context become listening(connectedPeers) + context.become(listening(connectedPeers)) } else if (handshakedPeer.nodeId.exists(connectedPeers.hasHandshakedWith)) { // FIXME: peers received after handshake should always have their nodeId defined, we could maybe later distinguish @@ -299,7 +303,7 @@ class PeerManagerActor( log.debug(s"Disconnecting from ${handshakedPeer.remoteAddress} as we are already connected to him") handshakedPeer.ref ! PeerActor.DisconnectPeer(Disconnect.Reasons.AlreadyConnected) } else { - context become listening(connectedPeers.promotePeerToHandshaked(handshakedPeer)) + context.become(listening(connectedPeers.promotePeerToHandshaked(handshakedPeer))) } } @@ -309,7 +313,7 @@ class PeerManagerActor( connectedPeers: ConnectedPeers ): (Peer, ConnectedPeers) = { val ref = peerFactory(context, address, incomingConnection) - context watch ref + context.watch(ref) // The peerId is unknown for a pending peer, hence it is created from the PeerActor's path. // Upon successful handshake, the pending peer is updated with the actual peerId derived from @@ -345,7 +349,7 @@ class PeerManagerActor( case PruneIncomingPeers(PeerStatisticsActor.StatsForAll(stats)) => val prunedConnectedPeers = pruneIncomingPeers(connectedPeers, stats) - context become listening(prunedConnectedPeers) + context.become(listening(prunedConnectedPeers)) } /** Disconnect some incoming connections so we can free up slots. */ @@ -371,18 +375,17 @@ class PeerManagerActor( prunedConnectedPeers } - private def getPeers(peers: Set[Peer]): Task[Peers] = { + private def getPeers(peers: Set[Peer]): Task[Peers] = Task .parSequence(peers.map(getPeerStatus)) .map(_.flatten.toMap) .map(Peers.apply) - } private def getPeerStatus(peer: Peer): Task[Option[(Peer, PeerActor.Status)]] = { implicit val timeout: Timeout = Timeout(2.seconds) peer.ref .askFor[PeerActor.StatusResponse](PeerActor.GetStatus) - .map { sr => Some((peer, sr.status)) } + .map(sr => Some((peer, sr.status))) .onErrorHandle(_ => None) } @@ -390,9 +393,8 @@ class PeerManagerActor( remoteAddress: InetSocketAddress, error: ConnectionError, stateCondition: Boolean - ): Either[ConnectionError, InetSocketAddress] = { + ): Either[ConnectionError, InetSocketAddress] = Either.cond(stateCondition, remoteAddress, error) - } private def handleConnectionErrors(error: ConnectionError): Unit = error match { case MaxIncomingPendingConnections(connection) => @@ -540,14 +542,13 @@ object PeerManagerActor { def outgoingConnectionDemand( connectedPeers: ConnectedPeers, peerConfiguration: PeerConfiguration.ConnectionLimits - ): Int = { + ): Int = if (connectedPeers.outgoingHandshakedPeersCount >= peerConfiguration.minOutgoingPeers) // We have established at least the minimum number of working connections. 0 else // Try to connect to more, up to the maximum, including pending peers. peerConfiguration.maxOutgoingPeers - connectedPeers.outgoingPeersCount - } def numberOfIncomingConnectionsToPrune( connectedPeers: ConnectedPeers, @@ -563,7 +564,7 @@ object PeerManagerActor { /** Assign a priority to peers that we can use to order connections, * with lower priorities being the ones to prune first. */ - def prunePriority(stats: Map[PeerId, PeerStat], currentTimeMillis: Long)(peerId: PeerId): Double = { + def prunePriority(stats: Map[PeerId, PeerStat], currentTimeMillis: Long)(peerId: PeerId): Double = stats .get(peerId) .flatMap { stat => @@ -577,7 +578,6 @@ object PeerManagerActor { maybeAgeSeconds.map(age => stat.responsesReceived.toDouble / age) } .getOrElse(0.0) - } def lruSet[A](maxEntries: Int): mutable.Set[A] = newSetFromMap[A](new java.util.LinkedHashMap[A, java.lang.Boolean]() { diff --git a/src/main/scala/io/iohk/ethereum/network/PeerStat.scala b/src/main/scala/io/iohk/ethereum/network/PeerStat.scala index 804faf1333..5e3fed2411 100644 --- a/src/main/scala/io/iohk/ethereum/network/PeerStat.scala +++ b/src/main/scala/io/iohk/ethereum/network/PeerStat.scala @@ -14,7 +14,7 @@ object PeerStat { private def mergeOpt[A, B](x: A, y: A)(f: A => Option[B])(g: (B, B) => B): Option[B] = { val (mx, my) = (f(x), f(y)) - (mx, my).mapN(g) orElse mx orElse my + (mx, my).mapN(g).orElse(mx).orElse(my) } implicit val monoid: Monoid[PeerStat] = diff --git a/src/main/scala/io/iohk/ethereum/network/PeerStatisticsActor.scala b/src/main/scala/io/iohk/ethereum/network/PeerStatisticsActor.scala index 354b307c67..61a36371c9 100644 --- a/src/main/scala/io/iohk/ethereum/network/PeerStatisticsActor.scala +++ b/src/main/scala/io/iohk/ethereum/network/PeerStatisticsActor.scala @@ -1,14 +1,15 @@ package io.iohk.ethereum.network -import akka.actor._ -import io.iohk.ethereum.network.PeerEventBusActor._ -import io.iohk.ethereum.network.p2p.messages.Codes import java.time.Clock -import io.iohk.ethereum.network.p2p.Message +import akka.actor._ import scala.concurrent.duration.FiniteDuration +import io.iohk.ethereum.network.PeerEventBusActor._ +import io.iohk.ethereum.network.p2p.Message +import io.iohk.ethereum.network.p2p.messages.Codes + class PeerStatisticsActor( peerEventBus: ActorRef, var maybeStats: Option[TimeSlotStats[PeerId, PeerStat]] @@ -23,7 +24,7 @@ class PeerStatisticsActor( peerEventBus ! Subscribe(SubscriptionClassifier.PeerDisconnectedClassifier(PeerSelector.AllPeers)) } - def receive: Receive = handlePeerEvents orElse handleStatsRequests + def receive: Receive = handlePeerEvents.orElse(handleStatsRequests) private def handlePeerEvents: Receive = { case PeerEvent.MessageFromPeer(msg, peerId) => @@ -67,7 +68,7 @@ object PeerStatisticsActor { case class GetStatsForPeer(window: FiniteDuration, peerId: PeerId) case class StatsForPeer(peerId: PeerId, stat: PeerStat) - val ResponseCodes = Set( + val ResponseCodes: Set[Int] = Set( Codes.NewBlockCode, Codes.NewBlockHashesCode, Codes.SignedTransactionsCode, @@ -78,16 +79,16 @@ object PeerStatisticsActor { Codes.ReceiptsCode ) - val RequestCodes = Set( + val RequestCodes: Set[Int] = Set( Codes.GetBlockHeadersCode, Codes.GetBlockBodiesCode, Codes.GetNodeDataCode, Codes.GetReceiptsCode ) - val MessageSubscriptionClassifier = + val MessageSubscriptionClassifier: SubscriptionClassifier.MessageClassifier = SubscriptionClassifier.MessageClassifier( - messageCodes = RequestCodes union ResponseCodes, + messageCodes = RequestCodes.union(ResponseCodes), peerSelector = PeerSelector.AllPeers ) } diff --git a/src/main/scala/io/iohk/ethereum/network/PortForwarder.scala b/src/main/scala/io/iohk/ethereum/network/PortForwarder.scala index 595277125d..a24442fc8c 100644 --- a/src/main/scala/io/iohk/ethereum/network/PortForwarder.scala +++ b/src/main/scala/io/iohk/ethereum/network/PortForwarder.scala @@ -1,13 +1,24 @@ package io.iohk.ethereum.network -import io.iohk.ethereum.utils.Logger import java.net.InetAddress import java.util.concurrent.ExecutorService + +import cats.effect.Resource +import cats.implicits._ + import monix.eval.Task + +import scala.jdk.CollectionConverters._ +import scala.util.chaining._ + import org.jupnp.DefaultUpnpServiceConfiguration +import org.jupnp.QueueingThreadPoolExecutor +import org.jupnp.UpnpService +import org.jupnp.UpnpServiceImpl import org.jupnp.support.igd.PortMappingListener import org.jupnp.support.model.PortMapping -import org.jupnp.support.model.PortMapping.Protocol.{TCP, UDP} +import org.jupnp.support.model.PortMapping.Protocol.TCP +import org.jupnp.support.model.PortMapping.Protocol.UDP import org.jupnp.tool.transport.JDKTransportConfiguration import org.jupnp.transport.Router import org.jupnp.transport.spi.NetworkAddressFactory @@ -15,16 +26,11 @@ import org.jupnp.transport.spi.StreamClient import org.jupnp.transport.spi.StreamClientConfiguration import org.jupnp.transport.spi.StreamServer import org.jupnp.transport.spi.StreamServerConfiguration -import org.jupnp.UpnpServiceImpl -import scala.jdk.CollectionConverters._ -import scala.util.chaining._ -import org.jupnp.QueueingThreadPoolExecutor -import cats.effect.Resource -import org.jupnp.UpnpService -import cats.implicits._ + +import io.iohk.ethereum.utils.Logger private class ClientOnlyUpnpServiceConfiguration extends DefaultUpnpServiceConfiguration() { - private final val THREAD_POOL_SIZE = 4 // seemingly the minimum required to perform port mapping + final private val THREAD_POOL_SIZE = 4 // seemingly the minimum required to perform port mapping override def createDefaultExecutorService(): ExecutorService = QueueingThreadPoolExecutor.createInstance("mantis-jupnp", THREAD_POOL_SIZE); @@ -47,7 +53,7 @@ private object NoStreamServer extends StreamServer[StreamServerConfiguration] { } object PortForwarder extends Logger { - private final val description = "Mantis" + final private val description = "Mantis" def openPorts(tcpPorts: Seq[Int], udpPorts: Seq[Int]): Resource[Task, Unit] = Resource.make(startForwarding(tcpPorts, udpPorts))(stopForwarding).void diff --git a/src/main/scala/io/iohk/ethereum/network/ServerActor.scala b/src/main/scala/io/iohk/ethereum/network/ServerActor.scala index 26727ed813..87912bd3dc 100644 --- a/src/main/scala/io/iohk/ethereum/network/ServerActor.scala +++ b/src/main/scala/io/iohk/ethereum/network/ServerActor.scala @@ -1,13 +1,24 @@ package io.iohk.ethereum.network import java.net.InetSocketAddress -import akka.actor.{Actor, ActorLogging, ActorRef, Props} -import akka.io.Tcp.{Bind, Bound, CommandFailed, Connected} -import akka.io.{IO, Tcp} -import io.iohk.ethereum.utils.{NodeStatus, ServerStatus} import java.util.concurrent.atomic.AtomicReference + +import akka.actor.Actor +import akka.actor.ActorLogging +import akka.actor.ActorRef +import akka.actor.Props +import akka.io.IO +import akka.io.Tcp +import akka.io.Tcp.Bind +import akka.io.Tcp.Bound +import akka.io.Tcp.CommandFailed +import akka.io.Tcp.Connected + import org.bouncycastle.util.encoders.Hex +import io.iohk.ethereum.utils.NodeStatus +import io.iohk.ethereum.utils.ServerStatus + class ServerActor(nodeStatusHolder: AtomicReference[NodeStatus], peerManager: ActorRef) extends Actor with ActorLogging { @@ -17,7 +28,7 @@ class ServerActor(nodeStatusHolder: AtomicReference[NodeStatus], peerManager: Ac override def receive: Receive = { case StartServer(address) => IO(Tcp) ! Bind(self, address) - context become waitingForBindingResult + context.become(waitingForBindingResult) } def waitingForBindingResult: Receive = { @@ -31,11 +42,11 @@ class ServerActor(nodeStatusHolder: AtomicReference[NodeStatus], peerManager: Ac localAddress.getPort ) nodeStatusHolder.getAndUpdate(_.copy(serverStatus = ServerStatus.Listening(localAddress))) - context become listening + context.become(listening) case CommandFailed(b: Bind) => log.warning("Binding to {} failed", b.localAddress) - context stop self + context.stop(self) } def listening: Receive = { case Connected(remoteAddress, _) => diff --git a/src/main/scala/io/iohk/ethereum/network/TimeSlotStats.scala b/src/main/scala/io/iohk/ethereum/network/TimeSlotStats.scala index ee67eae9e2..64a35a69fe 100644 --- a/src/main/scala/io/iohk/ethereum/network/TimeSlotStats.scala +++ b/src/main/scala/io/iohk/ethereum/network/TimeSlotStats.scala @@ -1,10 +1,13 @@ package io.iohk.ethereum.network +import java.time.Clock + import cats._ import cats.implicits._ -import java.time.Clock -import scala.concurrent.duration.{Duration, FiniteDuration} + import scala.annotation.tailrec +import scala.concurrent.duration.Duration +import scala.concurrent.duration.FiniteDuration /** Track statistics over time a fixed size timewindow. */ class TimeSlotStats[K, V: Monoid] private ( @@ -42,19 +45,18 @@ class TimeSlotStats[K, V: Monoid] private ( } /** Forget all statistics about a given key. */ - def remove(key: K): TimeSlotStats[K, V] = { + def remove(key: K): TimeSlotStats[K, V] = updated(lastIdx, buffer.map { case (k, v) => k -> v.remove(key) }) - } /** Aggregate stats for a key in all slots that are within the duration. */ def get(key: K, window: Option[Duration] = None): V = - fold(Monoid[V].empty, window getOrElse duration) { case (acc, stats) => + fold(Monoid[V].empty, window.getOrElse(duration)) { case (acc, stats) => stats.get(key).map(acc |+| _).getOrElse(acc) } /** Aggregate all stats in all slots within the duration. */ def getAll(window: Option[Duration] = None): Map[K, V] = - fold(Map.empty[K, V], window getOrElse duration) { case (acc, stats) => + fold(Map.empty[K, V], window.getOrElse(duration)) { case (acc, stats) => acc |+| stats } @@ -80,9 +82,8 @@ class TimeSlotStats[K, V: Monoid] private ( clock.millis() /** Truncate the current timestamp based on the slot duration. */ - private def slotId(timestamp: Timestamp): Timestamp = { + private def slotId(timestamp: Timestamp): Timestamp = timestamp - timestamp % slotDuration.toMillis - } /** The range of time slots based on the current timestamp and the buffer duration. */ def slotRange(timestamp: Timestamp, window: Duration): (Timestamp, Timestamp) = { diff --git a/src/main/scala/io/iohk/ethereum/network/discovery/DiscoveryConfig.scala b/src/main/scala/io/iohk/ethereum/network/discovery/DiscoveryConfig.scala index e0c49ad97a..cdf7fefb2e 100644 --- a/src/main/scala/io/iohk/ethereum/network/discovery/DiscoveryConfig.scala +++ b/src/main/scala/io/iohk/ethereum/network/discovery/DiscoveryConfig.scala @@ -1,9 +1,10 @@ package io.iohk.ethereum.network.discovery -import io.iohk.ethereum.utils.ConfigUtils import scala.concurrent.duration.FiniteDuration import scala.concurrent.duration._ +import io.iohk.ethereum.utils.ConfigUtils + case class DiscoveryConfig( discoveryEnabled: Boolean, host: Option[String], diff --git a/src/main/scala/io/iohk/ethereum/network/discovery/DiscoveryServiceBuilder.scala b/src/main/scala/io/iohk/ethereum/network/discovery/DiscoveryServiceBuilder.scala index 0fd7e36add..a9fe0bd925 100644 --- a/src/main/scala/io/iohk/ethereum/network/discovery/DiscoveryServiceBuilder.scala +++ b/src/main/scala/io/iohk/ethereum/network/discovery/DiscoveryServiceBuilder.scala @@ -1,22 +1,31 @@ package io.iohk.ethereum.network.discovery -import cats.effect.Resource -import io.iohk.ethereum.crypto -import io.iohk.ethereum.db.storage.KnownNodesStorage -import io.iohk.ethereum.network.discovery.codecs.RLPCodecs -import io.iohk.ethereum.utils.{NodeStatus, ServerStatus} -import io.iohk.scalanet.discovery.crypto.{PrivateKey, PublicKey, SigAlg} -import io.iohk.scalanet.discovery.ethereum.{Node => ENode, EthereumNodeRecord} -import io.iohk.scalanet.discovery.ethereum.v4 -import io.iohk.scalanet.peergroup.{InetMultiAddress, ExternalAddressResolver} -import io.iohk.scalanet.peergroup.udp.StaticUDPPeerGroup import java.net.InetAddress import java.net.InetSocketAddress import java.util.concurrent.atomic.AtomicReference + +import cats.effect.Resource + import monix.eval.Task import monix.execution.Scheduler -import scodec.bits.BitVector + +import io.iohk.scalanet.discovery.crypto.PrivateKey +import io.iohk.scalanet.discovery.crypto.PublicKey +import io.iohk.scalanet.discovery.crypto.SigAlg +import io.iohk.scalanet.discovery.ethereum.EthereumNodeRecord +import io.iohk.scalanet.discovery.ethereum.v4 +import io.iohk.scalanet.discovery.ethereum.{Node => ENode} +import io.iohk.scalanet.peergroup.ExternalAddressResolver +import io.iohk.scalanet.peergroup.InetMultiAddress +import io.iohk.scalanet.peergroup.udp.StaticUDPPeerGroup import scodec.Codec +import scodec.bits.BitVector + +import io.iohk.ethereum.crypto +import io.iohk.ethereum.db.storage.KnownNodesStorage +import io.iohk.ethereum.network.discovery.codecs.RLPCodecs +import io.iohk.ethereum.utils.NodeStatus +import io.iohk.ethereum.utils.ServerStatus trait DiscoveryServiceBuilder { diff --git a/src/main/scala/io/iohk/ethereum/network/discovery/Node.scala b/src/main/scala/io/iohk/ethereum/network/discovery/Node.scala index e861b10b9f..cb90f13ab5 100644 --- a/src/main/scala/io/iohk/ethereum/network/discovery/Node.scala +++ b/src/main/scala/io/iohk/ethereum/network/discovery/Node.scala @@ -1,13 +1,18 @@ package io.iohk.ethereum.network.discovery -import java.net.{InetSocketAddress, _} +import java.net.InetSocketAddress +import java.net._ import akka.util.ByteString -import io.iohk.ethereum.network -import io.iohk.ethereum.utils.Logger + +import scala.util.Failure +import scala.util.Success +import scala.util.Try + import org.bouncycastle.util.encoders.Hex -import scala.util.{Failure, Success, Try} +import io.iohk.ethereum.network +import io.iohk.ethereum.utils.Logger case class Node(id: ByteString, addr: InetAddress, tcpPort: Int, udpPort: Int) { @@ -23,7 +28,7 @@ case class Node(id: ByteString, addr: InetAddress, tcpPort: Int, udpPort: Int) { object Node { // If there is no udp port specified or it is malformed use tcp as default - private def getUdpPort(uri: URI, default: Int): Int = { + private def getUdpPort(uri: URI, default: Int): Int = Option(uri.getQuery).fold(default) { query => Try { val params = query.split("=") @@ -33,10 +38,9 @@ object Node { default } match { case Success(udpPort) => udpPort - case Failure(_) => default + case Failure(_) => default } } - } def fromUri(uri: URI): Node = { val nodeId = ByteString(Hex.decode(uri.getUserInfo)) @@ -52,13 +56,12 @@ object NodeParser extends Logger { type Error = String - private def validateTcpAddress(uri: URI): Either[Error, URI] = { + private def validateTcpAddress(uri: URI): Either[Error, URI] = Try(InetAddress.getByName(uri.getHost) -> uri.getPort) match { case Success(tcpAddress) if tcpAddress._2 != -1 => Right(uri) - case Success(_) => Left(s"No defined port for uri $uri") - case Failure(_) => Left(s"Error parsing ip address for $uri") + case Success(_) => Left(s"No defined port for uri $uri") + case Failure(_) => Left(s"Error parsing ip address for $uri") } - } private def validateScheme(uri: URI): Either[Error, URI] = { val scheme = Option(uri.getScheme).toRight(s"No defined scheme for uri $uri") @@ -71,7 +74,7 @@ object NodeParser extends Logger { private def validateNodeId(uri: URI): Either[Error, URI] = { val nodeId = Try(ByteString(Hex.decode(uri.getUserInfo))) match { case Success(id) => Right(id) - case Failure(_) => Left(s"Malformed nodeId for URI ${uri.toString}") + case Failure(_) => Left(s"Malformed nodeId for URI ${uri.toString}") } nodeId.flatMap(nodeId => @@ -79,12 +82,11 @@ object NodeParser extends Logger { ) } - private def validateUri(uriString: String): Either[Error, URI] = { + private def validateUri(uriString: String): Either[Error, URI] = Try(new URI(uriString)) match { case Success(nUri) => Right(nUri) - case Failure(ex) => Left(s"Malformed URI for node $uriString") + case Failure(_) => Left(s"Malformed URI for node $uriString") } - } private def validateNodeUri(node: String): Either[Set[Error], URI] = { import io.iohk.ethereum.utils.ValidationUtils._ @@ -100,19 +102,16 @@ object NodeParser extends Logger { } } - /** - * Parse a node string, for it to be valid it should have the format: + /** Parse a node string, for it to be valid it should have the format: * "enode://[128 char (64bytes) hex string]@[IPv4 address | '['IPv6 address']' ]:[port]" * * @param node to be parsed * @return the parsed node, or the errors detected during parsing */ - def parseNode(node: String): Either[Set[Error], Node] = { + def parseNode(node: String): Either[Set[Error], Node] = validateNodeUri(node).map(uri => Node.fromUri(uri)) - } - /** - * Parses a set of nodes, logging the invalid ones and returning the valid ones + /** Parses a set of nodes, logging the invalid ones and returning the valid ones * * @param unParsedNodes, nodes to be parsed * @return set of parsed and valid nodes diff --git a/src/main/scala/io/iohk/ethereum/network/discovery/PeerDiscoveryManager.scala b/src/main/scala/io/iohk/ethereum/network/discovery/PeerDiscoveryManager.scala index 0653117025..011fdf5fca 100644 --- a/src/main/scala/io/iohk/ethereum/network/discovery/PeerDiscoveryManager.scala +++ b/src/main/scala/io/iohk/ethereum/network/discovery/PeerDiscoveryManager.scala @@ -1,20 +1,31 @@ package io.iohk.ethereum.network.discovery -import akka.actor.{Actor, ActorLogging, ActorRef, Props} +import akka.actor.Actor +import akka.actor.ActorLogging +import akka.actor.ActorRef +import akka.actor.Props import akka.pattern.pipe import akka.util.ByteString + import cats.effect.Resource -import io.iohk.ethereum.db.storage.KnownNodesStorage -import io.iohk.scalanet.discovery.ethereum.v4 -import io.iohk.scalanet.discovery.ethereum.{Node => ENode} -import io.iohk.scalanet.discovery.crypto.PublicKey + +import monix.catnap.ConsumerF import monix.eval.Task -import monix.execution.{Scheduler, BufferCapacity} +import monix.execution.BufferCapacity +import monix.execution.Scheduler import monix.tail.Iterant -import monix.catnap.ConsumerF -import scala.util.{Failure, Success, Random} + +import scala.util.Failure +import scala.util.Random +import scala.util.Success + +import io.iohk.scalanet.discovery.crypto.PublicKey +import io.iohk.scalanet.discovery.ethereum.v4 +import io.iohk.scalanet.discovery.ethereum.{Node => ENode} import scodec.bits.BitVector +import io.iohk.ethereum.db.storage.KnownNodesStorage + class PeerDiscoveryManager( localNodeId: ByteString, discoveryConfig: DiscoveryConfig, @@ -29,7 +40,7 @@ class PeerDiscoveryManager( // Derive a random nodes iterator on top of the service so the node can quickly ramp up its peers // while it has demand to connect to more, rather than wait on the periodic lookups performed in // the background by the DiscoveryService. - val discoveryResources = for { + val discoveryResources: Resource[Task, (v4.DiscoveryService, Iterant.Consumer[Task, Node])] = for { service <- discoveryServiceResource // Create an Iterant (like a pull-based Observable) that repeatedly performs a random lookup @@ -86,7 +97,7 @@ class PeerDiscoveryManager( } // The service hasn't been started yet, so it just serves the static known nodes. - def init: Receive = handleNodeInfoRequests(None) orElse { + def init: Receive = handleNodeInfoRequests(None).orElse { case Start => if (discoveryConfig.discoveryEnabled) { log.info("Starting peer discovery...") @@ -101,7 +112,7 @@ class PeerDiscoveryManager( // Waiting for the DiscoveryService to be initialized. Keep serving known nodes. // This would not be needed if Actors were treated as resources themselves. - def starting: Receive = handleNodeInfoRequests(None) orElse { + def starting: Receive = handleNodeInfoRequests(None).orElse { case Start => case Stop => @@ -122,7 +133,7 @@ class PeerDiscoveryManager( // DiscoveryService started, we can ask it for nodes now. def started(discovery: Discovery, release: Task[Unit]): Receive = - handleNodeInfoRequests(Some(discovery)) orElse { + handleNodeInfoRequests(Some(discovery)).orElse { case Start => case Stop => @@ -133,7 +144,7 @@ class PeerDiscoveryManager( // Waiting for the DiscoveryService to be initialized OR we received a stop request // before it even got a chance to start, so we'll stop it immediately. - def stopping: Receive = handleNodeInfoRequests(None) orElse { + def stopping: Receive = handleNodeInfoRequests(None).orElse { case Start | Stop => case StartAttempt(result) => @@ -157,7 +168,7 @@ class PeerDiscoveryManager( context.become(init) } - def startDiscoveryService(): Unit = { + def startDiscoveryService(): Unit = discoveryResources.allocated.runToFuture .onComplete { case Failure(ex) => @@ -165,16 +176,14 @@ class PeerDiscoveryManager( case Success(result) => self ! StartAttempt(Right(result)) } - } - def stopDiscoveryService(release: Task[Unit]): Unit = { + def stopDiscoveryService(release: Task[Unit]): Unit = release.runToFuture.onComplete { case Failure(ex) => self ! StopAttempt(Left(ex)) case Success(result) => self ! StopAttempt(Right(result)) } - } def sendDiscoveredNodesInfo( maybeDiscoveryService: Option[v4.DiscoveryService], diff --git a/src/main/scala/io/iohk/ethereum/network/discovery/Secp256k1SigAlg.scala b/src/main/scala/io/iohk/ethereum/network/discovery/Secp256k1SigAlg.scala index ff4a7e0073..478cb83640 100644 --- a/src/main/scala/io/iohk/ethereum/network/discovery/Secp256k1SigAlg.scala +++ b/src/main/scala/io/iohk/ethereum/network/discovery/Secp256k1SigAlg.scala @@ -1,16 +1,22 @@ package io.iohk.ethereum.network.discovery import akka.util.ByteString -import io.iohk.ethereum.crypto -import io.iohk.ethereum.crypto.ECDSASignature -import io.iohk.ethereum.security.SecureRandomBuilder -import io.iohk.scalanet.discovery.crypto.{PrivateKey, PublicKey, SigAlg, Signature} + +import scala.collection.concurrent.TrieMap + +import io.iohk.scalanet.discovery.crypto.PrivateKey +import io.iohk.scalanet.discovery.crypto.PublicKey +import io.iohk.scalanet.discovery.crypto.SigAlg +import io.iohk.scalanet.discovery.crypto.Signature import org.bouncycastle.crypto.AsymmetricCipherKeyPair import org.bouncycastle.crypto.params.ECPublicKeyParameters +import scodec.Attempt +import scodec.Err import scodec.bits.BitVector -import scodec.{Attempt, Err} -import scala.collection.concurrent.TrieMap +import io.iohk.ethereum.crypto +import io.iohk.ethereum.crypto.ECDSASignature +import io.iohk.ethereum.security.SecureRandomBuilder class Secp256k1SigAlg extends SigAlg with SecureRandomBuilder { // We'll be using the same private key over and over to sign messages. @@ -55,7 +61,7 @@ class Secp256k1SigAlg extends SigAlg with SecureRandomBuilder { // ENR wants the signature without recovery ID, just 64 bytes. // The Packet on the other hand has the full 65 bytes. - override def removeRecoveryId(signature: Signature): Signature = { + override def removeRecoveryId(signature: Signature): Signature = signature.size / 8 match { case SignatureBytesSize => Signature(signature.dropRight(8)) @@ -64,9 +70,8 @@ class Secp256k1SigAlg extends SigAlg with SecureRandomBuilder { case other => throw new IllegalArgumentException(s"Unexpected signature size: $other bytes") } - } - override def compressPublicKey(publicKey: PublicKey): PublicKey = { + override def compressPublicKey(publicKey: PublicKey): PublicKey = publicKey.size / 8 match { case PublicKeyBytesSize => // This is a public key without the prefix, it consists of an x and y bigint. @@ -84,13 +89,12 @@ class Secp256k1SigAlg extends SigAlg with SecureRandomBuilder { case other => throw new IllegalArgumentException(s"Unexpected uncompressed public key size: $other bytes") } - } // The public key points lie on the curve `y^2 = x^3 + 7`. // In the compressed form we have x and a prefix telling us whether y is even or odd. // https://bitcoin.stackexchange.com/questions/86234/how-to-uncompress-a-public-key // https://bitcoin.stackexchange.com/questions/44024/get-uncompressed-public-key-from-compressed-form - def decompressPublicKey(publicKey: PublicKey): PublicKey = { + def decompressPublicKey(publicKey: PublicKey): PublicKey = publicKey.size / 8 match { case PublicKeyBytesSize => publicKey @@ -104,7 +108,6 @@ class Secp256k1SigAlg extends SigAlg with SecureRandomBuilder { case other => throw new IllegalArgumentException(s"Unexpected compressed public key size: $other bytes") } - } override def verify(publicKey: PublicKey, signature: Signature, data: BitVector): Boolean = { val message = crypto.kec256(data.toByteArray) @@ -160,7 +163,7 @@ class Secp256k1SigAlg extends SigAlg with SecureRandomBuilder { } // Based on whether we have the recovery ID in the signature we may have to try 1 or 2 signatures. - private def toECDSASignatures(signature: Signature): Iterable[ECDSASignature] = { + private def toECDSASignatures(signature: Signature): Iterable[ECDSASignature] = signature.size / 8 match { case SignatureBytesSize => val signatureBytes = signature.toByteArray @@ -177,10 +180,9 @@ class Secp256k1SigAlg extends SigAlg with SecureRandomBuilder { case other => throw new IllegalArgumentException(s"Unexpected signature size: $other bytes") } - } private def toECDSASignature(signatureBytes: Array[Byte]): ECDSASignature = - ECDSASignature.fromBytes(ByteString(signatureBytes)) getOrElse { + ECDSASignature.fromBytes(ByteString(signatureBytes)).getOrElse { throw new IllegalArgumentException(s"Could not convert to ECDSA signature.") } } diff --git a/src/main/scala/io/iohk/ethereum/network/discovery/codecs/RLPCodecs.scala b/src/main/scala/io/iohk/ethereum/network/discovery/codecs/RLPCodecs.scala index ed8c7babb3..2467244173 100644 --- a/src/main/scala/io/iohk/ethereum/network/discovery/codecs/RLPCodecs.scala +++ b/src/main/scala/io/iohk/ethereum/network/discovery/codecs/RLPCodecs.scala @@ -1,20 +1,31 @@ package io.iohk.ethereum.network.discovery.codecs -import io.iohk.scalanet.discovery.crypto.{PublicKey, Signature} -import io.iohk.scalanet.discovery.ethereum.{Node, EthereumNodeRecord} +import java.net.InetAddress + +import scala.util.Try + +import io.iohk.scalanet.discovery.crypto.PublicKey +import io.iohk.scalanet.discovery.crypto.Signature +import io.iohk.scalanet.discovery.ethereum.EthereumNodeRecord +import io.iohk.scalanet.discovery.ethereum.Node import io.iohk.scalanet.discovery.ethereum.v4.Payload import io.iohk.scalanet.discovery.hash.Hash +import scodec.Attempt +import scodec.Codec +import scodec.DecodeResult +import scodec.Err +import scodec.bits.BitVector +import scodec.bits.ByteVector + import io.iohk.ethereum.rlp -import io.iohk.ethereum.rlp.{RLPCodec, RLPList, RLPEncoder} +import io.iohk.ethereum.rlp.RLPCodec import io.iohk.ethereum.rlp.RLPCodec.Ops -import io.iohk.ethereum.rlp.RLPImplicits._ +import io.iohk.ethereum.rlp.RLPEncodeable +import io.iohk.ethereum.rlp.RLPEncoder import io.iohk.ethereum.rlp.RLPImplicitConversions.toEncodeable import io.iohk.ethereum.rlp.RLPImplicitDerivations._ -import scodec.{Codec, Attempt, Err, DecodeResult} -import scodec.bits.{BitVector, ByteVector} -import java.net.InetAddress -import scala.util.Try -import io.iohk.ethereum.rlp.RLPEncodeable +import io.iohk.ethereum.rlp.RLPImplicits._ +import io.iohk.ethereum.rlp.RLPList /** RLP codecs based on https://github.com/ethereum/devp2p/blob/master/discv4.md */ object RLPCodecs extends ContentCodecs with PayloadCodecs { @@ -131,7 +142,7 @@ trait ContentCodecs { trait PayloadCodecs { self: ContentCodecs => - private implicit val payloadDerivationPolicy = + implicit val payloadDerivationPolicy: DerivationPolicy = DerivationPolicy.default.copy(omitTrailingOptionals = true) implicit val pingRLPCodec: RLPCodec[Payload.Ping] = @@ -166,17 +177,17 @@ trait PayloadCodecs { self: ContentCodecs => (payload: Payload) => { val (packetType, packetData) = payload match { - case x: Payload.Ping => PacketType.Ping -> rlp.encode(x) - case x: Payload.Pong => PacketType.Pong -> rlp.encode(x) - case x: Payload.FindNode => PacketType.FindNode -> rlp.encode(x) - case x: Payload.Neighbors => PacketType.Neighbors -> rlp.encode(x) - case x: Payload.ENRRequest => PacketType.ENRRequest -> rlp.encode(x) + case x: Payload.Ping => PacketType.Ping -> rlp.encode(x) + case x: Payload.Pong => PacketType.Pong -> rlp.encode(x) + case x: Payload.FindNode => PacketType.FindNode -> rlp.encode(x) + case x: Payload.Neighbors => PacketType.Neighbors -> rlp.encode(x) + case x: Payload.ENRRequest => PacketType.ENRRequest -> rlp.encode(x) case x: Payload.ENRResponse => PacketType.ENRResponse -> rlp.encode(x) } Attempt.successful(BitVector(packetType.toByte +: packetData)) }, - (bits: BitVector) => { + (bits: BitVector) => bits.consumeThen(8)( err => Attempt.failure(Err(err)), (head, tail) => { @@ -185,19 +196,18 @@ trait PayloadCodecs { self: ContentCodecs => val tryPayload: Try[Payload] = Try { packetType match { - case PacketType.Ping => rlp.decode[Payload.Ping](packetData) - case PacketType.Pong => rlp.decode[Payload.Pong](packetData) - case PacketType.FindNode => rlp.decode[Payload.FindNode](packetData) - case PacketType.Neighbors => rlp.decode[Payload.Neighbors](packetData) - case PacketType.ENRRequest => rlp.decode[Payload.ENRRequest](packetData) + case PacketType.Ping => rlp.decode[Payload.Ping](packetData) + case PacketType.Pong => rlp.decode[Payload.Pong](packetData) + case PacketType.FindNode => rlp.decode[Payload.FindNode](packetData) + case PacketType.Neighbors => rlp.decode[Payload.Neighbors](packetData) + case PacketType.ENRRequest => rlp.decode[Payload.ENRRequest](packetData) case PacketType.ENRResponse => rlp.decode[Payload.ENRResponse](packetData) - case other => throw new RuntimeException(s"Unknown packet type: ${other}") + case other => throw new RuntimeException(s"Unknown packet type: ${other}") } } Attempt.fromTry(tryPayload.map(DecodeResult(_, BitVector.empty))) } ) - } ) } diff --git a/src/main/scala/io/iohk/ethereum/network/handshaker/EtcForkBlockExchangeState.scala b/src/main/scala/io/iohk/ethereum/network/handshaker/EtcForkBlockExchangeState.scala index d5627d65d6..7634d0df09 100644 --- a/src/main/scala/io/iohk/ethereum/network/handshaker/EtcForkBlockExchangeState.scala +++ b/src/main/scala/io/iohk/ethereum/network/handshaker/EtcForkBlockExchangeState.scala @@ -1,11 +1,14 @@ package io.iohk.ethereum.network.handshaker -import io.iohk.ethereum.network.EtcPeerManagerActor.{PeerInfo, RemoteStatus} +import io.iohk.ethereum.network.EtcPeerManagerActor.PeerInfo +import io.iohk.ethereum.network.EtcPeerManagerActor.RemoteStatus import io.iohk.ethereum.network.ForkResolver import io.iohk.ethereum.network.handshaker.Handshaker.NextMessage -import io.iohk.ethereum.network.p2p.messages.ETH62.{BlockHeaders, GetBlockHeaders} +import io.iohk.ethereum.network.p2p.Message +import io.iohk.ethereum.network.p2p.MessageSerializable +import io.iohk.ethereum.network.p2p.messages.ETH62.BlockHeaders +import io.iohk.ethereum.network.p2p.messages.ETH62.GetBlockHeaders import io.iohk.ethereum.network.p2p.messages.WireProtocol.Disconnect -import io.iohk.ethereum.network.p2p.{Message, MessageSerializable} import io.iohk.ethereum.utils.Logger case class EtcForkBlockExchangeState( @@ -54,7 +57,7 @@ case class EtcForkBlockExchangeState( log.debug("Received request for fork block") blockchainReader.getBlockHeaderByNumber(number) match { case Some(header) => Some(BlockHeaders(Seq(header))) - case None => Some(BlockHeaders(Nil)) + case None => Some(BlockHeaders(Nil)) } case _ => None diff --git a/src/main/scala/io/iohk/ethereum/network/handshaker/EtcHandshaker.scala b/src/main/scala/io/iohk/ethereum/network/handshaker/EtcHandshaker.scala index 300f1b7600..7b6236d8c0 100644 --- a/src/main/scala/io/iohk/ethereum/network/handshaker/EtcHandshaker.scala +++ b/src/main/scala/io/iohk/ethereum/network/handshaker/EtcHandshaker.scala @@ -1,8 +1,10 @@ package io.iohk.ethereum.network.handshaker import java.util.concurrent.atomic.AtomicReference + import io.iohk.ethereum.db.storage.AppStateStorage -import io.iohk.ethereum.domain.{Blockchain, BlockchainReader} +import io.iohk.ethereum.domain.Blockchain +import io.iohk.ethereum.domain.BlockchainReader import io.iohk.ethereum.network.EtcPeerManagerActor.PeerInfo import io.iohk.ethereum.network.ForkResolver import io.iohk.ethereum.network.PeerManagerActor.PeerConfiguration @@ -14,9 +16,8 @@ case class EtcHandshaker private ( handshakerConfiguration: EtcHandshakerConfiguration ) extends Handshaker[PeerInfo] { - protected def copy(handshakerState: HandshakerState[PeerInfo]): Handshaker[PeerInfo] = { + protected def copy(handshakerState: HandshakerState[PeerInfo]): Handshaker[PeerInfo] = EtcHandshaker(handshakerState, handshakerConfiguration) - } } diff --git a/src/main/scala/io/iohk/ethereum/network/handshaker/EtcHelloExchangeState.scala b/src/main/scala/io/iohk/ethereum/network/handshaker/EtcHelloExchangeState.scala index 77ed5d5a3c..cc5ba6252e 100644 --- a/src/main/scala/io/iohk/ethereum/network/handshaker/EtcHelloExchangeState.scala +++ b/src/main/scala/io/iohk/ethereum/network/handshaker/EtcHelloExchangeState.scala @@ -1,14 +1,17 @@ package io.iohk.ethereum.network.handshaker import akka.util.ByteString + import io.iohk.ethereum.network.EtcPeerManagerActor.PeerInfo import io.iohk.ethereum.network.handshaker.Handshaker.NextMessage import io.iohk.ethereum.network.p2p.Message -import io.iohk.ethereum.network.p2p.messages.Capability.Capabilities -import io.iohk.ethereum.network.p2p.messages.Capability.Capabilities._ -import io.iohk.ethereum.network.p2p.messages.{Capability, ProtocolVersions} -import io.iohk.ethereum.network.p2p.messages.WireProtocol.{Disconnect, Hello} -import io.iohk.ethereum.utils.{Config, Logger, ServerStatus} +import io.iohk.ethereum.network.p2p.messages.Capability +import io.iohk.ethereum.network.p2p.messages.ProtocolVersions +import io.iohk.ethereum.network.p2p.messages.WireProtocol.Disconnect +import io.iohk.ethereum.network.p2p.messages.WireProtocol.Hello +import io.iohk.ethereum.utils.Config +import io.iohk.ethereum.utils.Logger +import io.iohk.ethereum.utils.ServerStatus case class EtcHelloExchangeState(handshakerConfiguration: EtcHandshakerConfiguration) extends InProgressState[PeerInfo] @@ -49,7 +52,7 @@ case class EtcHelloExchangeState(handshakerConfiguration: EtcHandshakerConfigura val nodeStatus = nodeStatusHolder.get() val listenPort = nodeStatus.serverStatus match { case ServerStatus.Listening(address) => address.getPort - case ServerStatus.NotListening => 0 + case ServerStatus.NotListening => 0 } Hello( p2pVersion = EtcHelloExchangeState.P2pVersion, diff --git a/src/main/scala/io/iohk/ethereum/network/handshaker/EtcNodeStatus63ExchangeState.scala b/src/main/scala/io/iohk/ethereum/network/handshaker/EtcNodeStatus63ExchangeState.scala index 010554ee60..50791fbf6a 100644 --- a/src/main/scala/io/iohk/ethereum/network/handshaker/EtcNodeStatus63ExchangeState.scala +++ b/src/main/scala/io/iohk/ethereum/network/handshaker/EtcNodeStatus63ExchangeState.scala @@ -1,8 +1,11 @@ package io.iohk.ethereum.network.handshaker -import io.iohk.ethereum.network.EtcPeerManagerActor.{PeerInfo, RemoteStatus} -import io.iohk.ethereum.network.p2p.messages.{BaseETH6XMessages, ProtocolVersions} -import io.iohk.ethereum.network.p2p.{Message, MessageSerializable} +import io.iohk.ethereum.network.EtcPeerManagerActor.PeerInfo +import io.iohk.ethereum.network.EtcPeerManagerActor.RemoteStatus +import io.iohk.ethereum.network.p2p.Message +import io.iohk.ethereum.network.p2p.MessageSerializable +import io.iohk.ethereum.network.p2p.messages.BaseETH6XMessages +import io.iohk.ethereum.network.p2p.messages.ProtocolVersions case class EtcNodeStatus63ExchangeState( handshakerConfiguration: EtcHandshakerConfiguration diff --git a/src/main/scala/io/iohk/ethereum/network/handshaker/EtcNodeStatus64ExchangeState.scala b/src/main/scala/io/iohk/ethereum/network/handshaker/EtcNodeStatus64ExchangeState.scala index 4b70cd389b..208b41758f 100644 --- a/src/main/scala/io/iohk/ethereum/network/handshaker/EtcNodeStatus64ExchangeState.scala +++ b/src/main/scala/io/iohk/ethereum/network/handshaker/EtcNodeStatus64ExchangeState.scala @@ -1,8 +1,11 @@ package io.iohk.ethereum.network.handshaker -import io.iohk.ethereum.network.EtcPeerManagerActor.{PeerInfo, RemoteStatus} -import io.iohk.ethereum.network.p2p.messages.{ETC64, ProtocolVersions} -import io.iohk.ethereum.network.p2p.{Message, MessageSerializable} +import io.iohk.ethereum.network.EtcPeerManagerActor.PeerInfo +import io.iohk.ethereum.network.EtcPeerManagerActor.RemoteStatus +import io.iohk.ethereum.network.p2p.Message +import io.iohk.ethereum.network.p2p.MessageSerializable +import io.iohk.ethereum.network.p2p.messages.ETC64 +import io.iohk.ethereum.network.p2p.messages.ProtocolVersions case class EtcNodeStatus64ExchangeState( handshakerConfiguration: EtcHandshakerConfiguration diff --git a/src/main/scala/io/iohk/ethereum/network/handshaker/EtcNodeStatusExchangeState.scala b/src/main/scala/io/iohk/ethereum/network/handshaker/EtcNodeStatusExchangeState.scala index 915eacd6a2..4ab53fe91d 100644 --- a/src/main/scala/io/iohk/ethereum/network/handshaker/EtcNodeStatusExchangeState.scala +++ b/src/main/scala/io/iohk/ethereum/network/handshaker/EtcNodeStatusExchangeState.scala @@ -1,10 +1,13 @@ package io.iohk.ethereum.network.handshaker -import io.iohk.ethereum.network.EtcPeerManagerActor.{PeerInfo, RemoteStatus} +import io.iohk.ethereum.domain.BlockHeader +import io.iohk.ethereum.network.EtcPeerManagerActor.PeerInfo +import io.iohk.ethereum.network.EtcPeerManagerActor.RemoteStatus import io.iohk.ethereum.network.handshaker.Handshaker.NextMessage +import io.iohk.ethereum.network.p2p.Message +import io.iohk.ethereum.network.p2p.MessageSerializable import io.iohk.ethereum.network.p2p.messages.WireProtocol.Disconnect import io.iohk.ethereum.network.p2p.messages.WireProtocol.Disconnect.Reasons -import io.iohk.ethereum.network.p2p.{Message, MessageSerializable} import io.iohk.ethereum.utils.Logger trait EtcNodeStatusExchangeState[T <: Message] extends InProgressState[PeerInfo] with Logger { @@ -41,7 +44,7 @@ trait EtcNodeStatusExchangeState[T <: Message] extends InProgressState[PeerInfo] DisconnectedState(Reasons.DisconnectRequested) } - protected def getBestBlockHeader() = { + protected def getBestBlockHeader(): BlockHeader = { val bestBlockNumber = blockchain.getBestBlockNumber() blockchainReader.getBlockHeaderByNumber(bestBlockNumber).getOrElse(blockchain.genesisHeader) } diff --git a/src/main/scala/io/iohk/ethereum/network/handshaker/Handshaker.scala b/src/main/scala/io/iohk/ethereum/network/handshaker/Handshaker.scala index 17e9626937..3618d34745 100644 --- a/src/main/scala/io/iohk/ethereum/network/handshaker/Handshaker.scala +++ b/src/main/scala/io/iohk/ethereum/network/handshaker/Handshaker.scala @@ -1,17 +1,20 @@ package io.iohk.ethereum.network.handshaker -import io.iohk.ethereum.network.handshaker.Handshaker.HandshakeComplete.{HandshakeFailure, HandshakeSuccess} -import io.iohk.ethereum.network.handshaker.Handshaker.{HandshakeComplete, HandshakeResult, NextMessage} -import io.iohk.ethereum.network.p2p.{Message, MessageSerializable} - import scala.concurrent.duration.FiniteDuration +import io.iohk.ethereum.network.handshaker.Handshaker.HandshakeComplete +import io.iohk.ethereum.network.handshaker.Handshaker.HandshakeComplete.HandshakeFailure +import io.iohk.ethereum.network.handshaker.Handshaker.HandshakeComplete.HandshakeSuccess +import io.iohk.ethereum.network.handshaker.Handshaker.HandshakeResult +import io.iohk.ethereum.network.handshaker.Handshaker.NextMessage +import io.iohk.ethereum.network.p2p.Message +import io.iohk.ethereum.network.p2p.MessageSerializable + trait Handshaker[T <: HandshakeResult] { protected val handshakerState: HandshakerState[T] - /** - * Obtains the next message to be sent if the handshaking is in progress, or the result of the handshake + /** Obtains the next message to be sent if the handshaking is in progress, or the result of the handshake * * @return next message to be sent or the result of the handshake */ @@ -24,8 +27,7 @@ trait Handshaker[T <: HandshakeResult] { Left(HandshakeFailure(reason)) } - /** - * Processes a received message and obtains a new Handshaker if the handshaker handles the received message + /** Processes a received message and obtains a new Handshaker if the handshaker handles the received message * * @param receivedMessage, message received and to be processed * @return handshaker after the message was processed or None if it doesn't change @@ -38,8 +40,7 @@ trait Handshaker[T <: HandshakeResult] { case _ => None } - /** - * Obtains the response to a message if there should be one. + /** Obtains the response to a message if there should be one. * * @param receivedMessage, message received and to be optionally responded * @return message to be sent as a response to the received one, if there should be any @@ -50,8 +51,7 @@ trait Handshaker[T <: HandshakeResult] { case _ => None } - /** - * Processes a timeout to the latest message sent and obtains the new Handshaker + /** Processes a timeout to the latest message sent and obtains the new Handshaker * * @return handshaker after the timeout was processed */ @@ -62,8 +62,7 @@ trait Handshaker[T <: HandshakeResult] { case _ => this } - /** - * Obtains a Handshaker with the passed state + /** Obtains a Handshaker with the passed state * * @param handshakerState, for the new handshaker * @return handshaker with the passed state diff --git a/src/main/scala/io/iohk/ethereum/network/handshaker/HandshakerState.scala b/src/main/scala/io/iohk/ethereum/network/handshaker/HandshakerState.scala index b3939b9482..4b2484a3b9 100644 --- a/src/main/scala/io/iohk/ethereum/network/handshaker/HandshakerState.scala +++ b/src/main/scala/io/iohk/ethereum/network/handshaker/HandshakerState.scala @@ -1,21 +1,21 @@ package io.iohk.ethereum.network.handshaker -import io.iohk.ethereum.network.handshaker.Handshaker.{HandshakeResult, NextMessage} -import io.iohk.ethereum.network.p2p.{Message, MessageSerializable} +import io.iohk.ethereum.network.handshaker.Handshaker.HandshakeResult +import io.iohk.ethereum.network.handshaker.Handshaker.NextMessage +import io.iohk.ethereum.network.p2p.Message +import io.iohk.ethereum.network.p2p.MessageSerializable sealed trait HandshakerState[T <: HandshakeResult] trait InProgressState[T <: HandshakeResult] extends HandshakerState[T] { - /** - * Obtains the next message to be sent + /** Obtains the next message to be sent * * @return message to be sent with the timeout for awaiting its response */ def nextMessage: NextMessage - /** - * Processes a message and obtains the new state of the handshake after processing it, + /** Processes a message and obtains the new state of the handshake after processing it, * if the current state handles the received message * * @param receivedMessage, message received and to be processed by the current state @@ -23,8 +23,7 @@ trait InProgressState[T <: HandshakeResult] extends HandshakerState[T] { */ def applyMessage(receivedMessage: Message): Option[HandshakerState[T]] = applyResponseMessage.lift(receivedMessage) - /** - * Obtains the response to a message if there should be one. + /** Obtains the response to a message if there should be one. * This function should be overridden in the handshake states where a response is given. * * @param receivedMessage, message received and to be optionally responded @@ -32,15 +31,13 @@ trait InProgressState[T <: HandshakeResult] extends HandshakerState[T] { */ def respondToRequest(receivedMessage: Message): Option[MessageSerializable] = None - /** - * Processes a timeout to the sent message and obtains the new state of the handshake after processing it + /** Processes a timeout to the sent message and obtains the new state of the handshake after processing it * * @return new state after the timeout was processed */ def processTimeout: HandshakerState[T] - /** - * Function that is only defined at the messages handled by the current state, returns the new state after processing them. + /** Function that is only defined at the messages handled by the current state, returns the new state after processing them. * If defined, it processes a message and obtains a new state of the handshake */ protected def applyResponseMessage: PartialFunction[Message, HandshakerState[T]] diff --git a/src/main/scala/io/iohk/ethereum/network/p2p/Message.scala b/src/main/scala/io/iohk/ethereum/network/p2p/Message.scala index 33efbae442..2727d32b72 100644 --- a/src/main/scala/io/iohk/ethereum/network/p2p/Message.scala +++ b/src/main/scala/io/iohk/ethereum/network/p2p/Message.scala @@ -1,7 +1,6 @@ package io.iohk.ethereum.network.p2p import akka.util.ByteString -import io.iohk.ethereum.network.p2p.messages.Capability import scala.util.Try diff --git a/src/main/scala/io/iohk/ethereum/network/p2p/MessageDecoders.scala b/src/main/scala/io/iohk/ethereum/network/p2p/MessageDecoders.scala index 763c68c0ff..1025c308cf 100644 --- a/src/main/scala/io/iohk/ethereum/network/p2p/MessageDecoders.scala +++ b/src/main/scala/io/iohk/ethereum/network/p2p/MessageDecoders.scala @@ -1,7 +1,8 @@ package io.iohk.ethereum.network.p2p -import io.iohk.ethereum.network.p2p.messages.{Capability, Codes} import io.iohk.ethereum.network.p2p.messages.BaseETH6XMessages.SignedTransactions._ +import io.iohk.ethereum.network.p2p.messages.Capability +import io.iohk.ethereum.network.p2p.messages.Codes import io.iohk.ethereum.network.p2p.messages.ETH61.BlockHashesFromNumber._ import io.iohk.ethereum.network.p2p.messages.ETH62.BlockBodies._ import io.iohk.ethereum.network.p2p.messages.ETH62.BlockHeaders._ @@ -12,7 +13,6 @@ import io.iohk.ethereum.network.p2p.messages.ETH63.GetNodeData._ import io.iohk.ethereum.network.p2p.messages.ETH63.GetReceipts._ import io.iohk.ethereum.network.p2p.messages.ETH63.NodeData._ import io.iohk.ethereum.network.p2p.messages.ETH63.Receipts._ -import io.iohk.ethereum.network.p2p.messages.ProtocolVersions._ import io.iohk.ethereum.network.p2p.messages.WireProtocol.Disconnect._ import io.iohk.ethereum.network.p2p.messages.WireProtocol.Hello._ import io.iohk.ethereum.network.p2p.messages.WireProtocol.Ping._ @@ -24,10 +24,10 @@ object NetworkMessageDecoder extends MessageDecoder { override def fromBytes(msgCode: Int, payload: Array[Byte]): Message = msgCode match { case Disconnect.code => payload.toDisconnect - case Ping.code => payload.toPing - case Pong.code => payload.toPong - case Hello.code => payload.toHello - case _ => throw new RuntimeException(s"Unknown message type: $msgCode") + case Ping.code => payload.toPing + case Pong.code => payload.toPong + case Hello.code => payload.toHello + case _ => throw new RuntimeException(s"Unknown message type: $msgCode") } } @@ -36,58 +36,55 @@ object ETC64MessageDecoder extends MessageDecoder { import io.iohk.ethereum.network.p2p.messages.ETC64.Status._ import io.iohk.ethereum.network.p2p.messages.ETC64.NewBlock._ - def fromBytes(msgCode: Int, payload: Array[Byte]): Message = { + def fromBytes(msgCode: Int, payload: Array[Byte]): Message = msgCode match { - case Codes.StatusCode => payload.toStatus - case Codes.NewBlockCode => payload.toNewBlock - case Codes.GetNodeDataCode => payload.toGetNodeData - case Codes.NodeDataCode => payload.toNodeData - case Codes.GetReceiptsCode => payload.toGetReceipts - case Codes.ReceiptsCode => payload.toReceipts - case Codes.NewBlockHashesCode => payload.toNewBlockHashes - case Codes.GetBlockHeadersCode => payload.toGetBlockHeaders - case Codes.BlockHeadersCode => payload.toBlockHeaders - case Codes.GetBlockBodiesCode => payload.toGetBlockBodies - case Codes.BlockBodiesCode => payload.toBlockBodies + case Codes.StatusCode => payload.toStatus + case Codes.NewBlockCode => payload.toNewBlock + case Codes.GetNodeDataCode => payload.toGetNodeData + case Codes.NodeDataCode => payload.toNodeData + case Codes.GetReceiptsCode => payload.toGetReceipts + case Codes.ReceiptsCode => payload.toReceipts + case Codes.NewBlockHashesCode => payload.toNewBlockHashes + case Codes.GetBlockHeadersCode => payload.toGetBlockHeaders + case Codes.BlockHeadersCode => payload.toBlockHeaders + case Codes.GetBlockBodiesCode => payload.toGetBlockBodies + case Codes.BlockBodiesCode => payload.toBlockBodies case Codes.BlockHashesFromNumberCode => payload.toBlockHashesFromNumber - case Codes.SignedTransactionsCode => payload.toSignedTransactions - case _ => throw new RuntimeException(s"Unknown message type: $msgCode") + case Codes.SignedTransactionsCode => payload.toSignedTransactions + case _ => throw new RuntimeException(s"Unknown message type: $msgCode") } - } } object ETH63MessageDecoder extends MessageDecoder { import io.iohk.ethereum.network.p2p.messages.BaseETH6XMessages.Status._ import io.iohk.ethereum.network.p2p.messages.BaseETH6XMessages.NewBlock._ - def fromBytes(msgCode: Int, payload: Array[Byte]): Message = { + def fromBytes(msgCode: Int, payload: Array[Byte]): Message = msgCode match { - case Codes.GetNodeDataCode => payload.toGetNodeData - case Codes.NodeDataCode => payload.toNodeData - case Codes.GetReceiptsCode => payload.toGetReceipts - case Codes.ReceiptsCode => payload.toReceipts - case Codes.NewBlockHashesCode => payload.toNewBlockHashes - case Codes.GetBlockHeadersCode => payload.toGetBlockHeaders - case Codes.BlockHeadersCode => payload.toBlockHeaders - case Codes.GetBlockBodiesCode => payload.toGetBlockBodies - case Codes.BlockBodiesCode => payload.toBlockBodies + case Codes.GetNodeDataCode => payload.toGetNodeData + case Codes.NodeDataCode => payload.toNodeData + case Codes.GetReceiptsCode => payload.toGetReceipts + case Codes.ReceiptsCode => payload.toReceipts + case Codes.NewBlockHashesCode => payload.toNewBlockHashes + case Codes.GetBlockHeadersCode => payload.toGetBlockHeaders + case Codes.BlockHeadersCode => payload.toBlockHeaders + case Codes.GetBlockBodiesCode => payload.toGetBlockBodies + case Codes.BlockBodiesCode => payload.toBlockBodies case Codes.BlockHashesFromNumberCode => payload.toBlockHashesFromNumber - case Codes.StatusCode => payload.toStatus - case Codes.NewBlockCode => payload.toNewBlock - case Codes.SignedTransactionsCode => payload.toSignedTransactions - case _ => throw new RuntimeException(s"Unknown message type: $msgCode") + case Codes.StatusCode => payload.toStatus + case Codes.NewBlockCode => payload.toNewBlock + case Codes.SignedTransactionsCode => payload.toSignedTransactions + case _ => throw new RuntimeException(s"Unknown message type: $msgCode") } - } } // scalastyle:off object EthereumMessageDecoder { type Decoder = (Int, Array[Byte]) => Message - def ethMessageDecoder(protocolVersion: Capability): MessageDecoder = { + def ethMessageDecoder(protocolVersion: Capability): MessageDecoder = protocolVersion match { case Capability.Capabilities.Etc64Capability => ETC64MessageDecoder.fromBytes case Capability.Capabilities.Eth63Capability => ETH63MessageDecoder.fromBytes - case _ => throw new RuntimeException(s"Unsupported Protocol Version $protocolVersion") + case _ => throw new RuntimeException(s"Unsupported Protocol Version $protocolVersion") } - } } diff --git a/src/main/scala/io/iohk/ethereum/network/p2p/MessageSerializableImplicit.scala b/src/main/scala/io/iohk/ethereum/network/p2p/MessageSerializableImplicit.scala index 3d720cac27..22349cf624 100644 --- a/src/main/scala/io/iohk/ethereum/network/p2p/MessageSerializableImplicit.scala +++ b/src/main/scala/io/iohk/ethereum/network/p2p/MessageSerializableImplicit.scala @@ -1,14 +1,13 @@ package io.iohk.ethereum.network.p2p -/** - * Helper class +/** Helper class */ //FIXME: msg is redundant since `MessageSerializable` already exposes `underlyingMessage` abstract class MessageSerializableImplicit[T <: Message](val msg: T) extends MessageSerializable { override def equals(that: Any): Boolean = that match { - case that: MessageSerializableImplicit[T] => that.msg equals msg - case _ => false + case that: MessageSerializableImplicit[T] => that.msg.equals(msg) + case _ => false } override def hashCode(): Int = msg.hashCode() diff --git a/src/main/scala/io/iohk/ethereum/network/p2p/messages/BaseETH6XMessages.scala b/src/main/scala/io/iohk/ethereum/network/p2p/messages/BaseETH6XMessages.scala index 0d45b7d4f3..20dc6e239f 100644 --- a/src/main/scala/io/iohk/ethereum/network/p2p/messages/BaseETH6XMessages.scala +++ b/src/main/scala/io/iohk/ethereum/network/p2p/messages/BaseETH6XMessages.scala @@ -1,15 +1,18 @@ package io.iohk.ethereum.network.p2p.messages import akka.util.ByteString + +import org.bouncycastle.util.encoders.Hex + import io.iohk.ethereum.domain.BlockHeaderImplicits._ import io.iohk.ethereum.domain._ -import io.iohk.ethereum.network.p2p.{Message, MessageSerializableImplicit} +import io.iohk.ethereum.network.p2p.Message +import io.iohk.ethereum.network.p2p.MessageSerializableImplicit import io.iohk.ethereum.rlp.RLPImplicitConversions._ import io.iohk.ethereum.rlp.RLPImplicits._ import io.iohk.ethereum.rlp._ import io.iohk.ethereum.utils.ByteStringUtils.ByteStringOps import io.iohk.ethereum.utils.Config -import org.bouncycastle.util.encoders.Hex object BaseETH6XMessages { object Status { @@ -47,8 +50,7 @@ object BaseETH6XMessages { } - /** - * used by eth61, eth62, eth63 + /** used by eth61, eth62, eth63 */ case class Status( protocolVersion: Int, @@ -111,8 +113,7 @@ object BaseETH6XMessages { } } - /** - * used by eth61, eth62, eth63 + /** used by eth61, eth62, eth63 */ case class NewBlock(block: Block, totalDifficulty: BigInt) extends Message { @@ -167,7 +168,7 @@ object BaseETH6XMessages { implicit class SignedTransactionsDec(val bytes: Array[Byte]) extends AnyVal { def toSignedTransactions: SignedTransactions = rawDecode(bytes) match { case rlpList: RLPList => SignedTransactions(rlpList.items.map(_.toSignedTransaction)) - case _ => throw new RuntimeException("Cannot decode SignedTransactions") + case _ => throw new RuntimeException("Cannot decode SignedTransactions") } } diff --git a/src/main/scala/io/iohk/ethereum/network/p2p/messages/Capability.scala b/src/main/scala/io/iohk/ethereum/network/p2p/messages/Capability.scala index 96cd451ac4..394527cc8f 100644 --- a/src/main/scala/io/iohk/ethereum/network/p2p/messages/Capability.scala +++ b/src/main/scala/io/iohk/ethereum/network/p2p/messages/Capability.scala @@ -1,8 +1,12 @@ package io.iohk.ethereum.network.p2p.messages +import io.iohk.ethereum.rlp.RLPEncodeable +import io.iohk.ethereum.rlp.RLPException import io.iohk.ethereum.rlp.RLPImplicitConversions._ import io.iohk.ethereum.rlp.RLPImplicits._ -import io.iohk.ethereum.rlp.{RLPEncodeable, RLPException, RLPList, RLPSerializable, rawDecode} +import io.iohk.ethereum.rlp.RLPList +import io.iohk.ethereum.rlp.RLPSerializable +import io.iohk.ethereum.rlp.rawDecode case class Capability(name: String, version: Byte) @@ -10,7 +14,7 @@ object Capability { def negotiate(c1: List[Capability], c2: List[Capability]): Option[Capability] = c1.intersect(c2) match { case Nil => None - case l => Some(best(l)) + case l => Some(best(l)) } private val pattern = "(.*)/(\\d*)".r @@ -41,7 +45,7 @@ object Capability { implicit class CapabilityRLPEncodableDec(val rLPEncodeable: RLPEncodeable) extends AnyVal { def toCapability: Capability = rLPEncodeable match { case RLPList(name, version) => Capability(name, version) - case _ => throw new RLPException("Cannot decode Capability") + case _ => throw new RLPException("Cannot decode Capability") } } diff --git a/src/main/scala/io/iohk/ethereum/network/p2p/messages/ETC64.scala b/src/main/scala/io/iohk/ethereum/network/p2p/messages/ETC64.scala index 2cf8619f98..edd05f2fe7 100644 --- a/src/main/scala/io/iohk/ethereum/network/p2p/messages/ETC64.scala +++ b/src/main/scala/io/iohk/ethereum/network/p2p/messages/ETC64.scala @@ -1,16 +1,18 @@ package io.iohk.ethereum.network.p2p.messages import akka.util.ByteString + +import org.bouncycastle.util.encoders.Hex + import io.iohk.ethereum.domain.BlockHeaderImplicits._ import io.iohk.ethereum.domain._ -import io.iohk.ethereum.network.p2p.{Message, MessageSerializableImplicit} +import io.iohk.ethereum.network.p2p.Message +import io.iohk.ethereum.network.p2p.MessageSerializableImplicit import io.iohk.ethereum.rlp.RLPImplicitConversions._ import io.iohk.ethereum.rlp.RLPImplicits._ import io.iohk.ethereum.rlp._ -import org.bouncycastle.util.encoders.Hex -/** - * This is temporary ETC64 version, the real one will be implemented by ETCM-355 +/** This is temporary ETC64 version, the real one will be implemented by ETCM-355 * This one will be probably ETC67 in the future */ object ETC64 { diff --git a/src/main/scala/io/iohk/ethereum/network/p2p/messages/ETH61.scala b/src/main/scala/io/iohk/ethereum/network/p2p/messages/ETH61.scala index 8b8369254c..81bc81f0bb 100644 --- a/src/main/scala/io/iohk/ethereum/network/p2p/messages/ETH61.scala +++ b/src/main/scala/io/iohk/ethereum/network/p2p/messages/ETH61.scala @@ -1,11 +1,14 @@ package io.iohk.ethereum.network.p2p.messages import akka.util.ByteString -import io.iohk.ethereum.network.p2p.{Message, MessageSerializableImplicit} + +import org.bouncycastle.util.encoders.Hex + +import io.iohk.ethereum.network.p2p.Message +import io.iohk.ethereum.network.p2p.MessageSerializableImplicit import io.iohk.ethereum.rlp.RLPImplicitConversions._ import io.iohk.ethereum.rlp.RLPImplicits._ import io.iohk.ethereum.rlp._ -import org.bouncycastle.util.encoders.Hex object ETH61 { @@ -22,7 +25,7 @@ object ETH61 { implicit class NewBlockHashesDec(val bytes: Array[Byte]) extends AnyVal { def toNewBlockHashes: NewBlockHashes = rawDecode(bytes) match { case rlpList: RLPList => NewBlockHashes(rlpList.items.map(e => ByteString(e: Array[Byte]))) - case _ => throw new RuntimeException("Cannot decode NewBlockHashes") + case _ => throw new RuntimeException("Cannot decode NewBlockHashes") } } @@ -47,7 +50,7 @@ object ETH61 { implicit class BlockHashesFromNumberDec(val bytes: Array[Byte]) extends AnyVal { def toBlockHashesFromNumber: BlockHashesFromNumber = rawDecode(bytes) match { case RLPList(number, maxBlocks) => BlockHashesFromNumber(number, maxBlocks) - case _ => throw new RuntimeException("Cannot decode BlockHashesFromNumber") + case _ => throw new RuntimeException("Cannot decode BlockHashesFromNumber") } } } diff --git a/src/main/scala/io/iohk/ethereum/network/p2p/messages/ETH62.scala b/src/main/scala/io/iohk/ethereum/network/p2p/messages/ETH62.scala index 3e147d3b26..3ec23b1a85 100644 --- a/src/main/scala/io/iohk/ethereum/network/p2p/messages/ETH62.scala +++ b/src/main/scala/io/iohk/ethereum/network/p2p/messages/ETH62.scala @@ -1,14 +1,19 @@ package io.iohk.ethereum.network.p2p.messages import akka.util.ByteString -import io.iohk.ethereum.domain.{BlockHeader, BlockBody} -import io.iohk.ethereum.domain.BlockHeaderImplicits._ + +import org.bouncycastle.util.encoders.Hex + +import io.iohk.ethereum.domain.BlockBody import io.iohk.ethereum.domain.BlockBody._ -import io.iohk.ethereum.network.p2p.{Message, MessageSerializableImplicit} +import io.iohk.ethereum.domain.BlockHeader +import io.iohk.ethereum.domain.BlockHeaderImplicits._ +import io.iohk.ethereum.network.p2p.Message +import io.iohk.ethereum.network.p2p.MessageSerializableImplicit import io.iohk.ethereum.rlp.RLPImplicitConversions._ import io.iohk.ethereum.rlp.RLPImplicits._ -import io.iohk.ethereum.rlp.{RLPList, _} -import org.bouncycastle.util.encoders.Hex +import io.iohk.ethereum.rlp.RLPList +import io.iohk.ethereum.rlp._ object ETH62 { object BlockHash { @@ -24,7 +29,7 @@ object ETH62 { implicit class BlockHashRLPEncodableDec(val rlpEncodeable: RLPEncodeable) extends AnyVal { def toBlockHash: BlockHash = rlpEncodeable match { case RLPList(hash, number) => BlockHash(hash, number) - case _ => throw new RuntimeException("Cannot decode BlockHash") + case _ => throw new RuntimeException("Cannot decode BlockHash") } } } @@ -53,7 +58,7 @@ object ETH62 { import BlockHash._ def toNewBlockHashes: NewBlockHashes = rawDecode(bytes) match { case rlpList: RLPList => NewBlockHashes(rlpList.items.map(_.toBlockHash)) - case _ => throw new RuntimeException("Cannot decode NewBlockHashes") + case _ => throw new RuntimeException("Cannot decode NewBlockHashes") } } } @@ -78,7 +83,7 @@ object ETH62 { import msg._ block match { case Left(blockNumber) => RLPList(blockNumber, maxHeaders, skip, if (reverse) 1 else 0) - case Right(blockHash) => RLPList(blockHash, maxHeaders, skip, if (reverse) 1 else 0) + case Right(blockHash) => RLPList(blockHash, maxHeaders, skip, if (reverse) 1 else 0) } } } @@ -123,7 +128,7 @@ object ETH62 { implicit class BlockBodiesDec(val bytes: Array[Byte]) extends AnyVal { def toBlockBodies: BlockBodies = rawDecode(bytes) match { case rlpList: RLPList => BlockBodies(rlpList.items.map(_.toBlockBody)) - case _ => throw new RuntimeException("Cannot decode BlockBodies") + case _ => throw new RuntimeException("Cannot decode BlockBodies") } } } diff --git a/src/main/scala/io/iohk/ethereum/network/p2p/messages/ETH63.scala b/src/main/scala/io/iohk/ethereum/network/p2p/messages/ETH63.scala index f60ec0072b..37ffb2cc36 100644 --- a/src/main/scala/io/iohk/ethereum/network/p2p/messages/ETH63.scala +++ b/src/main/scala/io/iohk/ethereum/network/p2p/messages/ETH63.scala @@ -1,13 +1,17 @@ package io.iohk.ethereum.network.p2p.messages import akka.util.ByteString + +import org.bouncycastle.util.encoders.Hex + import io.iohk.ethereum.domain._ -import io.iohk.ethereum.mpt.{MptNode, MptTraversals} -import io.iohk.ethereum.network.p2p.{Message, MessageSerializableImplicit} +import io.iohk.ethereum.mpt.MptNode +import io.iohk.ethereum.mpt.MptTraversals +import io.iohk.ethereum.network.p2p.Message +import io.iohk.ethereum.network.p2p.MessageSerializableImplicit import io.iohk.ethereum.rlp.RLPImplicitConversions._ import io.iohk.ethereum.rlp.RLPImplicits._ import io.iohk.ethereum.rlp._ -import org.bouncycastle.util.encoders.Hex object ETH63 { @@ -23,7 +27,7 @@ object ETH63 { implicit class GetNodeDataDec(val bytes: Array[Byte]) extends AnyVal { def toGetNodeData: GetNodeData = rawDecode(bytes) match { case rlpList: RLPList => GetNodeData(fromRlpList[ByteString](rlpList)) - case _ => throw new RuntimeException("Cannot decode GetNodeData") + case _ => throw new RuntimeException("Cannot decode GetNodeData") } } } @@ -94,8 +98,8 @@ object ETH63 { implicit class NodeDataDec(val bytes: Array[Byte]) extends AnyVal { def toNodeData: NodeData = rawDecode(bytes) match { - case rlpList: RLPList => NodeData(rlpList.items.map { e => e: ByteString }) - case _ => throw new RuntimeException("Cannot decode NodeData") + case rlpList: RLPList => NodeData(rlpList.items.map(e => e: ByteString)) + case _ => throw new RuntimeException("Cannot decode NodeData") } } } @@ -123,7 +127,7 @@ object ETH63 { implicit class GetReceiptsDec(val bytes: Array[Byte]) extends AnyVal { def toGetReceipts: GetReceipts = rawDecode(bytes) match { case rlpList: RLPList => GetReceipts(fromRlpList[ByteString](rlpList)) - case _ => throw new RuntimeException("Cannot decode GetReceipts") + case _ => throw new RuntimeException("Cannot decode GetReceipts") } } } @@ -164,8 +168,8 @@ object ETH63 { import receipt._ val stateHash: RLPEncodeable = postTransactionStateHash match { case HashOutcome(hash) => hash - case SuccessOutcome => 1.toByte - case _ => 0.toByte + case SuccessOutcome => 1.toByte + case _ => 0.toByte } RLPList(stateHash, cumulativeGasUsed, logsBloomFilter, RLPList(logs.map(_.toRLPEncodable): _*)) } @@ -180,7 +184,7 @@ object ETH63 { def toReceipts: Seq[Receipt] = rawDecode(bytes) match { case RLPList(items @ _*) => items.map(_.toReceipt) - case _ => throw new RuntimeException("Cannot decode Receipts") + case _ => throw new RuntimeException("Cannot decode Receipts") } } @@ -188,9 +192,9 @@ object ETH63 { def toReceipt: Receipt = rlpEncodeable match { case RLPList(postTransactionStateHash, cumulativeGasUsed, logsBloomFilter, logs: RLPList) => val stateHash = postTransactionStateHash match { - case RLPValue(bytes) if bytes.length > 1 => HashOutcome(ByteString(bytes)) + case RLPValue(bytes) if bytes.length > 1 => HashOutcome(ByteString(bytes)) case RLPValue(bytes) if bytes.length == 1 && bytes.head == 1 => SuccessOutcome - case _ => FailureOutcome + case _ => FailureOutcome } Receipt(stateHash, cumulativeGasUsed, logsBloomFilter, logs.items.map(_.toTxLogEntry)) case _ => throw new RuntimeException("Cannot decode Receipt") @@ -216,7 +220,7 @@ object ETH63 { def toReceipts: Receipts = rawDecode(bytes) match { case rlpList: RLPList => Receipts(rlpList.items.collect { case r: RLPList => r.items.map(_.toReceipt) }) - case _ => throw new RuntimeException("Cannot decode Receipts") + case _ => throw new RuntimeException("Cannot decode Receipts") } } } diff --git a/src/main/scala/io/iohk/ethereum/network/p2p/messages/WireProtocol.scala b/src/main/scala/io/iohk/ethereum/network/p2p/messages/WireProtocol.scala index cd677a7de2..8673d4b0ea 100644 --- a/src/main/scala/io/iohk/ethereum/network/p2p/messages/WireProtocol.scala +++ b/src/main/scala/io/iohk/ethereum/network/p2p/messages/WireProtocol.scala @@ -1,11 +1,14 @@ package io.iohk.ethereum.network.p2p.messages import akka.util.ByteString -import io.iohk.ethereum.network.p2p.{Message, MessageSerializableImplicit} + +import org.bouncycastle.util.encoders.Hex + +import io.iohk.ethereum.network.p2p.Message +import io.iohk.ethereum.network.p2p.MessageSerializableImplicit import io.iohk.ethereum.rlp.RLPImplicitConversions._ import io.iohk.ethereum.rlp.RLPImplicits._ import io.iohk.ethereum.rlp._ -import org.bouncycastle.util.encoders.Hex object WireProtocol { @@ -47,7 +50,7 @@ object WireProtocol { override val code: Int = Hello.code - override def toString: String = { + override def toString: String = s"Hello { " + s"p2pVersion: $p2pVersion " + s"clientId: $clientId " + @@ -55,7 +58,6 @@ object WireProtocol { s"listenPort: $listenPort " + s"nodeId: ${Hex.toHexString(nodeId.toArray[Byte])} " + s"}" - } override def toShortString: String = toString } @@ -77,19 +79,19 @@ object WireProtocol { def reasonToString(reasonCode: Long): String = reasonCode match { - case Reasons.DisconnectRequested => "Disconnect requested" - case Reasons.TcpSubsystemError => "TCP sub-system error" - case Reasons.UselessPeer => "Useless peer" - case Reasons.TooManyPeers => "Too many peers" - case Reasons.AlreadyConnected => "Already connected" + case Reasons.DisconnectRequested => "Disconnect requested" + case Reasons.TcpSubsystemError => "TCP sub-system error" + case Reasons.UselessPeer => "Useless peer" + case Reasons.TooManyPeers => "Too many peers" + case Reasons.AlreadyConnected => "Already connected" case Reasons.IncompatibleP2pProtocolVersion => "Incompatible P2P protocol version" - case Reasons.NullNodeIdentityReceived => "Null node identity received - this is automatically invalid" - case Reasons.ClientQuitting => "Client quitting" - case Reasons.UnexpectedIdentity => "Unexpected identity" - case Reasons.IdentityTheSame => "Identity is the same as this node" - case Reasons.TimeoutOnReceivingAMessage => "Timeout on receiving a message" - case Reasons.Other => "Some other reason specific to a subprotocol" - case other => s"unknown reason code: $other" + case Reasons.NullNodeIdentityReceived => "Null node identity received - this is automatically invalid" + case Reasons.ClientQuitting => "Client quitting" + case Reasons.UnexpectedIdentity => "Unexpected identity" + case Reasons.IdentityTheSame => "Identity is the same as this node" + case Reasons.TimeoutOnReceivingAMessage => "Timeout on receiving a message" + case Reasons.Other => "Some other reason specific to a subprotocol" + case other => s"unknown reason code: $other" } val code = 0x01 @@ -105,7 +107,7 @@ object WireProtocol { implicit class DisconnectDec(val bytes: Array[Byte]) extends AnyVal { def toDisconnect: Disconnect = rawDecode(bytes) match { case RLPList(reason, _*) => Disconnect(reason = reason) - case _ => throw new RuntimeException("Cannot decode Disconnect") + case _ => throw new RuntimeException("Cannot decode Disconnect") } } } diff --git a/src/main/scala/io/iohk/ethereum/network/package.scala b/src/main/scala/io/iohk/ethereum/network/package.scala index 467412ca24..5bf00513c0 100644 --- a/src/main/scala/io/iohk/ethereum/network/package.scala +++ b/src/main/scala/io/iohk/ethereum/network/package.scala @@ -1,15 +1,19 @@ package io.iohk.ethereum -import java.io.{File, PrintWriter} -import java.net.{Inet6Address, InetAddress} +import java.io.File +import java.io.PrintWriter +import java.net.Inet6Address +import java.net.InetAddress import java.security.SecureRandom -import io.iohk.ethereum.crypto._ + +import scala.io.Source + import org.bouncycastle.crypto.AsymmetricCipherKeyPair import org.bouncycastle.crypto.params.ECPublicKeyParameters import org.bouncycastle.math.ec.ECPoint import org.bouncycastle.util.encoders.Hex -import scala.io.Source +import io.iohk.ethereum.crypto._ package object network { @@ -38,11 +42,8 @@ package object network { val (priv, pub) = keyPairToByteArrays(keysValuePair) require(file.getParentFile.exists() || file.getParentFile.mkdirs(), "Key's file parent directory creation failed") val writer = new PrintWriter(filePath) - try { - writer.write(Hex.toHexString(priv) + "\n" + Hex.toHexString(pub)) - } finally { - writer.close() - } + try writer.write(Hex.toHexString(priv) + "\n" + Hex.toHexString(pub)) + finally writer.close() keysValuePair } else { @@ -50,14 +51,11 @@ package object network { try { val privHex = reader.getLines().next() keyPairFromPrvKey(Hex.decode(privHex)) - } finally { - reader.close() - } + } finally reader.close() } } - /** - * Given an address, returns the corresponding host name for the URI. + /** Given an address, returns the corresponding host name for the URI. * All IPv6 addresses are enclosed in square brackets. * * @param address, whose host name will be obtained @@ -67,7 +65,7 @@ package object network { val hostName = address.getHostAddress address match { case _: Inet6Address => s"[$hostName]" - case _ => hostName + case _ => hostName } } diff --git a/src/main/scala/io/iohk/ethereum/network/rlpx/AuthHandshaker.scala b/src/main/scala/io/iohk/ethereum/network/rlpx/AuthHandshaker.scala index f56783f98c..8d7e8e11ae 100644 --- a/src/main/scala/io/iohk/ethereum/network/rlpx/AuthHandshaker.scala +++ b/src/main/scala/io/iohk/ethereum/network/rlpx/AuthHandshaker.scala @@ -5,18 +5,22 @@ import java.nio.ByteBuffer import java.security.SecureRandom import akka.util.ByteString -import io.iohk.ethereum.crypto._ -import io.iohk.ethereum.network._ -import io.iohk.ethereum.rlp -import io.iohk.ethereum.utils.ByteUtils._ + +import scala.util.Random + import org.bouncycastle.crypto.AsymmetricCipherKeyPair import org.bouncycastle.crypto.agreement.ECDHBasicAgreement import org.bouncycastle.crypto.digests.KeccakDigest -import org.bouncycastle.crypto.params.{ECPrivateKeyParameters, ECPublicKeyParameters} -import AuthInitiateMessageV4._ +import org.bouncycastle.crypto.params.ECPrivateKeyParameters +import org.bouncycastle.crypto.params.ECPublicKeyParameters import org.bouncycastle.math.ec.ECPoint -import scala.util.Random +import io.iohk.ethereum.crypto._ +import io.iohk.ethereum.network._ +import io.iohk.ethereum.rlp +import io.iohk.ethereum.utils.ByteUtils._ + +import AuthInitiateMessageV4._ sealed trait AuthHandshakeResult case object AuthHandshakeError extends AuthHandshakeResult @@ -31,8 +35,8 @@ class Secrets( ) object AuthHandshaker { - val InitiatePacketLength = AuthInitiateMessage.EncodedLength + ECIESCoder.OverheadSize - val ResponsePacketLength = AuthResponseMessage.EncodedLength + ECIESCoder.OverheadSize + val InitiatePacketLength: Int = AuthInitiateMessage.EncodedLength + ECIESCoder.OverheadSize + val ResponsePacketLength: Int = AuthResponseMessage.EncodedLength + ECIESCoder.OverheadSize val NonceSize = 32 val MacSize = 256 @@ -215,7 +219,7 @@ case class AuthHandshaker( ) } - successOpt getOrElse AuthHandshakeError + successOpt.getOrElse(AuthHandshakeError) } private def macSecretSetup( diff --git a/src/main/scala/io/iohk/ethereum/network/rlpx/AuthInitiateEcdsaCodec.scala b/src/main/scala/io/iohk/ethereum/network/rlpx/AuthInitiateEcdsaCodec.scala index f09c7c5318..7b63ef8c9e 100644 --- a/src/main/scala/io/iohk/ethereum/network/rlpx/AuthInitiateEcdsaCodec.scala +++ b/src/main/scala/io/iohk/ethereum/network/rlpx/AuthInitiateEcdsaCodec.scala @@ -1,10 +1,13 @@ package io.iohk.ethereum.network.rlpx import akka.util.ByteString -import io.iohk.ethereum.crypto.ECDSASignature -import io.iohk.ethereum.crypto.ECDSASignature.{RLength, SLength} + import org.bouncycastle.util.BigIntegers.asUnsignedByteArray +import io.iohk.ethereum.crypto.ECDSASignature +import io.iohk.ethereum.crypto.ECDSASignature.RLength +import io.iohk.ethereum.crypto.ECDSASignature.SLength + trait AuthInitiateEcdsaCodec { def encodeECDSA(sig: ECDSASignature): ByteString = { diff --git a/src/main/scala/io/iohk/ethereum/network/rlpx/AuthInitiateMessage.scala b/src/main/scala/io/iohk/ethereum/network/rlpx/AuthInitiateMessage.scala index 43b6d2d69c..ca7a22a4a8 100644 --- a/src/main/scala/io/iohk/ethereum/network/rlpx/AuthInitiateMessage.scala +++ b/src/main/scala/io/iohk/ethereum/network/rlpx/AuthInitiateMessage.scala @@ -1,9 +1,11 @@ package io.iohk.ethereum.network.rlpx import akka.util.ByteString -import io.iohk.ethereum.crypto._ + import org.bouncycastle.math.ec.ECPoint +import io.iohk.ethereum.crypto._ + object AuthInitiateMessage extends AuthInitiateEcdsaCodec { val NonceLength = 32 val EphemeralHashLength = 32 diff --git a/src/main/scala/io/iohk/ethereum/network/rlpx/AuthInitiateMessageV4.scala b/src/main/scala/io/iohk/ethereum/network/rlpx/AuthInitiateMessageV4.scala index 81acdee874..1adfc500fe 100644 --- a/src/main/scala/io/iohk/ethereum/network/rlpx/AuthInitiateMessageV4.scala +++ b/src/main/scala/io/iohk/ethereum/network/rlpx/AuthInitiateMessageV4.scala @@ -1,11 +1,13 @@ package io.iohk.ethereum.network.rlpx import akka.util.ByteString + +import org.bouncycastle.math.ec.ECPoint + import io.iohk.ethereum.crypto._ import io.iohk.ethereum.rlp.RLPImplicitConversions._ import io.iohk.ethereum.rlp.RLPImplicits._ import io.iohk.ethereum.rlp._ -import org.bouncycastle.math.ec.ECPoint object AuthInitiateMessageV4 extends AuthInitiateEcdsaCodec { diff --git a/src/main/scala/io/iohk/ethereum/network/rlpx/AuthResponseMessage.scala b/src/main/scala/io/iohk/ethereum/network/rlpx/AuthResponseMessage.scala index 03fbc33caa..fd7841e779 100644 --- a/src/main/scala/io/iohk/ethereum/network/rlpx/AuthResponseMessage.scala +++ b/src/main/scala/io/iohk/ethereum/network/rlpx/AuthResponseMessage.scala @@ -1,9 +1,11 @@ package io.iohk.ethereum.network.rlpx import akka.util.ByteString -import io.iohk.ethereum.crypto._ + import org.bouncycastle.math.ec.ECPoint +import io.iohk.ethereum.crypto._ + object AuthResponseMessage { private val PublicKeyLength = 64 @@ -12,14 +14,13 @@ object AuthResponseMessage { val EncodedLength: Int = PublicKeyLength + NonceLength + KnownPeerLength - def decode(input: Array[Byte]): AuthResponseMessage = { + def decode(input: Array[Byte]): AuthResponseMessage = AuthResponseMessage( ephemeralPublicKey = curve.getCurve.decodePoint(ECDSASignature.UncompressedIndicator +: input.take(PublicKeyLength)), nonce = ByteString(input.slice(PublicKeyLength, PublicKeyLength + NonceLength)), knownPeer = input(PublicKeyLength + NonceLength) == 1 ) - } } case class AuthResponseMessage(ephemeralPublicKey: ECPoint, nonce: ByteString, knownPeer: Boolean) { diff --git a/src/main/scala/io/iohk/ethereum/network/rlpx/AuthResponseMessageV4.scala b/src/main/scala/io/iohk/ethereum/network/rlpx/AuthResponseMessageV4.scala index 19ec040fe4..55033641e1 100644 --- a/src/main/scala/io/iohk/ethereum/network/rlpx/AuthResponseMessageV4.scala +++ b/src/main/scala/io/iohk/ethereum/network/rlpx/AuthResponseMessageV4.scala @@ -1,29 +1,35 @@ package io.iohk.ethereum.network.rlpx import akka.util.ByteString + +import org.bouncycastle.math.ec.ECPoint + import io.iohk.ethereum.crypto._ +import io.iohk.ethereum.rlp.RLPDecoder +import io.iohk.ethereum.rlp.RLPEncodeable +import io.iohk.ethereum.rlp.RLPEncoder import io.iohk.ethereum.rlp.RLPImplicitConversions._ import io.iohk.ethereum.rlp.RLPImplicits._ -import io.iohk.ethereum.rlp.{RLPDecoder, RLPEncodeable, RLPEncoder, RLPList} -import org.bouncycastle.math.ec.ECPoint +import io.iohk.ethereum.rlp.RLPList object AuthResponseMessageV4 { - implicit val rlpEncDec = new RLPEncoder[AuthResponseMessageV4] with RLPDecoder[AuthResponseMessageV4] { - override def encode(obj: AuthResponseMessageV4): RLPEncodeable = { - import obj._ - //byte 0 of encoded ECC point indicates that it is uncompressed point, it is part of bouncycastle encoding - RLPList(ephemeralPublicKey.getEncoded(false).drop(1), nonce.toArray[Byte], version) - } + implicit val rlpEncDec: RLPEncoder[AuthResponseMessageV4] with RLPDecoder[AuthResponseMessageV4] = + new RLPEncoder[AuthResponseMessageV4] with RLPDecoder[AuthResponseMessageV4] { + override def encode(obj: AuthResponseMessageV4): RLPEncodeable = { + import obj._ + //byte 0 of encoded ECC point indicates that it is uncompressed point, it is part of bouncycastle encoding + RLPList(ephemeralPublicKey.getEncoded(false).drop(1), nonce.toArray[Byte], version) + } - override def decode(rlp: RLPEncodeable): AuthResponseMessageV4 = rlp match { - case RLPList(ephemeralPublicKeyBytes, nonce, version, _*) => - val ephemeralPublicKey = - curve.getCurve.decodePoint(ECDSASignature.UncompressedIndicator +: (ephemeralPublicKeyBytes: Array[Byte])) - AuthResponseMessageV4(ephemeralPublicKey, ByteString(nonce: Array[Byte]), version) - case _ => throw new RuntimeException("Cannot decode auth response message") + override def decode(rlp: RLPEncodeable): AuthResponseMessageV4 = rlp match { + case RLPList(ephemeralPublicKeyBytes, nonce, version, _*) => + val ephemeralPublicKey = + curve.getCurve.decodePoint(ECDSASignature.UncompressedIndicator +: (ephemeralPublicKeyBytes: Array[Byte])) + AuthResponseMessageV4(ephemeralPublicKey, ByteString(nonce: Array[Byte]), version) + case _ => throw new RuntimeException("Cannot decode auth response message") + } } - } } case class AuthResponseMessageV4(ephemeralPublicKey: ECPoint, nonce: ByteString, version: Int) diff --git a/src/main/scala/io/iohk/ethereum/network/rlpx/FrameCodec.scala b/src/main/scala/io/iohk/ethereum/network/rlpx/FrameCodec.scala index 61c98bc492..58673f24b1 100644 --- a/src/main/scala/io/iohk/ethereum/network/rlpx/FrameCodec.scala +++ b/src/main/scala/io/iohk/ethereum/network/rlpx/FrameCodec.scala @@ -3,16 +3,19 @@ package io.iohk.ethereum.network.rlpx import java.io.IOException import akka.util.ByteString -import io.iohk.ethereum.rlp -import io.iohk.ethereum.rlp.RLPImplicits._ + +import scala.annotation.tailrec +import scala.collection.mutable.ArrayBuffer + import org.bouncycastle.crypto.StreamCipher import org.bouncycastle.crypto.digests.KeccakDigest import org.bouncycastle.crypto.engines.AESEngine import org.bouncycastle.crypto.modes.SICBlockCipher -import org.bouncycastle.crypto.params.{KeyParameter, ParametersWithIV} +import org.bouncycastle.crypto.params.KeyParameter +import org.bouncycastle.crypto.params.ParametersWithIV -import scala.annotation.tailrec -import scala.collection.mutable.ArrayBuffer +import io.iohk.ethereum.rlp +import io.iohk.ethereum.rlp.RLPImplicits._ case class Frame(header: Header, `type`: Int, payload: ByteString) @@ -43,8 +46,7 @@ class FrameCodec(private val secrets: Secrets) { private var headerOpt: Option[Header] = None - /** - * Note, this method is not reentrant. + /** Note, this method is not reentrant. * * @param data * @return @@ -89,7 +91,7 @@ class FrameCodec(private val secrets: Secrets) { readRecursive() } - private def tryReadHeader(): Unit = { + private def tryReadHeader(): Unit = if (unprocessedData.size >= HeaderLength) { val headBuffer = unprocessedData.take(HeaderLength).toArray @@ -109,10 +111,9 @@ class FrameCodec(private val secrets: Secrets) { unprocessedData = unprocessedData.drop(HeaderLength) headerOpt = Some(Header(bodySize, protocol, contextId, totalPacketSize)) } - } def writeFrames(frames: Seq[Frame]): ByteString = { - val bytes = frames.zipWithIndex flatMap { case (frame, index) => + val bytes = frames.zipWithIndex.flatMap { case (frame, index) => val firstFrame = index == 0 val lastFrame = index == frames.size - 1 @@ -131,8 +132,8 @@ class FrameCodec(private val secrets: Secrets) { var headerDataElems: Seq[Array[Byte]] = Nil headerDataElems :+= rlp.encode(frame.header.protocol) - frame.header.contextId.foreach { cid => headerDataElems :+= rlp.encode(cid) } - frame.header.totalPacketSize foreach { tfs => headerDataElems :+= rlp.encode(tfs) } + frame.header.contextId.foreach(cid => headerDataElems :+= rlp.encode(cid)) + frame.header.totalPacketSize.foreach(tfs => headerDataElems :+= rlp.encode(tfs)) val headerData = rlp.encode(headerDataElems)(seqEncDec[Array[Byte]]()) System.arraycopy(headerData, 0, headBuffer, 3, headerData.length) @@ -215,7 +216,7 @@ class FrameCodec(private val secrets: Secrets) { val length = 16 - (0 until length) foreach { i => + (0 until length).foreach { i => aesBlock(i) = (aesBlock(i) ^ seed(i + offset)).toByte } @@ -225,15 +226,14 @@ class FrameCodec(private val secrets: Secrets) { if (egress) System.arraycopy(result, 0, out, outOffset, length) else - (0 until length) foreach { i => + (0 until length).foreach { i => if (out(i + outOffset) != result(i)) throw new IOException("MAC mismatch") } result } - private def doSum(mac: KeccakDigest, out: Array[Byte]) = { + private def doSum(mac: KeccakDigest, out: Array[Byte]) = new KeccakDigest(mac).doFinal(out, 0) - } } diff --git a/src/main/scala/io/iohk/ethereum/network/rlpx/MessageCodec.scala b/src/main/scala/io/iohk/ethereum/network/rlpx/MessageCodec.scala index 3dbadc4b5b..f30ddd508a 100644 --- a/src/main/scala/io/iohk/ethereum/network/rlpx/MessageCodec.scala +++ b/src/main/scala/io/iohk/ethereum/network/rlpx/MessageCodec.scala @@ -1,14 +1,20 @@ package io.iohk.ethereum.network.rlpx import java.util.concurrent.atomic.AtomicInteger + import akka.util.ByteString -import io.iohk.ethereum.network.handshaker.EtcHelloExchangeState -import io.iohk.ethereum.network.p2p.messages.Capability -import io.iohk.ethereum.network.p2p.messages.WireProtocol.Hello -import io.iohk.ethereum.network.p2p.{Message, MessageDecoder, MessageSerializable} + +import scala.util.Failure +import scala.util.Success +import scala.util.Try + import org.xerial.snappy.Snappy -import scala.util.{Failure, Success, Try} +import io.iohk.ethereum.network.handshaker.EtcHelloExchangeState +import io.iohk.ethereum.network.p2p.Message +import io.iohk.ethereum.network.p2p.MessageDecoder +import io.iohk.ethereum.network.p2p.MessageSerializable +import io.iohk.ethereum.network.p2p.messages.WireProtocol.Hello object MessageCodec { val MaxFramePayloadSize: Int = Int.MaxValue // no framing @@ -31,8 +37,8 @@ class MessageCodec( readFrames(frames) } - def readFrames(frames: Seq[Frame]): Seq[Try[Message]] = { - frames map { frame => + def readFrames(frames: Seq[Frame]): Seq[Try[Message]] = + frames.map { frame => val frameData = frame.payload.toArray val payloadTry = if (remotePeer2PeerVersion >= EtcHelloExchangeState.P2pVersion && frame.`type` != Hello.code) { @@ -45,22 +51,20 @@ class MessageCodec( messageDecoder.fromBytes(frame.`type`, payload) } } - } - private def decompressData(data: Array[Byte]): Try[Array[Byte]] = { + private def decompressData(data: Array[Byte]): Try[Array[Byte]] = Try(Snappy.uncompressedLength(data)).flatMap { decompressedSize => if (decompressedSize > MaxDecompressedLength) Failure(new RuntimeException("Message size larger than 16mb")) else Try(Snappy.uncompress(data)) } - } def encodeMessage(serializable: MessageSerializable): ByteString = { val encoded: Array[Byte] = serializable.toBytes val numFrames = Math.ceil(encoded.length / MaxFramePayloadSize.toDouble).toInt val contextId = contextIdCounter.incrementAndGet() - val frames = (0 until numFrames) map { frameNo => + val frames = (0 until numFrames).map { frameNo => val framedPayload = encoded.drop(frameNo * MaxFramePayloadSize).take(MaxFramePayloadSize) val payload = if (remotePeer2PeerVersion >= EtcHelloExchangeState.P2pVersion && serializable.code != Hello.code) { diff --git a/src/main/scala/io/iohk/ethereum/network/rlpx/RLPxConnectionHandler.scala b/src/main/scala/io/iohk/ethereum/network/rlpx/RLPxConnectionHandler.scala index 5e5aaa6a44..82a97d1420 100644 --- a/src/main/scala/io/iohk/ethereum/network/rlpx/RLPxConnectionHandler.scala +++ b/src/main/scala/io/iohk/ethereum/network/rlpx/RLPxConnectionHandler.scala @@ -1,31 +1,34 @@ package io.iohk.ethereum.network.rlpx -import java.net.{InetSocketAddress, URI} +import java.net.InetSocketAddress +import java.net.URI + import akka.actor._ +import akka.io.IO +import akka.io.Tcp import akka.io.Tcp._ -import akka.io.{IO, Tcp} import akka.util.ByteString -import cats.data.NonEmptyList -import io.iohk.ethereum.network.p2p.messages.{Capability, WireProtocol} -import io.iohk.ethereum.network.p2p.messages.WireProtocol.Hello -import io.iohk.ethereum.network.p2p.messages.WireProtocol.Hello.HelloEnc -import io.iohk.ethereum.network.p2p.{ - EthereumMessageDecoder, - Message, - MessageDecoder, - MessageSerializable, - NetworkMessageDecoder -} -import io.iohk.ethereum.network.rlpx.RLPxConnectionHandler.{HelloCodec, RLPxConfiguration} -import io.iohk.ethereum.utils.ByteUtils -import org.bouncycastle.util.encoders.Hex import scala.collection.immutable.Queue import scala.concurrent.duration._ -import scala.util.{Failure, Success, Try} +import scala.util.Failure +import scala.util.Success +import scala.util.Try + +import org.bouncycastle.util.encoders.Hex + +import io.iohk.ethereum.network.p2p.EthereumMessageDecoder +import io.iohk.ethereum.network.p2p.Message +import io.iohk.ethereum.network.p2p.MessageSerializable +import io.iohk.ethereum.network.p2p.NetworkMessageDecoder +import io.iohk.ethereum.network.p2p.messages.Capability +import io.iohk.ethereum.network.p2p.messages.WireProtocol.Hello +import io.iohk.ethereum.network.p2p.messages.WireProtocol.Hello.HelloEnc +import io.iohk.ethereum.network.rlpx.RLPxConnectionHandler.HelloCodec +import io.iohk.ethereum.network.rlpx.RLPxConnectionHandler.RLPxConfiguration +import io.iohk.ethereum.utils.ByteUtils -/** - * This actors takes care of initiating a secure connection (auth handshake) between peers. +/** This actors takes care of initiating a secure connection (auth handshake) between peers. * Once such connection is established it allows to send/receive frames (messages) over it. * * The actor can be in one of four states: @@ -57,12 +60,12 @@ class RLPxConnectionHandler( def waitingForCommand: Receive = { case ConnectTo(uri) => tcpActor ! Connect(new InetSocketAddress(uri.getHost, uri.getPort)) - context become waitingForConnectionResult(uri) + context.become(waitingForConnectionResult(uri)) case HandleConnection(connection) => connection ! Register(self) val timeout = system.scheduler.scheduleOnce(rlpxConfiguration.waitForHandshakeTimeout, self, AuthHandshakeTimeout) - context become new ConnectedHandler(connection).waitingForAuthHandshakeInit(authHandshaker, timeout) + context.become(new ConnectedHandler(connection).waitingForAuthHandshakeInit(authHandshaker, timeout)) } def waitingForConnectionResult(uri: URI): Receive = { @@ -72,18 +75,18 @@ class RLPxConnectionHandler( val (initPacket, handshaker) = authHandshaker.initiate(uri) connection ! Write(initPacket) val timeout = system.scheduler.scheduleOnce(rlpxConfiguration.waitForHandshakeTimeout, self, AuthHandshakeTimeout) - context become new ConnectedHandler(connection).waitingForAuthHandshakeResponse(handshaker, timeout) + context.become(new ConnectedHandler(connection).waitingForAuthHandshakeResponse(handshaker, timeout)) case CommandFailed(_: Connect) => log.debug("[Stopping Connection] Connection to {} failed", uri) context.parent ! ConnectionFailed - context stop self + context.stop(self) } class ConnectedHandler(connection: ActorRef) { def waitingForAuthHandshakeInit(handshaker: AuthHandshaker, timeout: Cancellable): Receive = - handleTimeout orElse handleConnectionClosed orElse { case Received(data) => + handleTimeout.orElse(handleConnectionClosed).orElse { case Received(data) => timeout.cancel() // FIXME EIP8 is 6 years old, time to drop it val maybePreEIP8Result = Try { @@ -97,7 +100,7 @@ class RLPxConnectionHandler( (responsePacket, result, remainingData) } - maybePreEIP8Result orElse maybePostEIP8Result match { + maybePreEIP8Result.orElse(maybePostEIP8Result) match { case Success((responsePacket, result, remainingData)) => connection ! Write(responsePacket) processHandshakeResult(result, remainingData) @@ -109,12 +112,12 @@ class RLPxConnectionHandler( ex.getMessage ) context.parent ! ConnectionFailed - context stop self + context.stop(self) } } def waitingForAuthHandshakeResponse(handshaker: AuthHandshaker, timeout: Cancellable): Receive = - handleWriteFailed orElse handleTimeout orElse handleConnectionClosed orElse { case Received(data) => + handleWriteFailed.orElse(handleTimeout).orElse(handleConnectionClosed).orElse { case Received(data) => timeout.cancel() val maybePreEIP8Result = Try { val result = handshaker.handleResponseMessage(data.take(ResponsePacketLength)) @@ -126,7 +129,7 @@ class RLPxConnectionHandler( val result = handshaker.handleResponseMessageV4(packetData) (result, remainingData) } - maybePreEIP8Result orElse maybePostEIP8Result match { + maybePreEIP8Result.orElse(maybePostEIP8Result) match { case Success((result, remainingData)) => processHandshakeResult(result, remainingData) @@ -137,12 +140,11 @@ class RLPxConnectionHandler( ex.getMessage ) context.parent ! ConnectionFailed - context stop self + context.stop(self) } } - /** - * Decode V4 packet + /** Decode V4 packet * * @param data , includes both the V4 packet with bytes from next messages * @return data of the packet and the remaining data @@ -156,7 +158,7 @@ class RLPxConnectionHandler( def handleTimeout: Receive = { case AuthHandshakeTimeout => log.debug("[Stopping Connection] Auth handshake timeout for peer {}", peerId) context.parent ! ConnectionFailed - context stop self + context.stop(self) } def processHandshakeResult(result: AuthHandshakeResult, remainingData: ByteString): Unit = @@ -174,7 +176,7 @@ class RLPxConnectionHandler( case AuthHandshakeError => log.debug("[Stopping Connection] Auth handshake failed for peer {}", peerId) context.parent ! ConnectionFailed - context stop self + context.stop(self) } def awaitInitialHello( @@ -182,27 +184,29 @@ class RLPxConnectionHandler( cancellableAckTimeout: Option[CancellableAckTimeout] = None, seqNumber: Int = 0 ): Receive = - handleWriteFailed orElse handleConnectionClosed orElse { + handleWriteFailed.orElse(handleConnectionClosed).orElse { // TODO when cancellableAckTimeout is Some case SendMessage(h: HelloEnc) => val out = extractor.writeHello(h) connection ! Write(out, Ack) val timeout = system.scheduler.scheduleOnce(rlpxConfiguration.waitForTcpAckTimeout, self, AckTimeout(seqNumber)) - context become awaitInitialHello( - extractor, - Some(CancellableAckTimeout(seqNumber, timeout)), - increaseSeqNumber(seqNumber) + context.become( + awaitInitialHello( + extractor, + Some(CancellableAckTimeout(seqNumber, timeout)), + increaseSeqNumber(seqNumber) + ) ) case Ack if cancellableAckTimeout.nonEmpty => //Cancel pending message timeout cancellableAckTimeout.foreach(_.cancellable.cancel()) - context become awaitInitialHello(extractor, None, seqNumber) + context.become(awaitInitialHello(extractor, None, seqNumber)) case AckTimeout(ackSeqNumber) if cancellableAckTimeout.exists(_.seqNumber == ackSeqNumber) => cancellableAckTimeout.foreach(_.cancellable.cancel()) log.error("[Stopping Connection] Sending 'Hello' to {} failed", peerId) - context stop self + context.stop(self) case Received(data) => extractHello(extractor, data, cancellableAckTimeout, seqNumber) } @@ -212,7 +216,7 @@ class RLPxConnectionHandler( data: ByteString, cancellableAckTimeout: Option[CancellableAckTimeout] = None, seqNumber: Int = 0 - ): Unit = { + ): Unit = extractor.readHello(data) match { case Some((hello, restFrames)) => val messageCodecOpt = for { @@ -223,21 +227,22 @@ class RLPxConnectionHandler( } yield messageCodec messageCodecOpt match { case Some(messageCodec) => - context become handshaked( - messageCodec, - cancellableAckTimeout = cancellableAckTimeout, - seqNumber = seqNumber + context.become( + handshaked( + messageCodec, + cancellableAckTimeout = cancellableAckTimeout, + seqNumber = seqNumber + ) ) case None => log.debug("[Stopping Connection] Unable to negotiate protocol with {}", peerId) context.parent ! ConnectionFailed - context stop self + context.stop(self) } case None => log.debug("[Stopping Connection] Did not find 'Hello' in message from {}", peerId) - context become awaitInitialHello(extractor, cancellableAckTimeout, seqNumber) + context.become(awaitInitialHello(extractor, cancellableAckTimeout, seqNumber)) } - } private def negotiateCodec(hello: Hello, extractor: HelloCodec): Option[(MessageCodec, Capability)] = Capability.negotiate(hello.capabilities.toList, capabilities).map { negotiated => @@ -247,7 +252,7 @@ class RLPxConnectionHandler( private def processFrames(frames: Seq[Frame], messageCodec: MessageCodec): Unit = if (frames.nonEmpty) { val messagesSoFar = messageCodec.readFrames(frames) // omit hello - messagesSoFar foreach processMessage + messagesSoFar.foreach(processMessage) } def processMessage(messageTry: Try[Message]): Unit = messageTry match { @@ -257,11 +262,10 @@ class RLPxConnectionHandler( case Failure(ex) => log.info("Cannot decode message from {}, because of {}", peerId, ex.getMessage) // break connection in case of failed decoding, to avoid attack which would send us garbage - context stop self + context.stop(self) } - /** - * Handles sending and receiving messages from the Akka TCP connection, while also handling acknowledgement of + /** Handles sending and receiving messages from the Akka TCP connection, while also handling acknowledgement of * messages sent. Messages are only sent when all Ack from previous messages were received. * * @param messageCodec , for encoding the messages sent @@ -274,22 +278,24 @@ class RLPxConnectionHandler( messagesNotSent: Queue[MessageSerializable] = Queue.empty, cancellableAckTimeout: Option[CancellableAckTimeout] = None, seqNumber: Int = 0 - ): Receive = { - handleWriteFailed orElse handleConnectionClosed orElse { + ): Receive = + handleWriteFailed.orElse(handleConnectionClosed).orElse { case sm: SendMessage => if (cancellableAckTimeout.isEmpty) sendMessage(messageCodec, sm.serializable, seqNumber, messagesNotSent) else - context become handshaked( - messageCodec, - messagesNotSent :+ sm.serializable, - cancellableAckTimeout, - seqNumber + context.become( + handshaked( + messageCodec, + messagesNotSent :+ sm.serializable, + cancellableAckTimeout, + seqNumber + ) ) case Received(data) => val messages = messageCodec.readMessages(data) - messages foreach processMessage + messages.foreach(processMessage) case Ack if cancellableAckTimeout.nonEmpty => //Cancel pending message timeout @@ -299,17 +305,15 @@ class RLPxConnectionHandler( if (messagesNotSent.nonEmpty) sendMessage(messageCodec, messagesNotSent.head, seqNumber, messagesNotSent.tail) else - context become handshaked(messageCodec, Queue.empty, None, seqNumber) + context.become(handshaked(messageCodec, Queue.empty, None, seqNumber)) case AckTimeout(ackSeqNumber) if cancellableAckTimeout.exists(_.seqNumber == ackSeqNumber) => cancellableAckTimeout.foreach(_.cancellable.cancel()) log.debug("[Stopping Connection] Write to {} failed", peerId) - context stop self + context.stop(self) } - } - /** - * Sends an encoded message through the TCP connection, an Ack will be received when the message was + /** Sends an encoded message through the TCP connection, an Ack will be received when the message was * successfully queued for delivery. A cancellable timeout is created for the Ack message. * * @param messageCodec , for encoding the messages sent @@ -328,23 +332,24 @@ class RLPxConnectionHandler( log.debug("Sent message: {} to {}", messageToSend.underlyingMsg.toShortString, peerId) val timeout = system.scheduler.scheduleOnce(rlpxConfiguration.waitForTcpAckTimeout, self, AckTimeout(seqNumber)) - context become handshaked( - messageCodec = messageCodec, - messagesNotSent = remainingMsgsToSend, - cancellableAckTimeout = Some(CancellableAckTimeout(seqNumber, timeout)), - seqNumber = increaseSeqNumber(seqNumber) + context.become( + handshaked( + messageCodec = messageCodec, + messagesNotSent = remainingMsgsToSend, + cancellableAckTimeout = Some(CancellableAckTimeout(seqNumber, timeout)), + seqNumber = increaseSeqNumber(seqNumber) + ) ) } - /** - * Given a sequence number for the AckTimeouts, the next seq number is returned + /** Given a sequence number for the AckTimeouts, the next seq number is returned * * @param seqNumber , the current sequence number * @return the sequence number for the next message sent */ private def increaseSeqNumber(seqNumber: Int): Int = seqNumber match { case Int.MaxValue => 0 - case _ => seqNumber + 1 + case _ => seqNumber + 1 } def handleWriteFailed: Receive = { case CommandFailed(cmd: Write) => @@ -353,7 +358,7 @@ class RLPxConnectionHandler( peerId, Hex.toHexString(cmd.data.toArray[Byte]) ) - context stop self + context.stop(self) } def handleConnectionClosed: Receive = { case msg: ConnectionClosed => @@ -364,7 +369,7 @@ class RLPxConnectionHandler( log.debug("[Stopping Connection] Connection with {} closed because of error {}", peerId, msg.getErrorCause) } - context stop self + context.stop(self) } } } @@ -390,7 +395,7 @@ object RLPxConnectionHandler { negotiated: Capability, p2pVersion: Long ): MessageCodec = { - val md = EthereumMessageDecoder.ethMessageDecoder(negotiated) orElse NetworkMessageDecoder + val md = EthereumMessageDecoder.ethMessageDecoder(negotiated).orElse(NetworkMessageDecoder) new MessageCodec(frameCodec, md, p2pVersion) } @@ -434,7 +439,7 @@ object RLPxConnectionHandler { def writeHello(h: HelloEnc): ByteString = { val encoded: Array[Byte] = h.toBytes val numFrames = Math.ceil(encoded.length / MaxFramePayloadSize.toDouble).toInt - val frames = (0 until numFrames) map { frameNo => + val frames = (0 until numFrames).map { frameNo => val payload = encoded.drop(frameNo * MaxFramePayloadSize).take(MaxFramePayloadSize) val header = Header(payload.length, 0, None, None) Frame(header, h.code, ByteString(payload)) diff --git a/src/main/scala/io/iohk/ethereum/nodebuilder/NodeBuilder.scala b/src/main/scala/io/iohk/ethereum/nodebuilder/NodeBuilder.scala index ccca87004b..d7e9d435c6 100644 --- a/src/main/scala/io/iohk/ethereum/nodebuilder/NodeBuilder.scala +++ b/src/main/scala/io/iohk/ethereum/nodebuilder/NodeBuilder.scala @@ -1,77 +1,94 @@ package io.iohk.ethereum.nodebuilder import java.time.Clock -import akka.actor.{ActorRef, ActorSystem} +import java.util.concurrent.atomic.AtomicReference + +import akka.actor.ActorRef +import akka.actor.ActorSystem +import akka.util.ByteString + +import cats.implicits._ + +import monix.eval.Task +import monix.execution.Scheduler + +import scala.concurrent.Future +import scala.concurrent.duration._ +import scala.util.Failure +import scala.util.Success +import scala.util.Try + +import org.bouncycastle.crypto.AsymmetricCipherKeyPair + import io.iohk.ethereum.blockchain.data.GenesisDataLoader -import io.iohk.ethereum.blockchain.sync.{Blacklist, BlockchainHostActor, CacheBasedBlacklist, SyncController} +import io.iohk.ethereum.blockchain.sync.Blacklist +import io.iohk.ethereum.blockchain.sync.BlockchainHostActor +import io.iohk.ethereum.blockchain.sync.CacheBasedBlacklist +import io.iohk.ethereum.blockchain.sync.SyncController import io.iohk.ethereum.consensus._ +import io.iohk.ethereum.consensus.blocks.CheckpointBlockGenerator import io.iohk.ethereum.db.components.Storages.PruningModeComponent import io.iohk.ethereum.db.components._ -import io.iohk.ethereum.db.storage.{AppStateStorage, EvmCodeStorage} +import io.iohk.ethereum.db.storage.AppStateStorage import io.iohk.ethereum.db.storage.pruning.PruningMode import io.iohk.ethereum.domain._ import io.iohk.ethereum.jsonrpc.NetService.NetServiceConfig import io.iohk.ethereum.jsonrpc._ -import io.iohk.ethereum.security.{SSLContextBuilder, SecureRandomBuilder} import io.iohk.ethereum.jsonrpc.server.controllers.ApisBase import io.iohk.ethereum.jsonrpc.server.controllers.JsonRpcBaseController.JsonRpcConfig import io.iohk.ethereum.jsonrpc.server.http.JsonRpcHttpServer import io.iohk.ethereum.jsonrpc.server.ipc.JsonRpcIpcServer -import io.iohk.ethereum.keystore.{KeyStore, KeyStoreImpl} +import io.iohk.ethereum.keystore.KeyStore +import io.iohk.ethereum.keystore.KeyStoreImpl import io.iohk.ethereum.ledger._ import io.iohk.ethereum.network.EtcPeerManagerActor.PeerInfo +import io.iohk.ethereum.network.PeerManagerActor import io.iohk.ethereum.network.PeerManagerActor.PeerConfiguration -import io.iohk.ethereum.network.discovery.{DiscoveryConfig, DiscoveryServiceBuilder, PeerDiscoveryManager} -import io.iohk.ethereum.network.handshaker.{EtcHandshaker, EtcHandshakerConfiguration, Handshaker} +import io.iohk.ethereum.network.ServerActor +import io.iohk.ethereum.network._ +import io.iohk.ethereum.network.discovery.DiscoveryConfig +import io.iohk.ethereum.network.discovery.DiscoveryServiceBuilder +import io.iohk.ethereum.network.discovery.PeerDiscoveryManager +import io.iohk.ethereum.network.handshaker.EtcHandshaker +import io.iohk.ethereum.network.handshaker.EtcHandshakerConfiguration +import io.iohk.ethereum.network.handshaker.Handshaker +import io.iohk.ethereum.network.p2p.messages.Capability import io.iohk.ethereum.network.rlpx.AuthHandshaker -import io.iohk.ethereum.network.{PeerManagerActor, ServerActor, _} import io.iohk.ethereum.ommers.OmmersPool -import io.iohk.ethereum.testmode.{ - TestBlockchainBuilder, - TestEthBlockServiceWrapper, - TestModeServiceBuilder, - TestmodeConsensusBuilder -} -import io.iohk.ethereum.transactions.{PendingTransactionsManager, TransactionHistoryService} +import io.iohk.ethereum.security.SSLContextBuilder +import io.iohk.ethereum.security.SecureRandomBuilder +import io.iohk.ethereum.testmode.TestBlockchainBuilder +import io.iohk.ethereum.testmode.TestEthBlockServiceWrapper +import io.iohk.ethereum.testmode.TestModeServiceBuilder +import io.iohk.ethereum.testmode.TestmodeConsensusBuilder +import io.iohk.ethereum.transactions.PendingTransactionsManager +import io.iohk.ethereum.transactions.TransactionHistoryService import io.iohk.ethereum.utils.Config.SyncConfig import io.iohk.ethereum.utils._ -import java.util.concurrent.atomic.AtomicReference -import io.iohk.ethereum.consensus.blocks.CheckpointBlockGenerator -import org.bouncycastle.crypto.AsymmetricCipherKeyPair - -import scala.concurrent.Future -import scala.concurrent.duration._ -import scala.util.{Failure, Success, Try} -import akka.util.ByteString -import monix.execution.Scheduler -import cats.implicits._ -import io.iohk.ethereum.network.p2p.messages.Capability -import monix.eval.Task - // scalastyle:off number.of.types trait BlockchainConfigBuilder { lazy val blockchainConfig = Config.blockchains.blockchainConfig } trait VmConfigBuilder { - lazy val vmConfig = VmConfig(Config.config) + lazy val vmConfig: VmConfig = VmConfig(Config.config) } trait SyncConfigBuilder { - lazy val syncConfig = SyncConfig(Config.config) + lazy val syncConfig: SyncConfig = SyncConfig(Config.config) } trait TxPoolConfigBuilder { - lazy val txPoolConfig = TxPoolConfig(Config.config) + lazy val txPoolConfig: TxPoolConfig = TxPoolConfig(Config.config) } trait FilterConfigBuilder { - lazy val filterConfig = FilterConfig(Config.config) + lazy val filterConfig: FilterConfig = FilterConfig(Config.config) } trait KeyStoreConfigBuilder { - lazy val keyStoreConfig = KeyStoreConfig(Config.config) + lazy val keyStoreConfig: KeyStoreConfig = KeyStoreConfig(Config.config) } trait NodeKeyBuilder { @@ -80,7 +97,7 @@ trait NodeKeyBuilder { } trait AsyncConfigBuilder { - val asyncConfig = AsyncConfig(Config.config) + val asyncConfig: AsyncConfig = AsyncConfig(Config.config) } trait ActorSystemBuilder { @@ -99,13 +116,14 @@ trait StorageBuilder { } trait DiscoveryConfigBuilder extends BlockchainConfigBuilder { - lazy val discoveryConfig = DiscoveryConfig(Config.config, blockchainConfig.bootstrapNodes) + lazy val discoveryConfig: DiscoveryConfig = DiscoveryConfig(Config.config, blockchainConfig.bootstrapNodes) } trait KnownNodesManagerBuilder { self: ActorSystemBuilder with StorageBuilder => - lazy val knownNodesManagerConfig = KnownNodesManager.KnownNodesManagerConfig(Config.config) + lazy val knownNodesManagerConfig: KnownNodesManager.KnownNodesManagerConfig = + KnownNodesManager.KnownNodesManagerConfig(Config.config) lazy val knownNodesManager: ActorRef = system.actorOf( KnownNodesManager.props(knownNodesManagerConfig, storagesInstance.storages.knownNodesStorage), @@ -164,7 +182,7 @@ trait BlockchainBuilder { trait BlockQueueBuilder { self: BlockchainBuilder with SyncConfigBuilder => - lazy val blockQueue = BlockQueue(blockchain, syncConfig) + lazy val blockQueue: BlockQueue = BlockQueue(blockchain, syncConfig) } trait BlockImportBuilder { @@ -175,7 +193,7 @@ trait BlockImportBuilder { with ActorSystemBuilder with StorageBuilder => - lazy val blockImport = { + lazy val blockImport: BlockImport = { val blockValidation = new BlockValidation(consensus, blockchainReader, blockQueue) new BlockImport( blockchain, @@ -241,7 +259,7 @@ trait PeerStatisticsBuilder { self: ActorSystemBuilder with PeerEventBusBuilder => // TODO: a candidate to move upwards in trait hierarchy? - implicit val clock = Clock.systemUTC() + implicit val clock: Clock = Clock.systemUTC() lazy val peerStatistics: ActorRef = system.actorOf( PeerStatisticsActor.props( @@ -340,7 +358,7 @@ trait Web3ServiceBuilder { trait NetServiceBuilder { this: PeerManagerActorBuilder with NodeStatusBuilder => - lazy val netServiceConfig = NetServiceConfig(Config.config) + lazy val netServiceConfig: NetServiceConfig = NetServiceConfig(Config.config) lazy val netService = new NetService(nodeStatusHolder, peerManager, netServiceConfig) } @@ -693,7 +711,7 @@ trait JSONRpcHttpServerBuilder { with JSONRpcConfigBuilder with SSLContextBuilder => - lazy val maybeJsonRpcHttpServer = + lazy val maybeJsonRpcHttpServer: Either[String, JsonRpcHttpServer] = JsonRpcHttpServer( jsonRpcController, jsonRpcHealthChecker, @@ -820,12 +838,11 @@ trait ShutdownHookBuilder { lazy val shutdownTimeoutDuration: Duration = Config.shutdownTimeout Runtime.getRuntime.addShutdownHook(new Thread() { - override def run(): Unit = { + override def run(): Unit = shutdown() - } }) - def shutdownOnError[A](f: => A): A = { + def shutdownOnError[A](f: => A): A = Try(f) match { case Success(v) => v case Failure(t) => @@ -833,7 +850,6 @@ trait ShutdownHookBuilder { shutdown() throw t } - } } object ShutdownHookBuilder extends ShutdownHookBuilder with Logger diff --git a/src/main/scala/io/iohk/ethereum/nodebuilder/StdNode.scala b/src/main/scala/io/iohk/ethereum/nodebuilder/StdNode.scala index 00fc2d7de1..a6192d2fc6 100644 --- a/src/main/scala/io/iohk/ethereum/nodebuilder/StdNode.scala +++ b/src/main/scala/io/iohk/ethereum/nodebuilder/StdNode.scala @@ -1,19 +1,24 @@ package io.iohk.ethereum.nodebuilder +import scala.concurrent.Await +import scala.concurrent.ExecutionContext.Implicits.global +import scala.util.Failure +import scala.util.Success +import scala.util.Try + import io.iohk.ethereum.blockchain.sync.SyncProtocol import io.iohk.ethereum.consensus.StdConsensusBuilder -import io.iohk.ethereum.metrics.{Metrics, MetricsConfig} +import io.iohk.ethereum.metrics.Metrics +import io.iohk.ethereum.metrics.MetricsConfig +import io.iohk.ethereum.network.PeerManagerActor +import io.iohk.ethereum.network.ServerActor import io.iohk.ethereum.network.discovery.PeerDiscoveryManager -import io.iohk.ethereum.network.{PeerManagerActor, ServerActor} -import io.iohk.ethereum.testmode.{TestBlockchainBuilder, TestModeServiceBuilder, TestmodeConsensusBuilder} +import io.iohk.ethereum.testmode.TestBlockchainBuilder +import io.iohk.ethereum.testmode.TestModeServiceBuilder +import io.iohk.ethereum.testmode.TestmodeConsensusBuilder import io.iohk.ethereum.utils.Config -import scala.concurrent.ExecutionContext.Implicits.global -import scala.concurrent.Await -import scala.util.{Failure, Success, Try} - -/** - * A standard node is everything Ethereum prescribes except the consensus algorithm, +/** A standard node is everything Ethereum prescribes except the consensus algorithm, * which is plugged in dynamically. * * The design is historically related to the initial cake-pattern-based @@ -22,9 +27,8 @@ import scala.util.{Failure, Success, Try} * @see [[io.iohk.ethereum.nodebuilder.Node Node]] */ abstract class BaseNode extends Node { - private[this] def loadGenesisData(): Unit = { + private[this] def loadGenesisData(): Unit = if (!Config.testmode) genesisDataLoader.loadGenesisData() - } private[this] def startPeerManager(): Unit = peerManager ! PeerManagerActor.StartConnecting @@ -39,13 +43,12 @@ abstract class BaseNode extends Node { private[this] def startJsonRpcHttpServer(): Unit = maybeJsonRpcHttpServer match { case Right(jsonRpcServer) if jsonRpcConfig.httpServerConfig.enabled => jsonRpcServer.run() - case Left(error) if jsonRpcConfig.httpServerConfig.enabled => log.error(error) - case _ => //Nothing + case Left(error) if jsonRpcConfig.httpServerConfig.enabled => log.error(error) + case _ => //Nothing } - private[this] def startJsonRpcIpcServer(): Unit = { + private[this] def startJsonRpcIpcServer(): Unit = if (jsonRpcConfig.ipcServerConfig.enabled) jsonRpcIpcServer.run() - } private[this] def startMetricsClient(): Unit = { val metricsConfig = MetricsConfig(Config.config) diff --git a/src/main/scala/io/iohk/ethereum/nodebuilder/VmSetup.scala b/src/main/scala/io/iohk/ethereum/nodebuilder/VmSetup.scala index be45f4288d..15e490595d 100644 --- a/src/main/scala/io/iohk/ethereum/nodebuilder/VmSetup.scala +++ b/src/main/scala/io/iohk/ethereum/nodebuilder/VmSetup.scala @@ -3,9 +3,13 @@ package io.iohk.ethereum.nodebuilder import java.lang.ProcessBuilder.Redirect import akka.actor.ActorSystem -import io.iohk.ethereum.extvm.{ExtVMInterface, VmServerApp} + +import io.iohk.ethereum.extvm.ExtVMInterface +import io.iohk.ethereum.extvm.VmServerApp import io.iohk.ethereum.ledger.VMImpl -import io.iohk.ethereum.utils.{BlockchainConfig, Logger, VmConfig} +import io.iohk.ethereum.utils.BlockchainConfig +import io.iohk.ethereum.utils.Logger +import io.iohk.ethereum.utils.VmConfig import io.iohk.ethereum.utils.VmConfig.ExternalConfig object VmSetup extends Logger { @@ -28,7 +32,7 @@ object VmSetup extends Logger { throw new RuntimeException("Missing vm.external config for external VM") } - private def startExternalVm(externalConfig: ExternalConfig): Unit = { + private def startExternalVm(externalConfig: ExternalConfig): Unit = externalConfig.vmType match { case "iele" | "kevm" => log.info(s"Starting external ${externalConfig.vmType} VM process using executable path") @@ -42,10 +46,8 @@ object VmSetup extends Logger { log.info("Using external VM process not managed by Mantis") // expect the vm to be started by external means } - } - /** - * Runs a standard VM binary that takes $port and $host as input arguments + /** Runs a standard VM binary that takes $port and $host as input arguments */ private def startStandardVmProcess(externalConfig: ExternalConfig): Unit = { import externalConfig._ @@ -57,15 +59,13 @@ object VmSetup extends Logger { .start() } - private def startMantisVmProcess(externalConfig: ExternalConfig): Unit = { + private def startMantisVmProcess(externalConfig: ExternalConfig): Unit = if (externalConfig.executablePath.isDefined) startStandardVmProcess(externalConfig) else startMantisVmInThisProcess() - } - private def startMantisVmInThisProcess(): Unit = { + private def startMantisVmInThisProcess(): Unit = VmServerApp.main(Array()) - } } diff --git a/src/main/scala/io/iohk/ethereum/ommers/OmmersPool.scala b/src/main/scala/io/iohk/ethereum/ommers/OmmersPool.scala index 4197ddd723..5bfd68c1e2 100644 --- a/src/main/scala/io/iohk/ethereum/ommers/OmmersPool.scala +++ b/src/main/scala/io/iohk/ethereum/ommers/OmmersPool.scala @@ -1,13 +1,19 @@ package io.iohk.ethereum.ommers +import akka.actor.Actor +import akka.actor.ActorLogging +import akka.actor.Props import akka.util.ByteString -import akka.actor.{Actor, ActorLogging, Props} -import org.bouncycastle.util.encoders.Hex -import io.iohk.ethereum.domain.{BlockHeader, Blockchain, BlockchainReader} -import io.iohk.ethereum.ommers.OmmersPool.{AddOmmers, GetOmmers} import scala.annotation.tailrec +import org.bouncycastle.util.encoders.Hex + +import io.iohk.ethereum.domain.BlockHeader +import io.iohk.ethereum.domain.BlockchainReader +import io.iohk.ethereum.ommers.OmmersPool.AddOmmers +import io.iohk.ethereum.ommers.OmmersPool.GetOmmers + class OmmersPool( blockchainReader: BlockchainReader, ommersPoolSize: Int, @@ -37,29 +43,27 @@ class OmmersPool( private def collectAncestors(parentHash: ByteString, generationLimit: Int): List[BlockHeader] = { @tailrec - def rec(hash: ByteString, limit: Int, acc: List[BlockHeader]): List[BlockHeader] = { + def rec(hash: ByteString, limit: Int, acc: List[BlockHeader]): List[BlockHeader] = if (limit > 0) { blockchainReader.getBlockHeaderByHash(hash) match { case Some(bh) => rec(bh.parentHash, limit - 1, acc :+ bh) - case None => acc + case None => acc } } else { acc } - } rec(parentHash, generationLimit, List.empty) } private def logStatus(event: String, ommers: Seq[BlockHeader]): Unit = { - lazy val ommersAsString: Seq[String] = ommers.map { bh => s"[number = ${bh.number}, hash = ${bh.hashAsHexString}]" } + lazy val ommersAsString: Seq[String] = ommers.map(bh => s"[number = ${bh.number}, hash = ${bh.hashAsHexString}]") log.debug(s"$event ${ommersAsString}") } } object OmmersPool { - /** - * As is stated on section 11.1, eq. (143) of the YP + /** As is stated on section 11.1, eq. (143) of the YP * * @param ommerGenerationLimit should be === 6 * @param returnedOmmersSizeLimit should be === 2 diff --git a/src/main/scala/io/iohk/ethereum/rlp/UInt256RLPImplicits.scala b/src/main/scala/io/iohk/ethereum/rlp/UInt256RLPImplicits.scala index 081f64f261..564ecc4b6c 100644 --- a/src/main/scala/io/iohk/ethereum/rlp/UInt256RLPImplicits.scala +++ b/src/main/scala/io/iohk/ethereum/rlp/UInt256RLPImplicits.scala @@ -1,6 +1,7 @@ package io.iohk.ethereum.rlp import akka.util.ByteString + import io.iohk.ethereum.domain.UInt256 import io.iohk.ethereum.rlp.RLP._ @@ -18,7 +19,7 @@ object UInt256RLPImplicits { implicit class UInt256RLPEncodableDec(val rLPEncodeable: RLPEncodeable) extends AnyVal { def toUInt256: UInt256 = rLPEncodeable match { case RLPValue(b) => UInt256(b) - case _ => throw RLPException("src is not an RLPValue") + case _ => throw RLPException("src is not an RLPValue") } } diff --git a/src/main/scala/io/iohk/ethereum/security/FileUtils.scala b/src/main/scala/io/iohk/ethereum/security/FileUtils.scala index 243f4e4c53..57234e8b20 100644 --- a/src/main/scala/io/iohk/ethereum/security/FileUtils.scala +++ b/src/main/scala/io/iohk/ethereum/security/FileUtils.scala @@ -1,12 +1,14 @@ package io.iohk.ethereum.security -import java.io.{File, FileInputStream} +import java.io.File +import java.io.FileInputStream -import io.iohk.ethereum.utils.Logger - -import scala.io.{BufferedSource, Source} +import scala.io.BufferedSource +import scala.io.Source import scala.util.Try +import io.iohk.ethereum.utils.Logger + trait FileUtils extends Logger { def exist(pathName: String): Boolean = new File(pathName).isFile diff --git a/src/main/scala/io/iohk/ethereum/security/KeyStoreUtils.scala b/src/main/scala/io/iohk/ethereum/security/KeyStoreUtils.scala index dd0e0297b6..5d9606e19b 100644 --- a/src/main/scala/io/iohk/ethereum/security/KeyStoreUtils.scala +++ b/src/main/scala/io/iohk/ethereum/security/KeyStoreUtils.scala @@ -2,12 +2,15 @@ package io.iohk.ethereum.security import java.io.FileInputStream import java.security.KeyStore - -import io.iohk.ethereum.utils.Logger -import javax.net.ssl.{KeyManager, KeyManagerFactory, TrustManager, TrustManagerFactory} +import javax.net.ssl.KeyManager +import javax.net.ssl.KeyManagerFactory +import javax.net.ssl.TrustManager +import javax.net.ssl.TrustManagerFactory import scala.util.Try +import io.iohk.ethereum.utils.Logger + trait KeyStoreUtils extends Logger { lazy val algorithm: String = "SunX509" diff --git a/src/main/scala/io/iohk/ethereum/security/SSLConfig.scala b/src/main/scala/io/iohk/ethereum/security/SSLConfig.scala index 371d253e5d..b3053a37ba 100644 --- a/src/main/scala/io/iohk/ethereum/security/SSLConfig.scala +++ b/src/main/scala/io/iohk/ethereum/security/SSLConfig.scala @@ -12,7 +12,7 @@ object SSLConfig { val key = "certificate" - def apply(config: Config): Option[SSLConfig] = { + def apply(config: Config): Option[SSLConfig] = if (config.getIsNull(key)) None else { @@ -25,6 +25,5 @@ object SSLConfig { ) ) } - } } diff --git a/src/main/scala/io/iohk/ethereum/security/SSLContextBuilder.scala b/src/main/scala/io/iohk/ethereum/security/SSLContextBuilder.scala index 7054da67ea..1d42cd142f 100644 --- a/src/main/scala/io/iohk/ethereum/security/SSLContextBuilder.scala +++ b/src/main/scala/io/iohk/ethereum/security/SSLContextBuilder.scala @@ -1,7 +1,8 @@ package io.iohk.ethereum.security -import com.typesafe.config.ConfigFactory import javax.net.ssl.SSLContext +import com.typesafe.config.ConfigFactory + case class SSLError(reason: String) trait SSLContextBuilder { self: SecureRandomBuilder => diff --git a/src/main/scala/io/iohk/ethereum/security/SSLContextFactory.scala b/src/main/scala/io/iohk/ethereum/security/SSLContextFactory.scala index 299b448ad9..99972cc4d8 100644 --- a/src/main/scala/io/iohk/ethereum/security/SSLContextFactory.scala +++ b/src/main/scala/io/iohk/ethereum/security/SSLContextFactory.scala @@ -1,15 +1,15 @@ package io.iohk.ethereum.security import java.io.FileInputStream -import java.security.{KeyStore, SecureRandom} - +import java.security.KeyStore +import java.security.SecureRandom import javax.net.ssl.SSLContext import scala.util.Try case class SSLContextFactory() extends FileUtils with KeyStoreUtils { - def createSSLContext(sslConfig: SSLConfig, secureRandom: SecureRandom): Either[SSLError, SSLContext] = { + def createSSLContext(sslConfig: SSLConfig, secureRandom: SecureRandom): Either[SSLError, SSLContext] = for { _ <- validateCertificateFiles( sslConfig.keyStorePath, @@ -17,20 +17,16 @@ case class SSLContextFactory() extends FileUtils with KeyStoreUtils { ) sslContext <- getSSLContext(sslConfig, secureRandom) } yield sslContext - } private def getSSLContext(sslConfig: SSLConfig, secureRandom: SecureRandom): Either[SSLError, SSLContext] = { val passwordReader = getReader(sslConfig.passwordFile) try { val password = passwordReader.getLines().mkString obtainSSLContext(secureRandom, sslConfig.keyStorePath, sslConfig.keyStoreType, password) - } finally { - passwordReader.close() - } + } finally passwordReader.close() } - /** - * Validates that the keystore certificate file and password file were configured and that the files exists + /** Validates that the keystore certificate file and password file were configured and that the files exists * * @param keystorePath with the path to the certificate keystore if it was configured * @param passwordFile with the path to the password file if it was configured @@ -52,8 +48,7 @@ case class SSLContextFactory() extends FileUtils with KeyStoreUtils { Right(()) } - /** - * Constructs the SSL context given a certificate + /** Constructs the SSL context given a certificate * * @param secureRandom * @param keyStorePath path to the keystore where the certificate is stored diff --git a/src/main/scala/io/iohk/ethereum/security/SecureRandomBuilder.scala b/src/main/scala/io/iohk/ethereum/security/SecureRandomBuilder.scala index 0c02c1d19c..261eed422c 100644 --- a/src/main/scala/io/iohk/ethereum/security/SecureRandomBuilder.scala +++ b/src/main/scala/io/iohk/ethereum/security/SecureRandomBuilder.scala @@ -2,10 +2,14 @@ package io.iohk.ethereum.security import java.security.SecureRandom -import com.typesafe.config.{Config, ConfigFactory} -import io.iohk.ethereum.utils.Logger +import scala.util.Failure +import scala.util.Success +import scala.util.Try + +import com.typesafe.config.Config +import com.typesafe.config.ConfigFactory -import scala.util.{Failure, Success, Try} +import io.iohk.ethereum.utils.Logger trait SecureRandomBuilder extends Logger { diff --git a/src/main/scala/io/iohk/ethereum/testmode/TestBlockchainBuilder.scala b/src/main/scala/io/iohk/ethereum/testmode/TestBlockchainBuilder.scala index 95e5522bf2..83e85c3b78 100644 --- a/src/main/scala/io/iohk/ethereum/testmode/TestBlockchainBuilder.scala +++ b/src/main/scala/io/iohk/ethereum/testmode/TestBlockchainBuilder.scala @@ -1,8 +1,8 @@ package io.iohk.ethereum.testmode -import akka.util.ByteString -import io.iohk.ethereum.domain.{BlockchainImpl, UInt256} -import io.iohk.ethereum.nodebuilder.{BlockchainBuilder, StorageBuilder} +import io.iohk.ethereum.domain.BlockchainImpl +import io.iohk.ethereum.nodebuilder.BlockchainBuilder +import io.iohk.ethereum.nodebuilder.StorageBuilder trait TestBlockchainBuilder extends BlockchainBuilder { self: StorageBuilder => diff --git a/src/main/scala/io/iohk/ethereum/testmode/TestEthBlockServiceWrapper.scala b/src/main/scala/io/iohk/ethereum/testmode/TestEthBlockServiceWrapper.scala index 328d5f78ce..396ea7ce69 100644 --- a/src/main/scala/io/iohk/ethereum/testmode/TestEthBlockServiceWrapper.scala +++ b/src/main/scala/io/iohk/ethereum/testmode/TestEthBlockServiceWrapper.scala @@ -1,20 +1,25 @@ package io.iohk.ethereum.testmode -import io.iohk.ethereum.domain.{Block, BlockHeader, Blockchain, BlockchainReader, SignedTransaction, UInt256} -import io.iohk.ethereum.jsonrpc.EthBlocksService.{BlockByBlockHashResponse, BlockByNumberResponse} -import io.iohk.ethereum.jsonrpc.{ - BaseBlockResponse, - BaseTransactionResponse, - EthBlocksService, - JsonRpcError, - ServiceResponse, - TransactionData -} -import io.iohk.ethereum.utils.Logger -import io.iohk.ethereum.utils.ByteStringUtils._ import akka.util.ByteString + import io.iohk.ethereum.consensus.Consensus +import io.iohk.ethereum.domain.Block +import io.iohk.ethereum.domain.BlockHeader +import io.iohk.ethereum.domain.Blockchain +import io.iohk.ethereum.domain.BlockchainReader +import io.iohk.ethereum.domain.SignedTransaction +import io.iohk.ethereum.domain.UInt256 +import io.iohk.ethereum.jsonrpc.BaseBlockResponse +import io.iohk.ethereum.jsonrpc.BaseTransactionResponse +import io.iohk.ethereum.jsonrpc.EthBlocksService +import io.iohk.ethereum.jsonrpc.EthBlocksService.BlockByBlockHashResponse +import io.iohk.ethereum.jsonrpc.EthBlocksService.BlockByNumberResponse +import io.iohk.ethereum.jsonrpc.JsonRpcError +import io.iohk.ethereum.jsonrpc.ServiceResponse +import io.iohk.ethereum.jsonrpc.TransactionData import io.iohk.ethereum.ledger.BlockQueue +import io.iohk.ethereum.utils.ByteStringUtils._ +import io.iohk.ethereum.utils.Logger class TestEthBlockServiceWrapper( blockchain: Blockchain, @@ -24,8 +29,7 @@ class TestEthBlockServiceWrapper( ) extends EthBlocksService(blockchain, blockchainReader, consensus, blockQueue) with Logger { - /** - * Implements the eth_getBlockByHash method that fetches a requested block. + /** Implements the eth_getBlockByHash method that fetches a requested block. * * @param request with the hash of the block requested * @return the block requested or None if the client doesn't have the block @@ -46,7 +50,7 @@ class TestEthBlockServiceWrapper( case BlockByBlockHashResponse(Some(baseBlockResponse)) => val ethResponseOpt = for { hash <- baseBlockResponse.hash - fullBlock <- blockchainReader.getBlockByHash(hash) orElse blockQueue.getBlockByHash(hash) + fullBlock <- blockchainReader.getBlockByHash(hash).orElse(blockQueue.getBlockByHash(hash)) } yield toEthResponse(fullBlock, baseBlockResponse) ethResponseOpt match { @@ -60,8 +64,7 @@ class TestEthBlockServiceWrapper( } ) - /** - * Implements the eth_getBlockByNumber method that fetches a requested block. + /** Implements the eth_getBlockByNumber method that fetches a requested block. * * @param request with the block requested (by it's number or by tag) * @return the block requested or None if the client doesn't have the block @@ -71,10 +74,10 @@ class TestEthBlockServiceWrapper( ): ServiceResponse[EthBlocksService.BlockByNumberResponse] = super .getBlockByNumber(request) .map( - _.map(blockByBlockResponse => { + _.map { blockByBlockResponse => val fullBlock = blockchainReader.getBlockByNumber(blockByBlockResponse.blockResponse.get.number).get BlockByNumberResponse(blockByBlockResponse.blockResponse.map(response => toEthResponse(fullBlock, response))) - }) + } ) private def toEthResponse(block: Block, response: BaseBlockResponse) = EthBlockResponse( @@ -103,11 +106,11 @@ class TestEthBlockServiceWrapper( private def toEthTransaction( block: Block, responseTransactions: Either[Seq[ByteString], Seq[BaseTransactionResponse]] - ): Either[Seq[ByteString], Seq[BaseTransactionResponse]] = responseTransactions.map(_ => { + ): Either[Seq[ByteString], Seq[BaseTransactionResponse]] = responseTransactions.map { _ => block.body.transactionList.zipWithIndex.map { case (stx, transactionIndex) => EthTransactionResponse(tx = TransactionData(stx, Some(block.header), Some(transactionIndex))) } - }) + } } case class EthBlockResponse( diff --git a/src/main/scala/io/iohk/ethereum/testmode/TestModeBlockExecution.scala b/src/main/scala/io/iohk/ethereum/testmode/TestModeBlockExecution.scala index 1c29781cf2..4542cc36a0 100644 --- a/src/main/scala/io/iohk/ethereum/testmode/TestModeBlockExecution.scala +++ b/src/main/scala/io/iohk/ethereum/testmode/TestModeBlockExecution.scala @@ -1,10 +1,15 @@ package io.iohk.ethereum.testmode -import akka.util.ByteString -import io.iohk.ethereum.crypto import io.iohk.ethereum.db.storage.EvmCodeStorage -import io.iohk.ethereum.domain.{Block, BlockHeader, BlockchainImpl, BlockchainReader, UInt256} -import io.iohk.ethereum.ledger.{BlockExecution, BlockPreparator, BlockValidation, InMemoryWorldStateProxy} +import io.iohk.ethereum.domain.Block +import io.iohk.ethereum.domain.BlockHeader +import io.iohk.ethereum.domain.BlockchainImpl +import io.iohk.ethereum.domain.BlockchainReader +import io.iohk.ethereum.domain.UInt256 +import io.iohk.ethereum.ledger.BlockExecution +import io.iohk.ethereum.ledger.BlockPreparator +import io.iohk.ethereum.ledger.BlockValidation +import io.iohk.ethereum.ledger.InMemoryWorldStateProxy import io.iohk.ethereum.utils.BlockchainConfig import io.iohk.ethereum.vm.EvmConfig diff --git a/src/main/scala/io/iohk/ethereum/testmode/TestModeComponentsProvider.scala b/src/main/scala/io/iohk/ethereum/testmode/TestModeComponentsProvider.scala index 91c1cb2208..679612adaa 100644 --- a/src/main/scala/io/iohk/ethereum/testmode/TestModeComponentsProvider.scala +++ b/src/main/scala/io/iohk/ethereum/testmode/TestModeComponentsProvider.scala @@ -1,21 +1,23 @@ package io.iohk.ethereum.testmode import akka.util.ByteString -import io.iohk.ethereum.consensus.difficulty.DifficultyCalculator + +import monix.execution.Scheduler + import io.iohk.ethereum.consensus.ConsensusConfig +import io.iohk.ethereum.consensus.difficulty.DifficultyCalculator import io.iohk.ethereum.crypto import io.iohk.ethereum.db.storage.EvmCodeStorage -import io.iohk.ethereum.domain.{BlockchainImpl, BlockchainReader, UInt256} -import io.iohk.ethereum.ledger.VMImpl +import io.iohk.ethereum.domain.BlockchainImpl +import io.iohk.ethereum.domain.BlockchainReader +import io.iohk.ethereum.domain.UInt256 +import io.iohk.ethereum.ledger.BlockImport +import io.iohk.ethereum.ledger.BlockQueue +import io.iohk.ethereum.ledger.BlockValidation import io.iohk.ethereum.ledger.StxLedger +import io.iohk.ethereum.ledger.VMImpl import io.iohk.ethereum.utils.BlockchainConfig import io.iohk.ethereum.utils.Config.SyncConfig -import monix.execution.Scheduler -import io.iohk.ethereum.ledger.BlockImport -import io.iohk.ethereum.ledger.BlockValidation -import io.iohk.ethereum.ledger.BlockQueue - -import scala.collection.immutable.HashMap /** Provides a ledger or consensus instances with modifiable blockchain config (used in test mode). */ class TestModeComponentsProvider( @@ -63,14 +65,12 @@ class TestModeComponentsProvider( ) } - /** - * Clear the internal builder state + /** Clear the internal builder state */ - def clearState(): Unit = { + def clearState(): Unit = // blockQueue = BlockQueue(blockchain, syncConfig) // cache = cache.empty internalBlockQueue.clear() - } def stxLedger(blockchainConfig: BlockchainConfig, sealEngine: SealEngineType): StxLedger = new StxLedger( diff --git a/src/main/scala/io/iohk/ethereum/testmode/TestModeServiceBuilder.scala b/src/main/scala/io/iohk/ethereum/testmode/TestModeServiceBuilder.scala index 284aee3993..bf5fc6ce18 100644 --- a/src/main/scala/io/iohk/ethereum/testmode/TestModeServiceBuilder.scala +++ b/src/main/scala/io/iohk/ethereum/testmode/TestModeServiceBuilder.scala @@ -1,10 +1,13 @@ package io.iohk.ethereum.testmode +import monix.execution.Scheduler + +import io.iohk.ethereum.consensus.ConsensusBuilder +import io.iohk.ethereum.consensus.ConsensusConfigBuilder import io.iohk.ethereum.consensus.difficulty.DifficultyCalculator -import io.iohk.ethereum.consensus.{Consensus, ConsensusBuilder, ConsensusConfigBuilder} import io.iohk.ethereum.ledger._ -import io.iohk.ethereum.nodebuilder.{ActorSystemBuilder, _} -import monix.execution.Scheduler +import io.iohk.ethereum.nodebuilder.ActorSystemBuilder +import io.iohk.ethereum.nodebuilder._ trait TestModeServiceBuilder extends StxLedgerBuilder { self: BlockchainConfigBuilder @@ -17,7 +20,7 @@ trait TestModeServiceBuilder extends StxLedgerBuilder { with BlockQueueBuilder with VmBuilder => - val scheduler = Scheduler(system.dispatchers.lookup("validation-context")) + val scheduler: Scheduler = Scheduler(system.dispatchers.lookup("validation-context")) lazy val testModeComponentsProvider: TestModeComponentsProvider = new TestModeComponentsProvider( diff --git a/src/main/scala/io/iohk/ethereum/testmode/TestModeWorldStateProxy.scala b/src/main/scala/io/iohk/ethereum/testmode/TestModeWorldStateProxy.scala index e114cc3a2f..0cb402acdb 100644 --- a/src/main/scala/io/iohk/ethereum/testmode/TestModeWorldStateProxy.scala +++ b/src/main/scala/io/iohk/ethereum/testmode/TestModeWorldStateProxy.scala @@ -1,11 +1,17 @@ package io.iohk.ethereum.testmode import akka.util.ByteString -import io.iohk.ethereum.db.storage.{EvmCodeStorage, MptStorage} + +import io.iohk.ethereum.db.storage.EvmCodeStorage import io.iohk.ethereum.db.storage.EvmCodeStorage.Code +import io.iohk.ethereum.db.storage.MptStorage +import io.iohk.ethereum.domain.Account import io.iohk.ethereum.domain.Account.accountSerializer -import io.iohk.ethereum.domain.{Account, Address, UInt256} -import io.iohk.ethereum.ledger.{InMemorySimpleMapProxy, InMemoryWorldStateProxy, InMemoryWorldStateProxyStorage} +import io.iohk.ethereum.domain.Address +import io.iohk.ethereum.domain.UInt256 +import io.iohk.ethereum.ledger.InMemorySimpleMapProxy +import io.iohk.ethereum.ledger.InMemoryWorldStateProxy +import io.iohk.ethereum.ledger.InMemoryWorldStateProxyStorage import io.iohk.ethereum.mpt.MerklePatriciaTrie /** This is a wrapper around InMemoryWorldStateProxy. @@ -57,12 +63,11 @@ case class TestModeWorldStateProxy( override def clearTouchedAccounts: TestModeWorldStateProxy = copy(touchedAccounts = touchedAccounts.empty) - override def keepPrecompileTouched(world: InMemoryWorldStateProxy): TestModeWorldStateProxy = { + override def keepPrecompileTouched(world: InMemoryWorldStateProxy): TestModeWorldStateProxy = if (world.touchedAccounts.contains(ripmdContractAddress)) copy(touchedAccounts = touchedAccounts + ripmdContractAddress) else this - } override def saveCode(address: Address, code: ByteString): TestModeWorldStateProxy = copy(accountCodes = accountCodes + (address -> code)) @@ -83,7 +88,7 @@ object TestModeWorldStateProxy { noEmptyAccounts: Boolean, ethCompatibleStorage: Boolean, saveStoragePreimage: (UInt256) => Unit - ): TestModeWorldStateProxy = { + ): TestModeWorldStateProxy = new TestModeWorldStateProxy( stateStorage = nodesKeyValueStorage, accountsStateTrie = createProxiedAccountsStateTrie(nodesKeyValueStorage, stateRootHash), @@ -97,17 +102,15 @@ object TestModeWorldStateProxy { ethCompatibleStorage = ethCompatibleStorage, saveStoragePreimage = saveStoragePreimage ) - } private def createProxiedAccountsStateTrie( accountsStorage: MptStorage, stateRootHash: ByteString - ): InMemorySimpleMapProxy[Address, Account, MerklePatriciaTrie[Address, Account]] = { + ): InMemorySimpleMapProxy[Address, Account, MerklePatriciaTrie[Address, Account]] = InMemorySimpleMapProxy.wrap[Address, Account, MerklePatriciaTrie[Address, Account]]( MerklePatriciaTrie[Address, Account]( stateRootHash.toArray[Byte], accountsStorage )(Address.hashedAddressEncoder, accountSerializer) ) - } } diff --git a/src/main/scala/io/iohk/ethereum/testmode/TestmodeConsensus.scala b/src/main/scala/io/iohk/ethereum/testmode/TestmodeConsensus.scala index 08918a6972..c0fc44ba23 100644 --- a/src/main/scala/io/iohk/ethereum/testmode/TestmodeConsensus.scala +++ b/src/main/scala/io/iohk/ethereum/testmode/TestmodeConsensus.scala @@ -1,22 +1,36 @@ package io.iohk.ethereum.testmode import akka.util.ByteString + +import monix.eval.Task + import io.iohk.ethereum.consensus._ -import io.iohk.ethereum.consensus.blocks.{BlockTimestampProvider, NoOmmersBlockGenerator, TestBlockGenerator} +import io.iohk.ethereum.consensus.blocks.BlockTimestampProvider +import io.iohk.ethereum.consensus.blocks.NoOmmersBlockGenerator +import io.iohk.ethereum.consensus.blocks.TestBlockGenerator import io.iohk.ethereum.consensus.difficulty.DifficultyCalculator import io.iohk.ethereum.consensus.pow.miners.MinerProtocol -import io.iohk.ethereum.consensus.pow.miners.MockedMiner.{MockedMinerProtocol, MockedMinerResponse} +import io.iohk.ethereum.consensus.pow.miners.MockedMiner.MockedMinerProtocol +import io.iohk.ethereum.consensus.pow.miners.MockedMiner.MockedMinerResponse import io.iohk.ethereum.consensus.pow.miners.MockedMiner.MockedMinerResponses.MinerNotExist +import io.iohk.ethereum.consensus.pow.validators.ValidatorsExecutor import io.iohk.ethereum.consensus.validators._ -import io.iohk.ethereum.consensus.validators.std.{StdBlockValidator, StdSignedTransactionValidator} -import io.iohk.ethereum.domain.{Block, BlockBody, BlockHeader, BlockchainImpl, BlockchainReader, Receipt} +import io.iohk.ethereum.consensus.validators.std.StdBlockValidator +import io.iohk.ethereum.consensus.validators.std.StdSignedTransactionValidator +import io.iohk.ethereum.db.storage.EvmCodeStorage +import io.iohk.ethereum.domain.Block +import io.iohk.ethereum.domain.BlockBody +import io.iohk.ethereum.domain.BlockHeader +import io.iohk.ethereum.domain.BlockchainImpl +import io.iohk.ethereum.domain.BlockchainReader +import io.iohk.ethereum.domain.Receipt +import io.iohk.ethereum.ledger.BlockExecutionError +import io.iohk.ethereum.ledger.BlockExecutionSuccess +import io.iohk.ethereum.ledger.BlockPreparator +import io.iohk.ethereum.ledger.InMemoryWorldStateProxy import io.iohk.ethereum.ledger.VMImpl -import io.iohk.ethereum.ledger.{BlockExecutionError, BlockExecutionSuccess, BlockPreparator, InMemoryWorldStateProxy} import io.iohk.ethereum.nodebuilder._ import io.iohk.ethereum.utils.BlockchainConfig -import monix.eval.Task -import io.iohk.ethereum.consensus.pow.validators.ValidatorsExecutor -import io.iohk.ethereum.db.storage.EvmCodeStorage class TestmodeConsensus( override val vm: VMImpl, @@ -106,13 +120,11 @@ class TestmodeConsensus( override def startProtocol(node: Node): Unit = {} override def stopProtocol(): Unit = {} - /** - * Sends msg to the internal miner and waits for the response + /** Sends msg to the internal miner and waits for the response */ override def askMiner(msg: MockedMinerProtocol): Task[MockedMinerResponse] = Task.now(MinerNotExist) - /** - * Sends msg to the internal miner + /** Sends msg to the internal miner */ override def sendMiner(msg: MinerProtocol): Unit = {} } diff --git a/src/main/scala/io/iohk/ethereum/transactions/PendingTransactionsManager.scala b/src/main/scala/io/iohk/ethereum/transactions/PendingTransactionsManager.scala index c5f188e8a4..f2af8458ba 100644 --- a/src/main/scala/io/iohk/ethereum/transactions/PendingTransactionsManager.scala +++ b/src/main/scala/io/iohk/ethereum/transactions/PendingTransactionsManager.scala @@ -1,22 +1,36 @@ package io.iohk.ethereum.transactions -import akka.actor.{Actor, ActorLogging, ActorRef, Props} -import akka.util.{ByteString, Timeout} -import com.google.common.cache.{Cache, CacheBuilder, RemovalNotification} -import io.iohk.ethereum.domain.{SignedTransaction, SignedTransactionWithSender} +import akka.actor.Actor +import akka.actor.ActorLogging +import akka.actor.ActorRef +import akka.actor.Props +import akka.util.ByteString +import akka.util.Timeout + +import scala.concurrent.ExecutionContext.Implicits.global +import scala.concurrent.duration._ +import scala.jdk.CollectionConverters._ + +import com.google.common.cache.Cache +import com.google.common.cache.CacheBuilder +import com.google.common.cache.RemovalNotification + +import io.iohk.ethereum.domain.SignedTransaction +import io.iohk.ethereum.domain.SignedTransactionWithSender import io.iohk.ethereum.metrics.MetricsContainer -import io.iohk.ethereum.network.PeerEventBusActor.{PeerEvent, Subscribe, SubscriptionClassifier} +import io.iohk.ethereum.network.EtcPeerManagerActor +import io.iohk.ethereum.network.Peer +import io.iohk.ethereum.network.PeerEventBusActor.PeerEvent +import io.iohk.ethereum.network.PeerEventBusActor.Subscribe +import io.iohk.ethereum.network.PeerEventBusActor.SubscriptionClassifier +import io.iohk.ethereum.network.PeerId +import io.iohk.ethereum.network.PeerManagerActor import io.iohk.ethereum.network.PeerManagerActor.Peers import io.iohk.ethereum.network.p2p.messages.BaseETH6XMessages.SignedTransactions -import io.iohk.ethereum.network.{EtcPeerManagerActor, Peer, PeerId, PeerManagerActor} import io.iohk.ethereum.transactions.SignedTransactionsFilterActor.ProperSignedTransactions import io.iohk.ethereum.utils.ByteStringUtils.ByteStringOps import io.iohk.ethereum.utils.TxPoolConfig -import scala.jdk.CollectionConverters._ -import scala.concurrent.ExecutionContext.Implicits.global -import scala.concurrent.duration._ - object PendingTransactionsManager { def props( txPoolConfig: TxPoolConfig, @@ -60,19 +74,16 @@ class PendingTransactionsManager( import PendingTransactionsManager._ import akka.pattern.ask - private[this] final val TransactionsPoolSizeGauge = - metrics.gauge( - "transactions.pool.size.gauge", - () => pendingTransactions.size().toDouble - ) + metrics.gauge( + "transactions.pool.size.gauge", + () => pendingTransactions.size().toDouble + ) - /** - * stores information which tx hashes are "known" by which peers + /** stores information which tx hashes are "known" by which peers */ var knownTransactions: Map[ByteString, Set[PeerId]] = Map.empty - /** - * stores all pending transactions + /** stores all pending transactions */ val pendingTransactions: Cache[ByteString, PendingTransaction] = CacheBuilder .newBuilder() @@ -115,7 +126,7 @@ class PendingTransactionsManager( .mapTo[Peers] .map(_.handshaked) .filter(_.nonEmpty) - .foreach { peers => self ! NotifyPeers(transactionsToAdd.toSeq, peers) } + .foreach(peers => self ! NotifyPeers(transactionsToAdd.toSeq, peers)) } case AddOrOverrideTransaction(newStx) => @@ -137,7 +148,7 @@ class PendingTransactionsManager( .mapTo[Peers] .map(_.handshaked) .filter(_.nonEmpty) - .foreach { peers => self ! NotifyPeers(Seq(newPendingTx), peers) } + .foreach(peers => self ! NotifyPeers(Seq(newPendingTx), peers)) case NotifyPeers(signedTransactions, peers) => pendingTransactions.cleanUp() diff --git a/src/main/scala/io/iohk/ethereum/transactions/SignedTransactionsFilterActor.scala b/src/main/scala/io/iohk/ethereum/transactions/SignedTransactionsFilterActor.scala index 3602df113f..c15325a89c 100644 --- a/src/main/scala/io/iohk/ethereum/transactions/SignedTransactionsFilterActor.scala +++ b/src/main/scala/io/iohk/ethereum/transactions/SignedTransactionsFilterActor.scala @@ -1,14 +1,19 @@ package io.iohk.ethereum.transactions -import akka.actor.{Actor, ActorRef, Props} -import akka.dispatch.{BoundedMessageQueueSemantics, RequiresMessageQueue} +import akka.actor.Actor +import akka.actor.ActorRef +import akka.actor.Props +import akka.dispatch.BoundedMessageQueueSemantics +import akka.dispatch.RequiresMessageQueue + import io.iohk.ethereum.domain.SignedTransactionWithSender import io.iohk.ethereum.network.PeerEventBusActor.PeerEvent.MessageFromPeer -import io.iohk.ethereum.network.PeerEventBusActor.{PeerSelector, Subscribe} +import io.iohk.ethereum.network.PeerEventBusActor.PeerSelector +import io.iohk.ethereum.network.PeerEventBusActor.Subscribe import io.iohk.ethereum.network.PeerEventBusActor.SubscriptionClassifier.MessageClassifier import io.iohk.ethereum.network.PeerId -import io.iohk.ethereum.network.p2p.messages.Codes import io.iohk.ethereum.network.p2p.messages.BaseETH6XMessages.SignedTransactions +import io.iohk.ethereum.network.p2p.messages.Codes import io.iohk.ethereum.transactions.SignedTransactionsFilterActor.ProperSignedTransactions class SignedTransactionsFilterActor(pendingTransactionsManager: ActorRef, peerEventBus: ActorRef) diff --git a/src/main/scala/io/iohk/ethereum/transactions/TransactionHistoryService.scala b/src/main/scala/io/iohk/ethereum/transactions/TransactionHistoryService.scala index 2fb39652b7..96999adafd 100644 --- a/src/main/scala/io/iohk/ethereum/transactions/TransactionHistoryService.scala +++ b/src/main/scala/io/iohk/ethereum/transactions/TransactionHistoryService.scala @@ -2,22 +2,24 @@ package io.iohk.ethereum.transactions import akka.actor.ActorRef import akka.util.Timeout + import cats.implicits._ -import io.iohk.ethereum.domain._ -import io.iohk.ethereum.jsonrpc.AkkaTaskOps.TaskActorOps -import io.iohk.ethereum.transactions.PendingTransactionsManager.PendingTransaction -import io.iohk.ethereum.transactions.TransactionHistoryService.{ - ExtendedTransactionData, - MinedTxChecker, - PendingTxChecker -} -import io.iohk.ethereum.utils.Logger + import monix.eval.Task -import monix.reactive.{Observable, OverflowStrategy} +import monix.reactive.Observable +import monix.reactive.OverflowStrategy import scala.collection.immutable.NumericRange import scala.concurrent.duration.FiniteDuration +import io.iohk.ethereum.domain._ +import io.iohk.ethereum.jsonrpc.AkkaTaskOps.TaskActorOps +import io.iohk.ethereum.transactions.PendingTransactionsManager.PendingTransaction +import io.iohk.ethereum.transactions.TransactionHistoryService.ExtendedTransactionData +import io.iohk.ethereum.transactions.TransactionHistoryService.MinedTxChecker +import io.iohk.ethereum.transactions.TransactionHistoryService.PendingTxChecker +import io.iohk.ethereum.utils.Logger + class TransactionHistoryService( blockchain: Blockchain, blockchainReader: BlockchainReader, @@ -28,10 +30,10 @@ class TransactionHistoryService( account: Address, fromBlocks: NumericRange[BigInt] ): Task[List[ExtendedTransactionData]] = { - val getLastCheckpoint = Task { blockchain.getLatestCheckpointBlockNumber() }.memoizeOnSuccess + val getLastCheckpoint = Task(blockchain.getLatestCheckpointBlockNumber()).memoizeOnSuccess val txnsFromBlocks = Observable .from(fromBlocks.reverse) - .mapParallelOrdered(10)(blockNr => Task { blockchainReader.getBlockByNumber(blockNr) })( + .mapParallelOrdered(10)(blockNr => Task(blockchainReader.getBlockByNumber(blockNr)))( OverflowStrategy.Unbounded ) .collect { case Some(block) => block } @@ -54,7 +56,7 @@ class TransactionHistoryService( } .toListL - val txnsFromMempool = getTransactionsFromPool map { pendingTransactions => + val txnsFromMempool = getTransactionsFromPool.map { pendingTransactions => pendingTransactions .collect(Function.unlift(PendingTxChecker.checkTx(_, account))) } @@ -96,7 +98,7 @@ object TransactionHistoryService { tx.stx.tx.tx.receivingAddress.contains(maybeReceiver) def asSigned(tx: PendingTransaction): SignedTransaction = tx.stx.tx - def checkTx(tx: PendingTransaction, address: Address): Option[ExtendedTransactionData] = { + def checkTx(tx: PendingTransaction, address: Address): Option[ExtendedTransactionData] = if (isSender(tx, address)) { Some(ExtendedTransactionData(asSigned(tx), isOutgoing = true, None)) } else if (isReceiver(tx, address)) { @@ -104,7 +106,6 @@ object TransactionHistoryService { } else { None } - } } object MinedTxChecker { @@ -115,7 +116,7 @@ object TransactionHistoryService { def checkTx( tx: SignedTransaction, address: Address - ): Option[(SignedTransaction, MinedTransactionData => ExtendedTransactionData)] = { + ): Option[(SignedTransaction, MinedTransactionData => ExtendedTransactionData)] = if (isSender(tx, address)) { Some((tx, data => ExtendedTransactionData(tx, isOutgoing = true, Some(data)))) } else if (isReceiver(tx, address)) { @@ -123,7 +124,6 @@ object TransactionHistoryService { } else { None } - } def getMinedTxData( tx: SignedTransaction, diff --git a/src/main/scala/io/iohk/ethereum/transactions/TransactionPicker.scala b/src/main/scala/io/iohk/ethereum/transactions/TransactionPicker.scala index 19b5f51f2b..ad976f5d6d 100644 --- a/src/main/scala/io/iohk/ethereum/transactions/TransactionPicker.scala +++ b/src/main/scala/io/iohk/ethereum/transactions/TransactionPicker.scala @@ -2,12 +2,15 @@ package io.iohk.ethereum.transactions import akka.actor.ActorRef import akka.util.Timeout + +import monix.eval.Task + +import scala.concurrent.duration.FiniteDuration + import io.iohk.ethereum.jsonrpc.AkkaTaskOps.TaskActorOps import io.iohk.ethereum.transactions.PendingTransactionsManager import io.iohk.ethereum.transactions.PendingTransactionsManager.PendingTransactionsResponse import io.iohk.ethereum.utils.Logger -import monix.eval.Task -import scala.concurrent.duration.FiniteDuration trait TransactionPicker extends Logger { @@ -16,12 +19,11 @@ trait TransactionPicker extends Logger { implicit val timeout: Timeout = Timeout(getTransactionFromPoolTimeout) - def getTransactionsFromPool: Task[PendingTransactionsResponse] = { + def getTransactionsFromPool: Task[PendingTransactionsResponse] = pendingTransactionsManager .askFor[PendingTransactionsResponse](PendingTransactionsManager.GetPendingTransactions) .onErrorHandle { ex => log.error("Failed to get transactions, mining block with empty transactions list", ex) PendingTransactionsResponse(Nil) } - } } diff --git a/src/main/scala/io/iohk/ethereum/utils/BlockchainConfig.scala b/src/main/scala/io/iohk/ethereum/utils/BlockchainConfig.scala index 07b2bc2133..1d5e15d616 100644 --- a/src/main/scala/io/iohk/ethereum/utils/BlockchainConfig.scala +++ b/src/main/scala/io/iohk/ethereum/utils/BlockchainConfig.scala @@ -1,14 +1,17 @@ package io.iohk.ethereum.utils import akka.util.ByteString -import com.typesafe.config.{Config => TypesafeConfig} -import io.iohk.ethereum.domain.{Address, UInt256} -import io.iohk.ethereum.utils.NumericUtils._ import scala.jdk.CollectionConverters._ import scala.util.Try + import com.typesafe.config.ConfigRenderOptions +import com.typesafe.config.{Config => TypesafeConfig} + +import io.iohk.ethereum.domain.Address +import io.iohk.ethereum.domain.UInt256 import io.iohk.ethereum.network.p2p.messages.Capability +import io.iohk.ethereum.utils.NumericUtils._ case class BlockchainConfig( powTargetTime: Option[Long] = None, @@ -63,7 +66,7 @@ case class ForkBlockNumbers( case i: Option[_] => i.flatMap { case n if n.isInstanceOf[BigInt] => Some(n.asInstanceOf[BigInt]) - case n => None + case n => None } case default => None } diff --git a/src/main/scala/io/iohk/ethereum/utils/Config.scala b/src/main/scala/io/iohk/ethereum/utils/Config.scala index 4ec999da1a..ccc36ef732 100644 --- a/src/main/scala/io/iohk/ethereum/utils/Config.scala +++ b/src/main/scala/io/iohk/ethereum/utils/Config.scala @@ -2,23 +2,32 @@ package io.iohk.ethereum.utils import java.net.InetSocketAddress -import akka.util.{ByteString, Timeout} -import com.typesafe.config.{ConfigFactory, Config => TypesafeConfig} +import akka.util.ByteString +import akka.util.Timeout + +import scala.concurrent.duration._ +import scala.jdk.CollectionConverters._ +import scala.util.Try + +import com.typesafe.config.ConfigFactory +import com.typesafe.config.{Config => TypesafeConfig} + import io.iohk.ethereum.db.dataSource.RocksDbConfig -import io.iohk.ethereum.db.storage.pruning.{ArchivePruning, BasicPruning, InMemoryPruning, PruningMode} +import io.iohk.ethereum.db.storage.pruning.ArchivePruning +import io.iohk.ethereum.db.storage.pruning.BasicPruning +import io.iohk.ethereum.db.storage.pruning.InMemoryPruning +import io.iohk.ethereum.db.storage.pruning.PruningMode import io.iohk.ethereum.domain.Address -import io.iohk.ethereum.network.PeerManagerActor.{FastSyncHostConfiguration, PeerConfiguration} +import io.iohk.ethereum.network.PeerManagerActor.FastSyncHostConfiguration +import io.iohk.ethereum.network.PeerManagerActor.PeerConfiguration import io.iohk.ethereum.network.rlpx.RLPxConnectionHandler.RLPxConfiguration import io.iohk.ethereum.utils.VmConfig.VmMode -import ConfigUtils._ -import scala.jdk.CollectionConverters._ -import scala.concurrent.duration._ -import scala.util.Try +import ConfigUtils._ object Config { - val config = ConfigFactory.load().getConfig("mantis") + val config: TypesafeConfig = ConfigFactory.load().getConfig("mantis") val testmode: Boolean = config.getBoolean("testmode") @@ -40,7 +49,7 @@ object Config { object Network { private val networkConfig = config.getConfig("network") - val automaticPortForwarding = networkConfig.getBoolean("automatic-port-forwarding") + val automaticPortForwarding: Boolean = networkConfig.getBoolean("automatic-port-forwarding") object Server { private val serverConfig = networkConfig.getConfig("server-address") @@ -50,7 +59,7 @@ object Config { val listenAddress = new InetSocketAddress(interface, port) } - val peer = new PeerConfiguration { + val peer: PeerConfiguration = new PeerConfiguration { private val peerConfig = networkConfig.getConfig("peer") private val blockchainConfig: BlockchainConfig = blockchains.blockchainConfig @@ -248,13 +257,12 @@ object KeyStoreConfig { } } - def customKeyStoreConfig(path: String): KeyStoreConfig = { + def customKeyStoreConfig(path: String): KeyStoreConfig = new KeyStoreConfig { val keyStoreDir: String = path val minimalPassphraseLength: Int = 7 val allowNoPassphrase: Boolean = true } - } } trait FilterConfig { @@ -369,7 +377,7 @@ case class MonetaryPolicyConfig( } object MonetaryPolicyConfig { - def apply(mpConfig: TypesafeConfig): MonetaryPolicyConfig = { + def apply(mpConfig: TypesafeConfig): MonetaryPolicyConfig = MonetaryPolicyConfig( mpConfig.getInt("era-duration"), mpConfig.getDouble("reward-reduction-rate"), @@ -377,7 +385,6 @@ object MonetaryPolicyConfig { BigInt(mpConfig.getString("first-era-reduced-block-reward")), BigInt(mpConfig.getString("first-era-constantinople-reduced-block-reward")) ) - } } trait PruningConfig { @@ -389,8 +396,8 @@ object PruningConfig { val pruningConfig = etcClientConfig.getConfig("pruning") val pruningMode: PruningMode = pruningConfig.getString("mode") match { - case "basic" => BasicPruning(pruningConfig.getInt("history")) - case "archive" => ArchivePruning + case "basic" => BasicPruning(pruningConfig.getInt("history")) + case "archive" => ArchivePruning case "inmemory" => InMemoryPruning(pruningConfig.getInt("history")) } @@ -416,7 +423,7 @@ object VmConfig { val VmTypeMantis = "mantis" val VmTypeNone = "none" - val supportedVmTypes = Set(VmTypeIele, VmTypeKevm, VmTypeMantis, VmTypeNone) + val supportedVmTypes: Set[String] = Set(VmTypeIele, VmTypeKevm, VmTypeMantis, VmTypeNone) } case class ExternalConfig(vmType: String, executablePath: Option[String], host: String, port: Int) @@ -443,7 +450,7 @@ object VmConfig { mpConfig.getString("vm.mode") match { case "internal" => VmConfig(VmMode.Internal, None) case "external" => VmConfig(VmMode.External, Some(parseExternalConfig())) - case other => throw new RuntimeException(s"Unknown VM mode: $other. Expected one of: local, external") + case other => throw new RuntimeException(s"Unknown VM mode: $other. Expected one of: local, external") } } } diff --git a/src/main/scala/io/iohk/ethereum/utils/ConfigUtils.scala b/src/main/scala/io/iohk/ethereum/utils/ConfigUtils.scala index d84e8ae42d..3ef52a500a 100644 --- a/src/main/scala/io/iohk/ethereum/utils/ConfigUtils.scala +++ b/src/main/scala/io/iohk/ethereum/utils/ConfigUtils.scala @@ -1,25 +1,28 @@ package io.iohk.ethereum.utils -import akka.http.scaladsl.model.headers.HttpOrigin -import ch.megard.akka.http.cors.scaladsl.model.HttpOriginMatcher -import com.typesafe.config.{ConfigValue, Config => TypesafeConfig} import java.util.Map.Entry + +import akka.http.scaladsl.model.headers.HttpOrigin + import scala.jdk.CollectionConverters._ import scala.util.Try +import ch.megard.akka.http.cors.scaladsl.model.HttpOriginMatcher +import com.typesafe.config.ConfigValue +import com.typesafe.config.{Config => TypesafeConfig} + object ConfigUtils { - def parseCorsAllowedOrigins(config: TypesafeConfig, key: String): HttpOriginMatcher = { - (Try(parseMultipleOrigins(config.getStringList(key).asScala.toSeq)) recoverWith { case _ => + def parseCorsAllowedOrigins(config: TypesafeConfig, key: String): HttpOriginMatcher = + Try(parseMultipleOrigins(config.getStringList(key).asScala.toSeq)).recoverWith { case _ => Try(parseSingleOrigin(config.getString(key))) - }).get - } + }.get def parseMultipleOrigins(origins: Seq[String]): HttpOriginMatcher = HttpOriginMatcher(origins.map(HttpOrigin(_)): _*) def parseSingleOrigin(origin: String): HttpOriginMatcher = origin match { case "*" => HttpOriginMatcher.* - case s => HttpOriginMatcher.Default(HttpOrigin(s) :: Nil) + case s => HttpOriginMatcher.Default(HttpOrigin(s) :: Nil) } def getOptionalValue[V](config: TypesafeConfig, getter: TypesafeConfig => String => V, path: String): Option[V] = diff --git a/src/main/scala/io/iohk/ethereum/utils/FunctorOps.scala b/src/main/scala/io/iohk/ethereum/utils/FunctorOps.scala index 56ba1dd2ce..258cfc2d86 100644 --- a/src/main/scala/io/iohk/ethereum/utils/FunctorOps.scala +++ b/src/main/scala/io/iohk/ethereum/utils/FunctorOps.scala @@ -2,14 +2,14 @@ package io.iohk.ethereum.utils import cats.Functor -import scala.language.{higherKinds, implicitConversions} +import scala.language.implicitConversions class FunctorOps[A, F[_]: Functor](f: F[A]) { def tap[B](cb: A => Unit): F[A] = - Functor[F].map(f)(a => { + Functor[F].map(f) { a => cb(a) a - }) + } } object FunctorOps { implicit def functorToFunctorOps[A, F[_]: Functor](f: F[A]): FunctorOps[A, F] = new FunctorOps(f) diff --git a/src/main/scala/io/iohk/ethereum/utils/LoadFromApplicationConfiguration.scala b/src/main/scala/io/iohk/ethereum/utils/LoadFromApplicationConfiguration.scala index 2b9e3d2269..4253f84bb2 100644 --- a/src/main/scala/io/iohk/ethereum/utils/LoadFromApplicationConfiguration.scala +++ b/src/main/scala/io/iohk/ethereum/utils/LoadFromApplicationConfiguration.scala @@ -5,14 +5,12 @@ import ch.qos.logback.core.joran.spi.InterpretationContext import com.typesafe.config.ConfigFactory import org.xml.sax.Attributes -/** - * Make properties defined in application.conf available to logback +/** Make properties defined in application.conf available to logback */ class LoadFromApplicationConfiguration extends Action { val config = ConfigFactory.load - override def begin(ic: InterpretationContext, body: String, attributes: Attributes): Unit = { + override def begin(ic: InterpretationContext, body: String, attributes: Attributes): Unit = ic.addSubstitutionProperty(attributes.getValue("as"), config.getString(attributes.getValue("key"))) - } override def end(ic: InterpretationContext, body: String): Unit = () } diff --git a/src/main/scala/io/iohk/ethereum/utils/Logger.scala b/src/main/scala/io/iohk/ethereum/utils/Logger.scala index fc8f9038a2..508c557f32 100644 --- a/src/main/scala/io/iohk/ethereum/utils/Logger.scala +++ b/src/main/scala/io/iohk/ethereum/utils/Logger.scala @@ -1,7 +1,8 @@ package io.iohk.ethereum.utils import com.typesafe.scalalogging -import org.slf4j.{LoggerFactory, MDC} +import org.slf4j.LoggerFactory +import org.slf4j.MDC trait Logger { protected val log: scalalogging.Logger = com.typesafe.scalalogging.Logger(LoggerFactory.getLogger(getClass)) diff --git a/src/main/scala/io/iohk/ethereum/utils/NodeStatus.scala b/src/main/scala/io/iohk/ethereum/utils/NodeStatus.scala index 4748204438..767b282ffa 100644 --- a/src/main/scala/io/iohk/ethereum/utils/NodeStatus.scala +++ b/src/main/scala/io/iohk/ethereum/utils/NodeStatus.scala @@ -2,10 +2,11 @@ package io.iohk.ethereum.utils import java.net.InetSocketAddress -import io.iohk.ethereum.network._ import org.bouncycastle.crypto.AsymmetricCipherKeyPair import org.bouncycastle.crypto.params.ECPublicKeyParameters +import io.iohk.ethereum.network._ + sealed trait ServerStatus object ServerStatus { case object NotListening extends ServerStatus @@ -14,5 +15,5 @@ object ServerStatus { case class NodeStatus(key: AsymmetricCipherKeyPair, serverStatus: ServerStatus, discoveryStatus: ServerStatus) { - val nodeId = key.getPublic.asInstanceOf[ECPublicKeyParameters].toNodeId + val nodeId: Array[Byte] = key.getPublic.asInstanceOf[ECPublicKeyParameters].toNodeId } diff --git a/src/main/scala/io/iohk/ethereum/utils/Picklers.scala b/src/main/scala/io/iohk/ethereum/utils/Picklers.scala index 7d23a633b7..1da8e6506b 100644 --- a/src/main/scala/io/iohk/ethereum/utils/Picklers.scala +++ b/src/main/scala/io/iohk/ethereum/utils/Picklers.scala @@ -1,12 +1,19 @@ package io.iohk.ethereum.utils import akka.util.ByteString + import boopickle.DefaultBasic._ import boopickle.Pickler + import io.iohk.ethereum.crypto.ECDSASignature +import io.iohk.ethereum.domain.Address +import io.iohk.ethereum.domain.BlockBody +import io.iohk.ethereum.domain.BlockHeader import io.iohk.ethereum.domain.BlockHeader.HeaderExtraFields import io.iohk.ethereum.domain.BlockHeader.HeaderExtraFields._ -import io.iohk.ethereum.domain.{Address, BlockBody, BlockHeader, Checkpoint, SignedTransaction, Transaction} +import io.iohk.ethereum.domain.Checkpoint +import io.iohk.ethereum.domain.SignedTransaction +import io.iohk.ethereum.domain.Transaction object Picklers { implicit val byteStringPickler: Pickler[ByteString] = @@ -27,11 +34,11 @@ object Picklers { implicit val signedTransactionPickler: Pickler[SignedTransaction] = transformPickler[SignedTransaction, (Transaction, ECDSASignature)] { case (tx, signature) => new SignedTransaction(tx, signature) - } { stx => (stx.tx, stx.signature) } + }(stx => (stx.tx, stx.signature)) implicit val blockHeaderPickler: Pickler[BlockHeader] = generatePickler[BlockHeader] implicit val blockBodyPickler: Pickler[BlockBody] = transformPickler[BlockBody, (Seq[SignedTransaction], Seq[BlockHeader])] { case (stx, nodes) => BlockBody(stx, nodes) - } { blockBody => (blockBody.transactionList, blockBody.uncleNodesList) } + }(blockBody => (blockBody.transactionList, blockBody.uncleNodesList)) } diff --git a/src/main/scala/io/iohk/ethereum/utils/Ref.scala b/src/main/scala/io/iohk/ethereum/utils/Ref.scala index cebaa882ec..277e96883c 100644 --- a/src/main/scala/io/iohk/ethereum/utils/Ref.scala +++ b/src/main/scala/io/iohk/ethereum/utils/Ref.scala @@ -2,11 +2,10 @@ package io.iohk.ethereum.utils import java.util.concurrent.atomic.AtomicReference -/** - * An [[https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/atomic/AtomicReference.html AtomicReference]] that can be set once. +/** An [[https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/atomic/AtomicReference.html AtomicReference]] that can be set once. */ class Ref[T <: AnyRef] { - private[this] final val ref = new AtomicReference[Option[T]](None) + final private[this] val ref = new AtomicReference[Option[T]](None) // set once (but not necessarily compute once) final def setOnce(t: => T): Boolean = ref.get().isEmpty && ref.compareAndSet(None, Some(t)) diff --git a/src/main/scala/io/iohk/ethereum/utils/TryWithResources.scala b/src/main/scala/io/iohk/ethereum/utils/TryWithResources.scala index a5701951f4..3b31a76604 100644 --- a/src/main/scala/io/iohk/ethereum/utils/TryWithResources.scala +++ b/src/main/scala/io/iohk/ethereum/utils/TryWithResources.scala @@ -9,27 +9,22 @@ object TryWithResources { val resource: R = r require(resource != null, "resource is null") var exception: Throwable = null - try { - f(resource) - } catch { + try f(resource) + catch { case NonFatal(e) => exception = e throw e - } finally { - closeAndAddSuppressed(exception, resource) - } + } finally closeAndAddSuppressed(exception, resource) } - private def closeAndAddSuppressed(e: Throwable, resource: AutoCloseable): Unit = { + private def closeAndAddSuppressed(e: Throwable, resource: AutoCloseable): Unit = if (e != null) { - try { - resource.close() - } catch { + try resource.close() + catch { case NonFatal(suppressed) => e.addSuppressed(suppressed) } } else { resource.close() } - } } diff --git a/src/main/scala/io/iohk/ethereum/utils/ValidationUtils.scala b/src/main/scala/io/iohk/ethereum/utils/ValidationUtils.scala index c7b6f09912..c81b0aed17 100644 --- a/src/main/scala/io/iohk/ethereum/utils/ValidationUtils.scala +++ b/src/main/scala/io/iohk/ethereum/utils/ValidationUtils.scala @@ -2,8 +2,7 @@ package io.iohk.ethereum.utils object ValidationUtils { - /** - * This function combines multiple validations on object. + /** This function combines multiple validations on object. * * @param obj object to return if all validations pass . * @param eithers list of required validations. diff --git a/src/main/scala/io/iohk/ethereum/vm/Blake2bCompression.scala b/src/main/scala/io/iohk/ethereum/vm/Blake2bCompression.scala index 909bc48515..0b9029000c 100644 --- a/src/main/scala/io/iohk/ethereum/vm/Blake2bCompression.scala +++ b/src/main/scala/io/iohk/ethereum/vm/Blake2bCompression.scala @@ -34,8 +34,7 @@ object Blake2bCompression { def parseNumberOfRounds(input: Array[Byte]): Long = Integer.toUnsignedLong(bytesToInt(copyOfRange(input, 0, 4))) - /** - * Parses input according to the rules defined in: https://eips.ethereum.org/EIPS/eip-152 + /** Parses input according to the rules defined in: https://eips.ethereum.org/EIPS/eip-152 * The encoded inputs are corresponding to the ones specified in the BLAKE2 RFC Section 3.2: * * rounds - the number of rounds - 32-bit unsigned big-endian word @@ -73,7 +72,7 @@ object Blake2bCompression { (rounds, h, m, t, f) } - def blake2bCompress(input: Array[Byte]): Option[Array[Byte]] = { + def blake2bCompress(input: Array[Byte]): Option[Array[Byte]] = if (isValidInput(input)) { val (rounds, h, m, t, f) = parseInput(input) compress(rounds, h, m, t, f) @@ -81,7 +80,6 @@ object Blake2bCompression { } else { None } - } private def convertToBytes(h: Array[Long]): Array[Byte] = { var i = 0 diff --git a/src/main/scala/io/iohk/ethereum/vm/BlockchainConfigForEvm.scala b/src/main/scala/io/iohk/ethereum/vm/BlockchainConfigForEvm.scala index 90cd2d5c22..49368c1167 100644 --- a/src/main/scala/io/iohk/ethereum/vm/BlockchainConfigForEvm.scala +++ b/src/main/scala/io/iohk/ethereum/vm/BlockchainConfigForEvm.scala @@ -2,17 +2,18 @@ package io.iohk.ethereum.vm import io.iohk.ethereum.domain.UInt256 import io.iohk.ethereum.utils.BlockchainConfig -import io.iohk.ethereum.vm.BlockchainConfigForEvm.EtcForks.{Agharta, Atlantis, BeforeAtlantis, EtcFork, Phoenix} -import io.iohk.ethereum.vm.BlockchainConfigForEvm.EthForks.{ - BeforeByzantium, - Byzantium, - Constantinople, - Istanbul, - Petersburg -} +import io.iohk.ethereum.vm.BlockchainConfigForEvm.EtcForks.Agharta +import io.iohk.ethereum.vm.BlockchainConfigForEvm.EtcForks.Atlantis +import io.iohk.ethereum.vm.BlockchainConfigForEvm.EtcForks.BeforeAtlantis +import io.iohk.ethereum.vm.BlockchainConfigForEvm.EtcForks.EtcFork +import io.iohk.ethereum.vm.BlockchainConfigForEvm.EtcForks.Phoenix +import io.iohk.ethereum.vm.BlockchainConfigForEvm.EthForks.BeforeByzantium +import io.iohk.ethereum.vm.BlockchainConfigForEvm.EthForks.Byzantium +import io.iohk.ethereum.vm.BlockchainConfigForEvm.EthForks.Constantinople +import io.iohk.ethereum.vm.BlockchainConfigForEvm.EthForks.Istanbul +import io.iohk.ethereum.vm.BlockchainConfigForEvm.EthForks.Petersburg -/** - * A subset of [[io.iohk.ethereum.utils.BlockchainConfig]] that is required for instantiating an [[EvmConfig]] +/** A subset of [[io.iohk.ethereum.utils.BlockchainConfig]] that is required for instantiating an [[EvmConfig]] * Note that `accountStartNonce` is required for a [[WorldStateProxy]] implementation that is used * by a given VM */ @@ -38,17 +39,17 @@ case class BlockchainConfigForEvm( ) { def etcForkForBlockNumber(blockNumber: BigInt): EtcFork = blockNumber match { case _ if blockNumber < atlantisBlockNumber => BeforeAtlantis - case _ if blockNumber < aghartaBlockNumber => Atlantis - case _ if blockNumber < phoenixBlockNumber => Agharta + case _ if blockNumber < aghartaBlockNumber => Atlantis + case _ if blockNumber < phoenixBlockNumber => Agharta case _ if blockNumber >= phoenixBlockNumber => Phoenix } def ethForkForBlockNumber(blockNumber: BigInt): BlockchainConfigForEvm.EthForks.Value = blockNumber match { - case _ if blockNumber < byzantiumBlockNumber => BeforeByzantium + case _ if blockNumber < byzantiumBlockNumber => BeforeByzantium case _ if blockNumber < constantinopleBlockNumber => Byzantium - case _ if blockNumber < petersburgBlockNumber => Constantinople - case _ if blockNumber < istanbulBlockNumber => Petersburg - case _ if blockNumber >= istanbulBlockNumber => Istanbul + case _ if blockNumber < petersburgBlockNumber => Constantinople + case _ if blockNumber < istanbulBlockNumber => Petersburg + case _ if blockNumber >= istanbulBlockNumber => Istanbul } } diff --git a/src/main/scala/io/iohk/ethereum/vm/EvmConfig.scala b/src/main/scala/io/iohk/ethereum/vm/EvmConfig.scala index bfd0c67bfb..d5e2c89b71 100644 --- a/src/main/scala/io/iohk/ethereum/vm/EvmConfig.scala +++ b/src/main/scala/io/iohk/ethereum/vm/EvmConfig.scala @@ -1,12 +1,15 @@ package io.iohk.ethereum.vm import akka.util.ByteString + +import io.iohk.ethereum + import io.iohk.ethereum.domain.UInt256 import io.iohk.ethereum.utils.BlockchainConfig -import EvmConfig._ -import io.iohk.ethereum import io.iohk.ethereum.vm +import EvmConfig._ + // scalastyle:off magic.number object EvmConfig { @@ -18,14 +21,12 @@ object EvmConfig { Int.MaxValue ) /* used to artificially limit memory usage by incurring maximum gas cost */ - /** - * returns the evm config that should be used for given block + /** returns the evm config that should be used for given block */ def forBlock(blockNumber: BigInt, blockchainConfig: BlockchainConfig): EvmConfig = forBlock(blockNumber, BlockchainConfigForEvm(blockchainConfig)) - /** - * returns the evm config that should be used for given block + /** returns the evm config that should be used for given block */ def forBlock(blockNumber: BigInt, blockchainConfig: BlockchainConfigForEvm): EvmConfig = { // FIXME manage etc/eth forks in a more sophisticated way [ETCM-249] @@ -53,13 +54,13 @@ object EvmConfig { evmConfigBuilder(blockchainConfig) } - val FrontierOpCodes = OpCodeList(OpCodes.FrontierOpCodes) - val HomesteadOpCodes = OpCodeList(OpCodes.HomesteadOpCodes) - val ByzantiumOpCodes = OpCodeList(OpCodes.ByzantiumOpCodes) + val FrontierOpCodes: OpCodeList = OpCodeList(OpCodes.FrontierOpCodes) + val HomesteadOpCodes: OpCodeList = OpCodeList(OpCodes.HomesteadOpCodes) + val ByzantiumOpCodes: OpCodeList = OpCodeList(OpCodes.ByzantiumOpCodes) val AtlantisOpCodes = ByzantiumOpCodes - val ConstantinopleOpCodes = OpCodeList(OpCodes.ConstantinopleOpCodes) + val ConstantinopleOpCodes: OpCodeList = OpCodeList(OpCodes.ConstantinopleOpCodes) val AghartaOpCodes = ConstantinopleOpCodes - val PhoenixOpCodes = OpCodeList(OpCodes.PhoenixOpCodes) + val PhoenixOpCodes: OpCodeList = OpCodeList(OpCodes.PhoenixOpCodes) val FrontierConfigBuilder: EvmConfigBuilder = config => EvmConfig( @@ -158,8 +159,7 @@ case class EvmConfig( def byteToOpCode: Map[Byte, OpCode] = opCodeList.byteToOpCode - /** - * Calculate gas cost of memory usage. Incur a blocking gas cost if memory usage exceeds reasonable limits. + /** Calculate gas cost of memory usage. Incur a blocking gas cost if memory usage exceeds reasonable limits. * * @param memSize current memory size in bytes * @param offset memory offset to be written/read @@ -183,8 +183,7 @@ case class EvmConfig( c(memNeeded) - c(memSize) } - /** - * Calculates transaction intrinsic gas. See YP section 6.2 + /** Calculates transaction intrinsic gas. See YP section 6.2 */ def calcTransactionIntrinsicGas(txData: ByteString, isContractCreation: Boolean): BigInt = { val txDataZero = txData.count(_ == 0) @@ -196,8 +195,7 @@ case class EvmConfig( G_transaction } - /** - * If the initialization code completes successfully, a final contract-creation cost is paid, the code-deposit cost, + /** If the initialization code completes successfully, a final contract-creation cost is paid, the code-deposit cost, * proportional to the size of the created contract’s code. See YP equation (96) * * @param executionResultData Transaction code initialization result @@ -206,8 +204,7 @@ case class EvmConfig( def calcCodeDepositCost(executionResultData: ByteString): BigInt = G_codedeposit * executionResultData.size - /** - * a helper method used for gas adjustment in CALL and CREATE opcode, see YP eq. (224) + /** a helper method used for gas adjustment in CALL and CREATE opcode, see YP eq. (224) */ def gasCap(g: BigInt): BigInt = subGasCapDivisor.map(d => g - g / d).getOrElse(g) diff --git a/src/main/scala/io/iohk/ethereum/vm/ExecEnv.scala b/src/main/scala/io/iohk/ethereum/vm/ExecEnv.scala index a08be23a57..95d71085fa 100644 --- a/src/main/scala/io/iohk/ethereum/vm/ExecEnv.scala +++ b/src/main/scala/io/iohk/ethereum/vm/ExecEnv.scala @@ -1,7 +1,10 @@ package io.iohk.ethereum.vm import akka.util.ByteString -import io.iohk.ethereum.domain.{Address, BlockHeader, UInt256} + +import io.iohk.ethereum.domain.Address +import io.iohk.ethereum.domain.BlockHeader +import io.iohk.ethereum.domain.UInt256 object ExecEnv { def apply(context: ProgramContext[_, _], code: ByteString, ownerAddr: Address): ExecEnv = { diff --git a/src/main/scala/io/iohk/ethereum/vm/InternalTransaction.scala b/src/main/scala/io/iohk/ethereum/vm/InternalTransaction.scala index a8d8006a1c..5cc9a449c7 100644 --- a/src/main/scala/io/iohk/ethereum/vm/InternalTransaction.scala +++ b/src/main/scala/io/iohk/ethereum/vm/InternalTransaction.scala @@ -1,10 +1,10 @@ package io.iohk.ethereum.vm import akka.util.ByteString + import io.iohk.ethereum.domain.Address -/** - * This class may be used for tracing any internal calls (*CALL*, CREATE) during code execution. +/** This class may be used for tracing any internal calls (*CALL*, CREATE) during code execution. * Currently it's only in Ethereum Test Suite (ets) * * @param opcode - the opcode that caused the internal TX diff --git a/src/main/scala/io/iohk/ethereum/vm/Memory.scala b/src/main/scala/io/iohk/ethereum/vm/Memory.scala index af5de81d59..d809c49aa0 100644 --- a/src/main/scala/io/iohk/ethereum/vm/Memory.scala +++ b/src/main/scala/io/iohk/ethereum/vm/Memory.scala @@ -1,9 +1,11 @@ package io.iohk.ethereum.vm import akka.util.ByteString -import io.iohk.ethereum.domain.UInt256 + import org.bouncycastle.util.encoders.Hex +import io.iohk.ethereum.domain.UInt256 + object Memory { def empty: Memory = new Memory(ByteString()) @@ -11,8 +13,7 @@ object Memory { private def zeros(size: Int): ByteString = ByteString(Array.fill[Byte](size)(0)) } -/** - * Volatile memory with 256 bit address space. +/** Volatile memory with 256 bit address space. * Every mutating operation on a Memory returns a new updated copy of it. * * Related reading: @@ -70,11 +71,10 @@ class Memory private (private val underlying: ByteString) { new Memory(newUnderlying) } - def load(offset: UInt256): (UInt256, Memory) = { + def load(offset: UInt256): (UInt256, Memory) = doLoad(offset, UInt256.Size) match { case (bs, memory) => (UInt256(bs), memory) } - } def load(offset: UInt256, size: UInt256): (ByteString, Memory) = doLoad(offset, size.toInt) @@ -113,17 +113,15 @@ class Memory private (private val underlying: ByteString) { } } - /** - * @return memory size in bytes + /** @return memory size in bytes */ def size: Int = underlying.size - override def equals(that: Any): Boolean = { + override def equals(that: Any): Boolean = that match { case that: Memory => this.underlying.equals(that.underlying) - case other => false + case _ => false } - } override def hashCode: Int = underlying.hashCode() diff --git a/src/main/scala/io/iohk/ethereum/vm/OpCode.scala b/src/main/scala/io/iohk/ethereum/vm/OpCode.scala index e098e95964..6bbb42ad65 100644 --- a/src/main/scala/io/iohk/ethereum/vm/OpCode.scala +++ b/src/main/scala/io/iohk/ethereum/vm/OpCode.scala @@ -1,12 +1,17 @@ package io.iohk.ethereum.vm import akka.util.ByteString + import io.iohk.ethereum.crypto.kec256 -import io.iohk.ethereum.domain.{Account, Address, TxLogEntry, UInt256} +import io.iohk.ethereum.domain.Account +import io.iohk.ethereum.domain.Address +import io.iohk.ethereum.domain.TxLogEntry +import io.iohk.ethereum.domain.UInt256 import io.iohk.ethereum.domain.UInt256._ import io.iohk.ethereum.utils.ByteStringUtils.Padding +import io.iohk.ethereum.vm.BlockchainConfigForEvm.EtcForks import io.iohk.ethereum.vm.BlockchainConfigForEvm.EtcForks.EtcFork -import io.iohk.ethereum.vm.BlockchainConfigForEvm.{EtcForks, EthForks} +import io.iohk.ethereum.vm.BlockchainConfigForEvm.EthForks import io.iohk.ethereum.vm.BlockchainConfigForEvm.EthForks.EthFork // scalastyle:off magic.number @@ -160,8 +165,7 @@ object OpCode { } } -/** - * Base class for all the opcodes of the EVM +/** Base class for all the opcodes of the EVM * * @param code Opcode byte representation * @param delta number of words to be popped from stack @@ -172,7 +176,7 @@ abstract class OpCode(val code: Byte, val delta: Int, val alpha: Int, val constG with Serializable { def this(code: Int, pop: Int, push: Int, constGasFn: FeeSchedule => BigInt) = this(code.toByte, pop, push, constGasFn) - def execute[W <: WorldStateProxy[W, S], S <: Storage[S]](state: ProgramState[W, S]): ProgramState[W, S] = { + def execute[W <: WorldStateProxy[W, S], S <: Storage[S]](state: ProgramState[W, S]): ProgramState[W, S] = if (!availableInContext(state)) state.withError(OpCodeNotAvailableInStaticContext(code)) else if (state.stack.size < delta) @@ -188,7 +192,6 @@ abstract class OpCode(val code: Byte, val delta: Int, val alpha: Int, val constG else exec(state).spendGas(gas) } - } protected def varGas[W <: WorldStateProxy[W, S], S <: Storage[S]](state: ProgramState[W, S]): BigInt @@ -289,7 +292,7 @@ case object EXP extends BinaryOp(0x0a, _.G_exp)(_ ** _) { } } -case object SIGNEXTEND extends BinaryOp(0x0b, _.G_low)((a, b) => b signExtend a) with ConstGas +case object SIGNEXTEND extends BinaryOp(0x0b, _.G_low)((a, b) => b.signExtend(a)) with ConstGas case object LT extends BinaryOp(0x10, _.G_verylow)(_ < _) with ConstGas @@ -311,7 +314,7 @@ case object XOR extends BinaryOp(0x18, _.G_verylow)(_ ^ _) with ConstGas case object NOT extends UnaryOp(0x19, _.G_verylow)(~_) with ConstGas -case object BYTE extends BinaryOp(0x1a, _.G_verylow)((a, b) => b getByte a) with ConstGas +case object BYTE extends BinaryOp(0x1a, _.G_verylow)((a, b) => b.getByte(a)) with ConstGas // logical shift left case object SHL extends ShiftingOp(0x1b, _ << _) @@ -326,7 +329,7 @@ case object SAR extends OpCode(0x1d, 2, 1, _.G_verylow) with ConstGas { val result = if (shift >= UInt256(256)) { if (value.toSign >= 0) Zero else UInt256(-1) - } else value sshift shift + } else value.sshift(shift) val resultStack = remainingStack.push(result) state.withStack(resultStack).step() @@ -367,8 +370,7 @@ case object EXTCODEHASH extends OpCode(0x3f, 1, 1, _.G_balance) with ConstGas { val (accountAddress, stack1) = state.stack.pop val address = Address(accountAddress) - /** - * Specification of EIP1052 - https://eips.ethereum.org/EIPS/eip-1052, says that we should return 0 + /** Specification of EIP1052 - https://eips.ethereum.org/EIPS/eip-1052, says that we should return 0 * In case the account does not exist 0 is pushed to the stack. * * But the interpretation is, that account does not exists if: @@ -565,7 +567,7 @@ case object SLOAD extends OpCode(0x54, 1, 1, _.G_sload) with ConstGas { case object MSTORE8 extends OpCode(0x53, 2, 0, _.G_verylow) { protected def exec[W <: WorldStateProxy[W, S], S <: Storage[S]](state: ProgramState[W, S]): ProgramState[W, S] = { val (Seq(offset, value), stack1) = state.stack.pop(2) - val valueToByte = (value mod 256).toByte + val valueToByte = value.mod(256).toByte val updatedMem = state.memory.store(offset, valueToByte) state.withStack(stack1).withMemory(updatedMem).step() } @@ -670,7 +672,7 @@ case object SSTORE extends OpCode(0x55, 2, 0, _.G_zero) { // https://eips.ethereum.org/EIPS/eip-2200 private def isEip2200Enabled(etcFork: EtcFork, ethFork: EthFork): Boolean = - (ethFork >= EthForks.Istanbul || etcFork >= EtcForks.Phoenix) + ethFork >= EthForks.Istanbul || etcFork >= EtcForks.Phoenix } case object JUMP extends OpCode(0x56, 1, 0, _.G_mid) with ConstGas { @@ -706,9 +708,8 @@ case object MSIZE extends ConstOp(0x59)(s => (UInt256.Size * wordsForBytes(s.mem case object GAS extends ConstOp(0x5a)(state => (state.gas - state.config.feeSchedule.G_base).toUInt256) case object JUMPDEST extends OpCode(0x5b, 0, 0, _.G_jumpdest) with ConstGas { - protected def exec[W <: WorldStateProxy[W, S], S <: Storage[S]](state: ProgramState[W, S]): ProgramState[W, S] = { + protected def exec[W <: WorldStateProxy[W, S], S <: Storage[S]](state: ProgramState[W, S]): ProgramState[W, S] = state.step() - } } sealed abstract class PushOp(code: Int) extends OpCode(code, 0, 1, _.G_verylow) with ConstGas { @@ -936,8 +937,7 @@ abstract class CallOp(code: Int, delta: Int, alpha: Int) extends OpCode(code, de (toAddr, state.ownAddress, callValue, callValue, true, state.staticCtx) case STATICCALL => - /** - * We return `doTransfer = true` for STATICCALL as it should `functions equivalently to a CALL` (spec) + /** We return `doTransfer = true` for STATICCALL as it should `functions equivalently to a CALL` (spec) * Note that we won't transfer any founds during later transfer, as `value` and `endowment` are equal to Zero. * One thing that will change though is that both - recipient and sender addresses will be added to touched accounts * Set. And if empty they will be deleted at the end of transaction. @@ -1046,7 +1046,7 @@ abstract class CallOp(code: Int, delta: Int, alpha: Int) extends OpCode(code, de val memCostIn = state.config.calcMemCost(state.memory.size, inOffset, inSize) val memCostOut = state.config.calcMemCost(state.memory.size, outOffset, outSize) - memCostIn max memCostOut + memCostIn.max(memCostOut) } protected def getParams[W <: WorldStateProxy[W, S], S <: Storage[S]]( @@ -1074,12 +1074,11 @@ abstract class CallOp(code: Int, delta: Int, alpha: Int) extends OpCode(code, de state: ProgramState[W, S], g: BigInt, consumedGas: BigInt - ): BigInt = { + ): BigInt = if (state.config.subGasCapDivisor.isDefined && state.gas >= consumedGas) - g min state.config.gasCap(state.gas - consumedGas) + g.min(state.config.gasCap(state.gas - consumedGas)) else g - } private def gasExtra[W <: WorldStateProxy[W, S], S <: Storage[S]]( state: ProgramState[W, S], diff --git a/src/main/scala/io/iohk/ethereum/vm/PrecompiledContracts.scala b/src/main/scala/io/iohk/ethereum/vm/PrecompiledContracts.scala index 91f1daf0a4..1aa8e5757d 100644 --- a/src/main/scala/io/iohk/ethereum/vm/PrecompiledContracts.scala +++ b/src/main/scala/io/iohk/ethereum/vm/PrecompiledContracts.scala @@ -1,65 +1,67 @@ package io.iohk.ethereum.vm import akka.util.ByteString -import io.iohk.ethereum.utils.ByteStringUtils._ + +import scala.util.Try + import io.iohk.ethereum.crypto._ -import io.iohk.ethereum.crypto.zksnark.BN128.{BN128G1, BN128G2} -import io.iohk.ethereum.crypto.zksnark.{BN128Fp, PairingCheck} +import io.iohk.ethereum.crypto.zksnark.BN128.BN128G1 +import io.iohk.ethereum.crypto.zksnark.BN128.BN128G2 +import io.iohk.ethereum.crypto.zksnark.BN128Fp +import io.iohk.ethereum.crypto.zksnark.PairingCheck import io.iohk.ethereum.crypto.zksnark.PairingCheck.G1G2Pair import io.iohk.ethereum.domain.Address +import io.iohk.ethereum.utils.ByteStringUtils._ import io.iohk.ethereum.utils.ByteUtils +import io.iohk.ethereum.vm.BlockchainConfigForEvm.EtcForks import io.iohk.ethereum.vm.BlockchainConfigForEvm.EtcForks.EtcFork +import io.iohk.ethereum.vm.BlockchainConfigForEvm.EthForks import io.iohk.ethereum.vm.BlockchainConfigForEvm.EthForks.EthFork -import io.iohk.ethereum.vm.BlockchainConfigForEvm.{EtcForks, EthForks} - -import scala.util.Try // scalastyle:off magic.number object PrecompiledContracts { - val EcDsaRecAddr = Address(1) - val Sha256Addr = Address(2) - val Rip160Addr = Address(3) - val IdAddr = Address(4) - val ModExpAddr = Address(5) - val Bn128AddAddr = Address(6) - val Bn128MulAddr = Address(7) - val Bn128PairingAddr = Address(8) - val Blake2bCompressionAddr = Address(9) - - val contracts = Map( + val EcDsaRecAddr: Address = Address(1) + val Sha256Addr: Address = Address(2) + val Rip160Addr: Address = Address(3) + val IdAddr: Address = Address(4) + val ModExpAddr: Address = Address(5) + val Bn128AddAddr: Address = Address(6) + val Bn128MulAddr: Address = Address(7) + val Bn128PairingAddr: Address = Address(8) + val Blake2bCompressionAddr: Address = Address(9) + + val contracts: Map[Address, PrecompiledContract] = Map( EcDsaRecAddr -> EllipticCurveRecovery, Sha256Addr -> Sha256, Rip160Addr -> Ripemp160, IdAddr -> Identity ) - val byzantiumAtlantisContracts = contracts ++ Map( + val byzantiumAtlantisContracts: Map[Address, PrecompiledContract] = contracts ++ Map( ModExpAddr -> ModExp, Bn128AddAddr -> Bn128Add, Bn128MulAddr -> Bn128Mul, Bn128PairingAddr -> Bn128Pairing ) - val istanbulPhoenixContracts = byzantiumAtlantisContracts ++ Map( + val istanbulPhoenixContracts: Map[Address, PrecompiledContract] = byzantiumAtlantisContracts ++ Map( Blake2bCompressionAddr -> Blake2bCompress ) - /** - * Checks whether `ProgramContext#recipientAddr` points to a precompiled contract + /** Checks whether `ProgramContext#recipientAddr` points to a precompiled contract */ def isDefinedAt(context: ProgramContext[_, _]): Boolean = getContract(context).isDefined - /** - * Runs a contract for address provided in `ProgramContext#recipientAddr` + /** Runs a contract for address provided in `ProgramContext#recipientAddr` * Will throw an exception if the address does not point to a precompiled contract - callers should first * check with `isDefinedAt` */ def run[W <: WorldStateProxy[W, S], S <: Storage[S]](context: ProgramContext[W, S]): ProgramResult[W, S] = getContract(context).get.run(context) - private def getContract(context: ProgramContext[_, _]): Option[PrecompiledContract] = { + private def getContract(context: ProgramContext[_, _]): Option[PrecompiledContract] = context.recipientAddr.flatMap { addr => val ethFork = context.evmConfig.blockchainConfig.ethForkForBlockNumber(context.blockHeader.number) val etcFork = context.evmConfig.blockchainConfig.etcForkForBlockNumber(context.blockHeader.number) @@ -72,7 +74,6 @@ object PrecompiledContracts { } else contracts.get(addr) } - } sealed trait PrecompiledContract { protected def exec(inputData: ByteString): Option[ByteString] @@ -89,7 +90,7 @@ object PrecompiledContracts { if (g <= context.startGas) exec(context.inputData) match { case Some(returnData) => (returnData, None, context.startGas - g) - case None => (ByteString.empty, Some(PreCompiledContractFail), 0) + case None => (ByteString.empty, Some(PreCompiledContractFail), 0) } else (ByteString.empty, Some(OutOfGas), 0) @@ -250,9 +251,8 @@ object PrecompiledContracts { ByteUtils.toBigInt(number) } - private def safeAdd(a: Int, b: Int): Int = { + private def safeAdd(a: Int, b: Int): Int = safeInt(BigInt(a) + BigInt(b)) - } private def safeInt(value: BigInt): Int = if (value.isValidInt) @@ -284,7 +284,7 @@ object PrecompiledContracts { //Spec: https://github.com/ethereum/EIPs/blob/master/EIPS/eip-196.md object Bn128Add extends PrecompiledContract { - val expectedBytes = 4 * 32 + val expectedBytes: Int = 4 * 32 def exec(inputData: ByteString): Option[ByteString] = { val paddedInput = inputData.padToByteString(expectedBytes, 0.toByte) @@ -309,16 +309,15 @@ object PrecompiledContracts { else BigInt(500) - private def getCurvePointsBytes(input: ByteString): (ByteString, ByteString, ByteString, ByteString) = { + private def getCurvePointsBytes(input: ByteString): (ByteString, ByteString, ByteString, ByteString) = (input.slice(0, 32), input.slice(32, 64), input.slice(64, 96), input.slice(96, 128)) - } } //Spec: https://github.com/ethereum/EIPs/blob/master/EIPS/eip-196.md object Bn128Mul extends PrecompiledContract { - val expectedBytes = 3 * 32 - val maxScalar = BigInt(2).pow(256) - 1 + val expectedBytes: Int = 3 * 32 + val maxScalar: BigInt = BigInt(2).pow(256) - 1 def exec(inputData: ByteString): Option[ByteString] = { val paddedInput = inputData.padToByteString(expectedBytes, 0.toByte) @@ -345,9 +344,8 @@ object PrecompiledContracts { else 40000 - private def getCurvePointsBytes(input: ByteString): (ByteString, ByteString, ByteString) = { + private def getCurvePointsBytes(input: ByteString): (ByteString, ByteString, ByteString) = (input.slice(0, 32), input.slice(32, 64), input.slice(64, 96)) - } } //Spec: https://github.com/ethereum/EIPs/blob/master/EIPS/eip-197.md @@ -356,10 +354,10 @@ object PrecompiledContracts { private val wordLength = 32 private val inputLength = 6 * wordLength - val positiveResult = ByteUtils.padLeft(ByteString(1), wordLength) - val negativeResult = ByteString(Seq.fill(wordLength)(0.toByte).toArray) + val positiveResult: ByteString = ByteUtils.padLeft(ByteString(1), wordLength) + val negativeResult: ByteString = ByteString(Seq.fill(wordLength)(0.toByte).toArray) - def exec(inputData: ByteString): Option[ByteString] = { + def exec(inputData: ByteString): Option[ByteString] = if (inputData.length % inputLength != 0) { None } else { @@ -370,7 +368,6 @@ object PrecompiledContracts { negativeResult } } - } def gas(inputData: ByteString, etcFork: EtcFork, ethFork: EthFork): BigInt = { val k = inputData.length / inputLength @@ -385,16 +382,15 @@ object PrecompiledContracts { // BN128 curve private def getPairs(bytes: Iterator[ByteString]): Option[Seq[G1G2Pair]] = { var accum = List.empty[G1G2Pair] - while (bytes.hasNext) { + while (bytes.hasNext) getPair(bytes.next()) match { case Some(part) => accum = part :: accum - case None => return None // scalastyle:ignore + case None => return None // scalastyle:ignore } - } Some(accum) } - private def getPair(input: ByteString): Option[G1G2Pair] = { + private def getPair(input: ByteString): Option[G1G2Pair] = for { g1 <- BN128G1(getBytesOnPosition(input, 0), getBytesOnPosition(input, 1)) g2 <- BN128G2( @@ -404,7 +400,6 @@ object PrecompiledContracts { getBytesOnPosition(input, 4) ) } yield G1G2Pair(g1, g2) - } private def getBytesOnPosition(input: ByteString, pos: Int): ByteString = { val from = pos * wordLength @@ -415,9 +410,8 @@ object PrecompiledContracts { //Spec: https://eips.ethereum.org/EIPS/eip-152 // scalastyle: off object Blake2bCompress extends PrecompiledContract { - def exec(inputData: ByteString): Option[ByteString] = { + def exec(inputData: ByteString): Option[ByteString] = Blake2bCompression.blake2bCompress(inputData.toArray).map(ByteString.fromArrayUnsafe) - } def gas(inputData: ByteString, etcFork: EtcFork, ethFork: EthFork): BigInt = { val inputArray = inputData.toArray diff --git a/src/main/scala/io/iohk/ethereum/vm/Program.scala b/src/main/scala/io/iohk/ethereum/vm/Program.scala index f76cbf65f1..4ffaa097cc 100644 --- a/src/main/scala/io/iohk/ethereum/vm/Program.scala +++ b/src/main/scala/io/iohk/ethereum/vm/Program.scala @@ -1,13 +1,13 @@ package io.iohk.ethereum.vm import akka.util.ByteString -import io.iohk.ethereum.crypto.kec256 -import io.iohk.ethereum.utils.ByteStringUtils.Padding import scala.annotation.tailrec -/** - * Holds a program's code and provides utilities for accessing it (defaulting to zeroes when out of scope) +import io.iohk.ethereum.crypto.kec256 +import io.iohk.ethereum.utils.ByteStringUtils.Padding + +/** Holds a program's code and provides utilities for accessing it (defaulting to zeroes when out of scope) * * @param code the EVM bytecode as bytes */ @@ -23,15 +23,14 @@ case class Program(code: ByteString) { lazy val validJumpDestinations: Set[Int] = validJumpDestinationsAfterPosition(0) - /** - * Returns the valid jump destinations of the program after a given position + /** Returns the valid jump destinations of the program after a given position * See section 9.4.3 in Yellow Paper for more detail. * * @param pos from where to start searching for valid jump destinations in the code. * @param accum with the previously obtained valid jump destinations. */ @tailrec - private def validJumpDestinationsAfterPosition(pos: Int, accum: Set[Int] = Set.empty): Set[Int] = { + private def validJumpDestinationsAfterPosition(pos: Int, accum: Set[Int] = Set.empty): Set[Int] = if (pos < 0 || pos >= length) accum else { val byte = code(pos) @@ -40,11 +39,10 @@ case class Program(code: ByteString) { ) // we only need to check PushOp and JUMPDEST, they are both present in Frontier opCode match { case Some(pushOp: PushOp) => validJumpDestinationsAfterPosition(pos + pushOp.i + 2, accum) - case Some(JUMPDEST) => validJumpDestinationsAfterPosition(pos + 1, accum + pos) - case _ => validJumpDestinationsAfterPosition(pos + 1, accum) + case Some(JUMPDEST) => validJumpDestinationsAfterPosition(pos + 1, accum + pos) + case _ => validJumpDestinationsAfterPosition(pos + 1, accum) } } - } lazy val codeHash: ByteString = kec256(code) diff --git a/src/main/scala/io/iohk/ethereum/vm/ProgramContext.scala b/src/main/scala/io/iohk/ethereum/vm/ProgramContext.scala index 2a154f2414..6d05e03810 100644 --- a/src/main/scala/io/iohk/ethereum/vm/ProgramContext.scala +++ b/src/main/scala/io/iohk/ethereum/vm/ProgramContext.scala @@ -1,6 +1,7 @@ package io.iohk.ethereum.vm import akka.util.ByteString + import io.iohk.ethereum.domain._ object ProgramContext { @@ -35,8 +36,7 @@ object ProgramContext { } } -/** - * Input parameters to a program executed on the EVM. Apart from the code itself +/** Input parameters to a program executed on the EVM. Apart from the code itself * it should have all (interfaces to) the data accessible from the EVM. * * Execution constants, see section 9.3 in Yellow Paper for more detail. diff --git a/src/main/scala/io/iohk/ethereum/vm/ProgramError.scala b/src/main/scala/io/iohk/ethereum/vm/ProgramError.scala index 5af07d2b18..f7a7afe322 100644 --- a/src/main/scala/io/iohk/ethereum/vm/ProgramError.scala +++ b/src/main/scala/io/iohk/ethereum/vm/ProgramError.scala @@ -2,8 +2,7 @@ package io.iohk.ethereum.vm import io.iohk.ethereum.domain.UInt256 -/** - * Marker trait for errors that may occur during program execution +/** Marker trait for errors that may occur during program execution */ sealed trait ProgramError { val useWholeGas = true diff --git a/src/main/scala/io/iohk/ethereum/vm/ProgramResult.scala b/src/main/scala/io/iohk/ethereum/vm/ProgramResult.scala index ff6bb82a77..d9a75aded3 100644 --- a/src/main/scala/io/iohk/ethereum/vm/ProgramResult.scala +++ b/src/main/scala/io/iohk/ethereum/vm/ProgramResult.scala @@ -1,10 +1,11 @@ package io.iohk.ethereum.vm import akka.util.ByteString -import io.iohk.ethereum.domain.{Address, TxLogEntry} -/** - * Represenation of the result of execution of a contract +import io.iohk.ethereum.domain.Address +import io.iohk.ethereum.domain.TxLogEntry + +/** Represenation of the result of execution of a contract * * @param returnData bytes returned by the executed contract (set by [[RETURN]] opcode) * @param gasRemaining amount of gas remaining after execution diff --git a/src/main/scala/io/iohk/ethereum/vm/ProgramState.scala b/src/main/scala/io/iohk/ethereum/vm/ProgramState.scala index 6957603870..65c260d488 100644 --- a/src/main/scala/io/iohk/ethereum/vm/ProgramState.scala +++ b/src/main/scala/io/iohk/ethereum/vm/ProgramState.scala @@ -1,15 +1,17 @@ package io.iohk.ethereum.vm import akka.util.ByteString -import io.iohk.ethereum.domain.{Address, TxLogEntry, UInt256} + +import io.iohk.ethereum.domain.Address +import io.iohk.ethereum.domain.TxLogEntry +import io.iohk.ethereum.domain.UInt256 object ProgramState { def apply[W <: WorldStateProxy[W, S], S <: Storage[S]]( vm: VM[W, S], context: ProgramContext[W, S], env: ExecEnv - ): ProgramState[W, S] = { - + ): ProgramState[W, S] = ProgramState( vm = vm, env = env, @@ -19,11 +21,9 @@ object ProgramState { addressesToDelete = context.initialAddressesToDelete, originalWorld = context.originalWorld ) - } } -/** - * Intermediate state updated with execution of each opcode in the program +/** Intermediate state updated with execution of each opcode in the program * * @param vm the VM * @param env program constants diff --git a/src/main/scala/io/iohk/ethereum/vm/Stack.scala b/src/main/scala/io/iohk/ethereum/vm/Stack.scala index a8269a8bf7..ec93ab518a 100644 --- a/src/main/scala/io/iohk/ethereum/vm/Stack.scala +++ b/src/main/scala/io/iohk/ethereum/vm/Stack.scala @@ -4,8 +4,7 @@ import io.iohk.ethereum.domain.UInt256 object Stack { - /** - * Stack max size as defined in the YP (9.1) + /** Stack max size as defined in the YP (9.1) */ val DefaultMaxSize = 1024 @@ -14,8 +13,7 @@ object Stack { } //TODO: consider a List with head being top of the stack (DUP,SWAP go at most the depth of 16) [EC-251] -/** - * Stack for the EVM. Instruction pop their arguments from it and push their results to it. +/** Stack for the EVM. Instruction pop their arguments from it and push their results to it. * The Stack doesn't handle overflow and underflow errors. Any operations that trascend given stack bounds will * return the stack unchanged. Pop will always return zeroes in such case. */ @@ -30,8 +28,7 @@ class Stack private (private val underlying: Vector[UInt256], val maxSize: Int) (UInt256.Zero, this) } - /** - * Pop n elements from the stack. The first element in the resulting sequence will be the top-most element + /** Pop n elements from the stack. The first element in the resulting sequence will be the top-most element * in the current stack */ def pop(n: Int): (Seq[UInt256], Stack) = { @@ -50,8 +47,7 @@ class Stack private (private val underlying: Vector[UInt256], val maxSize: Int) this } - /** - * Push a sequence of elements to the stack. That last element of the sequence will be the top-most element + /** Push a sequence of elements to the stack. That last element of the sequence will be the top-most element * in the resulting stack */ def push(words: Seq[UInt256]): Stack = { @@ -62,8 +58,7 @@ class Stack private (private val underlying: Vector[UInt256], val maxSize: Int) copy(updated) } - /** - * Duplicate i-th element of the stack, pushing it to the top. i=0 is the top-most element. + /** Duplicate i-th element of the stack, pushing it to the top. i=0 is the top-most element. */ def dup(i: Int): Stack = { val j = underlying.length - i - 1 @@ -74,8 +69,7 @@ class Stack private (private val underlying: Vector[UInt256], val maxSize: Int) copy(underlying :+ underlying(j)) } - /** - * Swap i-th and the top-most elements of the stack. i=0 is the top-most element (and that would be a no-op) + /** Swap i-th and the top-most elements of the stack. i=0 is the top-most element (and that would be a no-op) */ def swap(i: Int): Stack = { val j = underlying.length - i - 1 @@ -92,15 +86,14 @@ class Stack private (private val underlying: Vector[UInt256], val maxSize: Int) def size: Int = underlying.size - /** - * @return the elements of the stack as a sequence, with the top-most element of the stack + /** @return the elements of the stack as a sequence, with the top-most element of the stack * as the first element in the sequence */ def toSeq: Seq[UInt256] = underlying.reverse override def equals(that: Any): Boolean = that match { case that: Stack => this.underlying == that.underlying - case _ => false + case _ => false } override def hashCode(): Int = underlying.hashCode diff --git a/src/main/scala/io/iohk/ethereum/vm/Storage.scala b/src/main/scala/io/iohk/ethereum/vm/Storage.scala index 614640df5b..96160417db 100644 --- a/src/main/scala/io/iohk/ethereum/vm/Storage.scala +++ b/src/main/scala/io/iohk/ethereum/vm/Storage.scala @@ -1,7 +1,6 @@ package io.iohk.ethereum.vm -/** - * Account's storage representation. Implementation should be immutable and only keep track of changes to the storage +/** Account's storage representation. Implementation should be immutable and only keep track of changes to the storage */ trait Storage[S <: Storage[S]] { def store(offset: BigInt, value: BigInt): S diff --git a/src/main/scala/io/iohk/ethereum/vm/VM.scala b/src/main/scala/io/iohk/ethereum/vm/VM.scala index fb5c37dbbc..8517d915dd 100644 --- a/src/main/scala/io/iohk/ethereum/vm/VM.scala +++ b/src/main/scala/io/iohk/ethereum/vm/VM.scala @@ -1,18 +1,20 @@ package io.iohk.ethereum.vm import akka.util.ByteString -import io.iohk.ethereum.domain.{Address, UInt256} -import io.iohk.ethereum.utils.Logger + import scala.annotation.tailrec +import io.iohk.ethereum.domain.Address +import io.iohk.ethereum.domain.UInt256 +import io.iohk.ethereum.utils.Logger + class VM[W <: WorldStateProxy[W, S], S <: Storage[S]] extends Logger { type PC = ProgramContext[W, S] type PR = ProgramResult[W, S] type PS = ProgramState[W, S] - /** - * Executes a top-level program (transaction) + /** Executes a top-level program (transaction) * @param context context to be executed * @return result of the execution */ @@ -35,8 +37,7 @@ class VM[W <: WorldStateProxy[W, S], S <: Storage[S]] extends Logger { } } - /** - * Message call - Θ function in YP + /** Message call - Θ function in YP */ private[vm] def call(context: PC, ownerAddr: Address): PR = if (!isValidCall(context)) @@ -59,8 +60,7 @@ class VM[W <: WorldStateProxy[W, S], S <: Storage[S]] extends Logger { } } - /** - * Contract creation - Λ function in YP + /** Contract creation - Λ function in YP * salt is used to create contract by CREATE2 opcode. See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1014.md */ private[vm] def create(context: PC, salt: Option[UInt256] = None): (PR, Address) = @@ -79,8 +79,7 @@ class VM[W <: WorldStateProxy[W, S], S <: Storage[S]] extends Logger { // to empty values. val conflict = context.world.nonEmptyCodeOrNonceAccount(newAddress) - /** - * Specification of https://eips.ethereum.org/EIPS/eip-1283 states, that `originalValue` should be taken from + /** Specification of https://eips.ethereum.org/EIPS/eip-1283 states, that `originalValue` should be taken from * world which is left after `a reversion happens on the current transaction`, so in current scope `context.originalWorld`. * * But ets test expects that it should be taken from world after the new account initialisation, which clears @@ -142,7 +141,7 @@ class VM[W <: WorldStateProxy[W, S], S <: Storage[S]] extends Logger { maxCodeSizeExceeded } - private def saveNewContract(context: PC, address: Address, result: PR, config: EvmConfig): PR = { + private def saveNewContract(context: PC, address: Address, result: PR, config: EvmConfig): PR = if (result.error.isDefined) { if (result.error.contains(RevertOccurs)) result else result.copy(gasRemaining = 0) } else { @@ -166,5 +165,4 @@ class VM[W <: WorldStateProxy[W, S], S <: Storage[S]] extends Logger { ) } } - } } diff --git a/src/main/scala/io/iohk/ethereum/vm/WorldStateProxy.scala b/src/main/scala/io/iohk/ethereum/vm/WorldStateProxy.scala index 8d6979629b..5fe36e1fbc 100644 --- a/src/main/scala/io/iohk/ethereum/vm/WorldStateProxy.scala +++ b/src/main/scala/io/iohk/ethereum/vm/WorldStateProxy.scala @@ -1,15 +1,17 @@ package io.iohk.ethereum.vm import akka.util.ByteString + import io.iohk.ethereum.crypto.kec256 -import io.iohk.ethereum.domain.{Account, Address, UInt256} +import io.iohk.ethereum.domain.Account +import io.iohk.ethereum.domain.Address +import io.iohk.ethereum.domain.UInt256 import io.iohk.ethereum.rlp import io.iohk.ethereum.rlp.RLPImplicitConversions._ import io.iohk.ethereum.rlp.RLPList import io.iohk.ethereum.rlp.UInt256RLPImplicits._ -/** - * This is a single entry point to all VM interactions with the persisted state. Implementations are meant to be +/** This is a single entry point to all VM interactions with the persisted state. Implementations are meant to be * immutable so that rolling back a transaction is equivalent to discarding resulting changes. The changes to state * should be kept in memory and applied only after a transaction completes without errors. This does not forbid mutable * caches for DB retrieval operations. @@ -37,10 +39,9 @@ trait WorldStateProxy[WS <: WorldStateProxy[WS, S], S <: Storage[S]] { self: WS * */ def keepPrecompileTouched(world: WS): WS - protected val ripmdContractAddress = Address(3) + protected val ripmdContractAddress: Address = Address(3) - /** - * In certain situation an account is guaranteed to exist, e.g. the account that executes the code, the account that + /** In certain situation an account is guaranteed to exist, e.g. the account that executes the code, the account that * transfer value to another. There could be no input to our application that would cause this fail, so we shouldn't * handle account existence in such cases. If it does fail, it means there's something terribly wrong with our code * and throwing an exception is an appropriate response. @@ -64,13 +65,12 @@ trait WorldStateProxy[WS <: WorldStateProxy[WS, S], S <: Storage[S]] { self: WS def getBalance(address: Address): UInt256 = getAccount(address).map(a => UInt256(a.balance)).getOrElse(UInt256.Zero) - def transfer(from: Address, to: Address, value: UInt256): WS = { + def transfer(from: Address, to: Address, value: UInt256): WS = if (from == to || isZeroValueTransferToNonExistentAccount(to, value)) touchAccounts(from) else // perhaps as an optimisation we could avoid touching accounts having non-zero nonce or non-empty code guaranteedTransfer(from, to, value).touchAccounts(from, to) - } private def guaranteedTransfer(from: Address, to: Address, value: UInt256): WS = { val debited = getGuaranteedAccount(from).increaseBalance(-value) @@ -78,8 +78,7 @@ trait WorldStateProxy[WS <: WorldStateProxy[WS, S], S <: Storage[S]] { self: WS saveAccount(from, debited).saveAccount(to, credited) } - /** - * IF EIP-161 is in effect this sets new contract's account initial nonce to 1 over the default value + /** IF EIP-161 is in effect this sets new contract's account initial nonce to 1 over the default value * for the given network (usually zero) */ def initialiseAccount(newAddress: Address): WS = { @@ -98,8 +97,7 @@ trait WorldStateProxy[WS <: WorldStateProxy[WS, S], S <: Storage[S]] { self: WS saveAccount(newAddress, accountWithCorrectNonce) } - /** - * In case of transfer to self, during selfdestruction the ether is actually destroyed + /** In case of transfer to self, during selfdestruction the ether is actually destroyed * see https://github.com/ethereum/wiki/wiki/Subtleties/d5d3583e1b0a53c7c49db2fa670fdd88aa7cabaf#other-operations * and https://github.com/ethereum/go-ethereum/blob/ff9a8682323648266d5c73f4f4bce545d91edccb/core/state/statedb.go#L322 */ @@ -108,8 +106,7 @@ trait WorldStateProxy[WS <: WorldStateProxy[WS, S], S <: Storage[S]] { self: WS saveAccount(address, debited).touchAccounts(address) } - /** - * Creates a new address based on the address and nonce of the creator. YP equation 82 + /** Creates a new address based on the address and nonce of the creator. YP equation 82 * * @param creatorAddr, the address of the creator of the new address * @return the new address @@ -120,8 +117,7 @@ trait WorldStateProxy[WS <: WorldStateProxy[WS, S], S <: Storage[S]] { self: WS Address(hash) } - /** - * Creates a new address based on the address, salt and init code + /** Creates a new address based on the address, salt and init code * see https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1014.md * * @param creatorAddr the address of the creator of the new address @@ -135,24 +131,21 @@ trait WorldStateProxy[WS <: WorldStateProxy[WS, S], S <: Storage[S]] { self: WS Address(hash) } - /** - * Increase nonce for a guaranteed account - ie. throws an error if this does not exist + /** Increase nonce for a guaranteed account - ie. throws an error if this does not exist */ def increaseNonce(address: Address): WS = { val account = getGuaranteedAccount(address).increaseNonce() saveAccount(address, account) } - /** - * Determines if account of provided address is dead. + /** Determines if account of provided address is dead. * According to EIP161: An account is considered dead when either it is non-existent or it is empty * * @param address, the address of the checked account * @return true if account is dead, false otherwise */ - def isAccountDead(address: Address): Boolean = { + def isAccountDead(address: Address): Boolean = getAccount(address).forall(_.isEmpty(accountStartNonce)) - } def nonEmptyCodeOrNonceAccount(address: Address): Boolean = getAccount(address).exists(_.nonEmptyCodeOrNonce(accountStartNonce)) diff --git a/src/main/scala/io/iohk/ethereum/vm/package.scala b/src/main/scala/io/iohk/ethereum/vm/package.scala index cbd8e00c99..11669ace03 100644 --- a/src/main/scala/io/iohk/ethereum/vm/package.scala +++ b/src/main/scala/io/iohk/ethereum/vm/package.scala @@ -4,8 +4,7 @@ import io.iohk.ethereum.domain.UInt256 package object vm { - /** - * Number of 32-byte UInt256s required to hold n bytes (~= math.ceil(n / 32)) + /** Number of 32-byte UInt256s required to hold n bytes (~= math.ceil(n / 32)) */ def wordsForBytes(n: BigInt): BigInt = if (n == 0) 0 else (n - 1) / UInt256.Size + 1 diff --git a/src/rpcTest/scala/io/iohk/ethereum/rpcTest/RpcApiTests.scala b/src/rpcTest/scala/io/iohk/ethereum/rpcTest/RpcApiTests.scala index a9fffe546f..fc15c3bded 100644 --- a/src/rpcTest/scala/io/iohk/ethereum/rpcTest/RpcApiTests.scala +++ b/src/rpcTest/scala/io/iohk/ethereum/rpcTest/RpcApiTests.scala @@ -2,31 +2,43 @@ package io.iohk.ethereum.rpcTest import java.math.BigInteger import java.security.SecureRandom + import akka.util.ByteString + +import scala.jdk.CollectionConverters._ +import scala.language.implicitConversions + +import com.typesafe.config.Config import com.typesafe.config.ConfigFactory -import io.iohk.ethereum.domain.Address -import io.iohk.ethereum.jsonrpc.TransactionRequest -import io.iohk.ethereum.keystore.{KeyStoreImpl, Wallet} -import io.iohk.ethereum.rlp -import io.iohk.ethereum.rpcTest.Tags.{MainNet, PrivNet, PrivNetNoMining} -import io.iohk.ethereum.utils.{KeyStoreConfig, Logger} import org.bouncycastle.util.encoders.Hex +import org.scalatest.flatspec.AnyFlatSpec +import org.scalatest.matchers.should.Matchers import org.web3j.protocol.admin.Admin import org.web3j.protocol.core.DefaultBlockParameter -import org.web3j.protocol.core.methods.request.{EthFilter, Transaction} -import org.web3j.protocol.core.methods.response.EthBlock.{TransactionHash, TransactionObject} +import org.web3j.protocol.core.methods.request.EthFilter +import org.web3j.protocol.core.methods.request.Transaction +import org.web3j.protocol.core.methods.response.EthBlock.TransactionHash +import org.web3j.protocol.core.methods.response.EthBlock.TransactionObject +import org.web3j.protocol.core.methods.response.EthLog +import org.web3j.protocol.core.methods.response.EthLog.Hash +import org.web3j.protocol.core.methods.response.EthLog.LogObject +import org.web3j.protocol.exceptions.ClientConnectionException import org.web3j.protocol.http.HttpService + +import io.iohk.ethereum.domain.Address +import io.iohk.ethereum.jsonrpc.TransactionRequest +import io.iohk.ethereum.keystore.KeyStoreImpl +import io.iohk.ethereum.keystore.Wallet import io.iohk.ethereum.network.p2p.messages.BaseETH6XMessages.SignedTransactions.SignedTransactionEnc -import org.web3j.protocol.core.methods.response.EthLog.{Hash, LogObject} +import io.iohk.ethereum.network.p2p.messages.Capability +import io.iohk.ethereum.rlp +import io.iohk.ethereum.rpcTest.Tags.MainNet +import io.iohk.ethereum.rpcTest.Tags.PrivNet +import io.iohk.ethereum.rpcTest.Tags.PrivNetNoMining import io.iohk.ethereum.rpcTest.TestContracts._ import io.iohk.ethereum.rpcTest.TestData._ -import org.scalatest.flatspec.AnyFlatSpec -import org.scalatest.matchers.should.Matchers -import org.web3j.protocol.core.methods.response.EthLog -import org.web3j.protocol.exceptions.ClientConnectionException - -import scala.jdk.CollectionConverters._ -import scala.language.implicitConversions +import io.iohk.ethereum.utils.KeyStoreConfig +import io.iohk.ethereum.utils.Logger class RpcApiTests extends AnyFlatSpec with Matchers with Logger { @@ -212,7 +224,7 @@ class RpcApiTests extends AnyFlatSpec with Matchers with Logger { val receivedNumber = response.getBlockNumber.asBigInt // Wait for new block - val minedBlock1 = service.blockFlowable(false).blockingFirst() + service.blockFlowable(false).blockingFirst() val response1 = service.ethBlockNumber().send() response1.getBlockNumber should not equal null @@ -292,7 +304,7 @@ class RpcApiTests extends AnyFlatSpec with Matchers with Logger { service.ethSendTransaction(valueTransfer(firstAccount.address, secondAccount.address, transferAmount)).send() response1.getError shouldEqual null - val minedTransactions = service.transactionFlowable().blockingFirst() + service.transactionFlowable().blockingFirst() val response2 = service.ethGetTransactionCount(firstAccount.address, latestBlock).send() val currentCount2 = response2.getTransactionCount.asBigInt @@ -435,7 +447,7 @@ class RpcApiTests extends AnyFlatSpec with Matchers with Logger { val rawValueTransaction4 = prepareRawTx(secondAcc, toAccount = Some(secondAccount), value = Some(value1), nonce = 0) val rawValueTransaction5 = prepareRawTx(firstAcc, toAccount = Some(secondAccount), value = Some(value2), nonce = 0) - val waitForNextBlock = service.blockFlowable(false).blockingFirst() + service.blockFlowable(false).blockingFirst() val transfer3 = service.ethSendRawTransaction(rawValueTransaction3).send() transfer3.getError shouldEqual null @@ -486,7 +498,7 @@ class RpcApiTests extends AnyFlatSpec with Matchers with Logger { response.getTransactionHash should not equal null // Wait till transaction is mined - val minedTransaction = service.transactionFlowable().blockingFirst() + service.transactionFlowable().blockingFirst() val response1 = service.ethGetTransactionReceipt(response.getTransactionHash).send() response1.getTransactionReceipt.isPresent shouldEqual true @@ -527,7 +539,7 @@ class RpcApiTests extends AnyFlatSpec with Matchers with Logger { response2.getTransaction.isPresent shouldEqual true // Wait for the transaction to be mined - val minedTransaction = service.transactionFlowable().blockingFirst() + service.transactionFlowable().blockingFirst() val response3 = service.ethGetTransactionByHash(tHash).send() response3.getTransaction.isPresent shouldEqual true @@ -542,7 +554,7 @@ class RpcApiTests extends AnyFlatSpec with Matchers with Logger { response2.getTransactionReceipt.isPresent shouldEqual false // Wait for the transaction to be mined - val minedTransaction = service.transactionFlowable().blockingFirst() + service.transactionFlowable().blockingFirst() val response3 = service.ethGetTransactionByHash(tHash).send() response3.getTransaction.isPresent shouldEqual true @@ -555,7 +567,7 @@ class RpcApiTests extends AnyFlatSpec with Matchers with Logger { val response2 = service.ethSendTransaction(createContract(firstAccount.address, counterEventContract)).send() val txHash = response2.getTransactionHash - val minedTransaction = service.transactionFlowable().blockingFirst() + service.transactionFlowable().blockingFirst() val response3 = service.ethGetTransactionReceipt(txHash).send() response3.getTransactionReceipt.isPresent shouldBe true @@ -566,12 +578,12 @@ class RpcApiTests extends AnyFlatSpec with Matchers with Logger { .send() hexToBigInt(response4.getValue) shouldEqual 0 - val response5 = service + service .ethSendTransaction( contractCall(firstAccount.address, receipt.getContractAddress, writeContract(1, incrementEventContract)) ) .send() - val minedTransaction1 = service.transactionFlowable().blockingFirst() + service.transactionFlowable().blockingFirst() val response6 = service .ethCall(contractCall(firstAccount.address, receipt.getContractAddress, readEventContract), latestBlock) @@ -586,7 +598,7 @@ class RpcApiTests extends AnyFlatSpec with Matchers with Logger { .send() response7.getError shouldEqual null - val minedTransaction2 = service.transactionFlowable().blockingFirst() + service.transactionFlowable().blockingFirst() val response8 = service .ethCall(contractCall(firstAccount.address, receipt.getContractAddress, readEventContract), pendingBlock) @@ -617,7 +629,7 @@ class RpcApiTests extends AnyFlatSpec with Matchers with Logger { val response2 = service.ethSendTransaction(createContract(firstAccount.address, testContract)).send() val txHash = response2.getTransactionHash - val minedTransaction = service.transactionFlowable().blockingFirst() + service.transactionFlowable().blockingFirst() val response3 = service.ethGetTransactionReceipt(txHash).send() response3.getTransactionReceipt.isPresent shouldEqual true @@ -629,11 +641,11 @@ class RpcApiTests extends AnyFlatSpec with Matchers with Logger { .ethSendTransaction(createContract(firstAccount.address, testContract, Some((gasEstimated - 1).bigInteger))) .send() val txHash1 = response4.getTransactionHash - val minedTransaction1 = service.transactionFlowable().blockingFirst() + service.transactionFlowable().blockingFirst() val response5 = service.ethGetTransactionReceipt(txHash1).send() response5.getTransactionReceipt.isPresent shouldEqual true - val receipt1 = response5.getTransactionReceipt.get() + response5.getTransactionReceipt.get() } it should "eth_getLogs" taggedAs (PrivNet) in new ScenarioSetup { @@ -646,7 +658,7 @@ class RpcApiTests extends AnyFlatSpec with Matchers with Logger { setupContractResponse1.getError shouldEqual null // Mine 2 Contract creation transactions - val minedBlock = service.blockFlowable(false).blockingFirst() + service.blockFlowable(false).blockingFirst() // Get receipt for both contract creation transactions val receiptResponse = service.ethGetTransactionReceipt(setupContractResponse.getTransactionHash).send() @@ -660,7 +672,7 @@ class RpcApiTests extends AnyFlatSpec with Matchers with Logger { val updateValue = 5 val emitValue = 10 // Call contracts which emits logs - val counterResponse = service + service .ethSendTransaction( contractCall( firstAccount.address, @@ -669,7 +681,7 @@ class RpcApiTests extends AnyFlatSpec with Matchers with Logger { ) ) .send() - val emiterResponse = service + service .ethSendTransaction( contractCall(firstAccount.address, receipt2.getContractAddress, writeContract(emitValue, emitEvent)) ) @@ -773,7 +785,7 @@ class RpcApiTests extends AnyFlatSpec with Matchers with Logger { setupContractResponse1.getError shouldEqual null // Mine 2 Contract creation transactions - val unused = service.blockFlowable(false).take(2).blockingLast() + service.blockFlowable(false).take(2).blockingLast() // Get receipt for both contract creation transactions val receiptResponse = service.ethGetTransactionReceipt(setupContractResponse.getTransactionHash).send() @@ -787,7 +799,7 @@ class RpcApiTests extends AnyFlatSpec with Matchers with Logger { val updateValue = 5 val emitValue = 10 // Call contracts which emits logs - val counterResponse = service + service .ethSendTransaction( contractCall( firstAccount.address, @@ -796,7 +808,7 @@ class RpcApiTests extends AnyFlatSpec with Matchers with Logger { ) ) .send() - val emiterResponse = service + service .ethSendTransaction( contractCall(firstAccount.address, receipt2.getContractAddress, writeContract(emitValue, emitEvent)) ) @@ -944,9 +956,9 @@ class RpcApiTests extends AnyFlatSpec with Matchers with Logger { val blockchanges = service.ethGetFilterChanges(blockFilterid).send() val addedBlocks = blockchanges.getLogs.asScala.toList.map(log => log.asInstanceOf[Hash].get) addedBlocks should contain(minedBlock.getBlock.getHash) - val uninstalTxFilterResponse3 = service.ethUninstallFilter(blockFilterid).send() + service.ethUninstallFilter(blockFilterid).send() uninstalTxFilterResponse.isUninstalled shouldEqual true - val minedBlock1 = service.blockFlowable(false).take(2).blockingLast() + service.blockFlowable(false).take(2).blockingLast() val blockchanges1 = service.ethGetFilterChanges(blockFilterid).send() blockchanges1.getLogs.asScala.toList.size shouldEqual 0 @@ -959,13 +971,13 @@ class RpcApiTests extends AnyFlatSpec with Matchers with Logger { val changes = service.ethGetFilterChanges(transactionFilterId).send() val pendingTransactions = changes.getLogs.asScala.toList.map(log => log.asInstanceOf[Hash].get) pendingTransactions.size shouldEqual 1 - val uninstalPendingFilter = service.ethUninstallFilter(transactionFilterId).send() + service.ethUninstallFilter(transactionFilterId).send() uninstalTxFilterResponse1.isUninstalled shouldEqual true val changes1 = service.ethGetFilterChanges(transactionFilterId).send() val pendingTransactions1 = changes1.getLogs.asScala.toList.map(log => log.asInstanceOf[Hash].get) pendingTransactions1.size shouldEqual 0 - val minedBlock2 = service.blockFlowable(false).blockingFirst() + service.blockFlowable(false).blockingFirst() val receiptResponse = service.ethGetTransactionReceipt(setupContractResponse.getTransactionHash).send() receiptResponse.getTransactionReceipt.isPresent shouldBe true @@ -973,7 +985,7 @@ class RpcApiTests extends AnyFlatSpec with Matchers with Logger { val updateValue = 5 // Call contracts which emits logs - val counterResponse = service + service .ethSendTransaction( contractCall( firstAccount.address, @@ -982,7 +994,7 @@ class RpcApiTests extends AnyFlatSpec with Matchers with Logger { ) ) .send() - val minedBlock3 = service.blockFlowable(false).blockingFirst() + service.blockFlowable(false).blockingFirst() // log filter was uninstalled val logsResponse = service.ethGetFilterChanges(logFilter).send() @@ -1112,9 +1124,9 @@ class RpcApiTests extends AnyFlatSpec with Matchers with Logger { val accounts = response2.getAccountIds.asScala accounts should contain.allOf(newAccId, newAccId1) - val transfer1 = service.ethSendTransaction(valueTransfer(firstAccount.address, newAccId, 1000)).send() + service.ethSendTransaction(valueTransfer(firstAccount.address, newAccId, 1000)).send() - val mined = service.transactionFlowable().blockingFirst() + service.transactionFlowable().blockingFirst() val transfer2 = service.personalSendTransaction(valueTransfer(newAccId, newAccId1, 100), "badpass").send() transfer2.getError should not equal null @@ -1144,25 +1156,25 @@ class RpcApiTests extends AnyFlatSpec with Matchers with Logger { } abstract class ScenarioSetup { - val testConfig = RpcTestConfig("test.conf") + val testConfig: RpcTestConfig = RpcTestConfig("test.conf") // Some data from mantis config (this data is not exposed to built version so it is safe to load it here - val config = ConfigFactory.load("application.conf").getConfig("mantis") + val config: Config = ConfigFactory.load("application.conf").getConfig("mantis") val clientVersion: String = io.iohk.ethereum.utils.Config.clientVersion val networkName: String = io.iohk.ethereum.utils.Config.blockchains.network - val capabilities = io.iohk.ethereum.utils.Config.blockchains.blockchains(networkName).capabilities + val capabilities: List[Capability] = io.iohk.ethereum.utils.Config.blockchains.blockchains(networkName).capabilities // - val service = Admin.build(new HttpService(testConfig.mantisUrl)) + val service: Admin = Admin.build(new HttpService(testConfig.mantisUrl)) val unexisitingBlockHash = "0xaaaaaaaaaaa959b3db6469104c59b803162cf37a23293e8df306e559218f5c6f" val badHash = "0xm" val emptyResponse = "0x" val generalErrorCode = -32602 - val futureBlock = DefaultBlockParameter.valueOf(BigInt(50000000000000L).bigInteger) - val latestBlock = DefaultBlockParameter.valueOf("latest") - val pendingBlock = DefaultBlockParameter.valueOf("pending") - val earliestBlock = DefaultBlockParameter.valueOf("earliest") + val futureBlock: DefaultBlockParameter = DefaultBlockParameter.valueOf(BigInt(50000000000000L).bigInteger) + val latestBlock: DefaultBlockParameter = DefaultBlockParameter.valueOf("latest") + val pendingBlock: DefaultBlockParameter = DefaultBlockParameter.valueOf("pending") + val earliestBlock: DefaultBlockParameter = DefaultBlockParameter.valueOf("earliest") def getBlockParam(number: BigInt): DefaultBlockParameter = { DefaultBlockParameter.valueOf(number) @@ -1231,27 +1243,27 @@ abstract class ScenarioSetup { ) } - val sampleTransaction = createContract(firstAccount.address, testContract) + val sampleTransaction: Transaction = createContract(firstAccount.address, testContract) // helper to setup two accounts with same nonce and some initial funding def setupTwoNewAccounts(fundsProvider: String, amount: BigInt): (TestAccount, TestAccount) = { val first = service.personalNewAccount("").send().getAccountId val second = service.personalNewAccount("").send().getAccountId - val firstUnlock = service.personalUnlockAccount(first, "", 0).send() - val secondUnlock = service.personalUnlockAccount(second, "", 0).send() + service.personalUnlockAccount(first, "", 0).send() + service.personalUnlockAccount(second, "", 0).send() - val trans = service.ethSendTransaction(valueTransfer(fundsProvider, first, amount)).send() - val trans1 = service.ethSendTransaction(valueTransfer(fundsProvider, second, amount)).send() + service.ethSendTransaction(valueTransfer(fundsProvider, first, amount)).send() + service.ethSendTransaction(valueTransfer(fundsProvider, second, amount)).send() // wait for mine - val block = service.blockFlowable(false).blockingFirst() + service.blockFlowable(false).blockingFirst() (TestAccount(first, "", amount), TestAccount(second, "", amount)) } // Needed to sign transaction and send raw transactions - val keyStoreConfig = KeyStoreConfig.customKeyStoreConfig(testConfig.keystoreDir) + val keyStoreConfig: KeyStoreConfig = KeyStoreConfig.customKeyStoreConfig(testConfig.keystoreDir) val keyStore = new KeyStoreImpl(keyStoreConfig, new SecureRandom()) diff --git a/src/rpcTest/scala/io/iohk/ethereum/rpcTest/TestContracts.scala b/src/rpcTest/scala/io/iohk/ethereum/rpcTest/TestContracts.scala index d124944e3a..cb7556e7b0 100644 --- a/src/rpcTest/scala/io/iohk/ethereum/rpcTest/TestContracts.scala +++ b/src/rpcTest/scala/io/iohk/ethereum/rpcTest/TestContracts.scala @@ -1,7 +1,9 @@ package io.iohk.ethereum.rpcTest import akka.util.ByteString + import org.bouncycastle.util.encoders.Hex + import io.iohk.ethereum.rpcTest.TestData.firstAccount object TestContracts { @@ -13,11 +15,11 @@ object TestContracts { // https://github.com/ethereum/wiki/wiki/JSON-RPC#example-14 val storageContract = "0x60606040525b6104d260006000508190555061162e600160005060003373ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600050819055505b600a8060546000396000f360606040526008565b00" - val pos0 = BigInt(1234) - val mapPos = "000000000000000000000000" + firstAccount.address.drop(2) + "0000000000000000000000000000000000000000000000000000000000000001" - val decoded = Hex.decode(mapPos) - val shaPos = BigInt(kec256(decoded)) - val mapResult = BigInt(5678) + val pos0: BigInt = BigInt(1234) + val mapPos: String = "000000000000000000000000" + firstAccount.address.drop(2) + "0000000000000000000000000000000000000000000000000000000000000001" + val decoded: Array[Byte] = Hex.decode(mapPos) + val shaPos: BigInt = BigInt(kec256(decoded)) + val mapResult: BigInt = BigInt(5678) val StorageCodeRuntimeRepresentation = "0x60606040526008565b00" @@ -37,7 +39,7 @@ object TestContracts { * * */ val counterEventContract = "0x6060604052600060006000505560d68060186000396000f360606040526000357c01000000000000000000000000000000000000000000000000000000009004806306661abd1460415780637cf5dab014606257603f565b005b604c600480505060cd565b6040518082815260200191505060405180910390f35b607660048080359060200190919050506078565b005b803373ffffffffffffffffffffffffffffffffffffffff167fb182275171042022ff972a26edbd0171bccc74463bd22e56dbbeba4e93b7a66860405180905060405180910390a3806000600050819055505b50565b6000600050548156" - val readEventContract = "06661abd" + "0000000000000000000000000000000000000000000000000000000000000000" + val readEventContract: String = "06661abd" + "0000000000000000000000000000000000000000000000000000000000000000" val incrementEventContract = "7cf5dab0" val counterContractEventHash = "0xb182275171042022ff972a26edbd0171bccc74463bd22e56dbbeba4e93b7a668" diff --git a/src/rpcTest/scala/io/iohk/ethereum/rpcTest/TestData.scala b/src/rpcTest/scala/io/iohk/ethereum/rpcTest/TestData.scala index 1dd029fda4..170a7677ae 100644 --- a/src/rpcTest/scala/io/iohk/ethereum/rpcTest/TestData.scala +++ b/src/rpcTest/scala/io/iohk/ethereum/rpcTest/TestData.scala @@ -5,18 +5,18 @@ import org.web3j.protocol.core.DefaultBlockParameter object TestData { case class TestBlock(hash: String, number: BigInt, transactions: List[TestTransaction] = List.empty , uncles: List[TestUncle] = List.empty) { - lazy val blockNumber = DefaultBlockParameter.valueOf(number.bigInteger) + lazy val blockNumber: DefaultBlockParameter = DefaultBlockParameter.valueOf(number.bigInteger) } case class TestTransaction(hash: String, index: BigInt) case class TestUncle(hash: String, index: BigInt) case class TestAccount(address: String, password: String, balance: BigInt) // MainNet existing blocks - val oneUncleTestBlock = TestBlock("0xb055593f14d994d333d4a7fbf6251c8fef00d24ca74e1355de90729ca9b6d7f5", 1024, + val oneUncleTestBlock: TestBlock = TestBlock("0xb055593f14d994d333d4a7fbf6251c8fef00d24ca74e1355de90729ca9b6d7f5", 1024, uncles = List(TestUncle("0xe00ecf0381819d0b8cf86eed3e1d91db26b3e78f80bab8b388768a49210c7e6f", 0)) ) - val noTransactionsOrUnclesBlock = TestBlock("0x73b20034e531f385a59401bbda9a225be12b2fd42d7c21e4c3d11b3d7be34244", 2000) - val twoTransactionBlock = TestBlock("0x3152ec08cab959b3db6469104c59b803162cf37a23293e8df306e559218f5c6f", 127117, + val noTransactionsOrUnclesBlock: TestBlock = TestBlock("0x73b20034e531f385a59401bbda9a225be12b2fd42d7c21e4c3d11b3d7be34244", 2000) + val twoTransactionBlock: TestBlock = TestBlock("0x3152ec08cab959b3db6469104c59b803162cf37a23293e8df306e559218f5c6f", 127117, List( TestTransaction("0x1f76a07cc698c1ef425c406ede5db8fa5ed67f084397ac74fd48348bd08fbb1d", 0), TestTransaction("0x4fcf5556f2ebb8d47e1335641fa1b1f1fd24e41645f666fa8b16af6c03eddf19", 1) @@ -24,17 +24,17 @@ object TestData { ) // Exisiting privatenet Accounts - val firstAccount = TestAccount("0x316158e265fa708c623cc3094b2bb5889e0f5ca5", "hunter2", BigInt("100000000000000000000")) - val secondAccount = TestAccount("0xb9ec69316a8810db91c36de79c4f1e785f2c35fc", "", BigInt("100000000000000000000")) + val firstAccount: TestAccount = TestAccount("0x316158e265fa708c623cc3094b2bb5889e0f5ca5", "hunter2", BigInt("100000000000000000000")) + val secondAccount: TestAccount = TestAccount("0xb9ec69316a8810db91c36de79c4f1e785f2c35fc", "", BigInt("100000000000000000000")) // Account not used in value transfers - val thirdAccount = TestAccount("0x488c10c91771d3b3c25f63b6414309b119baacb5", "", BigInt("100000000000000000000")) + val thirdAccount: TestAccount = TestAccount("0x488c10c91771d3b3c25f63b6414309b119baacb5", "", BigInt("100000000000000000000")) - val gethAccount = TestAccount("0x03010360ebbb7f49362a2c650a67661d464e2089", "", BigInt("0")) + val gethAccount: TestAccount = TestAccount("0x03010360ebbb7f49362a2c650a67661d464e2089", "", BigInt("0")) - val unexistingAccount = TestAccount("0xaaaa10c91771d3b3c25f63b6414309b119baacb5", "", BigInt("100000000000000000000")) + val unexistingAccount: TestAccount = TestAccount("0xaaaa10c91771d3b3c25f63b6414309b119baacb5", "", BigInt("100000000000000000000")) val coinbase = "0x0011223344556677889900112233445566778899" - val defaultGasPrice = BigInt(20000000000L) - val defaultGas = BigInt(90000) + val defaultGasPrice: BigInt = BigInt(20000000000L) + val defaultGas: BigInt = BigInt(90000) } diff --git a/src/test/scala/io/iohk/ethereum/BlockHelpers.scala b/src/test/scala/io/iohk/ethereum/BlockHelpers.scala index 0e05a5957a..14ff6e17e5 100644 --- a/src/test/scala/io/iohk/ethereum/BlockHelpers.scala +++ b/src/test/scala/io/iohk/ethereum/BlockHelpers.scala @@ -1,19 +1,21 @@ package io.iohk.ethereum import akka.util.ByteString + +import scala.util.Random + +import mouse.all._ +import org.bouncycastle.crypto.AsymmetricCipherKeyPair + import io.iohk.ethereum.crypto.generateKeyPair import io.iohk.ethereum.domain.BlockHeader.HeaderExtraFields import io.iohk.ethereum.domain._ import io.iohk.ethereum.security.SecureRandomBuilder -import mouse.all._ -import org.bouncycastle.crypto.AsymmetricCipherKeyPair - -import scala.util.Random object BlockHelpers extends SecureRandomBuilder { // scalastyle:off magic.number - val defaultHeader = Fixtures.Blocks.ValidBlock.header.copy( + val defaultHeader: BlockHeader = Fixtures.Blocks.ValidBlock.header.copy( difficulty = 1000000, number = 1, gasLimit = 1000000, @@ -21,7 +23,7 @@ object BlockHelpers extends SecureRandomBuilder { unixTimestamp = 0 ) - val defaultTx = Transaction( + val defaultTx: Transaction = Transaction( nonce = 42, gasPrice = 1, gasLimit = 90000, @@ -44,7 +46,7 @@ object BlockHelpers extends SecureRandomBuilder { } def resetHeaderExtraFields(hef: BlockHeader.HeaderExtraFields): BlockHeader.HeaderExtraFields = hef match { - case HeaderExtraFields.HefEmpty => HeaderExtraFields.HefEmpty + case HeaderExtraFields.HefEmpty => HeaderExtraFields.HefEmpty case HeaderExtraFields.HefPostEcip1097(_) => HeaderExtraFields.HefPostEcip1097(None) } @@ -63,12 +65,10 @@ object BlockHelpers extends SecureRandomBuilder { Block(header, BlockBody(List(stx.tx), List(ommer))) } - def updateHeader(block: Block, updater: BlockHeader => BlockHeader): Block = { + def updateHeader(block: Block, updater: BlockHeader => BlockHeader): Block = block.copy(header = updater(block.header)) - } - def withTransactions(block: Block, transactions: List[SignedTransaction]): Block = { + def withTransactions(block: Block, transactions: List[SignedTransaction]): Block = block.copy(body = block.body.copy(transactionList = transactions)) - } } diff --git a/src/test/scala/io/iohk/ethereum/BootstrapDownloadSpec.scala b/src/test/scala/io/iohk/ethereum/BootstrapDownloadSpec.scala index b7a9105b84..a30fa311a4 100644 --- a/src/test/scala/io/iohk/ethereum/BootstrapDownloadSpec.scala +++ b/src/test/scala/io/iohk/ethereum/BootstrapDownloadSpec.scala @@ -1,20 +1,23 @@ package io.iohk.ethereum import java.io.File +import java.net.URL +import java.nio.file.Path import java.nio.file.Paths import scala.io.Source + import org.scalatest.flatspec.AnyFlatSpec import org.scalatest.matchers.should.Matchers class BootstrapDownloadSpec extends AnyFlatSpec with Matchers { - val testURL = getClass.getResource("/downloadtest.zip") + val testURL: URL = getClass.getResource("/downloadtest.zip") // generated by `shasum -a 512` on macOs val expectedHash = "3fb5df802ca39b23924e349f7fd078e1fe88f443fe5f6623b7190807376c4f10d7e2174a47c6d1cd1daf117040bb6766c94acd373946005b1e35b85540dbc509" - val tmpFolder = Paths.get(System.getProperty("java.io.tmpdir")) + val tmpFolder: Path = Paths.get(System.getProperty("java.io.tmpdir")) val downloadTest = new File(tmpFolder.toFile, "downloadtest") val subfolder = new File(downloadTest, "subfolder") val subfolderSmallFile = new File(subfolder, "smallfile.subfolder.txt") diff --git a/src/test/scala/io/iohk/ethereum/ByteGenerators.scala b/src/test/scala/io/iohk/ethereum/ByteGenerators.scala index 73960c146c..279d0bcbbd 100644 --- a/src/test/scala/io/iohk/ethereum/ByteGenerators.scala +++ b/src/test/scala/io/iohk/ethereum/ByteGenerators.scala @@ -1,7 +1,9 @@ package io.iohk.ethereum import akka.util.ByteString -import org.scalacheck.{Arbitrary, Gen} + +import org.scalacheck.Arbitrary +import org.scalacheck.Gen trait ByteGenerators { def randomSizeByteArrayGen(minSize: Int, maxSize: Int): Gen[Array[Byte]] = @@ -19,18 +21,16 @@ trait ByteGenerators { def seqByteStringOfNItemsGen(n: Int): Gen[Seq[ByteString]] = Gen.listOf(byteStringOfLengthNGen(n)) - def hexPrefixDecodeParametersGen(): Gen[(Array[Byte], Boolean)] = { + def hexPrefixDecodeParametersGen(): Gen[(Array[Byte], Boolean)] = for { aByteList <- Gen.nonEmptyListOf(Arbitrary.arbitrary[Byte]) t <- Arbitrary.arbitrary[Boolean] } yield (aByteList.toArray, t) - } - def keyValueByteStringGen(size: Int): Gen[List[(ByteString, Array[Byte])]] = { + def keyValueByteStringGen(size: Int): Gen[List[(ByteString, Array[Byte])]] = for { byteStringList <- Gen.nonEmptyListOf(byteStringOfLengthNGen(size)) arrayList <- Gen.nonEmptyListOf(byteArrayOfNItemsGen(size)) } yield byteStringList.zip(arrayList) - } } object ByteGenerators extends ByteGenerators {} diff --git a/src/test/scala/io/iohk/ethereum/Fixtures.scala b/src/test/scala/io/iohk/ethereum/Fixtures.scala index 52b9d74889..a1c4b2e428 100644 --- a/src/test/scala/io/iohk/ethereum/Fixtures.scala +++ b/src/test/scala/io/iohk/ethereum/Fixtures.scala @@ -1,9 +1,11 @@ package io.iohk.ethereum import akka.util.ByteString -import io.iohk.ethereum.domain._ + import org.bouncycastle.util.encoders.Hex +import io.iohk.ethereum.domain._ + object Fixtures { object Blocks { @@ -27,7 +29,7 @@ object Fixtures { } object Block3125369 extends FixtureBlock { - val header = BlockHeader( + val header: BlockHeader = BlockHeader( parentHash = ByteString(Hex.decode("8345d132564b3660aa5f27c9415310634b50dbc92579c65a0825d9a255227a71")), ommersHash = ByteString(Hex.decode("1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347")), beneficiary = ByteString(Hex.decode("df7d7e053933b5cc24372f878c90e62dadad5d42")), @@ -45,7 +47,7 @@ object Fixtures { nonce = ByteString(Hex.decode("2b0fb0c002946392")) ) - val body = BlockBody( + val body: BlockBody = BlockBody( transactionList = Seq[SignedTransaction]( SignedTransaction( tx = Transaction( @@ -111,7 +113,7 @@ object Fixtures { uncleNodesList = Seq[BlockHeader]() ) - val transactionHashes = Seq( + val transactionHashes: Seq[ByteString] = Seq( ByteString(Hex.decode("af854c57c64191827d1c80fc50f716f824508973e12e4d4c60d270520ce72edb")), ByteString(Hex.decode("f3e33ba2cb400221476fa4025afd95a13907734c38a4a8dff4b7d860ee5adc8f")), ByteString(Hex.decode("202359a4c0b0f11ca07d44fdeb3502ffe91c86ad4a9af47c27f11b23653339f2")), @@ -122,7 +124,7 @@ object Fixtures { } object Genesis extends FixtureBlock { - val header = BlockHeader( + val header: BlockHeader = BlockHeader( parentHash = ByteString(Hex.decode("0000000000000000000000000000000000000000000000000000000000000000")), ommersHash = ByteString(Hex.decode("1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347")), beneficiary = ByteString(Hex.decode("0000000000000000000000000000000000000000")), diff --git a/src/test/scala/io/iohk/ethereum/Mocks.scala b/src/test/scala/io/iohk/ethereum/Mocks.scala index 31fec1eec8..c21917a102 100644 --- a/src/test/scala/io/iohk/ethereum/Mocks.scala +++ b/src/test/scala/io/iohk/ethereum/Mocks.scala @@ -1,22 +1,29 @@ package io.iohk.ethereum import akka.util.ByteString -import cats.data.NonEmptyList + +import io.iohk.ethereum.consensus.GetBlockHeaderByHash +import io.iohk.ethereum.consensus.GetNBlocksBack +import io.iohk.ethereum.consensus.pow.validators.OmmersValidator import io.iohk.ethereum.consensus.pow.validators.OmmersValidator.OmmersError.OmmersHeaderError import io.iohk.ethereum.consensus.pow.validators.OmmersValidator.OmmersValid -import io.iohk.ethereum.consensus.pow.validators.{OmmersValidator, ValidatorsExecutor} -import io.iohk.ethereum.consensus.validators.BlockHeaderError.{HeaderDifficultyError, HeaderNumberError} +import io.iohk.ethereum.consensus.pow.validators.ValidatorsExecutor +import io.iohk.ethereum.consensus.validators.BlockHeaderError.HeaderDifficultyError +import io.iohk.ethereum.consensus.validators.BlockHeaderError.HeaderNumberError import io.iohk.ethereum.consensus.validators._ -import io.iohk.ethereum.consensus.validators.std.StdBlockValidator.{BlockError, BlockTransactionsHashError, BlockValid} -import io.iohk.ethereum.consensus.{Consensus, GetBlockHeaderByHash, GetNBlocksBack} +import io.iohk.ethereum.consensus.validators.std.StdBlockValidator.BlockError +import io.iohk.ethereum.consensus.validators.std.StdBlockValidator.BlockTransactionsHashError +import io.iohk.ethereum.consensus.validators.std.StdBlockValidator.BlockValid import io.iohk.ethereum.domain._ import io.iohk.ethereum.ledger.BlockExecutionError.ValidationAfterExecError import io.iohk.ethereum.ledger._ -import io.iohk.ethereum.network.EtcPeerManagerActor.{PeerInfo, RemoteStatus} -import io.iohk.ethereum.network.handshaker.{ConnectedState, DisconnectedState, Handshaker, HandshakerState} +import io.iohk.ethereum.network.EtcPeerManagerActor.PeerInfo +import io.iohk.ethereum.network.EtcPeerManagerActor.RemoteStatus +import io.iohk.ethereum.network.handshaker.ConnectedState +import io.iohk.ethereum.network.handshaker.DisconnectedState +import io.iohk.ethereum.network.handshaker.Handshaker +import io.iohk.ethereum.network.handshaker.HandshakerState import io.iohk.ethereum.vm._ -import monix.eval.Task -import monix.execution.Scheduler object Mocks { private val defaultProgramResult: PC => PR = context => @@ -106,15 +113,13 @@ object Mocks { override def validateHeaderAndBody( blockHeader: BlockHeader, blockBody: BlockBody - ): Either[BlockError, BlockValid] = { + ): Either[BlockError, BlockValid] = if (blockHeader.number == number) Left(BlockTransactionsHashError) else Right(BlockValid) - } override def validateBlockAndReceipts( blockHeader: BlockHeader, receipts: Seq[Receipt] - ): Either[BlockError, BlockValid] = { + ): Either[BlockError, BlockValid] = if (blockHeader.number == number) Left(BlockTransactionsHashError) else Right(BlockValid) - } } override def validateBlockAfterExecution( @@ -122,9 +127,8 @@ object Mocks { stateRootHash: ByteString, receipts: Seq[Receipt], gasUsed: BigInt - ): Either[BlockExecutionError, BlockExecutionSuccess] = { + ): Either[BlockExecutionError, BlockExecutionSuccess] = if (block.header.number == number) Left(ValidationAfterExecError("")) else Right(BlockExecutionSuccess) - } } case class MockHandshakerAlwaysSucceeds( diff --git a/src/test/scala/io/iohk/ethereum/ObjectGenerators.scala b/src/test/scala/io/iohk/ethereum/ObjectGenerators.scala index ecf20fb8c7..00b9912e18 100644 --- a/src/test/scala/io/iohk/ethereum/ObjectGenerators.scala +++ b/src/test/scala/io/iohk/ethereum/ObjectGenerators.scala @@ -4,17 +4,25 @@ import java.math.BigInteger import java.security.SecureRandom import akka.util.ByteString + +import org.bouncycastle.crypto.AsymmetricCipherKeyPair +import org.scalacheck.Arbitrary +import org.scalacheck.Gen + import io.iohk.ethereum.blockchain.sync.StateSyncUtils.MptNodeData import io.iohk.ethereum.crypto.ECDSASignature import io.iohk.ethereum.domain.BlockHeader.HeaderExtraFields import io.iohk.ethereum.domain.BlockHeader.HeaderExtraFields._ import io.iohk.ethereum.domain._ +import io.iohk.ethereum.mpt.BranchNode +import io.iohk.ethereum.mpt.ExtensionNode +import io.iohk.ethereum.mpt.HashNode import io.iohk.ethereum.mpt.HexPrefix.bytesToNibbles -import io.iohk.ethereum.mpt.{BranchNode, ExtensionNode, HashNode, LeafNode, MptNode, MptTraversals} +import io.iohk.ethereum.mpt.LeafNode +import io.iohk.ethereum.mpt.MptNode +import io.iohk.ethereum.mpt.MptTraversals import io.iohk.ethereum.network.p2p.messages.BaseETH6XMessages.NewBlock import io.iohk.ethereum.network.p2p.messages.ETC64 -import org.bouncycastle.crypto.AsymmetricCipherKeyPair -import org.scalacheck.{Arbitrary, Gen, Shrink} // scalastyle:off number.of.methods trait ObjectGenerators { @@ -43,26 +51,23 @@ trait ObjectGenerators { def seqByteStringOfNItemsGen(n: Int): Gen[Seq[ByteString]] = Gen.listOf(byteStringOfLengthNGen(n)) - def hexPrefixDecodeParametersGen(): Gen[(Array[Byte], Boolean)] = { + def hexPrefixDecodeParametersGen(): Gen[(Array[Byte], Boolean)] = for { aByteList <- Gen.nonEmptyListOf(Arbitrary.arbitrary[Byte]) t <- Arbitrary.arbitrary[Boolean] } yield (aByteList.toArray, t) - } - def keyValueListGen(minValue: Int = Int.MinValue, maxValue: Int = Int.MaxValue): Gen[List[(Int, Int)]] = { + def keyValueListGen(minValue: Int = Int.MinValue, maxValue: Int = Int.MaxValue): Gen[List[(Int, Int)]] = for { values <- Gen.chooseNum(minValue, maxValue) aKeyList <- Gen.nonEmptyListOf(values).map(_.distinct) } yield aKeyList.zip(aKeyList) - } - def keyValueByteStringGen(size: Int): Gen[List[(ByteString, Array[Byte])]] = { + def keyValueByteStringGen(size: Int): Gen[List[(ByteString, Array[Byte])]] = for { byteStringList <- Gen.nonEmptyListOf(byteStringOfLengthNGen(size)) arrayList <- Gen.nonEmptyListOf(byteArrayOfNItemsGen(size)) } yield byteStringList.zip(arrayList) - } def receiptGen(): Gen[Receipt] = for { postTransactionStateHash <- byteArrayOfNItemsGen(32) @@ -142,11 +147,10 @@ trait ObjectGenerators { } } - def genKey(rnd: SecureRandom): Gen[AsymmetricCipherKeyPair] = { + def genKey(rnd: SecureRandom): Gen[AsymmetricCipherKeyPair] = Gen.resultOf { _: Unit => crypto.generateKeyPair(rnd) } - } def newBlockGen(secureRandom: SecureRandom, chainId: Option[Byte]): Gen[NewBlock] = for { blockHeader <- blockHeaderGen @@ -167,7 +171,7 @@ trait ObjectGenerators { checkpoint <- if (shouldCheckpoint.isDefined) Gen.option(fakeCheckpointOptGen(0, 5)) else Gen.const(None) } yield checkpoint match { case Some(definedCheckpoint) => HefPostEcip1097(definedCheckpoint) - case None => HefEmpty + case None => HefEmpty } def blockHeaderGen: Gen[BlockHeader] = for { @@ -243,7 +247,7 @@ trait ObjectGenerators { list <- Gen.listOfN(n, genMptNodeData) } yield list - val chainWeightGen = for { + val chainWeightGen: Gen[ChainWeight] = for { lcn <- bigIntGen td <- bigIntGen } yield ChainWeight(lcn, td) diff --git a/src/test/scala/io/iohk/ethereum/SpecBase.scala b/src/test/scala/io/iohk/ethereum/SpecBase.scala index 858c0d240e..9f81a10887 100644 --- a/src/test/scala/io/iohk/ethereum/SpecBase.scala +++ b/src/test/scala/io/iohk/ethereum/SpecBase.scala @@ -1,9 +1,16 @@ package io.iohk.ethereum +import cats.effect.Bracket +import cats.effect.Effect +import cats.effect.Resource import cats.effect.implicits._ -import cats.effect.{Bracket, Effect, Resource} + import monix.eval.Task import monix.execution.Scheduler + +import scala.concurrent.ExecutionContext +import scala.concurrent.Future + import org.scalactic.TypeCheckedTripleEquals import org.scalatest._ import org.scalatest.diagrams.Diagrams @@ -12,9 +19,6 @@ import org.scalatest.freespec.AsyncFreeSpecLike import org.scalatest.matchers.should.Matchers import org.scalatest.wordspec.AsyncWordSpecLike -import scala.concurrent.{ExecutionContext, Future} -import scala.language.higherKinds - trait SpecBase extends TypeCheckedTripleEquals with Diagrams with Matchers { self: AsyncTestSuite => override val executionContext = ExecutionContext.global @@ -22,16 +26,15 @@ trait SpecBase extends TypeCheckedTripleEquals with Diagrams with Matchers { sel def customTestCaseResourceM[M[_]: Effect, T]( fixture: Resource[M, T] - )(theTest: T => M[Assertion])(implicit bracket: Bracket[M, Throwable]): Future[Assertion] = { + )(theTest: T => M[Assertion])(implicit bracket: Bracket[M, Throwable]): Future[Assertion] = fixture.use(theTest).toIO.unsafeToFuture() - } def customTestCaseM[M[_]: Effect, T](fixture: => T)(theTest: T => M[Assertion]): Future[Assertion] = customTestCaseResourceM(Resource.pure[M, T](fixture))(theTest) def testCaseM[M[_]: Effect](theTest: => M[Assertion]): Future[Assertion] = customTestCaseM(())(_ => theTest) - def testCase(theTest: => Assertion): Future[Assertion] = testCaseM(Task { theTest }) + def testCase(theTest: => Assertion): Future[Assertion] = testCaseM(Task(theTest)) } trait FlatSpecBase extends AsyncFlatSpecLike with SpecBase {} @@ -60,8 +63,7 @@ trait ResourceFixtures { self: SpecBase => def testCaseM[M[_]: Effect](theTest: Fixture => M[Assertion]): Future[Assertion] = customTestCaseResourceM(fixtureResource.mapK(Task.liftTo[M]))(theTest) - /** - * Task-specific method to avoid type inference issues in [[testCaseM]] + /** Task-specific method to avoid type inference issues in [[testCaseM]] */ def testCaseT(theTest: Fixture => Task[Assertion]): Future[Assertion] = customTestCaseResourceM(fixtureResource)(theTest) diff --git a/src/test/scala/io/iohk/ethereum/SuperSlow.scala b/src/test/scala/io/iohk/ethereum/SuperSlow.scala index a533a21238..d83657b3bb 100644 --- a/src/test/scala/io/iohk/ethereum/SuperSlow.scala +++ b/src/test/scala/io/iohk/ethereum/SuperSlow.scala @@ -3,10 +3,9 @@ package io.iohk.ethereum import com.typesafe.config.ConfigFactory trait SuperSlow { - lazy private val skip = ConfigFactory.load().getBoolean("skip-super-slow-tests") + private lazy val skip = ConfigFactory.load().getBoolean("skip-super-slow-tests") - /** - * Some assertions may be prohibitively slow and shouldn't run on every CI run. Use this method when that's the case. + /** Some assertions may be prohibitively slow and shouldn't run on every CI run. Use this method when that's the case. * * @param f slow tests */ diff --git a/src/test/scala/io/iohk/ethereum/WithActorSystemShutDown.scala b/src/test/scala/io/iohk/ethereum/WithActorSystemShutDown.scala index ab0751130d..2bb72439f8 100644 --- a/src/test/scala/io/iohk/ethereum/WithActorSystemShutDown.scala +++ b/src/test/scala/io/iohk/ethereum/WithActorSystemShutDown.scala @@ -2,12 +2,13 @@ package io.iohk.ethereum import akka.actor.ActorSystem import akka.testkit.TestKit -import org.scalatest.{BeforeAndAfterAll, Suite} + +import org.scalatest.BeforeAndAfterAll +import org.scalatest.Suite trait WithActorSystemShutDown extends BeforeAndAfterAll { this: Suite => implicit val system: ActorSystem - override def afterAll(): Unit = { + override def afterAll(): Unit = TestKit.shutdownActorSystem(system, verifySystemShutdown = true) - } } diff --git a/src/test/scala/io/iohk/ethereum/blockchain/sync/BlockBroadcastSpec.scala b/src/test/scala/io/iohk/ethereum/blockchain/sync/BlockBroadcastSpec.scala index 9a680a4f2c..c131a7934e 100644 --- a/src/test/scala/io/iohk/ethereum/blockchain/sync/BlockBroadcastSpec.scala +++ b/src/test/scala/io/iohk/ethereum/blockchain/sync/BlockBroadcastSpec.scala @@ -3,19 +3,31 @@ package io.iohk.ethereum.blockchain.sync import java.net.InetSocketAddress import akka.actor.ActorSystem -import akka.testkit.{TestKit, TestProbe} +import akka.testkit.TestKit +import akka.testkit.TestProbe + +import org.scalatest.flatspec.AnyFlatSpecLike +import org.scalatest.matchers.should.Matchers + +import io.iohk.ethereum.Fixtures +import io.iohk.ethereum.WithActorSystemShutDown import io.iohk.ethereum.blockchain.sync.PeerListSupportNg.PeerWithInfo import io.iohk.ethereum.blockchain.sync.regular.BlockBroadcast import io.iohk.ethereum.blockchain.sync.regular.BlockBroadcast.BlockToBroadcast -import io.iohk.ethereum.domain.{Block, BlockBody, BlockHeader, ChainWeight} -import io.iohk.ethereum.network.EtcPeerManagerActor.{PeerInfo, RemoteStatus} -import io.iohk.ethereum.network.p2p.messages.ETH62.NewBlockHashes +import io.iohk.ethereum.domain.Block +import io.iohk.ethereum.domain.BlockBody +import io.iohk.ethereum.domain.BlockHeader +import io.iohk.ethereum.domain.ChainWeight +import io.iohk.ethereum.network.EtcPeerManagerActor +import io.iohk.ethereum.network.EtcPeerManagerActor.PeerInfo +import io.iohk.ethereum.network.EtcPeerManagerActor.RemoteStatus +import io.iohk.ethereum.network.Peer +import io.iohk.ethereum.network.PeerId +import io.iohk.ethereum.network.p2p.messages.BaseETH6XMessages import io.iohk.ethereum.network.p2p.messages.ETC64.NewBlock -import io.iohk.ethereum.network.p2p.messages.{BaseETH6XMessages, ETH62, ProtocolVersions} -import io.iohk.ethereum.network.{EtcPeerManagerActor, Peer, PeerId} -import io.iohk.ethereum.{Fixtures, WithActorSystemShutDown} -import org.scalatest.flatspec.AnyFlatSpecLike -import org.scalatest.matchers.should.Matchers +import io.iohk.ethereum.network.p2p.messages.ETH62 +import io.iohk.ethereum.network.p2p.messages.ETH62.NewBlockHashes +import io.iohk.ethereum.network.p2p.messages.ProtocolVersions class BlockBroadcastSpec extends TestKit(ActorSystem("BlockBroadcastSpec_System")) @@ -157,20 +169,20 @@ class BlockBroadcastSpec } class TestSetup(implicit system: ActorSystem) { - val etcPeerManagerProbe = TestProbe() + val etcPeerManagerProbe: TestProbe = TestProbe() val blockBroadcast = new BlockBroadcast(etcPeerManagerProbe.ref) val baseBlockHeader = Fixtures.Blocks.Block3125369.header - val peerStatus = RemoteStatus( + val peerStatus: RemoteStatus = RemoteStatus( protocolVersion = ProtocolVersions.ETC64.version, networkId = 1, chainWeight = ChainWeight(10, 10000), bestHash = Fixtures.Blocks.Block3125369.header.hash, genesisHash = Fixtures.Blocks.Genesis.header.hash ) - val initialPeerInfo = PeerInfo( + val initialPeerInfo: PeerInfo = PeerInfo( remoteStatus = peerStatus, chainWeight = peerStatus.chainWeight, forkAccepted = false, @@ -178,7 +190,7 @@ class BlockBroadcastSpec bestBlockHash = peerStatus.bestHash ) - val peerProbe = TestProbe() - val peer = Peer(PeerId("peer"), new InetSocketAddress("127.0.0.1", 0), peerProbe.ref, false) + val peerProbe: TestProbe = TestProbe() + val peer: Peer = Peer(PeerId("peer"), new InetSocketAddress("127.0.0.1", 0), peerProbe.ref, false) } } diff --git a/src/test/scala/io/iohk/ethereum/blockchain/sync/BlockchainHostActorSpec.scala b/src/test/scala/io/iohk/ethereum/blockchain/sync/BlockchainHostActorSpec.scala index a54b0d0fd9..b83634364f 100644 --- a/src/test/scala/io/iohk/ethereum/blockchain/sync/BlockchainHostActorSpec.scala +++ b/src/test/scala/io/iohk/ethereum/blockchain/sync/BlockchainHostActorSpec.scala @@ -1,27 +1,42 @@ package io.iohk.ethereum.blockchain.sync -import akka.actor.{ActorSystem, Props} -import akka.testkit.{TestActorRef, TestProbe} +import akka.actor.ActorSystem +import akka.actor.Props +import akka.testkit.TestActorRef +import akka.testkit.TestProbe import akka.util.ByteString -import io.iohk.ethereum.domain.{BlockBody, BlockHeader, Receipt} -import io.iohk.ethereum.mpt.{ExtensionNode, HashNode, HexPrefix, MptNode} + +import scala.concurrent.duration.FiniteDuration +import scala.concurrent.duration._ +import scala.language.postfixOps + +import org.bouncycastle.util.encoders.Hex +import org.scalatest.flatspec.AnyFlatSpec +import org.scalatest.matchers.should.Matchers + +import io.iohk.ethereum.Fixtures +import io.iohk.ethereum.Timeouts +import io.iohk.ethereum.crypto +import io.iohk.ethereum.domain.BlockBody +import io.iohk.ethereum.domain.BlockHeader +import io.iohk.ethereum.domain.Receipt +import io.iohk.ethereum.mpt.ExtensionNode +import io.iohk.ethereum.mpt.HashNode +import io.iohk.ethereum.mpt.HexPrefix +import io.iohk.ethereum.mpt.MptNode +import io.iohk.ethereum.network.EtcPeerManagerActor import io.iohk.ethereum.network.PeerEventBusActor.PeerEvent.MessageFromPeer +import io.iohk.ethereum.network.PeerEventBusActor.PeerSelector +import io.iohk.ethereum.network.PeerEventBusActor.Subscribe import io.iohk.ethereum.network.PeerEventBusActor.SubscriptionClassifier.MessageClassifier -import io.iohk.ethereum.network.PeerEventBusActor.{PeerSelector, Subscribe} -import io.iohk.ethereum.network.PeerManagerActor.{FastSyncHostConfiguration, PeerConfiguration} +import io.iohk.ethereum.network.PeerId +import io.iohk.ethereum.network.PeerManagerActor.FastSyncHostConfiguration +import io.iohk.ethereum.network.PeerManagerActor.PeerConfiguration import io.iohk.ethereum.network.p2p.messages.Codes import io.iohk.ethereum.network.p2p.messages.ETH62._ -import io.iohk.ethereum.network.p2p.messages.ETH63._ import io.iohk.ethereum.network.p2p.messages.ETH63.MptNodeEncoders._ +import io.iohk.ethereum.network.p2p.messages.ETH63._ import io.iohk.ethereum.network.rlpx.RLPxConnectionHandler.RLPxConfiguration -import io.iohk.ethereum.network.{EtcPeerManagerActor, PeerId} -import io.iohk.ethereum.{Fixtures, Timeouts, crypto} -import org.bouncycastle.util.encoders.Hex - -import scala.concurrent.duration.{FiniteDuration, _} -import scala.language.postfixOps -import org.scalatest.flatspec.AnyFlatSpec -import org.scalatest.matchers.should.Matchers class BlockchainHostActorSpec extends AnyFlatSpec with Matchers { @@ -259,11 +274,11 @@ class BlockchainHostActorSpec extends AnyFlatSpec with Matchers { } trait TestSetup extends EphemBlockchainTestSetup { - override implicit lazy val system = ActorSystem("BlockchainHostActor_System") + implicit override lazy val system: ActorSystem = ActorSystem("BlockchainHostActor_System") blockchain.storeBlockHeader(Fixtures.Blocks.Genesis.header).commit() - val peerConf = new PeerConfiguration { + val peerConf: PeerConfiguration = new PeerConfiguration { override val fastSyncHostConfiguration: FastSyncHostConfiguration = new FastSyncHostConfiguration { val maxBlocksHeadersPerMessage: Int = 200 val maxBlocksBodiesPerMessage: Int = 200 @@ -297,14 +312,14 @@ class BlockchainHostActorSpec extends AnyFlatSpec with Matchers { } val baseBlockHeader = Fixtures.Blocks.Block3125369.header - val baseBlockBody = BlockBody(Nil, Nil) + val baseBlockBody: BlockBody = BlockBody(Nil, Nil) - val peerId = PeerId("1") + val peerId: PeerId = PeerId("1") - val peerEventBus = TestProbe() - val etcPeerManager = TestProbe() + val peerEventBus: TestProbe = TestProbe() + val etcPeerManager: TestProbe = TestProbe() - val blockchainHost = TestActorRef( + val blockchainHost: TestActorRef[Nothing] = TestActorRef( Props( new BlockchainHostActor( blockchainReader, diff --git a/src/test/scala/io/iohk/ethereum/blockchain/sync/CacheBasedBlacklistSpec.scala b/src/test/scala/io/iohk/ethereum/blockchain/sync/CacheBasedBlacklistSpec.scala index afb8ec5cee..04c961ff82 100644 --- a/src/test/scala/io/iohk/ethereum/blockchain/sync/CacheBasedBlacklistSpec.scala +++ b/src/test/scala/io/iohk/ethereum/blockchain/sync/CacheBasedBlacklistSpec.scala @@ -1,16 +1,15 @@ package io.iohk.ethereum.blockchain.sync -import akka.actor.ActorSystem -import akka.testkit.TestKit -import io.iohk.ethereum.WithActorSystemShutDown -import io.iohk.ethereum.network.PeerId -import org.scalatest.matchers.must.Matchers -import org.scalatest.wordspec.AnyWordSpecLike +import java.util.concurrent.TimeUnit import scala.concurrent.duration._ -import com.google.common.testing.FakeTicker + import com.github.blemale.scaffeine.Scaffeine -import java.util.concurrent.TimeUnit +import com.google.common.testing.FakeTicker +import org.scalatest.matchers.must.Matchers +import org.scalatest.wordspec.AnyWordSpecLike + +import io.iohk.ethereum.network.PeerId class CacheBasedBlacklistSpec extends AnyWordSpecLike with Matchers { import Blacklist._ diff --git a/src/test/scala/io/iohk/ethereum/blockchain/sync/EphemBlockchainTestSetup.scala b/src/test/scala/io/iohk/ethereum/blockchain/sync/EphemBlockchainTestSetup.scala index f2922c18ef..17754acc3e 100644 --- a/src/test/scala/io/iohk/ethereum/blockchain/sync/EphemBlockchainTestSetup.scala +++ b/src/test/scala/io/iohk/ethereum/blockchain/sync/EphemBlockchainTestSetup.scala @@ -1,7 +1,9 @@ package io.iohk.ethereum.blockchain.sync -import io.iohk.ethereum.db.components.{EphemDataSourceComponent, Storages} -import io.iohk.ethereum.db.storage.pruning.{ArchivePruning, PruningMode} +import io.iohk.ethereum.db.components.EphemDataSourceComponent +import io.iohk.ethereum.db.components.Storages +import io.iohk.ethereum.db.storage.pruning.ArchivePruning +import io.iohk.ethereum.db.storage.pruning.PruningMode import io.iohk.ethereum.ledger.VMImpl import io.iohk.ethereum.nodebuilder.PruningConfigBuilder @@ -13,12 +15,11 @@ trait EphemBlockchainTestSetup extends ScenarioSetup { //+ cake overrides override lazy val vm: VMImpl = new VMImpl - override lazy val storagesInstance = new EphemDataSourceComponent - with LocalPruningConfigBuilder - with Storages.DefaultStorages + override lazy val storagesInstance + : EphemDataSourceComponent with LocalPruningConfigBuilder with Storages.DefaultStorages = + new EphemDataSourceComponent with LocalPruningConfigBuilder with Storages.DefaultStorages //- cake overrides - def getNewStorages: EphemDataSourceComponent with LocalPruningConfigBuilder with Storages.DefaultStorages = { + def getNewStorages: EphemDataSourceComponent with LocalPruningConfigBuilder with Storages.DefaultStorages = new EphemDataSourceComponent with LocalPruningConfigBuilder with Storages.DefaultStorages - } } diff --git a/src/test/scala/io/iohk/ethereum/blockchain/sync/EtcPeerManagerFake.scala b/src/test/scala/io/iohk/ethereum/blockchain/sync/EtcPeerManagerFake.scala index c99e2fa472..e30e08a9c6 100644 --- a/src/test/scala/io/iohk/ethereum/blockchain/sync/EtcPeerManagerFake.scala +++ b/src/test/scala/io/iohk/ethereum/blockchain/sync/EtcPeerManagerFake.scala @@ -1,21 +1,35 @@ package io.iohk.ethereum.blockchain.sync -import akka.actor.{ActorRef, ActorSystem} +import akka.actor.ActorRef +import akka.actor.ActorSystem import akka.testkit.TestActor.AutoPilot import akka.testkit.TestProbe import akka.util.ByteString + import cats.effect.concurrent.Deferred -import io.iohk.ethereum.blockchain.sync.PeerListSupportNg.PeerWithInfo -import io.iohk.ethereum.domain.{Block, BlockHeader} -import io.iohk.ethereum.network.{EtcPeerManagerActor, Peer, PeerId} -import io.iohk.ethereum.network.EtcPeerManagerActor.{PeerInfo, SendMessage} -import io.iohk.ethereum.network.PeerEventBusActor.PeerEvent.MessageFromPeer -import io.iohk.ethereum.network.p2p.messages.ETH62.{BlockBodies, BlockHeaders, GetBlockBodies, GetBlockHeaders} -import io.iohk.ethereum.network.p2p.messages.ETH63.{GetNodeData, GetReceipts, NodeData, Receipts} -import io.iohk.ethereum.utils.Config.SyncConfig + import monix.eval.Task import monix.execution.Scheduler import monix.reactive.Observable -import monix.reactive.subjects.{ReplaySubject, Subject} +import monix.reactive.subjects.ReplaySubject +import monix.reactive.subjects.Subject + +import io.iohk.ethereum.domain.Block +import io.iohk.ethereum.domain.BlockBody +import io.iohk.ethereum.domain.BlockHeader +import io.iohk.ethereum.network.EtcPeerManagerActor +import io.iohk.ethereum.network.EtcPeerManagerActor.PeerInfo +import io.iohk.ethereum.network.EtcPeerManagerActor.SendMessage +import io.iohk.ethereum.network.Peer +import io.iohk.ethereum.network.PeerEventBusActor.PeerEvent.MessageFromPeer +import io.iohk.ethereum.network.p2p.messages.ETH62.BlockBodies +import io.iohk.ethereum.network.p2p.messages.ETH62.BlockHeaders +import io.iohk.ethereum.network.p2p.messages.ETH62.GetBlockBodies +import io.iohk.ethereum.network.p2p.messages.ETH62.GetBlockHeaders +import io.iohk.ethereum.network.p2p.messages.ETH63.GetNodeData +import io.iohk.ethereum.network.p2p.messages.ETH63.GetReceipts +import io.iohk.ethereum.network.p2p.messages.ETH63.NodeData +import io.iohk.ethereum.network.p2p.messages.ETH63.Receipts +import io.iohk.ethereum.utils.Config.SyncConfig class EtcPeerManagerFake( syncConfig: SyncConfig, @@ -27,7 +41,7 @@ class EtcPeerManagerFake( private val requestsSubject: Subject[SendMessage, SendMessage] = ReplaySubject() private val peersConnectedDeferred = Deferred.unsafe[Task, Unit] - val probe = TestProbe("etc_peer_manager") + val probe: TestProbe = TestProbe("etc_peer_manager") val autoPilot = new EtcPeerManagerFake.EtcPeerManagerAutoPilot( requestsSubject, @@ -49,7 +63,7 @@ class EtcPeerManagerFake( (header, peer) } .bufferTumbling(peers.size) - .concatMap(headersFromPeers => { + .concatMap { headersFromPeers => val (headers, respondedPeers) = headersFromPeers.unzip if (headers.distinct.size == 1 && respondedPeers.toSet == peers.keySet.map(_.id)) { @@ -57,32 +71,32 @@ class EtcPeerManagerFake( } else { Observable.empty } - }) + } - val fetchedHeaders = responses + val fetchedHeaders: Observable[Seq[BlockHeader]] = responses .collect { case MessageFromPeer(BlockHeaders(headers), _) if headers.size == syncConfig.blockHeadersPerRequest => headers } - val fetchedBodies = responses + val fetchedBodies: Observable[Seq[BlockBody]] = responses .collect { case MessageFromPeer(BlockBodies(bodies), _) => bodies } - val requestedReceipts = requests.collect( + val requestedReceipts: Observable[Seq[ByteString]] = requests.collect( Function.unlift(msg => msg.message.underlyingMsg match { case GetReceipts(hashes) => Some(hashes) - case _ => None + case _ => None } ) ) - val fetchedBlocks = fetchedBodies + val fetchedBlocks: Observable[List[Block]] = fetchedBodies .scan[(List[Block], List[Block])]((Nil, blocks)) { case ((_, remainingBlocks), bodies) => remainingBlocks.splitAt(bodies.size) } .map(_._1) .combineLatestMap(requestedReceipts)((blocks, _) => blocks) // a big simplification, but should be sufficient here - val fetchedState = responses.collect { case MessageFromPeer(NodeData(values), _) => + val fetchedState: Observable[Seq[ByteString]] = responses.collect { case MessageFromPeer(NodeData(values), _) => values } @@ -97,7 +111,7 @@ object EtcPeerManagerFake { getMptNodes: List[ByteString] => List[ByteString] )(implicit scheduler: Scheduler) extends AutoPilot { - def run(sender: ActorRef, msg: Any) = { + def run(sender: ActorRef, msg: Any): EtcPeerManagerAutoPilot = { msg match { case EtcPeerManagerActor.GetHandshakedPeers => sender ! EtcPeerManagerActor.HandshakedPeers(peers) diff --git a/src/test/scala/io/iohk/ethereum/blockchain/sync/FastSyncSpec.scala b/src/test/scala/io/iohk/ethereum/blockchain/sync/FastSyncSpec.scala index a3465c85d1..f43e76cafb 100644 --- a/src/test/scala/io/iohk/ethereum/blockchain/sync/FastSyncSpec.scala +++ b/src/test/scala/io/iohk/ethereum/blockchain/sync/FastSyncSpec.scala @@ -1,22 +1,31 @@ package io.iohk.ethereum.blockchain.sync +import akka.actor.ActorRef import akka.actor.ActorSystem import akka.pattern.ask -import akka.testkit.{TestKit, TestProbe} +import akka.testkit.TestKit +import akka.testkit.TestProbe import akka.util.Timeout -import io.iohk.ethereum.blockchain.sync.SyncProtocol.Status -import io.iohk.ethereum.blockchain.sync.SyncProtocol.Status.Progress -import io.iohk.ethereum.utils.Config.SyncConfig -import io.iohk.ethereum.utils.GenOps.GenOps -import io.iohk.ethereum.{FreeSpecBase, ObjectGenerators, SpecFixtures, WithActorSystemShutDown} + import monix.eval.Task import monix.reactive.Observable + +import scala.concurrent.duration.DurationInt + import io.iohk.ethereum.BlockHelpers +import io.iohk.ethereum.FreeSpecBase +import io.iohk.ethereum.ObjectGenerators +import io.iohk.ethereum.SpecFixtures +import io.iohk.ethereum.WithActorSystemShutDown +import io.iohk.ethereum.blockchain.sync.SyncProtocol.Status +import io.iohk.ethereum.blockchain.sync.SyncProtocol.Status.Progress import io.iohk.ethereum.blockchain.sync.fast.FastSync +import io.iohk.ethereum.domain.Block import io.iohk.ethereum.domain.ChainWeight -import monix.execution.Scheduler - -import scala.concurrent.duration.DurationInt +import io.iohk.ethereum.network.EtcPeerManagerActor +import io.iohk.ethereum.network.Peer +import io.iohk.ethereum.utils.Config.SyncConfig +import io.iohk.ethereum.utils.GenOps.GenOps class FastSyncSpec extends TestKit(ActorSystem("FastSync_testing")) @@ -26,7 +35,7 @@ class FastSyncSpec implicit val timeout: Timeout = Timeout(30.seconds) class Fixture extends EphemBlockchainTestSetup with TestSyncConfig with TestSyncPeers { - override implicit lazy val system: ActorSystem = self.system + implicit override lazy val system: ActorSystem = self.system val blacklistMaxElems: Int = 100 val blacklist: CacheBasedBlacklist = CacheBasedBlacklist.empty(blacklistMaxElems) @@ -42,16 +51,16 @@ class FastSyncSpec (stateRoot, trieProvider) } - lazy val testBlocks = BlockHelpers.generateChain( + lazy val testBlocks: List[Block] = BlockHelpers.generateChain( 20, BlockHelpers.genesis, block => block.copy(header = block.header.copy(stateRoot = stateRoot)) ) - lazy val bestBlockAtStart = testBlocks(10) - lazy val expectedPivotBlockNumber = bestBlockAtStart.number - syncConfig.pivotBlockOffset - lazy val expectedTargetBlockNumber = expectedPivotBlockNumber + syncConfig.fastSyncBlockValidationX - lazy val testPeers = twoAcceptedPeers.map { case (k, peerInfo) => + lazy val bestBlockAtStart: Block = testBlocks(10) + lazy val expectedPivotBlockNumber: BigInt = bestBlockAtStart.number - syncConfig.pivotBlockOffset + lazy val expectedTargetBlockNumber: BigInt = expectedPivotBlockNumber + syncConfig.fastSyncBlockValidationX + lazy val testPeers: Map[Peer, EtcPeerManagerActor.PeerInfo] = twoAcceptedPeers.map { case (k, peerInfo) => val lastBlock = bestBlockAtStart k -> peerInfo .withBestBlockData(lastBlock.number, lastBlock.hash) @@ -64,8 +73,8 @@ class FastSyncSpec testBlocks, req => trieProvider.getNodes(req).map(_.data) ) - lazy val peerEventBus = TestProbe("peer_event-bus") - lazy val fastSync = system.actorOf( + lazy val peerEventBus: TestProbe = TestProbe("peer_event-bus") + lazy val fastSync: ActorRef = system.actorOf( FastSync.props( fastSyncStateStorage = storagesInstance.storages.fastSyncStateStorage, appStateStorage = storagesInstance.storages.appStateStorage, @@ -86,7 +95,7 @@ class FastSyncSpec blockchain.save(BlockHelpers.genesis, receipts = Nil, ChainWeight.totalDifficultyOnly(1), saveAsBestBlock = true) } - val startSync: Task[Unit] = Task { fastSync ! SyncProtocol.Start } + val startSync: Task[Unit] = Task(fastSync ! SyncProtocol.Start) val getSyncStatus: Task[Status] = Task.deferFuture((fastSync ? SyncProtocol.GetStatus).mapTo[Status]) @@ -115,14 +124,12 @@ class FastSyncSpec _ <- etcPeerManager.pivotBlockSelected.firstL _ <- etcPeerManager.fetchedHeaders.firstL status <- getSyncStatus - } yield { - status match { - case Status.Syncing(startingBlockNumber, blocksProgress, stateNodesProgress) => - assert(startingBlockNumber === BigInt(0)) - assert(blocksProgress.target === expectedPivotBlockNumber) - assert(stateNodesProgress === Some(Progress(0, 1))) - case Status.NotSyncing | Status.SyncDone => fail("Expected syncing status") - } + } yield status match { + case Status.Syncing(startingBlockNumber, blocksProgress, stateNodesProgress) => + assert(startingBlockNumber === BigInt(0)) + assert(blocksProgress.target === expectedPivotBlockNumber) + assert(stateNodesProgress === Some(Progress(0, 1))) + case Status.NotSyncing | Status.SyncDone => fail("Expected syncing status") }) .timeout(timeout.duration) } @@ -138,15 +145,13 @@ class FastSyncSpec blocksBatch <- etcPeerManager.fetchedBlocks.firstL status <- getSyncStatus lastBlockFromBatch = blocksBatch.last.number - } yield { - status match { - case Status.Syncing(startingBlockNumber, blocksProgress, stateNodesProgress) => - assert(startingBlockNumber === BigInt(0)) - assert(blocksProgress.current >= lastBlockFromBatch) - assert(blocksProgress.target === expectedPivotBlockNumber) - assert(stateNodesProgress === Some(Progress(0, 1))) - case Status.NotSyncing | Status.SyncDone => fail("Expected other state") - } + } yield status match { + case Status.Syncing(startingBlockNumber, blocksProgress, stateNodesProgress) => + assert(startingBlockNumber === BigInt(0)) + assert(blocksProgress.current >= lastBlockFromBatch) + assert(blocksProgress.target === expectedPivotBlockNumber) + assert(stateNodesProgress === Some(Progress(0, 1))) + case Status.NotSyncing | Status.SyncDone => fail("Expected other state") }) .timeout(timeout.duration) } diff --git a/src/test/scala/io/iohk/ethereum/blockchain/sync/LoadableBloomFilterSpec.scala b/src/test/scala/io/iohk/ethereum/blockchain/sync/LoadableBloomFilterSpec.scala index 9b24ed9248..3dfd386b37 100644 --- a/src/test/scala/io/iohk/ethereum/blockchain/sync/LoadableBloomFilterSpec.scala +++ b/src/test/scala/io/iohk/ethereum/blockchain/sync/LoadableBloomFilterSpec.scala @@ -1,17 +1,20 @@ package io.iohk.ethereum.blockchain.sync -import com.google.common.hash.{Funnel, Funnels, PrimitiveSink} +import monix.eval.Task +import monix.reactive.Observable + +import com.google.common.hash.Funnel +import com.google.common.hash.Funnels +import com.google.common.hash.PrimitiveSink + import io.iohk.ethereum.FlatSpecBase import io.iohk.ethereum.blockchain.sync.fast.LoadableBloomFilter import io.iohk.ethereum.db.dataSource.RocksDbDataSource.IterationError -import monix.eval.Task -import monix.reactive.Observable class LoadableBloomFilterSpec extends FlatSpecBase { implicit object LongFun extends Funnel[Long] { - override def funnel(from: Long, into: PrimitiveSink): Unit = { + override def funnel(from: Long, into: PrimitiveSink): Unit = Funnels.longFunnel().funnel(from, into) - } } "LoadableBloomFilter" should "load all correct elements " in testCaseM { diff --git a/src/test/scala/io/iohk/ethereum/blockchain/sync/PeersClientSpec.scala b/src/test/scala/io/iohk/ethereum/blockchain/sync/PeersClientSpec.scala index ebe509fe96..e6798ac20b 100644 --- a/src/test/scala/io/iohk/ethereum/blockchain/sync/PeersClientSpec.scala +++ b/src/test/scala/io/iohk/ethereum/blockchain/sync/PeersClientSpec.scala @@ -5,15 +5,19 @@ import java.net.InetSocketAddress import akka.actor.ActorSystem import akka.testkit.TestProbe import akka.util.ByteString -import io.iohk.ethereum.blockchain.sync.PeerListSupportNg.PeerWithInfo -import io.iohk.ethereum.domain.ChainWeight -import io.iohk.ethereum.network.EtcPeerManagerActor.{PeerInfo, RemoteStatus} -import io.iohk.ethereum.network.{Peer, PeerId} -import io.iohk.ethereum.network.p2p.messages.ProtocolVersions + import org.scalatest.flatspec.AnyFlatSpec import org.scalatest.matchers.should.Matchers import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks +import io.iohk.ethereum.blockchain.sync.PeerListSupportNg.PeerWithInfo +import io.iohk.ethereum.domain.ChainWeight +import io.iohk.ethereum.network.EtcPeerManagerActor.PeerInfo +import io.iohk.ethereum.network.EtcPeerManagerActor.RemoteStatus +import io.iohk.ethereum.network.Peer +import io.iohk.ethereum.network.PeerId +import io.iohk.ethereum.network.p2p.messages.ProtocolVersions + class PeersClientSpec extends AnyFlatSpec with Matchers with ScalaCheckPropertyChecks { "PeerClient" should "determined the best peer based on it latest checkpoint number and total difficulty" in { import Peers._ @@ -69,11 +73,11 @@ class PeersClientSpec extends AnyFlatSpec with Matchers with ScalaCheckPropertyC } object Peers { - implicit val system = ActorSystem("PeersClient_System") + implicit val system: ActorSystem = ActorSystem("PeersClient_System") - val peer1 = Peer(PeerId("peer1"), new InetSocketAddress("127.0.0.1", 1), TestProbe().ref, false) - val peer2 = Peer(PeerId("peer2"), new InetSocketAddress("127.0.0.1", 2), TestProbe().ref, false) - val peer3 = Peer(PeerId("peer3"), new InetSocketAddress("127.0.0.1", 3), TestProbe().ref, false) + val peer1: Peer = Peer(PeerId("peer1"), new InetSocketAddress("127.0.0.1", 1), TestProbe().ref, false) + val peer2: Peer = Peer(PeerId("peer2"), new InetSocketAddress("127.0.0.1", 2), TestProbe().ref, false) + val peer3: Peer = Peer(PeerId("peer3"), new InetSocketAddress("127.0.0.1", 3), TestProbe().ref, false) private val peerStatus = RemoteStatus( protocolVersion = ProtocolVersions.ETH63.version, diff --git a/src/test/scala/io/iohk/ethereum/blockchain/sync/PivotBlockSelectorSpec.scala b/src/test/scala/io/iohk/ethereum/blockchain/sync/PivotBlockSelectorSpec.scala index 3bdcc90961..852b2d1232 100644 --- a/src/test/scala/io/iohk/ethereum/blockchain/sync/PivotBlockSelectorSpec.scala +++ b/src/test/scala/io/iohk/ethereum/blockchain/sync/PivotBlockSelectorSpec.scala @@ -1,29 +1,45 @@ package io.iohk.ethereum.blockchain.sync import java.net.InetSocketAddress -import akka.actor.{ActorRef, ActorSystem} -import akka.testkit.{TestKit, TestProbe} + +import akka.actor.ActorRef +import akka.actor.ActorSystem +import akka.testkit.TestKit +import akka.testkit.TestProbe import akka.util.ByteString + +import scala.concurrent.duration._ + import com.miguno.akka.testing.VirtualTime +import org.scalatest.BeforeAndAfter +import org.scalatest.flatspec.AnyFlatSpecLike +import org.scalatest.matchers.should.Matchers + +import io.iohk.ethereum.Fixtures +import io.iohk.ethereum.WithActorSystemShutDown import io.iohk.ethereum.blockchain.sync.fast.PivotBlockSelector -import io.iohk.ethereum.blockchain.sync.fast.PivotBlockSelector.{Result, SelectPivotBlock} -import io.iohk.ethereum.domain.{BlockHeader, ChainWeight} -import io.iohk.ethereum.network.EtcPeerManagerActor.{HandshakedPeers, PeerInfo, RemoteStatus} +import io.iohk.ethereum.blockchain.sync.fast.PivotBlockSelector.Result +import io.iohk.ethereum.blockchain.sync.fast.PivotBlockSelector.SelectPivotBlock +import io.iohk.ethereum.domain.BlockHeader +import io.iohk.ethereum.domain.ChainWeight +import io.iohk.ethereum.network.EtcPeerManagerActor +import io.iohk.ethereum.network.EtcPeerManagerActor.HandshakedPeers +import io.iohk.ethereum.network.EtcPeerManagerActor.PeerInfo +import io.iohk.ethereum.network.EtcPeerManagerActor.RemoteStatus +import io.iohk.ethereum.network.Peer import io.iohk.ethereum.network.PeerEventBusActor.PeerEvent.MessageFromPeer -import io.iohk.ethereum.network.PeerEventBusActor.SubscriptionClassifier.{MessageClassifier, PeerDisconnectedClassifier} -import io.iohk.ethereum.network.PeerEventBusActor.{PeerSelector, Subscribe, Unsubscribe} +import io.iohk.ethereum.network.PeerEventBusActor.PeerSelector +import io.iohk.ethereum.network.PeerEventBusActor.Subscribe +import io.iohk.ethereum.network.PeerEventBusActor.SubscriptionClassifier.MessageClassifier +import io.iohk.ethereum.network.PeerEventBusActor.SubscriptionClassifier.PeerDisconnectedClassifier +import io.iohk.ethereum.network.PeerEventBusActor.Unsubscribe +import io.iohk.ethereum.network.PeerId import io.iohk.ethereum.network.p2p.Message import io.iohk.ethereum.network.p2p.messages.BaseETH6XMessages.NewBlock +import io.iohk.ethereum.network.p2p.messages.Codes import io.iohk.ethereum.network.p2p.messages.ETH62._ -import io.iohk.ethereum.network.p2p.messages.{Codes, ProtocolVersions} -import io.iohk.ethereum.network.{EtcPeerManagerActor, Peer, PeerId} +import io.iohk.ethereum.network.p2p.messages.ProtocolVersions import io.iohk.ethereum.utils.Config.SyncConfig -import io.iohk.ethereum.{Fixtures, WithActorSystemShutDown} -import org.scalatest.BeforeAndAfter -import org.scalatest.flatspec.AnyFlatSpecLike -import org.scalatest.matchers.should.Matchers - -import scala.concurrent.duration._ class PivotBlockSelectorSpec extends TestKit(ActorSystem("FastSyncPivotBlockSelectorSpec_System")) @@ -495,21 +511,21 @@ class PivotBlockSelectorSpec private def isNewBlock(msg: Message): Boolean = msg match { case _: NewBlock => true - case _ => false + case _ => false } - val etcPeerManager = TestProbe() + val etcPeerManager: TestProbe = TestProbe() etcPeerManager.ignoreMsg { case EtcPeerManagerActor.SendMessage(msg, _) if isNewBlock(msg.underlyingMsg) => true - case EtcPeerManagerActor.GetHandshakedPeers => true + case EtcPeerManagerActor.GetHandshakedPeers => true } - val peerMessageBus = TestProbe() + val peerMessageBus: TestProbe = TestProbe() peerMessageBus.ignoreMsg { case Subscribe(MessageClassifier(codes, PeerSelector.AllPeers)) if codes == Set(Codes.NewBlockCode, Codes.NewBlockHashesCode) => true - case Subscribe(PeerDisconnectedClassifier(_)) => true + case Subscribe(PeerDisconnectedClassifier(_)) => true case Unsubscribe(Some(PeerDisconnectedClassifier(_))) => true } @@ -531,7 +547,7 @@ class PivotBlockSelectorSpec blacklistDuration = 1.second ) - val fastSync = TestProbe() + val fastSync: TestProbe = TestProbe() val time = new VirtualTime lazy val pivotBlockSelector: ActorRef = system.actorOf( @@ -549,7 +565,7 @@ class PivotBlockSelectorSpec val bestBlock = 400000 // Ask for pivot block header (the best block from the best peer - offset) - val expectedPivotBlock = bestBlock - syncConfig.pivotBlockOffset + val expectedPivotBlock: Int = bestBlock - syncConfig.pivotBlockOffset val pivotBlockHeader: BlockHeader = baseBlockHeader.copy(number = expectedPivotBlock) val differentBlockHeader: BlockHeader = @@ -564,12 +580,12 @@ class PivotBlockSelectorSpec val peer3TestProbe: TestProbe = TestProbe("peer3")(system) val peer4TestProbe: TestProbe = TestProbe("peer4")(system) - val peer1 = Peer(PeerId("peer1"), new InetSocketAddress("127.0.0.1", 0), peer1TestProbe.ref, false) - val peer2 = Peer(PeerId("peer2"), new InetSocketAddress("127.0.0.2", 0), peer2TestProbe.ref, false) - val peer3 = Peer(PeerId("peer3"), new InetSocketAddress("127.0.0.3", 0), peer3TestProbe.ref, false) - val peer4 = Peer(PeerId("peer4"), new InetSocketAddress("127.0.0.4", 0), peer4TestProbe.ref, false) + val peer1: Peer = Peer(PeerId("peer1"), new InetSocketAddress("127.0.0.1", 0), peer1TestProbe.ref, false) + val peer2: Peer = Peer(PeerId("peer2"), new InetSocketAddress("127.0.0.2", 0), peer2TestProbe.ref, false) + val peer3: Peer = Peer(PeerId("peer3"), new InetSocketAddress("127.0.0.3", 0), peer3TestProbe.ref, false) + val peer4: Peer = Peer(PeerId("peer4"), new InetSocketAddress("127.0.0.4", 0), peer4TestProbe.ref, false) - val peer1Status = + val peer1Status: RemoteStatus = RemoteStatus( ProtocolVersions.ETC64.version, 1, @@ -577,11 +593,11 @@ class PivotBlockSelectorSpec ByteString("peer1_bestHash"), ByteString("unused") ) - val peer2Status = peer1Status.copy(bestHash = ByteString("peer2_bestHash")) - val peer3Status = peer1Status.copy(bestHash = ByteString("peer3_bestHash")) - val peer4Status = peer1Status.copy(bestHash = ByteString("peer4_bestHash")) + val peer2Status: RemoteStatus = peer1Status.copy(bestHash = ByteString("peer2_bestHash")) + val peer3Status: RemoteStatus = peer1Status.copy(bestHash = ByteString("peer3_bestHash")) + val peer4Status: RemoteStatus = peer1Status.copy(bestHash = ByteString("peer4_bestHash")) - val allPeers = Map( + val allPeers: Map[Peer, PeerInfo] = Map( peer1 -> PeerInfo( peer1Status, forkAccepted = true, @@ -612,7 +628,7 @@ class PivotBlockSelectorSpec ) ) - val threeAcceptedPeers = Map( + val threeAcceptedPeers: Map[Peer, PeerInfo] = Map( peer1 -> PeerInfo( peer1Status, forkAccepted = true, @@ -636,7 +652,7 @@ class PivotBlockSelectorSpec ) ) - val singlePeer = Map( + val singlePeer: Map[Peer, PeerInfo] = Map( peer1 -> PeerInfo( peer1Status, forkAccepted = true, @@ -646,7 +662,7 @@ class PivotBlockSelectorSpec ) ) - val peersFromDifferentNetworks = Map( + val peersFromDifferentNetworks: Map[Peer, PeerInfo] = Map( peer1 -> PeerInfo( peer1Status, forkAccepted = true, diff --git a/src/test/scala/io/iohk/ethereum/blockchain/sync/ScenarioSetup.scala b/src/test/scala/io/iohk/ethereum/blockchain/sync/ScenarioSetup.scala index b510698934..aa37041ba6 100644 --- a/src/test/scala/io/iohk/ethereum/blockchain/sync/ScenarioSetup.scala +++ b/src/test/scala/io/iohk/ethereum/blockchain/sync/ScenarioSetup.scala @@ -1,38 +1,40 @@ package io.iohk.ethereum.blockchain.sync -import io.iohk.ethereum.Mocks -import io.iohk.ethereum.Mocks.MockVM -import io.iohk.ethereum.consensus.pow.validators.ValidatorsExecutor -import io.iohk.ethereum.consensus.validators.Validators -import io.iohk.ethereum.consensus.{Consensus, Protocol, StdTestConsensusBuilder, TestConsensus} -import io.iohk.ethereum.domain.BlockchainImpl -import io.iohk.ethereum.ledger.VMImpl -import io.iohk.ethereum.nodebuilder._ -import io.iohk.ethereum.utils.BlockchainConfig - import java.util.concurrent.Executors + import monix.execution.Scheduler import scala.concurrent.ExecutionContext +import scala.concurrent.ExecutionContextExecutor + +import io.iohk.ethereum.Mocks +import io.iohk.ethereum.Mocks.MockVM +import io.iohk.ethereum.consensus.Consensus +import io.iohk.ethereum.consensus.Protocol +import io.iohk.ethereum.consensus.StdTestConsensusBuilder +import io.iohk.ethereum.consensus.TestConsensus +import io.iohk.ethereum.consensus.pow.validators.ValidatorsExecutor +import io.iohk.ethereum.consensus.validators.Validators import io.iohk.ethereum.ledger.BlockExecution import io.iohk.ethereum.ledger.BlockImport import io.iohk.ethereum.ledger.BlockValidation +import io.iohk.ethereum.ledger.VMImpl +import io.iohk.ethereum.nodebuilder._ -/** - * Provides a standard setup for the test suites. +/** Provides a standard setup for the test suites. * The reference to "cake" is about the "Cake Pattern" used in Mantis. * Specifically it relates to the creation and wiring of the several components of a * [[io.iohk.ethereum.nodebuilder.Node Node]]. */ trait ScenarioSetup extends StdTestConsensusBuilder with StxLedgerBuilder { - protected lazy val executionContextExecutor = ExecutionContext.fromExecutor(Executors.newFixedThreadPool(4)) - protected lazy val monixScheduler = Scheduler(executionContextExecutor) + protected lazy val executionContextExecutor: ExecutionContextExecutor = + ExecutionContext.fromExecutor(Executors.newFixedThreadPool(4)) + protected lazy val monixScheduler: Scheduler = Scheduler(executionContextExecutor) protected lazy val successValidators: Validators = Mocks.MockValidatorsAlwaysSucceed protected lazy val failureValidators: Validators = Mocks.MockValidatorsAlwaysFail protected lazy val powValidators: ValidatorsExecutor = ValidatorsExecutor(blockchainConfig, Protocol.PoW) - /** - * The default validators for the test cases. + /** The default validators for the test cases. * Override this if you want to alter the behaviour of consensus * or if you specifically want other validators than the consensus provides. * @@ -41,13 +43,11 @@ trait ScenarioSetup extends StdTestConsensusBuilder with StxLedgerBuilder { lazy val validators: Validators = successValidators //+ cake overrides - /** - * The default VM for the test cases. + /** The default VM for the test cases. */ override lazy val vm: VMImpl = new MockVM() - /** - * The default consensus for the test cases. + /** The default consensus for the test cases. * We redefine it here in order to take into account different validators and vm * that a test case may need. * @@ -58,8 +58,7 @@ trait ScenarioSetup extends StdTestConsensusBuilder with StxLedgerBuilder { */ override lazy val consensus: TestConsensus = buildTestConsensus().withValidators(validators).withVM(vm) - /** - * Reuses the existing consensus instance and creates a new one + /** Reuses the existing consensus instance and creates a new one * by overriding its `validators` and `vm`. * * @note The existing consensus instance is provided lazily via the cake, so that at the moment diff --git a/src/test/scala/io/iohk/ethereum/blockchain/sync/SchedulerStateSpec.scala b/src/test/scala/io/iohk/ethereum/blockchain/sync/SchedulerStateSpec.scala index 9e7e7487c2..2f9156ba0b 100644 --- a/src/test/scala/io/iohk/ethereum/blockchain/sync/SchedulerStateSpec.scala +++ b/src/test/scala/io/iohk/ethereum/blockchain/sync/SchedulerStateSpec.scala @@ -1,10 +1,14 @@ package io.iohk.ethereum.blockchain.sync import akka.util.ByteString -import io.iohk.ethereum.blockchain.sync.fast.SyncStateScheduler.{SchedulerState, StateNode, StateNodeRequest} + import org.scalatest.flatspec.AnyFlatSpec import org.scalatest.matchers.must.Matchers +import io.iohk.ethereum.blockchain.sync.fast.SyncStateScheduler.SchedulerState +import io.iohk.ethereum.blockchain.sync.fast.SyncStateScheduler.StateNode +import io.iohk.ethereum.blockchain.sync.fast.SyncStateScheduler.StateNodeRequest + class SchedulerStateSpec extends AnyFlatSpec with Matchers { "SchedulerState" should "schedule node hashes for retrieval" in new TestSetup { val stateWithRequest = schedulerState.schedule(request1) @@ -31,12 +35,12 @@ class SchedulerStateSpec extends AnyFlatSpec with Matchers { } trait TestSetup extends EphemBlockchainTestSetup { - val schedulerState = SchedulerState() - val request1 = StateNodeRequest(ByteString(1), None, StateNode, Seq(), 1, 0) - val request2 = StateNodeRequest(ByteString(2), None, StateNode, Seq(), 2, 0) - val request3 = StateNodeRequest(ByteString(3), None, StateNode, Seq(), 3, 0) - val request4 = StateNodeRequest(ByteString(4), None, StateNode, Seq(), 4, 0) + val schedulerState: SchedulerState = SchedulerState() + val request1: StateNodeRequest = StateNodeRequest(ByteString(1), None, StateNode, Seq(), 1, 0) + val request2: StateNodeRequest = StateNodeRequest(ByteString(2), None, StateNode, Seq(), 2, 0) + val request3: StateNodeRequest = StateNodeRequest(ByteString(3), None, StateNode, Seq(), 3, 0) + val request4: StateNodeRequest = StateNodeRequest(ByteString(4), None, StateNode, Seq(), 4, 0) - val reqestsInDepthOrder = List(request4, request3, request2, request1) + val reqestsInDepthOrder: List[StateNodeRequest] = List(request4, request3, request2, request1) } } diff --git a/src/test/scala/io/iohk/ethereum/blockchain/sync/StateStorageActorSpec.scala b/src/test/scala/io/iohk/ethereum/blockchain/sync/StateStorageActorSpec.scala index 216ab2e7b7..ea3fd045eb 100644 --- a/src/test/scala/io/iohk/ethereum/blockchain/sync/StateStorageActorSpec.scala +++ b/src/test/scala/io/iohk/ethereum/blockchain/sync/StateStorageActorSpec.scala @@ -2,16 +2,21 @@ package io.iohk.ethereum.blockchain.sync import akka.actor.ActorSystem import akka.pattern._ -import akka.testkit.{TestActorRef, TestKit} -import io.iohk.ethereum.{Fixtures, NormalPatience, WithActorSystemShutDown} +import akka.testkit.TestActorRef +import akka.testkit.TestKit + +import org.scalatest.concurrent.Eventually +import org.scalatest.flatspec.AnyFlatSpecLike +import org.scalatest.matchers.should.Matchers + +import io.iohk.ethereum.Fixtures +import io.iohk.ethereum.NormalPatience +import io.iohk.ethereum.WithActorSystemShutDown import io.iohk.ethereum.blockchain.sync.fast.FastSync.SyncState -import io.iohk.ethereum.blockchain.sync.fast.StateStorageActor.GetStorage import io.iohk.ethereum.blockchain.sync.fast.StateStorageActor +import io.iohk.ethereum.blockchain.sync.fast.StateStorageActor.GetStorage import io.iohk.ethereum.db.dataSource.EphemDataSource import io.iohk.ethereum.db.storage.FastSyncStateStorage -import org.scalatest.concurrent.Eventually -import org.scalatest.flatspec.AnyFlatSpecLike -import org.scalatest.matchers.should.Matchers class StateStorageActorSpec extends TestKit(ActorSystem("FastSyncStateActorSpec_System")) diff --git a/src/test/scala/io/iohk/ethereum/blockchain/sync/StateSyncSpec.scala b/src/test/scala/io/iohk/ethereum/blockchain/sync/StateSyncSpec.scala index d56bfedb74..5077ed6fcd 100644 --- a/src/test/scala/io/iohk/ethereum/blockchain/sync/StateSyncSpec.scala +++ b/src/test/scala/io/iohk/ethereum/blockchain/sync/StateSyncSpec.scala @@ -2,37 +2,47 @@ package io.iohk.ethereum.blockchain.sync import java.net.InetSocketAddress import java.util.concurrent.ThreadLocalRandom -import akka.actor.{ActorRef, ActorSystem} + +import akka.actor.ActorRef +import akka.actor.ActorSystem import akka.testkit.TestActor.AutoPilot -import akka.testkit.{TestKit, TestProbe} +import akka.testkit.TestKit +import akka.testkit.TestProbe import akka.util.ByteString -import io.iohk.ethereum.blockchain.sync.StateSyncUtils.{MptNodeData, TrieProvider} -import io.iohk.ethereum.blockchain.sync.fast.{SyncStateScheduler, SyncStateSchedulerActor} -import io.iohk.ethereum.blockchain.sync.fast.SyncStateSchedulerActor.{ - RestartRequested, - StartSyncingTo, - StateSyncFinished, - StateSyncStats, - WaitingForNewTargetBlock -} -import io.iohk.ethereum.domain.{Address, BlockchainImpl, BlockchainReader, ChainWeight} -import io.iohk.ethereum.network.EtcPeerManagerActor._ -import io.iohk.ethereum.network.PeerEventBusActor.PeerEvent.MessageFromPeer -import io.iohk.ethereum.network.p2p.messages.ETH63.GetNodeData.GetNodeDataEnc -import io.iohk.ethereum.network.p2p.messages.ETH63.NodeData -import io.iohk.ethereum.network.p2p.messages.ProtocolVersions -import io.iohk.ethereum.network.{Peer, PeerId} -import io.iohk.ethereum.utils.Config -import io.iohk.ethereum.{Fixtures, ObjectGenerators, WithActorSystemShutDown} -import monix.execution.Scheduler + +import scala.concurrent.duration._ +import scala.util.Random + import org.scalactic.anyvals.PosInt import org.scalatest.BeforeAndAfterAll import org.scalatest.flatspec.AnyFlatSpecLike import org.scalatest.matchers.should.Matchers import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks -import scala.concurrent.duration._ -import scala.util.Random +import io.iohk.ethereum.Fixtures +import io.iohk.ethereum.ObjectGenerators +import io.iohk.ethereum.WithActorSystemShutDown +import io.iohk.ethereum.blockchain.sync.StateSyncUtils.MptNodeData +import io.iohk.ethereum.blockchain.sync.StateSyncUtils.TrieProvider +import io.iohk.ethereum.blockchain.sync.fast.SyncStateScheduler +import io.iohk.ethereum.blockchain.sync.fast.SyncStateSchedulerActor +import io.iohk.ethereum.blockchain.sync.fast.SyncStateSchedulerActor.RestartRequested +import io.iohk.ethereum.blockchain.sync.fast.SyncStateSchedulerActor.StartSyncingTo +import io.iohk.ethereum.blockchain.sync.fast.SyncStateSchedulerActor.StateSyncFinished +import io.iohk.ethereum.blockchain.sync.fast.SyncStateSchedulerActor.StateSyncStats +import io.iohk.ethereum.blockchain.sync.fast.SyncStateSchedulerActor.WaitingForNewTargetBlock +import io.iohk.ethereum.domain.Address +import io.iohk.ethereum.domain.BlockchainImpl +import io.iohk.ethereum.domain.BlockchainReader +import io.iohk.ethereum.domain.ChainWeight +import io.iohk.ethereum.network.EtcPeerManagerActor._ +import io.iohk.ethereum.network.Peer +import io.iohk.ethereum.network.PeerEventBusActor.PeerEvent.MessageFromPeer +import io.iohk.ethereum.network.PeerId +import io.iohk.ethereum.network.p2p.messages.ETH63.GetNodeData.GetNodeDataEnc +import io.iohk.ethereum.network.p2p.messages.ETH63.NodeData +import io.iohk.ethereum.network.p2p.messages.ProtocolVersions +import io.iohk.ethereum.utils.Config class StateSyncSpec extends TestKit(ActorSystem("StateSyncSpec")) @@ -43,7 +53,8 @@ class StateSyncSpec with WithActorSystemShutDown { // those tests are somewhat long running 3 successful evaluation should be fine - implicit override val generatorDrivenConfig = PropertyCheckConfiguration(minSuccessful = PosInt(3)) + implicit override val generatorDrivenConfig: PropertyCheckConfiguration = + PropertyCheckConfiguration(minSuccessful = PosInt(3)) "StateSync" should "sync state to different tries" in new TestSetup() { forAll(ObjectGenerators.genMultipleNodeData(1000)) { nodeData => @@ -90,17 +101,13 @@ class StateSyncSpec initiator.send(syncStateSchedulerActor, StartSyncingTo(target, 1)) initiator.send(syncStateSchedulerActor, RestartRequested) initiator.fishForMessage(20.seconds) { - case _: StateSyncStats => false + case _: StateSyncStats => false case WaitingForNewTargetBlock => true } } } it should "start state sync when receiving start signal while bloom filter is loading" in new TestSetup() { - @volatile - var loadingFinished = false - val externalScheduler = Scheduler(system.dispatcher) - override def buildBlockChain(): (BlockchainReader, BlockchainImpl) = { val storages = getNewStorages.storages @@ -115,26 +122,22 @@ class StateSyncSpec val target = trieProvider1.buildWorld(nodeData) setAutoPilotWithProvider(trieProvider1) initiator.send(syncStateSchedulerActor, StartSyncingTo(target, 1)) - externalScheduler.scheduleOnce(2.second) { - loadingFinished = true - } - initiator.expectMsg(20.seconds, StateSyncFinished) } class TestSetup extends EphemBlockchainTestSetup with TestSyncConfig { - override implicit lazy val system = StateSyncSpec.this.system + implicit override lazy val system: ActorSystem = StateSyncSpec.this.system type PeerConfig = Map[PeerId, PeerAction] - val syncInit = TestProbe() + val syncInit: TestProbe = TestProbe() - val peerStatus = RemoteStatus( + val peerStatus: RemoteStatus = RemoteStatus( protocolVersion = ProtocolVersions.ETH63.version, networkId = 1, chainWeight = ChainWeight.totalDifficultyOnly(10000), bestHash = Fixtures.Blocks.Block3125369.header.hash, genesisHash = Fixtures.Blocks.Genesis.header.hash ) - val initialPeerInfo = PeerInfo( + val initialPeerInfo: PeerInfo = PeerInfo( remoteStatus = peerStatus, chainWeight = peerStatus.chainWeight, forkAccepted = false, @@ -145,7 +148,7 @@ class StateSyncSpec val trieProvider = new TrieProvider(blockchain, blockchainReader, getNewStorages.storages.evmCodeStorage, blockchainConfig) - val peersMap = (1 to 8).map { i => + val peersMap: Map[Peer, PeerInfo] = (1 to 8).map { i => ( Peer( PeerId(s"peer$i"), @@ -184,13 +187,13 @@ class StateSyncSpec } } - val etcPeerManager = TestProbe() + val etcPeerManager: TestProbe = TestProbe() - val peerEventBus = TestProbe() + val peerEventBus: TestProbe = TestProbe() - def setAutoPilotWithProvider(trieProvider: TrieProvider, peerConfig: PeerConfig = defaultPeerConfig): Unit = { + def setAutoPilotWithProvider(trieProvider: TrieProvider, peerConfig: PeerConfig = defaultPeerConfig): Unit = etcPeerManager.setAutoPilot(new AutoPilot { - override def run(sender: ActorRef, msg: Any): AutoPilot = { + override def run(sender: ActorRef, msg: Any): AutoPilot = msg match { case SendMessage(msg: GetNodeDataEnc, peer) => peerConfig(peer) match { @@ -214,9 +217,7 @@ class StateSyncSpec sender ! HandshakedPeers(peersMap) this } - } }) - } override lazy val syncConfig: Config.SyncConfig = defaultSyncConfig.copy( peersScanInterval = 0.5.second, @@ -243,11 +244,10 @@ class StateSyncSpec arr } - def genRandomByteString(): ByteString = { + def genRandomByteString(): ByteString = ByteString.fromArrayUnsafe(genRandomArray()) - } - lazy val syncStateSchedulerActor = { + lazy val syncStateSchedulerActor: ActorRef = { val (blockchainReader, blockchain) = buildBlockChain() system.actorOf( SyncStateSchedulerActor.props( diff --git a/src/test/scala/io/iohk/ethereum/blockchain/sync/StateSyncUtils.scala b/src/test/scala/io/iohk/ethereum/blockchain/sync/StateSyncUtils.scala index 040459cf10..22ef8e172d 100644 --- a/src/test/scala/io/iohk/ethereum/blockchain/sync/StateSyncUtils.scala +++ b/src/test/scala/io/iohk/ethereum/blockchain/sync/StateSyncUtils.scala @@ -1,12 +1,18 @@ package io.iohk.ethereum.blockchain.sync import akka.util.ByteString + import io.iohk.ethereum.blockchain.sync.fast.SyncStateScheduler.SyncResponse import io.iohk.ethereum.db.storage.EvmCodeStorage -import io.iohk.ethereum.domain.{Account, Address, Blockchain, BlockchainImpl, BlockchainReader} +import io.iohk.ethereum.domain.Account +import io.iohk.ethereum.domain.Address +import io.iohk.ethereum.domain.Blockchain +import io.iohk.ethereum.domain.BlockchainImpl +import io.iohk.ethereum.domain.BlockchainReader import io.iohk.ethereum.ledger.InMemoryWorldStateProxy import io.iohk.ethereum.mpt.MerklePatriciaTrie -import io.iohk.ethereum.utils.{BlockchainConfig, ByteUtils} +import io.iohk.ethereum.utils.BlockchainConfig +import io.iohk.ethereum.utils.ByteUtils object StateSyncUtils extends EphemBlockchainTestSetup { @@ -23,18 +29,17 @@ object StateSyncUtils extends EphemBlockchainTestSetup { evmCodeStorage: EvmCodeStorage, blockchainConfig: BlockchainConfig ) { - def getNodes(hashes: List[ByteString]) = { + def getNodes(hashes: List[ByteString]): List[SyncResponse] = hashes.map { hash => val maybeResult = blockchainReader.getMptNodeByHash(hash) match { case Some(value) => Some(ByteString(value.encode)) - case None => evmCodeStorage.get(hash) + case None => evmCodeStorage.get(hash) } maybeResult match { case Some(result) => SyncResponse(hash, result) - case None => throw new RuntimeException("Missing expected data in storage") + case None => throw new RuntimeException("Missing expected data in storage") } } - } def buildWorld(accountData: Seq[MptNodeData], existingTree: Option[ByteString] = None): ByteString = { val init = InMemoryWorldStateProxy( @@ -82,7 +87,7 @@ object StateSyncUtils extends EphemBlockchainTestSetup { } } - def createNodeDataStartingFrom(initialNumber: Int, lastNumber: Int, storageOffset: Int): Seq[MptNodeData] = { + def createNodeDataStartingFrom(initialNumber: Int, lastNumber: Int, storageOffset: Int): Seq[MptNodeData] = (initialNumber until lastNumber).map { i => val address = Address(i) val codeBytes = ByteString(BigInt(i).toByteArray) @@ -90,7 +95,6 @@ object StateSyncUtils extends EphemBlockchainTestSetup { val balance = i MptNodeData(address, Some(codeBytes), storage, balance) } - } def checkAllDataExists( nodeData: List[MptNodeData], @@ -98,7 +102,7 @@ object StateSyncUtils extends EphemBlockchainTestSetup { evmCodeStorage: EvmCodeStorage, blNumber: BigInt ): Boolean = { - def go(remaining: List[MptNodeData]): Boolean = { + def go(remaining: List[MptNodeData]): Boolean = if (remaining.isEmpty) { true } else { @@ -117,7 +121,6 @@ object StateSyncUtils extends EphemBlockchainTestSetup { false } } - } go(nodeData) } diff --git a/src/test/scala/io/iohk/ethereum/blockchain/sync/SyncControllerSpec.scala b/src/test/scala/io/iohk/ethereum/blockchain/sync/SyncControllerSpec.scala index 37471229fa..8d72d1a98c 100644 --- a/src/test/scala/io/iohk/ethereum/blockchain/sync/SyncControllerSpec.scala +++ b/src/test/scala/io/iohk/ethereum/blockchain/sync/SyncControllerSpec.scala @@ -1,36 +1,51 @@ package io.iohk.ethereum.blockchain.sync -import akka.actor.{ActorRef, ActorSystem, Props} +import akka.actor.ActorRef +import akka.actor.ActorSystem +import akka.actor.Props +import akka.testkit.ExplicitlyTriggeredScheduler import akka.testkit.TestActor.AutoPilot -import akka.testkit.{ExplicitlyTriggeredScheduler, TestActorRef, TestProbe} +import akka.testkit.TestActorRef +import akka.testkit.TestProbe import akka.util.ByteString + +import scala.concurrent.Await +import scala.concurrent.duration._ + import com.typesafe.config.ConfigFactory +import org.bouncycastle.util.encoders.Hex +import org.scalamock.scalatest.MockFactory +import org.scalatest.BeforeAndAfter +import org.scalatest.concurrent.Eventually +import org.scalatest.flatspec.AnyFlatSpec +import org.scalatest.matchers.should.Matchers + +import io.iohk.ethereum.Fixtures +import io.iohk.ethereum.Mocks +import io.iohk.ethereum.NormalPatience import io.iohk.ethereum.blockchain.sync.fast.FastSync.SyncState -import io.iohk.ethereum.consensus.validators.BlockHeaderError.{HeaderParentNotFoundError, HeaderPoWError} -import io.iohk.ethereum.consensus.validators.{BlockHeaderError, BlockHeaderValid, BlockHeaderValidator, Validators} -import io.iohk.ethereum.consensus.{GetBlockHeaderByHash, TestConsensus} +import io.iohk.ethereum.consensus.GetBlockHeaderByHash +import io.iohk.ethereum.consensus.TestConsensus +import io.iohk.ethereum.consensus.validators.BlockHeaderError +import io.iohk.ethereum.consensus.validators.BlockHeaderError.HeaderParentNotFoundError +import io.iohk.ethereum.consensus.validators.BlockHeaderError.HeaderPoWError +import io.iohk.ethereum.consensus.validators.BlockHeaderValid +import io.iohk.ethereum.consensus.validators.BlockHeaderValidator +import io.iohk.ethereum.consensus.validators.Validators import io.iohk.ethereum.domain._ import io.iohk.ethereum.ledger.VMImpl import io.iohk.ethereum.network.EtcPeerManagerActor -import io.iohk.ethereum.network.EtcPeerManagerActor.{HandshakedPeers, SendMessage} +import io.iohk.ethereum.network.EtcPeerManagerActor.HandshakedPeers +import io.iohk.ethereum.network.EtcPeerManagerActor.SendMessage import io.iohk.ethereum.network.PeerEventBusActor.PeerEvent.MessageFromPeer import io.iohk.ethereum.network.p2p.messages.ETH62.GetBlockBodies.GetBlockBodiesEnc import io.iohk.ethereum.network.p2p.messages.ETH62.GetBlockHeaders.GetBlockHeadersEnc import io.iohk.ethereum.network.p2p.messages.ETH62._ import io.iohk.ethereum.network.p2p.messages.ETH63.GetNodeData.GetNodeDataEnc import io.iohk.ethereum.network.p2p.messages.ETH63.GetReceipts.GetReceiptsEnc -import io.iohk.ethereum.network.p2p.messages.ETH63.{NodeData, Receipts} +import io.iohk.ethereum.network.p2p.messages.ETH63.NodeData +import io.iohk.ethereum.network.p2p.messages.ETH63.Receipts import io.iohk.ethereum.utils.Config.SyncConfig -import io.iohk.ethereum.{Fixtures, Mocks, NormalPatience} -import org.bouncycastle.util.encoders.Hex -import org.scalamock.scalatest.MockFactory -import org.scalatest.BeforeAndAfter -import org.scalatest.concurrent.Eventually -import org.scalatest.flatspec.AnyFlatSpec -import org.scalatest.matchers.should.Matchers - -import scala.concurrent.Await -import scala.concurrent.duration._ // scalastyle:off file.size.limit class SyncControllerSpec @@ -121,9 +136,8 @@ class SyncControllerSpec override def validate( blockHeader: BlockHeader, getBlockHeaderByHash: GetBlockHeaderByHash - ): Either[BlockHeaderError, BlockHeaderValid] = { + ): Either[BlockHeaderError, BlockHeaderValid] = Left(HeaderPoWError) - } override def validateHeaderOnly(blockHeader: BlockHeader): Either[BlockHeaderError, BlockHeaderValid] = Left(HeaderPoWError) @@ -170,13 +184,12 @@ class SyncControllerSpec override def validate( blockHeader: BlockHeader, getBlockHeaderByHash: GetBlockHeaderByHash - ): Either[BlockHeaderError, BlockHeaderValid] = { + ): Either[BlockHeaderError, BlockHeaderValid] = if (blockHeader.number == invalidBlockNNumber) { Left(HeaderParentNotFoundError) } else { Right(BlockHeaderValid) } - } override def validateHeaderOnly(blockHeader: BlockHeader): Either[BlockHeaderError, BlockHeaderValid] = Right(BlockHeaderValid) @@ -252,13 +265,12 @@ class SyncControllerSpec override def validate( blockHeader: BlockHeader, getBlockHeaderByHash: GetBlockHeaderByHash - ): Either[BlockHeaderError, BlockHeaderValid] = { + ): Either[BlockHeaderError, BlockHeaderValid] = if (blockHeader.number != 399500 + 10) { Right(BlockHeaderValid) } else { Left(HeaderParentNotFoundError) } - } override def validateHeaderOnly(blockHeader: BlockHeader): Either[BlockHeaderError, BlockHeaderValid] = Right(BlockHeaderValid) @@ -490,7 +502,7 @@ class SyncControllerSpec var stateDownloadStarted = false //+ cake overrides - override implicit lazy val system: ActorSystem = + implicit override lazy val system: ActorSystem = ActorSystem("SyncControllerSpec_System", ConfigFactory.load("explicit-scheduler")) override lazy val vm: VMImpl = new VMImpl @@ -501,11 +513,11 @@ class SyncControllerSpec //+ cake overrides - val etcPeerManager = TestProbe() - val peerMessageBus = TestProbe() - val pendingTransactionsManager = TestProbe() + val etcPeerManager: TestProbe = TestProbe() + val peerMessageBus: TestProbe = TestProbe() + val pendingTransactionsManager: TestProbe = TestProbe() - val ommersPool = TestProbe() + val ommersPool: TestProbe = TestProbe() val blacklist: CacheBasedBlacklist = CacheBasedBlacklist.empty(100) @@ -526,7 +538,7 @@ class SyncControllerSpec maxPivotBlockAge = 30 ) - lazy val syncController = TestActorRef( + lazy val syncController: TestActorRef[Nothing] = TestActorRef( Props( new SyncController( storagesInstance.storages.appStateStorage, @@ -559,7 +571,7 @@ class SyncControllerSpec receipts: Map[ByteString, Seq[Receipt]] ) object BlockchainData { - def apply(headers: Seq[BlockHeader]): BlockchainData = { + def apply(headers: Seq[BlockHeader]): BlockchainData = // assumes headers are correct chain headers.foldLeft(new BlockchainData(Map.empty, Map.empty, Map.empty)) { (state, header) => state.copy( @@ -568,7 +580,6 @@ class SyncControllerSpec receipts = state.receipts + (header.hash -> Seq.empty) ) } - } } // scalastyle:off method.length case class SyncStateAutoPilot( @@ -581,7 +592,7 @@ class SyncControllerSpec failedNodeRequest: Boolean, autoPilotProbeRef: ActorRef ) extends AutoPilot { - override def run(sender: ActorRef, msg: Any): AutoPilot = { + override def run(sender: ActorRef, msg: Any): AutoPilot = msg match { case EtcPeerManagerActor.GetHandshakedPeers => sender ! handshakedPeers @@ -600,7 +611,7 @@ class SyncControllerSpec this case SendMessage(msg: GetReceiptsEnc, peer) if !onlyPivot => - val underlyingMessage = msg.underlyingMsg + msg.underlyingMsg if (failedReceiptsTries > 0) { sender ! MessageFromPeer(Receipts(Seq()), peer) this.copy(failedReceiptsTries = failedReceiptsTries - 1) @@ -611,7 +622,7 @@ class SyncControllerSpec } case SendMessage(msg: GetBlockBodiesEnc, peer) if !onlyPivot => - val underlyingMessage = msg.underlyingMsg + msg.underlyingMsg if (failedBodiesTries > 0) { sender ! MessageFromPeer(BlockBodies(Seq()), peer) this.copy(failedBodiesTries = failedBodiesTries - 1) @@ -623,7 +634,7 @@ class SyncControllerSpec case SendMessage(msg: GetNodeDataEnc, peer) if !onlyPivot => stateDownloadStarted = true - val underlyingMessage = msg.underlyingMsg + msg.underlyingMsg if (!failedNodeRequest) { sender ! MessageFromPeer(NodeData(Seq(defaultStateMptLeafWithAccount)), peer) } @@ -633,7 +644,6 @@ class SyncControllerSpec sender ! DataUpdated this.copy(peers, pivot, data, failedReceipts, failedBodies, onlyPivot, failedNode) } - } def updateAutoPilot( handshakedPeers: HandshakedPeers, @@ -714,29 +724,29 @@ class SyncControllerSpec val defaultSafeDownloadTarget = defaultExpectedPivotBlock - val defaultBestBlock = defaultExpectedPivotBlock - 1 + val defaultBestBlock: Int = defaultExpectedPivotBlock - 1 val defaultStateRoot = "deae1dfad5ec8dcef15915811e1f044d2543674fd648f94345231da9fc2646cc" - val defaultPivotBlockHeader = + val defaultPivotBlockHeader: BlockHeader = baseBlockHeader.copy(number = defaultExpectedPivotBlock, stateRoot = ByteString(Hex.decode(defaultStateRoot))) - val defaultState = + val defaultState: SyncState = SyncState( defaultPivotBlockHeader, safeDownloadTarget = defaultSafeDownloadTarget, bestBlockHeaderNumber = defaultBestBlock ) - val defaultStateMptLeafWithAccount = + val defaultStateMptLeafWithAccount: ByteString = ByteString( Hex.decode( "f86d9e328415c225a782bb339b22acad1c739e42277bc7ef34de3623114997ce78b84cf84a0186cb7d8738d800a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a0c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470" ) ) - val beforeRestartPivot = defaultPivotBlockHeader.copy(number = defaultExpectedPivotBlock - 1) - val defaultStateBeforeNodeRestart = defaultState.copy( + val beforeRestartPivot: BlockHeader = defaultPivotBlockHeader.copy(number = defaultExpectedPivotBlock - 1) + val defaultStateBeforeNodeRestart: SyncState = defaultState.copy( pivotBlock = beforeRestartPivot, bestBlockHeaderNumber = defaultExpectedPivotBlock, nextBlockToFullyValidate = beforeRestartPivot.number + syncConfig.fastSyncBlockValidationX @@ -751,7 +761,7 @@ class SyncControllerSpec parenthash: ByteString, headers: Seq[BlockHeader], result: Seq[BlockHeader] = Seq.empty - ): Seq[BlockHeader] = { + ): Seq[BlockHeader] = if (headers.isEmpty) result else { @@ -760,23 +770,21 @@ class SyncControllerSpec val newHash = newHeader.hash genChain(newHash, headers.tail, result :+ newHeader) } - } val first = headers.head first +: genChain(first.hash, headers.tail) } - def startWithState(state: SyncState): Unit = { + def startWithState(state: SyncState): Unit = storagesInstance.storages.fastSyncStateStorage.putSyncState(state) - } private def testScheduler = system.scheduler.asInstanceOf[ExplicitlyTriggeredScheduler] - def littleTimePasses() = + def littleTimePasses(): Unit = testScheduler.timePasses(300.millis) - def someTimePasses() = + def someTimePasses(): Unit = testScheduler.timePasses(3000.millis) def cleanup(): Unit = @@ -785,10 +793,7 @@ class SyncControllerSpec def withTestSetup(validators: Validators = new Mocks.MockValidatorsAlwaysSucceed)(test: TestSetup => Any): Unit = { val testSetup = new TestSetup(validators) - try { - test(testSetup) - } finally { - testSetup.cleanup() - } + try test(testSetup) + finally testSetup.cleanup() } } diff --git a/src/test/scala/io/iohk/ethereum/blockchain/sync/SyncStateDownloaderStateSpec.scala b/src/test/scala/io/iohk/ethereum/blockchain/sync/SyncStateDownloaderStateSpec.scala index 54bd618f9c..a7c1ef080d 100644 --- a/src/test/scala/io/iohk/ethereum/blockchain/sync/SyncStateDownloaderStateSpec.scala +++ b/src/test/scala/io/iohk/ethereum/blockchain/sync/SyncStateDownloaderStateSpec.scala @@ -1,25 +1,30 @@ package io.iohk.ethereum.blockchain.sync import java.net.InetSocketAddress + +import akka.actor.ActorRef import akka.actor.ActorSystem -import akka.testkit.{TestKit, TestProbe} +import akka.testkit.TestKit +import akka.testkit.TestProbe import akka.util.ByteString + import cats.data.NonEmptyList + +import org.scalatest.BeforeAndAfterAll +import org.scalatest.flatspec.AnyFlatSpecLike +import org.scalatest.matchers.must.Matchers + import io.iohk.ethereum.WithActorSystemShutDown -import io.iohk.ethereum.blockchain.sync.fast.SyncStateScheduler.SyncResponse -import io.iohk.ethereum.blockchain.sync.fast.SyncStateSchedulerActor.{ - NoUsefulDataInResponse, - ResponseProcessingResult, - UnrequestedResponse, - UsefulData -} import io.iohk.ethereum.blockchain.sync.fast.DownloaderState +import io.iohk.ethereum.blockchain.sync.fast.SyncStateScheduler.SyncResponse +import io.iohk.ethereum.blockchain.sync.fast.SyncStateSchedulerActor.NoUsefulDataInResponse +import io.iohk.ethereum.blockchain.sync.fast.SyncStateSchedulerActor.ResponseProcessingResult +import io.iohk.ethereum.blockchain.sync.fast.SyncStateSchedulerActor.UnrequestedResponse +import io.iohk.ethereum.blockchain.sync.fast.SyncStateSchedulerActor.UsefulData import io.iohk.ethereum.crypto.kec256 -import io.iohk.ethereum.network.{Peer, PeerId} +import io.iohk.ethereum.network.Peer +import io.iohk.ethereum.network.PeerId import io.iohk.ethereum.network.p2p.messages.ETH63.NodeData -import org.scalatest.BeforeAndAfterAll -import org.scalatest.flatspec.AnyFlatSpecLike -import org.scalatest.matchers.must.Matchers class SyncStateDownloaderStateSpec extends TestKit(ActorSystem("SyncStateDownloaderStateSpec_System")) @@ -113,9 +118,9 @@ class SyncStateDownloaderStateSpec assert(handlingResult == UnrequestedResponse) // check that all requests are unchanged assert(newState2.activeRequests.size == 3) - assert(requests.forall({ req => + assert(requests.forall { req => req.nodes.forall(h => newState2.nodesToGet(h).contains(req.peer.id)) - })) + }) } it should "handle empty responses from from peers" in new TestSetup { @@ -222,28 +227,27 @@ class SyncStateDownloaderStateSpec } trait TestSetup { - def expectUsefulData(result: ResponseProcessingResult): UsefulData = { + def expectUsefulData(result: ResponseProcessingResult): UsefulData = result match { - case UnrequestedResponse => fail() + case UnrequestedResponse => fail() case NoUsefulDataInResponse => fail() - case data @ UsefulData(_) => data + case data @ UsefulData(_) => data } - } - - val ref1 = TestProbe().ref - val ref2 = TestProbe().ref - val ref3 = TestProbe().ref - val ref4 = TestProbe().ref - - val initialState = DownloaderState(Map.empty, Map.empty) - val peer1 = Peer(PeerId("peer1"), new InetSocketAddress("127.0.0.1", 1), ref1, incomingConnection = false) - val peer2 = Peer(PeerId("peer2"), new InetSocketAddress("127.0.0.1", 2), ref2, incomingConnection = false) - val peer3 = Peer(PeerId("peer3"), new InetSocketAddress("127.0.0.1", 3), ref3, incomingConnection = false) - val notKnownPeer = Peer(PeerId(""), new InetSocketAddress("127.0.0.1", 4), ref4, incomingConnection = false) - val peers = NonEmptyList.fromListUnsafe(List(peer1, peer2, peer3)) - val potentialNodes = (1 to 100).map(i => ByteString(i)).toList - val potentialNodesHashes = potentialNodes.map(node => kec256(node)) - val hashNodeMap = potentialNodesHashes.zip(potentialNodes).toMap + + val ref1: ActorRef = TestProbe().ref + val ref2: ActorRef = TestProbe().ref + val ref3: ActorRef = TestProbe().ref + val ref4: ActorRef = TestProbe().ref + + val initialState: DownloaderState = DownloaderState(Map.empty, Map.empty) + val peer1: Peer = Peer(PeerId("peer1"), new InetSocketAddress("127.0.0.1", 1), ref1, incomingConnection = false) + val peer2: Peer = Peer(PeerId("peer2"), new InetSocketAddress("127.0.0.1", 2), ref2, incomingConnection = false) + val peer3: Peer = Peer(PeerId("peer3"), new InetSocketAddress("127.0.0.1", 3), ref3, incomingConnection = false) + val notKnownPeer: Peer = Peer(PeerId(""), new InetSocketAddress("127.0.0.1", 4), ref4, incomingConnection = false) + val peers: NonEmptyList[Peer] = NonEmptyList.fromListUnsafe(List(peer1, peer2, peer3)) + val potentialNodes: List[ByteString] = (1 to 100).map(i => ByteString(i)).toList + val potentialNodesHashes: List[ByteString] = potentialNodes.map(node => kec256(node)) + val hashNodeMap: Map[ByteString, ByteString] = potentialNodesHashes.zip(potentialNodes).toMap } } diff --git a/src/test/scala/io/iohk/ethereum/blockchain/sync/SyncStateSchedulerSpec.scala b/src/test/scala/io/iohk/ethereum/blockchain/sync/SyncStateSchedulerSpec.scala index 081f7177bb..fb761f4926 100644 --- a/src/test/scala/io/iohk/ethereum/blockchain/sync/SyncStateSchedulerSpec.scala +++ b/src/test/scala/io/iohk/ethereum/blockchain/sync/SyncStateSchedulerSpec.scala @@ -1,25 +1,30 @@ package io.iohk.ethereum.blockchain.sync import akka.util.ByteString -import io.iohk.ethereum.Fixtures -import io.iohk.ethereum.blockchain.sync.StateSyncUtils.{MptNodeData, TrieProvider, checkAllDataExists} -import io.iohk.ethereum.blockchain.sync.fast.SyncStateScheduler -import io.iohk.ethereum.blockchain.sync.fast.SyncStateScheduler.{ - AlreadyProcessedItem, - CannotDecodeMptNode, - NotRequestedItem, - SchedulerState, - SyncResponse -} -import io.iohk.ethereum.db.components.{EphemDataSourceComponent, Storages} -import io.iohk.ethereum.domain.{Address, BlockchainImpl, BlockchainReader} -import io.iohk.ethereum.vm.Generators.genMultipleNodeData + import org.scalactic.anyvals.PosInt import org.scalatest.EitherValues import org.scalatest.flatspec.AnyFlatSpec import org.scalatest.matchers.must.Matchers import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks + +import io.iohk.ethereum.Fixtures import io.iohk.ethereum.SuperSlow +import io.iohk.ethereum.blockchain.sync.StateSyncUtils.MptNodeData +import io.iohk.ethereum.blockchain.sync.StateSyncUtils.TrieProvider +import io.iohk.ethereum.blockchain.sync.StateSyncUtils.checkAllDataExists +import io.iohk.ethereum.blockchain.sync.fast.SyncStateScheduler +import io.iohk.ethereum.blockchain.sync.fast.SyncStateScheduler.AlreadyProcessedItem +import io.iohk.ethereum.blockchain.sync.fast.SyncStateScheduler.CannotDecodeMptNode +import io.iohk.ethereum.blockchain.sync.fast.SyncStateScheduler.NotRequestedItem +import io.iohk.ethereum.blockchain.sync.fast.SyncStateScheduler.SchedulerState +import io.iohk.ethereum.blockchain.sync.fast.SyncStateScheduler.SyncResponse +import io.iohk.ethereum.db.components.EphemDataSourceComponent +import io.iohk.ethereum.db.components.Storages +import io.iohk.ethereum.domain.Address +import io.iohk.ethereum.domain.BlockchainImpl +import io.iohk.ethereum.domain.BlockchainReader +import io.iohk.ethereum.vm.Generators.genMultipleNodeData class SyncStateSchedulerSpec extends AnyFlatSpec @@ -160,7 +165,7 @@ class SyncStateSchedulerSpec val allMissingNodes2Response = prov.getNodes(allMissingNodes2) val state5 = syncStateScheduler.processResponses(state4, allMissingNodes2Response).value._1 val remaingNodes = state5.numberOfPendingRequests - val state6 = syncStateScheduler.persistBatch(state5, 1) + syncStateScheduler.persistBatch(state5, 1) // 1 non finalized request for branch node + 2 non finalized request for leaf nodes assert(state1.numberOfPendingRequests == 3) @@ -230,7 +235,8 @@ class SyncStateSchedulerSpec assert(result1.left.value == CannotDecodeMptNode) } - implicit override val generatorDrivenConfig = PropertyCheckConfiguration(minSuccessful = PosInt(3)) + implicit override val generatorDrivenConfig: PropertyCheckConfiguration = + PropertyCheckConfiguration(minSuccessful = PosInt(3)) // Long running test generating random mpt tries and checking that scheduler is able to correctly // traverse them diff --git a/src/test/scala/io/iohk/ethereum/blockchain/sync/TestSyncConfig.scala b/src/test/scala/io/iohk/ethereum/blockchain/sync/TestSyncConfig.scala index 814152d96f..45a4300869 100644 --- a/src/test/scala/io/iohk/ethereum/blockchain/sync/TestSyncConfig.scala +++ b/src/test/scala/io/iohk/ethereum/blockchain/sync/TestSyncConfig.scala @@ -1,10 +1,10 @@ package io.iohk.ethereum.blockchain.sync +import scala.concurrent.duration._ + import io.iohk.ethereum.nodebuilder.SyncConfigBuilder import io.iohk.ethereum.utils.Config.SyncConfig -import scala.concurrent.duration._ - trait TestSyncConfig extends SyncConfigBuilder { def defaultSyncConfig: SyncConfig = SyncConfig( printStatusInterval = 1.second, diff --git a/src/test/scala/io/iohk/ethereum/blockchain/sync/TestSyncPeers.scala b/src/test/scala/io/iohk/ethereum/blockchain/sync/TestSyncPeers.scala index 1f657f808c..45965626a8 100644 --- a/src/test/scala/io/iohk/ethereum/blockchain/sync/TestSyncPeers.scala +++ b/src/test/scala/io/iohk/ethereum/blockchain/sync/TestSyncPeers.scala @@ -1,11 +1,15 @@ package io.iohk.ethereum.blockchain.sync import java.net.InetSocketAddress + import akka.actor.ActorSystem import akka.testkit.TestProbe import akka.util.ByteString + import io.iohk.ethereum.domain.ChainWeight -import io.iohk.ethereum.network.EtcPeerManagerActor.{PeerInfo, RemoteStatus} -import io.iohk.ethereum.network.{Peer, PeerId} +import io.iohk.ethereum.network.EtcPeerManagerActor.PeerInfo +import io.iohk.ethereum.network.EtcPeerManagerActor.RemoteStatus +import io.iohk.ethereum.network.Peer +import io.iohk.ethereum.network.PeerId import io.iohk.ethereum.network.p2p.messages.ProtocolVersions trait TestSyncPeers { self: TestSyncConfig => @@ -15,11 +19,11 @@ trait TestSyncPeers { self: TestSyncConfig => val peer2TestProbe: TestProbe = TestProbe("peer2")(system) val peer3TestProbe: TestProbe = TestProbe("peer3")(system) - val peer1 = Peer(PeerId("peer1"), new InetSocketAddress("127.0.0.1", 0), peer1TestProbe.ref, false) - val peer2 = Peer(PeerId("peer2"), new InetSocketAddress("127.0.0.2", 0), peer2TestProbe.ref, false) - val peer3 = Peer(PeerId("peer3"), new InetSocketAddress("127.0.0.3", 0), peer3TestProbe.ref, false) + val peer1: Peer = Peer(PeerId("peer1"), new InetSocketAddress("127.0.0.1", 0), peer1TestProbe.ref, false) + val peer2: Peer = Peer(PeerId("peer2"), new InetSocketAddress("127.0.0.2", 0), peer2TestProbe.ref, false) + val peer3: Peer = Peer(PeerId("peer3"), new InetSocketAddress("127.0.0.3", 0), peer3TestProbe.ref, false) - val peer1Status = + val peer1Status: RemoteStatus = RemoteStatus( ProtocolVersions.ETC64.version, 1, @@ -27,12 +31,12 @@ trait TestSyncPeers { self: TestSyncConfig => ByteString("peer1_bestHash"), ByteString("unused") ) - val peer2Status = peer1Status.copy(bestHash = ByteString("peer2_bestHash")) + val peer2Status: RemoteStatus = peer1Status.copy(bestHash = ByteString("peer2_bestHash")) val bestBlock = 400000 - val expectedPivotBlock = bestBlock - syncConfig.pivotBlockOffset + val expectedPivotBlock: Int = bestBlock - syncConfig.pivotBlockOffset - val defaultPeer1Info = PeerInfo( + val defaultPeer1Info: PeerInfo = PeerInfo( peer1Status, forkAccepted = true, chainWeight = peer1Status.chainWeight, @@ -40,7 +44,7 @@ trait TestSyncPeers { self: TestSyncConfig => bestBlockHash = peer1Status.bestHash ) - val twoAcceptedPeers = Map( + val twoAcceptedPeers: Map[Peer, PeerInfo] = Map( peer1 -> PeerInfo( peer1Status, forkAccepted = true, @@ -57,7 +61,7 @@ trait TestSyncPeers { self: TestSyncConfig => ) ) - val singlePeer = Map( + val singlePeer: Map[Peer, PeerInfo] = Map( peer1 -> PeerInfo( peer1Status, forkAccepted = true, diff --git a/src/test/scala/io/iohk/ethereum/blockchain/sync/fast/FastSyncBranchResolverActorSpec.scala b/src/test/scala/io/iohk/ethereum/blockchain/sync/fast/FastSyncBranchResolverActorSpec.scala index 700930e6f3..8cb4fef0f6 100644 --- a/src/test/scala/io/iohk/ethereum/blockchain/sync/fast/FastSyncBranchResolverActorSpec.scala +++ b/src/test/scala/io/iohk/ethereum/blockchain/sync/fast/FastSyncBranchResolverActorSpec.scala @@ -2,35 +2,50 @@ package io.iohk.ethereum.blockchain.sync.fast import java.net.InetSocketAddress -import akka.actor.{ActorRef, ActorSystem} +import akka.actor.ActorRef +import akka.actor.ActorSystem import akka.pattern.gracefulStop import akka.testkit.TestActor.AutoPilot -import akka.testkit.{TestKit, TestProbe} -import akka.util.{ByteString, Timeout} +import akka.testkit.TestKit +import akka.testkit.TestProbe +import akka.util.ByteString +import akka.util.Timeout + import cats.effect.concurrent.Deferred import cats.implicits._ -import io.iohk.ethereum.blockchain.sync._ -import io.iohk.ethereum.blockchain.sync.fast.FastSyncBranchResolverActor.{BranchResolvedSuccessful, StartBranchResolver} -import io.iohk.ethereum.domain.{Block, BlockHeader, ChainWeight} -import io.iohk.ethereum.network.EtcPeerManagerActor._ -import io.iohk.ethereum.network.PeerEventBusActor.PeerEvent.MessageFromPeer -import io.iohk.ethereum.network.p2p.messages.ETH62.{BlockHeaders, GetBlockHeaders} -import io.iohk.ethereum.network.p2p.messages.ProtocolVersions -import io.iohk.ethereum.network.{EtcPeerManagerActor, Peer, PeerId} -import io.iohk.ethereum.utils.Logger -import io.iohk.ethereum.{BlockHelpers, NormalPatience, WithActorSystemShutDown} + import monix.eval.Task import monix.execution.Scheduler import monix.reactive.Observable -import monix.reactive.subjects.{ReplaySubject, Subject} -import org.scalatest.concurrent.ScalaFutures -import org.scalatest.freespec.AnyFreeSpecLike +import monix.reactive.subjects.ReplaySubject +import monix.reactive.subjects.Subject import scala.concurrent.duration.DurationInt -import scala.language.postfixOps import scala.util.Random + +import org.scalatest.concurrent.ScalaFutures +import org.scalatest.freespec.AnyFreeSpecLike + +import io.iohk.ethereum.BlockHelpers +import io.iohk.ethereum.NormalPatience +import io.iohk.ethereum.WithActorSystemShutDown +import io.iohk.ethereum.blockchain.sync._ import io.iohk.ethereum.blockchain.sync.fast.FastSyncBranchResolverActor.BranchResolutionFailed import io.iohk.ethereum.blockchain.sync.fast.FastSyncBranchResolverActor.BranchResolutionFailed.NoCommonBlockFound +import io.iohk.ethereum.blockchain.sync.fast.FastSyncBranchResolverActor.BranchResolvedSuccessful +import io.iohk.ethereum.blockchain.sync.fast.FastSyncBranchResolverActor.StartBranchResolver +import io.iohk.ethereum.domain.Block +import io.iohk.ethereum.domain.BlockHeader +import io.iohk.ethereum.domain.ChainWeight +import io.iohk.ethereum.network.EtcPeerManagerActor +import io.iohk.ethereum.network.EtcPeerManagerActor._ +import io.iohk.ethereum.network.Peer +import io.iohk.ethereum.network.PeerEventBusActor.PeerEvent.MessageFromPeer +import io.iohk.ethereum.network.PeerId +import io.iohk.ethereum.network.p2p.messages.ETH62.BlockHeaders +import io.iohk.ethereum.network.p2p.messages.ETH62.GetBlockHeaders +import io.iohk.ethereum.network.p2p.messages.ProtocolVersions +import io.iohk.ethereum.utils.Logger class FastSyncBranchResolverActorSpec extends TestKit(ActorSystem("FastSyncBranchResolver_testing")) @@ -45,7 +60,7 @@ class FastSyncBranchResolverActorSpec "FastSyncBranchResolver" - { "fetch headers from the new master peer" - { "the chain is repaired from the first request to the new master pair and then the last two blocks are removed" in new TestSetup { - override implicit lazy val system = self.system + implicit override lazy val system = self.system implicit val scheduler = Scheduler(system.dispatcher) val sender = TestProbe("sender") @@ -92,7 +107,7 @@ class FastSyncBranchResolverActorSpec "The chain is repaired doing binary searching with the new master peer and then remove the last invalid blocks" - { "highest common block is in the middle" in new TestSetup { - override implicit lazy val system = self.system + implicit override lazy val system = self.system implicit val scheduler = Scheduler(system.dispatcher) val sender = TestProbe("sender") @@ -129,7 +144,7 @@ class FastSyncBranchResolverActorSpec assert(getBestPeers.contains(response.masterPeer)) } "highest common block is in the first half" in new TestSetup { - override implicit lazy val system = self.system + implicit override lazy val system = self.system implicit val scheduler = Scheduler(system.dispatcher) val sender = TestProbe("sender") @@ -168,7 +183,7 @@ class FastSyncBranchResolverActorSpec } "highest common block is in the second half" in new TestSetup { - override implicit lazy val system = self.system + implicit override lazy val system = self.system implicit val scheduler = Scheduler(system.dispatcher) val sender = TestProbe("sender") @@ -207,7 +222,7 @@ class FastSyncBranchResolverActorSpec } "No common block is found" in new TestSetup { - override implicit lazy val system = self.system + implicit override lazy val system = self.system implicit val scheduler = Scheduler(system.dispatcher) val sender = TestProbe("sender") @@ -267,9 +282,8 @@ class FastSyncBranchResolverActorSpec val handshakedPeers: Map[Peer, PeerInfo] = (0 to 5).toList.map((peerId _).andThen(getPeer)).fproduct(getPeerInfo(_)).toMap - def saveBlocks(blocks: List[Block]): Unit = { + def saveBlocks(blocks: List[Block]): Unit = blocks.foreach(block => blockchain.save(block, Nil, ChainWeight.totalDifficultyOnly(1), saveAsBestBlock = true)) - } def createEtcPeerManager(peers: Map[Peer, PeerInfo], blocks: Map[Int, List[Block]])(implicit scheduler: Scheduler @@ -301,9 +315,8 @@ class FastSyncBranchResolverActorSpec ) ) - def stopController(actorRef: ActorRef): Unit = { + def stopController(actorRef: ActorRef): Unit = awaitCond(gracefulStop(actorRef, actorAskTimeout.duration).futureValue) - } def getBestPeers: List[Peer] = { val maxBlock = handshakedPeers.toList.map { case (_, peerInfo) => peerInfo.maxBlockNumber }.max @@ -321,12 +334,11 @@ object FastSyncBranchResolverActorSpec extends Logger { var responses: Observable[MessageFromPeer] = responsesSubject - def fetchedHeaders: Observable[Seq[BlockHeader]] = { + def fetchedHeaders: Observable[Seq[BlockHeader]] = responses .collect { case MessageFromPeer(BlockHeaders(headers), _) => headers } - } class EtcPeerManagerAutoPilot( responses: Subject[MessageFromPeer, MessageFromPeer], diff --git a/src/test/scala/io/iohk/ethereum/blockchain/sync/fast/FastSyncBranchResolverSpec.scala b/src/test/scala/io/iohk/ethereum/blockchain/sync/fast/FastSyncBranchResolverSpec.scala index 61df08da72..6f4c49726f 100644 --- a/src/test/scala/io/iohk/ethereum/blockchain/sync/fast/FastSyncBranchResolverSpec.scala +++ b/src/test/scala/io/iohk/ethereum/blockchain/sync/fast/FastSyncBranchResolverSpec.scala @@ -1,29 +1,35 @@ package io.iohk.ethereum.blockchain.sync.fast +import java.net.InetSocketAddress + import akka.actor.ActorRef import akka.util.ByteString -import io.iohk.ethereum.{BlockHelpers, Fixtures} -import io.iohk.ethereum.blockchain.sync.fast.BinarySearchSupport._ -import io.iohk.ethereum.blockchain.sync.fast.FastSyncBranchResolver.SearchState -import io.iohk.ethereum.domain.{Block, BlockHeader, Blockchain, BlockchainImpl, BlockchainReader} -import io.iohk.ethereum.network.{Peer, PeerId} + import org.scalamock.scalatest.MockFactory import org.scalatest.matchers.must.Matchers import org.scalatest.wordspec.AnyWordSpec -import java.net.InetSocketAddress +import io.iohk.ethereum.BlockHelpers +import io.iohk.ethereum.Fixtures +import io.iohk.ethereum.blockchain.sync.fast.BinarySearchSupport._ +import io.iohk.ethereum.blockchain.sync.fast.FastSyncBranchResolver.SearchState +import io.iohk.ethereum.domain.Block +import io.iohk.ethereum.domain.BlockHeader +import io.iohk.ethereum.domain.Blockchain +import io.iohk.ethereum.domain.BlockchainImpl +import io.iohk.ethereum.domain.BlockchainReader +import io.iohk.ethereum.network.Peer +import io.iohk.ethereum.network.PeerId class FastSyncBranchResolverSpec extends AnyWordSpec with Matchers with MockFactory { import Fixtures.Blocks.ValidBlock - private def blocksMap(amount: Int, parent: Block): Map[BigInt, Block] = { + private def blocksMap(amount: Int, parent: Block): Map[BigInt, Block] = BlockHelpers.generateChain(amount, parent).map(b => (b.number, b)).toMap - } - private def headersMap(amount: Int, parent: Block): Map[BigInt, BlockHeader] = { + private def headersMap(amount: Int, parent: Block): Map[BigInt, BlockHeader] = BlockHelpers.generateChain(amount, parent).map(b => (b.number, b.header)).toMap - } private def headersList(blocksMap: Map[BigInt, Block]): List[BlockHeader] = blocksMap.values.map(_.header).toList @@ -195,7 +201,7 @@ class FastSyncBranchResolverSpec extends AnyWordSpec with Matchers with MockFact initialSearchState ) match { case ContinueBinarySearch(searchState) => searchState - case _ => fail() + case _ => fail() } assert(s1 === SearchState(5, 10, dummyPeer)) @@ -210,7 +216,7 @@ class FastSyncBranchResolverSpec extends AnyWordSpec with Matchers with MockFact s1 ) match { case ContinueBinarySearch(searchState) => searchState - case _ => fail() + case _ => fail() } assert(s2 === SearchState(5, 6, dummyPeer)) @@ -226,7 +232,7 @@ class FastSyncBranchResolverSpec extends AnyWordSpec with Matchers with MockFact s2 ) match { case ContinueBinarySearch(searchState) => searchState - case _ => fail() + case _ => fail() } assert(s3 === SearchState(6, 6, dummyPeer)) @@ -241,12 +247,11 @@ class FastSyncBranchResolverSpec extends AnyWordSpec with Matchers with MockFact s3 ) match { case BinarySearchCompleted(highestHeader) => highestHeader - case _ => fail() + case _ => fail() } assert(res === BigInt(6)) } "complete search with no match" in { - val ourBestBlock = 10 val blocksSaved: List[Block] = BlockHelpers.generateChain(8, BlockHelpers.genesis) val blocksSavedInPeer: List[Block] = BlockHelpers.generateChain(8, BlockHelpers.genesis) @@ -271,7 +276,7 @@ class FastSyncBranchResolverSpec extends AnyWordSpec with Matchers with MockFact initialSearchState ) match { case ContinueBinarySearch(searchState) => searchState - case _ => fail() + case _ => fail() } assert(s1 === SearchState(1, 3, dummyPeer)) @@ -286,7 +291,7 @@ class FastSyncBranchResolverSpec extends AnyWordSpec with Matchers with MockFact s1 ) match { case ContinueBinarySearch(searchState) => searchState - case _ => fail() + case _ => fail() } assert(s2 === SearchState(1, 1, dummyPeer)) diff --git a/src/test/scala/io/iohk/ethereum/blockchain/sync/fast/HeaderSkeletonSpec.scala b/src/test/scala/io/iohk/ethereum/blockchain/sync/fast/HeaderSkeletonSpec.scala index 316f0700dd..3d7c17c43a 100644 --- a/src/test/scala/io/iohk/ethereum/blockchain/sync/fast/HeaderSkeletonSpec.scala +++ b/src/test/scala/io/iohk/ethereum/blockchain/sync/fast/HeaderSkeletonSpec.scala @@ -1,7 +1,7 @@ package io.iohk.ethereum.blockchain.sync.fast -import org.scalatest.wordspec.AnyWordSpec import org.scalatest.matchers.should.Matchers +import org.scalatest.wordspec.AnyWordSpec class HeaderSkeletonSpec extends AnyWordSpec with Matchers { diff --git a/src/test/scala/io/iohk/ethereum/blockchain/sync/regular/BlockFetcherSpec.scala b/src/test/scala/io/iohk/ethereum/blockchain/sync/regular/BlockFetcherSpec.scala index 2ad09ef63f..5e4b4872ed 100644 --- a/src/test/scala/io/iohk/ethereum/blockchain/sync/regular/BlockFetcherSpec.scala +++ b/src/test/scala/io/iohk/ethereum/blockchain/sync/regular/BlockFetcherSpec.scala @@ -4,35 +4,42 @@ import java.net.InetSocketAddress import akka.actor.ActorSystem import akka.actor.testkit.typed.scaladsl.ScalaTestWithActorTestKit +import akka.actor.typed.ActorRef import akka.actor.typed.scaladsl.adapter._ import akka.testkit.TestProbe + +import scala.concurrent.ExecutionContext.Implicits.global +import scala.concurrent.duration._ + import com.miguno.akka.testing.VirtualTime +import org.scalatest.freespec.AnyFreeSpecLike +import org.scalatest.matchers.should.Matchers + +import io.iohk.ethereum.BlockHelpers import io.iohk.ethereum.Fixtures.{Blocks => FixtureBlocks} -import io.iohk.ethereum.Mocks.{MockValidatorsAlwaysSucceed, MockValidatorsFailingOnBlockBodies} +import io.iohk.ethereum.Mocks.MockValidatorsAlwaysSucceed +import io.iohk.ethereum.Mocks.MockValidatorsFailingOnBlockBodies +import io.iohk.ethereum.Timeouts +import io.iohk.ethereum.blockchain.sync.Blacklist.BlacklistReason +import io.iohk.ethereum.blockchain.sync.PeersClient import io.iohk.ethereum.blockchain.sync.PeersClient.BlacklistPeer -import io.iohk.ethereum.blockchain.sync.regular.BlockFetcher.{ - AdaptedMessageFromEventBus, - InternalLastBlockImport, - InvalidateBlocksFrom, - PickBlocks -} -import io.iohk.ethereum.blockchain.sync.{PeersClient, TestSyncConfig} -import io.iohk.ethereum.domain.{Block, HeadersSeq} +import io.iohk.ethereum.blockchain.sync.TestSyncConfig +import io.iohk.ethereum.blockchain.sync.regular.BlockFetcher.AdaptedMessageFromEventBus +import io.iohk.ethereum.blockchain.sync.regular.BlockFetcher.InternalLastBlockImport +import io.iohk.ethereum.blockchain.sync.regular.BlockFetcher.InvalidateBlocksFrom +import io.iohk.ethereum.blockchain.sync.regular.BlockFetcher.PickBlocks +import io.iohk.ethereum.domain.Block +import io.iohk.ethereum.domain.HeadersSeq +import io.iohk.ethereum.network.Peer +import io.iohk.ethereum.network.PeerEventBusActor.PeerSelector +import io.iohk.ethereum.network.PeerEventBusActor.Subscribe import io.iohk.ethereum.network.PeerEventBusActor.SubscriptionClassifier.MessageClassifier -import io.iohk.ethereum.network.PeerEventBusActor.{PeerSelector, Subscribe} -import io.iohk.ethereum.network.p2p.messages.Codes +import io.iohk.ethereum.network.PeerId import io.iohk.ethereum.network.p2p.messages.BaseETH6XMessages.NewBlock +import io.iohk.ethereum.network.p2p.messages.Codes import io.iohk.ethereum.network.p2p.messages.ETH62._ -import io.iohk.ethereum.network.{Peer, PeerId} import io.iohk.ethereum.security.SecureRandomBuilder -import io.iohk.ethereum.{BlockHelpers, Timeouts} -import org.scalatest.freespec.AnyFreeSpecLike -import org.scalatest.matchers.should.Matchers - -import io.iohk.ethereum.blockchain.sync.Blacklist.BlacklistReason - -import scala.concurrent.ExecutionContext.Implicits.global -import scala.concurrent.duration._ +import io.iohk.ethereum.utils.Config class BlockFetcherSpec extends ScalaTestWithActorTestKit() with AnyFreeSpecLike with Matchers with SecureRandomBuilder { @@ -269,14 +276,14 @@ class BlockFetcherSpec extends ScalaTestWithActorTestKit() with AnyFreeSpecLike val time = new VirtualTime - val peersClient = TestProbe()(as) - val peerEventBus = TestProbe()(as) - val importer = TestProbe()(as) - val regularSync = TestProbe()(as) + val peersClient: TestProbe = TestProbe()(as) + val peerEventBus: TestProbe = TestProbe()(as) + val importer: TestProbe = TestProbe()(as) + val regularSync: TestProbe = TestProbe()(as) lazy val validators = new MockValidatorsAlwaysSucceed - override lazy val syncConfig = defaultSyncConfig.copy( + override lazy val syncConfig: Config.SyncConfig = defaultSyncConfig.copy( // Same request size was selected for simplification purposes of the flow blockHeadersPerRequest = 10, blockBodiesPerRequest = 10, @@ -286,9 +293,9 @@ class BlockFetcherSpec extends ScalaTestWithActorTestKit() with AnyFreeSpecLike ) val fakePeerActor: TestProbe = TestProbe()(as) - val fakePeer = Peer(PeerId("fakePeer"), new InetSocketAddress("127.0.0.1", 9000), fakePeerActor.ref, false) + val fakePeer: Peer = Peer(PeerId("fakePeer"), new InetSocketAddress("127.0.0.1", 9000), fakePeerActor.ref, false) - lazy val blockFetcher = spawn( + lazy val blockFetcher: ActorRef[BlockFetcher.FetchCommand] = spawn( BlockFetcher( peersClient.ref, peerEventBus.ref, @@ -321,13 +328,14 @@ class BlockFetcherSpec extends ScalaTestWithActorTestKit() with AnyFreeSpecLike blockFetcher ! AdaptedMessageFromEventBus(NewBlock(farAwayBlock, farAwayBlockTotalDifficulty), fakePeer.id) } - val firstBlocksBatch = BlockHelpers.generateChain(syncConfig.blockHeadersPerRequest, FixtureBlocks.Genesis.block) + val firstBlocksBatch: List[Block] = + BlockHelpers.generateChain(syncConfig.blockHeadersPerRequest, FixtureBlocks.Genesis.block) // Fetcher request for headers - val firstGetBlockHeadersRequest = + val firstGetBlockHeadersRequest: GetBlockHeaders = GetBlockHeaders(Left(1), syncConfig.blockHeadersPerRequest, skip = 0, reverse = false) - def handleFirstBlockBatchHeaders() = { + def handleFirstBlockBatchHeaders(): Unit = { peersClient.expectMsgPF() { case PeersClient.Request(`firstGetBlockHeadersRequest`, _, _) => () } // Respond first headers request @@ -336,8 +344,8 @@ class BlockFetcherSpec extends ScalaTestWithActorTestKit() with AnyFreeSpecLike } // First bodies request - val firstGetBlockBodiesRequest = GetBlockBodies(firstBlocksBatch.map(_.hash)) - def handleFirstBlockBatchBodies() = { + val firstGetBlockBodiesRequest: GetBlockBodies = GetBlockBodies(firstBlocksBatch.map(_.hash)) + def handleFirstBlockBatchBodies(): Unit = { peersClient.expectMsgPF() { case PeersClient.Request(`firstGetBlockBodiesRequest`, _, _) => () } // First bodies response @@ -345,7 +353,7 @@ class BlockFetcherSpec extends ScalaTestWithActorTestKit() with AnyFreeSpecLike peersClient.reply(PeersClient.Response(fakePeer, firstGetBlockBodiesResponse)) } - def handleFirstBlockBatch() = { + def handleFirstBlockBatch(): Unit = { handleFirstBlockBatchHeaders() handleFirstBlockBatchBodies() } diff --git a/src/test/scala/io/iohk/ethereum/blockchain/sync/regular/BlockFetcherStateSpec.scala b/src/test/scala/io/iohk/ethereum/blockchain/sync/regular/BlockFetcherStateSpec.scala index 859a5c0948..9c372306d5 100644 --- a/src/test/scala/io/iohk/ethereum/blockchain/sync/regular/BlockFetcherStateSpec.scala +++ b/src/test/scala/io/iohk/ethereum/blockchain/sync/regular/BlockFetcherStateSpec.scala @@ -1,16 +1,19 @@ package io.iohk.ethereum.blockchain.sync.regular import akka.actor.ActorSystem -import akka.testkit.{TestKit, TestProbe} -import io.iohk.ethereum.Mocks.MockValidatorsAlwaysSucceed -import io.iohk.ethereum.blockchain.sync.regular.BlockFetcherState.HeadersNotMatchingReadyBlocks -import io.iohk.ethereum.{BlockHelpers, WithActorSystemShutDown} -import io.iohk.ethereum.network.PeerId -import io.iohk.ethereum.utils.ByteStringUtils +import akka.testkit.TestKit +import akka.testkit.TestProbe + +import scala.collection.immutable.Queue + import org.scalatest.matchers.should.Matchers import org.scalatest.wordspec.AnyWordSpecLike -import scala.collection.immutable.Queue +import io.iohk.ethereum.BlockHelpers +import io.iohk.ethereum.Mocks.MockValidatorsAlwaysSucceed +import io.iohk.ethereum.WithActorSystemShutDown +import io.iohk.ethereum.blockchain.sync.regular.BlockFetcherState.HeadersNotMatchingReadyBlocks +import io.iohk.ethereum.network.PeerId class BlockFetcherStateSpec extends TestKit(ActorSystem("BlockFetcherStateSpec_System")) diff --git a/src/test/scala/io/iohk/ethereum/blockchain/sync/regular/RegularSyncFixtures.scala b/src/test/scala/io/iohk/ethereum/blockchain/sync/regular/RegularSyncFixtures.scala index f5110a1418..6c7b46823f 100644 --- a/src/test/scala/io/iohk/ethereum/blockchain/sync/regular/RegularSyncFixtures.scala +++ b/src/test/scala/io/iohk/ethereum/blockchain/sync/regular/RegularSyncFixtures.scala @@ -2,42 +2,54 @@ package io.iohk.ethereum.blockchain.sync.regular import java.net.InetSocketAddress -import akka.actor.{ActorRef, ActorSystem, PoisonPill} +import akka.actor.ActorRef +import akka.actor.ActorSystem +import akka.actor.PoisonPill import akka.pattern.ask import akka.testkit.TestActor.AutoPilot -import akka.testkit.{TestKitBase, TestProbe} -import akka.util.{ByteString, Timeout} +import akka.testkit.TestKitBase +import akka.testkit.TestProbe +import akka.util.ByteString +import akka.util.Timeout + import cats.Eq +import cats.data.NonEmptyList import cats.implicits._ + +import monix.eval.Task +import monix.execution.Scheduler +import monix.reactive.Observable +import monix.reactive.subjects.ReplaySubject + +import scala.collection.mutable +import scala.concurrent.duration.DurationInt +import scala.concurrent.duration.FiniteDuration +import scala.math.BigInt +import scala.reflect.ClassTag + +import org.scalamock.scalatest.AsyncMockFactory +import org.scalatest.matchers.should.Matchers + import io.iohk.ethereum.BlockHelpers import io.iohk.ethereum.blockchain.sync._ import io.iohk.ethereum.consensus.blocks.CheckpointBlockGenerator import io.iohk.ethereum.domain.BlockHeaderImplicits._ import io.iohk.ethereum.domain._ -import io.iohk.ethereum.security.SecureRandomBuilder import io.iohk.ethereum.ledger._ -import io.iohk.ethereum.network.EtcPeerManagerActor.{PeerInfo, RemoteStatus} +import io.iohk.ethereum.network.EtcPeerManagerActor.PeerInfo +import io.iohk.ethereum.network.EtcPeerManagerActor.RemoteStatus +import io.iohk.ethereum.network.Peer import io.iohk.ethereum.network.PeerEventBusActor.PeerEvent.MessageFromPeer import io.iohk.ethereum.network.PeerEventBusActor.Subscribe +import io.iohk.ethereum.network.PeerId import io.iohk.ethereum.network.p2p.Message -import io.iohk.ethereum.network.p2p.messages.ETH62._ -import io.iohk.ethereum.network.p2p.messages.ETH63.{GetNodeData, NodeData} import io.iohk.ethereum.network.p2p.messages.ETC64.NewBlock +import io.iohk.ethereum.network.p2p.messages.ETH62._ +import io.iohk.ethereum.network.p2p.messages.ETH63.GetNodeData +import io.iohk.ethereum.network.p2p.messages.ETH63.NodeData import io.iohk.ethereum.network.p2p.messages.ProtocolVersions -import io.iohk.ethereum.network.{Peer, PeerId} +import io.iohk.ethereum.security.SecureRandomBuilder import io.iohk.ethereum.utils.Config.SyncConfig -import monix.eval.Task -import monix.execution.Scheduler -import monix.reactive.Observable -import monix.reactive.subjects.ReplaySubject -import org.scalamock.scalatest.AsyncMockFactory -import org.scalatest.matchers.should.Matchers - -import scala.collection.mutable -import scala.concurrent.duration.{DurationInt, FiniteDuration} -import scala.math.BigInt -import scala.reflect.ClassTag -import cats.data.NonEmptyList // Fixture classes are wrapped in a trait due to problems with making mocks available inside of them trait RegularSyncFixtures { self: Matchers with AsyncMockFactory => @@ -148,20 +160,21 @@ trait RegularSyncFixtures { self: Matchers with AsyncMockFactory => val getSyncStatus: Task[SyncProtocol.Status] = Task.deferFuture((regularSync ? SyncProtocol.GetStatus).mapTo[SyncProtocol.Status]) - def pollForStatus(predicate: SyncProtocol.Status => Boolean) = Observable + def pollForStatus(predicate: SyncProtocol.Status => Boolean): Task[SyncProtocol.Status] = Observable .repeatEvalF(getSyncStatus.delayExecution(10.millis)) - .takeWhileInclusive(predicate andThen (!_)) + .takeWhileInclusive(predicate.andThen(!_)) .lastL .timeout(remainingOrDefault) - def fishForStatus[B](picker: PartialFunction[SyncProtocol.Status, B]) = Observable + def fishForStatus[B](picker: PartialFunction[SyncProtocol.Status, B]): Task[B] = Observable .repeatEvalF(getSyncStatus.delayExecution(10.millis)) .collect(picker) .firstL .timeout(remainingOrDefault) - protected val results = mutable.Map[ByteString, Task[BlockImportResult]]() - protected val importedBlocksSet = mutable.Set[Block]() + protected val results: mutable.Map[ByteString, Task[BlockImportResult]] = + mutable.Map[ByteString, Task[BlockImportResult]]() + protected val importedBlocksSet: mutable.Set[Block] = mutable.Set[Block]() private val importedBlocksSubject = ReplaySubject[Block]() val importedBlocks: Observable[Block] = importedBlocksSubject @@ -202,10 +215,10 @@ trait RegularSyncFixtures { self: Matchers with AsyncMockFactory => case PeersClient.Request(GetBlockHeaders(Left(minBlock), amount, _, _), _, _) => val maxBlock = minBlock + amount val matchingHeaders = blocks - .filter(b => { + .filter { b => val nr = b.number minBlock <= nr && nr < maxBlock - }) + } .map(_.header) .sortBy(_.number) sender ! PeersClient.Response(defaultPeer, BlockHeaders(matchingHeaders)) @@ -346,7 +359,7 @@ trait RegularSyncFixtures { self: Matchers with AsyncMockFactory => (blockImport .importBlock(_: Block)(_: Scheduler)) .when(*, *) - .onCall((block, _) => { + .onCall { (block, _) => if (block == newBlock) { importedNewBlock = true Task.now( @@ -358,7 +371,7 @@ trait RegularSyncFixtures { self: Matchers with AsyncMockFactory => } Task.now(BlockImportedToTop(Nil)) } - }) + } peersClient.setAutoPilot(new PeersClientAutoPilot) diff --git a/src/test/scala/io/iohk/ethereum/blockchain/sync/regular/RegularSyncSpec.scala b/src/test/scala/io/iohk/ethereum/blockchain/sync/regular/RegularSyncSpec.scala index da52fa727e..bf0a5c5d74 100644 --- a/src/test/scala/io/iohk/ethereum/blockchain/sync/regular/RegularSyncSpec.scala +++ b/src/test/scala/io/iohk/ethereum/blockchain/sync/regular/RegularSyncSpec.scala @@ -1,45 +1,66 @@ package io.iohk.ethereum.blockchain.sync.regular -import akka.actor.{ActorRef, ActorSystem, typed} +import akka.actor.ActorRef +import akka.actor.ActorSystem +import akka.actor.typed import akka.actor.typed.{ActorRef => TypedActorRef} import akka.testkit.TestActor.AutoPilot -import akka.testkit.{TestKit, TestProbe} +import akka.testkit.TestKit +import akka.testkit.TestProbe import akka.util.ByteString -import cats.data.NonEmptyList + import cats.effect.Resource import cats.syntax.traverse._ + +import monix.eval.Task +import monix.execution.Scheduler + +import scala.concurrent.Await +import scala.concurrent.Future +import scala.concurrent.Promise +import scala.concurrent.duration._ +import scala.math.BigInt + +import org.scalamock.scalatest.AsyncMockFactory +import org.scalatest.Assertion +import org.scalatest.BeforeAndAfterEach +import org.scalatest.diagrams.Diagrams +import org.scalatest.matchers.should.Matchers + +import io.iohk.ethereum.BlockHelpers +import io.iohk.ethereum.ObjectGenerators +import io.iohk.ethereum.ResourceFixtures +import io.iohk.ethereum.WordSpecBase import io.iohk.ethereum.blockchain.sync.Blacklist.BlacklistReason +import io.iohk.ethereum.blockchain.sync.PeersClient +import io.iohk.ethereum.blockchain.sync.SyncProtocol import io.iohk.ethereum.blockchain.sync.SyncProtocol.Status import io.iohk.ethereum.blockchain.sync.SyncProtocol.Status.Progress import io.iohk.ethereum.blockchain.sync.regular.BlockFetcher.Start import io.iohk.ethereum.blockchain.sync.regular.RegularSync.NewCheckpoint -import io.iohk.ethereum.blockchain.sync.{PeersClient, SyncProtocol} import io.iohk.ethereum.crypto.kec256 import io.iohk.ethereum.domain.BlockHeaderImplicits._ import io.iohk.ethereum.domain._ import io.iohk.ethereum.ledger._ import io.iohk.ethereum.mpt.MerklePatriciaTrie.MissingNodeException -import io.iohk.ethereum.network.EtcPeerManagerActor.{GetHandshakedPeers, HandshakedPeers, PeerInfo} +import io.iohk.ethereum.network.EtcPeerManagerActor +import io.iohk.ethereum.network.EtcPeerManagerActor.GetHandshakedPeers +import io.iohk.ethereum.network.EtcPeerManagerActor.HandshakedPeers +import io.iohk.ethereum.network.EtcPeerManagerActor.PeerInfo +import io.iohk.ethereum.network.Peer +import io.iohk.ethereum.network.PeerEventBusActor import io.iohk.ethereum.network.PeerEventBusActor.PeerEvent.MessageFromPeer +import io.iohk.ethereum.network.PeerEventBusActor.PeerSelector +import io.iohk.ethereum.network.PeerEventBusActor.Subscribe import io.iohk.ethereum.network.PeerEventBusActor.SubscriptionClassifier.MessageClassifier -import io.iohk.ethereum.network.PeerEventBusActor.{PeerSelector, Subscribe} -import io.iohk.ethereum.network.p2p.messages.{Codes, BaseETH6XMessages, ProtocolVersions} -import io.iohk.ethereum.network.p2p.messages.ETH62._ -import io.iohk.ethereum.network.p2p.messages.ETH63.{GetNodeData, NodeData} +import io.iohk.ethereum.network.p2p.messages.BaseETH6XMessages +import io.iohk.ethereum.network.p2p.messages.Codes import io.iohk.ethereum.network.p2p.messages.ETC64.NewBlock -import io.iohk.ethereum.network.{EtcPeerManagerActor, Peer, PeerEventBusActor} +import io.iohk.ethereum.network.p2p.messages.ETH62._ +import io.iohk.ethereum.network.p2p.messages.ETH63.GetNodeData +import io.iohk.ethereum.network.p2p.messages.ETH63.NodeData +import io.iohk.ethereum.network.p2p.messages.ProtocolVersions import io.iohk.ethereum.utils.Config.SyncConfig -import io.iohk.ethereum.{BlockHelpers, ObjectGenerators, ResourceFixtures, WordSpecBase} -import monix.eval.Task -import monix.execution.Scheduler -import org.scalamock.scalatest.AsyncMockFactory -import org.scalatest.diagrams.Diagrams -import org.scalatest.matchers.should.Matchers -import org.scalatest.{Assertion, BeforeAndAfterEach} - -import scala.concurrent.duration._ -import scala.concurrent.{Await, Future, Promise} -import scala.math.BigInt class RegularSyncSpec extends WordSpecBase @@ -51,9 +72,9 @@ class RegularSyncSpec with RegularSyncFixtures { type Fixture = RegularSyncFixture - val actorSystemResource = - Resource.make(Task { ActorSystem() })(system => Task { TestKit.shutdownActorSystem(system) }) - val fixtureResource = actorSystemResource.map(new Fixture(_)) + val actorSystemResource: Resource[Task, ActorSystem] = + Resource.make(Task(ActorSystem()))(system => Task(TestKit.shutdownActorSystem(system))) + val fixtureResource: Resource[Task, Fixture] = actorSystemResource.map(new Fixture(_)) // Used only in sync tests var testSystem: ActorSystem = _ @@ -462,7 +483,7 @@ class RegularSyncSpec (blockchainReader.getBlockHeaderByNumber _).when(*).returns(Some(BlockHelpers.genesis.header)) (blockchain.saveNode _) .when(*, *, *) - .onCall((hash, encoded, totalDifficulty) => { + .onCall { (hash, encoded, totalDifficulty) => val expectedNode = nodeData.head hash should be(kec256(expectedNode)) @@ -470,7 +491,7 @@ class RegularSyncSpec totalDifficulty should be(failingBlock.number) saveNodeWasCalled = true - }) + } regularSync ! SyncProtocol.Start @@ -536,7 +557,7 @@ class RegularSyncSpec case EtcPeerManagerActor.SendMessage(message, _) => message.underlyingMsg match { case NewBlock(block, _) if block == newBlock => true - case _ => false + case _ => false } case _ => false } @@ -606,7 +627,7 @@ class RegularSyncSpec case EtcPeerManagerActor.SendMessage(message, _) => message.underlyingMsg match { case NewBlock(block, _) if block == newBlock => true - case _ => false + case _ => false } case _ => false } @@ -635,7 +656,7 @@ class RegularSyncSpec regularSync ! newCheckpointMsg assertForDuration( - { didTryToImportBlock(checkpointBlock) shouldBe false }, + didTryToImportBlock(checkpointBlock) shouldBe false, 1.second ) blockPromise.success(BlockImportedToTop(Nil)) @@ -669,7 +690,7 @@ class RegularSyncSpec case EtcPeerManagerActor.SendMessage(message, _) => message.underlyingMsg match { case NewBlock(block, _) if block == checkpointBlock => true - case _ => false + case _ => false } case _ => false } @@ -697,7 +718,7 @@ class RegularSyncSpec case EtcPeerManagerActor.SendMessage(message, _) => message.underlyingMsg match { case BaseETH6XMessages.NewBlock(`newBlock`, _) => true - case _ => false + case _ => false } case _ => false } @@ -720,7 +741,7 @@ class RegularSyncSpec case EtcPeerManagerActor.SendMessage(message, _) => message.underlyingMsg match { case NewBlock(`newBlock`, _) => true - case _ => false + case _ => false } case _ => false } @@ -733,7 +754,7 @@ class RegularSyncSpec import fixture._ for { - _ <- Task { regularSync ! SyncProtocol.Start } + _ <- Task(regularSync ! SyncProtocol.Start) before <- getSyncStatus _ <- Task { peerEventBus.expectMsgClass(classOf[Subscribe]) @@ -758,7 +779,7 @@ class RegularSyncSpec _ <- testBlocks .take(5) .traverse(block => - Task { blockchain.save(block, Nil, ChainWeight.totalDifficultyOnly(10000), saveAsBestBlock = true) } + Task(blockchain.save(block, Nil, ChainWeight.totalDifficultyOnly(10000), saveAsBestBlock = true)) ) _ <- Task { regularSync ! SyncProtocol.Start @@ -801,9 +822,7 @@ class RegularSyncSpec } status <- pollForStatus(_.syncing) lastBlock = testBlocks.last.number - } yield { - assert(status === Status.Syncing(0, Progress(0, lastBlock), None)) - } + } yield assert(status === Status.Syncing(0, Progress(0, lastBlock), None)) } "return updated status after importing blocks" in testCaseT { fixture => @@ -838,7 +857,7 @@ class RegularSyncSpec import fixture._ for { - _ <- Task { goToTop() } + _ <- Task(goToTop()) status <- getSyncStatus } yield assert(status === Status.SyncDone) } diff --git a/src/test/scala/io/iohk/ethereum/checkpointing/CheckpointingTestHelpers.scala b/src/test/scala/io/iohk/ethereum/checkpointing/CheckpointingTestHelpers.scala index 3a1f224ddc..fef2ca53d7 100644 --- a/src/test/scala/io/iohk/ethereum/checkpointing/CheckpointingTestHelpers.scala +++ b/src/test/scala/io/iohk/ethereum/checkpointing/CheckpointingTestHelpers.scala @@ -1,9 +1,11 @@ package io.iohk.ethereum.checkpointing import akka.util.ByteString + +import org.bouncycastle.crypto.AsymmetricCipherKeyPair + import io.iohk.ethereum.crypto.ECDSASignature import io.iohk.ethereum.crypto.ECDSASignatureImplicits.ECDSASignatureOrdering -import org.bouncycastle.crypto.AsymmetricCipherKeyPair object CheckpointingTestHelpers { diff --git a/src/test/scala/io/iohk/ethereum/cli/CliCommandsSpec.scala b/src/test/scala/io/iohk/ethereum/cli/CliCommandsSpec.scala index a5de7eb6fe..c1d354a5d2 100644 --- a/src/test/scala/io/iohk/ethereum/cli/CliCommandsSpec.scala +++ b/src/test/scala/io/iohk/ethereum/cli/CliCommandsSpec.scala @@ -1,22 +1,23 @@ package io.iohk.ethereum.cli -import io.iohk.ethereum.keystore.EncryptedKeyJsonCodec -import io.iohk.ethereum.utils.ByteStringUtils import org.scalatest.EitherValues import org.scalatest.flatspec.AnyFlatSpec import org.scalatest.matchers.should.Matchers +import io.iohk.ethereum.keystore.EncryptedKeyJsonCodec +import io.iohk.ethereum.utils.ByteStringUtils + class CliCommandsSpec extends AnyFlatSpec with Matchers with EitherValues { import CliCommands._ import Fixture._ - behavior of generatePrivateKeyCommand + behavior.of(generatePrivateKeyCommand) it should "generate correct private key" in { api.parse(Seq(generatePrivateKeyCommand)) shouldBe a[Right[_, _]] } - behavior of deriveAddressCommand + behavior.of(deriveAddressCommand) it should "derive address from private key" in { api.parse(Seq(deriveAddressCommand, privateKey)).value shouldBe address } @@ -25,7 +26,7 @@ class CliCommandsSpec extends AnyFlatSpec with Matchers with EitherValues { api.parse(Seq(deriveAddressCommand)) shouldBe a[Left[_, _]] } - behavior of generateAllocsCommand + behavior.of(generateAllocsCommand) it should "generate correct alloc using private key" in { api .parse( @@ -78,7 +79,7 @@ class CliCommandsSpec extends AnyFlatSpec with Matchers with EitherValues { .value shouldBe s""""alloc": {$address: { "balance": $requestedBalance }, $address3: { "balance": $requestedBalance }, $address2: { "balance": $requestedBalance }}""" } - behavior of generateKeyPairsCommand + behavior.of(generateKeyPairsCommand) it should "generate one key pair when passed no args" in { val result = api.parse(Seq(generateKeyPairsCommand)) result shouldBe a[Right[_, _]] @@ -95,7 +96,7 @@ class CliCommandsSpec extends AnyFlatSpec with Matchers with EitherValues { stringSplit.length shouldEqual numOfKeysAsInt } - behavior of encryptKeyCommand + behavior.of(encryptKeyCommand) it should "encrypt private key (without passphrase)" in { val json = api.parse(Seq(encryptKeyCommand, privateKey)).value diff --git a/src/test/scala/io/iohk/ethereum/consensus/ConsensusConfigs.scala b/src/test/scala/io/iohk/ethereum/consensus/ConsensusConfigs.scala index e7f70a6856..53174856ed 100644 --- a/src/test/scala/io/iohk/ethereum/consensus/ConsensusConfigs.scala +++ b/src/test/scala/io/iohk/ethereum/consensus/ConsensusConfigs.scala @@ -1,6 +1,7 @@ package io.iohk.ethereum.consensus import akka.util.ByteString + import io.iohk.ethereum.Timeouts import io.iohk.ethereum.consensus.pow.EthashConfig import io.iohk.ethereum.domain.Address @@ -9,7 +10,7 @@ import io.iohk.ethereum.domain.Address object ConsensusConfigs { final val blockCacheSize = 30 final val coinbaseAddressNum = 42 - final val coinbase = Address(coinbaseAddressNum) + final val coinbase: Address = Address(coinbaseAddressNum) //noinspection ScalaStyle final val ethashConfig = new EthashConfig( @@ -27,5 +28,5 @@ object ConsensusConfigs { miningEnabled = false ) - final val fullConsensusConfig = FullConsensusConfig(consensusConfig, ethashConfig) + final val fullConsensusConfig: FullConsensusConfig[EthashConfig] = FullConsensusConfig(consensusConfig, ethashConfig) } diff --git a/src/test/scala/io/iohk/ethereum/consensus/blocks/BlockGeneratorSpec.scala b/src/test/scala/io/iohk/ethereum/consensus/blocks/BlockGeneratorSpec.scala index 12edb6b533..27c490655e 100644 --- a/src/test/scala/io/iohk/ethereum/consensus/blocks/BlockGeneratorSpec.scala +++ b/src/test/scala/io/iohk/ethereum/consensus/blocks/BlockGeneratorSpec.scala @@ -1,32 +1,40 @@ package io.iohk.ethereum.consensus.blocks +import java.time.Instant + import akka.util.ByteString + +import monix.execution.Scheduler +import monix.execution.schedulers.SchedulerService + +import org.bouncycastle.crypto.AsymmetricCipherKeyPair +import org.bouncycastle.crypto.params.ECPublicKeyParameters +import org.bouncycastle.util.encoders.Hex +import org.scalatest.flatspec.AnyFlatSpec +import org.scalatest.matchers.should.Matchers +import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks + import io.iohk.ethereum.blockchain.data.GenesisDataLoader import io.iohk.ethereum.blockchain.sync.EphemBlockchainTestSetup +import io.iohk.ethereum.consensus.ConsensusConfig import io.iohk.ethereum.consensus.pow.validators.ValidatorsExecutor import io.iohk.ethereum.consensus.validators._ import io.iohk.ethereum.crypto import io.iohk.ethereum.crypto._ import io.iohk.ethereum.domain.BlockHeader.HeaderExtraFields -import io.iohk.ethereum.domain.BlockHeader.HeaderExtraFields.{HefEmpty, HefPostEcip1097} +import io.iohk.ethereum.domain.BlockHeader.HeaderExtraFields.HefEmpty +import io.iohk.ethereum.domain.BlockHeader.HeaderExtraFields.HefPostEcip1097 import io.iohk.ethereum.domain.SignedTransaction.FirstByteOfAddress import io.iohk.ethereum.domain._ +import io.iohk.ethereum.ledger.BlockExecution import io.iohk.ethereum.ledger.BlockExecutionError.ValidationAfterExecError -import io.iohk.ethereum.ledger.{BlockExecution, BlockQueue, BlockValidation} +import io.iohk.ethereum.ledger.BlockQueue +import io.iohk.ethereum.ledger.BlockValidation import io.iohk.ethereum.mpt.MerklePatriciaTrie.MPTException import io.iohk.ethereum.utils._ -import monix.execution.Scheduler -import org.bouncycastle.crypto.AsymmetricCipherKeyPair -import org.bouncycastle.crypto.params.ECPublicKeyParameters -import org.bouncycastle.util.encoders.Hex -import org.scalatest.flatspec.AnyFlatSpec -import org.scalatest.matchers.should.Matchers -import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks - -import java.time.Instant class BlockGeneratorSpec extends AnyFlatSpec with Matchers with ScalaCheckPropertyChecks with Logger { - implicit val testContext = Scheduler.fixedPool("block-generator-spec-pool", 4) + implicit val testContext: SchedulerService = Scheduler.fixedPool("block-generator-spec-pool", 4) "BlockGenerator" should "generate correct block with empty transactions" in new TestSetup { val pendingBlock = @@ -101,7 +109,7 @@ class BlockGeneratorSpec extends AnyFlatSpec with Matchers with ScalaCheckProper ) // Import Block, to create some existing state - val res = blockImport.importBlock(fullBlock).runSyncUnsafe() + blockImport.importBlock(fullBlock).runSyncUnsafe() // Create new pending block, with updated stateRootHash val pendBlockAndState = blockGenerator.generateBlock( @@ -640,14 +648,14 @@ class BlockGeneratorSpec extends AnyFlatSpec with Matchers with ScalaCheckProper trait TestSetup extends EphemBlockchainTestSetup { val testAddress = 42 - val privateKey = BigInt(1, Hex.decode("f3202185c84325302d43887e90a2e23e7bc058d0450bb58ef2f7585765d7d48b")) + val privateKey: BigInt = BigInt(1, Hex.decode("f3202185c84325302d43887e90a2e23e7bc058d0450bb58ef2f7585765d7d48b")) lazy val keyPair: AsymmetricCipherKeyPair = keyPairFromPrvKey(privateKey) lazy val pubKey: Array[Byte] = keyPair.getPublic.asInstanceOf[ECPublicKeyParameters].getQ.getEncoded(false).tail - lazy val address = Address(crypto.kec256(pubKey).drop(FirstByteOfAddress)) + lazy val address: Address = Address(crypto.kec256(pubKey).drop(FirstByteOfAddress)) val txGasLimit = 21000 val txTransfer = 9000 - val transaction = Transaction( + val transaction: Transaction = Transaction( nonce = 0, gasPrice = 1, gasLimit = txGasLimit, @@ -657,14 +665,15 @@ class BlockGeneratorSpec extends AnyFlatSpec with Matchers with ScalaCheckProper ) //defined in test-genesis-treasury.json - val treasuryAccount = Address(0xeeeeee) - val maliciousAccount = Address(0x123) + val treasuryAccount: Address = Address(0xeeeeee) + val maliciousAccount: Address = Address(0x123) - lazy val signedTransaction = SignedTransaction.sign(transaction, keyPair, Some(0x3d.toByte)) - lazy val duplicatedSignedTransaction = + lazy val signedTransaction: SignedTransactionWithSender = + SignedTransaction.sign(transaction, keyPair, Some(0x3d.toByte)) + lazy val duplicatedSignedTransaction: SignedTransactionWithSender = SignedTransaction.sign(transaction.copy(gasLimit = 2), keyPair, Some(0x3d.toByte)) - val baseBlockchainConfig = BlockchainConfig( + val baseBlockchainConfig: BlockchainConfig = BlockchainConfig( forkBlockNumbers = ForkBlockNumbers( frontierBlockNumber = 0, homesteadBlockNumber = 1150000, @@ -709,7 +718,7 @@ class BlockGeneratorSpec extends AnyFlatSpec with Matchers with ScalaCheckProper new GenesisDataLoader(blockchain, blockchainReader, storagesInstance.storages.stateStorage, blockchainConfig) genesisDataLoader.loadGenesisData() - val bestBlock = blockchain.getBestBlock() + val bestBlock: Option[Block] = blockchain.getBestBlock() lazy val blockTimestampProvider = new FakeBlockTimestampProvider @@ -718,10 +727,11 @@ class BlockGeneratorSpec extends AnyFlatSpec with Matchers with ScalaCheckProper override lazy val validators: ValidatorsExecutor = powValidators - override lazy val consensusConfig = + override lazy val consensusConfig: ConsensusConfig = buildConsensusConfig().copy(headerExtraData = headerExtraData, blockCacheSize = blockCacheSize) - lazy val blockGenerator = consensus.blockGenerator.withBlockTimestampProvider(blockTimestampProvider) + lazy val blockGenerator: TestBlockGenerator = + consensus.blockGenerator.withBlockTimestampProvider(blockTimestampProvider) lazy val blockValidation = new BlockValidation(consensus, blockchainReader, BlockQueue(blockchain, syncConfig)) diff --git a/src/test/scala/io/iohk/ethereum/consensus/blocks/CheckpointBlockGeneratorSpec.scala b/src/test/scala/io/iohk/ethereum/consensus/blocks/CheckpointBlockGeneratorSpec.scala index f1950a3deb..65c0ec84a9 100644 --- a/src/test/scala/io/iohk/ethereum/consensus/blocks/CheckpointBlockGeneratorSpec.scala +++ b/src/test/scala/io/iohk/ethereum/consensus/blocks/CheckpointBlockGeneratorSpec.scala @@ -1,12 +1,14 @@ package io.iohk.ethereum.consensus.blocks import akka.util.ByteString + +import org.scalatest.flatspec.AnyFlatSpec +import org.scalatest.matchers.should.Matchers + import io.iohk.ethereum.Fixtures import io.iohk.ethereum.domain.BlockHeader.HeaderExtraFields.HefPostEcip1097 import io.iohk.ethereum.domain._ import io.iohk.ethereum.ledger.BloomFilter -import org.scalatest.flatspec.AnyFlatSpec -import org.scalatest.matchers.should.Matchers class CheckpointBlockGeneratorSpec extends AnyFlatSpec with Matchers { diff --git a/src/test/scala/io/iohk/ethereum/consensus/pow/EthashUtilsSpec.scala b/src/test/scala/io/iohk/ethereum/consensus/pow/EthashUtilsSpec.scala index 61dfeafe45..0384e38fb9 100644 --- a/src/test/scala/io/iohk/ethereum/consensus/pow/EthashUtilsSpec.scala +++ b/src/test/scala/io/iohk/ethereum/consensus/pow/EthashUtilsSpec.scala @@ -1,17 +1,15 @@ package io.iohk.ethereum.consensus.pow import akka.util.ByteString -import io.iohk.ethereum.crypto.kec256 -import org.scalacheck.Gen + import org.bouncycastle.util.encoders.Hex -import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks import org.scalatest.flatspec.AnyFlatSpec import org.scalatest.matchers.should.Matchers +import org.scalatest.prop.TableFor2 +import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks -import scala.annotation.tailrec import io.iohk.ethereum.SuperSlow import io.iohk.ethereum.utils.ByteStringUtils -import org.scalatest.prop.TableFor2 class EthashUtilsSpec extends AnyFlatSpec with Matchers with ScalaCheckPropertyChecks with SuperSlow { diff --git a/src/test/scala/io/iohk/ethereum/consensus/pow/KeccakCalculationSpec.scala b/src/test/scala/io/iohk/ethereum/consensus/pow/KeccakCalculationSpec.scala index a214f5ad89..7729fa5169 100644 --- a/src/test/scala/io/iohk/ethereum/consensus/pow/KeccakCalculationSpec.scala +++ b/src/test/scala/io/iohk/ethereum/consensus/pow/KeccakCalculationSpec.scala @@ -1,12 +1,14 @@ package io.iohk.ethereum.consensus.pow import akka.util.ByteString -import io.iohk.ethereum.consensus.pow.KeccakCalculation.KeccakMixHash -import io.iohk.ethereum.domain.BlockHeader + import org.bouncycastle.util.encoders.Hex import org.scalatest.flatspec.AnyFlatSpecLike import org.scalatest.matchers.should.Matchers +import io.iohk.ethereum.consensus.pow.KeccakCalculation.KeccakMixHash +import io.iohk.ethereum.domain.BlockHeader + class KeccakCalculationSpec extends AnyFlatSpecLike with Matchers { import KeccakDataUtils._ diff --git a/src/test/scala/io/iohk/ethereum/consensus/pow/KeccakDataUtils.scala b/src/test/scala/io/iohk/ethereum/consensus/pow/KeccakDataUtils.scala index 1da2a16ea5..20e637d270 100644 --- a/src/test/scala/io/iohk/ethereum/consensus/pow/KeccakDataUtils.scala +++ b/src/test/scala/io/iohk/ethereum/consensus/pow/KeccakDataUtils.scala @@ -1,11 +1,13 @@ package io.iohk.ethereum.consensus.pow import akka.util.ByteString -import io.iohk.ethereum.domain.BlockHeader + import org.bouncycastle.util.encoders.Hex +import io.iohk.ethereum.domain.BlockHeader + object KeccakDataUtils { - val header = BlockHeader( + val header: BlockHeader = BlockHeader( parentHash = ByteString(Hex.decode("ad22d4d8f0e94032cb32e86027e0a5533d945ed95088264e91dd71e4fbaebeda")), ommersHash = ByteString(Hex.decode("1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347")), beneficiary = ByteString(Hex.decode("6A9ECfa04e99726eC105517AC7ae1aba550BeA6c")), diff --git a/src/test/scala/io/iohk/ethereum/consensus/pow/MinerSpecSetup.scala b/src/test/scala/io/iohk/ethereum/consensus/pow/MinerSpecSetup.scala index 43323b1528..7a32c7fbb6 100644 --- a/src/test/scala/io/iohk/ethereum/consensus/pow/MinerSpecSetup.scala +++ b/src/test/scala/io/iohk/ethereum/consensus/pow/MinerSpecSetup.scala @@ -1,17 +1,32 @@ package io.iohk.ethereum.consensus.pow -import akka.actor.{ActorRef, ActorSystem => ClassicSystem} -import akka.testkit.{TestActor, TestProbe} +import akka.actor.ActorRef +import akka.actor.{ActorSystem => ClassicSystem} +import akka.testkit.TestActor +import akka.testkit.TestProbe import akka.util.ByteString + +import monix.eval.Task +import monix.execution.Scheduler + +import scala.concurrent.duration.Duration +import scala.concurrent.duration.FiniteDuration + +import org.bouncycastle.util.encoders.Hex +import org.scalamock.handlers.CallHandler3 +import org.scalamock.scalatest.MockFactory + import io.iohk.ethereum.Fixtures import io.iohk.ethereum.blockchain.sync.SyncProtocol +import io.iohk.ethereum.consensus.ConsensusConfigBuilder +import io.iohk.ethereum.consensus.FullConsensusConfig import io.iohk.ethereum.consensus.Protocol.NoAdditionalPoWData -import io.iohk.ethereum.consensus.{ConsensusConfigBuilder, FullConsensusConfig} -import io.iohk.ethereum.consensus.blocks.{PendingBlock, PendingBlockAndState} +import io.iohk.ethereum.consensus.blocks.PendingBlock +import io.iohk.ethereum.consensus.blocks.PendingBlockAndState import io.iohk.ethereum.consensus.pow.blocks.PoWBlockGenerator import io.iohk.ethereum.consensus.pow.difficulty.EthashDifficultyCalculator import io.iohk.ethereum.consensus.pow.validators.ValidatorsExecutor -import io.iohk.ethereum.db.storage.{EvmCodeStorage, MptStorage} +import io.iohk.ethereum.db.storage.EvmCodeStorage import io.iohk.ethereum.domain._ import io.iohk.ethereum.jsonrpc.EthMiningService import io.iohk.ethereum.jsonrpc.EthMiningService.SubmitHashRateResponse @@ -20,34 +35,28 @@ import io.iohk.ethereum.ledger.VMImpl import io.iohk.ethereum.ommers.OmmersPool import io.iohk.ethereum.transactions.PendingTransactionsManager import io.iohk.ethereum.utils.Config -import monix.eval.Task -import monix.execution.Scheduler -import org.bouncycastle.util.encoders.Hex -import org.scalamock.scalatest.MockFactory - -import scala.concurrent.duration.{Duration, FiniteDuration} trait MinerSpecSetup extends ConsensusConfigBuilder with MockFactory { - implicit val classicSystem = ClassicSystem() - implicit val scheduler = Scheduler(classicSystem.dispatcher) - val parentActor = TestProbe() - val sync = TestProbe() + implicit val classicSystem: ClassicSystem = ClassicSystem() + implicit val scheduler: Scheduler = Scheduler(classicSystem.dispatcher) + val parentActor: TestProbe = TestProbe() + val sync: TestProbe = TestProbe() val ommersPool: TestProbe = TestProbe() val pendingTransactionsManager: TestProbe = TestProbe() - val origin = Block(Fixtures.Blocks.Genesis.header, Fixtures.Blocks.Genesis.body) + val origin: Block = Block(Fixtures.Blocks.Genesis.header, Fixtures.Blocks.Genesis.body) val blockchainReader: BlockchainReader = mock[BlockchainReader] val blockchain: BlockchainImpl = mock[BlockchainImpl] - val blockCreator = mock[PoWBlockCreator] - val fakeWorld = mock[InMemoryWorldStateProxy] + val blockCreator: PoWBlockCreator = mock[PoWBlockCreator] + val fakeWorld: InMemoryWorldStateProxy = mock[InMemoryWorldStateProxy] val blockGenerator: PoWBlockGenerator = mock[PoWBlockGenerator] val ethMiningService: EthMiningService = mock[EthMiningService] val evmCodeStorage: EvmCodeStorage = mock[EvmCodeStorage] lazy val vm: VMImpl = new VMImpl - val txToMine = SignedTransaction( + val txToMine: SignedTransaction = SignedTransaction( tx = Transaction( nonce = BigInt("438553"), gasPrice = BigInt("20000000000"), @@ -65,9 +74,9 @@ trait MinerSpecSetup extends ConsensusConfigBuilder with MockFactory { lazy val consensus: PoWConsensus = buildPoWConsensus().withBlockGenerator(blockGenerator) lazy val blockchainConfig = Config.blockchains.blockchainConfig lazy val difficultyCalc = new EthashDifficultyCalculator(blockchainConfig) - val blockForMiningTimestamp = System.currentTimeMillis() + val blockForMiningTimestamp: Long = System.currentTimeMillis() - protected def getParentBlock(parentBlockNumber: Int) = + protected def getParentBlock(parentBlockNumber: Int): Block = origin.copy(header = origin.header.copy(number = parentBlockNumber)) def buildPoWConsensus(): PoWConsensus = { @@ -130,7 +139,11 @@ trait MinerSpecSetup extends ConsensusConfigBuilder with MockFactory { parentGas + gasLimitDifference - 1 } - protected def blockCreatorBehaviour(parentBlock: Block, withTransactions: Boolean, resultBlock: Block) = { + protected def blockCreatorBehaviour( + parentBlock: Block, + withTransactions: Boolean, + resultBlock: Block + ): CallHandler3[Block, Boolean, Option[InMemoryWorldStateProxy], Task[PendingBlockAndState]] = (blockCreator .getBlockForMining(_: Block, _: Boolean, _: Option[InMemoryWorldStateProxy])) .expects(parentBlock, withTransactions, *) @@ -138,13 +151,12 @@ trait MinerSpecSetup extends ConsensusConfigBuilder with MockFactory { Task.now(PendingBlockAndState(PendingBlock(resultBlock, Nil), fakeWorld)) ) .atLeastOnce() - } protected def blockCreatorBehaviourExpectingInitialWorld( parentBlock: Block, withTransactions: Boolean, resultBlock: Block - ) = { + ): CallHandler3[Block, Boolean, Option[InMemoryWorldStateProxy], Task[PendingBlockAndState]] = (blockCreator .getBlockForMining(_: Block, _: Boolean, _: Option[InMemoryWorldStateProxy])) .expects(where { (parent, withTxs, _) => @@ -154,7 +166,6 @@ trait MinerSpecSetup extends ConsensusConfigBuilder with MockFactory { Task.now(PendingBlockAndState(PendingBlock(resultBlock, Nil), fakeWorld)) ) .atLeastOnce() - } protected def prepareMocks(): Unit = { (ethMiningService.submitHashRate _) @@ -162,24 +173,22 @@ trait MinerSpecSetup extends ConsensusConfigBuilder with MockFactory { .returns(Task.now(Right(SubmitHashRateResponse(true)))) .atLeastOnce() - ommersPool.setAutoPilot((sender: ActorRef, _: Any) => { + ommersPool.setAutoPilot { (sender: ActorRef, _: Any) => sender ! OmmersPool.Ommers(Nil) TestActor.KeepRunning - }) + } - pendingTransactionsManager.setAutoPilot((sender: ActorRef, _: Any) => { + pendingTransactionsManager.setAutoPilot { (sender: ActorRef, _: Any) => sender ! PendingTransactionsManager.PendingTransactionsResponse(Nil) TestActor.KeepRunning - }) + } } - protected def waitForMinedBlock(implicit timeout: Duration): Block = { + protected def waitForMinedBlock(implicit timeout: Duration): Block = sync.expectMsgPF[Block](timeout) { case m: SyncProtocol.MinedBlock => m.block } - } - protected def expectNoNewBlockMsg(timeout: FiniteDuration): Unit = { + protected def expectNoNewBlockMsg(timeout: FiniteDuration): Unit = sync.expectNoMessage(timeout) - } } diff --git a/src/test/scala/io/iohk/ethereum/consensus/pow/PoWConsensusSpec.scala b/src/test/scala/io/iohk/ethereum/consensus/pow/PoWConsensusSpec.scala index 49883f6441..14940e87af 100644 --- a/src/test/scala/io/iohk/ethereum/consensus/pow/PoWConsensusSpec.scala +++ b/src/test/scala/io/iohk/ethereum/consensus/pow/PoWConsensusSpec.scala @@ -2,20 +2,27 @@ package io.iohk.ethereum.consensus.pow import akka.actor.ActorSystem import akka.testkit.TestKit + +import org.bouncycastle.crypto.AsymmetricCipherKeyPair +import org.scalamock.scalatest.MockFactory +import org.scalatest.flatspec.AnyFlatSpecLike +import org.scalatest.matchers.should.Matchers + import io.iohk.ethereum.WithActorSystemShutDown -import io.iohk.ethereum.blockchain.sync.{EphemBlockchainTestSetup, ScenarioSetup} +import io.iohk.ethereum.blockchain.sync.EphemBlockchainTestSetup +import io.iohk.ethereum.consensus.ConsensusConfigs import io.iohk.ethereum.consensus.ConsensusConfigs.ethashConfig -import io.iohk.ethereum.consensus.Protocol.{NoAdditionalPoWData, RestrictedPoWMinerData} -import io.iohk.ethereum.consensus.pow.blocks.{PoWBlockGeneratorImpl, RestrictedPoWBlockGeneratorImpl} +import io.iohk.ethereum.consensus.FullConsensusConfig +import io.iohk.ethereum.consensus.Protocol +import io.iohk.ethereum.consensus.Protocol.NoAdditionalPoWData +import io.iohk.ethereum.consensus.Protocol.RestrictedPoWMinerData +import io.iohk.ethereum.consensus.pow.blocks.PoWBlockGeneratorImpl +import io.iohk.ethereum.consensus.pow.blocks.RestrictedPoWBlockGeneratorImpl import io.iohk.ethereum.consensus.pow.validators.ValidatorsExecutor -import io.iohk.ethereum.consensus.{ConsensusConfigs, FullConsensusConfig, Protocol} import io.iohk.ethereum.db.storage.EvmCodeStorage -import io.iohk.ethereum.domain.{BlockchainImpl, BlockchainReader} +import io.iohk.ethereum.domain.BlockchainImpl +import io.iohk.ethereum.domain.BlockchainReader import io.iohk.ethereum.nodebuilder.StdNode -import org.bouncycastle.crypto.AsymmetricCipherKeyPair -import org.scalamock.scalatest.MockFactory -import org.scalatest.flatspec.AnyFlatSpecLike -import org.scalatest.matchers.should.Matchers class PoWConsensusSpec extends TestKit(ActorSystem("PoWConsensusSpec_System")) diff --git a/src/test/scala/io/iohk/ethereum/consensus/pow/PoWMiningCoordinatorSpec.scala b/src/test/scala/io/iohk/ethereum/consensus/pow/PoWMiningCoordinatorSpec.scala index a2d43da120..a608f7965b 100644 --- a/src/test/scala/io/iohk/ethereum/consensus/pow/PoWMiningCoordinatorSpec.scala +++ b/src/test/scala/io/iohk/ethereum/consensus/pow/PoWMiningCoordinatorSpec.scala @@ -2,22 +2,29 @@ package io.iohk.ethereum.consensus.pow import akka.actor.ActorRef import akka.actor.testkit.typed.LoggingEvent -import akka.actor.testkit.typed.scaladsl.{LoggingTestKit, ScalaTestWithActorTestKit} +import akka.actor.testkit.typed.scaladsl.LoggingTestKit +import akka.actor.testkit.typed.scaladsl.ScalaTestWithActorTestKit +import akka.actor.typed import akka.actor.typed.scaladsl.adapter._ -import akka.testkit.{TestActor, TestProbe} +import akka.testkit.TestActor +import akka.testkit.TestProbe + +import monix.eval.Task + +import scala.concurrent.duration._ + +import org.bouncycastle.util.encoders.Hex +import org.scalatest.freespec.AnyFreeSpecLike +import org.scalatest.matchers.should.Matchers + import io.iohk.ethereum.Fixtures import io.iohk.ethereum.blockchain.sync.SyncProtocol.MinedBlock import io.iohk.ethereum.consensus.pow.PoWMiningCoordinator._ -import io.iohk.ethereum.domain.{Block, UInt256} +import io.iohk.ethereum.domain.Block +import io.iohk.ethereum.domain.UInt256 import io.iohk.ethereum.jsonrpc.EthMiningService.SubmitHashRateResponse import io.iohk.ethereum.ommers.OmmersPool import io.iohk.ethereum.transactions.PendingTransactionsManager -import monix.eval.Task -import org.bouncycastle.util.encoders.Hex -import org.scalatest.freespec.AnyFreeSpecLike -import org.scalatest.matchers.should.Matchers - -import scala.concurrent.duration._ class PoWMiningCoordinatorSpec extends ScalaTestWithActorTestKit with AnyFreeSpecLike with Matchers { @@ -190,7 +197,7 @@ class PoWMiningCoordinatorSpec extends ScalaTestWithActorTestKit with AnyFreeSpe ommersPool = ommersPool.ref ) - val coordinator = testKit.spawn( + val coordinator: typed.ActorRef[CoordinatorProtocol] = testKit.spawn( PoWMiningCoordinator( sync.ref, ethMiningService, @@ -206,14 +213,14 @@ class PoWMiningCoordinatorSpec extends ScalaTestWithActorTestKit with AnyFreeSpe .returns(Task.now(Right(SubmitHashRateResponse(true)))) .atLeastOnce() - ommersPool.setAutoPilot((sender: ActorRef, _: Any) => { + ommersPool.setAutoPilot { (sender: ActorRef, _: Any) => sender ! OmmersPool.Ommers(Nil) TestActor.KeepRunning - }) + } - pendingTransactionsManager.setAutoPilot((sender: ActorRef, _: Any) => { + pendingTransactionsManager.setAutoPilot { (sender: ActorRef, _: Any) => sender ! PendingTransactionsManager.PendingTransactionsResponse(Nil) TestActor.KeepRunning - }) + } } } diff --git a/src/test/scala/io/iohk/ethereum/consensus/pow/RestrictedEthashSignerSpec.scala b/src/test/scala/io/iohk/ethereum/consensus/pow/RestrictedEthashSignerSpec.scala index 0ac85076aa..2f1ee9a4d9 100644 --- a/src/test/scala/io/iohk/ethereum/consensus/pow/RestrictedEthashSignerSpec.scala +++ b/src/test/scala/io/iohk/ethereum/consensus/pow/RestrictedEthashSignerSpec.scala @@ -1,11 +1,13 @@ package io.iohk.ethereum.consensus.pow -import io.iohk.ethereum.{ObjectGenerators, crypto} -import io.iohk.ethereum.security.SecureRandomBuilder import org.scalatest.flatspec.AnyFlatSpec import org.scalatest.matchers.should.Matchers import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks +import io.iohk.ethereum.ObjectGenerators +import io.iohk.ethereum.crypto +import io.iohk.ethereum.security.SecureRandomBuilder + class RestrictedEthashSignerSpec extends AnyFlatSpec with Matchers diff --git a/src/test/scala/io/iohk/ethereum/consensus/pow/miners/EthashMinerSpec.scala b/src/test/scala/io/iohk/ethereum/consensus/pow/miners/EthashMinerSpec.scala index 2dfae80521..572d7425ff 100644 --- a/src/test/scala/io/iohk/ethereum/consensus/pow/miners/EthashMinerSpec.scala +++ b/src/test/scala/io/iohk/ethereum/consensus/pow/miners/EthashMinerSpec.scala @@ -1,21 +1,26 @@ package io.iohk.ethereum.consensus.pow.miners -import io.iohk.ethereum.consensus.pow.PoWMiningCoordinator.{MiningSuccessful, MiningUnsuccessful} -import io.iohk.ethereum.consensus.pow.validators.PoWBlockHeaderValidator -import io.iohk.ethereum.consensus.pow.{EthashUtils, MinerSpecSetup, PoWBlockCreator} -import io.iohk.ethereum.consensus.validators.BlockHeaderValid -import io.iohk.ethereum.domain._ -import io.iohk.ethereum.{Fixtures, MiningPatience} +import scala.concurrent.duration._ + import org.bouncycastle.util.encoders.Hex import org.scalatest.Tag import org.scalatest.concurrent.Eventually import org.scalatest.flatspec.AnyFlatSpec import org.scalatest.matchers.should.Matchers -import scala.concurrent.duration._ +import io.iohk.ethereum.Fixtures +import io.iohk.ethereum.MiningPatience +import io.iohk.ethereum.consensus.pow.EthashUtils +import io.iohk.ethereum.consensus.pow.MinerSpecSetup +import io.iohk.ethereum.consensus.pow.PoWBlockCreator +import io.iohk.ethereum.consensus.pow.PoWMiningCoordinator.MiningSuccessful +import io.iohk.ethereum.consensus.pow.PoWMiningCoordinator.MiningUnsuccessful +import io.iohk.ethereum.consensus.pow.validators.PoWBlockHeaderValidator +import io.iohk.ethereum.consensus.validators.BlockHeaderValid +import io.iohk.ethereum.domain._ class EthashMinerSpec extends AnyFlatSpec with Matchers { - final val PoWMinerSpecTag = Tag("EthashMinerSpec") + final val PoWMinerSpecTag: Tag = Tag("EthashMinerSpec") "EthashMiner actor" should "mine valid blocks" taggedAs PoWMinerSpecTag in new TestSetup { val parentBlock: Block = origin @@ -82,16 +87,15 @@ class EthashMinerSpec extends AnyFlatSpec with Matchers { checkAssertions(minedBlock, parentBlock) } - def startMining(parentBlock: Block): Block = { + def startMining(parentBlock: Block): Block = eventually { miner.processMining(parentBlock).map { - case MiningSuccessful => true + case MiningSuccessful => true case MiningUnsuccessful => startMining(parentBlock) } val minedBlock = waitForMinedBlock minedBlock } - } private def checkAssertions(minedBlock: Block, parentBlock: Block): Unit = { minedBlock.body.transactionList shouldBe Seq(txToMine) diff --git a/src/test/scala/io/iohk/ethereum/consensus/pow/miners/KeccakMinerSpec.scala b/src/test/scala/io/iohk/ethereum/consensus/pow/miners/KeccakMinerSpec.scala index 8ec589eef7..3a6ffaccfd 100644 --- a/src/test/scala/io/iohk/ethereum/consensus/pow/miners/KeccakMinerSpec.scala +++ b/src/test/scala/io/iohk/ethereum/consensus/pow/miners/KeccakMinerSpec.scala @@ -1,18 +1,26 @@ package io.iohk.ethereum.consensus.pow.miners import akka.actor.testkit.typed.scaladsl.ScalaTestWithActorTestKit + +import scala.concurrent.duration.Duration +import scala.concurrent.duration.FiniteDuration +import scala.concurrent.duration._ + +import org.scalatest.flatspec.AnyFlatSpec +import org.scalatest.matchers.should.Matchers + import io.iohk.ethereum.Timeouts -import io.iohk.ethereum.consensus.pow.PoWMiningCoordinator.{MiningSuccessful, MiningUnsuccessful} +import io.iohk.ethereum.consensus.pow.EthashUtils +import io.iohk.ethereum.consensus.pow.MinerSpecSetup +import io.iohk.ethereum.consensus.pow.PoWBlockCreator +import io.iohk.ethereum.consensus.pow.PoWMiningCoordinator.MiningSuccessful +import io.iohk.ethereum.consensus.pow.PoWMiningCoordinator.MiningUnsuccessful import io.iohk.ethereum.consensus.pow.validators.PoWBlockHeaderValidator -import io.iohk.ethereum.consensus.pow.{EthashUtils, MinerSpecSetup, PoWBlockCreator} import io.iohk.ethereum.consensus.validators.BlockHeaderValid import io.iohk.ethereum.domain.Block import io.iohk.ethereum.jsonrpc.EthInfoService +import io.iohk.ethereum.utils.BlockchainConfig import io.iohk.ethereum.utils.Config -import org.scalatest.flatspec.AnyFlatSpec -import org.scalatest.matchers.should.Matchers - -import scala.concurrent.duration.{Duration, FiniteDuration, _} class KeccakMinerSpec extends AnyFlatSpec with Matchers { "KeccakMiner actor" should "mine valid blocks" in new TestSetup { @@ -43,9 +51,9 @@ class KeccakMinerSpec extends AnyFlatSpec with Matchers { } trait TestSetup extends ScalaTestWithActorTestKit with MinerSpecSetup { - private implicit val durationTimeout: Duration = Timeouts.miningTimeout + implicit private val durationTimeout: Duration = Timeouts.miningTimeout - override lazy val blockchainConfig = Config.blockchains.blockchainConfig + override lazy val blockchainConfig: BlockchainConfig = Config.blockchains.blockchainConfig .withUpdatedForkBlocks(_.copy(ecip1049BlockNumber = Some(0))) val powBlockHeaderValidator = new PoWBlockHeaderValidator(blockchainConfig) @@ -67,16 +75,15 @@ class KeccakMinerSpec extends AnyFlatSpec with Matchers { checkAssertions(minedBlock, parentBlock) } - def startMining(parentBlock: Block): Block = { + def startMining(parentBlock: Block): Block = eventually { miner.processMining(parentBlock).map { - case MiningSuccessful => true + case MiningSuccessful => true case MiningUnsuccessful => startMining(parentBlock) } val minedBlock = waitForMinedBlock minedBlock } - } private def checkAssertions(minedBlock: Block, parentBlock: Block): Unit = { minedBlock.body.transactionList shouldBe Seq(txToMine) diff --git a/src/test/scala/io/iohk/ethereum/consensus/pow/miners/MockedMinerSpec.scala b/src/test/scala/io/iohk/ethereum/consensus/pow/miners/MockedMinerSpec.scala index 780e1cc0fe..6439f9b081 100644 --- a/src/test/scala/io/iohk/ethereum/consensus/pow/miners/MockedMinerSpec.scala +++ b/src/test/scala/io/iohk/ethereum/consensus/pow/miners/MockedMinerSpec.scala @@ -1,20 +1,25 @@ package io.iohk.ethereum.consensus.pow.miners import akka.actor.{ActorSystem => ClassicSystem} -import akka.testkit.{TestActorRef, TestKit} +import akka.testkit.TestActorRef +import akka.testkit.TestKit + +import monix.eval.Task + +import scala.concurrent.duration._ + +import org.scalatest._ +import org.scalatest.matchers.should.Matchers +import org.scalatest.wordspec.AnyWordSpecLike + import io.iohk.ethereum.WithActorSystemShutDown import io.iohk.ethereum.consensus.pow.MinerSpecSetup import io.iohk.ethereum.consensus.pow.miners.MockedMiner.MineBlocks import io.iohk.ethereum.consensus.pow.miners.MockedMiner.MockedMinerResponses._ -import io.iohk.ethereum.domain.{Block, SignedTransaction} +import io.iohk.ethereum.domain.Block +import io.iohk.ethereum.domain.SignedTransaction import io.iohk.ethereum.ledger.InMemoryWorldStateProxy import io.iohk.ethereum.utils.ByteStringUtils -import monix.eval.Task -import org.scalatest._ -import org.scalatest.matchers.should.Matchers -import org.scalatest.wordspec.AnyWordSpecLike - -import scala.concurrent.duration._ class MockedMinerSpec extends TestKit(ClassicSystem("MockedPowMinerSpec_System")) @@ -22,7 +27,7 @@ class MockedMinerSpec with Matchers with WithActorSystemShutDown { - private implicit val timeout: Duration = 1.minute + implicit private val timeout: Duration = 1.minute "MockedPowMiner actor" should { "not mine blocks" when { @@ -212,9 +217,9 @@ class MockedMinerSpec } class TestSetup(implicit system: ClassicSystem) extends MinerSpecSetup { - val noMessageTimeOut = 3.seconds + val noMessageTimeOut: FiniteDuration = 3.seconds - val miner = TestActorRef( + val miner: TestActorRef[Nothing] = TestActorRef( MockedMiner.props( blockchain, blockchainReader, @@ -231,14 +236,13 @@ class MockedMinerSpec block.header.parentHash shouldBe parent.hash } - protected def withStartedMiner(behaviour: => Unit) = { + protected def withStartedMiner(behaviour: => Unit): Unit = { miner ! MinerProtocol.StartMining behaviour miner ! MinerProtocol.StopMining } - protected def sendToMiner(msg: MinerProtocol) = { + protected def sendToMiner(msg: MinerProtocol): Unit = miner.tell(msg, parentActor.ref) - } } } diff --git a/src/test/scala/io/iohk/ethereum/consensus/pow/validators/EthashBlockHeaderValidatorSpec.scala b/src/test/scala/io/iohk/ethereum/consensus/pow/validators/EthashBlockHeaderValidatorSpec.scala index 437fc67e86..39fb70d14a 100644 --- a/src/test/scala/io/iohk/ethereum/consensus/pow/validators/EthashBlockHeaderValidatorSpec.scala +++ b/src/test/scala/io/iohk/ethereum/consensus/pow/validators/EthashBlockHeaderValidatorSpec.scala @@ -1,16 +1,7 @@ package io.iohk.ethereum.consensus.pow.validators import akka.util.ByteString -import io.iohk.ethereum.blockchain.sync.EphemBlockchainTestSetup -import io.iohk.ethereum.consensus.difficulty.DifficultyCalculator -import io.iohk.ethereum.consensus.pow.difficulty.EthashDifficultyCalculator -import io.iohk.ethereum.consensus.validators.BlockHeaderError._ -import io.iohk.ethereum.consensus.validators.BlockHeaderValidator._ -import io.iohk.ethereum.consensus.validators.{BlockHeaderError, BlockHeaderValid, BlockHeaderValidatorSkeleton} -import io.iohk.ethereum.domain.BlockHeader.HeaderExtraFields._ -import io.iohk.ethereum.domain.{UInt256, _} -import io.iohk.ethereum.utils.{BlockchainConfig, DaoForkConfig, ForkBlockNumbers} -import io.iohk.ethereum.{Fixtures, ObjectGenerators, SuperSlow} + import org.bouncycastle.util.encoders.Hex import org.scalamock.scalatest.MockFactory import org.scalatest.flatspec.AnyFlatSpec @@ -18,6 +9,24 @@ import org.scalatest.matchers.should.Matchers import org.scalatest.prop.TableFor4 import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks +import io.iohk.ethereum.Fixtures +import io.iohk.ethereum.ObjectGenerators +import io.iohk.ethereum.SuperSlow +import io.iohk.ethereum.blockchain.sync.EphemBlockchainTestSetup +import io.iohk.ethereum.consensus.difficulty.DifficultyCalculator +import io.iohk.ethereum.consensus.pow.difficulty.EthashDifficultyCalculator +import io.iohk.ethereum.consensus.validators.BlockHeaderError +import io.iohk.ethereum.consensus.validators.BlockHeaderError._ +import io.iohk.ethereum.consensus.validators.BlockHeaderValid +import io.iohk.ethereum.consensus.validators.BlockHeaderValidator._ +import io.iohk.ethereum.consensus.validators.BlockHeaderValidatorSkeleton +import io.iohk.ethereum.domain.BlockHeader.HeaderExtraFields._ +import io.iohk.ethereum.domain.UInt256 +import io.iohk.ethereum.domain._ +import io.iohk.ethereum.utils.BlockchainConfig +import io.iohk.ethereum.utils.DaoForkConfig +import io.iohk.ethereum.utils.ForkBlockNumbers + // scalastyle:off magic.number class EthashBlockHeaderValidatorSpec extends AnyFlatSpec @@ -37,7 +46,7 @@ class EthashBlockHeaderValidatorSpec "BlockHeaderValidator" should "validate correctly formed BlockHeaders" in { powBlockHeaderValidator.validate(validBlockHeader, validParent.header) match { case Right(_) => succeed - case _ => fail() + case _ => fail() } } @@ -74,9 +83,9 @@ class EthashBlockHeaderValidatorSpec forAll(cases) { (blockHeader, parentBlock, supportsDaoFork, valid) => val blockHeaderValidator = new PoWBlockHeaderValidator(createBlockchainConfig(supportsDaoFork)) blockHeaderValidator.validate(blockHeader, parentBlock.header) match { - case Right(_) => assert(valid) + case Right(_) => assert(valid) case Left(DaoHeaderExtraDataError) => assert(!valid) - case _ => fail() + case _ => fail() } } } @@ -87,8 +96,8 @@ class EthashBlockHeaderValidatorSpec val validateResult = powBlockHeaderValidator.validate(blockHeader, validParent.header) timestamp match { case t if t <= validParentBlockHeader.unixTimestamp => assert(validateResult == Left(HeaderTimestampError)) - case validBlockHeader.unixTimestamp => assert(validateResult == Right(BlockHeaderValid)) - case _ => assert(validateResult == Left(HeaderDifficultyError)) + case validBlockHeader.unixTimestamp => assert(validateResult == Right(BlockHeaderValid)) + case _ => assert(validateResult == Left(HeaderDifficultyError)) } } } @@ -170,14 +179,14 @@ class EthashBlockHeaderValidatorSpec .commit() powBlockHeaderValidator.validate(validBlockHeader, blockchainReader.getBlockHeaderByHash _) match { case Right(_) => succeed - case _ => fail() + case _ => fail() } } it should "return a failure if the parent's header is not in storage" in new EphemBlockchainTestSetup { powBlockHeaderValidator.validate(validBlockHeader, blockchainReader.getBlockHeaderByHash _) match { case Left(HeaderParentNotFoundError) => succeed - case _ => fail() + case _ => fail() } } @@ -245,7 +254,7 @@ class EthashBlockHeaderValidatorSpec * extraDifficulty = 134217728 * difficultyWithoutBomb = 3480699544328087 + 1699560324378,95 * 0,33 = 3481260399235132 */ - val blockDifficultyAfterRewardReduction = BigInt("3484099629090779") + BigInt("3484099629090779") difficulty shouldBe afterRewardReductionBlockHeader.difficulty } @@ -261,7 +270,7 @@ class EthashBlockHeaderValidatorSpec val parentBody: BlockBody = BlockBody.empty - val pausedDifficultyBombBlock = BlockHeader( + val pausedDifficultyBombBlock: BlockHeader = BlockHeader( parentHash = ByteString(Hex.decode("77af90df2b60071da7f11060747b6590a3bc2f357da4addccb5eef7cb8c2b723")), ommersHash = ByteString(Hex.decode("1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347")), beneficiary = ByteString(Hex.decode("10807cacf99ac84b7b8f9b4077e3a11ee8880bf9")), @@ -279,7 +288,7 @@ class EthashBlockHeaderValidatorSpec nonce = ByteString(Hex.decode("81d6a5e8029f9446")) ) - val pausedDifficultyBombBlockParent = BlockHeader( + val pausedDifficultyBombBlockParent: BlockHeader = BlockHeader( parentHash = ByteString(Hex.decode("e6e90c1ba10df710365a2ae9f899bd787416d98f19874f4cb1a62f09c3b8277d")), ommersHash = ByteString(Hex.decode("1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347")), beneficiary = ByteString(Hex.decode("4c2b4e716883a2c3f6b980b70b577e54b9441060")), @@ -297,7 +306,7 @@ class EthashBlockHeaderValidatorSpec nonce = ByteString(Hex.decode("83e2d9b401cdfa77")) ) - val afterRewardReductionBlockHeader = BlockHeader( + val afterRewardReductionBlockHeader: BlockHeader = BlockHeader( parentHash = ByteString(Hex.decode("a5280b4589a1534946f83dba3fcec698be2046010c4d39fc0437c61837adc0f5")), ommersHash = ByteString(Hex.decode("1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347")), beneficiary = ByteString(Hex.decode("ea674fdde714fd979de3edf0f56aa9716b898ec8")), @@ -315,7 +324,7 @@ class EthashBlockHeaderValidatorSpec nonce = ByteString(Hex.decode("2cc9a5500763ce09")) ) - val afterRewardReductionParentBlockHeader = BlockHeader( + val afterRewardReductionParentBlockHeader: BlockHeader = BlockHeader( parentHash = ByteString(Hex.decode("ce5633dd4e056415c9e170b1fd934d88eec437c8a6f58014a2a1ef801a132ac5")), ommersHash = ByteString(Hex.decode("1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347")), beneficiary = ByteString(Hex.decode("b2930b35844a230f00e51431acae96fe543a0347")), @@ -333,7 +342,7 @@ class EthashBlockHeaderValidatorSpec nonce = ByteString(Hex.decode("b9fa123002b9407d")) ) - val validBlockHeader = BlockHeader( + val validBlockHeader: BlockHeader = BlockHeader( parentHash = ByteString(Hex.decode("d882d5c210bab4cb7ef0b9f3dc2130cb680959afcd9a8f9bf83ee6f13e2f9da3")), ommersHash = ByteString(Hex.decode("1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347")), beneficiary = ByteString(Hex.decode("95f484419881c6e9b6de7fb3f8ad03763bd49a89")), @@ -351,7 +360,7 @@ class EthashBlockHeaderValidatorSpec nonce = ByteString(Hex.decode("797a8f3a494f937b")) ) - val validParentBlockHeader = BlockHeader( + val validParentBlockHeader: BlockHeader = BlockHeader( parentHash = ByteString(Hex.decode("677a5fb51d52321b03552e3c667f602cc489d15fc1d7824445aee6d94a9db2e7")), ommersHash = ByteString(Hex.decode("1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347")), beneficiary = ByteString(Hex.decode("95f484419881c6e9b6de7fb3f8ad03763bd49a89")), @@ -369,8 +378,8 @@ class EthashBlockHeaderValidatorSpec nonce = ByteString(Hex.decode("3fc7bc671f7cee70")) ) - val validParentBlockBody = BlockBody(Seq.empty, Seq.empty) - val validParent = Block(validParentBlockHeader, validParentBlockBody) + val validParentBlockBody: BlockBody = BlockBody(Seq.empty, Seq.empty) + val validParent: Block = Block(validParentBlockHeader, validParentBlockBody) def createBlockchainConfig(supportsDaoFork: Boolean = false): BlockchainConfig = { import Fixtures.Blocks._ @@ -424,7 +433,7 @@ class EthashBlockHeaderValidatorSpec ) } - val ProDaoBlock1920008Header = BlockHeader( + val ProDaoBlock1920008Header: BlockHeader = BlockHeader( parentHash = ByteString(Hex.decode("05c45c9671ee31736b9f37ee98faa72c89e314059ecff3257206e6ab498eb9d1")), ommersHash = ByteString(Hex.decode("1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347")), beneficiary = ByteString(Hex.decode("2a65aca4d5fc5b5c859090a6c34d164135398226")), @@ -442,7 +451,7 @@ class EthashBlockHeaderValidatorSpec nonce = ByteString(Hex.decode("c207c8381305bef2")) ) - val ProDaoBlock1920009Header = BlockHeader( + val ProDaoBlock1920009Header: BlockHeader = BlockHeader( parentHash = ByteString(Hex.decode("41254723e12eb736ddef151371e4c3d614233e6cad95f2d9017de2ab8b469a18")), ommersHash = ByteString(Hex.decode("808d06176049aecfd504197dde49f46c3dd75f1af055e417d100228162eefdd8")), beneficiary = ByteString(Hex.decode("ea674fdde714fd979de3edf0f56aa9716b898ec8")), @@ -464,7 +473,7 @@ class EthashBlockHeaderValidatorSpec nonce = ByteString(Hex.decode("2b4b464c0a4da82a")) ) - val ProDaoBlock1920010Header = BlockHeader( + val ProDaoBlock1920010Header: BlockHeader = BlockHeader( parentHash = ByteString(Hex.decode("69d04aec94ad69d7d190d3b51d24cd42dded0c4767598a1d30480363509acbef")), ommersHash = ByteString(Hex.decode("1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347")), beneficiary = ByteString(Hex.decode("4bb96091ee9d802ed039c4d1a5f6216f90f81b01")), diff --git a/src/test/scala/io/iohk/ethereum/consensus/pow/validators/KeccakBlockHeaderValidatorSpec.scala b/src/test/scala/io/iohk/ethereum/consensus/pow/validators/KeccakBlockHeaderValidatorSpec.scala index d78aba2575..fe10183b5b 100644 --- a/src/test/scala/io/iohk/ethereum/consensus/pow/validators/KeccakBlockHeaderValidatorSpec.scala +++ b/src/test/scala/io/iohk/ethereum/consensus/pow/validators/KeccakBlockHeaderValidatorSpec.scala @@ -1,13 +1,16 @@ package io.iohk.ethereum.consensus.pow.validators import akka.util.ByteString -import io.iohk.ethereum.consensus.pow.KeccakDataUtils -import io.iohk.ethereum.consensus.validators.BlockHeaderError.HeaderPoWError -import io.iohk.ethereum.consensus.validators.BlockHeaderValid + import org.bouncycastle.util.encoders.Hex import org.scalatest.flatspec.AnyFlatSpecLike import org.scalatest.matchers.should.Matchers +import io.iohk.ethereum.consensus.pow.KeccakDataUtils +import io.iohk.ethereum.consensus.validators.BlockHeaderError.HeaderPoWError +import io.iohk.ethereum.consensus.validators.BlockHeaderValid +import io.iohk.ethereum.domain.BlockHeader + class KeccakBlockHeaderValidatorSpec extends AnyFlatSpecLike with Matchers { import KeccakBlockHeaderValidatorSpec._ @@ -24,7 +27,7 @@ class KeccakBlockHeaderValidatorSpec extends AnyFlatSpecLike with Matchers { object KeccakBlockHeaderValidatorSpec { import KeccakDataUtils._ - val validBlockHeader = header.copy( + val validBlockHeader: BlockHeader = header.copy( mixHash = ByteString(Hex.decode("d033f82e170ff16640e902fad569243c39bce9e4da948ccc298c541b34cd263b")), nonce = ByteString(Hex.decode("f245822d3412da7f")) ) diff --git a/src/test/scala/io/iohk/ethereum/consensus/pow/validators/PoWBlockHeaderValidatorSpec.scala b/src/test/scala/io/iohk/ethereum/consensus/pow/validators/PoWBlockHeaderValidatorSpec.scala index 0b33833596..ef4583e3cd 100644 --- a/src/test/scala/io/iohk/ethereum/consensus/pow/validators/PoWBlockHeaderValidatorSpec.scala +++ b/src/test/scala/io/iohk/ethereum/consensus/pow/validators/PoWBlockHeaderValidatorSpec.scala @@ -1,15 +1,16 @@ package io.iohk.ethereum.consensus.pow.validators import akka.util.ByteString + +import org.bouncycastle.util.encoders.Hex +import org.scalatest.flatspec.AnyFlatSpecLike +import org.scalatest.matchers.should.Matchers + import io.iohk.ethereum.consensus.pow.KeccakDataUtils -import io.iohk.ethereum.consensus.pow.KeccakDataUtils.header import io.iohk.ethereum.consensus.validators.BlockHeaderError.HeaderPoWError import io.iohk.ethereum.consensus.validators.BlockHeaderValid import io.iohk.ethereum.domain.BlockHeader import io.iohk.ethereum.utils.Config -import org.bouncycastle.util.encoders.Hex -import org.scalatest.flatspec.AnyFlatSpecLike -import org.scalatest.matchers.should.Matchers class PoWBlockHeaderValidatorSpec extends AnyFlatSpecLike with Matchers { import PoWBlockHeaderValidatorSpec._ @@ -37,12 +38,12 @@ class PoWBlockHeaderValidatorSpec extends AnyFlatSpecLike with Matchers { object PoWBlockHeaderValidatorSpec { val blockchainConfig = Config.blockchains.blockchainConfig - val validKeccakBlockHeader = KeccakDataUtils.header.copy( + val validKeccakBlockHeader: BlockHeader = KeccakDataUtils.header.copy( mixHash = ByteString(Hex.decode("d033f82e170ff16640e902fad569243c39bce9e4da948ccc298c541b34cd263b")), nonce = ByteString(Hex.decode("f245822d3412da7f")) ) - val validEthashBlockHeader = BlockHeader( + val validEthashBlockHeader: BlockHeader = BlockHeader( parentHash = ByteString(Hex.decode("d882d5c210bab4cb7ef0b9f3dc2130cb680959afcd9a8f9bf83ee6f13e2f9da3")), ommersHash = ByteString(Hex.decode("1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347")), beneficiary = ByteString(Hex.decode("95f484419881c6e9b6de7fb3f8ad03763bd49a89")), diff --git a/src/test/scala/io/iohk/ethereum/consensus/pow/validators/RestrictedEthashBlockHeaderValidatorSpec.scala b/src/test/scala/io/iohk/ethereum/consensus/pow/validators/RestrictedEthashBlockHeaderValidatorSpec.scala index 54352c140d..e83af60fe2 100644 --- a/src/test/scala/io/iohk/ethereum/consensus/pow/validators/RestrictedEthashBlockHeaderValidatorSpec.scala +++ b/src/test/scala/io/iohk/ethereum/consensus/pow/validators/RestrictedEthashBlockHeaderValidatorSpec.scala @@ -1,17 +1,24 @@ package io.iohk.ethereum.consensus.pow.validators import akka.util.ByteString + +import org.scalatest.flatspec.AnyFlatSpec +import org.scalatest.matchers.should.Matchers +import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks + import io.iohk.ethereum.consensus.pow.RestrictedPoWSigner -import io.iohk.ethereum.consensus.validators.BlockHeaderError.{HeaderPoWError, RestrictedPoWHeaderExtraDataError} +import io.iohk.ethereum.consensus.validators.BlockHeaderError.HeaderPoWError +import io.iohk.ethereum.consensus.validators.BlockHeaderError.RestrictedPoWHeaderExtraDataError import io.iohk.ethereum.consensus.validators.BlockHeaderValid import io.iohk.ethereum.crypto import io.iohk.ethereum.crypto.ECDSASignature -import io.iohk.ethereum.domain.{Address, BlockHeader, UInt256} +import io.iohk.ethereum.domain.Address +import io.iohk.ethereum.domain.BlockHeader +import io.iohk.ethereum.domain.UInt256 import io.iohk.ethereum.security.SecureRandomBuilder -import io.iohk.ethereum.utils.{BlockchainConfig, ByteStringUtils, ForkBlockNumbers} -import org.scalatest.flatspec.AnyFlatSpec -import org.scalatest.matchers.should.Matchers -import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks +import io.iohk.ethereum.utils.BlockchainConfig +import io.iohk.ethereum.utils.ByteStringUtils +import io.iohk.ethereum.utils.ForkBlockNumbers class RestrictedEthashBlockHeaderValidatorSpec extends AnyFlatSpec @@ -63,10 +70,10 @@ class RestrictedEthashBlockHeaderValidatorSpec } trait TestSetup { - val validKey = ByteStringUtils.string2hash( + val validKey: ByteString = ByteStringUtils.string2hash( "69f6b54223c0d699c91f1f649e11dc52cb05910896b80c50137cd74a54d90782b69128d3ad5a9ba8c26e338891e33a46e317a3eeaabbf62e70a6b33ec57e00e6" ) - def createBlockchainConfig(allowedMiners: Set[ByteString]): BlockchainConfig = { + def createBlockchainConfig(allowedMiners: Set[ByteString]): BlockchainConfig = BlockchainConfig( forkBlockNumbers = ForkBlockNumbers( frontierBlockNumber = 0, @@ -107,13 +114,11 @@ class RestrictedEthashBlockHeaderValidatorSpec checkpointPubKeys = Set.empty, allowedMinersPublicKeys = allowedMiners ) - } - /** - * validParent and validHeader are special headers with extended extraData field and are only useful when used + /** validParent and validHeader are special headers with extended extraData field and are only useful when used * with RestrictedEthashBlockHeaderValidator */ - val validParent = BlockHeader( + val validParent: BlockHeader = BlockHeader( parentHash = ByteStringUtils.string2hash("c12a822d0c9a1a777cd1023172ec304aca76e403355e4eb56592d299e4b86503"), ommersHash = ByteStringUtils.string2hash("1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347"), beneficiary = ByteStringUtils.string2hash("0011223344556677889900112233445566778899"), @@ -134,7 +139,7 @@ class RestrictedEthashBlockHeaderValidatorSpec nonce = ByteStringUtils.string2hash("a57246871d5c8bcc") ) - val validHeader = BlockHeader( + val validHeader: BlockHeader = BlockHeader( parentHash = ByteStringUtils.string2hash("28aad5edd02d139bf4fcf15d04ec04c93f12e382c64983fa271a9084189b3b23"), ommersHash = ByteStringUtils.string2hash("1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347"), beneficiary = ByteStringUtils.string2hash("0011223344556677889900112233445566778899"), diff --git a/src/test/scala/io/iohk/ethereum/consensus/pow/validators/StdOmmersValidatorSpec.scala b/src/test/scala/io/iohk/ethereum/consensus/pow/validators/StdOmmersValidatorSpec.scala index 25047bc831..5b395e9e5b 100644 --- a/src/test/scala/io/iohk/ethereum/consensus/pow/validators/StdOmmersValidatorSpec.scala +++ b/src/test/scala/io/iohk/ethereum/consensus/pow/validators/StdOmmersValidatorSpec.scala @@ -1,20 +1,24 @@ package io.iohk.ethereum.consensus.pow.validators import akka.util.ByteString -import io.iohk.ethereum.ObjectGenerators -import io.iohk.ethereum.blockchain.sync.EphemBlockchainTestSetup -import io.iohk.ethereum.consensus.pow.validators.OmmersValidator.OmmersError._ -import io.iohk.ethereum.domain.{Block, BlockBody, BlockHeader} + import org.bouncycastle.util.encoders.Hex import org.scalatest.flatspec.AnyFlatSpec import org.scalatest.matchers.should.Matchers import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks +import io.iohk.ethereum.ObjectGenerators +import io.iohk.ethereum.blockchain.sync.EphemBlockchainTestSetup +import io.iohk.ethereum.consensus.pow.validators.OmmersValidator.OmmersError._ +import io.iohk.ethereum.domain.Block +import io.iohk.ethereum.domain.BlockBody +import io.iohk.ethereum.domain.BlockHeader + class StdOmmersValidatorSpec extends AnyFlatSpec with Matchers with ScalaCheckPropertyChecks with ObjectGenerators { it should "validate correctly a valid list of ommers" in new BlockUtils { ommersValidator.validate(ommersBlockParentHash, ommersBlockNumber, ommers, blockchainReader) match { - case Right(_) => succeed + case Right(_) => succeed case Left(err) => fail(s"Unexpected validation error: $err") } } @@ -27,8 +31,8 @@ class StdOmmersValidatorSpec extends AnyFlatSpec with Matchers with ScalaCheckPr blockchainReader ) match { case Left(OmmersLengthError) => succeed - case Left(err) => fail(s"Unexpected validation error: $err") - case Right(_) => fail("Unexpected validation success") + case Left(err) => fail(s"Unexpected validation error: $err") + case Right(_) => fail("Unexpected validation success") } } @@ -42,8 +46,8 @@ class StdOmmersValidatorSpec extends AnyFlatSpec with Matchers with ScalaCheckPr blockchainReader ) match { case Left(OmmersHeaderError(List(_))) => succeed - case Left(err) => fail(s"Unexpected validation error: $err") - case Right(_) => fail("Unexpected validation success") + case Left(err) => fail(s"Unexpected validation error: $err") + case Right(_) => fail("Unexpected validation success") } } @@ -55,8 +59,8 @@ class StdOmmersValidatorSpec extends AnyFlatSpec with Matchers with ScalaCheckPr blockchainReader ) match { case Left(OmmersUsedBeforeError) => succeed - case Left(err) => fail(s"Unexpected validation error: $err") - case Right(_) => fail("Unexpected validation success") + case Left(err) => fail(s"Unexpected validation error: $err") + case Right(_) => fail("Unexpected validation success") } } @@ -68,8 +72,8 @@ class StdOmmersValidatorSpec extends AnyFlatSpec with Matchers with ScalaCheckPr blockchainReader ) match { case Left(OmmerIsAncestorError) => succeed - case Left(err) => fail(s"Unexpected validation error: $err") - case Right(_) => fail("Unexpected validation success") + case Left(err) => fail(s"Unexpected validation error: $err") + case Right(_) => fail("Unexpected validation success") } } @@ -84,7 +88,7 @@ class StdOmmersValidatorSpec extends AnyFlatSpec with Matchers with ScalaCheckPr getNBlocksBack ) match { case Left(OmmerParentIsNotAncestorError) => succeed - case err => fail(err.toString) + case err => fail(err.toString) } } @@ -98,7 +102,7 @@ class StdOmmersValidatorSpec extends AnyFlatSpec with Matchers with ScalaCheckPr getNBlocksBack ) match { case Left(OmmerParentIsNotAncestorError) => succeed - case err => fail(err.toString) + case err => fail(err.toString) } } @@ -110,7 +114,7 @@ class StdOmmersValidatorSpec extends AnyFlatSpec with Matchers with ScalaCheckPr blockchainReader ) match { case Left(OmmerParentIsNotAncestorError) => succeed - case err => fail(err.toString) + case err => fail(err.toString) } } @@ -122,8 +126,8 @@ class StdOmmersValidatorSpec extends AnyFlatSpec with Matchers with ScalaCheckPr blockchainReader ) match { case Left(OmmersDuplicatedError) => succeed - case Left(err) => fail(s"Unexpected validation error: $err") - case Right(_) => fail("Unexpected validation success") + case Left(err) => fail(s"Unexpected validation error: $err") + case Right(_) => fail("Unexpected validation success") } } @@ -132,7 +136,7 @@ class StdOmmersValidatorSpec extends AnyFlatSpec with Matchers with ScalaCheckPr val ommersValidator = new StdOmmersValidator(new PoWBlockHeaderValidator(blockchainConfig)) - val ommerInvalidBranch = BlockHeader( + val ommerInvalidBranch: BlockHeader = BlockHeader( parentHash = ByteString(Hex.decode("fd07e36cfaf327801e5696134b12345f6a89fb1e8f017f2411a29d0ae810ab8b")), ommersHash = ByteString(Hex.decode("7766c4251396a6833ccbe4be86fbda3a200dccbe6a15d80ae3de5378b1540e04")), beneficiary = ByteString(Hex.decode("28921e4e2c9d84f4c0f0c0ceb991f45751a0fe93")), @@ -155,7 +159,7 @@ class StdOmmersValidatorSpec extends AnyFlatSpec with Matchers with ScalaCheckPr ) //Ommers from block 0xe9fb121a7ee5cb03b33adbf59e95321a2453f09db98068e1f31f0da79860c50c (of number 97) - val ommer1 = BlockHeader( + val ommer1: BlockHeader = BlockHeader( parentHash = ByteString(Hex.decode("fd07e36cfaf327801e5696134b36678f6a89fb1e8f017f2411a29d0ae810ab8b")), ommersHash = ByteString(Hex.decode("7766c4251396a6833ccbe4be86fbda3a200dccbe6a15d80ae3de5378b1540e04")), beneficiary = ByteString(Hex.decode("1b7047b4338acf65be94c1a3e8c5c9338ad7d67c")), @@ -176,7 +180,7 @@ class StdOmmersValidatorSpec extends AnyFlatSpec with Matchers with ScalaCheckPr mixHash = ByteString(Hex.decode("c6d695926546d3d679199303a6d1fc983fe3f09f44396619a24c4271830a7b95")), nonce = ByteString(Hex.decode("62bc3dca012c1b27")) ) - val ommer2 = BlockHeader( + val ommer2: BlockHeader = BlockHeader( parentHash = ByteString(Hex.decode("fd07e36cfaf327801e5696134b36678f6a89fb1e8f017f2411a29d0ae810ab8b")), ommersHash = ByteString(Hex.decode("7766c4251396a6833ccbe4be86fbda3a200dccbe6a15d80ae3de5378b1540e04")), beneficiary = ByteString(Hex.decode("28921e4e2c9d84f4c0f0c0ceb991f45751a0fe93")), @@ -200,7 +204,7 @@ class StdOmmersValidatorSpec extends AnyFlatSpec with Matchers with ScalaCheckPr val ommers: Seq[BlockHeader] = Seq[BlockHeader](ommer1, ommer2) val ommersBlockNumber: BigInt = 97 - val block90 = Block( + val block90: Block = Block( BlockHeader( parentHash = ByteString(Hex.decode("6da5970538eba5db93162e219182fca7e093cfe4fbd8dd0b82789adb25dcbb42")), ommersHash = ByteString(Hex.decode("1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347")), @@ -224,7 +228,7 @@ class StdOmmersValidatorSpec extends AnyFlatSpec with Matchers with ScalaCheckPr ), BlockBody(Seq.empty, Seq.empty) ) - val block91 = Block( + val block91: Block = Block( BlockHeader( parentHash = ByteString(Hex.decode("69d2798993659c0d864d6f2824440b091368c147efc6c33410ef181036fc2bf1")), ommersHash = ByteString(Hex.decode("1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347")), @@ -248,7 +252,7 @@ class StdOmmersValidatorSpec extends AnyFlatSpec with Matchers with ScalaCheckPr ), BlockBody(Seq.empty, Seq.empty) ) - val block92 = Block( + val block92: Block = Block( BlockHeader( parentHash = ByteString(Hex.decode("d691ed6cf02375620d9cca9052bcf38a4a23f5c77058581c8bb54a06e2eb6ed9")), ommersHash = ByteString(Hex.decode("1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347")), @@ -272,7 +276,7 @@ class StdOmmersValidatorSpec extends AnyFlatSpec with Matchers with ScalaCheckPr ), BlockBody(Seq.empty, Seq.empty) ) - val block93 = Block( + val block93: Block = Block( BlockHeader( parentHash = ByteString(Hex.decode("c86dcbd8ba3cd836bd9c00d9dababe81ed5a42310ade70a77700d42b5ff8b64c")), ommersHash = ByteString(Hex.decode("445ccaa7ee03cf387e4835482288f6b08dc351eef4ecc94b3ed8de56afd298a6")), @@ -322,7 +326,7 @@ class StdOmmersValidatorSpec extends AnyFlatSpec with Matchers with ScalaCheckPr ) ) ) - val block94 = Block( + val block94: Block = Block( BlockHeader( parentHash = ByteString(Hex.decode("fd07e36cfaf327801e5696134b36678f6a89fb1e8f017f2411a29d0ae810ab8b")), ommersHash = ByteString(Hex.decode("7766c4251396a6833ccbe4be86fbda3a200dccbe6a15d80ae3de5378b1540e04")), @@ -372,7 +376,7 @@ class StdOmmersValidatorSpec extends AnyFlatSpec with Matchers with ScalaCheckPr ) ) ) - val block95 = Block( + val block95: Block = Block( BlockHeader( parentHash = ByteString(Hex.decode("665586bdd5aefc860f8ff2d186617544d5aa6e5ae7203bf54b26f310be372e91")), ommersHash = ByteString(Hex.decode("1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347")), @@ -396,7 +400,7 @@ class StdOmmersValidatorSpec extends AnyFlatSpec with Matchers with ScalaCheckPr ), BlockBody(Seq.empty, Seq.empty) ) - val block96 = Block( + val block96: Block = Block( BlockHeader( parentHash = ByteString(Hex.decode("c0f772db658b2279a736f232e75d98629a53d36086e34a18f9fe65a4650d50a7")), ommersHash = ByteString(Hex.decode("1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347")), @@ -421,7 +425,7 @@ class StdOmmersValidatorSpec extends AnyFlatSpec with Matchers with ScalaCheckPr BlockBody(Seq.empty, Seq.empty) ) - val block89 = Block( + val block89: Block = Block( BlockHeader( parentHash = ByteString(Hex.decode("ba39b4ee19e5db0f5a85c344aa2bd2e7b0cdb2404b7d5c0e6cdc08c83f85083e")), ommersHash = ByteString(Hex.decode("1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347")), diff --git a/src/test/scala/io/iohk/ethereum/consensus/validators/BlockWithCheckpointHeaderValidatorSpec.scala b/src/test/scala/io/iohk/ethereum/consensus/validators/BlockWithCheckpointHeaderValidatorSpec.scala index 5c3d17175b..d977e843e5 100644 --- a/src/test/scala/io/iohk/ethereum/consensus/validators/BlockWithCheckpointHeaderValidatorSpec.scala +++ b/src/test/scala/io/iohk/ethereum/consensus/validators/BlockWithCheckpointHeaderValidatorSpec.scala @@ -1,24 +1,32 @@ package io.iohk.ethereum.consensus.validators import akka.util.ByteString + +import org.bouncycastle.crypto.AsymmetricCipherKeyPair +import org.scalacheck.Gen +import org.scalamock.scalatest.MockFactory +import org.scalatest.Assertion +import org.scalatest.flatspec.AnyFlatSpec +import org.scalatest.matchers.should.Matchers +import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks + +import io.iohk.ethereum.Fixtures +import io.iohk.ethereum.ObjectGenerators import io.iohk.ethereum.checkpointing.CheckpointingTestHelpers import io.iohk.ethereum.consensus.blocks.CheckpointBlockGenerator import io.iohk.ethereum.consensus.difficulty.DifficultyCalculator import io.iohk.ethereum.consensus.validators.BlockHeaderError._ +import io.iohk.ethereum.crypto import io.iohk.ethereum.crypto.ECDSASignature import io.iohk.ethereum.crypto.ECDSASignatureImplicits.ECDSASignatureOrdering import io.iohk.ethereum.domain.BlockHeader.HeaderExtraFields.HefPostEcip1097 import io.iohk.ethereum.domain._ -import io.iohk.ethereum.security.SecureRandomBuilder import io.iohk.ethereum.ledger.BloomFilter import io.iohk.ethereum.nodebuilder.BlockchainConfigBuilder -import io.iohk.ethereum.utils.{BlockchainConfig, ByteStringUtils} -import io.iohk.ethereum.{Fixtures, ObjectGenerators, crypto} -import org.scalamock.scalatest.MockFactory -import org.scalatest.Assertion -import org.scalatest.flatspec.AnyFlatSpec -import org.scalatest.matchers.should.Matchers -import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks +import io.iohk.ethereum.security.SecureRandomBuilder +import io.iohk.ethereum.utils.BlockchainConfig +import io.iohk.ethereum.utils.ByteStringUtils + import ByteStringUtils.byteStringOrdering class BlockWithCheckpointHeaderValidatorSpec @@ -94,7 +102,7 @@ class BlockWithCheckpointHeaderValidatorSpec } it should "return failure if created based on invalid timestamp" in new TestSetup { - forAll(longGen suchThat (_ != validBlockParentHeader.unixTimestamp + 1)) { timestamp => + forAll(longGen.suchThat(_ != validBlockParentHeader.unixTimestamp + 1)) { timestamp => val blockHeader = validBlockHeaderWithCheckpoint.copy(unixTimestamp = timestamp) val validateResult = blockHeaderValidator.validate(blockHeader, validBlockParentHeader) assert(validateResult == Left(HeaderTimestampError)) @@ -102,7 +110,7 @@ class BlockWithCheckpointHeaderValidatorSpec } it should "return failure if difficulty is different than parent difficulty" in new TestSetup { - forAll(bigIntGen suchThat (_ != validBlockParentHeader.difficulty)) { difficulty => + forAll(bigIntGen.suchThat(_ != validBlockParentHeader.difficulty)) { difficulty => val blockHeader = validBlockHeaderWithCheckpoint.copy(difficulty = difficulty) val validateResult = blockHeaderValidator.validate(blockHeader, validBlockParentHeader) assert( @@ -112,7 +120,7 @@ class BlockWithCheckpointHeaderValidatorSpec } it should "return failure if gas used is not zero" in new TestSetup { - forAll(bigIntGen suchThat (_ != UInt256.Zero.toBigInt)) { gasUsed => + forAll(bigIntGen.suchThat(_ != UInt256.Zero.toBigInt)) { gasUsed => val blockHeader = validBlockHeaderWithCheckpoint.copy(gasUsed = gasUsed) val validateResult = blockHeaderValidator.validate(blockHeader, validBlockParentHeader) assert(validateResult == Left(HeaderGasUsedError)) @@ -120,7 +128,7 @@ class BlockWithCheckpointHeaderValidatorSpec } it should "return failure if gas limit is different than parent gas limit" in new TestSetup { - forAll(bigIntGen suchThat (_ != validBlockParentHeader.gasLimit)) { gasLimit => + forAll(bigIntGen.suchThat(_ != validBlockParentHeader.gasLimit)) { gasLimit => val blockHeader = validBlockHeaderWithCheckpoint.copy(gasLimit = gasLimit) val validateResult = blockHeaderValidator.validate(blockHeader, validBlockParentHeader) assert( @@ -131,7 +139,7 @@ class BlockWithCheckpointHeaderValidatorSpec it should "return failure if created based on invalid number" in new TestSetup { forAll( - longGen suchThat (num => + longGen.suchThat(num => num != validBlockParentHeader.number + 1 && num >= config.forkBlockNumbers.ecip1097BlockNumber ) ) { number => @@ -206,7 +214,6 @@ class BlockWithCheckpointHeaderValidatorSpec val invalidCheckpoint = Checkpoint((sameSignerSig +: validCheckpoint.signatures).sorted) // verify that we have 2 signatures from the same signer - import Ordering.Implicits._ val actualSigners = invalidCheckpoint.signatures.flatMap(_.publicKey(validBlockParent.hash)).sortBy(_.toSeq) val duplicatedSigner = ByteString(crypto.pubKeyFromKeyPair(keys.head)) val expectedSigners = (keys.map(kp => ByteString(crypto.pubKeyFromKeyPair(kp))) :+ duplicatedSigner).sorted @@ -245,7 +252,7 @@ class BlockWithCheckpointHeaderValidatorSpec val validBlockParent = Fixtures.Blocks.ValidBlock.block val validBlockParentHeader = validBlockParent.header - final val checkpointPubKeys = + final val checkpointPubKeys: Set[ByteString] = Set( // prv ee4fd3a153f6d66918d7a54e33b8fbafcb6a786551306d1248e62bef76e8fe52 ByteStringUtils.string2hash( @@ -272,7 +279,7 @@ class BlockWithCheckpointHeaderValidatorSpec checkpointPubKeys = checkpointPubKeys ) - val keys = Seq( + val keys: Seq[AsymmetricCipherKeyPair] = Seq( crypto.keyPairFromPrvKey( ByteStringUtils.string2hash("ee4fd3a153f6d66918d7a54e33b8fbafcb6a786551306d1248e62bef76e8fe52").toArray ), @@ -281,7 +288,7 @@ class BlockWithCheckpointHeaderValidatorSpec ) ) - val validCheckpoint = Checkpoint( + val validCheckpoint: Checkpoint = Checkpoint( CheckpointingTestHelpers.createCheckpointSignatures(keys, validBlockParentHeader.hash) ) @@ -294,11 +301,11 @@ class BlockWithCheckpointHeaderValidatorSpec Right(BlockHeaderValid) } - val blockHeaderValidator = blockHeaderValidatorBuilder(config) + val blockHeaderValidator: BlockHeaderValidatorSkeleton = blockHeaderValidatorBuilder(config) val checkpointBlockGenerator = new CheckpointBlockGenerator - val validBlockHeaderWithCheckpoint = + val validBlockHeaderWithCheckpoint: BlockHeader = checkpointBlockGenerator .generate( validBlockParent, @@ -306,19 +313,21 @@ class BlockWithCheckpointHeaderValidatorSpec ) .header - val randomSizeByteStringGenerator = randomSizeByteStringGen(0, 32) + val randomSizeByteStringGenerator: Gen[ByteString] = randomSizeByteStringGen(0, 32) def getBlockHeaderByHashMock(blockHeaders: Seq[BlockHeader])(hash: ByteString): Option[BlockHeader] = blockHeaders.find(_.hash == hash) - val getBlockHeaderWithParent = getBlockHeaderByHashMock(Seq(validBlockParentHeader)) _ - val getBlockHeaderWithNone = getBlockHeaderByHashMock(Nil) _ + val getBlockHeaderWithParent: ByteString => Option[BlockHeader] = getBlockHeaderByHashMock( + Seq(validBlockParentHeader) + ) _ + val getBlockHeaderWithNone: ByteString => Option[BlockHeader] = getBlockHeaderByHashMock(Nil) _ def testOfEmptyByteString( invalidBlockHeaderCreator: ByteString => BlockHeader, fieldName: String, emptyValue: ByteString = ByteString.empty - ): Assertion = { - forAll(randomSizeByteStringGenerator suchThat (_ != emptyValue)) { byteString => + ): Assertion = + forAll(randomSizeByteStringGenerator.suchThat(_ != emptyValue)) { byteString => val invalidBlockHeader = invalidBlockHeaderCreator(byteString) assert( blockHeaderValidator @@ -327,14 +336,13 @@ class BlockWithCheckpointHeaderValidatorSpec ) ) } - } def testOfTheSameValueAsParent( invalidBlockHeaderCreator: ByteString => BlockHeader, fieldName: String, filteredValue: ByteString - ): Assertion = { - forAll(randomSizeByteStringGenerator suchThat (_ != filteredValue)) { byteString => + ): Assertion = + forAll(randomSizeByteStringGenerator.suchThat(_ != filteredValue)) { byteString => val invalidBlockHeader = invalidBlockHeaderCreator(byteString) assert( blockHeaderValidator @@ -343,7 +351,6 @@ class BlockWithCheckpointHeaderValidatorSpec ) ) } - } } diff --git a/src/test/scala/io/iohk/ethereum/consensus/validators/std/StdBlockValidatorSpec.scala b/src/test/scala/io/iohk/ethereum/consensus/validators/std/StdBlockValidatorSpec.scala index 01249decbb..4434da014c 100644 --- a/src/test/scala/io/iohk/ethereum/consensus/validators/std/StdBlockValidatorSpec.scala +++ b/src/test/scala/io/iohk/ethereum/consensus/validators/std/StdBlockValidatorSpec.scala @@ -1,6 +1,12 @@ package io.iohk.ethereum.consensus.validators.std import akka.util.ByteString + +import org.bouncycastle.crypto.AsymmetricCipherKeyPair +import org.bouncycastle.util.encoders.Hex +import org.scalatest.flatspec.AnyFlatSpec +import org.scalatest.matchers.should.Matchers + import io.iohk.ethereum.checkpointing.CheckpointingTestHelpers import io.iohk.ethereum.consensus.blocks.CheckpointBlockGenerator import io.iohk.ethereum.consensus.validators.std.StdBlockValidator._ @@ -8,9 +14,6 @@ import io.iohk.ethereum.crypto import io.iohk.ethereum.domain._ import io.iohk.ethereum.ledger.BloomFilter import io.iohk.ethereum.security.SecureRandomBuilder -import org.bouncycastle.util.encoders.Hex -import org.scalatest.flatspec.AnyFlatSpec -import org.scalatest.matchers.should.Matchers class StdBlockValidatorSpec extends AnyFlatSpec with Matchers with SecureRandomBuilder { @@ -23,8 +26,8 @@ class StdBlockValidatorSpec extends AnyFlatSpec with Matchers with SecureRandomB it should "correctly handle the case where a block has no receipts" in { StdBlockValidator.validate(blockWithOutReceipts, Nil) match { - case Right(validated) => succeed - case _ => fail() + case Right(_) => succeed + case _ => fail() } } @@ -43,46 +46,46 @@ class StdBlockValidatorSpec extends AnyFlatSpec with Matchers with SecureRandomB it should "return a failure if created based on invalid transactions header" in { StdBlockValidator.validate(Block(wrongTransactionsRootHeader, validBlockBody), validReceipts) match { case Left(BlockTransactionsHashError) => succeed - case _ => fail() + case _ => fail() } } it should "return a failure if created based on invalid ommers header" in { StdBlockValidator.validate(Block(wrongOmmersHashHeader, validBlockBody), validReceipts) match { case Left(BlockOmmersHashError) => succeed - case _ => fail() + case _ => fail() } } it should "return a failure if created based on invalid receipts header" in { StdBlockValidator.validate(Block(wrongReceiptsHeader, validBlockBody), validReceipts) match { case Left(BlockReceiptsHashError) => succeed - case _ => fail() + case _ => fail() } } it should "return a failure if created based on invalid log bloom header" in { StdBlockValidator.validate(Block(wrongLogBloomBlockHeader, validBlockBody), validReceipts) match { case Left(BlockLogBloomError) => succeed - case _ => fail() + case _ => fail() } } it should "return a failure if a block body doesn't corresponds to a block header due to wrong tx hash" in { StdBlockValidator.validateHeaderAndBody(wrongTransactionsRootHeader, validBlockBody) match { case Left(BlockTransactionsHashError) => succeed - case _ => fail() + case _ => fail() } } it should "return a failure if a block body doesn't corresponds to a block header due to wrong ommers hash" in { StdBlockValidator.validateHeaderAndBody(wrongOmmersHashHeader, validBlockBody) match { case Left(BlockOmmersHashError) => succeed - case _ => fail() + case _ => fail() } } - val validBlockHeader = BlockHeader( + val validBlockHeader: BlockHeader = BlockHeader( parentHash = ByteString(Hex.decode("8345d132564b3660aa5f27c9415310634b50dbc92579c65a0825d9a255227a71")), ommersHash = ByteString(Hex.decode("1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347")), beneficiary = ByteString(Hex.decode("df7d7e053933b5cc24372f878c90e62dadad5d42")), @@ -100,7 +103,7 @@ class StdBlockValidatorSpec extends AnyFlatSpec with Matchers with SecureRandomB nonce = ByteString(Hex.decode("2b0fb0c002946392")) ) - val validBlockBody = BlockBody( + val validBlockBody: BlockBody = BlockBody( transactionList = Seq[SignedTransaction]( SignedTransaction( tx = Transaction( @@ -162,14 +165,16 @@ class StdBlockValidatorSpec extends AnyFlatSpec with Matchers with SecureRandomB uncleNodesList = Seq[BlockHeader]() ) - val keys = Seq( + val keys: Seq[AsymmetricCipherKeyPair] = Seq( crypto.generateKeyPair(secureRandom), crypto.generateKeyPair(secureRandom) ) - val validCheckpoint = Checkpoint(CheckpointingTestHelpers.createCheckpointSignatures(keys, validBlockHeader.hash)) + val validCheckpoint: Checkpoint = Checkpoint( + CheckpointingTestHelpers.createCheckpointSignatures(keys, validBlockHeader.hash) + ) - val validBlockHeaderWithCheckpoint = + val validBlockHeaderWithCheckpoint: BlockHeader = new CheckpointBlockGenerator() .generate( Block(validBlockHeader, validBlockBody), @@ -177,7 +182,7 @@ class StdBlockValidatorSpec extends AnyFlatSpec with Matchers with SecureRandomB ) .header - val validReceipts = Seq( + val validReceipts: Seq[Receipt] = Seq( Receipt.withHashOutcome( postTransactionStateHash = ByteString(Hex.decode("ce0ac687bb90d457b6573d74e4a25ea7c012fee329eb386dbef161c847f9842d")), @@ -208,23 +213,23 @@ class StdBlockValidatorSpec extends AnyFlatSpec with Matchers with SecureRandomB ) ) - val wrongTransactionsRootHeader = validBlockHeader.copy( + val wrongTransactionsRootHeader: BlockHeader = validBlockHeader.copy( transactionsRoot = ByteString(Hex.decode("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b420")) ) - val wrongOmmersHashHeader = validBlockHeader.copy( + val wrongOmmersHashHeader: BlockHeader = validBlockHeader.copy( ommersHash = ByteString(Hex.decode("1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d4934a")) ) - val wrongReceiptsHeader = validBlockHeader.copy( + val wrongReceiptsHeader: BlockHeader = validBlockHeader.copy( receiptsRoot = ByteString(Hex.decode("8b472d8d4d39bae6a5570c2a42276ed2d6a56ac51a1a356d5b17c5564d01fd5a")) ) - val wrongLogBloomBlockHeader = validBlockHeader.copy( + val wrongLogBloomBlockHeader: BlockHeader = validBlockHeader.copy( logsBloom = ByteString(Hex.decode("1" * 512)) ) - val blockWithOutReceipts = Block( + val blockWithOutReceipts: Block = Block( validBlockHeader.copy(receiptsRoot = Account.EmptyStorageRootHash, logsBloom = BloomFilter.EmptyBloomFilter), validBlockBody ) diff --git a/src/test/scala/io/iohk/ethereum/consensus/validators/std/StdSignedTransactionValidatorSpec.scala b/src/test/scala/io/iohk/ethereum/consensus/validators/std/StdSignedTransactionValidatorSpec.scala index 7b4b0e68b4..f843b0ec66 100644 --- a/src/test/scala/io/iohk/ethereum/consensus/validators/std/StdSignedTransactionValidatorSpec.scala +++ b/src/test/scala/io/iohk/ethereum/consensus/validators/std/StdSignedTransactionValidatorSpec.scala @@ -1,19 +1,24 @@ package io.iohk.ethereum.consensus.validators.std +import java.math.BigInteger +import java.security.SecureRandom + import akka.util.ByteString -import io.iohk.ethereum.consensus.validators.SignedTransactionError.{TransactionSignatureError, _} -import io.iohk.ethereum.consensus.validators.{SignedTransactionError, SignedTransactionValid} -import io.iohk.ethereum.crypto.ECDSASignature -import io.iohk.ethereum.domain._ -import io.iohk.ethereum.utils.Config -import io.iohk.ethereum.vm.EvmConfig -import io.iohk.ethereum.{Fixtures, crypto} + import org.bouncycastle.util.encoders.Hex import org.scalatest.flatspec.AnyFlatSpec import org.scalatest.matchers.should.Matchers -import java.math.BigInteger -import java.security.SecureRandom +import io.iohk.ethereum.Fixtures +import io.iohk.ethereum.consensus.validators.SignedTransactionError +import io.iohk.ethereum.consensus.validators.SignedTransactionError.TransactionSignatureError +import io.iohk.ethereum.consensus.validators.SignedTransactionError._ +import io.iohk.ethereum.consensus.validators.SignedTransactionValid +import io.iohk.ethereum.crypto +import io.iohk.ethereum.crypto.ECDSASignature +import io.iohk.ethereum.domain._ +import io.iohk.ethereum.utils.Config +import io.iohk.ethereum.vm.EvmConfig class StdSignedTransactionValidatorSpec extends AnyFlatSpec with Matchers { @@ -22,7 +27,7 @@ class StdSignedTransactionValidatorSpec extends AnyFlatSpec with Matchers { val signedTransactionValidator = new StdSignedTransactionValidator(blockchainConfig) //From block 0x228943f4ef720ac91ca09c08056d7764c2a1650181925dfaeb484f27e544404e with number 1100000 (tx index 0) - val txBeforeHomestead = Transaction( + val txBeforeHomestead: Transaction = Transaction( nonce = 81, gasPrice = BigInt("60000000000"), gasLimit = 21000, @@ -30,7 +35,7 @@ class StdSignedTransactionValidatorSpec extends AnyFlatSpec with Matchers { value = BigInt("1143962220000000000"), payload = ByteString.empty ) - val signedTxBeforeHomestead = SignedTransaction( + val signedTxBeforeHomestead: SignedTransaction = SignedTransaction( txBeforeHomestead, pointSign = 0x1b.toByte, signatureRandom = ByteString(Hex.decode("12bfc6e767e518c50f59006556ecc9911593094cfb6f6ef78c9959e3327137a3")), @@ -39,7 +44,7 @@ class StdSignedTransactionValidatorSpec extends AnyFlatSpec with Matchers { ) //From block 0xdc7874d8ea90b63aa0ba122055e514db8bb75c0e7d51a448abd12a31ca3370cf with number 1200003 (tx index 0) - val txAfterHomestead = Transaction( + val txAfterHomestead: Transaction = Transaction( nonce = 1631, gasPrice = BigInt("30000000000"), gasLimit = 21000, @@ -47,7 +52,7 @@ class StdSignedTransactionValidatorSpec extends AnyFlatSpec with Matchers { value = BigInt("1050230460000000000"), payload = ByteString.empty ) - val signedTxAfterHomestead = SignedTransaction( + val signedTxAfterHomestead: SignedTransaction = SignedTransaction( txAfterHomestead, pointSign = 0x1c.toByte, signatureRandom = ByteString(Hex.decode("f337e8ca3306c131eabb756aa3701ec7b00bef0d6cc21fbf6a6f291463d58baf")), @@ -57,13 +62,17 @@ class StdSignedTransactionValidatorSpec extends AnyFlatSpec with Matchers { val senderBalance = 100 - val senderAccountBeforeHomestead = Account.empty(UInt256(txBeforeHomestead.nonce)).copy(balance = senderBalance) + val senderAccountBeforeHomestead: Account = + Account.empty(UInt256(txBeforeHomestead.nonce)).copy(balance = senderBalance) - val senderAccountAfterHomestead = Account.empty(UInt256(txAfterHomestead.nonce)).copy(balance = senderBalance) + val senderAccountAfterHomestead: Account = + Account.empty(UInt256(txAfterHomestead.nonce)).copy(balance = senderBalance) - val blockHeaderBeforeHomestead = Fixtures.Blocks.Block3125369.header.copy(number = 1100000, gasLimit = 4700000) + val blockHeaderBeforeHomestead: BlockHeader = + Fixtures.Blocks.Block3125369.header.copy(number = 1100000, gasLimit = 4700000) - val blockHeaderAfterHomestead = Fixtures.Blocks.Block3125369.header.copy(number = 1200003, gasLimit = 4710000) + val blockHeaderAfterHomestead: BlockHeader = + Fixtures.Blocks.Block3125369.header.copy(number = 1200003, gasLimit = 4710000) val accumGasUsed = 0 //Both are the first tx in the block @@ -90,14 +99,14 @@ class StdSignedTransactionValidatorSpec extends AnyFlatSpec with Matchers { it should "report as valid a tx from before homestead" in { validateStx(signedTxBeforeHomestead, fromBeforeHomestead = true) match { case Right(_) => succeed - case _ => fail() + case _ => fail() } } it should "report as valid a tx from after homestead" in { validateStx(signedTxAfterHomestead, fromBeforeHomestead = false) match { case Right(_) => succeed - case _ => fail() + case _ => fail() } } @@ -107,7 +116,7 @@ class StdSignedTransactionValidatorSpec extends AnyFlatSpec with Matchers { signedTxBeforeHomestead.copy(tx = txBeforeHomestead.copy(nonce = BigInt(invalidNonce))) validateStx(signedTxWithInvalidNonce, fromBeforeHomestead = true) match { case Left(_: TransactionSyntaxError) => succeed - case _ => fail() + case _ => fail() } } @@ -117,7 +126,7 @@ class StdSignedTransactionValidatorSpec extends AnyFlatSpec with Matchers { signedTxBeforeHomestead.copy(tx = txBeforeHomestead.copy(gasLimit = BigInt(invalidGasLimit))) validateStx(signedTxWithInvalidGasLimit, fromBeforeHomestead = true) match { case Left(_: TransactionSyntaxError) => succeed - case _ => fail() + case _ => fail() } } @@ -127,7 +136,7 @@ class StdSignedTransactionValidatorSpec extends AnyFlatSpec with Matchers { signedTxBeforeHomestead.copy(tx = txBeforeHomestead.copy(gasPrice = BigInt(invalidGasPrice))) validateStx(signedTxWithInvalidGasPrice, fromBeforeHomestead = true) match { case Left(_: TransactionSyntaxError) => succeed - case _ => fail() + case _ => fail() } } @@ -137,7 +146,7 @@ class StdSignedTransactionValidatorSpec extends AnyFlatSpec with Matchers { signedTxBeforeHomestead.copy(tx = txBeforeHomestead.copy(value = BigInt(invalidValue))) validateStx(signedTxWithInvalidValue, fromBeforeHomestead = true) match { case Left(_: TransactionSyntaxError) => succeed - case _ => fail() + case _ => fail() } } @@ -148,7 +157,7 @@ class StdSignedTransactionValidatorSpec extends AnyFlatSpec with Matchers { val signedTxWithInvalidSignatureLength = signedTxBeforeHomestead.copy(signature = signatureWithInvalidS) validateStx(signedTxWithInvalidSignatureLength, fromBeforeHomestead = true) match { case Left(_: TransactionSyntaxError) => succeed - case _ => fail() + case _ => fail() } } @@ -159,7 +168,7 @@ class StdSignedTransactionValidatorSpec extends AnyFlatSpec with Matchers { val signedTxWithInvalidSignatureLength = signedTxBeforeHomestead.copy(signature = signatureWithInvalidR) validateStx(signedTxWithInvalidSignatureLength, fromBeforeHomestead = true) match { case Left(_: TransactionSyntaxError) => succeed - case _ => fail() + case _ => fail() } } @@ -168,7 +177,7 @@ class StdSignedTransactionValidatorSpec extends AnyFlatSpec with Matchers { val signedTxWithInvalidSignatureRandom = signedTxAfterHomestead.copy(signature = signatureWithInvalidR) validateStx(signedTxWithInvalidSignatureRandom, fromBeforeHomestead = false) match { case Left(TransactionSignatureError) => succeed - case _ => fail() + case _ => fail() } } @@ -178,7 +187,7 @@ class StdSignedTransactionValidatorSpec extends AnyFlatSpec with Matchers { val signedTxWithInvalidSignature = signedTxAfterHomestead.copy(signature = signatureWithInvalidS) validateStx(signedTxWithInvalidSignature, fromBeforeHomestead = false) match { case Left(TransactionSignatureError) => succeed - case _ => fail() + case _ => fail() } } @@ -187,7 +196,7 @@ class StdSignedTransactionValidatorSpec extends AnyFlatSpec with Matchers { val signedTxWithInvalidNonce = signedTxAfterHomestead.copy(tx = txWithInvalidNonce) validateStx(signedTxWithInvalidNonce, fromBeforeHomestead = false) match { case Left(_: TransactionNonceError) => succeed - case _ => fail() + case _ => fail() } } @@ -199,7 +208,7 @@ class StdSignedTransactionValidatorSpec extends AnyFlatSpec with Matchers { val signedTxWithInvalidGasLimit = signedTxAfterHomestead.copy(tx = txWithInvalidGasLimit) validateStx(signedTxWithInvalidGasLimit, fromBeforeHomestead = false) match { case Left(_: TransactionNotEnoughGasForIntrinsicError) => succeed - case _ => fail() + case _ => fail() } } @@ -213,7 +222,7 @@ class StdSignedTransactionValidatorSpec extends AnyFlatSpec with Matchers { accumGasUsed = accumGasUsed ) match { case Left(_: TransactionSenderCantPayUpfrontCostError) => succeed - case _ => fail() + case _ => fail() } } @@ -222,7 +231,7 @@ class StdSignedTransactionValidatorSpec extends AnyFlatSpec with Matchers { val signedTxWithInvalidGasLimit = signedTxAfterHomestead.copy(tx = txWithInvalidGasLimit) validateStx(signedTxWithInvalidGasLimit, fromBeforeHomestead = false) match { case Left(_: TransactionGasLimitTooBigError) => succeed - case _ => fail() + case _ => fail() } } @@ -237,7 +246,7 @@ class StdSignedTransactionValidatorSpec extends AnyFlatSpec with Matchers { accumGasUsed = accumGasUsed ) match { case Left(SignedTransactionError.TransactionSignatureError) => succeed - case _ => fail() + case _ => fail() } } @@ -252,7 +261,7 @@ class StdSignedTransactionValidatorSpec extends AnyFlatSpec with Matchers { accumGasUsed = accumGasUsed ) match { case Right(_) => succeed - case _ => fail() + case _ => fail() } } } diff --git a/src/test/scala/io/iohk/ethereum/db/dataSource/DataSourceTestBehavior.scala b/src/test/scala/io/iohk/ethereum/db/dataSource/DataSourceTestBehavior.scala index ebc04fc985..c8749901f4 100644 --- a/src/test/scala/io/iohk/ethereum/db/dataSource/DataSourceTestBehavior.scala +++ b/src/test/scala/io/iohk/ethereum/db/dataSource/DataSourceTestBehavior.scala @@ -2,12 +2,16 @@ package io.iohk.ethereum.db.dataSource import java.io.File import java.nio.file.Files -import io.iohk.ethereum.ObjectGenerators -import io.iohk.ethereum.db.dataSource.DataSource.{Key, Namespace, Value} -import io.iohk.ethereum.db.dataSource.RocksDbDataSource.RocksDbDataSourceClosedException + import org.scalatest.flatspec.AnyFlatSpec import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks +import io.iohk.ethereum.ObjectGenerators +import io.iohk.ethereum.db.dataSource.DataSource.Key +import io.iohk.ethereum.db.dataSource.DataSource.Namespace +import io.iohk.ethereum.db.dataSource.DataSource.Value +import io.iohk.ethereum.db.dataSource.RocksDbDataSource.RocksDbDataSourceClosedException + trait DataSourceTestBehavior extends ScalaCheckPropertyChecks with ObjectGenerators { this: AnyFlatSpec => @@ -23,9 +27,8 @@ trait DataSourceTestBehavior extends ScalaCheckPropertyChecks with ObjectGenerat def withDir(testCode: String => Any): Unit = { val path = Files.createTempDirectory("testdb").getFileName.toString - try { - testCode(path) - } finally { + try testCode(path) + finally { val dir = new File(path) assert(!dir.exists() || dir.delete(), "File deletion failed") } @@ -41,7 +44,7 @@ trait DataSourceTestBehavior extends ScalaCheckPropertyChecks with ObjectGenerat dataSource.get(OtherNamespace, someByteString) match { case Some(b) if b == someByteString => succeed - case _ => fail() + case _ => fail() } dataSource.destroy() diff --git a/src/test/scala/io/iohk/ethereum/db/dataSource/EphemDataSourceSuite.scala b/src/test/scala/io/iohk/ethereum/db/dataSource/EphemDataSourceSuite.scala index 627ffde189..4e16c18155 100644 --- a/src/test/scala/io/iohk/ethereum/db/dataSource/EphemDataSourceSuite.scala +++ b/src/test/scala/io/iohk/ethereum/db/dataSource/EphemDataSourceSuite.scala @@ -1,10 +1,12 @@ package io.iohk.ethereum.db.dataSource import akka.util.ByteString -import io.iohk.ethereum.ObjectGenerators + import org.scalacheck.Gen -import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks import org.scalatest.funsuite.AnyFunSuite +import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks + +import io.iohk.ethereum.ObjectGenerators class EphemDataSourceSuite extends AnyFunSuite with ScalaCheckPropertyChecks with ObjectGenerators { @@ -12,17 +14,15 @@ class EphemDataSourceSuite extends AnyFunSuite with ScalaCheckPropertyChecks wit val KeyNumberLimit: Int = 40 val OtherNamespace: IndexedSeq[Byte] = IndexedSeq[Byte]('e'.toByte) - def putMultiple(dataSource: DataSource, toInsert: Seq[(ByteString, ByteString)]): Unit = { + def putMultiple(dataSource: DataSource, toInsert: Seq[(ByteString, ByteString)]): Unit = toInsert.foreach { keyValuePair => dataSource.update(Seq(DataSourceUpdate(OtherNamespace, Seq(), Seq(keyValuePair)))) } - } - def removeMultiple(dataSource: DataSource, toDelete: Seq[ByteString]): Unit = { + def removeMultiple(dataSource: DataSource, toDelete: Seq[ByteString]): Unit = toDelete.foreach { key => dataSource.update(Seq(DataSourceUpdate(OtherNamespace, Seq(key), Seq()))) } - } test("EphemDataSource insert") { forAll(seqByteStringOfNItemsGen(KeySize)) { unFilteredKeyList: Seq[ByteString] => @@ -32,7 +32,7 @@ class EphemDataSourceSuite extends AnyFunSuite with ScalaCheckPropertyChecks wit keyList.foreach { key => val obtained = db.get(OtherNamespace, key) assert(obtained.isDefined) - assert(obtained.get sameElements key) + assert(obtained.get.sameElements(key)) } } } @@ -48,7 +48,7 @@ class EphemDataSourceSuite extends AnyFunSuite with ScalaCheckPropertyChecks wit keyValueLeft.foreach { key => val obtained = db.get(OtherNamespace, key) assert(obtained.isDefined) - assert(obtained.get sameElements key) + assert(obtained.get.sameElements(key)) } keysToDelete.foreach { key => assert(db.get(OtherNamespace, key).isEmpty) diff --git a/src/test/scala/io/iohk/ethereum/db/dataSource/RocksDbDataSourceTest.scala b/src/test/scala/io/iohk/ethereum/db/dataSource/RocksDbDataSourceTest.scala index 8d29d94220..af534ce6d0 100644 --- a/src/test/scala/io/iohk/ethereum/db/dataSource/RocksDbDataSourceTest.scala +++ b/src/test/scala/io/iohk/ethereum/db/dataSource/RocksDbDataSourceTest.scala @@ -2,9 +2,10 @@ package io.iohk.ethereum.db.dataSource import java.nio.file.Files -import io.iohk.ethereum.db.storage.Namespaces import org.scalatest.flatspec.AnyFlatSpec +import io.iohk.ethereum.db.storage.Namespaces + class RocksDbDataSourceTest extends AnyFlatSpec with DataSourceTestBehavior { private def createDataSource(path: String): RocksDbDataSource = { @@ -26,5 +27,5 @@ class RocksDbDataSourceTest extends AnyFlatSpec with DataSourceTestBehavior { ) } - it should behave like dataSource(createDataSource) + (it should behave).like(dataSource(createDataSource)) } diff --git a/src/test/scala/io/iohk/ethereum/db/storage/AppStateStorageSpec.scala b/src/test/scala/io/iohk/ethereum/db/storage/AppStateStorageSpec.scala index 16d40ce386..2c5721943b 100644 --- a/src/test/scala/io/iohk/ethereum/db/storage/AppStateStorageSpec.scala +++ b/src/test/scala/io/iohk/ethereum/db/storage/AppStateStorageSpec.scala @@ -1,10 +1,11 @@ package io.iohk.ethereum.db.storage -import io.iohk.ethereum.ObjectGenerators -import io.iohk.ethereum.db.dataSource.EphemDataSource import org.scalatest.wordspec.AnyWordSpec import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks +import io.iohk.ethereum.ObjectGenerators +import io.iohk.ethereum.db.dataSource.EphemDataSource + class AppStateStorageSpec extends AnyWordSpec with ScalaCheckPropertyChecks with ObjectGenerators { "AppStateStorage" should { diff --git a/src/test/scala/io/iohk/ethereum/db/storage/BlockBodiesStorageSpec.scala b/src/test/scala/io/iohk/ethereum/db/storage/BlockBodiesStorageSpec.scala index 50fb2b175d..e8757879c1 100644 --- a/src/test/scala/io/iohk/ethereum/db/storage/BlockBodiesStorageSpec.scala +++ b/src/test/scala/io/iohk/ethereum/db/storage/BlockBodiesStorageSpec.scala @@ -1,14 +1,15 @@ package io.iohk.ethereum.db.storage +import org.bouncycastle.util.encoders.Hex +import org.scalacheck.Gen +import org.scalatest.wordspec.AnyWordSpec +import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks + import io.iohk.ethereum.ObjectGenerators import io.iohk.ethereum.db.dataSource.EphemDataSource -import io.iohk.ethereum.security.SecureRandomBuilder import io.iohk.ethereum.network.p2p.messages.BaseETH6XMessages import io.iohk.ethereum.network.p2p.messages.BaseETH6XMessages.NewBlock -import org.bouncycastle.util.encoders.Hex -import org.scalacheck.Gen -import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks -import org.scalatest.wordspec.AnyWordSpec +import io.iohk.ethereum.security.SecureRandomBuilder class BlockBodiesStorageSpec extends AnyWordSpec diff --git a/src/test/scala/io/iohk/ethereum/db/storage/BlockHeadersStorageSpec.scala b/src/test/scala/io/iohk/ethereum/db/storage/BlockHeadersStorageSpec.scala index 306cfd7757..8bd4aad40e 100644 --- a/src/test/scala/io/iohk/ethereum/db/storage/BlockHeadersStorageSpec.scala +++ b/src/test/scala/io/iohk/ethereum/db/storage/BlockHeadersStorageSpec.scala @@ -1,11 +1,12 @@ package io.iohk.ethereum.db.storage +import org.scalacheck.Gen +import org.scalatest.wordspec.AnyWordSpec +import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks + import io.iohk.ethereum.ObjectGenerators import io.iohk.ethereum.db.dataSource.EphemDataSource import io.iohk.ethereum.domain.BlockHeader -import org.scalacheck.Gen -import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks -import org.scalatest.wordspec.AnyWordSpec class BlockHeadersStorageSpec extends AnyWordSpec with ScalaCheckPropertyChecks with ObjectGenerators { @@ -50,8 +51,7 @@ class BlockHeadersStorageSpec extends AnyWordSpec with ScalaCheckPropertyChecks } } - def checkIfIsInStorage(headers: List[BlockHeader], totalStorage: BlockHeadersStorage): Unit = { + def checkIfIsInStorage(headers: List[BlockHeader], totalStorage: BlockHeadersStorage): Unit = headers.foreach(header => assert(totalStorage.get(header.hash).contains(header))) - } } diff --git a/src/test/scala/io/iohk/ethereum/db/storage/CachedNodeStorageSpec.scala b/src/test/scala/io/iohk/ethereum/db/storage/CachedNodeStorageSpec.scala index 27dee2cd6b..8141ab0aae 100644 --- a/src/test/scala/io/iohk/ethereum/db/storage/CachedNodeStorageSpec.scala +++ b/src/test/scala/io/iohk/ethereum/db/storage/CachedNodeStorageSpec.scala @@ -1,23 +1,29 @@ package io.iohk.ethereum.db.storage import java.util.concurrent.TimeUnit + import akka.util.ByteString + +import scala.collection.mutable +import scala.concurrent.duration.FiniteDuration +import scala.concurrent.duration._ + +import org.scalatest.flatspec.AnyFlatSpec +import org.scalatest.matchers.should.Matchers +import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks + import io.iohk.ethereum.ObjectGenerators import io.iohk.ethereum.db.cache.MapCache import io.iohk.ethereum.db.dataSource.EphemDataSource -import io.iohk.ethereum.db.storage.NodeStorage.{NodeEncoded, NodeHash} +import io.iohk.ethereum.db.storage.NodeStorage.NodeEncoded +import io.iohk.ethereum.db.storage.NodeStorage.NodeHash import io.iohk.ethereum.utils.Config.NodeCacheConfig -import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks -import scala.concurrent.duration._ -import scala.concurrent.duration.FiniteDuration -import org.scalatest.flatspec.AnyFlatSpec -import org.scalatest.matchers.should.Matchers class CachedNodeStorageSpec extends AnyFlatSpec with Matchers with ScalaCheckPropertyChecks with ObjectGenerators { val iterations = 10 "CachedNodeStorage" should "not update dataSource until persist" in new TestSetup { - forAll(keyValueByteStringGen(kvSize)) { (keyvalues) => + forAll(keyValueByteStringGen(kvSize)) { keyvalues => cachedNodeStorage.update(Nil, keyvalues) } dataSource.storage shouldBe empty @@ -33,13 +39,13 @@ class CachedNodeStorageSpec extends AnyFlatSpec with Matchers with ScalaCheckPro } it should "persist elements to underlying data source when full" in new TestSetup { - forAll(keyValueByteStringGen(kvSize)) { (keyvalues) => + forAll(keyValueByteStringGen(kvSize)) { keyvalues => cachedNodeStorage.update(Nil, keyvalues) if (underLying.size > testCapacityCacheConfig.maxSize) assert(cachedNodeStorage.persist()) - keyvalues.foreach(elem => assert(cachedNodeStorage.get(elem._1).get sameElements elem._2)) + keyvalues.foreach(elem => assert(cachedNodeStorage.get(elem._1).get.sameElements(elem._2))) } } @@ -54,9 +60,9 @@ class CachedNodeStorageSpec extends AnyFlatSpec with Matchers with ScalaCheckPro } trait TestSetup { - val dataSource = EphemDataSource() + val dataSource: EphemDataSource = EphemDataSource() val nodeStorage = new NodeStorage(dataSource) - val underLying = MapCache.getMap[NodeHash, NodeEncoded] + val underLying: mutable.Map[NodeHash, NodeEncoded] = MapCache.getMap[NodeHash, NodeEncoded] val mapCache: MapCache[NodeHash, NodeEncoded] = new MapCache[NodeHash, NodeEncoded](underLying, testCapacityCacheConfig) val mapCacheTime: MapCache[NodeHash, NodeEncoded] = @@ -67,12 +73,12 @@ class CachedNodeStorageSpec extends AnyFlatSpec with Matchers with ScalaCheckPro object testCapacityCacheConfig extends NodeCacheConfig { override val maxSize = 30 - override val maxHoldTime = FiniteDuration(10, TimeUnit.MINUTES) + override val maxHoldTime: FiniteDuration = FiniteDuration(10, TimeUnit.MINUTES) } object testTimeCacheConfig extends NodeCacheConfig { override val maxSize = 30 - override val maxHoldTime = FiniteDuration(1, TimeUnit.SECONDS) + override val maxHoldTime: FiniteDuration = FiniteDuration(1, TimeUnit.SECONDS) } } diff --git a/src/test/scala/io/iohk/ethereum/db/storage/CachedReferenceCountedStorageSpec.scala b/src/test/scala/io/iohk/ethereum/db/storage/CachedReferenceCountedStorageSpec.scala index bf0bc1bce6..03acbc9a0a 100644 --- a/src/test/scala/io/iohk/ethereum/db/storage/CachedReferenceCountedStorageSpec.scala +++ b/src/test/scala/io/iohk/ethereum/db/storage/CachedReferenceCountedStorageSpec.scala @@ -1,17 +1,21 @@ package io.iohk.ethereum.db.storage import java.util.concurrent.TimeUnit + import akka.util.ByteString + +import scala.concurrent.duration.FiniteDuration + +import org.scalatest.flatspec.AnyFlatSpec +import org.scalatest.matchers.should.Matchers +import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks + import io.iohk.ethereum.ObjectGenerators -import io.iohk.ethereum.db.dataSource.EphemDataSource -import io.iohk.ethereum.mpt.NodesKeyValueStorage import io.iohk.ethereum.crypto.kec256 import io.iohk.ethereum.db.cache.LruCache +import io.iohk.ethereum.db.dataSource.EphemDataSource +import io.iohk.ethereum.mpt.NodesKeyValueStorage import io.iohk.ethereum.utils.Config.NodeCacheConfig -import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks -import scala.concurrent.duration.FiniteDuration -import org.scalatest.flatspec.AnyFlatSpec -import org.scalatest.matchers.should.Matchers // scalastyle:off magic.number class CachedReferenceCountedStorageSpec @@ -96,7 +100,7 @@ class CachedReferenceCountedStorageSpec } "CachedReferenceCountedStorage" should "prune not referenced nodes " in new TestSetup { - val storage = updateStorage(1) { stor => + updateStorage(1) { stor => stor.update(generateKeys(5).map(_._1), generateKeys(10)) } val storage1 = updateStorage(2) { stor => @@ -118,12 +122,12 @@ class CachedReferenceCountedStorageSpec } it should "not prune nodes which became referenced" in new TestSetup { - val storage = updateStorage(1) { stor => + updateStorage(1) { stor => stor.update(generateKeys(5).map(_._1), generateKeys(10)) } val reAllocatedKey = generateKeys(1).head._1 - val storage1 = updateStorage(2) { stor => + updateStorage(2) { stor => // One of potentialy deltable keys is allocated from other block stor.update(Nil, generateKeys(1)) stor.update(Nil, generateKeys(to = 20, from = 11)) @@ -146,13 +150,13 @@ class CachedReferenceCountedStorageSpec } it should "enable roll-backing changes made by block" in new TestSetup { - val storage = updateStorage(1) { stor => + updateStorage(1) { stor => stor.update(generateKeys(5).map(_._1), generateKeys(10)) } val cacheStateBeforeChanges = testLruCache.getValues assert(cacheStateBeforeChanges.size == 10) - val storage1 = updateStorage(2) { stor => + updateStorage(2) { stor => // 5 new nodes which need to be deleted during rollback stor.update(generateKeys(to = 10, from = 8).map(_._1), generateKeys(3) ++ generateKeys(15, 11)) stor.update(Nil, generateKeys(15, 11)) @@ -175,7 +179,7 @@ class CachedReferenceCountedStorageSpec } it should "flush exising nodes to disk" in new TestSetup { - val storage = updateStorage(1) { stor => + updateStorage(1) { stor => stor.update(generateKeys(5).map(_._1), generateKeys(10)) } val storage1 = updateStorage(2) { stor => @@ -193,7 +197,7 @@ class CachedReferenceCountedStorageSpec } trait TestSetup { - val dataSource = EphemDataSource() + val dataSource: EphemDataSource = EphemDataSource() val nodeStorage = new NodeStorage(dataSource) val changeLog = new ChangeLog(nodeStorage) @@ -207,9 +211,8 @@ class CachedReferenceCountedStorageSpec Some(CachedReferenceCountedStorage.saveOnlyNotificationHandler(nodeStorage)) ) - def generateKeys(to: Int, from: Int = 1): List[(ByteString, Array[Byte])] = { + def generateKeys(to: Int, from: Int = 1): List[(ByteString, Array[Byte])] = (from to to).map(i => kec256(ByteString(s"key$i")) -> ByteString(s"value$i").toArray[Byte]).toList - } def insertRangeKeys(n: Int, storage: NodesKeyValueStorage): Seq[(ByteString, Array[Byte])] = { val toInsert = generateKeys(n) @@ -218,10 +221,10 @@ class CachedReferenceCountedStorageSpec } def scatterUpdates(updates: List[Update]): (List[ByteString], List[ByteString]) = - updates.foldLeft(List.empty[ByteString], List.empty[ByteString]) { (acc, up) => + updates.foldLeft((List.empty[ByteString], List.empty[ByteString])) { (acc, up) => up match { case Increase(hash) => acc.copy(_2 = hash :: acc._2) - case New(hash) => acc.copy(_2 = hash :: acc._2) + case New(hash) => acc.copy(_2 = hash :: acc._2) case Decrease(hash) => acc.copy(_1 = hash :: acc._1) } } @@ -233,10 +236,9 @@ class CachedReferenceCountedStorageSpec storage } - def assertKeysExists(storage: NodesKeyValueStorage, keys: List[(ByteString, Array[Byte])]): Unit = { + def assertKeysExists(storage: NodesKeyValueStorage, keys: List[(ByteString, Array[Byte])]): Unit = keys.foreach { case (key, value) => - assert(storage.get(key).exists(enc => enc sameElements value)) + assert(storage.get(key).exists(enc => enc.sameElements(value))) } - } } } diff --git a/src/test/scala/io/iohk/ethereum/db/storage/ChainWeightStorageSuite.scala b/src/test/scala/io/iohk/ethereum/db/storage/ChainWeightStorageSuite.scala index b607ddaced..b9d33e5dcb 100644 --- a/src/test/scala/io/iohk/ethereum/db/storage/ChainWeightStorageSuite.scala +++ b/src/test/scala/io/iohk/ethereum/db/storage/ChainWeightStorageSuite.scala @@ -1,11 +1,12 @@ package io.iohk.ethereum.db.storage -import io.iohk.ethereum.ObjectGenerators -import io.iohk.ethereum.db.dataSource.EphemDataSource import org.scalacheck.Gen import org.scalatest.funsuite.AnyFunSuite import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks +import io.iohk.ethereum.ObjectGenerators +import io.iohk.ethereum.db.dataSource.EphemDataSource + class ChainWeightStorageSuite extends AnyFunSuite with ScalaCheckPropertyChecks with ObjectGenerators { test("ChainWeightStorage insert") { forAll(Gen.listOf(byteStringOfLengthNGen(32))) { blockByteArrayHashes => diff --git a/src/test/scala/io/iohk/ethereum/db/storage/CodeStorageSuite.scala b/src/test/scala/io/iohk/ethereum/db/storage/CodeStorageSuite.scala index a71ffdedf4..8ec9ef3617 100644 --- a/src/test/scala/io/iohk/ethereum/db/storage/CodeStorageSuite.scala +++ b/src/test/scala/io/iohk/ethereum/db/storage/CodeStorageSuite.scala @@ -1,11 +1,13 @@ package io.iohk.ethereum.db.storage import akka.util.ByteString -import io.iohk.ethereum.ObjectGenerators -import io.iohk.ethereum.db.dataSource.EphemDataSource + import org.scalacheck.Gen -import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks import org.scalatest.funsuite.AnyFunSuite +import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks + +import io.iohk.ethereum.ObjectGenerators +import io.iohk.ethereum.db.dataSource.EphemDataSource class CodeStorageSuite extends AnyFunSuite with ScalaCheckPropertyChecks with ObjectGenerators { val LimitCodeSize = 100 diff --git a/src/test/scala/io/iohk/ethereum/db/storage/KeyValueStorageSuite.scala b/src/test/scala/io/iohk/ethereum/db/storage/KeyValueStorageSuite.scala index 80686013d5..bb36879185 100644 --- a/src/test/scala/io/iohk/ethereum/db/storage/KeyValueStorageSuite.scala +++ b/src/test/scala/io/iohk/ethereum/db/storage/KeyValueStorageSuite.scala @@ -1,12 +1,16 @@ package io.iohk.ethereum.db.storage -import io.iohk.ethereum.ObjectGenerators -import io.iohk.ethereum.db.dataSource.{DataSource, DataSourceUpdate, EphemDataSource} -import io.iohk.ethereum.rlp.RLPImplicits._ -import io.iohk.ethereum.rlp.{decode => rlpDecode, encode => rlpEncode} import org.scalacheck.Gen -import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks import org.scalatest.funsuite.AnyFunSuite +import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks + +import io.iohk.ethereum.ObjectGenerators +import io.iohk.ethereum.db.dataSource.DataSource +import io.iohk.ethereum.db.dataSource.DataSourceUpdate +import io.iohk.ethereum.db.dataSource.EphemDataSource +import io.iohk.ethereum.rlp.RLPImplicits._ +import io.iohk.ethereum.rlp.{decode => rlpDecode} +import io.iohk.ethereum.rlp.{encode => rlpEncode} class KeyValueStorageSuite extends AnyFunSuite with ScalaCheckPropertyChecks with ObjectGenerators { val iterationsNumber = 100 @@ -34,21 +38,21 @@ class KeyValueStorageSuite extends AnyFunSuite with ScalaCheckPropertyChecks wit val initialIntStorage = new IntStorage(EphemDataSource()) - val dataGenerator = for { + val dataGenerator: Gen[(List[Int], List[Int])] = for { intsInStorage <- Gen.nonEmptyListOf(intGen) intsNotInStorage <- Gen.nonEmptyListOf(intGen.suchThat(value => !intsInStorage.contains(value))) } yield (intsInStorage, intsNotInStorage) test("Get ints from KeyValueStorage") { forAll(dataGenerator) { case (intsInStorage, intsNotInStorage) => - val intsInStorageIndexedSeq = intsInStorage.map { IntStorage.intSerializer(_) } + val intsInStorageIndexedSeq = intsInStorage.map(IntStorage.intSerializer(_)) val initialIntDataSource = EphemDataSource() initialIntDataSource.update( Seq(DataSourceUpdate(IntStorage.intNamespace, Seq(), intsInStorageIndexedSeq.zip(intsInStorageIndexedSeq))) ) val keyValueStorage = new IntStorage(initialIntDataSource) - intsInStorage.foreach { i => assert(keyValueStorage.get(i).contains(i)) } - intsNotInStorage.foreach { i => assert(keyValueStorage.get(i).isEmpty) } + intsInStorage.foreach(i => assert(keyValueStorage.get(i).contains(i))) + intsNotInStorage.foreach(i => assert(keyValueStorage.get(i).isEmpty)) } } diff --git a/src/test/scala/io/iohk/ethereum/db/storage/NodeStorageSuite.scala b/src/test/scala/io/iohk/ethereum/db/storage/NodeStorageSuite.scala index d5d60cce4a..2abf396e0e 100644 --- a/src/test/scala/io/iohk/ethereum/db/storage/NodeStorageSuite.scala +++ b/src/test/scala/io/iohk/ethereum/db/storage/NodeStorageSuite.scala @@ -1,12 +1,14 @@ package io.iohk.ethereum.db.storage import akka.util.ByteString + +import org.scalacheck.Gen +import org.scalatest.funsuite.AnyFunSuite +import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks + import io.iohk.ethereum.ObjectGenerators import io.iohk.ethereum.db.dataSource.EphemDataSource import io.iohk.ethereum.network.p2p.messages.ETH63.MptNodeEncoders._ -import org.scalacheck.Gen -import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks -import org.scalatest.funsuite.AnyFunSuite class NodeStorageSuite extends AnyFunSuite with ScalaCheckPropertyChecks with ObjectGenerators { test("NodeStorage insert") { @@ -44,7 +46,7 @@ class NodeStorageSuite extends AnyFunSuite with ScalaCheckPropertyChecks with Ob val obtainedNode = nodeStorageAfterDelete.get(ByteString(node.hash)).map(_.toMptNode) assert(obtainedNode.contains(node)) } - toDelete.foreach { node => assert(nodeStorageAfterDelete.get(ByteString(node.hash)).isEmpty) } + toDelete.foreach(node => assert(nodeStorageAfterDelete.get(ByteString(node.hash)).isEmpty)) } } } diff --git a/src/test/scala/io/iohk/ethereum/db/storage/ReadOnlyNodeStorageSpec.scala b/src/test/scala/io/iohk/ethereum/db/storage/ReadOnlyNodeStorageSpec.scala index bea0224025..763156369e 100644 --- a/src/test/scala/io/iohk/ethereum/db/storage/ReadOnlyNodeStorageSpec.scala +++ b/src/test/scala/io/iohk/ethereum/db/storage/ReadOnlyNodeStorageSpec.scala @@ -3,18 +3,23 @@ package io.iohk.ethereum.db.storage import java.util.concurrent.TimeUnit import akka.util.ByteString -import io.iohk.ethereum.db.cache.{LruCache, MapCache} + +import scala.concurrent.duration.FiniteDuration + +import org.scalatest.flatspec.AnyFlatSpec +import org.scalatest.matchers.should.Matchers + +import io.iohk.ethereum.db.cache.Cache +import io.iohk.ethereum.db.cache.LruCache +import io.iohk.ethereum.db.cache.MapCache import io.iohk.ethereum.db.dataSource.EphemDataSource -import io.iohk.ethereum.db.storage.NodeStorage.{NodeEncoded, NodeHash} +import io.iohk.ethereum.db.storage.NodeStorage.NodeEncoded +import io.iohk.ethereum.db.storage.NodeStorage.NodeHash import io.iohk.ethereum.db.storage.StateStorage.GenesisDataLoad import io.iohk.ethereum.db.storage.pruning.InMemoryPruning import io.iohk.ethereum.mpt.LeafNode import io.iohk.ethereum.utils.Config.NodeCacheConfig -import scala.concurrent.duration.FiniteDuration -import org.scalatest.flatspec.AnyFlatSpec -import org.scalatest.matchers.should.Matchers - class ReadOnlyNodeStorageSpec extends AnyFlatSpec with Matchers { "ReadOnlyNodeStorage" should "not update dataSource" in new TestSetup { @@ -58,8 +63,8 @@ class ReadOnlyNodeStorageSpec extends AnyFlatSpec with Matchers { } trait TestSetup { - val newLeaf = LeafNode(ByteString(1), ByteString(1)) - val dataSource = EphemDataSource() + val newLeaf: LeafNode = LeafNode(ByteString(1), ByteString(1)) + val dataSource: EphemDataSource = EphemDataSource() val (stateStorage, nodeStorage, cachedStorage) = StateStorage.createTestStateStorage(dataSource) object TestCacheConfig extends NodeCacheConfig { @@ -68,9 +73,10 @@ class ReadOnlyNodeStorageSpec extends AnyFlatSpec with Matchers { } val lruCache = new LruCache[NodeHash, HeapEntry](TestCacheConfig) val newNodeStorage = new NodeStorage(dataSource) - val testCache = MapCache.createTestCache[NodeHash, NodeEncoded](10) + val testCache: Cache[NodeHash, NodeEncoded] = MapCache.createTestCache[NodeHash, NodeEncoded](10) val newCachedNodeStorage = new CachedNodeStorage(newNodeStorage, testCache) - val cachedStateStorage = StateStorage(InMemoryPruning(10), newNodeStorage, newCachedNodeStorage, lruCache) + val cachedStateStorage: StateStorage = + StateStorage(InMemoryPruning(10), newNodeStorage, newCachedNodeStorage, lruCache) } } diff --git a/src/test/scala/io/iohk/ethereum/db/storage/ReceiptStorageSuite.scala b/src/test/scala/io/iohk/ethereum/db/storage/ReceiptStorageSuite.scala index eacecafa15..3f7c862ce2 100644 --- a/src/test/scala/io/iohk/ethereum/db/storage/ReceiptStorageSuite.scala +++ b/src/test/scala/io/iohk/ethereum/db/storage/ReceiptStorageSuite.scala @@ -1,11 +1,12 @@ package io.iohk.ethereum.db.storage +import org.scalacheck.Gen +import org.scalatest.funsuite.AnyFunSuite +import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks + import io.iohk.ethereum.ObjectGenerators import io.iohk.ethereum.db.dataSource.EphemDataSource import io.iohk.ethereum.domain.Receipt -import org.scalacheck.Gen -import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks -import org.scalatest.funsuite.AnyFunSuite class ReceiptStorageSuite extends AnyFunSuite with ScalaCheckPropertyChecks with ObjectGenerators { diff --git a/src/test/scala/io/iohk/ethereum/db/storage/ReferenceCountNodeStorageSpec.scala b/src/test/scala/io/iohk/ethereum/db/storage/ReferenceCountNodeStorageSpec.scala index 1f1f706286..dbef7de61c 100644 --- a/src/test/scala/io/iohk/ethereum/db/storage/ReferenceCountNodeStorageSpec.scala +++ b/src/test/scala/io/iohk/ethereum/db/storage/ReferenceCountNodeStorageSpec.scala @@ -3,14 +3,18 @@ package io.iohk.ethereum.db.storage import java.util.concurrent.TimeUnit import akka.util.ByteString + +import scala.collection.mutable +import scala.concurrent.duration.FiniteDuration + +import org.scalatest.flatspec.AnyFlatSpec +import org.scalatest.matchers.should.Matchers + +import io.iohk.ethereum.crypto.kec256 import io.iohk.ethereum.db.cache.MapCache import io.iohk.ethereum.db.dataSource.EphemDataSource import io.iohk.ethereum.mpt.NodesKeyValueStorage import io.iohk.ethereum.utils.Config.NodeCacheConfig -import io.iohk.ethereum.crypto.kec256 -import scala.concurrent.duration.FiniteDuration -import org.scalatest.flatspec.AnyFlatSpec -import org.scalatest.matchers.should.Matchers class ReferenceCountNodeStorageSpec extends AnyFlatSpec with Matchers { @@ -217,24 +221,24 @@ class ReferenceCountNodeStorageSpec extends AnyFlatSpec with Matchers { val storage = new ReferenceCountNodeStorage(cachedNodeStorage, bn = 1) - val inserted: Seq[(ByteString, Array[Byte])] = insertRangeKeys(1, storage) + insertRangeKeys(1, storage) val storage2 = new ReferenceCountNodeStorage(cachedNodeStorage, bn = 2) - val inserted2: Seq[(ByteString, Array[Byte])] = insertRangeKeys(1, storage2) + insertRangeKeys(1, storage2) val storage3 = new ReferenceCountNodeStorage(cachedNodeStorage, bn = 3) - val inserted3: Seq[(ByteString, Array[Byte])] = insertRangeKeys(1, storage3) + insertRangeKeys(1, storage3) // we are still in memory as cache size = 7 < 10 cachedNodeStorage.persist() shouldEqual false dataSource.storage.size shouldEqual 0 underlying.size shouldEqual 7 // 1 key + 3 block indexex + 3 snapshots - val storage4 = new ReferenceCountNodeStorage(cachedNodeStorage, bn = 4) + new ReferenceCountNodeStorage(cachedNodeStorage, bn = 4) - val inserted4: Seq[(ByteString, Array[Byte])] = insertRangeKeys(4, storage3) + insertRangeKeys(4, storage3) ReferenceCountNodeStorage.prune(1, cachedNodeStorage, inMemory = true) // Number of nodes in cache > maxsize, so everything goes to data source, including unpruned blocks 2,3,4 @@ -243,8 +247,8 @@ class ReferenceCountNodeStorageSpec extends AnyFlatSpec with Matchers { underlying.size shouldEqual 0 // Now as our block to prune(2) is <= best saved block(4), we need to prune junk from disk - val storage5 = new ReferenceCountNodeStorage(cachedNodeStorage, bn = 5) - val inserted5: Seq[(ByteString, Array[Byte])] = insertRangeKeys(4, storage3) + new ReferenceCountNodeStorage(cachedNodeStorage, bn = 5) + insertRangeKeys(4, storage3) ReferenceCountNodeStorage.prune(2, cachedNodeStorage, inMemory = false) cachedNodeStorage.persist() shouldEqual false // @@ -291,7 +295,7 @@ class ReferenceCountNodeStorageSpec extends AnyFlatSpec with Matchers { } trait TestSetup { - val dataSource = EphemDataSource() + val dataSource: EphemDataSource = EphemDataSource() val nodeStorage = new NodeStorage(dataSource) def insertRangeKeys(n: Int, storage: NodesKeyValueStorage): Seq[(ByteString, Array[Byte])] = { @@ -302,10 +306,10 @@ class ReferenceCountNodeStorageSpec extends AnyFlatSpec with Matchers { object testCacheConfig extends NodeCacheConfig { override val maxSize = 10 - override val maxHoldTime = FiniteDuration(5, TimeUnit.MINUTES) + override val maxHoldTime: FiniteDuration = FiniteDuration(5, TimeUnit.MINUTES) } - val underlying = MapCache.getMap[ByteString, Array[Byte]] + val underlying: mutable.Map[ByteString, Array[Byte]] = MapCache.getMap[ByteString, Array[Byte]] val cache = new MapCache[ByteString, Array[Byte]](underlying, testCacheConfig) val cachedNodeStorage = new CachedNodeStorage(nodeStorage, cache) diff --git a/src/test/scala/io/iohk/ethereum/db/storage/StateStorageSpec.scala b/src/test/scala/io/iohk/ethereum/db/storage/StateStorageSpec.scala index d9e367ef8f..b5f0d76442 100644 --- a/src/test/scala/io/iohk/ethereum/db/storage/StateStorageSpec.scala +++ b/src/test/scala/io/iohk/ethereum/db/storage/StateStorageSpec.scala @@ -1,22 +1,31 @@ package io.iohk.ethereum.db.storage import java.util.concurrent.TimeUnit + import akka.util.ByteString + +import scala.concurrent.duration.FiniteDuration + +import org.scalatest.flatspec.AnyFlatSpec +import org.scalatest.matchers.should.Matchers +import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks + import io.iohk.ethereum.ObjectGenerators -import io.iohk.ethereum.db.cache.{LruCache, MapCache} +import io.iohk.ethereum.db.cache.Cache +import io.iohk.ethereum.db.cache.LruCache +import io.iohk.ethereum.db.cache.MapCache import io.iohk.ethereum.db.dataSource.EphemDataSource -import io.iohk.ethereum.db.storage.NodeStorage.{NodeEncoded, NodeHash} -import io.iohk.ethereum.db.storage.pruning.{ArchivePruning, BasicPruning, InMemoryPruning} +import io.iohk.ethereum.db.storage.NodeStorage.NodeEncoded +import io.iohk.ethereum.db.storage.NodeStorage.NodeHash +import io.iohk.ethereum.db.storage.pruning.ArchivePruning +import io.iohk.ethereum.db.storage.pruning.BasicPruning +import io.iohk.ethereum.db.storage.pruning.InMemoryPruning import io.iohk.ethereum.mpt.NodesKeyValueStorage import io.iohk.ethereum.utils.Config.NodeCacheConfig -import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks -import scala.concurrent.duration.FiniteDuration -import org.scalatest.flatspec.AnyFlatSpec -import org.scalatest.matchers.should.Matchers class StateStorageSpec extends AnyFlatSpec with Matchers with ScalaCheckPropertyChecks with ObjectGenerators { - def saveNodeToDbTest(storage: StateStorage, nodeStorage: NodesKeyValueStorage): Unit = { + def saveNodeToDbTest(storage: StateStorage, nodeStorage: NodesKeyValueStorage): Unit = forAll(keyValueByteStringGen(32)) { keyvals => keyvals.foreach { case (key, value) => storage.saveNode(key, value, 10) @@ -25,12 +34,11 @@ class StateStorageSpec extends AnyFlatSpec with Matchers with ScalaCheckProperty keyvals.foreach { case (key, value) => val result = nodeStorage.get(key) assert(result.isDefined) - assert(result.get sameElements value) + assert(result.get.sameElements(value)) } } - } - def getNodeFromDbTest(stateStorage: StateStorage): Unit = { + def getNodeFromDbTest(stateStorage: StateStorage): Unit = forAll(nodeGen) { node => val storage = stateStorage.getBackingStorage(0) storage.updateNodesInStorage(Some(node), Nil) @@ -38,16 +46,14 @@ class StateStorageSpec extends AnyFlatSpec with Matchers with ScalaCheckProperty assert(fromStorage.isDefined) assert(fromStorage.get == node) } - } - def provideStorageForTrieTest(stateStorage: StateStorage): Unit = { + def provideStorageForTrieTest(stateStorage: StateStorage): Unit = forAll(nodeGen) { node => val storage = stateStorage.getBackingStorage(0) storage.updateNodesInStorage(Some(node), Nil) val fromStorage = storage.get(node.hash) - assert(fromStorage.hash sameElements node.hash) + assert(fromStorage.hash.sameElements(node.hash)) } - } "ArchiveStateStorage" should "save node directly to db" in new TestSetup { saveNodeToDbTest(archiveStateStorage, archiveNodeStorage) @@ -160,8 +166,8 @@ class StateStorageSpec extends AnyFlatSpec with Matchers with ScalaCheckProperty trait TestSetup { val minNodes = 5 val maxNodes = 15 - val dataSource = EphemDataSource() - val testCache = MapCache.createTestCache[NodeHash, NodeEncoded](10) + val dataSource: EphemDataSource = EphemDataSource() + val testCache: Cache[NodeHash, NodeEncoded] = MapCache.createTestCache[NodeHash, NodeEncoded](10) val nodeStorage = new NodeStorage(dataSource) val cachedNodeStorage = new CachedNodeStorage(nodeStorage, testCache) object TestCacheConfig extends NodeCacheConfig { @@ -173,12 +179,13 @@ class StateStorageSpec extends AnyFlatSpec with Matchers with ScalaCheckProperty val lruCache = new LruCache[NodeHash, HeapEntry](TestCacheConfig) val archiveNodeStorage = new ArchiveNodeStorage(nodeStorage) - val archiveStateStorage = StateStorage(ArchivePruning, nodeStorage, cachedNodeStorage, lruCache) + val archiveStateStorage: StateStorage = StateStorage(ArchivePruning, nodeStorage, cachedNodeStorage, lruCache) val refCountNodeStorage = new ReferenceCountNodeStorage(nodeStorage, 10) - val referenceCounteStateStorage = StateStorage(BasicPruning(10), nodeStorage, cachedNodeStorage, lruCache) + val referenceCounteStateStorage: StateStorage = + StateStorage(BasicPruning(10), nodeStorage, cachedNodeStorage, lruCache) - val cachedStateStorage = StateStorage(InMemoryPruning(10), nodeStorage, cachedNodeStorage, lruCache) + val cachedStateStorage: StateStorage = StateStorage(InMemoryPruning(10), nodeStorage, cachedNodeStorage, lruCache) val cachedPrunedNodeStorage = new CachedReferenceCountedStorage(nodeStorage, lruCache, changeLog, 10) } } diff --git a/src/test/scala/io/iohk/ethereum/db/storage/TransactionMappingStorageSuite.scala b/src/test/scala/io/iohk/ethereum/db/storage/TransactionMappingStorageSuite.scala index ed036b9fbb..a2f0c03563 100644 --- a/src/test/scala/io/iohk/ethereum/db/storage/TransactionMappingStorageSuite.scala +++ b/src/test/scala/io/iohk/ethereum/db/storage/TransactionMappingStorageSuite.scala @@ -1,11 +1,12 @@ package io.iohk.ethereum.db.storage +import org.scalacheck.Gen +import org.scalatest.funsuite.AnyFunSuite +import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks + import io.iohk.ethereum.ObjectGenerators import io.iohk.ethereum.db.dataSource.EphemDataSource import io.iohk.ethereum.db.storage.TransactionMappingStorage.TransactionLocation -import org.scalacheck.Gen -import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks -import org.scalatest.funsuite.AnyFunSuite class TransactionMappingStorageSuite extends AnyFunSuite with ScalaCheckPropertyChecks with ObjectGenerators { test("TransactionMappingStorage insert") { diff --git a/src/test/scala/io/iohk/ethereum/db/storage/TransactionalKeyValueStorageSuite.scala b/src/test/scala/io/iohk/ethereum/db/storage/TransactionalKeyValueStorageSuite.scala index f9cd6a4f1c..23d9ca074e 100644 --- a/src/test/scala/io/iohk/ethereum/db/storage/TransactionalKeyValueStorageSuite.scala +++ b/src/test/scala/io/iohk/ethereum/db/storage/TransactionalKeyValueStorageSuite.scala @@ -1,12 +1,16 @@ package io.iohk.ethereum.db.storage -import io.iohk.ethereum.ObjectGenerators -import io.iohk.ethereum.db.dataSource.{DataSource, DataSourceUpdate, EphemDataSource} -import io.iohk.ethereum.rlp.RLPImplicits._ -import io.iohk.ethereum.rlp.{decode => rlpDecode, encode => rlpEncode} import org.scalacheck.Gen -import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks import org.scalatest.funsuite.AnyFunSuite +import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks + +import io.iohk.ethereum.ObjectGenerators +import io.iohk.ethereum.db.dataSource.DataSource +import io.iohk.ethereum.db.dataSource.DataSourceUpdate +import io.iohk.ethereum.db.dataSource.EphemDataSource +import io.iohk.ethereum.rlp.RLPImplicits._ +import io.iohk.ethereum.rlp.{decode => rlpDecode} +import io.iohk.ethereum.rlp.{encode => rlpEncode} class TransactionalKeyValueStorageSuite extends AnyFunSuite with ScalaCheckPropertyChecks with ObjectGenerators { val iterationsNumber = 100 @@ -30,14 +34,14 @@ class TransactionalKeyValueStorageSuite extends AnyFunSuite with ScalaCheckPrope def newIntStorage(): IntStorage = new IntStorage(EphemDataSource()) - val dataGenerator = for { + val dataGenerator: Gen[(List[Int], List[Int])] = for { intsInStorage <- Gen.nonEmptyListOf(intGen) intsNotInStorage <- Gen.nonEmptyListOf(intGen.suchThat(value => !intsInStorage.contains(value))) } yield (intsInStorage, intsNotInStorage) test("Get ints from KeyValueStorage") { forAll(dataGenerator) { case (intsInStorage, intsNotInStorage) => - val intsInStorageIndexedSeq = intsInStorage.map { IntStorage.intSerializer(_) } + val intsInStorageIndexedSeq = intsInStorage.map(IntStorage.intSerializer(_)) val intDataSource = EphemDataSource() intDataSource.update( Seq(DataSourceUpdate(IntStorage.intNamespace, Seq(), intsInStorageIndexedSeq.zip(intsInStorageIndexedSeq))) diff --git a/src/test/scala/io/iohk/ethereum/domain/ArbitraryIntegerMptSpec.scala b/src/test/scala/io/iohk/ethereum/domain/ArbitraryIntegerMptSpec.scala index 6911dba62b..2397d94835 100644 --- a/src/test/scala/io/iohk/ethereum/domain/ArbitraryIntegerMptSpec.scala +++ b/src/test/scala/io/iohk/ethereum/domain/ArbitraryIntegerMptSpec.scala @@ -1,13 +1,15 @@ package io.iohk.ethereum.domain import akka.util.ByteString -import io.iohk.ethereum.blockchain.sync.EphemBlockchainTestSetup -import io.iohk.ethereum.mpt.MerklePatriciaTrie -import io.iohk.ethereum.vm.Generators._ + import org.scalacheck.Gen -import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks import org.scalatest.flatspec.AnyFlatSpec import org.scalatest.matchers.should.Matchers +import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks + +import io.iohk.ethereum.blockchain.sync.EphemBlockchainTestSetup +import io.iohk.ethereum.mpt.MerklePatriciaTrie +import io.iohk.ethereum.vm.Generators._ class ArbitraryIntegerMptSpec extends AnyFlatSpec with Matchers with ScalaCheckPropertyChecks { @@ -16,9 +18,9 @@ class ArbitraryIntegerMptSpec extends AnyFlatSpec with Matchers with ScalaCheckP "ArbitraryIntegerMpt" should "insert and retrieve values" in new TestSetup { forAll(Gen.listOfN(10, keyGen), Gen.listOfN(10, valueGen)) { (keys, values) => - val afterInsert = emptyMpt.update(Nil, keys zip values) + val afterInsert = emptyMpt.update(Nil, keys.zip(values)) - (keys zip values).foreach { case (k, v) => + keys.zip(values).foreach { case (k, v) => afterInsert.get(k) shouldBe Some(v) } } @@ -27,19 +29,19 @@ class ArbitraryIntegerMptSpec extends AnyFlatSpec with Matchers with ScalaCheckP it should "remove values" in new TestSetup { forAll(Gen.listOfN(10, keyGen), Gen.listOfN(10, valueGen)) { (keys, values) => val afterInsert = - emptyMpt.update(Nil, keys zip values) + emptyMpt.update(Nil, keys.zip(values)) - (keys zip values).foreach { case (k, v) => + keys.zip(values).foreach { case (k, v) => afterInsert.get(k) shouldBe Some(v) } // remove every 2nd key val afterRemove = - (keys zip values).zipWithIndex.filter(_._2 % 2 == 0).foldLeft(afterInsert) { case (mpt, ((k, _), _)) => + keys.zip(values).zipWithIndex.filter(_._2 % 2 == 0).foldLeft(afterInsert) { case (mpt, ((k, _), _)) => mpt.remove(k) } - (keys zip values).zipWithIndex.foreach { + keys.zip(values).zipWithIndex.foreach { case ((k, _), index) if index % 2 == 0 => afterRemove.get(k) shouldBe None case ((k, v), index) if index % 2 != 0 => afterRemove.get(k) shouldBe Some(v) } @@ -47,7 +49,7 @@ class ArbitraryIntegerMptSpec extends AnyFlatSpec with Matchers with ScalaCheckP } trait TestSetup extends EphemBlockchainTestSetup { - val emptyMpt = ArbitraryIntegerMpt.storageMpt( + val emptyMpt: MerklePatriciaTrie[BigInt, BigInt] = ArbitraryIntegerMpt.storageMpt( ByteString(MerklePatriciaTrie.EmptyRootHash), storagesInstance.storages.stateStorage.getReadOnlyStorage ) diff --git a/src/test/scala/io/iohk/ethereum/domain/BlockHeaderSpec.scala b/src/test/scala/io/iohk/ethereum/domain/BlockHeaderSpec.scala index 296ecf4cf4..43f1110f23 100644 --- a/src/test/scala/io/iohk/ethereum/domain/BlockHeaderSpec.scala +++ b/src/test/scala/io/iohk/ethereum/domain/BlockHeaderSpec.scala @@ -1,17 +1,20 @@ package io.iohk.ethereum.domain import akka.util.ByteString + +import org.bouncycastle.util.encoders.Hex +import org.scalatest.freespec.AnyFreeSpec +import org.scalatest.matchers.should.Matchers +import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks + +import io.iohk.ethereum.Fixtures +import io.iohk.ethereum.ObjectGenerators import io.iohk.ethereum.domain.BlockHeader.HeaderExtraFields._ import io.iohk.ethereum.domain.BlockHeaderImplicits._ import io.iohk.ethereum.rlp import io.iohk.ethereum.rlp.RLPImplicitConversions._ import io.iohk.ethereum.rlp.RLPImplicits._ import io.iohk.ethereum.rlp.RLPList -import io.iohk.ethereum.{Fixtures, ObjectGenerators} -import org.bouncycastle.util.encoders.Hex -import org.scalatest.freespec.AnyFreeSpec -import org.scalatest.matchers.should.Matchers -import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks class BlockHeaderSpec extends AnyFreeSpec with Matchers with ScalaCheckPropertyChecks with ObjectGenerators { @@ -146,7 +149,7 @@ class BlockHeaderSpec extends AnyFreeSpec with Matchers with ScalaCheckPropertyC } trait TestSetup { - val block1 = BlockHeader( + val block1: BlockHeader = BlockHeader( parentHash = ByteString(Hex.decode("d882d5c210bab4cb7ef0b9f3dc2130cb680959afcd9a8f9bf83ee6f13e2f9da3")), ommersHash = ByteString(Hex.decode("1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347")), beneficiary = ByteString(Hex.decode("95f484419881c6e9b6de7fb3f8ad03763bd49a89")), @@ -164,7 +167,7 @@ class BlockHeaderSpec extends AnyFreeSpec with Matchers with ScalaCheckPropertyC nonce = ByteString(Hex.decode("797a8f3a494f937b")) ) - val block2 = BlockHeader( + val block2: BlockHeader = BlockHeader( parentHash = ByteString(Hex.decode("677a5fb51d52321b03552e3c667f602cc489d15fc1d7824445aee6d94a9db2e7")), ommersHash = ByteString(Hex.decode("1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347")), beneficiary = ByteString(Hex.decode("95f484419881c6e9b6de7fb3f8ad03763bd49a89")), diff --git a/src/test/scala/io/iohk/ethereum/domain/BlockSpec.scala b/src/test/scala/io/iohk/ethereum/domain/BlockSpec.scala index 40b72e4c89..a232813367 100644 --- a/src/test/scala/io/iohk/ethereum/domain/BlockSpec.scala +++ b/src/test/scala/io/iohk/ethereum/domain/BlockSpec.scala @@ -1,9 +1,10 @@ package io.iohk.ethereum.domain -import io.iohk.ethereum.Fixtures.Blocks._ import org.scalatest.flatspec.AnyFlatSpec import org.scalatest.matchers.should.Matchers +import io.iohk.ethereum.Fixtures.Blocks._ + class BlockSpec extends AnyFlatSpec with Matchers { "Block size" should "be correct" in { assert(Block.size(Genesis.block) == Genesis.size) diff --git a/src/test/scala/io/iohk/ethereum/domain/BlockchainSpec.scala b/src/test/scala/io/iohk/ethereum/domain/BlockchainSpec.scala index d20ac4a49e..ac22df8286 100644 --- a/src/test/scala/io/iohk/ethereum/domain/BlockchainSpec.scala +++ b/src/test/scala/io/iohk/ethereum/domain/BlockchainSpec.scala @@ -1,25 +1,30 @@ package io.iohk.ethereum.domain import akka.util.ByteString + +import org.scalacheck.Gen +import org.scalamock.scalatest.MockFactory +import org.scalatest.flatspec.AnyFlatSpec +import org.scalatest.matchers.should.Matchers +import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks + +import io.iohk.ethereum.BlockHelpers +import io.iohk.ethereum.Fixtures +import io.iohk.ethereum.ObjectGenerators +import io.iohk.ethereum.ObjectGenerators._ import io.iohk.ethereum.blockchain.sync.EphemBlockchainTestSetup import io.iohk.ethereum.consensus.blocks.CheckpointBlockGenerator import io.iohk.ethereum.db.dataSource.EphemDataSource import io.iohk.ethereum.db.storage.StateStorage import io.iohk.ethereum.domain.BlockHeader.HeaderExtraFields.HefPostEcip1097 -import io.iohk.ethereum.mpt.{HashNode, MerklePatriciaTrie} -import io.iohk.ethereum.{BlockHelpers, Fixtures, ObjectGenerators} -import io.iohk.ethereum.ObjectGenerators._ +import io.iohk.ethereum.mpt.HashNode +import io.iohk.ethereum.mpt.MerklePatriciaTrie import io.iohk.ethereum.proof.MptProofVerifier import io.iohk.ethereum.proof.ProofVerifyResult.ValidProof -import org.scalacheck.Gen -import org.scalamock.scalatest.MockFactory -import org.scalatest.flatspec.AnyFlatSpec -import org.scalatest.matchers.should.Matchers -import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks class BlockchainSpec extends AnyFlatSpec with Matchers with ScalaCheckPropertyChecks { - val checkpoint = ObjectGenerators.fakeCheckpointGen(2, 5).sample.get + val checkpoint: Checkpoint = ObjectGenerators.fakeCheckpointGen(2, 5).sample.get val checkpointBlockGenerator = new CheckpointBlockGenerator "Blockchain" should "be able to store a block and return it if queried by hash" in new EphemBlockchainTestSetup { @@ -47,7 +52,7 @@ class BlockchainSpec extends AnyFlatSpec with Matchers with ScalaCheckPropertyCh it should "be able to do strict check of block existence in the chain" in new EphemBlockchainTestSetup { val validBlock = Fixtures.Blocks.ValidBlock.block blockchain.save(validBlock, Seq.empty, ChainWeight(100, 100), saveAsBestBlock = true) - blockchain.isInChain(validBlock.hash) === (false) + blockchain.isInChain(validBlock.hash) === false // simulation of node restart blockchain.saveBestKnownBlocks(validBlock.header.number - 1) blockchain.isInChain(validBlock.hash) should ===(false) @@ -130,7 +135,7 @@ class BlockchainSpec extends AnyFlatSpec with Matchers with ScalaCheckPropertyCh val validHeader = Fixtures.Blocks.ValidBlock.header - val stateStorage = StateStorage.createTestStateStorage(EphemDataSource())._1 + StateStorage.createTestStateStorage(EphemDataSource())._1 val emptyMpt = MerklePatriciaTrie[Address, Account]( storagesInstance.storages.stateStorage.getBackingStorage(0) ) @@ -189,7 +194,7 @@ class BlockchainSpec extends AnyFlatSpec with Matchers with ScalaCheckPropertyCh //the account doesn't exist, so we can't retrieve it, but we do receive a proof of non-existence with a full path of nodes(root node) that we iterated (retrievedAccountProofWrong.getOrElse(Vector.empty).toList match { case _ @HashNode(_) :: Nil => true - case _ => false + case _ => false }) shouldBe true mptWithAcc.get(wrongAddress) shouldBe None } @@ -207,9 +212,9 @@ class BlockchainSpec extends AnyFlatSpec with Matchers with ScalaCheckPropertyCh (stubStateStorage .onBlockSave(_: BigInt, _: BigInt)(_: () => Unit)) .when(*, *, *) - .onCall((bn, _, persistFn) => { + .onCall { (bn, _, persistFn) => if (blockImportToPersist.exists(_.number == bn)) persistFn() - }) + } blocksToImport.foreach { block => blockchainWithStubPersisting.save(block, Nil, ChainWeight.zero, true) @@ -230,9 +235,9 @@ class BlockchainSpec extends AnyFlatSpec with Matchers with ScalaCheckPropertyCh (stubStateStorage .onBlockRollback(_: BigInt, _: BigInt)(_: () => Unit)) .when(*, *, *) - .onCall((bn, _, persistFn) => { + .onCall { (bn, _, persistFn) => if (blockRollbackToPersist.exists(_.number == bn)) persistFn() - }) + } blocksToRollback.reverse.foreach { block => blockchainWithStubPersisting.removeBlock(block.hash, true) @@ -256,14 +261,14 @@ class BlockchainSpec extends AnyFlatSpec with Matchers with ScalaCheckPropertyCh blockImportPersisted: Option[BigInt], blockRollbackPersisted: Option[BigInt], blocksRollbacked: Seq[BigInt] - ): BigInt = { + ): BigInt = (blocksRollbacked, blockImportPersisted) match { case (Nil, Some(bi)) => // No blocks rollbacked, last persist was the persist during import bi case (nonEmptyRollbackedBlocks, Some(bi)) => // Last forced persist during apply/rollback - val maxForcedPersist = blockRollbackPersisted.fold(bi) { br => (br - 1).max(bi) } + val maxForcedPersist = blockRollbackPersisted.fold(bi)(br => (br - 1).max(bi)) // The above number would have been decreased by any rollbacked blocks (nonEmptyRollbackedBlocks.head - 1).min(maxForcedPersist) @@ -271,7 +276,6 @@ class BlockchainSpec extends AnyFlatSpec with Matchers with ScalaCheckPropertyCh // If persisted rollback, then it was decreased by the future rollbacks, if not no persistance was ever done blockRollbackPersisted.fold(0: BigInt)(_ => blocksRollbacked.head - 1) } - } trait StubPersistingBlockchainSetup { def stubStateStorage: StateStorage @@ -280,7 +284,7 @@ class BlockchainSpec extends AnyFlatSpec with Matchers with ScalaCheckPropertyCh def blockchainWithStubPersisting: BlockchainImpl } - def newSetup(): StubPersistingBlockchainSetup = { + def newSetup(): StubPersistingBlockchainSetup = new StubPersistingBlockchainSetup with EphemBlockchainTestSetup { override val stubStateStorage = stub[StateStorage] override val blockchainStoragesWithStubPersisting = new BlockchainStorages { @@ -291,8 +295,8 @@ class BlockchainSpec extends AnyFlatSpec with Matchers with ScalaCheckPropertyCh val evmCodeStorage = storagesInstance.storages.evmCodeStorage val chainWeightStorage = storagesInstance.storages.chainWeightStorage val transactionMappingStorage = storagesInstance.storages.transactionMappingStorage - val nodeStorage = storagesInstance.storages.nodeStorage - val pruningMode = storagesInstance.storages.pruningMode + storagesInstance.storages.nodeStorage + storagesInstance.storages.pruningMode val appStateStorage = storagesInstance.storages.appStateStorage val cachedNodeStorage = storagesInstance.storages.cachedNodeStorage val stateStorage = stubStateStorage @@ -303,7 +307,6 @@ class BlockchainSpec extends AnyFlatSpec with Matchers with ScalaCheckPropertyCh blockchainWithStubPersisting.storeBlock(Fixtures.Blocks.Genesis.block) } - } } } diff --git a/src/test/scala/io/iohk/ethereum/domain/SignedTransactionSpec.scala b/src/test/scala/io/iohk/ethereum/domain/SignedTransactionSpec.scala index b70f3e8678..98687ad9c6 100644 --- a/src/test/scala/io/iohk/ethereum/domain/SignedTransactionSpec.scala +++ b/src/test/scala/io/iohk/ethereum/domain/SignedTransactionSpec.scala @@ -1,15 +1,16 @@ package io.iohk.ethereum.domain +import org.bouncycastle.crypto.params.ECPublicKeyParameters +import org.scalacheck.Arbitrary +import org.scalatest.flatspec.AnyFlatSpec +import org.scalatest.matchers.should.Matchers +import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks + import io.iohk.ethereum.crypto import io.iohk.ethereum.crypto.generateKeyPair import io.iohk.ethereum.domain.SignedTransaction.FirstByteOfAddress import io.iohk.ethereum.security.SecureRandomBuilder import io.iohk.ethereum.vm.Generators -import org.scalacheck.Arbitrary -import org.bouncycastle.crypto.params.ECPublicKeyParameters -import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks -import org.scalatest.flatspec.AnyFlatSpec -import org.scalatest.matchers.should.Matchers class SignedTransactionSpec extends AnyFlatSpec with Matchers with ScalaCheckPropertyChecks with SecureRandomBuilder { "SignedTransaction" should "correctly set pointSign for chainId with chain specific signing schema" in { diff --git a/src/test/scala/io/iohk/ethereum/domain/UInt256Spec.scala b/src/test/scala/io/iohk/ethereum/domain/UInt256Spec.scala index 9ce0d3928c..63b4dd9cf7 100644 --- a/src/test/scala/io/iohk/ethereum/domain/UInt256Spec.scala +++ b/src/test/scala/io/iohk/ethereum/domain/UInt256Spec.scala @@ -1,17 +1,20 @@ package io.iohk.ethereum.domain import akka.util.ByteString -import io.iohk.ethereum.vm.Generators._ -import io.iohk.ethereum.domain.UInt256._ -import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks + import org.scalatest.funsuite.AnyFunSuite +import org.scalatest.prop.TableFor2 +import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks + +import io.iohk.ethereum.domain.UInt256._ +import io.iohk.ethereum.vm.Generators._ class UInt256Spec extends AnyFunSuite with ScalaCheckPropertyChecks { val Modulus: BigInt = UInt256.MaxValue.toBigInt + 1 val MaxSignedValue: BigInt = Modulus / 2 - 1 - val specialNumbers = + val specialNumbers: Seq[BigInt] = Seq(BigInt(-1), BigInt(0), BigInt(1), MaxValue.toBigInt, -MaxValue.toBigInt, -MaxValue.toBigInt + 1) val pairs: Seq[(BigInt, BigInt)] = specialNumbers @@ -19,7 +22,7 @@ class UInt256Spec extends AnyFunSuite with ScalaCheckPropertyChecks { .map { case Seq(n1, n2) => n1 -> n2 } .toSeq - val specialCases = Table(("n1", "n2"), pairs: _*) + val specialCases: TableFor2[BigInt, BigInt] = Table(("n1", "n2"), pairs: _*) def toSignedBigInt(n: BigInt): BigInt = if (n > MaxSignedValue) n - Modulus else n @@ -116,48 +119,48 @@ class UInt256Spec extends AnyFunSuite with ScalaCheckPropertyChecks { test("div") { forAll(bigIntGen, bigIntGen) { (n1: BigInt, n2: BigInt) => whenever(n2 != 0) { - assert((UInt256(n1) div UInt256(n2)) == UInt256(n1 / n2)) + assert((UInt256(n1).div(UInt256(n2))) == UInt256(n1 / n2)) } } forAll(specialCases) { (n1: BigInt, n2: BigInt) => whenever(n1 > 0 && n2 > 0) { - assert((UInt256(n1) div UInt256(n2)) == UInt256(n1 / n2)) + assert((UInt256(n1).div(UInt256(n2))) == UInt256(n1 / n2)) } } - assert((UInt256(1) div Zero) == Zero) + assert((UInt256(1).div(Zero)) == Zero) } test("sdiv") { forAll(bigIntGen, bigIntGen) { (n1: BigInt, n2: BigInt) => whenever(n2 != 0) { val expected: BigInt = toUnsignedBigInt(toSignedBigInt(n1) / toSignedBigInt(n2)) - assert((UInt256(n1) sdiv UInt256(n2)) == UInt256(expected)) + assert((UInt256(n1).sdiv(UInt256(n2))) == UInt256(expected)) } } - assert((UInt256(-1) sdiv UInt256(-MaxValue.toBigInt)) == UInt256(-1)) - assert((UInt256(-1) sdiv Zero) == Zero) + assert((UInt256(-1).sdiv(UInt256(-MaxValue.toBigInt))) == UInt256(-1)) + assert((UInt256(-1).sdiv(Zero)) == Zero) } test("mod") { forAll(bigIntGen, bigIntGen) { (n1: BigInt, n2: BigInt) => whenever(n2 != 0) { - assert((UInt256(n1) mod UInt256(n2)) == UInt256(n1 mod n2)) + assert((UInt256(n1).mod(UInt256(n2))) == UInt256(n1.mod(n2))) } } - assert((UInt256(-1) mod UInt256(MaxValue.toBigInt)) == Zero) - assert((UInt256(1) mod Zero) == Zero) + assert((UInt256(-1).mod(UInt256(MaxValue.toBigInt))) == Zero) + assert((UInt256(1).mod(Zero)) == Zero) } test("smod") { - assert((UInt256(Modulus - 1) smod UInt256(3)) == UInt256(Modulus - 1)) - assert((UInt256(-1) smod UInt256(MaxValue.toBigInt)) == Zero) - assert((UInt256(1) smod Zero) == Zero) + assert((UInt256(Modulus - 1).smod(UInt256(3))) == UInt256(Modulus - 1)) + assert((UInt256(-1).smod(UInt256(MaxValue.toBigInt))) == Zero) + assert((UInt256(1).smod(Zero)) == Zero) } test("addmod") { forAll(bigIntGen, bigIntGen, bigIntGen) { (n1: BigInt, n2: BigInt, n3: BigInt) => whenever(n3 != 0) { - assert(UInt256(n1).addmod(UInt256(n2), UInt256(n3)) == UInt256((n1 + n2) mod n3)) + assert(UInt256(n1).addmod(UInt256(n2), UInt256(n3)) == UInt256((n1 + n2).mod(n3))) } } assert(UInt256(42).addmod(UInt256(42), Zero) == Zero) @@ -166,7 +169,7 @@ class UInt256Spec extends AnyFunSuite with ScalaCheckPropertyChecks { test("mulmod") { forAll(bigIntGen, bigIntGen, bigIntGen) { (n1: BigInt, n2: BigInt, n3: BigInt) => whenever(n3 != 0) { - assert(UInt256(n1).mulmod(UInt256(n2), UInt256(n3)) == UInt256((n1 * n2) mod n3)) + assert(UInt256(n1).mulmod(UInt256(n2), UInt256(n3)) == UInt256((n1 * n2).mod(n3))) } } assert(UInt256(42).mulmod(UInt256(42), Zero) == Zero) @@ -223,26 +226,26 @@ class UInt256Spec extends AnyFunSuite with ScalaCheckPropertyChecks { test("slt") { forAll(bigIntGen, bigIntGen) { (n1: BigInt, n2: BigInt) => - assert((UInt256(n1) slt UInt256(n2)) == (toSignedBigInt(n1) < toSignedBigInt(n2))) + assert((UInt256(n1).slt(UInt256(n2))) == (toSignedBigInt(n1) < toSignedBigInt(n2))) } val testData = Table[UInt256, UInt256, Boolean](("a", "b", "result"), (-1, 1, true), (1, -1, false), (1, 0, false)) forAll(testData) { (a, b, result) => - assert((a slt b) == result) + assert((a.slt(b)) == result) } } test("sgt") { forAll(bigIntGen, bigIntGen) { (n1: BigInt, n2: BigInt) => - assert((UInt256(n1) sgt UInt256(n2)) == (toSignedBigInt(n1) > toSignedBigInt(n2))) + assert((UInt256(n1).sgt(UInt256(n2))) == (toSignedBigInt(n1) > toSignedBigInt(n2))) } val testData = Table[UInt256, UInt256, Boolean](("a", "b", "result"), (-1, 1, false), (1, -1, true), (0, 1, false), (1, 0, true)) forAll(testData) { (a, b, result) => - assert((a sgt b) == result) + assert((a.sgt(b)) == result) } } diff --git a/src/test/scala/io/iohk/ethereum/extvm/MessageHandlerSpec.scala b/src/test/scala/io/iohk/ethereum/extvm/MessageHandlerSpec.scala index 465f796614..ad6c3ad263 100644 --- a/src/test/scala/io/iohk/ethereum/extvm/MessageHandlerSpec.scala +++ b/src/test/scala/io/iohk/ethereum/extvm/MessageHandlerSpec.scala @@ -1,23 +1,31 @@ package io.iohk.ethereum.extvm +import java.math.BigInteger + import akka.actor.ActorSystem import akka.stream.OverflowStrategy -import akka.stream.scaladsl.{Keep, Sink, SinkQueueWithCancel, Source, SourceQueueWithComplete} +import akka.stream.scaladsl.Keep +import akka.stream.scaladsl.Sink +import akka.stream.scaladsl.SinkQueueWithCancel +import akka.stream.scaladsl.Source +import akka.stream.scaladsl.SourceQueueWithComplete import akka.testkit.TestProbe import akka.util.ByteString -import scalapb.{GeneratedMessage, GeneratedMessageCompanion} -import io.iohk.ethereum.vm.Generators -import java.math.BigInteger + +import scala.concurrent.ExecutionContext.Implicits.global import com.google.protobuf.CodedOutputStream import org.bouncycastle.util.BigIntegers import org.scalamock.scalatest.MockFactory -import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks - -import scala.concurrent.ExecutionContext.Implicits.global import org.scalatest.flatspec.AnyFlatSpec import org.scalatest.matchers.should.Matchers -import scalapb.descriptors.{FieldDescriptor, PValue} +import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks +import scalapb.GeneratedMessage +import scalapb.GeneratedMessageCompanion +import scalapb.descriptors.FieldDescriptor +import scalapb.descriptors.PValue + +import io.iohk.ethereum.vm.Generators class MessageHandlerSpec extends AnyFlatSpec with Matchers with MockFactory with ScalaCheckPropertyChecks { diff --git a/src/test/scala/io/iohk/ethereum/extvm/VMClientSpec.scala b/src/test/scala/io/iohk/ethereum/extvm/VMClientSpec.scala index ea253cfafb..428c719582 100644 --- a/src/test/scala/io/iohk/ethereum/extvm/VMClientSpec.scala +++ b/src/test/scala/io/iohk/ethereum/extvm/VMClientSpec.scala @@ -1,16 +1,24 @@ package io.iohk.ethereum.extvm import akka.util.ByteString -import scalapb.GeneratedMessageCompanion -import io.iohk.ethereum.domain.{Account, Address, UInt256} -import io.iohk.ethereum.extvm.msg.CallContext.Config -import io.iohk.ethereum.utils.{ForkBlockNumbers, VmConfig} -import io.iohk.ethereum.vm.utils.MockVmInput -import io.iohk.ethereum.vm._ -import org.scalamock.scalatest.MockFactory + import org.bouncycastle.util.encoders.Hex +import org.scalamock.scalatest.MockFactory import org.scalatest.flatspec.AnyFlatSpec import org.scalatest.matchers.should.Matchers +import scalapb.GeneratedMessageCompanion + +import io.iohk.ethereum.domain.Account +import io.iohk.ethereum.domain.Address +import io.iohk.ethereum.domain.SignedTransaction +import io.iohk.ethereum.domain.UInt256 +import io.iohk.ethereum.extvm.msg.CallContext.Config +import io.iohk.ethereum.extvm.msg.CallResult +import io.iohk.ethereum.extvm.msg.VMQuery +import io.iohk.ethereum.utils.ForkBlockNumbers +import io.iohk.ethereum.utils.VmConfig +import io.iohk.ethereum.vm._ +import io.iohk.ethereum.vm.utils.MockVmInput class VMClientSpec extends AnyFlatSpec with Matchers with MockFactory { @@ -170,9 +178,9 @@ class VMClientSpec extends AnyFlatSpec with Matchers with MockFactory { trait TestSetup { val blockHeader = Block3125369.header - val emptyWorld = MockWorldState() + val emptyWorld: MockWorldState = MockWorldState() - val blockchainConfigForEvm = BlockchainConfigForEvm( + val blockchainConfigForEvm: BlockchainConfigForEvm = BlockchainConfigForEvm( frontierBlockNumber = 0, homesteadBlockNumber = 0, eip150BlockNumber = 0, @@ -189,12 +197,12 @@ class VMClientSpec extends AnyFlatSpec with Matchers with MockFactory { phoenixBlockNumber = 0, chainId = 0x3d.toByte ) - val evmConfig = EvmConfig.FrontierConfigBuilder(blockchainConfigForEvm) + val evmConfig: EvmConfig = EvmConfig.FrontierConfigBuilder(blockchainConfigForEvm) - val senderAddress = Address("0x01") - val tx = MockVmInput.transaction(senderAddress, ByteString(""), 10, 123, 456) + val senderAddress: Address = Address("0x01") + val tx: SignedTransaction = MockVmInput.transaction(senderAddress, ByteString(""), 10, 123, 456) - val callResultMsg = msg.CallResult( + val callResultMsg: CallResult = msg.CallResult( returnData = ByteString("0011"), returnCode = ByteString(""), gasRemaining = ByteString(BigInt(99).toByteArray), @@ -203,11 +211,11 @@ class VMClientSpec extends AnyFlatSpec with Matchers with MockFactory { modifiedAccounts = Nil ) - val resultQueryMsg = msg.VMQuery(query = msg.VMQuery.Query.CallResult(callResultMsg)) + val resultQueryMsg: VMQuery = msg.VMQuery(query = msg.VMQuery.Query.CallResult(callResultMsg)) - val messageHandler = mock[MessageHandler] + val messageHandler: MessageHandler = mock[MessageHandler] - val externalVmConfig = VmConfig.ExternalConfig("mantis", None, "127.0.0.1", 0) + val externalVmConfig: VmConfig.ExternalConfig = VmConfig.ExternalConfig("mantis", None, "127.0.0.1", 0) val vmClient = new VMClient(externalVmConfig, messageHandler, testMode = false) } diff --git a/src/test/scala/io/iohk/ethereum/extvm/VMServerSpec.scala b/src/test/scala/io/iohk/ethereum/extvm/VMServerSpec.scala index 77068debe5..1aecc76732 100644 --- a/src/test/scala/io/iohk/ethereum/extvm/VMServerSpec.scala +++ b/src/test/scala/io/iohk/ethereum/extvm/VMServerSpec.scala @@ -1,12 +1,18 @@ package io.iohk.ethereum.extvm import akka.util.ByteString -import scalapb.GeneratedMessageCompanion -import io.iohk.ethereum.domain.{Account, Address} -import io.iohk.ethereum.extvm.msg.{CallContext, VMQuery} + import org.scalamock.scalatest.MockFactory import org.scalatest.flatspec.AnyFlatSpec import org.scalatest.matchers.should.Matchers +import scalapb.GeneratedMessageCompanion + +import io.iohk.ethereum.domain.Account +import io.iohk.ethereum.domain.Address +import io.iohk.ethereum.extvm.msg.CallContext +import io.iohk.ethereum.extvm.msg.EthereumConfig +import io.iohk.ethereum.extvm.msg.Hello +import io.iohk.ethereum.extvm.msg.VMQuery class VMServerSpec extends AnyFlatSpec with Matchers with MockFactory { @@ -101,7 +107,7 @@ class VMServerSpec extends AnyFlatSpec with Matchers with MockFactory { trait TestSetup { val blockchainConfig = io.iohk.ethereum.utils.Config.blockchains.blockchainConfig val forkBlockNumbers = blockchainConfig.forkBlockNumbers - val ethereumConfig = msg.EthereumConfig( + val ethereumConfig: EthereumConfig = msg.EthereumConfig( frontierBlockNumber = forkBlockNumbers.frontierBlockNumber, homesteadBlockNumber = forkBlockNumbers.homesteadBlockNumber, eip150BlockNumber = forkBlockNumbers.eip150BlockNumber, @@ -110,10 +116,10 @@ class VMServerSpec extends AnyFlatSpec with Matchers with MockFactory { maxCodeSize = ByteString(), accountStartNonce = blockchainConfig.accountStartNonce ) - val ethereumConfigMsg = msg.Hello.Config.EthereumConfig(ethereumConfig) - val helloMsg = msg.Hello(version = "2.0", config = ethereumConfigMsg) + val ethereumConfigMsg: Hello.Config.EthereumConfig = msg.Hello.Config.EthereumConfig(ethereumConfig) + val helloMsg: Hello = msg.Hello(version = "2.0", config = ethereumConfigMsg) - val messageHandler = mock[MessageHandler] + val messageHandler: MessageHandler = mock[MessageHandler] val vmServer = new VMServer(messageHandler) def expectAccountQuery(address: Address, response: Account): Unit = { diff --git a/src/test/scala/io/iohk/ethereum/extvm/WorldSpec.scala b/src/test/scala/io/iohk/ethereum/extvm/WorldSpec.scala index 700aacd2aa..6aa0f47b6c 100644 --- a/src/test/scala/io/iohk/ethereum/extvm/WorldSpec.scala +++ b/src/test/scala/io/iohk/ethereum/extvm/WorldSpec.scala @@ -1,12 +1,16 @@ package io.iohk.ethereum.extvm import akka.util.ByteString -import scalapb.GeneratedMessageCompanion -import io.iohk.ethereum.domain.{Account, Address, UInt256} -import org.scalamock.scalatest.MockFactory + import org.bouncycastle.util.encoders.Hex +import org.scalamock.scalatest.MockFactory import org.scalatest.flatspec.AnyFlatSpec import org.scalatest.matchers.should.Matchers +import scalapb.GeneratedMessageCompanion + +import io.iohk.ethereum.domain.Account +import io.iohk.ethereum.domain.Address +import io.iohk.ethereum.domain.UInt256 class WorldSpec extends AnyFlatSpec with Matchers with MockFactory { @@ -72,9 +76,9 @@ class WorldSpec extends AnyFlatSpec with Matchers with MockFactory { } trait TestSetup { - val addr = Address("0xFF") - val messageHandler = mock[MessageHandler] - val world = World(accountStartNonce = 0, noEmptyAccountsCond = true, messageHandler = messageHandler) + val addr: Address = Address("0xFF") + val messageHandler: MessageHandler = mock[MessageHandler] + val world: World = World(accountStartNonce = 0, noEmptyAccountsCond = true, messageHandler = messageHandler) } } diff --git a/src/test/scala/io/iohk/ethereum/faucet/FaucetHandlerSpec.scala b/src/test/scala/io/iohk/ethereum/faucet/FaucetHandlerSpec.scala index 540a643400..0784655c7f 100644 --- a/src/test/scala/io/iohk/ethereum/faucet/FaucetHandlerSpec.scala +++ b/src/test/scala/io/iohk/ethereum/faucet/FaucetHandlerSpec.scala @@ -2,26 +2,39 @@ package io.iohk.ethereum.faucet import java.security.SecureRandom -import akka.actor.{ActorSystem, Props} +import akka.actor.ActorRef +import akka.actor.ActorSystem +import akka.actor.Props import akka.pattern.gracefulStop -import akka.testkit.{ImplicitSender, TestKit, TestProbe} +import akka.testkit.ImplicitSender +import akka.testkit.TestKit +import akka.testkit.TestProbe import akka.util.ByteString -import io.iohk.ethereum.crypto.{generateKeyPair, keyPairToByteStrings} -import io.iohk.ethereum.domain.Address -import io.iohk.ethereum.faucet.FaucetHandler.{FaucetHandlerMsg, FaucetHandlerResponse} -import io.iohk.ethereum.faucet.jsonrpc.WalletService -import io.iohk.ethereum.jsonrpc.client.RpcClient.{ParserError, RpcClientError} -import io.iohk.ethereum.keystore.KeyStore.DecryptionFailed -import io.iohk.ethereum.keystore.Wallet -import io.iohk.ethereum.{NormalPatience, WithActorSystemShutDown, crypto} + import monix.eval.Task + +import scala.concurrent.ExecutionContext + +import org.bouncycastle.crypto.AsymmetricCipherKeyPair import org.bouncycastle.util.encoders.Hex import org.scalamock.scalatest.MockFactory import org.scalatest.concurrent.ScalaFutures import org.scalatest.freespec.AnyFreeSpecLike import org.scalatest.matchers.should.Matchers -import scala.concurrent.ExecutionContext +import io.iohk.ethereum.NormalPatience +import io.iohk.ethereum.WithActorSystemShutDown +import io.iohk.ethereum.crypto +import io.iohk.ethereum.crypto.generateKeyPair +import io.iohk.ethereum.crypto.keyPairToByteStrings +import io.iohk.ethereum.domain.Address +import io.iohk.ethereum.faucet.FaucetHandler.FaucetHandlerMsg +import io.iohk.ethereum.faucet.FaucetHandler.FaucetHandlerResponse +import io.iohk.ethereum.faucet.jsonrpc.WalletService +import io.iohk.ethereum.jsonrpc.client.RpcClient.ParserError +import io.iohk.ethereum.jsonrpc.client.RpcClient.RpcClientError +import io.iohk.ethereum.keystore.KeyStore.DecryptionFailed +import io.iohk.ethereum.keystore.Wallet class FaucetHandlerSpec extends TestKit(ActorSystem("ActorSystem_DebugFaucetHandlerSpec")) @@ -110,13 +123,13 @@ class FaucetHandlerSpec val walletService: WalletService = mock[WalletService] val paymentAddress: Address = Address("0x99") - val faucetHandler = system.actorOf(FaucetHandlerFake.props(walletService, faucetConfig)) + val faucetHandler: ActorRef = system.actorOf(FaucetHandlerFake.props(walletService, faucetConfig)) - val walletKeyPair = generateKeyPair(new SecureRandom) + val walletKeyPair: AsymmetricCipherKeyPair = generateKeyPair(new SecureRandom) val (prvKey, pubKey) = keyPairToByteStrings(walletKeyPair) - val wallet = Wallet(Address(crypto.kec256(pubKey)), prvKey) + val wallet: Wallet = Wallet(Address(crypto.kec256(pubKey)), prvKey) - val sender = TestProbe() + val sender: TestProbe = TestProbe() def withUnavailableFaucet(behaviour: => Unit): Unit = { (() => walletService.getWallet).expects().returning(Task.pure(Left(DecryptionFailed))) @@ -139,9 +152,8 @@ class FaucetHandlerSpec stopController() } - def stopController(): Unit = { + def stopController(): Unit = awaitCond(gracefulStop(faucetHandler, actorAskTimeout.duration).futureValue) - } } } diff --git a/src/test/scala/io/iohk/ethereum/faucet/jsonrpc/FaucetRpcServiceSpec.scala b/src/test/scala/io/iohk/ethereum/faucet/jsonrpc/FaucetRpcServiceSpec.scala index 4f14578059..b51a8da6ef 100644 --- a/src/test/scala/io/iohk/ethereum/faucet/jsonrpc/FaucetRpcServiceSpec.scala +++ b/src/test/scala/io/iohk/ethereum/faucet/jsonrpc/FaucetRpcServiceSpec.scala @@ -1,24 +1,16 @@ package io.iohk.ethereum.faucet.jsonrpc -import akka.actor.{ActorRef, ActorSystem} -import akka.testkit.{TestKit, TestProbe} +import akka.actor.ActorRef +import akka.actor.ActorSystem +import akka.testkit.TestKit +import akka.testkit.TestProbe import akka.util.ByteString -import io.iohk.ethereum.domain.Address -import io.iohk.ethereum.faucet.FaucetHandler.FaucetHandlerMsg -import io.iohk.ethereum.faucet.FaucetHandler.FaucetHandlerResponse.{ - FaucetIsUnavailable, - StatusResponse, - TransactionSent, - WalletRpcClientError -} -import io.iohk.ethereum.faucet.FaucetStatus.WalletAvailable -import io.iohk.ethereum.faucet.jsonrpc.FaucetDomain.{SendFundsRequest, StatusRequest} -import io.iohk.ethereum.faucet.{FaucetConfig, RpcClientConfig, SupervisorConfig} -import io.iohk.ethereum.jsonrpc.JsonRpcError -import io.iohk.ethereum.testing.ActorsTesting.simpleAutoPilot -import io.iohk.ethereum.{NormalPatience, WithActorSystemShutDown} + import monix.eval.Task import monix.execution.Scheduler.Implicits.global + +import scala.concurrent.duration._ + import org.bouncycastle.util.encoders.Hex import org.scalactic.TypeCheckedTripleEquals import org.scalamock.scalatest.MockFactory @@ -27,7 +19,22 @@ import org.scalatest.concurrent.ScalaFutures import org.scalatest.flatspec.AnyFlatSpecLike import org.scalatest.matchers.should.Matchers -import scala.concurrent.duration._ +import io.iohk.ethereum.NormalPatience +import io.iohk.ethereum.WithActorSystemShutDown +import io.iohk.ethereum.domain.Address +import io.iohk.ethereum.faucet.FaucetConfig +import io.iohk.ethereum.faucet.FaucetHandler.FaucetHandlerMsg +import io.iohk.ethereum.faucet.FaucetHandler.FaucetHandlerResponse.FaucetIsUnavailable +import io.iohk.ethereum.faucet.FaucetHandler.FaucetHandlerResponse.StatusResponse +import io.iohk.ethereum.faucet.FaucetHandler.FaucetHandlerResponse.TransactionSent +import io.iohk.ethereum.faucet.FaucetHandler.FaucetHandlerResponse.WalletRpcClientError +import io.iohk.ethereum.faucet.FaucetStatus.WalletAvailable +import io.iohk.ethereum.faucet.RpcClientConfig +import io.iohk.ethereum.faucet.SupervisorConfig +import io.iohk.ethereum.faucet.jsonrpc.FaucetDomain.SendFundsRequest +import io.iohk.ethereum.faucet.jsonrpc.FaucetDomain.StatusRequest +import io.iohk.ethereum.jsonrpc.JsonRpcError +import io.iohk.ethereum.testing.ActorsTesting.simpleAutoPilot class FaucetRpcServiceSpec extends TestKit(ActorSystem("ActorSystem_DebugFaucetRpcServiceSpec")) @@ -49,7 +56,7 @@ class FaucetRpcServiceSpec TransactionSent(txHash) }) faucetRpcService.sendFunds(request).runSyncUnsafe(Duration.Inf) match { - case Left(error) => fail(s"failure with error: $error") + case Left(error) => fail(s"failure with error: $error") case Right(response) => response.txId shouldBe txHash } } @@ -63,7 +70,7 @@ class FaucetRpcServiceSpec WalletRpcClientError(clientError) }) faucetRpcService.sendFunds(request).runSyncUnsafe(Duration.Inf) match { - case Right(_) => fail() + case Right(_) => fail() case Left(error) => error shouldBe JsonRpcError.LogicError(s"Faucet error: $clientError") } } @@ -98,7 +105,7 @@ class FaucetRpcServiceSpec StatusResponse(WalletAvailable) }) faucetRpcService.status(StatusRequest()).runSyncUnsafe(Duration.Inf) match { - case Left(error) => fail(s"failure with error: $error") + case Left(error) => fail(s"failure with error: $error") case Right(response) => response shouldBe FaucetDomain.StatusResponse(WalletAvailable) } } @@ -116,7 +123,7 @@ class FaucetRpcServiceSpec it should "answer internal error when tried to get status but the Faucet Handler is disable" in new TestSetup { val address: Address = Address("0x00") - val request: SendFundsRequest = SendFundsRequest(address) + SendFundsRequest(address) faucetRpcServiceWithoutFaucetHandler.status(StatusRequest()).runSyncUnsafe(Duration.Inf) match { case Right(_) => fail() @@ -141,18 +148,16 @@ class FaucetRpcServiceSpec shutdownTimeout = 15.seconds ) - val faucetHandler = TestProbe() + val faucetHandler: TestProbe = TestProbe() val faucetRpcService: FaucetRpcService = new FaucetRpcService(config) { - override def selectFaucetHandler()(implicit system: ActorSystem): Task[ActorRef] = { + override def selectFaucetHandler()(implicit system: ActorSystem): Task[ActorRef] = Task(faucetHandler.ref) - } } val faucetRpcServiceWithoutFaucetHandler: FaucetRpcService = new FaucetRpcService(config) { - override def selectFaucetHandler()(implicit system: ActorSystem): Task[ActorRef] = { + override def selectFaucetHandler()(implicit system: ActorSystem): Task[ActorRef] = Task.raiseError(new RuntimeException("time out")) - } } } diff --git a/src/test/scala/io/iohk/ethereum/faucet/jsonrpc/WalletServiceSpec.scala b/src/test/scala/io/iohk/ethereum/faucet/jsonrpc/WalletServiceSpec.scala index 1fb1066253..1767672728 100644 --- a/src/test/scala/io/iohk/ethereum/faucet/jsonrpc/WalletServiceSpec.scala +++ b/src/test/scala/io/iohk/ethereum/faucet/jsonrpc/WalletServiceSpec.scala @@ -3,22 +3,31 @@ package io.iohk.ethereum.faucet.jsonrpc import java.security.SecureRandom import akka.util.ByteString -import io.iohk.ethereum.crypto._ -import io.iohk.ethereum.domain.{Address, Transaction} -import io.iohk.ethereum.faucet.{FaucetConfig, RpcClientConfig, SupervisorConfig} -import io.iohk.ethereum.jsonrpc.client.RpcClient.ConnectionError -import io.iohk.ethereum.keystore.KeyStore.DecryptionFailed -import io.iohk.ethereum.keystore.{KeyStore, Wallet} -import io.iohk.ethereum.network.p2p.messages.BaseETH6XMessages.SignedTransactions.SignedTransactionEnc -import io.iohk.ethereum.{crypto, rlp} + import monix.eval.Task import monix.execution.Scheduler.Implicits.global + +import scala.concurrent.duration._ + +import org.bouncycastle.crypto.AsymmetricCipherKeyPair import org.bouncycastle.util.encoders.Hex import org.scalamock.scalatest.MockFactory import org.scalatest.flatspec.AnyFlatSpec import org.scalatest.matchers.should.Matchers -import scala.concurrent.duration._ +import io.iohk.ethereum.crypto +import io.iohk.ethereum.crypto._ +import io.iohk.ethereum.domain.Address +import io.iohk.ethereum.domain.Transaction +import io.iohk.ethereum.faucet.FaucetConfig +import io.iohk.ethereum.faucet.RpcClientConfig +import io.iohk.ethereum.faucet.SupervisorConfig +import io.iohk.ethereum.jsonrpc.client.RpcClient.ConnectionError +import io.iohk.ethereum.keystore.KeyStore +import io.iohk.ethereum.keystore.KeyStore.DecryptionFailed +import io.iohk.ethereum.keystore.Wallet +import io.iohk.ethereum.network.p2p.messages.BaseETH6XMessages.SignedTransactions.SignedTransactionEnc +import io.iohk.ethereum.rlp class WalletServiceSpec extends AnyFlatSpec with Matchers with MockFactory { @@ -75,12 +84,12 @@ class WalletServiceSpec extends AnyFlatSpec with Matchers with MockFactory { } trait TestSetup { - val walletKeyPair = generateKeyPair(new SecureRandom) + val walletKeyPair: AsymmetricCipherKeyPair = generateKeyPair(new SecureRandom) val (prvKey, pubKey) = keyPairToByteStrings(walletKeyPair) - val wallet = Wallet(Address(crypto.kec256(pubKey)), prvKey) + val wallet: Wallet = Wallet(Address(crypto.kec256(pubKey)), prvKey) - val walletRpcClient = mock[WalletRpcClient] - val mockKeyStore = mock[KeyStore] + val walletRpcClient: WalletRpcClient = mock[WalletRpcClient] + val mockKeyStore: KeyStore = mock[KeyStore] val config: FaucetConfig = FaucetConfig( walletAddress = wallet.address, diff --git a/src/test/scala/io/iohk/ethereum/forkid/ForkIdSpec.scala b/src/test/scala/io/iohk/ethereum/forkid/ForkIdSpec.scala index 4eafc29fce..95ae053557 100644 --- a/src/test/scala/io/iohk/ethereum/forkid/ForkIdSpec.scala +++ b/src/test/scala/io/iohk/ethereum/forkid/ForkIdSpec.scala @@ -1,16 +1,14 @@ package io.iohk.ethereum.forkid import akka.util.ByteString -import io.iohk.ethereum.forkid.ForkId._ -import io.iohk.ethereum.utils.ForkBlockNumbers -import io.iohk.ethereum.utils.Config._ -import org.scalatest.wordspec.AnyWordSpec -import org.scalatest.matchers.should._ import org.bouncycastle.util.encoders.Hex +import org.scalatest.matchers.should._ +import org.scalatest.wordspec.AnyWordSpec +import io.iohk.ethereum.forkid.ForkId._ import io.iohk.ethereum.rlp._ -import io.iohk.ethereum.rlp.RLPImplicits._ +import io.iohk.ethereum.utils.Config._ class ForkIdSpec extends AnyWordSpec with Matchers { diff --git a/src/test/scala/io/iohk/ethereum/forkid/ForkIdValidatorSpec.scala b/src/test/scala/io/iohk/ethereum/forkid/ForkIdValidatorSpec.scala index bba1f3ad89..ea8be0e7aa 100644 --- a/src/test/scala/io/iohk/ethereum/forkid/ForkIdValidatorSpec.scala +++ b/src/test/scala/io/iohk/ethereum/forkid/ForkIdValidatorSpec.scala @@ -1,16 +1,17 @@ package io.iohk.ethereum.forkid import akka.util.ByteString -import io.iohk.ethereum.forkid.ForkId._ -import io.iohk.ethereum.utils.Config._ -import io.iohk.ethereum.utils.ForkBlockNumbers + import monix.eval.Task import monix.execution.Scheduler.Implicits.global + +import scala.concurrent.duration._ + import org.bouncycastle.util.encoders.Hex import org.scalatest.matchers.should._ import org.scalatest.wordspec.AnyWordSpec -import scala.concurrent.duration._ +import io.iohk.ethereum.utils.Config._ import ForkIdValidator._ @@ -18,7 +19,9 @@ class ForkIdValidatorSpec extends AnyWordSpec with Matchers { val config = blockchains - val ethGenesisHash = ByteString(Hex.decode("d4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3")) + val ethGenesisHash: ByteString = ByteString( + Hex.decode("d4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3") + ) "ForkIdValidator" must { "correctly validate ETH peers" in { diff --git a/src/test/scala/io/iohk/ethereum/jsonrpc/CheckpointingJRCSpec.scala b/src/test/scala/io/iohk/ethereum/jsonrpc/CheckpointingJRCSpec.scala index 8dc965d20d..bfdd2bc559 100644 --- a/src/test/scala/io/iohk/ethereum/jsonrpc/CheckpointingJRCSpec.scala +++ b/src/test/scala/io/iohk/ethereum/jsonrpc/CheckpointingJRCSpec.scala @@ -1,16 +1,9 @@ package io.iohk.ethereum.jsonrpc -import io.iohk.ethereum.checkpointing.CheckpointingTestHelpers -import io.iohk.ethereum.crypto.ECDSASignature -import io.iohk.ethereum.jsonrpc.CheckpointingService._ -import io.iohk.ethereum.jsonrpc.server.controllers.JsonRpcBaseController.JsonRpcConfig -import io.iohk.ethereum.jsonrpc.JsonRpcError.InvalidParams -import io.iohk.ethereum.security.SecureRandomBuilder -import io.iohk.ethereum.nodebuilder.ApisBuilder -import io.iohk.ethereum.utils.{ByteStringUtils, Config} -import io.iohk.ethereum.{Fixtures, NormalPatience, crypto} import monix.eval.Task import monix.execution.Scheduler.Implicits.global + +import org.bouncycastle.crypto.AsymmetricCipherKeyPair import org.json4s.JsonAST._ import org.json4s.JsonDSL._ import org.scalamock.scalatest.MockFactory @@ -18,6 +11,19 @@ import org.scalatest.concurrent.ScalaFutures import org.scalatest.flatspec.AnyFlatSpec import org.scalatest.matchers.should.Matchers +import io.iohk.ethereum.Fixtures +import io.iohk.ethereum.NormalPatience +import io.iohk.ethereum.checkpointing.CheckpointingTestHelpers +import io.iohk.ethereum.crypto +import io.iohk.ethereum.crypto.ECDSASignature +import io.iohk.ethereum.jsonrpc.CheckpointingService._ +import io.iohk.ethereum.jsonrpc.JsonRpcError.InvalidParams +import io.iohk.ethereum.jsonrpc.server.controllers.JsonRpcBaseController.JsonRpcConfig +import io.iohk.ethereum.nodebuilder.ApisBuilder +import io.iohk.ethereum.security.SecureRandomBuilder +import io.iohk.ethereum.utils.ByteStringUtils +import io.iohk.ethereum.utils.Config + class CheckpointingJRCSpec extends AnyFlatSpec with Matchers @@ -185,24 +191,24 @@ class CheckpointingJRCSpec object Req { val block = Fixtures.Blocks.ValidBlock.block - val keys = Seq( + val keys: Seq[AsymmetricCipherKeyPair] = Seq( crypto.generateKeyPair(secureRandom), crypto.generateKeyPair(secureRandom) ) val signatures: List[ECDSASignature] = CheckpointingTestHelpers.createCheckpointSignatures(keys, block.hash).toList - def getLatestBlockRequestBuilder(json: JArray) = JsonRpcRequest( + def getLatestBlockRequestBuilder(json: JArray): JsonRpcRequest = JsonRpcRequest( "2.0", "checkpointing_getLatestBlock", Some(json), Some(1) ) - val expectedPositiveIntegerError = InvalidParams("Expected positive integer") - val notSupportedTypeError = InvalidParams("Not supported type for parentCheckpoint") + val expectedPositiveIntegerError: JsonRpcError = InvalidParams("Expected positive integer") + val notSupportedTypeError: JsonRpcError = InvalidParams("Not supported type for parentCheckpoint") - def pushCheckpointRequestBuilder(json: JArray) = JsonRpcRequest( + def pushCheckpointRequestBuilder(json: JArray): JsonRpcRequest = JsonRpcRequest( "2.0", "checkpointing_pushCheckpoint", Some(json), @@ -213,19 +219,19 @@ class CheckpointingJRCSpec trait TestSetup extends ApisBuilder { def config: JsonRpcConfig = JsonRpcConfig(Config.config, available) - val web3Service = mock[Web3Service] - val netService = mock[NetService] - val personalService = mock[PersonalService] - val debugService = mock[DebugService] - val ethService = mock[EthInfoService] - val ethMiningService = mock[EthMiningService] - val ethBlocksService = mock[EthBlocksService] - val ethTxService = mock[EthTxService] - val ethUserService = mock[EthUserService] - val ethFilterService = mock[EthFilterService] - val qaService = mock[QAService] - val checkpointingService = mock[CheckpointingService] - val mantisService = mock[MantisService] + val web3Service: Web3Service = mock[Web3Service] + val netService: NetService = mock[NetService] + val personalService: PersonalService = mock[PersonalService] + val debugService: DebugService = mock[DebugService] + val ethService: EthInfoService = mock[EthInfoService] + val ethMiningService: EthMiningService = mock[EthMiningService] + val ethBlocksService: EthBlocksService = mock[EthBlocksService] + val ethTxService: EthTxService = mock[EthTxService] + val ethUserService: EthUserService = mock[EthUserService] + val ethFilterService: EthFilterService = mock[EthFilterService] + val qaService: QAService = mock[QAService] + val checkpointingService: CheckpointingService = mock[CheckpointingService] + val mantisService: MantisService = mock[MantisService] val jsonRpcController = new JsonRpcController( diff --git a/src/test/scala/io/iohk/ethereum/jsonrpc/CheckpointingServiceSpec.scala b/src/test/scala/io/iohk/ethereum/jsonrpc/CheckpointingServiceSpec.scala index 8dac73ba15..f2b4e1cb27 100644 --- a/src/test/scala/io/iohk/ethereum/jsonrpc/CheckpointingServiceSpec.scala +++ b/src/test/scala/io/iohk/ethereum/jsonrpc/CheckpointingServiceSpec.scala @@ -1,19 +1,29 @@ package io.iohk.ethereum.jsonrpc import akka.actor.ActorSystem -import akka.testkit.{TestKit, TestProbe} -import io.iohk.ethereum.blockchain.sync.regular.RegularSync.NewCheckpoint -import io.iohk.ethereum.consensus.blocks.CheckpointBlockGenerator -import io.iohk.ethereum.domain.{Block, BlockBody, BlockchainImpl, BlockchainReader, Checkpoint} -import io.iohk.ethereum.jsonrpc.CheckpointingService._ -import io.iohk.ethereum.{Fixtures, NormalPatience, WithActorSystemShutDown} +import akka.testkit.TestKit +import akka.testkit.TestProbe + import monix.execution.Scheduler.Implicits.global + import org.scalacheck.Gen import org.scalamock.scalatest.MockFactory import org.scalatest.concurrent.ScalaFutures import org.scalatest.flatspec.AnyFlatSpecLike import org.scalatest.matchers.should.Matchers import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks + +import io.iohk.ethereum.Fixtures +import io.iohk.ethereum.NormalPatience +import io.iohk.ethereum.WithActorSystemShutDown +import io.iohk.ethereum.blockchain.sync.regular.RegularSync.NewCheckpoint +import io.iohk.ethereum.consensus.blocks.CheckpointBlockGenerator +import io.iohk.ethereum.domain.Block +import io.iohk.ethereum.domain.BlockBody +import io.iohk.ethereum.domain.BlockchainImpl +import io.iohk.ethereum.domain.BlockchainReader +import io.iohk.ethereum.domain.Checkpoint +import io.iohk.ethereum.jsonrpc.CheckpointingService._ import io.iohk.ethereum.ledger.BlockQueue class CheckpointingServiceSpec @@ -173,10 +183,10 @@ class CheckpointingServiceSpec } trait TestSetup { - val blockchain = mock[BlockchainImpl] - val blockchainReader = mock[BlockchainReader] - val blockQueue = mock[BlockQueue] - val syncController = TestProbe() + val blockchain: BlockchainImpl = mock[BlockchainImpl] + val blockchainReader: BlockchainReader = mock[BlockchainReader] + val blockQueue: BlockQueue = mock[BlockQueue] + val syncController: TestProbe = TestProbe() val checkpointBlockGenerator: CheckpointBlockGenerator = new CheckpointBlockGenerator() val service = new CheckpointingService(blockchain, blockchainReader, blockQueue, checkpointBlockGenerator, syncController.ref) diff --git a/src/test/scala/io/iohk/ethereum/jsonrpc/DebugServiceSpec.scala b/src/test/scala/io/iohk/ethereum/jsonrpc/DebugServiceSpec.scala index 5aa8640d05..069ec60ed0 100644 --- a/src/test/scala/io/iohk/ethereum/jsonrpc/DebugServiceSpec.scala +++ b/src/test/scala/io/iohk/ethereum/jsonrpc/DebugServiceSpec.scala @@ -1,21 +1,33 @@ package io.iohk.ethereum.jsonrpc import java.net.InetSocketAddress + import akka.actor.ActorSystem -import akka.testkit.{TestKit, TestProbe} -import io.iohk.ethereum.domain.ChainWeight -import io.iohk.ethereum.jsonrpc.DebugService.{ListPeersInfoRequest, ListPeersInfoResponse} -import io.iohk.ethereum.network.EtcPeerManagerActor.{PeerInfo, RemoteStatus} -import io.iohk.ethereum.network.PeerManagerActor.Peers -import io.iohk.ethereum.network.p2p.messages.ProtocolVersions -import io.iohk.ethereum.network.{EtcPeerManagerActor, Peer, PeerActor, PeerId, PeerManagerActor} -import io.iohk.ethereum.{Fixtures, WithActorSystemShutDown} +import akka.testkit.TestKit +import akka.testkit.TestProbe + import monix.execution.Scheduler.Implicits.global + import org.scalamock.scalatest.MockFactory import org.scalatest.concurrent.ScalaFutures import org.scalatest.flatspec.AnyFlatSpecLike import org.scalatest.matchers.should.Matchers +import io.iohk.ethereum.Fixtures +import io.iohk.ethereum.WithActorSystemShutDown +import io.iohk.ethereum.domain.ChainWeight +import io.iohk.ethereum.jsonrpc.DebugService.ListPeersInfoRequest +import io.iohk.ethereum.jsonrpc.DebugService.ListPeersInfoResponse +import io.iohk.ethereum.network.EtcPeerManagerActor +import io.iohk.ethereum.network.EtcPeerManagerActor.PeerInfo +import io.iohk.ethereum.network.EtcPeerManagerActor.RemoteStatus +import io.iohk.ethereum.network.Peer +import io.iohk.ethereum.network.PeerActor +import io.iohk.ethereum.network.PeerId +import io.iohk.ethereum.network.PeerManagerActor +import io.iohk.ethereum.network.PeerManagerActor.Peers +import io.iohk.ethereum.network.p2p.messages.ProtocolVersions + class DebugServiceSpec extends TestKit(ActorSystem("ActorSystem_DebugServiceSpec")) with AnyFlatSpecLike @@ -59,26 +71,26 @@ class DebugServiceSpec } class TestSetup(implicit system: ActorSystem) { - val peerManager = TestProbe() - val etcPeerManager = TestProbe() + val peerManager: TestProbe = TestProbe() + val etcPeerManager: TestProbe = TestProbe() val debugService = new DebugService(peerManager.ref, etcPeerManager.ref) - val peerStatus = RemoteStatus( + val peerStatus: RemoteStatus = RemoteStatus( protocolVersion = ProtocolVersions.ETH63.version, networkId = 1, chainWeight = ChainWeight.totalDifficultyOnly(10000), bestHash = Fixtures.Blocks.Block3125369.header.hash, genesisHash = Fixtures.Blocks.Genesis.header.hash ) - val initialPeerInfo = PeerInfo( + val initialPeerInfo: PeerInfo = PeerInfo( remoteStatus = peerStatus, chainWeight = peerStatus.chainWeight, forkAccepted = false, maxBlockNumber = Fixtures.Blocks.Block3125369.header.number, bestBlockHash = peerStatus.bestHash ) - val peer1Probe = TestProbe() - val peer1 = Peer(PeerId("peer1"), new InetSocketAddress("127.0.0.1", 1), peer1Probe.ref, false) + val peer1Probe: TestProbe = TestProbe() + val peer1: Peer = Peer(PeerId("peer1"), new InetSocketAddress("127.0.0.1", 1), peer1Probe.ref, false) val peer1Info: PeerInfo = initialPeerInfo.withForkAccepted(false) } } diff --git a/src/test/scala/io/iohk/ethereum/jsonrpc/EthBlocksServiceSpec.scala b/src/test/scala/io/iohk/ethereum/jsonrpc/EthBlocksServiceSpec.scala index f4792690b3..e698e5a90b 100644 --- a/src/test/scala/io/iohk/ethereum/jsonrpc/EthBlocksServiceSpec.scala +++ b/src/test/scala/io/iohk/ethereum/jsonrpc/EthBlocksServiceSpec.scala @@ -3,16 +3,11 @@ package io.iohk.ethereum.jsonrpc import akka.actor.ActorSystem import akka.testkit.TestKit import akka.util.ByteString -import io.iohk.ethereum.blockchain.sync.EphemBlockchainTestSetup -import io.iohk.ethereum.consensus.blocks.{PendingBlock, PendingBlockAndState} -import io.iohk.ethereum.consensus.pow.blocks.PoWBlockGenerator -import io.iohk.ethereum.consensus.{ConsensusConfigs, TestConsensus} -import io.iohk.ethereum.db.storage.AppStateStorage -import io.iohk.ethereum.domain.{Block, BlockBody, ChainWeight, UInt256} -import io.iohk.ethereum.jsonrpc.EthBlocksService._ -import io.iohk.ethereum.ledger.InMemoryWorldStateProxy -import io.iohk.ethereum.{Fixtures, NormalPatience, WithActorSystemShutDown} + import monix.execution.Scheduler.Implicits.global + +import scala.concurrent.duration.Duration + import org.scalactic.TypeCheckedTripleEquals import org.scalamock.scalatest.MockFactory import org.scalatest.OptionValues @@ -20,7 +15,22 @@ import org.scalatest.concurrent.ScalaFutures import org.scalatest.flatspec.AnyFlatSpecLike import org.scalatest.matchers.should.Matchers -import scala.concurrent.duration.Duration +import io.iohk.ethereum.Fixtures +import io.iohk.ethereum.NormalPatience +import io.iohk.ethereum.WithActorSystemShutDown +import io.iohk.ethereum.blockchain.sync.EphemBlockchainTestSetup +import io.iohk.ethereum.consensus.ConsensusConfigs +import io.iohk.ethereum.consensus.TestConsensus +import io.iohk.ethereum.consensus.blocks.PendingBlock +import io.iohk.ethereum.consensus.blocks.PendingBlockAndState +import io.iohk.ethereum.consensus.pow.blocks.PoWBlockGenerator +import io.iohk.ethereum.db.storage.AppStateStorage +import io.iohk.ethereum.domain.Block +import io.iohk.ethereum.domain.BlockBody +import io.iohk.ethereum.domain.ChainWeight +import io.iohk.ethereum.domain.UInt256 +import io.iohk.ethereum.jsonrpc.EthBlocksService._ +import io.iohk.ethereum.ledger.InMemoryWorldStateProxy class EthBlocksServiceSpec extends TestKit(ActorSystem("EthBlocksServiceSpec_ActorSystem")) @@ -395,8 +405,8 @@ class EthBlocksServiceSpec } class TestSetup(implicit system: ActorSystem) extends MockFactory with EphemBlockchainTestSetup { - val blockGenerator = mock[PoWBlockGenerator] - val appStateStorage = mock[AppStateStorage] + val blockGenerator: PoWBlockGenerator = mock[PoWBlockGenerator] + val appStateStorage: AppStateStorage = mock[AppStateStorage] override lazy val consensus: TestConsensus = buildTestConsensus().withBlockGenerator(blockGenerator) override lazy val consensusConfig = ConsensusConfigs.consensusConfig @@ -408,16 +418,16 @@ class EthBlocksServiceSpec blockQueue ) - val blockToRequest = Block(Fixtures.Blocks.Block3125369.header, Fixtures.Blocks.Block3125369.body) + val blockToRequest: Block = Block(Fixtures.Blocks.Block3125369.header, Fixtures.Blocks.Block3125369.body) val blockToRequestNumber = blockToRequest.header.number val blockToRequestHash = blockToRequest.header.hash - val blockWeight = ChainWeight.totalDifficultyOnly(blockToRequest.header.difficulty) + val blockWeight: ChainWeight = ChainWeight.totalDifficultyOnly(blockToRequest.header.difficulty) val uncle = Fixtures.Blocks.DaoForkBlock.header - val uncleWeight = ChainWeight.totalDifficultyOnly(uncle.difficulty) - val blockToRequestWithUncles = blockToRequest.copy(body = BlockBody(Nil, Seq(uncle))) + val uncleWeight: ChainWeight = ChainWeight.totalDifficultyOnly(uncle.difficulty) + val blockToRequestWithUncles: Block = blockToRequest.copy(body = BlockBody(Nil, Seq(uncle))) - val fakeWorld = InMemoryWorldStateProxy( + val fakeWorld: InMemoryWorldStateProxy = InMemoryWorldStateProxy( storagesInstance.storages.evmCodeStorage, blockchain.getBackingMptStorage(-1), (number: BigInt) => blockchainReader.getBlockHeaderByNumber(number).map(_.hash), diff --git a/src/test/scala/io/iohk/ethereum/jsonrpc/EthFilterServiceSpec.scala b/src/test/scala/io/iohk/ethereum/jsonrpc/EthFilterServiceSpec.scala index b130b004fa..761eea8fe9 100644 --- a/src/test/scala/io/iohk/ethereum/jsonrpc/EthFilterServiceSpec.scala +++ b/src/test/scala/io/iohk/ethereum/jsonrpc/EthFilterServiceSpec.scala @@ -3,22 +3,24 @@ package io.iohk.ethereum.jsonrpc import akka.actor.ActorSystem import akka.testkit.TestKit import akka.testkit.TestProbe -import io.iohk.ethereum.NormalPatience -import io.iohk.ethereum.Timeouts -import io.iohk.ethereum.utils.FilterConfig -import io.iohk.ethereum.WithActorSystemShutDown -import io.iohk.ethereum.jsonrpc.EthFilterService._ -import io.iohk.ethereum.jsonrpc.{FilterManager => FM} + +import monix.execution.Scheduler.Implicits.global + +import scala.concurrent.duration.FiniteDuration + import org.scalactic.TypeCheckedTripleEquals import org.scalamock.scalatest.MockFactory +import org.scalatest.OptionValues import org.scalatest.concurrent.ScalaFutures import org.scalatest.flatspec.AnyFlatSpecLike import org.scalatest.matchers.should.Matchers -import org.scalatest.OptionValues -import scala.concurrent.duration.FiniteDuration -import monix.execution.Scheduler.Implicits.global -import io.iohk.ethereum.jsonrpc.FilterManager.UninstallFilter -import io.iohk.ethereum.jsonrpc.FilterManager.FilterChanges + +import io.iohk.ethereum.NormalPatience +import io.iohk.ethereum.Timeouts +import io.iohk.ethereum.WithActorSystemShutDown +import io.iohk.ethereum.jsonrpc.EthFilterService._ +import io.iohk.ethereum.jsonrpc.{FilterManager => FM} +import io.iohk.ethereum.utils.FilterConfig class EthFilterServiceSpec extends TestKit(ActorSystem("EthFilterServiceSpec_ActorSystem")) @@ -50,7 +52,7 @@ class EthFilterServiceSpec val res = ethFilterService.newPendingTransactionFilter(NewPendingTransactionFilterRequest()).runToFuture filterManager.expectMsg(FM.NewPendingTransactionFilter) filterManager.reply(FM.NewFilterResponse(123)) - res.futureValue shouldEqual Right(NewFilterResponse((123))) + res.futureValue shouldEqual Right(NewFilterResponse(123)) } it should "handle uninstallFilter request" in new TestSetup { @@ -86,8 +88,8 @@ class EthFilterServiceSpec } class TestSetup(implicit system: ActorSystem) { - val filterManager = TestProbe() - val filterConfig = new FilterConfig { + val filterManager: TestProbe = TestProbe() + val filterConfig: FilterConfig = new FilterConfig { override val filterTimeout: FiniteDuration = Timeouts.normalTimeout override val filterManagerQueryTimeout: FiniteDuration = Timeouts.normalTimeout } diff --git a/src/test/scala/io/iohk/ethereum/jsonrpc/EthInfoServiceSpec.scala b/src/test/scala/io/iohk/ethereum/jsonrpc/EthInfoServiceSpec.scala index 42822982d6..7867413e1d 100644 --- a/src/test/scala/io/iohk/ethereum/jsonrpc/EthInfoServiceSpec.scala +++ b/src/test/scala/io/iohk/ethereum/jsonrpc/EthInfoServiceSpec.scala @@ -1,29 +1,38 @@ package io.iohk.ethereum.jsonrpc import akka.actor.ActorSystem -import akka.testkit.{TestKit, TestProbe} +import akka.testkit.TestKit +import akka.testkit.TestProbe import akka.util.ByteString + +import monix.execution.Scheduler.Implicits.global + +import org.bouncycastle.util.encoders.Hex +import org.scalactic.TypeCheckedTripleEquals +import org.scalamock.scalatest.MockFactory +import org.scalatest.OptionValues +import org.scalatest.concurrent.ScalaFutures +import org.scalatest.flatspec.AnyFlatSpecLike +import org.scalatest.matchers.should.Matchers + import io.iohk.ethereum._ +import io.iohk.ethereum.blockchain.sync.EphemBlockchainTestSetup +import io.iohk.ethereum.blockchain.sync.SyncProtocol import io.iohk.ethereum.blockchain.sync.SyncProtocol.Status.Progress -import io.iohk.ethereum.blockchain.sync.{EphemBlockchainTestSetup, SyncProtocol} import io.iohk.ethereum.consensus._ import io.iohk.ethereum.consensus.pow.blocks.PoWBlockGenerator import io.iohk.ethereum.db.storage.AppStateStorage -import io.iohk.ethereum.domain.{Block, UInt256, _} -import io.iohk.ethereum.jsonrpc.EthInfoService.{ProtocolVersionRequest, _} +import io.iohk.ethereum.domain.Block +import io.iohk.ethereum.domain.UInt256 +import io.iohk.ethereum.domain._ +import io.iohk.ethereum.jsonrpc.EthInfoService.ProtocolVersionRequest +import io.iohk.ethereum.jsonrpc.EthInfoService._ import io.iohk.ethereum.keystore.KeyStore +import io.iohk.ethereum.ledger.InMemoryWorldStateProxy +import io.iohk.ethereum.ledger.StxLedger import io.iohk.ethereum.ledger.TxResult -import io.iohk.ethereum.ledger.{InMemoryWorldStateProxy, StxLedger} import io.iohk.ethereum.network.p2p.messages.Capability import io.iohk.ethereum.testing.ActorsTesting.simpleAutoPilot -import monix.execution.Scheduler.Implicits.global -import org.bouncycastle.util.encoders.Hex -import org.scalactic.TypeCheckedTripleEquals -import org.scalamock.scalatest.MockFactory -import org.scalatest.OptionValues -import org.scalatest.concurrent.ScalaFutures -import org.scalatest.flatspec.AnyFlatSpecLike -import org.scalatest.matchers.should.Matchers class EthServiceSpec extends TestKit(ActorSystem("EthInfoServiceSpec_ActorSystem")) @@ -142,15 +151,15 @@ class EthServiceSpec // NOTE TestSetup uses Ethash consensus; check `consensusConfig`. class TestSetup(implicit system: ActorSystem) extends MockFactory with EphemBlockchainTestSetup { - val blockGenerator = mock[PoWBlockGenerator] - val appStateStorage = mock[AppStateStorage] - val keyStore = mock[KeyStore] - override lazy val stxLedger = mock[StxLedger] + val blockGenerator: PoWBlockGenerator = mock[PoWBlockGenerator] + val appStateStorage: AppStateStorage = mock[AppStateStorage] + val keyStore: KeyStore = mock[KeyStore] + override lazy val stxLedger: StxLedger = mock[StxLedger] override lazy val consensus: TestConsensus = buildTestConsensus().withBlockGenerator(blockGenerator) override lazy val consensusConfig = ConsensusConfigs.consensusConfig - val syncingController = TestProbe() + val syncingController: TestProbe = TestProbe() val currentProtocolVersion = 11 @@ -166,8 +175,8 @@ class EthServiceSpec Timeouts.shortTimeout ) - val blockToRequest = Block(Fixtures.Blocks.Block3125369.header, Fixtures.Blocks.Block3125369.body) + val blockToRequest: Block = Block(Fixtures.Blocks.Block3125369.header, Fixtures.Blocks.Block3125369.body) val txToRequest = Fixtures.Blocks.Block3125369.body.transactionList.head - val txSender = SignedTransaction.getSender(txToRequest).get + val txSender: Address = SignedTransaction.getSender(txToRequest).get } } diff --git a/src/test/scala/io/iohk/ethereum/jsonrpc/EthMiningServiceSpec.scala b/src/test/scala/io/iohk/ethereum/jsonrpc/EthMiningServiceSpec.scala index 707258d7fd..76bb947e37 100644 --- a/src/test/scala/io/iohk/ethereum/jsonrpc/EthMiningServiceSpec.scala +++ b/src/test/scala/io/iohk/ethereum/jsonrpc/EthMiningServiceSpec.scala @@ -1,35 +1,51 @@ package io.iohk.ethereum.jsonrpc import akka.actor.ActorSystem -import akka.testkit.{TestKit, TestProbe} +import akka.testkit.TestKit +import akka.testkit.TestProbe import akka.util.ByteString + +import monix.execution.Scheduler.Implicits.global + +import scala.concurrent.duration.DurationInt +import scala.concurrent.duration.FiniteDuration + +import org.bouncycastle.crypto.AsymmetricCipherKeyPair +import org.bouncycastle.util.encoders.Hex +import org.scalamock.scalatest.MockFactory +import org.scalatest.concurrent.ScalaFutures +import org.scalatest.flatspec.AnyFlatSpecLike +import org.scalatest.matchers.should.Matchers + import io.iohk.ethereum.Mocks.MockValidatorsAlwaysSucceed +import io.iohk.ethereum.NormalPatience +import io.iohk.ethereum.WithActorSystemShutDown import io.iohk.ethereum.blockchain.sync.EphemBlockchainTestSetup -import io.iohk.ethereum.consensus.blocks.{PendingBlock, PendingBlockAndState} -import io.iohk.ethereum.consensus.pow.blocks.{PoWBlockGenerator, RestrictedPoWBlockGeneratorImpl} +import io.iohk.ethereum.consensus.ConsensusConfigs +import io.iohk.ethereum.consensus.TestConsensus +import io.iohk.ethereum.consensus.blocks.PendingBlock +import io.iohk.ethereum.consensus.blocks.PendingBlockAndState +import io.iohk.ethereum.consensus.pow.blocks.PoWBlockGenerator +import io.iohk.ethereum.consensus.pow.blocks.RestrictedPoWBlockGeneratorImpl import io.iohk.ethereum.consensus.pow.difficulty.EthashDifficultyCalculator -import io.iohk.ethereum.consensus.{ConsensusConfigs, TestConsensus} +import io.iohk.ethereum.crypto import io.iohk.ethereum.crypto.kec256 import io.iohk.ethereum.db.storage.AppStateStorage +import io.iohk.ethereum.domain.Block +import io.iohk.ethereum.domain.BlockBody +import io.iohk.ethereum.domain.BlockHeader import io.iohk.ethereum.domain.BlockHeader.getEncodedWithoutNonce -import io.iohk.ethereum.domain.{Block, BlockBody, BlockHeader, ChainWeight, UInt256} +import io.iohk.ethereum.domain.ChainWeight +import io.iohk.ethereum.domain.UInt256 import io.iohk.ethereum.jsonrpc.EthMiningService._ import io.iohk.ethereum.jsonrpc.server.controllers.JsonRpcBaseController.JsonRpcConfig -import io.iohk.ethereum.ledger.{InMemoryWorldStateProxy, StxLedger} +import io.iohk.ethereum.ledger.InMemoryWorldStateProxy import io.iohk.ethereum.mpt.MerklePatriciaTrie import io.iohk.ethereum.nodebuilder.ApisBuilder import io.iohk.ethereum.ommers.OmmersPool import io.iohk.ethereum.transactions.PendingTransactionsManager -import io.iohk.ethereum.utils.{ByteStringUtils, Config} -import io.iohk.ethereum.{NormalPatience, WithActorSystemShutDown, crypto} -import monix.execution.Scheduler.Implicits.global -import org.bouncycastle.util.encoders.Hex -import org.scalamock.scalatest.MockFactory -import org.scalatest.concurrent.ScalaFutures -import org.scalatest.flatspec.AnyFlatSpecLike -import org.scalatest.matchers.should.Matchers - -import scala.concurrent.duration.{DurationInt, FiniteDuration} +import io.iohk.ethereum.utils.ByteStringUtils +import io.iohk.ethereum.utils.Config class EthMiningServiceSpec extends TestKit(ActorSystem("EthMiningServiceSpec_ActorSystem")) @@ -215,19 +231,19 @@ class EthMiningServiceSpec // NOTE TestSetup uses Ethash consensus; check `consensusConfig`. class TestSetup(implicit system: ActorSystem) extends MockFactory with EphemBlockchainTestSetup with ApisBuilder { - val blockGenerator = mock[PoWBlockGenerator] - val appStateStorage = mock[AppStateStorage] + val blockGenerator: PoWBlockGenerator = mock[PoWBlockGenerator] + val appStateStorage: AppStateStorage = mock[AppStateStorage] override lazy val consensus: TestConsensus = buildTestConsensus().withBlockGenerator(blockGenerator) override lazy val consensusConfig = ConsensusConfigs.consensusConfig - val syncingController = TestProbe() - val pendingTransactionsManager = TestProbe() - val ommersPool = TestProbe() + val syncingController: TestProbe = TestProbe() + val pendingTransactionsManager: TestProbe = TestProbe() + val ommersPool: TestProbe = TestProbe() val minerActiveTimeout: FiniteDuration = 5.seconds val getTransactionFromPoolTimeout: FiniteDuration = 5.seconds - lazy val minerKey = crypto.keyPairFromPrvKey( + lazy val minerKey: AsymmetricCipherKeyPair = crypto.keyPairFromPrvKey( ByteStringUtils.string2hash("00f7500a7178548b8a4488f78477660b548c9363e16b584c21e0208b3f1e0dc61f") ) @@ -244,7 +260,7 @@ class EthMiningServiceSpec minerKey ) - val jsonRpcConfig = JsonRpcConfig(Config.config, available) + val jsonRpcConfig: JsonRpcConfig = JsonRpcConfig(Config.config, available) lazy val ethMiningService = new EthMiningService( blockchain, @@ -258,7 +274,7 @@ class EthMiningServiceSpec ) val difficulty = 131072 - val parentBlock = Block( + val parentBlock: Block = Block( header = BlockHeader( parentHash = ByteString.empty, ommersHash = ByteString.empty, @@ -278,7 +294,7 @@ class EthMiningServiceSpec ), body = BlockBody.empty ) - val block = Block( + val block: Block = Block( header = BlockHeader( parentHash = parentBlock.header.hash, ommersHash = ByteString(Hex.decode("1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347")), @@ -298,11 +314,11 @@ class EthMiningServiceSpec ), body = BlockBody.empty ) - val seedHash = ByteString(Hex.decode("00" * 32)) - val powHash = ByteString(kec256(getEncodedWithoutNonce(block.header))) - val target = ByteString((BigInt(2).pow(256) / difficulty).toByteArray) + val seedHash: ByteString = ByteString(Hex.decode("00" * 32)) + val powHash: ByteString = ByteString(kec256(getEncodedWithoutNonce(block.header))) + val target: ByteString = ByteString((BigInt(2).pow(256) / difficulty).toByteArray) - val fakeWorld = InMemoryWorldStateProxy( + val fakeWorld: InMemoryWorldStateProxy = InMemoryWorldStateProxy( storagesInstance.storages.evmCodeStorage, blockchain.getReadOnlyMptStorage(), (number: BigInt) => blockchainReader.getBlockHeaderByNumber(number).map(_.hash), diff --git a/src/test/scala/io/iohk/ethereum/jsonrpc/EthProofServiceSpec.scala b/src/test/scala/io/iohk/ethereum/jsonrpc/EthProofServiceSpec.scala index 79c7c6a0ab..d3928faa98 100644 --- a/src/test/scala/io/iohk/ethereum/jsonrpc/EthProofServiceSpec.scala +++ b/src/test/scala/io/iohk/ethereum/jsonrpc/EthProofServiceSpec.scala @@ -3,21 +3,10 @@ package io.iohk.ethereum.jsonrpc import akka.actor.ActorSystem import akka.testkit.TestKit import akka.util.ByteString -import com.softwaremill.diffx.scalatest.DiffMatcher -import io.iohk.ethereum._ -import io.iohk.ethereum.blockchain.sync.EphemBlockchainTestSetup -import io.iohk.ethereum.consensus.pow.blocks.PoWBlockGenerator -import io.iohk.ethereum.domain._ -import io.iohk.ethereum.jsonrpc.EthUserService.{ - GetBalanceRequest, - GetBalanceResponse, - GetStorageAtRequest, - GetTransactionCountRequest -} -import io.iohk.ethereum.jsonrpc.ProofService.{GetProofRequest, StorageProofKey} -import io.iohk.ethereum.mpt.MerklePatriciaTrie -import io.iohk.ethereum.nodebuilder.ApisBuilder + import monix.execution.Scheduler.Implicits.global + +import com.softwaremill.diffx.scalatest.DiffMatcher import org.bouncycastle.util.encoders.Hex import org.scalactic.TypeCheckedTripleEquals import org.scalamock.scalatest.MockFactory @@ -25,7 +14,20 @@ import org.scalatest.OptionValues import org.scalatest.concurrent.ScalaFutures import org.scalatest.flatspec.AnyFlatSpecLike import org.scalatest.matchers.should.Matchers + +import io.iohk.ethereum._ +import io.iohk.ethereum.blockchain.sync.EphemBlockchainTestSetup +import io.iohk.ethereum.consensus.pow.blocks.PoWBlockGenerator +import io.iohk.ethereum.domain._ +import io.iohk.ethereum.jsonrpc.EthUserService.GetBalanceRequest +import io.iohk.ethereum.jsonrpc.EthUserService.GetBalanceResponse +import io.iohk.ethereum.jsonrpc.EthUserService.GetStorageAtRequest +import io.iohk.ethereum.jsonrpc.EthUserService.GetTransactionCountRequest +import io.iohk.ethereum.jsonrpc.ProofService.GetProofRequest +import io.iohk.ethereum.jsonrpc.ProofService.StorageProofKey +import io.iohk.ethereum.mpt.MerklePatriciaTrie import io.iohk.ethereum.mpt.MerklePatriciaTrie.defaultByteArraySerializable +import io.iohk.ethereum.nodebuilder.ApisBuilder import io.iohk.ethereum.rlp.RLPValue class EthProofServiceSpec @@ -106,10 +108,10 @@ class EthProofServiceSpec accountProof.codeHash shouldBe account.codeHash accountProof.nonce shouldBe nonce accountProof.storageHash shouldBe account.storageRoot - accountProof.storageProof.map(v => { + accountProof.storageProof.map { v => v.proof.nonEmpty shouldBe true v.value shouldBe BigInt(0) - }) + } } ) } @@ -131,10 +133,10 @@ class EthProofServiceSpec accountProof.codeHash shouldBe account.codeHash accountProof.nonce shouldBe nonce accountProof.storageHash shouldBe account.storageRoot - r.proofAccount.storageProof.map(v => { + r.proofAccount.storageProof.map { v => v.proof.nonEmpty shouldBe true v.value shouldBe BigInt(value) - }) + } } ) } @@ -158,10 +160,10 @@ class EthProofServiceSpec accountProof.nonce shouldBe nonce accountProof.storageHash shouldBe account.storageRoot accountProof.storageProof.size shouldBe 2 - accountProof.storageProof.map(v => { + accountProof.storageProof.map { v => v.proof.nonEmpty shouldBe true expectedValueStorageKey should contain(v.value) - }) + } } ) } @@ -214,9 +216,9 @@ class EthProofServiceSpec class TestSetup(implicit system: ActorSystem) extends MockFactory with EphemBlockchainTestSetup with ApisBuilder { - val blockGenerator = mock[PoWBlockGenerator] - val address = Address(ByteString(Hex.decode("abbb6bebfa05aa13e908eaa492bd7a8343760477"))) - val balance = UInt256(0) + val blockGenerator: PoWBlockGenerator = mock[PoWBlockGenerator] + val address: Address = Address(ByteString(Hex.decode("abbb6bebfa05aa13e908eaa492bd7a8343760477"))) + val balance: UInt256 = UInt256(0) val nonce = 0 val key = 333 @@ -226,7 +228,7 @@ class EthProofServiceSpec val key2 = 335 val value2 = 125 - val storageMpt = EthereumUInt256Mpt + val storageMpt: MerklePatriciaTrie[BigInt, BigInt] = EthereumUInt256Mpt .storageMpt( ByteString(MerklePatriciaTrie.EmptyRootHash), storagesInstance.storages.stateStorage.getBackingStorage(0) @@ -235,29 +237,29 @@ class EthProofServiceSpec .put(UInt256(key1), UInt256(value1)) .put(UInt256(key2), UInt256(value2)) - val account = Account( + val account: Account = Account( nonce = nonce, balance = balance, storageRoot = ByteString(storageMpt.getRootHash) ) - val mpt = + val mpt: MerklePatriciaTrie[Array[Byte], Account] = MerklePatriciaTrie[Array[Byte], Account](storagesInstance.storages.stateStorage.getBackingStorage(0)) .put( crypto.kec256(address.bytes.toArray[Byte]), account ) - val blockToRequest = Block(Fixtures.Blocks.Block3125369.header, Fixtures.Blocks.Block3125369.body) - val newBlockHeader = blockToRequest.header.copy(stateRoot = ByteString(mpt.getRootHash)) - val newblock = blockToRequest.copy(header = newBlockHeader) + val blockToRequest: Block = Block(Fixtures.Blocks.Block3125369.header, Fixtures.Blocks.Block3125369.body) + val newBlockHeader: BlockHeader = blockToRequest.header.copy(stateRoot = ByteString(mpt.getRootHash)) + val newblock: Block = blockToRequest.copy(header = newBlockHeader) blockchain.storeBlock(newblock).commit() blockchain.saveBestKnownBlocks(newblock.header.number) val ethGetProof = new EthProofService(blockchain, blockchainReader, blockGenerator, blockchainConfig.ethCompatibleStorage) - val storageKeys = Seq(StorageProofKey(key)) + val storageKeys: Seq[StorageProofKey] = Seq(StorageProofKey(key)) val blockNumber = BlockParam.Latest def fetchProof( diff --git a/src/test/scala/io/iohk/ethereum/jsonrpc/EthTxServiceSpec.scala b/src/test/scala/io/iohk/ethereum/jsonrpc/EthTxServiceSpec.scala index 10b4f839d1..60952ace30 100644 --- a/src/test/scala/io/iohk/ethereum/jsonrpc/EthTxServiceSpec.scala +++ b/src/test/scala/io/iohk/ethereum/jsonrpc/EthTxServiceSpec.scala @@ -1,18 +1,16 @@ package io.iohk.ethereum.jsonrpc import akka.actor.ActorSystem -import akka.testkit.{TestKit, TestProbe} +import akka.testkit.TestKit +import akka.testkit.TestProbe import akka.util.ByteString -import io.iohk.ethereum.{NormalPatience, WithActorSystemShutDown, _} -import io.iohk.ethereum.blockchain.sync.EphemBlockchainTestSetup -import io.iohk.ethereum.crypto.ECDSASignature -import io.iohk.ethereum.db.storage.AppStateStorage -import io.iohk.ethereum.domain._ -import io.iohk.ethereum.jsonrpc.EthTxService._ -import io.iohk.ethereum.transactions.PendingTransactionsManager -import io.iohk.ethereum.transactions.PendingTransactionsManager._ -import io.iohk.ethereum.utils._ + import monix.execution.Scheduler.Implicits.global + +import scala.concurrent.duration.Duration +import scala.concurrent.duration.DurationInt +import scala.concurrent.duration.FiniteDuration + import org.scalactic.TypeCheckedTripleEquals import org.scalamock.scalatest.MockFactory import org.scalatest.OptionValues @@ -20,7 +18,17 @@ import org.scalatest.concurrent.ScalaFutures import org.scalatest.flatspec.AnyFlatSpecLike import org.scalatest.matchers.should.Matchers -import scala.concurrent.duration.{Duration, DurationInt, FiniteDuration} +import io.iohk.ethereum.NormalPatience +import io.iohk.ethereum.WithActorSystemShutDown +import io.iohk.ethereum._ +import io.iohk.ethereum.blockchain.sync.EphemBlockchainTestSetup +import io.iohk.ethereum.crypto.ECDSASignature +import io.iohk.ethereum.db.storage.AppStateStorage +import io.iohk.ethereum.domain._ +import io.iohk.ethereum.jsonrpc.EthTxService._ +import io.iohk.ethereum.transactions.PendingTransactionsManager +import io.iohk.ethereum.transactions.PendingTransactionsManager._ +import io.iohk.ethereum.utils._ class EthTxServiceSpec extends TestKit(ActorSystem("EthServiceSpec_ActorSystem")) @@ -327,23 +335,21 @@ class EthTxServiceSpec } it should "send message to pendingTransactionsManager and return GetPendingTransactionsResponse with two transactions" in new TestSetup { - val transactions = (0 to 1) - .map(_ => { - val fakeTransaction = SignedTransactionWithSender( - Transaction( - nonce = 0, - gasPrice = 123, - gasLimit = 123, - receivingAddress = Address("0x1234"), - value = 0, - payload = ByteString() - ), - signature = ECDSASignature(0, 0, 0.toByte), - sender = Address("0x1234") - ) - PendingTransaction(fakeTransaction, System.currentTimeMillis) - }) - .toList + val transactions = (0 to 1).map { _ => + val fakeTransaction = SignedTransactionWithSender( + Transaction( + nonce = 0, + gasPrice = 123, + gasLimit = 123, + receivingAddress = Address("0x1234"), + value = 0, + payload = ByteString() + ), + signature = ECDSASignature(0, 0, 0.toByte), + sender = Address("0x1234") + ) + PendingTransaction(fakeTransaction, System.currentTimeMillis) + }.toList val res = ethTxService.getTransactionsFromPool.runToFuture @@ -364,8 +370,8 @@ class EthTxServiceSpec // NOTE TestSetup uses Ethash consensus; check `consensusConfig`. class TestSetup(implicit system: ActorSystem) extends MockFactory with EphemBlockchainTestSetup { - val appStateStorage = mock[AppStateStorage] - val pendingTransactionsManager = TestProbe() + val appStateStorage: AppStateStorage = mock[AppStateStorage] + val pendingTransactionsManager: TestProbe = TestProbe() val getTransactionFromPoolTimeout: FiniteDuration = 5.seconds lazy val ethTxService = new EthTxService( @@ -377,13 +383,13 @@ class EthTxServiceSpec storagesInstance.storages.transactionMappingStorage ) - val blockToRequest = Block(Fixtures.Blocks.Block3125369.header, Fixtures.Blocks.Block3125369.body) + val blockToRequest: Block = Block(Fixtures.Blocks.Block3125369.header, Fixtures.Blocks.Block3125369.body) val v: Byte = 0x1c - val r = ByteString(Hex.decode("b3493e863e48a8d67572910933114a4c0e49dac0cb199e01df1575f35141a881")) - val s = ByteString(Hex.decode("5ba423ae55087e013686f89ad71a449093745f7edb4eb39f30acd30a8964522d")) + val r: ByteString = ByteString(Hex.decode("b3493e863e48a8d67572910933114a4c0e49dac0cb199e01df1575f35141a881")) + val s: ByteString = ByteString(Hex.decode("5ba423ae55087e013686f89ad71a449093745f7edb4eb39f30acd30a8964522d")) - val payload = ByteString( + val payload: ByteString = ByteString( Hex.decode( "60606040526040516101e43803806101e483398101604052808051820191906020018051906020019091908051" + "9060200190919050505b805b83835b600060018351016001600050819055503373ffffffffffffffffffffffff" + @@ -419,9 +425,9 @@ class EthTxServiceSpec 0x3d.toByte ) - val contractCreatingTransactionSender = SignedTransaction.getSender(contractCreatingTransaction).get + val contractCreatingTransactionSender: Address = SignedTransaction.getSender(contractCreatingTransaction).get - val fakeReceipt = Receipt.withHashOutcome( + val fakeReceipt: Receipt = Receipt.withHashOutcome( postTransactionStateHash = ByteString(Hex.decode("01" * 32)), cumulativeGasUsed = 43, logsBloomFilter = ByteString(Hex.decode("00" * 256)), @@ -429,8 +435,8 @@ class EthTxServiceSpec ) val txToRequest = Fixtures.Blocks.Block3125369.body.transactionList.head - val txSender = SignedTransaction.getSender(txToRequest).get - val txToRequestWithSender = SignedTransactionWithSender(txToRequest, txSender) + val txSender: Address = SignedTransaction.getSender(txToRequest).get + val txToRequestWithSender: SignedTransactionWithSender = SignedTransactionWithSender(txToRequest, txSender) val txToRequestHash = txToRequest.hash } diff --git a/src/test/scala/io/iohk/ethereum/jsonrpc/EthUserServiceSpec.scala b/src/test/scala/io/iohk/ethereum/jsonrpc/EthUserServiceSpec.scala index 137c302d5c..b5567b24ee 100644 --- a/src/test/scala/io/iohk/ethereum/jsonrpc/EthUserServiceSpec.scala +++ b/src/test/scala/io/iohk/ethereum/jsonrpc/EthUserServiceSpec.scala @@ -3,13 +3,9 @@ package io.iohk.ethereum.jsonrpc import akka.actor.ActorSystem import akka.testkit.TestKit import akka.util.ByteString -import io.iohk.ethereum.{NormalPatience, WithActorSystemShutDown, _} -import io.iohk.ethereum.blockchain.sync.EphemBlockchainTestSetup -import io.iohk.ethereum.domain._ -import io.iohk.ethereum.jsonrpc.EthUserService._ -import io.iohk.ethereum.mpt.MerklePatriciaTrie -import io.iohk.ethereum.utils._ + import monix.execution.Scheduler.Implicits.global + import org.scalactic.TypeCheckedTripleEquals import org.scalamock.scalatest.MockFactory import org.scalatest.OptionValues @@ -17,6 +13,15 @@ import org.scalatest.concurrent.ScalaFutures import org.scalatest.flatspec.AnyFlatSpecLike import org.scalatest.matchers.should.Matchers +import io.iohk.ethereum.NormalPatience +import io.iohk.ethereum.WithActorSystemShutDown +import io.iohk.ethereum._ +import io.iohk.ethereum.blockchain.sync.EphemBlockchainTestSetup +import io.iohk.ethereum.domain._ +import io.iohk.ethereum.jsonrpc.EthUserService._ +import io.iohk.ethereum.mpt.MerklePatriciaTrie +import io.iohk.ethereum.utils._ + class EthUserServiceSpec extends TestKit(ActorSystem("EthServiceSpec_ActorSystem")) with AnyFlatSpecLike @@ -142,7 +147,7 @@ class EthUserServiceSpec storagesInstance.storages.evmCodeStorage, blockchainConfig ) - val blockToRequest = Block(Fixtures.Blocks.Block3125369.header, Fixtures.Blocks.Block3125369.body) + val blockToRequest: Block = Block(Fixtures.Blocks.Block3125369.header, Fixtures.Blocks.Block3125369.body) } } diff --git a/src/test/scala/io/iohk/ethereum/jsonrpc/ExpiringMapSpec.scala b/src/test/scala/io/iohk/ethereum/jsonrpc/ExpiringMapSpec.scala index ddf4340319..89e20b4309 100644 --- a/src/test/scala/io/iohk/ethereum/jsonrpc/ExpiringMapSpec.scala +++ b/src/test/scala/io/iohk/ethereum/jsonrpc/ExpiringMapSpec.scala @@ -2,20 +2,23 @@ package io.iohk.ethereum.jsonrpc import java.time.Duration -import io.iohk.ethereum.domain.{Account, Address} import org.scalatest.concurrent.Eventually -import org.scalatest.time.{Millis, Span} import org.scalatest.flatspec.AnyFlatSpec import org.scalatest.matchers.should.Matchers +import org.scalatest.time.Millis +import org.scalatest.time.Span + +import io.iohk.ethereum.domain.Account +import io.iohk.ethereum.domain.Address class ExpiringMapSpec extends AnyFlatSpec with Matchers with Eventually { val testResolution = 20 val holdTime = 100 - val holdTimeDur = Duration.ofMillis(holdTime) - val waitTime = holdTime + testResolution + val holdTimeDur: Duration = Duration.ofMillis(holdTime) + val waitTime: Int = holdTime + testResolution - implicit override val patienceConfig = + implicit override val patienceConfig: PatienceConfig = PatienceConfig(timeout = scaled(Span(waitTime, Millis)), interval = scaled(Span(testResolution, Millis))) it should "Put element in, for correct amount of time and not retain it afterwards" in new TestSetup { @@ -122,10 +125,10 @@ class ExpiringMapSpec extends AnyFlatSpec with Matchers with Eventually { trait TestSetup { val defaultHoldTime = holdTime val expiringMap: ExpiringMap[Address, Account] = ExpiringMap.empty(Duration.ofMillis(defaultHoldTime)) - val address1 = Address(0x123456) - val address2 = Address(0xabcdef) + val address1: Address = Address(0x123456) + val address2: Address = Address(0xabcdef) - val account1 = Account.empty() - val account2 = Account.empty().increaseBalance(10) + val account1: Account = Account.empty() + val account2: Account = Account.empty().increaseBalance(10) } } diff --git a/src/test/scala/io/iohk/ethereum/jsonrpc/FilterManagerSpec.scala b/src/test/scala/io/iohk/ethereum/jsonrpc/FilterManagerSpec.scala index f787fbbe4d..f253f9d400 100644 --- a/src/test/scala/io/iohk/ethereum/jsonrpc/FilterManagerSpec.scala +++ b/src/test/scala/io/iohk/ethereum/jsonrpc/FilterManagerSpec.scala @@ -1,31 +1,40 @@ package io.iohk.ethereum.jsonrpc -import akka.actor.{ActorSystem, Props} -import akka.testkit.{TestActorRef, TestKit, TestProbe} -import akka.util.ByteString -import io.iohk.ethereum.db.storage.AppStateStorage -import io.iohk.ethereum.domain._ -import io.iohk.ethereum.keystore.KeyStore -import org.scalamock.scalatest.MockFactory -import org.bouncycastle.util.encoders.Hex +import akka.actor.ActorSystem +import akka.actor.Props import akka.pattern.ask +import akka.testkit.TestActorRef +import akka.testkit.TestKit +import akka.testkit.TestProbe +import akka.util.ByteString + +import scala.concurrent.duration._ + import com.miguno.akka.testing.VirtualTime -import io.iohk.ethereum.consensus.blocks.{BlockGenerator, PendingBlock} -import io.iohk.ethereum.{NormalPatience, Timeouts, WithActorSystemShutDown} -import io.iohk.ethereum.crypto.{ECDSASignature, generateKeyPair} -import io.iohk.ethereum.jsonrpc.FilterManager.LogFilterLogs -import io.iohk.ethereum.security.SecureRandomBuilder -import io.iohk.ethereum.ledger.BloomFilter -import io.iohk.ethereum.transactions.PendingTransactionsManager -import io.iohk.ethereum.transactions.PendingTransactionsManager.PendingTransaction -import io.iohk.ethereum.utils.{FilterConfig, TxPoolConfig} import org.bouncycastle.crypto.AsymmetricCipherKeyPair +import org.bouncycastle.util.encoders.Hex +import org.scalamock.scalatest.MockFactory import org.scalatest.concurrent.ScalaFutures - -import scala.concurrent.duration._ import org.scalatest.flatspec.AnyFlatSpecLike import org.scalatest.matchers.should.Matchers +import io.iohk.ethereum.NormalPatience +import io.iohk.ethereum.Timeouts +import io.iohk.ethereum.WithActorSystemShutDown +import io.iohk.ethereum.consensus.blocks.BlockGenerator +import io.iohk.ethereum.consensus.blocks.PendingBlock +import io.iohk.ethereum.crypto.ECDSASignature +import io.iohk.ethereum.crypto.generateKeyPair +import io.iohk.ethereum.domain._ +import io.iohk.ethereum.jsonrpc.FilterManager.LogFilterLogs +import io.iohk.ethereum.keystore.KeyStore +import io.iohk.ethereum.ledger.BloomFilter +import io.iohk.ethereum.security.SecureRandomBuilder +import io.iohk.ethereum.transactions.PendingTransactionsManager +import io.iohk.ethereum.transactions.PendingTransactionsManager.PendingTransaction +import io.iohk.ethereum.utils.FilterConfig +import io.iohk.ethereum.utils.TxPoolConfig + class FilterManagerSpec extends TestKit(ActorSystem("FilterManagerSpec_System")) with AnyFlatSpecLike @@ -467,12 +476,12 @@ class FilterManagerSpec class TestSetup(implicit system: ActorSystem) extends MockFactory with SecureRandomBuilder { - val config = new FilterConfig { + val config: FilterConfig = new FilterConfig { override val filterTimeout = Timeouts.longTimeout override val filterManagerQueryTimeout: FiniteDuration = Timeouts.longTimeout } - val txPoolConfig = new TxPoolConfig { + val txPoolConfig: TxPoolConfig = new TxPoolConfig { override val txPoolSize: Int = 30 override val pendingTxManagerQueryTimeout: FiniteDuration = Timeouts.longTimeout override val transactionTimeout: FiniteDuration = Timeouts.normalTimeout @@ -483,13 +492,13 @@ class FilterManagerSpec val time = new VirtualTime - val blockchainReader = mock[BlockchainReader] - val blockchain = mock[BlockchainImpl] - val keyStore = mock[KeyStore] - val blockGenerator = mock[BlockGenerator] - val pendingTransactionsManager = TestProbe() + val blockchainReader: BlockchainReader = mock[BlockchainReader] + val blockchain: BlockchainImpl = mock[BlockchainImpl] + val keyStore: KeyStore = mock[KeyStore] + val blockGenerator: BlockGenerator = mock[BlockGenerator] + val pendingTransactionsManager: TestProbe = TestProbe() - val blockHeader = BlockHeader( + val blockHeader: BlockHeader = BlockHeader( parentHash = ByteString(Hex.decode("fd07e36cfaf327801e5696134b36678f6a89fb1e8f017f2411a29d0ae810ab8b")), ommersHash = ByteString(Hex.decode("7766c4251396a6833ccbe4be86fbda3a200dccbe6a15d80ae3de5378b1540e04")), beneficiary = ByteString(Hex.decode("1b7047b4338acf65be94c1a3e8c5c9338ad7d67c")), @@ -511,7 +520,7 @@ class FilterManagerSpec nonce = ByteString(Hex.decode("62bc3dca012c1b27")) ) - val filterManager = TestActorRef[FilterManager]( + val filterManager: TestActorRef[FilterManager] = TestActorRef[FilterManager]( Props( new FilterManager( blockchain, diff --git a/src/test/scala/io/iohk/ethereum/jsonrpc/JRCMatchers.scala b/src/test/scala/io/iohk/ethereum/jsonrpc/JRCMatchers.scala index d8aee796e9..6a3d2058dd 100644 --- a/src/test/scala/io/iohk/ethereum/jsonrpc/JRCMatchers.scala +++ b/src/test/scala/io/iohk/ethereum/jsonrpc/JRCMatchers.scala @@ -1,11 +1,19 @@ package io.iohk.ethereum.jsonrpc import akka.util.ByteString -import io.iohk.ethereum.utils.ByteStringUtils -import org.json4s.JsonAST.{JBool, JDecimal, JInt, JObject, JString, JValue} -import org.scalatest.matchers.{MatchResult, Matcher} + +import org.json4s.JsonAST.JBool +import org.json4s.JsonAST.JDecimal +import org.json4s.JsonAST.JInt +import org.json4s.JsonAST.JObject +import org.json4s.JsonAST.JString +import org.json4s.JsonAST.JValue +import org.scalatest.matchers.MatchResult +import org.scalatest.matchers.Matcher import org.scalatest.matchers.should.Matchers +import io.iohk.ethereum.utils.ByteStringUtils + trait JRCMatchers extends Matchers { class VersionMatcher private[JRCMatchers] (expectedVersion: String) extends Matcher[JsonRpcResponse] { diff --git a/src/test/scala/io/iohk/ethereum/jsonrpc/JsonRpcControllerEthSpec.scala b/src/test/scala/io/iohk/ethereum/jsonrpc/JsonRpcControllerEthSpec.scala index 9ed7aec673..ddb9614c95 100644 --- a/src/test/scala/io/iohk/ethereum/jsonrpc/JsonRpcControllerEthSpec.scala +++ b/src/test/scala/io/iohk/ethereum/jsonrpc/JsonRpcControllerEthSpec.scala @@ -3,43 +3,50 @@ package io.iohk.ethereum.jsonrpc import akka.actor.ActorSystem import akka.testkit.TestKit import akka.util.ByteString + +import monix.eval.Task +import monix.execution.Scheduler.Implicits.global + +import org.bouncycastle.util.encoders.Hex +import org.json4s.DefaultFormats +import org.json4s.Extraction +import org.json4s.Formats +import org.json4s.JsonAST._ +import org.json4s.JsonDSL._ +import org.scalatest.concurrent.Eventually +import org.scalatest.concurrent.ScalaFutures +import org.scalatest.flatspec.AnyFlatSpecLike +import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks + +import io.iohk.ethereum.Fixtures +import io.iohk.ethereum.LongPatience +import io.iohk.ethereum.Timeouts +import io.iohk.ethereum.WithActorSystemShutDown import io.iohk.ethereum.blockchain.sync.SyncProtocol import io.iohk.ethereum.blockchain.sync.SyncProtocol.Status.Progress -import io.iohk.ethereum.consensus.blocks.{PendingBlock, PendingBlockAndState} +import io.iohk.ethereum.consensus.blocks.PendingBlock +import io.iohk.ethereum.consensus.blocks.PendingBlockAndState import io.iohk.ethereum.crypto.kec256 import io.iohk.ethereum.domain._ -import io.iohk.ethereum.jsonrpc.EthBlocksService.{GetUncleCountByBlockHashResponse, GetUncleCountByBlockNumberResponse} +import io.iohk.ethereum.jsonrpc.EthBlocksService.GetUncleCountByBlockHashResponse +import io.iohk.ethereum.jsonrpc.EthBlocksService.GetUncleCountByBlockNumberResponse import io.iohk.ethereum.jsonrpc.EthFilterService._ import io.iohk.ethereum.jsonrpc.EthInfoService._ import io.iohk.ethereum.jsonrpc.EthUserService._ import io.iohk.ethereum.jsonrpc.FilterManager.LogFilterLogs import io.iohk.ethereum.jsonrpc.PersonalService._ -import io.iohk.ethereum.jsonrpc.ProofService.{ - GetProofRequest, - GetProofResponse, - ProofAccount, - StorageValueProof, - StorageProofKey -} -import io.iohk.ethereum.jsonrpc.serialization.JsonSerializers.{ - OptionNoneToJNullSerializer, - QuantitiesSerializer, - UnformattedDataJsonSerializer -} +import io.iohk.ethereum.jsonrpc.ProofService.GetProofRequest +import io.iohk.ethereum.jsonrpc.ProofService.GetProofResponse +import io.iohk.ethereum.jsonrpc.ProofService.ProofAccount +import io.iohk.ethereum.jsonrpc.ProofService.StorageProofKey +import io.iohk.ethereum.jsonrpc.ProofService.StorageValueProof +import io.iohk.ethereum.jsonrpc.serialization.JsonSerializers.OptionNoneToJNullSerializer +import io.iohk.ethereum.jsonrpc.serialization.JsonSerializers.QuantitiesSerializer +import io.iohk.ethereum.jsonrpc.serialization.JsonSerializers.UnformattedDataJsonSerializer import io.iohk.ethereum.ommers.OmmersPool import io.iohk.ethereum.ommers.OmmersPool.Ommers import io.iohk.ethereum.testing.ActorsTesting.simpleAutoPilot import io.iohk.ethereum.transactions.PendingTransactionsManager -import io.iohk.ethereum.{Fixtures, LongPatience, Timeouts, WithActorSystemShutDown} -import monix.eval.Task -import monix.execution.Scheduler.Implicits.global -import org.bouncycastle.util.encoders.Hex -import org.json4s.JsonAST._ -import org.json4s.JsonDSL._ -import org.json4s.{DefaultFormats, Extraction, Formats} -import org.scalatest.concurrent.{Eventually, ScalaFutures} -import org.scalatest.flatspec.AnyFlatSpecLike -import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks // scalastyle:off magic.number class JsonRpcControllerEthSpec @@ -242,7 +249,7 @@ class JsonRpcControllerEthSpec .decompose(BlockResponse(uncle, None, pendingBlock = false)) .removeField { case ("transactions", _) => true - case _ => false + case _ => false } response should haveResult(expectedUncleBlockResponse) @@ -267,7 +274,7 @@ class JsonRpcControllerEthSpec .decompose(BlockResponse(uncle, None, pendingBlock = false)) .removeField { case ("transactions", _) => true - case _ => false + case _ => false } response should haveResult(expectedUncleBlockResponse) diff --git a/src/test/scala/io/iohk/ethereum/jsonrpc/JsonRpcControllerEthTransactionSpec.scala b/src/test/scala/io/iohk/ethereum/jsonrpc/JsonRpcControllerEthTransactionSpec.scala index e6a0df0c13..728d3c60aa 100644 --- a/src/test/scala/io/iohk/ethereum/jsonrpc/JsonRpcControllerEthTransactionSpec.scala +++ b/src/test/scala/io/iohk/ethereum/jsonrpc/JsonRpcControllerEthTransactionSpec.scala @@ -3,31 +3,37 @@ package io.iohk.ethereum.jsonrpc import akka.actor.ActorSystem import akka.testkit.TestKit import akka.util.ByteString -import io.iohk.ethereum.crypto.ECDSASignature -import io.iohk.ethereum.domain._ -import io.iohk.ethereum.jsonrpc.EthBlocksService.GetBlockTransactionCountByNumberResponse -import io.iohk.ethereum.jsonrpc.EthTxService._ -import io.iohk.ethereum.jsonrpc.EthUserService._ -import io.iohk.ethereum.jsonrpc.FilterManager.TxLog -import io.iohk.ethereum.jsonrpc.PersonalService._ -import io.iohk.ethereum.jsonrpc.serialization.JsonSerializers.{ - OptionNoneToJNullSerializer, - QuantitiesSerializer, - UnformattedDataJsonSerializer -} -import io.iohk.ethereum.transactions.PendingTransactionsManager.PendingTransaction -import io.iohk.ethereum.{Fixtures, LongPatience, WithActorSystemShutDown} + import monix.eval.Task import monix.execution.Scheduler.Implicits.global + import org.bouncycastle.util.encoders.Hex +import org.json4s.DefaultFormats +import org.json4s.Extraction +import org.json4s.Formats import org.json4s.JsonAST._ import org.json4s.JsonDSL._ -import org.json4s.{DefaultFormats, Extraction, Formats} -import org.scalatest.concurrent.{Eventually, ScalaFutures} +import org.scalatest.concurrent.Eventually +import org.scalatest.concurrent.ScalaFutures import org.scalatest.flatspec.AnyFlatSpecLike import org.scalatest.matchers.should.Matchers import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks +import io.iohk.ethereum.Fixtures +import io.iohk.ethereum.LongPatience +import io.iohk.ethereum.WithActorSystemShutDown +import io.iohk.ethereum.crypto.ECDSASignature +import io.iohk.ethereum.domain._ +import io.iohk.ethereum.jsonrpc.EthBlocksService.GetBlockTransactionCountByNumberResponse +import io.iohk.ethereum.jsonrpc.EthTxService._ +import io.iohk.ethereum.jsonrpc.EthUserService._ +import io.iohk.ethereum.jsonrpc.FilterManager.TxLog +import io.iohk.ethereum.jsonrpc.PersonalService._ +import io.iohk.ethereum.jsonrpc.serialization.JsonSerializers.OptionNoneToJNullSerializer +import io.iohk.ethereum.jsonrpc.serialization.JsonSerializers.QuantitiesSerializer +import io.iohk.ethereum.jsonrpc.serialization.JsonSerializers.UnformattedDataJsonSerializer +import io.iohk.ethereum.transactions.PendingTransactionsManager.PendingTransaction + // scalastyle:off magic.number class JsonRpcControllerEthTransactionSpec extends TestKit(ActorSystem("JsonRpcControllerEthTransactionSpec_System")) @@ -529,7 +535,7 @@ class JsonRpcControllerEthTransactionSpec } it should "request pending transactions and return valid response when mempool has transactions" in new JsonRpcControllerFixture { - val transactions = (0 to 1).map(_ => { + val transactions = (0 to 1).map { _ => val fakeTransaction = SignedTransactionWithSender( Transaction( nonce = 0, @@ -543,7 +549,7 @@ class JsonRpcControllerEthTransactionSpec sender = Address("0x1234") ) PendingTransaction(fakeTransaction, System.currentTimeMillis) - }) + } val mockEthTxService = mock[EthTxService] (mockEthTxService.ethPendingTransactions _) @@ -565,11 +571,9 @@ class JsonRpcControllerEthTransactionSpec val response: JsonRpcResponse = jRpcController.handleRequest(request).runSyncUnsafe() val result = JArray( - transactions - .map(tx => { - encodeAsHex(tx.stx.tx.hash) - }) - .toList + transactions.map { tx => + encodeAsHex(tx.stx.tx.hash) + }.toList ) response should haveResult(result) diff --git a/src/test/scala/io/iohk/ethereum/jsonrpc/JsonRpcControllerFixture.scala b/src/test/scala/io/iohk/ethereum/jsonrpc/JsonRpcControllerFixture.scala index af88fa902c..41bfd232c0 100644 --- a/src/test/scala/io/iohk/ethereum/jsonrpc/JsonRpcControllerFixture.scala +++ b/src/test/scala/io/iohk/ethereum/jsonrpc/JsonRpcControllerFixture.scala @@ -3,27 +3,42 @@ package io.iohk.ethereum.jsonrpc import akka.actor.ActorSystem import akka.testkit.TestProbe import akka.util.ByteString + +import scala.concurrent.duration._ + +import org.bouncycastle.util.encoders.Hex +import org.json4s.JsonAST.JArray +import org.json4s.JsonAST.JInt +import org.json4s.JsonAST.JString +import org.json4s.JsonAST.JValue +import org.scalamock.scalatest.MockFactory + +import io.iohk.ethereum.Fixtures +import io.iohk.ethereum.ObjectGenerators +import io.iohk.ethereum.Timeouts import io.iohk.ethereum.blockchain.sync.EphemBlockchainTestSetup +import io.iohk.ethereum.consensus.ConsensusConfigs +import io.iohk.ethereum.consensus.TestConsensus import io.iohk.ethereum.consensus.blocks.CheckpointBlockGenerator import io.iohk.ethereum.consensus.pow.blocks.PoWBlockGenerator import io.iohk.ethereum.consensus.pow.validators.ValidatorsExecutor -import io.iohk.ethereum.consensus.{ConsensusConfigs, TestConsensus} import io.iohk.ethereum.crypto.ECDSASignature import io.iohk.ethereum.db.storage.AppStateStorage +import io.iohk.ethereum.domain.Block +import io.iohk.ethereum.domain.BlockBody +import io.iohk.ethereum.domain.BlockHeader import io.iohk.ethereum.domain.BlockHeader.HeaderExtraFields.HefEmpty -import io.iohk.ethereum.domain.{Block, BlockBody, SignedTransaction} +import io.iohk.ethereum.domain.Checkpoint +import io.iohk.ethereum.domain.SignedTransaction import io.iohk.ethereum.jsonrpc.server.controllers.JsonRpcBaseController.JsonRpcConfig import io.iohk.ethereum.keystore.KeyStore -import io.iohk.ethereum.ledger.{BloomFilter, InMemoryWorldStateProxy, StxLedger} +import io.iohk.ethereum.ledger.BloomFilter +import io.iohk.ethereum.ledger.InMemoryWorldStateProxy +import io.iohk.ethereum.ledger.StxLedger import io.iohk.ethereum.network.p2p.messages.Capability import io.iohk.ethereum.nodebuilder.ApisBuilder -import io.iohk.ethereum.utils.{Config, FilterConfig} -import io.iohk.ethereum.{Fixtures, ObjectGenerators, Timeouts} -import org.bouncycastle.util.encoders.Hex -import org.json4s.JsonAST.{JArray, JInt, JString, JValue} -import org.scalamock.scalatest.MockFactory - -import scala.concurrent.duration._ +import io.iohk.ethereum.utils.Config +import io.iohk.ethereum.utils.FilterConfig class JsonRpcControllerFixture(implicit system: ActorSystem) extends MockFactory @@ -37,16 +52,16 @@ class JsonRpcControllerFixture(implicit system: ActorSystem) xs.lift(idx) .map(encodeSignedTrx) - def encodeSignedTrx(x: SignedTransaction) = + def encodeSignedTrx(x: SignedTransaction): JString = encodeAsHex(RawTransactionCodec.asRawTransaction(x)) val version = Config.clientVersion - val blockGenerator = mock[PoWBlockGenerator] + val blockGenerator: PoWBlockGenerator = mock[PoWBlockGenerator] - val syncingController = TestProbe() + val syncingController: TestProbe = TestProbe() - override lazy val stxLedger = mock[StxLedger] - override lazy val validators = mock[ValidatorsExecutor] + override lazy val stxLedger: StxLedger = mock[StxLedger] + override lazy val validators: ValidatorsExecutor = mock[ValidatorsExecutor] (() => validators.signedTransactionValidator) .expects() .returns(null) @@ -56,27 +71,27 @@ class JsonRpcControllerFixture(implicit system: ActorSystem) .withValidators(validators) .withBlockGenerator(blockGenerator) - val keyStore = mock[KeyStore] + val keyStore: KeyStore = mock[KeyStore] - val pendingTransactionsManager = TestProbe() - val ommersPool = TestProbe() - val filterManager = TestProbe() + val pendingTransactionsManager: TestProbe = TestProbe() + val ommersPool: TestProbe = TestProbe() + val filterManager: TestProbe = TestProbe() val ethashConfig = ConsensusConfigs.ethashConfig override lazy val consensusConfig = ConsensusConfigs.consensusConfig val fullConsensusConfig = ConsensusConfigs.fullConsensusConfig val getTransactionFromPoolTimeout: FiniteDuration = 5.seconds - val filterConfig = new FilterConfig { + val filterConfig: FilterConfig = new FilterConfig { override val filterTimeout: FiniteDuration = Timeouts.normalTimeout override val filterManagerQueryTimeout: FiniteDuration = Timeouts.normalTimeout } val currentProtocolVersion = 63 - val appStateStorage = mock[AppStateStorage] + val appStateStorage: AppStateStorage = mock[AppStateStorage] val web3Service = new Web3Service - val netService = mock[NetService] + val netService: NetService = mock[NetService] val ethInfoService = new EthInfoService( blockchain, @@ -124,13 +139,13 @@ class JsonRpcControllerFixture(implicit system: ActorSystem) filterManager.ref, filterConfig ) - val personalService = mock[PersonalService] - val debugService = mock[DebugService] - val qaService = mock[QAService] - val checkpointingService = mock[CheckpointingService] - val mantisService = mock[MantisService] + val personalService: PersonalService = mock[PersonalService] + val debugService: DebugService = mock[DebugService] + val qaService: QAService = mock[QAService] + val checkpointingService: CheckpointingService = mock[CheckpointingService] + val mantisService: MantisService = mock[MantisService] - def jsonRpcController = + def jsonRpcController: JsonRpcController = JsonRpcController( web3Service, netService, @@ -150,7 +165,7 @@ class JsonRpcControllerFixture(implicit system: ActorSystem) config ) - val blockHeader = Fixtures.Blocks.ValidBlock.header.copy( + val blockHeader: BlockHeader = Fixtures.Blocks.ValidBlock.header.copy( logsBloom = BloomFilter.EmptyBloomFilter, difficulty = 10, number = 2, @@ -159,29 +174,29 @@ class JsonRpcControllerFixture(implicit system: ActorSystem) unixTimestamp = 0 ) - val checkpoint = ObjectGenerators.fakeCheckpointGen(2, 5).sample.get + val checkpoint: Checkpoint = ObjectGenerators.fakeCheckpointGen(2, 5).sample.get val checkpointBlockGenerator = new CheckpointBlockGenerator() - val blockWithCheckpoint = checkpointBlockGenerator.generate(Fixtures.Blocks.Block3125369.block, checkpoint) - val blockWithTreasuryOptOut = + val blockWithCheckpoint: Block = checkpointBlockGenerator.generate(Fixtures.Blocks.Block3125369.block, checkpoint) + val blockWithTreasuryOptOut: Block = Block( Fixtures.Blocks.Block3125369.header.copy(extraFields = HefEmpty), Fixtures.Blocks.Block3125369.body ) - val parentBlock = Block(blockHeader.copy(number = 1), BlockBody.empty) + val parentBlock: Block = Block(blockHeader.copy(number = 1), BlockBody.empty) val r: ByteString = ByteString(Hex.decode("a3f20717a250c2b0b729b7e5becbff67fdaef7e0699da4de7ca5895b02a170a1")) val s: ByteString = ByteString(Hex.decode("2d887fd3b17bfdce3481f10bea41f45ba9f709d39ce8325427b57afcfc994cee")) val v: Byte = ByteString(Hex.decode("1b")).last - val sig = ECDSASignature(r, s, v) + val sig: ECDSASignature = ECDSASignature(r, s, v) - def newJsonRpcRequest(method: String, params: List[JValue]) = + def newJsonRpcRequest(method: String, params: List[JValue]): JsonRpcRequest = JsonRpcRequest("2.0", method, Some(JArray(params)), Some(JInt(1))) - def newJsonRpcRequest(method: String) = + def newJsonRpcRequest(method: String): JsonRpcRequest = JsonRpcRequest("2.0", method, None, Some(JInt(1))) - val fakeWorld = InMemoryWorldStateProxy( + val fakeWorld: InMemoryWorldStateProxy = InMemoryWorldStateProxy( storagesInstance.storages.evmCodeStorage, blockchain.getReadOnlyMptStorage(), (number: BigInt) => blockchainReader.getBlockHeaderByNumber(number).map(_.hash), diff --git a/src/test/scala/io/iohk/ethereum/jsonrpc/JsonRpcControllerPersonalSpec.scala b/src/test/scala/io/iohk/ethereum/jsonrpc/JsonRpcControllerPersonalSpec.scala index 4cd8f9c16f..23ddeac56c 100644 --- a/src/test/scala/io/iohk/ethereum/jsonrpc/JsonRpcControllerPersonalSpec.scala +++ b/src/test/scala/io/iohk/ethereum/jsonrpc/JsonRpcControllerPersonalSpec.scala @@ -1,28 +1,32 @@ package io.iohk.ethereum.jsonrpc +import java.time.Duration + import akka.actor.ActorSystem import akka.testkit.TestKit import akka.util.ByteString -import io.iohk.ethereum.domain._ -import io.iohk.ethereum.jsonrpc.PersonalService._ -import io.iohk.ethereum.jsonrpc.serialization.JsonSerializers.{ - OptionNoneToJNullSerializer, - QuantitiesSerializer, - UnformattedDataJsonSerializer -} -import io.iohk.ethereum.{LongPatience, WithActorSystemShutDown} + import monix.eval.Task import monix.execution.Scheduler.Implicits.global + import org.bouncycastle.util.encoders.Hex +import org.json4s.DefaultFormats +import org.json4s.Formats import org.json4s.JsonAST._ import org.json4s.JsonDSL._ -import org.json4s.{DefaultFormats, Formats} -import org.scalatest.concurrent.{Eventually, ScalaFutures} +import org.scalatest.concurrent.Eventually +import org.scalatest.concurrent.ScalaFutures import org.scalatest.flatspec.AnyFlatSpecLike import org.scalatest.matchers.should.Matchers import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks -import java.time.Duration +import io.iohk.ethereum.LongPatience +import io.iohk.ethereum.WithActorSystemShutDown +import io.iohk.ethereum.domain._ +import io.iohk.ethereum.jsonrpc.PersonalService._ +import io.iohk.ethereum.jsonrpc.serialization.JsonSerializers.OptionNoneToJNullSerializer +import io.iohk.ethereum.jsonrpc.serialization.JsonSerializers.QuantitiesSerializer +import io.iohk.ethereum.jsonrpc.serialization.JsonSerializers.UnformattedDataJsonSerializer class JsonRpcControllerPersonalSpec extends TestKit(ActorSystem("JsonRpcControllerPersonalSpec_System")) @@ -72,7 +76,6 @@ class JsonRpcControllerPersonalSpec it should "personal_listAccounts" in new JsonRpcControllerFixture { val addresses = List(34, 12391, 123).map(Address(_)) - val pass = "aaa" (personalService.listAccounts _) .expects(ListAccountsRequest()) diff --git a/src/test/scala/io/iohk/ethereum/jsonrpc/JsonRpcControllerSpec.scala b/src/test/scala/io/iohk/ethereum/jsonrpc/JsonRpcControllerSpec.scala index 0657b53dbe..4695bf93d7 100644 --- a/src/test/scala/io/iohk/ethereum/jsonrpc/JsonRpcControllerSpec.scala +++ b/src/test/scala/io/iohk/ethereum/jsonrpc/JsonRpcControllerSpec.scala @@ -2,29 +2,41 @@ package io.iohk.ethereum.jsonrpc import akka.actor.ActorSystem import akka.testkit.TestKit -import io.iohk.ethereum.domain.ChainWeight -import io.iohk.ethereum.jsonrpc.DebugService.{ListPeersInfoRequest, ListPeersInfoResponse} -import io.iohk.ethereum.jsonrpc.NetService.{ListeningResponse, PeerCountResponse, VersionResponse} -import io.iohk.ethereum.jsonrpc.serialization.JsonSerializers.{ - OptionNoneToJNullSerializer, - QuantitiesSerializer, - UnformattedDataJsonSerializer -} -import io.iohk.ethereum.jsonrpc.server.controllers.JsonRpcBaseController.JsonRpcConfig -import io.iohk.ethereum.jsonrpc.server.http.JsonRpcHttpServer -import io.iohk.ethereum.jsonrpc.server.ipc.JsonRpcIpcServer -import io.iohk.ethereum.network.EtcPeerManagerActor.{PeerInfo, RemoteStatus} -import io.iohk.ethereum.network.p2p.messages.ProtocolVersions -import io.iohk.ethereum.{Fixtures, LongPatience, WithActorSystemShutDown} + import monix.eval.Task import monix.execution.Scheduler.Implicits.global -import org.json4s.{DefaultFormats, Formats, JArray, JObject, JString} -import org.scalatest.concurrent.{Eventually, ScalaFutures} + +import scala.concurrent.duration._ + +import org.json4s.DefaultFormats +import org.json4s.Formats +import org.json4s.JArray +import org.json4s.JObject +import org.json4s.JString +import org.scalatest.concurrent.Eventually +import org.scalatest.concurrent.ScalaFutures import org.scalatest.flatspec.AnyFlatSpecLike import org.scalatest.matchers.should.Matchers import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks -import scala.concurrent.duration._ +import io.iohk.ethereum.Fixtures +import io.iohk.ethereum.LongPatience +import io.iohk.ethereum.WithActorSystemShutDown +import io.iohk.ethereum.domain.ChainWeight +import io.iohk.ethereum.jsonrpc.DebugService.ListPeersInfoRequest +import io.iohk.ethereum.jsonrpc.DebugService.ListPeersInfoResponse +import io.iohk.ethereum.jsonrpc.NetService.ListeningResponse +import io.iohk.ethereum.jsonrpc.NetService.PeerCountResponse +import io.iohk.ethereum.jsonrpc.NetService.VersionResponse +import io.iohk.ethereum.jsonrpc.serialization.JsonSerializers.OptionNoneToJNullSerializer +import io.iohk.ethereum.jsonrpc.serialization.JsonSerializers.QuantitiesSerializer +import io.iohk.ethereum.jsonrpc.serialization.JsonSerializers.UnformattedDataJsonSerializer +import io.iohk.ethereum.jsonrpc.server.controllers.JsonRpcBaseController.JsonRpcConfig +import io.iohk.ethereum.jsonrpc.server.http.JsonRpcHttpServer +import io.iohk.ethereum.jsonrpc.server.ipc.JsonRpcIpcServer +import io.iohk.ethereum.network.EtcPeerManagerActor.PeerInfo +import io.iohk.ethereum.network.EtcPeerManagerActor.RemoteStatus +import io.iohk.ethereum.network.p2p.messages.ProtocolVersions class JsonRpcControllerSpec extends TestKit(ActorSystem("JsonRpcControllerSpec_System")) diff --git a/src/test/scala/io/iohk/ethereum/jsonrpc/MantisJRCSpec.scala b/src/test/scala/io/iohk/ethereum/jsonrpc/MantisJRCSpec.scala index 1cecd9e407..e89b6e12c4 100644 --- a/src/test/scala/io/iohk/ethereum/jsonrpc/MantisJRCSpec.scala +++ b/src/test/scala/io/iohk/ethereum/jsonrpc/MantisJRCSpec.scala @@ -1,14 +1,25 @@ package io.iohk.ethereum.jsonrpc +import monix.eval.Task + +import org.json4s.Extraction +import org.json4s.JArray +import org.json4s.JBool +import org.json4s.JInt +import org.json4s.JLong +import org.json4s.JObject +import org.json4s.JString +import org.scalamock.scalatest.AsyncMockFactory + +import io.iohk.ethereum.Fixtures +import io.iohk.ethereum.FreeSpecBase +import io.iohk.ethereum.SpecFixtures import io.iohk.ethereum.jsonrpc.MantisService.GetAccountTransactionsResponse import io.iohk.ethereum.jsonrpc.server.controllers.JsonRpcBaseController.JsonRpcConfig import io.iohk.ethereum.nodebuilder.ApisBuilder -import io.iohk.ethereum.transactions.TransactionHistoryService.{ExtendedTransactionData, MinedTransactionData} +import io.iohk.ethereum.transactions.TransactionHistoryService.ExtendedTransactionData +import io.iohk.ethereum.transactions.TransactionHistoryService.MinedTransactionData import io.iohk.ethereum.utils.Config -import io.iohk.ethereum.{Fixtures, FreeSpecBase, SpecFixtures} -import monix.eval.Task -import org.json4s.{Extraction, JArray, JBool, JInt, JLong, JObject, JString} -import org.scalamock.scalatest.AsyncMockFactory class MantisJRCSpec extends FreeSpecBase with SpecFixtures with AsyncMockFactory with JRCMatchers { import io.iohk.ethereum.jsonrpc.serialization.JsonSerializers.formats @@ -16,19 +27,19 @@ class MantisJRCSpec extends FreeSpecBase with SpecFixtures with AsyncMockFactory class Fixture extends ApisBuilder { def config: JsonRpcConfig = JsonRpcConfig(Config.config, available) - val web3Service = mock[Web3Service] - val netService = mock[NetService] - val personalService = mock[PersonalService] - val debugService = mock[DebugService] - val ethService = mock[EthInfoService] - val ethMiningService = mock[EthMiningService] - val ethBlocksService = mock[EthBlocksService] - val ethTxService = mock[EthTxService] - val ethUserService = mock[EthUserService] - val ethFilterService = mock[EthFilterService] - val qaService = mock[QAService] - val checkpointingService = mock[CheckpointingService] - val mantisService = mock[MantisService] + val web3Service: Web3Service = mock[Web3Service] + val netService: NetService = mock[NetService] + val personalService: PersonalService = mock[PersonalService] + val debugService: DebugService = mock[DebugService] + val ethService: EthInfoService = mock[EthInfoService] + val ethMiningService: EthMiningService = mock[EthMiningService] + val ethBlocksService: EthBlocksService = mock[EthBlocksService] + val ethTxService: EthTxService = mock[EthTxService] + val ethUserService: EthUserService = mock[EthUserService] + val ethFilterService: EthFilterService = mock[EthFilterService] + val qaService: QAService = mock[QAService] + val checkpointingService: CheckpointingService = mock[CheckpointingService] + val mantisService: MantisService = mock[MantisService] val jsonRpcController = new JsonRpcController( diff --git a/src/test/scala/io/iohk/ethereum/jsonrpc/MantisServiceSpec.scala b/src/test/scala/io/iohk/ethereum/jsonrpc/MantisServiceSpec.scala index 4f0625d489..b218c9d99d 100644 --- a/src/test/scala/io/iohk/ethereum/jsonrpc/MantisServiceSpec.scala +++ b/src/test/scala/io/iohk/ethereum/jsonrpc/MantisServiceSpec.scala @@ -1,27 +1,37 @@ package io.iohk.ethereum.jsonrpc -import akka.actor.{ActorRef, ActorSystem} -import akka.testkit.{TestKit, TestProbe} +import akka.actor.ActorRef +import akka.actor.ActorSystem +import akka.testkit.TestKit +import akka.testkit.TestProbe import akka.util.ByteString -import io.iohk.ethereum.blockchain.sync.EphemBlockchainTestSetup -import io.iohk.ethereum.crypto.ECDSASignature -import io.iohk.ethereum.domain.{Address, BlockBody, SignedTransactionWithSender, Transaction} -import io.iohk.ethereum.jsonrpc.MantisService.{GetAccountTransactionsRequest, GetAccountTransactionsResponse} -import io.iohk.ethereum.nodebuilder.{ - ApisBuilder, - JSONRpcConfigBuilder, - MantisServiceBuilder, - PendingTransactionsManagerBuilder, - TransactionHistoryServiceBuilder, - TxPoolConfigBuilder -} -import io.iohk.ethereum.transactions.TransactionHistoryService -import io.iohk.ethereum.transactions.TransactionHistoryService.{ExtendedTransactionData, MinedTransactionData} -import io.iohk.ethereum.{BlockHelpers, FreeSpecBase, SpecFixtures, WithActorSystemShutDown} + import monix.eval.Task import scala.collection.immutable.NumericRange +import io.iohk.ethereum.BlockHelpers +import io.iohk.ethereum.FreeSpecBase +import io.iohk.ethereum.SpecFixtures +import io.iohk.ethereum.WithActorSystemShutDown +import io.iohk.ethereum.blockchain.sync.EphemBlockchainTestSetup +import io.iohk.ethereum.crypto.ECDSASignature +import io.iohk.ethereum.domain.Address +import io.iohk.ethereum.domain.BlockBody +import io.iohk.ethereum.domain.SignedTransactionWithSender +import io.iohk.ethereum.domain.Transaction +import io.iohk.ethereum.jsonrpc.MantisService.GetAccountTransactionsRequest +import io.iohk.ethereum.jsonrpc.MantisService.GetAccountTransactionsResponse +import io.iohk.ethereum.nodebuilder.ApisBuilder +import io.iohk.ethereum.nodebuilder.JSONRpcConfigBuilder +import io.iohk.ethereum.nodebuilder.MantisServiceBuilder +import io.iohk.ethereum.nodebuilder.PendingTransactionsManagerBuilder +import io.iohk.ethereum.nodebuilder.TransactionHistoryServiceBuilder +import io.iohk.ethereum.nodebuilder.TxPoolConfigBuilder +import io.iohk.ethereum.transactions.TransactionHistoryService +import io.iohk.ethereum.transactions.TransactionHistoryService.ExtendedTransactionData +import io.iohk.ethereum.transactions.TransactionHistoryService.MinedTransactionData + class MantisServiceSpec extends TestKit(ActorSystem("MantisServiceSpec")) with FreeSpecBase @@ -35,7 +45,7 @@ class MantisServiceSpec with MantisServiceBuilder with JSONRpcConfigBuilder with ApisBuilder { - lazy val pendingTransactionsManagerProbe = TestProbe() + lazy val pendingTransactionsManagerProbe: TestProbe = TestProbe() override lazy val pendingTransactionsManager: ActorRef = pendingTransactionsManagerProbe.ref } def createFixture() = new Fixture diff --git a/src/test/scala/io/iohk/ethereum/jsonrpc/NetServiceSpec.scala b/src/test/scala/io/iohk/ethereum/jsonrpc/NetServiceSpec.scala index 50a872a5de..9b2092eb6e 100644 --- a/src/test/scala/io/iohk/ethereum/jsonrpc/NetServiceSpec.scala +++ b/src/test/scala/io/iohk/ethereum/jsonrpc/NetServiceSpec.scala @@ -2,19 +2,29 @@ package io.iohk.ethereum.jsonrpc import java.net.InetSocketAddress import java.util.concurrent.atomic.AtomicReference + +import akka.actor.ActorRef import akka.actor.ActorSystem import akka.testkit.TestProbe -import io.iohk.ethereum.jsonrpc.NetService._ -import io.iohk.ethereum.security.SecureRandomBuilder -import io.iohk.ethereum.network.{Peer, PeerActor, PeerId, PeerManagerActor} -import io.iohk.ethereum.utils.{NodeStatus, ServerStatus} -import io.iohk.ethereum.{NormalPatience, crypto} + import monix.execution.Scheduler.Implicits.global + +import scala.concurrent.duration._ + import org.scalatest.concurrent.ScalaFutures import org.scalatest.flatspec.AnyFlatSpec import org.scalatest.matchers.should.Matchers -import scala.concurrent.duration._ +import io.iohk.ethereum.NormalPatience +import io.iohk.ethereum.crypto +import io.iohk.ethereum.jsonrpc.NetService._ +import io.iohk.ethereum.network.Peer +import io.iohk.ethereum.network.PeerActor +import io.iohk.ethereum.network.PeerId +import io.iohk.ethereum.network.PeerManagerActor +import io.iohk.ethereum.security.SecureRandomBuilder +import io.iohk.ethereum.utils.NodeStatus +import io.iohk.ethereum.utils.ServerStatus class NetServiceSpec extends AnyFlatSpec with Matchers with ScalaFutures with NormalPatience with SecureRandomBuilder { @@ -46,13 +56,13 @@ class NetServiceSpec extends AnyFlatSpec with Matchers with ScalaFutures with No } trait TestSetup { - implicit val system = ActorSystem("Testsystem") + implicit val system: ActorSystem = ActorSystem("Testsystem") - val testRef = TestProbe().ref + val testRef: ActorRef = TestProbe().ref - val peerManager = TestProbe() + val peerManager: TestProbe = TestProbe() - val nodeStatus = NodeStatus( + val nodeStatus: NodeStatus = NodeStatus( crypto.generateKeyPair(secureRandom), ServerStatus.Listening(new InetSocketAddress(9000)), discoveryStatus = ServerStatus.NotListening diff --git a/src/test/scala/io/iohk/ethereum/jsonrpc/PersonalServiceSpec.scala b/src/test/scala/io/iohk/ethereum/jsonrpc/PersonalServiceSpec.scala index 896eccf7e2..a109c4cfa0 100644 --- a/src/test/scala/io/iohk/ethereum/jsonrpc/PersonalServiceSpec.scala +++ b/src/test/scala/io/iohk/ethereum/jsonrpc/PersonalServiceSpec.scala @@ -1,31 +1,46 @@ package io.iohk.ethereum.jsonrpc import java.time.Duration + import akka.actor.ActorSystem -import akka.testkit.{TestKit, TestProbe} +import akka.testkit.TestKit +import akka.testkit.TestProbe import akka.util.ByteString -import com.miguno.akka.testing.VirtualTime -import io.iohk.ethereum.crypto.ECDSASignature -import io.iohk.ethereum.db.storage.AppStateStorage -import io.iohk.ethereum.domain.{UInt256, _} -import io.iohk.ethereum.jsonrpc.JsonRpcError._ -import io.iohk.ethereum.jsonrpc.PersonalService._ -import io.iohk.ethereum.keystore.KeyStore.{DecryptionFailed, IOError} -import io.iohk.ethereum.keystore.{KeyStore, Wallet} -import io.iohk.ethereum.transactions.PendingTransactionsManager._ -import io.iohk.ethereum.utils.{BlockchainConfig, ForkBlockNumbers, MonetaryPolicyConfig, TxPoolConfig} -import io.iohk.ethereum.{Fixtures, NormalPatience, Timeouts, WithActorSystemShutDown} + import monix.execution.Scheduler.Implicits.global + +import scala.concurrent.duration.FiniteDuration +import scala.reflect.ClassTag + +import com.miguno.akka.testing.VirtualTime import org.bouncycastle.util.encoders.Hex import org.scalamock.matchers.MatcherBase import org.scalamock.scalatest.MockFactory -import org.scalatest.concurrent.{Eventually, ScalaFutures} +import org.scalatest.concurrent.Eventually +import org.scalatest.concurrent.ScalaFutures import org.scalatest.flatspec.AnyFlatSpecLike import org.scalatest.matchers.should.Matchers import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks -import scala.concurrent.duration.FiniteDuration -import scala.reflect.ClassTag +import io.iohk.ethereum.Fixtures +import io.iohk.ethereum.NormalPatience +import io.iohk.ethereum.Timeouts +import io.iohk.ethereum.WithActorSystemShutDown +import io.iohk.ethereum.crypto.ECDSASignature +import io.iohk.ethereum.db.storage.AppStateStorage +import io.iohk.ethereum.domain.UInt256 +import io.iohk.ethereum.domain._ +import io.iohk.ethereum.jsonrpc.JsonRpcError._ +import io.iohk.ethereum.jsonrpc.PersonalService._ +import io.iohk.ethereum.keystore.KeyStore +import io.iohk.ethereum.keystore.KeyStore.DecryptionFailed +import io.iohk.ethereum.keystore.KeyStore.IOError +import io.iohk.ethereum.keystore.Wallet +import io.iohk.ethereum.transactions.PendingTransactionsManager._ +import io.iohk.ethereum.utils.BlockchainConfig +import io.iohk.ethereum.utils.ForkBlockNumbers +import io.iohk.ethereum.utils.MonetaryPolicyConfig +import io.iohk.ethereum.utils.TxPoolConfig class PersonalServiceSpec extends TestKit(ActorSystem("JsonRpcControllerEthSpec_System")) @@ -343,7 +358,7 @@ class PersonalServiceSpec (blockchain.getBestBlockNumber _).expects().returning(1234) (blockchain.getAccount _).expects(address, BigInt(1234)).returning(Some(Account(nonce, 2 * txValue))) - val forkBlock = new Block(Fixtures.Blocks.Block3125369.header, Fixtures.Blocks.Block3125369.body) + new Block(Fixtures.Blocks.Block3125369.header, Fixtures.Blocks.Block3125369.body) (blockchain.getBestBlockNumber _).expects().returning(blockchainConfig.forkBlockNumbers.eip155BlockNumber) val req = SendTransactionWithPassphraseRequest(tx, passphrase) @@ -388,14 +403,14 @@ class PersonalServiceSpec } trait TestSetup { - val prvKey = ByteString(Hex.decode("7a44789ed3cd85861c0bbf9693c7e1de1862dd4396c390147ecf1275099c6e6f")) - val address = Address(Hex.decode("aa6826f00d01fe4085f0c3dd12778e206ce4e2ac")) + val prvKey: ByteString = ByteString(Hex.decode("7a44789ed3cd85861c0bbf9693c7e1de1862dd4396c390147ecf1275099c6e6f")) + val address: Address = Address(Hex.decode("aa6826f00d01fe4085f0c3dd12778e206ce4e2ac")) val passphrase = "aaa" val nonce = 7 val txValue = 128000 - val blockchainConfig = BlockchainConfig( + val blockchainConfig: BlockchainConfig = BlockchainConfig( chainId = 0x03.toByte, //unused networkId = 1, @@ -434,13 +449,13 @@ class PersonalServiceSpec treasuryAddress = Address(0) ) - val wallet = Wallet(address, prvKey) - val tx = TransactionRequest(from = address, to = Some(Address(42)), value = Some(txValue)) - val stxWithSender = wallet.signTx(tx.toTransaction(nonce), None) + val wallet: Wallet = Wallet(address, prvKey) + val tx: TransactionRequest = TransactionRequest(from = address, to = Some(Address(42)), value = Some(txValue)) + val stxWithSender: SignedTransactionWithSender = wallet.signTx(tx.toTransaction(nonce), None) val stx = stxWithSender.tx - val chainSpecificStx = wallet.signTx(tx.toTransaction(nonce), Some(blockchainConfig.chainId)).tx + val chainSpecificStx: SignedTransaction = wallet.signTx(tx.toTransaction(nonce), Some(blockchainConfig.chainId)).tx - val txPoolConfig = new TxPoolConfig { + val txPoolConfig: TxPoolConfig = new TxPoolConfig { override val txPoolSize: Int = 30 override val pendingTxManagerQueryTimeout: FiniteDuration = Timeouts.normalTimeout override val transactionTimeout: FiniteDuration = Timeouts.normalTimeout @@ -449,15 +464,15 @@ class PersonalServiceSpec val time = new VirtualTime - val keyStore = mock[KeyStore] + val keyStore: KeyStore = mock[KeyStore] - val txPool = TestProbe() - val appStateStorage = mock[AppStateStorage] - val blockchain = mock[BlockchainImpl] + val txPool: TestProbe = TestProbe() + val appStateStorage: AppStateStorage = mock[AppStateStorage] + val blockchain: BlockchainImpl = mock[BlockchainImpl] val personal = new PersonalService(keyStore, blockchain, txPool.ref, appStateStorage, blockchainConfig, txPoolConfig) def array[T](arr: Array[T])(implicit ev: ClassTag[Array[T]]): MatcherBase = - argThat((_: Array[T]) sameElements arr) + argThat((_: Array[T]).sameElements(arr)) } } diff --git a/src/test/scala/io/iohk/ethereum/jsonrpc/ProofServiceDummy.scala b/src/test/scala/io/iohk/ethereum/jsonrpc/ProofServiceDummy.scala index c3e26793ad..461a564fed 100644 --- a/src/test/scala/io/iohk/ethereum/jsonrpc/ProofServiceDummy.scala +++ b/src/test/scala/io/iohk/ethereum/jsonrpc/ProofServiceDummy.scala @@ -1,9 +1,14 @@ package io.iohk.ethereum.jsonrpc -import io.iohk.ethereum.domain.{Account, Address, UInt256} -import io.iohk.ethereum.jsonrpc.ProofService.{GetProofRequest, GetProofResponse, ProofAccount} import monix.eval.Task +import io.iohk.ethereum.domain.Account +import io.iohk.ethereum.domain.Address +import io.iohk.ethereum.domain.UInt256 +import io.iohk.ethereum.jsonrpc.ProofService.GetProofRequest +import io.iohk.ethereum.jsonrpc.ProofService.GetProofResponse +import io.iohk.ethereum.jsonrpc.ProofService.ProofAccount + object ProofServiceDummy extends ProofService { val EmptyAddress: Address = Address(Account.EmptyCodeHash) @@ -18,7 +23,6 @@ object ProofServiceDummy extends ProofService { ) val EmptyProofResponse: GetProofResponse = GetProofResponse(EmptyProofAccount) - override def getProof(req: GetProofRequest): ServiceResponse[GetProofResponse] = { + override def getProof(req: GetProofRequest): ServiceResponse[GetProofResponse] = Task.now(Right(EmptyProofResponse)) - } } diff --git a/src/test/scala/io/iohk/ethereum/jsonrpc/QAServiceSpec.scala b/src/test/scala/io/iohk/ethereum/jsonrpc/QAServiceSpec.scala index 9bcc874c01..a794434b57 100644 --- a/src/test/scala/io/iohk/ethereum/jsonrpc/QAServiceSpec.scala +++ b/src/test/scala/io/iohk/ethereum/jsonrpc/QAServiceSpec.scala @@ -1,8 +1,14 @@ package io.iohk.ethereum.jsonrpc import akka.actor.ActorSystem -import akka.testkit.{TestKit, TestProbe} +import akka.testkit.TestKit +import akka.testkit.TestProbe import akka.util.ByteString + +import monix.eval.Task + +import org.scalamock.scalatest.AsyncMockFactory + import io.iohk.ethereum._ import io.iohk.ethereum.blockchain.sync.regular.RegularSync.NewCheckpoint import io.iohk.ethereum.consensus.Consensus @@ -14,8 +20,6 @@ import io.iohk.ethereum.crypto.ECDSASignature import io.iohk.ethereum.domain._ import io.iohk.ethereum.jsonrpc.QAService._ import io.iohk.ethereum.nodebuilder.BlockchainConfigBuilder -import monix.eval.Task -import org.scalamock.scalatest.AsyncMockFactory class QAServiceSpec extends TestKit(ActorSystem("QAServiceSpec_ActorSystem")) @@ -104,9 +108,9 @@ class QAServiceSpec } lazy val testConsensus: TestConsensus = mock[TestConsensus] - lazy val blockchainReader = mock[BlockchainReader] - lazy val blockchain = mock[BlockchainImpl] - lazy val syncController = TestProbe() + lazy val blockchainReader: BlockchainReader = mock[BlockchainReader] + lazy val blockchain: BlockchainImpl = mock[BlockchainImpl] + lazy val syncController: TestProbe = TestProbe() lazy val checkpointBlockGenerator = new CheckpointBlockGenerator() lazy val qaService = new QAService( @@ -118,18 +122,18 @@ class QAServiceSpec syncController.ref ) - lazy val mineBlocksReq = MineBlocksRequest(1, true, None) - lazy val mineBlocksMsg = + lazy val mineBlocksReq: MineBlocksRequest = MineBlocksRequest(1, true, None) + lazy val mineBlocksMsg: MineBlocks = MineBlocks(mineBlocksReq.numBlocks, mineBlocksReq.withTransactions, mineBlocksReq.parentBlock) val fakeChainId: Byte = 42.toByte } trait CheckpointsGenerationFixture { val block = Fixtures.Blocks.ValidBlock.block - val privateKeys = seqByteStringOfNItemsOfLengthMGen(3, 32).sample.get - val signatures = privateKeys.map(ECDSASignature.sign(block.hash, _)) - val checkpoint = Checkpoint(signatures) - val req = GenerateCheckpointRequest(privateKeys, Some(block.hash)) + val privateKeys: Seq[ByteString] = seqByteStringOfNItemsOfLengthMGen(3, 32).sample.get + val signatures: Seq[ECDSASignature] = privateKeys.map(ECDSASignature.sign(block.hash, _)) + val checkpoint: Checkpoint = Checkpoint(signatures) + val req: GenerateCheckpointRequest = GenerateCheckpointRequest(privateKeys, Some(block.hash)) } def createFixture(): Fixture = new Fixture diff --git a/src/test/scala/io/iohk/ethereum/jsonrpc/QaJRCSpec.scala b/src/test/scala/io/iohk/ethereum/jsonrpc/QaJRCSpec.scala index b9fb1e1cad..5dcc5621f7 100644 --- a/src/test/scala/io/iohk/ethereum/jsonrpc/QaJRCSpec.scala +++ b/src/test/scala/io/iohk/ethereum/jsonrpc/QaJRCSpec.scala @@ -1,26 +1,37 @@ package io.iohk.ethereum.jsonrpc import akka.util.ByteString -import io.iohk.ethereum.consensus.pow.miners.MockedMiner.{MineBlocks, MockedMinerResponse, MockedMinerResponses} -import io.iohk.ethereum.crypto.ECDSASignature -import io.iohk.ethereum.db.storage.AppStateStorage -import io.iohk.ethereum.domain.Checkpoint -import io.iohk.ethereum.jsonrpc.server.controllers.JsonRpcBaseController.JsonRpcConfig -import io.iohk.ethereum.jsonrpc.QAService.MineBlocksResponse.MinerResponseType._ -import io.iohk.ethereum.jsonrpc.QAService._ -import io.iohk.ethereum.nodebuilder.{ApisBuilder, BlockchainConfigBuilder} -import io.iohk.ethereum.utils.{ByteStringUtils, Config} -import io.iohk.ethereum.{ByteGenerators, NormalPatience, crypto} + import monix.eval.Task import monix.execution.Scheduler.Implicits.global + +import org.bouncycastle.crypto.AsymmetricCipherKeyPair import org.json4s.Extraction import org.json4s.JsonAST._ import org.json4s.JsonDSL._ +import org.scalamock.handlers.CallHandler1 import org.scalamock.scalatest.MockFactory import org.scalatest.concurrent.PatienceConfiguration import org.scalatest.matchers.should.Matchers import org.scalatest.wordspec.AnyWordSpec +import io.iohk.ethereum.ByteGenerators +import io.iohk.ethereum.NormalPatience +import io.iohk.ethereum.consensus.pow.miners.MockedMiner.MineBlocks +import io.iohk.ethereum.consensus.pow.miners.MockedMiner.MockedMinerResponse +import io.iohk.ethereum.consensus.pow.miners.MockedMiner.MockedMinerResponses +import io.iohk.ethereum.crypto +import io.iohk.ethereum.crypto.ECDSASignature +import io.iohk.ethereum.db.storage.AppStateStorage +import io.iohk.ethereum.domain.Checkpoint +import io.iohk.ethereum.jsonrpc.QAService.MineBlocksResponse.MinerResponseType._ +import io.iohk.ethereum.jsonrpc.QAService._ +import io.iohk.ethereum.jsonrpc.server.controllers.JsonRpcBaseController.JsonRpcConfig +import io.iohk.ethereum.nodebuilder.ApisBuilder +import io.iohk.ethereum.nodebuilder.BlockchainConfigBuilder +import io.iohk.ethereum.utils.ByteStringUtils +import io.iohk.ethereum.utils.Config + class QaJRCSpec extends AnyWordSpec with Matchers @@ -237,20 +248,20 @@ class QaJRCSpec with ApisBuilder { def config: JsonRpcConfig = JsonRpcConfig(Config.config, available) - val appStateStorage = mock[AppStateStorage] - val web3Service = mock[Web3Service] - val netService = mock[NetService] - val personalService = mock[PersonalService] - val debugService = mock[DebugService] - val ethService = mock[EthInfoService] - val ethMiningService = mock[EthMiningService] - val ethBlocksService = mock[EthBlocksService] - val ethTxService = mock[EthTxService] - val ethUserService = mock[EthUserService] - val ethFilterService = mock[EthFilterService] - val checkpointingService = mock[CheckpointingService] - val mantisService = mock[MantisService] - val qaService = mock[QAService] + val appStateStorage: AppStateStorage = mock[AppStateStorage] + val web3Service: Web3Service = mock[Web3Service] + val netService: NetService = mock[NetService] + val personalService: PersonalService = mock[PersonalService] + val debugService: DebugService = mock[DebugService] + val ethService: EthInfoService = mock[EthInfoService] + val ethMiningService: EthMiningService = mock[EthMiningService] + val ethBlocksService: EthBlocksService = mock[EthBlocksService] + val ethTxService: EthTxService = mock[EthTxService] + val ethUserService: EthUserService = mock[EthUserService] + val ethFilterService: EthFilterService = mock[EthFilterService] + val checkpointingService: CheckpointingService = mock[CheckpointingService] + val mantisService: MantisService = mock[MantisService] + val qaService: QAService = mock[QAService] val jsonRpcController = new JsonRpcController( @@ -272,9 +283,9 @@ class QaJRCSpec config ) - val mineBlocksReq = MineBlocksRequest(1, withTransactions = true, None) + val mineBlocksReq: MineBlocksRequest = MineBlocksRequest(1, withTransactions = true, None) - val mineBlocksRpcRequest = JsonRpcRequest( + val mineBlocksRpcRequest: JsonRpcRequest = JsonRpcRequest( "2.0", "qa_mineBlocks", Some( @@ -288,21 +299,21 @@ class QaJRCSpec Some(JInt(1)) ) - val blockHash = byteStringOfLengthNGen(32).sample.get - val blockHashAsString = ByteStringUtils.hash2string(blockHash) - val privateKeys = seqByteStringOfNItemsOfLengthMGen(3, 32).sample.get.toList - val keyPairs = privateKeys.map { key => + val blockHash: ByteString = byteStringOfLengthNGen(32).sample.get + val blockHashAsString: String = ByteStringUtils.hash2string(blockHash) + val privateKeys: List[ByteString] = seqByteStringOfNItemsOfLengthMGen(3, 32).sample.get.toList + val keyPairs: List[AsymmetricCipherKeyPair] = privateKeys.map { key => crypto.keyPairFromPrvKey(key.toArray) } - val signatures = keyPairs.map(ECDSASignature.sign(blockHash.toArray, _)) - val checkpoint = Checkpoint(signatures) - val privateKeysAsJson = privateKeys.map { key => + val signatures: List[ECDSASignature] = keyPairs.map(ECDSASignature.sign(blockHash.toArray, _)) + val checkpoint: Checkpoint = Checkpoint(signatures) + val privateKeysAsJson: List[JString] = privateKeys.map { key => JString(ByteStringUtils.hash2string(key)) } - val generateCheckpointReq = GenerateCheckpointRequest(privateKeys, Some(blockHash)) + val generateCheckpointReq: GenerateCheckpointRequest = GenerateCheckpointRequest(privateKeys, Some(blockHash)) - val generateCheckpointRpcRequest = JsonRpcRequest( + val generateCheckpointRpcRequest: JsonRpcRequest = JsonRpcRequest( "2.0", "qa_generateCheckpoint", Some( @@ -318,7 +329,7 @@ class QaJRCSpec Some(1) ) - val getFederationMembersInfoRpcRequest = JsonRpcRequest( + val getFederationMembersInfoRpcRequest: JsonRpcRequest = JsonRpcRequest( "2.0", "qa_getFederationMembersInfo", Some( @@ -335,11 +346,12 @@ class QaJRCSpec def responseType(expectedType: MineBlocksResponse.MinerResponseType): JField = "responseType" -> JString(expectedType.entryName) - def mockSuccessfulMineBlocksBehaviour(resp: MockedMinerResponse) = { + def mockSuccessfulMineBlocksBehaviour( + resp: MockedMinerResponse + ): CallHandler1[MineBlocksRequest, Task[Either[JsonRpcError, MineBlocksResponse]]] = (qaService.mineBlocks _) .expects(mineBlocksReq) .returning(Task.now(Right(MineBlocksResponse(resp)))) - } val fakeChainId: Byte = 42.toByte } diff --git a/src/test/scala/io/iohk/ethereum/jsonrpc/server/http/JsonRpcHttpServerSpec.scala b/src/test/scala/io/iohk/ethereum/jsonrpc/server/http/JsonRpcHttpServerSpec.scala index f533015e68..6e1b37b8ad 100644 --- a/src/test/scala/io/iohk/ethereum/jsonrpc/server/http/JsonRpcHttpServerSpec.scala +++ b/src/test/scala/io/iohk/ethereum/jsonrpc/server/http/JsonRpcHttpServerSpec.scala @@ -5,26 +5,37 @@ import java.util.concurrent.TimeUnit import akka.actor.ActorSystem import akka.http.scaladsl.model._ -import akka.http.scaladsl.model.headers.{HttpOrigin, Origin, _} +import akka.http.scaladsl.model.headers.HttpOrigin +import akka.http.scaladsl.model.headers.Origin +import akka.http.scaladsl.model.headers._ import akka.http.scaladsl.server.Route import akka.http.scaladsl.testkit.ScalatestRouteTest import akka.util.ByteString -import ch.megard.akka.http.cors.scaladsl.model.HttpOriginMatcher -import org.json4s.native.JsonMethods._ -import io.iohk.ethereum.healthcheck.{HealthcheckResponse, HealthcheckResult} -import io.iohk.ethereum.jsonrpc._ -import io.iohk.ethereum.jsonrpc.server.controllers.JsonRpcBaseController -import io.iohk.ethereum.jsonrpc.server.http.JsonRpcHttpServer.{JsonRpcHttpServerConfig, RateLimitConfig} -import io.iohk.ethereum.utils.{BuildInfo, Logger} + import monix.eval.Task -import org.json4s.JsonAST.{JInt, JNothing, JString} + +import scala.concurrent.duration.FiniteDuration + +import ch.megard.akka.http.cors.scaladsl.model.HttpOriginMatcher +import org.json4s.DefaultFormats +import org.json4s.Extraction +import org.json4s.JsonAST.JInt +import org.json4s.JsonAST.JNothing +import org.json4s.JsonAST.JString import org.json4s.native.JsonMethods -import org.json4s.{DefaultFormats, Extraction} +import org.json4s.native.JsonMethods._ import org.scalamock.scalatest.MockFactory import org.scalatest.flatspec.AnyFlatSpec import org.scalatest.matchers.should.Matchers -import scala.concurrent.duration.FiniteDuration +import io.iohk.ethereum.healthcheck.HealthcheckResponse +import io.iohk.ethereum.healthcheck.HealthcheckResult +import io.iohk.ethereum.jsonrpc._ +import io.iohk.ethereum.jsonrpc.server.controllers.JsonRpcBaseController +import io.iohk.ethereum.jsonrpc.server.http.JsonRpcHttpServer.JsonRpcHttpServerConfig +import io.iohk.ethereum.jsonrpc.server.http.JsonRpcHttpServer.RateLimitConfig +import io.iohk.ethereum.utils.BuildInfo +import io.iohk.ethereum.utils.Logger class JsonRpcHttpServerSpec extends AnyFlatSpec with Matchers with ScalatestRouteTest { @@ -400,17 +411,17 @@ class JsonRpcHttpServerSpec extends AnyFlatSpec with Matchers with ScalatestRout trait TestSetup extends MockFactory { val jsonRpc = "2.0" val id = 1 - val jsonRequest = ByteString(s"""{"jsonrpc":"$jsonRpc", "method": "eth_blockNumber", "id": "$id"}""") - val resultSuccessful = JString("this is a response") - val jsonRpcResponseSuccessful = JsonRpcResponse(jsonRpc, Some(resultSuccessful), None, JInt(id)) + val jsonRequest: ByteString = ByteString(s"""{"jsonrpc":"$jsonRpc", "method": "eth_blockNumber", "id": "$id"}""") + val resultSuccessful: JString = JString("this is a response") + val jsonRpcResponseSuccessful: JsonRpcResponse = JsonRpcResponse(jsonRpc, Some(resultSuccessful), None, JInt(id)) - val rateLimitConfig = new RateLimitConfig { + val rateLimitConfig: RateLimitConfig = new RateLimitConfig { override val enabled: Boolean = false override val minRequestInterval: FiniteDuration = FiniteDuration.apply(20, TimeUnit.MILLISECONDS) override val latestTimestampCacheSize: Int = 1024 } - val serverConfig = new JsonRpcHttpServerConfig { + val serverConfig: JsonRpcHttpServerConfig = new JsonRpcHttpServerConfig { override val mode: String = "mockJsonRpc" override val enabled: Boolean = true override val interface: String = "" @@ -419,13 +430,13 @@ class JsonRpcHttpServerSpec extends AnyFlatSpec with Matchers with ScalatestRout override val rateLimit: RateLimitConfig = rateLimitConfig } - val rateLimitEnabledConfig = new RateLimitConfig { + val rateLimitEnabledConfig: RateLimitConfig = new RateLimitConfig { override val enabled: Boolean = true override val minRequestInterval: FiniteDuration = FiniteDuration.apply(20, TimeUnit.MILLISECONDS) override val latestTimestampCacheSize: Int = 1024 } - val serverConfigWithRateLimit = new JsonRpcHttpServerConfig { + val serverConfigWithRateLimit: JsonRpcHttpServerConfig = new JsonRpcHttpServerConfig { override val mode: String = "mockJsonRpc" override val enabled: Boolean = true override val interface: String = "" @@ -434,8 +445,8 @@ class JsonRpcHttpServerSpec extends AnyFlatSpec with Matchers with ScalatestRout override val rateLimit: RateLimitConfig = rateLimitEnabledConfig } - val mockJsonRpcController = mock[JsonRpcController] - val mockJsonRpcHealthChecker = mock[JsonRpcHealthChecker] + val mockJsonRpcController: JsonRpcController = mock[JsonRpcController] + val mockJsonRpcHealthChecker: JsonRpcHealthChecker = mock[JsonRpcHealthChecker] val mockJsonRpcHttpServer = new FakeJsonRpcHttpServer( jsonRpcController = mockJsonRpcController, @@ -444,7 +455,7 @@ class JsonRpcHttpServerSpec extends AnyFlatSpec with Matchers with ScalatestRout cors = serverConfig.corsAllowedOrigins ) - val corsAllowedOrigin = HttpOrigin("http://localhost:3333") + val corsAllowedOrigin: HttpOrigin = HttpOrigin("http://localhost:3333") val mockJsonRpcHttpServerWithCors = new FakeJsonRpcHttpServer( jsonRpcController = mockJsonRpcController, jsonRpcHealthChecker = mockJsonRpcHealthChecker, diff --git a/src/test/scala/io/iohk/ethereum/keystore/EncryptedKeySpec.scala b/src/test/scala/io/iohk/ethereum/keystore/EncryptedKeySpec.scala index 63cf897332..6bb7fd28a5 100644 --- a/src/test/scala/io/iohk/ethereum/keystore/EncryptedKeySpec.scala +++ b/src/test/scala/io/iohk/ethereum/keystore/EncryptedKeySpec.scala @@ -1,14 +1,15 @@ package io.iohk.ethereum.keystore +import org.scalatest.flatspec.AnyFlatSpec +import org.scalatest.matchers.should.Matchers + import io.iohk.ethereum.crypto import io.iohk.ethereum.domain.Address import io.iohk.ethereum.security.SecureRandomBuilder -import org.scalatest.flatspec.AnyFlatSpec -import org.scalatest.matchers.should.Matchers class EncryptedKeySpec extends AnyFlatSpec with Matchers with SecureRandomBuilder { - val gethKey = + val gethKey: String = """{ | "id": "033b7a63-30f2-47fc-bbbe-d22925a14ab3", | "address": "932245e1c40ec2026a2c7acc80befb68816cdba4", @@ -32,7 +33,7 @@ class EncryptedKeySpec extends AnyFlatSpec with Matchers with SecureRandomBuilde |} """.stripMargin - val parityKey = + val parityKey: String = """{ | "id": "20909a42-09c4-0740-02dc-a0b8cbaea688", | "version": 3, diff --git a/src/test/scala/io/iohk/ethereum/keystore/KeyStoreImplSpec.scala b/src/test/scala/io/iohk/ethereum/keystore/KeyStoreImplSpec.scala index a5be135d19..1cdedc3fc4 100644 --- a/src/test/scala/io/iohk/ethereum/keystore/KeyStoreImplSpec.scala +++ b/src/test/scala/io/iohk/ethereum/keystore/KeyStoreImplSpec.scala @@ -1,21 +1,30 @@ package io.iohk.ethereum.keystore import java.io.File -import java.nio.file.{FileSystemException, FileSystems, Files, Path} +import java.nio.file.FileSystemException +import java.nio.file.FileSystems +import java.nio.file.Files +import java.nio.file.Path import akka.util.ByteString -import io.iohk.ethereum.domain.Address -import io.iohk.ethereum.keystore.KeyStore.{DecryptionFailed, IOError, KeyNotFound, PassPhraseTooShort} -import io.iohk.ethereum.security.SecureRandomBuilder -import io.iohk.ethereum.utils.{Config, KeyStoreConfig} + +import scala.util.Try + import org.apache.commons.io.FileUtils import org.bouncycastle.util.encoders.Hex import org.scalatest.BeforeAndAfter - -import scala.util.Try import org.scalatest.flatspec.AnyFlatSpec import org.scalatest.matchers.should.Matchers +import io.iohk.ethereum.domain.Address +import io.iohk.ethereum.keystore.KeyStore.DecryptionFailed +import io.iohk.ethereum.keystore.KeyStore.IOError +import io.iohk.ethereum.keystore.KeyStore.KeyNotFound +import io.iohk.ethereum.keystore.KeyStore.PassPhraseTooShort +import io.iohk.ethereum.security.SecureRandomBuilder +import io.iohk.ethereum.utils.Config +import io.iohk.ethereum.utils.KeyStoreConfig + class KeyStoreImplSpec extends AnyFlatSpec with Matchers with BeforeAndAfter with SecureRandomBuilder { before(clearKeyStore()) @@ -129,7 +138,7 @@ class KeyStoreImplSpec extends AnyFlatSpec with Matchers with BeforeAndAfter wit } trait TestSetup { - val keyStoreConfig = KeyStoreConfig(Config.config) + val keyStoreConfig: KeyStoreConfig = KeyStoreConfig(Config.config) object testFailingPathConfig extends KeyStoreConfig { @@ -137,7 +146,7 @@ class KeyStoreImplSpec extends AnyFlatSpec with Matchers with BeforeAndAfter wit override val keyStoreDir: String = { val tmpDir: Path = Files.createTempDirectory("mentis-keystore") val principalLookupService = FileSystems.getDefault.getUserPrincipalLookupService - val rootOrAdminPrincipal = Try { principalLookupService.lookupPrincipalByName("root") }.orElse(Try { + val rootOrAdminPrincipal = Try(principalLookupService.lookupPrincipalByName("root")).orElse(Try { principalLookupService.lookupPrincipalByName("Administrator") }) Files.setOwner(tmpDir, rootOrAdminPrincipal.get) @@ -153,19 +162,17 @@ class KeyStoreImplSpec extends AnyFlatSpec with Matchers with BeforeAndAfter wit val keyStore = new KeyStoreImpl(keyStoreConfig, secureRandom) - def getKeyStore(config: KeyStoreConfig): KeyStoreImpl = { + def getKeyStore(config: KeyStoreConfig): KeyStoreImpl = new KeyStoreImpl(config, secureRandom) - } - val key1 = ByteString(Hex.decode("7a44789ed3cd85861c0bbf9693c7e1de1862dd4396c390147ecf1275099c6e6f")) - val addr1 = Address(Hex.decode("aa6826f00d01fe4085f0c3dd12778e206ce4e2ac")) - val key2 = ByteString(Hex.decode("ee9fb343c34856f3e64f6f0b5e2abd1b298aaa76d0ffc667d00eac4582cb69ca")) - val addr2 = Address(Hex.decode("f1c8084f32b8ef2cee7099446d9a6a185d732468")) - val key3 = ByteString(Hex.decode("ed341f91661a05c249c36b8c9f6d3b796aa9f629f07ddc73b04b9ffc98641a50")) - val addr3 = Address(Hex.decode("d2ecb1332a233d314c30fe3b53f44541b7a07a9e")) + val key1: ByteString = ByteString(Hex.decode("7a44789ed3cd85861c0bbf9693c7e1de1862dd4396c390147ecf1275099c6e6f")) + val addr1: Address = Address(Hex.decode("aa6826f00d01fe4085f0c3dd12778e206ce4e2ac")) + val key2: ByteString = ByteString(Hex.decode("ee9fb343c34856f3e64f6f0b5e2abd1b298aaa76d0ffc667d00eac4582cb69ca")) + val addr2: Address = Address(Hex.decode("f1c8084f32b8ef2cee7099446d9a6a185d732468")) + val key3: ByteString = ByteString(Hex.decode("ed341f91661a05c249c36b8c9f6d3b796aa9f629f07ddc73b04b9ffc98641a50")) + val addr3: Address = Address(Hex.decode("d2ecb1332a233d314c30fe3b53f44541b7a07a9e")) } - def clearKeyStore(): Unit = { + def clearKeyStore(): Unit = FileUtils.deleteDirectory(new File(KeyStoreConfig(Config.config).keyStoreDir)) - } } diff --git a/src/test/scala/io/iohk/ethereum/ledger/BlockExecutionSpec.scala b/src/test/scala/io/iohk/ethereum/ledger/BlockExecutionSpec.scala index 04a7b90661..25f988ff8f 100644 --- a/src/test/scala/io/iohk/ethereum/ledger/BlockExecutionSpec.scala +++ b/src/test/scala/io/iohk/ethereum/ledger/BlockExecutionSpec.scala @@ -1,29 +1,35 @@ package io.iohk.ethereum.ledger import akka.util.ByteString -import io.iohk.ethereum.Mocks.{MockVM, MockValidatorsAlwaysSucceed, MockValidatorsFailOnSpecificBlockNumber} -import io.iohk.ethereum.consensus.TestConsensus -import io.iohk.ethereum.consensus.blocks.CheckpointBlockGenerator -import io.iohk.ethereum.crypto.ECDSASignature -import io.iohk.ethereum.domain._ -import io.iohk.ethereum.ledger.BlockResult -import io.iohk.ethereum.ledger.BlockRewardCalculatorOps._ -import io.iohk.ethereum.vm.{EvmConfig, OutOfGas} -import io.iohk.ethereum.{BlockHelpers, Mocks, ObjectGenerators} + +import org.bouncycastle.crypto.AsymmetricCipherKeyPair import org.scalatest.matchers.should.Matchers +import org.scalatest.prop.TableFor2 +import org.scalatest.prop.TableFor3 import org.scalatest.prop.TableFor4 import org.scalatest.wordspec.AnyWordSpec import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks -import org.scalatest.prop.TableFor2 -import io.iohk.ethereum.utils.Hex -import io.iohk.ethereum.consensus.validators.BlockValidator -import io.iohk.ethereum.consensus.validators.BlockHeaderValidator + +import io.iohk.ethereum.BlockHelpers +import io.iohk.ethereum.Mocks +import io.iohk.ethereum.Mocks.MockVM +import io.iohk.ethereum.Mocks.MockValidatorsAlwaysSucceed +import io.iohk.ethereum.Mocks.MockValidatorsFailOnSpecificBlockNumber +import io.iohk.ethereum.ObjectGenerators +import io.iohk.ethereum.consensus.TestConsensus +import io.iohk.ethereum.consensus.blocks.CheckpointBlockGenerator import io.iohk.ethereum.consensus.pow.validators.OmmersValidator -import io.iohk.ethereum.consensus.validators.std.StdBlockValidator -import org.scalatest.prop.TableFor3 +import io.iohk.ethereum.consensus.validators.BlockHeaderValidator +import io.iohk.ethereum.consensus.validators.BlockValidator import io.iohk.ethereum.consensus.validators.Validators +import io.iohk.ethereum.consensus.validators.std.StdBlockValidator +import io.iohk.ethereum.crypto.ECDSASignature +import io.iohk.ethereum.domain._ +import io.iohk.ethereum.ledger.BlockResult +import io.iohk.ethereum.ledger.BlockRewardCalculatorOps._ import io.iohk.ethereum.utils.ByteStringUtils._ -import org.bouncycastle.crypto.AsymmetricCipherKeyPair +import io.iohk.ethereum.utils.Hex +import io.iohk.ethereum.vm.OutOfGas // scalastyle:off magic.number class BlockExecutionSpec extends AnyWordSpec with Matchers with ScalaCheckPropertyChecks { @@ -465,7 +471,7 @@ class BlockExecutionSpec extends AnyWordSpec with Matchers with ScalaCheckProper blockExecResult.left.forall { case e: BlockExecutionError.ValidationBeforeExecError => true - case _ => false + case _ => false } }) } @@ -519,7 +525,7 @@ class BlockExecutionSpec extends AnyWordSpec with Matchers with ScalaCheckProper assert(blockExecResult match { case Left(_: BlockExecutionError.ValidationAfterExecError) => true - case _ => false + case _ => false }) } } diff --git a/src/test/scala/io/iohk/ethereum/ledger/BlockImportSpec.scala b/src/test/scala/io/iohk/ethereum/ledger/BlockImportSpec.scala index 8f1c33de9f..2fb59be994 100644 --- a/src/test/scala/io/iohk/ethereum/ledger/BlockImportSpec.scala +++ b/src/test/scala/io/iohk/ethereum/ledger/BlockImportSpec.scala @@ -1,25 +1,29 @@ package io.iohk.ethereum.ledger import akka.util.ByteString + +import scala.concurrent.duration._ +import scala.language.postfixOps + +import org.scalatest.concurrent.ScalaFutures +import org.scalatest.flatspec.AnyFlatSpec +import org.scalatest.matchers.should.Matchers + import io.iohk.ethereum.Mocks import io.iohk.ethereum.Mocks.MockValidatorsAlwaysSucceed import io.iohk.ethereum.consensus._ -import io.iohk.ethereum.consensus.validators.BlockHeaderError.{HeaderDifficultyError, HeaderParentNotFoundError} +import io.iohk.ethereum.consensus.validators.BlockHeaderError.HeaderDifficultyError +import io.iohk.ethereum.consensus.validators.BlockHeaderError.HeaderParentNotFoundError import io.iohk.ethereum.consensus.validators._ import io.iohk.ethereum.db.storage.MptStorage import io.iohk.ethereum.domain._ import io.iohk.ethereum.ledger.BlockQueue.Leaf -import io.iohk.ethereum.mpt.{LeafNode, MerklePatriciaTrie} -import org.scalatest.concurrent.ScalaFutures -import org.scalatest.flatspec.AnyFlatSpec -import org.scalatest.matchers.should.Matchers - -import scala.concurrent.duration._ -import scala.language.postfixOps +import io.iohk.ethereum.mpt.LeafNode +import io.iohk.ethereum.mpt.MerklePatriciaTrie class BlockImportSpec extends AnyFlatSpec with Matchers with ScalaFutures { - override implicit val patienceConfig: PatienceConfig = + implicit override val patienceConfig: PatienceConfig = PatienceConfig(timeout = scaled(2 seconds), interval = scaled(1 second)) "Importing blocks" should "ignore existing block" in new ImportBlockTestSetup { @@ -29,12 +33,12 @@ class BlockImportSpec extends AnyFlatSpec with Matchers with ScalaFutures { setBlockExists(block1, inChain = true, inQueue = false) setBestBlock(bestBlock) - whenReady(blockImport.importBlock(block1).runToFuture) { _ shouldEqual DuplicateBlock } + whenReady(blockImport.importBlock(block1).runToFuture)(_ shouldEqual DuplicateBlock) setBlockExists(block2, inChain = false, inQueue = true) setBestBlock(bestBlock) - whenReady(blockImport.importBlock(block2).runToFuture) { _ shouldEqual DuplicateBlock } + whenReady(blockImport.importBlock(block2).runToFuture)(_ shouldEqual DuplicateBlock) } it should "import a block to top of the main chain" in new ImportBlockTestSetup { @@ -94,7 +98,7 @@ class BlockImportSpec extends AnyFlatSpec with Matchers with ScalaFutures { (blockQueue.removeSubtree _).expects(*) - whenReady(blockImport.importBlock(block).runToFuture) { _ shouldBe a[BlockImportFailed] } + whenReady(blockImport.importBlock(block).runToFuture)(_ shouldBe a[BlockImportFailed]) } // scalastyle:off magic.number @@ -127,7 +131,7 @@ class BlockImportSpec extends AnyFlatSpec with Matchers with ScalaFutures { .expects(newBranch, *) .returning((List(blockData2, blockData3), None)) - whenReady(blockImportWithMockedBlockExecution.importBlock(newBlock3).runToFuture) { _ shouldEqual BlockEnqueued } + whenReady(blockImportWithMockedBlockExecution.importBlock(newBlock3).runToFuture)(_ shouldEqual BlockEnqueued) whenReady(blockImportWithMockedBlockExecution.importBlock(newBlock2).runToFuture) { result => result shouldEqual ChainReorganised(oldBranch, newBranch, List(newWeight2, newWeight3)) } @@ -176,7 +180,7 @@ class BlockImportSpec extends AnyFlatSpec with Matchers with ScalaFutures { .expects(newBranch, *) .returning((List(blockData2, blockData3), None)) - whenReady(blockImportWithMockedBlockExecution.importBlock(newBlock3).runToFuture) { _ shouldEqual BlockEnqueued } + whenReady(blockImportWithMockedBlockExecution.importBlock(newBlock3).runToFuture)(_ shouldEqual BlockEnqueued) whenReady(blockImportWithMockedBlockExecution.importBlock(newBlock2).runToFuture) { result => result shouldEqual ChainReorganised(oldBranch, newBranch, List(newWeight2, newWeight3)) } @@ -201,7 +205,7 @@ class BlockImportSpec extends AnyFlatSpec with Matchers with ScalaFutures { val weight1 = ChainWeight.totalDifficultyOnly(block1.header.difficulty + 999) val newWeight2 = weight1.increase(newBlock2.header) - val newWeight3 = newWeight2.increase(newBlock3.header) + newWeight2.increase(newBlock3.header) val oldWeight2 = weight1.increase(oldBlock2.header) val oldWeight3 = oldWeight2.increase(oldBlock3.header) @@ -219,7 +223,7 @@ class BlockImportSpec extends AnyFlatSpec with Matchers with ScalaFutures { .expects(newBranch, *) .returning((List(blockData2), Some(execError))) - whenReady(blockImportWithMockedBlockExecution.importBlock(newBlock3).runToFuture) { _ shouldEqual BlockEnqueued } + whenReady(blockImportWithMockedBlockExecution.importBlock(newBlock3).runToFuture)(_ shouldEqual BlockEnqueued) whenReady(blockImportWithMockedBlockExecution.importBlock(newBlock2).runToFuture) { _ shouldBe a[BlockImportFailed] } @@ -246,7 +250,7 @@ class BlockImportSpec extends AnyFlatSpec with Matchers with ScalaFutures { .expects(newBlock.header, *) .returning(Left(HeaderParentNotFoundError)) - whenReady(blockImport.importBlock(newBlock).runToFuture) { _ shouldEqual UnknownParent } + whenReady(blockImport.importBlock(newBlock).runToFuture)(_ shouldEqual UnknownParent) } it should "validate blocks prior to import" in new ImportBlockTestSetup { @@ -275,7 +279,7 @@ class BlockImportSpec extends AnyFlatSpec with Matchers with ScalaFutures { setBestBlock(genesisBlock) setBlockExists(genesisBlock, inChain = true, inQueue = true) - whenReady(failBlockImport.importBlock(genesisBlock).runToFuture) { _ shouldEqual DuplicateBlock } + whenReady(failBlockImport.importBlock(genesisBlock).runToFuture)(_ shouldEqual DuplicateBlock) } it should "correctly import block with ommers and ancestor in block queue " in new OmmersTestSetup { @@ -316,7 +320,7 @@ class BlockImportSpec extends AnyFlatSpec with Matchers with ScalaFutures { .expects(newBranch, *) .returning((List(blockData2, blockData3), None)) - whenReady(blockImportWithMockedBlockExecution.importBlock(newBlock2).runToFuture) { _ shouldEqual BlockEnqueued } + whenReady(blockImportWithMockedBlockExecution.importBlock(newBlock2).runToFuture)(_ shouldEqual BlockEnqueued) whenReady(blockImportWithMockedBlockExecution.importBlock(newBlock3WithOmmer).runToFuture) { result => result shouldEqual ChainReorganised(oldBranch, newBranch, List(newWeight2, newWeight3)) } diff --git a/src/test/scala/io/iohk/ethereum/ledger/BlockPreparatorSpec.scala b/src/test/scala/io/iohk/ethereum/ledger/BlockPreparatorSpec.scala index 90ce03abca..1340ccd72a 100644 --- a/src/test/scala/io/iohk/ethereum/ledger/BlockPreparatorSpec.scala +++ b/src/test/scala/io/iohk/ethereum/ledger/BlockPreparatorSpec.scala @@ -2,30 +2,34 @@ package io.iohk.ethereum.ledger import akka.util.ByteString import akka.util.ByteString.{empty => bEmpty} + +import org.bouncycastle.crypto.AsymmetricCipherKeyPair +import org.bouncycastle.crypto.params.ECPublicKeyParameters +import org.scalatest.matchers.should.Matchers +import org.scalatest.prop.TableFor2 +import org.scalatest.prop.TableFor4 +import org.scalatest.wordspec.AnyWordSpec +import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks + import io.iohk.ethereum.Mocks -import io.iohk.ethereum.Mocks.{MockVM, MockValidatorsAlwaysSucceed} +import io.iohk.ethereum.Mocks.MockVM +import io.iohk.ethereum.Mocks.MockValidatorsAlwaysSucceed import io.iohk.ethereum.consensus.Consensus import io.iohk.ethereum.consensus.validators.SignedTransactionError.TransactionSignatureError -import io.iohk.ethereum.consensus.validators.{SignedTransactionValid, SignedTransactionValidator} -import io.iohk.ethereum.crypto.{generateKeyPair, kec256} +import io.iohk.ethereum.consensus.validators.SignedTransactionValid +import io.iohk.ethereum.consensus.validators.SignedTransactionValidator +import io.iohk.ethereum.crypto.generateKeyPair +import io.iohk.ethereum.crypto.kec256 import io.iohk.ethereum.domain._ import io.iohk.ethereum.ledger.BlockResult import io.iohk.ethereum.ledger.VMImpl -import io.iohk.ethereum.vm.{ - InvalidJump, - InvalidOpCode, - OutOfGas, - ProgramError, - RevertOccurs, - StackOverflow, - StackUnderflow -} -import org.bouncycastle.crypto.AsymmetricCipherKeyPair -import org.bouncycastle.crypto.params.ECPublicKeyParameters -import org.scalatest.prop.{TableFor2, TableFor4} -import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks -import org.scalatest.matchers.should.Matchers -import org.scalatest.wordspec.AnyWordSpec +import io.iohk.ethereum.vm.InvalidJump +import io.iohk.ethereum.vm.InvalidOpCode +import io.iohk.ethereum.vm.OutOfGas +import io.iohk.ethereum.vm.ProgramError +import io.iohk.ethereum.vm.RevertOccurs +import io.iohk.ethereum.vm.StackOverflow +import io.iohk.ethereum.vm.StackUnderflow // scalastyle:off magic.number class BlockPreparatorSpec extends AnyWordSpec with Matchers with ScalaCheckPropertyChecks { @@ -239,9 +243,9 @@ class BlockPreparatorSpec extends AnyWordSpec with Matchers with ScalaCheckPrope val newAccountAddress = Address(kec256(newAccountKeyPair.getPublic.asInstanceOf[ECPublicKeyParameters].getQ.getEncoded(false).tail)) - override lazy val vm: VMImpl = new MockVM((pc: PC) => { + override lazy val vm: VMImpl = new MockVM((pc: PC) => createResult(pc, defaultGasLimit, defaultGasLimit, 0, None, returnData = ByteString("contract code")) - }) + ) val tx: Transaction = defaultTx.copy(gasPrice = 0, receivingAddress = None, payload = inputData) val stx: SignedTransactionWithSender = SignedTransaction.sign(tx, newAccountKeyPair, Some(blockchainConfig.chainId)) @@ -259,12 +263,10 @@ class BlockPreparatorSpec extends AnyWordSpec with Matchers with ScalaCheckPrope "remember executed transaction in case of many failures in the middle" in new TestSetup { val newAccountKeyPair: AsymmetricCipherKeyPair = generateKeyPair(secureRandom) - val newAccountAddress = - Address(kec256(newAccountKeyPair.getPublic.asInstanceOf[ECPublicKeyParameters].getQ.getEncoded(false).tail)) + Address(kec256(newAccountKeyPair.getPublic.asInstanceOf[ECPublicKeyParameters].getQ.getEncoded(false).tail)) - override lazy val vm: VMImpl = new MockVM((pc: PC) => { - createResult(pc, defaultGasLimit, defaultGasLimit, 0, None, returnData = ByteString.empty) - }) + override lazy val vm: VMImpl = + new MockVM((pc: PC) => createResult(pc, defaultGasLimit, defaultGasLimit, 0, None, returnData = ByteString.empty)) override lazy val validators: MockValidatorsAlwaysSucceed = new Mocks.MockValidatorsAlwaysSucceed { override val signedTransactionValidator: SignedTransactionValidator = @@ -301,12 +303,10 @@ class BlockPreparatorSpec extends AnyWordSpec with Matchers with ScalaCheckPrope "produce empty block if all txs fail" in new TestSetup { val newAccountKeyPair: AsymmetricCipherKeyPair = generateKeyPair(secureRandom) - val newAccountAddress = - Address(kec256(newAccountKeyPair.getPublic.asInstanceOf[ECPublicKeyParameters].getQ.getEncoded(false).tail)) + Address(kec256(newAccountKeyPair.getPublic.asInstanceOf[ECPublicKeyParameters].getQ.getEncoded(false).tail)) - override lazy val vm = new MockVM((pc: PC) => { - createResult(pc, defaultGasLimit, defaultGasLimit, 0, None, returnData = ByteString.empty) - }) + override lazy val vm = + new MockVM((pc: PC) => createResult(pc, defaultGasLimit, defaultGasLimit, 0, None, returnData = ByteString.empty)) override lazy val validators: Mocks.MockValidatorsAlwaysSucceed = new Mocks.MockValidatorsAlwaysSucceed { override val signedTransactionValidator: SignedTransactionValidator = diff --git a/src/test/scala/io/iohk/ethereum/ledger/BlockQueueSpec.scala b/src/test/scala/io/iohk/ethereum/ledger/BlockQueueSpec.scala index f1211345da..f123151b75 100644 --- a/src/test/scala/io/iohk/ethereum/ledger/BlockQueueSpec.scala +++ b/src/test/scala/io/iohk/ethereum/ledger/BlockQueueSpec.scala @@ -1,15 +1,23 @@ package io.iohk.ethereum.ledger import akka.util.ByteString -import io.iohk.ethereum.ObjectGenerators -import io.iohk.ethereum.domain.{Block, BlockBody, BlockchainImpl, ChainWeight} + +import org.scalamock.handlers.CallHandler0 +import org.scalamock.handlers.CallHandler1 +import org.scalamock.scalatest.MockFactory +import org.scalatest.flatspec.AnyFlatSpec +import org.scalatest.matchers.should.Matchers + import io.iohk.ethereum.Fixtures +import io.iohk.ethereum.ObjectGenerators +import io.iohk.ethereum.domain.Block +import io.iohk.ethereum.domain.BlockBody +import io.iohk.ethereum.domain.BlockHeader +import io.iohk.ethereum.domain.BlockchainImpl +import io.iohk.ethereum.domain.ChainWeight import io.iohk.ethereum.ledger.BlockQueue.Leaf import io.iohk.ethereum.utils.Config import io.iohk.ethereum.utils.Config.SyncConfig -import org.scalamock.scalatest.MockFactory -import org.scalatest.flatspec.AnyFlatSpec -import org.scalatest.matchers.should.Matchers class BlockQueueSpec extends AnyFlatSpec with Matchers with MockFactory { @@ -154,20 +162,24 @@ class BlockQueueSpec extends AnyFlatSpec with Matchers with MockFactory { } trait TestConfig { - val syncConfig = SyncConfig(Config.config).copy(maxQueuedBlockNumberAhead = 10, maxQueuedBlockNumberBehind = 10) - val blockchain = mock[BlockchainImpl] - val blockQueue = BlockQueue(blockchain, syncConfig) + val syncConfig: SyncConfig = + SyncConfig(Config.config).copy(maxQueuedBlockNumberAhead = 10, maxQueuedBlockNumberBehind = 10) + val blockchain: BlockchainImpl = mock[BlockchainImpl] + val blockQueue: BlockQueue = BlockQueue(blockchain, syncConfig) - def setBestBlockNumber(n: BigInt) = + def setBestBlockNumber(n: BigInt): CallHandler0[BigInt] = (blockchain.getBestBlockNumber _).expects().returning(n) - def setChainWeightForParent(block: Block, weight: Option[ChainWeight] = None) = + def setChainWeightForParent( + block: Block, + weight: Option[ChainWeight] = None + ): CallHandler1[ByteString, Option[ChainWeight]] = (blockchain.getChainWeightByHash _).expects(block.header.parentHash).returning(weight) def randomHash(): ByteString = ObjectGenerators.byteStringOfLengthNGen(32).sample.get - val defaultHeader = Fixtures.Blocks.ValidBlock.header.copy( + val defaultHeader: BlockHeader = Fixtures.Blocks.ValidBlock.header.copy( difficulty = 1000000, number = 1, gasLimit = 1000000, diff --git a/src/test/scala/io/iohk/ethereum/ledger/BlockRewardCalculatorSpec.scala b/src/test/scala/io/iohk/ethereum/ledger/BlockRewardCalculatorSpec.scala index db0654e6d5..0df2789d79 100644 --- a/src/test/scala/io/iohk/ethereum/ledger/BlockRewardCalculatorSpec.scala +++ b/src/test/scala/io/iohk/ethereum/ledger/BlockRewardCalculatorSpec.scala @@ -1,10 +1,11 @@ package io.iohk.ethereum.ledger -import io.iohk.ethereum.utils.MonetaryPolicyConfig -import io.iohk.ethereum.ledger.BlockRewardCalculatorOps._ -import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks import org.scalatest.flatspec.AnyFlatSpec import org.scalatest.matchers.should.Matchers +import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks + +import io.iohk.ethereum.ledger.BlockRewardCalculatorOps._ +import io.iohk.ethereum.utils.MonetaryPolicyConfig // scalastyle:off magic.number class BlockRewardCalculatorSpec extends AnyFlatSpec with Matchers with ScalaCheckPropertyChecks { diff --git a/src/test/scala/io/iohk/ethereum/ledger/BlockRewardSpec.scala b/src/test/scala/io/iohk/ethereum/ledger/BlockRewardSpec.scala index ac20bf2527..a06b63af00 100644 --- a/src/test/scala/io/iohk/ethereum/ledger/BlockRewardSpec.scala +++ b/src/test/scala/io/iohk/ethereum/ledger/BlockRewardSpec.scala @@ -1,20 +1,24 @@ package io.iohk.ethereum.ledger import akka.util.ByteString + +import org.scalamock.scalatest.MockFactory +import org.scalatest.flatspec.AnyFlatSpec +import org.scalatest.matchers.should.Matchers +import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks + import io.iohk.ethereum.Fixtures import io.iohk.ethereum.Mocks.MockVM import io.iohk.ethereum.blockchain.sync.EphemBlockchainTestSetup import io.iohk.ethereum.domain.BlockHeader.HeaderExtraFields.HefEmpty import io.iohk.ethereum.domain._ import io.iohk.ethereum.ledger.BlockPreparator._ -import io.iohk.ethereum.ledger.VMImpl import io.iohk.ethereum.ledger.BlockRewardCalculatorOps._ +import io.iohk.ethereum.ledger.VMImpl import io.iohk.ethereum.mpt.MerklePatriciaTrie -import io.iohk.ethereum.utils.{Config, ForkBlockNumbers} -import org.scalamock.scalatest.MockFactory -import org.scalatest.flatspec.AnyFlatSpec -import org.scalatest.matchers.should.Matchers -import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks +import io.iohk.ethereum.utils.BlockchainConfig +import io.iohk.ethereum.utils.Config +import io.iohk.ethereum.utils.ForkBlockNumbers class BlockRewardSpec extends AnyFlatSpec with Matchers with ScalaCheckPropertyChecks with MockFactory { @@ -167,29 +171,29 @@ class BlockRewardSpec extends AnyFlatSpec with Matchers with ScalaCheckPropertyC //- cake overrides - val validAccountAddress = Address(0xababab) // 11250603 - val validAccountAddress2 = Address(0xcdcdcd) // 13487565 - val validAccountAddress3 = Address(0xefefef) // 15724527 + val validAccountAddress: Address = Address(0xababab) // 11250603 + val validAccountAddress2: Address = Address(0xcdcdcd) // 13487565 + val validAccountAddress3: Address = Address(0xefefef) // 15724527 - val validAccountAddress4 = Address("0x29a2241af62c0001") // 3000000000000000001 - val validAccountAddress5 = Address("0x29a2241af64e2223") // 3000000000002236963 - val validAccountAddress6 = Address("0x29a2241af6704445") // 3000000000004473925 + val validAccountAddress4: Address = Address("0x29a2241af62c0001") // 3000000000000000001 + val validAccountAddress5: Address = Address("0x29a2241af64e2223") // 3000000000002236963 + val validAccountAddress6: Address = Address("0x29a2241af6704445") // 3000000000004473925 val treasuryAddress = validAccountAddress2 val baseBlockchainConfig = Config.blockchains.blockchainConfig private val forkBlockNumbers: ForkBlockNumbers = baseBlockchainConfig.forkBlockNumbers - override lazy val blockchainConfig = baseBlockchainConfig + override lazy val blockchainConfig: BlockchainConfig = baseBlockchainConfig .copy( treasuryAddress = treasuryAddress, forkBlockNumbers = forkBlockNumbers .copy(ecip1098BlockNumber = forkBlockNumbers.byzantiumBlockNumber + 100) ) - val minerTwoOmmersReward = BigInt("5312500000000000000") - val ommerFiveBlocksDifferenceReward = BigInt("1875000000000000000") + val minerTwoOmmersReward: BigInt = BigInt("5312500000000000000") + val ommerFiveBlocksDifferenceReward: BigInt = BigInt("1875000000000000000") val afterByzantiumNewBlockReward: BigInt = BigInt(10).pow(18) * 3 - val worldState = InMemoryWorldStateProxy( + val worldState: InMemoryWorldStateProxy = InMemoryWorldStateProxy( storagesInstance.storages.evmCodeStorage, blockchain.getBackingMptStorage(-1), (number: BigInt) => blockchainReader.getBlockHeaderByNumber(number).map(_.hash), diff --git a/src/test/scala/io/iohk/ethereum/ledger/BlockValidationSpec.scala b/src/test/scala/io/iohk/ethereum/ledger/BlockValidationSpec.scala index 8ddde4106b..b8a72b2782 100644 --- a/src/test/scala/io/iohk/ethereum/ledger/BlockValidationSpec.scala +++ b/src/test/scala/io/iohk/ethereum/ledger/BlockValidationSpec.scala @@ -1,13 +1,15 @@ package io.iohk.ethereum.ledger import akka.util.ByteString -import io.iohk.ethereum.Mocks -import io.iohk.ethereum.consensus.validators.std.StdBlockValidator -import io.iohk.ethereum.domain._ + import org.bouncycastle.util.encoders.Hex import org.scalamock.scalatest.MockFactory import org.scalatest.matchers.should.Matchers import org.scalatest.wordspec.AnyWordSpec + +import io.iohk.ethereum.Mocks +import io.iohk.ethereum.consensus.validators.std.StdBlockValidator +import io.iohk.ethereum.domain._ import io.iohk.ethereum.utils.ByteStringUtils._ class BlockValidationSpec extends AnyWordSpec with Matchers with MockFactory { diff --git a/src/test/scala/io/iohk/ethereum/ledger/BloomFilterSpec.scala b/src/test/scala/io/iohk/ethereum/ledger/BloomFilterSpec.scala index 79ab5fbd77..bb0f8b59f4 100644 --- a/src/test/scala/io/iohk/ethereum/ledger/BloomFilterSpec.scala +++ b/src/test/scala/io/iohk/ethereum/ledger/BloomFilterSpec.scala @@ -1,11 +1,15 @@ package io.iohk.ethereum.ledger import akka.util.ByteString -import io.iohk.ethereum.domain.{Address, Receipt, TxLogEntry} + import org.bouncycastle.util.encoders.Hex import org.scalatest.flatspec.AnyFlatSpec import org.scalatest.matchers.should.Matchers +import io.iohk.ethereum.domain.Address +import io.iohk.ethereum.domain.Receipt +import io.iohk.ethereum.domain.TxLogEntry + class BloomFilterSpec extends AnyFlatSpec with Matchers { it should "properly create the bloom filter for without logs" in { @@ -24,7 +28,7 @@ class BloomFilterSpec extends AnyFlatSpec with Matchers { } //From tx 0xe9e91f1ee4b56c0df2e9f06c2b8c27c6076195a88a7b8537ba8313d80e6f124e - val receiptWithoutLogs = Receipt.withHashOutcome( + val receiptWithoutLogs: Receipt = Receipt.withHashOutcome( postTransactionStateHash = ByteString(Hex.decode("fa28ef92787192b577a8628e520b546ab58b72102572e08191ddecd51d0851e5")), cumulativeGasUsed = 50244, @@ -37,7 +41,7 @@ class BloomFilterSpec extends AnyFlatSpec with Matchers { ) //From tx 0x864f61c4fbf1952bfb55d4617e4bde3a0338322b37c832119ed1e8717b502530 - val receiptOneLogOneTopic = Receipt.withHashOutcome( + val receiptOneLogOneTopic: Receipt = Receipt.withHashOutcome( postTransactionStateHash = ByteString(Hex.decode("d74e64c4beb7627811f456baedfe05d26364bef11136b922b8c44769ad1e6ac6")), cumulativeGasUsed = BigInt("1674016"), @@ -60,7 +64,7 @@ class BloomFilterSpec extends AnyFlatSpec with Matchers { ) //From tx 0x0bb157f90f918fad96d6954d9e620a4aa490da57a66303a6b41e855fd0f19a59 - val receiptWithManyLogs = Receipt.withHashOutcome( + val receiptWithManyLogs: Receipt = Receipt.withHashOutcome( postTransactionStateHash = ByteString(Hex.decode("fe375456a6f22f90f2f55bd57e72c7c663ef7733d5795f091a06496ad5895c67")), cumulativeGasUsed = 319269, diff --git a/src/test/scala/io/iohk/ethereum/ledger/BranchResolutionSpec.scala b/src/test/scala/io/iohk/ethereum/ledger/BranchResolutionSpec.scala index bb4558d400..0c9125afae 100644 --- a/src/test/scala/io/iohk/ethereum/ledger/BranchResolutionSpec.scala +++ b/src/test/scala/io/iohk/ethereum/ledger/BranchResolutionSpec.scala @@ -1,15 +1,21 @@ package io.iohk.ethereum.ledger import akka.util.ByteString + import cats.data.NonEmptyList -import io.iohk.ethereum.ObjectGenerators -import io.iohk.ethereum.domain.{Block, BlockBody, BlockHeader, ChainWeight} + import org.scalacheck.Gen import org.scalatest.concurrent.ScalaFutures import org.scalatest.matchers.should.Matchers import org.scalatest.wordspec.AnyWordSpec import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks +import io.iohk.ethereum.ObjectGenerators +import io.iohk.ethereum.domain.Block +import io.iohk.ethereum.domain.BlockBody +import io.iohk.ethereum.domain.BlockHeader +import io.iohk.ethereum.domain.ChainWeight + class BranchResolutionSpec extends AnyWordSpec with Matchers diff --git a/src/test/scala/io/iohk/ethereum/ledger/DeleteAccountsSpec.scala b/src/test/scala/io/iohk/ethereum/ledger/DeleteAccountsSpec.scala index 7b36701a0f..f658a4ab3b 100644 --- a/src/test/scala/io/iohk/ethereum/ledger/DeleteAccountsSpec.scala +++ b/src/test/scala/io/iohk/ethereum/ledger/DeleteAccountsSpec.scala @@ -1,40 +1,45 @@ package io.iohk.ethereum.ledger import akka.util.ByteString + +import org.scalamock.scalatest.MockFactory +import org.scalatest.flatspec.AnyFlatSpec +import org.scalatest.matchers.should.Matchers + import io.iohk.ethereum.Mocks.MockVM import io.iohk.ethereum.blockchain.sync.EphemBlockchainTestSetup -import io.iohk.ethereum.domain.{Account, Address, BlockchainImpl, BlockchainReader, UInt256} +import io.iohk.ethereum.domain.Account +import io.iohk.ethereum.domain.Address +import io.iohk.ethereum.domain.BlockchainImpl +import io.iohk.ethereum.domain.UInt256 import io.iohk.ethereum.ledger.VMImpl import io.iohk.ethereum.mpt.MerklePatriciaTrie import io.iohk.ethereum.utils.Config import io.iohk.ethereum.utils.Config.SyncConfig -import org.scalamock.scalatest.MockFactory -import org.scalatest.flatspec.AnyFlatSpec -import org.scalatest.matchers.should.Matchers class DeleteAccountsSpec extends AnyFlatSpec with Matchers with MockFactory { val blockchainConfig = Config.blockchains.blockchainConfig - val syncConfig = SyncConfig(Config.config) + val syncConfig: SyncConfig = SyncConfig(Config.config) - val blockchain = mock[BlockchainImpl] + val blockchain: BlockchainImpl = mock[BlockchainImpl] it should "delete no accounts when none of them should be deleted" in new TestSetup { val newWorld = InMemoryWorldStateProxy.persistState(consensus.blockPreparator.deleteAccounts(Set.empty)(worldState)) - accountAddresses.foreach { a => assert(newWorld.getAccount(a).isDefined) } + accountAddresses.foreach(a => assert(newWorld.getAccount(a).isDefined)) newWorld.stateRootHash shouldBe worldState.stateRootHash } it should "delete the accounts listed for deletion" in new TestSetup { val newWorld = consensus.blockPreparator.deleteAccounts(accountAddresses.tail)(worldState) - accountAddresses.tail.foreach { a => assert(newWorld.getAccount(a).isEmpty) } + accountAddresses.tail.foreach(a => assert(newWorld.getAccount(a).isEmpty)) assert(newWorld.getAccount(accountAddresses.head).isDefined) } it should "delete all the accounts if they are all listed for deletion" in new TestSetup { val newWorld = InMemoryWorldStateProxy.persistState(consensus.blockPreparator.deleteAccounts(accountAddresses)(worldState)) - accountAddresses.foreach { a => assert(newWorld.getAccount(a).isEmpty) } + accountAddresses.foreach(a => assert(newWorld.getAccount(a).isEmpty)) newWorld.stateRootHash shouldBe Account.EmptyStorageRootHash } @@ -58,13 +63,13 @@ class DeleteAccountsSpec extends AnyFlatSpec with Matchers with MockFactory { //- cake overrides - val validAccountAddress = Address(0xababab) - val validAccountAddress2 = Address(0xcdcdcd) - val validAccountAddress3 = Address(0xefefef) + val validAccountAddress: Address = Address(0xababab) + val validAccountAddress2: Address = Address(0xcdcdcd) + val validAccountAddress3: Address = Address(0xefefef) - val accountAddresses = Set(validAccountAddress, validAccountAddress2, validAccountAddress3) + val accountAddresses: Set[Address] = Set(validAccountAddress, validAccountAddress2, validAccountAddress3) - val worldStateWithoutPersist = InMemoryWorldStateProxy( + val worldStateWithoutPersist: InMemoryWorldStateProxy = InMemoryWorldStateProxy( storagesInstance.storages.evmCodeStorage, blockchain.getBackingMptStorage(-1), (number: BigInt) => blockchainReader.getBlockHeaderByNumber(number).map(_.hash), @@ -76,7 +81,7 @@ class DeleteAccountsSpec extends AnyFlatSpec with Matchers with MockFactory { .saveAccount(validAccountAddress, Account(balance = 10)) .saveAccount(validAccountAddress2, Account(balance = 20)) .saveAccount(validAccountAddress3, Account(balance = 30)) - val worldState = InMemoryWorldStateProxy.persistState(worldStateWithoutPersist) + val worldState: InMemoryWorldStateProxy = InMemoryWorldStateProxy.persistState(worldStateWithoutPersist) } } diff --git a/src/test/scala/io/iohk/ethereum/ledger/DeleteTouchedAccountsSpec.scala b/src/test/scala/io/iohk/ethereum/ledger/DeleteTouchedAccountsSpec.scala index 476b6787ea..4a5927c3da 100644 --- a/src/test/scala/io/iohk/ethereum/ledger/DeleteTouchedAccountsSpec.scala +++ b/src/test/scala/io/iohk/ethereum/ledger/DeleteTouchedAccountsSpec.scala @@ -1,26 +1,31 @@ package io.iohk.ethereum.ledger import akka.util.ByteString + +import org.scalatest.flatspec.AnyFlatSpec +import org.scalatest.matchers.should.Matchers + import io.iohk.ethereum.Mocks.MockVM import io.iohk.ethereum.blockchain.sync.EphemBlockchainTestSetup -import io.iohk.ethereum.domain.{Account, Address, BlockchainImpl, BlockchainReader, UInt256} +import io.iohk.ethereum.domain.Account +import io.iohk.ethereum.domain.Address +import io.iohk.ethereum.domain.UInt256 import io.iohk.ethereum.ledger.VMImpl import io.iohk.ethereum.mpt.MerklePatriciaTrie import io.iohk.ethereum.utils.Config import io.iohk.ethereum.utils.Config.SyncConfig -import io.iohk.ethereum.vm.{BlockchainConfigForEvm, EvmConfig} -import org.scalatest.flatspec.AnyFlatSpec -import org.scalatest.matchers.should.Matchers +import io.iohk.ethereum.vm.BlockchainConfigForEvm +import io.iohk.ethereum.vm.EvmConfig class DeleteTouchedAccountsSpec extends AnyFlatSpec with Matchers { val blockchainConfig = Config.blockchains.blockchainConfig - val syncConfig = SyncConfig(Config.config) + val syncConfig: SyncConfig = SyncConfig(Config.config) it should "delete no accounts when there are no touched accounts" in new TestSetup { val newWorld = InMemoryWorldStateProxy.persistState(consensus.blockPreparator.deleteEmptyTouchedAccounts(worldStatePostEIP161)) - accountAddresses.foreach { a => assert(newWorld.getAccount(a).isDefined) } + accountAddresses.foreach(a => assert(newWorld.getAccount(a).isDefined)) newWorld.stateRootHash shouldBe worldStatePostEIP161.stateRootHash } @@ -30,7 +35,7 @@ class DeleteTouchedAccountsSpec extends AnyFlatSpec with Matchers { val newWorld = InMemoryWorldStateProxy.persistState(consensus.blockPreparator.deleteEmptyTouchedAccounts(worldAfterTransfer)) - accountAddresses.foreach { a => assert(newWorld.getAccount(a).isDefined) } + accountAddresses.foreach(a => assert(newWorld.getAccount(a).isDefined)) } it should "delete touched empty account" in new TestSetup { @@ -41,7 +46,7 @@ class DeleteTouchedAccountsSpec extends AnyFlatSpec with Matchers { val newWorld = InMemoryWorldStateProxy.persistState(consensus.blockPreparator.deleteEmptyTouchedAccounts(worldAfterTransfer)) - (accountAddresses - validEmptyAccountAddress).foreach { a => assert(newWorld.getAccount(a).isDefined) } + (accountAddresses - validEmptyAccountAddress).foreach(a => assert(newWorld.getAccount(a).isDefined)) newWorld.getAccount(validEmptyAccountAddress) shouldBe None newWorld.touchedAccounts.size shouldEqual 0 } @@ -54,7 +59,7 @@ class DeleteTouchedAccountsSpec extends AnyFlatSpec with Matchers { val newWorld = InMemoryWorldStateProxy.persistState(consensus.blockPreparator.deleteEmptyTouchedAccounts(worldAfterTransfer)) - (accountAddresses - validEmptyAccountAddress).foreach { a => assert(newWorld.getAccount(a).isDefined) } + (accountAddresses - validEmptyAccountAddress).foreach(a => assert(newWorld.getAccount(a).isDefined)) newWorld.getAccount(validEmptyAccountAddress) shouldBe None newWorld.touchedAccounts.size shouldEqual 0 } @@ -74,7 +79,7 @@ class DeleteTouchedAccountsSpec extends AnyFlatSpec with Matchers { val newWorld = InMemoryWorldStateProxy.persistState(consensus.blockPreparator.deleteEmptyTouchedAccounts(worldAfterTransfer)) - accountAddresses.foreach { a => assert(newWorld.getAccount(a).isDefined) } + accountAddresses.foreach(a => assert(newWorld.getAccount(a).isDefined)) } it should "delete multiple touched empty accounts" in new TestSetup { @@ -113,7 +118,7 @@ class DeleteTouchedAccountsSpec extends AnyFlatSpec with Matchers { consensus.blockPreparator.deleteEmptyTouchedAccounts(worldAfterInitAndTransfer) ) - (accountAddresses + validCreatedAccountAddress).foreach { a => assert(newWorld.getAccount(a).isDefined) } + (accountAddresses + validCreatedAccountAddress).foreach(a => assert(newWorld.getAccount(a).isDefined)) newWorld.touchedAccounts.size shouldEqual 0 } @@ -124,21 +129,21 @@ class DeleteTouchedAccountsSpec extends AnyFlatSpec with Matchers { //- cake overrides - val conf = BlockchainConfigForEvm(blockchainConfig) - val postEip161Config = EvmConfig.PostEIP161ConfigBuilder(conf) - val postEip160Config = EvmConfig.PostEIP160ConfigBuilder(conf) + val conf: BlockchainConfigForEvm = BlockchainConfigForEvm(blockchainConfig) + val postEip161Config: EvmConfig = EvmConfig.PostEIP161ConfigBuilder(conf) + val postEip160Config: EvmConfig = EvmConfig.PostEIP160ConfigBuilder(conf) - val validAccountAddress = Address(0xababab) + val validAccountAddress: Address = Address(0xababab) val validAccountBalance = 10 - val validAccountAddress2 = Address(0xcdcdcd) - val validAccountAddress3 = Address(0xefefef) - val validEmptyAccountAddress = Address(0xaaaaaa) - val validEmptyAccountAddress1 = Address(0xbbbbbb) + val validAccountAddress2: Address = Address(0xcdcdcd) + val validAccountAddress3: Address = Address(0xefefef) + val validEmptyAccountAddress: Address = Address(0xaaaaaa) + val validEmptyAccountAddress1: Address = Address(0xbbbbbb) - val validCreatedAccountAddress = Address(0xcccccc) + val validCreatedAccountAddress: Address = Address(0xcccccc) - val accountAddresses = Set( + val accountAddresses: Set[Address] = Set( validAccountAddress, validAccountAddress2, validAccountAddress3, @@ -146,7 +151,7 @@ class DeleteTouchedAccountsSpec extends AnyFlatSpec with Matchers { validEmptyAccountAddress1 ) - val worldStateWithoutPersist = InMemoryWorldStateProxy( + val worldStateWithoutPersist: InMemoryWorldStateProxy = InMemoryWorldStateProxy( storagesInstance.storages.evmCodeStorage, blockchain.getBackingMptStorage(-1), (number: BigInt) => blockchainReader.getBlockHeaderByNumber(number).map(_.hash), @@ -161,7 +166,7 @@ class DeleteTouchedAccountsSpec extends AnyFlatSpec with Matchers { .saveAccount(validEmptyAccountAddress, Account.empty()) .saveAccount(validEmptyAccountAddress1, Account.empty()) - val worldStateWithoutPersistPreEIP161 = InMemoryWorldStateProxy( + val worldStateWithoutPersistPreEIP161: InMemoryWorldStateProxy = InMemoryWorldStateProxy( storagesInstance.storages.evmCodeStorage, blockchain.getBackingMptStorage(-1), (number: BigInt) => blockchainReader.getBlockHeaderByNumber(number).map(_.hash), @@ -179,8 +184,9 @@ class DeleteTouchedAccountsSpec extends AnyFlatSpec with Matchers { val transferBalance = 5 val zeroTransferBalance = 0 - val worldStatePostEIP161 = InMemoryWorldStateProxy.persistState(worldStateWithoutPersist) - val worldStatePreEIP161 = InMemoryWorldStateProxy.persistState(worldStateWithoutPersistPreEIP161) + val worldStatePostEIP161: InMemoryWorldStateProxy = InMemoryWorldStateProxy.persistState(worldStateWithoutPersist) + val worldStatePreEIP161: InMemoryWorldStateProxy = + InMemoryWorldStateProxy.persistState(worldStateWithoutPersistPreEIP161) } } diff --git a/src/test/scala/io/iohk/ethereum/ledger/InMemorySimpleMapProxySpec.scala b/src/test/scala/io/iohk/ethereum/ledger/InMemorySimpleMapProxySpec.scala index 10dea8b508..c321fa97f1 100644 --- a/src/test/scala/io/iohk/ethereum/ledger/InMemorySimpleMapProxySpec.scala +++ b/src/test/scala/io/iohk/ethereum/ledger/InMemorySimpleMapProxySpec.scala @@ -2,12 +2,14 @@ package io.iohk.ethereum.ledger import java.nio.ByteBuffer +import org.scalatest.flatspec.AnyFlatSpec +import org.scalatest.matchers.should.Matchers + import io.iohk.ethereum.common.SimpleMap import io.iohk.ethereum.db.dataSource.EphemDataSource import io.iohk.ethereum.db.storage.StateStorage -import io.iohk.ethereum.mpt.{ByteArraySerializable, MerklePatriciaTrie} -import org.scalatest.flatspec.AnyFlatSpec -import org.scalatest.matchers.should.Matchers +import io.iohk.ethereum.mpt.ByteArraySerializable +import io.iohk.ethereum.mpt.MerklePatriciaTrie class InMemorySimpleMapProxySpec extends AnyFlatSpec with Matchers { @@ -87,7 +89,7 @@ class InMemorySimpleMapProxySpec extends AnyFlatSpec with Matchers { def assertNotContainsKey[I <: SimpleMap[Int, Int, I]](trie: I, key: Int): Unit = assert(trie.get(key).isEmpty) trait TestSetup { - implicit val intByteArraySerializable = new ByteArraySerializable[Int] { + implicit val intByteArraySerializable: ByteArraySerializable[Int] = new ByteArraySerializable[Int] { override def toBytes(input: Int): Array[Byte] = { val b: ByteBuffer = ByteBuffer.allocate(4) b.putInt(input) @@ -97,7 +99,7 @@ class InMemorySimpleMapProxySpec extends AnyFlatSpec with Matchers { override def fromBytes(bytes: Array[Byte]): Int = ByteBuffer.wrap(bytes).getInt() } - val stateStorage = StateStorage.createTestStateStorage(EphemDataSource())._1 + val stateStorage: StateStorage = StateStorage.createTestStateStorage(EphemDataSource())._1 val mpt: MerklePatriciaTrie[Int, Int] = MerklePatriciaTrie[Int, Int](stateStorage.getReadOnlyStorage) } diff --git a/src/test/scala/io/iohk/ethereum/ledger/InMemoryWorldStateProxySpec.scala b/src/test/scala/io/iohk/ethereum/ledger/InMemoryWorldStateProxySpec.scala index 02bfec7f2e..0f54233369 100644 --- a/src/test/scala/io/iohk/ethereum/ledger/InMemoryWorldStateProxySpec.scala +++ b/src/test/scala/io/iohk/ethereum/ledger/InMemoryWorldStateProxySpec.scala @@ -1,15 +1,20 @@ package io.iohk.ethereum.ledger import akka.util.ByteString -import io.iohk.ethereum.blockchain.sync.EphemBlockchainTestSetup -import io.iohk.ethereum.domain.{Account, Address, BlockchainImpl, BlockchainReader, UInt256} -import io.iohk.ethereum.mpt.MerklePatriciaTrie -import io.iohk.ethereum.mpt.MerklePatriciaTrie.MPTException -import io.iohk.ethereum.vm.{EvmConfig, Generators} + import org.bouncycastle.util.encoders.Hex import org.scalatest.flatspec.AnyFlatSpec import org.scalatest.matchers.should.Matchers +import io.iohk.ethereum.blockchain.sync.EphemBlockchainTestSetup +import io.iohk.ethereum.domain.Account +import io.iohk.ethereum.domain.Address +import io.iohk.ethereum.domain.UInt256 +import io.iohk.ethereum.mpt.MerklePatriciaTrie +import io.iohk.ethereum.mpt.MerklePatriciaTrie.MPTException +import io.iohk.ethereum.vm.EvmConfig +import io.iohk.ethereum.vm.Generators + class InMemoryWorldStateProxySpec extends AnyFlatSpec with Matchers { "InMemoryWorldStateProxy" should "allow to create and retrieve an account" in new TestSetup { @@ -73,7 +78,9 @@ class InMemoryWorldStateProxySpec extends AnyFlatSpec with Matchers { .store(UInt256.One, UInt256.One) ) ) - persistedWorldStateWithAnAccount.stateRootHash equals persistedWithContractStorageValue.stateRootHash shouldBe false + persistedWorldStateWithAnAccount.stateRootHash.equals( + persistedWithContractStorageValue.stateRootHash + ) shouldBe false val persistedWithZero = InMemoryWorldStateProxy.persistState( persistedWorldStateWithAnAccount.saveStorage( @@ -236,7 +243,7 @@ class InMemoryWorldStateProxySpec extends AnyFlatSpec with Matchers { val startValue = 100 val account = Account(UInt256.One, startValue) - val code = ByteString(Hex.decode("deadbeefdeadbeefdeadbeef")) + ByteString(Hex.decode("deadbeefdeadbeefdeadbeef")) val initialWorld = InMemoryWorldStateProxy.persistState(worldState.saveAccount(address1, account)) @@ -330,9 +337,9 @@ class InMemoryWorldStateProxySpec extends AnyFlatSpec with Matchers { } trait TestSetup extends EphemBlockchainTestSetup { - val postEip161Config = EvmConfig.PostEIP161ConfigBuilder(io.iohk.ethereum.vm.Fixtures.blockchainConfig) + val postEip161Config: EvmConfig = EvmConfig.PostEIP161ConfigBuilder(io.iohk.ethereum.vm.Fixtures.blockchainConfig) - val worldState = InMemoryWorldStateProxy( + val worldState: InMemoryWorldStateProxy = InMemoryWorldStateProxy( storagesInstance.storages.evmCodeStorage, blockchain.getBackingMptStorage(-1), (number: BigInt) => blockchainReader.getBlockHeaderByNumber(number).map(_.hash), @@ -342,7 +349,7 @@ class InMemoryWorldStateProxySpec extends AnyFlatSpec with Matchers { ethCompatibleStorage = true ) - val postEIP161WorldState = InMemoryWorldStateProxy( + val postEIP161WorldState: InMemoryWorldStateProxy = InMemoryWorldStateProxy( storagesInstance.storages.evmCodeStorage, blockchain.getBackingMptStorage(-1), (number: BigInt) => blockchainReader.getBlockHeaderByNumber(number).map(_.hash), @@ -352,8 +359,8 @@ class InMemoryWorldStateProxySpec extends AnyFlatSpec with Matchers { ethCompatibleStorage = false ) - val address1 = Address(0x123456) - val address2 = Address(0xabcdef) - val address3 = Address(0xfedcba) + val address1: Address = Address(0x123456) + val address2: Address = Address(0xabcdef) + val address3: Address = Address(0xfedcba) } } diff --git a/src/test/scala/io/iohk/ethereum/ledger/LedgerTestSetup.scala b/src/test/scala/io/iohk/ethereum/ledger/LedgerTestSetup.scala index 9da80267c8..2cb045cd4c 100644 --- a/src/test/scala/io/iohk/ethereum/ledger/LedgerTestSetup.scala +++ b/src/test/scala/io/iohk/ethereum/ledger/LedgerTestSetup.scala @@ -2,29 +2,48 @@ package io.iohk.ethereum.ledger import akka.util.ByteString import akka.util.ByteString.{empty => bEmpty} + import cats.data.NonEmptyList + +import monix.execution.Scheduler + +import org.bouncycastle.crypto.AsymmetricCipherKeyPair +import org.bouncycastle.crypto.params.ECPublicKeyParameters +import org.bouncycastle.util.encoders.Hex +import org.scalamock.handlers.CallHandler0 +import org.scalamock.handlers.CallHandler1 +import org.scalamock.handlers.CallHandler4 +import org.scalamock.scalatest.MockFactory + +import io.iohk.ethereum.Fixtures +import io.iohk.ethereum.Mocks +import io.iohk.ethereum.ObjectGenerators import io.iohk.ethereum.blockchain.sync.EphemBlockchainTestSetup +import io.iohk.ethereum.consensus.GetBlockHeaderByHash +import io.iohk.ethereum.consensus.GetNBlocksBack +import io.iohk.ethereum.consensus.TestConsensus import io.iohk.ethereum.consensus.blocks.CheckpointBlockGenerator -import io.iohk.ethereum.consensus.pow.validators.{OmmersValidator, StdOmmersValidator} +import io.iohk.ethereum.consensus.pow.validators.OmmersValidator +import io.iohk.ethereum.consensus.pow.validators.StdOmmersValidator +import io.iohk.ethereum.consensus.validators.BlockHeaderError import io.iohk.ethereum.consensus.validators.BlockHeaderError.HeaderParentNotFoundError -import io.iohk.ethereum.consensus.validators.{BlockHeaderError, BlockHeaderValid, BlockHeaderValidator, Validators} -import io.iohk.ethereum.consensus.{GetBlockHeaderByHash, GetNBlocksBack, TestConsensus} -import io.iohk.ethereum.crypto.{generateKeyPair, kec256} +import io.iohk.ethereum.consensus.validators.BlockHeaderValid +import io.iohk.ethereum.consensus.validators.BlockHeaderValidator +import io.iohk.ethereum.crypto.generateKeyPair +import io.iohk.ethereum.crypto.kec256 import io.iohk.ethereum.domain._ import io.iohk.ethereum.ledger.BlockExecutionError.ValidationAfterExecError -import io.iohk.ethereum.ledger.{PC, PR, VMImpl} +import io.iohk.ethereum.ledger.PC +import io.iohk.ethereum.ledger.PR +import io.iohk.ethereum.ledger.VMImpl import io.iohk.ethereum.mpt.MerklePatriciaTrie import io.iohk.ethereum.security.SecureRandomBuilder +import io.iohk.ethereum.utils.BlockchainConfig +import io.iohk.ethereum.utils.Config import io.iohk.ethereum.utils.Config.SyncConfig -import io.iohk.ethereum.utils.{BlockchainConfig, Config, DaoForkConfig} -import io.iohk.ethereum.vm.{ProgramError, ProgramResult} -import io.iohk.ethereum.{Fixtures, Mocks, ObjectGenerators} -import monix.execution.Scheduler -import org.bouncycastle.crypto.AsymmetricCipherKeyPair -import org.bouncycastle.crypto.params.ECPublicKeyParameters -import org.bouncycastle.util.encoders.Hex -import org.scalamock.handlers.{CallHandler0, CallHandler1, CallHandler4} -import org.scalamock.scalatest.MockFactory +import io.iohk.ethereum.utils.DaoForkConfig +import io.iohk.ethereum.vm.ProgramError +import io.iohk.ethereum.vm.ProgramResult // scalastyle:off magic.number trait TestSetup extends SecureRandomBuilder with EphemBlockchainTestSetup { @@ -36,15 +55,15 @@ trait TestSetup extends SecureRandomBuilder with EphemBlockchainTestSetup { val originKeyPair: AsymmetricCipherKeyPair = generateKeyPair(secureRandom) val receiverKeyPair: AsymmetricCipherKeyPair = generateKeyPair(secureRandom) //byte 0 of encoded ECC point indicates that it is uncompressed point, it is part of bouncycastle encoding - val originAddress = Address( + val originAddress: Address = Address( kec256(originKeyPair.getPublic.asInstanceOf[ECPublicKeyParameters].getQ.getEncoded(false).tail) ) - val receiverAddress = Address( + val receiverAddress: Address = Address( kec256(receiverKeyPair.getPublic.asInstanceOf[ECPublicKeyParameters].getQ.getEncoded(false).tail) ) - val minerAddress = Address(666) + val minerAddress: Address = Address(666) - val defaultBlockHeader = Fixtures.Blocks.ValidBlock.header.copy( + val defaultBlockHeader: BlockHeader = Fixtures.Blocks.ValidBlock.header.copy( difficulty = 1000000, number = blockchainConfig.forkBlockNumbers.homesteadBlockNumber + 1, gasLimit = 1000000, @@ -52,7 +71,7 @@ trait TestSetup extends SecureRandomBuilder with EphemBlockchainTestSetup { unixTimestamp = 1486752441 ) - val defaultTx = Transaction( + val defaultTx: Transaction = Transaction( nonce = 42, gasPrice = 1, gasLimit = 90000, @@ -61,21 +80,22 @@ trait TestSetup extends SecureRandomBuilder with EphemBlockchainTestSetup { payload = ByteString.empty ) - val defaultLog = TxLogEntry( + val defaultLog: TxLogEntry = TxLogEntry( loggerAddress = originAddress, logTopics = Seq(ByteString(Hex.decode("962cd36cf694aa154c5d3a551f19c98f356d906e96828eeb616e16fae6415738"))), data = ByteString(Hex.decode("1" * 128)) ) - val defaultChainWeight = ChainWeight.zero.increase(defaultBlockHeader) + val defaultChainWeight: ChainWeight = ChainWeight.zero.increase(defaultBlockHeader) val initialOriginBalance: UInt256 = 100000000 val initialMinerBalance: UInt256 = 2000000 val initialOriginNonce: BigInt = defaultTx.nonce - val defaultAddressesToDelete = Set(Address(Hex.decode("01")), Address(Hex.decode("02")), Address(Hex.decode("03"))) - val defaultLogs = Seq(defaultLog.copy(loggerAddress = defaultAddressesToDelete.head)) + val defaultAddressesToDelete: Set[Address] = + Set(Address(Hex.decode("01")), Address(Hex.decode("02")), Address(Hex.decode("03"))) + val defaultLogs: Seq[TxLogEntry] = Seq(defaultLog.copy(loggerAddress = defaultAddressesToDelete.head)) val defaultGasPrice: UInt256 = 10 val defaultGasLimit: UInt256 = 1000000 val defaultValue: BigInt = 1000 @@ -272,7 +292,7 @@ trait TestSetupWithVmAndValidators extends EphemBlockchainTestSetup { def randomHash(): ByteString = ObjectGenerators.byteStringOfLengthNGen(32).sample.get - val defaultHeader = Fixtures.Blocks.ValidBlock.header.copy( + val defaultHeader: BlockHeader = Fixtures.Blocks.ValidBlock.header.copy( difficulty = 100, number = 1, gasLimit = 1000000, @@ -316,15 +336,15 @@ trait TestSetupWithVmAndValidators extends EphemBlockchainTestSetup { def getChainHeadersNel(from: BigInt, to: BigInt, parent: ByteString = randomHash()): NonEmptyList[BlockHeader] = NonEmptyList.fromListUnsafe(getChainHeaders(from, to, parent)) - val receipts = Seq(Receipt.withHashOutcome(randomHash(), 50000, randomHash(), Nil)) + val receipts: Seq[Receipt] = Seq(Receipt.withHashOutcome(randomHash(), 50000, randomHash(), Nil)) - val currentWeight = ChainWeight.totalDifficultyOnly(99999) + val currentWeight: ChainWeight = ChainWeight.totalDifficultyOnly(99999) - val bestNum = BigInt(5) + val bestNum: BigInt = BigInt(5) val bestBlock: Block = getBlock(bestNum, currentWeight.totalDifficulty / 2) - val execError = ValidationAfterExecError("error") + val execError: ValidationAfterExecError = ValidationAfterExecError("error") object FailHeaderValidation extends Mocks.MockValidatorsAlwaysSucceed { override val blockHeaderValidator: BlockHeaderValidator = new BlockHeaderValidator { @@ -347,9 +367,9 @@ trait TestSetupWithVmAndValidators extends EphemBlockchainTestSetup { ): Either[BlockExecutionError, BlockExecutionSuccess] = Right(BlockExecutionSuccess) } - lazy val failBlockImport = mkBlockImport(validators = FailHeaderValidation) + lazy val failBlockImport: BlockImport = mkBlockImport(validators = FailHeaderValidation) - lazy val blockImportNotFailingAfterExecValidation = { + lazy val blockImportNotFailingAfterExecValidation: BlockImport = { val consensuz = consensus.withValidators(NotFailAfterExecValidation).withVM(new Mocks.MockVM()) val blockValidation = new BlockValidation(consensuz, blockchainReader, blockQueue) new BlockImport( @@ -422,12 +442,11 @@ trait MockBlockchain extends MockFactory { self: TestSetupWithVmAndValidators => receipts: Seq[Receipt], weight: ChainWeight, saveAsBestBlock: Boolean - ): CallHandler4[Block, Seq[Receipt], ChainWeight, Boolean, Unit] = { + ): CallHandler4[Block, Seq[Receipt], ChainWeight, Boolean, Unit] = (blockchain .save(_: Block, _: Seq[Receipt], _: ChainWeight, _: Boolean)) .expects(block, receipts, weight, saveAsBestBlock) .once() - } def setHeaderInChain(hash: ByteString, result: Boolean = true): CallHandler1[ByteString, Boolean] = (blockchain.isInChain _).expects(hash).returning(result) @@ -440,7 +459,7 @@ trait MockBlockchain extends MockFactory { self: TestSetupWithVmAndValidators => } trait EphemBlockchain extends TestSetupWithVmAndValidators with MockFactory { - override lazy val blockQueue = BlockQueue(blockchain, SyncConfig(Config.config)) + override lazy val blockQueue: BlockQueue = BlockQueue(blockchain, SyncConfig(Config.config)) lazy val blockImportWithMockedBlockExecution: BlockImport = mkBlockImport(blockExecutionOpt = Some(mock[BlockExecution])) diff --git a/src/test/scala/io/iohk/ethereum/ledger/StxLedgerSpec.scala b/src/test/scala/io/iohk/ethereum/ledger/StxLedgerSpec.scala index 4b25c88831..88f39e6985 100644 --- a/src/test/scala/io/iohk/ethereum/ledger/StxLedgerSpec.scala +++ b/src/test/scala/io/iohk/ethereum/ledger/StxLedgerSpec.scala @@ -1,24 +1,25 @@ package io.iohk.ethereum.ledger import akka.util.ByteString + +import org.bouncycastle.util.encoders.Hex +import org.scalatest.flatspec.AnyFlatSpec +import org.scalatest.matchers.should.Matchers + import io.iohk.ethereum.blockchain.sync.EphemBlockchainTestSetup import io.iohk.ethereum.crypto.ECDSASignature import io.iohk.ethereum.domain.Block.BlockDec import io.iohk.ethereum.domain._ +import io.iohk.ethereum.ledger.TxResult import io.iohk.ethereum.mpt.MerklePatriciaTrie import io.iohk.ethereum.mpt.MerklePatriciaTrie.MPTException import io.iohk.ethereum.utils._ -import org.bouncycastle.util.encoders.Hex -import io.iohk.ethereum.ledger.TxResult -import org.scalatest.flatspec.AnyFlatSpec -import org.scalatest.matchers.should.Matchers class StxLedgerSpec extends AnyFlatSpec with Matchers with Logger { "StxLedger" should "correctly estimate minimum gasLimit to run transaction which throws" in new ScenarioSetup { - /** - * Transaction requires gasLimit equal to 121825, but actual gas used due to refund is equal 42907. + /** Transaction requires gasLimit equal to 121825, but actual gas used due to refund is equal 42907. * Our simulateTransaction properly estimates gas usage to 42907, but requires at least 121825 gas to * make that simulation * @@ -178,10 +179,10 @@ trait ScenarioSetup extends EphemBlockchainTestSetup { ethCompatibleStorage = true ) - val existingAddress = Address(10) - val existingAccount = Account(nonce = UInt256.Zero, balance = UInt256(10)) + val existingAddress: Address = Address(10) + val existingAccount: Account = Account(nonce = UInt256.Zero, balance = UInt256(10)) - val existingEmptyAccountAddres = Address(20) + val existingEmptyAccountAddres: Address = Address(20) val existingEmptyAccount: Account = Account.empty() /** Failing code which mess up with gas estimation @@ -198,20 +199,20 @@ trait ScenarioSetup extends EphemBlockchainTestSetup { * * @note Example from https://github.com/ethereum/go-ethereum/pull/3587 */ - val failingCode = ByteString( + val failingCode: ByteString = ByteString( Hex.decode( "60606040526000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806323fcf32a146100495780634f28bf0e146100a0575b610000565b346100005761009e600480803590602001908201803590602001908080601f01602080910402602001604051908101604052809392919081815260200183838082843782019150505050505091905050610136565b005b34610000576100ad6101eb565b60405180806020018281038252838181518152602001915080519060200190808383600083146100fc575b8051825260208311156100fc576020820191506020810190506020830392506100d8565b505050905090810190601f1680156101285780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b620186a05a101561014657610000565b8060009080519060200190828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061019257805160ff19168380011785556101c0565b828001600101855582156101c0579182015b828111156101bf5782518255916020019190600101906101a4565b5b5090506101e591905b808211156101e15760008160009055506001016101c9565b5090565b50505b50565b60008054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156102815780601f1061025657610100808354040283529160200191610281565b820191906000526020600020905b81548152906001019060200180831161026457829003601f168201915b5050505050815600a165627a7a7230582075b8ec2ccf191572d3bfdd93dee7d107668265f37d7918e48132b1ba16df17320029" ) ) - val sendData = ByteString( + val sendData: ByteString = ByteString( Hex.decode( "23fcf32a0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000564756e6e6f000000000000000000000000000000000000000000000000000000" ) ) - val fromBalance = UInt256(10) - val fromAddress = Address(0) + val fromBalance: UInt256 = UInt256(10) + val fromAddress: Address = Address(0) val startAccount: Account = Account.empty().increaseBalance(fromBalance) val worldWithAccount: InMemoryWorldStateProxy = InMemoryWorldStateProxy.persistState( @@ -234,7 +235,7 @@ trait ScenarioSetup extends EphemBlockchainTestSetup { block.copy(header = block.header.copy(stateRoot = worldWithAccount.stateRootHash, gasLimit = 1000000)) val genesisHash: ByteString = genesisBlock.header.hash val genesisHeader: BlockHeader = genesisBlock.header - val genesisWeight = ChainWeight.zero.increase(genesisHeader) + val genesisWeight: ChainWeight = ChainWeight.zero.increase(genesisHeader) val lastBlockGasLimit: BigInt = genesisBlock.header.gasLimit blockchain diff --git a/src/test/scala/io/iohk/ethereum/mpt/HexPrefixSuite.scala b/src/test/scala/io/iohk/ethereum/mpt/HexPrefixSuite.scala index 880a4445c7..dd74b7a2e0 100644 --- a/src/test/scala/io/iohk/ethereum/mpt/HexPrefixSuite.scala +++ b/src/test/scala/io/iohk/ethereum/mpt/HexPrefixSuite.scala @@ -1,8 +1,9 @@ package io.iohk.ethereum.mpt -import io.iohk.ethereum.ObjectGenerators -import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks import org.scalatest.funsuite.AnyFunSuite +import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks + +import io.iohk.ethereum.ObjectGenerators class HexPrefixSuite extends AnyFunSuite with ScalaCheckPropertyChecks with ObjectGenerators { @@ -13,7 +14,7 @@ class HexPrefixSuite extends AnyFunSuite with ScalaCheckPropertyChecks with Obje val packed = HexPrefix.encode(nibbles, t) val (unpacked, b) = HexPrefix.decode(packed) val bytesObtained = HexPrefix.nibblesToBytes(unpacked) - assert(bytes sameElements bytesObtained) + assert(bytes.sameElements(bytesObtained)) assert(b == t) } } @@ -21,32 +22,32 @@ class HexPrefixSuite extends AnyFunSuite with ScalaCheckPropertyChecks with Obje test("testCompactEncodeOddCompact") { val test: Array[Byte] = Array[Byte](1, 2, 3, 4, 5) val expectedData: Array[Byte] = Array[Byte](0x11, 0x23, 0x45) - assert(expectedData sameElements HexPrefix.encode(test, isLeaf = false)) + assert(expectedData.sameElements(HexPrefix.encode(test, isLeaf = false))) } test("testCompactEncodeEvenCompact") { val test: Array[Byte] = Array[Byte](0, 1, 2, 3, 4, 5) val expectedData: Array[Byte] = Array[Byte](0x00, 0x01, 0x23, 0x45) - assert(expectedData sameElements HexPrefix.encode(test, isLeaf = false)) + assert(expectedData.sameElements(HexPrefix.encode(test, isLeaf = false))) } test("testCompactEncodeEvenTerminated") { val test: Array[Byte] = Array[Byte](0, 15, 1, 12, 11, 8) val expectedData: Array[Byte] = Array[Byte](0x20, 0x0f, 0x1c, 0xb8.toByte) - assert(expectedData sameElements HexPrefix.encode(test, isLeaf = true)) + assert(expectedData.sameElements(HexPrefix.encode(test, isLeaf = true))) } test("testCompactEncodeOddTerminated") { val test: Array[Byte] = Array[Byte](15, 1, 12, 11, 8) val expectedData: Array[Byte] = Array[Byte](0x3f, 0x1c, 0xb8.toByte) - assert(expectedData sameElements HexPrefix.encode(test, isLeaf = true)) + assert(expectedData.sameElements(HexPrefix.encode(test, isLeaf = true))) } test("testCompactDecodeOddCompact") { val test: Array[Byte] = Array[Byte](0x11, 0x23, 0x45) val expected: Array[Byte] = Array[Byte](1, 2, 3, 4, 5) val (obtained, t) = HexPrefix.decode(test) - assert(expected sameElements obtained) + assert(expected.sameElements(obtained)) assert(!t) } @@ -54,7 +55,7 @@ class HexPrefixSuite extends AnyFunSuite with ScalaCheckPropertyChecks with Obje val test: Array[Byte] = Array[Byte](0x00, 0x01, 0x23, 0x45) val expected: Array[Byte] = Array[Byte](0, 1, 2, 3, 4, 5) val (obtained, t) = HexPrefix.decode(test) - assert(expected sameElements obtained) + assert(expected.sameElements(obtained)) assert(!t) } @@ -62,7 +63,7 @@ class HexPrefixSuite extends AnyFunSuite with ScalaCheckPropertyChecks with Obje val test: Array[Byte] = Array[Byte](0x20, 0x0f, 0x1c, 0xb8.toByte) val expected: Array[Byte] = Array[Byte](0, 15, 1, 12, 11, 8) val (obtained, t) = HexPrefix.decode(test) - assert(expected sameElements obtained) + assert(expected.sameElements(obtained)) assert(t) } @@ -70,25 +71,25 @@ class HexPrefixSuite extends AnyFunSuite with ScalaCheckPropertyChecks with Obje val test: Array[Byte] = Array[Byte](0x3f, 0x1c, 0xb8.toByte) val expected: Array[Byte] = Array[Byte](15, 1, 12, 11, 8) val (obtained, t) = HexPrefix.decode(test) - assert(expected sameElements obtained) + assert(expected.sameElements(obtained)) assert(t) } test("testCompactHexEncode_1") { val test: Array[Byte] = "stallion".getBytes val result: Array[Byte] = Array[Byte](7, 3, 7, 4, 6, 1, 6, 12, 6, 12, 6, 9, 6, 15, 6, 14) - assert(result sameElements HexPrefix.bytesToNibbles(bytes = test)) + assert(result.sameElements(HexPrefix.bytesToNibbles(bytes = test))) } test("testCompactHexEncode_2") { val test: Array[Byte] = "verb".getBytes val result: Array[Byte] = Array[Byte](7, 6, 6, 5, 7, 2, 6, 2) - assert(result sameElements HexPrefix.bytesToNibbles(bytes = test)) + assert(result.sameElements(HexPrefix.bytesToNibbles(bytes = test))) } test("testCompactHexEncode_3") { val test: Array[Byte] = "puppy".getBytes val result: Array[Byte] = Array[Byte](7, 0, 7, 5, 7, 0, 7, 0, 7, 9) - assert(result sameElements HexPrefix.bytesToNibbles(bytes = test)) + assert(result.sameElements(HexPrefix.bytesToNibbles(bytes = test))) } } diff --git a/src/test/scala/io/iohk/ethereum/mpt/MerklePatriciaTrieSuite.scala b/src/test/scala/io/iohk/ethereum/mpt/MerklePatriciaTrieSuite.scala index d4d41063b9..b49353f46a 100644 --- a/src/test/scala/io/iohk/ethereum/mpt/MerklePatriciaTrieSuite.scala +++ b/src/test/scala/io/iohk/ethereum/mpt/MerklePatriciaTrieSuite.scala @@ -1,29 +1,36 @@ package io.iohk.ethereum.mpt import java.nio.ByteBuffer + import akka.util.ByteString + +import scala.collection.immutable.ArraySeq +import scala.util.Random +import scala.util.Try + +import org.bouncycastle.util.encoders.Hex +import org.scalacheck.Arbitrary +import org.scalacheck.Gen +import org.scalatest.funsuite.AnyFunSuite +import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks + import io.iohk.ethereum.ObjectGenerators -import io.iohk.ethereum.db.dataSource.{DataSourceUpdate, EphemDataSource} +import io.iohk.ethereum.db.dataSource.DataSourceUpdate +import io.iohk.ethereum.db.dataSource.EphemDataSource import io.iohk.ethereum.db.storage._ import io.iohk.ethereum.db.storage.pruning.BasicPruning -import io.iohk.ethereum.mpt.MerklePatriciaTrie.{MPTException, defaultByteArraySerializable} +import io.iohk.ethereum.mpt.MerklePatriciaTrie.MPTException +import io.iohk.ethereum.mpt.MerklePatriciaTrie.defaultByteArraySerializable import io.iohk.ethereum.proof.MptProofVerifier import io.iohk.ethereum.proof.ProofVerifyResult.ValidProof -import org.scalacheck.{Arbitrary, Gen} -import org.bouncycastle.util.encoders.Hex -import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks - -import scala.util.{Random, Try} -import org.scalatest.funsuite.AnyFunSuite - -import scala.collection.immutable.ArraySeq class MerklePatriciaTrieSuite extends AnyFunSuite with ScalaCheckPropertyChecks with ObjectGenerators { val dataSource: EphemDataSource = EphemDataSource() val (stateStorage, emptyNodeStorage, _) = StateStorage.createTestStateStorage(dataSource) - val emptyEphemNodeStorage = stateStorage.getBackingStorage(0) - val emptyMpt = MerklePatriciaTrie[Array[Byte], Array[Byte]](emptyEphemNodeStorage) + val emptyEphemNodeStorage: MptStorage = stateStorage.getBackingStorage(0) + val emptyMpt: MerklePatriciaTrie[Array[Byte], Array[Byte]] = + MerklePatriciaTrie[Array[Byte], Array[Byte]](emptyEphemNodeStorage) implicit val intByteArraySerializable: ByteArraySerializable[Int] = new ByteArraySerializable[Int] { override def toBytes(input: Int): Array[Byte] = { @@ -52,7 +59,7 @@ class MerklePatriciaTrieSuite extends AnyFunSuite with ScalaCheckPropertyChecks val collapsed = MptTraversals.collapseTrie(unfoldedTrie) // then rootHash - assert(collapsed._1.hashNode sameElements trie.getRootHash) + assert(collapsed._1.hashNode.sameElements(trie.getRootHash)) // then can recreate MPT val newTrie = MerklePatriciaTrie[Int, Int](collapsed._1.hashNode, emptyEphemNodeStorage) @@ -69,7 +76,7 @@ class MerklePatriciaTrieSuite extends AnyFunSuite with ScalaCheckPropertyChecks val encoded = MptTraversals.encodeNode(unfoldedTrieNode) val decoded = MptTraversals.decodeNode(encoded) - assert(unfoldedTrieNode.hash sameElements decoded.hash) + assert(unfoldedTrieNode.hash.sameElements(decoded.hash)) } } @@ -87,7 +94,7 @@ class MerklePatriciaTrieSuite extends AnyFunSuite with ScalaCheckPropertyChecks assertNotHave(trieAfterDelete, keyValueToDelete) val trieWithKeyValueLeft = addEveryKeyValuePair(keyValueLeft) - assert(trieAfterDelete.getRootHash sameElements trieWithKeyValueLeft.getRootHash) + assert(trieAfterDelete.getRootHash.sameElements(trieWithKeyValueLeft.getRootHash)) } } @@ -98,7 +105,7 @@ class MerklePatriciaTrieSuite extends AnyFunSuite with ScalaCheckPropertyChecks val keyValueListShuffle = Random.shuffle(keyValueList) val trieShuffled = addEveryKeyValuePair(keyValueListShuffle) - assert(trie.getRootHash sameElements trieShuffled.getRootHash) + assert(trie.getRootHash.sameElements(trieShuffled.getRootHash)) } } @@ -106,7 +113,7 @@ class MerklePatriciaTrieSuite extends AnyFunSuite with ScalaCheckPropertyChecks test("Remove key from an empty tree") { val emptyTrie = MerklePatriciaTrie[Int, Int](emptyEphemNodeStorage) val afterDeleteTrie = emptyTrie.remove(1) - assert(afterDeleteTrie.getRootHash sameElements emptyTrie.getRootHash) + assert(afterDeleteTrie.getRootHash.sameElements(emptyTrie.getRootHash)) } test("Remove a key that does not exist") { @@ -139,10 +146,10 @@ class MerklePatriciaTrieSuite extends AnyFunSuite with ScalaCheckPropertyChecks val trieWithTwoElements = trieWithOneElement.put(key2, val1) val obtained1 = trieWithTwoElements.get(key1) assert(obtained1.isDefined) - assert(obtained1.get sameElements val1) + assert(obtained1.get.sameElements(val1)) val obtained2 = trieWithTwoElements.get(key2) assert(obtained2.isDefined) - assert(obtained2.get sameElements val1) + assert(obtained2.get.sameElements(val1)) } test("Insert two (key, value) pairs with one hex or more in common") { @@ -153,10 +160,10 @@ class MerklePatriciaTrieSuite extends AnyFunSuite with ScalaCheckPropertyChecks val trieWithTwoElements = trieWithOneElement.put(key2, val1) val obtained1 = trieWithTwoElements.get(key1) assert(obtained1.isDefined) - assert(obtained1.get sameElements val1) + assert(obtained1.get.sameElements(val1)) val obtained2 = trieWithTwoElements.get(key2) assert(obtained2.isDefined) - assert(obtained2.get sameElements val1) + assert(obtained2.get.sameElements(val1)) } test("Insert two (key, value) pairs with the same key") { @@ -167,7 +174,7 @@ class MerklePatriciaTrieSuite extends AnyFunSuite with ScalaCheckPropertyChecks val trieAfterSecondInsert = trieWithOneElement.put(key1, val2) val obtained2 = trieAfterSecondInsert.get(key1) assert(obtained2.isDefined) - assert(obtained2.get sameElements val2) + assert(obtained2.get.sameElements(val2)) } test("Insert 3 (key, value) pairs with different first hex") { @@ -182,20 +189,20 @@ class MerklePatriciaTrieSuite extends AnyFunSuite with ScalaCheckPropertyChecks val trieWithThreeElement = trieWithTwoElement.put(key3, val3) val obtained1 = trieWithThreeElement.get(key1) assert(obtained1.isDefined) - assert(obtained1.get sameElements val1) + assert(obtained1.get.sameElements(val1)) val obtained2 = trieWithThreeElement.get(key2) assert(obtained2.isDefined) - assert(obtained2.get sameElements val2) + assert(obtained2.get.sameElements(val2)) val obtained3 = trieWithThreeElement.get(key3) assert(obtained3.isDefined) - assert(obtained3.get sameElements val3) + assert(obtained3.get.sameElements(val3)) } test("Multiple insertions") { val keys = List("123456", "234567", "123467", "12346789", "0123").map(Hex.decode) val vals = List("01", "02", "03", "04", "05").map(Hex.decode) val keysWithVal = keys.zip(vals) - val trie = keysWithVal.foldLeft(emptyMpt) { (recTrie, elem) => recTrie.put(elem._1, elem._2) } + val trie = keysWithVal.foldLeft(emptyMpt)((recTrie, elem) => recTrie.put(elem._1, elem._2)) assertCanGetEveryKeyValues(trie, keysWithVal) } @@ -207,10 +214,10 @@ class MerklePatriciaTrieSuite extends AnyFunSuite with ScalaCheckPropertyChecks ) val vals = List("01", "02", "03", "04", "05", "06", "07", "08", "09", "10").map(Hex.decode) val keysWithVal = keys.zip(vals) - val trie = keysWithVal.foldLeft(emptyMpt) { (recTrie, elem) => recTrie.put(elem._1, elem._2) } + val trie = keysWithVal.foldLeft(emptyMpt)((recTrie, elem) => recTrie.put(elem._1, elem._2)) val (keysWithValToDelete, keysWithValLeft) = keysWithVal.splitAt(3) - val trieAfterDelete = keysWithValToDelete.foldLeft(trie) { (recTrie, elem) => recTrie.remove(elem._1) } + val trieAfterDelete = keysWithValToDelete.foldLeft(trie)((recTrie, elem) => recTrie.remove(elem._1)) assertCanGetEveryKeyValues(trieAfterDelete, keysWithValLeft) assertNotHave(trieAfterDelete, keysWithValToDelete) trieAfterDelete.get(Hex.decode("01")) @@ -224,7 +231,7 @@ class MerklePatriciaTrieSuite extends AnyFunSuite with ScalaCheckPropertyChecks val keys = List(key1, key2, key3) val vals = List(val1, val1, val1) val keysWithVal = keys.zip(vals) - val trie = keysWithVal.foldLeft(emptyMpt) { (recTrie, elem) => recTrie.put(elem._1, elem._2) } + val trie = keysWithVal.foldLeft(emptyMpt)((recTrie, elem) => recTrie.put(elem._1, elem._2)) assertCanGetEveryKeyValues(trie, keysWithVal) } @@ -240,7 +247,7 @@ class MerklePatriciaTrieSuite extends AnyFunSuite with ScalaCheckPropertyChecks assert(obtained1.isEmpty) val obtained2 = trieAfterDelete.get(key2) assert(obtained2.isDefined) - assert(obtained2.get sameElements val2) + assert(obtained2.get.sameElements(val2)) } test("Insert 2 (key-value) pairs with more than one hex in common and then delete one of them") { @@ -254,7 +261,7 @@ class MerklePatriciaTrieSuite extends AnyFunSuite with ScalaCheckPropertyChecks assert(obtained1.isEmpty) val obtained2 = trieAfterDelete.get(key2) assert(obtained2.isDefined) - assert(obtained2.get sameElements val2) + assert(obtained2.get.sameElements(val2)) } test( @@ -270,8 +277,8 @@ class MerklePatriciaTrieSuite extends AnyFunSuite with ScalaCheckPropertyChecks assert(obtained1.isEmpty) val obtained2 = trieAfterDelete.get(key2) assert(obtained2.isDefined) - assert(obtained2.get sameElements val2) - assert(trieAfterDelete.getRootHash sameElements emptyMpt.put(key2, val2).getRootHash) + assert(obtained2.get.sameElements(val2)) + assert(trieAfterDelete.getRootHash.sameElements(emptyMpt.put(key2, val2).getRootHash)) } test( @@ -287,8 +294,8 @@ class MerklePatriciaTrieSuite extends AnyFunSuite with ScalaCheckPropertyChecks assert(obtained1.isEmpty) val obtained2 = trieAfterDelete.get(key2) assert(obtained2.isDefined) - assert(obtained2.get sameElements val2) - assert(trieAfterDelete.getRootHash sameElements emptyMpt.put(key2, val2).getRootHash) + assert(obtained2.get.sameElements(val2)) + assert(trieAfterDelete.getRootHash.sameElements(emptyMpt.put(key2, val2).getRootHash)) } test("Remove of a trie with an extension whose next is not on source") { @@ -331,9 +338,9 @@ class MerklePatriciaTrieSuite extends AnyFunSuite with ScalaCheckPropertyChecks val key1Get = trie.get(key1) val key2Get = trie.get(key2) val key3Get = trie.get(key3) - assert(key1Get.isDefined && (key1Get.get sameElements key1)) - assert(key2Get.isDefined && (key2Get.get sameElements key2)) - assert(key3Get.isDefined && (key3Get.get sameElements val3)) + assert(key1Get.isDefined && (key1Get.get.sameElements(key1))) + assert(key2Get.isDefined && (key2Get.get.sameElements(key2))) + assert(key3Get.isDefined && (key3Get.get.sameElements(val3))) } test("Remove of a key (not in trie) whose value should be in a branch node") { @@ -341,7 +348,7 @@ class MerklePatriciaTrieSuite extends AnyFunSuite with ScalaCheckPropertyChecks val key2: Array[Byte] = Hex.decode("11f0") val trieWithBranch = emptyMpt.put(key1, key1).put(key2, key2) val trieAfterDelete = trieWithBranch.remove(Hex.decode("11")) - assert(trieAfterDelete.getRootHash sameElements trieWithBranch.getRootHash) + assert(trieAfterDelete.getRootHash.sameElements(trieWithBranch.getRootHash)) } test("Remove of a key (not in trie) that should be in the child of a BranchNode that is not present") { @@ -349,7 +356,7 @@ class MerklePatriciaTrieSuite extends AnyFunSuite with ScalaCheckPropertyChecks val key2: Array[Byte] = Hex.decode("11f0") val trieWithBranch = emptyMpt.put(key1, key1).put(key2, key2) val trieAfterDelete = trieWithBranch.remove(Hex.decode("11a0")) - assert(trieAfterDelete.getRootHash sameElements trieWithBranch.getRootHash) + assert(trieAfterDelete.getRootHash.sameElements(trieWithBranch.getRootHash)) } test("Invalid root hash should return an error accordingly") { @@ -439,8 +446,7 @@ class MerklePatriciaTrieSuite extends AnyFunSuite with ScalaCheckPropertyChecks } - /** - * The MPT tested in this example has duplicated nodes as the branch node has two children with the same node: LeafNode("a", value) + /** The MPT tested in this example has duplicated nodes as the branch node has two children with the same node: LeafNode("a", value) * When one of the key-value that uses one of this nodes is removed, this shouldn't affect the use of the other key-value * which shares the same LeafNode */ @@ -455,18 +461,17 @@ class MerklePatriciaTrieSuite extends AnyFunSuite with ScalaCheckPropertyChecks val trieAfterRemoval = trie.remove(key1) //Old trie still works - assert(trie.get(key1).getOrElse(Array.emptyByteArray) sameElements value) - assert(trie.get(key2).getOrElse(Array.emptyByteArray) sameElements value) - assert(trie.get(key3).getOrElse(Array.emptyByteArray) sameElements value) + assert(trie.get(key1).getOrElse(Array.emptyByteArray).sameElements(value)) + assert(trie.get(key2).getOrElse(Array.emptyByteArray).sameElements(value)) + assert(trie.get(key3).getOrElse(Array.emptyByteArray).sameElements(value)) //New trie is consistent assert(trieAfterRemoval.get(key1).isEmpty) - assert(trieAfterRemoval.get(key2).getOrElse(Array.emptyByteArray) sameElements value) - assert(trieAfterRemoval.get(key3).getOrElse(Array.emptyByteArray) sameElements value) + assert(trieAfterRemoval.get(key2).getOrElse(Array.emptyByteArray).sameElements(value)) + assert(trieAfterRemoval.get(key3).getOrElse(Array.emptyByteArray).sameElements(value)) } - /** - * Tests whether the creation of a duplicated valid temporal extension node removes it's original copy. + /** Tests whether the creation of a duplicated valid temporal extension node removes it's original copy. * The creation of this temporal nodes happens in the case that an insertion is done on an extension node with a * partial match between the extension node key and the search key * Case tested: @@ -507,8 +512,7 @@ class MerklePatriciaTrieSuite extends AnyFunSuite with ScalaCheckPropertyChecks assert(trieAtBlock10.get(decodeHexString("aaaa")).contains(6)) } - /** - * Tests whether the creation of a duplicated valid temporal leaf node removes it's original copy. + /** Tests whether the creation of a duplicated valid temporal leaf node removes it's original copy. * The creation of this temporal nodes happens in the case that an insertion is done on an leaf node with a * partial match between the leaf node key and the search key * Case tested: @@ -568,7 +572,7 @@ class MerklePatriciaTrieSuite extends AnyFunSuite with ScalaCheckPropertyChecks val proof = trie.getProof(wrongKey) assert(proof.getOrElse(Vector.empty).toList match { case _ @HashNode(_) :: Nil => true - case _ => false + case _ => false }) } } @@ -585,7 +589,7 @@ class MerklePatriciaTrieSuite extends AnyFunSuite with ScalaCheckPropertyChecks val proof = emptyTrie.getProof(key = wrongKey) assert(proof.getOrElse(Vector.empty).toList match { case _ @HashNode(_) :: tail => tail.nonEmpty - case _ => false + case _ => false }) } @@ -623,14 +627,14 @@ class MerklePatriciaTrieSuite extends AnyFunSuite with ScalaCheckPropertyChecks recTrie.put(key, value) } - input.toList.foreach(x => { + input.toList.foreach { x => val keyToFind = x._1 val proof = trie.getProof(keyToFind) assert(proof.isDefined) proof.map { p => assert(verifyProof[Array[Byte], Array[Byte]](trie.getRootHash, keyToFind, p) == ValidProof) } - }) + } } } @@ -656,7 +660,7 @@ class MerklePatriciaTrieSuite extends AnyFunSuite with ScalaCheckPropertyChecks kvs.foreach { case (key, value) => val obtained = trie.get(key) assert(obtained.isDefined) - assert(obtained.get sameElements value) + assert(obtained.get.sameElements(value)) } private def assertNotHave[K, V](trie: MerklePatriciaTrie[K, V], kvs: List[(K, V)]): Unit = diff --git a/src/test/scala/io/iohk/ethereum/mpt/PersistentStorage.scala b/src/test/scala/io/iohk/ethereum/mpt/PersistentStorage.scala index 9d2f25d43c..70ef35871d 100644 --- a/src/test/scala/io/iohk/ethereum/mpt/PersistentStorage.scala +++ b/src/test/scala/io/iohk/ethereum/mpt/PersistentStorage.scala @@ -29,13 +29,11 @@ trait PersistentStorage { dataSource.destroy() } - private def testExecution(testCode: MptStorage => Unit, dbPath: String, dataSource: DataSource): Unit = { - try { - testCode(new SerializingMptStorage(new ArchiveNodeStorage(new NodeStorage(dataSource)))) - } finally { + private def testExecution(testCode: MptStorage => Unit, dbPath: String, dataSource: DataSource): Unit = + try testCode(new SerializingMptStorage(new ArchiveNodeStorage(new NodeStorage(dataSource)))) + finally { val dir = new File(dbPath) !dir.exists() || dir.delete() } - } } diff --git a/src/test/scala/io/iohk/ethereum/network/AsymmetricCipherKeyPairLoaderSpec.scala b/src/test/scala/io/iohk/ethereum/network/AsymmetricCipherKeyPairLoaderSpec.scala index afd8c86cc4..952d42ac11 100644 --- a/src/test/scala/io/iohk/ethereum/network/AsymmetricCipherKeyPairLoaderSpec.scala +++ b/src/test/scala/io/iohk/ethereum/network/AsymmetricCipherKeyPairLoaderSpec.scala @@ -3,21 +3,22 @@ package io.iohk.ethereum.network import java.io.File import java.nio.file.Files -import io.iohk.ethereum.security.SecureRandomBuilder -import io.iohk.ethereum.network import org.bouncycastle.crypto.AsymmetricCipherKeyPair -import org.bouncycastle.crypto.params.{ECPrivateKeyParameters, ECPublicKeyParameters} +import org.bouncycastle.crypto.params.ECPrivateKeyParameters +import org.bouncycastle.crypto.params.ECPublicKeyParameters import org.scalatest.flatspec.AnyFlatSpec import org.scalatest.matchers.should.Matchers +import io.iohk.ethereum.network +import io.iohk.ethereum.security.SecureRandomBuilder + class AsymmetricCipherKeyPairLoaderSpec extends AnyFlatSpec with Matchers with SecureRandomBuilder { def withFilePath(testCode: String => Any): Unit = { val path = Files.createTempFile("key-", "").toAbsolutePath.toString require(new File(path).delete(), "File deletion before test failed") - try { - testCode(path) - } finally { + try testCode(path) + finally { val file = new File(path) assert(!file.exists() || file.delete(), "File deletion after test failed") } diff --git a/src/test/scala/io/iohk/ethereum/network/AuthHandshakerSpec.scala b/src/test/scala/io/iohk/ethereum/network/AuthHandshakerSpec.scala index 135cebeee3..2d67bc08cf 100644 --- a/src/test/scala/io/iohk/ethereum/network/AuthHandshakerSpec.scala +++ b/src/test/scala/io/iohk/ethereum/network/AuthHandshakerSpec.scala @@ -4,15 +4,21 @@ import java.math.BigInteger import java.net.URI import akka.util.ByteString -import io.iohk.ethereum.crypto._ -import io.iohk.ethereum.security.SecureRandomBuilder -import io.iohk.ethereum.network.rlpx.{AuthHandshakeSuccess, AuthHandshaker, AuthResponseMessage, Secrets} -import org.bouncycastle.crypto.params.{ECPrivateKeyParameters, ECPublicKeyParameters} + import org.bouncycastle.crypto.AsymmetricCipherKeyPair +import org.bouncycastle.crypto.params.ECPrivateKeyParameters +import org.bouncycastle.crypto.params.ECPublicKeyParameters import org.bouncycastle.util.encoders.Hex import org.scalatest.flatspec.AnyFlatSpec import org.scalatest.matchers.should.Matchers +import io.iohk.ethereum.crypto._ +import io.iohk.ethereum.network.rlpx.AuthHandshakeSuccess +import io.iohk.ethereum.network.rlpx.AuthHandshaker +import io.iohk.ethereum.network.rlpx.AuthResponseMessage +import io.iohk.ethereum.network.rlpx.Secrets +import io.iohk.ethereum.security.SecureRandomBuilder + class AuthHandshakerSpec extends AnyFlatSpec with Matchers with SecureRandomBuilder { val remoteNodeKey = new AsymmetricCipherKeyPair( @@ -45,7 +51,7 @@ class AuthHandshakerSpec extends AnyFlatSpec with Matchers with SecureRandomBuil ) ) - val remoteNonce = ByteString(Array.fill[Byte](AuthHandshaker.NonceSize)(9.toByte)) + val remoteNonce: ByteString = ByteString(Array.fill[Byte](AuthHandshaker.NonceSize)(9.toByte)) val remoteNodeId: Array[Byte] = remoteNodeKey.getPublic.asInstanceOf[ECPublicKeyParameters].toNodeId val remoteUri = new URI(s"enode://${Hex.toHexString(remoteNodeId)}@127.0.0.1:30303") @@ -80,7 +86,7 @@ class AuthHandshakerSpec extends AnyFlatSpec with Matchers with SecureRandomBuil ) ) - val nonce = ByteString(Array.fill[Byte](AuthHandshaker.NonceSize)(1.toByte)) + val nonce: ByteString = ByteString(Array.fill[Byte](AuthHandshaker.NonceSize)(1.toByte)) "AuthHandshaker" should "handle init response" in { val (_, authHandshaker) = AuthHandshaker(nodeKey, nonce, ephemeralKey, secureRandom).initiate(remoteUri) diff --git a/src/test/scala/io/iohk/ethereum/network/AuthInitiateMessageSpec.scala b/src/test/scala/io/iohk/ethereum/network/AuthInitiateMessageSpec.scala index 803d6ab6bd..56d5e72f4d 100644 --- a/src/test/scala/io/iohk/ethereum/network/AuthInitiateMessageSpec.scala +++ b/src/test/scala/io/iohk/ethereum/network/AuthInitiateMessageSpec.scala @@ -1,16 +1,20 @@ package io.iohk.ethereum.network import akka.util.ByteString -import io.iohk.ethereum.crypto._ -import io.iohk.ethereum.security.SecureRandomBuilder -import io.iohk.ethereum.network.rlpx.{AuthHandshaker, AuthInitiateMessage} -import io.iohk.ethereum.utils.ByteUtils + import org.bouncycastle.crypto.generators.ECKeyPairGenerator -import org.bouncycastle.crypto.params.{ECKeyGenerationParameters, ECPublicKeyParameters} +import org.bouncycastle.crypto.params.ECKeyGenerationParameters +import org.bouncycastle.crypto.params.ECPublicKeyParameters import org.bouncycastle.util.encoders.Hex import org.scalatest.flatspec.AnyFlatSpec import org.scalatest.matchers.should.Matchers +import io.iohk.ethereum.crypto._ +import io.iohk.ethereum.network.rlpx.AuthHandshaker +import io.iohk.ethereum.network.rlpx.AuthInitiateMessage +import io.iohk.ethereum.security.SecureRandomBuilder +import io.iohk.ethereum.utils.ByteUtils + class AuthInitiateMessageSpec extends AnyFlatSpec with Matchers with SecureRandomBuilder { "AuthInitiateMessage" should "encode and decode itself" in { diff --git a/src/test/scala/io/iohk/ethereum/network/EtcPeerManagerSpec.scala b/src/test/scala/io/iohk/ethereum/network/EtcPeerManagerSpec.scala index fe506ae857..dc77488f27 100644 --- a/src/test/scala/io/iohk/ethereum/network/EtcPeerManagerSpec.scala +++ b/src/test/scala/io/iohk/ethereum/network/EtcPeerManagerSpec.scala @@ -2,26 +2,39 @@ package io.iohk.ethereum.network import java.net.InetSocketAddress -import akka.actor.{ActorSystem, Props} -import akka.testkit.{TestActorRef, TestProbe} +import akka.actor.ActorSystem +import akka.actor.Props +import akka.testkit.TestActorRef +import akka.testkit.TestProbe import akka.util.ByteString + +import org.bouncycastle.util.encoders.Hex +import org.scalatest.flatspec.AnyFlatSpec +import org.scalatest.matchers.should.Matchers + import io.iohk.ethereum.Fixtures -import io.iohk.ethereum.Fixtures.Blocks.{DaoForkBlock, Genesis} +import io.iohk.ethereum.Fixtures.Blocks.DaoForkBlock +import io.iohk.ethereum.Fixtures.Blocks.Genesis import io.iohk.ethereum.blockchain.sync.EphemBlockchainTestSetup -import io.iohk.ethereum.domain.{Block, BlockBody, BlockHeader, ChainWeight} +import io.iohk.ethereum.domain.Block +import io.iohk.ethereum.domain.BlockBody +import io.iohk.ethereum.domain.BlockHeader +import io.iohk.ethereum.domain.ChainWeight import io.iohk.ethereum.network.EtcPeerManagerActor._ import io.iohk.ethereum.network.PeerActor.DisconnectPeer -import io.iohk.ethereum.network.PeerEventBusActor.PeerEvent.{MessageFromPeer, PeerDisconnected, PeerHandshakeSuccessful} +import io.iohk.ethereum.network.PeerEventBusActor.PeerEvent.MessageFromPeer +import io.iohk.ethereum.network.PeerEventBusActor.PeerEvent.PeerDisconnected +import io.iohk.ethereum.network.PeerEventBusActor.PeerEvent.PeerHandshakeSuccessful +import io.iohk.ethereum.network.PeerEventBusActor.PeerSelector +import io.iohk.ethereum.network.PeerEventBusActor.Subscribe import io.iohk.ethereum.network.PeerEventBusActor.SubscriptionClassifier._ -import io.iohk.ethereum.network.PeerEventBusActor.{PeerSelector, Subscribe} import io.iohk.ethereum.network.p2p.messages.BaseETH6XMessages.NewBlock +import io.iohk.ethereum.network.p2p.messages.Codes +import io.iohk.ethereum.network.p2p.messages.ETC64 import io.iohk.ethereum.network.p2p.messages.ETH62._ +import io.iohk.ethereum.network.p2p.messages.ProtocolVersions import io.iohk.ethereum.network.p2p.messages.WireProtocol.Disconnect -import io.iohk.ethereum.network.p2p.messages.{Codes, ETC64, ProtocolVersions} import io.iohk.ethereum.utils.Config -import org.bouncycastle.util.encoders.Hex -import org.scalatest.flatspec.AnyFlatSpec -import org.scalatest.matchers.should.Matchers class EtcPeerManagerSpec extends AnyFlatSpec with Matchers { @@ -277,14 +290,14 @@ class EtcPeerManagerSpec extends AnyFlatSpec with Matchers { } trait TestSetup extends EphemBlockchainTestSetup { - override implicit lazy val system = ActorSystem("PeersInfoHolderSpec_System") + implicit override lazy val system: ActorSystem = ActorSystem("PeersInfoHolderSpec_System") blockchain.storeBlockHeader(Fixtures.Blocks.Genesis.header).commit() override lazy val blockchainConfig = Config.blockchains.blockchainConfig val forkResolver = new ForkResolver.EtcForkResolver(blockchainConfig.daoForkConfig.get) - val peerStatus = RemoteStatus( + val peerStatus: RemoteStatus = RemoteStatus( protocolVersion = ProtocolVersions.ETH63.version, networkId = 1, chainWeight = ChainWeight.totalDifficultyOnly(10000), @@ -292,7 +305,7 @@ class EtcPeerManagerSpec extends AnyFlatSpec with Matchers { genesisHash = Fixtures.Blocks.Genesis.header.hash ) - val initialPeerInfo = PeerInfo( + val initialPeerInfo: PeerInfo = PeerInfo( remoteStatus = peerStatus, chainWeight = peerStatus.chainWeight, forkAccepted = false, @@ -300,7 +313,7 @@ class EtcPeerManagerSpec extends AnyFlatSpec with Matchers { bestBlockHash = peerStatus.bestHash ) - val initialPeerInfoETC64 = PeerInfo( + val initialPeerInfoETC64: PeerInfo = PeerInfo( remoteStatus = peerStatus.copy(protocolVersion = ProtocolVersions.ETC64.version), chainWeight = peerStatus.chainWeight, forkAccepted = false, @@ -308,27 +321,30 @@ class EtcPeerManagerSpec extends AnyFlatSpec with Matchers { bestBlockHash = peerStatus.bestHash ) - val fakeNodeId = ByteString() - - val peer1Probe = TestProbe() - val peer1 = Peer(PeerId("peer1"), new InetSocketAddress("127.0.0.1", 1), peer1Probe.ref, false, Some(fakeNodeId)) - val peer1Info = initialPeerInfo.withForkAccepted(false) - val peer1InfoETC64 = initialPeerInfoETC64.withForkAccepted(false) - val peer2Probe = TestProbe() - val peer2 = Peer(PeerId("peer2"), new InetSocketAddress("127.0.0.1", 2), peer2Probe.ref, false, Some(fakeNodeId)) - val peer2Info = initialPeerInfo.withForkAccepted(false) - val peer3Probe = TestProbe() - val peer3 = Peer(PeerId("peer3"), new InetSocketAddress("127.0.0.1", 3), peer3Probe.ref, false, Some(fakeNodeId)) - - val freshPeerProbe = TestProbe() - val freshPeer = + val fakeNodeId: ByteString = ByteString() + + val peer1Probe: TestProbe = TestProbe() + val peer1: Peer = + Peer(PeerId("peer1"), new InetSocketAddress("127.0.0.1", 1), peer1Probe.ref, false, Some(fakeNodeId)) + val peer1Info: PeerInfo = initialPeerInfo.withForkAccepted(false) + val peer1InfoETC64: PeerInfo = initialPeerInfoETC64.withForkAccepted(false) + val peer2Probe: TestProbe = TestProbe() + val peer2: Peer = + Peer(PeerId("peer2"), new InetSocketAddress("127.0.0.1", 2), peer2Probe.ref, false, Some(fakeNodeId)) + val peer2Info: PeerInfo = initialPeerInfo.withForkAccepted(false) + val peer3Probe: TestProbe = TestProbe() + val peer3: Peer = + Peer(PeerId("peer3"), new InetSocketAddress("127.0.0.1", 3), peer3Probe.ref, false, Some(fakeNodeId)) + + val freshPeerProbe: TestProbe = TestProbe() + val freshPeer: Peer = Peer(PeerId(""), new InetSocketAddress("127.0.0.1", 4), freshPeerProbe.ref, false, Some(fakeNodeId)) - val freshPeerInfo = initialPeerInfo.withForkAccepted(false) + val freshPeerInfo: PeerInfo = initialPeerInfo.withForkAccepted(false) - val peerManager = TestProbe() - val peerEventBus = TestProbe() + val peerManager: TestProbe = TestProbe() + val peerEventBus: TestProbe = TestProbe() - val peersInfoHolder = TestActorRef( + val peersInfoHolder: TestActorRef[Nothing] = TestActorRef( Props( new EtcPeerManagerActor( peerManager.ref, @@ -339,11 +355,11 @@ class EtcPeerManagerSpec extends AnyFlatSpec with Matchers { ) ) - val requestSender = TestProbe() + val requestSender: TestProbe = TestProbe() val baseBlockHeader = Fixtures.Blocks.Block3125369.header - val baseBlockBody = BlockBody(Nil, Nil) - val baseBlock = Block(baseBlockHeader, baseBlockBody) + val baseBlockBody: BlockBody = BlockBody(Nil, Nil) + val baseBlock: Block = Block(baseBlockHeader, baseBlockBody) def setupNewPeer(peer: Peer, peerProbe: TestProbe, peerInfo: PeerInfo): Unit = { diff --git a/src/test/scala/io/iohk/ethereum/network/KnownNodesManagerSpec.scala b/src/test/scala/io/iohk/ethereum/network/KnownNodesManagerSpec.scala index ab05596186..7eeca546f8 100644 --- a/src/test/scala/io/iohk/ethereum/network/KnownNodesManagerSpec.scala +++ b/src/test/scala/io/iohk/ethereum/network/KnownNodesManagerSpec.scala @@ -2,16 +2,20 @@ package io.iohk.ethereum.network import java.net.URI -import akka.actor.{ActorSystem, Props} +import akka.actor.ActorRef +import akka.actor.ActorSystem +import akka.actor.Props import akka.testkit.TestProbe -import com.miguno.akka.testing.VirtualTime -import io.iohk.ethereum.blockchain.sync.EphemBlockchainTestSetup -import io.iohk.ethereum.network.KnownNodesManager.KnownNodesManagerConfig import scala.concurrent.duration._ + +import com.miguno.akka.testing.VirtualTime import org.scalatest.flatspec.AnyFlatSpec import org.scalatest.matchers.should.Matchers +import io.iohk.ethereum.blockchain.sync.EphemBlockchainTestSetup +import io.iohk.ethereum.network.KnownNodesManager.KnownNodesManagerConfig + class KnownNodesManagerSpec extends AnyFlatSpec with Matchers { "KnownNodesManager" should "keep a list of nodes and persist changes" in new TestSetup { @@ -59,16 +63,16 @@ class KnownNodesManagerSpec extends AnyFlatSpec with Matchers { } trait TestSetup extends EphemBlockchainTestSetup { - override implicit lazy val system = ActorSystem("KnownNodesManagerSpec_System") + implicit override lazy val system: ActorSystem = ActorSystem("KnownNodesManagerSpec_System") val time = new VirtualTime - val config = KnownNodesManagerConfig(persistInterval = 5.seconds, maxPersistedNodes = 5) + val config: KnownNodesManagerConfig = KnownNodesManagerConfig(persistInterval = 5.seconds, maxPersistedNodes = 5) - val client = TestProbe() + val client: TestProbe = TestProbe() def uri(n: Int): URI = new URI(s"enode://test$n@test$n.com:9000") - val knownNodesManager = system.actorOf( + val knownNodesManager: ActorRef = system.actorOf( Props(new KnownNodesManager(config, storagesInstance.storages.knownNodesStorage, Some(time.scheduler))) ) } diff --git a/src/test/scala/io/iohk/ethereum/network/NodeParserSpec.scala b/src/test/scala/io/iohk/ethereum/network/NodeParserSpec.scala index 1ab3142a8f..3a58437dc4 100644 --- a/src/test/scala/io/iohk/ethereum/network/NodeParserSpec.scala +++ b/src/test/scala/io/iohk/ethereum/network/NodeParserSpec.scala @@ -1,9 +1,10 @@ package io.iohk.ethereum.network -import io.iohk.ethereum.network.discovery.NodeParser -import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks import org.scalatest.flatspec.AnyFlatSpec import org.scalatest.matchers.should.Matchers +import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks + +import io.iohk.ethereum.network.discovery.NodeParser class NodeParserSpec extends AnyFlatSpec with Matchers with ScalaCheckPropertyChecks { diff --git a/src/test/scala/io/iohk/ethereum/network/PeerActorHandshakingSpec.scala b/src/test/scala/io/iohk/ethereum/network/PeerActorHandshakingSpec.scala index 01e5e441ea..8b8ae074c3 100644 --- a/src/test/scala/io/iohk/ethereum/network/PeerActorHandshakingSpec.scala +++ b/src/test/scala/io/iohk/ethereum/network/PeerActorHandshakingSpec.scala @@ -1,27 +1,40 @@ package io.iohk.ethereum.network -import java.net.{InetSocketAddress, URI} -import akka.actor.{ActorSystem, Props} -import akka.testkit.{TestActorRef, TestProbe} +import java.net.InetSocketAddress +import java.net.URI + +import akka.actor.ActorSystem +import akka.actor.Props +import akka.testkit.TestActorRef +import akka.testkit.TestProbe import akka.util.ByteString + import com.miguno.akka.testing.VirtualTime -import io.iohk.ethereum.Mocks.{MockHandshakerAlwaysFails, MockHandshakerAlwaysSucceeds} +import org.scalatest.flatspec.AnyFlatSpec +import org.scalatest.matchers.should.Matchers + +import io.iohk.ethereum.Fixtures +import io.iohk.ethereum.Mocks.MockHandshakerAlwaysFails +import io.iohk.ethereum.Mocks.MockHandshakerAlwaysSucceeds +import io.iohk.ethereum.Timeouts import io.iohk.ethereum.blockchain.sync.EphemBlockchainTestSetup -import io.iohk.ethereum.network.EtcPeerManagerActor.{PeerInfo, RemoteStatus} +import io.iohk.ethereum.network.EtcPeerManagerActor.PeerInfo +import io.iohk.ethereum.network.EtcPeerManagerActor.RemoteStatus +import io.iohk.ethereum.network.PeerActor.ConnectTo +import io.iohk.ethereum.network.PeerActor.GetStatus import io.iohk.ethereum.network.PeerActor.Status.Handshaked -import io.iohk.ethereum.network.PeerActor.{ConnectTo, GetStatus, StatusResponse} +import io.iohk.ethereum.network.PeerActor.StatusResponse import io.iohk.ethereum.network.handshaker.Handshaker.NextMessage import io.iohk.ethereum.network.handshaker._ import io.iohk.ethereum.network.p2p.Message -import io.iohk.ethereum.network.p2p.messages.Capability.Capabilities._ import io.iohk.ethereum.network.p2p.messages.BaseETH6XMessages.Status -import io.iohk.ethereum.network.p2p.messages.{Capability, ProtocolVersions} -import io.iohk.ethereum.network.p2p.messages.WireProtocol.{Disconnect, Hello, Pong} +import io.iohk.ethereum.network.p2p.messages.Capability.Capabilities._ +import io.iohk.ethereum.network.p2p.messages.ProtocolVersions +import io.iohk.ethereum.network.p2p.messages.WireProtocol.Disconnect +import io.iohk.ethereum.network.p2p.messages.WireProtocol.Hello +import io.iohk.ethereum.network.p2p.messages.WireProtocol.Pong import io.iohk.ethereum.network.rlpx.RLPxConnectionHandler import io.iohk.ethereum.utils.Config -import io.iohk.ethereum.{Fixtures, Timeouts} -import org.scalatest.flatspec.AnyFlatSpec -import org.scalatest.matchers.should.Matchers class PeerActorHandshakingSpec extends AnyFlatSpec with Matchers { @@ -139,16 +152,16 @@ class PeerActorHandshakingSpec extends AnyFlatSpec with Matchers { } trait TestSetup extends EphemBlockchainTestSetup { - override implicit lazy val system = ActorSystem("PeerActorSpec_System") + implicit override lazy val system: ActorSystem = ActorSystem("PeerActorSpec_System") val time = new VirtualTime val uri = new URI( "enode://18a551bee469c2e02de660ab01dede06503c986f6b8520cb5a65ad122df88b17b285e3fef09a40a0d44f99e014f8616cf1ebc2e094f96c6e09e2f390f5d34857@47.90.36.129:30303" ) - val rlpxConnectionProbe = TestProbe() - val peerMessageBus = TestProbe() - val knownNodesManager = TestProbe() + val rlpxConnectionProbe: TestProbe = TestProbe() + val peerMessageBus: TestProbe = TestProbe() + val knownNodesManager: TestProbe = TestProbe() def peerActor(handshaker: Handshaker[PeerInfo]): TestActorRef[PeerActor[PeerInfo]] = TestActorRef( Props( @@ -167,18 +180,18 @@ class PeerActorHandshakingSpec extends AnyFlatSpec with Matchers { } object DefaultValues { - val defaultStatusMsg = Status( + val defaultStatusMsg: Status = Status( protocolVersion = ProtocolVersions.ETH63.version, networkId = 1, totalDifficulty = Fixtures.Blocks.Genesis.header.difficulty, bestHash = Fixtures.Blocks.Genesis.header.hash, genesisHash = Fixtures.Blocks.Genesis.header.hash ) - val defaultStatus = RemoteStatus(defaultStatusMsg) + val defaultStatus: RemoteStatus = RemoteStatus(defaultStatusMsg) val defaultBlockNumber = 1000 val defaultForkAccepted = true - val defaultPeerInfo = PeerInfo( + val defaultPeerInfo: PeerInfo = PeerInfo( defaultStatus, defaultStatus.chainWeight, defaultForkAccepted, @@ -188,7 +201,7 @@ class PeerActorHandshakingSpec extends AnyFlatSpec with Matchers { val defaultReasonDisconnect = Disconnect.Reasons.Other - val defaultHello = Hello( + val defaultHello: Hello = Hello( p2pVersion = 0, clientId = "notused", capabilities = Seq(Eth63Capability), @@ -206,9 +219,8 @@ class PeerActorHandshakingSpec extends AnyFlatSpec with Matchers { } object MockHandshakerRequiresHello { - def apply(): MockHandshakerRequiresHello = { + def apply(): MockHandshakerRequiresHello = new MockHandshakerRequiresHello(MockHelloExchangeState) - } } case object MockHelloExchangeState extends InProgressState[PeerInfo] { @@ -219,7 +231,7 @@ class PeerActorHandshakingSpec extends AnyFlatSpec with Matchers { def applyResponseMessage: PartialFunction[Message, HandshakerState[PeerInfo]] = { case helloMsg: Hello => ConnectedState(defaultPeerInfo) - case status: Status => DisconnectedState(defaultReasonDisconnect) + case status: Status => DisconnectedState(defaultReasonDisconnect) } def processTimeout: HandshakerState[PeerInfo] = DisconnectedState(defaultReasonDisconnect) diff --git a/src/test/scala/io/iohk/ethereum/network/PeerEventBusActorSpec.scala b/src/test/scala/io/iohk/ethereum/network/PeerEventBusActorSpec.scala index 2e6b27f29e..10f4b81e9c 100644 --- a/src/test/scala/io/iohk/ethereum/network/PeerEventBusActorSpec.scala +++ b/src/test/scala/io/iohk/ethereum/network/PeerEventBusActorSpec.scala @@ -2,19 +2,26 @@ package io.iohk.ethereum.network import java.net.InetSocketAddress +import akka.actor.ActorRef import akka.actor.ActorSystem import akka.testkit.TestProbe import akka.util.ByteString + +import org.scalatest.flatspec.AnyFlatSpec +import org.scalatest.matchers.should.Matchers + import io.iohk.ethereum.Fixtures import io.iohk.ethereum.domain.ChainWeight -import io.iohk.ethereum.network.EtcPeerManagerActor.{PeerInfo, RemoteStatus} -import io.iohk.ethereum.network.PeerEventBusActor.PeerEvent.{MessageFromPeer, PeerDisconnected, PeerHandshakeSuccessful} +import io.iohk.ethereum.network.EtcPeerManagerActor.PeerInfo +import io.iohk.ethereum.network.EtcPeerManagerActor.RemoteStatus +import io.iohk.ethereum.network.PeerEventBusActor.PeerEvent.MessageFromPeer +import io.iohk.ethereum.network.PeerEventBusActor.PeerEvent.PeerDisconnected +import io.iohk.ethereum.network.PeerEventBusActor.PeerEvent.PeerHandshakeSuccessful import io.iohk.ethereum.network.PeerEventBusActor.PeerSelector import io.iohk.ethereum.network.PeerEventBusActor.SubscriptionClassifier._ import io.iohk.ethereum.network.p2p.messages.ProtocolVersions -import io.iohk.ethereum.network.p2p.messages.WireProtocol.{Ping, Pong} -import org.scalatest.flatspec.AnyFlatSpec -import org.scalatest.matchers.should.Matchers +import io.iohk.ethereum.network.p2p.messages.WireProtocol.Ping +import io.iohk.ethereum.network.p2p.messages.WireProtocol.Pong class PeerEventBusActorSpec extends AnyFlatSpec with Matchers { @@ -238,18 +245,18 @@ class PeerEventBusActorSpec extends AnyFlatSpec with Matchers { } trait TestSetup { - implicit val system = ActorSystem("test-system") + implicit val system: ActorSystem = ActorSystem("test-system") - val peerEventBusActor = system.actorOf(PeerEventBusActor.props) + val peerEventBusActor: ActorRef = system.actorOf(PeerEventBusActor.props) - val peerStatus = RemoteStatus( + val peerStatus: RemoteStatus = RemoteStatus( protocolVersion = ProtocolVersions.ETH63.version, networkId = 1, chainWeight = ChainWeight.totalDifficultyOnly(10000), bestHash = Fixtures.Blocks.Block3125369.header.hash, genesisHash = Fixtures.Blocks.Genesis.header.hash ) - val initialPeerInfo = PeerInfo( + val initialPeerInfo: PeerInfo = PeerInfo( remoteStatus = peerStatus, chainWeight = peerStatus.chainWeight, forkAccepted = false, diff --git a/src/test/scala/io/iohk/ethereum/network/PeerManagerSpec.scala b/src/test/scala/io/iohk/ethereum/network/PeerManagerSpec.scala index 9f90d95353..2e4f7f55ec 100644 --- a/src/test/scala/io/iohk/ethereum/network/PeerManagerSpec.scala +++ b/src/test/scala/io/iohk/ethereum/network/PeerManagerSpec.scala @@ -1,39 +1,63 @@ package io.iohk.ethereum.network -import java.net.{InetSocketAddress, URI} +import java.net.InetSocketAddress +import java.net.URI import java.util.concurrent.TimeUnit import akka.actor._ -import akka.testkit.{TestActorRef, TestKit, TestProbe} +import akka.testkit.TestActorRef +import akka.testkit.TestKit +import akka.testkit.TestProbe import akka.util.ByteString + +import scala.concurrent.duration._ + +import com.github.blemale.scaffeine.Cache +import com.github.blemale.scaffeine.Scaffeine +import com.google.common.testing.FakeTicker import com.miguno.akka.testing.VirtualTime -import io.iohk.ethereum.domain.{Block, BlockBody, BlockHeader, ChainWeight} -import io.iohk.ethereum.network.EtcPeerManagerActor.{PeerInfo, RemoteStatus} -import io.iohk.ethereum.network.PeerActor.{ConnectTo, PeerClosedConnection} -import io.iohk.ethereum.network.PeerEventBusActor.PeerEvent.PeerDisconnected -import io.iohk.ethereum.network.PeerEventBusActor.SubscriptionClassifier.PeerHandshaked -import io.iohk.ethereum.network.PeerEventBusActor.{PeerEvent, Publish, Subscribe} -import io.iohk.ethereum.network.PeerManagerActor.{GetPeers, PeerAddress, PeerConfiguration, Peers, SendMessage} -import io.iohk.ethereum.network.discovery.{DiscoveryConfig, Node, PeerDiscoveryManager} -import io.iohk.ethereum.network.p2p.messages.BaseETH6XMessages.NewBlock -import io.iohk.ethereum.network.p2p.messages.ProtocolVersions -import io.iohk.ethereum.network.p2p.messages.WireProtocol.Disconnect -import io.iohk.ethereum.utils.Config -import io.iohk.ethereum.{Fixtures, NormalPatience, WithActorSystemShutDown} import org.bouncycastle.util.encoders.Hex +import org.scalacheck.Arbitrary +import org.scalacheck.Gen import org.scalatest.Inspectors import org.scalatest.concurrent.Eventually import org.scalatest.flatspec.AnyFlatSpecLike import org.scalatest.matchers.should.Matchers import org.scalatestplus.scalacheck.ScalaCheckDrivenPropertyChecks -import org.scalacheck.{Arbitrary, Gen} -import Arbitrary.arbitrary -import com.github.blemale.scaffeine.Scaffeine -import com.google.common.testing.FakeTicker -import io.iohk.ethereum.blockchain.sync.Blacklist.{BlacklistId, BlacklistReason} + +import io.iohk.ethereum.Fixtures +import io.iohk.ethereum.NormalPatience +import io.iohk.ethereum.WithActorSystemShutDown +import io.iohk.ethereum.blockchain.sync.Blacklist.BlacklistId +import io.iohk.ethereum.blockchain.sync.Blacklist.BlacklistReason import io.iohk.ethereum.blockchain.sync.CacheBasedBlacklist +import io.iohk.ethereum.domain.Block +import io.iohk.ethereum.domain.BlockBody +import io.iohk.ethereum.domain.BlockHeader +import io.iohk.ethereum.domain.ChainWeight +import io.iohk.ethereum.network.EtcPeerManagerActor.PeerInfo +import io.iohk.ethereum.network.EtcPeerManagerActor.RemoteStatus +import io.iohk.ethereum.network.PeerActor.ConnectTo +import io.iohk.ethereum.network.PeerActor.PeerClosedConnection +import io.iohk.ethereum.network.PeerEventBusActor.PeerEvent +import io.iohk.ethereum.network.PeerEventBusActor.PeerEvent.PeerDisconnected +import io.iohk.ethereum.network.PeerEventBusActor.Publish +import io.iohk.ethereum.network.PeerEventBusActor.Subscribe +import io.iohk.ethereum.network.PeerEventBusActor.SubscriptionClassifier.PeerHandshaked +import io.iohk.ethereum.network.PeerManagerActor.GetPeers +import io.iohk.ethereum.network.PeerManagerActor.PeerAddress +import io.iohk.ethereum.network.PeerManagerActor.PeerConfiguration +import io.iohk.ethereum.network.PeerManagerActor.Peers +import io.iohk.ethereum.network.PeerManagerActor.SendMessage +import io.iohk.ethereum.network.discovery.DiscoveryConfig +import io.iohk.ethereum.network.discovery.Node +import io.iohk.ethereum.network.discovery.PeerDiscoveryManager +import io.iohk.ethereum.network.p2p.messages.BaseETH6XMessages.NewBlock +import io.iohk.ethereum.network.p2p.messages.ProtocolVersions +import io.iohk.ethereum.network.p2p.messages.WireProtocol.Disconnect +import io.iohk.ethereum.utils.Config -import scala.concurrent.duration._ +import Arbitrary.arbitrary // scalastyle:off magic.number class PeerManagerSpec @@ -45,7 +69,7 @@ class PeerManagerSpec with NormalPatience with ScalaCheckDrivenPropertyChecks { - behavior of "PeerManagerActor" + behavior.of("PeerManagerActor") it should "try to connect to bootstrap and known nodes on startup" in new TestSetup { start() @@ -313,7 +337,7 @@ class PeerManagerSpec peerAsOutgoingProbe.expectMsg(PeerActor.DisconnectPeer(Disconnect.Reasons.AlreadyConnected)) } - behavior of "outgoingConnectionDemand" + behavior.of("outgoingConnectionDemand") it should "try to connect to at least min-outgoing-peers but no more than max-outgoing-peers" in new ConnectedPeersFixture { forAll { (connectedPeers: ConnectedPeers) => @@ -369,7 +393,7 @@ class PeerManagerSpec peerManager.underlyingActor.triedNodes.size shouldEqual 3 } - behavior of "numberOfIncomingConnectionsToPrune" + behavior.of("numberOfIncomingConnectionsToPrune") it should "try to prune incoming connections down to the minimum allowed number" in new ConnectedPeersFixture { forAll { (connectedPeers: ConnectedPeers) => @@ -388,7 +412,7 @@ class PeerManagerSpec } } - behavior of "ConnectedPeers.prunePeers" + behavior.of("ConnectedPeers.prunePeers") // The `ConnectedPeers` is quite slow to generate, so doing a few tests in one go. it should "prune peers which are old enough, protecting against repeated forced pruning" in new ConnectedPeersFixture { @@ -457,7 +481,7 @@ class PeerManagerSpec numPeers = numPeersToPrune, currentTimeMillis = now + peerConfiguration.minPruneAge.toMillis ) - peers1.toSet intersect peers2.toSet shouldBe empty + peers1.toSet.intersect(peers2.toSet) shouldBe empty } // Prune peers with minimum priority first. @@ -468,7 +492,7 @@ class PeerManagerSpec priority = _.hashCode.toDouble // Dummy priority ) whenever(peers.nonEmpty) { - Inspectors.forAll(peers.init zip peers.tail) { case (a, b) => + Inspectors.forAll(peers.init.zip(peers.tail)) { case (a, b) => a.id.hashCode shouldBe <=(b.id.hashCode) } } @@ -512,7 +536,7 @@ class PeerManagerSpec } } - behavior of "prunePriority" + behavior.of("prunePriority") it should "calculate priority as count(responses)/lifetime" in { val now = System.currentTimeMillis @@ -548,7 +572,7 @@ class PeerManagerSpec minPruneAge: FiniteDuration = 30.minutes ) extends PeerManagerActor.PeerConfiguration.ConnectionLimits - val peerConfiguration = TestConfig() + val peerConfiguration: TestConfig = TestConfig() implicit val arbConnectedPeers: Arbitrary[ConnectedPeers] = Arbitrary { genConnectedPeers(peerConfiguration.maxIncomingPeers, peerConfiguration.maxOutgoingPeers) @@ -563,12 +587,13 @@ class PeerManagerSpec var createdPeers: Seq[TestPeer] = Seq.empty val peerConfiguration: PeerConfiguration = Config.Network.peer - val discoveryConfig = DiscoveryConfig(Config.config, Config.blockchains.blockchainConfig.bootstrapNodes) + val discoveryConfig: DiscoveryConfig = + DiscoveryConfig(Config.config, Config.blockchains.blockchainConfig.bootstrapNodes) - val peerDiscoveryManager = TestProbe() - val peerEventBus = TestProbe() - val knownNodesManager = TestProbe() - val peerStatistics = TestProbe() + val peerDiscoveryManager: TestProbe = TestProbe() + val peerEventBus: TestProbe = TestProbe() + val knownNodesManager: TestProbe = TestProbe() + val peerStatistics: TestProbe = TestProbe() val bootstrapNodes: Set[Node] = DiscoveryConfig(Config.config, Config.blockchains.blockchainConfig.bootstrapNodes).bootstrapNodes @@ -582,17 +607,17 @@ class PeerManagerSpec } val port = 30340 - val incomingConnection1 = TestProbe() - val incomingNodeId1 = ByteString(1) + val incomingConnection1: TestProbe = TestProbe() + val incomingNodeId1: ByteString = ByteString(1) val incomingPeerAddress1 = new InetSocketAddress("127.0.0.2", port) - val incomingConnection2 = TestProbe() - val incomingNodeId2 = ByteString(2) + val incomingConnection2: TestProbe = TestProbe() + val incomingNodeId2: ByteString = ByteString(2) val incomingPeerAddress2 = new InetSocketAddress("127.0.0.3", port) - val incomingConnection3 = TestProbe() - val incomingNodeId3 = ByteString(3) + val incomingConnection3: TestProbe = TestProbe() + val incomingNodeId3: ByteString = ByteString(3) val incomingPeerAddress3 = new InetSocketAddress("127.0.0.4", port) val ticker = new FakeTicker() - val cache = Scaffeine() + val cache: Cache[BlacklistId, BlacklistReason.BlacklistReasonType] = Scaffeine() .expireAfter[BlacklistId, BlacklistReason.BlacklistReasonType]( create = (_, _) => 60.minutes, update = (_, _, _) => 60.minutes, @@ -605,14 +630,14 @@ class PeerManagerSpec .build[BlacklistId, BlacklistReason.BlacklistReasonType]() val blacklist: CacheBasedBlacklist = CacheBasedBlacklist(cache) - val peerStatus = RemoteStatus( + val peerStatus: RemoteStatus = RemoteStatus( protocolVersion = ProtocolVersions.ETH63.version, networkId = 1, chainWeight = ChainWeight.totalDifficultyOnly(10000), bestHash = Fixtures.Blocks.Block3125369.header.hash, genesisHash = Fixtures.Blocks.Genesis.header.hash ) - val initialPeerInfo = PeerInfo( + val initialPeerInfo: PeerInfo = PeerInfo( remoteStatus = peerStatus, chainWeight = peerStatus.chainWeight, forkAccepted = false, @@ -668,8 +693,8 @@ class PeerManagerSpec ) } - val genIncomingPeer = arbitrary[Peer].map(_.copy(incomingConnection = true)) - val genOugoingPeer = arbitrary[Peer].map(_.copy(incomingConnection = false)) + val genIncomingPeer: Gen[Peer] = arbitrary[Peer].map(_.copy(incomingConnection = true)) + val genOugoingPeer: Gen[Peer] = arbitrary[Peer].map(_.copy(incomingConnection = false)) def genConnectedPeers( maxIncomingPeers: Int, diff --git a/src/test/scala/io/iohk/ethereum/network/PeerStatisticsSpec.scala b/src/test/scala/io/iohk/ethereum/network/PeerStatisticsSpec.scala index 3e6449a950..78e0bac0fc 100644 --- a/src/test/scala/io/iohk/ethereum/network/PeerStatisticsSpec.scala +++ b/src/test/scala/io/iohk/ethereum/network/PeerStatisticsSpec.scala @@ -1,15 +1,18 @@ package io.iohk.ethereum.network import akka.actor._ -import akka.testkit.{TestKit, TestProbe} -import io.iohk.ethereum.network.PeerEventBusActor._ -import io.iohk.ethereum.network.p2p.messages.ETH61.NewBlockHashes -import io.iohk.ethereum.WithActorSystemShutDown -import io.iohk.ethereum.utils.MockClock +import akka.testkit.TestKit +import akka.testkit.TestProbe + +import scala.concurrent.duration._ + import org.scalatest.flatspec.AnyFlatSpecLike import org.scalatest.matchers.should.Matchers -import scala.concurrent.duration._ +import io.iohk.ethereum.WithActorSystemShutDown +import io.iohk.ethereum.network.PeerEventBusActor._ +import io.iohk.ethereum.network.p2p.messages.ETH61.NewBlockHashes +import io.iohk.ethereum.utils.MockClock class PeerStatisticsSpec extends TestKit(ActorSystem("PeerStatisticsSpec_System")) @@ -20,14 +23,14 @@ class PeerStatisticsSpec import PeerStatisticsActor._ val TICK: Long = 50 - val mockClock = new MockClock(0L) { + val mockClock: MockClock = new MockClock(0L) { override def millis(): Long = { windByMillis(TICK) super.millis() } } - behavior of "PeerStatisticsActor" + behavior.of("PeerStatisticsActor") it should "subscribe to peer events" in new Fixture { peerEventBus.expectMsg(Subscribe(PeerStatisticsActor.MessageSubscriptionClassifier)) @@ -70,11 +73,11 @@ class PeerStatisticsSpec } trait Fixture { - val sender = TestProbe() - implicit val senderRef = sender.ref + val sender: TestProbe = TestProbe() + implicit val senderRef: ActorRef = sender.ref - val peerEventBus = TestProbe() - val peerStatistics = + val peerEventBus: TestProbe = TestProbe() + val peerStatistics: ActorRef = system.actorOf(PeerStatisticsActor.props(peerEventBus.ref, slotDuration = 1.minute, slotCount = 30)(mockClock)) } } diff --git a/src/test/scala/io/iohk/ethereum/network/TimeSlotStatsSpec.scala b/src/test/scala/io/iohk/ethereum/network/TimeSlotStatsSpec.scala index 45b773d3b1..45205d8ea0 100644 --- a/src/test/scala/io/iohk/ethereum/network/TimeSlotStatsSpec.scala +++ b/src/test/scala/io/iohk/ethereum/network/TimeSlotStatsSpec.scala @@ -1,30 +1,34 @@ package io.iohk.ethereum.network -import cats._ -import cats.implicits._ +import java.time.Clock + import cats.data.State +import cats.implicits._ import cats.kernel.Monoid -import java.time.Clock + +import scala.concurrent.duration._ + +import org.scalacheck.Arbitrary +import org.scalacheck.Gen +import org.scalatest.Inspectors +import org.scalatest.compatible.Assertion import org.scalatest.flatspec.AnyFlatSpec import org.scalatest.matchers.should.Matchers -import org.scalatest.Inspectors import org.scalatestplus.scalacheck.ScalaCheckDrivenPropertyChecks -import org.scalacheck.{Arbitrary, Gen, Shrink}, Arbitrary.arbitrary -import scala.concurrent.duration._ -import org.scalatest.compatible.Assertion + import io.iohk.ethereum.utils.MockClock +import Arbitrary.arbitrary + class TimeSlotStatsSpec extends AnyFlatSpec with Matchers with ScalaCheckDrivenPropertyChecks { import TimeSlotStatsSpec._ - behavior of "TimeSlotStats" + behavior.of("TimeSlotStats") it should "add new keys to the last timeslot" in test { for { stats <- add("foo", 1) - } yield { - stats.buffer(0).slotStats("foo") shouldBe 1 - } + } yield stats.buffer(0).slotStats("foo") shouldBe 1 } it should "merge keys in the last timeslot" in test { @@ -45,9 +49,7 @@ class TimeSlotStatsSpec extends AnyFlatSpec with Matchers with ScalaCheckDrivenP stats0 <- add("foo", 1) _ <- windClock(-defaultSlotDuration - 1.millis) stats1 <- add("foo", 2) - } yield { - stats0.buffer shouldBe stats1.buffer - } + } yield stats0.buffer shouldBe stats1.buffer } it should "add new slots for the next timeslot" in test { @@ -77,7 +79,7 @@ class TimeSlotStatsSpec extends AnyFlatSpec with Matchers with ScalaCheckDrivenP entry.slotStats should not contain key("foo") } Inspectors.forExactly(2, stats.buffer.values) { entry => - entry.slotStats should contain key ("bar") + (entry.slotStats should contain).key("bar") } } } @@ -98,7 +100,7 @@ class TimeSlotStatsSpec extends AnyFlatSpec with Matchers with ScalaCheckDrivenP } } - def testAggregate(f: TestState[String, Int, Assertion]) = test { + def testAggregate(f: TestState[String, Int, Assertion]): Unit = test { val setup = for { _ <- add("foo", 1) _ <- windClock(defaultSlotDuration * defaultSlotCount) // puts t0 out of scope @@ -128,27 +130,21 @@ class TimeSlotStatsSpec extends AnyFlatSpec with Matchers with ScalaCheckDrivenP it should "aggregate all stats" in testAggregate { for { stats <- getStats - } yield { - stats.getAll() shouldBe Map("foo" -> 3, "bar" -> 6) - } + } yield stats.getAll() shouldBe Map("foo" -> 3, "bar" -> 6) } it should "aggregate stats that still fall in the window" in testAggregate { for { _ <- windClock(defaultSlotDuration * 2) stats <- getStats - } yield { - stats.getAll() should not be empty - } + } yield stats.getAll() should not be empty } it should "not aggregate beyond the window" in testAggregate { for { _ <- windClock(defaultSlotDuration * (defaultSlotCount + 1)) stats <- getStats - } yield { - stats.getAll() shouldBe empty - } + } yield stats.getAll() shouldBe empty } it should "handle 0 in configuration" in { @@ -182,7 +178,7 @@ class TimeSlotStatsSpec extends AnyFlatSpec with Matchers with ScalaCheckDrivenP testRandomAggregation[Int, Vector[Int]](_ ++ _) } - def testRandomAggregation[K: Arbitrary, V: Arbitrary: Monoid](f: (V, V) => V): Unit = { + def testRandomAggregation[K: Arbitrary, V: Arbitrary: Monoid](f: (V, V) => V): Unit = forAll(genTimeSlotStats[K, V]) { case (stats, clock, window) => val timestamp = clock.millis() val (start, end) = stats.slotRange(timestamp, window) @@ -212,16 +208,15 @@ class TimeSlotStatsSpec extends AnyFlatSpec with Matchers with ScalaCheckDrivenP stats.get(key, Some(window)) shouldBe expected } } - } } object TimeSlotStatsSpec { - implicit val clock = new MockClock() + implicit val clock: MockClock = new MockClock() type TestState[K, V, A] = State[(TimeSlotStats[K, V], MockClock), A] - val defaultSlotDuration = 1.minute + val defaultSlotDuration: FiniteDuration = 1.minute val defaultSlotCount = 30 def getStats[K, V]: TestState[K, V, TimeSlotStats[K, V]] = diff --git a/src/test/scala/io/iohk/ethereum/network/discovery/PeerDiscoveryManagerSpec.scala b/src/test/scala/io/iohk/ethereum/network/discovery/PeerDiscoveryManagerSpec.scala index 746077f77a..11f4499928 100644 --- a/src/test/scala/io/iohk/ethereum/network/discovery/PeerDiscoveryManagerSpec.scala +++ b/src/test/scala/io/iohk/ethereum/network/discovery/PeerDiscoveryManagerSpec.scala @@ -1,29 +1,41 @@ package io.iohk.ethereum.network.discovery +import java.net.URI + import akka.actor.ActorSystem -import akka.pattern.{AskTimeoutException, ask} -import akka.testkit.{TestActorRef, TestKit} -import akka.util.{ByteString, Timeout} +import akka.pattern.AskTimeoutException +import akka.pattern.ask +import akka.testkit.TestActorRef +import akka.testkit.TestKit +import akka.util.ByteString +import akka.util.Timeout + import cats.effect.Resource -import io.iohk.ethereum.db.storage.KnownNodesStorage -import io.iohk.ethereum.utils.Config -import io.iohk.ethereum.{NormalPatience, WithActorSystemShutDown} -import io.iohk.scalanet.discovery.crypto.PublicKey -import io.iohk.scalanet.discovery.ethereum.v4.DiscoveryService -import io.iohk.scalanet.discovery.ethereum.{Node => ENode} + import monix.eval.Task import monix.execution.Scheduler import monix.execution.atomic.AtomicInt + +import scala.collection.immutable.SortedSet +import scala.concurrent.Future +import scala.concurrent.duration._ +import scala.math.Ordering.Implicits._ +import scala.util.control.NoStackTrace + +import io.iohk.scalanet.discovery.crypto.PublicKey +import io.iohk.scalanet.discovery.ethereum.v4.DiscoveryService +import io.iohk.scalanet.discovery.ethereum.{Node => ENode} import org.scalamock.scalatest.MockFactory -import org.scalatest.concurrent.{Eventually, ScalaFutures} +import org.scalatest.concurrent.Eventually +import org.scalatest.concurrent.ScalaFutures import org.scalatest.flatspec.AnyFlatSpecLike import org.scalatest.matchers.should.Matchers import scodec.bits.BitVector -import scala.collection.immutable.SortedSet -import scala.concurrent.duration._ -import scala.util.control.NoStackTrace -import scala.math.Ordering.Implicits._ +import io.iohk.ethereum.NormalPatience +import io.iohk.ethereum.WithActorSystemShutDown +import io.iohk.ethereum.db.storage.KnownNodesStorage +import io.iohk.ethereum.utils.Config class PeerDiscoveryManagerSpec extends TestKit(ActorSystem("PeerDiscoveryManagerSpec_System")) @@ -35,29 +47,30 @@ class PeerDiscoveryManagerSpec with ScalaFutures with NormalPatience { - implicit val scheduler = Scheduler.Implicits.global + implicit val scheduler: Scheduler = Scheduler.Implicits.global implicit val timeout: Timeout = 1.second - val defaultConfig = DiscoveryConfig(Config.config, bootstrapNodes = Set.empty) + val defaultConfig: DiscoveryConfig = DiscoveryConfig(Config.config, bootstrapNodes = Set.empty) - val sampleKnownUris = Set( + val sampleKnownUris: Set[URI] = Set( "enode://a59e33ccd2b3e52d578f1fbd70c6f9babda2650f0760d6ff3b37742fdcdfdb3defba5d56d315b40c46b70198c7621e63ffa3f987389c7118634b0fefbbdfa7fd@51.158.191.43:38556?discport=38556", "enode://651b484b652c07c72adebfaaf8bc2bd95b420b16952ef3de76a9c00ef63f07cca02a20bd2363426f9e6fe372cef96a42b0fec3c747d118f79fd5e02f2a4ebd4e@51.158.190.99:45678?discport=45678", "enode://9b1bf9613d859ac2071d88509ab40a111b75c1cfc51f4ad78a1fdbb429ff2405de0dc5ea8ae75e6ac88e03e51a465f0b27b517e78517f7220ae163a2e0692991@51.158.190.99:30426?discport=30426" ).map(new java.net.URI(_)) - val sampleNodes = Set( + val sampleNodes: Set[Node] = Set( "enode://111bd28d5b2c1378d748383fd83ff59572967c317c3063a9f475a26ad3f1517642a164338fb5268d4e32ea1cc48e663bd627dec572f1d201c7198518e5a506b1@88.99.216.30:45834?discport=45834", "enode://2b69a3926f36a7748c9021c34050be5e0b64346225e477fe7377070f6289bd363b2be73a06010fd516e6ea3ee90778dd0399bc007bb1281923a79374f842675a@51.15.116.226:30303?discport=30303" ).map(new java.net.URI(_)).map(Node.fromUri) trait Fixture { lazy val discoveryConfig = defaultConfig - lazy val knownNodesStorage = mock[KnownNodesStorage] - lazy val discoveryService = mock[DiscoveryService] - lazy val discoveryServiceResource = Resource.pure[Task, DiscoveryService](discoveryService) + lazy val knownNodesStorage: KnownNodesStorage = mock[KnownNodesStorage] + lazy val discoveryService: DiscoveryService = mock[DiscoveryService] + lazy val discoveryServiceResource: Resource[Task, DiscoveryService] = + Resource.pure[Task, DiscoveryService](discoveryService) - lazy val peerDiscoveryManager = + lazy val peerDiscoveryManager: TestActorRef[PeerDiscoveryManager] = TestActorRef[PeerDiscoveryManager]( PeerDiscoveryManager.props( localNodeId = ByteString.fromString("test-node"), @@ -67,24 +80,20 @@ class PeerDiscoveryManagerSpec ) ) - def getPeers = + def getPeers: Future[PeerDiscoveryManager.DiscoveredNodesInfo] = (peerDiscoveryManager ? PeerDiscoveryManager.GetDiscoveredNodesInfo) .mapTo[PeerDiscoveryManager.DiscoveredNodesInfo] - def getRandomPeer = + def getRandomPeer: Future[PeerDiscoveryManager.RandomNodeInfo] = (peerDiscoveryManager ? PeerDiscoveryManager.GetRandomNodeInfo) .mapTo[PeerDiscoveryManager.RandomNodeInfo] def test(): Unit } - def test(fixture: Fixture): Unit = { - try { - fixture.test() - } finally { - system.stop(fixture.peerDiscoveryManager) - } - } + def test(fixture: Fixture): Unit = + try fixture.test() + finally system.stop(fixture.peerDiscoveryManager) def toENode(node: Node): ENode = ENode( @@ -92,16 +101,15 @@ class PeerDiscoveryManagerSpec address = ENode.Address(ip = node.addr, udpPort = node.udpPort, tcpPort = node.tcpPort) ) - behavior of "PeerDiscoveryManager" + behavior.of("PeerDiscoveryManager") it should "serve no peers if discovery is disabled and known peers are disabled and the manager isn't started" in test { new Fixture { override lazy val discoveryConfig = defaultConfig.copy(discoveryEnabled = false, reuseKnownNodes = false) - override def test(): Unit = { + override def test(): Unit = getPeers.futureValue.nodes shouldBe empty - } } } @@ -110,9 +118,8 @@ class PeerDiscoveryManagerSpec override lazy val discoveryConfig = defaultConfig.copy(discoveryEnabled = false, reuseKnownNodes = true, bootstrapNodes = sampleNodes) - override def test(): Unit = { - getPeers.futureValue.nodes should contain theSameElementsAs (sampleNodes) - } + override def test(): Unit = + getPeers.futureValue.nodes should contain theSameElementsAs sampleNodes } } @@ -126,9 +133,8 @@ class PeerDiscoveryManagerSpec .returning(sampleKnownUris) .once() - override def test(): Unit = { - getPeers.futureValue.nodes.map(_.toUri) should contain theSameElementsAs (sampleKnownUris) - } + override def test(): Unit = + getPeers.futureValue.nodes.map(_.toUri) should contain theSameElementsAs sampleKnownUris } } @@ -152,7 +158,7 @@ class PeerDiscoveryManagerSpec override def test(): Unit = { peerDiscoveryManager ! PeerDiscoveryManager.Start eventually { - getPeers.futureValue.nodes.map(_.toUri) should contain theSameElementsAs (expected) + getPeers.futureValue.nodes.map(_.toUri) should contain theSameElementsAs expected } } } @@ -243,9 +249,8 @@ class PeerDiscoveryManagerSpec val expectedLookups = Range.inclusive(3, 4) val lookupCount = AtomicInt(0) - implicit val nodeOrd: Ordering[ENode] = { + implicit val nodeOrd: Ordering[ENode] = Ordering.by(_.id.toByteArray.toSeq) - } (discoveryService.lookup _) .expects(*) @@ -261,7 +266,7 @@ class PeerDiscoveryManagerSpec eventually { val n0 = getRandomPeer.futureValue.node val n1 = getRandomPeer.futureValue.node - val n2 = getRandomPeer.futureValue.node + getRandomPeer.futureValue.node Set(n0, n1) shouldBe randomNodes } @@ -282,9 +287,8 @@ class PeerDiscoveryManagerSpec .returning(sampleKnownUris) .once() - override def test(): Unit = { + override def test(): Unit = getRandomPeer.failed.futureValue shouldBe an[AskTimeoutException] - } } } } diff --git a/src/test/scala/io/iohk/ethereum/network/discovery/Secp256k1SigAlgSpec.scala b/src/test/scala/io/iohk/ethereum/network/discovery/Secp256k1SigAlgSpec.scala index f230a8adfa..8c160109f2 100644 --- a/src/test/scala/io/iohk/ethereum/network/discovery/Secp256k1SigAlgSpec.scala +++ b/src/test/scala/io/iohk/ethereum/network/discovery/Secp256k1SigAlgSpec.scala @@ -1,12 +1,13 @@ package io.iohk.ethereum.network.discovery +import scala.util.Random + import org.scalatest.flatspec.AnyFlatSpec import org.scalatest.matchers.should.Matchers import scodec.bits.BitVector -import scala.util.Random class Secp256k1SigAlgSpec extends AnyFlatSpec with Matchers { - behavior of "Secp256k1SigAlg" + behavior.of("Secp256k1SigAlg") val sigalg = new Secp256k1SigAlg diff --git a/src/test/scala/io/iohk/ethereum/network/discovery/codecs/EIP8CodecsSpec.scala b/src/test/scala/io/iohk/ethereum/network/discovery/codecs/EIP8CodecsSpec.scala index 89e5360557..b7d53a3975 100644 --- a/src/test/scala/io/iohk/ethereum/network/discovery/codecs/EIP8CodecsSpec.scala +++ b/src/test/scala/io/iohk/ethereum/network/discovery/codecs/EIP8CodecsSpec.scala @@ -1,14 +1,18 @@ package io.iohk.ethereum.network.discovery.codecs -import org.scalatest.matchers.should.Matchers -import org.scalatest.flatspec.AnyFlatSpec -import io.iohk.scalanet.discovery.ethereum.v4.{Packet, Payload} -import io.iohk.scalanet.discovery.crypto.{SigAlg, PrivateKey} -import io.iohk.ethereum.network.discovery.Secp256k1SigAlg -import scodec.bits.BitVector -import scodec.Codec import java.net.InetAddress + +import io.iohk.scalanet.discovery.crypto.PrivateKey +import io.iohk.scalanet.discovery.crypto.SigAlg +import io.iohk.scalanet.discovery.ethereum.v4.Packet +import io.iohk.scalanet.discovery.ethereum.v4.Payload import org.scalatest.compatible.Assertion +import org.scalatest.flatspec.AnyFlatSpec +import org.scalatest.matchers.should.Matchers +import scodec.Codec +import scodec.bits.BitVector + +import io.iohk.ethereum.network.discovery.Secp256k1SigAlg class EIP8CodecsSpec extends AnyFlatSpec with Matchers { @@ -19,9 +23,9 @@ class EIP8CodecsSpec extends AnyFlatSpec with Matchers { implicit val sigalg: SigAlg = new Secp256k1SigAlg - val localhost = InetAddress.getByName("127.0.0.1") + val localhost: InetAddress = InetAddress.getByName("127.0.0.1") - behavior of "RLPCodecs with the EIP8 test vectors" + behavior.of("RLPCodecs with the EIP8 test vectors") // Test vectors from https://github.com/ethereum/EIPs/blob/b883968936d83aa1c458d48fdc81bc59e8095da5/EIPS/eip-8.md#rlpx-discovery-protocol case class EIP8TestVector( @@ -29,7 +33,7 @@ class EIP8CodecsSpec extends AnyFlatSpec with Matchers { data: String, test: Payload => Assertion ) - val EIP8TestVectors = Vector( + val EIP8TestVectors: Vector[EIP8TestVector] = Vector( EIP8TestVector( "ping packet with version 4, additional list elements", """ @@ -140,7 +144,7 @@ class EIP8CodecsSpec extends AnyFlatSpec with Matchers { // See if it survives a roundtrip. val bits2 = Codec[Packet].encode(Packet.pack(payload, privateKey).require).require - val packet2 = Codec[Packet].decodeValue(bits2).require + Codec[Packet].decodeValue(bits2).require val (payload2, publicKey2) = Packet.unpack(packet).require payload2 shouldBe payload diff --git a/src/test/scala/io/iohk/ethereum/network/discovery/codecs/ENRCodecsSpec.scala b/src/test/scala/io/iohk/ethereum/network/discovery/codecs/ENRCodecsSpec.scala index 8d7a19ded6..04b2654b7c 100644 --- a/src/test/scala/io/iohk/ethereum/network/discovery/codecs/ENRCodecsSpec.scala +++ b/src/test/scala/io/iohk/ethereum/network/discovery/codecs/ENRCodecsSpec.scala @@ -1,21 +1,31 @@ package io.iohk.ethereum.network.discovery.codecs -import org.scalatest.matchers.should.Matchers -import org.scalatest.flatspec.AnyFlatSpec -import io.iohk.scalanet.discovery.ethereum.{Node, EthereumNodeRecord} +import java.net.InetAddress + +import scala.language.implicitConversions + +import io.iohk.scalanet.discovery.crypto.PrivateKey +import io.iohk.scalanet.discovery.crypto.PublicKey +import io.iohk.scalanet.discovery.crypto.SigAlg +import io.iohk.scalanet.discovery.ethereum.EthereumNodeRecord +import io.iohk.scalanet.discovery.ethereum.Node import io.iohk.scalanet.discovery.ethereum.v4.Payload.ENRResponse -import io.iohk.scalanet.discovery.crypto.{SigAlg, PrivateKey, PublicKey} -import io.iohk.scalanet.discovery.hash.{Hash, Keccak256} +import io.iohk.scalanet.discovery.hash.Hash +import io.iohk.scalanet.discovery.hash.Keccak256 +import org.scalatest.flatspec.AnyFlatSpec +import org.scalatest.matchers.should.Matchers +import scodec.bits.ByteVector +import scodec.bits.HexStringSyntax + import io.iohk.ethereum.network.discovery.Secp256k1SigAlg import io.iohk.ethereum.rlp -import io.iohk.ethereum.rlp.{RLPList, RLPEncoder, RLPValue} -import io.iohk.ethereum.rlp.RLPImplicits._ -import io.iohk.ethereum.rlp.RLPImplicitConversions._ -import scodec.bits.{ByteVector, HexStringSyntax} -import java.net.InetAddress -import io.iohk.ethereum.rlp.RLPEncodeable import io.iohk.ethereum.rlp.RLPDecoder -import scala.language.implicitConversions +import io.iohk.ethereum.rlp.RLPEncodeable +import io.iohk.ethereum.rlp.RLPEncoder +import io.iohk.ethereum.rlp.RLPImplicitConversions._ +import io.iohk.ethereum.rlp.RLPImplicits._ +import io.iohk.ethereum.rlp.RLPList +import io.iohk.ethereum.rlp.RLPValue class ENRCodecsSpec extends AnyFlatSpec with Matchers { @@ -23,18 +33,20 @@ class ENRCodecsSpec extends AnyFlatSpec with Matchers { implicit val sigalg: SigAlg = new Secp256k1SigAlg - val localhost = InetAddress.getByName("127.0.0.1") + val localhost: InetAddress = InetAddress.getByName("127.0.0.1") - behavior of "RLPCodecs with ENR" + behavior.of("RLPCodecs with ENR") // https://github.com/ethereum/devp2p/blob/master/enr.md#test-vectors - val nodeId = Hash(hex"a448f24c6d18e575453db13171562b71999873db5b286df957af199ec94617f7".toBitVector) - val privateKey = PrivateKey(hex"b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291".toBitVector) - val publicKey = sigalg.toPublicKey(privateKey) + val nodeId: Hash.Tagged = Hash(hex"a448f24c6d18e575453db13171562b71999873db5b286df957af199ec94617f7".toBitVector) + val privateKey: PrivateKey.Tagged = PrivateKey( + hex"b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291".toBitVector + ) + val publicKey: io.iohk.scalanet.discovery.crypto.PublicKey = sigalg.toPublicKey(privateKey) val enrString = "enr:-IS4QHCYrYZbAKWCBRlAy5zzaDZXJBGkcnh4MHcBFZntXNFrdvJjX04jRzjzCBOonrkTfj499SZuOh8R33Ls8RRcy5wBgmlkgnY0gmlwhH8AAAGJc2VjcDI1NmsxoQPKY0yuDUmstAHYpMa2_oxVtw0RW_QAdpzBQA8yWM0xOIN1ZHCCdl8" - val enrRLP = RLPList( + val enrRLP: RLPList = RLPList( hex"7098ad865b00a582051940cb9cf36836572411a47278783077011599ed5cd16b76f2635f4e234738f30813a89eb9137e3e3df5266e3a1f11df72ecf1145ccb9c", 1L, "id", @@ -72,7 +84,7 @@ class ENRCodecsSpec extends AnyFlatSpec with Matchers { // .toString hack used because RLPValue has mutable arrays in it where equality doesn't work. val encoded = a.map(_.toString).toList val expected = b.map(_.toString).toList - encoded should contain theSameElementsInOrderAs expected + (encoded should contain).theSameElementsInOrderAs(expected) } // Ignoring the signature, taking items up to where "tcp" would be. diff --git a/src/test/scala/io/iohk/ethereum/network/discovery/codecs/RLPCodecsSpec.scala b/src/test/scala/io/iohk/ethereum/network/discovery/codecs/RLPCodecsSpec.scala index 38b24a0fa2..88d6d8142d 100644 --- a/src/test/scala/io/iohk/ethereum/network/discovery/codecs/RLPCodecsSpec.scala +++ b/src/test/scala/io/iohk/ethereum/network/discovery/codecs/RLPCodecsSpec.scala @@ -1,32 +1,42 @@ package io.iohk.ethereum.network.discovery.codecs -import org.scalatest.matchers.should.Matchers -import org.scalatest.flatspec.AnyFlatSpec +import java.net.InetAddress + +import scala.reflect.ClassTag +import scala.util.Random + +import _root_.io.iohk.ethereum.rlp.RLPException import io.iohk.scalanet.discovery.crypto.PublicKey +import io.iohk.scalanet.discovery.ethereum.EthereumNodeRecord +import io.iohk.scalanet.discovery.ethereum.Node +import io.iohk.scalanet.discovery.ethereum.v4.Packet +import io.iohk.scalanet.discovery.ethereum.v4.Payload import io.iohk.scalanet.discovery.hash.Hash -import io.iohk.scalanet.discovery.ethereum.{Node, EthereumNodeRecord} -import io.iohk.scalanet.discovery.ethereum.v4.{Packet, Payload} -import io.iohk.ethereum.network.discovery.Secp256k1SigAlg -import io.iohk.ethereum.rlp.{RLPList, RLPEncoder, RLPDecoder, RLPValue, RLPEncodeable} +import org.scalactic.Equality +import org.scalatest.Assertion +import org.scalatest.flatspec.AnyFlatSpec +import org.scalatest.matchers.should.Matchers import scodec.Codec import scodec.bits.BitVector -import java.net.InetAddress -import scala.util.Random -import org.scalactic.Equality -import scala.reflect.ClassTag -import _root_.io.iohk.ethereum.rlp.RLPException + +import io.iohk.ethereum.network.discovery.Secp256k1SigAlg +import io.iohk.ethereum.rlp.RLPDecoder +import io.iohk.ethereum.rlp.RLPEncodeable +import io.iohk.ethereum.rlp.RLPEncoder +import io.iohk.ethereum.rlp.RLPList +import io.iohk.ethereum.rlp.RLPValue class RLPCodecsSpec extends AnyFlatSpec with Matchers { import io.iohk.ethereum.rlp.RLPImplicitConversions._ import io.iohk.ethereum.rlp.RLPImplicits._ import RLPCodecs._ - implicit val sigalg = new Secp256k1SigAlg() + implicit val sigalg: Secp256k1SigAlg = new Secp256k1SigAlg() implicit val packetCodec: Codec[Packet] = Packet.packetCodec(allowDecodeOverMaxPacketSize = false) - val localhost = InetAddress.getByName("127.0.0.1") + val localhost: InetAddress = InetAddress.getByName("127.0.0.1") def randomBytes(n: Int): BitVector = { val size = Random.nextInt(n) @@ -35,7 +45,7 @@ class RLPCodecsSpec extends AnyFlatSpec with Matchers { BitVector(bytes) } - behavior of "RLPCodecs" + behavior.of("RLPCodecs") it should "encode a Ping with an ENR as 5 items" in { val ping = Payload.Ping( @@ -113,7 +123,7 @@ class RLPCodecsSpec extends AnyFlatSpec with Matchers { // Structrual equality checker for RLPEncodeable. // It has different wrappers for items based on whether it was hand crafted or generated // by codecs, and the RLPValue has mutable arrays inside. - implicit val eqRLPList = new Equality[RLPEncodeable] { + implicit val eqRLPList: Equality[RLPEncodeable] = new Equality[RLPEncodeable] { override def areEqual(a: RLPEncodeable, b: Any): Boolean = (a, b) match { case (a: RLPList, b: RLPList) => @@ -127,16 +137,16 @@ class RLPCodecsSpec extends AnyFlatSpec with Matchers { } } - def name = implicitly[ClassTag[T]].runtimeClass.getSimpleName + def name: String = implicitly[ClassTag[T]].runtimeClass.getSimpleName def p: T def e: RLPEncodeable - def testEncode = RLPEncoder.encode(p) should equal(e) - def testDecode = RLPDecoder.decode[T](e) should equal(p) + def testEncode: Assertion = RLPEncoder.encode(p) should equal(e) + def testDecode: Assertion = RLPDecoder.decode[T](e) should equal(p) } - val examples = List( + val examples: List[RLPFixture[_ <: Payload]] = List( new RLPFixture[Payload.Ping] { override val p = Payload.Ping( version = 4, diff --git a/src/test/scala/io/iohk/ethereum/network/handshaker/EtcHandshakerSpec.scala b/src/test/scala/io/iohk/ethereum/network/handshaker/EtcHandshakerSpec.scala index a78fc25218..88d64f46f3 100644 --- a/src/test/scala/io/iohk/ethereum/network/handshaker/EtcHandshakerSpec.scala +++ b/src/test/scala/io/iohk/ethereum/network/handshaker/EtcHandshakerSpec.scala @@ -3,27 +3,36 @@ package io.iohk.ethereum.network.handshaker import java.util.concurrent.atomic.AtomicReference import akka.util.ByteString + +import org.scalatest.flatspec.AnyFlatSpec +import org.scalatest.matchers.should.Matchers + import io.iohk.ethereum.Fixtures import io.iohk.ethereum.blockchain.sync.EphemBlockchainTestSetup import io.iohk.ethereum.crypto.generateKeyPair import io.iohk.ethereum.db.storage.AppStateStorage import io.iohk.ethereum.domain._ -import io.iohk.ethereum.network.EtcPeerManagerActor.{PeerInfo, RemoteStatus} +import io.iohk.ethereum.network.EtcPeerManagerActor.PeerInfo +import io.iohk.ethereum.network.EtcPeerManagerActor.RemoteStatus import io.iohk.ethereum.network.ForkResolver import io.iohk.ethereum.network.PeerManagerActor.PeerConfiguration -import io.iohk.ethereum.network.handshaker.Handshaker.HandshakeComplete.{HandshakeFailure, HandshakeSuccess} -import io.iohk.ethereum.network.p2p.messages.Capability.Capabilities._ +import io.iohk.ethereum.network.handshaker.Handshaker.HandshakeComplete.HandshakeFailure +import io.iohk.ethereum.network.handshaker.Handshaker.HandshakeComplete.HandshakeSuccess +import io.iohk.ethereum.network.p2p.messages.BaseETH6XMessages import io.iohk.ethereum.network.p2p.messages.BaseETH6XMessages.Status.StatusEnc +import io.iohk.ethereum.network.p2p.messages.Capability +import io.iohk.ethereum.network.p2p.messages.Capability.Capabilities._ +import io.iohk.ethereum.network.p2p.messages.ETC64 +import io.iohk.ethereum.network.p2p.messages.ETH62.BlockHeaders +import io.iohk.ethereum.network.p2p.messages.ETH62.GetBlockHeaders import io.iohk.ethereum.network.p2p.messages.ETH62.GetBlockHeaders.GetBlockHeadersEnc -import io.iohk.ethereum.network.p2p.messages.ETH62.{BlockHeaders, GetBlockHeaders} +import io.iohk.ethereum.network.p2p.messages.ProtocolVersions +import io.iohk.ethereum.network.p2p.messages.WireProtocol.Disconnect +import io.iohk.ethereum.network.p2p.messages.WireProtocol.Hello import io.iohk.ethereum.network.p2p.messages.WireProtocol.Hello.HelloEnc -import io.iohk.ethereum.network.p2p.messages.WireProtocol.{Disconnect, Hello} -import io.iohk.ethereum.network.p2p.messages.{Capability, BaseETH6XMessages, ETC64, ProtocolVersions} -import io.iohk.ethereum.utils._ import io.iohk.ethereum.security.SecureRandomBuilder import io.iohk.ethereum.utils.ByteStringUtils._ -import org.scalatest.flatspec.AnyFlatSpec -import org.scalatest.matchers.should.Matchers +import io.iohk.ethereum.utils._ class EtcHandshakerSpec extends AnyFlatSpec with Matchers { @@ -251,18 +260,18 @@ class EtcHandshakerSpec extends AnyFlatSpec with Matchers { trait TestSetup extends SecureRandomBuilder with EphemBlockchainTestSetup { - val genesisBlock = Block( + val genesisBlock: Block = Block( Fixtures.Blocks.Genesis.header, Fixtures.Blocks.Genesis.body ) - val genesisWeight = ChainWeight.zero.increase(genesisBlock.header) + val genesisWeight: ChainWeight = ChainWeight.zero.increase(genesisBlock.header) val forkBlockHeader = Fixtures.Blocks.DaoForkBlock.header blockchain.save(genesisBlock, Nil, genesisWeight, saveAsBestBlock = true) - val nodeStatus = NodeStatus( + val nodeStatus: NodeStatus = NodeStatus( key = generateKeyPair(secureRandom), serverStatus = ServerStatus.NotListening, discoveryStatus = ServerStatus.NotListening @@ -280,24 +289,24 @@ class EtcHandshakerSpec extends AnyFlatSpec with Matchers { override val blockchainReader: BlockchainReader = TestSetup.this.blockchainReader } - val etcHandshakerConfigurationWithResolver = new MockEtcHandshakerConfiguration { + val etcHandshakerConfigurationWithResolver: MockEtcHandshakerConfiguration = new MockEtcHandshakerConfiguration { override val forkResolverOpt: Option[ForkResolver] = Some( new ForkResolver.EtcForkResolver(blockchainConfig.daoForkConfig.get) ) } - val initHandshakerWithoutResolver = EtcHandshaker( + val initHandshakerWithoutResolver: EtcHandshaker = EtcHandshaker( new MockEtcHandshakerConfiguration(List(ProtocolVersions.ETC64, ProtocolVersions.ETH63)) ) - val initHandshakerWithResolver = EtcHandshaker(etcHandshakerConfigurationWithResolver) + val initHandshakerWithResolver: EtcHandshaker = EtcHandshaker(etcHandshakerConfigurationWithResolver) - val firstBlock = + val firstBlock: Block = genesisBlock.copy(header = genesisBlock.header.copy(parentHash = genesisBlock.header.hash, number = 1)) } trait LocalPeerSetup extends TestSetup { - val localHello = Hello( + val localHello: Hello = Hello( p2pVersion = EtcHelloExchangeState.P2pVersion, clientId = Config.clientId, capabilities = Seq(Etc64Capability, Eth63Capability), @@ -305,34 +314,34 @@ class EtcHandshakerSpec extends AnyFlatSpec with Matchers { nodeId = ByteString(nodeStatus.nodeId) ) - val localGetBlockHeadersRequest = + val localGetBlockHeadersRequest: GetBlockHeaders = GetBlockHeaders(Left(forkBlockHeader.number), maxHeaders = 1, skip = 0, reverse = false) } trait LocalPeerETH63Setup extends LocalPeerSetup { - val localStatusMsg = BaseETH6XMessages.Status( + val localStatusMsg: BaseETH6XMessages.Status = BaseETH6XMessages.Status( protocolVersion = ProtocolVersions.ETH63.version, networkId = Config.Network.peer.networkId, totalDifficulty = genesisBlock.header.difficulty, bestHash = genesisBlock.header.hash, genesisHash = genesisBlock.header.hash ) - val localStatus = RemoteStatus(localStatusMsg) + val localStatus: RemoteStatus = RemoteStatus(localStatusMsg) } trait LocalPeerETC64Setup extends LocalPeerSetup { - val localStatusMsg = ETC64.Status( + val localStatusMsg: ETC64.Status = ETC64.Status( protocolVersion = ProtocolVersions.ETC64.version, networkId = Config.Network.peer.networkId, chainWeight = ChainWeight.zero.increase(genesisBlock.header), bestHash = genesisBlock.header.hash, genesisHash = genesisBlock.header.hash ) - val localStatus = RemoteStatus(localStatusMsg) + val localStatus: RemoteStatus = RemoteStatus(localStatusMsg) } trait RemotePeerSetup extends TestSetup { - val remoteNodeStatus = NodeStatus( + val remoteNodeStatus: NodeStatus = NodeStatus( key = generateKeyPair(secureRandom), serverStatus = ServerStatus.NotListening, discoveryStatus = ServerStatus.NotListening @@ -341,7 +350,7 @@ class EtcHandshakerSpec extends AnyFlatSpec with Matchers { } trait RemotePeerETH63Setup extends RemotePeerSetup { - val remoteHello = Hello( + val remoteHello: Hello = Hello( p2pVersion = EtcHelloExchangeState.P2pVersion, clientId = "remote-peer", capabilities = Seq(Eth63Capability), @@ -349,7 +358,7 @@ class EtcHandshakerSpec extends AnyFlatSpec with Matchers { nodeId = ByteString(remoteNodeStatus.nodeId) ) - val remoteStatusMsg = BaseETH6XMessages.Status( + val remoteStatusMsg: BaseETH6XMessages.Status = BaseETH6XMessages.Status( protocolVersion = ProtocolVersions.ETH63.version, networkId = Config.Network.peer.networkId, totalDifficulty = 0, @@ -357,11 +366,11 @@ class EtcHandshakerSpec extends AnyFlatSpec with Matchers { genesisHash = genesisBlock.header.hash ) - val remoteStatus = RemoteStatus(remoteStatusMsg) + val remoteStatus: RemoteStatus = RemoteStatus(remoteStatusMsg) } trait RemotePeerETC64Setup extends RemotePeerSetup { - val remoteHello = Hello( + val remoteHello: Hello = Hello( p2pVersion = EtcHelloExchangeState.P2pVersion, clientId = "remote-peer", capabilities = Seq(Etc64Capability, Eth63Capability), @@ -369,7 +378,7 @@ class EtcHandshakerSpec extends AnyFlatSpec with Matchers { nodeId = ByteString(remoteNodeStatus.nodeId) ) - val remoteStatusMsg = + val remoteStatusMsg: ETC64.Status = ETC64.Status( protocolVersion = ProtocolVersions.ETC64.version, networkId = Config.Network.peer.networkId, diff --git a/src/test/scala/io/iohk/ethereum/network/p2p/FrameCodecSpec.scala b/src/test/scala/io/iohk/ethereum/network/p2p/FrameCodecSpec.scala index 7dd0694ad3..c1b7e9fd86 100644 --- a/src/test/scala/io/iohk/ethereum/network/p2p/FrameCodecSpec.scala +++ b/src/test/scala/io/iohk/ethereum/network/p2p/FrameCodecSpec.scala @@ -1,13 +1,20 @@ package io.iohk.ethereum.network.p2p import akka.util.ByteString -import io.iohk.ethereum.rlp.RLPImplicitConversions._ -import io.iohk.ethereum.rlp.RLPImplicits._ -import io.iohk.ethereum.network.rlpx.{Frame, FrameCodec, Header} -import io.iohk.ethereum.rlp.{RLPEncodeable, RLPList, RLPSerializable, rawDecode} + import org.scalatest.flatspec.AnyFlatSpec import org.scalatest.matchers.should.Matchers +import io.iohk.ethereum.network.rlpx.Frame +import io.iohk.ethereum.network.rlpx.FrameCodec +import io.iohk.ethereum.network.rlpx.Header +import io.iohk.ethereum.rlp.RLPEncodeable +import io.iohk.ethereum.rlp.RLPImplicitConversions._ +import io.iohk.ethereum.rlp.RLPImplicits._ +import io.iohk.ethereum.rlp.RLPList +import io.iohk.ethereum.rlp.RLPSerializable +import io.iohk.ethereum.rlp.rawDecode + class FrameCodecSpec extends AnyFlatSpec with Matchers { import DummyMsg._ @@ -43,7 +50,7 @@ class FrameCodecSpec extends AnyFlatSpec with Matchers { implicit class DummyMsgDec(val bytes: Array[Byte]) { def toSample: DummyMsg = rawDecode(bytes) match { case RLPList(aField, anotherField) => DummyMsg(aField, anotherField) - case _ => throw new RuntimeException("Cannot decode Status") + case _ => throw new RuntimeException("Cannot decode Status") } } } diff --git a/src/test/scala/io/iohk/ethereum/network/p2p/MessageCodecSpec.scala b/src/test/scala/io/iohk/ethereum/network/p2p/MessageCodecSpec.scala index 048b95a133..eb9979595e 100644 --- a/src/test/scala/io/iohk/ethereum/network/p2p/MessageCodecSpec.scala +++ b/src/test/scala/io/iohk/ethereum/network/p2p/MessageCodecSpec.scala @@ -1,22 +1,24 @@ package io.iohk.ethereum.network.p2p import akka.util.ByteString + +import org.scalatest.flatspec.AnyFlatSpec +import org.scalatest.matchers.should.Matchers + import io.iohk.ethereum.network.handshaker.EtcHelloExchangeState -import io.iohk.ethereum.network.handshaker.EtcHelloExchangeState.P2pVersion -import io.iohk.ethereum.network.p2p.messages.Capability.Capabilities._ import io.iohk.ethereum.network.p2p.messages.BaseETH6XMessages.Status +import io.iohk.ethereum.network.p2p.messages.Capability.Capabilities._ import io.iohk.ethereum.network.p2p.messages.ProtocolVersions import io.iohk.ethereum.network.p2p.messages.WireProtocol.Hello -import io.iohk.ethereum.network.rlpx.{FrameCodec, MessageCodec} +import io.iohk.ethereum.network.rlpx.FrameCodec +import io.iohk.ethereum.network.rlpx.MessageCodec import io.iohk.ethereum.utils.Config -import org.scalatest.flatspec.AnyFlatSpec -import org.scalatest.matchers.should.Matchers class MessageCodecSpec extends AnyFlatSpec with Matchers { it should "not compress messages when remote side advertises p2p version less than 5" in new TestSetup { val remoteHello = remoteMessageCodec.encodeMessage(helloV4) - val localReceivedRemoteHello = messageCodec.readMessages(remoteHello) + messageCodec.readMessages(remoteHello) val localNextMessageAfterHello = messageCodec.encodeMessage(status) val remoteReadNotCompressedStatus = remoteMessageCodec.readMessages(localNextMessageAfterHello) @@ -31,7 +33,7 @@ class MessageCodecSpec extends AnyFlatSpec with Matchers { override lazy val negotiatedLocalP2PVersion: Long = 4L val remoteHello = remoteMessageCodec.encodeMessage(helloV5) - val localReceivedRemoteHello = messageCodec.readMessages(remoteHello) + messageCodec.readMessages(remoteHello) val localNextMessageAfterHello = messageCodec.encodeMessage(status) val remoteReadNotCompressedStatus = remoteMessageCodec.readMessages(localNextMessageAfterHello) @@ -44,10 +46,10 @@ class MessageCodecSpec extends AnyFlatSpec with Matchers { it should "compress messages when both sides advertises p2p version larger or equal 5" in new TestSetup { val remoteHello = remoteMessageCodec.encodeMessage(helloV5) - val localReceivedRemoteHello = messageCodec.readMessages(remoteHello) + messageCodec.readMessages(remoteHello) val localHello = messageCodec.encodeMessage(helloV5) - val remoteReceivedLocalHello = remoteMessageCodec.readMessages(localHello) + remoteMessageCodec.readMessages(localHello) val localNextMessageAfterHello = messageCodec.encodeMessage(status) val remoteReadNextMessageAfterHello = remoteMessageCodec.readMessages(localNextMessageAfterHello) @@ -59,7 +61,7 @@ class MessageCodecSpec extends AnyFlatSpec with Matchers { it should "compress and decompress first message after hello when receiving 2 frames" in new TestSetup { val remoteHello = remoteMessageCodec.encodeMessage(helloV5) - val localReceivedRemoteHello = messageCodec.readMessages(remoteHello) + messageCodec.readMessages(remoteHello) // hello won't be compressed as per spec it never is, and status will be compressed as remote peer advertised proper versions val localHello = messageCodec.encodeMessage(helloV5) @@ -80,7 +82,7 @@ class MessageCodecSpec extends AnyFlatSpec with Matchers { lazy val negotiatedRemoteP2PVersion: Long = 5L lazy val negotiatedLocalP2PVersion: Long = 5L - val helloV5 = Hello( + val helloV5: Hello = Hello( p2pVersion = EtcHelloExchangeState.P2pVersion, clientId = Config.clientId, capabilities = Seq(Eth63Capability), @@ -88,9 +90,9 @@ class MessageCodecSpec extends AnyFlatSpec with Matchers { nodeId = ByteString(1) ) - val helloV4 = helloV5.copy(p2pVersion = 4) + val helloV4: Hello = helloV5.copy(p2pVersion = 4) - val status = Status( + val status: Status = Status( protocolVersion = ProtocolVersions.ETH63.version, networkId = Config.Network.peer.networkId, totalDifficulty = 1, @@ -98,7 +100,8 @@ class MessageCodecSpec extends AnyFlatSpec with Matchers { genesisHash = ByteString(1) ) - val decoder = NetworkMessageDecoder.orElse(EthereumMessageDecoder.ethMessageDecoder(Eth63Capability)) + val decoder: MessageDecoder = + NetworkMessageDecoder.orElse(EthereumMessageDecoder.ethMessageDecoder(Eth63Capability)) val messageCodec = new MessageCodec(frameCodec, decoder, negotiatedLocalP2PVersion) val remoteMessageCodec = new MessageCodec(remoteFrameCodec, decoder, negotiatedRemoteP2PVersion) diff --git a/src/test/scala/io/iohk/ethereum/network/p2p/MessageDecodersSpec.scala b/src/test/scala/io/iohk/ethereum/network/p2p/MessageDecodersSpec.scala index 88d6cb04ff..5c3ca28455 100644 --- a/src/test/scala/io/iohk/ethereum/network/p2p/MessageDecodersSpec.scala +++ b/src/test/scala/io/iohk/ethereum/network/p2p/MessageDecodersSpec.scala @@ -1,21 +1,26 @@ package io.iohk.ethereum.network.p2p import akka.util.ByteString -import io.iohk.ethereum.{Fixtures, ObjectGenerators} + +import org.bouncycastle.util.encoders.Hex +import org.scalatest.flatspec.AnyFlatSpec +import org.scalatest.matchers.should.Matchers + +import io.iohk.ethereum.Fixtures +import io.iohk.ethereum.ObjectGenerators import io.iohk.ethereum.domain.ChainWeight -import io.iohk.ethereum.network.p2p.messages.Capability.Capabilities._ import io.iohk.ethereum.network.p2p.messages.BaseETH6XMessages.SignedTransactions +import io.iohk.ethereum.network.p2p.messages.Capability.Capabilities._ import io.iohk.ethereum.network.p2p.messages._ import io.iohk.ethereum.security.SecureRandomBuilder -import org.bouncycastle.util.encoders.Hex -import org.scalatest.flatspec.AnyFlatSpec -import org.scalatest.matchers.should.Matchers class MessageDecodersSpec extends AnyFlatSpec with Matchers with SecureRandomBuilder { def decode: Capability => MessageDecoder = EthereumMessageDecoder.ethMessageDecoder _ - val exampleHash = ByteString(Hex.decode("fccdbfe911f9df0a6cc0107d1240f76dfdd1d301b65fdc3cd2ae62752affbef6")) + val exampleHash: ByteString = ByteString( + Hex.decode("fccdbfe911f9df0a6cc0107d1240f76dfdd1d301b65fdc3cd2ae62752affbef6") + ) val blockHashesFromNumberBytes: Array[Byte] = Hex.decode("c20c28") diff --git a/src/test/scala/io/iohk/ethereum/network/p2p/PeerActorSpec.scala b/src/test/scala/io/iohk/ethereum/network/p2p/PeerActorSpec.scala index aa213898aa..e804824471 100644 --- a/src/test/scala/io/iohk/ethereum/network/p2p/PeerActorSpec.scala +++ b/src/test/scala/io/iohk/ethereum/network/p2p/PeerActorSpec.scala @@ -1,45 +1,66 @@ package io.iohk.ethereum.network.p2p -import java.net.{InetSocketAddress, URI} +import java.net.InetSocketAddress +import java.net.URI import java.security.SecureRandom import java.util.concurrent.atomic.AtomicReference -import akka.actor.{ActorSystem, PoisonPill, Props, Terminated} -import akka.testkit.{TestActorRef, TestKit, TestProbe} + +import akka.actor.ActorRef +import akka.actor.ActorSystem +import akka.actor.PoisonPill +import akka.actor.Props +import akka.actor.Terminated +import akka.testkit.TestActorRef +import akka.testkit.TestKit +import akka.testkit.TestProbe import akka.util.ByteString + +import scala.concurrent.duration._ +import scala.language.postfixOps + import com.miguno.akka.testing.VirtualTime +import org.bouncycastle.crypto.AsymmetricCipherKeyPair +import org.bouncycastle.crypto.params.ECPublicKeyParameters +import org.bouncycastle.util.encoders.Hex +import org.scalatest.flatspec.AnyFlatSpecLike +import org.scalatest.matchers.should.Matchers + import io.iohk.ethereum._ import io.iohk.ethereum.blockchain.sync.EphemBlockchainTestSetup import io.iohk.ethereum.crypto.generateKeyPair import io.iohk.ethereum.db.storage.AppStateStorage import io.iohk.ethereum.domain._ import io.iohk.ethereum.network.EtcPeerManagerActor.RemoteStatus +import io.iohk.ethereum.network.ForkResolver +import io.iohk.ethereum.network.PeerActor +import io.iohk.ethereum.network.PeerActor.GetStatus import io.iohk.ethereum.network.PeerActor.Status.Handshaked -import io.iohk.ethereum.network.PeerActor.{GetStatus, StatusResponse} -import io.iohk.ethereum.network.PeerManagerActor.{FastSyncHostConfiguration, PeerConfiguration} -import io.iohk.ethereum.network.handshaker.{EtcHandshaker, EtcHandshakerConfiguration} -import io.iohk.ethereum.network.p2p.messages.Capability.Capabilities._ +import io.iohk.ethereum.network.PeerActor.StatusResponse +import io.iohk.ethereum.network.PeerEventBusActor +import io.iohk.ethereum.network.PeerManagerActor.FastSyncHostConfiguration +import io.iohk.ethereum.network.PeerManagerActor.PeerConfiguration +import io.iohk.ethereum.network._ +import io.iohk.ethereum.network.handshaker.EtcHandshaker +import io.iohk.ethereum.network.handshaker.EtcHandshakerConfiguration import io.iohk.ethereum.network.p2p.messages.BaseETH6XMessages.Status import io.iohk.ethereum.network.p2p.messages.BaseETH6XMessages.Status.StatusEnc +import io.iohk.ethereum.network.p2p.messages.Capability +import io.iohk.ethereum.network.p2p.messages.Capability.Capabilities._ +import io.iohk.ethereum.network.p2p.messages.ETC64 import io.iohk.ethereum.network.p2p.messages.ETH62.GetBlockHeaders.GetBlockHeadersEnc import io.iohk.ethereum.network.p2p.messages.ETH62._ -import io.iohk.ethereum.network.p2p.messages.{Capability, ETC64, ProtocolVersions} -import io.iohk.ethereum.network.p2p.messages.WireProtocol.Disconnect.{DisconnectEnc, Reasons} +import io.iohk.ethereum.network.p2p.messages.ProtocolVersions +import io.iohk.ethereum.network.p2p.messages.WireProtocol.Disconnect.DisconnectEnc +import io.iohk.ethereum.network.p2p.messages.WireProtocol.Disconnect.Reasons import io.iohk.ethereum.network.p2p.messages.WireProtocol.Hello.HelloEnc import io.iohk.ethereum.network.p2p.messages.WireProtocol.Pong.PongEnc import io.iohk.ethereum.network.p2p.messages.WireProtocol._ import io.iohk.ethereum.network.rlpx.RLPxConnectionHandler import io.iohk.ethereum.network.rlpx.RLPxConnectionHandler.RLPxConfiguration -import io.iohk.ethereum.network.{ForkResolver, PeerActor, PeerEventBusActor, _} import io.iohk.ethereum.security.SecureRandomBuilder -import io.iohk.ethereum.utils.{Config, NodeStatus, ServerStatus} -import org.bouncycastle.crypto.AsymmetricCipherKeyPair -import org.bouncycastle.crypto.params.ECPublicKeyParameters -import org.bouncycastle.util.encoders.Hex -import org.scalatest.flatspec.AnyFlatSpecLike -import org.scalatest.matchers.should.Matchers - -import scala.concurrent.duration._ -import scala.language.postfixOps +import io.iohk.ethereum.utils.Config +import io.iohk.ethereum.utils.NodeStatus +import io.iohk.ethereum.utils.ServerStatus class PeerActorSpec extends TestKit(ActorSystem("PeerActorSpec_System")) @@ -68,7 +89,7 @@ class PeerActorSpec rlpxConnection.watch(peer) - (0 to 3) foreach { _ => + (0 to 3).foreach { _ => time.advance(5.seconds) rlpxConnection.expectMsgClass(classOf[RLPxConnectionHandler.ConnectTo]) rlpxConnection.reply(RLPxConnectionHandler.ConnectionFailed) @@ -78,7 +99,7 @@ class PeerActorSpec } it should "try to reconnect on broken rlpx connection" in new NodeStatusSetup with HandshakerSetup { - override implicit lazy val system = ActorSystem("PeerActorSpec_System") + implicit override lazy val system = ActorSystem("PeerActorSpec_System") override def protocol: Capability = ProtocolVersions.ETH63 val time = new VirtualTime @@ -160,7 +181,7 @@ class PeerActorSpec it should "fail handshake with peer that has a wrong genesis hash" in new TestSetup { val uri = new URI(s"enode://${Hex.toHexString(remoteNodeId.toArray[Byte])}@localhost:9000") - val completeUri = new URI(s"enode://${Hex.toHexString(remoteNodeId.toArray[Byte])}@127.0.0.1:9000?discport=9000") + new URI(s"enode://${Hex.toHexString(remoteNodeId.toArray[Byte])}@127.0.0.1:9000?discport=9000") peer ! PeerActor.ConnectTo(uri) peer ! PeerActor.ConnectTo(uri) @@ -491,7 +512,7 @@ class PeerActorSpec val etcForkBlockHeader = Fixtures.Blocks.DaoForkBlock.header - val nonEtcForkBlockHeader = + val nonEtcForkBlockHeader: BlockHeader = etcForkBlockHeader.copy( parentHash = ByteString("this"), ommersHash = ByteString("is"), @@ -504,21 +525,21 @@ class PeerActorSpec } trait NodeStatusSetup extends SecureRandomBuilder with EphemBlockchainTestSetup { - override lazy val nodeKey = crypto.generateKeyPair(secureRandom) + override lazy val nodeKey: AsymmetricCipherKeyPair = crypto.generateKeyPair(secureRandom) - val nodeStatus = + val nodeStatus: NodeStatus = NodeStatus(key = nodeKey, serverStatus = ServerStatus.NotListening, discoveryStatus = ServerStatus.NotListening) val nodeStatusHolder = new AtomicReference(nodeStatus) val genesisBlock = Fixtures.Blocks.Genesis.block - val genesisWeight = ChainWeight.totalDifficultyOnly(genesisBlock.header.difficulty) + val genesisWeight: ChainWeight = ChainWeight.totalDifficultyOnly(genesisBlock.header.difficulty) blockchain.save(genesisBlock, Nil, genesisWeight, saveAsBestBlock = true) val daoForkBlockNumber = 1920000 - val peerConf = new PeerConfiguration { + val peerConf: PeerConfiguration = new PeerConfiguration { override val fastSyncHostConfiguration: FastSyncHostConfiguration = new FastSyncHostConfiguration { val maxBlocksHeadersPerMessage: Int = 200 val maxBlocksBodiesPerMessage: Int = 200 @@ -556,7 +577,7 @@ class PeerActorSpec trait HandshakerSetup extends NodeStatusSetup { self => def protocol: Capability - val handshakerConfiguration = new EtcHandshakerConfiguration { + val handshakerConfiguration: EtcHandshakerConfiguration = new EtcHandshakerConfiguration { override val forkResolverOpt: Option[ForkResolver] = Some( new ForkResolver.EtcForkResolver(self.blockchainConfig.daoForkConfig.get) ) @@ -568,7 +589,7 @@ class PeerActorSpec override val capabilities: List[Capability] = List(protocol) } - val handshaker = EtcHandshaker(handshakerConfiguration) + val handshaker: EtcHandshaker = EtcHandshaker(handshakerConfiguration) } trait TestSetup extends NodeStatusSetup with BlockUtils with HandshakerSetup { @@ -576,17 +597,17 @@ class PeerActorSpec val genesisHash = genesisBlock.hash - val daoForkBlockChainTotalDifficulty = BigInt("39490964433395682584") + val daoForkBlockChainTotalDifficulty: BigInt = BigInt("39490964433395682584") - val rlpxConnection = TestProbe() + val rlpxConnection: TestProbe = TestProbe() val time = new VirtualTime - val peerMessageBus = system.actorOf(PeerEventBusActor.props) + val peerMessageBus: ActorRef = system.actorOf(PeerEventBusActor.props) - val knownNodesManager = TestProbe() + val knownNodesManager: TestProbe = TestProbe() - val peer = TestActorRef( + val peer: TestActorRef[Nothing] = TestActorRef( Props( new PeerActor( new InetSocketAddress("127.0.0.1", 0), diff --git a/src/test/scala/io/iohk/ethereum/network/p2p/SecureChannelSetup.scala b/src/test/scala/io/iohk/ethereum/network/p2p/SecureChannelSetup.scala index 55b5e3b3cb..938cc080fb 100644 --- a/src/test/scala/io/iohk/ethereum/network/p2p/SecureChannelSetup.scala +++ b/src/test/scala/io/iohk/ethereum/network/p2p/SecureChannelSetup.scala @@ -3,15 +3,19 @@ package io.iohk.ethereum.network.p2p import java.net.URI import akka.util.ByteString -import io.iohk.ethereum.crypto -import io.iohk.ethereum.crypto._ -import io.iohk.ethereum.security.SecureRandomBuilder -import io.iohk.ethereum.network._ -import io.iohk.ethereum.network.rlpx.{AuthHandshakeSuccess, AuthHandshaker, Secrets} + import org.bouncycastle.crypto.AsymmetricCipherKeyPair import org.bouncycastle.crypto.params.ECPublicKeyParameters import org.bouncycastle.util.encoders.Hex +import io.iohk.ethereum.crypto +import io.iohk.ethereum.crypto._ +import io.iohk.ethereum.network._ +import io.iohk.ethereum.network.rlpx.AuthHandshakeSuccess +import io.iohk.ethereum.network.rlpx.AuthHandshaker +import io.iohk.ethereum.network.rlpx.Secrets +import io.iohk.ethereum.security.SecureRandomBuilder + trait SecureChannelSetup extends SecureRandomBuilder { val remoteNodeKey: AsymmetricCipherKeyPair = generateKeyPair(secureRandom) @@ -24,8 +28,8 @@ trait SecureChannelSetup extends SecureRandomBuilder { val ephemeralKey: AsymmetricCipherKeyPair = generateKeyPair(secureRandom) val nonce: ByteString = randomNonce() - val handshaker = AuthHandshaker(nodeKey, nonce, ephemeralKey, secureRandom) - val remoteHandshaker = AuthHandshaker(remoteNodeKey, remoteNonce, remoteEphemeralKey, secureRandom) + val handshaker: AuthHandshaker = AuthHandshaker(nodeKey, nonce, ephemeralKey, secureRandom) + val remoteHandshaker: AuthHandshaker = AuthHandshaker(remoteNodeKey, remoteNonce, remoteEphemeralKey, secureRandom) val (initPacket, handshakerInitiated) = handshaker.initiate(remoteUri) val (responsePacket, AuthHandshakeSuccess(remoteSecrets: Secrets, _)) = diff --git a/src/test/scala/io/iohk/ethereum/network/p2p/messages/MessagesSerializationSpec.scala b/src/test/scala/io/iohk/ethereum/network/p2p/messages/MessagesSerializationSpec.scala index c8984cde4a..42cb3cdbd7 100644 --- a/src/test/scala/io/iohk/ethereum/network/p2p/messages/MessagesSerializationSpec.scala +++ b/src/test/scala/io/iohk/ethereum/network/p2p/messages/MessagesSerializationSpec.scala @@ -1,16 +1,19 @@ package io.iohk.ethereum.network.p2p.messages import akka.util.ByteString + +import org.scalatest.matchers.should.Matchers +import org.scalatest.wordspec.AnyWordSpec +import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks + import io.iohk.ethereum.Fixtures import io.iohk.ethereum.domain.ChainWeight +import io.iohk.ethereum.network.p2p.EthereumMessageDecoder +import io.iohk.ethereum.network.p2p.NetworkMessageDecoder import io.iohk.ethereum.network.p2p.messages.BaseETH6XMessages._ import io.iohk.ethereum.network.p2p.messages.ETH61.BlockHashesFromNumber import io.iohk.ethereum.network.p2p.messages.ETH62._ import io.iohk.ethereum.network.p2p.messages.WireProtocol._ -import io.iohk.ethereum.network.p2p.{EthereumMessageDecoder, NetworkMessageDecoder} -import org.scalatest.matchers.should.Matchers -import org.scalatest.wordspec.AnyWordSpec -import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks class MessagesSerializationSpec extends AnyWordSpec with ScalaCheckPropertyChecks with Matchers { @@ -159,5 +162,5 @@ class MessagesSerializationSpec extends AnyWordSpec with ScalaCheckPropertyCheck messageDecoder(version).fromBytes(code, encode(msg)) shouldEqual msg private def messageDecoder(version: Capability) = - NetworkMessageDecoder orElse EthereumMessageDecoder.ethMessageDecoder(version) + NetworkMessageDecoder.orElse(EthereumMessageDecoder.ethMessageDecoder(version)) } diff --git a/src/test/scala/io/iohk/ethereum/network/p2p/messages/NewBlockSpec.scala b/src/test/scala/io/iohk/ethereum/network/p2p/messages/NewBlockSpec.scala index 5365828c03..e012652fdc 100644 --- a/src/test/scala/io/iohk/ethereum/network/p2p/messages/NewBlockSpec.scala +++ b/src/test/scala/io/iohk/ethereum/network/p2p/messages/NewBlockSpec.scala @@ -1,18 +1,24 @@ package io.iohk.ethereum.network.p2p.messages import akka.util.ByteString + +import org.bouncycastle.util.encoders.Hex +import org.scalatest.funsuite.AnyFunSuite +import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks + import io.iohk.ethereum.ObjectGenerators -import io.iohk.ethereum.domain.{Block, BlockBody, BlockHeader, ChainWeight} +import io.iohk.ethereum.domain.Block +import io.iohk.ethereum.domain.BlockBody +import io.iohk.ethereum.domain.BlockHeader +import io.iohk.ethereum.domain.ChainWeight import io.iohk.ethereum.network.p2p.messages.BaseETH6XMessages.NewBlock -import org.bouncycastle.util.encoders.Hex -import NewBlock._ import io.iohk.ethereum.security.SecureRandomBuilder -import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks -import org.scalatest.funsuite.AnyFunSuite + +import NewBlock._ class NewBlockSpec extends AnyFunSuite with ScalaCheckPropertyChecks with ObjectGenerators with SecureRandomBuilder { - val chainId = Hex.decode("3d").head + val chainId: Byte = Hex.decode("3d").head test("NewBlock v63 messages are encoded and decoded properly") { forAll(newBlockGen(secureRandom, Some(chainId))) { newBlock => @@ -43,7 +49,7 @@ class NewBlockSpec extends AnyFunSuite with ScalaCheckPropertyChecks with Object assert(obtainEncoded64 == expectedEncoded64) } - val newBlock = NewBlock( + val newBlock: NewBlock = NewBlock( Block( BlockHeader( parentHash = ByteString(Hex.decode("0000000000000000000000000000000000000000000000000000000000000000")), @@ -67,7 +73,7 @@ class NewBlockSpec extends AnyFunSuite with ScalaCheckPropertyChecks with Object 983040 ) - val newBlock64 = ETC64.NewBlock( + val newBlock64: ETC64.NewBlock = ETC64.NewBlock( Block( BlockHeader( parentHash = ByteString(Hex.decode("98352d9c1300bd82334cb3e5034c3ec622d437963f55cf5a00a49642806c2f32")), diff --git a/src/test/scala/io/iohk/ethereum/network/p2p/messages/NodeDataSpec.scala b/src/test/scala/io/iohk/ethereum/network/p2p/messages/NodeDataSpec.scala index 72c8e8008b..83539a9b29 100644 --- a/src/test/scala/io/iohk/ethereum/network/p2p/messages/NodeDataSpec.scala +++ b/src/test/scala/io/iohk/ethereum/network/p2p/messages/NodeDataSpec.scala @@ -1,21 +1,30 @@ package io.iohk.ethereum.network.p2p.messages import akka.util.ByteString + +import scala.collection.immutable.ArraySeq + +import org.bouncycastle.util.encoders.Hex +import org.scalatest.flatspec.AnyFlatSpec +import org.scalatest.matchers.should.Matchers + import io.iohk.ethereum.crypto._ import io.iohk.ethereum.domain.Account -import io.iohk.ethereum.mpt.{BranchNode, ExtensionNode, HashNode, LeafNode, MptNode, NullNode} -import io.iohk.ethereum.mpt.HexPrefix.{bytesToNibbles, encode => hpEncode} -import io.iohk.ethereum.network.p2p.messages.ETH63._ +import io.iohk.ethereum.mpt.BranchNode +import io.iohk.ethereum.mpt.ExtensionNode +import io.iohk.ethereum.mpt.HashNode +import io.iohk.ethereum.mpt.HexPrefix.bytesToNibbles +import io.iohk.ethereum.mpt.HexPrefix.{encode => hpEncode} +import io.iohk.ethereum.mpt.LeafNode +import io.iohk.ethereum.mpt.MptNode +import io.iohk.ethereum.mpt.NullNode +import io.iohk.ethereum.network.p2p.EthereumMessageDecoder import io.iohk.ethereum.network.p2p.messages.ETH63.MptNodeEncoders._ +import io.iohk.ethereum.network.p2p.messages.ETH63._ import io.iohk.ethereum.rlp.RLPImplicitConversions._ import io.iohk.ethereum.rlp.RLPImplicits._ -import io.iohk.ethereum.rlp.{encode, _} -import org.bouncycastle.util.encoders.Hex -import io.iohk.ethereum.network.p2p.EthereumMessageDecoder -import org.scalatest.flatspec.AnyFlatSpec -import org.scalatest.matchers.should.Matchers - -import scala.collection.immutable.ArraySeq +import io.iohk.ethereum.rlp._ +import io.iohk.ethereum.rlp.encode class NodeDataSpec extends AnyFlatSpec with Matchers { @@ -31,17 +40,17 @@ class NodeDataSpec extends AnyFlatSpec with Matchers { val accountNonce = 12 val accountBalance = 2000 - val exampleNibbles = ByteString(bytesToNibbles(Hex.decode("ffddaa"))) - val exampleHash = ByteString(kec256(Hex.decode("ab" * 32))) - val exampleHashAsArray = exampleHash.toArray[Byte] - val exampleValue = ByteString(Hex.decode("abcdee")) - val exampleKey = ByteString(Hex.decode("ffddee")) + val exampleNibbles: ByteString = ByteString(bytesToNibbles(Hex.decode("ffddaa"))) + val exampleHash: ByteString = ByteString(kec256(Hex.decode("ab" * 32))) + val exampleHashAsArray: Array[Byte] = exampleHash.toArray[Byte] + val exampleValue: ByteString = ByteString(Hex.decode("abcdee")) + val exampleKey: ByteString = ByteString(Hex.decode("ffddee")) - val account = Account(accountNonce, accountBalance, emptyStorageRoot, emptyEvmHash) - val encodedAccount = RLPList(accountNonce, accountBalance, emptyStorageRoot, emptyEvmHash) + val account: Account = Account(accountNonce, accountBalance, emptyStorageRoot, emptyEvmHash) + val encodedAccount: RLPList = RLPList(accountNonce, accountBalance, emptyStorageRoot, emptyEvmHash) - val encodedLeafNode = RLPList(hpEncode(exampleNibbles.toArray[Byte], isLeaf = true), encode(encodedAccount)) - val leafNode = LeafNode(exampleNibbles, account.toBytes, parsedRlp = Some(encodedLeafNode)) + val encodedLeafNode: RLPList = RLPList(hpEncode(exampleNibbles.toArray[Byte], isLeaf = true), encode(encodedAccount)) + val leafNode: LeafNode = LeafNode(exampleNibbles, account.toBytes, parsedRlp = Some(encodedLeafNode)) val branchNode = new BranchNode( (Array.fill[MptNode](3)(NullNode) :+ HashNode(exampleHashAsArray)) ++ @@ -50,7 +59,7 @@ class NodeDataSpec extends AnyFlatSpec with Matchers { None ) - val encodedBranchNode = { + val encodedBranchNode: RLPList = { val encodeableList: Array[RLPEncodeable] = (Array.fill[RLPValue](3)(RLPValue(Array.emptyByteArray)) :+ (exampleHash: RLPEncodeable)) ++ (Array.fill[RLPValue](6)(RLPValue(Array.emptyByteArray)) :+ (exampleHash: RLPEncodeable)) ++ @@ -58,15 +67,15 @@ class NodeDataSpec extends AnyFlatSpec with Matchers { RLPList(ArraySeq.unsafeWrapArray(encodeableList): _*) } - val extensionNode = ExtensionNode(exampleNibbles, HashNode(exampleHashAsArray)) - val encodedExtensionNode = + val extensionNode: ExtensionNode = ExtensionNode(exampleNibbles, HashNode(exampleHashAsArray)) + val encodedExtensionNode: RLPList = RLPList(hpEncode(exampleNibbles.toArray[Byte], isLeaf = false), RLPValue(exampleHashAsArray)) - val nodeData = NodeData( + val nodeData: NodeData = NodeData( Seq(leafNode.toBytes, branchNode.toBytes, extensionNode.toBytes, emptyEvmHash, emptyStorageRoot) ) - val encodedNodeData = RLPList( + val encodedNodeData: RLPList = RLPList( encode(encodedLeafNode), encode(encodedBranchNode), encode(encodedExtensionNode), diff --git a/src/test/scala/io/iohk/ethereum/network/p2p/messages/ReceiptsSpec.scala b/src/test/scala/io/iohk/ethereum/network/p2p/messages/ReceiptsSpec.scala index 11573a1a39..43556a9a7c 100644 --- a/src/test/scala/io/iohk/ethereum/network/p2p/messages/ReceiptsSpec.scala +++ b/src/test/scala/io/iohk/ethereum/network/p2p/messages/ReceiptsSpec.scala @@ -1,40 +1,44 @@ package io.iohk.ethereum.network.p2p.messages import akka.util.ByteString + +import org.bouncycastle.util.encoders.Hex +import org.scalatest.flatspec.AnyFlatSpec +import org.scalatest.matchers.should.Matchers + import io.iohk.ethereum.crypto._ -import io.iohk.ethereum.domain.{Address, Receipt, TxLogEntry} +import io.iohk.ethereum.domain.Address +import io.iohk.ethereum.domain.Receipt +import io.iohk.ethereum.domain.TxLogEntry import io.iohk.ethereum.network.p2p.EthereumMessageDecoder import io.iohk.ethereum.network.p2p.messages.ETH63.Receipts import io.iohk.ethereum.rlp.RLPImplicitConversions._ import io.iohk.ethereum.rlp.RLPImplicits._ import io.iohk.ethereum.rlp._ -import org.bouncycastle.util.encoders.Hex -import org.scalatest.flatspec.AnyFlatSpec -import org.scalatest.matchers.should.Matchers class ReceiptsSpec extends AnyFlatSpec with Matchers { - val exampleHash = ByteString(kec256((0 until 32).map(_ => 1: Byte).toArray)) - val exampleLogsBloom = ByteString((0 until 256).map(_ => 1: Byte).toArray) + val exampleHash: ByteString = ByteString(kec256((0 until 32).map(_ => 1: Byte).toArray)) + val exampleLogsBloom: ByteString = ByteString((0 until 256).map(_ => 1: Byte).toArray) - val loggerAddress = Address(0xff) - val logData = ByteString(Hex.decode("bb")) - val logTopics = Seq(ByteString(Hex.decode("dd")), ByteString(Hex.decode("aa"))) + val loggerAddress: Address = Address(0xff) + val logData: ByteString = ByteString(Hex.decode("bb")) + val logTopics: Seq[ByteString] = Seq(ByteString(Hex.decode("dd")), ByteString(Hex.decode("aa"))) - val exampleLog = TxLogEntry(loggerAddress, logTopics, logData) + val exampleLog: TxLogEntry = TxLogEntry(loggerAddress, logTopics, logData) val cumulativeGas: BigInt = 0 - val receipt = Receipt.withHashOutcome( + val receipt: Receipt = Receipt.withHashOutcome( postTransactionStateHash = exampleHash, cumulativeGasUsed = cumulativeGas, logsBloomFilter = exampleLogsBloom, logs = Seq(exampleLog) ) - val receipts = Receipts(Seq(Seq(receipt))) + val receipts: Receipts = Receipts(Seq(Seq(receipt))) - val encodedReceipts = + val encodedReceipts: RLPList = RLPList( RLPList( RLPList( diff --git a/src/test/scala/io/iohk/ethereum/network/p2p/messages/TransactionSpec.scala b/src/test/scala/io/iohk/ethereum/network/p2p/messages/TransactionSpec.scala index 6adb516dd9..a32ea4bb3b 100644 --- a/src/test/scala/io/iohk/ethereum/network/p2p/messages/TransactionSpec.scala +++ b/src/test/scala/io/iohk/ethereum/network/p2p/messages/TransactionSpec.scala @@ -1,14 +1,18 @@ package io.iohk.ethereum.network.p2p.messages import akka.util.ByteString -import io.iohk.ethereum.crypto -import io.iohk.ethereum.domain.{Address, SignedTransaction, Transaction} -import io.iohk.ethereum.utils.Config + import org.bouncycastle.math.ec.ECPoint import org.bouncycastle.util.encoders.Hex import org.scalatest.flatspec.AnyFlatSpec import org.scalatest.matchers.should.Matchers +import io.iohk.ethereum.crypto +import io.iohk.ethereum.domain.Address +import io.iohk.ethereum.domain.SignedTransaction +import io.iohk.ethereum.domain.Transaction +import io.iohk.ethereum.utils.Config + class TransactionSpec extends AnyFlatSpec with Matchers { val blockchainConfig = Config.blockchains.blockchainConfig @@ -20,7 +24,7 @@ class TransactionSpec extends AnyFlatSpec with Matchers { val publicKey: ECPoint = crypto.curve.getCurve.decodePoint(rawPublicKey) val address: Address = Address(crypto.kec256(rawPublicKey.tail).slice(12, 32)) - val validTx = Transaction( + val validTx: Transaction = Transaction( nonce = 172320, gasPrice = BigInt("50000000000"), gasLimit = 90000, @@ -29,7 +33,7 @@ class TransactionSpec extends AnyFlatSpec with Matchers { payload = ByteString.empty ) - val validTransactionSignatureOldSchema = SignedTransaction( + val validTransactionSignatureOldSchema: SignedTransaction = SignedTransaction( validTx, pointSign = 28.toByte, signatureRandom = ByteString(Hex.decode("cfe3ad31d6612f8d787c45f115cc5b43fb22bcc210b62ae71dc7cbf0a6bea8df")), @@ -37,17 +41,17 @@ class TransactionSpec extends AnyFlatSpec with Matchers { chainId = blockchainConfig.chainId ) - val invalidTransactionSignatureNewSchema = SignedTransaction( + val invalidTransactionSignatureNewSchema: SignedTransaction = SignedTransaction( validTx, - pointSign = (-98).toByte, + pointSign = -98.toByte, signatureRandom = ByteString(Hex.decode("cfe3ad31d6612f8d787c45f115cc5b43fb22bcc210b62ae71dc7cbf0a6bea8df")), signature = ByteString(Hex.decode("57db8998114fae3c337e99dbd8573d4085691880f4576c6c1f6c5bbfe67d6cf0")), chainId = blockchainConfig.chainId ) - val invalidStx = SignedTransaction( + val invalidStx: SignedTransaction = SignedTransaction( validTx.copy(gasPrice = 0), - pointSign = (-98).toByte, + pointSign = -98.toByte, signatureRandom = ByteString(Hex.decode("cfe3ad31d6612f8d787c45f115cc5b43fb22bcc210b62ae71dc7cbf0a6bea8df")), signature = ByteString(Hex.decode("57db8998114fae3c337e99dbd8573d4085691880f4576c6c1f6c5bbfe67d6cf0")), chainId = blockchainConfig.chainId @@ -58,9 +62,9 @@ class TransactionSpec extends AnyFlatSpec with Matchers { "048fc6373a74ad959fd61d10f0b35e9e0524de025cb9a2bf8e0ff60ccb3f5c5e4d566ebe3c159ad572c260719fc203d820598ee5d9c9fa8ae14ecc8d5a2d8a2af1" ) val publicKeyForNewSigningScheme: ECPoint = crypto.curve.getCurve.decodePoint(rawPublicKeyForNewSigningScheme) - val addreesForNewSigningScheme = Address(crypto.kec256(rawPublicKeyForNewSigningScheme.tail).slice(12, 32)) + val addreesForNewSigningScheme: Address = Address(crypto.kec256(rawPublicKeyForNewSigningScheme.tail).slice(12, 32)) - val validTransactionForNewSigningScheme = Transaction( + val validTransactionForNewSigningScheme: Transaction = Transaction( nonce = 587440, gasPrice = BigInt("20000000000"), gasLimit = 90000, @@ -69,15 +73,15 @@ class TransactionSpec extends AnyFlatSpec with Matchers { payload = ByteString.empty ) - val validSignedTransactionForNewSigningScheme = SignedTransaction( + val validSignedTransactionForNewSigningScheme: SignedTransaction = SignedTransaction( tx = validTransactionForNewSigningScheme, - pointSign = (-98).toByte, + pointSign = -98.toByte, signatureRandom = ByteString(Hex.decode("1af423b3608f3b4b35e191c26f07175331de22ed8f60d1735f03210388246ade")), signature = ByteString(Hex.decode("4d5b6b9e3955a0db8feec9c518d8e1aae0e1d91a143fbbca36671c3b89b89bc3")), blockchainConfig.chainId ) - val stxWithInvalidPointSign = SignedTransaction( + val stxWithInvalidPointSign: SignedTransaction = SignedTransaction( validTx, pointSign = 26.toByte, signatureRandom = ByteString(Hex.decode("cfe3ad31d6612f8d787c45f115cc5b43fb22bcc210b62ae71dc7cbf0a6bea8df")), diff --git a/src/test/scala/io/iohk/ethereum/network/rlpx/MessageCompressionSpec.scala b/src/test/scala/io/iohk/ethereum/network/rlpx/MessageCompressionSpec.scala index 8e14487f2c..370adc0100 100644 --- a/src/test/scala/io/iohk/ethereum/network/rlpx/MessageCompressionSpec.scala +++ b/src/test/scala/io/iohk/ethereum/network/rlpx/MessageCompressionSpec.scala @@ -1,14 +1,16 @@ package io.iohk.ethereum.network.rlpx import akka.util.ByteString -import org.bouncycastle.util.encoders.Hex -import org.scalamock.scalatest.MockFactory -import org.xerial.snappy.Snappy -import io.iohk.ethereum.domain.Block._ import scala.io.Source + +import org.bouncycastle.util.encoders.Hex +import org.scalamock.scalatest.MockFactory import org.scalatest.flatspec.AnyFlatSpec import org.scalatest.matchers.should.Matchers +import org.xerial.snappy.Snappy + +import io.iohk.ethereum.domain.Block._ class MessageCompressionSpec extends AnyFlatSpec with Matchers with MockFactory { diff --git a/src/test/scala/io/iohk/ethereum/network/rlpx/RLPxConnectionHandlerSpec.scala b/src/test/scala/io/iohk/ethereum/network/rlpx/RLPxConnectionHandlerSpec.scala index 150d9d2c15..29f5ad42c8 100644 --- a/src/test/scala/io/iohk/ethereum/network/rlpx/RLPxConnectionHandlerSpec.scala +++ b/src/test/scala/io/iohk/ethereum/network/rlpx/RLPxConnectionHandlerSpec.scala @@ -1,28 +1,36 @@ package io.iohk.ethereum.network.rlpx -import java.net.{InetSocketAddress, URI} -import akka.actor.{ActorRef, ActorSystem, Props} +import java.net.InetSocketAddress +import java.net.URI + +import akka.actor.ActorRef +import akka.actor.ActorSystem +import akka.actor.Props import akka.io.Tcp -import akka.testkit.{TestActorRef, TestKit, TestProbe} +import akka.testkit.TestActorRef +import akka.testkit.TestKit +import akka.testkit.TestProbe import akka.util.ByteString -import io.iohk.ethereum.network.p2p.messages.Capability.Capabilities -import io.iohk.ethereum.{Timeouts, WithActorSystemShutDown} -import io.iohk.ethereum.network.p2p.{MessageDecoder, MessageSerializable} -import io.iohk.ethereum.network.p2p.messages.{Capability, ProtocolVersions} -import io.iohk.ethereum.network.p2p.messages.WireProtocol.{Hello, Ping} -import io.iohk.ethereum.network.rlpx.RLPxConnectionHandler.{ - HelloCodec, - InitialHelloReceived, - MessageReceived, - RLPxConfiguration -} -import io.iohk.ethereum.security.SecureRandomBuilder -import org.scalamock.scalatest.MockFactory import scala.concurrent.duration.FiniteDuration + +import org.scalamock.scalatest.MockFactory import org.scalatest.flatspec.AnyFlatSpecLike import org.scalatest.matchers.should.Matchers +import io.iohk.ethereum.Timeouts +import io.iohk.ethereum.WithActorSystemShutDown +import io.iohk.ethereum.network.p2p.MessageDecoder +import io.iohk.ethereum.network.p2p.MessageSerializable +import io.iohk.ethereum.network.p2p.messages.Capability.Capabilities +import io.iohk.ethereum.network.p2p.messages.ProtocolVersions +import io.iohk.ethereum.network.p2p.messages.WireProtocol.Hello +import io.iohk.ethereum.network.p2p.messages.WireProtocol.Ping +import io.iohk.ethereum.network.rlpx.RLPxConnectionHandler.HelloCodec +import io.iohk.ethereum.network.rlpx.RLPxConnectionHandler.InitialHelloReceived +import io.iohk.ethereum.network.rlpx.RLPxConnectionHandler.RLPxConfiguration +import io.iohk.ethereum.security.SecureRandomBuilder + class RLPxConnectionHandlerSpec extends TestKit(ActorSystem("RLPxConnectionHandlerSpec_System")) with AnyFlatSpecLike @@ -180,14 +188,14 @@ class RLPxConnectionHandlerSpec trait TestSetup extends MockFactory with SecureRandomBuilder { //Mock parameters for RLPxConnectionHandler - val mockMessageDecoder = new MessageDecoder { + val mockMessageDecoder: MessageDecoder = new MessageDecoder { override def fromBytes(`type`: Int, payload: Array[Byte]) = throw new Exception("Mock message decoder fails to decode all messages") } val protocolVersion = ProtocolVersions.ETH63 - val mockHandshaker = mock[AuthHandshaker] - val connection = TestProbe() - val mockMessageCodec = mock[MessageCodec] + val mockHandshaker: AuthHandshaker = mock[AuthHandshaker] + val connection: TestProbe = TestProbe() + val mockMessageCodec: MessageCodec = mock[MessageCodec] val mockHelloExtractor: HelloCodec = mock[HelloCodec] val uri = new URI( @@ -195,16 +203,16 @@ class RLPxConnectionHandlerSpec ) val inetAddress = new InetSocketAddress(uri.getHost, uri.getPort) - val rlpxConfiguration = new RLPxConfiguration { + val rlpxConfiguration: RLPxConfiguration = new RLPxConfiguration { override val waitForTcpAckTimeout: FiniteDuration = Timeouts.normalTimeout //unused override val waitForHandshakeTimeout: FiniteDuration = Timeouts.veryLongTimeout } - val tcpActorProbe = TestProbe() - val rlpxConnectionParent = TestProbe() - val rlpxConnection = TestActorRef( + val tcpActorProbe: TestProbe = TestProbe() + val rlpxConnectionParent: TestProbe = TestProbe() + val rlpxConnection: TestActorRef[Nothing] = TestActorRef( Props( new RLPxConnectionHandler( protocolVersion :: Nil, @@ -218,7 +226,7 @@ class RLPxConnectionHandlerSpec ), rlpxConnectionParent.ref ) - rlpxConnectionParent watch rlpxConnection + rlpxConnectionParent.watch(rlpxConnection) //Setup for RLPxConnection, after it the RLPxConnectionHandler is in a handshaked state def setupIncomingRLPxConnection(): Unit = { @@ -235,7 +243,7 @@ class RLPxConnectionHandlerSpec .returning((response, AuthHandshakeSuccess(mock[Secrets], ByteString()))) (mockHelloExtractor.readHello _) .expects(ByteString.empty) - .returning(Some(Hello(5, "", Capabilities.Eth63Capability :: Nil, 30303, ByteString("abc")), Seq.empty)) + .returning(Some((Hello(5, "", Capabilities.Eth63Capability :: Nil, 30303, ByteString("abc")), Seq.empty))) (mockMessageCodec.readMessages _) .expects(hello) .returning(Nil) //For processing of messages after handshaking finishes diff --git a/src/test/scala/io/iohk/ethereum/ommers/OmmersPoolSpec.scala b/src/test/scala/io/iohk/ethereum/ommers/OmmersPoolSpec.scala index bc97ec9c55..ae7d096630 100644 --- a/src/test/scala/io/iohk/ethereum/ommers/OmmersPoolSpec.scala +++ b/src/test/scala/io/iohk/ethereum/ommers/OmmersPoolSpec.scala @@ -1,16 +1,23 @@ package io.iohk.ethereum.ommers +import akka.actor.ActorRef import akka.actor.ActorSystem -import akka.testkit.{ImplicitSender, TestKit, TestProbe} -import io.iohk.ethereum.Fixtures.Blocks.Block3125369 -import io.iohk.ethereum.Timeouts -import io.iohk.ethereum.domain.{BlockchainImpl, BlockchainReader} -import io.iohk.ethereum.ommers.OmmersPool.{AddOmmers, GetOmmers} -import io.iohk.ethereum.WithActorSystemShutDown +import akka.testkit.ImplicitSender +import akka.testkit.TestKit +import akka.testkit.TestProbe + import org.scalamock.scalatest.MockFactory import org.scalatest.freespec.AnyFreeSpecLike import org.scalatest.matchers.should.Matchers +import io.iohk.ethereum.Fixtures.Blocks.Block3125369 +import io.iohk.ethereum.Timeouts +import io.iohk.ethereum.WithActorSystemShutDown +import io.iohk.ethereum.domain.BlockHeader +import io.iohk.ethereum.domain.BlockchainReader +import io.iohk.ethereum.ommers.OmmersPool.AddOmmers +import io.iohk.ethereum.ommers.OmmersPool.GetOmmers + class OmmersPoolSpec extends TestKit(ActorSystem("OmmersPoolSpec_System")) with AnyFreeSpecLike @@ -23,8 +30,7 @@ class OmmersPoolSpec "should not return ommers if there is no any" in new TestSetup { - /** - * 00 --> 11 --> 21 --> [31] (chain1) + /** 00 --> 11 --> 21 --> [31] (chain1) * \-> 14 (chain4) * [] new block, reference! * () ommer given the new block @@ -48,8 +54,7 @@ class OmmersPoolSpec "in case of a chain with less length than the generation limit" in new TestSetup { - /** - * 00 --> (11) --> 21 --> 31 (chain1) + /** 00 --> (11) --> 21 --> 31 (chain1) * \ \ \-> 33 (chain3) * \ \--> 22 --> 32 (chain2) * \-> [14] (chain4) @@ -75,8 +80,7 @@ class OmmersPoolSpec "despite of start losing older ommers candidates" in new TestSetup { - /** - * XX --> (11) --> 21 --> 31 (chain1) + /** XX --> (11) --> 21 --> 31 (chain1) * \ \ \-> 33 (chain3) * \ \--> 22 --> 32 (chain2) * \--> 14 ---> [24] (chain4) @@ -110,8 +114,7 @@ class OmmersPoolSpec "by respecting size and generation limits" in new TestSetup { - /** - * 00 --> 11 --> 21 --> [31] (chain1) + /** 00 --> 11 --> 21 --> [31] (chain1) * \ \ \-> (33) (chain3) * \ \--> (22) --> 32 (chain2) * \-> 14 (chain4) @@ -149,33 +152,38 @@ class OmmersPoolSpec val ommerGenerationLimit: Int = 2 val returnedOmmerSizeLimit: Int = 2 // Max amount of ommers allowed per block - /** - * 00 ---> 11 --> 21 --> 31 (chain1) + /** 00 ---> 11 --> 21 --> 31 (chain1) * \ \ \--> 33 (chain3) * \ \--> 22 --> 32 (chain2) * \--> 14 --> 24 (chain4) * \-> 15 (chain5) */ - val block0 = Block3125369.header.copy(number = 0, difficulty = 0) + val block0: BlockHeader = Block3125369.header.copy(number = 0, difficulty = 0) - val block1Chain1 = Block3125369.header.copy(number = 1, parentHash = block0.hash, difficulty = 11) - val block2Chain1 = Block3125369.header.copy(number = 2, parentHash = block1Chain1.hash, difficulty = 21) - val block3Chain1 = Block3125369.header.copy(number = 3, parentHash = block2Chain1.hash, difficulty = 31) + val block1Chain1: BlockHeader = Block3125369.header.copy(number = 1, parentHash = block0.hash, difficulty = 11) + val block2Chain1: BlockHeader = + Block3125369.header.copy(number = 2, parentHash = block1Chain1.hash, difficulty = 21) + val block3Chain1: BlockHeader = + Block3125369.header.copy(number = 3, parentHash = block2Chain1.hash, difficulty = 31) - val block2Chain2 = Block3125369.header.copy(number = 2, parentHash = block1Chain1.hash, difficulty = 22) - val block3Chain2 = Block3125369.header.copy(number = 2, parentHash = block2Chain2.hash, difficulty = 32) + val block2Chain2: BlockHeader = + Block3125369.header.copy(number = 2, parentHash = block1Chain1.hash, difficulty = 22) + val block3Chain2: BlockHeader = + Block3125369.header.copy(number = 2, parentHash = block2Chain2.hash, difficulty = 32) - val block3Chain3 = Block3125369.header.copy(number = 3, parentHash = block2Chain1.hash, difficulty = 33) + val block3Chain3: BlockHeader = + Block3125369.header.copy(number = 3, parentHash = block2Chain1.hash, difficulty = 33) - val block1Chain4 = Block3125369.header.copy(number = 1, parentHash = block0.hash, difficulty = 14) - val block2Chain4 = Block3125369.header.copy(number = 2, parentHash = block1Chain4.hash, difficulty = 24) + val block1Chain4: BlockHeader = Block3125369.header.copy(number = 1, parentHash = block0.hash, difficulty = 14) + val block2Chain4: BlockHeader = + Block3125369.header.copy(number = 2, parentHash = block1Chain4.hash, difficulty = 24) - val block1Chain5 = Block3125369.header.copy(number = 1, parentHash = block0.hash, difficulty = 15) + val block1Chain5: BlockHeader = Block3125369.header.copy(number = 1, parentHash = block0.hash, difficulty = 15) - val testProbe = TestProbe() + val testProbe: TestProbe = TestProbe() - val blockchainReader = mock[BlockchainReader] - val ommersPool = + val blockchainReader: BlockchainReader = mock[BlockchainReader] + val ommersPool: ActorRef = system.actorOf( OmmersPool.props(blockchainReader, ommersPoolSize, ommerGenerationLimit, returnedOmmerSizeLimit) ) diff --git a/src/test/scala/io/iohk/ethereum/patience.scala b/src/test/scala/io/iohk/ethereum/patience.scala index 49c887c9b5..ed828cc42d 100644 --- a/src/test/scala/io/iohk/ethereum/patience.scala +++ b/src/test/scala/io/iohk/ethereum/patience.scala @@ -1,10 +1,11 @@ package io.iohk.ethereum import akka.util.Timeout -import org.scalatest.concurrent.PatienceConfiguration import scala.concurrent.duration._ +import org.scalatest.concurrent.PatienceConfiguration + trait NormalPatience { self: PatienceConfiguration => diff --git a/src/test/scala/io/iohk/ethereum/proof/MptProofVerifier.scala b/src/test/scala/io/iohk/ethereum/proof/MptProofVerifier.scala index 7e1782df77..7426fbd7dd 100644 --- a/src/test/scala/io/iohk/ethereum/proof/MptProofVerifier.scala +++ b/src/test/scala/io/iohk/ethereum/proof/MptProofVerifier.scala @@ -1,12 +1,20 @@ package io.iohk.ethereum.proof import akka.util.ByteString + import cats.syntax.either._ + import io.iohk.ethereum.db.dataSource.EphemDataSource -import io.iohk.ethereum.db.storage.{NodeStorage, SerializingMptStorage, StateStorage} +import io.iohk.ethereum.db.storage.NodeStorage +import io.iohk.ethereum.db.storage.SerializingMptStorage +import io.iohk.ethereum.db.storage.StateStorage import io.iohk.ethereum.jsonrpc.ProofService.MptProofError -import io.iohk.ethereum.mpt.{ByteArrayEncoder, ByteArraySerializable, MerklePatriciaTrie, MptNode} -import io.iohk.ethereum.proof.ProofVerifyResult.{InvalidProof, ValidProof} +import io.iohk.ethereum.mpt.ByteArrayEncoder +import io.iohk.ethereum.mpt.ByteArraySerializable +import io.iohk.ethereum.mpt.MerklePatriciaTrie +import io.iohk.ethereum.mpt.MptNode +import io.iohk.ethereum.proof.ProofVerifyResult.InvalidProof +import io.iohk.ethereum.proof.ProofVerifyResult.ValidProof sealed trait ProofVerifyResult object ProofVerifyResult { diff --git a/src/test/scala/io/iohk/ethereum/security/SSLContextFactorySpec.scala b/src/test/scala/io/iohk/ethereum/security/SSLContextFactorySpec.scala index 14343f156a..7c9a03bd61 100644 --- a/src/test/scala/io/iohk/ethereum/security/SSLContextFactorySpec.scala +++ b/src/test/scala/io/iohk/ethereum/security/SSLContextFactorySpec.scala @@ -1,16 +1,21 @@ package io.iohk.ethereum.security -import java.io.{ByteArrayInputStream, File, FileInputStream, FileOutputStream} -import java.security.{KeyStore, SecureRandom} +import java.io.ByteArrayInputStream +import java.io.File +import java.io.FileInputStream +import java.io.FileOutputStream +import java.security.KeyStore +import java.security.SecureRandom +import javax.net.ssl.KeyManager +import javax.net.ssl.TrustManager + +import scala.io.BufferedSource -import javax.net.ssl.{KeyManager, TrustManager} import org.scalamock.scalatest.MockFactory import org.scalatest.BeforeAndAfterAll import org.scalatest.flatspec.AnyFlatSpec import org.scalatest.matchers.should.Matchers -import scala.io.BufferedSource - class SSLContextFactorySpec extends AnyFlatSpec with Matchers with MockFactory with BeforeAndAfterAll { val fileName: String = "temp.txt" @@ -21,9 +26,8 @@ class SSLContextFactorySpec extends AnyFlatSpec with Matchers with MockFactory w file = new File(fileName) } - override def afterAll(): Unit = { + override def afterAll(): Unit = file.delete() - } val keyStorePath = "mantisCA.p12" val keyStoreType = "pkcs12" @@ -194,7 +198,7 @@ class SSLContextFactorySpec extends AnyFlatSpec with Matchers with MockFactory w fGetTrustManager: () => Either[Throwable, Array[TrustManager]] ) { - val sSLContextFactory = new SSLContextFactory { + val sSLContextFactory: SSLContextFactory = new SSLContextFactory { override def exist(pathName: String): Boolean = existingFiles.contains(pathName) diff --git a/src/test/scala/io/iohk/ethereum/testing/ActorsTesting.scala b/src/test/scala/io/iohk/ethereum/testing/ActorsTesting.scala index 09c7b21820..b16be64adc 100644 --- a/src/test/scala/io/iohk/ethereum/testing/ActorsTesting.scala +++ b/src/test/scala/io/iohk/ethereum/testing/ActorsTesting.scala @@ -3,16 +3,15 @@ import akka.actor.ActorRef import akka.testkit.TestActor.AutoPilot object ActorsTesting { - def simpleAutoPilot(makeResponse: PartialFunction[Any, Any]): AutoPilot = { + def simpleAutoPilot(makeResponse: PartialFunction[Any, Any]): AutoPilot = new AutoPilot { def run(sender: ActorRef, msg: Any) = { val response = makeResponse.lift(msg) response match { case Some(value) => sender ! value - case _ => () + case _ => () } this } } - } } diff --git a/src/test/scala/io/iohk/ethereum/transactions/PendingTransactionsManagerSpec.scala b/src/test/scala/io/iohk/ethereum/transactions/PendingTransactionsManagerSpec.scala index e27392d51a..b831dc0193 100644 --- a/src/test/scala/io/iohk/ethereum/transactions/PendingTransactionsManagerSpec.scala +++ b/src/test/scala/io/iohk/ethereum/transactions/PendingTransactionsManagerSpec.scala @@ -2,28 +2,39 @@ package io.iohk.ethereum.transactions import java.net.InetSocketAddress +import akka.actor.ActorRef import akka.actor.ActorSystem import akka.pattern.ask import akka.testkit.TestProbe import akka.util.ByteString -import io.iohk.ethereum.domain.{Address, SignedTransaction, SignedTransactionWithSender, Transaction} -import io.iohk.ethereum.security.SecureRandomBuilder + +import scala.concurrent.duration._ + +import org.bouncycastle.crypto.AsymmetricCipherKeyPair +import org.scalatest.concurrent.ScalaFutures +import org.scalatest.flatspec.AnyFlatSpec +import org.scalatest.matchers.should.Matchers + +import io.iohk.ethereum.NormalPatience +import io.iohk.ethereum.Timeouts +import io.iohk.ethereum.crypto +import io.iohk.ethereum.domain.Address +import io.iohk.ethereum.domain.SignedTransaction +import io.iohk.ethereum.domain.SignedTransactionWithSender +import io.iohk.ethereum.domain.Transaction +import io.iohk.ethereum.network.EtcPeerManagerActor +import io.iohk.ethereum.network.Peer import io.iohk.ethereum.network.PeerActor.Status.Handshaked import io.iohk.ethereum.network.PeerEventBusActor.PeerEvent +import io.iohk.ethereum.network.PeerId +import io.iohk.ethereum.network.PeerManagerActor import io.iohk.ethereum.network.PeerManagerActor.Peers import io.iohk.ethereum.network.handshaker.Handshaker.HandshakeResult import io.iohk.ethereum.network.p2p.messages.BaseETH6XMessages.SignedTransactions -import io.iohk.ethereum.network.{EtcPeerManagerActor, Peer, PeerId, PeerManagerActor} +import io.iohk.ethereum.security.SecureRandomBuilder import io.iohk.ethereum.transactions.PendingTransactionsManager._ -import io.iohk.ethereum.{NormalPatience, Timeouts, crypto} import io.iohk.ethereum.transactions.SignedTransactionsFilterActor.ProperSignedTransactions import io.iohk.ethereum.utils.TxPoolConfig -import org.scalatest.concurrent.ScalaFutures -import org.bouncycastle.crypto.AsymmetricCipherKeyPair - -import scala.concurrent.duration._ -import org.scalatest.flatspec.AnyFlatSpec -import org.scalatest.matchers.should.Matchers class PendingTransactionsManagerSpec extends AnyFlatSpec with Matchers with ScalaFutures with NormalPatience { @@ -200,12 +211,12 @@ class PendingTransactionsManagerSpec extends AnyFlatSpec with Matchers with Scal } trait TestSetup extends SecureRandomBuilder { - implicit val system = ActorSystem("test-system") + implicit val system: ActorSystem = ActorSystem("test-system") - val keyPair1 = crypto.generateKeyPair(secureRandom) - val keyPair2 = crypto.generateKeyPair(secureRandom) + val keyPair1: AsymmetricCipherKeyPair = crypto.generateKeyPair(secureRandom) + val keyPair2: AsymmetricCipherKeyPair = crypto.generateKeyPair(secureRandom) - val tx = Transaction(1, 1, 1, Some(Address(42)), 10, ByteString("")) + val tx: Transaction = Transaction(1, 1, 1, Some(Address(42)), 10, ByteString("")) def newStx( nonce: BigInt = 0, @@ -214,14 +225,14 @@ class PendingTransactionsManagerSpec extends AnyFlatSpec with Matchers with Scal ): SignedTransactionWithSender = SignedTransaction.sign(tx, keyPair, Some(0x3d)) - val peer1TestProbe = TestProbe() - val peer1 = Peer(PeerId("peer1"), new InetSocketAddress("127.0.0.1", 9000), peer1TestProbe.ref, false) - val peer2TestProbe = TestProbe() - val peer2 = Peer(PeerId("peer2"), new InetSocketAddress("127.0.0.2", 9000), peer2TestProbe.ref, false) - val peer3TestProbe = TestProbe() - val peer3 = Peer(PeerId("peer3"), new InetSocketAddress("127.0.0.3", 9000), peer3TestProbe.ref, false) + val peer1TestProbe: TestProbe = TestProbe() + val peer1: Peer = Peer(PeerId("peer1"), new InetSocketAddress("127.0.0.1", 9000), peer1TestProbe.ref, false) + val peer2TestProbe: TestProbe = TestProbe() + val peer2: Peer = Peer(PeerId("peer2"), new InetSocketAddress("127.0.0.2", 9000), peer2TestProbe.ref, false) + val peer3TestProbe: TestProbe = TestProbe() + val peer3: Peer = Peer(PeerId("peer3"), new InetSocketAddress("127.0.0.3", 9000), peer3TestProbe.ref, false) - val txPoolConfig = new TxPoolConfig { + val txPoolConfig: TxPoolConfig = new TxPoolConfig { override val txPoolSize: Int = 300 //unused @@ -230,10 +241,10 @@ class PendingTransactionsManagerSpec extends AnyFlatSpec with Matchers with Scal override val getTransactionFromPoolTimeout: FiniteDuration = Timeouts.veryLongTimeout } - val peerManager = TestProbe() - val etcPeerManager = TestProbe() - val peerMessageBus = TestProbe() - val pendingTransactionsManager = system.actorOf( + val peerManager: TestProbe = TestProbe() + val etcPeerManager: TestProbe = TestProbe() + val peerMessageBus: TestProbe = TestProbe() + val pendingTransactionsManager: ActorRef = system.actorOf( PendingTransactionsManager.props(txPoolConfig, peerManager.ref, etcPeerManager.ref, peerMessageBus.ref) ) } diff --git a/src/test/scala/io/iohk/ethereum/transactions/TransactionHistoryServiceSpec.scala b/src/test/scala/io/iohk/ethereum/transactions/TransactionHistoryServiceSpec.scala index 8c69c74032..a2291ed372 100644 --- a/src/test/scala/io/iohk/ethereum/transactions/TransactionHistoryServiceSpec.scala +++ b/src/test/scala/io/iohk/ethereum/transactions/TransactionHistoryServiceSpec.scala @@ -1,19 +1,25 @@ package io.iohk.ethereum.transactions import akka.actor.ActorSystem -import akka.testkit.{TestKit, TestProbe} +import akka.testkit.TestKit +import akka.testkit.TestProbe import akka.util.ByteString + +import monix.eval.Task + import com.softwaremill.diffx.scalatest.DiffMatcher +import mouse.all._ +import org.scalatest.matchers.should.Matchers + import io.iohk.ethereum.blockchain.sync.EphemBlockchainTestSetup -import io.iohk.ethereum.crypto.{ECDSASignature, generateKeyPair} +import io.iohk.ethereum.crypto.ECDSASignature +import io.iohk.ethereum.crypto.generateKeyPair import io.iohk.ethereum.domain.BlockHeader.HeaderExtraFields.HefPostEcip1097 import io.iohk.ethereum.domain._ -import io.iohk.ethereum.transactions.TransactionHistoryService.{ExtendedTransactionData, MinedTransactionData} +import io.iohk.ethereum.transactions.TransactionHistoryService.ExtendedTransactionData +import io.iohk.ethereum.transactions.TransactionHistoryService.MinedTransactionData import io.iohk.ethereum.transactions.testing.PendingTransactionsManagerAutoPilot import io.iohk.ethereum.{blockchain => _, _} -import monix.eval.Task -import mouse.all._ -import org.scalatest.matchers.should.Matchers class TransactionHistoryServiceSpec extends TestKit(ActorSystem("TransactionHistoryServiceSpec-system")) @@ -23,7 +29,7 @@ class TransactionHistoryServiceSpec with Matchers with DiffMatcher { class Fixture extends EphemBlockchainTestSetup { - val pendingTransactionManager = TestProbe() + val pendingTransactionManager: TestProbe = TestProbe() pendingTransactionManager.setAutoPilot(PendingTransactionsManagerAutoPilot()) val transactionHistoryService = new TransactionHistoryService(blockchain, blockchainReader, pendingTransactionManager.ref, Timeouts.normalTimeout) @@ -101,8 +107,8 @@ class TransactionHistoryServiceSpec Seq(ExtendedTransactionData(signedTx.tx, isOutgoing = true, None)) for { - _ <- Task { blockchain.storeBlock(blockWithTx).commit() } - _ <- Task { pendingTransactionManager.ref ! PendingTransactionsManager.AddTransactions(signedTx) } + _ <- Task(blockchain.storeBlock(blockWithTx).commit()) + _ <- Task(pendingTransactionManager.ref ! PendingTransactionsManager.AddTransactions(signedTx)) response <- transactionHistoryService.getAccountTransactions( signedTx.senderAddress, BigInt(3125371) to BigInt(3125381) @@ -155,10 +161,10 @@ class TransactionHistoryServiceSpec block.body.transactionList.map(tx => Receipt(HashOutcome(block.hash), BigInt(21000), ByteString("foo"), Nil)) for { - _ <- Task { blockchain.save(block1, makeReceipts(block1), ChainWeight(0, block1.header.difficulty), true) } - _ <- Task { blockchain.save(block2, Nil, ChainWeight(2, block1.header.difficulty), true) } - _ <- Task { blockchain.save(block3, makeReceipts(block3), ChainWeight(2, block1.header.difficulty * 2), true) } - lastCheckpoint <- Task { blockchain.getLatestCheckpointBlockNumber() } + _ <- Task(blockchain.save(block1, makeReceipts(block1), ChainWeight(0, block1.header.difficulty), true)) + _ <- Task(blockchain.save(block2, Nil, ChainWeight(2, block1.header.difficulty), true)) + _ <- Task(blockchain.save(block3, makeReceipts(block3), ChainWeight(2, block1.header.difficulty * 2), true)) + lastCheckpoint <- Task(blockchain.getLatestCheckpointBlockNumber()) response <- transactionHistoryService.getAccountTransactions( senderAddress, BigInt.apply(0) to BigInt(10) diff --git a/src/test/scala/io/iohk/ethereum/transactions/testing/PendingTransactionsManagerAutoPilot.scala b/src/test/scala/io/iohk/ethereum/transactions/testing/PendingTransactionsManagerAutoPilot.scala index 328862aa64..39e2327985 100644 --- a/src/test/scala/io/iohk/ethereum/transactions/testing/PendingTransactionsManagerAutoPilot.scala +++ b/src/test/scala/io/iohk/ethereum/transactions/testing/PendingTransactionsManagerAutoPilot.scala @@ -2,13 +2,15 @@ package io.iohk.ethereum.transactions.testing import akka.actor.ActorRef import akka.testkit.TestActor.AutoPilot import akka.util.ByteString -import io.iohk.ethereum.domain.{SignedTransaction, SignedTransactionWithSender} + +import io.iohk.ethereum.domain.SignedTransaction +import io.iohk.ethereum.domain.SignedTransactionWithSender import io.iohk.ethereum.transactions.PendingTransactionsManager._ import io.iohk.ethereum.transactions.SignedTransactionsFilterActor.ProperSignedTransactions case class PendingTransactionsManagerAutoPilot(pendingTransactions: Set[PendingTransaction] = Set.empty) extends AutoPilot { - def run(sender: ActorRef, msg: Any) = { + def run(sender: ActorRef, msg: Any): AutoPilot = msg match { case AddUncheckedTransactions(transactions) => val validTxs = SignedTransactionWithSender.getSignedTransactions(transactions) @@ -33,15 +35,14 @@ case class PendingTransactionsManagerAutoPilot(pendingTransactions: Set[PendingT case RemoveTransactions(signedTransactions) => this.removeTransactions(signedTransactions.map(_.hash).toSet) - case ProperSignedTransactions(transactions, peerId) => + case ProperSignedTransactions(transactions, _) => this.addTransactions(transactions) case ClearPendingTransactions => copy(pendingTransactions = Set.empty) } - } - def addTransactions(signedTransactions: Set[SignedTransactionWithSender]) = { + def addTransactions(signedTransactions: Set[SignedTransactionWithSender]): PendingTransactionsManagerAutoPilot = { val timestamp = System.currentTimeMillis() val stxs = pendingTransactions.map(_.stx) val transactionsToAdd = signedTransactions.diff(stxs).map(tx => PendingTransaction(tx, timestamp)) @@ -49,7 +50,6 @@ case class PendingTransactionsManagerAutoPilot(pendingTransactions: Set[PendingT copy(pendingTransactions ++ transactionsToAdd) } - def removeTransactions(hashes: Set[ByteString]) = { + def removeTransactions(hashes: Set[ByteString]): PendingTransactionsManagerAutoPilot = copy(pendingTransactions.filterNot(ptx => hashes.contains(ptx.stx.tx.hash))) - } } diff --git a/src/test/scala/io/iohk/ethereum/utils/MockClock.scala b/src/test/scala/io/iohk/ethereum/utils/MockClock.scala index f9ff71c68f..e194ef692f 100644 --- a/src/test/scala/io/iohk/ethereum/utils/MockClock.scala +++ b/src/test/scala/io/iohk/ethereum/utils/MockClock.scala @@ -1,6 +1,8 @@ package io.iohk.ethereum.utils -import java.time.{Clock, Instant, ZoneId} +import java.time.Clock +import java.time.Instant +import java.time.ZoneId class MockClock( private var currentTimeMillis: Long = System.currentTimeMillis, diff --git a/src/test/scala/io/iohk/ethereum/utils/VersionInfoSpec.scala b/src/test/scala/io/iohk/ethereum/utils/VersionInfoSpec.scala index c3182accb5..2c13cc6eb2 100644 --- a/src/test/scala/io/iohk/ethereum/utils/VersionInfoSpec.scala +++ b/src/test/scala/io/iohk/ethereum/utils/VersionInfoSpec.scala @@ -4,11 +4,12 @@ import org.scalatest.flatspec.AnyFlatSpec import org.scalatest.matchers.should.Matchers class VersionInfoSpec extends AnyFlatSpec with Matchers { - behavior of "nodeName" + behavior.of("nodeName") it should "match ethstats expected structure and preserve major and minor Java version" in { - VersionInfo - .nodeName() should fullyMatch regex """mantis/v\d(\.\d+)*(-SNAPSHOT)?-[a-z0-9]{7}/[^/]+-[^/]+/[^/]+-.[^/]+-java-\d+\.\d+[._0-9]*""" + (VersionInfo + .nodeName() should fullyMatch) + .regex("""mantis/v\d(\.\d+)*(-SNAPSHOT)?-[a-z0-9]{7}/[^/]+-[^/]+/[^/]+-.[^/]+-java-\d+\.\d+[._0-9]*""") } it should "augment the name with an identity" in { diff --git a/src/test/scala/io/iohk/ethereum/vm/Assembly.scala b/src/test/scala/io/iohk/ethereum/vm/Assembly.scala index b27efff268..34468466d6 100644 --- a/src/test/scala/io/iohk/ethereum/vm/Assembly.scala +++ b/src/test/scala/io/iohk/ethereum/vm/Assembly.scala @@ -32,6 +32,6 @@ case class Assembly(byteCode: ByteCode*) { def linearConstGas(config: EvmConfig): BigInt = byteCode.foldLeft(BigInt(0)) { case (g, b: OpCodeAsByteCode) => g + b.op.constGasFn(config.feeSchedule) - case (g, _) => g + case (g, _) => g } } diff --git a/src/test/scala/io/iohk/ethereum/vm/BlakeCompressionSpec.scala b/src/test/scala/io/iohk/ethereum/vm/BlakeCompressionSpec.scala index b92d9bc0a4..3ac7d1aea1 100644 --- a/src/test/scala/io/iohk/ethereum/vm/BlakeCompressionSpec.scala +++ b/src/test/scala/io/iohk/ethereum/vm/BlakeCompressionSpec.scala @@ -1,13 +1,14 @@ package io.iohk.ethereum.vm import org.bouncycastle.util.encoders.Hex -import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks import org.scalatest.flatspec.AnyFlatSpec import org.scalatest.matchers.should.Matchers +import org.scalatest.prop.TableFor2 +import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks class BlakeCompressionSpec extends AnyFlatSpec with Matchers with ScalaCheckPropertyChecks { // test vectors from: https://eips.ethereum.org/EIPS/eip-152 - val testVectors = Table[String, Option[String]]( + val testVectors: TableFor2[String, Option[String]] = Table[String, Option[String]]( ("value", "result"), ( "00000c48c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000001", diff --git a/src/test/scala/io/iohk/ethereum/vm/CallOpFixture.scala b/src/test/scala/io/iohk/ethereum/vm/CallOpFixture.scala index 1e0d93bcdb..07274b2c92 100644 --- a/src/test/scala/io/iohk/ethereum/vm/CallOpFixture.scala +++ b/src/test/scala/io/iohk/ethereum/vm/CallOpFixture.scala @@ -1,24 +1,28 @@ package io.iohk.ethereum.vm import akka.util.ByteString -import io.iohk.ethereum.crypto.kec256 -import io.iohk.ethereum.domain.{Account, Address, UInt256} + import io.iohk.ethereum.Fixtures.{Blocks => BlockFixtures} -import io.iohk.ethereum.vm.MockWorldState._ +import io.iohk.ethereum.crypto.kec256 +import io.iohk.ethereum.domain.Account +import io.iohk.ethereum.domain.Address +import io.iohk.ethereum.domain.BlockHeader +import io.iohk.ethereum.domain.UInt256 import io.iohk.ethereum.utils.ByteStringUtils._ +import io.iohk.ethereum.vm.MockWorldState._ class CallOpFixture(val config: EvmConfig, val startState: MockWorldState) { import config.feeSchedule._ - val ownerAddr = Address(0xcafebabe) - val extAddr = Address(0xfacefeed) - val callerAddr = Address(0xdeadbeef) + val ownerAddr: Address = Address(0xcafebabe) + val extAddr: Address = Address(0xfacefeed) + val callerAddr: Address = Address(0xdeadbeef) - val ownerOffset = UInt256(0) - val callerOffset = UInt256(1) - val valueOffset = UInt256(2) + val ownerOffset: UInt256 = UInt256(0) + val callerOffset: UInt256 = UInt256(1) + val valueOffset: UInt256 = UInt256(2) - val extCode = Assembly( + val extCode: Assembly = Assembly( //store owner address ADDRESS, PUSH1, @@ -48,19 +52,19 @@ class CallOpFixture(val config: EvmConfig, val startState: MockWorldState) { RETURN ) - val selfDestructCode = Assembly( + val selfDestructCode: Assembly = Assembly( PUSH20, callerAddr.bytes, SELFDESTRUCT ) - val selfDestructTransferringToSelfCode = Assembly( + val selfDestructTransferringToSelfCode: Assembly = Assembly( PUSH20, extAddr.bytes, SELFDESTRUCT ) - val sstoreWithClearCode = Assembly( + val sstoreWithClearCode: Assembly = Assembly( //Save a value to the storage PUSH1, 10, @@ -76,7 +80,7 @@ class CallOpFixture(val config: EvmConfig, val startState: MockWorldState) { ) val valueToReturn = 23 - val returnSingleByteProgram = Assembly( + val returnSingleByteProgram: Assembly = Assembly( PUSH1, valueToReturn, PUSH1, @@ -89,7 +93,7 @@ class CallOpFixture(val config: EvmConfig, val startState: MockWorldState) { RETURN ) - val revertProgram = Assembly( + val revertProgram: Assembly = Assembly( PUSH1, valueToReturn, PUSH1, @@ -102,12 +106,12 @@ class CallOpFixture(val config: EvmConfig, val startState: MockWorldState) { REVERT ) - val inputData = Generators.getUInt256Gen().sample.get.bytes - val expectedMemCost = config.calcMemCost(inputData.size, inputData.size, inputData.size / 2) + val inputData: ByteString = Generators.getUInt256Gen().sample.get.bytes + val expectedMemCost: BigInt = config.calcMemCost(inputData.size, inputData.size, inputData.size / 2) - val initialBalance = UInt256(1000) + val initialBalance: UInt256 = UInt256(1000) - val requiredGas = { + val requiredGas: BigInt = { val storageCost = 3 * G_sset val memCost = config.calcMemCost(0, 0, 32) val copyCost = G_copy * wordsForBytes(32) @@ -117,47 +121,47 @@ class CallOpFixture(val config: EvmConfig, val startState: MockWorldState) { val gasMargin = 13 - val initialOwnerAccount = Account(balance = initialBalance) + val initialOwnerAccount: Account = Account(balance = initialBalance) val extProgram = extCode.program - val invalidProgram = Program(concatByteStrings(extProgram.code.init, INVALID.code)) + val invalidProgram: Program = Program(concatByteStrings(extProgram.code.init, INVALID.code)) val selfDestructProgram = selfDestructCode.program val sstoreWithClearProgram = sstoreWithClearCode.program val accountWithCode: ByteString => Account = code => Account.empty().withCode(kec256(code)) - val worldWithoutExtAccount = startState.saveAccount(ownerAddr, initialOwnerAccount) + val worldWithoutExtAccount: MockWorldState = startState.saveAccount(ownerAddr, initialOwnerAccount) - val worldWithExtAccount = worldWithoutExtAccount + val worldWithExtAccount: MockWorldState = worldWithoutExtAccount .saveAccount(extAddr, accountWithCode(extProgram.code)) .saveCode(extAddr, extProgram.code) - val worldWithExtEmptyAccount = worldWithoutExtAccount.saveAccount(extAddr, Account.empty()) + val worldWithExtEmptyAccount: MockWorldState = worldWithoutExtAccount.saveAccount(extAddr, Account.empty()) - val worldWithInvalidProgram = worldWithoutExtAccount + val worldWithInvalidProgram: MockWorldState = worldWithoutExtAccount .saveAccount(extAddr, accountWithCode(invalidProgram.code)) .saveCode(extAddr, invalidProgram.code) - val worldWithSelfDestructProgram = worldWithoutExtAccount + val worldWithSelfDestructProgram: MockWorldState = worldWithoutExtAccount .saveAccount(extAddr, accountWithCode(selfDestructProgram.code)) .saveCode(extAddr, selfDestructCode.code) - val worldWithRevertProgram = worldWithoutExtAccount + val worldWithRevertProgram: MockWorldState = worldWithoutExtAccount .saveAccount(extAddr, accountWithCode(revertProgram.code)) .saveCode(extAddr, revertProgram.code) - val worldWithSelfDestructSelfProgram = worldWithoutExtAccount + val worldWithSelfDestructSelfProgram: MockWorldState = worldWithoutExtAccount .saveAccount(extAddr, Account.empty()) .saveCode(extAddr, selfDestructTransferringToSelfCode.code) - val worldWithSstoreWithClearProgram = worldWithoutExtAccount + val worldWithSstoreWithClearProgram: MockWorldState = worldWithoutExtAccount .saveAccount(extAddr, accountWithCode(sstoreWithClearProgram.code)) .saveCode(extAddr, sstoreWithClearCode.code) - val worldWithReturnSingleByteCode = worldWithoutExtAccount + val worldWithReturnSingleByteCode: MockWorldState = worldWithoutExtAccount .saveAccount(extAddr, accountWithCode(returnSingleByteProgram.code)) .saveCode(extAddr, returnSingleByteProgram.code) - val fakeHeader = BlockFixtures.ValidBlock.header.copy(number = 0, unixTimestamp = 0) + val fakeHeader: BlockHeader = BlockFixtures.ValidBlock.header.copy(number = 0, unixTimestamp = 0) val context: PC = ProgramContext( callerAddr = callerAddr, @@ -192,7 +196,7 @@ class CallOpFixture(val config: EvmConfig, val startState: MockWorldState) { val vm = new TestVM - val env = ExecEnv(context, ByteString.empty, ownerAddr) + val env: ExecEnv = ExecEnv(context, ByteString.empty, ownerAddr) private val params = Seq(UInt256(gas), to.toUInt256, value, inOffset, inSize, outOffset, outSize).reverse diff --git a/src/test/scala/io/iohk/ethereum/vm/CallOpcodesSpec.scala b/src/test/scala/io/iohk/ethereum/vm/CallOpcodesSpec.scala index f2d9dbf74b..88e0042e21 100644 --- a/src/test/scala/io/iohk/ethereum/vm/CallOpcodesSpec.scala +++ b/src/test/scala/io/iohk/ethereum/vm/CallOpcodesSpec.scala @@ -1,21 +1,26 @@ package io.iohk.ethereum.vm import akka.util.ByteString + +import org.scalatest.matchers.should.Matchers +import org.scalatest.wordspec.AnyWordSpec +import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks + import io.iohk.ethereum.crypto._ -import io.iohk.ethereum.domain.{Account, Address, UInt256} +import io.iohk.ethereum.domain.Account +import io.iohk.ethereum.domain.Address +import io.iohk.ethereum.domain.UInt256 import io.iohk.ethereum.utils.ByteUtils import io.iohk.ethereum.vm.MockWorldState._ + import Fixtures.blockchainConfig -import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks -import org.scalatest.matchers.should.Matchers -import org.scalatest.wordspec.AnyWordSpec // scalastyle:off object.name // scalastyle:off file.size.limit class CallOpcodesSpec extends AnyWordSpec with Matchers with ScalaCheckPropertyChecks { - val config = EvmConfig.ByzantiumConfigBuilder(blockchainConfig) - val startState = MockWorldState(touchedAccounts = Set.empty) + val config: EvmConfig = EvmConfig.ByzantiumConfigBuilder(blockchainConfig) + val startState: MockWorldState = MockWorldState(touchedAccounts = Set.empty) import config.feeSchedule._ val fxt = new CallOpFixture(config, startState) @@ -256,8 +261,7 @@ class CallOpcodesSpec extends AnyWordSpec with Matchers with ScalaCheckPropertyC def callVarMemCost(config: EvmConfig): fxt.CallResult = { - /** - * Amount of memory which causes the improper OOG exception, if we don take memcost into account + /** Amount of memory which causes the improper OOG exception, if we don take memcost into account * during calculation of post EIP150 CALLOp gasCap: gasCap(state, gas, gExtra + memCost) */ val gasFailingBeforeEIP150Fix = 141072 @@ -675,8 +679,7 @@ class CallOpcodesSpec extends AnyWordSpec with Matchers with ScalaCheckPropertyC } } - /** - * This test should result in an OutOfGas error as (following the equations. on the DELEGATECALL opcode in the YP): + /** This test should result in an OutOfGas error as (following the equations. on the DELEGATECALL opcode in the YP): * DELEGATECALL cost = memoryCost + C_extra + C_gascap * and * memoryCost = 0 (result written were input was) @@ -687,7 +690,6 @@ class CallOpcodesSpec extends AnyWordSpec with Matchers with ScalaCheckPropertyC */ "gas cost bigger than available gas DELEGATECALL" should { - val memCost = 0 val c_extra = config.feeSchedule.G_call val startGas = c_extra - 1 val gas = UInt256.MaxValue - c_extra + 1 //u_s[0] diff --git a/src/test/scala/io/iohk/ethereum/vm/CallOpcodesSpecPostEip161.scala b/src/test/scala/io/iohk/ethereum/vm/CallOpcodesSpecPostEip161.scala index 1f847d2ba1..4da32479db 100644 --- a/src/test/scala/io/iohk/ethereum/vm/CallOpcodesSpecPostEip161.scala +++ b/src/test/scala/io/iohk/ethereum/vm/CallOpcodesSpecPostEip161.scala @@ -1,17 +1,20 @@ package io.iohk.ethereum.vm -import io.iohk.ethereum.domain.{Address, UInt256} -import io.iohk.ethereum.vm.MockWorldState._ -import Fixtures.blockchainConfig -import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks import org.scalatest.matchers.should.Matchers import org.scalatest.wordspec.AnyWordSpec +import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks + +import io.iohk.ethereum.domain.Address +import io.iohk.ethereum.domain.UInt256 +import io.iohk.ethereum.vm.MockWorldState._ + +import Fixtures.blockchainConfig // scalastyle:off object.name class CallOpcodesSpecPostEip161 extends AnyWordSpec with Matchers with ScalaCheckPropertyChecks { - val config = EvmConfig.PostEIP161ConfigBuilder(blockchainConfig) - val startState = MockWorldState(touchedAccounts = Set.empty, noEmptyAccountsCond = true) + val config: EvmConfig = EvmConfig.PostEIP161ConfigBuilder(blockchainConfig) + val startState: MockWorldState = MockWorldState(touchedAccounts = Set.empty, noEmptyAccountsCond = true) import config.feeSchedule._ val fxt = new CallOpFixture(config, startState) diff --git a/src/test/scala/io/iohk/ethereum/vm/CreateOpcodeSpec.scala b/src/test/scala/io/iohk/ethereum/vm/CreateOpcodeSpec.scala index 0ef7187f3a..9d7f7a5f52 100644 --- a/src/test/scala/io/iohk/ethereum/vm/CreateOpcodeSpec.scala +++ b/src/test/scala/io/iohk/ethereum/vm/CreateOpcodeSpec.scala @@ -1,32 +1,39 @@ package io.iohk.ethereum.vm -import io.iohk.ethereum.domain.{Account, Address, UInt256} -import io.iohk.ethereum.Fixtures.{Blocks => BlockFixtures} -import MockWorldState._ import akka.util.ByteString -import Fixtures.blockchainConfig -import io.iohk.ethereum.crypto.kec256 + import org.bouncycastle.util.encoders.Hex -import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks import org.scalatest.matchers.should.Matchers import org.scalatest.wordspec.AnyWordSpec +import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks + +import io.iohk.ethereum.Fixtures.{Blocks => BlockFixtures} +import io.iohk.ethereum.crypto.kec256 +import io.iohk.ethereum.domain.Account +import io.iohk.ethereum.domain.Address +import io.iohk.ethereum.domain.BlockHeader +import io.iohk.ethereum.domain.UInt256 + +import MockWorldState._ +import Fixtures.blockchainConfig // scalastyle:off method.length class CreateOpcodeSpec extends AnyWordSpec with Matchers with ScalaCheckPropertyChecks { - val config = EvmConfig.ByzantiumConfigBuilder(blockchainConfig) + val config: EvmConfig = EvmConfig.ByzantiumConfigBuilder(blockchainConfig) import config.feeSchedule._ // scalastyle:off object fxt { - val fakeHeader = BlockFixtures.ValidBlock.header.copy(number = blockchainConfig.constantinopleBlockNumber - 1) - val addresWithRevert = Address(10) - val creatorAddr = Address(0xcafe) + val fakeHeader: BlockHeader = + BlockFixtures.ValidBlock.header.copy(number = blockchainConfig.constantinopleBlockNumber - 1) + val addresWithRevert: Address = Address(10) + val creatorAddr: Address = Address(0xcafe) val salt = UInt256.Zero // doubles the value passed in the input data - val contractCode = Assembly( + val contractCode: Assembly = Assembly( PUSH1, 0, CALLDATALOAD, @@ -61,15 +68,15 @@ class CreateOpcodeSpec extends AnyWordSpec with Matchers with ScalaCheckProperty RETURN ) - val initWithSelfDestruct = Assembly( + val initWithSelfDestruct: Assembly = Assembly( PUSH1, creatorAddr.toUInt256.toInt, SELFDESTRUCT ) - val gas1000 = ByteString(3, -24) + val gas1000: ByteString = ByteString(3, -24) - val initWithSelfDestructAndCall = Assembly( + val initWithSelfDestructAndCall: Assembly = Assembly( PUSH1, 1, PUSH1, @@ -90,7 +97,7 @@ class CreateOpcodeSpec extends AnyWordSpec with Matchers with ScalaCheckProperty SELFDESTRUCT ) - val initWithSstoreWithClear = Assembly( + val initWithSstoreWithClear: Assembly = Assembly( //Save a value to the storage PUSH1, 10, @@ -106,7 +113,7 @@ class CreateOpcodeSpec extends AnyWordSpec with Matchers with ScalaCheckProperty ) val revertValue = 21 - val initWithRevertProgram = Assembly( + val initWithRevertProgram: Assembly = Assembly( PUSH1, revertValue, PUSH1, @@ -119,7 +126,7 @@ class CreateOpcodeSpec extends AnyWordSpec with Matchers with ScalaCheckProperty REVERT ) - val revertProgram = Assembly( + val revertProgram: Assembly = Assembly( PUSH1, revertValue, PUSH1, @@ -135,22 +142,24 @@ class CreateOpcodeSpec extends AnyWordSpec with Matchers with ScalaCheckProperty val accountWithCode: ByteString => Account = code => Account.empty().withCode(kec256(code)) val endowment: UInt256 = 123 - val initWorld = MockWorldState().saveAccount(creatorAddr, Account.empty().increaseBalance(endowment)) - val newAddr = initWorld.increaseNonce(creatorAddr).createAddress(creatorAddr) + val initWorld: MockWorldState = + MockWorldState().saveAccount(creatorAddr, Account.empty().increaseBalance(endowment)) + val newAddr: Address = initWorld.increaseNonce(creatorAddr).createAddress(creatorAddr) - val worldWithRevertProgram = initWorld + val worldWithRevertProgram: MockWorldState = initWorld .saveAccount(addresWithRevert, accountWithCode(revertProgram.code)) .saveCode(addresWithRevert, revertProgram.code) - val createCode = Assembly(initPart(contractCode.code.size).byteCode ++ contractCode.byteCode: _*) + val createCode: Assembly = Assembly(initPart(contractCode.code.size).byteCode ++ contractCode.byteCode: _*) - val copyCodeGas = G_copy * wordsForBytes(contractCode.code.size) + config.calcMemCost(0, 0, contractCode.code.size) + val copyCodeGas: BigInt = + G_copy * wordsForBytes(contractCode.code.size) + config.calcMemCost(0, 0, contractCode.code.size) val storeGas = G_sset - def gasRequiredForInit(withHashCost: Boolean) = initPart(contractCode.code.size).linearConstGas( + def gasRequiredForInit(withHashCost: Boolean): BigInt = initPart(contractCode.code.size).linearConstGas( config ) + copyCodeGas + storeGas + (if (withHashCost) G_sha3word * wordsForBytes(contractCode.code.size) else 0) - val depositGas = config.calcCodeDepositCost(contractCode.code) - def gasRequiredForCreation(withHashCost: Boolean) = gasRequiredForInit(withHashCost) + depositGas + G_create + val depositGas: BigInt = config.calcCodeDepositCost(contractCode.code) + def gasRequiredForCreation(withHashCost: Boolean): BigInt = gasRequiredForInit(withHashCost) + depositGas + G_create val context: PC = ProgramContext( callerAddr = Address(0), @@ -180,11 +189,11 @@ class CreateOpcodeSpec extends AnyWordSpec with Matchers with ScalaCheckProperty ownerAddress: Address = fxt.creatorAddr ) { val vm = new TestVM - val env = ExecEnv(context, ByteString.empty, ownerAddress) + val env: ExecEnv = ExecEnv(context, ByteString.empty, ownerAddress) - val mem = Memory.empty.store(0, createCode) - val stack = opcode match { - case CREATE => Stack.empty().push(Seq[UInt256](createCode.size, 0, value)) + val mem: Memory = Memory.empty.store(0, createCode) + val stack: Stack = opcode match { + case CREATE => Stack.empty().push(Seq[UInt256](createCode.size, 0, value)) case CREATE2 => Stack.empty().push(Seq[UInt256](salt, createCode.size, 0, value)) } val stateIn: PS = ProgramState(vm, context, env).withStack(stack).withMemory(mem) @@ -196,12 +205,12 @@ class CreateOpcodeSpec extends AnyWordSpec with Matchers with ScalaCheckProperty def commonBehaviour(opcode: CreateOp): Unit = { def newAccountAddress(code: ByteString = fxt.createCode.code) = opcode match { - case CREATE => fxt.initWorld.increaseNonce(fxt.creatorAddr).createAddress(fxt.creatorAddr) + case CREATE => fxt.initWorld.increaseNonce(fxt.creatorAddr).createAddress(fxt.creatorAddr) case CREATE2 => fxt.initWorld.create2Address(fxt.creatorAddr, fxt.salt, code) } val withHashCost = opcode match { - case CREATE => false + case CREATE => false case CREATE2 => true } @@ -480,7 +489,7 @@ class CreateOpcodeSpec extends AnyWordSpec with Matchers with ScalaCheckProperty } "CREATE" should { - behave like commonBehaviour(CREATE) + behave.like(commonBehaviour(CREATE)) "account with non-zero balance, but empty code and zero nonce, already exists" should { @@ -503,7 +512,7 @@ class CreateOpcodeSpec extends AnyWordSpec with Matchers with ScalaCheckProperty } "CREATE2" should { - behave like commonBehaviour(CREATE2) + behave.like(commonBehaviour(CREATE2)) "returns correct address and spends correct amount of gas (examples from https://eips.ethereum.org/EIPS/eip-1014)" in { diff --git a/src/test/scala/io/iohk/ethereum/vm/Fixtures.scala b/src/test/scala/io/iohk/ethereum/vm/Fixtures.scala index 78260e8773..72a090564f 100644 --- a/src/test/scala/io/iohk/ethereum/vm/Fixtures.scala +++ b/src/test/scala/io/iohk/ethereum/vm/Fixtures.scala @@ -7,7 +7,7 @@ object Fixtures { val PhoenixBlockNumber = 600 val IstanbulBlockNumber = 600 - val blockchainConfig = BlockchainConfigForEvm( + val blockchainConfig: BlockchainConfigForEvm = BlockchainConfigForEvm( // block numbers are irrelevant frontierBlockNumber = 0, homesteadBlockNumber = 0, diff --git a/src/test/scala/io/iohk/ethereum/vm/Generators.scala b/src/test/scala/io/iohk/ethereum/vm/Generators.scala index 14721cf566..cde8a5afed 100644 --- a/src/test/scala/io/iohk/ethereum/vm/Generators.scala +++ b/src/test/scala/io/iohk/ethereum/vm/Generators.scala @@ -1,11 +1,17 @@ package io.iohk.ethereum.vm import akka.util.ByteString -import io.iohk.ethereum.ObjectGenerators -import io.iohk.ethereum.domain.{Account, Address, UInt256} + +import org.scalacheck.Arbitrary +import org.scalacheck.Gen + import io.iohk.ethereum.Fixtures.{Blocks => BlockFixtures} +import io.iohk.ethereum.ObjectGenerators +import io.iohk.ethereum.domain.Account +import io.iohk.ethereum.domain.Address +import io.iohk.ethereum.domain.UInt256 import io.iohk.ethereum.vm.MockWorldState._ -import org.scalacheck.{Arbitrary, Gen} + import Fixtures.blockchainConfig // scalastyle:off magic.number @@ -61,8 +67,8 @@ object Generators extends ObjectGenerators { def getStorageGen(maxSize: Int = 0, uint256Gen: Gen[UInt256] = getUInt256Gen()): Gen[MockStorage] = getListGen(0, maxSize, uint256Gen).map(MockStorage.fromSeq) - val ownerAddr = Address(0x123456) - val callerAddr = Address(0xabcdef) + val ownerAddr: Address = Address(0x123456) + val callerAddr: Address = Address(0xabcdef) val exampleBlockHeader = BlockFixtures.ValidBlock.header diff --git a/src/test/scala/io/iohk/ethereum/vm/MemorySpec.scala b/src/test/scala/io/iohk/ethereum/vm/MemorySpec.scala index 1a480901d8..a6c179a933 100644 --- a/src/test/scala/io/iohk/ethereum/vm/MemorySpec.scala +++ b/src/test/scala/io/iohk/ethereum/vm/MemorySpec.scala @@ -1,28 +1,29 @@ package io.iohk.ethereum.vm import akka.util.ByteString -import io.iohk.ethereum.vm.Generators._ -import org.scalacheck.{Arbitrary, Gen} -import io.iohk.ethereum.domain.UInt256 -import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks + +import org.scalacheck.Arbitrary +import org.scalacheck.Gen import org.scalatest.funsuite.AnyFunSuite import org.scalatest.matchers.should.Matchers +import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks + +import io.iohk.ethereum.domain.UInt256 +import io.iohk.ethereum.vm.Generators._ class MemorySpec extends AnyFunSuite with ScalaCheckPropertyChecks with Matchers { - def zeros(size: Int): ByteString = { + def zeros(size: Int): ByteString = if (size <= 0) ByteString() else ByteString(Array.fill[Byte](size)(0)) - } - def consecutiveBytes(size: Int, start: Int = 0): ByteString = { + def consecutiveBytes(size: Int, start: Int = 0): ByteString = if (size <= 0) ByteString() else ByteString((start until (start + size)).map(_.toByte): _*) - } import Arbitrary._ import Gen._ diff --git a/src/test/scala/io/iohk/ethereum/vm/MockStorage.scala b/src/test/scala/io/iohk/ethereum/vm/MockStorage.scala index 0ca9a486d4..a0ec664afd 100644 --- a/src/test/scala/io/iohk/ethereum/vm/MockStorage.scala +++ b/src/test/scala/io/iohk/ethereum/vm/MockStorage.scala @@ -3,7 +3,7 @@ package io.iohk.ethereum.vm import io.iohk.ethereum.domain.UInt256 object MockStorage { - val Empty = MockStorage() + val Empty: MockStorage = MockStorage() def fromSeq(words: Seq[UInt256]): MockStorage = { val map = words.zipWithIndex.map { case (w, i) => BigInt(i) -> w.toBigInt }.toMap diff --git a/src/test/scala/io/iohk/ethereum/vm/MockWorldState.scala b/src/test/scala/io/iohk/ethereum/vm/MockWorldState.scala index 4cffae3865..5f9ea0d1e8 100644 --- a/src/test/scala/io/iohk/ethereum/vm/MockWorldState.scala +++ b/src/test/scala/io/iohk/ethereum/vm/MockWorldState.scala @@ -1,8 +1,11 @@ package io.iohk.ethereum.vm import akka.util.ByteString + import io.iohk.ethereum.crypto.kec256 -import io.iohk.ethereum.domain.{Account, Address, UInt256} +import io.iohk.ethereum.domain.Account +import io.iohk.ethereum.domain.Address +import io.iohk.ethereum.domain.UInt256 object MockWorldState { type TestVM = VM[MockWorldState, MockStorage] @@ -69,10 +72,9 @@ case class MockWorldState( def noEmptyAccounts: Boolean = noEmptyAccountsCond - override def keepPrecompileTouched(world: MockWorldState): MockWorldState = { + override def keepPrecompileTouched(world: MockWorldState): MockWorldState = if (world.touchedAccounts.contains(ripmdContractAddress)) copy(touchedAccounts = touchedAccounts + ripmdContractAddress) else this - } } diff --git a/src/test/scala/io/iohk/ethereum/vm/OpCodeFunSpec.scala b/src/test/scala/io/iohk/ethereum/vm/OpCodeFunSpec.scala index d67107bb46..be07c77968 100644 --- a/src/test/scala/io/iohk/ethereum/vm/OpCodeFunSpec.scala +++ b/src/test/scala/io/iohk/ethereum/vm/OpCodeFunSpec.scala @@ -1,28 +1,33 @@ package io.iohk.ethereum.vm import akka.util.ByteString -import io.iohk.ethereum.crypto.kec256 -import io.iohk.ethereum.domain.{Account, Address, TxLogEntry, UInt256} -import io.iohk.ethereum.vm.Generators._ -import io.iohk.ethereum.domain.UInt256._ + import org.scalacheck.Gen -import Fixtures.blockchainConfig -import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks import org.scalatest.funsuite.AnyFunSuite import org.scalatest.matchers.should.Matchers +import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks + +import io.iohk.ethereum.crypto.kec256 +import io.iohk.ethereum.domain.Account +import io.iohk.ethereum.domain.Address +import io.iohk.ethereum.domain.TxLogEntry +import io.iohk.ethereum.domain.UInt256 +import io.iohk.ethereum.domain.UInt256._ +import io.iohk.ethereum.vm.Generators._ + +import Fixtures.blockchainConfig class OpCodeFunSpec extends AnyFunSuite with OpCodeTesting with Matchers with ScalaCheckPropertyChecks { import MockWorldState.PS - override val config = EvmConfig.PhoenixConfigBuilder(blockchainConfig) + override val config: EvmConfig = EvmConfig.PhoenixConfigBuilder(blockchainConfig) - def executeOp(op: OpCode, stateIn: PS): PS = { + def executeOp(op: OpCode, stateIn: PS): PS = // gas is not tested in this spec op.execute(stateIn).copy(gas = stateIn.gas, gasRefund = stateIn.gasRefund) - } - def withStackVerification(op: OpCode, stateIn: PS, stateOut: PS)(body: => Any): Any = { + def withStackVerification(op: OpCode, stateIn: PS, stateOut: PS)(body: => Any): Any = if (stateIn.stack.size < op.delta) stateOut shouldEqual stateIn.withError(StackUnderflow).halt else if (stateIn.stack.size - op.delta + op.alpha > stateIn.stack.maxSize) @@ -38,7 +43,6 @@ class OpCodeFunSpec extends AnyFunSuite with OpCodeTesting with Matchers with Sc } body } - } def stateWithCode(state: PS, code: ByteString): PS = { val newProgram = Program(code) @@ -161,7 +165,7 @@ class OpCodeFunSpec extends AnyFunSuite with OpCodeTesting with Matchers with Sc val (addr, stack1) = stateIn.stack.pop val account = Account(balance = accountBalance) - val world1 = stateIn.world.saveAccount(Address(addr mod UInt256(BigInt(2).pow(160))), account) + val world1 = stateIn.world.saveAccount(Address(addr.mod(UInt256(BigInt(2).pow(160)))), account) val stateInWithAccount = stateIn.withWorld(world1) val stateOutWithAccount = executeOp(op, stateInWithAccount) @@ -185,7 +189,7 @@ class OpCodeFunSpec extends AnyFunSuite with OpCodeTesting with Matchers with Sc val codeHash = kec256(extCode) val account = Account(codeHash = codeHash) - val accAddr = Address(addr mod UInt256(BigInt(2).pow(160))) + val accAddr = Address(addr.mod(UInt256(BigInt(2).pow(160)))) val world1 = stateIn.world.saveAccount(accAddr, account).saveCode(accAddr, extCode) val stateInWithAccount = stateIn.withWorld(world1) @@ -410,7 +414,7 @@ class OpCodeFunSpec extends AnyFunSuite with OpCodeTesting with Matchers with Sc withStackVerification(op, stateIn, stateOut) { val (Seq(offset, value), _) = stateIn.stack.pop(2) val (data, _) = stateOut.memory.load(offset, 1) - ByteString((value mod 256).toByte) shouldEqual data + ByteString(value.mod(256).toByte) shouldEqual data stateOut shouldEqual stateIn.withStack(stateOut.stack).withMemory(stateOut.memory).step() } diff --git a/src/test/scala/io/iohk/ethereum/vm/OpCodeGasSpec.scala b/src/test/scala/io/iohk/ethereum/vm/OpCodeGasSpec.scala index d237daa747..9246f53602 100644 --- a/src/test/scala/io/iohk/ethereum/vm/OpCodeGasSpec.scala +++ b/src/test/scala/io/iohk/ethereum/vm/OpCodeGasSpec.scala @@ -1,17 +1,21 @@ package io.iohk.ethereum.vm -import io.iohk.ethereum.domain.UInt256._ -import io.iohk.ethereum.domain.{Account, Address, UInt256} -import io.iohk.ethereum.vm.Generators._ -import Fixtures.blockchainConfig import org.scalacheck.Gen -import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks import org.scalatest.funsuite.AnyFunSuite import org.scalatest.matchers.should.Matchers +import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks + +import io.iohk.ethereum.domain.Account +import io.iohk.ethereum.domain.Address +import io.iohk.ethereum.domain.UInt256 +import io.iohk.ethereum.domain.UInt256._ +import io.iohk.ethereum.vm.Generators._ + +import Fixtures.blockchainConfig class OpCodeGasSpec extends AnyFunSuite with OpCodeTesting with Matchers with ScalaCheckPropertyChecks { - override val config = EvmConfig.PhoenixConfigBuilder(blockchainConfig) + override val config: EvmConfig = EvmConfig.PhoenixConfigBuilder(blockchainConfig) import config.feeSchedule._ @@ -556,7 +560,7 @@ class OpCodeGasSpec extends AnyFunSuite with OpCodeTesting with Matchers with Sc } // Sending refund to an already existing account - forAll(stateGen) { (stateIn) => + forAll(stateGen) { stateIn => val (refund, _) = stateIn.stack.pop val world = stateIn.world.saveAccount(Address(refund), Account.empty()) val updatedStateIn = stateIn.withWorld(world) diff --git a/src/test/scala/io/iohk/ethereum/vm/OpCodeGasSpecPostEip161.scala b/src/test/scala/io/iohk/ethereum/vm/OpCodeGasSpecPostEip161.scala index c62cc63b26..b0db96329c 100644 --- a/src/test/scala/io/iohk/ethereum/vm/OpCodeGasSpecPostEip161.scala +++ b/src/test/scala/io/iohk/ethereum/vm/OpCodeGasSpecPostEip161.scala @@ -1,16 +1,19 @@ package io.iohk.ethereum.vm +import org.scalatest.funsuite.AnyFunSuite +import org.scalatest.matchers.should.Matchers +import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks + +import io.iohk.ethereum.domain.Account +import io.iohk.ethereum.domain.Address import io.iohk.ethereum.domain.UInt256._ -import io.iohk.ethereum.domain.{Account, Address} import io.iohk.ethereum.vm.Generators._ + import Fixtures.blockchainConfig -import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks -import org.scalatest.funsuite.AnyFunSuite -import org.scalatest.matchers.should.Matchers class OpCodeGasSpecPostEip161 extends AnyFunSuite with OpCodeTesting with Matchers with ScalaCheckPropertyChecks { - override val config = EvmConfig.PostEIP161ConfigBuilder(blockchainConfig) + override val config: EvmConfig = EvmConfig.PostEIP161ConfigBuilder(blockchainConfig) import config.feeSchedule._ @@ -31,7 +34,7 @@ class OpCodeGasSpecPostEip161 extends AnyFunSuite with OpCodeTesting with Matche } // Sending refund to an already existing account not dead account - forAll(stateGen) { (stateIn) => + forAll(stateGen) { stateIn => val (refund, _) = stateIn.stack.pop val world = stateIn.world.saveAccount(Address(refund), Account.empty().increaseNonce()) val updatedStateIn = stateIn.withWorld(world) diff --git a/src/test/scala/io/iohk/ethereum/vm/OpCodeTesting.scala b/src/test/scala/io/iohk/ethereum/vm/OpCodeTesting.scala index c895730425..c1adbe761d 100644 --- a/src/test/scala/io/iohk/ethereum/vm/OpCodeTesting.scala +++ b/src/test/scala/io/iohk/ethereum/vm/OpCodeTesting.scala @@ -1,23 +1,24 @@ package io.iohk.ethereum.vm -import io.iohk.ethereum.vm.MockWorldState.PS import org.scalatest.funsuite.AnyFunSuiteLike import org.scalatest.matchers.should.Matchers +import io.iohk.ethereum.vm.MockWorldState.PS + trait OpCodeTesting extends AnyFunSuiteLike { matchers: Matchers => val config: EvmConfig - lazy val unaryOps = config.opCodes.collect { case op: UnaryOp => op } - lazy val binaryOps = config.opCodes.collect { case op: BinaryOp => op } - lazy val ternaryOps = config.opCodes.collect { case op: TernaryOp => op } - lazy val constOps = config.opCodes.collect { case op: ConstOp => op } - lazy val pushOps = config.opCodes.collect { case op: PushOp => op } - lazy val dupOps = config.opCodes.collect { case op: DupOp => op } - lazy val swapOps = config.opCodes.collect { case op: SwapOp => op } - lazy val logOps = config.opCodes.collect { case op: LogOp => op } - lazy val constGasOps = config.opCodes.collect { case op: ConstGas if op != INVALID => op } + lazy val unaryOps: List[UnaryOp] = config.opCodes.collect { case op: UnaryOp => op } + lazy val binaryOps: List[BinaryOp] = config.opCodes.collect { case op: BinaryOp => op } + lazy val ternaryOps: List[TernaryOp] = config.opCodes.collect { case op: TernaryOp => op } + lazy val constOps: List[ConstOp] = config.opCodes.collect { case op: ConstOp => op } + lazy val pushOps: List[PushOp] = config.opCodes.collect { case op: PushOp => op } + lazy val dupOps: List[DupOp] = config.opCodes.collect { case op: DupOp => op } + lazy val swapOps: List[SwapOp] = config.opCodes.collect { case op: SwapOp => op } + lazy val logOps: List[LogOp] = config.opCodes.collect { case op: LogOp => op } + lazy val constGasOps: List[OpCode with ConstGas] = config.opCodes.collect { case op: ConstGas if op != INVALID => op } def test[T <: OpCode](ops: T*)(f: T => Any): Unit = ops.foreach(op => test(op.toString)(f(op))) @@ -25,11 +26,10 @@ trait OpCodeTesting extends AnyFunSuiteLike { def ignore[T <: OpCode](ops: T*)(f: T => Any): Unit = ops.foreach(op => ignore(op.toString)(f(op))) - /** - * Run this as the last test in the suite + /** Run this as the last test in the suite * Ignoring an OpCode test will NOT cause this test to fail */ - def verifyAllOpCodesRegistered(except: OpCode*): Unit = { + def verifyAllOpCodesRegistered(except: OpCode*): Unit = test("all opcodes have been registered") { val untested = config.opCodes.filterNot(op => testNames(op.toString)).diff(except) if (untested.isEmpty) @@ -37,17 +37,16 @@ trait OpCodeTesting extends AnyFunSuiteLike { else fail("Unregistered opcodes: " + untested.mkString(", ")) } - } - def verifyGas(expectedGas: BigInt, stateIn: PS, stateOut: PS, allowOOG: Boolean = true): Unit = { + def verifyGas(expectedGas: BigInt, stateIn: PS, stateOut: PS, allowOOG: Boolean = true): Unit = if (stateOut.error.contains(OutOfGas) && allowOOG) stateIn.gas should be < expectedGas else if (stateOut.error.contains(OutOfGas) && !allowOOG) fail(s"Unexpected $OutOfGas error") else if ( stateOut.error.isDefined && stateOut.error.collect { - case InvalidJump(_) => () - case RevertOccurs => () + case InvalidJump(_) => () + case RevertOccurs => () case ReturnDataOverflow => () }.isEmpty ) { @@ -56,5 +55,4 @@ trait OpCodeTesting extends AnyFunSuiteLike { } else { stateOut.gas shouldEqual (stateIn.gas - expectedGas) } - } } diff --git a/src/test/scala/io/iohk/ethereum/vm/PrecompiledContractsSpec.scala b/src/test/scala/io/iohk/ethereum/vm/PrecompiledContractsSpec.scala index 606280f7ac..de1e29e332 100644 --- a/src/test/scala/io/iohk/ethereum/vm/PrecompiledContractsSpec.scala +++ b/src/test/scala/io/iohk/ethereum/vm/PrecompiledContractsSpec.scala @@ -1,19 +1,25 @@ package io.iohk.ethereum.vm import akka.util.ByteString -import io.iohk.ethereum.crypto._ -import io.iohk.ethereum.domain.{Account, Address, UInt256} -import io.iohk.ethereum.Fixtures.{Blocks => BlockFixtures} -import MockWorldState._ -import io.iohk.ethereum.utils.ByteUtils + import org.bouncycastle.util.encoders.Hex -import Fixtures.blockchainConfig -import io.iohk.ethereum.security.SecureRandomBuilder -import io.iohk.ethereum.vm.BlockchainConfigForEvm.{EtcForks, EthForks} -import io.iohk.ethereum.vm.PrecompiledContracts.ModExp -import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks import org.scalatest.funsuite.AnyFunSuite import org.scalatest.matchers.should.Matchers +import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks + +import io.iohk.ethereum.Fixtures.{Blocks => BlockFixtures} +import io.iohk.ethereum.crypto._ +import io.iohk.ethereum.domain.Account +import io.iohk.ethereum.domain.Address +import io.iohk.ethereum.domain.UInt256 +import io.iohk.ethereum.security.SecureRandomBuilder +import io.iohk.ethereum.utils.ByteUtils +import io.iohk.ethereum.vm.BlockchainConfigForEvm.EtcForks +import io.iohk.ethereum.vm.BlockchainConfigForEvm.EthForks +import io.iohk.ethereum.vm.PrecompiledContracts.ModExp + +import MockWorldState._ +import Fixtures.blockchainConfig class PrecompiledContractsSpec extends AnyFunSuite @@ -235,7 +241,7 @@ class PrecompiledContractsSpec } } - val modexpTestInputs = Map( + val modexpTestInputs: Map[String, (String, String)] = Map( "modexp_nagydani_1_square" -> ("000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000040e09ad9675465c53a109fac66a445c91b292d2bb2c5268addb30cd82f80fcb0033ff97c80a5fc6f39193ae969c6ede6710a6b7ac27078a06d90ef1c72e5c85fb502fc9e1f6beb81516545975218075ec2af118cd8798df6e08a147c60fd6095ac2bb02c2908cf4dd7c81f11c289e4bce98f3553768f392a80ce22bf5c4f4a248c6b", "60008f1614cc01dcfb6bfb09c625cf90b47d4468db81b5f8b7a39d42f332eab9b2da8f2d95311648a8f243f4bb13cfb3d8f7f2a3c014122ebb3ed41b02783adc"), diff --git a/src/test/scala/io/iohk/ethereum/vm/ProgramSpec.scala b/src/test/scala/io/iohk/ethereum/vm/ProgramSpec.scala index 1668d8bd9b..dfdc119407 100644 --- a/src/test/scala/io/iohk/ethereum/vm/ProgramSpec.scala +++ b/src/test/scala/io/iohk/ethereum/vm/ProgramSpec.scala @@ -1,11 +1,13 @@ package io.iohk.ethereum.vm -import Generators._ import akka.util.ByteString + import org.scalacheck.Gen -import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks import org.scalatest.flatspec.AnyFlatSpec import org.scalatest.matchers.should.Matchers +import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks + +import Generators._ class ProgramSpec extends AnyFlatSpec with Matchers with ScalaCheckPropertyChecks { @@ -40,7 +42,10 @@ class ProgramSpec extends AnyFlatSpec with Matchers with ScalaCheckPropertyCheck //Removing the PUSH1 that would be used as a parameter of another PUSH1 // Example: In "PUSH1 PUSH1 JUMPDEST", the JUMPDEST is a valid jump destination - val pushOpLocationsNotParameters = (pushOpLocations diff jumpDestLocations).toList.sorted + val pushOpLocationsNotParameters = pushOpLocations + .diff(jumpDestLocations) + .toList + .sorted .foldLeft(List.empty[Int]) { case (recPushOpLocations, i) => if (recPushOpLocations.lastOption.contains(i - 1)) recPushOpLocations else recPushOpLocations :+ i } diff --git a/src/test/scala/io/iohk/ethereum/vm/SSTOREOpCodeGasPostConstantinopleSpec.scala b/src/test/scala/io/iohk/ethereum/vm/SSTOREOpCodeGasPostConstantinopleSpec.scala index 81254bfeab..4afc84fa76 100644 --- a/src/test/scala/io/iohk/ethereum/vm/SSTOREOpCodeGasPostConstantinopleSpec.scala +++ b/src/test/scala/io/iohk/ethereum/vm/SSTOREOpCodeGasPostConstantinopleSpec.scala @@ -1,16 +1,21 @@ package io.iohk.ethereum.vm import akka.util.ByteString -import io.iohk.ethereum.domain.{Account, Address, BlockHeader} -import io.iohk.ethereum.Fixtures.{Blocks => BlockFixtures} -import io.iohk.ethereum.vm.Fixtures.blockchainConfig -import io.iohk.ethereum.vm.MockWorldState.{PC, TestVM} import akka.util.ByteString.{empty => bEmpty} -import io.iohk.ethereum.crypto.kec256 + import org.bouncycastle.util.encoders.Hex -import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks import org.scalatest.matchers.should.Matchers import org.scalatest.wordspec.AnyWordSpec +import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks + +import io.iohk.ethereum.Fixtures.{Blocks => BlockFixtures} +import io.iohk.ethereum.crypto.kec256 +import io.iohk.ethereum.domain.Account +import io.iohk.ethereum.domain.Address +import io.iohk.ethereum.domain.BlockHeader +import io.iohk.ethereum.vm.Fixtures.blockchainConfig +import io.iohk.ethereum.vm.MockWorldState.PC +import io.iohk.ethereum.vm.MockWorldState.TestVM class StoreOpCodeGasPostConstantinopleSpec extends AnyWordSpec @@ -44,13 +49,11 @@ class StoreOpCodeGasPostConstantinopleSpec ) forAll(eip1283table) { (code, original, gasUsed, refund) => - { - val result = - vm.exec(prepareProgramState(ByteString(Hex.decode(code)), original, defaultGaspool, EipToCheck.EIP1283)) + val result = + vm.exec(prepareProgramState(ByteString(Hex.decode(code)), original, defaultGaspool, EipToCheck.EIP1283)) - result.gasUsed shouldEqual gasUsed - result.gasRefund shouldEqual refund - } + result.gasUsed shouldEqual gasUsed + result.gasRefund shouldEqual refund } } @@ -80,13 +83,11 @@ class StoreOpCodeGasPostConstantinopleSpec ) forAll(eip2200table) { (code, original, gasUsed, refund, gaspool, maybeError) => - { - val result = vm.exec(prepareProgramState(ByteString(Hex.decode(code)), original, gaspool, EipToCheck.EIP2200)) + val result = vm.exec(prepareProgramState(ByteString(Hex.decode(code)), original, gaspool, EipToCheck.EIP2200)) - result.gasUsed shouldEqual gasUsed - result.gasRefund shouldEqual refund - result.error shouldEqual maybeError - } + result.gasUsed shouldEqual gasUsed + result.gasRefund shouldEqual refund + result.error shouldEqual maybeError } } } @@ -94,8 +95,8 @@ class StoreOpCodeGasPostConstantinopleSpec trait TestSetup { val vm = new TestVM - val senderAddr = Address(0xcafebabeL) - val senderAcc = Account(nonce = 1, balance = 1000000) + val senderAddr: Address = Address(0xcafebabeL) + val senderAcc: Account = Account(nonce = 1, balance = 1000000) val accountWithCode: ByteString => Account = code => Account.empty().withCode(kec256(code)) diff --git a/src/test/scala/io/iohk/ethereum/vm/ShiftingOpCodeSpec.scala b/src/test/scala/io/iohk/ethereum/vm/ShiftingOpCodeSpec.scala index 28d53ca897..a0d54f2954 100644 --- a/src/test/scala/io/iohk/ethereum/vm/ShiftingOpCodeSpec.scala +++ b/src/test/scala/io/iohk/ethereum/vm/ShiftingOpCodeSpec.scala @@ -2,37 +2,61 @@ package io.iohk.ethereum.vm import akka.util.ByteString import akka.util.ByteString.{empty => bEmpty} -import io.iohk.ethereum.crypto.kec256 -import io.iohk.ethereum.domain.{Account, Address, UInt256} -import io.iohk.ethereum.Fixtures.{Blocks => BlockFixtures} -import io.iohk.ethereum.vm.Fixtures.blockchainConfig -import io.iohk.ethereum.vm.MockWorldState.{PC, TestVM} + import org.bouncycastle.util.encoders.Hex -import org.scalatest.prop.TableFor5 -import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks import org.scalatest.matchers.should.Matchers +import org.scalatest.prop.TableFor5 import org.scalatest.wordspec.AnyWordSpec +import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks + +import io.iohk.ethereum.Fixtures.{Blocks => BlockFixtures} +import io.iohk.ethereum.crypto.kec256 +import io.iohk.ethereum.domain.Account +import io.iohk.ethereum.domain.Address +import io.iohk.ethereum.domain.BlockHeader +import io.iohk.ethereum.domain.UInt256 +import io.iohk.ethereum.vm.Fixtures.blockchainConfig +import io.iohk.ethereum.vm.MockWorldState.PC +import io.iohk.ethereum.vm.MockWorldState.TestVM // scalastyle:off magic.number class ShiftingOpCodeSpec extends AnyWordSpec with Matchers with ScalaCheckPropertyChecks { - val array_0x01 = Array(1.toByte) - val array_0x00 = Array(0.toByte) + val array_0x01: Array[Byte] = Array(1.toByte) + val array_0x00: Array[Byte] = Array(0.toByte) val byteCode_0x80: Array[Byte] = array_0x01 ++ Array.fill(255)(0.toByte) val byteCode_0xff: Array[Byte] = Array.fill(256)(1.toByte) val byteCode_0xfe: Array[Byte] = Array.fill(255)(1.toByte) ++ array_0x00 val byteCode_0x7f: Array[Byte] = Array.fill(255)(1.toByte) - val byteString_0x40 = ByteString(Hex.decode("4000000000000000000000000000000000000000000000000000000000000000")) - val byteString_0x07f = ByteString(Hex.decode("000000000000000000000000000000000000000000000000000000000000007f")) - val byteString_0xfe = ByteString(Hex.decode("fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe")) - val byteString_0x7f = ByteString(Hex.decode("7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")) - val byteString_0x80 = ByteString(Hex.decode("8000000000000000000000000000000000000000000000000000000000000000")) - val byteString_0xff = ByteString(Hex.decode("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")) - val byteString_0xc0 = ByteString(Hex.decode("c000000000000000000000000000000000000000000000000000000000000000")) - val byteString_0x01 = ByteString(Hex.decode("0000000000000000000000000000000000000000000000000000000000000001")) - val byteString_0x00 = ByteString(Hex.decode("0000000000000000000000000000000000000000000000000000000000000000")) + val byteString_0x40: ByteString = ByteString( + Hex.decode("4000000000000000000000000000000000000000000000000000000000000000") + ) + val byteString_0x07f: ByteString = ByteString( + Hex.decode("000000000000000000000000000000000000000000000000000000000000007f") + ) + val byteString_0xfe: ByteString = ByteString( + Hex.decode("fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe") + ) + val byteString_0x7f: ByteString = ByteString( + Hex.decode("7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff") + ) + val byteString_0x80: ByteString = ByteString( + Hex.decode("8000000000000000000000000000000000000000000000000000000000000000") + ) + val byteString_0xff: ByteString = ByteString( + Hex.decode("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff") + ) + val byteString_0xc0: ByteString = ByteString( + Hex.decode("c000000000000000000000000000000000000000000000000000000000000000") + ) + val byteString_0x01: ByteString = ByteString( + Hex.decode("0000000000000000000000000000000000000000000000000000000000000001") + ) + val byteString_0x00: ByteString = ByteString( + Hex.decode("0000000000000000000000000000000000000000000000000000000000000000") + ) val array_0x80: Array[Byte] = byteString_0x80.toArray val array_0xff: Array[Byte] = byteString_0xff.toArray @@ -130,17 +154,17 @@ class ShiftingOpCodeSpec extends AnyWordSpec with Matchers with ScalaCheckProper } trait TestSetup { - val config = EvmConfig.ConstantinopleConfigBuilder(blockchainConfig) + val config: EvmConfig = EvmConfig.ConstantinopleConfigBuilder(blockchainConfig) val vm = new TestVM - val senderAddr = Address(0xcafebabeL) - val senderAcc = Account(nonce = 1, balance = 1000000) + val senderAddr: Address = Address(0xcafebabeL) + val senderAcc: Account = Account(nonce = 1, balance = 1000000) val accountWithCode: ByteString => Account = code => Account.empty().withCode(kec256(code)) def defaultWorld: MockWorldState = MockWorldState().saveAccount(senderAddr, senderAcc) - val blockHeader = BlockFixtures.ValidBlock.header.copy( + val blockHeader: BlockHeader = BlockFixtures.ValidBlock.header.copy( difficulty = 1000000, number = 1, gasLimit = 10000000, diff --git a/src/test/scala/io/iohk/ethereum/vm/StackSpec.scala b/src/test/scala/io/iohk/ethereum/vm/StackSpec.scala index 982280c896..85240e0abf 100644 --- a/src/test/scala/io/iohk/ethereum/vm/StackSpec.scala +++ b/src/test/scala/io/iohk/ethereum/vm/StackSpec.scala @@ -1,20 +1,21 @@ package io.iohk.ethereum.vm import org.scalacheck.Gen -import io.iohk.ethereum.domain.UInt256 -import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks import org.scalatest.funsuite.AnyFunSuite import org.scalatest.matchers.should.Matchers +import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks + +import io.iohk.ethereum.domain.UInt256 class StackSpec extends AnyFunSuite with Matchers with ScalaCheckPropertyChecks { val maxStackSize = 32 - val stackGen = Generators.getStackGen(maxSize = maxStackSize) - val intGen = Gen.choose(0, maxStackSize).filter(_ >= 0) - val uint256Gen = Generators.getUInt256Gen() - val uint256ListGen = Generators.getListGen(0, 16, uint256Gen) - val fullStackGen = intGen.flatMap(n => Generators.getStackGen(n, n, uint256Gen, n)) - val nonFullStackGen = + val stackGen: Gen[Stack] = Generators.getStackGen(maxSize = maxStackSize) + val intGen: Gen[Int] = Gen.choose(0, maxStackSize).filter(_ >= 0) + val uint256Gen: Gen[UInt256] = Generators.getUInt256Gen() + val uint256ListGen: Gen[List[UInt256]] = Generators.getListGen(0, 16, uint256Gen) + val fullStackGen: Gen[Stack] = intGen.flatMap(n => Generators.getStackGen(n, n, uint256Gen, n)) + val nonFullStackGen: Gen[Stack] = Generators.getStackGen(maxElems = maxStackSize - 1, maxSize = maxStackSize, valueGen = uint256Gen) test("pop single element") { diff --git a/src/test/scala/io/iohk/ethereum/vm/StaticCallOpcodeSpec.scala b/src/test/scala/io/iohk/ethereum/vm/StaticCallOpcodeSpec.scala index afacff71d8..0bb3519910 100644 --- a/src/test/scala/io/iohk/ethereum/vm/StaticCallOpcodeSpec.scala +++ b/src/test/scala/io/iohk/ethereum/vm/StaticCallOpcodeSpec.scala @@ -1,16 +1,17 @@ package io.iohk.ethereum.vm -import io.iohk.ethereum.vm.Fixtures.blockchainConfig -import io.iohk.ethereum.vm.MockWorldState._ -import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks import org.scalatest.matchers.should.Matchers import org.scalatest.wordspec.AnyWordSpec +import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks + +import io.iohk.ethereum.vm.Fixtures.blockchainConfig +import io.iohk.ethereum.vm.MockWorldState._ // scalastyle:off object.name class StaticCallOpcodeSpec extends AnyWordSpec with Matchers with ScalaCheckPropertyChecks { - val config = EvmConfig.ByzantiumConfigBuilder(blockchainConfig) - val startState = MockWorldState(touchedAccounts = Set.empty, noEmptyAccountsCond = true) + val config: EvmConfig = EvmConfig.ByzantiumConfigBuilder(blockchainConfig) + val startState: MockWorldState = MockWorldState(touchedAccounts = Set.empty, noEmptyAccountsCond = true) val fxt = new CallOpFixture(config, startState) diff --git a/src/test/scala/io/iohk/ethereum/vm/VMSpec.scala b/src/test/scala/io/iohk/ethereum/vm/VMSpec.scala index 9de5b3593a..41e5e0c112 100644 --- a/src/test/scala/io/iohk/ethereum/vm/VMSpec.scala +++ b/src/test/scala/io/iohk/ethereum/vm/VMSpec.scala @@ -2,12 +2,14 @@ package io.iohk.ethereum.vm import akka.util.ByteString import akka.util.ByteString.{empty => bEmpty} -import io.iohk.ethereum.domain._ -import io.iohk.ethereum.Fixtures.{Blocks => BlockFixtures} -import io.iohk.ethereum.vm.MockWorldState._ -import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks + import org.scalatest.matchers.should.Matchers import org.scalatest.wordspec.AnyWordSpec +import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks + +import io.iohk.ethereum.Fixtures.{Blocks => BlockFixtures} +import io.iohk.ethereum.domain._ +import io.iohk.ethereum.vm.MockWorldState._ class VMSpec extends AnyWordSpec with ScalaCheckPropertyChecks with Matchers { @@ -137,7 +139,7 @@ class VMSpec extends AnyWordSpec with ScalaCheckPropertyChecks with Matchers { trait TestSetup { val vm = new TestVM - val blockHeader = BlockFixtures.ValidBlock.header.copy( + val blockHeader: BlockHeader = BlockFixtures.ValidBlock.header.copy( difficulty = 1000000, number = 1, gasLimit = 10000000, @@ -145,7 +147,7 @@ class VMSpec extends AnyWordSpec with ScalaCheckPropertyChecks with Matchers { unixTimestamp = 0 ) - val evmBlockchainConfig = BlockchainConfigForEvm( + val evmBlockchainConfig: BlockchainConfigForEvm = BlockchainConfigForEvm( frontierBlockNumber = Long.MaxValue, homesteadBlockNumber = Long.MaxValue, eip150BlockNumber = Long.MaxValue, @@ -163,12 +165,12 @@ class VMSpec extends AnyWordSpec with ScalaCheckPropertyChecks with Matchers { chainId = 0x3d.toByte ) - val homesteadConfig = EvmConfig.forBlock(0, evmBlockchainConfig.copy(homesteadBlockNumber = 0)) - val eip161Config = EvmConfig.forBlock(0, evmBlockchainConfig.copy(eip161BlockNumber = 0)) + val homesteadConfig: EvmConfig = EvmConfig.forBlock(0, evmBlockchainConfig.copy(homesteadBlockNumber = 0)) + val eip161Config: EvmConfig = EvmConfig.forBlock(0, evmBlockchainConfig.copy(eip161BlockNumber = 0)) - val senderAddr = Address(0xcafebabeL) - val senderAcc = Account(nonce = 1, balance = 1000000) - def defaultWorld = MockWorldState().saveAccount(senderAddr, senderAcc) + val senderAddr: Address = Address(0xcafebabeL) + val senderAcc: Account = Account(nonce = 1, balance = 1000000) + def defaultWorld: MockWorldState = MockWorldState().saveAccount(senderAddr, senderAcc) def getContext( recipientAddr: Option[Address], @@ -198,10 +200,10 @@ class VMSpec extends AnyWordSpec with ScalaCheckPropertyChecks with Matchers { } trait MessageCall extends TestSetup { - val recipientAddr = Some(Address(0xdeadbeefL)) - val recipientAcc = Account(nonce = 1) + val recipientAddr: Some[Address] = Some(Address(0xdeadbeefL)) + val recipientAcc: Account = Account(nonce = 1) - override val defaultWorld = super.defaultWorld.saveAccount(recipientAddr.get, recipientAcc) + override val defaultWorld: MockWorldState = super.defaultWorld.saveAccount(recipientAddr.get, recipientAcc) def getContext(world: MockWorldState = defaultWorld, inputData: ByteString = bEmpty): PC = getContext(recipientAddr, world, inputData, homesteadConfig) @@ -210,7 +212,7 @@ class VMSpec extends AnyWordSpec with ScalaCheckPropertyChecks with Matchers { trait ContractCreation extends TestSetup { val recipientAddr = None - val expectedNewAddress = defaultWorld.createAddress(senderAddr) + val expectedNewAddress: Address = defaultWorld.createAddress(senderAddr) val storedValue = 42 val secondStoredValue = 13 diff --git a/src/test/scala/io/iohk/ethereum/vm/utils/MockVmInput.scala b/src/test/scala/io/iohk/ethereum/vm/utils/MockVmInput.scala index 035229b245..a370b74f26 100644 --- a/src/test/scala/io/iohk/ethereum/vm/utils/MockVmInput.scala +++ b/src/test/scala/io/iohk/ethereum/vm/utils/MockVmInput.scala @@ -1,9 +1,13 @@ package io.iohk.ethereum.vm.utils import akka.util.ByteString -import io.iohk.ethereum.crypto.ECDSASignature -import io.iohk.ethereum.domain.{Address, BlockHeader, SignedTransaction, Transaction} + import io.iohk.ethereum.Fixtures.{Blocks => BlockFixtures} +import io.iohk.ethereum.crypto.ECDSASignature +import io.iohk.ethereum.domain.Address +import io.iohk.ethereum.domain.BlockHeader +import io.iohk.ethereum.domain.SignedTransaction +import io.iohk.ethereum.domain.Transaction object MockVmInput {