sodium and zmq libs weren't using the same variable name which would end
up linking to system libsodium even when we meant to link to the static
one from contrib/depends.
quorum_vote_t's were serialized as blob data, which is highly
non-portable (probably isn't the same on non-amd64 arches) and broke
between 5.x and 6.x because `signature` is aligned now (which changed
its offset and thus broke 5.x <-> 6.x vote transmission).
This adds a hack to write votes into a block of memory compatible with
AMD64 5.x nodes up until HF14, then switches to a new command that fully
serializes starting at the hard fork (after which we can remove the
backwards compatibility stuff added here).
Checkpoint votes internally use a circular buffer, but that's rather
difficult to read for the `print_sn` output; this changes print_sn to
de-circularize the listed votes.
If a block adding fails (triggering the "Block added hook signalled
failure" error message) the service node list doesn't get reset, which
immediately leads to a bad service node winner (because the winner was
already incremented and not popped off).
This updates it to call the blockchain detached hooks to do the cleanup.
It also changes around loki::defer a little bit to rename the internal
class to `deferred` and make it cancellable (by calling `.cancel()`).
`loki::defer` is repurposed as a free function to get a named `deferred`
object given a lambda, which is needed to be able to call `cancel()` on
it. (The LOKI_DEFER macro still works as is).
The argument order felt wrong: switch it to (NAME, TYPE, FUNC)
Since register_command is meant to be called statically there is little
purpose in being able to accept a non-function-pointer callback (i.e.
direct function or capture-less lambda), so drop using std::function<>'s
for command callbacks to avoid the virtual call overhead.
Changes commands from two types (quorum & public) to three:
- anyone -> service node (SNNetwork::command_type::public_)
- service node -> anyone (SNNetwork::command_type::response)
- service node -> service node (command_type::quorum)
Previously quorum commands could be issued to non-SN nodes, but that
should not be allowed (and the code would dereference a nullptr if that
happened).
macOS's std::lock() is broken in that it internally calls non-namespaced
function `try_lock` leading to an ADL conflict with boost::try_lock when
any of the arguments is a `boost::whatever`. `boost::lock` will do the
job for now.
The m_blockchain lock added in #975 was causing deadlocks because we
have ordered `m_blockchain -> ... -> m_sn_mutex` lock sequences but
`proof.store()` was adding a `m_sn_mutex -> ... -> m_blockchain`
sequence when called when receiving an uptime proof. Fix it by also
taking out an m_blockchain lock where we take out the `m_sn_mutex`.
auto locks = tools::unique_locks(mutex1, mutex2, ...);
gives you a tuple of unique_locks and obtains the locks atomically.
auto lock = tools::unique_lock(lock1);
is essentially the same as:
std::unique_lock<decltype(lock1)> lock{lock1};
but less ugly (and extends nicely to the plural version).
* Simplify and avoid uninitialized value warning
Rearranging/simplifying this code slightly to avoid gcc giving a
possibly-uninitialized value use on the dereference that follows this
changed code.
* More simplification: don't need optional
Apparently it's not safe to use "transactions" in the LMDB without first
taking out an exclusive lock on the Blockchain class. Transactions
apparently aren't actually transactions, they are just fatal errors that
forever deadlock the database if you try to take two write transactions
at once.
Work around this terrible design by adding the appropriate magic
incantation.
Current when a blink gets mined it just looks like an ordinary
transaction, but this isn't right: it's still a blink with special
status until it gets checkpointed.
loki started life with transfer details serialization version 9, so we
can drop the stuff to handle earlier versions. Also this code structure
that repeats a call to `initialize_transfer_details` 100 times is gross,
so fix it.
If we've previously printed some alerts about not submitting proofs
because of lokinet/storage server it's nice to print a message as soon
as we get the needed ping. Also nice to see on startup for the first
one to know things are working.
Checkpoint votes were only going over quorumnet, which was quite broken
as they need to go out universally: random nodes piece together the
individual checkpoints to create checkpoints on their own, and so need
to see all of the votes. With the current code only service nodes that
participated in the specific quorum ever saw the checkpoint votes.
This commit returns checkpoint vote distribution to distribution over
p2p.
We could, in theory, do checkpoint vote collection over quorumnet and
then relay the set of votes as a pack to reduce p2p traffic a bit, but
this wouldn't be a huge optimization since we'd still have to distribute
all the votes over p2p at some point anyway, so leaving that as a future
optimization for now.
(Obligations votes, in contrast, don't need to be distributed at all --
if a vote results in a state change, the quorum members themselves can
produce and distribute the state change tx).
`update_checkpoint` was being set to true whenever we don't have enough
signatures, but it really should only be set to true when we don't have
enough signatures *and* we insert one (otherwise we can end up calling
`update_checkpoint` even when we have nothing to update). It looks like
this was the intention of the inner-loop `update_checkpoints = true`
already, so this removes the outer assignment and keeps the inner loop
assignment.
Also import boost::endian namespace because the boost::endian's
throughout the file were needlessly verbose (the little_to_native calls
are already obvious).