Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

NODE-2642 Transaction snapshots API #3931

Merged
merged 25 commits into from
Jan 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/check-pr.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ jobs:
sbt lang/assembly
git clone https://github.com/waves-exchange/neutrino-contract
git clone https://github.com/waves-exchange/contracts
git clone https://oauth2:${{ secrets.DUCKS_GITHUB_TOKEN }}@github.com/akharazyan/wavesducks-public
git clone https://github.com/waves-ducks-core/wavesducks-public
git clone https://oauth2:${{ secrets.SWOPFI_GITLAB_TOKEN }}@gitlabwp.wvservices.com/swopfi/swopfi-smart-contracts
find neutrino-contract/script -name "*.ride" -type f -exec java -jar lang/jvm/target/file-compiler.jar {} +;
find contracts/ride -name "*.ride" -type f -exec java -jar lang/jvm/target/file-compiler.jar {} +;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,20 +1,21 @@
package com.wavesplatform.api.grpc

import scala.concurrent.Future
import com.wavesplatform.account.AddressScheme
import com.wavesplatform.api.common.{CommonTransactionsApi, TransactionMeta}
import com.wavesplatform.api.grpc.TransactionsApiGrpcImpl.applicationStatusFromTxStatus
import com.wavesplatform.protobuf.*
import com.wavesplatform.protobuf.transaction.*
import com.wavesplatform.protobuf.utils.PBImplicitConversions.PBRecipientImplicitConversionOps
import com.wavesplatform.state.{Blockchain, TxMeta, InvokeScriptResult as VISR}
import com.wavesplatform.transaction.{Authorized, EthereumTransaction}
import com.wavesplatform.transaction.TxValidationError.GenericError
import io.grpc.{Status, StatusRuntimeException}
import com.wavesplatform.transaction.{Authorized, EthereumTransaction}
import io.grpc.stub.StreamObserver
import io.grpc.{Status, StatusRuntimeException}
import monix.execution.Scheduler
import monix.reactive.Observable

import scala.concurrent.Future

class TransactionsApiGrpcImpl(blockchain: Blockchain, commonApi: CommonTransactionsApi)(implicit sc: Scheduler)
extends TransactionsApiGrpc.TransactionsApi {

Expand Down Expand Up @@ -64,6 +65,20 @@ class TransactionsApiGrpcImpl(blockchain: Blockchain, commonApi: CommonTransacti
)
}

override def getTransactionSnapshots(
request: TransactionSnapshotsRequest,
responseObserver: StreamObserver[TransactionSnapshotResponse]
): Unit =
responseObserver.interceptErrors {
val snapshots =
for {
id <- Observable.fromIterable(request.transactionIds)
(snapshot, status) <- Observable.fromIterable(blockchain.transactionSnapshot(id.toByteStr))
pbSnapshot = PBSnapshots.toProtobuf(snapshot, status)
} yield TransactionSnapshotResponse(id, Some(pbSnapshot))
responseObserver.completeWith(snapshots)
}

override def getUnconfirmed(request: TransactionsRequest, responseObserver: StreamObserver[TransactionResponse]): Unit =
responseObserver.interceptErrors {
val unconfirmedTransactions = if (!request.sender.isEmpty) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package com.wavesplatform.api.grpc.test

import com.google.protobuf.ByteString
import com.wavesplatform.account.KeyPair
import com.wavesplatform.api.grpc.{ApplicationStatus, TransactionResponse, TransactionsApiGrpcImpl, TransactionsRequest}
import com.wavesplatform.api.grpc.{ApplicationStatus, TransactionResponse, TransactionSnapshotResponse, TransactionSnapshotsRequest, TransactionsApiGrpcImpl, TransactionsRequest}
import com.wavesplatform.block.Block
import com.wavesplatform.common.state.ByteStr
import com.wavesplatform.common.utils.EitherExt2
Expand All @@ -11,16 +11,21 @@ import com.wavesplatform.db.WithDomain
import com.wavesplatform.db.WithState.AddrWithBalance
import com.wavesplatform.history.Domain
import com.wavesplatform.protobuf.transaction.{PBTransactions, Recipient}
import com.wavesplatform.state.TxMeta
import com.wavesplatform.protobuf.{ByteStrExt, PBSnapshots}
import com.wavesplatform.state.diffs.ENOUGH_AMT
import com.wavesplatform.state.{StateSnapshot, TxMeta}
import com.wavesplatform.test.*
import com.wavesplatform.test.DomainPresets.*
import com.wavesplatform.transaction.Asset.Waves
import com.wavesplatform.transaction.{TxHelpers, TxVersion}
import com.wavesplatform.transaction.TxHelpers.*
import com.wavesplatform.transaction.assets.exchange.{ExchangeTransaction, Order, OrderType}
import com.wavesplatform.transaction.{TxHelpers, TxVersion}
import com.wavesplatform.utils.DiffMatchers
import monix.execution.Scheduler.Implicits.global
import org.scalatest.{Assertion, BeforeAndAfterAll}

import scala.collection.immutable.VectorMap

class TransactionsApiGrpcSpec extends FreeSpec with BeforeAndAfterAll with DiffMatchers with WithDomain with GrpcApiHelpers {

val sender: KeyPair = TxHelpers.signer(1)
Expand Down Expand Up @@ -69,6 +74,67 @@ class TransactionsApiGrpcSpec extends FreeSpec with BeforeAndAfterAll with DiffM
}
}

"GetTransactionSnapshots" in withDomain(TransactionStateSnapshot, AddrWithBalance.enoughBalances(secondSigner)) { d =>
val recipient = signer(2).toAddress
val txs = Seq.fill(5)(transfer(amount = 1, fee = 100_000, from = secondSigner, to = recipient))

val firstThreeSnapshots = Seq(
StateSnapshot(balances =
VectorMap(
(secondAddress, Waves) -> (ENOUGH_AMT - 100_001),
(recipient, Waves) -> 1,
(defaultAddress, Waves) -> 200_040_000 // reward and 40% fee
)
),
StateSnapshot(balances =
VectorMap(
(secondAddress, Waves) -> (ENOUGH_AMT - 200_002),
(recipient, Waves) -> 2,
(defaultAddress, Waves) -> 200_080_000
)
),
StateSnapshot(balances =
VectorMap(
(secondAddress, Waves) -> (ENOUGH_AMT - 300_003),
(recipient, Waves) -> 3,
(defaultAddress, Waves) -> 200_120_000
)
)
)

def getSnapshots() = {
val request = TransactionSnapshotsRequest.of(txs.map(_.id().toByteString))
val (observer, response) = createObserver[TransactionSnapshotResponse]
getGrpcApi(d).getTransactionSnapshots(request, observer)
response.runSyncUnsafe().flatMap(_.snapshot).map(PBSnapshots.fromProtobuf(_, ByteStr.empty, 0)._1)
}

d.appendBlock(txs(0), txs(1))
d.appendMicroBlock(txs(2))

// both liquid and solid state
getSnapshots() shouldBe firstThreeSnapshots

// hardened state
d.appendBlock(txs(3), txs(4))
getSnapshots() shouldBe firstThreeSnapshots ++ Seq(
StateSnapshot(balances =
VectorMap(
(secondAddress, Waves) -> (ENOUGH_AMT - 400_004),
(recipient, Waves) -> 4,
(defaultAddress, Waves) -> 400_340_000 // 2 blocks reward, 100% fee from previous block and 40% fee from current
)
),
StateSnapshot(balances =
VectorMap(
(secondAddress, Waves) -> (ENOUGH_AMT - 500_005),
(recipient, Waves) -> 5,
(defaultAddress, Waves) -> 400_380_000
)
)
)
}

"NODE-973. GetTransactions should return correct data for orders with attachment" in {
def checkOrderAttachment(txResponse: TransactionResponse, expectedAttachment: ByteStr): Assertion = {
PBTransactions
Expand Down Expand Up @@ -143,7 +209,10 @@ class TransactionsApiGrpcSpec extends FreeSpec with BeforeAndAfterAll with DiffM
val challengedMiner = TxHelpers.signer(2)
val resender = TxHelpers.signer(3)
val recipient = TxHelpers.signer(4)
withDomain(TransactionStateSnapshot.configure(_.copy(lightNodeBlockFieldsAbsenceInterval = 0)), balances = AddrWithBalance.enoughBalances(sender)) { d =>
withDomain(
TransactionStateSnapshot.configure(_.copy(lightNodeBlockFieldsAbsenceInterval = 0)),
balances = AddrWithBalance.enoughBalances(sender)
) { d =>
val grpcApi = getGrpcApi(d)
val challengingMiner = d.wallet.generateNewAccount().get

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,8 @@ trait Script {
}

object Script {

case class ComplexityInfo(verifierComplexity: Long, callableComplexities: Map[String, Long], maxComplexity: Long)

val checksumLength = 4

def fromBase64String(str: String): Either[ScriptParseError, Script] =
for {
bytes <- Base64.tryDecode(str).toEither.left.map(ex => ScriptParseError(s"Unable to decode base64: ${ex.getMessage}"))
Expand Down Expand Up @@ -93,9 +90,7 @@ object Script {
)
complexityInfo = verifierFuncOpt.fold(
ComplexityInfo(0L, callableComplexities, maxComplexity)
)(
v => ComplexityInfo(callableComplexities(v.u.name), callableComplexities - v.u.name, maxComplexity)
)
)(v => ComplexityInfo(callableComplexities(v.u.name), callableComplexities - v.u.name, maxComplexity))
} yield complexityInfo
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ class AmountAsStringSuite extends BaseTransactionSuite with OverflowBlock {
amount,
price,
ts,
ts + Order.MaxLiveTime,
ts + Order.MaxLiveTime / 2,
matcherFee
)
.explicitGet()
Expand All @@ -95,7 +95,7 @@ class AmountAsStringSuite extends BaseTransactionSuite with OverflowBlock {
amount,
price,
ts,
ts + Order.MaxLiveTime,
ts + Order.MaxLiveTime / 2,
matcherFee
)
.explicitGet()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,7 @@ class VRFProtobufActivationSuite extends BaseTransactionSuite {
amount,
price,
ts,
ts + Order.MaxLiveTime,
ts + Order.MaxLiveTime / 2,
matcherFee
)
.explicitGet()
Expand All @@ -237,7 +237,7 @@ class VRFProtobufActivationSuite extends BaseTransactionSuite {
amount,
price,
ts,
ts + Order.MaxLiveTime,
ts + Order.MaxLiveTime / 2,
matcherFee
)
.explicitGet()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ class ExchangeTransactionGrpcSuite extends GrpcBaseTransactionSuite with NTPTime
val pair = AssetPair.createAssetPair("WAVES", exchAssetId).get
for ((o1ver, o2ver, tver) <- versions) {
val ts = ntpTime.correctedTime()
val expirationTimestamp = ts + Order.MaxLiveTime
val expirationTimestamp = ts + Order.MaxLiveTime / 2
val buy = Order.buy(o1ver, buyer, matcher.publicKey, pair, amount, price, ts, expirationTimestamp, matcherFee).explicitGet()
val sell = Order.sell(o2ver, seller, matcher.publicKey, pair, amount, price, ts, expirationTimestamp, matcherFee).explicitGet()
val buyerWavesBalanceBefore = sender.wavesBalance(buyerAddress).available
Expand Down Expand Up @@ -98,7 +98,7 @@ class ExchangeTransactionGrpcSuite extends GrpcBaseTransactionSuite with NTPTime
val sellerAssetBalanceBefore = sender.assetsBalance(sellerAddress, Seq(feeAssetId.toString)).getOrElse(feeAssetId.toString, 0L)

val ts = ntpTime.correctedTime()
val expirationTimestamp = ts + Order.MaxLiveTime
val expirationTimestamp = ts + Order.MaxLiveTime / 2
val assetPair = AssetPair.createAssetPair("WAVES", feeAssetId.toString).get
val buy =
Order.buy(o1ver, buyer, matcher.publicKey, assetPair, amount, price, ts, expirationTimestamp, matcherFee, matcherFeeOrder1).explicitGet()
Expand Down Expand Up @@ -133,7 +133,7 @@ class ExchangeTransactionGrpcSuite extends GrpcBaseTransactionSuite with NTPTime

val assetId = exchAsset.id().toString
val ts = ntpTime.correctedTime()
val expirationTimestamp = ts + Order.MaxLiveTime
val expirationTimestamp = ts + Order.MaxLiveTime / 2
val price = 2 * Order.PriceConstant
val amount = 1
val pair = AssetPair.createAssetPair("WAVES", assetId).get
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ package object smartcontract {
val seller = accounts.tail.head // second one
val matcher = accounts.last
val ts = time.correctedTime()
val expirationTimestamp = ts + Order.MaxLiveTime
val expirationTimestamp = ts + Order.MaxLiveTime / 2
val buyPrice = 1 * Order.PriceConstant
val sellPrice = (0.50 * Order.PriceConstant).toLong
val buyAmount = 2
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ class ExchangeTransactionSuite extends BaseTransactionSuite with NTPTime {
val matcher = acc2

val ts = ntpTime.correctedTime()
val expirationTimestamp = ts + Order.MaxLiveTime
val expirationTimestamp = ts + Order.MaxLiveTime / 2

val buyPrice = 2 * Order.PriceConstant
val sellPrice = 2 * Order.PriceConstant
Expand Down Expand Up @@ -197,7 +197,7 @@ class ExchangeTransactionSuite extends BaseTransactionSuite with NTPTime {

val matcher = thirdKeyPair
val ts = ntpTime.correctedTime()
val expirationTimestamp = ts + Order.MaxLiveTime
val expirationTimestamp = ts + Order.MaxLiveTime / 2
var assetBalanceBefore: Long = 0L

if (matcherFeeOrder1 == Waves && matcherFeeOrder2 != Waves) {
Expand Down Expand Up @@ -283,7 +283,7 @@ class ExchangeTransactionSuite extends BaseTransactionSuite with NTPTime {

val matcher = thirdKeyPair
val ts = ntpTime.correctedTime()
val expirationTimestamp = ts + Order.MaxLiveTime
val expirationTimestamp = ts + Order.MaxLiveTime / 2
val amount = 1
val nftWavesPrice = 1000 * math.pow(10, 8).toLong
val nftForAssetPrice = 1 * math.pow(10, 8).toLong
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -288,7 +288,7 @@ object FailedTransactionSuiteLike {
100,
100,
timestamp,
timestamp + Order.MaxLiveTime,
timestamp + Order.MaxLiveTime / 2,
buyMatcherFee,
Asset.fromString(Some(buyMatcherFeeAsset))
).explicitGet()
Expand All @@ -300,7 +300,7 @@ object FailedTransactionSuiteLike {
100,
100,
timestamp,
timestamp + Order.MaxLiveTime,
timestamp + Order.MaxLiveTime / 2,
sellMatcherFee,
Asset.fromString(Some(sellMatcherFeeAsset))
).explicitGet()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -426,7 +426,7 @@ class SignAndBroadcastApiSuite extends BaseTransactionSuite with NTPTime with Be
val seller = secondKeyPair
val matcher = thirdKeyPair
val ts = ntpTime.correctedTime()
val expirationTimestamp = ts + Order.MaxLiveTime
val expirationTimestamp = ts + Order.MaxLiveTime / 2
val buyPrice = 1 * Order.PriceConstant
val sellPrice = (0.50 * Order.PriceConstant).toLong
val mf = 300000L
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ class TransferNFTSuite extends BaseTransactionSuite with NTPTime {
amount = 1,
price = 1.waves,
timestamp = ts,
expiration = ts + Order.MaxLiveTime,
expiration = ts + Order.MaxLiveTime / 2,
matcherFee = matcherFee
)
.explicitGet()
Expand All @@ -174,7 +174,7 @@ class TransferNFTSuite extends BaseTransactionSuite with NTPTime {
amount = 1,
price = 1.waves,
timestamp = ts,
expiration = ts + Order.MaxLiveTime,
expiration = ts + Order.MaxLiveTime / 2,
matcherFee = matcherFee
)
.explicitGet()
Expand Down
1 change: 1 addition & 0 deletions node/src/main/resources/application.conf
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,7 @@ waves {
# Max number of transactions
# returned by /transactions/address/{address}/limit/{limit}
transactions-by-address-limit = 1000
transaction-snapshots-limit = 100
distribution-address-limit = 1000
data-keys-request-limit = 1000
asset-details-limit = 100
Expand Down
Loading