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

Fixed InvalidStateHash #3937

Open
wants to merge 7 commits into
base: version-1.5.x
Choose a base branch
from
Open
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
2 changes: 1 addition & 1 deletion .github/workflows/publish-docker-image.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ on:
baseImage:
description: 'Base image'
required: true
default: 'eclipse-temurin:11-jre-noble'
default: 'eclipse-temurin:21-jre-noble'
type: string

env:
Expand Down
5 changes: 3 additions & 2 deletions node/src/main/scala/com/wavesplatform/mining/Miner.scala
Original file line number Diff line number Diff line change
Expand Up @@ -166,12 +166,13 @@ class MinerImpl(
}
}

def forgeBlock(account: KeyPair): Either[String, (Block, MiningConstraint)] = {
def forgeBlock(account: KeyPair, referenceOpt: Option[ByteStr] = None): Either[String, (Block, MiningConstraint)] = {
// should take last block right at the time of mining since microblocks might have been added
val height = blockchainUpdater.height
val version = blockchainUpdater.nextBlockVersion
val lastBlockHeader = blockchainUpdater.lastBlockHeader.get.header
val reference = blockchainUpdater.bestLastBlockInfo(System.currentTimeMillis() - minMicroBlockDurationMills).get.blockId
val lastBlockInfo = blockchainUpdater.bestLastBlockInfo(System.currentTimeMillis() - minMicroBlockDurationMills)
val reference = referenceOpt.getOrElse(lastBlockInfo.get.blockId)

metrics.blockBuildTimeStats.measureSuccessful(for {
_ <- checkQuorumAvailable()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ class MicroBlockMinerImpl(
case Retry =>
Task
.defer(generateMicroBlockSequence(account, accumulatedBlock, restTotalConstraint, lastMicroBlock))
.delayExecution(1 second)
.delayExecution((settings.microBlockInterval / 2).max(1.millis))
case Stop =>
setDebugState(MinerDebugInfo.MiningBlocks)
Task(log.debug("MicroBlock mining completed, block is full"))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,33 @@ class BlockchainUpdaterImpl(
.orElse(lastBlockReward)
}

/** Referenced blockchain for mining.
* @return
* SnapshotBlockchain with a reward for a next height
* @note
* Do not use for other purposes
*/
def referencedBlockchain(reference: ByteStr): Blockchain =
ngState
.flatMap { ng =>
if (ng.base.header.reference == reference)
Some(SnapshotBlockchain(rocksdb, ng.reward)) // Same reward for a competitor's block, because same height
else
ng.snapshotOf(reference)
.map { case (forgedBlock, liquidSnapshot, carry, _, stateHash, _) =>
SnapshotBlockchain(
rocksdb,
liquidSnapshot,
forgedBlock,
ng.hitSource,
carry,
computeNextReward,
Some(stateHash)
)
}
}
.getOrElse(SnapshotBlockchain(rocksdb, computeNextReward)) // WARN: This seems not happen

override def processBlock(
block: Block,
hitSource: ByteStr,
Expand Down Expand Up @@ -798,15 +825,17 @@ class BlockchainUpdaterImpl(
snapshotBlockchain.resolveERC20Address(address)
}

override def lastStateHash(refId: Option[ByteStr]): ByteStr =
override def lastStateHash(refId: Option[ByteStr]): ByteStr = readLock {
ngState
.map { ng =>
refId.filter(ng.contains).fold(ng.bestLiquidComputedStateHash)(id => ng.snapshotFor(id)._4)
}
.getOrElse(rocksdb.lastStateHash(None))
}

def snapshotBlockchain: SnapshotBlockchain =
def snapshotBlockchain: SnapshotBlockchain = readLock {
ngState.fold[SnapshotBlockchain](SnapshotBlockchain(rocksdb, StateSnapshot.empty))(SnapshotBlockchain(rocksdb, _))
}

// noinspection ScalaStyle,TypeAnnotation
private[this] object metrics {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@ object BlockAppender extends ScorexLogging {
)(newBlock: Block, snapshot: Option[BlockSnapshotResponse]): Task[Either[ValidationError, BlockApplyResult]] =
Task {
if (
blockchainUpdater
.isLastBlockId(newBlock.header.reference) || blockchainUpdater.lastBlockHeader.exists(_.header.reference == newBlock.header.reference)
blockchainUpdater.isLastBlockId(newBlock.header.reference) ||
blockchainUpdater.lastBlockHeader.exists(_.header.reference == newBlock.header.reference)
) {
if (newBlock.header.challengedHeader.isDefined) {
appendChallengeBlock(blockchainUpdater, utxStorage, pos, time, log, verify, txSignParCheck)(newBlock, snapshot)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -284,19 +284,19 @@ object BlockDiffer {
}

def createInitialBlockSnapshot(
blockchain: BlockchainUpdater & Blockchain,
blockchainUpdater: BlockchainUpdater & Blockchain,
reference: ByteStr,
miner: Address
): Either[ValidationError, StateSnapshot] = {
val fullReward = blockchain.computeNextReward.fold(Portfolio.empty)(Portfolio.waves)
val blockchain = blockchainUpdater.referencedBlockchain(reference)
val feeFromPreviousBlock = Portfolio.waves(blockchain.carryFee(Some(reference)))

val daoAddress = blockchain.settings.functionalitySettings.daoAddressParsed.toOption.flatten
val xtnBuybackAddress = blockchain.settings.functionalitySettings.xtnBuybackAddressParsed.toOption.flatten

val rewardShares = BlockRewardCalculator.getBlockRewardShares(
blockchain.height + 1,
fullReward.balance,
blockchainUpdater.computeNextReward.getOrElse(0),
daoAddress,
xtnBuybackAddress,
blockchain
Expand Down Expand Up @@ -497,6 +497,6 @@ object BlockDiffer {
Either.cond(
!blockchain.supportsLightNodeBlockFields() || blockStateHash.contains(computedStateHash),
(),
InvalidStateHash(blockStateHash)
InvalidStateHash(blockStateHash, Some(computedStateHash))
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import com.wavesplatform.block.Block.BlockId
import com.wavesplatform.block.{Block, BlockSnapshot, MicroBlock, MicroBlockSnapshot}
import com.wavesplatform.common.state.ByteStr
import com.wavesplatform.lang.ValidationError
import com.wavesplatform.state.Blockchain
import com.wavesplatform.state.BlockchainUpdaterImpl.BlockApplyResult
import monix.reactive.Observable

Expand All @@ -20,6 +21,7 @@ trait BlockchainUpdater {
def removeAfter(blockId: ByteStr): Either[ValidationError, DiscardedBlocks]
def lastBlockInfo: Observable[LastBlockInfo]
def isLastBlockId(id: ByteStr): Boolean
def referencedBlockchain(reference: ByteStr): Blockchain
def shutdown(): Unit
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ object TxValidationError {
override def toString: String = s"InvalidSignature(${entity.toString + " reason: " + details})"
}

case class InvalidStateHash(blockStateHash: Option[ByteStr]) extends ValidationError
case class InvalidStateHash(blockStateHash: Option[ByteStr], computedStateHash: Option[ByteStr]) extends ValidationError

sealed trait WithLog extends Product with Serializable {
def log: Log[Id]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import com.wavesplatform.block.{Block, BlockHeader, SignedBlockHeader}
import com.wavesplatform.common.state.ByteStr
import com.wavesplatform.common.utils.EitherExt2
import com.wavesplatform.crypto.DigestLength
import com.wavesplatform.db.WithDomain
import com.wavesplatform.features.BlockchainFeatures
import com.wavesplatform.history.{chainBaseAndMicro, defaultSigner}
import com.wavesplatform.lagonaki.mocks.TestBlock
Expand All @@ -28,7 +27,8 @@ import org.scalatest.enablers.Length

import java.util.concurrent.atomic.AtomicReference
import scala.concurrent.duration.*
class BlockV5Test extends FlatSpec with WithDomain with OptionValues with EitherValues with BlocksTransactionsHelpers {

class BlockV5Test extends FlatSpec with WithMiner with OptionValues with EitherValues with BlocksTransactionsHelpers {
import BlockV5Test.*

private val testTime = TestTime(1)
Expand Down
Loading
Loading