Skip to content

Commit

Permalink
MassTransfer Proofs: added proofs to SignedMassTransferRequest
Browse files Browse the repository at this point in the history
  • Loading branch information
peterz committed Feb 22, 2018
1 parent 0ddb0d8 commit 5ded053
Show file tree
Hide file tree
Showing 6 changed files with 19 additions and 14 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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") {
Expand All @@ -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]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ class MassTransferTransactionSuite extends BaseTransactionSuite with CancelAfter
fee,
timestamp,
attachment.headOption.map(_ => Base58.encode(attachment)),
proofs.base58()
proofs.base58().toList
)
}
}
7 changes: 4 additions & 3 deletions src/main/scala/scorex/api/http/BroadcastRequest.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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)) }
}
Original file line number Diff line number Diff line change
@@ -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}
Expand All @@ -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)
Expand Down
4 changes: 2 additions & 2 deletions src/main/scala/scorex/transaction/Proofs.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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()

Expand Down
2 changes: 0 additions & 2 deletions src/main/scala/scorex/transaction/TransactionParser.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down

0 comments on commit 5ded053

Please sign in to comment.