2

How can you calculate gas cost on an iteration of something such as updating balances on 1000 token holders?

4

I would strongly recommend against the use of an iterative contract function for such a thing because it's sure to fail at some level of token holders. Even if it's okay at 1,000, what about 10,000? What about 100,000?

Your first instinct should be to rethink the application in such a way that such iteration isn't required. If that's impossible, then consider a small atomic function that will deal with one token-holder at a time and a strategy of a trusted address tasked with performing the iteration and submitting the many tiny transactions. Take care that each "step" leaves the contract in a valid state. In other words, it's important that things continue to work as expected while the batch process is in progress.

In the case that the contract would be in an invalid state while the batch process is underway, you could react with a guard to take the contract out of service until the batch process is successfully completed.

In my opinion all such measures strongly suggest the process itself needs revision because it's not well-adapted to smart contract patterns.

Hope it helps.

Updated

For example, there might be a requirement to distribute dividends or royalties to a large number of token holders. I'll set aside some exchange-related concerns and focus on the topic of handling a large number iterations.

Designing for a smart contract platform with a hard (moving) ceiling often involves inverting control. Distributing thousands of payments is one such example. To invert this:

  1. Each token holder claims their distribution (favor "pull" over "push").
  2. Contract checks if claim is acceptable
  3. If acceptable, claim is allocated and storage is updated to prevent double-claim.
  4. Claims are cumulative. Clients may excercise claims at their leisure without risk of loss.
  5. A spendable "balance" would be the regular balance, plus any unclaimed distributions. For most purposes, math and processing can proceed as though the claim has already occured.

It's worth noting that claims/entitlements are knowable and caculable by all participants with or without actual on-chain processing. It's also worth noting that clients themselves would "pay" the processing costs of the transactions.

Consider a simple case with token holders having a balance and some sort of claim, at intervals:

function calculateUnclaimed(address holder) internal returns(uint pending) {
  // calculate accrued unclaimed for one user
  return calculation;
}

function getSpendable(address holder) public constant returns(uint spendable) {
  return balances[holder] + calculateUnclaimed(holder);
}

function processClaim(address holder) public returns(uint newBalance) {
  balances[holder] += calculateUnclaimed(holder);
  zeroOutPending(holder); 
     // as each distribution emerges, append to master list
     // as each claim is processed, note holder has claimed his part
  return balances[holder];
}

This is a quickly contrived example to show how the processing can be reoriented toward clients "pulling" the claims instead of server "pushing" the distribution.

Even on first look, it begins to appear that processClaim may not be necessary at all, but it may be helpful to clean up and reduce transaction costs. The goal should be achieve a consistent gas cost for all transactions at any scale.

Hope it helps.

| improve this answer | |
  • Thank you for your response. Iterations are required since it it related to distributions.. I will be simulating a transaction of 100,000 token holders on a private net.. How similar are the outcomes of this on a private net vs on frontier in terms of allowing the transaction to process? Rather than just doing one transaction as you suggested why not in blocks of 100 or 1000 or 10000? Is there a disadvatage or advantage over one another ? – Dino Anastos Sep 17 '17 at 0:20
  • Thanks for the vote. I updated the answer in light of your comment. – Rob Hitchens Sep 17 '17 at 1:23
  • 1
    Thank you for that well thought out answer... However... I should point out that at some point a snapshot of the state of tokenholders balances needs to take place.. this snapshot will be used to determine what each tokenholder is entitled to.. How do you avoid the inherent problem of ever changing balances in a token that is trading live without iterating over at one point to peg down the state of holdings at a particular time? The work around seems to be is by going off chain for the snapshot if gas limit is a concern for the iteration. – Dino Anastos Sep 17 '17 at 1:46
  • It seems that without a snapshot of a point in time, tokenholders withdrawing their amounts may game the system. – Dino Anastos Sep 17 '17 at 1:46
  • 1
    You're right. The example is flawed in the details, but hopefully encourages some outside-the-loop thinking. :-) – Rob Hitchens Sep 17 '17 at 2:11

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.