-
Notifications
You must be signed in to change notification settings - Fork 110
p2p/simulation: Test snapshot correctness and minimal benchmark #1038
Conversation
a4aa391
to
c3ca10e
Compare
p2p/simulations/test.go
Outdated
// but implements node.Service interface. | ||
type NoopService struct { | ||
useChannel bool | ||
C map[enode.ID]chan struct{} |
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.
C should not be exported. It is used only internally.
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.
Actually, it's used in network_test.go
. And the idea is that this should be available outside of the package, which means it would need to be exported. But you mean that as long as that's not the case it should be private?
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, when there is a need for it to be exported, then it should be exported, not before. Or if you want to provide the functionality from start, It would be good to have comments or examples how it should be used, as in network_test.go
it is injected as the exported field.
I would even say that maybe useChannel
is not needed, as NewNoopService can accept the map and set it to the field c
so the Run function can check if the c
map is nil instead to check if useChannel
is true. This way, c
can remain unexported with the functionality is available outside.
} | ||
|
||
type noopService struct { | ||
simulations.NoopService |
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.
While reducing code duplication, which is good, this approach also changes the previous noopService to have protocols, even more not to initialize a map used in the protocols run function. While this is working now, changes to the simulations.NoopService Run function may result in an unexpected failure in simulation package. This is creating more coupled code at the benefit of reducing a few lines in simulations package. I do not think that that benefit is great enough for this coupling, but I do not insist for changes, just awareness.
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.
How about a bool in the constructor that omits the protocol altogether, or is that too convoluted?
Alternately, chaining methods to add protocol or not, api or not...?
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 think that any more options would just add to the complexity. I would like to avoid any more complexity. This is fine now, until it does not extended to be more convoluted.
p2p/simulations/network_test.go
Outdated
|
||
// load the snapshot | ||
// spawn separate thread to avoid deadlock in the event listeners | ||
go func() { |
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.
We should signal to the main goroutine when the Load has returned to check if all connections are created before or after. They all should be created before when the ethereum/go-ethereum#18220 is merged.
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.
Cool, let's mark this PR pending yours. That makes sense anyhow.
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.
Actually since the subscription is before, this is ok and even should be in a goroutine because we want to handle all the events as they happen, no?
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, this should be in a goroutine, but this goroutine should signal the main goroutine when Load function returns, to check if that happens after all expected connection events are received. Or there are connections from the snapshot that happened after the Load function has returned, which should be an error.
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 understand what you mean. But given that we know exactly how many connections to expect, and we audit exactly those connections, and check at the end of the function for one second of "silence," isn't that already guaranteed?
(the latter would have to be checked in any case?)
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.
The main purpose for ethereum/go-ethereum#18220 is that connections are all established before the Load function returns. This test currently do not provide such validation, as Load function is in the goroutine that can finish at any time and connection checking is in another goroutine that can finish at any time. Connections are checked but they can be established after the Load function return and this test does not check for that as the time when Load function returns is not known or such event is not signaled to the main goroutine.
8c4e8d7
to
9dd40d2
Compare
p2p/simulations/network_test.go
Outdated
} | ||
|
||
// check that we have all expected connections in the network | ||
for _, snapConn := range snap.Conns { |
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.
@janos since this is now a separate goroutine, can we be sure all of this will be executed before the test ends? The main routine may finish first. Or do tests in all cases join all threads before finishing?
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.
Great catch @nolash. No implicit joining happens. I updated the code.
LGTM. Need one more review, I guess. Maybe even two, since we're now both complicit, @janos |
Thanks @nolash. I agree. Since I also edited this PR, my approval should not count, but it LGTM. |
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.
LGTM, rebase and submit to upstream
61ca22e
to
6fb6980
Compare
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.
@nolash generally LGTM
}) | ||
// \todo consider making a member of network, set to true threadsafe when shutdown | ||
runningOne := true | ||
defer func() { |
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.
use sync.Once
instead?
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.
well, I'm not sure it's clearer in this case. It would if both shutdowns were the same.
submitted upstream ethereum/go-ethereum#18287 |
This refactor was done as the second part of our current network testing efforts; as outlined in #1038. Co-authored-by: Elad Nachmias <theman@elad.im>
1478373
to
b5ee891
Compare
merged as ethereum/go-ethereum#18287 |
Pending merge of ethereum/go-ethereum#18220
This PR is part one of four PRs that adds test and benchmark to ensure that the snapshot connection content is correct upon creation, and that the correct connections are made after snapshot is loaded. All actual connections should be contained in snapshot, and all connections and only those connections should be in the network after load.
Part one creates the correctness test and adds a vanilla benchmark function.
Part two will move connection methods from
swarm/network/simulation
top2p/simulations
Part three will add a snapshot generation binary leveraging the different configurations provided by part two.
Part four will add exhaustive benchmarks with different snapshots generated from part three.
This PR also moved the
NoopService
from theswarm/network/simulation
package, since this minimal service is also useful for tests involvingp2p/simulations
directly.It also adds a "test" tag to the travis script, to enable build of symbols across packages needed for testing only.(linter script will apparently not easily work with build tags)