Skip to content

Commit

Permalink
Merge branch 'version-1.5.x' into node-micro-block-inv-absence
Browse files Browse the repository at this point in the history
  • Loading branch information
xrtm000 authored Nov 17, 2023
2 parents 28971ae + 899fd66 commit 309ee34
Show file tree
Hide file tree
Showing 27 changed files with 331 additions and 142 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,15 @@ class AccountsApiGrpcImpl(commonApi: CommonAccountsApi)(implicit sc: Scheduler)

override def getScript(request: AccountRequest): Future[ScriptResponse] = Future {
commonApi.script(request.address.toAddress()) match {
case Some(desc) => ScriptResponse(PBTransactions.toPBScript(Some(desc.script)), desc.script.expr.toString, desc.verifierComplexity, desc.publicKey.toByteString)
case None => ScriptResponse()
case Some(desc) =>
ScriptResponse(
PBTransactions.toPBScript(Some(desc.script)),
desc.script.expr.toString,
desc.verifierComplexity,
desc.publicKey.toByteString
)
case None =>
ScriptResponse()
}
}

Expand Down
42 changes: 26 additions & 16 deletions grpc-server/src/main/scala/com/wavesplatform/events/events.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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)

Expand Down Expand Up @@ -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) =>
Expand Down Expand Up @@ -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)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import com.wavesplatform.lang.v1.FunctionHeader
import com.wavesplatform.lang.v1.compiler.Terms
import com.wavesplatform.lang.v1.compiler.Terms.FUNCTION_CALL
import com.wavesplatform.state.DataEntry.Format
import com.wavesplatform.state.{AssetDistributionPage, DataEntry, EmptyDataEntry, LeaseBalance, Portfolio}
import com.wavesplatform.state.{AssetDistribution, AssetDistributionPage, DataEntry, EmptyDataEntry, LeaseBalance, Portfolio}
import com.wavesplatform.transaction.Asset.{IssuedAsset, Waves}
import com.wavesplatform.transaction.assets.*
import com.wavesplatform.transaction.assets.exchange.{Order, ExchangeTransaction as ExchangeTx}
Expand Down Expand Up @@ -338,6 +338,11 @@ object AsyncHttpApi extends Assertions {
get(url, amountsAsStrings).as[AssetDistributionPage](amountsAsStrings)
}

def assetDistribution(asset: String, amountsAsStrings: Boolean = false): Future[AssetDistribution] = {
val req = s"/assets/$asset/distribution"
get(req, amountsAsStrings).as[AssetDistribution](amountsAsStrings)
}

def effectiveBalance(address: String, confirmations: Option[Int] = None, amountsAsStrings: Boolean = false): Future[Balance] = {
val maybeConfirmations = confirmations.fold("")(a => s"/$a")
get(s"/addresses/effectiveBalance/$address$maybeConfirmations", amountsAsStrings).as[Balance](amountsAsStrings)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import com.wavesplatform.it.Node
import com.wavesplatform.it.sync.*
import com.wavesplatform.lang.script.v1.ExprScript
import com.wavesplatform.lang.v1.compiler.Terms
import com.wavesplatform.state.{AssetDistributionPage, DataEntry}
import com.wavesplatform.state.{AssetDistribution, AssetDistributionPage, DataEntry}
import com.wavesplatform.transaction.assets.exchange.Order
import com.wavesplatform.transaction.lease.{LeaseCancelTransaction, LeaseTransaction}
import com.wavesplatform.transaction.smart.InvokeScriptTransaction
Expand Down Expand Up @@ -261,6 +261,9 @@ object SyncHttpApi extends Assertions with matchers.should.Matchers {
): AssetDistributionPage =
sync(async(n).assetDistributionAtHeight(asset, height, limit, maybeAfter, amountsAsStrings))

def assetDistribution(asset: String): AssetDistribution =
sync(async(n).assetDistribution(asset))

def broadcastIssue(
source: KeyPair,
name: String,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -250,15 +250,15 @@ class IssueReissueBurnAssetSuite extends BaseFreeSpec {
val acc = createDapp(script(simpleReissuableAsset))
val asset = issueValidated(acc, simpleReissuableAsset)
invokeScript(acc, "transferAndBurn", assetId = asset, count = 100)
val height1 = nodes.waitForHeightArise()
sender.assetDistributionAtHeight(asset, height1 - 1, 10).items.map { case (a, v) => a.toString -> v } shouldBe Map(
nodes.waitForHeightArise()
sender.assetDistribution(asset).map { case (a, v) => a.toString -> v } shouldBe Map(
miner.address -> 100L,
acc.toAddress.toString -> (simpleReissuableAsset.quantity - 200)
)
reissue(acc, CallableMethod, asset, 400, reissuable = false)
invokeScript(acc, "transferAndBurn", assetId = asset, count = 100)
val height2 = nodes.waitForHeightArise()
sender.assetDistributionAtHeight(asset, height2 - 1, 10).items.map { case (a, v) => a.toString -> v } shouldBe Map(
nodes.waitForHeightArise()
sender.assetDistribution(asset).map { case (a, v) => a.toString -> v } shouldBe Map(
miner.address -> 200L,
acc.toAddress.toString -> simpleReissuableAsset.quantity
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import com.wavesplatform.state.AssetDistributionPage
import com.wavesplatform.transaction.transfer.MassTransferTransaction
import org.scalatest.CancelAfterFailure

import scala.concurrent.duration.*

class AssetDistributionSuite extends BaseTransactionSuite with CancelAfterFailure {

lazy val node: Node = nodes.head
Expand All @@ -23,7 +25,7 @@ class AssetDistributionSuite extends BaseTransactionSuite with CancelAfterFailur

nodes.waitForHeightArise()

val issueTx = node.issue(issuer, "TestCoin", "no description", issueAmount, 8, false, issueFee, waitForTx = true).id
val issueTx = node.issue(issuer, "TestCoin", "no description", issueAmount, 8, reissuable = false, issueFee, waitForTx = true).id

node.massTransfer(
issuer,
Expand All @@ -47,6 +49,8 @@ class AssetDistributionSuite extends BaseTransactionSuite with CancelAfterFailur

val issuerAssetDis = assetDis.view.filterKeys(_ == issuer.toAddress).values

assetDis should be equals node.assetDistribution(issueTx)

issuerAssetDis.size shouldBe 1
issuerAssetDis.head shouldBe (issueAmount - addresses.length * transferAmount)

Expand All @@ -68,10 +72,34 @@ class AssetDistributionSuite extends BaseTransactionSuite with CancelAfterFailur
)
}

test("'Asset distribution' works properly") {
val receivers = for (i <- 0 until 10) yield KeyPair(s"receiver#$i".getBytes("UTF-8"))

val issueTx = node.issue(issuer, "TestCoin#2", "no description", issueAmount, 8, reissuable = false, issueFee, waitForTx = true).id

node
.massTransfer(
issuer,
receivers.map(rc => MassTransferTransaction.Transfer(rc.toAddress.toString, 10)).toList,
minFee + minFee * receivers.length,
assetId = Some(issueTx),
waitForTx = true
)

nodes.waitForHeightArise()

val distribution = node.assetDistribution(issueTx)

distribution.size shouldBe (receivers.size + 1)
distribution(issuer.toAddress) shouldBe (issueAmount - 10 * receivers.length)

assert(receivers.forall(rc => distribution(rc.toAddress) == 10), "Distribution correct")
}

test("Correct last page and entry count") {
val receivers = for (i <- 0 until 50) yield KeyPair(s"receiver#$i".getBytes("UTF-8"))

val issueTx = node.issue(issuer, "TestCoin#2", "no description", issueAmount, 8, false, issueFee, waitForTx = true).id
val issueTx = node.issue(issuer, "TestCoin#2", "no description", issueAmount, 8, reissuable = false, issueFee, waitForTx = true).id

node
.massTransfer(
Expand All @@ -96,6 +124,24 @@ class AssetDistributionSuite extends BaseTransactionSuite with CancelAfterFailur
assert(pages.map(_.items.size).sum == 51)
}

test("Unlimited list") {
val assetId = node.issue(issuer, "TestCoin#2", "no description", issueAmount, 8, reissuable = false, issueFee, waitForTx = true).id

val receivers = for (i <- 0 until 2000) yield KeyPair(s"receiver#$i".getBytes("UTF-8"))

val transfers = receivers.map { r => MassTransferTransaction.Transfer(r.toAddress.toString, 10L) }.toList

transfers.grouped(100).foreach { t =>
node.massTransfer(issuer, t, minFee + t.length * minFee, assetId = Some(assetId))
}

node.waitFor("empty utx")(_.utxSize, (_: Int) == 0, 1 second)
nodes.waitForHeightArise()

val list = node.assetDistribution(assetId)
list should have size 2001
}

def distributionPages(asset: String, height: Int, limit: Int): List[AssetDistributionPage] = {
def _load(acc: List[AssetDistributionPage], maybeAfter: Option[String]): List[AssetDistributionPage] = {
val page = node.assetDistributionAtHeight(asset, height, limit, maybeAfter)
Expand Down
32 changes: 32 additions & 0 deletions node/src/main/resources/swagger-ui/openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2440,6 +2440,38 @@ paths:
type: string
balance:
type: string
'/assets/{assetId}/distribution':
get:
tags:
- assets
summary: Asset balance distribution
description: Get asset balance distribution by addresses
operationId: getAssetDistributionOld
parameters:
- $ref: '#/components/parameters/assetId'
responses:
'200':
description: successful operation
content:
application/json:
schema:
type: object
additionalProperties:
type: integer
format: int64
description: map of assetId <-> balance
example:
2eEUvypDSivnzPiLrbYEW39SM8yMZ1aq4eJuiKfs4sEY: 15
3PPqZ623dAfbmxmnpTjwV6yD5GA5s3PJiUG: 25
application/json;large-significand-format=string:
schema:
type: object
additionalProperties:
type: string
description: map of assetId <-> balance
example:
2eEUvypDSivnzPiLrbYEW39SM8yMZ1aq4eJuiKfs4sEY: "15"
3PPqZ623dAfbmxmnpTjwV6yD5GA5s3PJiUG: "25"
'/assets/{assetId}/distribution/{height}/limit/{limit}':
get:
tags:
Expand Down
6 changes: 3 additions & 3 deletions node/src/main/scala/com/wavesplatform/Application.scala
Original file line number Diff line number Diff line change
Expand Up @@ -374,9 +374,8 @@ class Application(val actorSystem: ActorSystem, val settings: WavesSettings, con
else heavyRequestExecutor
)

val routeTimeout = new RouteTimeout(
FiniteDuration(settings.config.getDuration("akka.http.server.request-timeout").getSeconds, TimeUnit.SECONDS)
)(heavyRequestScheduler)
val serverRequestTimeout = FiniteDuration(settings.config.getDuration("akka.http.server.request-timeout").getSeconds, TimeUnit.SECONDS)
val routeTimeout = new RouteTimeout(serverRequestTimeout)(heavyRequestScheduler)

val apiRoutes = Seq(
new EthRpcRoute(blockchainUpdater, extensionContext.transactionsApi, time),
Expand Down Expand Up @@ -440,6 +439,7 @@ class Application(val actorSystem: ActorSystem, val settings: WavesSettings, con
),
AssetsApiRoute(
settings.restAPISettings,
serverRequestTimeout,
wallet,
transactionPublisher,
blockchainUpdater,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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) {

Expand Down Expand Up @@ -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]
}
}
Loading

0 comments on commit 309ee34

Please sign in to comment.