Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added new attributes to the getstakinginfo and getstakereport commands #485

Merged
merged 9 commits into from Jun 12, 2019

Conversation

mxaddict
Copy link
Contributor

Added new attributes to the getstakinginfo and getstakereport commands

getstakinginfo now has expecteddailyreward

getstakereport now has Last 7 Days Avg, Last 30 Days Avg and Last 365 Days Avg

reports looks like these:

{
  "enabled": true,
  "staking": true,
  "errors": "",
  "currentblocksize": 1000,
  "currentblocktx": 0,
  "difficulty": 537692.0995617752,
  "search-interval": 16,
  "weight": 1198583732549,
  "netstakeweight": 1339930863008790,
  "expectedtime": 33537,
  "expecteddailyreward": 5.15236448
}
{
  "2019-05-15 16:00:00": "2.00",
  "2019-05-14 16:00:00": "2.00",
  "2019-05-13 16:00:00": "2.00",
  "2019-05-12 16:00:00": "2.00",
  "2019-05-11 16:00:00": "2.00",
  "2019-05-10 16:00:00": "6.0001",
  "2019-05-09 16:00:00": "4.00",
  "2019-05-08 16:00:00": "4.00",
  "2019-05-07 16:00:00": "6.00",
  "2019-05-06 16:00:00": "4.00",
  "2019-05-05 16:00:00": "2.00",
  "2019-05-04 16:00:00": "4.00",
  "2019-05-03 16:00:00": "8.00",
  "2019-05-02 16:00:00": "4.00",
  "2019-05-01 16:00:00": "6.00",
  "2019-04-30 16:00:00": "2.00",
  "2019-04-29 16:00:00": "0.00",
  "2019-04-28 16:00:00": "4.00",
  "2019-04-27 16:00:00": "4.00",
  "2019-04-26 16:00:00": "2.00",
  "2019-04-25 16:00:00": "4.00",
  "2019-04-24 16:00:00": "4.00",
  "2019-04-23 16:00:00": "0.00",
  "2019-04-22 16:00:00": "2.00",
  "2019-04-21 16:00:00": "2.00",
  "2019-04-20 16:00:00": "2.00",
  "2019-04-19 16:00:00": "4.00",
  "2019-04-18 16:00:00": "2.00",
  "2019-04-17 16:00:00": "2.00",
  "2019-04-16 16:00:00": "4.00",
  "Last 24H": "2.00",
  "Last 7 Days": "22.0001",
  "Last 7 Days Avg": "3.14287142",
  "Last 30 Days": "98.0001",
  "Last 30 Days Avg": "3.26667",
  "Last 365 Days": "425.2213209",
  "Last 365 Days Avg": "1.16498992",
  "Last All": "438.03126175",
  "Latest Stake": "2.00",
  "Latest Time": "2019-05-15 20:53:04",
  "Stake counted": 274,
  "time took (ms)": 1
}

// Check if we need to add the average
if (nDays > 0) {
// Add the Average
result.push_back(Pair(vIt->Name + " Avg", FormatMoney(vIt->Total / nDays).c_str()));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't the average be calculated only over the amount for days where a stake happened? If my wallet is 60 days old, it'll need 305 days to show an accurate number in "365 Avg", for example.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So you mean calculate the average stake for the last X days where X Days is the number of days past since your first stake that is no older than 365 days?

Well, that would not really be a 365 day average, that would be more an average since staking.

The current formula would be 100% accurate if your wallet is 1 year old, but as you say it would be completely off if your wallet has only been staking for like 45 days.

I'll see what I can come up with for making the average more accurate.

I think I can calculate the wallet age based on first stake date and use it to adjust nDays value.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would define “X Avg” as the daily average received as rewards over the last X days of active staking.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this should be clearly documented somewhere so people don't accidentally assume the averages are simple averages over the entire X timeframe regardless of initial staking activity.

@mxaddict
Copy link
Contributor Author

mxaddict commented May 16, 2019 via email

@aguycalled
Copy link
Member

aguycalled commented May 16, 2019

Ahh, so just add a new attribute to the response?

what I mean is, as a general definition, “X Avg” should show Sum(stakes[today-X:today])/min(X,n) for a wallet which is n days old

@mxaddict
Copy link
Contributor Author

mxaddict commented May 16, 2019

Ahh, so just add a new attribute to the response?

what I mean is, as a general definition, “X Avg” should show Sum(stakes[today-X:today])/min(X,n) for a wallet which is n days old

You mean like this:

{
  "Last 24H": "2.00",
  "Last 7 Days": "22.0001",
  "Last 7 Days Avg": "3.14287142",
  "Last 30 Days": "98.0001",
  "Last 30 Days Avg": "3.26667",
  "Last 365 Days": "425.2213209",
  "Last 365 Days Avg": "1.16498992",
  "Last X Avg": "3.14287142",
  "Last All": "438.03126175"
}

@aguycalled
Copy link
Member

Ahh, so just add a new attribute to the response?

what I mean is, as a general definition, “X Avg” should show Sum(stakes[today-X:today])/min(X,n) for a wallet which is n days old

You mean like this:

{
  "Last 24H": "2.00",
  "Last 7 Days": "22.0001",
  "Last 7 Days Avg": "3.14287142",
  "Last 30 Days": "98.0001",
  "Last 30 Days Avg": "3.26667",
  "Last 365 Days": "425.2213209",
  "Last 365 Days Avg": "1.16498992",
  "Last X Avg": "3.14287142",
  "Last All": "438.03126175"
}

Let X be 7, 30 or 365.

else if (tx->vout[1].scriptPubKey.IsColdStaking())
return tx->GetCredit(pwalletMain->IsMine(tx->vout[1])) - tx->GetDebit(pwalletMain->IsMine(tx->vout[1]));

return tx->GetCredit(ISMINE_SPENDABLE) + tx->GetCredit(ISMINE_STAKABLE) - tx->GetDebit(ISMINE_SPENDABLE) - tx->GetDebit(ISMINE_STAKABLE);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ignoring ISMINE_SPENDABLE_STAKABLE would make this to fail for wallets holding both the spending and staking key (not an ideal scenario from a security perspective but its technically possible)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll see if I can add more scenarios to the test case

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this scenario was already covered by the test cases

Please check this code in the test and let me know what you think:

        # Import the 2 keys into a third wallet
        self.nodes[0].importprivkey(spending_address_private_key)
        self.nodes[0].importprivkey(staking_address_private_key)

Basically in the test cases, there are 3 modes, node 1 has spending key, node 2 has staking key and node 0 has both keys imported

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes you are right, my bad as ISMINE_SPENDABLE_STAKABLE = ISMINE_SPENDABLE | ISMINE_STAKABLE

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I forget why, but in the 4.6.0 fix that I created for this

This would not get the correct amounts:

tx->GetCredit(ISMINE_SPENDABLE_STAKABLE) - tx->GetDebit(ISMINE_SPENDABLE_STAKABLE);

Bu this would:

tx->GetCredit(ISMINE_SPENDABLE) + tx->GetCredit(ISMINE_STAKABLE) - tx->GetDebit(ISMINE_SPENDABLE) - tx->GetDebit(ISMINE_STAKABLE);

While in theory they should be the same, but I don't remember exactly why.

I think there was code in GetCredit and GetDebit that was causing an issue when passing ISMINE_SPENDABLE_STAKABLE

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ISMINE_SPENDABLE_STAKABLE is both Spendable+Stakable

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Anyways, I think the scenarios are covered in the test case

And I also added the time travel stuff that we discussed with @craigmacgregor during the 4.6.0 release which we skipped due to time constraints.

const CWalletTx* tx;

// scan the entire wallet transactions
for (auto it = pwalletMain->mapWallet.end(); it != pwalletMain->mapWallet.begin(); --it)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maps are ordered per key so theres no assurance the first stake you will hit is the oldest stake, i'd say the easiest would be to iterate over wtxOrdered

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ACK, I will replace this with wtxOrdered, thanks for the heads up.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I pushed a commit which addresses this.

@mxaddict
Copy link
Contributor Author

Rebased the branch from master

@proletesseract
Copy link
Member

Just to confirm, all the Last X Days Avg values are programmed to give the daily average amount staked within period X or the daily average amount from the first stake till the end of X period if that length is shorter than X.

@proletesseract
Copy link
Member

Builds on Ubuntu 18.04. Tests pass. Tests make sense.

const CWalletTx* tx;

// scan the entire wallet transactions
for (auto it = pwalletMain->wtxOrdered.begin(); it != pwalletMain->wtxOrdered.end(); ++it)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If wtxOrdered is not changing length during this loop, you could cache the end iterator to save it being calculated each time the loop iterates. I'm not sure on the exact syntax here, in javascript you can do it directly into the loop declaration like this;

for(let i=0, l=my_array.length(); i<l; i++) {
    console.log(my_array[i]);
}

I don't think there's an inline way to do it in C++, so you'd just cache the iterator before you start the loop something like this;

std::vector<uint32_t>::const_iterator end = pwalletMain->wtxOrdered.end();
for (auto it = pwalletMain->wtxOrdered.begin(); it != end; ++it)
{
    //do stuff
}

It's probably not hugely relevant here since we're hoping the first item is the one we're looking for, but its a neat trick that can optimise loops especially when you're iterating through thousands of items like we can be doing when dealing with wallet transactions and especially long lived staking addresses. Keep it in mind if it's useful somewhere else!

:)

// Check if we need to add the average
if (nDays > 0) {
// Add the Average
result.push_back(Pair(vIt->Name + " Avg", FormatMoney(vIt->Total / nDays).c_str()));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this should be clearly documented somewhere so people don't accidentally assume the averages are simple averages over the entire X timeframe regardless of initial staking activity.

@mxaddict
Copy link
Contributor Author

@proletesseract Rebased on master and added cache for the wallet first stake value (Just in memory, so when the report is run more than once it will use the cached timestamp)

But this report will be slower for wallets with TX data but no stakes (Since it will have to loop all the TX every time in case it has staked since the last check)

@proletesseract
Copy link
Member

code looks good. need to resolve travis issues though.

@mxaddict
Copy link
Contributor Author

Travis-CI Passed, merging

@mxaddict mxaddict merged commit 82a2ba8 into navcoin:master Jun 12, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants