Commit graph

185 commits

Author SHA1 Message Date
Jason Rhinelander
b627b3b4bb Move epee includes under "epee/..."
This ends epee's include pollution.
2020-10-24 12:46:27 -03:00
Jason Rhinelander
1dd98f3dae std::filesystem
Converts all use of boost::filesystem to std::filesystem.

For macos and potentially other exotic systems where std::filesystem
isn't available, we use ghc::filesystem instead (which is a drop-in
replacement for std::filesystem, unlike boost::filesystem).

This also greatly changes how we handle filenames internally by holding
them in filesystem::path objects as soon as possible (using
fs::u8path()), rather than strings, which avoids a ton of issues around
unicode filenames.  As a result this lets us drop the boost::locale
dependency on Windows along with a bunch of messy Windows ifdef code,
and avoids the need for doing gross boost locale codecvt calls.
2020-10-24 12:45:37 -03:00
Jason Rhinelander
b7dd5e8911 Target macos 10.12
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*`.
2020-10-18 11:18:08 -03:00
Doyle
320e999be7 Pulse: Apply block limit penalty on SN reward
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
2020-09-23 10:25:40 +10:00
Jason Rhinelander
caf5e59984 Merge branch 'pulse' into dev 2020-09-18 17:40:25 -03:00
Jason Rhinelander
9b196322f4 Init quorumnet to make tests work 2020-09-18 14:03:53 -03:00
Doyle
9c4aa8fa2a tests: Set txn fee more accurately for new coinbase checks 2020-09-18 13:50:06 -03:00
Doyle
c7edbe0557 tests: Fix old reorg tests not working HF16 reorg rules
- After HF16 reorgs only happen with checkpoints, prior is PoW
+ checkpoints, and earlier than that is PoW only.
2020-09-18 13:50:05 -03:00
Doyle
65cd0faaf2 Pulse: Handle alternative block reorg with Pulse blocks
- 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
2020-09-18 13:50:05 -03:00
Doyle
d0b743d667 Pulse: Pull blocks by header in rescan, avoid extra copies 2020-09-18 13:50:05 -03:00
Jason Rhinelander
30480bedee Lokinet LNS
Revamps how .loki LNS registrations work:

- Enable lokinet registrations beginning at HF16.

- rework renewal so that you can renew at any time and it simply adds to the end of the current
  expiry.  Previously there was only a window in which you could renew.

- Renewals are a new type of LNS transaction, distinct from buys and updates.  (Internally it is an
  update with no fields, which cannot be produced in the existing code).

- Add optional "type=" parameter to lns commands.  Commands default to trying to auto-detect (i.e.
  if the name ends with .loki it is lokinet), but the type allows you to be explicit *and* allows
  select non-default registration lengths for lokinet buys/renewals.

- change .loki naming requirements: we now require <= 32 chars if it doesn't contain a -, and 63 if
  it does.  We also reserve names starting "??--" for any ?? other than xn-- (punycode), as this is
  a DNS restriction.  "loki.loki" and "snode.loki" are also now reserved (just in case someone
  sticks .loki as a DNS search domain).

- Tweak LNS registration times to consider "a year" to be 368 days worth of blocks (to allow for
  leap years and some minor block time drift).

- Overhaul how LNS registrations are displayed in the cli wallet.  For example:

    [wallet L6QPcD]: lns_print_name_to_owners jasonv.loki jason.loki jasonz.loki
    Error: jasonv.loki not found

    Name: jason.loki
        Type: lokinet
        Value: azfoj73snr9f3neh5c6sf7rtbaeabyxhr1m4un5aydsmsrxo964o.loki
        Owner: L6QPcDVp6Fu7HwtXrXjtfvWvgBPvvMQ9FiyquMWn2BBEDsk2vydwu1A3BrK2uQcCo94G7HA5xiKvpZ4CMQva6pxW2GXkCG9
        Last updated height: 46
        Expiration height: 75
        Encrypted value: 870e42cd172a(snip)

    Error: jasonz.loki not found

- Add an RPC end-point to do simple LNS resolution; you can get the same info out of
  names-to-owners, but the new lns_resolve end-point is considerably simpler for doing simple
  lookups (e.g. for lokinet), and allows for a simpler SQL query + processing.

Code changes:

- Rename mapping_type::lokinet_1year to mapping_type::lokinet (see next point).

- Don't store lokinet_2y, etc. in the database, but instead always store as type=2/::lokinet.  The
  LNS extra data can still specify different lengths, but this now just affects the
  expiration_height value that we set.

- Reworked some binding code to use std::variant's and add a bind_container() to simplify passing in
  a variable list of bind parameters of different types.

- Accept both base64 and hex inputs for binary LNS parameters in the RPC interface.

- This commit adds some (incomplete) expiry adjustment code, but ignore it as it all gets replaced
  with the following commit to overhaul record updating.

- Updated a bunch of test suite code, mainly related to lokinet.

- Some random C++17 niceties (string_view, variant, structured binding returns) in the related code.

- Tweaked the test suite to generate a bit fewer blocks in some cases where we just need to
  confirm/unlock a transfers rather than a coinbase tx.
2020-09-17 10:24:48 -03:00
Jason Rhinelander
7f8cc65b2a Make debug log level tests less noisy 2020-09-17 10:24:09 -03:00
Doyle
6eadb17dee
Merge pull request #1258 from jagerman/update-deps
Update deps
2020-09-17 13:51:22 +10:00
Jason Rhinelander
61a9a14e7b Init quorumnet to make tests work 2020-09-16 21:38:07 -03:00
Jason Rhinelander
d697903bf0 Fix tests
- CLSAG handling was being missed in some test suite code
- quorumnet initialization wasn't being done
2020-09-16 20:45:09 -03:00
Jason Rhinelander
82514b9956 Construct LNS txes with no destination (the way the wallet does) 2020-09-16 20:43:52 -03:00
Doyle
62fe4db413 config: Convert DIFFICULTY_BLOCKS_V2 to TARGET_BLOCK_TIME 2020-08-18 11:59:53 +10:00
Doyle
457fd4d027 Pulse: Change queued_winner->block_leader, verify alt round rewards
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.
2020-08-18 11:59:53 +10:00
Doyle
2189bd29aa tests: Adjust tests to work with leader validation 2020-08-18 11:59:53 +10:00
Doyle
95a2ae88bc service_nodes: Rename block_winner to payouts
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.
2020-08-18 11:59:53 +10:00
Doyle
8938003027 Pulse: Setup miner_tx to handle pulse/miner block producers 2020-08-18 11:59:53 +10:00
Doyle
0a53182ad6 tests: Check that miner blocks fails when Pulse is avail 2020-08-18 11:59:53 +10:00
Doyle
7883c875e0 Pulse: Support rounds changing the leader/validators in blocks
- Previously we generated quorums based off the previous quorum. To
  incorporate the round, we can no longer pre-compute the quorum.
  Instead it must be calculated when the block arrives, just before the
  Service Node List is changed.
- Add tests to check round changing works
2020-08-18 11:59:53 +10:00
Doyle
62ad3d603e tests: Update pulse validation tests 2020-08-18 11:59:53 +10:00
Doyle
0abb47848a tests: Divide create_block into begin_block/end_block pair
Allows us to insert custom pulse data inbetween the begin and end pairs
by separating the SN list update step (which relies on the block) from
the block miner TX/TX list construction step.
2020-08-18 11:59:53 +10:00
Doyle
a9f1d1c5de Tests: Fix test entropy using wrong height
- Entropy is taken from the blockchain height, (i.e. if top block is block
  100, then the blockchain height is 101). When the Core Tests is generating
  a block in the tests, we haven't added the block to the DB yet, so when
  db.height() is called in the tests, the height returned is 100.

  Whereas when the Blockchain is receiving a block and on validation,
  block 100, has been added to the DB already (added to DB, then we do
  Service Node List validation). So the DB returns a blockchain height of
  101. The 2 inconsistencies causes differences in the source entropy
  for the blockchain.

- Begin moving code to allow creating blocks with custom pulse data in
  tests by introducing loki_create_block_params. The workflow is to get
  loki_chain_generator to return you the parameters to form the next
  valid block. The user can modify the parameters to other valid
  blocks/invalid blocks.

- Change the stable sort to a normal sort to avoid requiring the caller
  side of the API needing to implicitly know that the list given must
  be sorted lexicographically.
2020-08-18 11:59:53 +10:00
Doyle
475ed74b28 Pulse: Move verification to block. Add support to core tests.
Verification needs to go to the block, not the header to ensure it does
not get included in the block hash.
2020-08-18 11:59:53 +10:00
Jason Rhinelander
42a7e83c33 Replace epee http rpc server with uWebSockets
This replaces the NIH epee http server which does not work all that well
with an external C++ library called uWebSockets.  Fundamentally this
gives the following advantages:

- Much less code to maintain
- Just one thread for handling HTTP connections versus epee's pool of
threads
- Uses existing LokiMQ job server and existing thread pool for handling
the actual tasks; they are processed/scheduled in the same "rpc" or
"admin" queues as lokimq rpc calls.  One notable benefit is that "admin"
rpc commands get their own queue (and thus cannot be delayed by long rpc
commands).  Currently the lokimq threads and the http rpc thread pool
and the p2p thread pool and the job queue thread pool and the dns lookup
thread pool and... are *all* different thread pools; this is a step
towards consolidating them.
- Very little mutex contention (which has been a major problem with epee
RPC in the past): there is one mutex (inside uWebSockets) for putting
responses back into the thread managing the connection; everything
internally gets handled through (lock-free) lokimq inproc sockets.
- Faster RPC performance on average, and much better worst case
performance.  Epee's http interface seems to have some race condition
that ocassionally stalls a request (even a very simple one) for a dozen
or more seconds for no good reason.
- Long polling gets redone here to no longer need threads; instead we
just store the request and respond when the thread pool, or else in a
timer (that runs once/second) for timing out long polls.

---

The basic idea of how this works from a high level:

We launch a single thread to handle HTTP RPC requests and response data.
This uWebSockets thread is essentially running an event loop: it never
actually handles any logic; it only serves to shuttle data that arrives
in a request to some other thread, and then, at some later point, to
send some reply back to that waiting connection.  Everything is
asynchronous and non-blocking here: the basic uWebSockets event loop
just operates as things arrive, passes it off immediately, and goes back
to waiting for the next thing to arrive.

The basic flow is like this:

    0. uWS thread -- listens on localhost:22023
    1. uWS thread -- incoming request on localhost:22023
    2. uWS thread -- fires callback, which injects the task into the LokiMQ job queue
    3. LMQ main loop -- schedules it as an RPC job
    4. LMQ rpc thread -- Some LokiMQ thread runs it, gets the result
    5. LMQ rpc thread -- Result gets queued up for the uWS thread
    6. uWS thread -- takes the request and starts sending it
       (asynchronously) back to the requestor.

In more detail:

uWebSockets has registered has registered handlers for non-jsonrpc
requests (legacy JSON or binary).  If the port is restricted then admin
commands get mapped to a "Access denied" response handler, otherwise
public commands (and admin commands on an unrestricted port) go to the
rpc command handler.

POST requests to /json_rpc have their own handler; this is a little
different than the above because it has to parse the request before it
can determine whether it is allowed or not, but once this is done it
continues roughly the same as legacy/binary requests.

uWebSockets then listens on the given IP/port for new incoming requests,
and starts listening for requests in a thread (we own this thread).
When a request arrives, it fires the event handler for that request.
(This may happen multiple times, if the client is sending a bunch of
data in a POST request).  Once we have the full request, we then queue
the job in LokiMQ, putting it in the "rpc" or "admin" command
categories.  (The one practical different here is that "admin" is
configured to be allowed to start up its own thread if all other threads
are busy, while "rpc" commands are prioritized along with everything
else.)  LokiMQ then schedules this, along with native LokiMQ "rpc." or
"admin." requests.

When a LMQ worker thread becomes available, the RPC command gets called
in it and runs.  Whatever output it produces (or error message, if it
throws) then gets wrapped up in jsonrpc boilerplate (if necessary), and
delivered to the uWebSockets thread to be sent in reply to that request.

uWebSockets picks up the data and sends whatever it can without
blocking, then buffers whatever it couldn't send to be sent again in a
later event loop iteration once the requestor can accept more data.
(This part is outside lokid; we only have to give uWS the data and let
it worry about delivery).

---

PR specifics:

Things removed from this PR:

1. ssl settings; with this PR the HTTP RPC interface is plain-text.  The
previous default generated a self-signed certificate for the server on
startup and then the client accepted any certificate.  This is actually
*worse* than unencrypted because it is entirely MITM-readable and yet
might make people think that their RPC communication is encrypted, and
setting up actual certificates is difficult enough that I think most
people don't bother.

uWebSockets *does* support HTTPS, and we could glue the existing options
into it, but I'm not convinced it's worthwhile: it works much better to
put HTTPS in a front-end proxy holding the certificate that proxies
requests to the backend (which can then listen in restricted mode on
some localhost port).  One reason this is better is that it is much
easier to reload and/or restart such a front-end server, while
certificate updates with lokid require a full restart.  Another reason
is that you get an error page instead of a timeout if something is wrong
with the backend.  Finally we also save having to generate a temporary
certificate on *every* lokid invocation.

2. HTTP Digest authentication.  Digest authentication is obsolete (and
was already obsolete when it got added to Monero).  HTTP-Digest was
originally an attempt to provide a password authentication mechanism
that does not leak the password in transit, but still required that the
server know the password.  It only has marginal value against replay
attacks, and is made entirely obsolete by sending traffic over HTTPS
instead.  No client out there supports Digest but *not* Basic auth, and
so given the limited usefulness it seems pointless to support more than
Basic auth for HTTP RPC login.

What's worse is that epee's HTTP Digest authentication is a terrible
implementation: it uses boost::spirit -- a recursive descent parser
meant for building complex language grammars -- just to parse a single
HTTP header for Digest auth.  This is a big load of crap that should
never have been accepted upstream, and that we should get rid of (even
if we wanted to support Digest auth it takes less than 100 lines of code
to do it when *not* using a recursive descent parser).
2020-08-07 17:14:02 -03:00
Jason Rhinelander
fc4e251ab0 DRY REGISTER_CALLBACK
REGISTER_CALLBACK and REGISTER_CALLBACK_METHOD do *exactly the same
thing*, and both take a different and unnecessary argument.  DRY it out
and make it use a lambda instead of boost::bind.
2020-07-02 12:52:13 -03:00
Jason Rhinelander
6a7deea931 boost::function -> std::function 2020-07-02 12:52:13 -03:00
Jason Rhinelander
e7d056edf1 boost::variant -> std::variant
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.
2020-07-02 12:52:12 -03:00
Jason Rhinelander
a506790f1c Serialization (part2): application 2020-07-02 12:52:12 -03:00
Jason Rhinelander
96354a0e0f boost::optional -> std::optional 2020-07-02 12:52:12 -03:00
Jason Rhinelander
9c5c1dac50 Replace boost::regex with std::regex 2020-07-02 12:52:12 -03:00
Jason Rhinelander
3b110879b6 Temp fix for boost compatibility
To be reverted with C++17 changes.
2020-06-14 23:43:35 -03:00
Doyle
e263d132f9 Fix core_tests for upstream merge 2020-06-02 12:09:22 +10:00
Doyle
4cc48ed813 Merge commit 'fe73607' into MergeUpstream3 2020-05-27 14:38:37 +10:00
Doyle
713d848146 core_tests: Fix core still expecting cryptonote_protocol to be set 2020-04-24 14:19:04 +10:00
Jason Rhinelander
934e398f96 sqlite3_close from name_system_db destructor 2020-03-31 04:13:43 -03:00
Jason Rhinelander
23d934eb06 Test suite fixes
- De-const a bunch of things that need to be non-const now
- Stick lns_db_ in a shared_ptr because it isn't copyable anymore but
the chain generator needs to remain copyable for fork testing.
2020-03-31 04:05:12 -03:00
Doyle
0112974dda LNS: Store wallet addresses to DB
- Renames generic_key->generic_owner
- Move generic_owner and generic_signature out of crypto.h because they
aren't really crypto items, rather composition of crypto primitives.
generic_owner also needs access to account_public_address, while that is
just 2 public keys, I've decided to include cryptonote_basic.h into
tx_extra.h instead of crypto.h.
- Some generic_owner helper functions were moved into
cryptonote_basic/format_utils as they need to avoid circular
dependencies between cryptonote_core/cryptonote_basic had I included
generic_owner/generic_signature into loki_name_system.h
- Utilise the normal serialize macros since tx_extra.h already includes
the serializing headers.
2020-03-13 16:07:14 +11:00
Doyle
1bff385cac Add support for backup owners and allow updating LNS fields 2020-03-11 10:58:05 +11:00
Doyle
aefdbbcae4 Update SQL commands to handle backup owner keys 2020-03-11 10:58:05 +11:00
Doyle
9071ecbc92 Make LNS take generic keys/sigs where it can for owner keys 2020-03-11 10:58:05 +11:00
Doyle
1ba657d3b5 Encrypt mapping values via libsodium, using the name as secret 2020-03-06 16:25:41 +11:00
Doyle
2ee128c47a Use enum_field for type to use lns::mapping_type 2020-02-20 09:34:25 +11:00
Doyle
523635db0b Generate a proper hash for signatures to prevent LNS update replays 2020-02-20 09:34:25 +11:00
Doyle
0363e5d50c Add various LNS tests for updating record variants 2020-02-20 09:34:25 +11:00
Doyle
f47efd713a Introduce LNS update transaction to update the underlying value mapping 2020-02-20 09:34:25 +11:00
Doyle
103f92a6a0 Resolve enabled mapping types via hf aware function instead of via enum 2020-02-13 11:07:47 +11:00