<commit_before>package com.wavesplatform.it.sync

import com.wavesplatform.it.api.SyncHttpApi._
import com.wavesplatform.it.transactions.BaseTransactionSuite
import com.wavesplatform.it.util._
import org.scalatest.CancelAfterFailure
import play.api.libs.json.{JsNumber, JsObject, Json}
import scorex.api.http.assets.SignedMassTransferRequest
import scorex.crypto.encode.Base58
import scorex.transaction.assets.MassTransferTransaction.{MaxTransferCount, Transfer}
import scorex.transaction.assets.{MassTransferTransaction, TransferTransaction}

import scala.concurrent.duration._
import scala.util.Random

class MassTransferTransactionSuite extends BaseTransactionSuite with CancelAfterFailure {

  private val assetQuantity              = 100.waves
  private val transferAmount             = 5.waves
  private val leasingAmount              = 5.waves
  private val leasingFee                 = 0.003.waves
  private val transferFee                = notMiner.settings.feesSettings.fees(TransferTransaction.typeId)(0).fee
  private val issueFee                   = 1.waves
  private val massTransferFeePerTransfer = notMiner.settings.feesSettings.fees(MassTransferTransaction.typeId)(0).fee

  private def calcFee(numberOfRecipients: Int): Long = {
    transferFee + numberOfRecipients * massTransferFeePerTransfer
  }

  private def fakeSignature = Base58.encode(Array.fill(64)(Random.nextInt.toByte))

  test("asset mass transfer changes asset balances and sender's.waves balance is decreased by fee.") {

    val (balance1, eff1) = notMiner.accountBalances(firstAddress)
    val (balance2, eff2) = notMiner.accountBalances(secondAddress)

    val transfers = List(Transfer(secondAddress, transferAmount))
    val assetId   = sender.issue(firstAddress, "name", "description", assetQuantity, 8, reissuable = false, issueFee).id
    nodes.waitForHeightAriseAndTxPresent(assetId)

    val massTransferTransactionFee = calcFee(transfers.size)
    val transferId                 = sender.massTransfer(firstAddress, transfers, massTransferTransactionFee, Some(assetId)).id
    nodes.waitForHeightAriseAndTxPresent(transferId)

    notMiner.assertBalances(firstAddress, balance1 - massTransferTransactionFee - issueFee, eff1 - massTransferTransactionFee - issueFee)
    notMiner.assertAssetBalance(firstAddress, assetId, assetQuantity - transferAmount)
    notMiner.assertBalances(secondAddress, balance2, eff2)
    notMiner.assertAssetBalance(secondAddress, assetId, transferAmount)
  }

  test("waves mass transfer changes waves balances") {

    val (balance1, eff1) = notMiner.accountBalances(firstAddress)
    val (balance2, eff2) = notMiner.accountBalances(secondAddress)
    val (balance3, eff3) = notMiner.accountBalances(thirdAddress)
    val transfers        = List(Transfer(secondAddress, transferAmount), Transfer(thirdAddress, 2 * transferAmount))

    val massTransferTransactionFee = calcFee(transfers.size)
    val transferId                 = sender.massTransfer(firstAddress, transfers, massTransferTransactionFee).id
    nodes.waitForHeightAriseAndTxPresent(transferId)

    notMiner.assertBalances(firstAddress,
                            balance1 - massTransferTransactionFee - 3 * transferAmount,
                            eff1 - massTransferTransactionFee - 3 * transferAmount)
    notMiner.assertBalances(secondAddress, balance2 + transferAmount, eff2 + transferAmount)
    notMiner.assertBalances(thirdAddress, balance3 + 2 * transferAmount, eff3 + 2 * transferAmount)
  }

  test("can not make mass transfer without having enough waves") {
    val (balance1, eff1) = notMiner.accountBalances(firstAddress)
    val (balance2, eff2) = notMiner.accountBalances(secondAddress)
    val transfers        = List(Transfer(secondAddress, balance1 / 2), Transfer(thirdAddress, balance1 / 2))

    assertBadRequestAndResponse(sender.massTransfer(firstAddress, transfers, calcFee(transfers.size)), "negative waves balance")

    nodes.waitForHeightAraise()
    notMiner.assertBalances(firstAddress, balance1, eff1)
    notMiner.assertBalances(secondAddress, balance2, eff2)
  }

  test("can not make mass transfer when fee less then mininal ") {

    val (balance1, eff1) = notMiner.accountBalances(firstAddress)
    val (balance2, eff2) = notMiner.accountBalances(secondAddress)
    val transfers        = List(Transfer(secondAddress, transferAmount))

    assertBadRequestAndResponse(sender.massTransfer(firstAddress, transfers, transferFee), "Fee .* does not exceed minimal value")
    nodes.waitForHeightAraise()
    notMiner.assertBalances(firstAddress, balance1, eff1)
    notMiner.assertBalances(secondAddress, balance2, eff2)
  }

  test("can not make mass transfer without having enough of effective balance") {
    val (balance1, eff1) = notMiner.accountBalances(firstAddress)
    val (balance2, eff2) = notMiner.accountBalances(secondAddress)
    val transfers        = List(Transfer(secondAddress, balance1 - leasingFee - transferFee))

    val leaseTxId = sender.lease(firstAddress, secondAddress, leasingAmount, leasingFee).id
    nodes.waitForHeightAriseAndTxPresent(leaseTxId)

    assertBadRequestAndResponse(sender.massTransfer(firstAddress, transfers, calcFee(transfers.size)), "negative waves balance")
    nodes.waitForHeightAraise()
    notMiner.assertBalances(firstAddress, balance1 - leasingFee, eff1 - leasingAmount - leasingFee)
    notMiner.assertBalances(secondAddress, balance2, eff2 + leasingAmount)
  }

  test("invalid transfer should not be in UTX or blockchain") {
    import scorex.transaction.assets.TransferTransaction.MaxAttachmentSize

    def request(version: Byte = MassTransferTransaction.Version,
                transfers: List[Transfer] = List(Transfer(secondAddress, transferAmount)),
                fee: Long = calcFee(1),
                timestamp: Long = System.currentTimeMillis,
                attachment: Array[Byte] = Array.emptyByteArray) = {
      val txEi = for {
        parsedTransfers <- MassTransferTransaction.parseTransfersList(transfers)
        tx <- MassTransferTransaction.selfSigned(version, None, sender.privateKey, parsedTransfers, timestamp, fee, attachment)
      } yield tx

      val (signature, idOpt) = txEi.fold(
        _ => (List(fakeSignature), None),
        tx => (tx.proofs.base58().toList, Some(tx.id())))

      val req = SignedMassTransferRequest(version,
        Base58.encode(sender.publicKey.publicKey),
        None, transfers, fee, timestamp,
        attachment.headOption.map(_ => Base58.encode(attachment)),
        signature)

      (req, idOpt)
    }<commit_msg>NODE-615 Fixed rebase issues<commit_after>package com.wavesplatform.it.sync

import com.wavesplatform.it.api.SyncHttpApi._
import com.wavesplatform.it.transactions.BaseTransactionSuite
import com.wavesplatform.it.util._
import org.scalatest.CancelAfterFailure
import play.api.libs.json.{JsNumber, JsObject, Json}
import scorex.api.http.assets.SignedMassTransferRequest
import scorex.crypto.encode.Base58
import scorex.transaction.assets.MassTransferTransaction.{MaxTransferCount, Transfer}
import scorex.transaction.assets.{MassTransferTransaction, TransferTransaction}

import scala.concurrent.duration._
import scala.util.Random

class MassTransferTransactionSuite extends BaseTransactionSuite with CancelAfterFailure {

  private val assetQuantity              = 100.waves
  private val transferAmount             = 5.waves
  private val leasingAmount              = 5.waves
  private val leasingFee                 = 0.003.waves
  private val transferFee                = notMiner.settings.feesSettings.fees(TransferTransaction.typeId)(0).fee
  private val issueFee                   = 1.waves
  private val massTransferFeePerTransfer = notMiner.settings.feesSettings.fees(MassTransferTransaction.typeId)(0).fee

  private def calcFee(numberOfRecipients: Int): Long = {
    transferFee + numberOfRecipients * massTransferFeePerTransfer
  }

  private def fakeSignature = Base58.encode(Array.fill(64)(Random.nextInt.toByte))

  test("asset mass transfer changes asset balances and sender's.waves balance is decreased by fee.") {

    val (balance1, eff1) = notMiner.accountBalances(firstAddress)
    val (balance2, eff2) = notMiner.accountBalances(secondAddress)

    val transfers = List(Transfer(secondAddress, transferAmount))
    val assetId   = sender.issue(firstAddress, "name", "description", assetQuantity, 8, reissuable = false, issueFee).id
    nodes.waitForHeightAriseAndTxPresent(assetId)

    val massTransferTransactionFee = calcFee(transfers.size)
    val transferId                 = sender.massTransfer(firstAddress, transfers, massTransferTransactionFee, Some(assetId)).id
    nodes.waitForHeightAriseAndTxPresent(transferId)

    notMiner.assertBalances(firstAddress, balance1 - massTransferTransactionFee - issueFee, eff1 - massTransferTransactionFee - issueFee)
    notMiner.assertAssetBalance(firstAddress, assetId, assetQuantity - transferAmount)
    notMiner.assertBalances(secondAddress, balance2, eff2)
    notMiner.assertAssetBalance(secondAddress, assetId, transferAmount)
  }

  test("waves mass transfer changes waves balances") {

    val (balance1, eff1) = notMiner.accountBalances(firstAddress)
    val (balance2, eff2) = notMiner.accountBalances(secondAddress)
    val (balance3, eff3) = notMiner.accountBalances(thirdAddress)
    val transfers        = List(Transfer(secondAddress, transferAmount), Transfer(thirdAddress, 2 * transferAmount))

    val massTransferTransactionFee = calcFee(transfers.size)
    val transferId                 = sender.massTransfer(firstAddress, transfers, massTransferTransactionFee).id
    nodes.waitForHeightAriseAndTxPresent(transferId)

    notMiner.assertBalances(firstAddress,
                            balance1 - massTransferTransactionFee - 3 * transferAmount,
                            eff1 - massTransferTransactionFee - 3 * transferAmount)
    notMiner.assertBalances(secondAddress, balance2 + transferAmount, eff2 + transferAmount)
    notMiner.assertBalances(thirdAddress, balance3 + 2 * transferAmount, eff3 + 2 * transferAmount)
  }

  test("can not make mass transfer without having enough waves") {
    val (balance1, eff1) = notMiner.accountBalances(firstAddress)
    val (balance2, eff2) = notMiner.accountBalances(secondAddress)
    val transfers        = List(Transfer(secondAddress, balance1 / 2), Transfer(thirdAddress, balance1 / 2))

    assertBadRequestAndResponse(sender.massTransfer(firstAddress, transfers, calcFee(transfers.size)), "negative waves balance")

    nodes.waitForHeightAraise()
    notMiner.assertBalances(firstAddress, balance1, eff1)
    notMiner.assertBalances(secondAddress, balance2, eff2)
  }

  test("can not make mass transfer when fee less then mininal ") {

    val (balance1, eff1) = notMiner.accountBalances(firstAddress)
    val (balance2, eff2) = notMiner.accountBalances(secondAddress)
    val transfers        = List(Transfer(secondAddress, transferAmount))

    assertBadRequestAndResponse(sender.massTransfer(firstAddress, transfers, transferFee), "Fee .* does not exceed minimal value")
    nodes.waitForHeightAraise()
    notMiner.assertBalances(firstAddress, balance1, eff1)
    notMiner.assertBalances(secondAddress, balance2, eff2)
  }

  test("can not make mass transfer without having enough of effective balance") {
    val (balance1, eff1) = notMiner.accountBalances(firstAddress)
    val (balance2, eff2) = notMiner.accountBalances(secondAddress)
    val transfers        = List(Transfer(secondAddress, balance1 - leasingFee - transferFee))

    val leaseTxId = sender.lease(firstAddress, secondAddress, leasingAmount, leasingFee).id
    nodes.waitForHeightAriseAndTxPresent(leaseTxId)

    assertBadRequestAndResponse(sender.massTransfer(firstAddress, transfers, calcFee(transfers.size)), "negative waves balance")
    nodes.waitForHeightAraise()
    notMiner.assertBalances(firstAddress, balance1 - leasingFee, eff1 - leasingAmount - leasingFee)
    notMiner.assertBalances(secondAddress, balance2, eff2 + leasingAmount)
  }

  test("invalid transfer should not be in UTX or blockchain") {
    import scorex.transaction.assets.TransferTransaction.MaxAttachmentSize

    def request(version: Byte = MassTransferTransaction.version,
                transfers: List[Transfer] = List(Transfer(secondAddress, transferAmount)),
                fee: Long = calcFee(1),
                timestamp: Long = System.currentTimeMillis,
                attachment: Array[Byte] = Array.emptyByteArray) = {
      val txEi = for {
        parsedTransfers <- MassTransferTransaction.parseTransfersList(transfers)
        tx <- MassTransferTransaction.selfSigned(version, None, sender.privateKey, parsedTransfers, timestamp, fee, attachment)
      } yield tx

      val (signature, idOpt) = txEi.fold(
        _ => (List(fakeSignature), None),
        tx => (tx.proofs.base58().toList, Some(tx.id())))

      val req = SignedMassTransferRequest(version,
        Base58.encode(sender.publicKey.publicKey),
        None, transfers, fee, timestamp,
        attachment.headOption.map(_ => Base58.encode(attachment)),
        signature)

      (req, idOpt)
    }
{'fraction_non_alphanumeric': 0.08706562238613033, 'fraction_numerical': 0.012394494715230782, 'mean_word_length': 4.229423459244533, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 9, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6080970', 'n_tokens_mistral': 3784, 'n_tokens_neox': 3609, 'n_words': 767}