Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Accounting for unparsed header bytes #2151

Merged
merged 4 commits into from
Jun 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -262,7 +262,7 @@ class AutolykosPowScheme(val k: Int, val n: Int) extends ScorexLogging {
val (parentId, height) = AutolykosPowScheme.derivedHeaderFields(parentOpt)

val h = HeaderWithoutPow(version, parentId, adProofsRoot, stateRoot, transactionsRoot, timestamp,
nBits, height, extensionHash, votes)
nBits, height, extensionHash, votes, Array.emptyByteArray)
val msg = msgByHeader(h)
val b = getB(nBits)
val x = randomSecret()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ object CandidateUtils {
candidate.nBits,
height,
extensionRoot,
candidate.votes
candidate.votes,
Array.emptyByteArray
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ class DefaultFakePowScheme(k: Int, n: Int) extends AutolykosPowScheme(k, n) {
val d: BigInt = q / (height + 10)
val s = AutolykosSolution(pk, w, n, d)
Some(Header(version, parentId, adProofsRoot, stateRoot, transactionsRoot, timestamp,
nBits, height, extensionHash, s, votes))
nBits, height, extensionHash, s, votes, Array.emptyByteArray))
}

override def realDifficulty(header: Header): PrivateKey = header.requiredDifficulty
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ import scala.concurrent.duration.FiniteDuration
* @param extensionRoot - Merkle tree digest of the extension section of the block
* @param powSolution - solution for the proof-of-work puzzle
* @param votes - votes for changing system parameters
* @param unparsedBytes - bytes of fields added in future versions of the protocol and not parseable
* @param sizeOpt - optionally, size of the header (to avoid serialization on calling .length)
*/
case class Header(override val version: Header.Version,
Expand All @@ -53,8 +54,9 @@ case class Header(override val version: Header.Version,
override val extensionRoot: Digest32,
powSolution: AutolykosSolution,
override val votes: Array[Byte], //3 bytes
override val unparsedBytes: Array[Byte],
override val sizeOpt: Option[Int] = None) extends HeaderWithoutPow(version, parentId, ADProofsRoot, stateRoot, transactionsRoot, timestamp,
nBits, height, extensionRoot, votes) with PreHeader with BlockSection {
nBits, height, extensionRoot, votes, unparsedBytes) with PreHeader with BlockSection {

override def serializedId: Array[Header.Version] = Algos.hash(bytes)

Expand Down Expand Up @@ -138,6 +140,11 @@ object Header extends ApiCodecs {
*/
val Interpreter50Version: Byte = 3

/**
* Block version after the 6.0 soft-fork
* 6.0 interpreter (EIP-50)
*/
val Interpreter60Version: Byte = 4

def toSigma(header: Header): sigma.Header =
CHeader(
Expand Down Expand Up @@ -180,7 +187,8 @@ object Header extends ApiCodecs {
"size" -> h.size.asJson,
"extensionId" -> Algos.encode(h.extensionId).asJson,
"transactionsId" -> Algos.encode(h.transactionsId).asJson,
"adProofsId" -> Algos.encode(h.ADProofsId).asJson
"adProofsId" -> Algos.encode(h.ADProofsId).asJson,
"unparsedBytes" -> Algos.encode(h.unparsedBytes).asJson
).asJson
}

Expand All @@ -197,8 +205,10 @@ object Header extends ApiCodecs {
version <- c.downField("version").as[Byte]
votes <- c.downField("votes").as[String]
solutions <- c.downField("powSolutions").as[AutolykosSolution]
unparsedBytes <- c.downField("unparsedBytes").as[Option[Array[Byte]]]
} yield Header(version, parentId, adProofsRoot, stateRoot,
transactionsRoot, timestamp, nBits, height, extensionHash, solutions, Algos.decode(votes).get)
transactionsRoot, timestamp, nBits, height, extensionHash, solutions, Algos.decode(votes).get,
unparsedBytes.getOrElse(Array.emptyByteArray))
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@ object HeaderSerializer extends ErgoSerializer[Header] {
// For block version >= 2, this new byte encodes length of possible new fields.
// Set to 0 for now, so no new fields.
if (h.version > Header.InitialVersion) {
w.putUByte(0)
w.putUByte(h.unparsedBytes.length)
w.putBytes(h.unparsedBytes)
}
}

Expand All @@ -56,15 +57,20 @@ object HeaderSerializer extends ErgoSerializer[Header] {

// For block version >= 2, a new byte encodes length of possible new fields.
// If this byte > 0, we read new fields but do nothing, as semantics of the fields is not known.
if (version > Header.InitialVersion) {
val unparsedBytes = if (version > Header.InitialVersion) {
val newFieldsSize = r.getUByte()
if (newFieldsSize > 0) {
if (newFieldsSize > 0 && version > Header.Interpreter60Version) {
// new bytes could be added only for block version >= 5
r.getBytes(newFieldsSize)
} else {
Array.emptyByteArray
}
} else {
Array.emptyByteArray
}

HeaderWithoutPow(version, parentId, ADProofsRoot, stateRoot, transactionsRoot, timestamp,
nBits, height, extensionHash, votes)
nBits, height, extensionHash, votes, unparsedBytes)
}

override def parse(r: Reader): Header = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,19 +17,20 @@ class HeaderWithoutPow(val version: Header.Version, // 1 byte
val nBits: Long, //actually it is unsigned int
val height: Int,
val extensionRoot: Digest32,
val votes: Array[Byte]) { //3 bytes
val votes: Array[Byte], //3 bytes
val unparsedBytes: Array[Byte]) {
def toHeader(powSolution: AutolykosSolution, headerSize: Option[Int] = None): Header =
Header(version, parentId, ADProofsRoot, stateRoot, transactionsRoot, timestamp,
nBits, height, extensionRoot, powSolution, votes, headerSize)
nBits, height, extensionRoot, powSolution, votes, unparsedBytes, headerSize)
}

object HeaderWithoutPow {

def apply(version: Header.Version, parentId: ModifierId, ADProofsRoot: Digest32, stateRoot: ADDigest,
transactionsRoot: Digest32, timestamp: Header.Timestamp, nBits: Long, height: Int,
extensionRoot: Digest32, votes: Array[Byte]): HeaderWithoutPow = {
extensionRoot: Digest32, votes: Array[Byte], unparsedBytes: Array[Byte]): HeaderWithoutPow = {
new HeaderWithoutPow(version, parentId, ADProofsRoot, stateRoot, transactionsRoot, timestamp,
nBits, height, extensionRoot, votes)
nBits, height, extensionRoot, votes, unparsedBytes)
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ object PreGenesisHeader extends Header(
extensionRoot = null,
powSolution = null,
votes = null,
unparsedBytes = Array.emptyByteArray,
sizeOpt = None) {

override def serializedId: Array[Byte] = idToBytes(Header.GenesisParentId)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ class HeaderSerializationSpecification extends ErgoCorePropertyTest {
val votes = Array[Byte](4, 3, 0)

val h = Header(version, parentId, adProofsRoot, stateRoot, transactionsRoot, timestamp, nBits,
height, extensionRoot, powSolution, votes)
height, extensionRoot, powSolution, votes, Array.emptyByteArray)

h.id shouldBe "8cf6dca6b9505243e36192fa107735024c0000cf4594b1daa2dc4e13ee86f26f"

Expand Down Expand Up @@ -141,7 +141,7 @@ class HeaderSerializationSpecification extends ErgoCorePropertyTest {
val votes = Array[Byte](0, 0, 0)

val h = Header(version, parentId, adProofsRoot, stateRoot, transactionsRoot, timestamp, nBits,
height, extensionRoot, powSolution, votes)
height, extensionRoot, powSolution, votes, Array.emptyByteArray)

h.id shouldBe "f46c89e44f13a92d8409341490f97f05c85785fa8d2d2164332cc066eda95c39"

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,7 @@ object ErgoCoreGenerators {
extensionHash,
powSolution,
Array.fill(3)(0: Byte),
Array.emptyByteArray,
None
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -903,7 +903,8 @@ object CandidateGenerator extends ScorexLogging {
candidate.nBits,
height,
extensionRoot,
candidate.votes
candidate.votes,
Array.emptyByteArray
)
}

Expand Down
Loading