From e6a5b4a6a18e0dec0481e15a6eca901077e3be3c Mon Sep 17 00:00:00 2001 From: Artyom Sayadyan Date: Fri, 27 Oct 2023 17:27:40 +0300 Subject: [PATCH 1/9] NODE-2626 Corrected snapshot hash of LeaseState --- .../scala/com/wavesplatform/state/StateSnapshot.scala | 8 +++----- .../wavesplatform/state/TxStateSnapshotHashBuilder.scala | 7 ++++++- .../state/snapshot/StateSnapshotProtoTest.scala | 6 +++--- .../state/snapshot/StateSnapshotStorageTest.scala | 8 ++++---- .../state/snapshot/TxStateSnapshotHashSpec.scala | 7 ++++++- project/Dependencies.scala | 2 +- 6 files changed, 23 insertions(+), 15 deletions(-) diff --git a/node/src/main/scala/com/wavesplatform/state/StateSnapshot.scala b/node/src/main/scala/com/wavesplatform/state/StateSnapshot.scala index bbf9912715..fd6f56bd2e 100644 --- a/node/src/main/scala/com/wavesplatform/state/StateSnapshot.scala +++ b/node/src/main/scala/com/wavesplatform/state/StateSnapshot.scala @@ -77,9 +77,7 @@ case class StateSnapshot( pbStatus, amount, sender.toByteString, - ByteString.copyFrom(recipient.asInstanceOf[Address].bytes), - sourceId.toByteString, - height + ByteString.copyFrom(recipient.asInstanceOf[Address].bytes) ) }.toSeq, accountScripts.map { case (publicKey, scriptOpt) => @@ -184,8 +182,8 @@ object StateSnapshot { case _ => LeaseDetails.Status.Active }, - ls.originTransactionId.toByteStr, - ls.height + sourceId = ByteStr.empty, + height = 0 ) ) .toMap diff --git a/node/src/main/scala/com/wavesplatform/state/TxStateSnapshotHashBuilder.scala b/node/src/main/scala/com/wavesplatform/state/TxStateSnapshotHashBuilder.scala index c5c60a8bbe..7c980d2d90 100644 --- a/node/src/main/scala/com/wavesplatform/state/TxStateSnapshotHashBuilder.scala +++ b/node/src/main/scala/com/wavesplatform/state/TxStateSnapshotHashBuilder.scala @@ -75,7 +75,12 @@ object TxStateSnapshotHashBuilder { } addEntry(KeyType.AssetScript, asset.id.arr)(scriptInfo.script.bytes().arr) snapshot.leaseStates.foreach { case (leaseId, details) => - addEntry(KeyType.LeaseStatus, leaseId.arr)(booleanToBytes(details.isActive)) + addEntry(KeyType.LeaseStatus, leaseId.arr)( + booleanToBytes(details.isActive), + details.sender.arr, + details.recipient.bytes, + Longs.toByteArray(details.amount) + ) } snapshot.sponsorships.foreach { case (asset, sponsorship) => diff --git a/node/src/test/scala/com/wavesplatform/state/snapshot/StateSnapshotProtoTest.scala b/node/src/test/scala/com/wavesplatform/state/snapshot/StateSnapshotProtoTest.scala index 7f2d5ae0a1..89f2a44bb8 100644 --- a/node/src/test/scala/com/wavesplatform/state/snapshot/StateSnapshotProtoTest.scala +++ b/node/src/test/scala/com/wavesplatform/state/snapshot/StateSnapshotProtoTest.scala @@ -60,14 +60,14 @@ class StateSnapshotProtoTest extends PropSpec { IssuedAsset(ByteStr.fromBytes(2, 2, 2)) -> SponsorshipValue(0) ), Map( - ByteStr.fromBytes(4, 5, 6) -> LeaseDetails(defaultSigner.publicKey, secondAddress, 123, Status.Active, ByteStr.fromBytes(1, 2, 3), 4), + ByteStr.fromBytes(4, 5, 6) -> LeaseDetails(defaultSigner.publicKey, secondAddress, 123, Status.Active, ByteStr.empty, 0), ByteStr.fromBytes(7, 8, 9) -> LeaseDetails( secondSigner.publicKey, defaultAddress, 0, Status.Cancelled(2, Some(ByteStr.fromBytes(5, 5, 5))), - ByteStr.fromBytes(1, 2, 3), - 777777777 + ByteStr.empty, + 0 ) ), Map( diff --git a/node/src/test/scala/com/wavesplatform/state/snapshot/StateSnapshotStorageTest.scala b/node/src/test/scala/com/wavesplatform/state/snapshot/StateSnapshotStorageTest.scala index 34a4c6c90a..395cd2d91c 100644 --- a/node/src/test/scala/com/wavesplatform/state/snapshot/StateSnapshotStorageTest.scala +++ b/node/src/test/scala/com/wavesplatform/state/snapshot/StateSnapshotStorageTest.scala @@ -175,7 +175,7 @@ class StateSnapshotStorageTest extends PropSpec with WithDomain { recipient -> LeaseBalance(leaseTx.amount.value, 0) ), leaseStates = Map( - leaseTx.id() -> LeaseDetails(sender.publicKey, recipient, leaseTx.amount.value, Active, leaseTx.id(), d.solidStateHeight + 2) + leaseTx.id() -> LeaseDetails(sender.publicKey, recipient, leaseTx.amount.value, Active, ByteStr.empty, 0) ) ) ) @@ -198,8 +198,8 @@ class StateSnapshotStorageTest extends PropSpec with WithDomain { recipient, leaseTx.amount.value, Cancelled(d.solidStateHeight + 2, Some(leaseCancelTx.id())), - leaseTx.id(), - d.solidStateHeight + ByteStr.empty, + 0 ) ) ) @@ -333,7 +333,7 @@ class StateSnapshotStorageTest extends PropSpec with WithDomain { dAppAssetId -> AssetInfo("name", "description", Height(height)) ), leaseStates = Map( - leaseId -> LeaseDetails(dAppPk, senderAddress, 123, Active, invokeId, height) + leaseId -> LeaseDetails(dAppPk, senderAddress, 123, Active, ByteStr.empty, 0) ), accountData = Map( dAppPk.toAddress -> Map("key" -> StringDataEntry("key", "abc")) diff --git a/node/src/test/scala/com/wavesplatform/state/snapshot/TxStateSnapshotHashSpec.scala b/node/src/test/scala/com/wavesplatform/state/snapshot/TxStateSnapshotHashSpec.scala index 75ea473f46..7ad7f43ed4 100644 --- a/node/src/test/scala/com/wavesplatform/state/snapshot/TxStateSnapshotHashSpec.scala +++ b/node/src/test/scala/com/wavesplatform/state/snapshot/TxStateSnapshotHashSpec.scala @@ -132,7 +132,12 @@ class TxStateSnapshotHashSpec extends PropSpec with WithDomain { Array(KeyType.LeaseBalance.id.toByte) ++ address1.bytes ++ Longs.toByteArray(addr1PortfolioDiff.lease.in) ++ Longs.toByteArray( addr1PortfolioDiff.lease.out ), - Array(KeyType.LeaseStatus.id.toByte) ++ leaseId.arr ++ (if (leaseDetails.isActive) Array(1: Byte) else Array(0: Byte)), + Array(KeyType.LeaseStatus.id.toByte) + ++ leaseId.arr + ++ (if (leaseDetails.isActive) Array(1: Byte) else Array(0: Byte)) + ++ leaseDetails.sender.arr + ++ leaseDetails.recipient.bytes + ++ Longs.toByteArray(leaseDetails.amount), Array(KeyType.Sponsorship.id.toByte) ++ assetId1.id.arr ++ Longs.toByteArray(sponsorship.minFee), Array(KeyType.Alias.id.toByte) ++ address1.bytes ++ addr1Alias1.name.getBytes(StandardCharsets.UTF_8), Array(KeyType.Alias.id.toByte) ++ address1.bytes ++ addr1Alias2.name.getBytes(StandardCharsets.UTF_8), diff --git a/project/Dependencies.scala b/project/Dependencies.scala index 155d73d95e..423ee1d527 100644 --- a/project/Dependencies.scala +++ b/project/Dependencies.scala @@ -6,7 +6,7 @@ import sbt.{Def, _} object Dependencies { // Node protobuf schemas private[this] val protoSchemasLib = - "com.wavesplatform" % "protobuf-schemas" % "1.5.0" classifier "protobuf-src" intransitive () + "com.wavesplatform" % "protobuf-schemas" % "1.5.1-84-SNAPSHOT" classifier "protobuf-src" intransitive () def akkaModule(module: String): ModuleID = "com.typesafe.akka" %% s"akka-$module" % "2.6.20" From c17f6506f8b8fbd8042ab5eccca66bfd8581b778 Mon Sep 17 00:00:00 2001 From: Artyom Sayadyan Date: Fri, 27 Oct 2023 17:55:10 +0300 Subject: [PATCH 2/9] Adapted protobuf changes --- .../wavesplatform/api/grpc/AccountsApiGrpcImpl.scala | 10 ++++++---- .../scala/com/wavesplatform/it/api/SyncGrpcApi.scala | 2 +- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/grpc-server/src/main/scala/com/wavesplatform/api/grpc/AccountsApiGrpcImpl.scala b/grpc-server/src/main/scala/com/wavesplatform/api/grpc/AccountsApiGrpcImpl.scala index 75a848b370..e9a0b98525 100644 --- a/grpc-server/src/main/scala/com/wavesplatform/api/grpc/AccountsApiGrpcImpl.scala +++ b/grpc-server/src/main/scala/com/wavesplatform/api/grpc/AccountsApiGrpcImpl.scala @@ -61,15 +61,17 @@ class AccountsApiGrpcImpl(commonApi: CommonAccountsApi)(implicit sc: Scheduler) responseObserver.completeWith(responseStream) } - override def getScript(request: AccountRequest): Future[ScriptData] = Future { + override def getScript(request: AccountRequest): Future[ScriptResponse] = Future { commonApi.script(request.address.toAddress) match { - case Some(desc) => ScriptData( + case Some(desc) => + ScriptResponse( PBTransactions.toPBScript(Some(desc.script)), desc.script.expr.toString, - desc.verifierComplexity + desc.verifierComplexity, + desc.publicKey.toByteString ) case None => - ScriptData() + ScriptResponse() } } diff --git a/node-it/src/test/scala/com/wavesplatform/it/api/SyncGrpcApi.scala b/node-it/src/test/scala/com/wavesplatform/it/api/SyncGrpcApi.scala index 18f089a22f..ce4224cd46 100644 --- a/node-it/src/test/scala/com/wavesplatform/it/api/SyncGrpcApi.scala +++ b/node-it/src/test/scala/com/wavesplatform/it/api/SyncGrpcApi.scala @@ -298,7 +298,7 @@ object SyncGrpcApi extends Assertions { maybeWaitForTransaction(sync(async(n).setScript(sender, script, fee, timestamp, version)), waitForTx) } - def scriptInfo(address: ByteString): ScriptData = { + def scriptInfo(address: ByteString): ScriptResponse = { accounts.getScript(AccountRequest.of(address)) } From 656fc31b84fe711357e5a2c12f4393e5f8f1e0e5 Mon Sep 17 00:00:00 2001 From: Artyom Sayadyan Date: Mon, 30 Oct 2023 11:57:10 +0300 Subject: [PATCH 3/9] Adapted protobuf changes --- .../wavesplatform/state/snapshot/StateSnapshotProtoTest.scala | 2 +- .../wavesplatform/state/snapshot/StateSnapshotStorageTest.scala | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/node/src/test/scala/com/wavesplatform/state/snapshot/StateSnapshotProtoTest.scala b/node/src/test/scala/com/wavesplatform/state/snapshot/StateSnapshotProtoTest.scala index 89f2a44bb8..85f827e16a 100644 --- a/node/src/test/scala/com/wavesplatform/state/snapshot/StateSnapshotProtoTest.scala +++ b/node/src/test/scala/com/wavesplatform/state/snapshot/StateSnapshotProtoTest.scala @@ -65,7 +65,7 @@ class StateSnapshotProtoTest extends PropSpec { secondSigner.publicKey, defaultAddress, 0, - Status.Cancelled(2, Some(ByteStr.fromBytes(5, 5, 5))), + Status.Cancelled(0, None), ByteStr.empty, 0 ) diff --git a/node/src/test/scala/com/wavesplatform/state/snapshot/StateSnapshotStorageTest.scala b/node/src/test/scala/com/wavesplatform/state/snapshot/StateSnapshotStorageTest.scala index 395cd2d91c..a2b764af1a 100644 --- a/node/src/test/scala/com/wavesplatform/state/snapshot/StateSnapshotStorageTest.scala +++ b/node/src/test/scala/com/wavesplatform/state/snapshot/StateSnapshotStorageTest.scala @@ -197,7 +197,7 @@ class StateSnapshotStorageTest extends PropSpec with WithDomain { sender.publicKey, recipient, leaseTx.amount.value, - Cancelled(d.solidStateHeight + 2, Some(leaseCancelTx.id())), + Cancelled(0, None), ByteStr.empty, 0 ) From d1a035bb3ee9fb504af24df4f02b35134c72ba1d Mon Sep 17 00:00:00 2001 From: Artyom Sayadyan Date: Mon, 30 Oct 2023 11:59:34 +0300 Subject: [PATCH 4/9] Adapted StateSnapshot --- .../wavesplatform/state/StateSnapshot.scala | 23 +++++-------------- 1 file changed, 6 insertions(+), 17 deletions(-) diff --git a/node/src/main/scala/com/wavesplatform/state/StateSnapshot.scala b/node/src/main/scala/com/wavesplatform/state/StateSnapshot.scala index fd6f56bd2e..d98413d9ca 100644 --- a/node/src/main/scala/com/wavesplatform/state/StateSnapshot.scala +++ b/node/src/main/scala/com/wavesplatform/state/StateSnapshot.scala @@ -13,7 +13,6 @@ import com.wavesplatform.protobuf.snapshot.TransactionStateSnapshot import com.wavesplatform.protobuf.snapshot.TransactionStateSnapshot.AssetStatic import com.wavesplatform.protobuf.transaction.{PBAmounts, PBRecipients, PBTransactions} import com.wavesplatform.protobuf.{AddressExt, ByteStrExt, ByteStringExt} -import com.wavesplatform.state.reader.LeaseDetails.Status import com.wavesplatform.state.reader.{LeaseDetails, SnapshotBlockchain} import com.wavesplatform.transaction.Asset.{IssuedAsset, Waves} import com.wavesplatform.transaction.TxValidationError.GenericError @@ -63,18 +62,10 @@ case class StateSnapshot( orderFills.map { case (orderId, VolumeAndFee(volume, fee)) => S.OrderFill(orderId.toByteString, volume, fee) }.toSeq, - leaseStates.map { case (leaseId, LeaseDetails(sender, recipient, amount, status, sourceId, height)) => - val pbStatus = status match { - case Status.Active => - S.LeaseState.Status.Active(S.LeaseState.Active()) - case Status.Cancelled(cancelHeight, txId) => - S.LeaseState.Status.Cancelled(S.LeaseState.Cancelled(cancelHeight, txId.fold(ByteString.EMPTY)(_.toByteString))) - case Status.Expired(expiredHeight) => - S.LeaseState.Status.Cancelled(S.LeaseState.Cancelled(expiredHeight)) - } + leaseStates.map { case (leaseId, details @ LeaseDetails(sender, recipient, amount, _, _, _)) => S.LeaseState( leaseId.toByteString, - pbStatus, + details.isActive, amount, sender.toByteString, ByteString.copyFrom(recipient.asInstanceOf[Address].bytes) @@ -176,12 +167,10 @@ object StateSnapshot { ls.sender.toPublicKey, PBRecipients.toAddress(ls.recipient.toByteArray, AddressScheme.current.chainId).explicitGet(), ls.amount, - ls.status match { - case TransactionStateSnapshot.LeaseState.Status.Cancelled(c) => - LeaseDetails.Status.Cancelled(c.height, if (c.transactionId.isEmpty) None else Some(c.transactionId.toByteStr)) - case _ => - LeaseDetails.Status.Active - }, + if (ls.status) + LeaseDetails.Status.Active + else + LeaseDetails.Status.Cancelled(0, None), sourceId = ByteStr.empty, height = 0 ) From a4304b7386024561d8a1dd4aa41da1aea7f39317 Mon Sep 17 00:00:00 2001 From: Artyom Sayadyan Date: Mon, 30 Oct 2023 13:52:22 +0300 Subject: [PATCH 5/9] Adapted to new model --- .../wavesplatform/state/StateSnapshot.scala | 57 +++++++++++-------- .../snapshot/StateSnapshotProtoTest.scala | 7 ++- .../snapshot/StateSnapshotStorageTest.scala | 7 ++- project/Dependencies.scala | 2 +- 4 files changed, 42 insertions(+), 31 deletions(-) diff --git a/node/src/main/scala/com/wavesplatform/state/StateSnapshot.scala b/node/src/main/scala/com/wavesplatform/state/StateSnapshot.scala index d98413d9ca..c90791d699 100644 --- a/node/src/main/scala/com/wavesplatform/state/StateSnapshot.scala +++ b/node/src/main/scala/com/wavesplatform/state/StateSnapshot.scala @@ -3,16 +3,18 @@ import cats.data.Ior import cats.implicits.{catsSyntaxEitherId, catsSyntaxSemigroup, toBifunctorOps, toTraverseOps} import cats.kernel.Monoid import com.google.protobuf.ByteString -import com.wavesplatform.account.{Address, AddressScheme, Alias, PublicKey} +import com.wavesplatform.account.{Address, Alias, PublicKey} import com.wavesplatform.common.state.ByteStr import com.wavesplatform.common.utils.EitherExt2 +import com.wavesplatform.crypto.KeyLength import com.wavesplatform.database.protobuf.EthereumTransactionMeta import com.wavesplatform.lang.ValidationError import com.wavesplatform.lang.script.ScriptReader import com.wavesplatform.protobuf.snapshot.TransactionStateSnapshot import com.wavesplatform.protobuf.snapshot.TransactionStateSnapshot.AssetStatic -import com.wavesplatform.protobuf.transaction.{PBAmounts, PBRecipients, PBTransactions} +import com.wavesplatform.protobuf.transaction.{PBAmounts, PBTransactions} import com.wavesplatform.protobuf.{AddressExt, ByteStrExt, ByteStringExt} +import com.wavesplatform.state.reader.LeaseDetails.Status import com.wavesplatform.state.reader.{LeaseDetails, SnapshotBlockchain} import com.wavesplatform.transaction.Asset.{IssuedAsset, Waves} import com.wavesplatform.transaction.TxValidationError.GenericError @@ -62,14 +64,14 @@ case class StateSnapshot( orderFills.map { case (orderId, VolumeAndFee(volume, fee)) => S.OrderFill(orderId.toByteString, volume, fee) }.toSeq, - leaseStates.map { case (leaseId, details @ LeaseDetails(sender, recipient, amount, _, _, _)) => - S.LeaseState( - leaseId.toByteString, - details.isActive, - amount, - sender.toByteString, - ByteString.copyFrom(recipient.asInstanceOf[Address].bytes) - ) + leaseStates.map { case (leaseId, LeaseDetails(sender, recipient, amount, status, _, _)) => + val pbStatus = status match { + case Status.Active => + S.LeaseState.Status.Active(S.LeaseState.Active(amount, sender.toByteString, recipient.asInstanceOf[Address].toByteString)) + case _: Status.Cancelled | _: Status.Expired => + S.LeaseState.Status.Cancelled(S.LeaseState.Cancelled()) + } + S.LeaseState(leaseId.toByteString, pbStatus) }.toSeq, accountScripts.map { case (publicKey, scriptOpt) => scriptOpt.fold( @@ -161,21 +163,28 @@ object StateSnapshot { .toMap val leaseStates: Map[ByteStr, LeaseDetails] = - pbSnapshot.leaseStates - .map(ls => - ls.leaseId.toByteStr -> LeaseDetails( - ls.sender.toPublicKey, - PBRecipients.toAddress(ls.recipient.toByteArray, AddressScheme.current.chainId).explicitGet(), - ls.amount, - if (ls.status) - LeaseDetails.Status.Active - else + pbSnapshot.leaseStates.map { ls => + ls.status match { + case TransactionStateSnapshot.LeaseState.Status.Active(value) => + ls.leaseId.toByteStr -> LeaseDetails( + value.sender.toPublicKey, + value.recipient.toAddress, + value.amount, + LeaseDetails.Status.Active, + sourceId = ByteStr.empty, + height = 0 + ) + case _: TransactionStateSnapshot.LeaseState.Status.Cancelled | TransactionStateSnapshot.LeaseState.Status.Empty => + ls.leaseId.toByteStr -> LeaseDetails( + PublicKey(ByteStr.fill(KeyLength)(0)), + Address(Array.fill(Address.HashLength)(0)), + 0, LeaseDetails.Status.Cancelled(0, None), - sourceId = ByteStr.empty, - height = 0 - ) - ) - .toMap + sourceId = ByteStr.empty, + height = 0 + ) + } + }.toMap val aliases: Map[Alias, Address] = pbSnapshot.aliases diff --git a/node/src/test/scala/com/wavesplatform/state/snapshot/StateSnapshotProtoTest.scala b/node/src/test/scala/com/wavesplatform/state/snapshot/StateSnapshotProtoTest.scala index 85f827e16a..a160e159f8 100644 --- a/node/src/test/scala/com/wavesplatform/state/snapshot/StateSnapshotProtoTest.scala +++ b/node/src/test/scala/com/wavesplatform/state/snapshot/StateSnapshotProtoTest.scala @@ -1,9 +1,10 @@ package com.wavesplatform.state.snapshot import com.google.protobuf.ByteString -import com.wavesplatform.account.Alias +import com.wavesplatform.account.{Address, Alias, PublicKey} import com.wavesplatform.common.state.ByteStr import com.wavesplatform.common.utils.EitherExt2 +import com.wavesplatform.crypto.KeyLength import com.wavesplatform.lang.directives.values.V6 import com.wavesplatform.lang.v1.compiler.TestCompiler import com.wavesplatform.protobuf.snapshot.TransactionStateSnapshot.AssetStatic @@ -62,8 +63,8 @@ class StateSnapshotProtoTest extends PropSpec { Map( ByteStr.fromBytes(4, 5, 6) -> LeaseDetails(defaultSigner.publicKey, secondAddress, 123, Status.Active, ByteStr.empty, 0), ByteStr.fromBytes(7, 8, 9) -> LeaseDetails( - secondSigner.publicKey, - defaultAddress, + PublicKey(ByteStr.fill(KeyLength)(0)), + Address(Array.fill(Address.HashLength)(0)), 0, Status.Cancelled(0, None), ByteStr.empty, diff --git a/node/src/test/scala/com/wavesplatform/state/snapshot/StateSnapshotStorageTest.scala b/node/src/test/scala/com/wavesplatform/state/snapshot/StateSnapshotStorageTest.scala index a2b764af1a..e0c7d10d00 100644 --- a/node/src/test/scala/com/wavesplatform/state/snapshot/StateSnapshotStorageTest.scala +++ b/node/src/test/scala/com/wavesplatform/state/snapshot/StateSnapshotStorageTest.scala @@ -5,6 +5,7 @@ import com.wavesplatform.TestValues.fee import com.wavesplatform.account.{Address, Alias, PublicKey} import com.wavesplatform.common.state.ByteStr import com.wavesplatform.common.utils.EitherExt2 +import com.wavesplatform.crypto.KeyLength import com.wavesplatform.db.WithDomain import com.wavesplatform.lang.directives.values.V6 import com.wavesplatform.lang.v1.compiler.TestCompiler @@ -194,9 +195,9 @@ class StateSnapshotStorageTest extends PropSpec with WithDomain { ), leaseStates = Map( leaseTx.id() -> LeaseDetails( - sender.publicKey, - recipient, - leaseTx.amount.value, + PublicKey(ByteStr.fill(KeyLength)(0)), + Address(Array.fill(Address.HashLength)(0)), + 0, Cancelled(0, None), ByteStr.empty, 0 diff --git a/project/Dependencies.scala b/project/Dependencies.scala index 423ee1d527..bffb544f44 100644 --- a/project/Dependencies.scala +++ b/project/Dependencies.scala @@ -6,7 +6,7 @@ import sbt.{Def, _} object Dependencies { // Node protobuf schemas private[this] val protoSchemasLib = - "com.wavesplatform" % "protobuf-schemas" % "1.5.1-84-SNAPSHOT" classifier "protobuf-src" intransitive () + "com.wavesplatform" % "protobuf-schemas" % "1.5.1.2-84-SNAPSHOT" classifier "protobuf-src" intransitive () def akkaModule(module: String): ModuleID = "com.typesafe.akka" %% s"akka-$module" % "2.6.20" From 714756d72794524fcffb6a2361bd1161ec21ede6 Mon Sep 17 00:00:00 2001 From: Artyom Sayadyan Date: Mon, 30 Oct 2023 14:10:34 +0300 Subject: [PATCH 6/9] Adapted hash --- .../state/TxStateSnapshotHashBuilder.scala | 17 +++++++++------ .../snapshot/TxStateSnapshotHashSpec.scala | 21 ++++++++++++------- project/Dependencies.scala | 2 +- 3 files changed, 25 insertions(+), 15 deletions(-) diff --git a/node/src/main/scala/com/wavesplatform/state/TxStateSnapshotHashBuilder.scala b/node/src/main/scala/com/wavesplatform/state/TxStateSnapshotHashBuilder.scala index 7c980d2d90..dd58886706 100644 --- a/node/src/main/scala/com/wavesplatform/state/TxStateSnapshotHashBuilder.scala +++ b/node/src/main/scala/com/wavesplatform/state/TxStateSnapshotHashBuilder.scala @@ -75,12 +75,17 @@ object TxStateSnapshotHashBuilder { } addEntry(KeyType.AssetScript, asset.id.arr)(scriptInfo.script.bytes().arr) snapshot.leaseStates.foreach { case (leaseId, details) => - addEntry(KeyType.LeaseStatus, leaseId.arr)( - booleanToBytes(details.isActive), - details.sender.arr, - details.recipient.bytes, - Longs.toByteArray(details.amount) - ) + if (details.isActive) + addEntry(KeyType.LeaseStatus, leaseId.arr)( + booleanToBytes(true), + details.sender.arr, + details.recipient.bytes, + Longs.toByteArray(details.amount) + ) + else + addEntry(KeyType.LeaseStatus, leaseId.arr)( + booleanToBytes(false) + ) } snapshot.sponsorships.foreach { case (asset, sponsorship) => diff --git a/node/src/test/scala/com/wavesplatform/state/snapshot/TxStateSnapshotHashSpec.scala b/node/src/test/scala/com/wavesplatform/state/snapshot/TxStateSnapshotHashSpec.scala index 7ad7f43ed4..9ed626dccd 100644 --- a/node/src/test/scala/com/wavesplatform/state/snapshot/TxStateSnapshotHashSpec.scala +++ b/node/src/test/scala/com/wavesplatform/state/snapshot/TxStateSnapshotHashSpec.scala @@ -35,8 +35,10 @@ class TxStateSnapshotHashSpec extends PropSpec with WithDomain { private val orderId = ByteStr.fill(DigestLength)(5) private val volumeAndFee = VolumeAndFee(11, 2) - private val leaseId = ByteStr.fill(DigestLength)(6) - private val leaseDetails = LeaseDetails(TxHelpers.signer(1).publicKey, address2, 1.waves, LeaseDetails.Status.Active, leaseId, 2) + private val leaseId1 = ByteStr.fill(DigestLength)(6) + private val leaseId2 = ByteStr.fill(DigestLength)(7) + private val leaseDetails1 = LeaseDetails(TxHelpers.signer(1).publicKey, address2, 1.waves, LeaseDetails.Status.Active, leaseId1, 2) + private val leaseDetails2 = LeaseDetails(TxHelpers.signer(1).publicKey, address2, 1.waves, LeaseDetails.Status.Cancelled(1, None), leaseId2, 2) private val addr1Balance = 10.waves private val addr2Balance = 20.waves @@ -100,7 +102,7 @@ class TxStateSnapshotHashSpec extends PropSpec with WithDomain { ), aliases = Map(addr1Alias1 -> address1, addr2Alias -> address2, addr1Alias2 -> address1), orderFills = Map(orderId -> volumeAndFee), - leaseState = Map(leaseId -> leaseDetails), + leaseState = Map(leaseId1 -> leaseDetails1, leaseId2 -> leaseDetails2), scripts = Map(TxHelpers.signer(2).publicKey -> Some(accountScriptInfo)), assetScripts = Map(assetId1 -> Some(assetScriptInfo)), accountData = Map(address1 -> Map(dataEntry.key -> dataEntry)), @@ -133,11 +135,14 @@ class TxStateSnapshotHashSpec extends PropSpec with WithDomain { addr1PortfolioDiff.lease.out ), Array(KeyType.LeaseStatus.id.toByte) - ++ leaseId.arr - ++ (if (leaseDetails.isActive) Array(1: Byte) else Array(0: Byte)) - ++ leaseDetails.sender.arr - ++ leaseDetails.recipient.bytes - ++ Longs.toByteArray(leaseDetails.amount), + ++ leaseId1.arr + ++ Array(1: Byte) + ++ leaseDetails1.sender.arr + ++ leaseDetails1.recipient.bytes + ++ Longs.toByteArray(leaseDetails1.amount), + Array(KeyType.LeaseStatus.id.toByte) + ++ leaseId2.arr + ++ Array(0: Byte), Array(KeyType.Sponsorship.id.toByte) ++ assetId1.id.arr ++ Longs.toByteArray(sponsorship.minFee), Array(KeyType.Alias.id.toByte) ++ address1.bytes ++ addr1Alias1.name.getBytes(StandardCharsets.UTF_8), Array(KeyType.Alias.id.toByte) ++ address1.bytes ++ addr1Alias2.name.getBytes(StandardCharsets.UTF_8), diff --git a/project/Dependencies.scala b/project/Dependencies.scala index bffb544f44..423ee1d527 100644 --- a/project/Dependencies.scala +++ b/project/Dependencies.scala @@ -6,7 +6,7 @@ import sbt.{Def, _} object Dependencies { // Node protobuf schemas private[this] val protoSchemasLib = - "com.wavesplatform" % "protobuf-schemas" % "1.5.1.2-84-SNAPSHOT" classifier "protobuf-src" intransitive () + "com.wavesplatform" % "protobuf-schemas" % "1.5.1-84-SNAPSHOT" classifier "protobuf-src" intransitive () def akkaModule(module: String): ModuleID = "com.typesafe.akka" %% s"akka-$module" % "2.6.20" From e56a132534e699d1d21d19221f757b3212ecd459 Mon Sep 17 00:00:00 2001 From: Artyom Sayadyan Date: Thu, 16 Nov 2023 00:37:13 +0300 Subject: [PATCH 7/9] Fetch source transaction ID and height for lease --- .../com/wavesplatform/events/events.scala | 42 ++++++++++++------- .../api/http/TransactionJsonSerializer.scala | 8 ++-- .../database/RocksDBWriter.scala | 14 ++++--- .../state/BlockchainUpdaterImpl.scala | 3 +- .../wavesplatform/state/LeaseSnapshot.scala | 30 +++++++++++++ .../wavesplatform/state/StateSnapshot.scala | 24 +++++------ .../state/diffs/DiffsCommon.scala | 6 +-- .../state/patch/CancelAllLeases.scala | 6 +-- .../patch/CancelLeasesToDisabledAliases.scala | 10 ++--- .../state/reader/SnapshotBlockchain.scala | 14 ++++++- .../wavesplatform/history/SnapshotOps.scala | 5 ++- .../http/DebugApiRouteSpec.scala | 37 ++++++++-------- .../snapshot/StateSnapshotProtoTest.scala | 9 ++-- .../snapshot/StateSnapshotStorageTest.scala | 11 ++--- .../blockchain/SupportedBlockchain.scala | 4 +- 15 files changed, 131 insertions(+), 92 deletions(-) create mode 100644 node/src/main/scala/com/wavesplatform/state/LeaseSnapshot.scala diff --git a/grpc-server/src/main/scala/com/wavesplatform/events/events.scala b/grpc-server/src/main/scala/com/wavesplatform/events/events.scala index a83d09fdc2..c08030cb2f 100644 --- a/grpc-server/src/main/scala/com/wavesplatform/events/events.scala +++ b/grpc-server/src/main/scala/com/wavesplatform/events/events.scala @@ -23,7 +23,7 @@ import com.wavesplatform.transaction.assets.exchange.ExchangeTransaction import com.wavesplatform.transaction.lease.LeaseTransaction import com.wavesplatform.transaction.smart.InvokeScriptTransaction import com.wavesplatform.transaction.transfer.{MassTransferTransaction, TransferTransaction} -import com.wavesplatform.transaction.{Asset, Authorized, CreateAliasTransaction, EthereumTransaction} +import com.wavesplatform.transaction.{Asset, Authorized, CreateAliasTransaction, EthereumTransaction, Transaction} import scala.collection.mutable import scala.collection.mutable.ArrayBuffer @@ -389,7 +389,11 @@ object StateUpdate { private lazy val WavesAlias = Alias.fromString("alias:W:waves", Some('W'.toByte)).explicitGet() private lazy val WavesAddress = Address.fromString("3PGd1eQR8EhLkSogpmu9Ne7hSH1rQ5ALihd", Some('W'.toByte)).explicitGet() - def atomic(blockchainBeforeWithMinerReward: Blockchain, snapshot: StateSnapshot): StateUpdate = { + def atomic( + blockchainBeforeWithMinerReward: Blockchain, + snapshot: StateSnapshot, + txWithLeases: Iterable[(Transaction, Map[ByteStr, LeaseSnapshot])] + ): StateUpdate = { val blockchain = blockchainBeforeWithMinerReward val blockchainAfter = SnapshotBlockchain(blockchain, snapshot) @@ -426,18 +430,20 @@ object StateUpdate { assetAfter = blockchainAfter.assetDescription(asset) } yield AssetStateUpdate(asset.id, assetBefore, assetAfter) - val updatedLeases = snapshot.leaseStates.map { case (leaseId, newState) => - LeaseUpdate( - leaseId, - if (newState.isActive) LeaseStatus.Active else LeaseStatus.Inactive, - newState.amount, - newState.sender, - newState.recipient match { - case `WavesAlias` => WavesAddress - case other => blockchainAfter.resolveAlias(other).explicitGet() - }, - newState.sourceId - ) + val updatedLeases = txWithLeases.flatMap { case (sourceTxId, leases) => + leases.map { case (leaseId, newState) => + LeaseUpdate( + leaseId, + if (newState.isActive) LeaseStatus.Active else LeaseStatus.Inactive, + newState.amount, + newState.sender, + newState.recipient match { + case `WavesAlias` => WavesAddress + case other => blockchainAfter.resolveAlias(other).explicitGet() + }, + newState.toDetails(blockchain, Some(sourceTxId), blockchain.leaseDetails(leaseId)).sourceId + ) + } }.toVector val updatedScripts = snapshot.accountScriptsByAddress.map { case (address, newScript) => @@ -546,13 +552,17 @@ object StateUpdate { val accBlockchain = SnapshotBlockchain(blockchainBeforeWithReward, accSnapshot) ( accSnapshot |+| txInfo.snapshot, - updates :+ atomic(accBlockchain, txInfo.snapshot) + updates :+ atomic(accBlockchain, txInfo.snapshot, Seq((txInfo.transaction, txInfo.snapshot.leaseStates))) ) } val blockchainAfter = SnapshotBlockchain(blockchainBeforeWithReward, totalSnapshot) val metadata = transactionsMetadata(blockchainAfter, totalSnapshot) val refAssets = referencedAssets(blockchainAfter, txsStateUpdates) - val keyBlockUpdate = atomic(blockchainBeforeWithReward, keyBlockSnapshot) + val keyBlockUpdate = atomic( + blockchainBeforeWithReward, + keyBlockSnapshot, + keyBlockSnapshot.transactions.map { case (_, txInfo) => (txInfo.transaction, txInfo.snapshot.leaseStates) } + ) (keyBlockUpdate, txsStateUpdates, metadata, refAssets) } } diff --git a/node/src/main/scala/com/wavesplatform/api/http/TransactionJsonSerializer.scala b/node/src/main/scala/com/wavesplatform/api/http/TransactionJsonSerializer.scala index 97e19d5ba5..b67c81bf8b 100644 --- a/node/src/main/scala/com/wavesplatform/api/http/TransactionJsonSerializer.scala +++ b/node/src/main/scala/com/wavesplatform/api/http/TransactionJsonSerializer.scala @@ -16,18 +16,18 @@ import com.wavesplatform.lang.v1.compiler.Terms.{ARR, CONST_BOOLEAN, CONST_BYTES import com.wavesplatform.lang.v1.serialization.SerdeV1 import com.wavesplatform.protobuf.transaction.PBAmounts import com.wavesplatform.state.InvokeScriptResult.{AttachedPayment, Burn, Call, ErrorMessage, Invocation, Issue, Lease, LeaseCancel, Reissue, SponsorFee} -import com.wavesplatform.state.{Blockchain, DataEntry, InvokeScriptResult, TxMeta} import com.wavesplatform.state.reader.LeaseDetails +import com.wavesplatform.state.{Blockchain, DataEntry, InvokeScriptResult, TxMeta} import com.wavesplatform.transaction.Asset.{IssuedAsset, Waves} -import com.wavesplatform.transaction.{Asset, PBSince, Transaction} import com.wavesplatform.transaction.lease.{LeaseCancelTransaction, LeaseTransaction} import com.wavesplatform.transaction.serialization.impl.InvokeScriptTxSerializer import com.wavesplatform.transaction.smart.InvokeScriptTransaction import com.wavesplatform.transaction.smart.InvokeScriptTransaction.Payment import com.wavesplatform.transaction.transfer.MassTransferTransaction +import com.wavesplatform.transaction.{Asset, PBSince, Transaction} import com.wavesplatform.utils.EthEncoding +import play.api.libs.json.* import play.api.libs.json.JsonConfiguration.Aux -import play.api.libs.json.{JsArray, JsBoolean, JsNumber, JsObject, JsString, JsValue, Json, JsonConfiguration, OWrites, OptionHandlers} final case class TransactionJsonSerializer(blockchain: Blockchain, commonApi: CommonTransactionsApi) { @@ -525,6 +525,6 @@ object TransactionJsonSerializer { object LeaseRef { import com.wavesplatform.utils.byteStrFormat implicit val config: Aux[Json.MacroOptions] = JsonConfiguration(optionHandlers = OptionHandlers.WritesNull) - implicit val jsonWrites: OWrites[LeaseRef] = Json.writes[LeaseRef] + implicit val jsonWrites: OWrites[LeaseRef] = Json.writes[LeaseRef] } } diff --git a/node/src/main/scala/com/wavesplatform/database/RocksDBWriter.scala b/node/src/main/scala/com/wavesplatform/database/RocksDBWriter.scala index b16f420538..97c0b1ff60 100644 --- a/node/src/main/scala/com/wavesplatform/database/RocksDBWriter.scala +++ b/node/src/main/scala/com/wavesplatform/database/RocksDBWriter.scala @@ -7,8 +7,8 @@ import com.google.common.hash.{BloomFilter, Funnels} import com.google.common.primitives.Ints import com.wavesplatform.account.{Address, Alias} import com.wavesplatform.api.common.WavesBalanceIterator -import com.wavesplatform.block.BlockSnapshot import com.wavesplatform.block.Block.BlockId +import com.wavesplatform.block.BlockSnapshot import com.wavesplatform.common.state.ByteStr import com.wavesplatform.common.utils.EitherExt2 import com.wavesplatform.database @@ -17,8 +17,7 @@ import com.wavesplatform.database.protobuf.{StaticAssetInfo, TransactionMeta, Bl import com.wavesplatform.features.BlockchainFeatures import com.wavesplatform.lang.ValidationError import com.wavesplatform.protobuf.block.PBBlocks -import com.wavesplatform.protobuf.snapshot.TransactionStateSnapshot -import com.wavesplatform.protobuf.snapshot.TransactionStatus as PBStatus +import com.wavesplatform.protobuf.snapshot.{TransactionStateSnapshot, TransactionStatus as PBStatus} import com.wavesplatform.protobuf.{ByteStrExt, ByteStringExt} import com.wavesplatform.settings.{BlockchainSettings, DBSettings} import com.wavesplatform.state.* @@ -485,9 +484,12 @@ class RocksDBWriter( expiredKeys ++= updateHistory(rw, Keys.assetDetailsHistory(asset), threshold, Keys.assetDetails(asset)) } - for ((id, details) <- snapshot.leaseStates) { - rw.put(Keys.leaseDetails(id)(height), Some(Right(details))) - expiredKeys ++= updateHistory(rw, Keys.leaseDetailsHistory(id), threshold, Keys.leaseDetails(id)) + snapshot.transactions.foreach { case (_, txInfo) => + for ((id, lease) <- txInfo.snapshot.leaseStates) { + val details = lease.toDetails(this, Some(txInfo.transaction), leaseDetails(id)) + rw.put(Keys.leaseDetails(id)(height), Some(Right(details))) + expiredKeys ++= updateHistory(rw, Keys.leaseDetailsHistory(id), threshold, Keys.leaseDetails(id)) + } } for ((addressId, script) <- accountScripts) { diff --git a/node/src/main/scala/com/wavesplatform/state/BlockchainUpdaterImpl.scala b/node/src/main/scala/com/wavesplatform/state/BlockchainUpdaterImpl.scala index 90ccafbdb2..99d193f72b 100644 --- a/node/src/main/scala/com/wavesplatform/state/BlockchainUpdaterImpl.scala +++ b/node/src/main/scala/com/wavesplatform/state/BlockchainUpdaterImpl.scala @@ -437,14 +437,13 @@ class BlockchainUpdaterImpl( val snapshotsById = for { lt <- leaseTransactions - ltMeta <- transactionMeta(lt.id()).toSeq recipient <- rocksdb.resolveAlias(lt.recipient).toSeq portfolios = Map( lt.sender.toAddress -> Portfolio(0, LeaseBalance(0, -lt.amount.value)), recipient -> Portfolio(0, LeaseBalance(-lt.amount.value, 0)) ) leaseStates = Map( - lt.id() -> LeaseDetails(lt.sender, lt.recipient, lt.amount.value, LeaseDetails.Status.Expired(height), lt.id(), ltMeta.height) + lt.id() -> LeaseSnapshot(lt.sender, lt.recipient, lt.amount.value, LeaseDetails.Status.Expired(height)) ) snapshot = StateSnapshot.build(rocksdb, portfolios, leaseStates = leaseStates).explicitGet() } yield lt.id() -> snapshot diff --git a/node/src/main/scala/com/wavesplatform/state/LeaseSnapshot.scala b/node/src/main/scala/com/wavesplatform/state/LeaseSnapshot.scala new file mode 100644 index 0000000000..e49fa4a09d --- /dev/null +++ b/node/src/main/scala/com/wavesplatform/state/LeaseSnapshot.scala @@ -0,0 +1,30 @@ +package com.wavesplatform.state +import com.wavesplatform.account.{AddressOrAlias, PublicKey} +import com.wavesplatform.common.state.ByteStr +import com.wavesplatform.state.reader.LeaseDetails +import com.wavesplatform.transaction.Transaction +import com.wavesplatform.transaction.lease.LeaseCancelTransaction + +import scala.util.Try + +case class LeaseSnapshot(sender: PublicKey, recipient: AddressOrAlias, amount: Long, status: LeaseDetails.Status) { + val isActive: Boolean = status == LeaseDetails.Status.Active + + def toDetails(blockchain: Blockchain, txOpt: Option[Transaction], innerDetails: => Option[LeaseDetails]): LeaseDetails = { + def height(id: ByteStr) = blockchain.transactionMeta(id).map(_.height).getOrElse(blockchain.height) + val (sourceId, sourceHeight) = txOpt match { + case Some(c: LeaseCancelTransaction) => (c.leaseId, height(c.leaseId)) + case Some(i) if isActive => (i.id(), blockchain.height) // produced by lease or invoke (including eth) + case Some(i) if !isActive && innerDetails.isEmpty => (i.id(), blockchain.height) // produced and cancelled by the same invoke + case _ => + def id = innerDetails.get.sourceId // cancelled by invoke and produced by other transaction from the state + Try((id, height(id))).getOrElse((ByteStr.empty, 0)) + } + LeaseDetails(sender, recipient, amount, status, sourceId, sourceHeight) + } +} + +object LeaseSnapshot { + def fromDetails(details: LeaseDetails): LeaseSnapshot = + LeaseSnapshot(details.sender, details.recipient, details.amount, details.status) +} diff --git a/node/src/main/scala/com/wavesplatform/state/StateSnapshot.scala b/node/src/main/scala/com/wavesplatform/state/StateSnapshot.scala index ca8be68cc0..f3782f2707 100644 --- a/node/src/main/scala/com/wavesplatform/state/StateSnapshot.scala +++ b/node/src/main/scala/com/wavesplatform/state/StateSnapshot.scala @@ -31,7 +31,7 @@ case class StateSnapshot( assetNamesAndDescriptions: Map[IssuedAsset, AssetInfo] = Map(), assetScripts: Map[IssuedAsset, AssetScriptInfo] = Map(), sponsorships: Map[IssuedAsset, SponsorshipValue] = Map(), - leaseStates: Map[ByteStr, LeaseDetails] = Map(), + leaseStates: Map[ByteStr, LeaseSnapshot] = Map(), aliases: Map[Alias, Address] = Map(), orderFills: Map[ByteStr, VolumeAndFee] = Map(), accountScripts: Map[PublicKey, Option[AccountScriptInfo]] = Map(), @@ -64,7 +64,7 @@ case class StateSnapshot( orderFills.map { case (orderId, VolumeAndFee(volume, fee)) => S.OrderFill(orderId.toByteString, volume, fee) }.toSeq, - leaseStates.map { case (leaseId, LeaseDetails(sender, recipient, amount, status, _, _)) => + leaseStates.map { case (leaseId, LeaseSnapshot(sender, recipient, amount, status)) => val pbStatus = status match { case Status.Active => S.LeaseState.Status.Active(S.LeaseState.Active(amount, sender.toByteString, recipient.asInstanceOf[Address].toByteString)) @@ -162,26 +162,22 @@ object StateSnapshot { .map(s => s.assetId.toIssuedAssetId -> SponsorshipValue(s.minFee)) .toMap - val leaseStates: Map[ByteStr, LeaseDetails] = + val leaseStates: Map[ByteStr, LeaseSnapshot] = pbSnapshot.leaseStates.map { ls => ls.status match { case TransactionStateSnapshot.LeaseState.Status.Active(value) => - ls.leaseId.toByteStr -> LeaseDetails( + ls.leaseId.toByteStr -> LeaseSnapshot( value.sender.toPublicKey, value.recipient.toAddress(), value.amount, - LeaseDetails.Status.Active, - sourceId = ByteStr.empty, - height = 0 + LeaseDetails.Status.Active ) case _: TransactionStateSnapshot.LeaseState.Status.Cancelled | TransactionStateSnapshot.LeaseState.Status.Empty => - ls.leaseId.toByteStr -> LeaseDetails( + ls.leaseId.toByteStr -> LeaseSnapshot( PublicKey(ByteStr.fill(KeyLength)(0)), Address(Array.fill(Address.HashLength)(0)), 0, - LeaseDetails.Status.Cancelled(0, None), - sourceId = ByteStr.empty, - height = 0 + LeaseDetails.Status.Cancelled(0, None) ) } }.toMap @@ -250,7 +246,7 @@ object StateSnapshot { updatedAssets: Map[IssuedAsset, Ior[AssetInfo, AssetVolumeInfo]] = Map(), assetScripts: Map[IssuedAsset, AssetScriptInfo] = Map(), sponsorships: Map[IssuedAsset, Sponsorship] = Map(), - leaseStates: Map[ByteStr, LeaseDetails] = Map(), + leaseStates: Map[ByteStr, LeaseSnapshot] = Map(), aliases: Map[Alias, Address] = Map(), accountData: Map[Address, Map[String, DataEntry[?]]] = Map(), accountScripts: Map[PublicKey, Option[AccountScriptInfo]] = Map(), @@ -377,9 +373,9 @@ object StateSnapshot { private def resolvedLeaseStates( blockchain: Blockchain, - leaseStates: Map[ByteStr, LeaseDetails], + leaseStates: Map[ByteStr, LeaseSnapshot], aliases: Map[Alias, Address] - ): Map[ByteStr, LeaseDetails] = + ): Map[ByteStr, LeaseSnapshot] = leaseStates.view .mapValues(details => details.copy(recipient = details.recipient match { diff --git a/node/src/main/scala/com/wavesplatform/state/diffs/DiffsCommon.scala b/node/src/main/scala/com/wavesplatform/state/diffs/DiffsCommon.scala index bc5ccd8c90..5c83e03e36 100644 --- a/node/src/main/scala/com/wavesplatform/state/diffs/DiffsCommon.scala +++ b/node/src/main/scala/com/wavesplatform/state/diffs/DiffsCommon.scala @@ -16,7 +16,7 @@ import com.wavesplatform.lang.v1.estimator.v2.ScriptEstimatorV2 import com.wavesplatform.lang.v1.estimator.{ScriptEstimator, ScriptEstimatorV1} import com.wavesplatform.lang.v1.traits.domain.* import com.wavesplatform.state.reader.LeaseDetails -import com.wavesplatform.state.{AssetVolumeInfo, Blockchain, LeaseBalance, Portfolio, SponsorshipValue, StateSnapshot} +import com.wavesplatform.state.{AssetVolumeInfo, Blockchain, LeaseBalance, LeaseSnapshot, Portfolio, SponsorshipValue, StateSnapshot} import com.wavesplatform.transaction.Asset.{IssuedAsset, Waves} import com.wavesplatform.transaction.TxValidationError.GenericError @@ -166,7 +166,7 @@ object DiffsCommon { senderAddress -> Portfolio(-fee, LeaseBalance(0, amount)), recipientAddress -> Portfolio(0, LeaseBalance(amount, 0)) ) - details = LeaseDetails(sender, recipient, amount, LeaseDetails.Status.Active, txId, blockchain.height) + details = LeaseSnapshot(sender, recipient, amount, LeaseDetails.Status.Active) snapshot <- StateSnapshot.build( blockchain, portfolios = portfolioDiff, @@ -207,7 +207,7 @@ object DiffsCommon { snapshot <- StateSnapshot.build( blockchain, portfolios = portfolios, - leaseStates = Map(leaseId -> actionInfo) + leaseStates = Map(leaseId -> LeaseSnapshot.fromDetails(actionInfo)) ) } yield snapshot } diff --git a/node/src/main/scala/com/wavesplatform/state/patch/CancelAllLeases.scala b/node/src/main/scala/com/wavesplatform/state/patch/CancelAllLeases.scala index 7a7462691e..15c83699c3 100644 --- a/node/src/main/scala/com/wavesplatform/state/patch/CancelAllLeases.scala +++ b/node/src/main/scala/com/wavesplatform/state/patch/CancelAllLeases.scala @@ -5,7 +5,7 @@ import com.wavesplatform.account.{Address, PublicKey} import com.wavesplatform.common.state.ByteStr import com.wavesplatform.common.utils.* import com.wavesplatform.state.reader.LeaseDetails -import com.wavesplatform.state.{Blockchain, LeaseBalance, StateSnapshot} +import com.wavesplatform.state.{Blockchain, LeaseBalance, LeaseSnapshot, StateSnapshot} import play.api.libs.json.{Json, OFormat} case object CancelAllLeases extends PatchAtHeight('W' -> 462000, 'T' -> 51500) { @@ -13,11 +13,11 @@ case object CancelAllLeases extends PatchAtHeight('W' -> 462000, 'T' -> 51500) { private[patch] case class CancelledLeases(balances: Map[Address, LeaseBalance], cancelledLeases: Seq[LeaseData]) { private[this] val height: Int = patchHeight.getOrElse(0) - val leaseStates: Map[ByteStr, LeaseDetails] = cancelledLeases.map { data => + val leaseStates: Map[ByteStr, LeaseSnapshot] = cancelledLeases.map { data => val sender = PublicKey(ByteStr.decodeBase58(data.senderPublicKey).get) val recipient = Address.fromString(data.recipient).explicitGet() val id = ByteStr.decodeBase58(data.id).get - (id, LeaseDetails(sender, recipient, data.amount, status = LeaseDetails.Status.Expired(height), id, height)) + (id, LeaseSnapshot(sender, recipient, data.amount, status = LeaseDetails.Status.Expired(height))) }.toMap } diff --git a/node/src/main/scala/com/wavesplatform/state/patch/CancelLeasesToDisabledAliases.scala b/node/src/main/scala/com/wavesplatform/state/patch/CancelLeasesToDisabledAliases.scala index 1dc9349c6e..e1e343e4bf 100644 --- a/node/src/main/scala/com/wavesplatform/state/patch/CancelLeasesToDisabledAliases.scala +++ b/node/src/main/scala/com/wavesplatform/state/patch/CancelLeasesToDisabledAliases.scala @@ -6,7 +6,7 @@ import com.wavesplatform.common.state.ByteStr import com.wavesplatform.common.utils.{Base58, EitherExt2} import com.wavesplatform.features.BlockchainFeatures import com.wavesplatform.state.reader.LeaseDetails -import com.wavesplatform.state.{Blockchain, LeaseBalance, Portfolio, StateSnapshot} +import com.wavesplatform.state.{Blockchain, LeaseBalance, LeaseSnapshot, Portfolio, StateSnapshot} import play.api.libs.json.{Json, Reads} case object CancelLeasesToDisabledAliases extends PatchOnFeature(BlockchainFeatures.SynchronousCalls, Set('W')) { @@ -19,7 +19,7 @@ case object CancelLeasesToDisabledAliases extends PatchOnFeature(BlockchainFeatu height: Int ) - def patchData: Map[ByteStr, (LeaseDetails, Address)] = { + def patchData: Map[ByteStr, (LeaseSnapshot, Address)] = { implicit val cancelDetailsReads: Reads[CancelDetails] = Json.reads readPatchData[Seq[CancelDetails]]().map { cancelDetails => @@ -27,13 +27,11 @@ case object CancelLeasesToDisabledAliases extends PatchOnFeature(BlockchainFeatu val sender = PublicKey(Base58.decode(cancelDetails.senderPublicKey)) val recipientAlias = Alias.fromString(cancelDetails.recipientAlias).explicitGet() val recipientAddress = Address.fromString(cancelDetails.recipientAddress).explicitGet() - leaseId -> (LeaseDetails( + leaseId -> (LeaseSnapshot( sender, recipientAlias, cancelDetails.amount, - LeaseDetails.Status.Expired(0), - leaseId, - cancelDetails.height + LeaseDetails.Status.Expired(0) ) -> recipientAddress) }.toMap } diff --git a/node/src/main/scala/com/wavesplatform/state/reader/SnapshotBlockchain.scala b/node/src/main/scala/com/wavesplatform/state/reader/SnapshotBlockchain.scala index d8347f6c35..abc3ac79d5 100644 --- a/node/src/main/scala/com/wavesplatform/state/reader/SnapshotBlockchain.scala +++ b/node/src/main/scala/com/wavesplatform/state/reader/SnapshotBlockchain.scala @@ -84,8 +84,18 @@ case class SnapshotBlockchain( override def assetDescription(asset: IssuedAsset): Option[AssetDescription] = SnapshotBlockchain.assetDescription(asset, snapshot, height, inner) - override def leaseDetails(leaseId: ByteStr): Option[LeaseDetails] = - snapshot.leaseStates.get(leaseId).orElse(inner.leaseDetails(leaseId)) + override def leaseDetails(leaseId: ByteStr): Option[LeaseDetails] = { + lazy val innerDetails = inner.leaseDetails(leaseId) + val txOpt = + snapshot.transactions + .collectFirst { + case (_, txInfo) if txInfo.snapshot.leaseStates.contains(leaseId) => txInfo.transaction + } + snapshot.leaseStates + .get(leaseId) + .map(_.toDetails(this, txOpt, innerDetails)) + .orElse(innerDetails) + } override def transferById(id: ByteStr): Option[(Int, TransferTransactionLike)] = snapshot.transactions diff --git a/node/src/test/scala/com/wavesplatform/history/SnapshotOps.scala b/node/src/test/scala/com/wavesplatform/history/SnapshotOps.scala index d1d6195c51..185f5ad708 100644 --- a/node/src/test/scala/com/wavesplatform/history/SnapshotOps.scala +++ b/node/src/test/scala/com/wavesplatform/history/SnapshotOps.scala @@ -7,6 +7,7 @@ import com.wavesplatform.common.utils.EitherExt2 import com.wavesplatform.lang.ValidationError import com.wavesplatform.protobuf.ByteStringExt import com.wavesplatform.state.* +import com.wavesplatform.state.reader.LeaseDetails import com.wavesplatform.transaction.Asset.IssuedAsset import scala.collection.immutable.VectorMap @@ -21,7 +22,7 @@ object SnapshotOps { updatedAssets, s.aliases, orderFills(blockchain), - s.leaseStates, + s.leaseStates.map(l => (l._1, LeaseDetails(l._2.sender, l._2.recipient, l._2.amount, l._2.status, ByteStr.empty, 0))), s.accountScripts, s.assetScripts.view.mapValues(Some(_)).toMap, s.accountData, @@ -96,7 +97,7 @@ object SnapshotOps { diff.updatedAssets, diff.assetScripts.collect { case (asset, Some(info)) => (asset, info) }, diff.sponsorship, - diff.leaseState, + diff.leaseState.map(l => (l._1, LeaseSnapshot(l._2.sender, l._2.recipient, l._2.amount, l._2.status))), diff.aliases, diff.accountData, diff.scripts, diff --git a/node/src/test/scala/com/wavesplatform/http/DebugApiRouteSpec.scala b/node/src/test/scala/com/wavesplatform/http/DebugApiRouteSpec.scala index 52350e5698..2908946046 100644 --- a/node/src/test/scala/com/wavesplatform/http/DebugApiRouteSpec.scala +++ b/node/src/test/scala/com/wavesplatform/http/DebugApiRouteSpec.scala @@ -1,9 +1,8 @@ package com.wavesplatform.http -import java.util.concurrent.TimeUnit - import akka.http.scaladsl.model.{ContentTypes, HttpEntity, StatusCodes} import com.typesafe.config.ConfigObject +import com.wavesplatform.* import com.wavesplatform.account.{Alias, KeyPair} import com.wavesplatform.api.common.CommonTransactionsApi import com.wavesplatform.api.http.ApiError.ApiKeyNotValid @@ -42,12 +41,12 @@ import com.wavesplatform.transaction.smart.script.ScriptCompiler import com.wavesplatform.transaction.{ERC20Address, Transaction, TxHelpers, TxVersion} import com.wavesplatform.utils.SharedSchedulerMixin import com.wavesplatform.wallet.Wallet -import com.wavesplatform.* import monix.eval.Task import org.scalamock.scalatest.PathMockFactory import org.scalatest.{Assertion, OptionValues} import play.api.libs.json.{JsArray, JsObject, JsValue, Json} +import java.util.concurrent.TimeUnit import scala.concurrent.duration.* import scala.util.Random @@ -1619,10 +1618,10 @@ class DebugApiRouteSpec } "invoke tx returning leases" in { - val dAppPk = TxHelpers.defaultSigner.publicKey - val dAppAddress = dAppPk.toAddress - val invoke = TxHelpers.invoke(dAppPk.toAddress) - val leaseCancelId = ByteStr(bytes32gen.sample.get) + val dAppPk = TxHelpers.defaultSigner.publicKey + val dAppAddress = dAppPk.toAddress + val invoke = TxHelpers.invoke(dAppPk.toAddress) + val canceledLeaseId = ByteStr(bytes32gen.sample.get) val amount1 = 100 val recipient1 = Recipient.Address(ByteStr.decodeBase58("3NAgxLPGnw3RGv9JT6NTDaG5D1iLUehg2xd").get) @@ -1660,7 +1659,7 @@ class DebugApiRouteSpec | [ | Lease(Address(base58'${recipient1.bytes}'), $amount1, $nonce1), | Lease(Alias("${recipient2.name}"), $amount2, $nonce2), - | LeaseCancel(base58'$leaseCancelId') + | LeaseCancel(base58'$canceledLeaseId') | ] | else [] |} @@ -1685,13 +1684,13 @@ class DebugApiRouteSpec (blockchain.hasAccountScript _).when(*).returns(true) (blockchain.transactionMeta _) - .when(leaseCancelId) + .when(canceledLeaseId) .returns(Some(TxMeta(Height(1), Status.Succeeded, 0L))) .anyNumberOfTimes() (blockchain.leaseDetails _) - .when(leaseCancelId) - .returns(Some(LeaseDetails(dAppPk, TxHelpers.defaultAddress, leaseCancelAmount, LeaseDetails.Status.Active, leaseCancelId, 1))) + .when(canceledLeaseId) + .returns(Some(LeaseDetails(dAppPk, TxHelpers.defaultAddress, leaseCancelAmount, LeaseDetails.Status.Active, invoke.id(), 1))) .anyNumberOfTimes() (blockchain.leaseDetails _) @@ -1743,8 +1742,8 @@ class DebugApiRouteSpec | "cancelTransactionId" : null | } ], | "leaseCancels" : [ { - | "id" : "$leaseCancelId", - | "originTransactionId" : "$leaseCancelId", + | "id" : "$canceledLeaseId", + | "originTransactionId" : "${invoke.id()}", | "sender" : "$dAppAddress", | "recipient" : "${TxHelpers.defaultAddress}", | "amount" : $leaseCancelAmount, @@ -1797,8 +1796,8 @@ class DebugApiRouteSpec | "cancelTransactionId" : null | } ], | "leaseCancels" : [ { - | "id" : "$leaseCancelId", - | "originTransactionId" : "$leaseCancelId", + | "id" : "$canceledLeaseId", + | "originTransactionId" : "${invoke.id()}", | "sender" : "3MtGzgmNa5fMjGCcPi5nqMTdtZkfojyWHL9", | "recipient" : "3MtGzgmNa5fMjGCcPi5nqMTdtZkfojyWHL9", | "amount" : $leaseCancelAmount, @@ -2007,7 +2006,7 @@ class DebugApiRouteSpec | "type" : "Array", | "value" : [ { | "type" : "ByteVector", - | "value" : "$leaseCancelId" + | "value" : "$canceledLeaseId" | } ] | }, { | "name" : "LeaseCancel.@complexity", @@ -2025,7 +2024,7 @@ class DebugApiRouteSpec | "value" : { | "leaseId" : { | "type" : "ByteVector", - | "value" : "$leaseCancelId" + | "value" : "$canceledLeaseId" | } | } | }, { @@ -2071,7 +2070,7 @@ class DebugApiRouteSpec | "value" : { | "leaseId" : { | "type" : "ByteVector", - | "value" : "$leaseCancelId" + | "value" : "$canceledLeaseId" | } | } | } ] @@ -2136,7 +2135,7 @@ class DebugApiRouteSpec | "value" : { | "leaseId" : { | "type" : "ByteVector", - | "value" : "$leaseCancelId" + | "value" : "$canceledLeaseId" | } | } | } ] diff --git a/node/src/test/scala/com/wavesplatform/state/snapshot/StateSnapshotProtoTest.scala b/node/src/test/scala/com/wavesplatform/state/snapshot/StateSnapshotProtoTest.scala index a160e159f8..78c5df5722 100644 --- a/node/src/test/scala/com/wavesplatform/state/snapshot/StateSnapshotProtoTest.scala +++ b/node/src/test/scala/com/wavesplatform/state/snapshot/StateSnapshotProtoTest.scala @@ -9,7 +9,6 @@ import com.wavesplatform.lang.directives.values.V6 import com.wavesplatform.lang.v1.compiler.TestCompiler import com.wavesplatform.protobuf.snapshot.TransactionStateSnapshot.AssetStatic import com.wavesplatform.state.* -import com.wavesplatform.state.reader.LeaseDetails import com.wavesplatform.state.reader.LeaseDetails.Status import com.wavesplatform.test.PropSpec import com.wavesplatform.transaction.Asset.{IssuedAsset, Waves} @@ -61,14 +60,12 @@ class StateSnapshotProtoTest extends PropSpec { IssuedAsset(ByteStr.fromBytes(2, 2, 2)) -> SponsorshipValue(0) ), Map( - ByteStr.fromBytes(4, 5, 6) -> LeaseDetails(defaultSigner.publicKey, secondAddress, 123, Status.Active, ByteStr.empty, 0), - ByteStr.fromBytes(7, 8, 9) -> LeaseDetails( + ByteStr.fromBytes(4, 5, 6) -> LeaseSnapshot(defaultSigner.publicKey, secondAddress, 123, Status.Active), + ByteStr.fromBytes(7, 8, 9) -> LeaseSnapshot( PublicKey(ByteStr.fill(KeyLength)(0)), Address(Array.fill(Address.HashLength)(0)), 0, - Status.Cancelled(0, None), - ByteStr.empty, - 0 + Status.Cancelled(0, None) ) ), Map( diff --git a/node/src/test/scala/com/wavesplatform/state/snapshot/StateSnapshotStorageTest.scala b/node/src/test/scala/com/wavesplatform/state/snapshot/StateSnapshotStorageTest.scala index e0c7d10d00..abe2f5495f 100644 --- a/node/src/test/scala/com/wavesplatform/state/snapshot/StateSnapshotStorageTest.scala +++ b/node/src/test/scala/com/wavesplatform/state/snapshot/StateSnapshotStorageTest.scala @@ -16,7 +16,6 @@ import com.wavesplatform.state.* import com.wavesplatform.state.TxMeta.Status.{Failed, Succeeded} import com.wavesplatform.state.diffs.BlockDiffer.CurrentBlockFeePart import com.wavesplatform.state.diffs.ENOUGH_AMT -import com.wavesplatform.state.reader.LeaseDetails import com.wavesplatform.state.reader.LeaseDetails.Status.{Active, Cancelled} import com.wavesplatform.test.DomainPresets.* import com.wavesplatform.test.{NumericExt, PropSpec} @@ -176,7 +175,7 @@ class StateSnapshotStorageTest extends PropSpec with WithDomain { recipient -> LeaseBalance(leaseTx.amount.value, 0) ), leaseStates = Map( - leaseTx.id() -> LeaseDetails(sender.publicKey, recipient, leaseTx.amount.value, Active, ByteStr.empty, 0) + leaseTx.id() -> LeaseSnapshot(sender.publicKey, recipient, leaseTx.amount.value, Active) ) ) ) @@ -194,13 +193,11 @@ class StateSnapshotStorageTest extends PropSpec with WithDomain { recipient -> LeaseBalance(0, 0) ), leaseStates = Map( - leaseTx.id() -> LeaseDetails( + leaseTx.id() -> LeaseSnapshot( PublicKey(ByteStr.fill(KeyLength)(0)), Address(Array.fill(Address.HashLength)(0)), 0, - Cancelled(0, None), - ByteStr.empty, - 0 + Cancelled(0, None) ) ) ) @@ -334,7 +331,7 @@ class StateSnapshotStorageTest extends PropSpec with WithDomain { dAppAssetId -> AssetInfo("name", "description", Height(height)) ), leaseStates = Map( - leaseId -> LeaseDetails(dAppPk, senderAddress, 123, Active, ByteStr.empty, 0) + leaseId -> LeaseSnapshot(dAppPk, senderAddress, 123, Active) ), accountData = Map( dAppPk.toAddress -> Map("key" -> StringDataEntry("key", "abc")) diff --git a/ride-runner/src/main/scala/com/wavesplatform/ride/runner/blockchain/SupportedBlockchain.scala b/ride-runner/src/main/scala/com/wavesplatform/ride/runner/blockchain/SupportedBlockchain.scala index c9a15ca1a8..4ff162f111 100644 --- a/ride-runner/src/main/scala/com/wavesplatform/ride/runner/blockchain/SupportedBlockchain.scala +++ b/ride-runner/src/main/scala/com/wavesplatform/ride/runner/blockchain/SupportedBlockchain.scala @@ -4,7 +4,7 @@ import com.wavesplatform.account.Address import com.wavesplatform.block.Block.BlockId import com.wavesplatform.common.state.ByteStr import com.wavesplatform.state.reader.LeaseDetails -import com.wavesplatform.state.{AssetScriptInfo, Blockchain, TxMeta, VolumeAndFee} +import com.wavesplatform.state.{AssetScriptInfo, Blockchain, LeaseSnapshot, TxMeta, VolumeAndFee} import com.wavesplatform.transaction.transfer.TransferTransactionLike import com.wavesplatform.transaction.{Asset, ERC20Address, Transaction} import com.wavesplatform.utils.ScorexLogging @@ -78,7 +78,7 @@ trait SupportedBlockchain extends Blockchain with ScorexLogging { override def containsTransaction(tx: Transaction): Boolean = kill("containsTransaction") - override def leaseDetails(leaseId: ByteStr): Option[LeaseDetails] = kill("leaseDetails") + override def leaseDetails(leaseId: ByteStr): Option[LeaseSnapshot] = kill("leaseDetails") override def filledVolumeAndFee(orderId: ByteStr): VolumeAndFee = kill("filledVolumeAndFee") From 913ffa03c9114d26fef971694c813a9ad0bcf35b Mon Sep 17 00:00:00 2001 From: Artyom Sayadyan Date: Thu, 16 Nov 2023 00:55:34 +0300 Subject: [PATCH 8/9] Corrected compilation --- .../ride/runner/blockchain/SupportedBlockchain.scala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ride-runner/src/main/scala/com/wavesplatform/ride/runner/blockchain/SupportedBlockchain.scala b/ride-runner/src/main/scala/com/wavesplatform/ride/runner/blockchain/SupportedBlockchain.scala index 4ff162f111..c9a15ca1a8 100644 --- a/ride-runner/src/main/scala/com/wavesplatform/ride/runner/blockchain/SupportedBlockchain.scala +++ b/ride-runner/src/main/scala/com/wavesplatform/ride/runner/blockchain/SupportedBlockchain.scala @@ -4,7 +4,7 @@ import com.wavesplatform.account.Address import com.wavesplatform.block.Block.BlockId import com.wavesplatform.common.state.ByteStr import com.wavesplatform.state.reader.LeaseDetails -import com.wavesplatform.state.{AssetScriptInfo, Blockchain, LeaseSnapshot, TxMeta, VolumeAndFee} +import com.wavesplatform.state.{AssetScriptInfo, Blockchain, TxMeta, VolumeAndFee} import com.wavesplatform.transaction.transfer.TransferTransactionLike import com.wavesplatform.transaction.{Asset, ERC20Address, Transaction} import com.wavesplatform.utils.ScorexLogging @@ -78,7 +78,7 @@ trait SupportedBlockchain extends Blockchain with ScorexLogging { override def containsTransaction(tx: Transaction): Boolean = kill("containsTransaction") - override def leaseDetails(leaseId: ByteStr): Option[LeaseSnapshot] = kill("leaseDetails") + override def leaseDetails(leaseId: ByteStr): Option[LeaseDetails] = kill("leaseDetails") override def filledVolumeAndFee(orderId: ByteStr): VolumeAndFee = kill("filledVolumeAndFee") From f8ab55c587a856c293c0c040a79ac3e8466f88f9 Mon Sep 17 00:00:00 2001 From: Artyom Sayadyan Date: Thu, 16 Nov 2023 01:49:14 +0300 Subject: [PATCH 9/9] Adapted for LeaseExpiration --- .../wavesplatform/database/RocksDBWriter.scala | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/node/src/main/scala/com/wavesplatform/database/RocksDBWriter.scala b/node/src/main/scala/com/wavesplatform/database/RocksDBWriter.scala index 97c0b1ff60..4b11f41289 100644 --- a/node/src/main/scala/com/wavesplatform/database/RocksDBWriter.scala +++ b/node/src/main/scala/com/wavesplatform/database/RocksDBWriter.scala @@ -484,12 +484,16 @@ class RocksDBWriter( expiredKeys ++= updateHistory(rw, Keys.assetDetailsHistory(asset), threshold, Keys.assetDetails(asset)) } - snapshot.transactions.foreach { case (_, txInfo) => - for ((id, lease) <- txInfo.snapshot.leaseStates) { - val details = lease.toDetails(this, Some(txInfo.transaction), leaseDetails(id)) - rw.put(Keys.leaseDetails(id)(height), Some(Right(details))) - expiredKeys ++= updateHistory(rw, Keys.leaseDetailsHistory(id), threshold, Keys.leaseDetails(id)) - } + val txLeases = for { + (_, txInfo) <- snapshot.transactions + (id, lease) <- txInfo.snapshot.leaseStates + } yield (Some(txInfo.transaction), id, lease) + val txLeaseIdSet = txLeases.map(_._2).toSet + val allLeases = txLeases ++ snapshot.leaseStates.collect { case (id, lease) if !txLeaseIdSet.contains(id) => (None, id, lease) } + allLeases.foreach { case (txOpt, id, lease) => + val details = lease.toDetails(this, txOpt, leaseDetails(id)) + rw.put(Keys.leaseDetails(id)(height), Some(Right(details))) + expiredKeys ++= updateHistory(rw, Keys.leaseDetailsHistory(id), threshold, Keys.leaseDetails(id)) } for ((addressId, script) <- accountScripts) {