- We avoid generating outputs if the amount is 0 (0 miner rewards in
HF16, alternative rounds with no tx's have 0 fees awarded)
- Adjust the time catch/delay mechanism for Pulse from 15s to 30s.
- Alternative pulse blocks must be verified against the quorum they belong to.
This updates alt_block_added hook in Service Node List to check the new Pulse
invariants and on passing allow the alt block to be stored into the DB until
enough blocks have been checkpointed.
- New reorganization behaviour for the Pulse hard fork. Currently reorganization
rules work by preferring chains with greater cumulative difficulty and or
a chain with more checkpoints. Pulse blocks introduces a 'fake' difficulty to
allow falling back to PoW and continuing the chain with reasonable difficulty.
If we fall into a position where we have an alt chain of mixed Pulse blocks
and PoW blocks, difficulty is no longer a valid metric to compare blocks (a
completely PoW chain could have much higher cumulative difficulty if hash
power is thrown at it vs Pulse chain with fixed difficulty).
So starting in HF16 we only reorganize when 2 consecutive checkpoints prevail
on one chain. This aligns with the idea of a PoS network that is
governed by the Service Nodes. The chain doesn't essentially recover until
Pulse is re-enabled and Service Nodes on that chain checkpoint the chain
again, causing the PoW chain to switch over.
- Generating Pulse Entropy no longer does a confusing +-1 to the height dance
and always begins from the top block. It now takes a block instead of a height
since the blocks may be on an alternative chain or the main chain. In the
former case, we have to query the alternative DB table to grab the blocks to
work.
- Removes the developer debug hashes in code for entropy.
- Adds core tests to check reorganization works
- Change get_next_difficulty_for_alternative_chain to
get_difficulty_for_alternative_chain to match
get_difficulty_for_next_block. This was an annoying function to find
because of the irregular naming scheme was different from the canonical
difficulty function.
- Pulse blocks will forcibly get the difficulty set to
1'000'000 * TARGET_BLOCK_TIME throughout time
- When PoW is required again, the past window of blocks will use these
difficulties, i.e. setup the chain for mining at 1'000'000 difficulty
which is easily mineable to continue the network and continue to pull
difficulties from the new-er mined blocks until the network is ready
for Pulse again.
- Difficulty is still necessary for falling back to mining when Pulse
fails. Switching between the two systems seamlessly can be done by
continuing to set the difficulty for Pulse blocks.
Changes naming scheme
- Block Producer: The Service Node/Miner reponsible for generating the block
- Block Leader: The Service Node that is at the top of the Service Node
List queue. They are also by default on pulse round 0, the block producer.
If that round fails, then the block producer is changed as per the LIP-6
with multi-block seeding.
This commit also re-writes validate miner TX to repeat some of the
verification code. This appears to be clearer than having multiple
variables that change the verification loop in small ways which was more
error prone than I'd like to tolerate.
With Service Node List now generating 2 coinbase rewards, block_winner
is ambiguous, so, distinguish the reward generated for nodes at the top
of the queued list as- queued_winner.
Merging payout entries can be done when batching is implemented instead
of drilling down too deep in implementation too early before the other
parts of Pulse are fleshed out.
- Remove PoW/Difficulty information for Pulse Block printout
- Use unary + to co-erce char's in ostreams
- Avoid epee::string_tools::pod_to_hex for lokimq equivalent
- Express validator bitmask in terms of PULSE_QUORUM_NUM_VALIDATORS
- Fix bug in generating Pulse Quorum, avoiding the use of the 0th
service node in pulse_candidates
- Switch to std::any for void * context
- By merging the quorum verification with pre-existing checkpointing
code, checkpoints votes are currently being sorted by the vote index
order. This was also enforced on the pulse signatures.
- Add opt-in tx-extra parsing to `get_transactions`; this now lets you
get most tx details (including service node tx info) via the RPC.
- Add ability for RPC block header requests to include a list of tx
hashes contained in the block.
- remove long-deprecated txs_as_hex from `get_transactions`: this
essentially doubled the length of requests since txs[i].as_hex has the
exact same data. Despite this being the "new" format for several
years, wallet code was still relying on the "old" format. Since 8.x
already breaks the RPC, this seems a good time to remove it.
- Significantly cleaned up and documented how pruned transactions
results are returned in GET_TRANSACTIONS. Previously it was fairly
uncertain when you'd get a pruned or unpruned transaction. (See
comments added in core_rpc_server_commands_defs.h)
- Stop returning the transaction data hex values when you ask for
`decode_as_json`. The documentation already implied you don't get
it, but you do, and this is virtually always just wasted extra data
when you're asking for the json-decoded value.
- fix miner txes being treated in the RPC as pruned transactions (they
aren't: they just have no prunable data).
- Made a bunch of `get_transactions` fields (including virtually all of
the new parsed tx-extras fields) into std::optional's so that the keys
aren't included when the values are empty.
- Fix bug in `get_transactions` that raised an exception if *some* (but
not all) of the requested transactions were missed. Previously you
could only get all-missed, all-found, or an exception.
Currently all the variables in here need to be added into every
compilation unit; C++17 inline constexpr avoids that by throwing away
the duplicates at link time, plus lets the compiler optimize things
away.
Also eliminates a side effect in `get_config()` that mutated the
variable (so that one `get_config()` would end up changing the data of a
previous `get_config()`). Instead `get_config()` is now always constant
and doesn't care about the hard fork version; instead there is a
convenience method to get the governance wallet_address which takes the
hf version.
This purges epee::critical_region/epee::critical_section and the awful
CRITICAL_REGION_LOCAL and CRITICAL_REGION_LOCAL1 and
CRITICAL_REGION_BEGIN1 and all that crap from epee code.
This wrapper class around a mutex is just painful, macro-infested
indirection that accomplishes nothing (and, worse, forces all using code
to use a std::recursive_mutex even when a different mutex type is more
appropriate).
This commit purges it, replacing the "critical_section" mutex wrappers
with either std::mutex, std::recursive_mutex, or std::shared_mutex as
appropriate. I kept anything that looked uncertain as a
recursive_mutex, simple cases that obviously don't recurse as
std::mutex, and simple cases with reader/writing mechanics as a
shared_mutex.
Ideally all the recursive_mutexes should be eliminated because a
recursive_mutex is almost always a design flaw where someone has let the
locking code get impossibly tangled, but that requires a lot more time
to properly trace down all the ways the mutexes are used.
Other notable changes:
- There was one NIH promise/future-like class here that was used in
example one place in p2p/net_node; I replaced it with a
std::promise/future.
- moved the mutex for LMDB resizing into LMDB itself; having it in the
abstract base class is bad design, and also made it impossible to make a
moveable base class (which gets used for the fake db classes in the test
code).
When you have a comment just before your thread pool initialization that
reads:
// we only need 1
that is a pretty good indicator that you don't need a thread *pool* for
the thing you are doing.
Replace it with a single std::thread.
common/util.h has become something of a dumping ground of random
functions. This splits them up a little by moving the filesystem bits
to common/file.h, the sha256sum functions to common/sha256sum.h, and the
(singleton) signal handler to common/signal_handler.h.
A huge amount of this is repetitive:
- `boost::get<T>(variant)` becomes `std::get<T>(variant)`
- `boost::get<T>(variant_ptr)` becomes `std::get_if<T>(variant_ptr)`
- `variant.type() == typeid(T)` becomes `std::holds_alternative<T>(variant)`
There are also some simplifications to visitors using simpler stl
visitors, or (simpler still) generic lambdas as visitors.
Also adds boost serialization serializers for std::variant and
std::optional.