loki_tx_builder fails for this test: it creates unserializable txes
because `vin` is too large. This was previously "passing" the test for
completely wrong reasons: the test produces transactions that fail to
serialize (triggering a "invalid mg_ss2 size: have 2, expected 3"
failure) while the point of the test was to produce serializable, but
invalid, transactions.
The failure wasn't being detected because the `tx_to_blob(t)` call in
`cryptonote_format_utils.cpp` would return a *partially filled*
serialization blob in case of serialization failure, which was
incredibly broken. `calculate_transaction_hash()` then was perfectly
happy to proceed with hashing this broken blob.
`tx_to_blob(t)` now returns an empty string on such a serialization
failure, and this made the test start failing because
`calculate_transaction_hash()` now fails.
This improves `calculate_transaction_hash()` a little more to add
earlier and more direct detection of such a failure, and fixes the test
by reverting it to the original Monero tx builder test code, which
creates the intended serializable-but-invalid transactions.
The tx extra getting/setting API is a little non-DRY, so this dries it
out with some small changes:
- Added get_field_from_tx_extra that takes a specific tx_extra lvalue
reference and fetches it. This eliminates a bunch of nearly duplicate
code that calls parse - find - return.
- Add three new functions to add tagged data:
- add_tagged_data_to_tx_extra is a raw function that takes a
tag and string_view and appends it to tx_extra
- add_tx_extra<T>(tx_extra, val) lets you copy `val` directly as a
`T`. `val` does *not* have to be the same as `T` (`T` is not
deduced) but rather just has to have the same size. This makes it
very easy to add simple tx_extra values such as `tx_extra_pub_key`
from just a pub key without needing to wrap it first:
add_tx_extra<tx_extra_pub_key>(tx.extra, regular_old_pubkey);
- add_tx_extra<T>(tx, val) - very light wrapper around the above that
takes a transaction lvalue directly (rather than the extra vector)
for slight convenience.
These additions allow removing several now-unneeded methods and simplify
some code around the tx extra handling.
This commit also converts the TX_EXTRA_* macros into constexprs.
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.
Switch loki dev branch to C++17 compilation, and update the code with
various C++17 niceties.
- stop including the (deprecated) lokimq/string_view.h header and
instead switch everything to use std::string_view and `""sv` instead of
`""_sv`.
- std::string_view is much nicer than epee::span, so updated various
loki-specific code to use it instead.
- made epee "portable storage" serialization accept a std::string_view
instead of const lvalue std::string so that we can avoid copying.
- switched from mapbox::variant to std::variant
- use `auto [a, b] = whatever()` instead of `T1 a; T2 b; std::tie(a, b)
= whatever()` in a couple places (in the wallet code).
- switch to std::lock(...) instead of boost::lock(...) for simultaneous
lock acquisition. boost::lock() won't compile in C++17 mode when given
locks of different types.
- removed various pre-C++17 workarounds, e.g. for fold expressions,
unused argument attributes, and byte-spannable object detection.
- class template deduction means lock types no longer have to specify
the mutex, so `std::unique_lock<std::mutex> lock{mutex}` can become
`std::unique_lock lock{mutex}`. This will make switching any mutex
types (e.g. from boost to std mutexes) far easier as you just have to
update the type in the header and everything should work. This also
makes the tools::unique_lock and tools::shared_lock methods redundant
(which were a sort of poor-mans-pre-C++17 way to eliminate the
redundancy) so they are now gone and replaced with direct unique_lock or
shared_lock constructions.
- Redid the LNS validation using a string_view; instead of using raw
char pointers the code now uses a string view and chops off parts of the
view as it validates. So, for instance, it starts with "abcd.loki",
validates the ".loki" and chops the view to "abcd", then validates the
first character and chops to "bcd", validates the last and chops to
"bc", then can just check everything remaining for is-valid-middle-char.
- LNS validation gained a couple minor validation checks in the process:
- slightly tightened the requirement on lokinet addresses to require
that the last character of the mapped address is 'y' or 'o' (the
last base32z char holds only one significant bit).
- In parse_owner_to_generic_owner made sure that the owner value has
the correct size (otherwise we could up end not filling or
overfilling the pubkey buffer).
- Replaced base32z/base64/hex conversions with lokimq's versions which
have a nicer interface, are better optimized, and don't depend on epee.
Removes all "using namespace epee;" and "using namespace std;" from the
code and fixes up the various crappy places where unnamespaced types
were being used.
Also removes the ENDL macro (which was defined to be `std::endl`)
because it is retarded, and because even using std::endl instead of a
plain "\n" is usually a mistake (`<< std::endl` is equivalent to `<<
"\n" << std::flush`, and that explicit flush is rarely desirable).
We have never had decomposed amounts. (And I think the stuck v1
transactions are stuck precisely *because* they are v1 transactions
which are not valid decomposed amounts).
An automatic tx variable is initialized properly on the first
run through the loop, but not the second. Moving the variable
inside the loop ensures the ctor is called again to init it.
- 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.
We want to allow people to buy LNS entries on behalf of other users. If
this is the case we don't need signatures to verify that the purchaser
knows the secret key. What we actually want in this scenario is that,
there's a LNS entry, and people can voluntarily pay to renew/buy that.
The wallet does something funky with the key storage that the
values have changed, even after decrypting the wallet keys. The ed keys are
different from when we originally derived them, so for now, just re-derive
// NOTE: Compiling with a minimum Mac OSX API of 10.13 and generating
// a binary_archive with a one_shot_read_buffer, causes the following snippet
// to fail
explicit binary_archive(stream_type &s) : base_type(s) {
stream_type::pos_type pos = stream_.tellg();
stream_.seekg(0, std::ios_base::end);
eof_pos_ = stream_.tellg();
stream_.seekg(pos);
}
// In particular
// stream_.seekg(0, std::ios_base::end);
// eof_pos_ = stream_.tellg();
// A seekg followed by a tellg returns 0, no state flags are set on the io
// stream. So use the old method that copies the blob into a stringstream
// instead for APPLE targets.
- Fix assert to use version_t::_count in service_node_list.cpp
- Incoporate staking changes from LNS which revamp construct tx to
derive more of the parameters from hf_version and type. This removes
extraneous parameters that can be derived elsewhere.
Also delegate setting loki_construct_tx_params into wallet2 atleast,
so that callers into the wallet logic, like rpc server, simplewallet
don't need bend backwards to get the HF version whereas the wallet has
dedicated functions for determining the HF.
This adds the ability for check_fee() to also check the burn amount.
This requires passing extra info through `add_tx()` (and the various
things that call it), so I took the:
bool keeped_by_block, bool relayed, bool do_not_relay
argument triplet, moved it into a struct in tx_pool.h, then added the other fee
options there (along with some static factory functions for generating the
typical sets of option).
The majority of this commit is chasing that change through the codebase and
test suite.
This is used by blink but should also help LNS and other future burn
transactions to verify a burn amount simply when adding the transation to the
mempool. It supports a fixed burn amount, a burn amount as a multiple of the
minimum tx fee, and also allows you to increase the minimum tx fee (so that,
for example, we could require blink txes to pay miners 250% of the usual
minimum (unimportant) priority tx fee.
- Removed a useless core::add_new_tx() overload that wasn't used anywhere.
Blink-specific changes:
(I'd normally separate these into a separate commit, but they got interwoven
fairly heavily with the above change).
- changed the way blink burning is specified so that we have three knobs for
fee adjustment (fixed burn fee; base fee multiple; and required miner tx fee).
The fixed amount is currently 0, base fee is 400%, and require miner tx fee is
simply 100% (i.e. no different than a normal transaction). This is the same as
before this commit, but is changing how they are being specified in
cryptonote_config.h.
- blink tx fee, burn amount, and miner tx fee (if > 100%) now get checked
before signing a blink tx. (These fee checks don't apply to anyone else --
when propagating over the network only the miner tx fee is checked).
- Added a couple of checks for blink quorums: 1) make sure they have reached
the blink hf; 2) make sure the submitted tx version conforms to the current hf
min/max tx version.
- print blink fee information in simplewallet's `fee` output
- add "typical" fee calculations in the `fee` output:
[wallet T6SCwL (has locked stakes)]: fee
Current fee is 0.000000850 loki per byte + 0.020000000 loki per output
No backlog at priority 1
No backlog at priority 2
No backlog at priority 3
No backlog at priority 4
Current blink fee is 0.000004250 loki per byte + 0.100000000 loki per output
Estimated typical small transaction fees: 0.042125000 (unimportant), 0.210625000 (normal), 1.053125000 (elevated), 5.265625000 (priority), 0.210625000 (blink)
where "small" here is the same tx size (2500 bytes + 2 outputs) used to
estimate backlogs.
Neither of these have a place in modern C++11; boost::value_initialized
is entirely superseded by `Type var{};` which does value initialization
(or default construction if a default constructor is defined). More
problematically, each `boost::value_initialized<T>` requires
instantiation of another wrapping templated type which is a pointless
price to pay the compiler in C++11 or newer.
Also removed is the AUTO_VAL_INIT macro (which is just a simple macro
around constructing a boost::value_initialized<T>).
BOOST_FOREACH is a similarly massive pile of code to implement
C++11-style for-each loops. (And bizarrely it *doesn't* appear to fall
back to C++ for-each loops even when under a C++11 compiler!)
This removes both entirely from the codebase.
This adds a tx extra field that specifies an amount of the tx fee that
must be burned; the miner can claim only (txnFee - burnFee) when
including the block.
This will be used for the extra, burned part of blink fees and LNS fees
and any other transaction that requires fee burning in the future.
If the peer (whether pruned or not itself) supports sending pruned blocks
to syncing nodes, the pruned version will be sent along with the hash
of the pruned data and the block weight. The original tx hashes can be
reconstructed from the pruned txes and theur prunable data hash. Those
hashes and the block weights are hashes and checked against the set of
precompiled hashes, ensuring the data we received is the original data.
It is currently not possible to use this system when not using the set
of precompiled hashes, since block weights can not otherwise be checked
for validity.
This is off by default for now, and is enabled by --sync-pruned-blocks