-
Notifications
You must be signed in to change notification settings - Fork 812
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
chain: emit 'reset' when reorganizing SPV chain #755
base: master
Are you sure you want to change the base?
Conversation
Codecov Report
@@ Coverage Diff @@
## master #755 +/- ##
==========================================
+ Coverage 56.64% 62.43% +5.79%
==========================================
Files 112 106 -6
Lines 28140 27860 -280
Branches 4800 4756 -44
==========================================
+ Hits 15939 17394 +1455
+ Misses 12201 10466 -1735
Continue to review full report at Codecov.
|
return await job.mineAsync(); | ||
} | ||
|
||
async function event(obj, name) { |
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.
I should add this to test/util/common.js
in #748, so it'll be available for other tests.
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.
I agree, it is a good test utility function
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 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.
Okay, I moved it to /test/util/common.js
as from #748
// Give SPV node a second to catch up before checking sync with fullnode. | ||
// Waiting for specific events like 'block', 'full', or 'tip' is hard here | ||
// because we don't really know when we are at the proper tip. | ||
await new Promise(r => setTimeout(r, 5000)); |
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.
Maybe we can wait for an event with a specific value?
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.
Tried a few things with while
loops waiting for a certain chain height, can't really figure out a more elegant way to do this... any thoughts?
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 about something like this?
async function eventValue(obj, name, expected, timeout = 10000) {
assert(typeof obj === 'object');
assert(typeof name === 'string');
return new Promise((resolve, reject) => {
let timer = null;
const check = (value) => {
if (value === expected) {
obj.removeListener(name, check);
clearTimeout(timer);
resolve();
}
};
obj.addListener(name, check);
timer = setTimeout(() => {
obj.removeListener(name, check);
reject(new Error('Timeout waiting for event value.'));
}, timeout);
});
}
I have been using this in #758 to wait for values:
async function forValue(obj, key, val, timeout = 60000) {
assert(typeof obj === 'object');
assert(typeof key === 'string');
const ms = 10;
let interval = null;
let count = 0;
return new Promise((resolve, reject) => {
interval = setInterval(() => {
if (obj[key] === val) {
clearInterval(interval);
resolve();
} else if (count * ms >= timeout) {
clearInterval(interval);
reject(new Error('Timeout waiting for value.'));
}
count += 1;
}, ms);
});
};
@braydonf I also want to copy this test exactly (once we're happy here) but connecting two full nodes. |
This issue is fixed in the https://github.com/bcoin-org/bcoin/tree/chain-expansion branch. |
Port of bcoin-org/bcoin#755 Co-authored-by: Matthew Zipkin <pinheadmz@gmail.com>
Port of bcoin-org/bcoin#755 Co-authored-by: Matthew Zipkin <pinheadmz@gmail.com>
Closes #655
The bugfix here was to set the
silent
flag tofalse
when_reset()
is called byreorganizeSPV()
.@braydonf found the commit that introduced the
silent
flag here: 025a5b9 but it is unclear to me in the current state of the codebase whether or not it is still necessary.Either way, by setting
silent
tofalse
here, chain will emit a'reset'
event during a reorg, which is caught bypool
, which responds by re-syncing the chain. Without this change, SPV nodes that detect a chain reorg will reset to the fork-point of the reorg, and then stop. Wheras full nodes at this point would reconnect blocks from the fork point back up to the new tip, SPV nodes sit here and wait for a new block to be added to the [newly correct] chain before downloading blocks from the network.SPV must re-download blocks after a reorg because it doesn't store any [filter-matched] transactions from "alternate" blocks.
This PR also includes a comprehensive SPV-sync test. It's an integration test, and it's slow, connecting a Full node to SPV node.
The test is based on the existing
node-test.js
script which tests a fullnode against chain reorgs. There a few other open PR's with SPV test but none have been merged yet. I think this is good place to start, it would have caught the regression in the commit listed above.