diff --git a/generator/src/main/scala/com.wavesplatform.generator/NarrowTransactionGenerator.scala b/generator/src/main/scala/com.wavesplatform.generator/NarrowTransactionGenerator.scala index ce9a214c23c..6ba471c501b 100644 --- a/generator/src/main/scala/com.wavesplatform.generator/NarrowTransactionGenerator.scala +++ b/generator/src/main/scala/com.wavesplatform.generator/NarrowTransactionGenerator.scala @@ -11,7 +11,7 @@ import scorex.transaction.assets.MassTransferTransaction.ParsedTransfer import scorex.transaction.assets._ import scorex.transaction.assets.exchange.{AssetPair, ExchangeTransaction, Order} import scorex.transaction.lease.{LeaseCancelTransaction, LeaseTransaction} -import scorex.transaction.{CreateAliasTransaction, Transaction, ValidationError} +import scorex.transaction.{CreateAliasTransaction, Proofs, Transaction, ValidationError} import scorex.utils.LoggerFacade import scala.concurrent.duration._ @@ -140,7 +140,7 @@ class NarrowTransactionGenerator(settings: Settings, }) } else Some(randomFrom(accounts).get, None) senderAndAssetOpt.flatMap { case (sender, asset) => - logOption(MassTransferTransaction.create(asset, sender, transfers.toList, ts, moreThatStandartFee, + logOption(MassTransferTransaction.selfSigned(Proofs.Version, asset, sender, transfers.toList, ts, moreThatStandartFee, Array.fill(r.nextInt(100))(r.nextInt().toByte))) } } diff --git a/generator/src/main/scala/com.wavesplatform.generator/utils/Gen.scala b/generator/src/main/scala/com.wavesplatform.generator/utils/Gen.scala index d4042031c38..e47e6f26031 100644 --- a/generator/src/main/scala/com.wavesplatform.generator/utils/Gen.scala +++ b/generator/src/main/scala/com.wavesplatform.generator/utils/Gen.scala @@ -6,7 +6,7 @@ import com.wavesplatform.generator.utils.Implicits._ import scorex.account.{Address, PrivateKeyAccount} import scorex.transaction.assets.MassTransferTransaction.ParsedTransfer import scorex.transaction.assets.{MassTransferTransaction, TransferTransaction} -import scorex.transaction.{Transaction, TransactionParser} +import scorex.transaction.{Proofs, Transaction, TransactionParser} object Gen { private def random = ThreadLocalRandom.current @@ -40,7 +40,7 @@ object Gen { senderGen.zip(transferCountGen).map { case (sender, count) => val transfers = List.tabulate(count)(_ => ParsedTransfer(recipientGen.next(), amountGen.next())) val fee = 100000 + count * 50000 - MassTransferTransaction.create(None, sender, transfers, System.currentTimeMillis, fee, Array.emptyByteArray) + MassTransferTransaction.selfSigned(Proofs.Version, None, sender, transfers, System.currentTimeMillis, fee, Array.emptyByteArray) }.collect { case Right(tx) => tx } } 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 34f649bea45..73e24883b9d 100644 --- a/it/src/test/scala/com/wavesplatform/it/transactions/MassTransferTransactionSuite.scala +++ b/it/src/test/scala/com/wavesplatform/it/transactions/MassTransferTransactionSuite.scala @@ -6,10 +6,12 @@ import org.scalatest.CancelAfterFailure import scorex.account.AddressOrAlias import scorex.api.http.assets.SignedMassTransferRequest import scorex.crypto.encode.Base58 +import scorex.transaction.Proofs import scorex.transaction.TransactionParser.TransactionType import scorex.transaction.assets.MassTransferTransaction import scorex.transaction.assets.MassTransferTransaction.MaxTransferCount import scorex.transaction.assets.MassTransferTransaction.{ParsedTransfer, Transfer} + import scala.concurrent.duration._ import scorex.transaction.assets.TransferTransaction.MaxAttachmentSize @@ -102,8 +104,8 @@ class MassTransferTransactionSuite extends BaseTransactionSuite with CancelAfter test("invalid transfer should not be in UTX or blockchain") { import scorex.transaction.assets.MassTransferTransaction.MaxTransferCount val address2 = AddressOrAlias.fromString(secondAddress).right.get - val valid = MassTransferTransaction.create( - None, sender.privateKey, + val valid = MassTransferTransaction.selfSigned( + Proofs.Version, None, sender.privateKey, List(ParsedTransfer(address2, transferAmount)), System.currentTimeMillis, calcFee(1), Array.emptyByteArray).right.get @@ -128,7 +130,6 @@ class MassTransferTransactionSuite extends BaseTransactionSuite with CancelAfter test("huuuge transactions are allowed") { - val (balance1, eff1) = notMiner.accountBalances(firstAddress) val fee = calcFee(MaxTransferCount) val amount = (balance1 - fee) / MaxTransferCount @@ -138,8 +139,6 @@ class MassTransferTransactionSuite extends BaseTransactionSuite with CancelAfter nodes.waitForHeightAraiseAndTxPresent(transferId) notMiner.assertBalances(firstAddress, balance1 - fee, eff1 - fee) - - } private def createSignedMassTransferRequest(tx: MassTransferTransaction): SignedMassTransferRequest = { @@ -151,7 +150,7 @@ class MassTransferTransactionSuite extends BaseTransactionSuite with CancelAfter fee, timestamp, attachment.headOption.map(_ => Base58.encode(attachment)), - signature.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 3aa3ca877fc..d182b190a78 100644 --- a/src/main/scala/scorex/api/http/assets/SignedMassTransferRequest.scala +++ b/src/main/scala/scorex/api/http/assets/SignedMassTransferRequest.scala @@ -1,13 +1,13 @@ 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.SignatureStringLength import scorex.transaction.assets.MassTransferTransaction.Transfer import scorex.transaction.assets.{MassTransferTransaction, TransferTransaction} -import scorex.transaction.{AssetIdStringLength, ValidationError} +import scorex.transaction.{AssetIdStringLength, Proofs, ValidationError} object SignedMassTransferRequest { implicit val jsonFormat: Format[SignedMassTransferRequest] = Json.format @@ -27,13 +27,14 @@ case class SignedMassTransferRequest(@ApiModelProperty(value = "Base58 encoded s @ApiModelProperty(value = "Base58 encoded attachment") attachment: Option[String], @ApiModelProperty(required = true) - signature: 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) - _signature <- parseBase58(signature, "invalid.signature", SignatureStringLength) + _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(_assetId, _sender, _transfers, timestamp, fee, _attachment.arr, _signature) + t <- MassTransferTransaction.create(Proofs.Version, _assetId, _sender, _transfers, timestamp, fee, _attachment.arr, _proofs) } yield t } diff --git a/src/main/scala/scorex/transaction/Proofs.scala b/src/main/scala/scorex/transaction/Proofs.scala index f05cc3a4130..44c5ca464c3 100644 --- a/src/main/scala/scorex/transaction/Proofs.scala +++ b/src/main/scala/scorex/transaction/Proofs.scala @@ -2,6 +2,7 @@ package scorex.transaction import com.wavesplatform.state2._ import monix.eval.Coeval +import scorex.crypto.encode.Base58 import scorex.serialization.Deser import scorex.transaction.ValidationError.GenericError @@ -9,13 +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[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/TransactionFactory.scala b/src/main/scala/scorex/transaction/TransactionFactory.scala index 09395308ffb..eff475b27a8 100644 --- a/src/main/scala/scorex/transaction/TransactionFactory.scala +++ b/src/main/scala/scorex/transaction/TransactionFactory.scala @@ -33,7 +33,8 @@ object TransactionFactory { for { senderPrivateKey <- wallet.findWallet(request.sender) transfers <- MassTransferTransaction.parseTransfersList(request.transfers) - tx <- MassTransferTransaction.create( + tx <- MassTransferTransaction.selfSigned( + Proofs.Version, request.assetId.map(s => ByteStr.decodeBase58(s).get), senderPrivateKey, transfers, diff --git a/src/main/scala/scorex/transaction/assets/MassTransferTransaction.scala b/src/main/scala/scorex/transaction/assets/MassTransferTransaction.scala index 35cc728212c..fe46d2b11d5 100644 --- a/src/main/scala/scorex/transaction/assets/MassTransferTransaction.scala +++ b/src/main/scala/scorex/transaction/assets/MassTransferTransaction.scala @@ -3,7 +3,7 @@ package scorex.transaction.assets import cats.implicits._ import com.google.common.primitives.{Bytes, Longs, Shorts} import com.wavesplatform.crypto -import com.wavesplatform.state2.ByteStr +import com.wavesplatform.state2._ import monix.eval.Coeval import play.api.libs.json.{Format, JsObject, JsValue, Json} import scorex.account.{AddressOrAlias, PrivateKeyAccount, PublicKeyAccount} @@ -16,13 +16,14 @@ import scorex.transaction.assets.MassTransferTransaction.{ParsedTransfer, toJson import scala.util.{Either, Failure, Success, Try} -case class MassTransferTransaction private(assetId: Option[AssetId], +case class MassTransferTransaction private(version: Byte, + assetId: Option[AssetId], sender: PublicKeyAccount, transfers: List[ParsedTransfer], timestamp: Long, fee: Long, attachment: Array[Byte], - signature: ByteStr) extends SignedTransaction with FastHashId { + proofs: Proofs) extends ProvenTransaction with FastHashId { override val transactionType: TransactionType.Value = TransactionType.MassTransferTransaction override val assetFee: (Option[AssetId], Long) = (None, fee) @@ -35,6 +36,7 @@ case class MassTransferTransaction private(assetId: Option[AssetId], Bytes.concat( Array(transactionType.id.toByte), + Array(version), sender.publicKey, assetIdBytes, Shorts.toByteArray(transfers.size.toShort), @@ -58,7 +60,7 @@ case class MassTransferTransaction private(assetId: Option[AssetId], def compactJson(recipient: AddressOrAlias): JsObject = jsonBase() ++ Json.obj( "transfers" -> toJson(transfers.filter(_.address == recipient))) - override val bytes: Coeval[Array[Byte]] = Coeval.evalOnce(Bytes.concat(bodyBytes(), signature.arr)) + override val bytes: Coeval[Array[Byte]] = Coeval.evalOnce(Bytes.concat(bodyBytes(), proofs.bytes())) } object MassTransferTransaction { @@ -71,8 +73,9 @@ object MassTransferTransaction { implicit val transferFormat: Format[Transfer] = Json.format def parseTail(bytes: Array[Byte]): Try[MassTransferTransaction] = Try { - val sender = PublicKeyAccount(bytes.slice(0, KeyLength)) - val (assetIdOpt, s0) = Deser.parseByteArrayOption(bytes, KeyLength, AssetIdLength) + val version = bytes(0) + val sender = PublicKeyAccount(bytes.slice(1, KeyLength + 1)) + val (assetIdOpt, s0) = Deser.parseByteArrayOption(bytes, KeyLength + 1, AssetIdLength) val transferCount = Shorts.fromByteArray(bytes.slice(s0, s0 + 2)) def readTransfer(offset: Int): (Validation[ParsedTransfer], Int) = { @@ -92,20 +95,21 @@ object MassTransferTransaction { transfers <- transfersList.map { case (ei, _) => ei }.sequence timestamp = Longs.fromByteArray(bytes.slice(s1, s1 + 8)) feeAmount = Longs.fromByteArray(bytes.slice(s1 + 8, s1 + 16)) - (attachment, s2) = Deser.parseArraySize(bytes, s1 + 16) - signature = ByteStr(bytes.slice(s2, s2 + SignatureLength)) - mtt <- MassTransferTransaction.create(assetIdOpt.map(ByteStr(_)), sender, transfers, timestamp, feeAmount, attachment, signature) + (attachment, attachEnd) = Deser.parseArraySize(bytes, s1 + 16) + proofs <- Proofs.fromBytes(bytes.drop(attachEnd)) + mtt <- MassTransferTransaction.create(version, assetIdOpt.map(ByteStr(_)), sender, transfers, timestamp, feeAmount, attachment, proofs) } yield mtt tx.fold(left => Failure(new Exception(left.toString)), right => Success(right)) }.flatten - def create(assetId: Option[AssetId], + def create(version: Byte, + assetId: Option[AssetId], sender: PublicKeyAccount, transfers: List[ParsedTransfer], timestamp: Long, feeAmount: Long, attachment: Array[Byte], - signature: ByteStr): Either[ValidationError, MassTransferTransaction] = { + proofs: Proofs): Either[ValidationError, MassTransferTransaction] = { Try { transfers.map(_.amount).fold(feeAmount)(Math.addExact) }.fold( @@ -120,19 +124,20 @@ object MassTransferTransaction { } else if (feeAmount <= 0) { Left(ValidationError.InsufficientFee) } else { - Right(MassTransferTransaction(assetId, sender, transfers, timestamp, feeAmount, attachment, signature)) + Right(MassTransferTransaction(version, assetId, sender, transfers, timestamp, feeAmount, attachment, proofs)) } ) } - def create(assetId: Option[AssetId], - sender: PrivateKeyAccount, - transfers: List[ParsedTransfer], - timestamp: Long, - feeAmount: Long, - attachment: Array[Byte]): Either[ValidationError, MassTransferTransaction] = { - create(assetId, sender, transfers, timestamp, feeAmount, attachment, ByteStr.empty).right.map { unsigned => - unsigned.copy(signature = ByteStr(crypto.sign(sender, unsigned.bodyBytes()))) + def selfSigned(version: Byte, + assetId: Option[AssetId], + sender: PrivateKeyAccount, + transfers: List[ParsedTransfer], + timestamp: Long, + feeAmount: Long, + attachment: Array[Byte]): Either[ValidationError, MassTransferTransaction] = { + create(version, assetId, sender, transfers, timestamp, feeAmount, attachment, Proofs.empty).right.map { unsigned => + unsigned.copy(proofs = Proofs.create(Seq(ByteStr(crypto.sign(sender, unsigned.bodyBytes())))).explicitGet()) } } diff --git a/src/main/scala/scorex/transaction/assets/ScriptTransferTransaction.scala b/src/main/scala/scorex/transaction/assets/ScriptTransferTransaction.scala index 16e5c04af1a..a580d688046 100644 --- a/src/main/scala/scorex/transaction/assets/ScriptTransferTransaction.scala +++ b/src/main/scala/scorex/transaction/assets/ScriptTransferTransaction.scala @@ -33,14 +33,14 @@ case class ScriptTransferTransaction private(version: Byte, val amountBytes = Longs.toByteArray(amount) val feeBytes = Longs.toByteArray(fee) - Bytes.concat(Bytes.concat(Array(version), + Bytes.concat(Array(version), sender.publicKey, assetIdBytes, timestampBytes, amountBytes, feeBytes, recipient.bytes.arr, - Deser.serializeArray(attachment))) + Deser.serializeArray(attachment)) } override val json: Coeval[JsObject] = Coeval.evalOnce(jsonBase() ++ Json.obj( diff --git a/src/test/scala/com/wavesplatform/TransactionGen.scala b/src/test/scala/com/wavesplatform/TransactionGen.scala index 4992668b718..2bd8147c3fe 100644 --- a/src/test/scala/com/wavesplatform/TransactionGen.scala +++ b/src/test/scala/com/wavesplatform/TransactionGen.scala @@ -188,7 +188,7 @@ trait TransactionGen extends ScriptGen { def massTransferGeneratorP(sender: PrivateKeyAccount, transfers: List[ParsedTransfer], assetId: Option[AssetId]): Gen[MassTransferTransaction] = for { (_, _, _, _, timestamp, _, feeAmount, attachment) <- transferParamGen - } yield MassTransferTransaction.create(assetId, sender, transfers, timestamp, feeAmount, attachment).right.get + } yield MassTransferTransaction.selfSigned(Proofs.Version, assetId, sender, transfers, timestamp, feeAmount, attachment).right.get def createWavesTransfer(sender: PrivateKeyAccount, recipient: Address, amount: Long, fee: Long, timestamp: Long): Either[ValidationError, TransferTransaction] = @@ -227,7 +227,7 @@ trait TransactionGen extends ScriptGen { amount <- Gen.choose(1L, Long.MaxValue / MaxTransferCount) } yield ParsedTransfer(recipient, amount) recipients <- Gen.listOfN(transferCount, transferGen) - } yield MassTransferTransaction.create(assetId, sender, recipients, timestamp, feeAmount, attachment).right.get + } yield MassTransferTransaction.selfSigned(Proofs.Version, assetId, sender, recipients, timestamp, feeAmount, attachment).right.get }.label("massTransferTransaction") val MinIssueFee = 100000000 diff --git a/src/test/scala/com/wavesplatform/UtxPoolSpecification.scala b/src/test/scala/com/wavesplatform/UtxPoolSpecification.scala index 187fb73ee3f..3c58eefd22d 100755 --- a/src/test/scala/com/wavesplatform/UtxPoolSpecification.scala +++ b/src/test/scala/com/wavesplatform/UtxPoolSpecification.scala @@ -20,7 +20,7 @@ import scorex.transaction.TransactionParser.TransactionType import scorex.transaction.ValidationError.SenderIsBlacklisted import scorex.transaction.assets.MassTransferTransaction.ParsedTransfer import scorex.transaction.assets.{MassTransferTransaction, TransferTransaction} -import scorex.transaction.{FeeCalculator, Transaction} +import scorex.transaction.{FeeCalculator, Proofs, Transaction} import scorex.utils.Time import scala.concurrent.duration._ @@ -70,7 +70,7 @@ class UtxPoolSpecification extends FreeSpec val transfers = recipients.map(r => ParsedTransfer(r.toAddress, amount)) val txs = for { fee <- chooseNum(1, amount) - } yield MassTransferTransaction.create(None, sender, transfers, time.getTimestamp(), fee, Array.empty[Byte]).right.get + } yield MassTransferTransaction.selfSigned(Proofs.Version, None, sender, transfers, time.getTimestamp(), fee, Array.empty[Byte]).right.get txs.label("transferWithRecipient") } diff --git a/src/test/scala/scorex/transaction/MassTransferTransactionSpecification.scala b/src/test/scala/scorex/transaction/MassTransferTransactionSpecification.scala index a005b874876..7d397befc34 100644 --- a/src/test/scala/scorex/transaction/MassTransferTransactionSpecification.scala +++ b/src/test/scala/scorex/transaction/MassTransferTransactionSpecification.scala @@ -39,32 +39,32 @@ class MassTransferTransactionSpecification extends PropSpec with PropertyChecks property("property validation") { import MassTransferTransaction.create forAll(massTransferGen) { - case MassTransferTransaction(assetId, sender, transfers, timestamp, fee, attachment, signature) => + case MassTransferTransaction(version, assetId, sender, transfers, timestamp, fee, attachment, proofs) => val tooManyTransfers = List.fill(MaxTransferCount + 1)(ParsedTransfer(sender.toAddress, 1L)) - val tooManyTransfersEi = create(assetId, sender, tooManyTransfers, timestamp, fee, attachment, signature) + val tooManyTransfersEi = create(version, assetId, sender, tooManyTransfers, timestamp, fee, attachment, proofs) tooManyTransfersEi shouldBe Left(GenericError(s"Number of transfers is greater than $MaxTransferCount")) val negativeTransfer = List(ParsedTransfer(sender.toAddress, -1L)) - val negativeTransferEi = create(assetId, sender, negativeTransfer, timestamp, fee, attachment, signature) + val negativeTransferEi = create(version, assetId, sender, negativeTransfer, timestamp, fee, attachment, proofs) negativeTransferEi shouldBe Left(GenericError("One of the transfers has negative amount")) val oneHalf = Long.MaxValue / 2 + 1 val overflow = List.fill(2)(ParsedTransfer(sender.toAddress, oneHalf)) - val overflowEi = create(assetId, sender, overflow, timestamp, fee, attachment, signature) + val overflowEi = create(version, assetId, sender, overflow, timestamp, fee, attachment, proofs) overflowEi shouldBe Left(ValidationError.OverflowError) val feeOverflow = List(ParsedTransfer(sender.toAddress, oneHalf)) - val feeOverflowEi = create(assetId, sender, feeOverflow, timestamp, oneHalf, attachment, signature) + val feeOverflowEi = create(version, assetId, sender, feeOverflow, timestamp, oneHalf, attachment, proofs) feeOverflowEi shouldBe Left(ValidationError.OverflowError) val longAttachment = Array.fill(TransferTransaction.MaxAttachmentSize + 1)(1: Byte) - val longAttachmentEi = create(assetId, sender, transfers, timestamp, fee, longAttachment, signature) + val longAttachmentEi = create(version, assetId, sender, transfers, timestamp, fee, longAttachment, proofs) longAttachmentEi shouldBe Left(ValidationError.TooBigArray) - val noFeeEi = create(assetId, sender, feeOverflow, timestamp, 0, attachment, signature) + val noFeeEi = create(version, assetId, sender, feeOverflow, timestamp, 0, attachment, proofs) noFeeEi shouldBe Left(ValidationError.InsufficientFee) - val negativeFeeEi = create(assetId, sender, feeOverflow, timestamp, -100, attachment, signature) + val negativeFeeEi = create(version, assetId, sender, feeOverflow, timestamp, -100, attachment, proofs) negativeFeeEi shouldBe Left(ValidationError.InsufficientFee) } }