Skip to content

Commit

Permalink
Merge branch 'version-0.14.x' into version-0.14.7
Browse files Browse the repository at this point in the history
  • Loading branch information
peterz committed Oct 29, 2018
2 parents b6d660e + d8fa867 commit 8a02718
Show file tree
Hide file tree
Showing 18 changed files with 292 additions and 288 deletions.
148 changes: 59 additions & 89 deletions it/src/main/scala/com/wavesplatform/it/api/AsyncMatcherHttpApi.scala
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package com.wavesplatform.it.api

import com.google.common.primitives.Longs
import com.wavesplatform.account.{PrivateKeyAccount, PublicKeyAccount}
import com.wavesplatform.account.PrivateKeyAccount
import com.wavesplatform.crypto
import com.wavesplatform.http.api_key
import com.wavesplatform.it.Node
Expand All @@ -10,7 +10,7 @@ import com.wavesplatform.matcher.api.CancelOrderRequest
import com.wavesplatform.state.ByteStr
import com.wavesplatform.transaction.assets.exchange.{AssetPair, Order, OrderType}
import com.wavesplatform.utils.Base58
import org.asynchttpclient.Dsl.{get => _get, delete => _delete}
import org.asynchttpclient.Dsl.{delete => _delete, get => _get}
import org.asynchttpclient.util.HttpConstants
import org.asynchttpclient.{RequestBuilder, Response}
import org.scalatest.Assertions
Expand All @@ -26,6 +26,18 @@ object AsyncMatcherHttpApi extends Assertions {

val DefaultMatcherFee: Int = 300000

def cancelRequest(sender: PrivateKeyAccount, orderId: String): CancelOrderRequest = {
val req = CancelOrderRequest(sender, Some(ByteStr.decodeBase58(orderId).get), None, Array.emptyByteArray)
val signature = crypto.sign(sender, req.toSign)
req.copy(signature = signature)
}

def batchCancelRequest(sender: PrivateKeyAccount, timestamp: Long): CancelOrderRequest = {
val req = CancelOrderRequest(sender, None, Some(timestamp), Array.emptyByteArray)
val signature = crypto.sign(sender, req.toSign)
req.copy(signature = signature)
}

implicit class MatcherAsyncHttpApi(matcherNode: Node) extends NodeAsyncHttpApi(matcherNode) {

def matcherGet(path: String,
Expand All @@ -43,11 +55,14 @@ object AsyncMatcherHttpApi extends Assertions {
.build()
)

def matcherGetWithSignature(path: String, ts: Long, signature: ByteStr, f: RequestBuilder => RequestBuilder = identity): Future[Response] =
def matcherGetWithSignature(path: String,
sender: PrivateKeyAccount,
timestamp: Long = System.currentTimeMillis(),
f: RequestBuilder => RequestBuilder = identity): Future[Response] =
retrying {
_get(s"${matcherNode.matcherApiEndpoint}$path")
.setHeader("Timestamp", ts)
.setHeader("Signature", signature)
.setHeader("Timestamp", timestamp)
.setHeader("Signature", Base58.encode(crypto.sign(sender, sender.publicKey ++ Longs.toByteArray(timestamp))))
.build()
}

Expand All @@ -67,113 +82,72 @@ object AsyncMatcherHttpApi extends Assertions {
)

def orderStatus(orderId: String, assetPair: AssetPair, waitForStatus: Boolean = true): Future[MatcherStatusResponse] = {
val (amountAsset, priceAsset) = parseAssetPair(assetPair)
matcherGet(s"/matcher/orderbook/$amountAsset/$priceAsset/$orderId", waitForStatus = waitForStatus)
matcherGet(s"/matcher/orderbook/${assetPair.toUri}/$orderId", waitForStatus = waitForStatus)
.as[MatcherStatusResponse]
}

def transactionsByOrder(orderId: String): Future[Seq[ExchangeTransaction]] =
matcherGet(s"/matcher/transactions/$orderId").as[Seq[ExchangeTransaction]]

def orderBook(assetPair: AssetPair): Future[OrderBookResponse] = {
val (amountAsset, priceAsset) = parseAssetPair(assetPair)
matcherGet(s"/matcher/orderbook/$amountAsset/$priceAsset").as[OrderBookResponse]
}
def orderBook(assetPair: AssetPair): Future[OrderBookResponse] =
matcherGet(s"/matcher/orderbook/${assetPair.toUri}").as[OrderBookResponse]

def deleteOrderBook(assetPair: AssetPair): Future[OrderBookResponse] = {
val (amountAsset, priceAsset) = parseAssetPair(assetPair)
retrying(_delete(s"${matcherNode.matcherApiEndpoint}/matcher/orderbook/$amountAsset/$priceAsset").withApiKey(matcherNode.apiKey).build())
def deleteOrderBook(assetPair: AssetPair): Future[OrderBookResponse] =
retrying(_delete(s"${matcherNode.matcherApiEndpoint}/matcher/orderbook/${assetPair.toUri}").withApiKey(matcherNode.apiKey).build())
.as[OrderBookResponse]
}

def marketStatus(assetPair: AssetPair): Future[MarketStatusResponse] = {
val (amountAsset, priceAsset) = parseAssetPair(assetPair)
matcherGet(s"/matcher/orderbook/$amountAsset/$priceAsset/status").as[MarketStatusResponse]
}
def marketStatus(assetPair: AssetPair): Future[MarketStatusResponse] =
matcherGet(s"/matcher/orderbook/${assetPair.toUri}/status").as[MarketStatusResponse]

def parseAssetPair(assetPair: AssetPair): (String, String) = {
val amountAsset = assetPair.amountAsset match {
case None => "WAVES"
case _ => assetPair.amountAsset.get.base58
}
val priceAsset = assetPair.priceAsset match {
case None => "WAVES"
case _ => assetPair.priceAsset.get.base58
def cancelOrder(sender: Node, assetPair: AssetPair, orderId: String): Future[MatcherStatusResponse] =
cancelOrder(sender.privateKey, assetPair, orderId)

def cancelOrder(sender: PrivateKeyAccount, assetPair: AssetPair, orderId: String): Future[MatcherStatusResponse] =
matcherPost(s"/matcher/orderbook/${assetPair.toUri}/cancel", cancelRequest(sender, orderId)).as[MatcherStatusResponse]

def expectCancelRejected(sender: PrivateKeyAccount, assetPair: AssetPair, orderId: String): Future[Unit] = {
val requestUri = s"/matcher/orderbook/${assetPair.toUri}/cancel"
matcherPost(requestUri, cancelRequest(sender, orderId)).transform {
case Failure(UnexpectedStatusCodeException(_, 400, body)) if (Json.parse(body) \ "status").as[String] == "OrderCancelRejected" => Success(())
case Failure(cause) => Failure(cause)
case Success(resp) => Failure(UnexpectedStatusCodeException(requestUri, resp.getStatusCode, resp.getResponseBody))
}
(amountAsset, priceAsset)
}

def cancelOrder(sender: Node, assetPair: AssetPair, orderId: Option[String], timestamp: Option[Long] = None): Future[MatcherStatusResponse] =
cancelOrder(sender.privateKey, assetPair, orderId, timestamp)

def cancelOrder(sender: PrivateKeyAccount,
assetPair: AssetPair,
orderId: Option[String],
timestamp: Option[Long]): Future[MatcherStatusResponse] = {
val privateKey = sender.privateKey
val publicKey = PublicKeyAccount(sender.publicKey)
val request = CancelOrderRequest(publicKey, orderId.map(ByteStr.decodeBase58(_).get), timestamp, Array.emptyByteArray)
val sig = crypto.sign(privateKey, request.toSign)
val signedRequest = request.copy(signature = sig)
val (amountAsset, priceAsset) = parseAssetPair(assetPair)
matcherPost(s"/matcher/orderbook/$amountAsset/$priceAsset/cancel", signedRequest).as[MatcherStatusResponse]
}
def cancelOrdersForPair(sender: Node, assetPair: AssetPair, timestamp: Long): Future[MatcherStatusResponse] =
matcherPost(s"/matcher/orderbook/${assetPair.toUri}/cancel", Json.toJson(batchCancelRequest(sender.privateKey, timestamp)))
.as[MatcherStatusResponse]

def cancelAllOrders(sender: Node, timestamp: Option[Long]): Future[MatcherStatusResponse] = {
val privateKey = sender.privateKey
val publicKey = sender.publicKey
val request = CancelOrderRequest(publicKey, None, timestamp, Array.emptyByteArray)
val sig = crypto.sign(privateKey, request.toSign)
val signedRequest = request.copy(signature = sig)
matcherPost(s"/matcher/orderbook/cancel", Json.toJson(signedRequest)).as[MatcherStatusResponse]
}
def cancelAllOrders(sender: Node, timestamp: Long): Future[MatcherStatusResponse] =
matcherPost(s"/matcher/orderbook/cancel", Json.toJson(batchCancelRequest(sender.privateKey, timestamp))).as[MatcherStatusResponse]

def cancelOrderWithApiKey(orderId: String): Future[MatcherStatusResponse] = {
def cancelOrderWithApiKey(orderId: String): Future[MatcherStatusResponse] =
postWithAPiKey(s"/matcher/orders/cancel/$orderId").as[MatcherStatusResponse]
}

def fullOrdersHistory(sender: Node): Future[Seq[OrderbookHistory]] = {
val ts = System.currentTimeMillis()
matcherGetWithSignature(s"/matcher/orderbook/${sender.publicKeyStr}", ts, signature(sender, ts)).as[Seq[OrderbookHistory]]
}
def fullOrdersHistory(sender: Node): Future[Seq[OrderbookHistory]] =
matcherGetWithSignature(s"/matcher/orderbook/${sender.publicKeyStr}", sender.privateKey).as[Seq[OrderbookHistory]]

def orderHistoryByPair(sender: Node, assetPair: AssetPair, activeOnly: Boolean = false): Future[Seq[OrderbookHistory]] = {
val ts = System.currentTimeMillis()
val (amountAsset, priceAsset) = parseAssetPair(assetPair)
matcherGetWithSignature(s"/matcher/orderbook/$amountAsset/$priceAsset/publicKey/${sender.publicKeyStr}?activeOnly=$activeOnly",
ts,
signature(sender, ts))
matcherGetWithSignature(s"/matcher/orderbook/${assetPair.toUri}/publicKey/${sender.publicKeyStr}?activeOnly=$activeOnly", sender.privateKey)
.as[Seq[OrderbookHistory]]
}

def activeOrderHistory(sender: Node): Future[Seq[OrderbookHistory]] = {
val ts = System.currentTimeMillis()
matcherGetWithSignature(s"/matcher/orderbook/${sender.publicKeyStr}?activeOnly=true", ts, signature(sender, ts)).as[Seq[OrderbookHistory]]
matcherGetWithSignature(s"/matcher/orderbook/${sender.publicKeyStr}?activeOnly=true", sender.privateKey).as[Seq[OrderbookHistory]]
}

def reservedBalance(sender: Node): Future[Map[String, Long]] = reservedBalance(sender.privateKey)

def reservedBalance(sender: PrivateKeyAccount): Future[Map[String, Long]] = {
val ts = System.currentTimeMillis()
val privateKey = sender.privateKey
val publicKey = sender.publicKey
val signature = ByteStr(crypto.sign(privateKey, publicKey ++ Longs.toByteArray(ts)))
def reservedBalance(sender: PrivateKeyAccount): Future[Map[String, Long]] =
matcherGetWithSignature(s"/matcher/balance/reserved/${Base58.encode(sender.publicKey)}", sender).as[Map[String, Long]]

matcherGetWithSignature(s"/matcher/balance/reserved/${Base58.encode(sender.publicKey)}", ts, signature).as[Map[String, Long]]
}
def tradableBalance(sender: Node, assetPair: AssetPair): Future[Map[String, Long]] =
matcherGet(s"/matcher/orderbook/${assetPair.toUri}/tradableBalance/${sender.address}").as[Map[String, Long]]

def tradableBalance(sender: Node, assetPair: AssetPair): Future[Map[String, Long]] = {
val (amountAsset, priceAsset) = parseAssetPair(assetPair)
matcherGet(s"/matcher/orderbook/$amountAsset/$priceAsset/tradableBalance/${sender.address}").as[Map[String, Long]]
}
def tradableBalance(sender: PrivateKeyAccount, assetPair: AssetPair): Future[Map[String, Long]] =
matcherGet(s"/matcher/orderbook/${assetPair.toUri}/tradableBalance/${sender.address}").as[Map[String, Long]]

def tradableBalance(sender: PrivateKeyAccount, assetPair: AssetPair): Future[Map[String, Long]] = {
val (amountAsset, priceAsset) = parseAssetPair(assetPair)
matcherGet(s"/matcher/orderbook/$amountAsset/$priceAsset/tradableBalance/${sender.address}").as[Map[String, Long]]
}

def tradingMarkets(): Future[MarketDataInfo] =
matcherGet(s"/matcher/orderbook").as[MarketDataInfo]
def tradingMarkets(): Future[MarketDataInfo] = matcherGet(s"/matcher/orderbook").as[MarketDataInfo]

def waitOrderStatus(assetPair: AssetPair,
orderId: String,
Expand Down Expand Up @@ -242,17 +216,13 @@ object AsyncMatcherHttpApi extends Assertions {

def ordersByAddress(senderAddress: String, activeOnly: Boolean): Future[Seq[OrderbookHistory]] =
matcherGetWithApiKey(s"/matcher/orders/$senderAddress?activeOnly=$activeOnly").as[Seq[OrderbookHistory]]

private def signature(node: Node, timestamp: Long) = {
val privateKey = node.privateKey
val publicKey = node.publicKey.publicKey
ByteStr(crypto.sign(privateKey, publicKey ++ Longs.toByteArray(timestamp)))
}

}

implicit class RequestBuilderOps(self: RequestBuilder) {
def withApiKey(x: String): RequestBuilder = self.setHeader(api_key.name, x)
}

implicit class AssetPairExt(val p: AssetPair) extends AnyVal {
def toUri: String = s"${AssetPair.assetIdStr(p.amountAsset)}/${AssetPair.assetIdStr(p.priceAsset)}"
}
}
38 changes: 20 additions & 18 deletions it/src/main/scala/com/wavesplatform/it/api/SyncMatcherHttpApi.scala
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,17 @@ import com.wavesplatform.it.Node
import com.wavesplatform.transaction.assets.exchange.{AssetPair, Order, OrderType}
import org.asynchttpclient.util.HttpConstants
import org.asynchttpclient.{RequestBuilder, Response}
import org.scalatest.{Assertions, Matchers}
import play.api.libs.json.{Format, Json, Writes}

import scala.concurrent.Await
import scala.concurrent.duration._

object SyncMatcherHttpApi extends Assertions {
object SyncMatcherHttpApi {
case class ErrorMessage(error: Int, message: String)

implicit val errorMessageFormat: Format[ErrorMessage] = Json.format

implicit class MatcherNodeExtSync(m: Node) extends Matchers {
implicit class MatcherNodeExtSync(m: Node) {

import com.wavesplatform.it.api.AsyncMatcherHttpApi.{MatcherAsyncHttpApi => async}

Expand Down Expand Up @@ -93,21 +92,24 @@ object SyncMatcherHttpApi extends Assertions {
waitTime: Duration = OrderRequestAwaitTime): Boolean =
Await.result(async(m).expectIncorrectOrderPlacement(order, expectedStatusCode, expectedStatus), waitTime)

def cancelOrder(sender: Node,
assetPair: AssetPair,
orderId: Option[String],
timestamp: Option[Long] = None,
waitTime: Duration = OrderRequestAwaitTime): MatcherStatusResponse =
cancelOrder(sender.privateKey, assetPair, orderId, timestamp, waitTime)

def cancelOrder(sender: PrivateKeyAccount,
assetPair: AssetPair,
orderId: Option[String],
timestamp: Option[Long],
waitTime: Duration): MatcherStatusResponse =
Await.result(async(m).cancelOrder(sender, assetPair, orderId, timestamp), waitTime)

def cancelAllOrders(sender: Node, timestamp: Option[Long] = None, waitTime: Duration = OrderRequestAwaitTime): MatcherStatusResponse =
def expectCancelRejected(sender: PrivateKeyAccount, assetPair: AssetPair, orderId: String, waitTime: Duration = OrderRequestAwaitTime): Unit =
Await.result(async(m).expectCancelRejected(sender, assetPair, orderId), waitTime)

def cancelOrder(sender: Node, assetPair: AssetPair, orderId: String, waitTime: Duration = OrderRequestAwaitTime): MatcherStatusResponse =
cancelOrder(sender.privateKey, assetPair, orderId, waitTime)

def cancelOrder(sender: PrivateKeyAccount, assetPair: AssetPair, orderId: String, waitTime: Duration): MatcherStatusResponse =
Await.result(async(m).cancelOrder(sender, assetPair, orderId), waitTime)

def cancelOrdersForPair(sender: Node,
assetPair: AssetPair,
timestamp: Long = System.currentTimeMillis(),
waitTime: Duration = OrderRequestAwaitTime): MatcherStatusResponse =
Await.result(async(m).cancelOrdersForPair(sender, assetPair, timestamp), waitTime)

def cancelAllOrders(sender: Node,
timestamp: Long = System.currentTimeMillis(),
waitTime: Duration = OrderRequestAwaitTime): MatcherStatusResponse =
Await.result(async(m).cancelAllOrders(sender, timestamp), waitTime)

def cancelOrderWithApiKey(orderId: String, waitTime: Duration = OrderRequestAwaitTime): MatcherStatusResponse =
Expand Down
Loading

0 comments on commit 8a02718

Please sign in to comment.