Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: let internal govobj/vote inv request trackers expire after 60 sec #6156

Merged
merged 7 commits into from
Aug 29, 2024

Conversation

UdjinM6
Copy link

@UdjinM6 UdjinM6 commented Jul 24, 2024

Issue being fixed or feature implemented

Another issue noticed during recent sb voting period. Lots of inv are coming from peers that never send the object/vote they announced. Let's not wait for these forever, 60 seconds should be enough.

What was done?

Add a "timer" to each request.

How Has This Been Tested?

Run tests, run a MN on mainnet and check logs.

Breaking Changes

n/a

Checklist:

  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have added or updated relevant unit/integration/functional/e2e tests
  • I have made corresponding changes to the documentation
  • I have assigned this pull request to a milestone (for repository code-owners and collaborators only)

knst
knst previously approved these changes Jul 26, 2024
Copy link
Collaborator

@knst knst left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

utACK 75f4115

@@ -270,8 +270,8 @@ class CGovernanceManager : public GovernanceStore
int nCachedBlockHeight;
std::map<uint256, CGovernanceObject> mapPostponedObjects;
hash_s_t setAdditionalRelayObjects;
hash_s_t setRequestedObjects;
hash_s_t setRequestedVotes;
std::map<uint256, int64_t> mapRequestedObjects;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if set is giving information what that's just a set of requested object, the map as a member name prefix doesn't give a context.

Consider renaming mapRequestedObjects to requestedObjectsWithTime or timeOfRequestedObjects or something else.

Same for AcceptMessage: mapHash -> hashesWithTime ?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point 👍 Also the logic for these 2 maps is essentially the same so I took it a bit further and squashed them into one, see dea1395.

break;
default:
return false;
}

const auto& [_itr, inserted] = setHash->insert(inv.hash);
const auto& [_itr, inserted] = mapHash->emplace(inv.hash, GetTime<std::chrono::seconds>().count() + RELIABLE_PROPAGATION_TIME);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

note for myself: GetTime return mocked time here

knst
knst previously approved these changes Jul 26, 2024
Copy link
Collaborator

@knst knst left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

utACK dea1395

}

const auto& [_itr, inserted] = setHash->insert(inv.hash);
const auto valid_until = GetTime<std::chrono::seconds>().count() + RELIABLE_PROPAGATION_TIME;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe we keep the times here in std::chrono types?

@coolaj86
Copy link

coolaj86 commented Aug 12, 2024

Could someone please explain simply what this fix means in terms of the user pipeline for gobject prepare; gobject submit?
(which I hope is no change)

Real-World, Implemented-in-Production Use Case

I created the following proposal with a time backdated to match start_epoch (or otherwise time is one day in the past on the same hour as start_epoch):

This was to avoid the following, documented-as-dangerous UX bug:

    // This command is dangerous because it consumes 5 DASH irreversibly.
    // If params are lost, it's very hard to bruteforce them and yet
    // users ignore all instructions on dashcentral etc. and do not save them...
    // Let's log them here and hope users do not mess with debug.log

The code for generating the timestamps to circumvent that bug is here:

/**
   * Creates a draft object with reasonable and default values
   * @param {Uint53} now - use Date.now(), except in testing
   * @param {Uint53} startEpochMs - used to create a deterministic gobject time
   * @param {GObjectData} data - will be sorted and hex-ified
   * @param {GObject} [gobj] - override values
   */
  DashGov.proposal.draft = function (now, startEpochMs, data, gobj) {
    let dataHex = gobj?.dataHex || DashGov.proposal.sortAndEncodeJson(data);
    let time = DashGov.proposal._selectKnownTime(now, startEpochMs);

    /** @type {DashGov.GObject} */
    let normalGObj = {
      hashParent: 0,
      revision: 1,
      time: time,
      dataHex: "",
      masternodeOutpoint: null,
      collateralTxId: null,
      collateralTxOutputIndex: null,
      signature: null,
    };
    Object.assign(normalGObj, gobj, { dataHex });

    return normalGObj;
  };
/**
   * The arbitrary use of random times is a leading cause of lost money during
   * the proposal process, so instead we use the 'start epoch' when appropriate,
   * or otherwise a UTC day interval of the start epoch
   * @param {Uint53} now
   * @param {Uint53} startMs
   */
  DashGov.proposal._selectKnownTime = function (now, startMs) {
    let startEpochDate = new Date(startMs);
    let today = new Date();
    if (today < startEpochDate) {
      let date = today.getUTCDate();
      startEpochDate.setUTCFullYear(today.getUTCFullYear());
      startEpochDate.setUTCMonth(today.getUTCMonth());
      startEpochDate.setUTCDate(date - 1);
    }
    let knownTimeMs = startEpochDate.valueOf();
    let knownSecs = knownTimeMs / 1000;
    knownSecs = Math.floor(knownSecs);

    return knownSecs;
  };

Assumption

I believe what this issue is saying is just that it's going to ignore inventory spam based on actual MN message time from the (supposed) gobject submit that should be sending inventory via p2p and gobject via the MN network simultaneously. So I believe it won't affect this sort of fix, but I'd like an ACK... or a change to the code to not cement the UX bug further in place at the protocol layer.

edit: hmm... not sure why github isn't unfurling those code blocks like it normally does, updated with code

@UdjinM6
Copy link
Author

UdjinM6 commented Aug 12, 2024

@coolaj86 this PR has nothing to do with the proposal data itself, it's dealing with an observed misbehaviour on p2p level only. Basically, a peer says "I have a governance object/vote with hash X", we remember this and request it. The object with hash X never arrives but we kept waiting for it forever (not really waiting in networking terms, just remembering that we asked for it earlier). This PR simply lets us forget about such requests after 60 seconds.

@PastaPastaPasta
Copy link
Member

let's rebase I guess to have CI green? may just be a flaky failure, restarting.

Copy link
Member

@PastaPastaPasta PastaPastaPasta left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

utACK d41d87a; changes to tests for this expiration logic would be appreciated

Copy link
Collaborator

@knst knst left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

utACK 1f4e1a1

@PastaPastaPasta PastaPastaPasta merged commit a40802b into dashpay:develop Aug 29, 2024
33 checks passed
@UdjinM6 UdjinM6 modified the milestones: 21.2, 22 Oct 29, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants