-
Notifications
You must be signed in to change notification settings - Fork 92
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
CFundDB extra log and ensure read before modify #622
Conversation
utACK |
@chasingkirkjufell fixed in 96e9d51 |
added test unit 5f43066 |
test unit fails on master:
passes on this branch:
|
utACK new native testcases make sense. Ran the test_navcoin binary from this branch against master and master failed. Ran the test_navcoin binary from this branch against this pr and it passed. I'll approve as soon as I'm done with the manual test scenario that I used to replicate the 000000000 hash request. |
Tested with this manual scenario:
On master I was able to get node 1 to fork, still testing on this PR. |
To completely reproduce the issue we've seen we need to bring it further to the payment request's payout. |
I think that might be covered in my test, cause I let Node 2 stake up to 300+ more blocks than node 1. Which should be more than enough for the payment request to be paid already @aguycalled can you confirm this is the case with my test scenario? |
@mxaddict that is one possible wrong case. |
test from c27635f passes on this branch and 4.7.1. But does not pass in 4.7.0 c8d9d72. My theory: Bootstrap downloaded from
|
@aguycalled I agree with your idea to add a new hash to the merkle root, should we add it into this PR? |
Nevermind this comment :D |
Related to previous comments: #625 |
This PR compiles and runs on OSX 10.14.5. I can verify that 4.7.0 fails the test This branch (which is forked from master after 4.7.1) passes the test. Now continuing with the code & test review. |
Test makes sense, thanks for leaving comments in the file. Regarding these changes, as i understand it we have a few areas with the potential to cause a fork if they were unable to be reorganised correctly;
As far as I can tell the test only reorgs a payment request, after the proposal is accepted on the same chain by each node. Is it also worth having the same test but reorg the proposal itself and ensure payment requests can still be submitted? We have; These and probably more permutations are the types of things i want to map out in miniature and make sure are covered in a robust and micro focused python test framework. After we get the new testnet up and running. I think this test is probably enough for now, and we can leave the full audit of the cfund tests for that stage of the network stability review. |
mapProposal.insert(make_pair(it->first, it->second)); | ||
|
||
for (auto it = mapProposal.begin(); it != mapProposal.end();) | ||
it->second.IsNull() ? mapProposal.erase(it++) : ++it; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it necessary to erase entries with the null proposal pair since the loop above only inserts when it is not null?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes, because it can have null entries from cacheProposals, which are entries marked to be removed in the base view when a flush is executed later
mapPaymentRequests.insert(make_pair(it->first, it->second)); | ||
|
||
for (auto it = mapPaymentRequests.begin(); it != mapPaymentRequests.end();) | ||
it->second.IsNull() ? mapPaymentRequests.erase(it++) : ++it; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same comment as above for here, if my above comment is valid.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same answer as before
@@ -221,14 +229,22 @@ CCoinsModifier CCoinsViewCache::ModifyCoins(const uint256 &txid) { | |||
CProposalModifier CCoinsViewCache::ModifyProposal(const uint256 &pid) { | |||
assert(!hasModifier); | |||
std::pair<CProposalMap::iterator, bool> ret = cacheProposals.insert(std::make_pair(pid, CProposal())); | |||
ret.first->second.fDirty = true; | |||
if (ret.second) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you explain what this function is doing sorry? I can see it's called before adding votes to proposals in the cache and.. again when we're updating the state at the end of the voting cycles.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
::ModifyProposal returns a pointer to an entry in the view cache we want to modify.
std::pair<CProposalMap::iterator, bool> ret = cacheProposals.insert(std::make_pair(pid, CProposal()));
Here we try to insert in the view cache an empty proposal with the hash pid
.
if (ret.second) {
This means the insert was successful (no previous entry with that hash in the cache).
if (!base->GetProposal(pid, ret.first->second)) {
ret.first->second.SetNull();
}
We try to get the entry from the base view, and if it's not possible we set it to null (which is redundant but safer).
return CProposalModifier(*this, ret.first);
Finally we construct the CProposalModifier object and return it.
CProposalModifier proposal = view.ModifyProposal(it->first); | ||
proposal->nVotesYes = it->second.first; | ||
proposal->nVotesNo = it->second.second; | ||
if (*proposal != oldproposal) | ||
{ | ||
proposal->fDirty = true; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what is the fDirty boolean used for?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Only entries flagged as dirty are written to the base view when flushed.
@@ -815,6 +847,13 @@ void CFund::CFundStep(const CValidationState& state, CBlockIndex *pindexNew, con | |||
prequest->nVotesNo = 0; | |||
} | |||
} | |||
|
|||
if (*prequest != oldprequest) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
does the == operator overload match != as well for these if statements?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is an operator!= declaration which simply returns the inverse of ==, is that what you are referring to?
@@ -3425,13 +3475,15 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin | |||
{ | |||
uint256 prid = uint256S(metadata[nPaymentRequestsCount].get_str()); | |||
|
|||
if(!view.HavePaymentRequest(prid)) | |||
CPaymentRequest prequest; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's the benefit of doing the following operations on the cache prequest rather than the CPaymentRequestModifier? We now guarantee that we've done all the null checks on the payment request before running these block checks?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there somewhere in main where we should be doing a similar thing with the cache for proposals like we're doing for payment requests here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's no real benefit more than being more strictly correct with the purpose of each object.
CProposal and CPaymentRequest changes are not reflected in the cache view, while Modifiers can be changed and the changes are reflected in the cache view.
The declaration of mprequest could be moved forward, so it only happens if all the previous checks are satisfied. 36269a2
CProposalModifier (3 times) and CPaymentRequestModifier (4 times) are used very rarely in the code. A global search would show where one can put some more attention.
Diff reviewed in full while exploring some horizontal and vertical context around the changes. Comments above. |
A new build of 36269a2 has completed succesfully! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
changing approval status until discussed test is added
I've added the test for checking a re-organised proposal can still make it through payment request submission, voting and payment. The test passes on this branch and fails on v4.7.0. the 4.7.0 test failure is on line 96 Which confirms this action would end with the nodes disagreeing on the blockHash of the proposal. If someone can review the test that would be great; https://github.com/navcoin/navcoin-core/blob/09b636b3954b1d7374156339da10f6bb1ad91c61/qa/rpc-tests/cfund-fork-reorg-proposal.py |
A new build of b0af91b has completed succesfully! |
Build on Ubuntu 19.10 and ran the 2 new tests for cfund-fork-reorg*, tests passed |
Read the new test that @proletesseract added, makes sense. |
@aguycalled @proletesseract I'll let you do the honors incase you want to add more changes to the tests. |
* add extra log * add __func__ * ensure read before modify * fix log * optimize log * do not access modifier * only set dirty when necessary * check for nullified * add extra log * do not insert nullified entries * HaveProposalInCache/HavePaymentRequestInCache * add cfunddb_tests.cpp * add 250 rounds and random remove * Added new test for cfund reorg scenario * Updates to the test as per aguycalled's suggestions * update qa/rpc-tests/cfund-fork-reorg.py * Added new test to the suite * move mprequest * adding (failing) test for proposal reorg * removed 5th cycle * fixed preq voting, removed logs added final payout check
This PR adds extra log for all the modifications of the CFundDB and ensures entries are read in the memory cache before being modified