diff --git a/project/Dependencies.scala b/project/Dependencies.scala index 2e149415e0..3d34cb6597 100644 --- a/project/Dependencies.scala +++ b/project/Dependencies.scala @@ -47,6 +47,7 @@ object Dependencies { val boopickle = Seq("io.suzaku" %% "boopickle" % "1.3.3") val rocksDb = Seq( + // use "5.18.3" for older macOS "org.rocksdb" % "rocksdbjni" % "6.11.4" ) diff --git a/src/main/protobuf/extvm b/src/main/protobuf/extvm index 53eb31f3c5..6b3039be92 160000 --- a/src/main/protobuf/extvm +++ b/src/main/protobuf/extvm @@ -1 +1 @@ -Subproject commit 53eb31f3c59f7200994915b834e626bd292df7ed +Subproject commit 6b3039be92882df6ef6c15887c8d0b5f10c86d6f diff --git a/src/main/scala/io/iohk/ethereum/consensus/ethash/RestrictedEthashSigner.scala b/src/main/scala/io/iohk/ethereum/consensus/ethash/RestrictedEthashSigner.scala index 03a53664ad..f27cc3f058 100644 --- a/src/main/scala/io/iohk/ethereum/consensus/ethash/RestrictedEthashSigner.scala +++ b/src/main/scala/io/iohk/ethereum/consensus/ethash/RestrictedEthashSigner.scala @@ -11,23 +11,26 @@ object RestrictedEthashSigner { def validateSignature(blockHeader: BlockHeader, allowedMiners: Set[ByteString]): Boolean = { val signature = blockHeader.extraData.takeRight(ECDSASignature.EncodedLength) - val blockHeaderWithoutSig = blockHeader.dropRightNExtraDataBytes(ECDSASignature.EncodedLength) - val encodedBlockHeader = getEncodedWithoutNonce(blockHeaderWithoutSig) - val headerHash = crypto.kec256(encodedBlockHeader) - val maybePubKey = for { - sig <- ECDSASignature.fromBytes(signature) - pubKeyBytes <- sig.publicKey(headerHash) - } yield ByteString.fromArrayUnsafe(pubKeyBytes) + val headerHash = hashHeaderForSigning(blockHeader) + val maybePubKey = ECDSASignature.fromBytes(signature).flatMap(_.publicKey(headerHash)) maybePubKey.exists(allowedMiners.contains) } def signHeader(blockHeader: BlockHeader, keyPair: AsymmetricCipherKeyPair): BlockHeader = { - val encoded = getEncodedWithoutNonce(blockHeader) - val hash = crypto.kec256(encoded) - val signed = ECDSASignature.sign(hash, keyPair) + val hash = hashHeaderForSigning(blockHeader) + val signed = ECDSASignature.sign(hash.toArray, keyPair) val sigBytes = signed.toBytes blockHeader.withAdditionalExtraData(sigBytes) } + def hashHeaderForSigning(blockHeader: BlockHeader): ByteString = { + val blockHeaderWithoutSig = + if (blockHeader.extraData.length >= ECDSASignature.EncodedLength) + blockHeader.dropRightNExtraDataBytes(ECDSASignature.EncodedLength) + else blockHeader + val encodedBlockHeader = getEncodedWithoutNonce(blockHeaderWithoutSig) + ByteString(crypto.kec256(encodedBlockHeader)) + } + } diff --git a/src/main/scala/io/iohk/ethereum/extvm/VMServer.scala b/src/main/scala/io/iohk/ethereum/extvm/VMServer.scala index ba181d3b84..6d00a300f4 100644 --- a/src/main/scala/io/iohk/ethereum/extvm/VMServer.scala +++ b/src/main/scala/io/iohk/ethereum/extvm/VMServer.scala @@ -70,8 +70,11 @@ class VMServer(messageHandler: MessageHandler) extends Logger { private def awaitHello(): Unit = { val helloMsg = messageHandler.awaitMessage[msg.Hello] - require(helloMsg.version == ApiVersionProvider.version) - require(helloMsg.config.isEthereumConfig) + require( + helloMsg.version == ApiVersionProvider.version, + s"Wrong Hello message version. Expected ${ApiVersionProvider.version} but was ${helloMsg.version}" + ) + require(helloMsg.config.isEthereumConfig, "Hello message ethereum config must be true") defaultBlockchainConfig = constructBlockchainConfig(helloMsg.config.ethereumConfig.get) } diff --git a/src/main/scala/io/iohk/ethereum/jsonrpc/BlockResponse.scala b/src/main/scala/io/iohk/ethereum/jsonrpc/BlockResponse.scala index c646968ec5..c0839e7bd4 100644 --- a/src/main/scala/io/iohk/ethereum/jsonrpc/BlockResponse.scala +++ b/src/main/scala/io/iohk/ethereum/jsonrpc/BlockResponse.scala @@ -2,11 +2,14 @@ package io.iohk.ethereum.jsonrpc import akka.util.ByteString import cats.implicits._ +import io.iohk.ethereum.consensus.ethash.RestrictedEthashSigner import io.iohk.ethereum.crypto.ECDSASignature import io.iohk.ethereum.domain.{Block, BlockBody, BlockHeader, ChainWeight} +import io.iohk.ethereum.utils.ByteStringUtils case class CheckpointResponse(signatures: Seq[ECDSASignature], signers: Seq[ByteString]) +//scalastyle:off method.length case class BlockResponse( number: BigInt, hash: Option[ByteString], @@ -29,7 +32,9 @@ case class BlockResponse( checkpoint: Option[CheckpointResponse], treasuryOptOut: Option[Boolean], transactions: Either[Seq[ByteString], Seq[TransactionResponse]], - uncles: Seq[ByteString] + uncles: Seq[ByteString], + signature: String, + signer: String ) { val chainWeight: Option[ChainWeight] = for { lcn <- lastCheckpointNumber @@ -39,6 +44,8 @@ case class BlockResponse( object BlockResponse { + val NotAvailable = "N/A" + def apply( block: Block, weight: Option[ChainWeight] = None, @@ -61,6 +68,17 @@ object BlockResponse { val (lcn, td) = weight.map(_.asTuple).separate + val signature = + if (block.header.extraData.length >= ECDSASignature.EncodedLength) + ECDSASignature.fromBytes(block.header.extraData.takeRight(ECDSASignature.EncodedLength)) + else None + + val signatureStr = signature.map(_.toBytes).map(ByteStringUtils.hash2string).getOrElse(NotAvailable) + val signerStr = signature + .flatMap(_.publicKey(RestrictedEthashSigner.hashHeaderForSigning(block.header))) + .map(ByteStringUtils.hash2string) + .getOrElse(NotAvailable) + BlockResponse( number = block.header.number, hash = if (pendingBlock) None else Some(block.header.hash), @@ -83,7 +101,9 @@ object BlockResponse { checkpoint = checkpoint, treasuryOptOut = block.header.treasuryOptOut, transactions = transactions, - uncles = block.body.uncleNodesList.map(_.hash) + uncles = block.body.uncleNodesList.map(_.hash), + signature = signatureStr, + signer = signerStr ) } diff --git a/src/test/scala/io/iohk/ethereum/extvm/VMServerSpec.scala b/src/test/scala/io/iohk/ethereum/extvm/VMServerSpec.scala index 9ee50e0dfd..fbbf3db535 100644 --- a/src/test/scala/io/iohk/ethereum/extvm/VMServerSpec.scala +++ b/src/test/scala/io/iohk/ethereum/extvm/VMServerSpec.scala @@ -110,7 +110,7 @@ class VMServerSpec extends AnyFlatSpec with Matchers with MockFactory { accountStartNonce = blockchainConfig.accountStartNonce ) val ethereumConfigMsg = msg.Hello.Config.EthereumConfig(ethereumConfig) - val helloMsg = msg.Hello(version = "1.1", config = ethereumConfigMsg) + val helloMsg = msg.Hello(version = "2.0", config = ethereumConfigMsg) val messageHandler = mock[MessageHandler] val vmServer = new VMServer(messageHandler)