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

[Bug] CachedNonceManager should not be Clone #1507

Open
pmikolajczyk41 opened this issue Oct 17, 2024 · 1 comment
Open

[Bug] CachedNonceManager should not be Clone #1507

pmikolajczyk41 opened this issue Oct 17, 2024 · 1 comment
Labels
bug Something isn't working

Comments

@pmikolajczyk41
Copy link

Component

provider, pubsub

What version of Alloy are you on?

alloy-provider v0.4.2 (main branch)

Operating System

Linux

Describe the bug

Problem description

CachedNonceManager keeps DashMap for local storing of the current nonce per account. DashMap implements Clone (https://docs.rs/dashmap/latest/src/dashmap/lib.rs.html#96-110) by simply coping every entry. Therefore, two clones of a CachedNonceManager instance will fall into a conflict after just one transaction.

The right way of using it

As in the unit test (https://github.com/alloy-rs/alloy/blob/main/crates/provider/src/fillers/nonce.rs#L213-L214), any provider using nonce caching underneath MUST be kept under Arc. However, lib API doesn't enforce that and thus it is very easy (and pretty natural) to clone raw providers and counting that the nonce caching will be shared across clones.

If these clones share signer (e.g. WalletFiller), then a nonce conflict is inevitable (unless provider is always cloned before sending any transaction, but then we don't benefit from local caching, since the nonce is always being fetched).

General solution

IMHO the problem lies in the totally weird impl Clone for DashMap and thus I suggest two ways of keeping users safe:

  1. change DashMap to anything reasonable, where cloning actually preserves entries
  2. make CachedNonceManager !Clone

Reproduction of a very easy misuse

    #[tokio::test]
    async fn cloned_caching_does_not_cooperate() {
        let filler = NonceFiller::<CachedNonceManager>::default();
        let filler_copy = filler.clone();

        let provider = ProviderBuilder::new().on_anvil();
        let address = Address::ZERO;

        assert_eq!(
            filler.nonce_manager.get_next_nonce(&provider, address).await.unwrap(),
            0
        );
        assert_eq!(
            filler_copy.nonce_manager.get_next_nonce(&provider, address).await.unwrap(),
            1
        );
    }
@pmikolajczyk41 pmikolajczyk41 added the bug Something isn't working label Oct 17, 2024
@nadtech-hub
Copy link
Contributor

🙋‍♂️

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

3 participants
@nadtech-hub @pmikolajczyk41 and others