diff --git a/node/src/main/scala/com/wavesplatform/Application.scala b/node/src/main/scala/com/wavesplatform/Application.scala index 73e314ce97..ae91db955e 100644 --- a/node/src/main/scala/com/wavesplatform/Application.scala +++ b/node/src/main/scala/com/wavesplatform/Application.scala @@ -5,6 +5,11 @@ import java.security.Security import java.util.concurrent.ConcurrentHashMap import java.util.concurrent.atomic.AtomicBoolean +import scala.concurrent.{Await, Future} +import scala.concurrent.ExecutionContext.Implicits.global +import scala.concurrent.duration._ +import scala.util.{Failure, Success, Try} + import akka.actor.ActorSystem import akka.http.scaladsl.Http import akka.http.scaladsl.Http.ServerBinding @@ -22,7 +27,7 @@ import com.wavesplatform.api.http.leasing.LeaseApiRoute import com.wavesplatform.common.state.ByteStr import com.wavesplatform.consensus.PoSSelector import com.wavesplatform.consensus.nxt.api.http.NxtConsensusApiRoute -import com.wavesplatform.database.{DBExt, Keys, openDB} +import com.wavesplatform.database.{openDB, DBExt, Keys} import com.wavesplatform.events.{BlockchainUpdateTriggers, UtxEvent} import com.wavesplatform.extensions.{Context, Extension} import com.wavesplatform.features.EstimatorProvider._ @@ -33,12 +38,12 @@ import com.wavesplatform.metrics.Metrics import com.wavesplatform.mining.{Miner, MinerDebugInfo, MinerImpl} import com.wavesplatform.network._ import com.wavesplatform.settings.WavesSettings -import com.wavesplatform.state.appender.{BlockAppender, ExtensionAppender, MicroblockAppender} import com.wavesplatform.state.{Blockchain, BlockchainUpdaterImpl, Diff, Height} -import com.wavesplatform.transaction.smart.script.trace.TracedResult +import com.wavesplatform.state.appender.{BlockAppender, ExtensionAppender, MicroblockAppender} import com.wavesplatform.transaction.{Asset, DiscardedBlocks, Transaction} -import com.wavesplatform.utils.Schedulers._ +import com.wavesplatform.transaction.smart.script.trace.TracedResult import com.wavesplatform.utils._ +import com.wavesplatform.utils.Schedulers._ import com.wavesplatform.utx.{UtxPool, UtxPoolImpl} import com.wavesplatform.wallet.Wallet import io.netty.channel.Channel @@ -55,11 +60,6 @@ import org.influxdb.dto.Point import org.iq80.leveldb.DB import org.slf4j.LoggerFactory -import scala.concurrent.ExecutionContext.Implicits.global -import scala.concurrent.duration._ -import scala.concurrent.{Await, Future} -import scala.util.{Failure, Success, Try} - class Application(val actorSystem: ActorSystem, val settings: WavesSettings, configRoot: ConfigObject, time: NTP) extends ScorexLogging { app => @@ -351,7 +351,8 @@ class Application(val actorSystem: ActorSystem, val settings: WavesSettings, con scoreStatsReporter, configRoot, loadBalanceHistory, - levelDB.loadStateHash + levelDB.loadStateHash, + () => utxStorage.priorityPool.compositeBlockchain ), AssetsApiRoute( settings.restAPISettings, @@ -541,8 +542,8 @@ object Application extends ScorexLogging { Metrics.start(settings.metrics, time) def dumpMinerConfig(): Unit = { - import settings.synchronizationSettings.microBlockSynchronizer import settings.{minerSettings => miner} + import settings.synchronizationSettings.microBlockSynchronizer Metrics.write( Point diff --git a/node/src/main/scala/com/wavesplatform/api/http/DebugApiRoute.scala b/node/src/main/scala/com/wavesplatform/api/http/DebugApiRoute.scala index 4f825045c8..3d8e6a0026 100644 --- a/node/src/main/scala/com/wavesplatform/api/http/DebugApiRoute.scala +++ b/node/src/main/scala/com/wavesplatform/api/http/DebugApiRoute.scala @@ -3,6 +3,11 @@ package com.wavesplatform.api.http import java.net.{InetAddress, InetSocketAddress, URI} import java.util.concurrent.ConcurrentMap +import scala.concurrent.{ExecutionContext, Future} +import scala.concurrent.duration._ +import scala.util.{Failure, Success} +import scala.util.control.NonFatal + import akka.http.scaladsl.common.{EntityStreamingSupport, JsonEntityStreamingSupport} import akka.http.scaladsl.model.StatusCodes import akka.http.scaladsl.model.headers.Accept @@ -12,18 +17,18 @@ import cats.implicits._ import cats.kernel.Monoid import com.typesafe.config.{ConfigObject, ConfigRenderOptions} import com.wavesplatform.account.Address -import com.wavesplatform.api.common.CommonTransactionsApi.TransactionMeta import com.wavesplatform.api.common.{CommonAccountsApi, CommonAssetsApi, CommonTransactionsApi} +import com.wavesplatform.api.common.CommonTransactionsApi.TransactionMeta import com.wavesplatform.api.http.TransactionsApiRoute.TransactionJsonSerializer import com.wavesplatform.common.state.ByteStr import com.wavesplatform.lang.ValidationError import com.wavesplatform.mining.{Miner, MinerDebugInfo} import com.wavesplatform.network.{PeerDatabase, PeerInfo, _} import com.wavesplatform.settings.{RestAPISettings, WavesSettings} -import com.wavesplatform.state.diffs.TransactionDiffer import com.wavesplatform.state.{Blockchain, LeaseBalance, NG, Portfolio, StateHash} -import com.wavesplatform.transaction.TxValidationError.{GenericError, InvalidRequestSignature} +import com.wavesplatform.state.diffs.TransactionDiffer import com.wavesplatform.transaction._ +import com.wavesplatform.transaction.TxValidationError.{GenericError, InvalidRequestSignature} import com.wavesplatform.transaction.smart.script.trace.TracedResult import com.wavesplatform.utils.{ScorexLogging, Time} import com.wavesplatform.utx.UtxPool @@ -31,13 +36,8 @@ import com.wavesplatform.wallet.Wallet import io.netty.channel.Channel import monix.eval.{Coeval, Task} import monix.execution.Scheduler -import play.api.libs.json.Json.JsValueWrapper import play.api.libs.json._ - -import scala.concurrent.duration._ -import scala.concurrent.{ExecutionContext, Future} -import scala.util.control.NonFatal -import scala.util.{Failure, Success} +import play.api.libs.json.Json.JsValueWrapper case class DebugApiRoute( ws: WavesSettings, @@ -58,7 +58,8 @@ case class DebugApiRoute( scoreReporter: Coeval[RxScoreObserver.Stats], configRoot: ConfigObject, loadBalanceHistory: Address => Seq[(Int, Long)], - loadStateHash: Int => Option[StateHash] + loadStateHash: Int => Option[StateHash], + priorityPoolBlockchain: () => Blockchain ) extends ApiRoute with AuthRoute with ScorexLogging { @@ -224,13 +225,14 @@ case class DebugApiRoute( def validate: Route = path("validate")(jsonPost[JsObject] { jsv => - val startTime = System.nanoTime() - + val blockchain = priorityPoolBlockchain() + val startTime = System.nanoTime() + val parsedTransaction = TransactionFactory.fromSignedRequest(jsv) val tracedDiff = for { tx <- TracedResult(parsedTransaction) - diff <- TransactionDiffer(blockchain.lastBlockTimestamp, time.correctedTime())(blockchain, tx) + diff <- TransactionDiffer.forceValidate(blockchain.lastBlockTimestamp, time.correctedTime())(blockchain, tx) } yield (tx, diff) val error = tracedDiff.resultE match { diff --git a/node/src/test/scala/com/wavesplatform/history/Domain.scala b/node/src/test/scala/com/wavesplatform/history/Domain.scala index 4b2497bc8d..33170bf268 100644 --- a/node/src/test/scala/com/wavesplatform/history/Domain.scala +++ b/node/src/test/scala/com/wavesplatform/history/Domain.scala @@ -3,15 +3,15 @@ package com.wavesplatform.history import cats.syntax.option._ import com.wavesplatform.account.Address import com.wavesplatform.api.common.{AddressPortfolio, AddressTransactions} -import com.wavesplatform.block.Block.BlockId import com.wavesplatform.block.{Block, MicroBlock} +import com.wavesplatform.block.Block.BlockId import com.wavesplatform.common.state.ByteStr import com.wavesplatform.common.utils.EitherExt2 import com.wavesplatform.database.{DBExt, LevelDBWriter} import com.wavesplatform.lang.ValidationError import com.wavesplatform.state._ -import com.wavesplatform.transaction.Asset.IssuedAsset import com.wavesplatform.transaction.{BlockchainUpdater, _} +import com.wavesplatform.transaction.Asset.IssuedAsset import org.iq80.leveldb.DB case class Domain(db: DB, blockchainUpdater: BlockchainUpdaterImpl, levelDBWriter: LevelDBWriter) { diff --git a/node/src/test/scala/com/wavesplatform/http/DebugApiRouteSpec.scala b/node/src/test/scala/com/wavesplatform/http/DebugApiRouteSpec.scala index 48a0a49035..9807569c96 100644 --- a/node/src/test/scala/com/wavesplatform/http/DebugApiRouteSpec.scala +++ b/node/src/test/scala/com/wavesplatform/http/DebugApiRouteSpec.scala @@ -1,30 +1,33 @@ package com.wavesplatform.http +import scala.util.Random + import akka.http.scaladsl.model.{ContentTypes, HttpEntity, StatusCodes} +import com.wavesplatform.{BlockchainStubHelpers, NTPTime, TestValues, TestWallet} import com.wavesplatform.api.http.ApiError.ApiKeyNotValid import com.wavesplatform.api.http.DebugApiRoute import com.wavesplatform.block.SignedBlockHeader import com.wavesplatform.common.state.ByteStr import com.wavesplatform.common.utils._ +import com.wavesplatform.db.WithDomain +import com.wavesplatform.features.BlockchainFeatures import com.wavesplatform.it.util._ import com.wavesplatform.lagonaki.mocks.TestBlock import com.wavesplatform.lang.v1.estimator.v3.ScriptEstimatorV3 import com.wavesplatform.lang.v1.traits.domain.Issue import com.wavesplatform.network.PeerDatabase import com.wavesplatform.settings.WavesSettings -import com.wavesplatform.state.StateHash.SectionId import com.wavesplatform.state.{AccountScriptInfo, AssetDescription, AssetScriptInfo, Blockchain, Height, NG, StateHash} +import com.wavesplatform.state.StateHash.SectionId import com.wavesplatform.transaction.TxHelpers import com.wavesplatform.transaction.assets.exchange.OrderType import com.wavesplatform.transaction.smart.InvokeScriptTransaction import com.wavesplatform.transaction.smart.InvokeScriptTransaction.Payment import com.wavesplatform.transaction.smart.script.ScriptCompiler -import com.wavesplatform.{BlockchainStubHelpers, NTPTime, TestValues, TestWallet} +import com.wavesplatform.transaction.transfer.TransferTransaction import monix.eval.Task import org.scalamock.scalatest.PathMockFactory -import play.api.libs.json.{JsArray, JsObject, JsValue, Json} - -import scala.util.Random +import play.api.libs.json.{JsArray, JsObject, Json, JsValue} //noinspection ScalaStyle class DebugApiRouteSpec @@ -33,7 +36,8 @@ class DebugApiRouteSpec with TestWallet with NTPTime with PathMockFactory - with BlockchainStubHelpers { + with BlockchainStubHelpers + with WithDomain { val wavesSettings = WavesSettings.default() val configObject = wavesSettings.config.root() @@ -68,7 +72,8 @@ class DebugApiRouteSpec _ => Seq.empty, { case 2 => Some(testStateHash) case _ => None - } + }, + () => blockchain ) import debugApiRoute._ @@ -94,14 +99,34 @@ class DebugApiRouteSpec } routePath("/validate") - { + def routeWithBlockchain(blockchain: Blockchain with NG) = + debugApiRoute.copy(blockchain = blockchain, priorityPoolBlockchain = () => blockchain).route + + + def validatePost(tx: TransferTransaction) = + Post(routePath("/validate"), HttpEntity(ContentTypes.`application/json`, tx.json().toString())) + + "takes the priority pool into account" in withDomain(domainSettingsWithFeatures(BlockchainFeatures.NG)) { d => + d.appendBlock(TxHelpers.genesis(TxHelpers.defaultAddress)) + d.appendBlock(TxHelpers.transfer(to = TxHelpers.secondAddress, amount = 1.waves + TestValues.fee)) + + val route = debugApiRoute.copy(priorityPoolBlockchain = () => d.blockchain).route + val tx = TxHelpers.transfer(TxHelpers.secondSigner, TestValues.address, 1.waves) + validatePost(tx) ~> route ~> check { + val json = Json.parse(responseAs[String]) + (json \ "valid").as[Boolean] shouldBe true + (json \ "validationTime").as[Int] shouldBe 1000 +- 1000 + } + } + "valid tx" in { val blockchain = createBlockchainStub() (blockchain.balance _).when(TxHelpers.defaultSigner.publicKey.toAddress, *).returns(Long.MaxValue) - val route = debugApiRoute.copy(blockchain = blockchain).route + val route = routeWithBlockchain(blockchain) val tx = TxHelpers.transfer(TxHelpers.defaultSigner, TestValues.address, 1.waves) - Post(routePath("/validate"), HttpEntity(ContentTypes.`application/json`, tx.json().toString())) ~> route ~> check { + validatePost(tx) ~> route ~> check { val json = Json.parse(responseAs[String]) (json \ "valid").as[Boolean] shouldBe true (json \ "validationTime").as[Int] shouldBe 1000 +- 1000 @@ -112,10 +137,10 @@ class DebugApiRouteSpec val blockchain = createBlockchainStub() (blockchain.balance _).when(TxHelpers.defaultSigner.publicKey.toAddress, *).returns(0) - val route = debugApiRoute.copy(blockchain = blockchain).route + val route = routeWithBlockchain(blockchain) val tx = TxHelpers.transfer(TxHelpers.defaultSigner, TestValues.address, Long.MaxValue) - Post(routePath("/validate"), HttpEntity(ContentTypes.`application/json`, tx.json().toString())) ~> route ~> check { + validatePost(tx) ~> route ~> check { val json = Json.parse(responseAs[String]) (json \ "valid").as[Boolean] shouldBe false (json \ "validationTime").as[Int] shouldBe 1000 +- 1000 @@ -150,7 +175,7 @@ class DebugApiRouteSpec ) } - val route = debugApiRoute.copy(blockchain = blockchain).route + val route = routeWithBlockchain(blockchain) val tx = TxHelpers.exchange(TxHelpers.order(OrderType.BUY, TestValues.asset), TxHelpers.order(OrderType.SELL, TestValues.asset)) jsonPost(routePath("/validate"), tx.json()) ~> route ~> check { val json = Json.parse(responseAs[String]) @@ -249,8 +274,7 @@ class DebugApiRouteSpec (blockchain.hasAccountScript _).when(*).returns(true) } - val route = debugApiRoute.copy(blockchain = blockchain).route - + val route = routeWithBlockchain(blockchain) def testFunction(name: String, result: InvokeScriptTransaction => String) = withClue(s"function $name") { val tx = TxHelpers.invoke(TxHelpers.defaultAddress, name, fee = 102500000) @@ -518,7 +542,7 @@ class DebugApiRouteSpec ) ) } - val route = debugApiRoute.copy(blockchain = blockchain).route + val route = routeWithBlockchain(blockchain) val tx = TxHelpers.transfer(TxHelpers.defaultSigner, TxHelpers.defaultAddress, 1, TestValues.asset) jsonPost(routePath("/validate"), tx.json()) ~> route ~> check {