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

NODE-2632 Delayed Light Node block structure #3917

Merged
merged 29 commits into from
Dec 7, 2023
Merged
Show file tree
Hide file tree
Changes from 15 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
d687aeb
Directory for LightNode integration tests
xrtm000 Nov 17, 2023
9234c3d
NODE-2632 Delayed Light Node block structure
xrtm000 Nov 22, 2023
a1ef6c7
Optimised imports
xrtm000 Nov 22, 2023
bfa329d
Merge remote-tracking branch 'origin/version-1.5.x' into node-2632-de…
xrtm000 Nov 22, 2023
995e66d
Restored log.debug
xrtm000 Nov 22, 2023
46a2ef2
Typo
xrtm000 Nov 23, 2023
f40c9cc
Adapted withMiner()
xrtm000 Nov 23, 2023
54cd9df
Corrected BlockDiffer
xrtm000 Nov 23, 2023
b51a445
Improved LightNodeBlockFieldsTest
xrtm000 Nov 23, 2023
c7a841f
Restored GenericError
xrtm000 Nov 23, 2023
4c4d019
Better code
xrtm000 Nov 23, 2023
00e054f
Overflow protection
xrtm000 Nov 23, 2023
98de172
Adapted WithState
xrtm000 Nov 23, 2023
497e6e1
Experiment
xrtm000 Nov 23, 2023
9c3f289
Configurable light-node-block-fields-absence-interval
xrtm000 Nov 23, 2023
44d7b29
Merge branch 'version-1.5.x' into node-2632-delayed-light-node-block-…
phearnot Dec 1, 2023
317e394
Imports
xrtm000 Nov 30, 2023
3a73598
Reduced blocks count in LightNodeBlockFieldsTest
xrtm000 Nov 30, 2023
e667dc9
Corrected fields checks
xrtm000 Dec 4, 2023
510ca73
Adapted tests
xrtm000 Dec 4, 2023
054505e
Adapted tests
xrtm000 Dec 4, 2023
1fab951
Test that new fields are prohibited for an interval
xrtm000 Dec 4, 2023
dd82095
Adapted light node mining
xrtm000 Dec 5, 2023
80b75d4
Merge branch 'version-1.5.x' into node-2632-delayed-light-node-block-…
phearnot Dec 5, 2023
eb652de
Merge branch 'version-1.5.x' into node-2632-delayed-light-node-block-…
phearnot Dec 5, 2023
7900745
Removed excessive validation and adapted test
xrtm000 Dec 6, 2023
4d26bee
Merge remote-tracking branch 'origin/version-1.5.x' into node-2632-de…
xrtm000 Dec 7, 2023
33005f4
Improved test
xrtm000 Dec 7, 2023
3423863
Reduced code
xrtm000 Dec 7, 2023
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 @@ -3,15 +3,7 @@ package com.wavesplatform.api.grpc.test
import com.google.protobuf.ByteString
import com.wavesplatform.TestValues
import com.wavesplatform.account.{Address, KeyPair}
import com.wavesplatform.api.grpc.{
AccountRequest,
AccountsApiGrpcImpl,
BalanceResponse,
BalancesRequest,
DataEntryResponse,
DataRequest,
LeaseResponse
}
import com.wavesplatform.api.grpc.{AccountRequest, AccountsApiGrpcImpl, BalanceResponse, BalancesRequest, DataEntryResponse, DataRequest, LeaseResponse}
import com.wavesplatform.block.Block
import com.wavesplatform.common.state.ByteStr
import com.wavesplatform.crypto.DigestLength
Expand All @@ -27,6 +19,7 @@ import com.wavesplatform.transaction.TxHelpers
import com.wavesplatform.utils.DiffMatchers
import monix.execution.Scheduler.Implicits.global
import org.scalatest.{Assertion, BeforeAndAfterAll}
import com.wavesplatform.test.DomainPresets.*

import scala.concurrent.Await
import scala.concurrent.duration.{DurationInt, FiniteDuration}
Expand Down Expand Up @@ -194,7 +187,7 @@ class AccountsApiGrpcSpec extends FreeSpec with BeforeAndAfterAll with DiffMatch

val sender = TxHelpers.signer(1)
val challengedMiner = TxHelpers.signer(2)
withDomain(DomainPresets.TransactionStateSnapshot, balances = AddrWithBalance.enoughBalances(sender)) { d =>
withDomain(TransactionStateSnapshot.configure(_.copy(lightNodeBlockFieldsAbsenceInterval = 0)), balances = AddrWithBalance.enoughBalances(sender)) { d =>
val grpcApi = getGrpcApi(d)

val challengingMiner = d.wallet.generateNewAccount().get
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -253,7 +253,7 @@ class BlocksApiGrpcSpec extends FreeSpec with BeforeAndAfterAll with DiffMatcher

"NODE-922. GetBlock should return correct data for challenging block" in {
val sender = TxHelpers.signer(1)
withDomain(DomainPresets.TransactionStateSnapshot, balances = AddrWithBalance.enoughBalances(sender, defaultSigner)) { d =>
withDomain(TransactionStateSnapshot.configure(_.copy(lightNodeBlockFieldsAbsenceInterval = 0)), balances = AddrWithBalance.enoughBalances(sender, defaultSigner)) { d =>
val grpcApi = getGrpcApi(d)
val challengingMiner = d.wallet.generateNewAccount().get

Expand Down Expand Up @@ -304,7 +304,7 @@ class BlocksApiGrpcSpec extends FreeSpec with BeforeAndAfterAll with DiffMatcher

"NODE-922. GetBlockRange should return correct data for challenging block" in {
val sender = TxHelpers.signer(1)
withDomain(DomainPresets.TransactionStateSnapshot, balances = AddrWithBalance.enoughBalances(sender, defaultSigner)) { d =>
withDomain(TransactionStateSnapshot.configure(_.copy(lightNodeBlockFieldsAbsenceInterval = 0)), balances = AddrWithBalance.enoughBalances(sender, defaultSigner)) { d =>
val grpcApi = getGrpcApi(d)
val challengingMiner = d.wallet.generateNewAccount().get

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import com.wavesplatform.history.Domain
import com.wavesplatform.protobuf.transaction.{PBTransactions, Recipient}
import com.wavesplatform.state.TxMeta
import com.wavesplatform.test.*
import com.wavesplatform.test.DomainPresets.*
import com.wavesplatform.transaction.Asset.Waves
import com.wavesplatform.transaction.{TxHelpers, TxVersion}
import com.wavesplatform.transaction.assets.exchange.{ExchangeTransaction, Order, OrderType}
Expand Down Expand Up @@ -142,7 +143,7 @@ class TransactionsApiGrpcSpec extends FreeSpec with BeforeAndAfterAll with DiffM
val challengedMiner = TxHelpers.signer(2)
val resender = TxHelpers.signer(3)
val recipient = TxHelpers.signer(4)
withDomain(DomainPresets.TransactionStateSnapshot, balances = AddrWithBalance.enoughBalances(sender)) { d =>
withDomain(TransactionStateSnapshot.configure(_.copy(lightNodeBlockFieldsAbsenceInterval = 0)), balances = AddrWithBalance.enoughBalances(sender)) { d =>
val grpcApi = getGrpcApi(d)
val challengingMiner = d.wallet.generateNewAccount().get

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -812,7 +812,7 @@ class BlockchainUpdatesSpec extends FreeSpec with WithBUDomain with ScalaFutures
val sender = TxHelpers.signer(3)
val recipient = TxHelpers.signer(4)

withDomainAndRepo(settings = DomainPresets.TransactionStateSnapshot) { case (d, repo) =>
withDomainAndRepo(settings = TransactionStateSnapshot.configure(_.copy(lightNodeBlockFieldsAbsenceInterval = 0))) { case (d, repo) =>
val challengingMiner = d.wallet.generateNewAccount().get

val initSenderBalance = 100000.waves
Expand Down
Original file line number Diff line number Diff line change
@@ -1,24 +1,24 @@
package com.wavesplatform.it.sync
package com.wavesplatform.it.sync.lightnode

import com.typesafe.config.Config
import com.wavesplatform.account.KeyPair
import com.wavesplatform.block.Block
import com.wavesplatform.common.state.ByteStr
import com.wavesplatform.common.utils.EitherExt2
import com.wavesplatform.consensus.FairPoSCalculator
import com.wavesplatform.{TestValues, crypto}
import com.wavesplatform.features.BlockchainFeatures
import com.wavesplatform.it.api.Block as ApiBlock
import com.wavesplatform.it.{BaseFunSuite, Node, NodeConfigs, TransferSending}
import com.wavesplatform.it.api.AsyncNetworkApi.NodeAsyncNetworkApi
import com.wavesplatform.it.api.Block as ApiBlock
import com.wavesplatform.it.api.SyncHttpApi.*
import com.wavesplatform.it.{BaseFunSuite, Node, NodeConfigs, TransferSending}
import com.wavesplatform.lang.directives.values.V8
import com.wavesplatform.lang.v1.compiler.TestCompiler
import com.wavesplatform.network.RawBytes
import com.wavesplatform.transaction.Asset.Waves
import com.wavesplatform.transaction.assets.exchange.OrderType
import com.wavesplatform.transaction.transfer.MassTransferTransaction.ParsedTransfer
import com.wavesplatform.transaction.{Transaction, TxHelpers, TxNonNegativeAmount}
import com.wavesplatform.{TestValues, crypto}

import scala.concurrent.Await
import scala.concurrent.duration.*
Expand All @@ -36,6 +36,7 @@ class BlockChallengeSuite extends BaseFunSuite with TransferSending {
BlockchainFeatures.LightNode.id.toInt -> 0
)
)
.overrideBase(_.raw("waves.blockchain.custom.functionality.light-node-block-fields-absence-interval = 0"))
.withDefault(1)
.withSpecial(1, _.lightNode)
.withSpecial(2, _.nonMiner)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
package com.wavesplatform.it.sync
package com.wavesplatform.it.sync.lightnode

import com.google.common.primitives.Ints
import com.typesafe.config.Config
import com.wavesplatform.account.{Address, PublicKey}
import com.wavesplatform.it.{BaseFunSuite, NodeConfigs, TransferSending}
import com.wavesplatform.it.api.SyncHttpApi.*
import com.wavesplatform.it.{BaseFunSuite, NodeConfigs, TransferSending}

class LightNodeBroadcastSuite extends BaseFunSuite with TransferSending {
override def nodeConfigs: Seq[Config] =
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
package com.wavesplatform.it.sync
package com.wavesplatform.it.sync.lightnode

import com.google.common.primitives.Ints
import com.typesafe.config.Config
import com.wavesplatform.account.{Address, PublicKey}
import com.wavesplatform.it.{BaseFunSuite, NodeConfigs, TransferSending}
import com.wavesplatform.it.api.SyncHttpApi.*
import com.wavesplatform.it.{BaseFunSuite, NodeConfigs, TransferSending}

class LightNodeRollbackSuite extends BaseFunSuite with TransferSending {
override def nodeConfigs: Seq[Config] =
Expand Down
4 changes: 4 additions & 0 deletions node/src/main/resources/custom-defaults.conf
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ functionality {
lease-expiration = 1000000
min-block-time = 15s
delay-delta = 8

# Fill new block header fields (state hash and challenged header)
# only specified number of blocks after the Light Node blockchain feature activation
light-node-block-fields-absence-interval = 1000
}

# Block rewards settings
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -128,9 +128,9 @@ case class BlocksApiRoute(settings: RestAPISettings, commonApi: CommonBlocksApi,
val predictedHeight = (lowerBound + offset).max(lowerBound).min(upperBound)

val timestamp = timestampOf(predictedHeight)
val rightTimestmap = timestampOf(predictedHeight + 1, Long.MaxValue)
val rightTimestamp = timestampOf(predictedHeight + 1, Long.MaxValue)
val leftHit = timestamp <= target
val rightHit = rightTimestmap <= target
val rightHit = rightTimestamp <= target

val (newLower, newUpper) = {
if (!leftHit) (lowerBound, (predictedHeight - 1).max(lowerBound))
Expand Down
3 changes: 1 addition & 2 deletions node/src/main/scala/com/wavesplatform/crypto/package.scala
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
package com.wavesplatform

import java.lang.reflect.Constructor

import com.wavesplatform.account.{PrivateKey, PublicKey}
import com.wavesplatform.common.state.ByteStr
import com.wavesplatform.lang.ValidationError
import com.wavesplatform.transaction.TxValidationError.GenericError
import com.wavesplatform.utils.*
import org.whispersystems.curve25519.OpportunisticCurve25519Provider

import java.lang.reflect.Constructor
import scala.util.Try

package object crypto {
Expand Down
38 changes: 20 additions & 18 deletions node/src/main/scala/com/wavesplatform/mining/BlockChallenger.scala
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,8 @@ class BlockChallengerImpl(
settings: WavesSettings,
timeService: Time,
pos: PoSSelector,
appendBlock: Block => Task[Either[ValidationError, BlockApplyResult]]
appendBlock: Block => Task[Either[ValidationError, BlockApplyResult]],
timeDrift: Long = MaxTimeDrift
) extends BlockChallenger
with ScorexLogging {

Expand Down Expand Up @@ -179,8 +180,6 @@ class BlockChallengerImpl(
blockchainUpdater.parentHeader(prevBlockHeader, 2).map(_.timestamp),
blockTime
)

initialBlockSnapshot <- BlockDiffer.createInitialBlockSnapshot(blockchainUpdater, challengedBlock.header.reference, acc.toAddress)
blockWithoutChallengeAndStateHash <- Block.buildAndSign(
challengedBlock.header.version,
blockTime,
Expand All @@ -204,6 +203,7 @@ class BlockChallengerImpl(
blockchainUpdater.computeNextReward,
None
)
initialBlockSnapshot <- BlockDiffer.createInitialBlockSnapshot(blockchainUpdater, challengedBlock.header.reference, acc.toAddress)
stateHash <- TxStateSnapshotHashBuilder
.computeStateHash(
txs,
Expand All @@ -227,26 +227,28 @@ class BlockChallengerImpl(
acc,
blockFeatures(blockchainUpdater, settings),
blockRewardVote(settings),
Some(stateHash),
Some(
ChallengedHeader(
challengedBlock.header.timestamp,
challengedBlock.header.baseTarget,
challengedBlock.header.generationSignature,
challengedBlock.header.featureVotes,
challengedBlock.header.generator,
challengedBlock.header.rewardVote,
challengedStateHash,
challengedSignature
if (blockchainWithNewBlock.supportsLightNodeBlockFields()) Some(stateHash) else None,
if (blockchainWithNewBlock.supportsLightNodeBlockFields())
Some(
ChallengedHeader(
challengedBlock.header.timestamp,
challengedBlock.header.baseTarget,
challengedBlock.header.generationSignature,
challengedBlock.header.featureVotes,
challengedBlock.header.generator,
challengedBlock.header.rewardVote,
challengedStateHash,
challengedSignature
)
)
)
else None
)
} yield {
log.debug(s"Forged challenging block $challengingBlock")
challengingBlock
}
}.flatMap {
case res @ Right(block) => waitForTimeAlign(block.header.timestamp).map(_ => res)
case res @ Right(block) => waitForTimeAlign(block.header.timestamp, timeDrift).map(_ => res)
case err @ Left(_) => Task(err)
}

Expand All @@ -262,10 +264,10 @@ class BlockChallengerImpl(
private def blockRewardVote(settings: WavesSettings): Long =
settings.rewardsSettings.desired.getOrElse(-1L)

private def waitForTimeAlign(blockTime: Long): Task[Unit] =
private def waitForTimeAlign(blockTime: Long, timeDrift: Long): Task[Unit] =
Task {
val currentTime = timeService.correctedTime()
blockTime - currentTime - MaxTimeDrift
blockTime - currentTime - timeDrift
}.flatMap { timeDiff =>
if (timeDiff > 0) {
Task.sleep(timeDiff.millis)
Expand Down
15 changes: 8 additions & 7 deletions node/src/main/scala/com/wavesplatform/mining/Miner.scala
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package com.wavesplatform.mining

import java.time.LocalTime
import cats.syntax.either.*
import com.wavesplatform.account.{Address, KeyPair, PKKeyPair}
import com.wavesplatform.block.Block.*
Expand All @@ -18,11 +17,11 @@ import com.wavesplatform.state.*
import com.wavesplatform.state.BlockchainUpdaterImpl.BlockApplyResult.{Applied, Ignored}
import com.wavesplatform.state.appender.BlockAppender
import com.wavesplatform.state.diffs.BlockDiffer
import com.wavesplatform.transaction.TxValidationError.BlockFromFuture
import com.wavesplatform.transaction.*
import com.wavesplatform.transaction.TxValidationError.BlockFromFuture
import com.wavesplatform.utils.{ScorexLogging, Time}
import com.wavesplatform.utx.UtxPool.PackStrategy
import com.wavesplatform.utx.UtxPool
import com.wavesplatform.utx.UtxPool.PackStrategy
import com.wavesplatform.wallet.Wallet
import io.netty.channel.group.ChannelGroup
import kamon.Kamon
Expand All @@ -31,6 +30,7 @@ import monix.execution.cancelables.{CompositeCancelable, SerialCancelable}
import monix.execution.schedulers.SchedulerService
import monix.reactive.Observable

import java.time.LocalTime
import scala.concurrent.duration.*

trait Miner {
Expand Down Expand Up @@ -60,7 +60,8 @@ class MinerImpl(
pos: PoSSelector,
val minerScheduler: SchedulerService,
val appenderScheduler: SchedulerService,
transactionAdded: Observable[Unit]
transactionAdded: Observable[Unit],
maxTimeDrift: Long = appender.MaxTimeDrift
) extends Miner
with MinerDebugInfo
with ScorexLogging {
Expand Down Expand Up @@ -184,11 +185,11 @@ class MinerImpl(
currentTime - 1.minute.toMillis
)
_ <- Either.cond(
blockTime <= currentTime + appender.MaxTimeDrift,
blockTime <= currentTime + maxTimeDrift,
log.debug(
s"Forging with ${account.toAddress}, balance $balance, prev block $reference at $height with target ${lastBlockHeader.baseTarget}"
),
s"Block time $blockTime is from the future: current time is $currentTime, MaxTimeDrift = ${appender.MaxTimeDrift}"
s"Block time $blockTime is from the future: current time is $currentTime, MaxTimeDrift = $maxTimeDrift"
)
consensusData <- consensusData(height, account, lastBlockHeader, blockTime)
prevStateHash =
Expand All @@ -207,7 +208,7 @@ class MinerImpl(
account,
blockFeatures(version),
blockRewardVote(version),
stateHash,
if (blockchainUpdater.supportsLightNodeBlockFields(height + 1)) stateHash else None,
None
)
.leftMap(_.err)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ class MicroBlockMinerImpl(
signer = account,
featureVotes = accumulatedBlock.header.featureVotes,
rewardVote = accumulatedBlock.header.rewardVote,
stateHash = stateHash,
stateHash = if (blockchainUpdater.supportsLightNodeBlockFields()) stateHash else None,
challengedHeader = None
)
.leftMap(BlockBuildError)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,8 @@ case class FunctionalitySettings(
ethInvokePaymentsCheckHeight: Int = 0,
daoAddress: Option[String] = None,
xtnBuybackAddress: Option[String] = None,
xtnBuybackRewardPeriod: Int = Int.MaxValue
xtnBuybackRewardPeriod: Int = Int.MaxValue,
lightNodeBlockFieldsAbsenceInterval: Int = 1000
) {
val allowLeasedBalanceTransferUntilHeight: Int = blockVersion3AfterHeight
val allowTemporaryNegativeUntil: Long = lastTimeBasedForkParameter
Expand Down
4 changes: 4 additions & 0 deletions node/src/main/scala/com/wavesplatform/state/Blockchain.scala
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import com.wavesplatform.block.Block.*
import com.wavesplatform.block.{Block, BlockHeader, SignedBlockHeader}
import com.wavesplatform.common.state.ByteStr
import com.wavesplatform.consensus.GeneratingBalanceProvider
import com.wavesplatform.features.BlockchainFeatures.LightNode
import com.wavesplatform.features.{BlockchainFeature, BlockchainFeatureStatus, BlockchainFeatures}
import com.wavesplatform.lang.ValidationError
import com.wavesplatform.lang.script.ContractScript
Expand Down Expand Up @@ -221,5 +222,8 @@ object Blockchain {

def hasBannedEffectiveBalance(address: Address, height: Int = blockchain.height): Boolean =
blockchain.effectiveBalanceBanHeights(address).contains(height)

def supportsLightNodeBlockFields(height: Int = blockchain.height): Boolean =
blockchain.featureActivationHeight(LightNode.id).exists(height >= _ + blockchain.settings.functionalitySettings.lightNodeBlockFieldsAbsenceInterval)
}
}
Loading