Write a Steemit Web App: Part 7 - Bandwidth AvailabilitysteemCreated with Sketch.

in #steemdev7 years ago (edited)

(Previous Post: Part 6)

There has been a lot of talk lately about Bandwidth on Steemit. It seems that certain anti-spam measures that are built into the system were maybe a little too aggressive. As a result, people were locked out of posting and powering up because they did not have enough allocated bandwidth remaining to commit the transaction to the blockchain.

A soft fork is in the works to address the aggressiveness aspect (as well as an integer overflow issue). But, let's take a look at how to calculate Bandwidth-related values in case you want to include those metrics into your Steemit Web App.

Note: This is information that I gathered by researching the Steem source code and other resources. If it is inaccurate in any way, then please leave a comment so that I can fix this article.

Bandwidth

Bandwidth is allocated per user based on the user's Steem Power (more accurately, based on their total vesting shares). There is a Maximum Virtual Bandwidth that represents 100% of the bytes that are available for all users to share. This can be calculated as:

number_of_blocks_per_week * maximum_block_size * current_reserve_ratio

maximum_block_size (currently 65536) and current_reserve_ratio (currently 416 as I write this) are values that can be found in the Dynamic Global Properties. The current_reserve_ratio is the anti-spam number that fluctuates in response to bursts of new transactions.

number_of_blocks_per_week is a constant, but is calculated as 20*60*24*7 (20 blocks per minute, 60 minutes per hour, 24 hours per day, 7 days per week... which comes out to be 201600).

So, in theory, there is a maximum of 5496215961600 bytes per week that can be used if the blockchain was 100% filled.

However, you don't actually have to calculate this every time because the Dynamic Global Properties also has a field named max_virtual_bandwidth that has this value in it (well, this value multiplied by 1000000 so that up to six decimal places are represented in the integer value).

// gprops
{
  current_reserve_ratio: 416,
  max_virtual_bandwidth: "5496215961600000000",
  maximum_block_size: 65536,
  total_vesting_shares: "374404675433.834843 VESTS"
}



Remember back in Part 3 when I said that voting power is updated after each vote, but must be recalculated on-the-fly in order to get the most current value? Well, bandwidth works the same way. When you post to the blockchain, the witness nodes calculate your average bandwidth usage and store it at that point in time. However, your average will continue to tick downwards as time goes on (if you don't post anything further, that is). Therefore, any app that shows your current bandwidth must perform a calculation:

((total_seconds - seconds_since_last_update) * average_bandwidth) / total_seconds

total_seconds, in this case, is the total number of seconds in a week (or 60*60*24*7).

seconds_since_last_update must be calculated as the difference between the current date/time (in UTC) and the last_bandwidth_update date in the user's Account data.

average_bandwidth also comes from the user's Account data, and, as stated before, represents the bandwidth usage at that point in time... but we're trying to figure out what the current value would be, hence the use of proportions in the calculation.

Note: The average bandwidth number is also saved as an integer with six decimal places represented. Divide by 1000000 in order to get the actual bytes of bandwidth.

// account data
{
  average_bandwidth: "23420877883",
  last_bandwidth_update: "2017-07-19T12:57:45",
  received_vesting_shares: "57000.000000 VESTS",
  vesting_shares: "228916.300865 VESTS"
}


The last piece of the puzzle is how to calculate the portion of the max_virtual_bandwidth that is allocated to the user:

(vesting_shares + received_vesting_shares) * max_virtual_bandwidth / total_vesting_shares

vesting_shares and received_vesting_shares comes from the user's Account data. The suffix of "VESTS" will need to be trimmed off of the string in the data.

max_virtual_bandwidth and total_vesting_shares comes from the Dynamic Global Properties.

Let's see it in JavaScript

steem.api.getAccountsAsync([accountName])
  .then(function (result) {
    steem.api.getDynamicGlobalPropertiesAsync()
      .then(function (gprops) {
        const STEEMIT_BANDWIDTH_AVERAGE_WINDOW_SECONDS = 60 * 60 * 24 * 7;
        let vestingShares = parseFloat(result[0].vesting_shares.replace(" VESTS", ""))
        let receivedVestingShares = parseFloat(result[0].received_vesting_shares.replace(" VESTS", ""))
        let totalVestingShares = parseFloat(gprops.total_vesting_shares.replace(" VESTS", ""))
        let max_virtual_bandwidth = parseInt(gprops.max_virtual_bandwidth, 10)
        let average_bandwidth = parseInt(result[0].average_bandwidth, 10)

        let delta_time = (new Date - new Date(result[0].last_bandwidth_update + "Z")) / 1000

        let bandwidthAllocated = (max_virtual_bandwidth  * (vestingShares + receivedVestingShares) / totalVestingShares)
        bandwidthAllocated = Math.round(bandwidthAllocated / 1000000);
        
        let new_bandwidth = 0
        if (delta_time < STEEMIT_BANDWIDTH_AVERAGE_WINDOW_SECONDS) {
          new_bandwidth = (((STEEMIT_BANDWIDTH_AVERAGE_WINDOW_SECONDS - delta_time)*average_bandwidth)/STEEMIT_BANDWIDTH_AVERAGE_WINDOW_SECONDS)
        }
        new_bandwidth = Math.round(new_bandwidth / 1000000)

        console.log("current bandwidth used", new_bandwidth)
        console.log("current bandwidth allocated", bandwidthAllocated)
        console.log("bandwidth % used", 100 * new_bandwidth / bandwidthAllocated)
        console.log("bandwidth % remaining", 100 - (100 * new_bandwidth / bandwidthAllocated))
      })
  })


Results:

current bandwidth used 18826
current bandwidth allocated 4197217
bandwidth % used 0.4485353032735739
bandwidth % remaining 99.55146469672643


And, just like the Voting Power post, improvements to this would be to periodically recalculate the value using a timer so that the user always sees their latest bandwidth usage.

javascriptlogo.png

(Next Post: Part 8)

Sort:  

Your numbers may differ from https://steemd.com because it looks like you're querying against a v0.19.0 node. Version 0.19.1 included some bandwidth updates but none of the math changed.

Ah, that makes me feel better. I couldn't figure out why https://steemd.com had numbers that were so different than mine! :-)

Keep the good work, Loving it.

Good job, I'll keep supporting your work.

I am waiting for your posts man! You will rock!

I see you are not supporting everyone's work on here @newsflash - why are you downvoting my comments and committing economic violence against people who wish to vote for me that have invested in this platform? What alternative do you want? A socialist state of sociopathic whales?? Those who invest in this platform should be allowed to vote freely without intervention. This is a libertarian platform not a Communist one. Please state your reasons for flagging. I do look forward to your answer.

Great Series! I'm sure your articles will help me with my own projects. Thank you!

Congratulations @jfollas! You have completed some achievement on Steemit and have been rewarded with new badge(s) :

Award for the total payout received

Click on any badge to view your own Board of Honor on SteemitBoard.
For more information about SteemitBoard, click here

If you no longer want to receive notifications, reply to this comment with the word STOP

By upvoting this notification, you can help all Steemit users. Learn how here!

Coin Marketplace

STEEM 0.22
TRX 0.20
JST 0.034
BTC 99266.82
ETH 3364.44
USDT 1.00
SBD 3.11