aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorj-berman <justinberman95@gmail.com>2021-08-19 14:58:50 -0700
committerj-berman <justinberman95@gmail.com>2021-08-19 14:59:12 -0700
commit99bee1ccf0a9ea97bdb2401038b72da7717e178e (patch)
treeec60cc9211c6e1ce08ffee09fad3d74e98a36075
parentMerge pull request #7734 (diff)
downloadmonero-99bee1ccf0a9ea97bdb2401038b72da7717e178e.tar.xz
Apply gamma distr from chain tip when selecting decoys
- matches the paper by Miller et al to apply the gamma from chain tip, rather than after unlock time - if the gamma produces an output more recent than the unlock time, the algo packs that output into one of the first 50 spendable blocks, respecting the block density factor
-rw-r--r--src/wallet/wallet2.cpp31
1 files changed, 31 insertions, 0 deletions
diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp
index 642777797..3a0d45a33 100644
--- a/src/wallet/wallet2.cpp
+++ b/src/wallet/wallet2.cpp
@@ -142,6 +142,9 @@ using namespace cryptonote;
#define IGNORE_LONG_PAYMENT_ID_FROM_BLOCK_VERSION 12
+#define DEFAULT_UNLOCK_TIME (CRYPTONOTE_DEFAULT_TX_SPENDABLE_AGE * DIFFICULTY_TARGET_V2)
+#define RECENT_SPEND_WINDOW (50 * DIFFICULTY_TARGET_V2)
+
static const std::string MULTISIG_SIGNATURE_MAGIC = "SigMultisigPkV1";
static const std::string MULTISIG_EXTRA_INFO_MAGIC = "MultisigxV1";
@@ -1031,6 +1034,34 @@ uint64_t gamma_picker::pick()
{
double x = gamma(engine);
x = exp(x);
+
+ if (x > DEFAULT_UNLOCK_TIME)
+ {
+ // We are trying to select an output from the chain that appeared 'x' seconds before the
+ // current chain tip, where 'x' is selected from the gamma distribution recommended in Miller et al.
+ // (https://arxiv.org/pdf/1704.04299/).
+ // Our method is to get the average time delta between outputs in the recent past, estimate the number of
+ // outputs 'n' that would have appeared between 'chain_tip - x' and 'chain_tip', select the real output at
+ // 'current_num_outputs - n', then randomly select an output from the block where that output appears.
+ // Source code to paper: https://github.com/maltemoeser/moneropaper
+ //
+ // Due to the 'default spendable age' mechanic in Monero, 'current_num_outputs' only contains
+ // currently *unlocked* outputs, which means the earliest output that can be selected is not at the chain tip!
+ // Therefore, we must offset 'x' so it matches up with the timing of the outputs being considered. We do
+ // this by saying if 'x` equals the expected age of the first unlocked output (compared to the current
+ // chain tip - i.e. DEFAULT_UNLOCK_TIME), then select the first unlocked output.
+ x -= DEFAULT_UNLOCK_TIME;
+ }
+ else
+ {
+ // If the spent time suggested by the gamma is less than the unlock time, that means the gamma is suggesting an output
+ // that is no longer feasible to be spent (possible since the gamma was constructed when consensus rules did not enforce the
+ // lock time). The assumption made in this code is that an output expected spent quicker than the unlock time would likely
+ // be spent within RECENT_SPEND_WINDOW after allowed. So it returns an output that falls between 0 and the RECENT_SPEND_WINDOW.
+ // The RECENT_SPEND_WINDOW was determined with empirical analysis of observed data.
+ x = crypto::rand_idx(static_cast<uint64_t>(RECENT_SPEND_WINDOW));
+ }
+
uint64_t output_index = x / average_output_time;
if (output_index >= num_rct_outputs)
return std::numeric_limits<uint64_t>::max(); // bad pick