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

Manage durable nonce stored value in runtime #7684

Merged
merged 7 commits into from
Jan 10, 2020

Conversation

t-nelson
Copy link
Contributor

@t-nelson t-nelson commented Jan 5, 2020

Problem

As per #7443, managing the stored durable nonce value in a program instruction leaves executions resulting in InstructionError open to continuous replay and fee theft until the stored nonce is successfully advanced.

Summary of Changes

Store nonce account of durable nonce TXs that fail with InstructionError
Check nonce premature-usage in runtime
Advance nonce in runtime

Fixes #7443

@codecov
Copy link

codecov bot commented Jan 5, 2020

Codecov Report

Merging #7684 into master will increase coverage by <.1%.
The diff coverage is 99.2%.

@@           Coverage Diff            @@
##           master   #7684     +/-   ##
========================================
+ Coverage    81.7%   81.7%   +<.1%     
========================================
  Files         241     241             
  Lines       50750   50871    +121     
========================================
+ Hits        41502   41609    +107     
- Misses       9248    9262     +14

@t-nelson
Copy link
Contributor Author

t-nelson commented Jan 5, 2020

Dropped the removal of instruction nonce advance to regain advancing explicitly with non-durable-nonce TX (fixes CLI integration tests). Probably a good safe guard to keep around in any case. Now I'm considering only doing the runtime advance on InstructionError. wdyt @rob-solana ?

@rob-solana
Copy link
Contributor

I think I've lost the trail of this.

I thought the fix was going to be pay fee + verify the Nonce instruction worked (do both of these during load()). If the Nonce can't advance, don't collect fee, report load failure.

There'd be no store-side changes needed.

@t-nelson
Copy link
Contributor Author

t-nelson commented Jan 6, 2020

The fee theft opportunity presents itself if any instruction in the transaction fails. We have to advance the nonce, or not charge fees. Not charging fees opens us up to DoS, so always advancing the nonce seems like the surest path

@rob-solana
Copy link
Contributor

rob-solana commented Jan 6, 2020

The fee theft opportunity presents itself if any instruction in the transaction fails. We have to advance the nonce, or not charge fees. Not charging fees opens us up to DoS, so always advancing the nonce seems like the surest path

I think we're on the same page there. I'd hoped that running the Nonce instruction or checking that the Nonce instruction would succeed would be part of load()

like, do it here: https://github.com/solana-labs/solana/pull/7684/files#diff-0104dfa96426a3a49428815872a0356eR154

@t-nelson
Copy link
Contributor Author

t-nelson commented Jan 6, 2020

The new_nonce != stored_nonce check is. However thinking more on this, without checking for the authority's sig, I'm pretty sure anyone can advance any nonce account now...

Lemme see how gross executing the instruction is

@t-nelson
Copy link
Contributor Author

t-nelson commented Jan 6, 2020

This might not actually be too bad! 🤞

@t-nelson
Copy link
Contributor Author

t-nelson commented Jan 10, 2020

@rob-solana Sorry, didn't see your edit

like, do it here: https://github.com/solana-labs/solana/pull/7684/files#diff-0104dfa96426a3a49428815872a0356eR154

I initially put the nonce ix pre-execution in the caller, since we had more of the stuff needed to call process_message()-based function. It's in another branch ATM, top four at https://github.com/t-nelson/solana/commits/full-nonce-ix-check

I don't think this'll work purely load-side, though. The problem is the initial TX failing InstructionError having its successful NonceAdvance rolled back, not the replays being loaded. Those willl all get tagged by verify_nonce() and result in a TransactionError::BlockhashNotFound as implemented here. Or am I missing something and the pre-execution is supposed to check something else? I've struggled to get to the pre-execution failure with a test

@rob-solana
Copy link
Contributor

Ok, I think you're right. I think what you have will work.

@t-nelson
Copy link
Contributor Author

Thanks!

@t-nelson t-nelson merged commit 9754fc7 into solana-labs:master Jan 10, 2020
mergify bot pushed a commit that referenced this pull request Jan 10, 2020
* Bank: Return nonce pubkey/account from `check_tx_durable_nonce`

* Forward account with HashAgeKind::DurableNonce

* Add durable nonce helper for HashAgeKind

* Add nonce util for advancing stored nonce in runtime

* Advance nonce in runtime

* Store rolled back nonce account on TX InstructionError

* nonce: Add test for replayed InstErr fee theft

(cherry picked from commit 9754fc7)

# Conflicts:
#	runtime/src/accounts.rs
@t-nelson t-nelson deleted the nonce-runtime-advance branch January 11, 2020 00:00
t-nelson added a commit that referenced this pull request Jan 11, 2020
* Bank: Return nonce pubkey/account from `check_tx_durable_nonce`

* Forward account with HashAgeKind::DurableNonce

* Add durable nonce helper for HashAgeKind

* Add nonce util for advancing stored nonce in runtime

* Advance nonce in runtime

* Store rolled back nonce account on TX InstructionError

* nonce: Add test for replayed InstErr fee theft
solana-grimes pushed a commit that referenced this pull request Jan 11, 2020
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.

Durable nonce transactions resulting in an instruction error allow fee theft
2 participants