Skip to content

Commit

Permalink
Merge branch 'master' into i590
Browse files Browse the repository at this point in the history
  • Loading branch information
kushti authored Jan 16, 2019
2 parents 1baa0dc + 7b29846 commit bf7adae
Show file tree
Hide file tree
Showing 108 changed files with 2,037 additions and 869 deletions.
1 change: 1 addition & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ branches:
- v2.0
- master
- /^\d\.\d+$/
- height-as-int
jdk:
- oraclejdk9
scala:
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,6 @@ To run specific Ergo version as a service with custom config:
-p 9052:9052 \
-v ergo:/root/ergo/data \
-v /path/on/host/system/to/myergo.conf:/root/ergo/myergo.conf \
ergoplatform/ergo:v1.5.3 /root/ergo/myergo.conf
ergoplatform/ergo:v1.9.0 /root/ergo/myergo.conf

This will connect to Ergo mainnet or testnet respecting your configuration passed in `myergo.conf`. Every default config value would be overwritten with corresponding value in `myergo.conf`. This also would store your data in named Docker volume `ergo` (if you change default data location in your config file, do not forget mount `ergo` volume to new location in container) and open ports `9007` and `9052` on host system. Note that `9052` is used for API, so it is ok not to open it into whole Internet. Also, Ergo node works normally under NAT, so you can keep closed your `9007` port too, hence other nodes could not discover and connect to yours one, only your node could initiate connections.
20 changes: 12 additions & 8 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ import sbt._
lazy val commonSettings = Seq(
organization := "org.ergoplatform",
name := "ergo",
version := "1.8.1",
scalaVersion := "2.12.7",
version := "1.9.0",
scalaVersion := "2.12.8",
resolvers ++= Seq("Sonatype Releases" at "https://oss.sonatype.org/content/repositories/releases/",
"SonaType" at "https://oss.sonatype.org/content/groups/public",
"Typesafe maven releases" at "http://repo.typesafe.com/typesafe/maven-releases/",
Expand All @@ -15,19 +15,23 @@ lazy val commonSettings = Seq(
)

val scorexVersion = "53207304-SNAPSHOT"
val sigmaStateVersion = "master-5f01afb6-SNAPSHOT"
// for testing current sigmastate build (see sigmastate-ergo-it jenkins job)
val effectiveSigmaStateVersion = Option(System.getenv().get("SIGMASTATE_VERSION")).getOrElse(sigmaStateVersion)

libraryDependencies ++= Seq(
"ch.qos.logback" % "logback-classic" % "1.2.3",
"com.google.guava" % "guava" % "21.0",
("org.scorexfoundation" %% "sigma-state" % "master-c645b1a1-SNAPSHOT")
("org.scorexfoundation" %% "sigma-state" % effectiveSigmaStateVersion)
.exclude("ch.qos.logback", "logback-classic")
.exclude("org.scorexfoundation", "scrypto"),
"org.scala-lang.modules" %% "scala-async" % "0.9.7",
("org.scorexfoundation" %% "avl-iodb" % "0.2.15").exclude("ch.qos.logback", "logback-classic"),
"org.scorexfoundation" %% "iodb" % "0.3.2",
("org.scorexfoundation" %% "scorex-core" % scorexVersion).exclude("ch.qos.logback", "logback-classic"),

"javax.xml.bind" % "jaxb-api" % "2.+",
"com.iheart" %% "ficus" % "1.4.+",
"ch.qos.logback" % "logback-classic" % "1.2.3",
"com.google.guava" % "guava" % "21.0",

"com.storm-enroute" %% "scalameter" % "0.8.+" % "test",
"org.scalactic" %% "scalactic" % "3.0.+" % "test",
Expand All @@ -37,8 +41,8 @@ libraryDependencies ++= Seq(
"com.typesafe.akka" %% "akka-testkit" % "2.5.+" % "test",
"com.typesafe.akka" %% "akka-http-testkit" % "10.+" % "test",
"org.asynchttpclient" % "async-http-client" % "2.6.+" % "test",
"com.spotify" % "docker-client" % "8.14.5" % "test" classifier "shaded",
"com.fasterxml.jackson.dataformat" % "jackson-dataformat-properties" % "2.9.2" % "test"
"com.fasterxml.jackson.dataformat" % "jackson-dataformat-properties" % "2.9.2" % "test",
"com.spotify" % "docker-client" % "8.14.5" % "test" classifier "shaded"
)

coverageExcludedPackages := ".*ErgoApp.*;.*routes.*;.*ErgoPersistentModifier"
Expand Down Expand Up @@ -99,7 +103,7 @@ assemblyMergeStrategy in assembly := {
enablePlugins(sbtdocker.DockerPlugin)

Defaults.itSettings
configs(IntegrationTest extend (Test))
configs(IntegrationTest extend Test)
inConfig(IntegrationTest)(Seq(
parallelExecution := false,
test := (test dependsOn docker).value,
Expand Down
24 changes: 21 additions & 3 deletions lock.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,19 @@
// This file is auto generated by sbt-lock 0.4.0.
// https://github.com/tkawachi/sbt-lock/
dependencyOverrides in ThisBuild ++= Seq(
"cglib" % "cglib" % "3.2.3",
"ch.qos.logback" % "logback-classic" % "1.2.3",
"ch.qos.logback" % "logback-core" % "1.2.3",
"com.chuusai" % "shapeless_2.12" % "2.3.2",
"com.github.kxbmap" % "configs_2.12" % "0.4.4",
"com.google.code.findbugs" % "jsr305" % "3.0.2",
"com.google.guava" % "guava" % "21.0",
"com.iheart" % "ficus_2.12" % "1.4.4",
"com.lihaoyi" % "fastparse-utils_2.12" % "1.0.0",
"com.lihaoyi" % "fastparse_2.12" % "1.0.0",
"com.lihaoyi" % "sourcecode_2.12" % "0.1.4",
"com.sksamuel.scapegoat" % "scalac-scapegoat-plugin_2.12" % "1.3.3",
"com.trueaccord.lenses" % "lenses_2.12" % "0.4.12",
"com.typesafe" % "config" % "1.3.3",
"com.typesafe" % "ssl-config-core_2.12" % "0.2.4",
"com.typesafe.akka" % "akka-actor_2.12" % "2.5.16",
Expand All @@ -21,37 +24,52 @@ dependencyOverrides in ThisBuild ++= Seq(
"com.typesafe.akka" % "akka-protobuf_2.12" % "2.5.16",
"com.typesafe.akka" % "akka-stream_2.12" % "2.5.16",
"com.typesafe.scala-logging" % "scala-logging_2.12" % "3.9.0",
"commons-io" % "commons-io" % "2.5",
"commons-net" % "commons-net" % "3.6",
"de.heikoseeberger" % "akka-http-circe_2.12" % "1.19.0",
"io.circe" % "circe-core_2.12" % "0.9.0",
"io.circe" % "circe-generic_2.12" % "0.8.0",
"io.circe" % "circe-jawn_2.12" % "0.9.0",
"io.circe" % "circe-numbers_2.12" % "0.9.0",
"io.circe" % "circe-parser_2.12" % "0.8.0",
"io.github.scalan" % "common_2.12" % "master-6eca3f22-SNAPSHOT",
"io.github.scalan" % "core_2.12" % "master-6eca3f22-SNAPSHOT",
"io.github.scalan" % "library-api_2.12" % "master-6eca3f22-SNAPSHOT",
"io.github.scalan" % "library-impl_2.12" % "master-6eca3f22-SNAPSHOT",
"io.github.scalan" % "library_2.12" % "master-6eca3f22-SNAPSHOT",
"io.github.scalan" % "macros_2.12" % "master-6eca3f22-SNAPSHOT",
"io.github.scalan" % "meta_2.12" % "master-6eca3f22-SNAPSHOT",
"io.github.scalan" % "sigma-api_2.12" % "master-354d6254-SNAPSHOT",
"io.github.scalan" % "sigma-impl_2.12" % "master-354d6254-SNAPSHOT",
"io.github.scalan" % "sigma-library_2.12" % "master-354d6254-SNAPSHOT",
"javax.activation" % "javax.activation-api" % "1.2.0",
"javax.xml.bind" % "jaxb-api" % "2.4.0-b180830.0359",
"jline" % "jline" % "2.14.3",
"net.jpountz.lz4" % "lz4" % "1.3.0",
"org.apache.ant" % "ant" % "1.9.6",
"org.apache.ant" % "ant-launcher" % "1.9.6",
"org.bitbucket.inkytonik.dsinfo" % "dsinfo_2.12" % "0.4.0",
"org.bitbucket.inkytonik.dsprofile" % "dsprofile_2.12" % "0.4.0",
"org.bitbucket.inkytonik.kiama" % "kiama_2.12" % "2.1.0",
"org.bitlet" % "weupnp" % "0.1.4",
"org.bouncycastle" % "bcprov-jdk15on" % "1.60",
"org.objenesis" % "objenesis" % "2.4",
"org.ow2.asm" % "asm" % "5.0.4",
"org.reactivestreams" % "reactive-streams" % "1.0.2",
"org.rogach" % "scallop_2.12" % "2.1.1",
"org.rudogma" % "supertagged_2.12" % "1.4",
"org.scala-lang.modules" % "scala-async_2.12" % "0.9.7",
"org.scala-lang.modules" % "scala-java8-compat_2.12" % "0.8.0",
"org.scala-lang.modules" % "scala-parser-combinators_2.12" % "1.1.1",
"org.scala-lang.modules" % "scala-xml_2.12" % "1.0.5",
"org.scala-lang.modules" % "scala-xml_2.12" % "1.0.6",
"org.scala-sbt" % "test-interface" % "1.0",
"org.scalacheck" % "scalacheck_2.12" % "1.13.5",
"org.scorexfoundation" % "avl-iodb_2.12" % "0.2.15",
"org.scorexfoundation" % "iodb_2.12" % "0.3.2",
"org.scorexfoundation" % "scorex-core_2.12" % "53207304-SNAPSHOT",
"org.scorexfoundation" % "scorex-util_2.12" % "0.1.1",
"org.scorexfoundation" % "scrypto_2.12" % "2.1.4",
"org.scorexfoundation" % "sigma-state_2.12" % "master-c645b1a1-SNAPSHOT",
"org.scorexfoundation" % "sigma-state_2.12" % "master-5f01afb6-SNAPSHOT",
"org.slf4j" % "slf4j-api" % "1.7.25",
"org.spire-math" % "jawn-parser_2.12" % "0.11.0",
"org.typelevel" % "cats-core_2.12" % "1.0.1",
Expand All @@ -61,4 +79,4 @@ dependencyOverrides in ThisBuild ++= Seq(
"org.typelevel" % "macro-compat_2.12" % "1.1.1",
"org.whispersystems" % "curve25519-java" % "0.5.0"
)
// LIBRARY_DEPENDENCIES_HASH 512b10b02a03749bcad48afb2e41e6f03b15e4a2
// LIBRARY_DEPENDENCIES_HASH 01c39505e85e30aab640238478bddf972e4f2d71
22 changes: 11 additions & 11 deletions papers/yellow/block.tex
Original file line number Diff line number Diff line change
Expand Up @@ -51,17 +51,17 @@ \subsection{Header}
\end{itemize}

\subsection{Extension}
\label{sec:extension}

Extension is a key-value storage for a variety of data.
It contains 2 parts:
\begin{itemize}
\item{\em Mandatory fields } - fields which keys are set via consensus rules and may be changed
via soft/hard forks only. These fields have 4 bytes key and at most 64 bytes value.
Value length is known for all peers and this limit only important due to soft forks -
it is allowed to add at most 1 new key to this section per epoch (256 blocks between
difficulty recalculation), if key is not known to a peer it assumes that soft fork that
added this key was performed.
\item{\em Optional fields } - random data miner may add to a block. This section contains at most 2
elements with 32 byte key size and at most 64 byte value size.
\end{itemize}

A key is always 2-bytes long, maximum size of a value is 64 bytes. Extension could be no more than of $10,240$ bytes.
Some keys have predefined semantics. In particular, if the first byte of a key is equals to $0x00$, then the second byte
defines parameter identifier, and the value defines value of the parameter. See Section~\ref{sec:params-table}
for details. Other prefixes may be used freely.

\knote{$0x01$ - will be used for interlinks}




1 change: 0 additions & 1 deletion papers/yellow/main.tex
Original file line number Diff line number Diff line change
Expand Up @@ -801,7 +801,6 @@ \subsection{Token Emission}
\vnote{outputs->boxes?}
\input{tokens.tex}

\section{Voting}
\input{voting.tex}


Expand Down
99 changes: 78 additions & 21 deletions papers/yellow/voting.tex
Original file line number Diff line number Diff line change
@@ -1,21 +1,78 @@
Subjects to voting are instructions costs, computational cost limit, block size limit,
and the block version. Voting for the block version lasts for 16 epochs, and requires
90 percent of the miners to vote for the change.

All other kinds of voting are organized in the following way. A miner who
successfully generates the first block in the epoch initiates the voting over one
of the parameters, stating explicitly whether a value of the parameter should be
decreased~(except the case when the current value is below $min\_step$) or increased from miner's
point of view.

The value of the change is predefined as $\max(\lceil0.01 \times current\_value\rceil, min\_step)$ with $min\_step$
being the hard-coded value. The voting lasts for one epoch. Every miner
submitting the block during this epoch has two options: accept or reject the
proposal. Miner's vote must be written in the generated block. Change in the
value requires the majority of votes over the epoch. Every block contains the
vote of the miner who generated it. In case the proposal fails, the parameters
remain unchanged.

\knote{Foundation wallet address change via 90 percent voting?}

\knote{Foundation tax change after first years?}
\section{Voting}

Many parameters can be changed on-the-fly via miners voting, such as instruction costs, computational cost limit per block,
block size limit, storage fee factor, block version, and so on. Voting for the block version~(so for a soft-fork)
lasts for 32 epochs~(see epoch length below), and requires more than 90 percent of the miners to vote for the change.
For less critical changes~(such as block size limit), simple majority is enough. We will further refer to the changes
of the first kind as to foundational changes, we call the changes of the second kind as to everyday changes.
Per block, a miner can vote for two everyday changes and also one foundational change.

To vote "Yes"~("I'm agree on the change proposed"), a miner is publishing identifier of the change directly in a
block header. To vote "No" (or avoid voting at all, which is the same), a miner is simply writing zero value instead of
a corresponding byte (another option is to provide a vote identifier which is not being considered within the epoch).
To initialize a voting procedure, a miner is publishing change identifier in a first block of an epoch.

System constants:
\begin{itemize}
\item{} Voting epoch length = 1024 blocks.
\item{} Voting epochs per foundational change = 32
\item{} Voting epochs before approved foundational change activation = 128
\end{itemize}

\subsection{Parameters table}
\label{sec:params-table}

The following table describes vote identifiers, default value (during launch), possible step, minimum and maximum values.
If the step is not defined in the table, its value is defined as $\max(\lceil0.01 \times current\_value\rceil, 1)$.
If minimum value for a parameter is not defined, it equals to zero. If maximum value is not defined, it equals to
1,073,741,823.

To propose or vote for increasing a parameter, a miner is inluding a parameter identifier ($id$) into a blockheader.
If miner is for decreasing parameter, the miner is including ($-id$) into a block header.

\begin{tabular}{| l | l | l | l | l | l |}
\hline
Id & Description & Default & Step & Min & Max \\
\hline
\hline
1 & Storage fee factor & 1250000 & 25000 & 0 & 5000000 \\
& (in nanoErgs per byte per storage period) & & & & \\
\hline
2 & Minimum monetary value of a box (in nanoErgs) & 360 & 10 & 0 & 10000 \\
\hline
3 & Maximum block size & 524288 & - & 16384 & - \\
\hline
4 & Maximum cumulative computational cost of a block & 1000000 & - & 16384 & - \\
\hline
\end{tabular}

Parameter values are to be written into extension section on first block of a voting epoch, that is, in the extension
of a block when its $height\,mod\,1024 = 0 \land height > 0$. Parameters for initial moment of time~$(height = 0)$ are simply
hardcoded. It is prohibited to start voting on $height = 0$.

\subsection{Proposing a change and voting for it}

To propose a change, in the first block of a voting epoch (of $1,024$ blocks, so in a block of
$height\,mod\,1024 = 0 \land height > 0$), a miner is posting vote for a change. There are three slots (three bytes)
in a block header for changes to propose, with two slots for everyday chanegs and third one to propose a softfork. Slot
not occuppied by a proposal is to be set to zero. Votes could come in any order. Examples of the bytes:
$(0, 1, 120)$, $(0, -3, 120)$. In the first case, a miner is proposing to increase storage fee factor ($id:1$), and
also proposes a soft-fork ($id:120$), In the second case, a miner is proposing to decrease block size ($id:-3$), and also
is proposing a soft-fork ($id:120$).

To vote for a proposal~(proposed in the first block of an epoch) within the epoch, a miner is including vote identifier
into the block header. Identifiers not proposed in the first block of the epoch are ignored.

If majority of votes within an epoch are supporting an everyday change (so at least 513 blocks are containing an
identifier), a new value of the parameter should be written into the extension section of the first block of the next
epoch.

\subsection{Voting for a soft-fork}

Soft-fork is when a protocol version supported by the network is being increased. This version is written in a block
header.

To start voting for a soft-fork, a miner needs to publish identifier $120$ in the first block of the epoch, consider,
for example, that its height is $h_s$. Next epoch, a miner should post height when start fork was proposed ($122: h_s$)
in the extension section of the block, and number of votes collected in the previous epochs $v_s$ should be written
there as well as $(121, v_s)$.
24 changes: 12 additions & 12 deletions src/it/resources/parameters-template.txt

Large diffs are not rendered by default.

7 changes: 4 additions & 3 deletions src/it/scala/org/ergoplatform/it/OpenApiSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,10 @@ class OpenApiSpec extends FreeSpec with IntegrationSuite {
.flatMap { _ => node.headerIdsByHeight(expectedHeight) }
.map { headerIds =>
createParamsFile(
Map("blockHeight" -> expectedHeight.toString,
"lastHeadersCount" -> expectedHeight.toString,
"headerId" -> headerIds.head)
Map(
"blockHeight" -> expectedHeight.toString,
"lastHeadersCount" -> expectedHeight.toString,
"headerId" -> headerIds.head)
)

val apiAddressToCheck: String = s"${node.nodeInfo.networkIpAddress}:${node.nodeInfo.containerApiPort}"
Expand Down
12 changes: 8 additions & 4 deletions src/it/scala/org/ergoplatform/it/PrunedDigestNodeSyncSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import scala.concurrent.duration._

class PrunedDigestNodeSyncSpec extends FreeSpec with IntegrationSuite {

val approxTargetHeight = 20
val approxTargetHeight = 10
val blocksToKeep: Int = approxTargetHeight / 5

val localVolume = s"$localDataDir/digest-node-sync-spec/data"
Expand All @@ -26,6 +26,8 @@ class PrunedDigestNodeSyncSpec extends FreeSpec with IntegrationSuite {
val minerConfig: Config = nodeSeedConfigs.head
.withFallback(miningDelayConfig(10000))
.withFallback(specialDataDirConfig(remoteVolume))
val nodeForSyncingConfig: Config = minerConfig
.withFallback(nonGeneratingPeerConfig)
val digestConfig: Config = digestStatePeerConfig
.withFallback(blockIntervalConfig(10000))
.withFallback(prunedHistoryConfig(blocksToKeep))
Expand All @@ -45,11 +47,13 @@ class PrunedDigestNodeSyncSpec extends FreeSpec with IntegrationSuite {

val result = Async.async {
Async.await(minerNode.waitForHeight(approxTargetHeight, 1.second))
docker.stopNode(minerNode.containerId, secondsToWait = 0)
val nodeForSyncing = docker.startNode(
minerConfig.withFallback(nonGeneratingPeerConfig), specialVolumeOpt = Some((localVolume, remoteVolume))).get
docker.stopNode(minerNode, secondsToWait = 0)

val nodeForSyncing = docker
.startNode(nodeForSyncingConfig, specialVolumeOpt = Some((localVolume, remoteVolume))).get
Async.await(nodeForSyncing.waitForHeight(approxTargetHeight))
val sampleInfo = Async.await(nodeForSyncing.info)

val digestNode = docker.startNode(digestConfig).get
val targetHeight = sampleInfo.bestBlockHeightOpt.value
val targetBlockId = sampleInfo.bestBlockIdOpt.value
Expand Down
4 changes: 2 additions & 2 deletions src/it/scala/org/ergoplatform/it/UtxoStateNodesSyncSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,11 @@ class UtxoStateNodesSyncSpec extends FreeSpec with IntegrationSuite {

s"Utxo state nodes synchronisation ($blocksQty blocks)" in {
val result = for {
initHeight <- Future.traverse(nodes)(_.height).map(_.max)
initHeight <- Future.traverse(nodes)(_.height).map(x => math.max(x.max, 1))
_ <- Future.traverse(nodes)(_.waitForHeight(initHeight + blocksQty))
headers <- Future.traverse(nodes)(_.headerIdsByHeight(initHeight + blocksQty - forkDepth))
} yield {
log.debug(s"Headers at height ${initHeight + blocksQty - forkDepth}: ${headers.mkString(",")}")
log.info(s"Headers at height ${initHeight + blocksQty - forkDepth}: ${headers.mkString(",")}")
val headerIdsAtSameHeight = headers.flatten
val sample = headerIdsAtSameHeight.head
headerIdsAtSameHeight should contain only sample
Expand Down
8 changes: 5 additions & 3 deletions src/it/scala/org/ergoplatform/it/container/Docker.scala
Original file line number Diff line number Diff line change
Expand Up @@ -71,9 +71,9 @@ class Docker(suiteConfig: Config = ConfigFactory.empty,
def startNodes(nodeConfigs: List[Config],
configEnrich: ExtraConfig = noExtraConfig): Try[List[Node]] = {
log.trace(s"Starting ${nodeConfigs.size} containers")
val nodes: Try[List[Node]] = nodeConfigs.map(cfg => startNode(cfg, configEnrich)).sequence
blocking(Thread.sleep(nodeConfigs.size * 5000))
nodes
nodeConfigs.map(cfg => startNode(cfg, configEnrich))
.sequence
.map(waitForStartupBlocking(_))
}

def waitForStartupBlocking(nodes: List[Node]): List[Node] = {
Expand Down Expand Up @@ -278,6 +278,8 @@ class Docker(suiteConfig: Config = ConfigFactory.empty,
}
}

def stopNode(node: Node, secondsToWait: Int): Unit = stopNode(node.containerId, secondsToWait)

def stopNode(containerId: String, secondsToWait: Int = 5): Unit = {
nodeRepository = nodeRepository.filterNot(_.containerId == containerId)
client.stopContainer(containerId, secondsToWait)
Expand Down
Loading

0 comments on commit bf7adae

Please sign in to comment.