From 5ded053ed7946a90008a9ee1324c40f24dffbdee Mon Sep 17 00:00:00 2001 From: peterz Date: Thu, 22 Feb 2018 16:12:59 +0300 Subject: [PATCH] MassTransfer Proofs: added proofs to SignedMassTransferRequest --- .../com/wavesplatform/it/TransactionsApiSuite.scala | 11 ++++++++--- .../transactions/MassTransferTransactionSuite.scala | 2 +- src/main/scala/scorex/api/http/BroadcastRequest.scala | 7 ++++--- .../api/http/assets/SignedMassTransferRequest.scala | 7 ++++--- src/main/scala/scorex/transaction/Proofs.scala | 4 ++-- .../scala/scorex/transaction/TransactionParser.scala | 2 -- 6 files changed, 19 insertions(+), 14 deletions(-) diff --git a/it/src/test/scala/com/wavesplatform/it/TransactionsApiSuite.scala b/it/src/test/scala/com/wavesplatform/it/TransactionsApiSuite.scala index a8beb5b794d..27e3e8409ea 100644 --- a/it/src/test/scala/com/wavesplatform/it/TransactionsApiSuite.scala +++ b/it/src/test/scala/com/wavesplatform/it/TransactionsApiSuite.scala @@ -141,7 +141,8 @@ class TransactionsApiSuite extends BaseTransactionSuite { "sender" -> firstAddress, "transfers" -> Json.toJson(Seq(Transfer(secondAddress, 1.waves), Transfer(thirdAddress, 2.waves))), "fee" -> 200000, - "attachment" -> Base58.encode("masspay".getBytes))) + "attachment" -> Base58.encode("masspay".getBytes)), + usesProofs = true) } test("/transactions/sign should produce lease/cancel transactions that are good for /transactions/broadcast") { @@ -167,12 +168,16 @@ class TransactionsApiSuite extends BaseTransactionSuite { "fee" -> 100000)) } - private def signAndBroadcast(json: JsObject): String = { + private def signAndBroadcast(json: JsObject, usesProofs: Boolean = false): String = { val f = for { rs <- sender.postJsonWithApiKey("/transactions/sign", json) _ = assert(rs.getStatusCode == HttpConstants.ResponseStatusCodes.OK_200) body = Json.parse(rs.getResponseBody) - _ = assert((body \ "signature").as[String].nonEmpty) + signed: Boolean = if (usesProofs) { + val proofs = (body \ "proofs").as[Seq[String]] + proofs.lengthCompare(1) == 0 && proofs.head.nonEmpty + } else (body \ "signature").as[String].nonEmpty + _ = assert(signed) rb <- sender.postJson("/transactions/broadcast", body) _ = assert(rb.getStatusCode == HttpConstants.ResponseStatusCodes.OK_200) id = (Json.parse(rb.getResponseBody) \ "id").as[String] diff --git a/it/src/test/scala/com/wavesplatform/it/transactions/MassTransferTransactionSuite.scala b/it/src/test/scala/com/wavesplatform/it/transactions/MassTransferTransactionSuite.scala index 5bc721767e0..73e24883b9d 100644 --- a/it/src/test/scala/com/wavesplatform/it/transactions/MassTransferTransactionSuite.scala +++ b/it/src/test/scala/com/wavesplatform/it/transactions/MassTransferTransactionSuite.scala @@ -150,7 +150,7 @@ class MassTransferTransactionSuite extends BaseTransactionSuite with CancelAfter fee, timestamp, attachment.headOption.map(_ => Base58.encode(attachment)), - proofs.base58() + proofs.base58().toList ) } } diff --git a/src/main/scala/scorex/api/http/BroadcastRequest.scala b/src/main/scala/scorex/api/http/BroadcastRequest.scala index 36a78d922de..ee69c509bba 100755 --- a/src/main/scala/scorex/api/http/BroadcastRequest.scala +++ b/src/main/scala/scorex/api/http/BroadcastRequest.scala @@ -2,15 +2,16 @@ package scorex.api.http import com.wavesplatform.state2.ByteStr import scorex.transaction.ValidationError +import scorex.transaction.ValidationError.Validation trait BroadcastRequest { - protected def parseBase58(v: String, error: String, maxLength: Int): Either[ValidationError, ByteStr] = + protected def parseBase58(v: String, error: String, maxLength: Int): Validation[ByteStr] = if (v.length > maxLength) Left(ValidationError.GenericError(error)) else ByteStr.decodeBase58(v).toOption.toRight(ValidationError.GenericError(error)) - protected def parseBase58(v: Option[String], error: String, maxLength: Int): Either[ValidationError, ByteStr] = + protected def parseBase58(v: Option[String], error: String, maxLength: Int): Validation[ByteStr] = v.fold[Either[ValidationError, ByteStr]](Right(ByteStr(Array.emptyByteArray)))(_v => parseBase58(_v, error, maxLength)) - protected def parseBase58ToOption(v: Option[String], error: String, maxLength: Int): Either[ValidationError, Option[ByteStr]] = + protected def parseBase58ToOption(v: Option[String], error: String, maxLength: Int): Validation[Option[ByteStr]] = v.fold[Either[ValidationError, Option[ByteStr]]](Right(None)) { s => parseBase58(s, error, maxLength).map(b => Option(b)) } } diff --git a/src/main/scala/scorex/api/http/assets/SignedMassTransferRequest.scala b/src/main/scala/scorex/api/http/assets/SignedMassTransferRequest.scala index a0cc57d66b8..d182b190a78 100644 --- a/src/main/scala/scorex/api/http/assets/SignedMassTransferRequest.scala +++ b/src/main/scala/scorex/api/http/assets/SignedMassTransferRequest.scala @@ -1,10 +1,10 @@ package scorex.api.http.assets +import cats.implicits._ import io.swagger.annotations.{ApiModel, ApiModelProperty} import play.api.libs.json.{Format, Json} import scorex.account.PublicKeyAccount import scorex.api.http.BroadcastRequest -import scorex.transaction.TransactionParser.MaxProofsStringLength import scorex.transaction.assets.MassTransferTransaction.Transfer import scorex.transaction.assets.{MassTransferTransaction, TransferTransaction} import scorex.transaction.{AssetIdStringLength, Proofs, ValidationError} @@ -27,11 +27,12 @@ case class SignedMassTransferRequest(@ApiModelProperty(value = "Base58 encoded s @ApiModelProperty(value = "Base58 encoded attachment") attachment: Option[String], @ApiModelProperty(required = true) - proofs: String) extends BroadcastRequest { + proofs: List[String]) extends BroadcastRequest { def toTx: Either[ValidationError, MassTransferTransaction] = for { _sender <- PublicKeyAccount.fromBase58String(senderPublicKey) _assetId <- parseBase58ToOption(assetId.filter(_.length > 0), "invalid.assetId", AssetIdStringLength) - _proofs <- parseBase58(proofs, "invalid proof", MaxProofsStringLength).flatMap(bstr => Proofs.fromBytes(bstr.arr)) + _proofBytes <- proofs.traverse(s => parseBase58(s, "invalid proof", Proofs.MaxProofSize)) + _proofs <- Proofs.create(_proofBytes) _attachment <- parseBase58(attachment.filter(_.length > 0), "invalid.attachment", TransferTransaction.MaxAttachmentStringSize) _transfers <- MassTransferTransaction.parseTransfersList(transfers) t <- MassTransferTransaction.create(Proofs.Version, _assetId, _sender, _transfers, timestamp, fee, _attachment.arr, _proofs) diff --git a/src/main/scala/scorex/transaction/Proofs.scala b/src/main/scala/scorex/transaction/Proofs.scala index 0a1420c9a0a..44c5ca464c3 100644 --- a/src/main/scala/scorex/transaction/Proofs.scala +++ b/src/main/scala/scorex/transaction/Proofs.scala @@ -10,14 +10,14 @@ import scala.util.Try case class Proofs private(proofs: Seq[ByteStr]) { val bytes: Coeval[Array[Byte]] = Coeval.evalOnce(Proofs.Version +: Deser.serializeArrays(proofs.map(_.arr))) - val base58: Coeval[String] = Coeval.evalOnce(Base58.encode(bytes())) + val base58: Coeval[Seq[String]] = Coeval.evalOnce(proofs.map(p => Base58.encode(p.arr))) } object Proofs { val Version = 1: Byte val MaxProofs = 8 - val MaxProofSize = 64 + val MaxProofSize = 512 lazy val empty = create(Seq.empty).explicitGet() diff --git a/src/main/scala/scorex/transaction/TransactionParser.scala b/src/main/scala/scorex/transaction/TransactionParser.scala index 94bb50d964c..425a93bd8bb 100644 --- a/src/main/scala/scorex/transaction/TransactionParser.scala +++ b/src/main/scala/scorex/transaction/TransactionParser.scala @@ -34,8 +34,6 @@ object TransactionParser { val SignatureStringLength: Int = base58Length(SignatureLength) val KeyLength = 32 val KeyStringLength: Int = base58Length(KeyLength) - val MaxProofsLength = 8 * 512 - val MaxProofsStringLength: Int = base58Length(MaxProofsLength) def parseBytes(data: Array[Byte]): Try[Transaction] = data.head match {