-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* PM-2938: Added Hash type and Keccak256. * PM-2938: Add LeaderSelection and RoundRobin. * PM-2938: LeaderSelection.Hashing * PM-2938: Use hashing leader selection in HotStuff basic tests. * PM-2938: Silence logs from networking in tests. * PM-2966: Add some sleep in tests.
- Loading branch information
Showing
16 changed files
with
258 additions
and
35 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,14 @@ | ||
package metronome.core | ||
|
||
/** Can be used to tag any particular type as validated, for example: | ||
* | ||
* ``` | ||
* def validateBlock(block: Block): Either[Error, Validated[Block]] | ||
* def storeBlock(block: Validated[Block]) | ||
* ``` | ||
* | ||
* It's a bit more lightweight than opting into the `ValidatedNel` from `cats`, | ||
* mostly just serves as control that the right methods have been called in a | ||
* pipeline. | ||
*/ | ||
object Validated extends GenericTagger |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
package metronome.crypto.hash | ||
|
||
import metronome.core.Tagger | ||
import scodec.bits.ByteVector | ||
|
||
object Hash extends Tagger[ByteVector] |
20 changes: 20 additions & 0 deletions
20
metronome/crypto/src/metronome/crypto/hash/Keccak256.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
package metronome.crypto.hash | ||
|
||
import org.bouncycastle.crypto.digests.KeccakDigest | ||
import scodec.bits.{BitVector, ByteVector} | ||
|
||
object Keccak256 { | ||
def apply(data: Array[Byte]): Hash = { | ||
val output = new Array[Byte](32) | ||
val digest = new KeccakDigest(256) | ||
digest.update(data, 0, data.length) | ||
digest.doFinal(output, 0) | ||
Hash(ByteVector(output)) | ||
} | ||
|
||
def apply(data: ByteVector): Hash = | ||
apply(data.toArray) | ||
|
||
def apply(data: BitVector): Hash = | ||
apply(data.toByteArray) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
package metronome.crypto | ||
|
||
package object hash { | ||
type Hash = Hash.Tagged | ||
} |
21 changes: 21 additions & 0 deletions
21
metronome/crypto/test/src/metronome/crypto/hash/Keccak256Spec.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
package metronome.crypto.hash | ||
|
||
import scodec.bits._ | ||
import org.scalatest.flatspec.AnyFlatSpec | ||
import org.scalatest.matchers.should.Matchers | ||
|
||
class Keccak256Spec extends AnyFlatSpec with Matchers { | ||
behavior of "Keccak256" | ||
|
||
it should "hash empty data" in { | ||
Keccak256( | ||
"".getBytes | ||
) shouldBe hex"c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470" | ||
} | ||
|
||
it should "hash non-empty data" in { | ||
Keccak256( | ||
"abc".getBytes | ||
) shouldBe hex"4e03657aea45a94fc7d47ba826c8d667c0d1e6e33a64a036ec44f58fa12d6c45" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
53 changes: 53 additions & 0 deletions
53
metronome/hotstuff/consensus/src/metronome/hotstuff/consensus/LeaderSelection.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
package metronome.hotstuff.consensus | ||
|
||
import metronome.crypto.hash.Keccak256 | ||
import scodec.bits.ByteVector | ||
|
||
/** Strategy to pick the leader for a given view number from | ||
* federation of with a fixed size. | ||
*/ | ||
trait LeaderSelection { | ||
|
||
/** Return the index of the federation member who should lead the view. */ | ||
def leaderOf(viewNumber: ViewNumber, size: Int): Int | ||
} | ||
|
||
object LeaderSelection { | ||
|
||
/** Simple strategy cycling through leaders in a static order. */ | ||
object RoundRobin extends LeaderSelection { | ||
override def leaderOf(viewNumber: ViewNumber, size: Int): Int = | ||
(viewNumber % size).toInt | ||
} | ||
|
||
/** Leader assignment based on view-number has not been discussed in the Hotstuff | ||
* paper and in general, it does not affect the safety and liveness. | ||
* However, it does affect worst-case latency. | ||
* | ||
* Consider a static adversary under a round-robin leader change scheme. | ||
* All the f nodes can set their public keys so that they are consecutive. | ||
* In such a scenario those f consecutive leaders can create timeouts leading | ||
* to an O(f) confirmation latency. (Recall that in a normal case, the latency is O(1)). | ||
* | ||
* A minor improvement to this is to assign leaders based on | ||
* "publicKeys((H256(viewNumber).toInt % size).toInt)". | ||
* | ||
* This leader order randomization via a hash function will ensure that even | ||
* if adversarial public keys are consecutive in PublicKey set, they are not | ||
* necessarily consecutive in leader order. | ||
* | ||
* Note that the above policy will not ensure that adversarial leaders are never consecutive, | ||
* but the probability of such occurrence will be lower under a static adversary. | ||
*/ | ||
object Hashing extends LeaderSelection { | ||
override def leaderOf(viewNumber: ViewNumber, size: Int): Int = { | ||
val bytes = ByteVector.fromLong(viewNumber) // big-endian | ||
val hash = Keccak256(bytes) | ||
// If we prepend 0.toByte then it would treat it as unsigned, at the cost of an array copy. | ||
// Instead of doing that I'll just make sure we deal with negative modulo. | ||
val num = BigInt(hash.toArray) | ||
val mod = (num % size).toInt | ||
if (mod < 0) mod + size else mod | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
44 changes: 44 additions & 0 deletions
44
...onome/hotstuff/consensus/test/src/metronome/hotstuff/consensus/LeaderSelectionProps.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
package metronome.hotstuff.consensus | ||
|
||
import metronome.core.Tagger | ||
import org.scalacheck._ | ||
import org.scalacheck.Prop.forAll | ||
|
||
abstract class LeaderSelectionProps(name: String, val selector: LeaderSelection) | ||
extends Properties(name) { | ||
|
||
object Size extends Tagger[Int] | ||
type Size = Size.Tagged | ||
|
||
implicit val arbViewNumber: Arbitrary[ViewNumber] = Arbitrary { | ||
Gen.posNum[Long].map(ViewNumber(_)) | ||
} | ||
|
||
implicit val arbFederationSize: Arbitrary[Size] = Arbitrary { | ||
Gen.posNum[Int].map(Size(_)) | ||
} | ||
|
||
property("leaderOf") = forAll { (viewNumber: ViewNumber, size: Size) => | ||
val idx = selector.leaderOf(viewNumber, size) | ||
0 <= idx && idx < size | ||
} | ||
} | ||
|
||
object RoundRobinSelectionProps | ||
extends LeaderSelectionProps( | ||
"LeaderSelection.RoundRobin", | ||
LeaderSelection.RoundRobin | ||
) { | ||
|
||
property("round-robin") = forAll { (viewNumber: ViewNumber, size: Size) => | ||
val idx0 = selector.leaderOf(viewNumber, size) | ||
val idx1 = selector.leaderOf(viewNumber.next, size) | ||
idx1 == idx0 + 1 || idx0 == size - 1 && idx1 == 0 | ||
} | ||
} | ||
|
||
object HashingSelectionProps | ||
extends LeaderSelectionProps( | ||
"LeaderSelection.Hashing", | ||
LeaderSelection.Hashing | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
<configuration> | ||
|
||
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> | ||
<encoder> | ||
<pattern>%d{HH:mm:ss.SSS} %-5level %logger{36} %msg%n</pattern> | ||
</encoder> | ||
</appender> | ||
|
||
<logger name="io.netty" level="OFF"/> | ||
|
||
<logger name="io.iohk.scalanet.peergroup" level="OFF"/> | ||
|
||
<root level="WARN"> | ||
<appender-ref ref="STDOUT"/> | ||
</root> | ||
|
||
</configuration> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.