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.
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.
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.
same comment as above for here, if my above comment is valid.
There was a problem hiding this comment.
same answer as before
| 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.
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.
::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.
| proposal->nVotesNo = it->second.second; | ||
| if (*proposal != oldproposal) | ||
| { | ||
| proposal->fDirty = true; |
There was a problem hiding this comment.
what is the fDirty boolean used for?
There was a problem hiding this comment.
Only entries flagged as dirty are written to the base view when flushed.
| } | ||
| } | ||
|
|
||
| if (*prequest != oldprequest) |
There was a problem hiding this comment.
does the == operator overload match != as well for these if statements?
There was a problem hiding this comment.
There is an operator!= declaration which simply returns the inverse of ==, is that what you are referring to?
| uint256 prid = uint256S(metadata[nPaymentRequestsCount].get_str()); | ||
|
|
||
| if(!view.HavePaymentRequest(prid)) | ||
| CPaymentRequest prequest; |
There was a problem hiding this comment.
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.
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.
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! |
proletesseract
left a comment
There was a problem hiding this comment.
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