This updates the coinbase transactions to reward service nodes
periodically rather than every block. If you recieve a service node
reward this reward will be delayed x blocks, if you receive another
reward to the same wallet before those blocks have been completed it
will be added to your total and all will be paid out after those x
blocks has passed.
For example if our batching interval is 2 blocks:
Block 1 - Address A receives reward of 10 oxen - added to batch
Block 2 - Address A receives reward of 10 oxen - added to batch
Block 3 - Address A is paid out 20 oxen.
Batching accumulates a small reward for all nodes every block
The batching of service node rewards allows us to drip feed rewards
to service nodes. Rather than accruing each service node 16.5 oxen every
time they are pulse block leader we now reward every node the 16.5 /
num_service_nodes every block and pay each wallet the full amount that
has been accrued after a period of time (Likely 3.5 days).
To spread each payment evenly we now pay the rewards based on the
address of the recipient. This modulus of their address determines which
block the address should be paid and by setting the interval to our
service_node_batching interval we can guarantee they will be paid out
regularly and evenly distribute the payments for all wallets over this
All the encoding parts move to oxen-encoding recently; this updates to
the latest version of oxen-mq, adds oxen-encoding, and converts
everything to use oxenc headers rather than the oxenmq compatibility
shims.
Remove support for old (non-bt) proofs with the 9.2.0 snode revision
block (I'm not 100% sure on what to call this; "snode revision"? "soft
fork"? "spork"?).
Also bumps the working version to 9.2.0; this likely isn't release
ready, but allows for testing of this on testnet.
Snode revisions are a secondary version that let us put out a mandatory
update for snodes that isn't a hardfork (and so isn't mandatory for
wallets/exchanges/etc.).
The main point of this is to let us make a 9.2.0 release that includes
new mandatory minimums of future versions of storage server (2.2.0) and
lokinet (0.9.4) to bring upgrades to the network.
This slightly changes the HF7 blocks to 0 (instead of 1) because,
apparently, we weren't properly checking the HF value of the
pre-first-hf genesis block at all before. (In practice this changes
nothing because genesis blocks are v7 anyway).
This also changes (slightly) how we check for hard forks: now if we skip
some hard forks then we still want to know the height when a hard fork
triggers. For example, if the hf tables contains {7,14} then we still
need to know that the HF14 block height also is the height that
activates HF9, 10, etc.
It works just like storage server testing.
Renames the report_peer_storage_server_status to report_peer_status, and
repurposes the code to handle both SS and lokinet.
This *doesn't* need a HF by design because the reason bit field was
deliberately designed so that we can add reason fields (older clients
will just ignore unknown bits).
The timestamp inside the proof is only for signature validation, but we
were using it in some places as the uptime proof time, but not updating
it everywhere we needed to. This fixes it by using our own timestamp
for all local timed events (e.g. when we received it, when the node is
not sending proofs, etc.) to fix the issue.
This moves all the responsibility of ping testing (deciding when it's
unreachable, etc.) into oxend, allowing for better reporting on SS ping
results and eliminating some edge cases that can lead to oxend and
storage server getting "stuck" thinking each is in a different state.
Improves the oxend<->storage server communications protocol:
- pass storage server HTTPS port as part of the storage server ping
(which already carries the also-required OMQ port) rather than needing
to provide it when starting up oxend. --storage-server-port is now
obsolete (and ignored, if specified).
- Fix up the internal API to use `storage_https_port` and
`storage_omq_port` rather than `storage_port` and `storage_lmq_port`.
- Redo and the SS ping RPC endpoint so that it is less verbose and more
closely matches the lokinet endpoint; instead of:
{ "version_major": 2, "version_minor": 0, "version_patch": 9, "storage_lmq_port": 22222 }
we now expect:
{ "version": [2,0,9], "https_port": 11111, "omq_port": 22222 }
- Tweaks the (not-yet-released) SS proof key names: "s"->"shp" and "slp"->"sop"
This makes uptime proof times network-dependent, and tweaks them a bit.
Also converts the times to type-safe std::chrono types rather than
macros.
Mainnet/testnet/devnet:
- Send the first proof 30s after startup rather than waiting 2 minutes.
- Check for whether we need to send a proof every 30s rather than every
5mins.
Mainnet:
Other times unchanged.
Testnet/devnet:
- Send proofs every 10min instead of 1h, and consider nodes to be down
after 21m instead of 2h5m.
Fakechain:
- Send 5s after startup, check every 5s, and send every 1min.
- Expiry after 2min5s
Also remove the cmake debug option for short proofs since the fakechain
changes above basically incorporate what it did.
random sampling of service nodes, call timestamp lmq message
checks timestamp of 5 service nodes, if local time is 30 seconds different from 80% of the nodes tested then warn user
tracks external timesync status and timestamp participation of service nodes
clean up includes
new template struct for participation history, individual types for participation entry
refactor checking participation
update select_randomly, move the testing for variance overflow
version locks, bump to 8.1.5
explicit casting for mac & clang
note to remove after hard fork
timestamp debugging log messages
debugging messages for before timesync - before message sent
logging errord with compiling
print version and change add_command to add_request_command
log if statement test
std::to_string replaced with tools::view_guts for x25519 key
check if my sn is active before sending timestamp requests
logging the failures
checking if statement for success of message
more logging, if guards arn't passing
more logging, successfully tests if service node might be out of sync
more tests before we decide we are out of sync
logging output if sn isn't passing tests
if check_participation fails then disconnect
print timestamp status
remove saving variance from the participation history
reduce MIN_TIME_IN_S_BEFORE_VOTING
reset participation history on recommission
undo reduction in startup time
reduce log levels
Set hardfork time in testnet
There is no reason at all to sign a *different* message in every stake
unlock; signatures already have their own nonce.
Having something that serves no purpose is worse than not having it
(because it leads to questions about why such a thing is there), so this
commit removes it by always using 0 as a nonce and comments about it.
Removing this from the broadcast tx would require a new tx extra field
so that isn't worth doing for now (but can be done in the future if we
change the tx extra structure for unlocks).
This also simplifies the nonce-to-hash code and fixes an endian bug in
it.
We use generate_ring_signature and check_ring_signature somewhat
inappropriately to sign and check a signature of a single key image.
While it works for that, the full ring signature algorithm adds quite a
bit of complexity that we don't need (and simply doesn't run) for the
key image proof included in stake transactions and exported key images
from the wallet.
This splits it up, makes the key image interface considerably simpler,
and adds annotation comments through it (and also adds comments into the
"main" signature code).
This is a necessary step to getting stake transactions and key image
exports working with Ledger, without implementing the full ring
signature (because that is quite involved, and not needed for most of
these cases).
Also remove unused gen/check_ring_signatures interfaces: The raw pointer
code is never called, except through the vector version and one place in
the test suite, so just remove it and make the vector version the main
implementation.
When targetting macos <10.14 macos won't allow use of anything from
C++17 that throws, such as:
- std::get on a variant
- std::visit
- std::optional::value()
- std::any_cast
This avoids all of these.
For std::get, we either replace with std::get_if (where appropriate), or
else use a `var::get` implementation of std::get added to lokimq (also
updated here). (This `var` namespace is just an `std` alias everywhere
*except* old target macos).
For std::visit, likewise lokimq adds an var::visit implementation for
old macos that we use.
std::optional::value() uses weren't useful anyway as everywhere it calls
them we've already checked that the option has a value, in which case we
can use `*opt` (which doesn't check for contents and throw).
std::any just has to be avoided as far as I can tell, but the one place
we used it is only ever a block, so I just replaced it with a `const
block*`.
- Currently nodes that have updated over time will have seeded their
sort key to a different value than everyone else, causing everone to
generate Pulse quorums that are inconsistent with each other.
Instead, set the sort key to 0. Ties in the sort list are currently
dealt with by sorting on the public key itself.
This changes the `get_quorum_state` RPC endpoint in two ways:
- If requesting a pulse quorum for a height that includes the current
height (i.e. top block + 1), this returns the current height, round-0
pulse quorum.
- When requesting the latest quorum state (i.e. the no-argument request)
you now get back the latest available quorum of each requested type,
instead of the quorum for the latest available block. Thus requesting
all types will now give you:
- the current top-of-the-chain round-0 pulse quorum
- the top block obligations quorum (no change)
- the top divisible-by-4 block for checkpoint quorums
- the top divisible-by-5 block for blink quorums
Previously you would just get whatever quorums existing for the top
height, which often meant just the one-old pulse quorum + top block
obligations quorum, only only checkpoint 25% of the time and blink 20%
of the time.
- Also updated the RPC comments for GET_QUORUM_STATE, both to reflect
the above and to update some parts which were a bit stale.
- We also remove the distinction between service_node_total and
service_node_paid. Previously the portions payout may still have some
remainder dust loki that was not distributed, and or distributed to the
miner as the difference between the pay out and the base reward was
added to the miner.
This is still the case for backwards compatibility before HF16. After
HF16, dust is not allowed and everything is split with the remainder
dust going to the 1st contributor in the Service Node (the operator).
- Avoid situations where rescanning/syncing the chain pre records the
node participation when it may not be relevant anymore (i.e. someone
restarting their node would re-record historical non-participation in
blocks and prime them for re-voting off a particular node).
- Instead of the Pulse quorums validators recording participation
between each other- so failures may not manifest in a decommission until
the several common nodes align and agree to vote off the node.
Voting now occurs when blocks arrives, validators participating in the
generation of the block are marked. This is shared information between
all nodes syncing the chain so decommissions are more readily agreeable
and acted upon in the Obligation quorums immediately.
The reward pre-hf16 is removed from the miner as they are the block
producer. After Pulse, the block producer changes to the Service Node.
Here we subtract the penalty from the Service Node Leader (the node at
the top of the Service Node List irrespective of round or even after PoW
the fallback).
https://github.com/loki-project/loki-core/issues/1267
The miner reward includes atomic dust resulting from truncation errors
of the other amounts, so this test for exact miner amounts failed (on
current mainnet blocks, particularly ones with lots of SN reward
recipients where such dust is likely).
- 0 amount outputs can still be generated if the portions was too low
for splitting the reward amount. An example where this can happen is on
alternative rounds, splitting the TX fee to the alternative quorum, if
the portions is too low we could potentially get a 0 output which would
be interpreted as RCT and cause some bugs on the chain.
The fix here is always check each output is > 0 before generating the
output in the miner tx.
- Also explicitly check the miner output amount when validating miner
transactions. Previously we only check the sum of the outputs match the
total expected amounts, and the service node outputs match our expected
rewards (and so i.e. no explicit checking on miner amount at any point).
- Avoid generating any outputs on an alternative round, for the
alternative block producer if the total tx fee was 0.
- Remove the 1 atomic loki awarded to the miner in HF16 (previously kept
to 1 for making sure tests work, whilst implementing the new block
reward split)