Commit graph

481 commits

Author SHA1 Message Date
Julian Knutsen
4dc4532c91
Remove isDataOwner from P2PDataStorage
Remove all usages in code and tests now that the behavior is
internal to the BroadcastHandler
2019-12-03 12:33:29 -08:00
Julian Knutsen
bfdb8f5715
Make isDataOwner a private policy decision in BroadcastHandler
isDataOwner is used when deciding how many peer nodes should receive
a BroadcastMessage. If the BroadcastMessage originated
on the local node it is sent to ALL peer nodes with a small delay.

If the node is only relaying the message (it originated on a different
node) it is sent to MAX(peers.size(), 7) peers with a delay that is
twice as long.

All the information needed to determine whether or not the
BroadcastMessage originated on the local node is available at the final
broadcast site and there is no reason to have callers pass it in.

In the event that the sender address is not known during broadcast (which
is only a remote possibility due to how early the local node address
is set during startup) we can default to relay mode.

This first patch just removes the deep parameters. The next will remove
everything else. There is one real change in LiteNodeNetworkService.java
where it was using the local node when it should have been using the
peer node. This was updated to the correct behavior.
2019-12-03 12:33:29 -08:00
Julian Knutsen
9f69134568
[REFACTOR] Clean up ClientAPI for refreshTTL
Remove isDataOwner from the client API. All users pass in true. All test
users don't care.
2019-12-03 12:30:07 -08:00
Julian Knutsen
77413c9671
[REFACTOR] Clean up ClientAPI for remove
Remove isDataOwner from the client API. All users pass in true. All test
users don't care.
2019-12-03 12:30:06 -08:00
Julian Knutsen
0e6b1a2044
[REFACTOR] Clean up ClientAPI for addProtectedStorageEntry
Remove isDataOwner from the client API. All users pass in true. All test
users don't care.
2019-12-03 12:30:06 -08:00
Julian Knutsen
56a7661a02
[REFACTOR] Clean up ClientAPI for addPersistableNetworkPayload
Now that more callers have moved internal, the public facing API
can be cleaner and more simple. This should lead to a more maintainable
API and less sharp edges with future development work.
2019-12-03 12:30:06 -08:00
Julian Knutsen
0649323505
Make addPersistableNetworkPayloadFromInitialRequest private
Now that the only user is internal, the API can be made private and the
tests can be removed. This involved adding a few test cases to
processGetDataResponse to ensure the invalid hash size condition was
still covered.
2019-12-03 12:30:05 -08:00
Julian Knutsen
4fe19aeec2
[DEADCODE] Remove old request handler tests
Now that all the implementations are unit tested in P2PDataStorage,
the old tests can be removed.
2019-12-03 12:20:42 -08:00
Julian Knutsen
b1a06fe4e2
Remove @Nullable around supportedCapabilities in PreliminaryGetDataRequest
The only two users of this constructor are the fromProto path which
now creates an empty Capabilities object similar to GetDataResponse.
The other internal usage of Capabilities.app which is initialized to empty.
2019-12-03 12:20:42 -08:00
Julian Knutsen
c503bcbaed
Remove @Nullable around supportedCapabilities in GetDataResponse
The only two users of this constructor are the fromProto path which
already creates an empty Capabilities object if one is not provided and
the internal usage of Capabilities.app which is initialized to empty.

Remove the @Nullable so future readers aren't confused.
2019-12-03 12:20:41 -08:00
Julian Knutsen
a0fae12068
Remove @Nullable around persistableNetworkPayloadSet
Checking for null creates hard-to-read code and it is simpler to just
create an empty set if we receive a pre-v0.6 GetDataResponse protobuf
message that does not have the field set.
2019-12-03 12:20:41 -08:00
Julian Knutsen
ecae31eddb
[RENAME] LazyProcessedPayload to ProcessOncePersistableNetworkPayload
Name is left over from previous implementation. Change it to be more
relevant to the current code and update comments to indicate the
current usage.
2019-12-03 12:20:41 -08:00
Julian Knutsen
5db128587f
[REFACTOR] Clean up processGetDataResponse
- Add more comments
- Use Clock instead of System
- Remove unnecessary AtomicInteger
2019-12-03 12:20:40 -08:00
Julian Knutsen
f92893b097
[TESTS] Write synchronization integration tests
Write a few integration test that exercises the exercise interesting
synchronization states including the lost remove bug. This fails
with the proper validation, but will pass at the end of the new feature
development.
2019-12-03 12:20:40 -08:00
Julian Knutsen
3d6e9fbef5
Remove static from initialRequestApplied
Previously, multiple handlers needed to signal off one global variable.
Now, that this check is inside the singleton P2PDataStorage, make it
non-static and private.
2019-12-03 12:20:40 -08:00
Julian Knutsen
a34488b735
[TESTS] Add unit tests for processGetDataResponse
Add a full set of unit tests that uncovered some unexpected
behavior w.r.t. signalers.
2019-12-03 12:20:39 -08:00
Julian Knutsen
690b9808b1
[TESTS] Make verify() functions more flexible
Now that we want to unit test the GetData path which has different
behavior w.r.t. broadcasts, the tests need a way to verify that
state was updated, but not broadcast during an add.

This patch changes all verification function to take each state update
explicitly so the tests can do the proper verification.
2019-12-03 12:20:39 -08:00
Julian Knutsen
873271c5ce
[REFACTOR] Introduce processGetDataResponse
Just a code move for now.
2019-12-03 12:20:39 -08:00
Julian Knutsen
c7bce9e999
[TESTS] Add test of RequestDataHandler::onMessage
Add heavy-handed test that exercises the logic to use as a safeguard
for refactoring.
2019-12-03 12:20:38 -08:00
Julian Knutsen
00128d912d
[BUGFIX] Fix off-by-one in truncation logic
Now, the truncation is only triggered if more than MAX_ENTRIES could
have been returned.
2019-12-03 12:20:38 -08:00
Julian Knutsen
e7673407f1
[REFACTOR] Remove duplication in filtering functions
Introduce a generic function that can be used to filter
Map<ByteArray, PersistableNetworkPayload> or
Map<ByteArray, ProtectedStorageEntry>.

Used to deduplicate the GetData code paths and ensure the logic is the
same between the two payload types.
2019-12-03 12:20:37 -08:00
Julian Knutsen
4c5d8184b7
[REFACTOR] Inline filtering functions
Removes unnecessary calculations converting Set<byte[]> into
Set<ByteArray> and allows additional deduplication of stream operations.
2019-12-03 12:20:37 -08:00
Julian Knutsen
3aaf8a285e
[REFACTOR] Inline capability check for ProtectedStorageEntries
Move the capability check inside the stream operation. This should
improve performance slightly, but more importantly it makes the
two filter functions almost identical so they can be combined.
2019-12-03 12:20:37 -08:00
Julian Knutsen
703a9a0ddd
[REFACTOR] Move required capabilities log
Move the logging function to the common capabilities check
so it can run on both ProtectedStoragePayload and
PersistableNetworkPayload objects
2019-12-03 12:20:36 -08:00
Julian Knutsen
caf946dfe0
Remove redundant HashSet lookups in filter functions
The appendOnlyDataStoreService and map already have unique keys that
are based on the hash of the payload. This would catch instances
where:

PersistableNetworkPayload
- None: The key is based on ByteArray(payload.getHash()) which is the
        same as this check.

ProtectedStorageEntry
- Cases where multiple PSEs contain payloads that have equivalent
  hashCode(), but different data.toProtoMessage().toByteArray().
  I don't think it is a good idea to keep 2 "unique" methods on
  payloads. This is likely left over from a time when
  Payload hashCode() needed to be different than the hash of
  the payload.
2019-12-03 12:20:36 -08:00
Julian Knutsen
5630b35755
[TESTS] Unit tests of buildGetDataResponse
Write a full set of unit tests for buildGetDataResponse. This provides
a safety net with additional refactoring work.
2019-12-03 12:20:36 -08:00
Julian Knutsen
dafc76200a
[REFACTOR] Pass peerCapabilities into buildGetDataResponse
Remove the dependence on the connection object by having the handler
pass in the peer's capabilities. This now allows unit testing of
buildGetDataResponse without any connection dependencies.
2019-12-03 12:20:35 -08:00
Julian Knutsen
a6e8868563
[REFACTOR] Extract truncation logging
Move the logging that utilizes connection information into the request
handler. Now, buildGetDataResponse just returns whether or not the list
is truncated which will make it easier to test.
2019-12-03 12:20:35 -08:00
Julian Knutsen
54021551bf
[REFACTOR] Extract getDataResponse logging
Changed the log to reference getDataResponse instead of getData. Now
that we might truncate the response, it ins't true that this is exactly
what the peer asked.
2019-12-03 12:20:35 -08:00
Julian Knutsen
8208f78837
[REFACTOR] Extract connectionInfo String 2019-12-03 12:20:34 -08:00
Julian Knutsen
944b3fffbc
[REFACTOR] Introduce buildGetDataResponse
This is just a strict move of code to reduce errors.
2019-12-03 12:20:34 -08:00
Julian Knutsen
daffe6dc38
[TESTS] Add tests of GetDataRequestHandler
Add some basic sanity tests prior to the refactor to help catch issues.
2019-12-03 12:20:34 -08:00
Julian Knutsen
a927ed42ac
[TESTS] Add tests of new RequestData APIs
These are identical test cases to the requestHandler tests, but with much
fewer dependencies. The requestHandler tests will eventually be deleted,
but they are going to remain throughout development as an extra safety
net.
2019-12-03 12:20:33 -08:00
Julian Knutsen
1e814d9f1d
[REFACTOR] Introduce buildGetDataRequest variants
As part of changing the GetData path, we want to move all creation
and processing of GetData messages inside P2PDataStorage. This will allow
easier unit testing of the behavior as well as cleaner code in the
request handlers that can just focus on nonces, connections, etc.
2019-12-03 12:20:33 -08:00
Julian Knutsen
5fcd18c4b5
[TESTS] Add tests of requestData
This will allow us to push the GetData creation inside P2PDataStorage
safely.
2019-12-03 12:20:28 -08:00
Christoph Atteneder
3b384172a4
Update data stores 2019-11-27 10:26:24 +01:00
Christoph Atteneder
9c3c6182c2
Refactor checkMaxConnections (#3126)
* Change access level for checkMaxConnections to be tested

* Refactor checkMaxConnections

Fix connection limit checks so as to prevent the following warning:

> WARN  b.n.p2p.peers.PeerManager: No candidates found to remove (That
case should not be possible as we use in the last case all
connections).

* Add MockNode that allows for simulating connections

* Add PeerManagerTest

The old PeerManagerTest was located under network/p2p/routing, which is
no longer the correct location. Additionally, it was outdated so I
just removed it and added a new file under network/p2p/peers containing
tests for checkMaxConnections.

* Add testCompile dependency to core

This is necessary because bisq.network.p2p.MockNode imports
bisq.core.network.p2p.seed.DefaultSeedNodeRepository.

* Update based on review feedback

Mock the SeedNodeRepository superclass, thus eliminating the dependency
to core.
2019-11-26 15:16:07 +01:00
Christoph Atteneder
b15eb70485
(8/8) Persist changes to ProtectedStoragePayload objects implementing PersistablePayload (#3640)
* [PR COMMENTS] Make maxSequenceNumberBeforePurge final

Instead of using a subclass that overwrites a value, utilize Guice
to inject the real value of 10000 in the app and let the tests overwrite
it with their own.

* [TESTS] Clean up 'Analyze Code' warnings

Remove unused imports and clean up some access modifiers now that
the final test structure is complete

* [REFACTOR] HashMapListener::onAdded/onRemoved

Previously, this interface was called each time an item was changed. This
required listeners to understand performance implications of multiple
adds or removes in a short time span.

Instead, give each listener the ability to process a list of added or
removed entrys which can help them avoid performance issues.

This patch is just a refactor. Each listener is called once for each
ProtectedStorageEntry. Future patches will change this.

* [REFACTOR] removeFromMapAndDataStore can operate on Collections

Minor performance overhead for constructing MapEntry and Collections
of one element, but keeps the code cleaner and all removes can still
use the same logic to remove from map, delete from data store, signal
listeners, etc.

The MapEntry type is used instead of Pair since it will require less
operations when this is eventually used in the removeExpiredEntries path.

* Change removeFromMapAndDataStore to signal listeners at the end in a batch

All current users still call this one-at-a-time. But, it gives the ability
for the expire code path to remove in a batch.

* Update removeExpiredEntries to remove all items in a batch

This will cause HashMapChangedListeners to receive just one onRemoved()
call for the expire work instead of multiple onRemoved() calls for each
item.

This required a bit of updating for the remove validation in tests so
that it correctly compares onRemoved with multiple items.

* ProposalService::onProtectedDataRemoved signals listeners once on batch removes

#3143 identified an issue that tempProposals listeners were being
signaled once for each item that was removed during the P2PDataStore
operation that expired old TempProposal objects. Some of the listeners
are very expensive (ProposalListPresentation::updateLists()) which results
in large UI performance issues.

Now that the infrastructure is in place to receive updates from the
P2PDataStore in a batch, the ProposalService can apply all of the removes
received from the P2PDataStore at once. This results in only 1 onChanged()
callback for each listener.

The end result is that updateLists() is only called once and the performance
problems are reduced.

This removes the need for #3148 and those interfaces will be removed in
the next patch.

* Remove HashmapChangedListener::onBatch operations

Now that the only user of this interface has been removed, go ahead
and delete it. This is a partial revert of
f5d75c4f60 that includes the code that was
added into ProposalService that subscribed to the P2PDataStore.

* [TESTS] Regression test for #3629

Write a test that shows the incorrect behavior for #3629, the hashmap
is rebuilt from disk using the 20-byte key instead of the 32-byte key.

* [BUGFIX] Reconstruct HashMap using 32-byte key

Addresses the first half of #3629 by ensuring that the reconstructed
HashMap always has the 32-byte key for each payload.

It turns out, the TempProposalStore persists the ProtectedStorageEntrys
on-disk as a List and doesn't persist the key at all. Then, on
reconstruction, it creates the 20-byte key for its internal map.

The fix is to update the TempProposalStore to use the 32-byte key instead.
This means that all writes, reads, and reconstrution of the TempProposalStore
uses the 32-byte key which matches perfectly with the in-memory map
of the P2PDataStorage that expects 32-byte keys.

Important to note that until all seednodes receive this update, nodes
will continue to have both the 20-byte and 32-byte keys in their HashMap.

* [BUGFIX] Use 32-byte key in requestData path

Addresses the second half of #3629 by using the HashMap, not the
protectedDataStore to generate the known keys in the requestData path.

This won't have any bandwidth reduction until all seednodes have the
update and only have the 32-byte key in their HashMap.

fixes #3629

* [DEAD CODE] Remove getProtectedDataStoreMap

The only user has been migrated to getMap(). Delete it so future
development doesn't have the same 20-byte vs 32-byte key issue.

* [TESTS] Allow tests to validate SequenceNumberMap write separately

In order to implement remove-before-add behavior, we need a way to
verify that the SequenceNumberMap was the only item updated.

* Implement remove-before-add message sequence behavior

It is possible to receive a RemoveData or RemoveMailboxData message
before the relevant AddData, but the current code does not handle
it.

This results in internal state updates and signal handler's being called
when an Add is received with a lower sequence number than a previously
seen Remove.

Minor test validation changes to allow tests to specify that only the
SequenceNumberMap should be written during an operation.

* [TESTS] Allow remove() verification to be more flexible

Now that we have introduced remove-before-add, we need a way
to validate that the SequenceNumberMap was written, but nothing
else. Add this feature to the validation path.

* Broadcast remove-before-add messages to P2P network

In order to aid in propagation of remove() messages, broadcast them
in the event the remove is seen before the add.

* [TESTS] Clean up remove verification helpers

Now that there are cases where the SequenceNumberMap and Broadcast
are called, but no other internal state is updated, the existing helper
functions conflate too many decisions. Remove them in favor of explicitly
defining each state change expected.

* [BUGFIX] Fix duplicate sequence number use case (startup)

Fix a bug introduced in d484617385 that
did not properly handle a valid use case for duplicate sequence numbers.

For in-memory-only ProtectedStoragePayloads, the client nodes need a way
to reconstruct the Payloads after startup from peer and seed nodes. This
involves sending a ProtectedStorageEntry with a sequence number that
is equal to the last one the client had already seen.

This patch adds tests to confirm the bug and fix as well as the changes
necessary to allow adding of Payloads that were previously seen, but
removed during a restart.

* Clean up AtomicBoolean usage in FileManager

Although the code was correct, it was hard to understand the relationship
between the to-be-written object and the savePending flag.

Trade two dependent atomics for one and comment the code to make it more
clear for the next reader.

* [DEADCODE] Clean up FileManager.java

* [BUGFIX] Shorter delay values not taking precedence

Fix a bug in the FileManager where a saveLater called with a low delay
won't execute until the delay specified by a previous saveLater call.

The trade off here is the execution of a task that returns early vs.
losing the requested delay.

* [REFACTOR] Inline saveNowInternal

Only one caller after deadcode removal.

* [TESTS] Introduce MapStoreServiceFake

Now that we want to make changes to the MapStoreService,
it isn't sufficient to have a Fake of the ProtectedDataStoreService.

Tests now use a REAL ProtectedDataStoreService and a FAKE MapStoreService
to exercise more of the production code and allow future testing of
changes to MapStoreService.

* Persist changes to ProtectedStorageEntrys

With the addition of ProtectedStorageEntrys, there are now persistable
maps that have different payloads and the same keys. In the
ProtectedDataStoreService case, the value is the ProtectedStorageEntry
which has a createdTimeStamp, sequenceNumber, and signature that can
all change, but still contain an identical payload.

Previously, the service was only updating the on-disk representation on
the first object and never again. So, when it was recreated from disk it
would not have any of the updated metadata. This was just copied from the
append-only implementation where the value was the Payload
which was immutable.

This hasn't caused any issues to this point, but it causes strange behavior
such as always receiving seqNr==1 items from seednodes on startup. It
is good practice to keep the in-memory objects and on-disk objects in
sync and removes an unexpected failure in future dev work that expects
the same behavior as the append-only on-disk objects.

* [DEADCODE] Remove protectedDataStoreListener

There were no users.

* [DEADCODE] Remove unused methods in ProtectedDataStoreService
2019-11-26 14:47:38 +01:00
Christoph Atteneder
62aea83308
Cleanup fmxlview and javax imports (#3661)
* Remove @FxmlView from abstract view classes

* Use generic javax imports for DI

* Additional cleanup of redundant DI annotations
2019-11-26 14:36:01 +01:00
Julian Knutsen
44a11a0619
[DEADCODE] Remove unused methods in ProtectedDataStoreService 2019-11-25 17:54:52 -08:00
Julian Knutsen
3503fe3b10
[DEADCODE] Remove protectedDataStoreListener
There were no users.
2019-11-25 17:54:52 -08:00
Julian Knutsen
f3faf4bb63
Persist changes to ProtectedStorageEntrys
With the addition of ProtectedStorageEntrys, there are now persistable
maps that have different payloads and the same keys. In the
ProtectedDataStoreService case, the value is the ProtectedStorageEntry
which has a createdTimeStamp, sequenceNumber, and signature that can
all change, but still contain an identical payload.

Previously, the service was only updating the on-disk representation on
the first object and never again. So, when it was recreated from disk it
would not have any of the updated metadata. This was just copied from the
append-only implementation where the value was the Payload
which was immutable.

This hasn't caused any issues to this point, but it causes strange behavior
such as always receiving seqNr==1 items from seednodes on startup. It
is good practice to keep the in-memory objects and on-disk objects in
sync and removes an unexpected failure in future dev work that expects
the same behavior as the append-only on-disk objects.
2019-11-25 17:54:52 -08:00
Julian Knutsen
66f71e59f8
[TESTS] Introduce MapStoreServiceFake
Now that we want to make changes to the MapStoreService,
it isn't sufficient to have a Fake of the ProtectedDataStoreService.

Tests now use a REAL ProtectedDataStoreService and a FAKE MapStoreService
to exercise more of the production code and allow future testing of
changes to MapStoreService.
2019-11-25 17:54:44 -08:00
Julian Knutsen
3d571c4ca3
[BUGFIX] Fix duplicate sequence number use case (startup)
Fix a bug introduced in d484617385 that
did not properly handle a valid use case for duplicate sequence numbers.

For in-memory-only ProtectedStoragePayloads, the client nodes need a way
to reconstruct the Payloads after startup from peer and seed nodes. This
involves sending a ProtectedStorageEntry with a sequence number that
is equal to the last one the client had already seen.

This patch adds tests to confirm the bug and fix as well as the changes
necessary to allow adding of Payloads that were previously seen, but
removed during a restart.
2019-11-25 08:13:49 -08:00
Julian Knutsen
6e2ea6e3ed
[TESTS] Clean up remove verification helpers
Now that there are cases where the SequenceNumberMap and Broadcast
are called, but no other internal state is updated, the existing helper
functions conflate too many decisions. Remove them in favor of explicitly
defining each state change expected.
2019-11-22 08:42:58 -08:00
Julian Knutsen
0472ffc794
Broadcast remove-before-add messages to P2P network
In order to aid in propagation of remove() messages, broadcast them
in the event the remove is seen before the add.
2019-11-22 08:35:57 -08:00
Julian Knutsen
931c1f47b4
[TESTS] Allow remove() verification to be more flexible
Now that we have introduced remove-before-add, we need a way
to validate that the SequenceNumberMap was written, but nothing
else. Add this feature to the validation path.
2019-11-22 08:16:02 -08:00
Justin Carter
d4e7f86ff6
Use generic javax imports for DI 2019-11-22 14:50:21 +01:00
Julian Knutsen
372c26de74
Implement remove-before-add message sequence behavior
It is possible to receive a RemoveData or RemoveMailboxData message
before the relevant AddData, but the current code does not handle
it.

This results in internal state updates and signal handler's being called
when an Add is received with a lower sequence number than a previously
seen Remove.

Minor test validation changes to allow tests to specify that only the
SequenceNumberMap should be written during an operation.
2019-11-20 16:31:56 -08:00
Julian Knutsen
526aee5ed4
[TESTS] Allow tests to validate SequenceNumberMap write separately
In order to implement remove-before-add behavior, we need a way to
verify that the SequenceNumberMap was the only item updated.
2019-11-20 16:31:56 -08:00