Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
sss.openstar.test.MultiIdentityTestTransactionSenderInternalClaim.scala Maven / Gradle / Ivy
package sss.openstar.test
import akka.actor.Status.{Failure => FutureFailure}
import akka.actor.{Actor, ActorContext, ActorLogging, ActorRef, Cancellable, Props, ReceiveTimeout}
import akka.pattern.pipe
import sss.ancillary.FutureOps.AwaitResult
import sss.openstar.Currency
import sss.openstar.account.{NodeIdTag, NodeIdentity, NodeIdentityManager}
import sss.openstar.chains.TxWriterActor._
import sss.openstar.common.users.UserDirectory
import sss.openstar.contract.FindPublicKeyAccOpt
import sss.openstar.ledger.LedgerId
import sss.openstar.network.MessageEventBus
import sss.openstar.test.MultiIdentityTestTransactionSender.FireTxs
import sss.openstar.test.MultiIdentityTestTransactionSenderInternalClaim.{Claimed, Funded}
import sss.openstar.tools.SendTxSupport.SendTx
import sss.openstar.wallet.UnlockedWallet
import sss.openstar.wallet.UtxoTracker.TrackWallet
import sss.openstar.wallet.Wallet.Payment
import java.util.concurrent.atomic.AtomicLong
import scala.concurrent.duration._
import scala.util.{Failure, Random, Success, Try}
object MultiIdentityTestTransactionSenderInternalClaim {
case object Register
case class Claimed(newId: NodeIdentity)
case class Funded(newId: String, amount: Long)
def apply[C <: Currency](nodeIdentityManager: NodeIdentityManager,
accountOpt: FindPublicKeyAccOpt,
users: UserDirectory,
testUsersConfig: Int,
initialAmount: Long,
testBalanceLedgerId: LedgerId,
buildUnlockedWallet: NodeIdentity => UnlockedWallet[C],
maxInProgress: Int,
maxTotalTxs: Int,
toIdentityLedgerOwner: NodeIdentity => Option[NodeIdentity],
hostingNodeIdentity: NodeIdentity
)(implicit actorSystem: ActorContext,
sendTx: SendTx,
messageEventBus: MessageEventBus
): ActorRef = {
actorSystem.actorOf(
Props(new MultiIdentityTestTransactionSenderInternalClaim[C](
nodeIdentityManager: NodeIdentityManager,
accountOpt: FindPublicKeyAccOpt,
users: UserDirectory,
testUsersConfig: Int,
initialAmount: Long,
testBalanceLedgerId: LedgerId,
buildUnlockedWallet: NodeIdentity => UnlockedWallet[C],
maxInProgress,
maxTotalTxs,
toIdentityLedgerOwner,
hostingNodeIdentity)
), "MultiIdentityTestTransactionSenderInternalClaim")
}
}
class MultiIdentityTestTransactionSenderInternalClaim[C <: Currency](nodeIdentityManager: NodeIdentityManager,
accountOpt: FindPublicKeyAccOpt,
users: UserDirectory,
testUsersConfig: Int,
initialAmount: Long,
testBalanceLedgerId: LedgerId,
buildUnlockedWallet: NodeIdentity => UnlockedWallet[C],
maxInProgress: Int,
maxTotalTxs: Int,
toIdentityLedgerOwner: NodeIdentity => Option[NodeIdentity],
hostingNodeIdentity: NodeIdentity
)(implicit
sendTx: SendTx,
messageEventBus: MessageEventBus)
extends Actor with ActorLogging {
private val defaultPassword = "Password10!"
import context.dispatcher
context.setReceiveTimeout(120.seconds)
private var testUsersWallets: Seq[UnlockedWallet[C]] = {
users.listUsers() map { user =>
val ni = nodeIdentityManager(user.identity, NodeIdTag.defaultTag, defaultPassword).await()
buildUnlockedWallet(ni)
}
}
private var schedFire: Option[Cancellable] = None
private def scheduleFireTxs(delayInSeconds: Int) = {
schedFire = schedFire match {
case None =>
Option(context.system.scheduler.scheduleOnce(delayInSeconds.seconds, self, FireTxs))
case x => x
}
}
case class AddWallet(wallet: UnlockedWallet[C])
//private var testUsersWallets: Seq[UnlockedWallet[C]] = Seq.empty
private def randomWallet(notIn: String*): UnlockedWallet[C] = {
val candidate = testUsersWallets(Random.nextInt(testUsersWallets.size))
if(notIn.contains(candidate.w.walletOwner)) randomWallet(notIn: _*)
else candidate
}
private def randomWallet(): UnlockedWallet[C] = {
testUsersWallets(Random.nextInt(testUsersWallets.size))
}
private var inProgress = 0
private var totalTxsProcessed: Int = 0
private val totalTimeProcessing = new AtomicLong(0)
private def calculateLatency(): Double = {
val time = totalTimeProcessing.get()
val totalTxs = totalTxsProcessed
if (time > 0 && totalTxs > 0) {
time.toDouble / totalTxs.toDouble
} else {
0
}
}
{
context.actorOf(Props(
new ClaimUsersActor(testUsersConfig, users, defaultPassword, nodeIdentityManager, accountOpt, toIdentityLedgerOwner, hostingNodeIdentity)
), "ClaimUsersActor")
}
scheduleFireTxs(1)
override def receive: Receive = {
case FutureFailure(e) =>
log.warning("Failed, retry, " + e.toString)
inProgress -= 1
scheduleFireTxs(2)
case ReceiveTimeout =>
log.info("All quiet, print out wallet balances")
var balances:Long = 0
testUsersWallets.foreach(w => {
balances = balances + w.w.balance().get.value
log.info(s"${w.w.walletOwner} balance ${w.w.balance()}")
})
log.info(s"Total balances $balances")
val lat = calculateLatency()
log.info(s"Latency $lat, total ${totalTxsProcessed}")
//self ! PoisonPill
case com: InternalCommit =>
log.info(s"Got commit: $com, going again")
inProgress -= 1
self ! FireTxs
case ack: InternalAck =>
//log.info(s"Got ack: $ack")
case r: InternalTempNack =>
inProgress -= 1
if (inProgress % 20 == 0) {
log.info(r.toString + s" TxResult $r rescheule")
}
scheduleFireTxs(2)
case r: InternalTxResult =>
inProgress -= 1
self ! FireTxs
case FireTxs if inProgress < maxInProgress && totalTxsProcessed < maxTotalTxs && testUsersWallets.size > 1 =>
schedFire = None
var fired = false
(0 until (maxInProgress - inProgress)) foreach {
_ =>
val wallet = randomWallet()
val wallet2 = randomWallet(wallet.w.walletOwner)
val bal = wallet.w.balance().get.value
log.info(s"User: ${wallet.w.walletOwner} -> balance: ${bal} ${wallet.w.ledgerId} ${wallet.w.clientBalanceTotal()}")
if (bal > 0) {
Try(wallet.payAsync(Payment(wallet2.w.walletOwner, 1, 5))) match {
case Success(f) =>
inProgress += 1
val now = System.currentTimeMillis()
f andThen { case Success(_) =>
totalTxsProcessed += 1
totalTimeProcessing.addAndGet(System.currentTimeMillis() - now)
}
f pipeTo self
case Failure(e) =>
log.debug(e.toString)
log.info("Problem, try again")
if (!fired) {
fired = true
scheduleFireTxs(1)
}
}
} else if (!fired) {
fired = true
scheduleFireTxs(1)
}
}
case FireTxs if totalTxsProcessed < maxTotalTxs=>
schedFire.map(_.cancel())
schedFire = None
if (inProgress % 2 == 0) {
log.info(s"$inProgress in progress, wait a few.... (total ${totalTxsProcessed}) average latency = ${calculateLatency()} ms")
}
scheduleFireTxs(1)
case Claimed(newNodeIdentity) =>
buildUnlockedWallet(newNodeIdentity).w.balance() map { amount =>
val isFunded= amount.value > 0
if(isFunded) {
self ! Funded(newNodeIdentity.id, amount.value)
} else {
context.actorOf(Props(
new FundWithTestCoinbase(newNodeIdentity.id, initialAmount, testBalanceLedgerId)
))
}
} recover {
case e => log.warning(s"Failed to build wallet for ${newNodeIdentity.id} {}", e)
}
case AddWallet(wallet) =>
testUsersWallets = testUsersWallets :+ wallet
if(testUsersWallets.size % 5000 == 0) {
log.info(s"TEST USERS NOW ${testUsersWallets.size}")
}
case Funded(newId, amount) =>
Try {
if(testUsersWallets.exists(_.w.walletOwner == newId)) {
log.warning(s"Skipping add of ${newId} already exists.")
} else {
val nodeIdentity = nodeIdentityManager(newId, NodeIdTag.defaultTag, defaultPassword).await()
val wallet = buildUnlockedWallet(nodeIdentity)
log.info(s"Add wallet for ${newId} : ${amount} ${wallet.w.balance()}")
messageEventBus publish TrackWallet[C](wallet.w, wallet.w.amount(amount))
context.system.scheduler.scheduleOnce(5.seconds, self, AddWallet(wallet))
}
scheduleFireTxs(2)
} recover {
case e => log.warning(s"Failed to create fund!", e)
}
}
}