def info(bot, update): logger.info("network") response = messages.markdown("<u><b>SmartNode Network<b><u>\n\n", bot.messenger) with bot.nodeList as nodeList: if nodeList.synced() and nodeList.enabled(): lastBlock = nodeList.lastBlock created = nodeList.count() enabled = nodeList.enabled() preEnabled = nodeList.preEnabled expired = nodeList.expired newStartRequired = nodeList.newStartRequired qualifiedNormal = nodeList.qualifiedNormal qualifiedUpgrade = nodeList.qualifiedUpgrade upgradeModeDuration = nodeList.remainingUpgradeModeDuration protocolRequirement = nodeList.protocolRequirement() protocolOld = nodeList.count(nodeList.oldProtocol) protocolNew = nodeList.count(nodeList.newProtocol) initialWait = nodeList.minimumUptime() minPosition = int(enabled * 0.1) aberration = bot.aberration # Fallback if for whatever reason the top node could not filtered which # should actually not happen. top10Seconds = (int( (qualifiedNormal * 55) / 0.5) * (1 + bot.aberration)) topNode = list( filter(lambda x: x.position == minPosition, nodeList.nodes.values())) if len(topNode) and topNode[0].lastPaidTime: top10FromList = time.time() - topNode[0].lastPaidTime if top10FromList < 1.2 * top10Seconds: top10Seconds = top10FromList top10Time = util.secondsToText(top10Seconds) if upgradeModeDuration: upgradeModeDuration = util.secondsToText(upgradeModeDuration) response += messages.networkState( bot.messenger, lastBlock, created, preEnabled, enabled, expired, newStartRequired, qualifiedNormal, qualifiedUpgrade, upgradeModeDuration, protocolRequirement, nodeList.oldProtocol, nodeList.newProtocol, protocolOld, protocolNew, util.secondsToText(initialWait), top10Time, aberration) else: response += messages.notSynced(bot.messenger) return response
def position(bot): with bot.nodeList as nodeList: if not nodeList.synced() or not nodeList.enabled(): return messages.notSynced(bot.messenger) nodes = nodeList.count() enabled = nodeList.enabled() qualified = nodeList.qualifiedNormal unqualified = nodes - qualified minPosition = int(enabled * 0.1) top10Seconds = (int((qualified * 55) / 0.5) * (1 + bot.aberration)) topNode = list(filter(lambda x: x.position == minPosition, nodeList.nodes.values())) if len(topNode) and topNode[0].lastPaidTime: top10FromList = time.time() - topNode[0].lastPaidTime if top10FromList < 1.2 * top10Seconds: top10Seconds = top10FromList top10Time = util.secondsToText(top10Seconds) return ( "We have currenty <b>{}<b> qualified SmartNodes. All those are in a " "virtual payout queue. Every other mined block (2*55seconds) one " "of the nodes in the top 10% of that queue gets picked perchance and" " receives a payout. After that it moves back to the end of the queue.\n\n" "The position of your node represents the position in the queue. Once " "your node has a position <b>less<b> than (currently) <b>{}<b>" " it is in the <b>random payout zone<b> (top 10%).\n\n" "The minimum position depends on the number of enabled nodes and will change" " when the number of enabled nodes changes.\n\n" "Right now it takes <b>{}<b> to reach the payout zone.\n\n" "It's normal and to be expected that your nodes moves also backwards a " "bit in the queue from time to time. This happens each time a node that" " has received its last payment longer ago as yours becomes eligible" " for payouts (it jumpes into the queue and receives a position)." " At this moment we have <b>{}<b> SmartNodes. <b>{}<b> of them are" " <b>not<b> qualified for payouts. Each time one of the unqualified" " nodes becomes eligible due to a full match of the requirements" " it is very likely that it will jump ahead of yours.\n\n" "You can send me <cb>info<ca> to see the number of qualified nodes, " "to check your nodes positions send me <cb>detail<ca>, <cb>nodes<ca>" " <cb>top<ca> or use the <cb>lookup<ca> command.\n\n" ).format(qualified, minPosition, top10Time, nodes, unqualified)
def rewards(bot): with bot.nodeList as nodeList: if not nodeList.synced() or not nodeList.enabled(): return messages.notSynced(bot.messenger) enabled = nodeList.enabled() minPosition = int(enabled * 0.1) qualified = nodeList.qualifiedNormal lastBlock = nodeList.lastBlock # Fallback if for whatever reason the top node could not filtered which # should actually not happen. top10Seconds = (int((qualified * 55) / 0.5) * (1 + bot.aberration)) topNode = list(filter(lambda x: x.position == minPosition, nodeList.nodes.values())) if len(topNode) and topNode[0].lastPaidTime: top10FromList = time.time() - topNode[0].lastPaidTime if top10FromList < 1.2 * top10Seconds: top10Seconds = top10FromList payoutSeconds = top10Seconds + (10 * 60 * 60) payoutDays = payoutSeconds / 86400.0 interval = util.secondsToText(int(payoutSeconds)) currentReward = round(5000.0 * 143500.0 / lastBlock * 0.1,1) / 0.5 perMonth = round((30.5 / payoutDays) * currentReward,1) return ( "The SmartNode rewards are calculated by the following formula\n\n" "```reward = 5000 x 143500 / blockHeight * 0.1```\n\n" "At this moment our blockchain is at the height <b>{}<b> that means" "\n\n```5000 x 143500 / {} * 0.1 => {} SMART per block```\n\n" "Each block with an <b>even<b> blockheight one of the the nodes receive this reward for 2 blocks. With the current " "estimated payout interval of <b>{}<b> you can expect roughly" " <b>{:,} SMART<b> per month per SmartNode. This can vary a bit upwards and downwards though.\n\n" "Due to the constant increase of the <c>blockHeight<c> of the SmartCash blockchain" " the rewards will decrease a little bit every 55 seconds." " Also the increase of the number of qualified nodes will increase the payout interval." " As result your monthly payout will slightly decrease over the time.\n\n" "You can look at the chart in the link below to see the reward decrease " "for the first 4 years after the SmartNode launch.\n\n" ).format(lastBlock, lastBlock, currentReward, interval, perMonth)\ + messages.link(bot.messenger, "https://goo.gl/Va817H", "Click here to open the chart")
def initial(bot): with bot.nodeList as nodeList: if not nodeList.synced() or not nodeList.enabled(): return messages.notSynced(bot.messenger) initialWait = util.secondsToText(nodeList.minimumUptime()) return ( "When your node shows <b>Initial wait time<b> instead of a position it's" " uptime does not match the minimum uptime requirement. At this time the" " node must have a minimum uptime of <b>{}<b>." " Your uptime will be set to zero when your node was down for more than" " <b>1 hour<b> or when you issue a <b>new start<b> of the node with your desktop wallet" " by running <c>Start alias<c>.\n\n" "You can check your node's uptime when you send me <cb>detail<ca> or by" " running the <cb>lookup<ca> command.\n\n" ).format(initialWait)
def collateral(bot): with bot.nodeList as nodeList: if not nodeList.synced() or not nodeList.enabled(): return messages.notSynced(bot.messenger) confirmations = nodeList.enabledWithMinProtocol() timeString = util.secondsToText(confirmations * 55) return ( "A too new collateral means that your nodes collateral transaction (the 10k one) does not" " have the minimum required number of confirmations in the Curium blockchain." "This number of confirmations is currently <b>{}<b>.\nYour collateral gets 1 confirmation with each" " new mined block.\n\nMeans right now you need to wait {} x 55 seconds => <b>~{}<b> until" " your collateral transaction matches the requirement.\n\n" "You can check your nodes collateral confirmations" " by running the <cb>lookup<ca> command.\n\n" ).format(confirmations, confirmations, timeString)
def lookup(bot, userId, args): response = messages.markdown("<u><b>Node lookup<b><u>\n\n", bot.messenger) with bot.nodeList as nodeList: if nodeList.synced() and nodeList.lastBlock: if not len(args): response += messages.lookupArgumentRequiredError(bot.messenger) else: errors = [] lookups = [] for arg in args: ip = util.validateIp(arg) if not ip: errors.append( messages.invalidIpError(bot.messenger, arg)) else: result = nodeList.lookup(ip) if result: lookups.append( messages.lookupResult(bot.messenger, result)) else: errors.append( messages.nodeNotInListError(bot.messenger, ip)) for e in errors: response += e for l in lookups: response += l else: response += messages.notSynced(bot.messenger) return response
def qualified(bot): with bot.nodeList as nodeList: if not nodeList.synced() or not nodeList.enabled(): return messages.notSynced(bot.messenger) confirmations = nodeList.enabledWithMinProtocol() initialWait = util.secondsToText(nodeList.minimumUptime()) protocolRequirement = nodeList.protocolRequirement() return ( "Your node has to match the following requirements before it's ready to" " receive payouts\n\n" "- The node's status has to be <b>ENABLED<b>\n" "- The node's collateral transaction needs to have at least <b>{}<b>" " confirmations\n" "- The node must have a minimum uptime of <b>{}<b>\n" "- The node must run at least on the protocol <b>{}<b> number\n\n" "Once your node matches <b>all<b> the above requirements it will get a" " position in the payout queue.\n\n" "You can check all this requirements for your nodes when you send me" " <cb>detail<ca> or by running the <cb>lookup<ca> command.\n\n" ).format(confirmations, initialWait, protocolRequirement)