Skip to content

Commit 309ee34

Browse files
authored
Merge branch 'version-1.5.x' into node-micro-block-inv-absence
2 parents 28971ae + 899fd66 commit 309ee34

27 files changed

+331
-142
lines changed

grpc-server/src/main/scala/com/wavesplatform/api/grpc/AccountsApiGrpcImpl.scala

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,8 +63,15 @@ class AccountsApiGrpcImpl(commonApi: CommonAccountsApi)(implicit sc: Scheduler)
6363

6464
override def getScript(request: AccountRequest): Future[ScriptResponse] = Future {
6565
commonApi.script(request.address.toAddress()) match {
66-
case Some(desc) => ScriptResponse(PBTransactions.toPBScript(Some(desc.script)), desc.script.expr.toString, desc.verifierComplexity, desc.publicKey.toByteString)
67-
case None => ScriptResponse()
66+
case Some(desc) =>
67+
ScriptResponse(
68+
PBTransactions.toPBScript(Some(desc.script)),
69+
desc.script.expr.toString,
70+
desc.verifierComplexity,
71+
desc.publicKey.toByteString
72+
)
73+
case None =>
74+
ScriptResponse()
6875
}
6976
}
7077

grpc-server/src/main/scala/com/wavesplatform/events/events.scala

Lines changed: 26 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ import com.wavesplatform.transaction.assets.exchange.ExchangeTransaction
2323
import com.wavesplatform.transaction.lease.LeaseTransaction
2424
import com.wavesplatform.transaction.smart.InvokeScriptTransaction
2525
import com.wavesplatform.transaction.transfer.{MassTransferTransaction, TransferTransaction}
26-
import com.wavesplatform.transaction.{Asset, Authorized, CreateAliasTransaction, EthereumTransaction}
26+
import com.wavesplatform.transaction.{Asset, Authorized, CreateAliasTransaction, EthereumTransaction, Transaction}
2727

2828
import scala.collection.mutable
2929
import scala.collection.mutable.ArrayBuffer
@@ -389,7 +389,11 @@ object StateUpdate {
389389
private lazy val WavesAlias = Alias.fromString("alias:W:waves", Some('W'.toByte)).explicitGet()
390390
private lazy val WavesAddress = Address.fromString("3PGd1eQR8EhLkSogpmu9Ne7hSH1rQ5ALihd", Some('W'.toByte)).explicitGet()
391391

392-
def atomic(blockchainBeforeWithMinerReward: Blockchain, snapshot: StateSnapshot): StateUpdate = {
392+
def atomic(
393+
blockchainBeforeWithMinerReward: Blockchain,
394+
snapshot: StateSnapshot,
395+
txWithLeases: Iterable[(Transaction, Map[ByteStr, LeaseSnapshot])]
396+
): StateUpdate = {
393397
val blockchain = blockchainBeforeWithMinerReward
394398
val blockchainAfter = SnapshotBlockchain(blockchain, snapshot)
395399

@@ -426,18 +430,20 @@ object StateUpdate {
426430
assetAfter = blockchainAfter.assetDescription(asset)
427431
} yield AssetStateUpdate(asset.id, assetBefore, assetAfter)
428432

429-
val updatedLeases = snapshot.leaseStates.map { case (leaseId, newState) =>
430-
LeaseUpdate(
431-
leaseId,
432-
if (newState.isActive) LeaseStatus.Active else LeaseStatus.Inactive,
433-
newState.amount,
434-
newState.sender,
435-
newState.recipient match {
436-
case `WavesAlias` => WavesAddress
437-
case other => blockchainAfter.resolveAlias(other).explicitGet()
438-
},
439-
newState.sourceId
440-
)
433+
val updatedLeases = txWithLeases.flatMap { case (sourceTxId, leases) =>
434+
leases.map { case (leaseId, newState) =>
435+
LeaseUpdate(
436+
leaseId,
437+
if (newState.isActive) LeaseStatus.Active else LeaseStatus.Inactive,
438+
newState.amount,
439+
newState.sender,
440+
newState.recipient match {
441+
case `WavesAlias` => WavesAddress
442+
case other => blockchainAfter.resolveAlias(other).explicitGet()
443+
},
444+
newState.toDetails(blockchain, Some(sourceTxId), blockchain.leaseDetails(leaseId)).sourceId
445+
)
446+
}
441447
}.toVector
442448

443449
val updatedScripts = snapshot.accountScriptsByAddress.map { case (address, newScript) =>
@@ -546,13 +552,17 @@ object StateUpdate {
546552
val accBlockchain = SnapshotBlockchain(blockchainBeforeWithReward, accSnapshot)
547553
(
548554
accSnapshot |+| txInfo.snapshot,
549-
updates :+ atomic(accBlockchain, txInfo.snapshot)
555+
updates :+ atomic(accBlockchain, txInfo.snapshot, Seq((txInfo.transaction, txInfo.snapshot.leaseStates)))
550556
)
551557
}
552558
val blockchainAfter = SnapshotBlockchain(blockchainBeforeWithReward, totalSnapshot)
553559
val metadata = transactionsMetadata(blockchainAfter, totalSnapshot)
554560
val refAssets = referencedAssets(blockchainAfter, txsStateUpdates)
555-
val keyBlockUpdate = atomic(blockchainBeforeWithReward, keyBlockSnapshot)
561+
val keyBlockUpdate = atomic(
562+
blockchainBeforeWithReward,
563+
keyBlockSnapshot,
564+
keyBlockSnapshot.transactions.map { case (_, txInfo) => (txInfo.transaction, txInfo.snapshot.leaseStates) }
565+
)
556566
(keyBlockUpdate, txsStateUpdates, metadata, refAssets)
557567
}
558568
}

node-it/src/test/scala/com/wavesplatform/it/api/AsyncHttpApi.scala

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ import com.wavesplatform.lang.v1.FunctionHeader
2323
import com.wavesplatform.lang.v1.compiler.Terms
2424
import com.wavesplatform.lang.v1.compiler.Terms.FUNCTION_CALL
2525
import com.wavesplatform.state.DataEntry.Format
26-
import com.wavesplatform.state.{AssetDistributionPage, DataEntry, EmptyDataEntry, LeaseBalance, Portfolio}
26+
import com.wavesplatform.state.{AssetDistribution, AssetDistributionPage, DataEntry, EmptyDataEntry, LeaseBalance, Portfolio}
2727
import com.wavesplatform.transaction.Asset.{IssuedAsset, Waves}
2828
import com.wavesplatform.transaction.assets.*
2929
import com.wavesplatform.transaction.assets.exchange.{Order, ExchangeTransaction as ExchangeTx}
@@ -338,6 +338,11 @@ object AsyncHttpApi extends Assertions {
338338
get(url, amountsAsStrings).as[AssetDistributionPage](amountsAsStrings)
339339
}
340340

341+
def assetDistribution(asset: String, amountsAsStrings: Boolean = false): Future[AssetDistribution] = {
342+
val req = s"/assets/$asset/distribution"
343+
get(req, amountsAsStrings).as[AssetDistribution](amountsAsStrings)
344+
}
345+
341346
def effectiveBalance(address: String, confirmations: Option[Int] = None, amountsAsStrings: Boolean = false): Future[Balance] = {
342347
val maybeConfirmations = confirmations.fold("")(a => s"/$a")
343348
get(s"/addresses/effectiveBalance/$address$maybeConfirmations", amountsAsStrings).as[Balance](amountsAsStrings)

node-it/src/test/scala/com/wavesplatform/it/api/SyncHttpApi.scala

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import com.wavesplatform.it.Node
1414
import com.wavesplatform.it.sync.*
1515
import com.wavesplatform.lang.script.v1.ExprScript
1616
import com.wavesplatform.lang.v1.compiler.Terms
17-
import com.wavesplatform.state.{AssetDistributionPage, DataEntry}
17+
import com.wavesplatform.state.{AssetDistribution, AssetDistributionPage, DataEntry}
1818
import com.wavesplatform.transaction.assets.exchange.Order
1919
import com.wavesplatform.transaction.lease.{LeaseCancelTransaction, LeaseTransaction}
2020
import com.wavesplatform.transaction.smart.InvokeScriptTransaction
@@ -261,6 +261,9 @@ object SyncHttpApi extends Assertions with matchers.should.Matchers {
261261
): AssetDistributionPage =
262262
sync(async(n).assetDistributionAtHeight(asset, height, limit, maybeAfter, amountsAsStrings))
263263

264+
def assetDistribution(asset: String): AssetDistribution =
265+
sync(async(n).assetDistribution(asset))
266+
264267
def broadcastIssue(
265268
source: KeyPair,
266269
name: String,

node-it/src/test/scala/com/wavesplatform/it/asset/IssueReissueBurnAssetSuite.scala

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -250,15 +250,15 @@ class IssueReissueBurnAssetSuite extends BaseFreeSpec {
250250
val acc = createDapp(script(simpleReissuableAsset))
251251
val asset = issueValidated(acc, simpleReissuableAsset)
252252
invokeScript(acc, "transferAndBurn", assetId = asset, count = 100)
253-
val height1 = nodes.waitForHeightArise()
254-
sender.assetDistributionAtHeight(asset, height1 - 1, 10).items.map { case (a, v) => a.toString -> v } shouldBe Map(
253+
nodes.waitForHeightArise()
254+
sender.assetDistribution(asset).map { case (a, v) => a.toString -> v } shouldBe Map(
255255
miner.address -> 100L,
256256
acc.toAddress.toString -> (simpleReissuableAsset.quantity - 200)
257257
)
258258
reissue(acc, CallableMethod, asset, 400, reissuable = false)
259259
invokeScript(acc, "transferAndBurn", assetId = asset, count = 100)
260-
val height2 = nodes.waitForHeightArise()
261-
sender.assetDistributionAtHeight(asset, height2 - 1, 10).items.map { case (a, v) => a.toString -> v } shouldBe Map(
260+
nodes.waitForHeightArise()
261+
sender.assetDistribution(asset).map { case (a, v) => a.toString -> v } shouldBe Map(
262262
miner.address -> 200L,
263263
acc.toAddress.toString -> simpleReissuableAsset.quantity
264264
)

node-it/src/test/scala/com/wavesplatform/it/sync/AssetDistributionSuite.scala

Lines changed: 48 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ import com.wavesplatform.state.AssetDistributionPage
88
import com.wavesplatform.transaction.transfer.MassTransferTransaction
99
import org.scalatest.CancelAfterFailure
1010

11+
import scala.concurrent.duration.*
12+
1113
class AssetDistributionSuite extends BaseTransactionSuite with CancelAfterFailure {
1214

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

2426
nodes.waitForHeightArise()
2527

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

2830
node.massTransfer(
2931
issuer,
@@ -47,6 +49,8 @@ class AssetDistributionSuite extends BaseTransactionSuite with CancelAfterFailur
4749

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

52+
assetDis should be equals node.assetDistribution(issueTx)
53+
5054
issuerAssetDis.size shouldBe 1
5155
issuerAssetDis.head shouldBe (issueAmount - addresses.length * transferAmount)
5256

@@ -68,10 +72,34 @@ class AssetDistributionSuite extends BaseTransactionSuite with CancelAfterFailur
6872
)
6973
}
7074

75+
test("'Asset distribution' works properly") {
76+
val receivers = for (i <- 0 until 10) yield KeyPair(s"receiver#$i".getBytes("UTF-8"))
77+
78+
val issueTx = node.issue(issuer, "TestCoin#2", "no description", issueAmount, 8, reissuable = false, issueFee, waitForTx = true).id
79+
80+
node
81+
.massTransfer(
82+
issuer,
83+
receivers.map(rc => MassTransferTransaction.Transfer(rc.toAddress.toString, 10)).toList,
84+
minFee + minFee * receivers.length,
85+
assetId = Some(issueTx),
86+
waitForTx = true
87+
)
88+
89+
nodes.waitForHeightArise()
90+
91+
val distribution = node.assetDistribution(issueTx)
92+
93+
distribution.size shouldBe (receivers.size + 1)
94+
distribution(issuer.toAddress) shouldBe (issueAmount - 10 * receivers.length)
95+
96+
assert(receivers.forall(rc => distribution(rc.toAddress) == 10), "Distribution correct")
97+
}
98+
7199
test("Correct last page and entry count") {
72100
val receivers = for (i <- 0 until 50) yield KeyPair(s"receiver#$i".getBytes("UTF-8"))
73101

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

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

127+
test("Unlimited list") {
128+
val assetId = node.issue(issuer, "TestCoin#2", "no description", issueAmount, 8, reissuable = false, issueFee, waitForTx = true).id
129+
130+
val receivers = for (i <- 0 until 2000) yield KeyPair(s"receiver#$i".getBytes("UTF-8"))
131+
132+
val transfers = receivers.map { r => MassTransferTransaction.Transfer(r.toAddress.toString, 10L) }.toList
133+
134+
transfers.grouped(100).foreach { t =>
135+
node.massTransfer(issuer, t, minFee + t.length * minFee, assetId = Some(assetId))
136+
}
137+
138+
node.waitFor("empty utx")(_.utxSize, (_: Int) == 0, 1 second)
139+
nodes.waitForHeightArise()
140+
141+
val list = node.assetDistribution(assetId)
142+
list should have size 2001
143+
}
144+
99145
def distributionPages(asset: String, height: Int, limit: Int): List[AssetDistributionPage] = {
100146
def _load(acc: List[AssetDistributionPage], maybeAfter: Option[String]): List[AssetDistributionPage] = {
101147
val page = node.assetDistributionAtHeight(asset, height, limit, maybeAfter)

node/src/main/resources/swagger-ui/openapi.yaml

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2440,6 +2440,38 @@ paths:
24402440
type: string
24412441
balance:
24422442
type: string
2443+
'/assets/{assetId}/distribution':
2444+
get:
2445+
tags:
2446+
- assets
2447+
summary: Asset balance distribution
2448+
description: Get asset balance distribution by addresses
2449+
operationId: getAssetDistributionOld
2450+
parameters:
2451+
- $ref: '#/components/parameters/assetId'
2452+
responses:
2453+
'200':
2454+
description: successful operation
2455+
content:
2456+
application/json:
2457+
schema:
2458+
type: object
2459+
additionalProperties:
2460+
type: integer
2461+
format: int64
2462+
description: map of assetId <-> balance
2463+
example:
2464+
2eEUvypDSivnzPiLrbYEW39SM8yMZ1aq4eJuiKfs4sEY: 15
2465+
3PPqZ623dAfbmxmnpTjwV6yD5GA5s3PJiUG: 25
2466+
application/json;large-significand-format=string:
2467+
schema:
2468+
type: object
2469+
additionalProperties:
2470+
type: string
2471+
description: map of assetId <-> balance
2472+
example:
2473+
2eEUvypDSivnzPiLrbYEW39SM8yMZ1aq4eJuiKfs4sEY: "15"
2474+
3PPqZ623dAfbmxmnpTjwV6yD5GA5s3PJiUG: "25"
24432475
'/assets/{assetId}/distribution/{height}/limit/{limit}':
24442476
get:
24452477
tags:

node/src/main/scala/com/wavesplatform/Application.scala

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -374,9 +374,8 @@ class Application(val actorSystem: ActorSystem, val settings: WavesSettings, con
374374
else heavyRequestExecutor
375375
)
376376

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

381380
val apiRoutes = Seq(
382381
new EthRpcRoute(blockchainUpdater, extensionContext.transactionsApi, time),
@@ -440,6 +439,7 @@ class Application(val actorSystem: ActorSystem, val settings: WavesSettings, con
440439
),
441440
AssetsApiRoute(
442441
settings.restAPISettings,
442+
serverRequestTimeout,
443443
wallet,
444444
transactionPublisher,
445445
blockchainUpdater,

node/src/main/scala/com/wavesplatform/api/http/TransactionJsonSerializer.scala

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,18 +16,18 @@ import com.wavesplatform.lang.v1.compiler.Terms.{ARR, CONST_BOOLEAN, CONST_BYTES
1616
import com.wavesplatform.lang.v1.serialization.SerdeV1
1717
import com.wavesplatform.protobuf.transaction.PBAmounts
1818
import com.wavesplatform.state.InvokeScriptResult.{AttachedPayment, Burn, Call, ErrorMessage, Invocation, Issue, Lease, LeaseCancel, Reissue, SponsorFee}
19-
import com.wavesplatform.state.{Blockchain, DataEntry, InvokeScriptResult, TxMeta}
2019
import com.wavesplatform.state.reader.LeaseDetails
20+
import com.wavesplatform.state.{Blockchain, DataEntry, InvokeScriptResult, TxMeta}
2121
import com.wavesplatform.transaction.Asset.{IssuedAsset, Waves}
22-
import com.wavesplatform.transaction.{Asset, PBSince, Transaction}
2322
import com.wavesplatform.transaction.lease.{LeaseCancelTransaction, LeaseTransaction}
2423
import com.wavesplatform.transaction.serialization.impl.InvokeScriptTxSerializer
2524
import com.wavesplatform.transaction.smart.InvokeScriptTransaction
2625
import com.wavesplatform.transaction.smart.InvokeScriptTransaction.Payment
2726
import com.wavesplatform.transaction.transfer.MassTransferTransaction
27+
import com.wavesplatform.transaction.{Asset, PBSince, Transaction}
2828
import com.wavesplatform.utils.EthEncoding
29+
import play.api.libs.json.*
2930
import play.api.libs.json.JsonConfiguration.Aux
30-
import play.api.libs.json.{JsArray, JsBoolean, JsNumber, JsObject, JsString, JsValue, Json, JsonConfiguration, OWrites, OptionHandlers}
3131

3232
final case class TransactionJsonSerializer(blockchain: Blockchain, commonApi: CommonTransactionsApi) {
3333

@@ -525,6 +525,6 @@ object TransactionJsonSerializer {
525525
object LeaseRef {
526526
import com.wavesplatform.utils.byteStrFormat
527527
implicit val config: Aux[Json.MacroOptions] = JsonConfiguration(optionHandlers = OptionHandlers.WritesNull)
528-
implicit val jsonWrites: OWrites[LeaseRef] = Json.writes[LeaseRef]
528+
implicit val jsonWrites: OWrites[LeaseRef] = Json.writes[LeaseRef]
529529
}
530530
}

0 commit comments

Comments
 (0)